/* * Turingol parser * references: * Donald E. Knuth "Semantics of Context-Free Languages" * Mathematical Systems Theory, Vol. 2, No. 2, 1968 */ %{ #include #include #include #include "lexer.h" #include "symtabs.h" #include "output.h" /* Get bison to dump it's behaviour to stderr */ #define YYDEBUG 1 extern int yydebug; /* The cheap and easy alternative... */ #define YYERROR_VERBOSE 1 #define YYPRINT(file, type, value) yyprint(file, type, value) /*void yyprint(FILE *file, int type, YYSTYPE value);*/ int yyerror(char *s); SymNode *alphabet_lookup(char *symbol); STNode *goto_lookup(char *label); %} /* Semantic datatypes */ %union { STNode *st; SymNode *sym; char *id; int dir; } /* Tokens */ %token TAI /* tape alphabet is */ %token IF /* if the tape symbol is */ %token THEN /* then */ %token GOTO /* to to */ %token MOVE /* move */ %token PRINT /* print */ %token DIR /* left | right*/ %token ONESQUARE /* one square */ %token IDENT %token COLON /* : */ %token COMMA /* , */ %token DQUOTE /* " */ %token LBRACE /* { */ %token PERIOD /* . */ %token RBRACE /* } */ %token SEMICOLON /* ; */ /* Semantic value: points to the state immediately following this statement */ %type statement statements %{ /* The parser functions */ int yyparse(); int yyprint(FILE *file, int type, YYSTYPE value); %} %% program: declarations SEMICOLON statements PERIOD ; declarations: TAI IDENT { sym_insert(&alphabet, strdup($2), NULL); } | declarations COMMA IDENT { sym_insert(&alphabet, strdup($3), NULL); } ; statements: statement { $$ = $1; } | statements SEMICOLON statement { $$ = $3; } | error SEMICOLON {} ; statement: /* empty */ { $$ = st_last(); } | IF DQUOTE IDENT { $$ = st_StartIF(alphabet_lookup($3)); } DQUOTE THEN statement { $$ = st_EndIF($4); } | IDENT { st_labelled($1); } COLON statement { $$ = $4; } | LBRACE statements RBRACE { $$ = $2; } | GOTO IDENT { $$ = goto_lookup($2); } | MOVE DIR ONESQUARE { $$ = st_MOVE($2); } | PRINT DQUOTE IDENT { $$ = alphabet_lookup($3); } DQUOTE { $$ = st_PRINT($4); } ; %% /* Lookup the alphabet and abort if symbol not found */ SymNode *alphabet_lookup(char *symbol) { SymNode *sym = sym_lookup(&alphabet, symbol); if(sym == NULL) { /* error */ yyerror(strcat("symbol \"", strcat(symbol, "\" not found.\n"))); /* YYABORT;*/ } return(sym); } STNode *goto_lookup(char *label) { SymNode *sym = sym_lookup(&labels, label); /*printf("GOTO(%s)\n", (sym == NULL) ? NULL : sym->name);*/ if(sym == NULL) { sym_insert(&forwardrefs, strdup(label), st_last()); return(st_GOTO(NULL)); } else return(st_GOTO(sym->state)); } /* Print out semantic values */ int yyprint(FILE *file, int type, YYSTYPE value) { switch(type) { case DIR: fprintf(file, " %d", value.dir); break; case IDENT: fprintf(file, " %s", value.id); break; } return(0); } /* Trivial error handler */ int yyerror(char *s) { printf("line %d: %s\n", line_num, s); return(0); } /* Fix forward-referencing GOTOs */ void postprocess() { SymNode *node, *cur; for(node = forwardrefs; node != NULL; ) { if((cur = sym_lookup(&labels, node->name)) == NULL) { /* Label not defined */ printf("turingol: label \"%s\" not defined.\n", node->name); exit(1); } node->state->data.dest = cur->state; cur = node; node = sym_traverse(&node); free(cur->name); free(cur); } forwardrefs = NULL; } void usage(char *name, char *err1, char *err2) { printf("%s%s\nUsage: %s [-o outfile] [-r runfile] [-d] [sourcefile]\n", err1, err2, name); exit(1); } /* handle command line parms: "filename" == input filename (default: stdin) "-d" == debug "-o filename" == output filename for tuples (default: stdout) "-r filename" == output filename for execution (default: don't run) */ int main(int argc, char *argv[]) { int i; FILE *outfile = NULL, *runfile = stdout; yyin = stdin; if(argc > 1) for(i = 1; i < argc; i++) { if(argv[i][0] == '-') { if(!strcmp(argv[i], "-d")) yydebug = 1; else if(!strcmp(argv[i], "-o")) { if(++i < argc && outfile == stdout) { if((outfile = fopen(argv[i], "w")) == NULL) { /* file open error */ fprintf(stderr, "%s: cannot open file: %s, ", argv[0], argv[i]); exit(1); } } else usage(argv[0], "Bad option: ", argv[i - 1]); } else if(!strcmp(argv[i], "-r")) { if(++i < argc && runfile == NULL) { if((runfile = fopen(argv[i], "w")) == NULL) { /* file open error */ fprintf(stderr, "%s: cannot open file: %s, ", argv[0], argv[i]); exit(1); } } else usage(argv[0], "Bad option: ", argv[i - 1]); } else usage(argv[0], "Unknown option: ", argv[i]); } else { if((yyin = fopen(argv[i], "r")) == NULL) { /* file open error */ fprintf(stderr, "%s: cannot open file: %s, ", argv[0], argv[i]); exit(1); } } } st_init(); i = yyparse(); fclose(yyin); if(!i) { postprocess(); if (outfile != NULL) { tuple_header(outfile); traverse_graph(outfile, tuple_out); fclose(outfile); } if(runfile != NULL) { st_run(runfile); fclose(runfile); } return(0); } else return(1); }