165 lines
3.4 KiB
C
165 lines
3.4 KiB
C
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <ctype.h>
|
|
#include <unistd.h>
|
|
|
|
#include "table.h"
|
|
#include "tape.h"
|
|
#include "program.h"
|
|
|
|
struct turing
|
|
{
|
|
struct table *states;
|
|
struct table *symbols;
|
|
struct table *program;
|
|
};
|
|
|
|
void *str_clone(void *p)
|
|
{
|
|
return (void *)strdup((char *)p);
|
|
}
|
|
|
|
int str_cmp(void *a, void *b)
|
|
{
|
|
return strcmp((char *)a, (char *)b);
|
|
}
|
|
|
|
void str_repr(void *p, char *buf, int size)
|
|
{
|
|
strncpy(buf, (char *)p, size-1);
|
|
buf[size-1] = '\0';
|
|
}
|
|
|
|
void turing_free(struct turing *tm)
|
|
{
|
|
if (tm == NULL)
|
|
return;
|
|
if (tm->program != NULL)
|
|
table_free(tm->program);
|
|
if (tm->symbols != NULL)
|
|
table_free(tm->symbols);
|
|
if (tm->states != NULL)
|
|
table_free(tm->states);
|
|
free(tm);
|
|
}
|
|
|
|
struct turing *turing_new(char *programfn, char *start, char *blank)
|
|
{
|
|
struct turing *r;
|
|
FILE *programf;
|
|
|
|
programf = fopen(programfn, "r");
|
|
if (programf == NULL)
|
|
return NULL;
|
|
|
|
r = (struct turing *)malloc(sizeof(struct turing));
|
|
|
|
if (r == NULL)
|
|
return NULL;
|
|
|
|
r->states = r->symbols = r->program = NULL;
|
|
r->states = table_new(20, 10, str_clone, free, str_cmp, str_repr);
|
|
r->symbols = table_new(20, 10, str_clone, free, str_cmp, str_repr);
|
|
r->program = program_new();
|
|
if ((r->states == NULL) || (r->symbols == NULL) || (r->program == NULL)) {
|
|
turing_free(r);
|
|
return NULL;
|
|
}
|
|
|
|
if (start != NULL)
|
|
table_insert(r->states, start);
|
|
if (blank != NULL)
|
|
table_insert(r->symbols, blank);
|
|
|
|
program_load(programf, r->program, r->states, r->symbols);
|
|
fclose(programf);
|
|
|
|
printf("STATES: ");
|
|
table_print(r->states);
|
|
printf("SYMBOLS: ");
|
|
table_print(r->symbols);
|
|
printf("PROGRAM: ");
|
|
table_print(r->program);
|
|
|
|
return r;
|
|
}
|
|
|
|
int turing_run(struct turing *tm, char *tapefn)
|
|
{
|
|
FILE *tapef;
|
|
struct instruction row, *insn;
|
|
int iinsn;
|
|
int steps;
|
|
struct tape *tape;
|
|
|
|
|
|
tapef = fopen(tapefn, "r");
|
|
if (tapef == NULL)
|
|
return EXIT_FAILURE;
|
|
|
|
tape = tape_new(0);
|
|
tape_load(tape, tapef, 0, tm->symbols);
|
|
|
|
fclose(tapef);
|
|
|
|
steps = 0;
|
|
row.state = 0;
|
|
for (;;) {
|
|
tape_print(tape, tm->symbols);
|
|
row.symbol = tape_read(tape, tape->head);
|
|
iinsn = table_find(tm->program, &row);
|
|
if (iinsn < 0)
|
|
break;
|
|
insn = table_lookup(tm->program, iinsn);
|
|
row.state = insn->nextstate;
|
|
tape_write(tape, tape->head, insn->write);
|
|
tape->head += insn->move;
|
|
steps++;
|
|
}
|
|
|
|
return steps;
|
|
}
|
|
|
|
int main(int argc, char *argv[])
|
|
{
|
|
int opt;
|
|
char *start, *blank;
|
|
|
|
struct turing *tm;
|
|
|
|
start = blank = NULL;
|
|
|
|
while ((opt = getopt(argc, argv, "s:b:")) != -1) {
|
|
switch (opt) {
|
|
case 's':
|
|
start = optarg;
|
|
break;
|
|
case 'b':
|
|
blank = optarg;
|
|
break;
|
|
default:
|
|
fprintf(stderr, "Usage: %s [-s start] [-b blank] program tape\n",
|
|
argv[0]);
|
|
return EXIT_FAILURE;
|
|
}
|
|
}
|
|
|
|
if (optind >= argc - 1) {
|
|
fprintf(stderr, "Expected arguments\n");
|
|
return EXIT_FAILURE;
|
|
}
|
|
|
|
tm = turing_new(argv[optind], start, blank);
|
|
if (tm == NULL) {
|
|
fprintf(stderr, "Error loading program.\n");
|
|
return EXIT_FAILURE;
|
|
}
|
|
|
|
turing_run(tm, argv[optind+1]);
|
|
|
|
turing_free(tm);
|
|
|
|
return EXIT_SUCCESS;
|
|
}
|