Yet Another Compiler Compiler
Yet Another Compiler Compiler
Example grammar:
expr -> ( expr ) | expr '+' expr | expr '-' expr | expr '*' expr | expr '/' expr | - expr | INT ;
expr : '(' expr ')' | expr '+' expr | expr '-' expr | expr '*' expr | expr '/' expr | - expr | INT ;
Exampe Input: 10 * 3 + 4
Yacc Derivation:
expr => expr + expr => expr * expr + expr => 10*3 + 4
Resolving Ambiguities
%left '+', '-' %left '*', '/' %left UMINUS %% expr : '(' expr ')' | expr '+' expr | expr '-' expr | expr '*' expr | expr '/' expr | '-' expr %prec UMINUS | INT ;
Actions
%left '+', '-' %left '*', '/' %left UMINUS %% expr : '(' expr ')' {$$ = $2;} | expr '+' expr {$$ = $1 + $3;} | expr '-' expr {$$ = $1 - $3;} | expr '*' expr {$$ = $1 * $3;} | expr '/' expr {$$ = $1 / $3;} | '-' expr %prec UMINUS {$$ = -$2;} | INT {$$ = $1;} ;
program : expr {printf("Expr value = %d \n", $1);} | error {printf("YACC: syntax error near line %d \n", linenum); abort();} ;
expr : '(' expr ')' {$$ = $2;} | expr '+' expr {$$ = $1 + $3;} | expr '-' expr {$$ = $1 - $3;} | expr '*' expr {$$ = $1 * $3;} | expr '/' expr {$$ = $1 / $3;} | '-' expr %prec UMINUS {$$ = -$2;} | INT {$$ = $1;} ;
%% #include "lex.yy.c"
Execution Example
Input: Output:
10 + 20*(3 - 4 + 25)
[0-9]+ {sscanf(yytext, "%d", &temp_int); yylval.int_val = temp_int; return INT;} . {printf("LEX: unknown input string found in line %d \n", linenum); abort();}
Compiling:
yacc YaccFile lex LexFile cc y.tab.c -ly -ll -o myparser
Executable: myparser
program : stmt_list | error {printf("YACC: syntax error near line %d \n", linenum); abort();} ; stmt_list : stmt_list stmt | stmt ; stmt : expr ';' ; {printf("Expr value = %d \n", $1);}
expr : '(' expr ')' {$$ = $2;} | expr '+' expr {$$ = $1 + $3;} | expr '-' expr {$$ = $1 - $3;} | expr '*' expr {$$ = $1 * $3;} | expr '/' expr {$$ = $1 / $3;} | '-' expr %prec UMINUS {$$ = -$2;} | INT {$$ = $1;} ; %%
#include "lex.yy.c"
Output:
{return '+';} {return '-';} {return '*';} {return '/';} {return ')';} {return '(';} {return ';';}
[0-9]+ {sscanf(yytext, "%d", &temp_int); yylval.int_val = temp_int; return INT;} . {printf("LEX: unknown input string found in line %d \n", linenum); abort();}
%left '+', '-' %left '*', '/' %left UMINUS %token PRINT %token NEWLINE %token <str_val> STRING %token <int_val> INT %type <int_val> expr %start program %%
program : stmt_list | error {printf("YACC: syntax error near line %d \n", linenum); abort();} ;
stmt_list : stmt_list stmt | stmt ; stmt : expr ';' | PRINT expr ';' | PRINT STRING ';' | PRINT NEWLINE ';' ; {printf("expression found\n");} {printf("%d", $2);} {printf("%s", $2);} {printf("\n");}
expr : '(' expr ')' {$$ = $2;} | expr '+' expr {$$ = $1 + $3;} | expr '-' expr {$$ = $1 - $3;} | expr '*' expr {$$ = $1 * $3;} | expr '/' expr {$$ = $1 / $3;} | '-' expr %prec UMINUS {$$ = -$2;} | INT {$$ = $1;} ; %% #include "lex.yy.c"
Output:
"+" {return '+';} "-" {return '-';} "*" {return '*';} "/" {return '/';} ")" {return ')';} "(" {return '(';} ";" {return ';';} "print" {return PRINT;} "newline" {return NEWLINE;}
[0-9]+ {sscanf(yytext, "%d", &temp_int); yylval.int_val = temp_int; return INT;} \"[^"\n]*\" {strncpy(temp_str, &(yytext[1]), strlen(yytext)-2); temp_str[strlen(yytext)-2] = (char) 0; yylval.str_val = temp_str; return STRING;} . {printf("LEX: unknown input string found in line %d \n", linenum); abort();}