First commit
This commit is contained in:
commit
86194ae081
|
@ -0,0 +1,4 @@
|
||||||
|
*[~%]
|
||||||
|
*.o
|
||||||
|
core
|
||||||
|
turing
|
|
@ -0,0 +1,24 @@
|
||||||
|
.POSIX:
|
||||||
|
.PHONY: clean all pretty
|
||||||
|
DEFINES=-D_XOPEN_SOURCE=500
|
||||||
|
CFLAGS=-std=c99 -Wall -pedantic $(DEFINES)
|
||||||
|
RM=-rm -f
|
||||||
|
|
||||||
|
BINARIES=turing
|
||||||
|
OFILES=turing.o table.o program.o tape.o
|
||||||
|
|
||||||
|
all: $(BINARIES)
|
||||||
|
|
||||||
|
turing.o: turing.c table.h program.h tape.h
|
||||||
|
table.o: table.c table.h
|
||||||
|
program.o: program.c program.h table.h
|
||||||
|
tape.o: tape.c tape.h table.h
|
||||||
|
|
||||||
|
turing: $(OFILES)
|
||||||
|
$(CC) $(LDFLAGS) -o $@ $(OFILES) $(LDLIBS)
|
||||||
|
|
||||||
|
pretty:
|
||||||
|
astyle --style=mozilla *.c *.h
|
||||||
|
|
||||||
|
clean:
|
||||||
|
$(RM) *% *~ *.o *.orig core $(BINARIES)
|
|
@ -0,0 +1,121 @@
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
|
||||||
|
#include "table.h"
|
||||||
|
#include "program.h"
|
||||||
|
|
||||||
|
static void *row_clone(void *p)
|
||||||
|
{
|
||||||
|
struct instruction *row;
|
||||||
|
|
||||||
|
row = (struct instruction *)malloc(sizeof(struct instruction));
|
||||||
|
memcpy((void *)row, p, sizeof(struct instruction));
|
||||||
|
|
||||||
|
return (void *)row;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int row_cmp(void *a, void *b)
|
||||||
|
{
|
||||||
|
struct instruction *ra, *rb;
|
||||||
|
|
||||||
|
ra = (struct instruction *)a;
|
||||||
|
rb = (struct instruction *)b;
|
||||||
|
|
||||||
|
if (ra->state < rb->state)
|
||||||
|
return -1;
|
||||||
|
if (ra->state > rb->state)
|
||||||
|
return 1;
|
||||||
|
if (ra->symbol < rb->symbol)
|
||||||
|
return -1;
|
||||||
|
if (ra->symbol > rb->symbol)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void row_repr(void *p, char *buf, int size)
|
||||||
|
{
|
||||||
|
struct instruction *row;
|
||||||
|
static char *moves = "LNR";
|
||||||
|
|
||||||
|
row = (struct instruction *)p;
|
||||||
|
|
||||||
|
snprintf(buf, size, "[%d %d | %d %d %c]",
|
||||||
|
row->state, row->symbol, row->nextstate, row->write,
|
||||||
|
((row->move >= -1) && (row->move <=1) ? moves[1+row->move] : '?'));
|
||||||
|
buf[size-1] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
static short int parse_move(char *m)
|
||||||
|
{
|
||||||
|
char c;
|
||||||
|
|
||||||
|
c = (char)tolower(m[0]);
|
||||||
|
if (c == 'l')
|
||||||
|
return -1;
|
||||||
|
if (c == 'r')
|
||||||
|
return 1;
|
||||||
|
if (c == 'n')
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return atoi(m);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct table *program_new()
|
||||||
|
{
|
||||||
|
return table_new(20, 10, row_clone, free, row_cmp, row_repr);
|
||||||
|
}
|
||||||
|
|
||||||
|
int program_load(FILE *f, struct table *prg, struct table *st, struct table *sym)
|
||||||
|
{
|
||||||
|
char line[LINE_LEN+1];
|
||||||
|
char state[STATE_LEN+1];
|
||||||
|
char symbol[SYMBOL_LEN+1];
|
||||||
|
char write[SYMBOL_LEN+1];
|
||||||
|
char move[8];
|
||||||
|
char nextstate[STATE_LEN+1];
|
||||||
|
int ll;
|
||||||
|
char *l;
|
||||||
|
char *p;
|
||||||
|
int r;
|
||||||
|
struct instruction row;
|
||||||
|
int cnt;
|
||||||
|
|
||||||
|
line[LINE_LEN] = '\0';
|
||||||
|
cnt = 0;
|
||||||
|
for (;;) {
|
||||||
|
l = fgets(line, sizeof(line)-1, f);
|
||||||
|
if (l == NULL)
|
||||||
|
break;
|
||||||
|
ll = strlen(l);
|
||||||
|
if (ll > 0) {
|
||||||
|
p = &line[ll-1];
|
||||||
|
while ((ll > 0) && ((*p == '\r') || (*p == '\n'))) {
|
||||||
|
*p = '\0';
|
||||||
|
ll--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
p = strchr(l, '#');
|
||||||
|
if (p != NULL)
|
||||||
|
*p = '\0';
|
||||||
|
r = sscanf(l, "%s %s %s %s %s",
|
||||||
|
state, symbol, nextstate, write, move);
|
||||||
|
if (r == 0)
|
||||||
|
continue;
|
||||||
|
if (r != 5) {
|
||||||
|
printf("Parsing error!\n");
|
||||||
|
} else {
|
||||||
|
row.state = table_insert(st, state);
|
||||||
|
row.symbol = table_insert(sym, symbol);
|
||||||
|
row.write = table_insert(sym, write);
|
||||||
|
row.move = parse_move(move);
|
||||||
|
row.nextstate = table_insert(st, nextstate);
|
||||||
|
table_insert(prg, &row);
|
||||||
|
cnt++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return cnt;
|
||||||
|
}
|
|
@ -0,0 +1,26 @@
|
||||||
|
#ifndef _PROGRAM_H
|
||||||
|
#define _PROGRAM_H
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include "table.h"
|
||||||
|
#include "program.h"
|
||||||
|
|
||||||
|
#define LINE_LEN 100
|
||||||
|
#define SYMBOL_LEN 20
|
||||||
|
#define STATE_LEN 20
|
||||||
|
|
||||||
|
struct instruction
|
||||||
|
{
|
||||||
|
int state;
|
||||||
|
int symbol;
|
||||||
|
int write;
|
||||||
|
short int move;
|
||||||
|
int nextstate;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct table *program_new();
|
||||||
|
int program_load(FILE *f, struct table *prg, struct table *st, struct table *sym);
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,9 @@
|
||||||
|
A simple and portable Turing Machine simulator
|
||||||
|
==============================================
|
||||||
|
|
||||||
|
This code should build cleanly on any POSIX OS using a C99 compliant
|
||||||
|
C compiler.
|
||||||
|
|
||||||
|
The goal of this project is to be easily understandable and hackable,
|
||||||
|
and is not meant to be efficient.
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
start nul carry nul L
|
||||||
|
start 0 start 0 R
|
||||||
|
start 1 start 1 R
|
||||||
|
carry nul halt 1 N
|
||||||
|
carry 0 halt 1 N
|
||||||
|
carry 1 carry 0 L
|
|
@ -0,0 +1 @@
|
||||||
|
1 1 0 0 1 0 1 1
|
|
@ -0,0 +1,6 @@
|
||||||
|
A 0 B 1 R
|
||||||
|
A 1 C 1 L
|
||||||
|
B 0 A 1 L
|
||||||
|
B 1 B 1 R
|
||||||
|
C 0 B 1 L
|
||||||
|
C 1 halt 1 N
|
|
@ -0,0 +1 @@
|
||||||
|
|
|
@ -0,0 +1,151 @@
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "table.h"
|
||||||
|
|
||||||
|
struct table *table_new(int capacity, int increment,
|
||||||
|
item_clone_f clone_f, item_free_f free_f, item_compare_f compare_f, item_repr_f repr_f)
|
||||||
|
{
|
||||||
|
struct table *r;
|
||||||
|
|
||||||
|
r = (struct table *)malloc(sizeof(*r));
|
||||||
|
if (r != NULL) {
|
||||||
|
r->items = (void **)malloc(capacity*sizeof(void *));
|
||||||
|
if (r->items == NULL) {
|
||||||
|
free(r);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
r->indexes = (int *)malloc(capacity*sizeof(int));
|
||||||
|
if (r->indexes == NULL) {
|
||||||
|
free(r->items);
|
||||||
|
free(r);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
r->size = 0;
|
||||||
|
r->capacity = capacity;
|
||||||
|
r->increment = increment;
|
||||||
|
r->clone_f = clone_f;
|
||||||
|
r->free_f = free_f;
|
||||||
|
r->compare_f = compare_f;
|
||||||
|
r->repr_f = repr_f;
|
||||||
|
r->dirty = true;
|
||||||
|
r->lookup = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
void table_free(struct table *t)
|
||||||
|
{
|
||||||
|
if (t->lookup != NULL)
|
||||||
|
free(t->lookup);
|
||||||
|
if (t->free_f != NULL)
|
||||||
|
for (int i=0; i < t->size; i++)
|
||||||
|
t->free_f(t->items[i]);
|
||||||
|
free(t->indexes);
|
||||||
|
free(t->items);
|
||||||
|
free(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool table_find_internal(struct table *t, void *entry, int *pos)
|
||||||
|
{
|
||||||
|
int cmp;
|
||||||
|
|
||||||
|
for (*pos=0; *pos < t->size; (*pos)++) {
|
||||||
|
cmp = t->compare_f(entry, t->items[*pos]);
|
||||||
|
if (cmp == 0)
|
||||||
|
return true;
|
||||||
|
if (cmp < 0)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int table_find(struct table *t, void *entry)
|
||||||
|
{
|
||||||
|
int pos;
|
||||||
|
|
||||||
|
if (table_find_internal(t, entry, &pos))
|
||||||
|
return t->indexes[pos];
|
||||||
|
else
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int table_insert(struct table *t, void *entry)
|
||||||
|
{
|
||||||
|
bool found;
|
||||||
|
int pos;
|
||||||
|
void **newitems;
|
||||||
|
int *newindexes;
|
||||||
|
void *swap;
|
||||||
|
int swapidx;
|
||||||
|
int r;
|
||||||
|
int newcapacity;
|
||||||
|
|
||||||
|
found = table_find_internal(t, entry, &pos);
|
||||||
|
|
||||||
|
if (!found) {
|
||||||
|
if (t->capacity <= t->size) {
|
||||||
|
newcapacity = t->capacity + t->increment;
|
||||||
|
newitems = (void **) realloc(
|
||||||
|
t->items, newcapacity*sizeof(void *));
|
||||||
|
if (newitems == NULL)
|
||||||
|
return -1;
|
||||||
|
newindexes = (int *) realloc(
|
||||||
|
t->indexes, newcapacity*sizeof(int));
|
||||||
|
if (newindexes == NULL) {
|
||||||
|
t->items = (void **) realloc(
|
||||||
|
newitems, t->capacity*sizeof(void *));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
t->items = newitems;
|
||||||
|
t->indexes = newindexes;
|
||||||
|
t->capacity = newcapacity;
|
||||||
|
}
|
||||||
|
r = t->size;
|
||||||
|
if (t->clone_f != NULL)
|
||||||
|
entry = t->clone_f(entry);
|
||||||
|
for (int i=pos; i <= t->size; i++) {
|
||||||
|
swap = t->items[i];
|
||||||
|
swapidx = t->indexes[i];
|
||||||
|
t->items[i] = entry;
|
||||||
|
t->indexes[i] = r;
|
||||||
|
entry = swap;
|
||||||
|
r = swapidx;
|
||||||
|
}
|
||||||
|
t->size++;
|
||||||
|
t->dirty = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return t->indexes[pos];
|
||||||
|
}
|
||||||
|
|
||||||
|
void *table_lookup(struct table *t, int idx)
|
||||||
|
{
|
||||||
|
if (t->dirty) {
|
||||||
|
t->lookup = realloc(t->lookup, t->size*sizeof(void *));
|
||||||
|
// TODO: check allocation
|
||||||
|
for (int i=0; i<t->size; i++)
|
||||||
|
t->lookup[t->indexes[i]] = t->items[i];
|
||||||
|
t->dirty = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return t->lookup[idx];
|
||||||
|
}
|
||||||
|
|
||||||
|
void table_print(struct table *t)
|
||||||
|
{
|
||||||
|
char buf[200];
|
||||||
|
|
||||||
|
printf("size=%d capacity=%d increment=%d\n", t->size, t->capacity, t->increment);
|
||||||
|
for (int i=0; i<t->size; i++) {
|
||||||
|
if (t->repr_f != NULL)
|
||||||
|
t->repr_f(t->items[i], buf, sizeof(buf));
|
||||||
|
printf(" %d (%d) %s\n", i, t->indexes[i],
|
||||||
|
(t->repr_f != NULL ? buf : "???"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,34 @@
|
||||||
|
#ifndef __TABLE_H
|
||||||
|
#define __TABLE_H
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
typedef void *(*item_clone_f)(void *);
|
||||||
|
typedef void (*item_free_f)(void *);
|
||||||
|
typedef int (*item_compare_f)(void *, void *);
|
||||||
|
typedef void (*item_repr_f)(void *, char *, int);
|
||||||
|
|
||||||
|
struct table
|
||||||
|
{
|
||||||
|
int size; // Number of entries actually used
|
||||||
|
int capacity; // Total allocated number of entries
|
||||||
|
int increment; // How many additional entries to allocate when growing the table
|
||||||
|
item_clone_f clone_f;
|
||||||
|
item_free_f free_f;
|
||||||
|
item_compare_f compare_f;
|
||||||
|
item_repr_f repr_f;
|
||||||
|
void **items; // Table entries, sorted
|
||||||
|
int *indexes; // Maps entried ids to their index inside the items array
|
||||||
|
void **lookup; // Cached lookup results
|
||||||
|
bool dirty; // Cached lookup entries are not up to date
|
||||||
|
};
|
||||||
|
|
||||||
|
struct table *table_new(int capacity, int increment,
|
||||||
|
item_clone_f clone_f, item_free_f free_f, item_compare_f compare_f, item_repr_f repr_f);
|
||||||
|
void table_free(struct table *t);
|
||||||
|
int table_find(struct table *t, void *entry);
|
||||||
|
int table_insert(struct table *t, void *entry);
|
||||||
|
void *table_lookup(struct table *t, int idx);
|
||||||
|
void table_print(struct table *t);
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,167 @@
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "tape.h"
|
||||||
|
|
||||||
|
struct tape *tape_new(int blank)
|
||||||
|
{
|
||||||
|
struct tape *r;
|
||||||
|
|
||||||
|
r = (struct tape *)malloc(sizeof(struct tape));
|
||||||
|
|
||||||
|
if (r != NULL) {
|
||||||
|
r->head = 0;
|
||||||
|
r->blank = blank;
|
||||||
|
r->ncapacity = r->pcapacity = 0;
|
||||||
|
r->nsyms = r->psyms = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
int tape_read(struct tape *t, int pos)
|
||||||
|
{
|
||||||
|
if (pos >= 0) {
|
||||||
|
if (pos >= t->pcapacity)
|
||||||
|
return t->blank;
|
||||||
|
else
|
||||||
|
return t->psyms[pos];
|
||||||
|
} else {
|
||||||
|
pos = -1 - pos;
|
||||||
|
if (pos >= t->ncapacity)
|
||||||
|
return t->blank;
|
||||||
|
else
|
||||||
|
return t->nsyms[pos];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool tape_grow(struct tape *t, int pos)
|
||||||
|
{
|
||||||
|
int **side;
|
||||||
|
int *capacity;
|
||||||
|
int newcapacity;
|
||||||
|
int *newside;
|
||||||
|
|
||||||
|
if (pos >= 0) {
|
||||||
|
side = &t->psyms;
|
||||||
|
capacity = &t->pcapacity;
|
||||||
|
} else {
|
||||||
|
pos = -1 - pos;
|
||||||
|
side = &t->nsyms;
|
||||||
|
capacity = &t->ncapacity;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pos + 1 < *capacity)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
newcapacity = pos + TAPE_CHUNK_SIZE;
|
||||||
|
printf("Grow tape to %d\n", newcapacity);
|
||||||
|
newside = (int *)realloc(*side, newcapacity*sizeof(int));
|
||||||
|
|
||||||
|
if (newside == NULL)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
*side = newside;
|
||||||
|
while (*capacity < newcapacity)
|
||||||
|
(*side)[(*capacity)++] = t->blank;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void tape_write(struct tape *t, int pos, int sym)
|
||||||
|
{
|
||||||
|
if (pos >= 0) {
|
||||||
|
if (pos >= t->pcapacity) {
|
||||||
|
if (sym == t->blank)
|
||||||
|
return;
|
||||||
|
if (!tape_grow(t, pos)) // TODO: error out
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
t->psyms[pos] = sym;
|
||||||
|
} else {
|
||||||
|
pos = -1 - pos;
|
||||||
|
if (pos >= t->ncapacity) {
|
||||||
|
if (sym == t->blank)
|
||||||
|
return;
|
||||||
|
if (!tape_grow(t, -1 - pos)) // TODO: error out
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
t->nsyms[pos] = sym;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int tape_load(struct tape *t, FILE *f, int offset, struct table *symbols)
|
||||||
|
{
|
||||||
|
char line[1000];
|
||||||
|
char *l;
|
||||||
|
int ll;
|
||||||
|
char *tok;
|
||||||
|
char *toksave;
|
||||||
|
static char *delim = " \t\f\n\r";
|
||||||
|
int counter = 0;
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
l = fgets(line, sizeof(line)-1, f);
|
||||||
|
if (l == NULL)
|
||||||
|
break;
|
||||||
|
ll = strlen(l);
|
||||||
|
if (ll > 0) {
|
||||||
|
tok = strtok_r(line, delim, &toksave);
|
||||||
|
while (tok != NULL) {
|
||||||
|
tape_write(t, offset+counter, table_insert(symbols, tok));
|
||||||
|
counter++;
|
||||||
|
tok = strtok_r(NULL, delim, &toksave);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return counter;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define HL_ON "\x01b[7m"
|
||||||
|
#define HL_OFF "\x01b[0m"
|
||||||
|
|
||||||
|
void tape_print(struct tape *t, struct table *sym)
|
||||||
|
{
|
||||||
|
int si;
|
||||||
|
int first, last;
|
||||||
|
|
||||||
|
printf("TAPE: ");
|
||||||
|
|
||||||
|
if ((t->ncapacity == 0) && (t->pcapacity == 0)) {
|
||||||
|
printf("(empty)\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
first = t->pcapacity;
|
||||||
|
last = -1-t->ncapacity;
|
||||||
|
for (int i=-1-t->ncapacity; i<t->pcapacity; i++) {
|
||||||
|
si = tape_read(t, i);
|
||||||
|
if ((si != t->blank) || (i == t->head)) {
|
||||||
|
if (i < first)
|
||||||
|
first = i;
|
||||||
|
if (i > last)
|
||||||
|
last = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((first == last) && (tape_read(t, first) == t->blank)) {
|
||||||
|
printf("(empty)\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i=first; i <= last; i++) {
|
||||||
|
if (i == t->head)
|
||||||
|
printf(HL_ON);
|
||||||
|
si = tape_read(t, i);
|
||||||
|
if (sym == NULL)
|
||||||
|
printf("%d", si);
|
||||||
|
else
|
||||||
|
printf("%s", (char *)table_lookup(sym, si));
|
||||||
|
if (i == t->head)
|
||||||
|
printf(HL_OFF);
|
||||||
|
printf(" ");
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
#ifndef _TAPE_H
|
||||||
|
#define _TAPE_H
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include "table.h"
|
||||||
|
|
||||||
|
#define TAPE_CHUNK_SIZE 100
|
||||||
|
|
||||||
|
struct tape
|
||||||
|
{
|
||||||
|
int head; // Head position
|
||||||
|
int blank; // Blank symbol
|
||||||
|
int *nsyms, *psyms; // Halves of the infinite tape for negative and positive indices
|
||||||
|
int ncapacity, pcapacity; // Capacities of the two tape halves
|
||||||
|
};
|
||||||
|
|
||||||
|
struct tape *tape_new(int blank);
|
||||||
|
int tape_read(struct tape *t, int pos);
|
||||||
|
void tape_write(struct tape *t, int pos, int sym);
|
||||||
|
int tape_load(struct tape *t, FILE *f, int offset, struct table *symbols);
|
||||||
|
void tape_print(struct tape *t, struct table *sym);
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,164 @@
|
||||||
|
#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;
|
||||||
|
}
|
Loading…
Reference in New Issue