Ive been working on a project and have come across:
Below is the list of if declarations, I have everything here except for the types in typeSpec, but we don't have to worry about those for right now. I am fairly sure that I understand what shift/reduce and reduce/reduce errors are but (lucky for me) the compiler doesn't tell me where the conflicts are. Can someone point me in the right direction on where the conflicts are, or give me some tips on how to find where the conflicts are would be really appreciated. Also if I am missing something from the post, anything and everything is greatly appreciated aswell!
%%
program
: declList { syntaxTree = $1; }
;
declList
: declList decl { $$ = AddSibling($1, $2); }
| decl { $$ = $1; }
;
decl
: varDecl { $$ = $1; }
| funDecl { $$ = $1; }
;
varDecl
: typeSpec varDeclList SEMICOLON { $$ = $2; SetType($2, $1, false); }
;
scopedVarDecl
: STATIC typeSpec varDeclList SEMICOLON { $$ = $3; SetType($3, $2, true); }
| typeSpec varDeclList SEMICOLON { $$ = $2; SetType($2, $1, false); }
;
varDeclList
: varDeclList COMMA varDeclInit { $$ = AddSibling($1, $3); }
| varDeclInit { $$ = $1; }
;
varDeclInit
: varDeclId { $$ = $1; }
| varDeclId COLON simpleExp { $$ = $1; AddChild($$, $3); }
;
varDeclId
: ID { $$ = NewDeclNode(VarK, UndefinedType, $1); $$->tmp = $1->idIndex; }
| ID LBRACKET NUMCONST RBRACKET{ $$ = NewDeclNode(VarK, UndefinedType, $1); $$->isArray = true; $$->aSize = $3->nvalue; $$->tmp = $1->idIndex;}
;
typeSpec
: {}
;
funDecl
: typeSpec ID LPAREN parms RPAREN compoundStmt { $$ = NewDeclNode(FuncK, $1, $2, $4, $6);$$->tmp = $2->idIndex; SetType($$, $1, true);}
| ID LPAREN parms RPAREN compoundStmt{ $$ = NewDeclNode(FuncK, Void, $1, $3, $5); $$->tmp = $1->idIndex; }
;
parms
: parmList { $$ = $1; }
| { $$ = NULL; }
;
parmList
: parmList SEMICOLON parmTypeList { $$ = AddSibling($1, $3); }
| parmTypeList { $$ = $1; }
;
parmTypeList
: typeSpec parmIdList { $$ = $2; SetType($2, $1, false); }
;
parmIdList
: parmIdList COMMA parmId { $$ = AddSibling($1, $3); }
| parmId { $$ = $1; }
;
parmId
: ID { $$ = NewDeclNode(ParamK, Void, $1); $$->tmp = $1->svalue; }
| ID LBRACKET RBRACKET { $$ = NewDeclNode(ParamK, Void, $1); $$->isArray = true; $$->tmp = $1->svalue; }
;
stmt
: matched { $$ = $1; }
| unmatched { $$ = $1; }
;
matched
: expStmt { $$ = $1; }
| compoundStmt { $$ = $1; }
| returnStmt { $$ = $1; } //
| breakStmt { $$ = $1; } //
| matchedSelectStmt { $$ = $1; }
| matchedIterStmt { $$ = $1; }
;
unmatched
: unmatchedSelectStmt{ $$ = $1; }
| unmatchedIterStmt { $$ = $1; }
;
expStmt
: exp SEMICOLON { $$ = $1; }
| SEMICOLON { $$ = NULL; }
;
compoundStmt
: BEG localDecls stmtList END { $$ = NewStmtNode(CompoundK, $1, $2, $3); }
;
localDecls
: localDecls scopedVarDecl { $$ = AddSibling($1, $2); }
| { $$ = NULL; }
;
stmtList
: stmtList stmt { $$ = AddSibling($1, $2); }
| { $$ = NULL; }
;
matchedSelectStmt : IF simpleExp THEN matched ELSE matched
{ $$ = NewStmtNode(IfK, $1, $2, $4, $6); }
;
unmatchedSelectStmt
: IF simpleExp THEN stmt { $$ = NewStmtNode(IfK, $1, $2, $4); }
| IF simpleExp THEN matched ELSE unmatched { $$ = NewStmtNode(IfK, $1, $2, $4, $6); }
;
matchedIterStmt
: WHILE simpleExp DO matched { $$ = NewStmtNode(WhileK, $1, $2, $4); }
| FOR ID ASGN iterRange DO matched { $$ = NewStmtNode(ForK, $1, NewDeclNode(VarK, Integer, $2), $4, $6); $$->tmp = $2->idIndex; }
;
unmatchedIterStmt
: WHILE simpleExp DO unmatched { $$ = NewStmtNode(WhileK, $1, $2, $4); }
| FOR ID ASGN iterRange DO unmatched { $$ = NewStmtNode(ForK, $1, NewDeclNode(VarK, Integer, $2), $4, $6); $$->tmp = $2->idIndex; }
;
iterRange
: simpleExp TO simpleExp { $$ = NewStmtNode(RangeK, $2, $1, $3);}
| simpleExp TO simpleExp BY simpleExp { $$ = NewStmtNode(RangeK, $2, $1, $3, $5); $$->tmp = $2->idIndex; }
;
returnStmt
: RETURN SEMICOLON { $$ = NewStmtNode(ReturnK, $1); }
| RETURN exp SEMICOLON { $$ = NewStmtNode(ReturnK, $1, $2); }
;
breakStmt
: BREAK SEMICOLON { $$ = NewStmtNode(BreakK, $1); }
;
exp
: mutable ASGN exp { $$ = NewExpNode(AssignK, $2, $1, $3); }
| mutable ADDASGN exp { $$ = NewExpNode(AssignK, $2, $1, $3); }
| mutable SUBASGN exp { $$ = NewExpNode(AssignK, $2, $1, $3); }
| mutable MULASGN exp { $$ = NewExpNode(AssignK, $2, $1, $3); }
| mutable DIVASGN exp { $$ = NewExpNode(AssignK, $2, $1, $3); }
| mutable INC { $$ = NewExpNode(AssignK, $2, $1); }
| mutable DEC { $$ = NewExpNode(AssignK, $2, $1); }
| simpleExp {$$ = $1; }
;
simpleExp
: simpleExp OR andExp { $$ = NewExpNode(OpK, $2, $1, $3); }
| andExp { $$ = $1; }
;
andExp
: andExp AND unaryRelExp { $$ = NewExpNode(OpK, $2, $1, $3); }
| unaryExp { $$ = $1; }
;
unaryRelExp
: NOT unaryRelExp { $$ = NewExpNode(OpK, $1, $2); }
| relExp { $$ = $1; }
;
relExp
: sumExp relop sumExp { $$ = $2; AddChild($$, $1); AddChild($$, $3); }
| sumExp { $$ = $1; }
;
relop
: GT { $$ = NewExpNode(OpK, $1); }
| GEQ { $$ = NewExpNode(OpK, $1); }
| LT { $$ = NewExpNode(OpK, $1); }
| LEQ { $$ = NewExpNode(OpK, $1); }
| EQ { $$ = NewExpNode(OpK, $1); }
| NEQ { $$ = NewExpNode(OpK, $1); }
;
sumExp
: sumExp sumop mulExp { $$ = $2; AddChild($$,$1); AddChild($$,$3); }
| mulExp { $$ = $1; }
;
sumop
: ADD { $$ = NewExpNode(OpK, $1); }
| MINUS { $$ = NewExpNode(OpK, $1); }
;
mulExp
: mulExp mulop unaryExp { $$ = $2; AddChild($$, $1); AddChild($$, $3); }
| unaryExp { $$ = $1; }
;
mulop
: STAR { $$ = NewExpNode(OpK, $1); }
| DIV { $$ = NewExpNode(OpK, $1); }
| PERCENT { $$ = NewExpNode(OpK, $1); }
;
unaryExp
: unaryop unaryExp { $$ = $1; AddChild($$, $2); }
| factor { $$ = $1; }
;
unaryop
: MINUS { $$ = NewExpNode(OpK, $1); }
| STAR { $$ = NewExpNode(OpK, $1); }
| QMARK { $$ = NewExpNode(OpK, $1); }
;
factor
: mutable { $$ = $1; }
| immutable { $$ = $1; }
mutable
: ID { $$ = NewExpNode(IdK, $1); $$->name = $1->idIndex; }
| ID LBRACKET exp RBRACKET { $$ = NewExpNode(OpK, $2, NewExpNode(IdK, $1), $3); $$->child[0]->name = $1->idIndex; }
;
immutable
: LPAREN exp RPAREN { $$ = $2; }
| call { $$ = $1; }
| constant { $$ = $1; }
;
call
: ID LPAREN args RPAREN { $$ = NewExpNode(CallK, $1, $3); $$->name = $1->idIndex; }
;
args
: argList { $$ = $1; }
| { $$ = NULL; }
;
argList
: argList COMMA exp { $$ = AddSibling($1, $3); $$->name = $2->svalue; }
| exp { $$ = $1; }
;
constant
: NUMCONST { $$ = NewExpNode(ConstantK, $1); $$->expType = Integer; $$->value = $1->nvalue; }
| CHARCONST { $$ = NewExpNode(ConstantK, $1); $$->expType = Char; $$->cvalue = $1->cvalue; }
| STRINGCONST { $$ = NewExpNode(ConstantK, $1); $$->expType = String; $$->string = $1->svalue; }
| BOOLCONST { $$ = NewExpNode(ConstantK, $1); $$->expType = Boolean; $$->value = $1->nvalue;}
;
%%
I am trying to run my first flex bison project and this happens:
aky#aky-VirtualBox:~/wk1$ flex project1.l
aky#aky-VirtualBox:~/wk1$ bison -d project1.y
aky#aky-VirtualBox:~/wk1$ gcc -o project1 project1.c project1.tab.c lex.yy.c
project1.c: In function ‘main’:
project1.c:18:9: warning: implicit declaration of function ‘yyparse’
project1.tab.c:1213:16: warning: implicit declaration of function ‘yylex’
lex.yy.c:(.text+0x470): undefined reference to `lookup'
The related code:
project1.c ----------------------------
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "project1.h"
void yyerror(char *s)
{
fprintf(stderr, "error: %s\n", s);
}
int main(int argc, char **argv)
{
extern FILE *yyin;
++argv; --argc;
yyin = fopen(argv[0], "r");
return yyparse();
}
project1.l ------------------------
%option noyywrap nodefault yylineno
%{
#include "project1.h"
#include "project1.tab.h"
%}
EXP ([Ex][-+]?[0-9]+)
%%
".." { return DOTS; }
"+" |
"-" |
"*" |
"/" |
"=" |
"|" |
"," |
";" |
":" |
"." |
"[" |
"]" |
"{" |
"}" |
"(" |
")" { return yytext[0]; }
">" { yylval.fn = 1; return CMP; }
"<" { yylval.fn = 2; return CMP; }
"<>" { yylval.fn = 3; return CMP; }
"==" { yylval.fn = 4; return CMP; }
">=" { yylval.fn = 5; return CMP; }
"<=" { yylval.fn = 6; return CMP; }
"integer" { yylval.type_c = 'a'; return STD_TYPE; }
"real" { yylval.type_c = 'b'; return STD_TYPE; }
"program" { return PROGRAM; }
"var" { return VAR; }
"array" { return ARRAY; }
"of" { return OF; }
"begin" { return BGN; }
"end" { return END; }
"if" { return IF; }
"then" { return THEN; }
"else" { return ELSE; }
"while" {return WHILE; }
"do" { return DO; }
"print" { return PRINT; }
[a-zA-Z][a-zA-Z0-9]* { yylval.s = lookup(yytext); return ID; }
[0-9]+"."[0-9]+ |
[0-9]+ { yylval.d = atof(yytext); return NUMBER; }
"//".*
[ \t\n]
. { yyerror("Mystery character.\n"); }
%%
project1.y ------------------------
%{
#include <stdio.h>
#include <stdlib.h>
#include "project1.h"
%}
%union {
struct ast *a;
double d;
struct symbol *s;
struct symlist *sl;
struct numlist *nl;
int fn;
char type_c;
}
/* declare tokens */
%token <d> NUMBER
%token <s> ID
%token PROGRAM VAR ARRAY OF INTEGER REAL BGN END IF THEN ELSE WHILE DO DOTS PRINT
%token <type_c> STD_TYPE
%nonassoc <fn> CMP
%right '='
%left '+' '-'
%left '*' '/'
%nonassoc '|' UMINUS
%type <a> decl_list decl stmt_list stmt exp
%type <sl> id_list
%type <nl> num_list
%start program
%%
program: PROGRAM ID '(' id_list ')' ';' decl_list BGN stmt_list END '.'
{ printf("new program.\n"); }
;
decl_list: { /*$$ = NULL;*/ }
| decl ';' decl_list { printf("new declaration.\n"); }
;
decl: VAR id_list ':' STD_TYPE { }
| VAR id_list ':' ARRAY '[' NUMBER DOTS NUMBER ']' OF STD_TYPE
{ }
;
stmt: IF exp THEN '{' stmt_list '}' { }
| IF exp THEN '{' stmt_list '}' ELSE '{' stmt_list '}' { }
| WHILE exp DO '{' stmt_list '}' { }
| exp
;
stmt_list: stmt { printf("new statement.\n"); }
| stmt_list ';' stmt { }
;
exp: exp CMP exp { }
| exp '+' exp { }
| exp '-' exp { }
| exp '*' exp { }
| exp '/' exp { }
| '|' exp { }
| '(' exp ')' { }
| '-' exp %prec UMINUS { }
| NUMBER{ }
| ID { }
| ID '[' exp ']' { }
| ID '[' exp ']' '=' exp { }
| ID '=' exp { }
| ID '=' '{' num_list '}' { }
| PRINT '(' exp ')' { }
;
num_list: NUMBER { }
| NUMBER ',' num_list {}
;
id_list: ID { }
| ID ',' id_list { }
;
%%
project1.tab.h --------------------
#ifndef YY_YY_PROJECT1_TAB_H_INCLUDED
# define YY_YY_PROJECT1_TAB_H_INCLUDED
/* Debug traces. */
#ifndef YYDEBUG
# define YYDEBUG 0
#endif
#if YYDEBUG
extern int yydebug;
#endif
/* Token type. */
#ifndef YYTOKENTYPE
# define YYTOKENTYPE
enum yytokentype
{
NUMBER = 258,
ID = 259,
PROGRAM = 260,
VAR = 261,
ARRAY = 262,
OF = 263,
INTEGER = 264,
REAL = 265,
BGN = 266,
END = 267,
IF = 268,
THEN = 269,
ELSE = 270,
WHILE = 271,
DO = 272,
DOTS = 273,
PRINT = 274,
STD_TYPE = 275,
CMP = 276,
UMINUS = 277
};
#endif
/* Value type. */
#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
union YYSTYPE
{
#line 7 "project1.y" /* yacc.c:1909 */
struct ast *a;
double d;
struct symbol *s;
struct symlist *sl;
struct numlist *nl;
int fn;
char type_c;
#line 87 "project1.tab.h" /* yacc.c:1909 */
};
typedef union YYSTYPE YYSTYPE;
# define YYSTYPE_IS_TRIVIAL 1
# define YYSTYPE_IS_DECLARED 1
#endif
extern YYSTYPE yylval;
int yyparse (void);
#endif /* !YY_YY_PROJECT1_TAB_H_INCLUDED */
yyparse is declared in project1.tab.h so you need to #include that file in any translation unit which refers to yyparse.
yylex is not declared in any header. In your yacc/bison file, you need to insert a correct declaration:
int yylex(void);
That should go after the #includes.
It's not clear to me which file lookup is defined in, but you need to add it to your final compilation command .
This is not homework, but it is from a book.
I'm given a following bison spec file:
%{
#include <stdio.h>
#include <ctype.h>
int yylex();
int yyerror();
%}
%token NUMBER
%%
command : exp { printf("%d\n", $1); }
; /* allows printing of the result */
exp : exp '+' term { $$ = $1 + $3; }
| exp '-' term { $$ = $1 - $3; }
| term { $$ = $1; }
;
term : term '*' factor { $$ = $1 * $3; }
| factor { $$ = $1; }
;
factor : NUMBER { $$ = $1; }
| '(' exp ')' { $$ = $2; }
;
%%
int main() {
return yyparse();
}
int yylex() {
int c;
/* eliminate blanks*/
while((c = getchar()) == ' ');
if (isdigit(c)) {
ungetc(c, stdin);
scanf("%d", &yylval);
return (NUMBER);
}
/* makes the parse stop */
if (c == '\n') return 0;
return (c);
}
int yyerror(char * s) {
fprintf(stderr, "%s\n", s);
return 0;
} /* allows for printing of an error message */
The task is to do the following:
Rewrite the spec to add the following useful error messages:
"missing right parenthesis," generated by the string (2+3
"missing left parenthesis," generated by the string 2+3)
"missing operator," generated by the string 2 3
"missing operand," generated by the string (2+)
The simplest solution that I was able to come up with is to do the following:
half_exp : exp '+' { $$ = $1; }
| exp '-' { $$ = $1; }
| exp '*' { $$ = $1; }
;
factor : NUMBER { $$ = $1; }
| '(' exp '\n' { yyerror("missing right parenthesis"); }
| exp ')' { yyerror("missing left parenthesis"); }
| '(' exp '\n' { yyerror("missing left parenthesis"); }
| '(' exp ')' { $$ = $2; }
| '(' half_exp ')' { yyerror("missing operand"); exit(0); }
;
exp : exp '+' term { $$ = $1 + $3; }
| exp '-' term { $$ = $1 - $3; }
| term { $$ = $1; }
| exp exp { yyerror("missing operator"); }
;
These changes work, however they lead to a lot of conflicts.
Here is my question.
Is there a way to rewrite this grammar in such a way so that it wouldn't generate conflicts?
Any help is appreciated.
Yes it is possible:
command : exp { printf("%d\n", $1); }
; /* allows printing of the result */
exp: exp '+' exp {
// code
}
| exp '-' exp {
// code
}
| exp '*' exp {
// code
}
| exp '/' exp {
// code
}
|'(' exp ')' {
// code
}
Bison allows Ambiguous grammars.
I don't see how can you rewrite grammar to avoid conflicts. You just missed the point of terms, factors etc. You use these when you want left recursion context free grammar.
From this grammar:
E -> E+T
|T
T -> T*F
|F
F -> (E)
|num
Once you free it from left recursion you would go to:
E -> TE' { num , ( }
E' -> +TE' { + }
| eps { ) , EOI }
T -> FT' { ( , num }
T' -> *FT' { * }
|eps { + , ) , EOI }
F -> (E) { ( }
|num { num }
These sets alongside rules are showing what input character has to be in order to use that rule. Of course this is just example for simple arithmetic expressions for example 2*(3+4)*5+(3*3*3+4+5*6) etc.
If you want to learn more about this topic I suggest you to read about "left recursion context free grammar". There are some great books covering this topic and also covering how to get input sets.
But as I said above, all of this can be avoided because Bison allows Ambiguous grammars.
I'm trying to study compiler construction on my own. I'm reading a book and this is one of the exercises (I want to stress that this is not homework, I'm doing this on my own).
The following grammar represents a simple arithmetic expressions in
LISP-like prefix notation
lexp -> number | ( op lexp-seq )
op -> + | * | +
lexp-seq -> lexp-seq lexp | lexp
For example, the expression (* (-2) 3 4) has a value of -24. Write
Yacc/Bison specification for a program that will compute and print
the value of expressions in this syntax. (Hint: this will require
rewriting the grammar, as well as the use of a mechanism for passing
the operator to an lexp-seq
I have solved it. The solution is provided below. However I have questions about my solution as well as the problem itself. Here they are:
I don't modify a grammar in my solution and it seems to be working perfectly. There are no conflicts when Yacc/Bison spec is converted to a .c file. So why is the author saying that I need to rewrite a grammar?
My solution is using a stack as a mechanism for passing the operator to an lexp-seq. Can someone suggest a different method, the one that will not use a stack?
Here is my solution to the problem (I'm not posting code for stack manipulation as the assumption is that the reader is familiar with how stacks work)
%{
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include "linkedstack.h"
int yylex();
int yyerror();
node *operatorStack;
%}
%token NUMBER
%%
command : lexp { printf("%d\n", $1); };
lexp : NUMBER { $$ = $1; }
| '(' op lexp_seq ')'
{
int operator;
operatorStack = pop(operatorStack, &operator);
switch(operator) {
default:
yyerror("Unknown operator");
exit(1);
break;
case '+':
case '*':
$$ = $3;
break;
case '-':
$$ = -$3;
break;
}
}
;
op : '+' { operatorStack = push(operatorStack, '+'); }
| '-' { operatorStack = push(operatorStack, '-'); }
| '*' { operatorStack = push(operatorStack, '*'); }
;
lexp_seq : lexp_seq lexp
{
switch(operatorStack->data) {
default:
yyerror("Unrecognized operator");
exit(1);
break;
case '+':
$$ = $1 + $2;
break;
case '-':
$$ = $1 - $2;
break;
case '*':
$$ = $1 * $2;
break;
}
}
| lexp { $$ = $1; }
;
%%
int main(int argc, char** argv) {
int retVal;
init(operatorStack);
if (2 == argc && (0 == strcmp("-g", argv[1])))
yydebug = 1;
retVal = yyparse();
destroy(operatorStack);
return retVal;
}
int yylex() {
int c;
/* eliminate blanks*/
while((c = getchar()) == ' ');
if (isdigit(c)) {
ungetc(c, stdin);
scanf("%d", &yylval);
return (NUMBER);
}
/* makes the parse stop */
if (c == '\n') return 0;
return (c);
}
int yyerror(char * s) {
fprintf(stderr, "%s\n", s);
return 0;
} /* allows for printing of an error message */
Using a stack here is unnecessary if you rewrite the grammar.
One way is to use a different non-terminal for each operator:
command : lexp '\n' { printf("%d\n", $1); }
lexp : NUMBER
| '(' op_exp ')' { $$ = $2; }
op_exp : plus_exp | times_exp | minus_exp
plus_exp: '+' lexp { $$ = $2; }
| plus_exp lexp { $$ = $1 + $2; }
times_exp: '*' lexp { $$ = $2; }
| times_exp lexp { $$ = $1 * $2; }
minus_exp: '-' lexp { $$ = -$2; }
| minus_exp lexp { $$ = $1 - $2; }
I don't know if that is what your book's author had in mind. There are certainly other possible implementations.
In a real lisp-like language, you would need to do this quite differently, because the first object in an lexp could be a higher-order value (i.e. a function), which might even be the result of a function call, so you can't encode the operations into the syntax (and you can't necessarily partially evaluate the expression as you parse new arguments, either).
I recently started learning bison and I already hit a wall. The manual sections are a little bit ambiguous, so I guess an error was to be expected. The code below is the first tutorial from the official manual - The Reverse Polish Notation Calculator, saved in a single file - rpcalc.y.
/* Reverse polish notation calculator */
%{
#include <stdio.h>
#include <math.h>
#include <ctype.h>
int yylex (void);
void yyerror (char const *);
%}
%define api.value.type {double}
%token NUM
%% /* Grammar rules and actions follow. */
input:
%empty
| input line
;
line:
'\n'
| exp '\n' {printf ("%.10g\n", $1);}
;
exp:
NUM {$$ = $1; }
| exp exp '+' {$$ = $1 + $2; }
| exp exp '-' {$$ = $1 - $2; }
| exp exp '*' {$$ = $1 * $2; }
| exp exp '/' {$$ = $1 / $2; }
| exp exp '^' {$$ = pow ($1, $2); }
| exp 'n' {$$ = -$1; }
;
%%
/* The lexical analyzer */
int yylex (void)
{
int c;
/* Skip white space */
while((c = getchar()) == ' ' || c == '\t')
continue;
/* Process numbers */
if(c == '.' || isdigit (c))
{
ungetc (c, stdin);
scanf ("%lf", $yylval);
return NUM;
}
/* Return end-of-imput */
if (c == EOF)
return 0;
/* Return a single char */
return c;
}
int main (void)
{
return yyparse ();
}
void yyerror (char const *s)
{
fprintf (stderr, "%s\n", s);
}
Executing bison rpcalc.y in cmd returns the following error:
rpcalc.y:11.24-31: syntax error, unexpected {...}
What seems to be the problem?
The fault is caused by you using features that are new to the 3.0 version of bison, whereas you have an older version of bison installed. If you are unable to upgrade to version 3.0, it is an easy change to convert the grammar to using the features of earlier versions of bison.
The %define api.value.type {double} can be changed to a %type command, and the %empty command removed. The resulting bison program would be:
/* Reverse polish notation calculator */
%{
#include <stdio.h>
#include <math.h>
#include <ctype.h>
int yylex (void);
void yyerror (char const *);
%}
%type <double> exp
%token <double> NUM
%% /* Grammar rules and actions follow. */
input:
| input line
;
line:
'\n'
| exp '\n' {printf ("%.10g\n", $1);}
;
exp:
NUM {$$ = $1; }
| exp exp '+' {$$ = $1 + $2; }
| exp exp '-' {$$ = $1 - $2; }
| exp exp '*' {$$ = $1 * $2; }
| exp exp '/' {$$ = $1 / $2; }
| exp exp '^' {$$ = pow ($1, $2); }
| exp 'n' {$$ = -$1; }
;
%%
/* The lexical analyzer */
int yylex (void)
{
int c;
/* Skip white space */
while((c = getchar()) == ' ' || c == '\t')
continue;
/* Process numbers */
if(c == '.' || isdigit (c))
{
ungetc (c, stdin);
scanf ("%lf", $yylval);
return NUM;
}
/* Return end-of-imput */
if (c == EOF)
return 0;
/* Return a single char */
return c;
}
int main (void)
{
return yyparse ();
}
void yyerror (char const *s)
{
fprintf (stderr, "%s\n", s);
}
This runs in a wider range of bison versions.