Bison, Flex and compiling my compiler error with parser.y - c

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.

Related

Large amount of errors compiling lex and yacc files

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.

I'm receiving an error when giving my language a second input

The program generated from my bison/flex files works fine for the first input(the first run of yyparse()), but throws an error when I try and run it a second time.
for example:
chris#chris-Inspiron-1525:~/4850/hw$ ./calc
HORN 3+4*6-11+33*2 ?
= 82
HORN 1+1 ?
error: syntax error
Basically, commands exist between 'HORN' and '?'
Here's my .y file:
%{
#include <stdlib.h>
#include <stdio.h>
void yyerror(const char *str);
%}
%union
{
int ival;
float fval;
char* word;
}
%start line
%type <word> wexp
%type <ival> iexp
%type <fval> fexp
%left PLUS MINUS
%left STAR DIV MOD
%left POW
%token GT
%token LT
%token ASGN
%token LP
%token RP
%token LB
%token RB
%token NOT
%token GTEQ
%token LTEQ
%token EQTO
%token NOTEQ
%token HORN
%token QMARK
%token <word> WORD
%token <fval> FLOAT
%token <ival> INTEGER
%%
line : HORN wexp QMARK { printf("=\t%s\n", $2); }
| HORN iexp QMARK { printf("=\t%d\n", $2); }
| HORN fexp QMARK { printf("=\t%f\n", $2); }
;
iexp : iexp MINUS iexp { $$ = $1 - $3; }
| iexp PLUS iexp { $$ = $1 + $3; }
| iexp STAR iexp { $$ = $1 * $3; }
| iexp DIV iexp { $$ = $1 / $3; }
| INTEGER { $$ = $1; }
;
fexp : FLOAT { $$ = $1; }
;
wexp : WORD { $$ = $1; }
;
%%
int main(){
yyparse();
}
void yyerror(const char *str)
{
printf("error: %s\n",str);
}
Thanks for any input!
Your yacc grammar only declare one line. When you have finished one line any following input is a syntax error.
The current way to allow as many lines as you need is to add as first rule something like :
lines : line
| lines line
;
Provided you correctly ignore end of line in the lex part ...

Segmentation Fault after assignment statement(lex and yacc)

This code works perfectly fine. After compiling lex and yacc, the code is able to do basic arithmetic operations, and even echoes the value of a variable when asked to do so. The only problem is with assignment statements.
If I want to, say, do A = 12, and later type A to see its value, the program crashes and I get a segmentation fault. How do I ensure that my assignment statements work, and how can I avoid this segmentation fault?
Here is my code:
//lex file
/*Lex input specification*/
%{
#include <stdlib.h>
#include <stdio.h>
#include "y.tab.h"
void yyerror(char*);
%}
%%
" " ;
[A-Z] { yylval = *yytext-'a'; return VARIABLE;}
[0-9]+([0-9])* { yylval=atoi(yytext); return INTEGER;}
[-/+()=*\n] { return *yytext;}
[\t] ;
. { yyerror("invalid character");}
%%
int yywrap(void) { return 1;}
And the yacc file:
/*yacc*/
%token INTEGER VARIABLE
%left '|'
%left '&'
%left '+' '-'
%left '*' '/'
%left UMINUS
%{
void yyerror(char*);
int yylex(void);
int sym[26];
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
%}
%%
program:
program statement '\n'
|
;
statement:
expr {printf("%d\n",$1);}
| VARIABLE '=' expr {sym[$1] = $3;}
;
expr:
INTEGER {$$ = $1;}
| VARIABLE {$$ = sym[$1];}
| expr '*' expr {$$ = $1 * $3;}
| expr '/' expr {$$ = $1 / $3;}
| expr '+' expr {$$ = $1 + $3;}
| expr '-' expr {$$ = $1 - $3;}
| '(' expr ')' {$$ = $2;}
;
%%
void yyerror(char*s) {
fprintf(stderr, "%s\n", s);
}
int main(void) {
yyparse();
return 0;
}
(I flagged this as "not reproducible" because the fix was so trivial; however the flag has now timed-out/aged away. I'll answer instead so it is not shown as an open unanswered question).
As #BLUEPIXY noted:
maybe *yytext-'A'
Which, to clarify, is the lex rule:
[A-Z] { yylval = *yytext-'A'; return VARIABLE;}

error in yacc: ''x' has no declared type

I want to run the following .y code for constructing a C compiler. The code was taken exactky from this Book
The following miniC.y code is:
%{
#include <stdio.h>
#include "mini.h"
#include "miniC.h"
%}
%union {
ADDRESS address;
int code; /* comparison code 1-6 */
struct {int L1;
int L2;
int L3;
int L4;} labels;
}
%token <address> IDENTIFIER
%token <code> INT
%token <code> FLOAT
%token FOR
%token WHILE
%token <code> COMPARISON
%token IF
%token ELSE
%token <address> NUM
%type <code> Type
%type <address> Expr
%type <address> OptExpr
%type <labels> WhileStmt
%type <labels> ForStmt
%type <labels> IfStmt
%type <labels> Label
%right '='
%left COMPARISON
%left '+' '-'
%left '*' '/'
%left UMINUS UPLUS
%%
Function: Type IDENTIFIER '(' ArgListOpt ')' CompoundStmt
;
ArgListOpt: ArgList
|
;
ArgList: ArgList ',' Arg
| Arg
;
Arg: Type IDENTIFIER
;
Declaration: Type {dcl = TRUE;
identType = $1;}
IdentList ';' {dcl = FALSE;}
;
IdentList: IDENTIFIER ',' IdentList
| IDENTIFIER
;
Type: INT {$$ = $1;}
| FLOAT {$$ = $1;}
;
Stmt: ForStmt
| WhileStmt
| Expr ';'
| IfStmt
| CompoundStmt
| Declaration
| ';' /* null statement */
;
ForStmt: FOR '(' Expr ';' {$$.L1 = newlabel();
atom (LBL,NULL,NULL,NULL,0,$$.L1);}
OptExpr ';' {$$.L2 = newlabel();
atom (TST,$6,zero,NULL,6,
$<labels>$.L2);
$$.L3 = newlabel();
atom (JMP,NULL,NULL,NULL,0,
$<labels>$.L3);
$$.L4 = newlabel();
atom (LBL,NULL,NULL,NULL,0,
$<labels>$.L4);}
OptExpr ')' {atom (JMP,NULL,NULL,NULL,0,
$<labels>5.L1);
atom (LBL,NULL,NULL,NULL,0,
$<labels>8.L2);}
Stmt {atom (JMP,NULL,NULL,NULL,0,
$<labels>8.L4);
atom (LBL,NULL,NULL,NULL,0,
$<labels>8.L3);}
;
OptExpr: Expr {$$ = $1;}
| {$$ = one;} /* default to inf loop */
;
WhileStmt: WHILE {$$.L1 = newlabel();
atom (LBL,NULL,NULL,NULL,0,$$.L1);}
'(' Expr ')' {$$.L2 = newlabel();
atom (TST,$4, zero, NULL,1,$$.L2);}
Stmt {atom (JMP,NULL,NULL,NULL,0,
$<labels>2.L1);
atom (LBL,NULL,NULL,NULL,0,
$<labels>6.L2);}
;
IfStmt: IF '(' Expr ')' {$$.L1 = newlabel();
atom (TST, $3, zero, NULL, 1, $$.L1);}
Stmt {$$.L2 = newlabel();
atom (JMP,NULL,NULL,NULL,0, $$.L2);
atom (LBL,NULL,NULL,NULL,0,
$<labels>5.L1);}
ElsePart {atom (LBL,NULL,NULL,NULL,0,
$<labels>7.L2);}
;
ElsePart:
| ELSE Stmt
;
CompoundStmt: '{' StmtList '}'
;
StmtList: StmtList Stmt
|
;
Expr: IDENTIFIER '=' Expr {atom (MOV, $3, NULL, $1,0,0);
$$ = $3;}
| Expr COMPARISON Expr
Label {$$ = alloc(1);
atom (MOV, one, NULL, $$,0,0);
atom (TST, $1, $3, NULL, $2, $4.L1);
atom (MOV, zero, NULL, $$,0,0);
atom (LBL,NULL,NULL,NULL,0,$4.L1);}
| '+' Expr %prec UPLUS {$$ = $2;}
| '-' Expr %prec UMINUS {$$ = alloc(1);
atom (NEG, $2,NULL,$$,0,0); }
| Expr '+' Expr {$$ = alloc(1);
atom (ADD, $1, $3,$$,0,0); }
| Expr '-' Expr {$$ = alloc(1);
atom (SUB, $1, $3, $$,0,0); }
| Expr '*' Expr {$$ = alloc(1);
atom (MUL, $1, $3, $$,0,0); }
| Expr '/' Expr {$$ = alloc(1);
atom (DIV, $1, $3, $$,0,0); }
| '(' Expr ')' {$$ = $2;}
| IDENTIFIER {$$ = $1; }
| NUM {$$ = $1; }
;
Label: {$$.L1 = newlabel();}
; /* Used to store a label in
compare expr above */
%%
char *progname;
char * op_text();
int lineno = 1;
ADDRESS save;
ADDRESS one;
ADDRESS zero;
int nextlabel = 1;
#include "lex.yy.c"
#include "gen.c"
main (int argc, char *argv[]){
progname = argv[0];
atom_file_ptr = fopen ("atoms", "wb");
strcpy (yytext,"0.0");
zero = searchNums(); /* install the constant 0.0 in table */
strcpy (yytext, "1.0");
one = searchNums(); /* also 1.0 */
yyparse();
fclose (atom_file_ptr);
if (!err_flag) code_gen();
}
yyerror (char * s){
fprintf(stderr, "%s[%d]: %s\n", progname, lineno, s);
printf ("yytext is <%s>", yytext);
err_flag = TRUE;
}
newlabel (void){ return nextlabel++;}
atom (int operation, ADDRESS operand1, ADDRESS operand2,
ADDRESS result, int comparison, int dest)
/* put out an atom. destination will be a label number. */
{ struct atom outp;
outp.op = operation;
outp.left = operand1;
outp.right = operand2;
outp.result = result;
outp.cmp = comparison;
outp.dest = dest;
fwrite (&outp, sizeof (struct atom), 1, atom_file_ptr);
}
decode (int atom){
switch (atom){
case ADD: strcpy (mne, "ADD");
break;
case SUB: strcpy (mne, "SUB");
break;
case MUL: strcpy (mne, "MUL");
break;
case DIV: strcpy (mne, "DIV");
break;
case JMP: strcpy (mne, "JMP");
break;
case NEG: strcpy (mne, "NEG");
break;
case LBL: strcpy (mne, "LBL");
break;
case TST: strcpy (mne, "TST");
break;
case MOV: strcpy (mne, "MOV");
}
}
The errors are:
miniC.y:65.42-43: $$ for the midrule at $5 of 'ForStmt' has no declared type
miniC.y:66.69-70: $$ for the midrule at $5 of 'ForStmt' has no declared type
miniC.y:67.42-43: $$ for the midrule at $8 of 'ForStmt' has no declared type
miniC.y:70.42-43: $$ for the midrule at $8 of 'ForStmt' has no declared type
miniC.y:73.42-43: $$ for the midrule at $8 of 'ForStmt' has no declared type
miniC.y:88.42-43: $$ for the midrule at $2 of 'WhileStmt' has no declared type
miniC.y:89.69-70: $$ for the midrule at $2 of 'WhileStmt' has no declared type
miniC.y:90.42-43: $$ for the midrule at $6 of 'WhileStmt' has no declared type
miniC.y:91.69-70: $$ for the midrule at $6 of 'WhileStmt' has no declared type
miniC.y:97.42-43: $$ for the midrule at $5 of 'IfStmt' has no declared type
miniC.y:98.72-73: $$ for the midrule at $5 of 'IfStmt' has no declared type
miniC.y:99.42-43: $$ for the midrule at $7 of 'IfStmt' has no declared type
miniC.y:100.70-71: $$ for the midrule at $7 of 'IfStmt' has no declared type
make: *** [y.tab.c] Error 1
My makefile contains:
miniC: lex.yy.c y.tab.c
gcc -g y.tab.c -o miniC -ly -ll
lex.yy.c:miniC.l
lex miniC.l
y.tab.c:miniC.y
yacc -d miniC.y
Can any mentor will come forward to advice me to resolve this problem.
Thank Yoy
The errors are complaining about the use of $$ (no type tag included) in midaction rules, which is illegal. ALL uses of $$ in midaction rules need a type tag. Interestingly, not all uses are incorrect -- SOME of them have the type tag $<labels>$.
I think what you need to do is replace $$ with $<labels>$ in all the mid rule actions (but NOT in the end-of-rule actions...) The easiest would be to go through the error messages (looking at the line and column of each), and replace that $$ with $<labels>$
Which version of bison/yacc are you using? What is the command line? My version gave these ( very common ) messages:
[Charlies-MacBook-Pro:~/junk] crb% bison x.y
x.y: conflicts: 6 shift/reduce
[Charlies-MacBook-Pro:~/junk] crb% bison --version
bison (GNU Bison) 2.3
Written by Robert Corbett and Richard Stallman.
It seems to say that your grammar is mostly fine.
Maybe post your Makefile and look at your bison version.

Flex Bison Not Reading Full Input

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

Resources