Syntax Analysis Part VIII Exercises: Bison Text adapted from : Marinella Sciortino, Università di Palermo
Exercise I Write an interpreter for hand calculator with the following operators +, - (binary) *, / (binary, with precedence over +, -) (unary, absolute value) Use balanced parentheses to force precedence
Exercise I: Bison %{ #include <stdio.h> % %token NUMBER OP CP %token ADD SUB MUL DIV ABS %token EOL
Exercise I: Bison %% calclist: /* empty */ calclist exp EOL { printf("= %d\n", $2) Default action: copy $1 exp: factor exp ADD factor { $$ = $1 + $3 exp SUB factor { $$ = $1 - $3 factor: term factor MUL term { $$ = $1 * $3 factor DIV term { $$ = $1 / $3
Exercise I: Bison term: NUMBER ABS term { $$ = $2 >= 0? $2 : - $2 OP exp CP { $$ = $2 %% main(int argc, char **argv) { yyparse() yyerror(char *s) { fprintf(stderr, "error: %s\n", s)
Exercise I: Flex %option noyywrap %{ #include "calculator.tab.h" % %% "(" { return OP ")" { return CP "+" { return ADD "-" { return SUB "*" { return MUL "/" { return DIV " " { return ABS [0-9]+ { yylval = atoi(yytext) return NUMBER \n { return EOL [ \t] { /* ignore whitespace */. { printf("mystery character %c\n", *yytext) %%
Exercise II Write an interpreter that checks expressions of well-nested parentheses computes the number of parentheses in the expression
Exercise II: Bison %{ % #include <ctype.h> #include<stdio.h> %% lines : lines expr '\n' { printf("%d\n", $2) lines '\n' { printf("0\n") expr : '(' expr ')' { $$ = $2 + 2 '(' expr ')' expr { $$ = $2 + $4 + 2 '(' ')' { $$ = 2 '(' ')' expr { $$ = $3 + 2
Exercise II: Bison %% int yylex() { int c = getchar() return c int main() { if (yyparse()!= 0 ) fprintf(stderr, "Abnormal exit\n") return 0 int yyerror(char *s) { fprintf(stderr, "Error: %s\n", s)
Exercise III Write a parser accepting the language L = { a n b n c n n 1 L is not context-free: need to use semantic actions
Exercise III: Bison %{ % #include <stdio.h> int counta = 0, countb = 0, countc = 0 int yylex() void yyerror(char *s) void checkcounters()
Exercise III: Bison %% lines : lines S '\n' lines '\n' /* empty */ S : As Bs Cs {checkcounters() As : As 'a' {counta++ 'a' {counta++ Bs : Bs 'b' {countb++ 'b' {countb++ Cs : Cs 'c' {countc++ 'c' {countc++
Exercise III: Bison %% void checkcounters(){ if ((counta == countb) && (counta == countc)) printf("%s\n", "accept") else printf("%s\n", "reject" ) counta = 0 countb = 0 countc = 0 int yylex() { int c = getchar() return c
Exercise III: Bison int main() { if (yyparse()!= 0 ) fprintf(stderr, "Exit\n") return 0 void yyerror(char *s) { fprintf(stderr, "Error: %s\n", s)
Exercise IV Write a parser accepting the language MIX(3) = { w w {a, b, c *, # a (w) = # b (w) = # c (w) L is not context-free: need to use semantic actions
Exercise IV: Bison %{ #include <stdio.h> #include <ctype.h> int yylex() void yyerror(char const *) int counta, countb, countc, valid = 0 %
Exercise IV: Bison %% lines : lines S '\n { valid = (counta == countb && countb == countc)? 1 : 0 printf("the string %s to the language.\n\n, (valid == 1? "belongs" : "does not belong")) counta = countb = countc = 0 lines error '\n' { yyerrok /* empty */ S : 'a' S { counta++ 'b' S { countb++ 'c' S { countc++ /* empty */ {
Exercise IV: Bison %% int main() { if (yyparse()!= 0) { fprintf(stderr, "%s\n\n", "Abnormal exit.") return 0 int yylex() { return getchar() void yyerror(char const *s) { counta = countb = countc = 0 fprintf(stderr, "Error: %s.\n\n", s)
Exercise V Write an interpreter for micro-language with instructions : int id id = num id = id id = id + id print(id)
Exercise V identifiers use only alphabetic symbols each identifier must be uniquely defined and initialized to 0 numbers are unsigned integers print(id) prints the string "id : num"
Exercise V Example : int n int k n = 132 k = n k = k + n print(k) k : 264
Exercise V: Flex %option noyywrap %{ % #include <stdio.h> #include "parser.tab.h" WS [ \t\n] LETTER [A-Za-z] DIGIT [0-9] NZDIGIT [1-9] EQUAL "="
Exercise V: Flex %% print { return PRINT int { return INT {LETTER+ { yylval.identifier = strdup(yytext) return ID {NZDIGIT{DIGIT* { yylval.number = atoi( yytext ) return NUM {WS+ /* eat up whitespaces */ <<EOF>> { return ENDFILE. { return yytext[0]
Exercise V: Bison %{ #include <ctype.h> #include <stdio.h> #include "uthash.h" int yylex() void yyerror(char *s) /* base structure of a variable in the symbol table */ typedef struct variable { const char *id // hash key int value UT_hash_handle hh // makes structure hashable variable /* symbol table initialization */ variable *mysymboltable = NULL
Exercise V: Bison /* * add variable to symbol table */ void addvar(char *id){ variable *tmp HASH_FIND_STR(mySymbolTable, id, tmp) if (tmp == NULL){ tmp = (variable*) malloc(sizeof(variable)) tmp->id = id tmp->value = 0 HASH_ADD_KEYPTR(hh, mysymboltable, tmp->id, strlen(tmp->id), tmp) else { printf("error: multiple definition for variable %s\n", id) exit(-1)
Exercise V: Bison /* * update variable "id" in the symbol table */ void setvar(char *id, int value){ variable *tmp HASH_FIND_STR(mySymbolTable, id, tmp) if(tmp == NULL){ printf("error: variable %s is not defined\n", id) exit(-1) tmp->value = value
Exercise V: Bison % /* * read variable "id" in the symbol table */ int getvar(char *id){ variable *tmp HASH_FIND_STR(mySymbolTable, id, tmp) if(tmp == NULL){ printf("error: variable %s is not defined\n", id) exit(-1) return tmp->value
Exercise V: Bison %union { int number char* identifier %token %token %token %type <number> NUM <identifier> ID PRINT INT ENDFILE <number> expr
Exercise V: Bison %% program : program stmt ' stmt '' program ENDFILE { return 0 stmt : INT ID { addvar($2) ID '=' expr { setvar($1, $3) PRINT '(' ID ')' { printf("%s : %d\n", $3, getvar($3)) expr : ID '+' ID { getvar($1) + getvar($3) ID { $$ = getvar($1) NUM { $$ = $1
Exercise V: Bison %% int main() { if (yyparse()!= 0) fprintf(stderr, "Abnormal exit\n") return 0 void yyerror(char *s) { fprintf(stderr, "Error: %s\n", s)