Install Yacc:
sudo apt install bison
The Yacc input file calc.y:
%{ void yyerror(char *s); #include<stdio.h> /* c declarations used in actions */ #include<stdlib.h> int symbols[52]; /* symbol table a through z and A through Z */ int symbolVal(char symbol); void updateSymbolVal(char symbol, int val); %} /* Yacc definitions the union lets me specify the different types that my lexical analyzer can return integers put in num and characters in id */ %union{int num; char id;} %start line %token print %token exit_command %token <num> number %token <id> identifier %type <num> line exp term %type <id> assignment %% /* descriptions of expected inputs corresponding actions in c */ line : assignment ';' {;} | exit_command ';' {exit(EXIT_SUCCESS);} | print exp ';' {printf("Printing %d ", $2);} | line assignment ';' {;} | line print exp ';' {printf("Printing %d ", $3);} | line exit_command ';' {exit(EXIT_SUCCESS);} ; assignment : identifier '=' exp { updateSymbolVal($1,$3); } ; exp : term {$$ = $1; } | exp '+' term {$$ = $1 + $3;} | exp '-' term {$$ = $1 - $3;} ; term : number {$$ = $1;} | identifier {$$ = symbolVal($1);} ; %% /* c code */ int computeSymbolIndex(char token){ int idx = -1; if(islower(token)){ idx = token - 'a' + 26; /* the lower case are going to map from 26 to 51 */ } else if(isupper(token)){ idx = token - 'A'; } return idx; } /* returns the value of a given symbol */ int symbolVal(char symbol){ int bucket = computeSymbolIndex(symbol); return symbols[bucket]; } /* update the value of a given symbol */ void updateSymbolVal(char symbol, int val){ int bucket = computeSymbolIndex(symbol); symbols[bucket] = val; } int main(void){ /* init symbol table */ int i; for(i=0; i<52; i++){ symbols[i] = 0; } return yyparse();//the function generated by yacc } void yyerror(char *s){fprintf(stderr, "%s ",s);}
The lex input file calc.l
%{ #include"y.tab.h" %} %% "print" {return print;} "exit" {return exit_command;} [a-zA-Z] {yylval.id = yytext[0]; return identifier;} [0-9]+ {yylval.num = atoi(yytext); return number;} [ ] ; [-+=;] {return yytext[0];} . {ECHO; yyerror ("unexpected character");} %% int yywrap (void) {return 1;}
Commands to generate the interpreter:
yacc -d calc.y # to generate y.tab.h and y.tab.c is the actual generated parser lex calc.l # generates lex.yy.c gcc lex.yy.c y.tab.c -o calc
Sample results: