I am writing a nor calculator using Flex and Bison. Here is my .l file:
%{
#include <stdlib.h>
#include "y.tab.h"
%}
%%
("true"|"false") {return BOOLEAN;}
"nor" {return NOR;}
. {return yytext[0];}
%%
int main(void)
{
yyparse();
return 0;
}
int yywrap(void)
{
return 0;
}
int yyerror(void)
{
getchar();
printf("Error\n");
}
Here is my .y file:
/* Bison declarations. */
%token BOOLEAN
%token NOR
%left 'nor'
%% /* The grammar follows. */
input:
/* empty */
| input line
;
line:
'\n'
| exp '\n' { printf ("%s",$1); }
;
exp:
BOOLEAN { $$ = $1; }
| exp 'nor' exp { $$ = !($1 || $3); }
| '(' exp ')' { $$ = $2; }
;
%%
The problem is that if I type an input such as "true nor false", the lexer only gets to return BOOLEAN, then return yytext[0], then throws my error (in the flex code). Anyone see what's wrong?
the problem is here :
%left 'nor'
and
exp:
BOOLEAN { $$ = $1; }
| exp 'nor' exp { $$ = !($1 || $3); }
| '(' exp ')' { $$ = $2; }
;
you'v written 'nor' as a terminal token, your parser can't recognize 'nor' as token, so you should substitute this by NOR as the lexer returns:
"nor" {return NOR;}
solution
%left NOR
and
exp:
BOOLEAN { $$ = $1; }
| exp NOR exp { $$ = !($1 || $3); }
| '(' exp ')' { $$ = $2; }
;
Your lexer also needs to recognize white space. Make another rule " ". You don't need an action
Related
I'm trying to make a simple calculator with yacc/lex, but I keep getting a large amount of errors with a lot of them saying the errors are in the generated files.
I run gcc lex.yy.c y.tab.c -o minicalc and get errors like
bas.y:34:16: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘{’ token
int main(void) {
y.tab.c:499:2: error: expected declaration specifiers before ‘;’ token
};
These are the most common but there are many more. The thing is, I'm getting errors like
In file included from lex.yy.c:459:0:
/usr/include/unistd.h: In function ‘yyerror’:
/usr/include/unistd.h:258:22: error: storage class specified for parameter ‘useconds_t’
typedef __useconds_t useconds_t;
^~~~~~~~~~
that make it seem like the error is not in my code.
This is my lex code:
%{
#include <stdlib.h>
#include "y.tab.h"
void yyerror(char *)
%}
%%
/* a is value of last expresion */
a {
yyval = *yytext - 'a';
return LAST;
}
/* integers */
[0-9]+ {
yyval = atoi(yytext);
return INTEGER;
}
/* operators */
[-+()=/*\n] { return *yytext; }
/* skip whitespace */
[ \t] { ; }
/* all else is error */
. yyerror("invalid character");
%%
int yywrap(void) {
return 1;
}
and this is my yacc code:
%token INTEGER LAST
%left '+' '-'
%left '*' '/'
%{
void yyerror(char *)
int yylex(void);
int lastval;
%}
%%
program:
program expr '\n' { lastval = $2; }
|
;
expr:
INTEGER
| LAST { $$ = lastval; }
| expr '+' expr { $$ = $1 + $3; }
| expr '-' expr { $$ = $1 - $3; }
| expr '*' expr { $$ = $1 * $3; }
| expr '/' expr { $$ = $1 / $3; }
| '(' expr ')' { $$ = $2; }
;
%%
void yyerror(char *) {
fprintf(stderr, "%s\n", s);
}
int main(void) {
yyparse();
return 0;
}
Thanks in advance.
You're missing a semicolon after void yyerror(char *) in both the .y and the .l file. So the compiler expects a ; on the lines that come after it in the generated code, leading to the error messages you're seeing.
Here is the code in question:
calc.y
%{
#include <stdio.h>
void yyerror(char *);
int yylex(void);
int sym[26];
%}
%token INTEGER VARIABLE
%left '+' '-'
%left '*' '/'
%%
program:
program statement '\n'
| /* NULL */
;
statement:
expression { printf("%d\n", $1); }
| VARIABLE '=' expression { sym[$1] = $3; }
;
expression:
INTEGER
| VARIABLE { $$ = sym[$1]; }
| expression '+' expression { $$ = $1 + $3; }
| expression '-' expression { $$ = $1 - $3; }
| expression '*' expression { $$ = $1 * $3; }
| expression '/' expression { $$ = $1 / $3; }
| '(' expression ')' { $$ = $2; }
;
%%
void yyerror(char *s){
fprintf(stderr, "%s\n", s);
}
int main(void){
yyparse();
}
calc.l
%{
#include "calc.tab.h"
#include <stdlib.h>
void yyerror(char *);
%}
%%
[a-z] {
yylval = *yytext - 'a';
return VARIABLE;
}
[0-9]+ {
yylval = atoi(yytext);
return INTEGER;
}
[-+()=/*\n] { return *yytext; }
[\t] ;
. yyerror("Unkown Character");
%%
int yywrap(void) {
return 1;
}
When I run above code with the following commands, it works well.
$ bison -d calc.y
$ flex calc.l
However, when it is run like this:
$ gcc lex.yy.c calc.tab.c -o app
this command does not work well. And I am getting following error:
Bus error: 10
Can anyone explain why this is happening ?
Or, how can I solve this error ?
Please need help.
You need to make up your mind as to whether VARIABLE is sym[$1] or just the index into sym[].myouve used it both ways in your grammar. Judging by your lexer it is the index. In fact I don't see any necessity for sym[] at all.
And you didn't get the bus error when you generate the .c files or when you compiled them. You got it when you executed your application.
I am trying to display the whole arithmetic expression from text file and its result, I tried it with file handling option but it is not working.
YACC :
%{
#include <stdio.h>
#include <string.h>
#define YYSTYPE int /* the attribute type for Yacc's stack */
extern int yylval; /* defined by lex, holds attrib of cur token */
extern char yytext[]; /* defined by lex and holds most recent token */
extern FILE * yyin; /* defined by lex; lex reads from this file */
%}
%token NUM
%%
Calc : Expr {printf(" = %d\n",$1);}
| Calc Expr {printf(" = %d\n",$2);}
| Calc error {yyerror("\n");}
;
Expr : Term { $$ = $1; }
| Expr '+' Term { $$ = $1 + $3; }
| Expr '-' Term { $$ = $1 - $3; }
;
Term : Fact { $$ = $1; }
| Term '*' Fact { $$ = $1 * $3; }
| Term '/' Fact { if($3==0){
yyerror("Divide by Zero Encountered.");
break;}
else
$$ = $1 / $3;
}
;
Fact : Prim { $$ = $1; }
| '-' Prim { $$ = -$2; }
;
Prim : '(' Expr ')' { $$ = $2; }
| Id { $$ = $1; }
;
Id :NUM { $$ = yylval; }
;
%%
void yyerror(char *mesg); /* this one is required by YACC */
main(int argc, char* *argv){
char ch,c;
FILE *f;
if(argc != 2) {printf("useage: calc filename \n"); exit(1);}
if( !(yyin = fopen(argv[1],"r")) ){
printf("cannot open file\n");exit(1);
}
/*
f=fopen(argv[1],"r");
if(f!=NULL){
char line[1000];
while(fgets(line,sizeof(line),f)!=NULL)
{
fprintf(stdout,"%s",line);
yyparse();
}
}
*/
yyparse();
}
void yyerror(char *mesg){
printf("\n%s", mesg);
}
LEX
%{
#include <stdio.h>
#include "y.tab.h"
int yylval; /*declared extern by yacc code. used to pass info to yacc*/
%}
letter [A-Za-z]
digit ([0-9])*
op "+"|"*"|"("|")"|"/"|"-"
ws [ \t\n\r]+$
other .
%%
{ws} { /*Nothing*/ }
{digit} { yylval = atoi(yytext); return NUM;}
{op} { return yytext[0];}
{other} { printf("bad%cbad%d\n",*yytext,*yytext); return '?'; }
%%
My Text file contains these two expressions :
4+3-2*(-7)
9/3-2*(-5)
I want output as :
4+3-2*(-7)=21
9/3-2*(-5)=13
But the Output Is :
=21
=13
because a parser will do all calculations at once so this (the commented code) is not legit to use. So what is needed is to show pass input expression to grammar and print in Calc block. I am not able to find anything relevant on google about displaying input in grammar.Thanks in advance for comments & suggestions.
You don't want to do this in the grammar. Too complicated, and too subject to whatever rearrangement the grammar may do. You could consider doing it in the lexer, i.e. print yytext in every action other than the whitespace action, just before you return it, but I would echo all the input as it is read, by overriding lex(1)'s input function.
NB You should be using flex(1), not lex(1), and note that if you change, yyyext ceases being a char[] and becomes a char *.
I didn't mention it in your prior question, but this rule:
{other} { printf("bad%cbad%d\n",*yytext,*yytext); return '?'; }
would better be written as:
{other} { return yytext[0]; }
That way the parser will see it and produce a syntax error, so you don't have to print anything yourself. This technique also lets you get rid of the rules for the individual special characters +,-=*,/,(,), as the parser will recognize them via yytext[0].
Finally, I got it :
YACC
%{
#include <stdio.h>
#include <string.h>
#define YYSTYPE int /* the attribute type for Yacc's stack */
extern int yylval; /* defined by lex, holds attrib of cur token */
extern char yytext[]; /* defined by lex and holds most recent token */
extern FILE * yyin; /* defined by lex; lex reads from this
file */ %}
%token NUM
%%
Calc : Expr {printf(" = %d\n",$1);}
| Calc Expr {printf(" = %d\n",$2);}
| error {yyerror("Bad Expression\n");}
;
Expr : Term { $$ = $1; }
| Expr Add Term { $$ = $1 + $3; }
| Expr Sub Term { $$ = $1 - $3; }
;
Term : Fact { $$ = $1; }
| Term Mul Fact { $$ = $1 * $3; }
| Term Div Fact { if($3==0){
yyerror("Divide by Zero Encountered.");
break;}
else
$$ = $1 / $3;
}
;
Fact : Prim { $$ = $1; }
| '-' Prim { $$ = -$2; }
;
Prim : LP Expr RP { $$ = $2; }
| Id { $$ = $1; }
;
Id :NUM { $$ = yylval; printf("%d",yylval); }
;
Add : '+' {printf("+");}
Sub : '-' {printf("-");}
Mul : '*' {printf("*");}
Div : '/' {printf("/");}
LP : '(' {printf("(");}
RP : ')' {printf(")");}
%%
void yyerror(char *mesg); /* this one is required by YACC */
main(int argc, char* *argv){
char ch,c;
FILE *f;
if(argc != 2) {printf("useage: calc filename \n"); exit(1);}
if( !(yyin = fopen(argv[1],"r")) ){
printf("cannot open file\n");exit(1);
}
yyparse();
}
void yyerror(char *mesg){
printf("%s ", mesg);
}
Thanks EJP & EMACS User for responding.
I'm getting an error on compiling my compiler and I have no idea why. I'm running OS X 10.9.1 and the latest Xcode.
parser.y:1.1-5: invalid directive: `%code'
parser.y:1.7-9: syntax error, unexpected identifier
Here is the code of my parser.y
%code top {
#include "frontend.h"
#include "type.h"
#include "ast.h"
#include "env.h"
#include <glib.h>
#include <assert.h>
#include <stdio.h>
#include <string.h>
extern int yylex(void);
extern int yyerror(const char*);
}
%code requires {
#include "type.h"
#include "ast.h"
#include <glib.h>
}
%union {
char* id;
char* str;
int num;
GList* list;
Type* type;
struct exp* exp;
struct decl* decl;
struct stmt *stmt;
struct GList *stmts_list;
};
%type <exp> exp
%type <exp> aexp
%type <exp> bexp
%type <exp> obj_lit
%type <exp> lvalue
%type <exp> fun_call
%type <list> decls
%type <list> var_decls
%type <decl> decl
%type <decl> var_decl
%type <decl> fun_decl
%type <decl> type_decl
%type <type> type
/* Ids could be types or exps. */
%token <id> T_ID
%token <str> T_STR
%token <num> T_NUM
%token T_LT_EQ "<="
%token T_GT_EQ ">="
%token T_EQ "=="
%token T_NOT_EQ "!="
%token T_VAR T_TYPE T_FUNCTION
T_FOR T_TO T_WHILE T_IF T_ELSE T_RETURN
T_NIL T_TRUE T_FALSE
T_INT T_BOOL
T_UNKNOWN
%left '|'
%left '&'
%left "==" "!="
%left '<' '>' "<=" ">="
%left '+' '-'
%left '*' '/' '%'
%left T_UMINUS T_UPLUS '!'
%start program
%%
// ian start
program:
decls {
done_parsing($1);
}
decls:
{ GList* declsList = NULL; $$ = declsList; }
| decls decl {
$$ = g_list_append($1, $2);
}
decl: var_decl {
$$ = $1;
}
| fun_decl {
$$ = $1;
}
| type_decl {
$$ = $1;
}
var_decls:
{ GList* declsList = NULL; $$ = declsList; } | var_decls var_decl {
$$ = g_list_append($1, $2);
}
var_decl:
T_VAR T_ID ':' type ';' {
Symbol varName = symbol_var($2);
$$ = decl_new(varName, $4, NULL, NULL, NULL);
}
| T_VAR T_ID ':' type '=' exp ';' {
Symbol varName = symbol_var($2);
$$ = decl_new(varName, $4, $6, NULL, NULL);
}
type_decl:
T_TYPE T_ID ':' type ';' {
Symbol typeName = symbol_typename($2);
$$ = decl_new(typeName, $4, NULL, NULL, NULL);
}
// ian end
// adam start
param_decl:
T_ID ':' type
param_decls:
param_decl
| param_decls ',' param_decl
field_decl:
T_ID ':' type
field_decls:
field_decl
| field_decls ',' field_decl
type:
T_INT
| T_BOOL
| T_ID
| '[' type ']'
| '{' field_decls '}'
fun_decl:
T_FUNCTION T_ID '(' param_decls ')' ':' type '{' var_decls stmts '}'
| T_FUNCTION T_ID '(' param_decls ')' '{' var_decls stmts '}'
| T_FUNCTION T_ID '(' ')' ':' type '{' var_decls stmts '}'
| T_FUNCTION T_ID '(' ')' '{' var_decls stmts '}'
// adam end
// vv IAN
exp:
aexp {
$$ = $1;
}
| bexp {
$$ = $1;
}
| obj_lit {
$$ = $1;
}
| fun_call {
$$ = $1;
}
| lvalue {
$$ = $1;
}
| '(' exp ')' {
$$ = $2;
}
aexp:
T_NUM {
exp_num_new($1);
}
| '+' exp %prec T_UPLUS {
$$ = exp_binop_new(AST_EXP_MUL, exp_num_new(1), $2);
}
| '-' exp %prec T_UMINUS {
$$ = exp_binop_new(AST_EXP_MUL, exp_num_new(-1), $2);
}
| exp '+' exp {
$$ = exp_binop_new(AST_EXP_PLUS, $1, $3);
}
| exp '-' exp {
$$ = exp_binop_new(AST_EXP_MINUS, $1, $3);
}
| exp '/' exp {
$$ = exp_binop_new(AST_EXP_DIV, $1, $3);
}
| exp '%' exp {
$$ = exp_binop_new(AST_EXP_MOD, $1, $3);
}
| exp '*' exp {
$$ = exp_binop_new(AST_EXP_MUL, $1, $3);
}
bexp:
T_TRUE {
$$ = exp_new(AST_EXP_TRUE);
}
| T_FALSE {
$$ = exp_new(AST_EXP_FALSE);
}
| '!' exp {
$$ = exp_not_new($2);
}
| exp '|' exp {
$$ = exp_binop_new(AST_EXP_OR, $1, $3);
}
| exp '&' exp {
$$ = exp_binop_new(AST_EXP_AND, $1, $3);
}
| exp '<' exp {
$$ = exp_binop_new(AST_EXP_LT, $1, $3);
}
| exp "<=" exp {
$$ = exp_binop_new(AST_EXP_LT_EQ, $1, $3);
}
| exp '>' exp {
$$ = exp_binop_new(AST_EXP_GT, $1, $3);
}
| exp ">=" exp {
$$ = exp_binop_new(AST_EXP_GT_EQ, $1, $3);
}
| exp "==" exp {
$$ = exp_binop_new(AST_EXP_EQ, $1, $3);
}
| exp "!=" exp {
$$ = exp_binop_new(AST_EXP_NOT_EQ, $1, $3);
}
// jon start
obj_lit: array_lit | struct_lit
| T_NIL
array_lit:
'[' exps ']'
| T_STR
exps:
exp
| exps ',' exp
struct_lit:
'{' field_inits '}'
field_init:
T_ID '=' exp
field_inits:
field_init
| field_inits ',' field_init
fun_call:
T_ID '(' exps ')'
| T_ID '(' ')'
lvalue:
T_ID
| struct_exp '.' T_ID
| array_exp '[' exp ']'
array_exp: array_lit | fun_call | lvalue
struct_exp: struct_lit | fun_call | lvalue
// jon end
// patrick start
stmts: { GList *stmts_list = NULL; stmts_list = $$; }
| stmts stmt { $$ = g_list_append($1, $2); }
stmt:
exp ';' { $$ = stmt_exp_new($2); }
| lvalue '=' exp ';' { $$ = stmt_assign_new($1 , $3); }
| T_IF '(' exp ')' block T_ELSE block { $$ = stmt_if_new($3, $5, $7); }
| T_IF '(' exp ')' block { $$ = stmt_if_new($3, $5, NULL); }
| T_WHILE '(' exp ')' block { $$ = stmt_while_new($3, $5); }
| T_FOR '(' lvalue '=' exp T_TO exp ')' block { $$ = stmt_for_new($3, $5, $7, $9); }
| T_RETURN '(' exp ')' ';' { $$ = stmt_return_new($3); }
| T_RETURN ';' { $$ = stmt_return_new(NULL); }
block:
'{' stmts '}' { $$ = $2; }
//patrick end
%%
int yyerror(const char *p) {
fprintf(stderr, "Error: %s\n", p);
return 0;
}
From the comments, it seems likely that the version of bison which you are using does not support the %code directive. I believe the initial form of that directive didn't get into bison until version 2.3b, and the qualified version (%code top) was introduced some time in 2007. (That's from perusing the change log, not the code history.)
If that's the case, you have two choices:
Just use %{...%}. I don't see any obvious reason in your source file why you would need %code top in the first place. (Or why you feel the need to #include some of your own headers twice.)
Download and compile a version of bison which more closely corresponds to the manual you're reading.
These are not mutually incompatible, of course.
I'm trying to make a calculator from flex and bison, but I found an error during the compile.
Here is the error:
C:\GnuWin32\src>gcc lex.yy.c y.tab.c -o tugas
tugas.y:51: error: conflicting types for 'yyerror'
y.tab.c:1433: error: previous implicit declaration of 'yyerror' was here
Here is my .l code :
%{
#include <stdio.h>
#include "y.tab.h"
YYSTYPE yylval;
%}
plus [+]
semi [;]
minus [-]
var [a-z]
digit [0-1]+
equal [:=]
%%
{var} {yylval = *yytext - 'a'; return VAR;}
{digit} {yylval = atoi(yytext); return DIGIT;}
{plus} {return PLUS;}
{minus} {return MINUS;}
{equal} {return EQUAL;}
{semi} {return SEMI;}
. { return *yytext; }
%%
int main(void)
{
yyparse();
return 0;
}
int yywrap(void)
{
return 0;
}
int yyerror(void)
{
printf("Error\n");
exit(1);
}
And here is my .y code :
%{
int sym[26];
%}
%token DIGIT VAR
%token MINUS PLUS EQUAL
%token SEMI
%%
program: dlist SEMI slist
;
dlist: /* nothing */
| decl SEMI dlist
;
decl: 'VAR' VAR {printf("deklarasi variable accepted");}
;
slist: stmt
| slist SEMI stmt
;
stmt: VAR EQUAL expr {sym[$1] = $3;}
| 'PRINT' VAR {printf("%d",sym[$2]);}
;
expr: term {$$ = $1;}
| expr PLUS term { $$ = $1 + $3;}
| expr MINUS term { $$ = $1 - $3; }
;
term: int {$$ = $1;}
| VAR {$$ = sym[$1]; }
;
int: DIGIT {$$ = $1;}
| int DIGIT
;
Why I am getting this error? any suggestion to overcome this issue.Thanks in advance
yyerror should have this signature:
int yyerror(char *);
Since it is expected to accept a string to be used in the error message (would probably be better with a const char *, but you might get additional (ignorable) warnings with that...
You need to change
int yyerror(void)
to
int yyerror(char*)
In other words, yyerror() must take a single c-string argument which describes the error which occured.