%{ #include #include #include #include typedef struct _term term_t; struct _term { int kind; union { char c; char* s; term_t* t; } u; term_t* next; }; static FILE* outf; static int yylex (); static void yyerror (char*); static void xlate (term_t* ts); static void nonTerm (char* s) { fprintf (outf, "%s", s); } static void gen (char* name, term_t* ts) { fprintf (outf, "\n "); nonTerm (name); fprintf (outf, "\n :\n "); xlate (ts); fprintf (outf, "\n\n"); for (ts = ts->next; ts; ts = ts->next) { fprintf (outf, "\n \n |\n "); xlate (ts); fprintf (outf, "\n\n"); } } static term_t* mkLiteral (char c, int kind) { term_t* nt = malloc(sizeof(term_t)); nt->kind = kind; nt->u.c = c; nt->next = 0; return nt; } static term_t* mkID (char* s, int kind) { term_t* nt = malloc(sizeof(term_t)); nt->kind = kind; nt->u.s = s; nt->next = 0; return nt; } static term_t* mkSeq (term_t* t1, term_t* t2, int kind) { term_t* nt = malloc(sizeof(term_t)); nt->kind = kind; nt->u.t = t1; t1->next = t2; nt->next = 0; return nt; } static term_t* mkTerm (term_t* t, int kind) { term_t* nt = malloc(sizeof(term_t)); nt->kind = kind; nt->u.t = t; nt->next = 0; return nt; } %} %union { char c; char* str; term_t* term; } %token T_literal %token T_name T_token T_opt T_seq T_choice %type atomterm term rule rulelist %start prods %% prods : prods prod | prod ; prod : T_name '=' rulelist '\n' { gen ($1, $3); } rulelist : rule '|' rulelist { $1->next = $3; $$ = $1; } | rule { $$ = $1; } ; rule : term rule { if ($2->kind == T_seq) { $1->next = $2->u.t; $2->u.t = $1; $$ = $2;} else $$ = mkSeq ($1, $2, T_seq); } | term { $$ = $1; } ; term : '[' rule ']' { $$ = mkTerm ($2, T_opt); } | '(' rulelist ')' { $$ = mkTerm ($2, T_choice); } | atomterm { $$ = $1; } ; atomterm : T_literal { $$ = mkLiteral($1, T_literal); } | T_token { $$ = mkID($1, T_token); } | T_name { $$ = mkID($1, T_name); } ; %% static void xlate (term_t* ts) { term_t* t; switch (ts->kind) { case T_name : nonTerm (ts->u.s); break; case T_literal : fprintf (outf, "'%c'", ts->u.c); break; case T_token : fprintf (outf, "%s", ts->u.s); break; case T_opt : fprintf (outf, "[ "); xlate (ts->u.t); fprintf (outf, " ]"); break; case T_seq : t = ts->u.t; xlate (t); for (t = t->next; t; t = t->next) { fprintf (outf, " "); xlate (t); } break; case T_choice : fprintf (outf, "("); t = ts->u.t; xlate (t); for (t = t->next; t; t = t->next) { fprintf (outf, " | "); xlate (t); } fprintf (outf, ")"); break; } } #define BSIZE 2048 static FILE* inf; static char buf[BSIZE]; static char* lexptr; static int lineno; static char* skipSpace (char* p) { int c; while (isspace ((c = *p)) && (c != '\n')) p++; return p; } static char* mystrndup (char* p, int sz) { char* s = malloc (sz+1); memcpy (s, p, sz); s[sz] = '\0'; return s; } static char* readLiteral (char* p) { int c; char* s = p; while (((c = *p) != '\'') && (c != '\0')) p++; if (c == '\0') { fprintf (stderr, "Unclosed literal '%s, line %d\n", s, lineno); exit (1); } yylval.c = *s; return (p+1); } static char* readName (char* p) { int c; char* s = p; while (!isspace ((c = *p)) && (c != '\0')) p++; yylval.str = mystrndup (s, p-s); return p; } static void yyerror (char* msg) { fprintf (stderr, "%s, line %d\n", msg, lineno); } static void lexinit () { lexptr = buf; } #ifdef DEBUG static int _yylex (); int yylex() { /* for debugging */ int rv = _yylex(); fprintf(stderr, "returning %d\n", rv); switch (rv) { case T_name : case T_token : fprintf(stderr, "string val is '%s'\n", yylval.str); break; case T_literal : fprintf(stderr, "string val is '%c'\n", yylval.c); break; } return rv; } #define yylex _yylex #endif static int yylex () { int c; do { if (*lexptr == '\0') { if (!fgets (buf, BSIZE, inf)) return EOF; lineno++; lexptr = buf; } lexptr = skipSpace (lexptr); } while (*lexptr == '\0'); switch (c = *lexptr++) { case '\n' : case '|' : case '=' : case '(' : case ')' : case '[' : case ']' : return c; break; case '\'' : lexptr = readLiteral (lexptr); return T_literal; break; case 'T' : if (*lexptr == '_') { lexptr = readName (lexptr+1); return T_token; } else { lexptr = readName (lexptr-1); return T_name; } break; default : lexptr = readName (lexptr-1); return T_name; break; } } #ifdef DEBUG #undef yylex #endif static FILE* openF (char* fname, char* mode) { FILE* f = fopen (fname, mode); if (!f) { fprintf (stderr, "Could not open %s for %s\n", fname, mode); exit(1); } return f; } int main (int argc, char* argv[]) { if (argc != 3) { fprintf (stderr, "mklang: 2 arguments required\n"); exit(1); } inf = openF (argv[1], "r"); outf = openF (argv[2], "w"); lexinit(); yyparse (); return (0); }