%{ #include #include #include #include "lex.h" #define OVECCOUNT 3 int yylex (void); void yyerror (char const *); int regex_cmp(char* s, char* r); struct tree* tree_malloc(int type); void print_tree(struct tree* t, int ind); struct tree { enum { ST_IF, ST_COND, ST_BLOCK, ST_ASS, ST_LEAF, ST_EMPTY, ST_ARROW, ST_OP } st; /* subtree type */ union { struct { struct tree* c; /* condition */ struct tree* i; /* if */ struct tree* e; /* else */ } tif; struct { int op; struct tree* left; struct tree* right; } cond; /* binary operator */ struct { struct tree* head; struct tree* tail; } block; struct { struct tree* left; struct tree* right; } ass; struct { enum { L_VAR, L_CONST, L_NUM } type; union { char* s; int n; } value; } leaf; struct { char* kw_left; char* kw_right; struct tree* s; } arrow; struct { int op; struct tree* left; struct tree* right; } op; } pt; }; struct tree* input_tree; %} %error-verbose %union { int n; char* str; struct tree* tr; } %token CONST %token NUM %token VAR %token KW_PIPE KW_MAIL KW_COPY %token '(' ')' '{' '}' ';' %nonassoc KW_IF %nonassoc KW_ELSE %left ARROW %left EQ NEQ GE LE '<' '>' RE NRE %left '=' %left '.' %left '+' '-' %left '*' '/' %left '|' %left '^' %left '&' %left '!' %type input %type command %type next %type ass %type ass_right %type cif %type arrow %type cond %type rop %type left %type right %type leaves %% input: /* empty */ { $$ = input_tree = NULL; } | command input { $$ = tree_malloc(ST_BLOCK); $$->pt.block.head = $1; $$->pt.block.tail = $2; input_tree = $$; } ; command: ';' { $$ = tree_malloc(ST_EMPTY); } | '{' command next '}' { $$ = tree_malloc(ST_BLOCK); $$->pt.block.head = $2; $$->pt.block.tail = $3; } | '{' '}' { $$ = tree_malloc(ST_EMPTY); } | cif | ass ';' { $$ = $1} | arrow ';' { $$ = $1} ; next: /* empty */ {$$ = NULL} | command ; cif: KW_IF cond command KW_ELSE command { $$ = tree_malloc(ST_IF); $$->pt.tif.c = $2; $$->pt.tif.i = $3; $$->pt.tif.e = $5; } | KW_IF cond command { $$ = tree_malloc(ST_IF); $$->pt.tif.c = $2; $$->pt.tif.i = $3; $$->pt.tif.e = NULL; } ; cond: '!' cond { $$ = tree_malloc(ST_COND); $$->pt.cond.left = $2; $$->pt.cond.right = NULL; $$->pt.cond.op = $1; } | cond '|' cond { $$ = tree_malloc(ST_COND); $$->pt.cond.left = $1; $$->pt.cond.right = $3; $$->pt.cond.op = $2; } | cond '&' cond { $$ = tree_malloc(ST_COND); $$->pt.cond.left = $1; $$->pt.cond.right = $3; $$->pt.cond.op = $2; } | cond '^' cond { $$ = tree_malloc(ST_COND); $$->pt.cond.left = $1; $$->pt.cond.right = $3; $$->pt.cond.op = $2; } | '(' cond ')' { $$ = $2; } | ass_right rop ass_right { $$ = tree_malloc(ST_COND); $$->pt.cond.left = $1; $$->pt.cond.right = $3; $$->pt.cond.op = $2; } ; rop: '>' | '<' | EQ | NEQ | LE | GE | RE | NRE ; ass: VAR '=' ass_right { $$ = tree_malloc(ST_ASS); $$->pt.ass.left = tree_malloc(ST_LEAF); $$->pt.ass.left->pt.leaf.type = L_VAR; $$->pt.ass.left->pt.leaf.value.s = $1; $$->pt.ass.right = $3; } ; leaves: NUM { $$ = tree_malloc(ST_LEAF); $$->pt.leaf.type = L_NUM; $$->pt.leaf.value.n = $1; } | VAR { $$ = tree_malloc(ST_LEAF); $$->pt.leaf.type = L_VAR; $$->pt.leaf.value.s = $1; } | CONST { $$ = tree_malloc(ST_LEAF); $$->pt.leaf.type = L_CONST; $$->pt.leaf.value.s = $1; } ; arrow: left ARROW right ass_right { $$ = tree_malloc(ST_ARROW); $$->pt.arrow.s = $4; $$->pt.arrow.kw_left = $1; $$->pt.arrow.kw_right = $3; } ; left: /* empty */ {$$=NULL} | KW_COPY { $$ = "copy" } ; right: /* empty */ {$$ = NULL} | KW_PIPE { $$ = "pipe" } | KW_MAIL { $$ = "mail" } ; ass_right: leaves | ass_right '.' ass_right { $$ = tree_malloc(ST_OP); $$->pt.op.op = '.'; $$->pt.op.left = $1; $$->pt.op.right = $3; } ; %% struct tree* tree_malloc(int type) { struct tree* temp; temp = xmalloc(sizeof (struct tree)); temp->st=type; return temp; } int regex_cmp(char* s, char* r) { pcre *brum; int erroroffset; const char* error; int ovector[OVECCOUNT]; brum = pcre_compile(r,0,&error,&erroroffset,NULL); if (!brum) return -1; int res = pcre_exec(brum,NULL,s,strlen(s),0,0,ovector,OVECCOUNT); pcre_free(brum); return res; } void yyerror (char const *s) { fprintf (stderr, "Line %d: %s\n", line, s); } void print_ind(int num, char c) { int i; for (i = 0; i < num; i++){ putchar(c); } } void print_tree(struct tree* t, int ind) { if (!t) return; switch (t->st){ case ST_IF: print_ind(ind,' '); puts("if"); print_tree(t->pt.tif.c,ind+1); print_ind(ind,' '); puts("then"); print_tree(t->pt.tif.i,ind+1); print_ind(ind,' '); puts("else"); print_tree(t->pt.tif.e,ind+1); break; case ST_COND: #define UPPER(a) ((a) >> 8) #define LOWER(a) ((a) & 0xFF) print_tree(t->pt.cond.left, ind+1); print_ind(ind,' '); if (UPPER(t->pt.cond.op) > 0) putchar(UPPER(t->pt.cond.op)); putchar(LOWER(t->pt.cond.op)); putchar('\n'); print_tree(t->pt.cond.right, ind+1); break; case ST_BLOCK: print_tree(t->pt.block.head,ind); print_tree(t->pt.block.tail,ind); break; case ST_ASS: print_tree(t->pt.ass.left, ind+1); print_ind(ind,' '); puts("="); print_tree(t->pt.ass.right, ind+1); break; case ST_LEAF: print_ind(ind, ' '); switch (t->pt.leaf.type){ case L_VAR: putchar('$'); case L_CONST: puts(t->pt.leaf.value.s); break; case L_NUM: printf("%d\n",t->pt.leaf.value.n); break; } break; case ST_ARROW: if (t->pt.arrow.kw_left){ print_ind(ind+1, ' '); puts(t->pt.arrow.kw_left); } print_ind(ind, ' '); printf("->\n"); if (t->pt.arrow.kw_right){ print_ind(ind+1, ' '); puts(t->pt.arrow.kw_right); } print_tree(t->pt.arrow.s,ind+1); break; case ST_OP: print_tree(t->pt.op.left, ind+1); print_ind(ind,' '); putchar(t->pt.op.op); putchar('\n'); print_tree(t->pt.op.right, ind+1); break; case ST_EMPTY: break; } } int main(void) { // yydebug=1; yyparse (); print_tree(input_tree,0); return 0; }