%{
#include "defs.h"
%}
%union
{
List *lst;
Node *node;
Cons *cons;
Stmt *stmt;
Expr *expr;
}
%token <node> tSYMBOL tREGEXP tSTRING tINTEGER tREAL
%token tSUB tSTATE tSTART tSTARTRULES tNAMERULES tBEGIN tEND tRETURN tIF tELSE
%token tLOCAL tWHILE tFOR tEXTENDS
%right '=' tADDASSIGN tSUBASSIGN tMULASSIGN tDIVASSIGN
%right '?' ':'
%left tOR
%left tAND
%left tEQ tNE
%left '<' '>' tGE tLE
%left '+' '-'
%left '*' tDIV
%right '!' tPLUSPLUS tMINUSMINUS
%left '[' ']'
%type <lst> regexp_sym_list symbol_list rest_symbol_list staterules
%type <lst> stmt_list expr_list rest_expr_list locals locals_rest
%type <stmt> stmt
%type <expr> expr cond_expr
%type <cons> staterule local_def
%%
file :
| file toplevel
;
toplevel : tSTART '{' stmt_list '}' { start_stmts = $3; }
| tSTARTRULES '{' regexp_sym_list '}'
{ startrules = $3; }
| tNAMERULES '{' regexp_sym_list '}'
{ namerules = $3; }
| tSTATE tSYMBOL '{' staterules '}'
{ define_state ($2, NULL, $4); }
| tSTATE tSYMBOL tEXTENDS tSYMBOL '{' staterules '}'
{ define_state ($2, $4, $6); }
| stmt { list_append (global_stmts, $1); }
;
regexp_sym_list : { $$ = list (); }
| regexp_sym_list tREGEXP tSYMBOL ';'
{ list_append ($1, cons ($2, $3)); }
;
staterules : { $$ = list (); }
| staterules staterule { list_append ($1, $2); }
staterule : tBEGIN '{' stmt_list '}' { $$ = cons (RULE_BEGIN, $3); }
| tEND '{' stmt_list '}' { $$ = cons (RULE_END, $3); }
| tREGEXP '{' stmt_list '}' { $$ = cons ($1, $3); }
| tSYMBOL '{' stmt_list '}' { $$ = cons ($1, $3); }
;
symbol_list : { $$ = list (); }
| rest_symbol_list { $$ = $1; }
;
rest_symbol_list : tSYMBOL { $$ = list (); list_append ($$, $1); }
| rest_symbol_list ',' tSYMBOL { list_append ($1, $3); }
;
locals : { $$ = list (); }
| tLOCAL locals_rest ';' { $$ = $2; }
;
locals_rest : local_def { $$ = list (); list_append ($$, $1); }
| locals_rest ',' local_def { list_append ($1, $3); }
;
local_def : tSYMBOL { $$ = cons ($1, NULL); }
| tSYMBOL '=' expr { $$ = cons ($1, $3); }
;
stmt_list : { $$ = list (); }
| stmt_list stmt { list_append ($1, $2); }
;
stmt : tRETURN ';' { $$ = mk_stmt (sRETURN, NULL, NULL,
NULL, NULL); }
| tRETURN expr ';' { $$ = mk_stmt (sRETURN, $2, NULL,
NULL, NULL); }
| tSUB tSYMBOL '(' symbol_list ')' '{' locals stmt_list '}'
{ $$ = mk_stmt (sDEFSUB, $2,
cons (cons ($4, $7),
$8),
NULL, NULL); }
| '{' stmt_list '}' { $$ = mk_stmt (sBLOCK, $2, NULL,
NULL, NULL); }
| tIF '(' expr ')' stmt { $$ = mk_stmt (sIF, $3, $5, NULL,
NULL); }
| tIF '(' expr ')' stmt tELSE stmt
{ $$ = mk_stmt (sIF, $3, $5, $7,
NULL); }
| tWHILE '(' expr ')' stmt { $$ = mk_stmt (sWHILE, $3, $5,
NULL, NULL); }
| tFOR '(' cond_expr ';' expr ';' cond_expr ')' stmt
{ $$ = mk_stmt (sFOR, $3, $5, $7,
$9); }
| expr ';' { $$ = mk_stmt (sEXPR, $1, NULL,
NULL, NULL); }
;
expr : tSTRING { $$ = mk_expr (eSTRING, $1, NULL,
NULL); }
| tREGEXP { $$ = mk_expr (eREGEXP, $1, NULL,
NULL); }
| tINTEGER { $$ = mk_expr (eINTEGER, $1, NULL,
NULL); }
| tREAL { $$ = mk_expr (eREAL, $1, NULL,
NULL); }
| tSYMBOL { $$ = mk_expr (eSYMBOL, $1, NULL,
NULL); }
| '!' expr { $$ = mk_expr (eNOT, $2, NULL,
NULL); }
| expr tAND expr { $$ = mk_expr (eAND, $1, $3, NULL); }
| expr tOR expr { $$ = mk_expr (eOR, $1, $3, NULL); }
| tSYMBOL '(' expr_list ')' { $$ = mk_expr (eFCALL, $1, $3,
NULL); }
| tSYMBOL '=' expr { $$ = mk_expr (eASSIGN, $1, $3,
NULL); }
| tSYMBOL tADDASSIGN expr { $$ = mk_expr (eADDASSIGN, $1, $3,
NULL); }
| tSYMBOL tSUBASSIGN expr { $$ = mk_expr (eSUBASSIGN, $1, $3,
NULL); }
| tSYMBOL tMULASSIGN expr { $$ = mk_expr (eMULASSIGN, $1, $3,
NULL); }
| tSYMBOL tDIVASSIGN expr { $$ = mk_expr (eDIVASSIGN, $1, $3,
NULL); }
| tSYMBOL tPLUSPLUS { $$ = mk_expr (ePOSTFIXADD, $1, NULL,
NULL); }
| tSYMBOL tMINUSMINUS { $$ = mk_expr (ePOSTFIXSUB, $1, NULL,
NULL); }
| tPLUSPLUS tSYMBOL { $$ = mk_expr (ePREFIXADD, $2, NULL,
NULL); }
| tMINUSMINUS tSYMBOL { $$ = mk_expr (ePREFIXSUB, $2, NULL,
NULL); }
| expr '[' expr ']' '=' expr { $$ = mk_expr (eARRAYASSIGN, $1, $3,
$6); }
| '(' expr ')' { $$ = $2; }
| expr '[' expr ']' { $$ = mk_expr (eARRAYREF, $1, $3,
NULL); }
| expr '?' expr ':' expr { $$ = mk_expr (eQUESTCOLON, $1, $3,
$5); }
| expr '*' expr { $$ = mk_expr (eMULT, $1, $3, NULL); }
| expr tDIV expr { $$ = mk_expr (eDIV, $1, $3, NULL); }
| expr '+' expr { $$ = mk_expr (ePLUS, $1, $3, NULL); }
| expr '-' expr { $$ = mk_expr (eMINUS, $1, $3,
NULL); }
| expr '<' expr { $$ = mk_expr (eLT, $1, $3, NULL); }
| expr '>' expr { $$ = mk_expr (eGT, $1, $3, NULL); }
| expr tEQ expr { $$ = mk_expr (eEQ, $1, $3, NULL); }
| expr tNE expr { $$ = mk_expr (eNE, $1, $3, NULL); }
| expr tGE expr { $$ = mk_expr (eGE, $1, $3, NULL); }
| expr tLE expr { $$ = mk_expr (eLE, $1, $3, NULL); }
;
cond_expr : { $$ = NULL; }
| expr { $$ = $1; }
;
expr_list : { $$ = list (); }
| rest_expr_list { $$ = $1; }
;
rest_expr_list: expr { $$ = list (); list_append ($$, $1); }
| rest_expr_list ',' expr { list_append ($1, $3); }
;
%%
void
yyerror (msg)
char *msg;
{
fprintf (stderr, "%s:%d: %s\n", yyin_name, linenum, msg);
}