Segmentation Fault after assignment statement(lex and yacc) - c

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;}

Related

Syntax error by Yacc even though the syntax is per grammar

My yacc parser is showing syntax error even though the syntax is as per grammar.
my Yacc code:
%{
void yyerror (char *s);
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
int symbols[100];
int yylex();
int symbolVal(char symbol);
void updateSymbolVal(char symbol,int val);
%}
%union {int num; char id;}
%start line
%token WHILE
%token lt
%token gt
%token exit_command
%token <num> number
%token <id> identifier
%type <num> line exp term
%type <id> assignment
%type <num> condition
%%
line: assignment {;}
|line assignment {;}
|exit_command {exit(EXIT_SUCCESS);}
|line exit_command {exit(EXIT_SUCCESS);}
|whileLoop {;}
|condition {;}
;
whileLoop: WHILE '(' condition ')' '{' assignment '}' {printf("while loop condition var:%d\n",$3);}
;
assignment : identifier '=' exp {updateSymbolVal($1,$3);}
;
exp : term {$$ = $1;}
| exp '+' term {$$ = $1 + $3;}
| exp '-' term {$$ = $1 - $3;}
;
term : number {$$ = $1;}
| identifier {$$ = symbolVal($1);}
;
condition : identifier cond_op identifier {$$ = $1;}
|identifier cond_op number {$$ = $1;}
;
cond_op : lt
| gt
;
%%
int computeSymbolIndex(char token){
int idx = -1;
if(islower(token)){
idx = token - 'a' +26;
}
else if(isupper(token)){
idx = token - 'A' + 26;
}
return idx;
}
int symbolVal(char symbol){
int bucket = computeSymbolIndex(symbol);
return symbols[bucket];
}
void updateSymbolVal(char symbol, int val){
int bucket = computeSymbolIndex(symbol);
symbols[bucket] = val;
}
int main(void){
int i;
for(i=0;i<52;i++){
symbols[i] = 0;
}
return yyparse();
}
void yyerror (char *s){fprintf (stderr, "%s\n",s);}
My Lex code:
%{
#include "y.tab.h"
%}
%%
"while" {printf("while\n"); return WHILE;}
"exit" {return exit_command;}
[a-zA-Z] {yylval.id = yytext[0]; return identifier;}
[0-9]+ {yylval.num = atoi(yytext); return number;}
"<" {return lt;}
">" {return gt;}
[ \t\n] ;
[-+=;] {return yytext[0];}
. ;
%%
int yywrap (void)
{
return 1;
}
Example text on which a syntax error is shown:
while(i>0){i = i-1}
"while" gets printed as per lex but the next line of output is "Syntax Error".
Even the "while loop condition var" is not getting printed.
The syntax error is shown especially of the while loop.
All the other things like the condition statements assignments etc seem to work fine.
Why is this happening?
You have a lexer fallback rule which silently discards unrecognised characters:
. ;
That's really not a good idea, as you have just discovered. In this case, no other rule recognises ( or ), so they are ignored by the above rule. Your parser, however, is expecting a parenthesis. It doesn't get one, so it reports a syntax error.
Better is the following fallback rule, which could replace the preceding rule:
/* [-+=;] {return yytext[0];} */ /* now redundant*/
. {return yytext[0];}
This accepts any character in the lexer. However, most characters are not used as character literals anywhere in the grammar, so they will be treated as invalid tokens by the parser, causing a syntax error.
You could get a more precise error message by writing the error in your lex fallback rule, but yhen you need to make sure that all vslid characters are recognised:
[-+=;(){}] {return yytext[0];}
. {return yytext[0];}
Personally, I'd add <> to that list rather than having dedicated rules (and unnecessary token names.)

For loop parser yacc

I'm trying to write my own scripting language using flex and bison. I have a basic parser and I would like to add a for statement very similar to the C language for statement. It is not clear to me how to code the action associated to the for statement
Suppose I have the following production for the 'for' statement:
for_loop: FOR '(' assignment ';' condition ';' compteur')' '{' list_instructions '}' {;}
/// Lex program
%{
#include "ex5q1.tab.h"
%}
aplha[a-zA-Z]
digit[0-9]
%%
[\t\n] {}
"for" return FOR;
{digit}+ return NUM;
{alpha}({alpha}|{digit})* return id;
"<=" return le;
">=" return ge;
"==" return eq;
"!=" return ne;
"&&" return and;
"||" return or;
. return yytext[0];
%%
int yywrap(){}
/// yacc program
%{
#include <stdio.h>
#include <stdlib.h>
int yylex(void);
int yyerror(char* s);
%}
%token NUM id FOR le ge eq ne or and
%right '='
%left or and
%left '>' '<' le ge eq ne
%left '+' '-'
%left '*' '/'
%left '!'
%%
s:st{printf("valid Input");return 0;}
st: FOR'('E';'E2';'E')'DEF
;
DEF: '{'BODY'}'
|E';'
|st
|
;
BODY: BODY BODY
|E';'
|st
|
;
E: id'='E
|E'+'E
|E'-'E
|E'*'E
|E'/'E
|E'<'E
|E'>'E
|EleE
|EgeE
|EeqE
|EneE
|EorE
|EandE
|E'+'+'
|E'-''-'
|id
|NUM
;
E2:E'<'E
|E'>'E
|EleE
|EgeE
|EeqE
|EneE
|EorE
|EandE
;
%%
int main() {
printf("Enter the expression\n");
yyparse();
return 0;
}
int yyerror(char* s) {
printf("Expression is invalid\n");
}

Bus error: 10 in bison and flex on mac os

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.

lex and yacc analyzer

Now here is my lex code
%{
#include <stdio.h>
#include "y.tab.h"
extern int yylval;
int yywrap();
%}
%%
[a-zA-Z] {yylval = *yytext; return ALPHABET;}
[0-9]+ {yylval = atoi(yytext); return NUMBER;}
[0-9]+"."[0-9]* {yylval = atof(yytext); return NUMBER;}
"==" return EQ;
"<=" return LE;
">=" return GE;
"!=" return NE;
[\t] ;
\n return 0;
. return yytext[0];
%%
int yywrap()
{
return 1;
}
and here is my yacc code
%{
#include<stdio.h>
extern int yylex();
extern int yyparse();
extern FILE* yyin;
int flag = 0;
%}
%token NUMBER
%token ALPHABET
%left '+''-'
%left '*''/''%'
%left '&''|''^''~'
%right EQ LE GE NE'<''>'
%left '('')'
%left UMINUS
%left UPLUS
%start check
%%
check : E { }
E:E '+' E {$$ = $1 + $3;}
|E '-' E {$$ = $1 - $3;}
|E '&' E {$$ = $1 & $3;}
|E '|' E {$$ = $1 | $3;}
|E '^' E {$$ = $1 ^ $3;}
|'~' E {$$ = ~$2;}
|E EQ E {$$ = (EQ, $1, $3);}
|E LE E {$$ = (LE, $1, $3);}
|E GE E {$$ = (GE, $1, $3);}
|E NE E {$$ = (NE, $1, $3);}
|E '<' E {$$ = ('<', $1, $3);}
|E '>' E {$$ = ('>', $1, $3);}
|'(' E ')' {$$ = $2;}
|'-' E %prec UMINUS
{$$ = - $2;}
|'+' E %prec UPLUS
{$$ = + $2;}
|NUMBER {$$ = $1;}
|ALPHABET {$$ = $1;}
;
%%
int main(int argc, char** argv)
{
char filename[30];
char line[300];
printf("\nEnter filename\n");
scanf("%s",filename);
yyin = fopen(filename, "r");
if(NULL == yyin)
{
fprintf(stderr,"Can't read file %s\n",filename);
return 1;
}
else
{
while(fgets(line, sizeof line, yyin) != NULL)
{
printf("%s\n", line);
}
yyparse();
fclose(yyin);
printf("\nValue of yyparse : %d\n",yyparse());
}
if(flag == 0)
printf("\nBoolean Arithmetic Expression is valid\n");
return 0;
}
void yyerror()
{
printf("\nBoolean Arithmetic expression is invalid\n\n");
flag = 1;
}
This is my main part for reading text file and do some operations, so anyone can tell me this how to read multiple line in text file using Yacc. Now I put my fully Yacc code and I try to check Boolean expression is correct or not my text file expressions are : -
a-b
a+b&c
(P!=F+E-O+F-(U>Y+I<N))
(((a+B)-7+4-(c-d))+((P^q)-(L|z))+(m&n)+(O-g)
((A-2)&(B+2)|(C-4)^(D+4)+(~E))==F+(G!=)-(i<j)-(K>M)
((((a+b)-(c+d))-((E-F)+(G-H)))+((a&B)+(c|d))-((e^f)+(~g)+(i==2)-(j!=2)+(k<=8)-(l>=17.98)+(M<N)-(O>p)-((-2+4)+(6-(-5)))))
So my code check only first expression. So my problem is that how to check all expressions line by line.
Now please check where is the problem for reading text line by line and give message expression is valid or not please help.
Some expressions are valid and some are invalid so please check and tell me the problem and how to correct it.
You grammar only handles a single ArithmeticExpression, and once that is done the parser returns.
One way to solve your problem is to modify the parser grammar just a little, so it handles multiple "lines" (or rather multiple expressions in your case) itself:
ArithmeticExpression_list
: ArithmeticExpression
| ArithmeticExpression_list ArithmeticExpression
;
Then you simply use the return value of the yyparse() function to see if parsing was successful or not. If yyparse() return 0 then all expressions were syntactically okay.
If you want to print for each and every expression, just add a semantic action for the ArithmeticExpression, if there's a syntax error it will not be invoked.
The structure of main() is wrong. It reads the whole of the input file using fgets(), and then seems to expect yyparse() to read some more information from it.
What you probably need to do is:
while (yyparse() == 0)
printf("OK\n");
Well, something along those lines. You might need to analyze flag, and/or set flag to 0 (or 1) after each iteration. If you want to read lines and have the grammar read the string, you have more work to do — setting up appropriate input functions, etc.
To get the code to compile cleanly, I used the following code. I added #define YY_NO_INPUT and full prototypes and various other changes — and cleaned up the triple comma expressions in the grammar for the comparison operations. They probably aren't what you'll use in the long term, but they satisfy the stringent compiler options I use.
testlex.l
%{
#include <stdio.h>
#include "y.tab.h"
#define YY_NO_INPUT
extern int yylval;
int yywrap(void);
extern void use_yyunput(char c);
%}
%%
[a-zA-Z] {yylval = *yytext; return ALPHABET;}
[0-9]+ {yylval = atoi(yytext); return NUMBER;}
[0-9]+"."[0-9]* {yylval = atof(yytext); return NUMBER;}
"==" return EQ;
"<=" return LE;
">=" return GE;
"!=" return NE;
[\t] ;
\n return 0;
. return yytext[0];
%%
int yywrap(void)
{
return 1;
}
void use_yyunput(char c)
{
unput(c);
}
testyacc.y
%{
#include <stdio.h>
#include <assert.h>
extern int yylex(void);
extern int yyparse(void);
extern void yyerror(char *str);
extern FILE* yyin;
int flag = 0;
%}
%token NUMBER
%token ALPHABET
%left '+''-'
%left '*''/''%'
%left '&''|''^''~'
%right EQ LE GE NE'<''>'
%left '('')'
%left UMINUS
%left UPLUS
%start check
%%
check : E { }
E:E '+' E {$$ = $1 + $3;}
|E '-' E {$$ = $1 - $3;}
|E '&' E {$$ = $1 & $3;}
|E '|' E {$$ = $1 | $3;}
|E '^' E {$$ = $1 ^ $3;}
|'~' E {$$ = ~$2;}
|E EQ E {$$ = ($1 == $3);}
|E LE E {$$ = ($1 <= $3);}
|E GE E {$$ = ($1 >= $3);}
|E NE E {$$ = ($1 != $3);}
|E '<' E {$$ = ($1 < $3);}
|E '>' E {$$ = ($1 > $3);}
|'(' E ')' {$$ = $2;}
|'-' E %prec UMINUS
{$$ = - $2;}
|'+' E %prec UPLUS
{$$ = + $2;}
|NUMBER {$$ = $1;}
|ALPHABET {$$ = $1;}
;
%%
int main(void)
{
char filename[30];
printf("\nEnter filename\n");
scanf("%s",filename);
yyin = fopen(filename, "r");
if(NULL == yyin)
{
fprintf(stderr,"Can't read file %s\n",filename);
return 1;
}
else
{
while (yyparse() == 0)
{
printf("OK\n");
}
fclose(yyin);
}
if(flag == 0)
printf("\nBoolean Arithmetic Expression is valid\n");
return 0;
}
void yyerror(char *str)
{
assert(str != 0);
printf("\nBoolean Arithmetic expression is invalid\n\n");
flag = 1;
}
Compilation and run
The file data contained the data from the question. rmk is a variation on the theme of make.
$ rmk testyacc.o testlex.o
yacc testyacc.y
gcc -O3 -g -I/Users/jleffler/inc -std=c11 -Wall -Wextra -Wmissing-prototypes -Wstrict-prototypes -Wold-style-definition -Werror -c y.tab.c
mv y.tab.o testyacc.o
rm -f y.tab.c
lex testlex.l
gcc -O3 -g -I/Users/jleffler/inc -std=c11 -Wall -Wextra -Wmissing-prototypes -Wstrict-prototypes -Wold-style-definition -Werror -c lex.yy.c
mv lex.yy.o testlex.o
rm -f lex.yy.c
$ gcc -o testit testyacc.o testlex.o
$ ./testit
Enter filename
data
OK
OK
OK
Boolean Arithmetic expression is invalid
$
Your stack uses integers, I believe. The use of atof() isn't going to help very much. That mainly means you've still got a lot of work to do.
Testing on Mac OS X 10.11.2 with GCC 5.3.0 (with flex 2.5.35 Apple(flex-31) and
bison (GNU Bison) 2.3 masquerading as lex and yacc).

Bison conflicting type for yyerror

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.

Resources