After running the compiler and type the entry on, works fine. Then if I type another entry (and if it also works ok) it gave me Syntax Error.
I must mention I am a new in the world of flex/bison. To be honest I do not know what's could be wrong, some one please help?
Here is my lex code:
%{
#include <stdio.h>
#include "calc.tab.h"
void yyerror(char *);
%}
%option noyywrap
DIGIT -?[0-9]
NUM -?{DIGIT}+
%%
{NUM} { yylval = atoi(yytext); return NUMBER; }
[-()+*/;] { return *yytext; }
"evaluar" { return EVALUAR; }
[[:blank:]] ;
\r {}
. yyerror("caracter invalido");
%%
and here it is my bison code:
%{
#include <stdio.h>
int yylex(void);
void yyerror(char *s);
%}
%token NUMBER EVALUAR
%start INICIO
%left '+' '-'
%left '*' '/'
%%
INICIO
: EVALUAR '(' Expr ')' ';'
{
printf("\nResultado=%d\n", $3);
}
;
Expr
: Expr '+' Expr
{
$$ = $1 + $3;
}
| Expr '-' Expr
{
$$ = $1 - $3;
}
| Expr '*' Expr
{
$$ = $1 * $3;
}
| Expr '/' Expr
{
$$ = $1 / $3;
}
| NUMBER
{
$$ = $1;
}
;
%%
int main(){
return(yyparse());
}
void yyerror(char *s){
printf("\n%s\n", s);
}
int yywrap(){
return 1;
}
Here is an example of the output:
C:\Users\Uchih\Desktop\bison>a
evaluar(2+3);
Resultado=5
evaluar(3+2);
syntax error
Your parser is written to accept a single input INICIO rule/clause, after which it will expect an EOF (and will exit after it sees it). Since instead you have a second INICIO, you get a syntax error message.
To fix this, you want your grammar to accept one or more things. Add a rule like this:
input: INICIO | input INICIO ;
and change the start to
%start input
I created a small compiler and need help to fix it.
Code of my compiler:
t.l:
%{
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "y.tab.h"
%}
%x DOUBLE_QUOTES
%%
<INITIAL>[s|S][h|H][o|O][w|W] {return show;}
<INITIAL>[a-zA-z] {yylval.id=yytext[0];return identifier;}
<INITIAL>[0-9]+ {yylval.num=atoi(yytext);return number;}
<INITIAL>[\-\+\=\;\*\/] {return yytext[0];}
<INITIAL>["] {
printf("(STRING_OPEN) ");
BEGIN(DOUBLE_QUOTES);
}
<DOUBLE_QUOTES>["] {
printf("(STRING_CLOSE) ");
BEGIN(INITIAL);
printf("(STRING:%S) ",yytext[1]);
}
%%
int yywrap (void) {return 1;}
t.y:
%{
void yyerror(char *s);
#include <stdio.h>
#include <stdlib.h>
int symbols[52];
int symbolVal(char symbol);
void updateSymbolVal(char symbol,int val);
%}
%union {int num;char id;}
%start line
%token show
%token <num> number
%token <id> identifier
%type <num> line exp term
%type <id> assignment
%%
line : assignment ';' {;}
| show exp ';' {printf("showing : %d\n",$2);}
| line assignment ';' {;}
| line show exp ';' {printf("showing : %d\n",$3);}
;
assignment: identifier '=' exp {updateSymbolVal($1,$3);}
;
exp : term {$$ = $1;}
| exp '+' term {$$ = $1 + $3;}
| exp '-' term {$$ = $1 - $3;}
| exp '*' term {$$ = $1 * $3;}
| exp '/' term {$$ = $1 / $3;}
;
term : number {$$ = $1;}
| identifier {$$ = symbolVal($1);}
%%
int computerSymbolIndex(char token)
{
int idx=-1;
if(islower(token))
{
idx=token-'a'+26;
}
else if(isupper(token))
{
idx = token - 'A';
}
return idx;
}
int symbolVal(char symbol)
{
int bucket = computerSymbolIndex(symbol);
return symbols[bucket];
}
void updateSymbolVal(char symbol,int val)
{
int bucket = computerSymbolIndex(symbol);
symbols[bucket] = val;
}
int main (void) {
printf("Created By BoxWeb Inc\n");
int i;
for(i=0;i<52;i++)
{
symbols[i]=0;
}
return yyparse();
}
void yyerror (char *s) {printf("-%s at %s !\n",s );}
command for test compiler :
show 5+5;
show 5*2;
show 5+5-2*2/1;
i need to upgrade to (want can print string):
show "hello" . " " . "mr";//hello mr
show 5+5 . " ?";//10 ?
and more....
In the lexer I use :
<INITIAL>["] {
printf("(STRING_OPEN) ");
BEGIN(DOUBLE_QUOTES);
}
<DOUBLE_QUOTES>["] {
printf("(STRING_CLOSE) ");
BEGIN(INITIAL);
printf("(STRING:%S) ",yytext[1]);
}
but I don't know how use this in a parser.
Please help me to complete this compiler.
Lets simplify it for a moment to just one possible operation
We have the following grammar
assignment: '$' identifier '=' exp ';' {updateSymbolVal($2,$4); }
;
exp: number {$$ = createExp($1);}
| string {$$ = createExp($1);}
| exp '+' exp {$$ = addExp($1,$3);}
;
Since the expression can be many different things we can't just save it in a integer but need a more complex structure, something like this:
enum expType {NUMBER, STRING};
struct Exp{
expType type;
double number;
std::string str;
};
Then we make the functions to create your expressions:
Exp* createExp(int v){
Exp *e = new Exp();
e->type = NUMBER;
e->number = v;
return e;
}
Exp* createExp(std::string s){
Exp *e = new Exp();
e->type = STRING;
e->str = s;
return e;
}
And then to do all your calculations and assignment you will always have to check the type.
Exp* addExp(Exp *a, Exp *b){
Exp *c;
if(a->type == NUMBER && b->type == NUMBER){
c->type == NUMBER;
c->number == a->number + b->number;
}
else{
std::cout << "some nice error message\n";
}
return c;
}
Same with the assign function
void updateSymbolVal(const std::string &identifier, Exp *e){
if(e->type == NUMBER){
myNumbers[identifier] = e->number;
}
if(e->type == STRING){
myStrings[identifier] = e->str;
}
}
Of course you could also make a map/vector/array of the struct Exp if you need to do some more manipulations with it. Or just hand it over to the next level.
Edit for the question of multi-language support
As written in the comment I refer to this question Flex(lexer) support for unicode. To simplify it to your need here you can make it like this.
ASC [a-zA-Z_0-9]
U [\x80-\xbf]
U2 [\xc2-\xdf]
U3 [\xe0-\xef]
U4 [\xf0-\xf4]
UANY {ASC}|{U2}{U}|{U3}{U}{U}|{U4}{U}{U}{U}
UANY+ {yylval.id = yytext[0]; return string;}
I made a .l and a .y files for the parsing and the calculation result for my new language: it is working fine! A string like this:
SET(IFEL(MAJEQ(IFEL(EQ(VAL(16),MUL(VAL(2),VAL(8))),VAL(11),VAL(10)),VAL(10)),MUL(VAL(3),VAL(4)),SUB(VAL(6),VAL(2))))
is correctly parsed and calculated by my two files:
%{
#include <stdio.h>
#include <string>
#include <cstring>
using namespace std;
extern int yylex();
extern void yyerror(char*);
%}
//Symbols
%union
{
char *str_val;
int int_val;
};
%token OPEN;
%token CLOSE;
%token SET;
%token STORE;
%token MUL;
%token ADD;
%token DIV;
%token SUB;
%token ABS;
%token IFEL;
%token AND;
%token OR;
%token NOT;
%token MAJEQ;
%token MINEQ;
%token MAJ;
%token MIN;
%token EQ;
%token GET;
%token S; /* separator */
%token VAR;
%token VAL;
%token <int_val> NUMBER
%token <str_val> IDENTIFIER
%type <int_val> Exp
%type <int_val> Cond
%type <int_val> Check
%type <int_val> Var
%start Expression
%%
Expression:
/* empty */
| SET OPEN Exp CLOSE
{
printf("value set %d\n",$3);
}
| STORE OPEN VAR OPEN IDENTIFIER CLOSE S Exp CLOSE
{
printf("var %s set on %d\n",$5,$8);
}
;
Exp:
Var
| IFEL OPEN Cond S Exp S Exp CLOSE
{
if($3==1){
$$ = $5;
}else{
$$ = $7;
}
}
| ADD OPEN Exp S Exp CLOSE
{
$$ = $3+$5;
}
| SUB OPEN Exp S Exp CLOSE
{
$$ = $3-$5;
}
| MUL OPEN Exp S Exp CLOSE
{
$$ = $3*$5;
}
| DIV OPEN Exp S Exp CLOSE
{
$$ = $3/$5; //TBD check div 0
}
| ABS OPEN Exp CLOSE
{
$$ = $3; //TBD
}
;
Cond:
NOT OPEN Cond CLOSE
{
int result = $3;
if(result==1) $$ = 0;
else $$ = 1;
}
| AND OPEN Cond S Cond CLOSE
{
int result1 = $3;
int result2 = $5;
if(result1==1 && result2==1) $$ = 1;
else $$ = 0;
}
| OR OPEN Cond S Cond CLOSE
{
int result1 = $3;
int result2 = $5;
if(result1==1 || result2==1) $$ = 1;
else $$ = 0;
}
| Check
;
Check:
MAJ OPEN Exp S Exp CLOSE
{
int val1 = $3;
int val2 = $5;
if(val1>val2) $$ = 1;
else $$ = 0;
}
| MIN OPEN Exp S Exp CLOSE
{
int val1 = $3;
int val2 = $5;
if(val1<val2) $$ = 1;
else $$ = 0;
}
| EQ OPEN Exp S Exp CLOSE
{
int val1 = $3;
int val2 = $5;
if(val1==val2) $$ = 1;
else $$ = 0;
}
| MAJEQ OPEN Exp S Exp CLOSE
{
int val1 = $3;
int val2 = $5;
if(val1>=val2) $$ = 1;
else $$ = 0;
}
| MINEQ OPEN Exp S Exp CLOSE
{
int val1 = $3;
int val2 = $5;
if(val1<=val2) $$ = 1;
else $$ = 0;
}
;
Var:
VAR OPEN IDENTIFIER CLOSE
{
$$ = atoi($3); //TBD
}
| VAL OPEN NUMBER CLOSE
{
$$ = $3;
}
| GET OPEN CLOSE
{
$$ = 11; //TBD
}
;
%%
and
%{
#include <string>
#include "expression.tab.h"
void yyerror(char*);
extern void printVars();
int yyparse(void);
%}
%%
[ \t\n]+ { /* ignore */ };
"(" return(OPEN);
")" return(CLOSE);
"SET" return(SET);
"STORE" return(STORE);
"MUL" return(MUL);
"ADD" return(ADD);
"DIV" return(DIV);
"SUB" return(SUB);
"ABS" return(ABS);
"IFEL" return(IFEL);
"NOT" return(NOT);
"AND" return(AND);
"OR" return(OR);
"MAJEQ" return(MAJEQ);
"MINEQ" return(MINEQ);
"MAJ" return(MAJ);
"MIN" return(MIN);
"EQ" return(EQ);
"VAR" return(VAR);
"VAL" return(VAL);
"GET" return(GET);
"," return(S);
[[:digit:]]+ { yylval.int_val = atoi(yytext); return NUMBER;}
[[:alnum:]]+ { yylval.str_val = strdup(yytext); return IDENTIFIER;}
. return yytext[0];
%%
void yyerror(char *s){
printf("<ERR> %s at %s in this line:\n", s, yytext);
}
int yywrap (void){
}
int main(int num_args, char** args){
if(num_args != 2) {printf("usage: ./parser filename\n"); exit(0);}
FILE* file = fopen(args[1],"r");
if(file == NULL) {printf("couldn't open %s\n",args[1]); exit(0);}
yyin = file;
yyparse();
fclose(file);
}
But actually the value inside Var in input as you can see will not be static but should be dynamic. So my next step is to modify the project: instead of calculating should write a C++ code in order to make the calculation dynamic.
My questions:
1) do you have a better solution instead of concatenate every step a char * for making the code?
2) If not, can you help me to find a smart way to concatenate all the strings and solving the following error that I face while compiling:
expression.y:75:43: error: invalid operands of types ‘const char [2]’
and ‘char*’ to binary ‘operator+’ $$ = "("+$3+"-"+$5+")";
... I would like to don't use the "malloc" every time...
char* str;
str = malloc(1+strlen(text1)+strlen(text2));
strcpy(str, text1);
strcat(str, text2);
is there any smarter way? Following the flex and bison modified files:
expression.l
%{
#include <string>
#include "expression.tab.h"
void yyerror(char*);
extern void printVars();
int yyparse(void);
%}
%%
[ \t\n]+ { /* ignore */ };
"(" return(OPEN);
")" return(CLOSE);
"SET" return(SET);
"STORE" return(STORE);
"MUL" return(MUL);
"ADD" return(ADD);
"DIV" return(DIV);
"SUB" return(SUB);
"ABS" return(ABS);
"IFEL" return(IFEL);
"NOT" return(NOT);
"AND" return(AND);
"OR" return(OR);
"MAJEQ" return(MAJEQ);
"MINEQ" return(MINEQ);
"MAJ" return(MAJ);
"MIN" return(MIN);
"EQ" return(EQ);
"VAR" return(VAR);
"VAL" return(VAL);
"GET" return(GET);
"," return(S);
([a-z0-9]+)|([0-9]+.[0-9]+) { yylval.str_val = strdup(yytext); return IDENTIFIER;}
. return yytext[0];
%%
void yyerror(char *s){
printf("<ERR> %s at %s in this line:\n", s, yytext);
}
int yywrap (void){
}
int main(int num_args, char** args){
if(num_args != 2) {printf("usage: ./parser filename\n"); exit(0);}
FILE* file = fopen(args[1],"r");
if(file == NULL) {printf("couldn't open %s\n",args[1]); exit(0);}
yyin = file;
yyparse();
fclose(file);
}
expression.y
%{
#include <stdio.h>
#include <string>
#include <cstring>
using namespace std;
extern int yylex();
extern void yyerror(char*);
%}
//Symbols
%union
{
char *str_val;
int int_val;
};
%token OPEN;
%token CLOSE;
%token SET;
%token STORE;
%token MUL;
%token ADD;
%token DIV;
%token SUB;
%token ABS;
%token IFEL;
%token AND;
%token OR;
%token NOT;
%token MAJEQ;
%token MINEQ;
%token MAJ;
%token MIN;
%token EQ;
%token GET;
%token S; /* separator */
%token VAR;
%token VAL;
%token <str_val> IDENTIFIER
%type <str_val> Exp
%type <str_val> Cond
%type <str_val> Check
%type <str_val> Var
%start Expression
%%
Expression:
/* empty */
| SET OPEN Exp CLOSE
{
printf("%s\n",$3);
}
| STORE OPEN VAR OPEN IDENTIFIER CLOSE S Exp CLOSE
{
printf("var %s with following code:\n%s\n",$5,$8);
}
;
Exp:
Var
| IFEL OPEN Cond S Exp S Exp CLOSE
{
$$ = "("+$3+" == 'true') ? ("+$5+") : ("+$7+")";
}
| ADD OPEN Exp S Exp CLOSE
{
$$ = "("+$3+"+"+$5+")";
}
| SUB OPEN Exp S Exp CLOSE
{
$$ = "("+$3+"-"+$5+")";
}
| MUL OPEN Exp S Exp CLOSE
{
$$ = "("+$3+"*"+$5+")";
}
| DIV OPEN Exp S Exp CLOSE
{
$$ = "("+$3+"/"+$5+")"; //TBD check div 0
}
| ABS OPEN Exp CLOSE
{
$$ = "("+$3+">0) ? "+$3+" : "(+$3+"*(-1))";
}
;
Cond:
NOT OPEN Cond CLOSE
{
$$ = "("+$3+"=='true') ? 'false' : 'true'";
}
| AND OPEN Cond S Cond CLOSE
{
$$ = "("+$3+"=='true' && "+$5+"=='true') ? 'true' : 'false'";
}
| OR OPEN Cond S Cond CLOSE
{
$$ = "("+$3+"=='true' || "+$5+"=='true') ? 'true' : 'false'";
}
| Check
;
Check:
MAJ OPEN Exp S Exp CLOSE
{
$$ = "("+$3+">"+$5+") ? 'true' : 'false'";
}
| MIN OPEN Exp S Exp CLOSE
{
$$ = "("+$3+"<"+$5+") ? 'true' : 'false'";
}
| EQ OPEN Exp S Exp CLOSE
{
$$ = "("+$3+"=="+$5+") ? 'true' : 'false'";
}
| MAJEQ OPEN Exp S Exp CLOSE
{
$$ = "("+$3+">="+$5+") ? 'true' : 'false'";
}
| MINEQ OPEN Exp S Exp CLOSE
{
$$ = "("+$3+"<="+$5+") ? 'true' : 'false'";
}
;
Var:
VAR OPEN IDENTIFIER CLOSE
{
//TBD check if variable exists in the engine
$$ = $3;
}
| VAL OPEN IDENTIFIER CLOSE
{
//TBD check correct value
$$ = $3;
}
| GET OPEN CLOSE
{
$$ = "getField()"; //TBD to implement in the engine
}
;
%%
It's difficult to do string concatenation without some form of memory allocation. Of course, it is possible avoid avoid malloc -- you could use new instead, or hide the memory allocation inside of a std::string or std::stringstream -- but in the end, you're going to have to deal with dynamic memory allocation, and furthermore with releasing the memory when you no longer need it.
It's worth noting that your (correct) use of strdup in your scanner action for IDENTIFIER is a memory leak, because you never free the allocated memory. So you already need to deal with this issue.
As you note, doing string concatenation in C can be pretty clunky. In a case like this, it's worth the trouble to reduce the clunkiness. My preferred solution is my wrapper function concatf, whose prototype is just like printf except that it returns a malloc'd character string instead of printing. (See this answer for implementations on various platforms).
With the help of this function, it would be possible to write:
Exp:
Var
| IFEL OPEN Cond S Exp S Exp CLOSE
{
$$ = concatf("(%s == 'true') ? (%s) : (%s)", $3, $5, $7);
}
Note that x == 'true' is not valid C++. You probably meant == true, but that's a dangerous idiom; better is an explicit cast to bool (although that's actually redundant in the context of the ternary operator), so I think you actually want
$$ = concatf("bool(%s) ? (%s) : (%s)", $3, $5, $7);
or just
$$ = concatf("(%s) ? (%s) : (%s)", $3, $5, $7);
But, as mentioned above, that results in memory leaks because the malloc'd strings are never freed. So let's fix that. First, in each action, it is necessary to explicitly free all malloc'd values which are never used again. In simple cases like yours, that will be all malloc'd values, except for unit productions in which the malloc'd value is just assigned to a different non-terminal. Since all IDENTIFIER have semantic values created by strdup, it's reasonable to assume that all str_val values have been malloc'd (and this needs to be a constraint; if you ever create a str_val value from a literal character string, you'll end up with a problem). Now, we can write the rule:
Exp:
Var { /* No free needed; this is a unit production */ }
| IFEL OPEN Cond S Exp S Exp CLOSE
{
$$ = concatf("(%s) ? (%s) : (%s)", $3, $5, $7);
free($3); free($5); free($7);
}
Another example. Note the added strdup in the last rule.
Var:
VAR OPEN IDENTIFIER CLOSE
{
$$ = $3; /* No free needed; value is moved on the stack */
}
| VAL OPEN IDENTIFIER CLOSE
{
$$ = $3; /* As above */
}
| GET OPEN CLOSE
{
$$ = strdup("getField()"); /* str_val's must be malloc'd */
}
;
(There are alternatives to calling strdup on literals, but usually the use case is uncommon, and the overhead is slight.)
That style will handle all cases where rule actions are executed, but there are also occasions when bison will discard values from the stack without every invoking a rule. That will happen during error recovery, and at the end of an unsuccessful parse when the parser stack is non-empty. To assist with this case, bison lets you declare a destructor action, which will be invoked on each stack value which it discards. In this case, the declaration is almost trivial:
%destructor { free($$); } <str_val>
Well... I solved the issue in this way:
...
Exp:
Var
| IFEL OPEN Cond S Exp S Exp CLOSE
{
string t1 = $3;
string t2 = $5;
string t3 = $7;
string result = "("+t1+" == 'true') ? ("+t2+") : ("+t3+")";
$$ = (char*)result.c_str();
}
...
It is working fine...
For some reason or another, bison doesn't want to do any evaluation. Compilation of all files goes smoothly and the program runs. When I enter the expression 4+5 and press return, it creates tokens for 4 + 5 respectively. I can even put in some printf into the places where bison recognizes the attributes of each token including the plus (43).
However the program never evaluates this production expr '+' term { $$ = $1 + $3; }. It's simply never called at least to my knowledge and even if it was this production assign '\n' { printf("%d\n", $1); } never prints out the value. Upon ^D to quit, it fires void yyerror(const char *).
Any help on this matter is much appreciated. Thanks!
//FLEX
%{
//#include <stdio.h>
#include "y.tab.h"
%}
%option noyywrap
letter [A-Za-z]
digit [0-9]
space [ \t]
var {letter}
int {digit}+
ws {space}+
%%
{var} { yylval = (int)yytext[0]; return VAR; }
{int} { yylval = atoi(yytext); return CONST; }
{ws} { }
. { return (int)yytext[0]; }
%%
/* nothing */
.
//BISON
%{
//INCLUDE
//#include <ctype.h>
//DEFINE
#define YYDEBUG 1
//PROTOTYPE
void yyerror(const char *);
void print_welcome();
int get_val(int);
void set_val(int, int);
%}
%token CONST
%token VAR
%%
session
: { print_welcome(); }
eval
;
eval
: eval line
|
;
line
: assign '\n' { printf("%d\n", $1); }
;
assign
: VAR '=' expr { set_val($1, $3); $$ = $3; }
| expr { $$ = $1; }
;
expr
: expr '+' term { $$ = $1 + $3; }
| expr '-' term { $$ = $1 - $3; }
| term { $$ = $1; }
;
term
: term '*' factor { $$ = $1 * $3; }
| term '/' factor { $$ = $1 / $3; }
| term '%' factor { $$ = $1 % $3; }
| factor { $$ = $1; }
;
factor
: '(' expr ')' { $$ = $2; }
| CONST { $$ = $1; }
| VAR { $$ = get_val($1); }
;
%%
void yyerror(const char * s)
{
fprintf(stderr, "%s\n", s);
}
void print_welcome()
{
printf("Welcome to the Simple Expression Evaluator.\n");
printf("Enter one expression per line, end with ^D\n\n");
}
static int val_tab[26];
int get_val(int var)
{
return val_tab[var - 'A'];
}
void set_val(int var, int val)
{
val_tab[var - 'A'] = val;
}
.
//MAIN
//PROTOTYPE
int yyparse();
int main()
{
extern int yydebug;
yydebug = 0;
yyparse();
return 0;
}
Your lex file does not have any rule which matches \n, because in lex/flex, . matches any character except line-end. The default rule for lex (or flex) echoes and otherwise ignores the matched character, so that's what happens to the \n. Since the parser won't be able to accept a line unless it sees a \n token, it will eventually be forced to present you with a syntax error.
So you need to change the rule
. { return (int)yytext[0]; }
to
.|\n { return (int)yytext[0]; }
(I wouldn't have bothered with the cast to int but it's certainly not doing any harm, so I left it in.)
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Good tools for creating a C/C++ parser/analyzer
String input to flex lexer
My idea is to create a parser that can calculate the expression of Boolean, and my next step is to use it in my c++ program, but I don't know how to use it.
Currently, this calculator can run in command line, the code is not good, and I don't know how to use it in my program. I want to use a function lex_yacc(var) to call this calculator, and var is the input, for example, the main program read the var is (T+F), so it will be sent to lex_yacc(var), finally, the func returns 1.
I define the lexya.l as follows:
%{
#include <stdlib.h>
void yyerror(char *);
#include "lexya_a1.tab.h"
%}
%%
"T" { yylval = 1; return boolean; }
"F" { yylval = 0; return boolean; }
"!F" { yylval = 1; return boolean; }
"!T" { yylval = 0; return boolean; }
[+*\n] return *yytext;
"(" return *yytext;
")" return *yytext;
[\t] ;/* .... */
. yyerror("....");
%%
int yywrap(void) {
return 1;
}
And lexya_a1.y:
%{
#include <stdlib.h>
int yylex(void);
void yyerror(char *);
%}
%token boolean
%left '+' '-'
%left '*'
%left '(' ')'
%%
program:
program expr '\n' { printf("%d\n", $2); }
|
;
expr:
boolean { $$ = $1; }
| expr '*' expr { $$ = $1 * $3; }
| expr '+' expr { $$ = $1 + $3; }
| '(' expr ')' { $$ = $2; }
;
%%
void yyerror(char *s) {
printf("%s\n", s);
}
int main(void) {
yyparse();
return 0;
}