%{ #include #include #include #include #include #include #include "iburg.h" #define YYDEBUG 1 extern int yylex(void); static int nextern = 1; %} %union { int n; char* string; Nonterm nonterm; Tree tree; Rule rule; struct reg* reg; struct stringlist* stringlist; struct terminfo terminfo; struct expr* expr; } %term ALLOCATES %term COST %term DECLARATIONS %term EMIT %term FRAGMENT %term PATTERNS %term REGISTERS %term PREFERS %term REQUIRES %token INT %token ID %token QFRAGMENT %type allocates %type declaration %type register %type emit %type pattern %type cfragments %type qfragments %type terminfo %type rhs %type predicate %type predicate_args %% spec : REGISTERS registers DECLARATIONS declarations PATTERNS patterns ; registers : /* nothing */ | registers register ';' | register ';' ; register : ID { $$ = makereg($1); } | register ID { $$ = $1; addregclass($1, $2); } ; declarations : /* nothing */ | declarations declaration ';' | declaration ';' ; declaration : ID { $$ = nonterm($1, true); } | declaration FRAGMENT { $$ = $1; $$->is_fragment = true; } | allocates { $$ = $1; } ; allocates : declaration ALLOCATES '(' ID ')' { $$ = $1; if ($$->allocate) yyerror("pattern type is defined to already allocate a register"); $$->allocate = getregclass($4); } ; patterns : /* nothing */ | patterns pattern ';' | patterns ';' ; pattern : ID '=' rhs { nonterm($1, false); $$ = rule($1, $3, nextern++); } | rhs { $$ = rule("stmt", $1, nextern++); } | pattern PREFERS predicate { $$ = $1; array_append(&$$->prefers, $3); } | pattern REQUIRES predicate { $$ = $1; array_append(&$$->requires, $3); } | emit { $$ = $1; } | pattern COST INT { $$ = $1; $$->cost = $3; } ; rhs : terminfo { $$ = tree(&$1, NULL, NULL); } | terminfo '(' rhs ')' { $$ = tree(&$1, $3, NULL); } | terminfo '(' rhs ',' rhs ')' { $$ = tree(&$1, $3, $5); } ; terminfo : ID { $$.name = $1; } | ID '.' ID { $$.name = $1; $$.regattr = $3; } | ID ':' ID { $$.label = $1; $$.name = $3; } | ID ':' ID '.' ID { $$.label = $1; $$.name = $3; $$.regattr = $5; } ; emit : pattern EMIT qfragments { $$ = $1; if (!$$->lhs->is_fragment) stringlist_add($3, "\n"); stringlist_addall(&$$->code, $3); } ; qfragments : /* nothing */ { $$ = calloc(1, sizeof *$$); } | qfragments QFRAGMENT { $$ = $1; stringlist_add($$, $2); } ; predicate : ID '(' predicate_args ')' { $$ = calloc(1, sizeof *$$); $$->name = $1; $$->next = $3; } ; predicate_args : /* nothing */ | ID { $$ = calloc(1, sizeof *$$); $$->name = $1; } | ID ',' predicate_args { $$ = calloc(1, sizeof *$$); $$->name = $1; $$->next = $3; } ; %% #include #include int errcnt = 0; FILE *infp = NULL; FILE *outfp = NULL; static char buf[BUFSIZ], *bp = buf; static int ppercent = 0; void yyerror(char *fmt, ...) { va_list ap; va_start(ap, fmt); if (yylineno > 0) fprintf(stderr, "line %d: ", yylineno); vfprintf(stderr, fmt, ap); if (fmt[strlen(fmt)-1] != '\n') fprintf(stderr, "\n"); errcnt++; exit(1); } void yywarn(char *fmt, ...) { va_list ap; va_start(ap, fmt); if (yylineno > 0) fprintf(stderr, "line %d: ", yylineno); fprintf(stderr, "warning: "); vfprintf(stderr, fmt, ap); } /* vim: set sw=4 ts=4 expandtab : */