turing/turing.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;
}