Sample1: Simple infix calculator using flex and bison with optional input from a string or file. See download main.c /** * Example code for flex/yacc * Makefile and part of main.c taken from Kyle R. Burton <mortis@voicenet.com> * and http://www.gnu.org/manual/bison-1.35/bison.html and modified. * * * Author: Mike Chirico <mchirico@users.sourceforge.net> * * Copyright 2003 Mike Chirico, All rights reserved. * This source code is copyrighted under the GNU GPL. * * Input can be read 1 of 2 ways. From a file ./main file or * if no file is given, it will read from buff and buff2. * * Note, to show how parser.y handles errors, buff2 is incorrect. */ #include <stdio.h> /** * We have to declare these here - they're not in any header files * we can inclde. yyparse() is declared with an empty argument list * so that it is compatible with the generated C code from bison. * */ extern int yyparse(); extern FILE *yyin; extern int yy_scan_string(const char *); extern void reset_lexer(void); extern void reset_parser(void); int main(int argc,char** argv) { /** * Two strings the parser will work on. * The second string, by design, contains * 2 errors. */ char *buff = "3.2+5.3\n" "5.0e2+5.2E2\n" "(7+9)*2\n" "r=34+2\n" "r\n"; char *buff2 = "3+3\n" "5+-2\n" "2^(5--2)\n" "5/2\n" "5/0\n" "5/0.001\n" "5+3\n" "+3+3"; /** * take input from file only,then, exit */ if ( argc == 2 ) { yyin = fopen( argv[1], "r" ); reset_lexer(); reset_parser(); yyparse(); return(1); /*Exit program from here */ } printf("main: scaning buf:\n%s\nOutput:",buff); reset_lexer(); /* implemented in lexer.l */ reset_parser(); /* implemented in parser.y */ /** * command to set input. */ yy_scan_string(buff); /** * invoke the parser */ yyparse(); /** * scan the second string */ printf("main: scaning buf2 (Note 2 errors in buf2 by design):\n%s\nOutput:",buff2); reset_lexer(); reset_parser(); yy_scan_string(buff2); yyparse(); return 0; } lexer.l %{ #include "parser.h" extern double sngvbltable[26]; int line = 1, col = 1; %} %% ([0-9]+|([0-9]*\.[0-9]+)([eE][-+]?[0-9]+)?) { col += (int) strlen(yytext); yylval.dval = atof(yytext); return NUM; } [ \t] { col += (int) strlen(yytext); } /* ignore but count white space */ [a-z] { col += (int) strlen(yytext); yylval.vblno = yytext[0] - 'a'; return NAME; } \n { col = 0; ++line; return yytext[0]; } . { col += (int) strlen(yytext); return yytext[0]; } %% /** * reset the line and column count * * */ void reset_lexer(void) { line = 1; col = 1; } /** * yyerror() is invoked when the lexer or the parser encounter * an error. The error message is passed via *s * * */ void yyerror(char *s) { printf("error: %s at line: %d col: %d\n",s,line,col); } /** * Normaly, the scanner reads from file handles, this function * is responsible for telling the scanner that there is no more * input. It should return true if there are no more input files, * or if there are, it should close the previous file, open the next, * and return false (0). * * */ int yywrap(void) { return 1; } parser.y %{ #include <stdio.h> #include <stdlib.h> #include <math.h> double sngvbltable[26]; /* single variable lookup table */ extern int yyerror(char *s); extern int yylex( void ); extern char* yytext; int num = 0; %} %union { double dval; int vblno; } %token <vblno> NAME %token <dval> NUM %left '-' '+' %left '*' '/' /* order defines precedence '+' and '-' are at lowest level */ %left NEG /* negation--unary minus */ %right '^' /* exponentiation */ %type <dval> exp /* Grammar follows */ %% input: /* empty string */ | statement '\n' | input statement '\n' ; statement: NAME '=' exp {sngvbltable[$1] = $3; } | exp { printf ("\t%g\n", $1); } ; /* Precedence for '+','-' vs '*', '/' is NOT defined here. * Instead, the two %left commands above perform that role. */ exp: exp '+' exp { $$ = $1 + $3; } | exp '-' exp { $$ = $1 - $3; } | exp '*' exp { $$ = $1 * $3; } | exp '/' exp { if ( $3 == 0.0) yyerror("divide by zero error"); else $$ = $1 / $3; } | '-' exp %prec NEG { $$ = -$2; } | exp '^' exp { $$ = pow ($1, $3); } | '(' exp ')' { $$ = $2; } | NUM | NAME { $$ = sngvbltable[$1]; } ; %% Makefile main: main.o lexer.o parser.o gcc -o main -Wall main.c lexer.o parser.c -lm parser.o: parser.c parser.c: parser.y bison -d parser.y test -e parser.tab.c && mv parser.tab.c parser.c test -e parser.tab.h && mv parser.tab.h parser.h parser.h: parser.c lexer.o: lexer.c lexer.c: lexer.l parser.h flex lexer.l test -e lex.yy.c && mv lex.yy.c lexer.c clean: -rm -f main *.o parser.h parser.c lexer.c a.out *.a core test: main ./main
/** * Example code for flex/yacc * Makefile and part of main.c taken from Kyle R. Burton <mortis@voicenet.com> * and http://www.gnu.org/manual/bison-1.35/bison.html and modified. * * * Author: Mike Chirico <mchirico@users.sourceforge.net> * * Copyright 2003 Mike Chirico, All rights reserved. * This source code is copyrighted under the GNU GPL. * * Input can be read 1 of 2 ways. From a file ./main file or * if no file is given, it will read from buff and buff2. * * Note, to show how parser.y handles errors, buff2 is incorrect. */ #include <stdio.h> /** * We have to declare these here - they're not in any header files * we can inclde. yyparse() is declared with an empty argument list * so that it is compatible with the generated C code from bison. * */ extern int yyparse(); extern FILE *yyin; extern int yy_scan_string(const char *); extern void reset_lexer(void); extern void reset_parser(void); int main(int argc,char** argv) { /** * Two strings the parser will work on. * The second string, by design, contains * 2 errors. */ char *buff = "3.2+5.3\n" "5.0e2+5.2E2\n" "(7+9)*2\n" "r=34+2\n" "r\n"; char *buff2 = "3+3\n" "5+-2\n" "2^(5--2)\n" "5/2\n" "5/0\n" "5/0.001\n" "5+3\n" "+3+3"; /** * take input from file only,then, exit */ if ( argc == 2 ) { yyin = fopen( argv[1], "r" ); reset_lexer(); reset_parser(); yyparse(); return(1); /*Exit program from here */ } printf("main: scaning buf:\n%s\nOutput:",buff); reset_lexer(); /* implemented in lexer.l */ reset_parser(); /* implemented in parser.y */ /** * command to set input. */ yy_scan_string(buff); /** * invoke the parser */ yyparse(); /** * scan the second string */ printf("main: scaning buf2 (Note 2 errors in buf2 by design):\n%s\nOutput:",buff2); reset_lexer(); reset_parser(); yy_scan_string(buff2); yyparse(); return 0; }
%{ #include "parser.h" extern double sngvbltable[26]; int line = 1, col = 1; %} %% ([0-9]+|([0-9]*\.[0-9]+)([eE][-+]?[0-9]+)?) { col += (int) strlen(yytext); yylval.dval = atof(yytext); return NUM; } [ \t] { col += (int) strlen(yytext); } /* ignore but count white space */ [a-z] { col += (int) strlen(yytext); yylval.vblno = yytext[0] - 'a'; return NAME; } \n { col = 0; ++line; return yytext[0]; } . { col += (int) strlen(yytext); return yytext[0]; } %% /** * reset the line and column count * * */ void reset_lexer(void) { line = 1; col = 1; } /** * yyerror() is invoked when the lexer or the parser encounter * an error. The error message is passed via *s * * */ void yyerror(char *s) { printf("error: %s at line: %d col: %d\n",s,line,col); } /** * Normaly, the scanner reads from file handles, this function * is responsible for telling the scanner that there is no more * input. It should return true if there are no more input files, * or if there are, it should close the previous file, open the next, * and return false (0). * * */ int yywrap(void) { return 1; }
%{ #include <stdio.h> #include <stdlib.h> #include <math.h> double sngvbltable[26]; /* single variable lookup table */ extern int yyerror(char *s); extern int yylex( void ); extern char* yytext; int num = 0; %} %union { double dval; int vblno; } %token <vblno> NAME %token <dval> NUM %left '-' '+' %left '*' '/' /* order defines precedence '+' and '-' are at lowest level */ %left NEG /* negation--unary minus */ %right '^' /* exponentiation */ %type <dval> exp /* Grammar follows */ %% input: /* empty string */ | statement '\n' | input statement '\n' ; statement: NAME '=' exp {sngvbltable[$1] = $3; } | exp { printf ("\t%g\n", $1); } ; /* Precedence for '+','-' vs '*', '/' is NOT defined here. * Instead, the two %left commands above perform that role. */ exp: exp '+' exp { $$ = $1 + $3; } | exp '-' exp { $$ = $1 - $3; } | exp '*' exp { $$ = $1 * $3; } | exp '/' exp { if ( $3 == 0.0) yyerror("divide by zero error"); else $$ = $1 / $3; } | '-' exp %prec NEG { $$ = -$2; } | exp '^' exp { $$ = pow ($1, $3); } | '(' exp ')' { $$ = $2; } | NUM | NAME { $$ = sngvbltable[$1]; } ; %%
main: main.o lexer.o parser.o gcc -o main -Wall main.c lexer.o parser.c -lm parser.o: parser.c parser.c: parser.y bison -d parser.y test -e parser.tab.c && mv parser.tab.c parser.c test -e parser.tab.h && mv parser.tab.h parser.h parser.h: parser.c lexer.o: lexer.c lexer.c: lexer.l parser.h flex lexer.l test -e lex.yy.c && mv lex.yy.c lexer.c clean: -rm -f main *.o parser.h parser.c lexer.c a.out *.a core test: main ./main