summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDimitri Sokolyuk <demon@dim13.org>2008-04-11 15:29:37 +0000
committerDimitri Sokolyuk <demon@dim13.org>2008-04-11 15:29:37 +0000
commit379fc3ff97b8baed0328e76e27d8f3eed5f6bd13 (patch)
tree744d00ddfa21e3acbc8031971641e9fe511a7085
parent875ff024fdfeca973bbccb9dd5e4fab7ee333f0e (diff)
mayor improvement of the tape output routine,
replace fgetln with fgets for compatibility sake get ride of some global variables, refill stuctures
-rw-r--r--tm.c260
1 files changed, 157 insertions, 103 deletions
diff --git a/tm.c b/tm.c
index 1e2761c..145ab7b 100644
--- a/tm.c
+++ b/tm.c
@@ -24,11 +24,11 @@
#include <string.h>
#include <unistd.h>
-
/* tape, head, table, state register */
struct table {
struct tulpe *tulpe;
+ char *initstring;
};
struct tulpe {
@@ -41,7 +41,10 @@ struct tulpe {
};
struct tape {
- struct cell *head;
+ struct cell *lvis; /* fist visible cell (lhs) */
+ struct cell *head; /* head position */
+ struct cell *rvis; /* last visible cell (rhs) */
+ int width; /* width of the visible part of tape */
};
struct cell {
@@ -58,15 +61,26 @@ typedef struct tape Tape;
typedef struct cell Cell;
typedef struct table Table;
typedef struct tulpe Tulpe;
+
char blank = ' ';
char init = 'A';
-char stop = 'H';
-int width = 15;
-int counter = 0;
+char halt = 'H';
+int width = 21;
+
+long counter = 0;
int cells = 0;
int state = 0;
-int die = 0;
-char *initstring;
+int dflag = 0;
+int sflag = 0;
+int nflag = 0;
+
+enum {NOMOVE, TOLEFT, TORIGHT};
+char *move[] = {
+ [NOMOVE] = " ",
+ [TOLEFT] = "<<<",
+ [TORIGHT] = ">>>"
+};
+int movetape = NOMOVE;
Tape *alloctape(char *);
Cell *alloccell(void);
@@ -74,10 +88,10 @@ Table *alloctable(char *);
Tulpe *findtulpe(Table *, Cell *);
int movehead(Tape *, char);
int execute(Tape *, Table *, int);
-void printtape(Tape *, Tulpe *, int, char);
-void printtable(Table *);
-void printtulpe(Tulpe *, char);
-void halt(int);
+void printtape(Tape *, Tulpe *, int);
+void die(int);
+void usage(void);
+int nonblank(Tape *);
Tape *
alloctape(char *init)
@@ -90,9 +104,10 @@ alloctape(char *init)
assert(t);
c = alloccell();
- t->head = c;
+ t->lvis = t->head = t->rvis = c;
+ t->width = 1;
- if (init != NULL) {
+ if (init) {
s = init;
while (*s != '\0' && *s != '\n') {
t->head->symb = *(s++);
@@ -127,7 +142,7 @@ alloctable(char *fname)
Table *tab;
Tulpe *t, **pt;
FILE *fd;
- char *buf;
+ char buf[256];
size_t len;
t = NULL;
@@ -136,29 +151,30 @@ alloctable(char *fname)
tab = malloc(sizeof(Table));
assert(tab);
- initstring = NULL;
+ tab->initstring = NULL;
fd = fopen(fname, "r");
- assert(fd);
- while ((buf = fgetln(fd, &len)) != NULL) {
- switch (*buf) {
+ if (!fd)
+ err(1, fname);
+ while (fgets(buf, sizeof(buf), fd)) {
+ len = strlen(buf);
+ switch (buf[0]) {
case '#': /* commentar */
case '\n': /* empty line */
- continue;
+ break;
case '!': /* initial string */
- initstring = calloc(len, sizeof(char));
- assert(initstring);
- memcpy(initstring, ++buf, len);
- continue;
+ tab->initstring = calloc(len + 1, sizeof(char));
+ assert(tab->initstring);
+ memcpy(tab->initstring, &buf[1], len);
+ break;
case '%':
- ++buf;
- init = buf[0];
- blank = buf[1];
- stop = buf[2];
- continue;
+ init = buf[1];
+ blank = buf[2];
+ halt = buf[3];
+ break;
default:
if (len < 5)
- continue;
+ break;
*pt = malloc(sizeof(Tulpe));
assert(*pt);
@@ -170,6 +186,7 @@ alloctable(char *fname)
(*pt)->newst = buf[4];
pt = &(*pt)->next;
+ break;
}
}
fclose(fd);
@@ -185,7 +202,7 @@ findtulpe(Table *tab, Cell *cell)
{
Tulpe *t;
- for (t = tab->tulpe; t != NULL; t = t->next) {
+ for (t = tab->tulpe; t; t = t->next) {
if (state != t->curst)
continue;
if (cell->symb != t->ssymb)
@@ -205,21 +222,44 @@ movehead(Tape *tape, char move)
case 'L':
case 'l':
case '<':
- if (tape->head->left == NULL) {
+ /* add a new cell on the lhs */
+ if (!tape->head->left) {
c = alloccell();
tape->head->left = c;
c->right = tape->head;
}
+ /* shift tape to the right */
+ if (!nflag && tape->head == tape->lvis) {
+ tape->lvis = tape->lvis->left;
+ if (tape->width < width)
+ ++tape->width;
+ else
+ tape->rvis = tape->rvis->left;
+ movetape = TORIGHT;
+ }
+ /* move the head */
tape->head = tape->head->left;
break;
case 'R':
case 'r':
case '>':
- if (tape->head->right == NULL) {
+ /* add a new cell on the rhs */
+ if (!tape->head->right) {
c = alloccell();
tape->head->right = c;
c->left = tape->head;
}
+ /* shift tape to the left */
+ if (!nflag && tape->head == tape->rvis) {
+ tape->rvis = tape->rvis->right;
+ if (tape->width < width)
+ ++tape->width;
+ else {
+ tape->lvis = tape->lvis->right;
+ movetape = TOLEFT;
+ }
+ }
+ /* move the head */
tape->head = tape->head->right;
break;
case 'N':
@@ -229,6 +269,7 @@ movehead(Tape *tape, char move)
break;
}
+
return 0;
}
@@ -237,64 +278,62 @@ execute(Tape *tape, Table *tab, int u)
{
Tulpe *t;
- if (initstring != NULL)
- printtape(tape, NULL, width, '\r');
+ if (!nflag && tab->initstring)
+ printtape(tape, NULL, 0);
+
+ while (state != halt && !dflag) {
+ t = findtulpe(tab, tape->head); /* read & find */
+ if (!t) {
+ putchar('\n');
+ errx(1, "cannot find proper tulpe");
+ }
- while (state != stop && die == 0) {
- t = findtulpe(tab, tape->head); /* read, find */
- if (t == NULL) {
- fprintf(stderr, "\ncannot find proper tulpe");
- exit(1);
+ if (!nflag) {
+ printtape(tape, t, sflag);
+ usleep(u);
}
tape->head->symb = t->psymb; /* write */
- printtape(tape, t, width, '\r');
- usleep(u);
+ if (!nflag) {
+ printtape(tape, t, 0);
+ usleep(u);
+ }
movehead(tape, t->move); /* move head */
state = t->newst; /* save new state */
++counter;
}
- printtape(tape, NULL, width, '\n');
+
+ if (!nflag)
+ printtape(tape, NULL, 1);
return 0;
}
void
-printtape(Tape *t, Tulpe *tulpe, int n, char fin)
+printtape(Tape *t, Tulpe *tulpe, int nl)
{
- int i;
Cell *c;
- char *s;
- char *ps;
-
- s = calloc(n + 1 + n, sizeof(char));
-
- for (i = 0; i < n + 1 + n; i++)
- s[i] = blank;
-
- for (i = 0, c = t->head; i < n && c != NULL; i++, c = c->left)
- s[n - i] = c->symb;
- for (i = 0, c = t->head; i < n && c != NULL; i++, c = c->right)
- s[n + i] = c->symb;
- s[n] = t->head->symb;
-
- printtulpe(tulpe, '\t');
-
- ps = s;
- for (i = 0; i < n; i++)
- printf("%c ", *(ps++));
- printf("(%c)", *(ps++));
- for (i = 0; i < n; i++)
- printf(" %c", *(ps++));
-
- printf("%c", fin);
+ printf("%c %c %c %c %c %s",
+ tulpe ? tulpe->curst : ' ',
+ tulpe ? tulpe->ssymb : ' ',
+ tulpe ? tulpe->psymb : ' ',
+ tulpe ? tulpe->move : ' ',
+ tulpe ? tulpe->newst : ' ',
+ move[movetape]);
+ movetape = NOMOVE;
+ putchar('\t');
+
+ for (c = t->lvis; c != t->rvis->right; c = c->right) {
+ putchar(c == t->head ? '(' : ' ');
+ putchar(c->symb);
+ putchar(c == t->head ? ')' : ' ');
+ }
+ putchar(nl ? '\n' : '\r');
fflush(stdout);
-
- free(s);
}
int
@@ -302,71 +341,86 @@ main(int argc, char **argv)
{
Tape *tape;
Table *table;
- int delay = 250; /* miliseconds */
+ int delay = 100; /* miliseconds */
int c;
+ char *columns;
- /* TODO: add scroll flag & execution velocity parameter */
- while ((c = getopt(argc, argv, "d:")) != -1)
+ while ((c = getopt(argc, argv, "d:ns")) != -1)
switch (c) {
- case 'd':
+ case 'd': /* execution velocity */
delay = atoi(optarg);
if (delay < 0)
- exit(1);
+ usage();
+ break;
+ case 's': /* scroll */
+ sflag = 1;
+ break;
+ case 'n': /* be quite */
+ nflag = 1;
break;
default:
- exit(1);
+ usage();
+ /* NOTREACHED */
}
delay *= 1000; /* ms -> us */
+ columns = getenv("COLUMNS");
+ if (columns)
+ width = (atoi(columns) - 16) / 3;
+
argc -= optind;
argv += optind;
if (argc != 1)
- exit(1);
+ usage();
- signal(SIGHUP, halt);
- signal(SIGINT, halt);
+ signal(SIGHUP, die);
+ signal(SIGINT, die);
table = alloctable(*argv);
- tape = alloctape(initstring);
+ tape = alloctape(table->initstring);
execute(tape, table, delay);
- printf("halted after %d steps\n", counter);
- printf("wasted %d cells\n", cells);
+
+ warnx("halted after %ld moves leaving %d non-empty cells of %d used",
+ counter, nonblank(tape), cells);
return 0;
}
void
-printtable(Table *tab)
+die(int sig)
{
- Tulpe *t;
-
- for (t = tab->tulpe; t != NULL; t = t->next) {
- printtulpe(t, '\n');
- printf("\n");
- }
+ dflag = 1;
}
void
-printtulpe(Tulpe *t, char fin)
+usage(void)
{
- if (t == NULL)
- printf("\t");
- else
- printf("%c %c %c %c %c",
- t->curst,
- t->ssymb,
- t->psymb,
- t->move,
- t->newst);
- printf("%c", fin);
+ extern char *__progname;
+
+ (void) fprintf(stderr, "usage: %s [-d ms] [-ns] <prog>\n", __progname);
+
+ exit(1);
}
-void
-halt(int sig)
+int
+nonblank(Tape *t)
{
- die = 1;
+ int n = 0;
+ Cell *c;
+
+ /* rewind to the left */
+ for (c = t->head; c; c = c->left)
+ if (c->symb != blank)
+ ++n;
+
+ /* rewind to the right */
+ for (c = t->head->right; c; c = c->right)
+ if (c->symb != blank)
+ ++n;
+
+ return n;
}