For loop parser yacc - loops

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

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.)

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

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.

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

What is wrong with this yacc file?

I'm getting this error tema4.y:13.19-26: syntax error, unexpected typetype on the following code, please help me!
%{
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
%}
%union {
int intval;
char* strval;
char* charval;
}
%token <charval>SHR <intval>NR
%token CMP
%type <strval>str <intval>expr
%nonassoc CMP '|'
%left '+' '-'
%left '*' '`' '#'
%start s
%%
s:str {printf("%s \n",$<strval>$);}
| expr {printf("%s \n",$<intval>$)}
;
str : str '+' str {
char* s=malloc(strlen($1)+strlen($3)+1);
strcpy(s,$1);
strcat(s,$3);
$$=s;
}
| str '-' str {
char *s=malloc(strlen($1));
char *sir=malloc(strlen($1)-strlen($3));
char *pt,*ps;
int i;
strcpy(s,$1);
pt=strstr(s,$3);
if(pt) {
ps=pt+strlen($3);
strncpy(pt,ps,strlen(ps));
ps+=strlen(ps);
strncpy(sir,s,strlen($1)-strlen($3));
}
$$=sir;
}
| str '*' NR {
int i;
char* s=malloc(strlen($1)*NR+1);
for(i=0;i<$3;i++)
{
strcat(s,$1);
}
$$=s;
}
| str '#' NR {
char *s=malloc($3+1);
strcpy(s,$1);
if($3>strlen($1)) {printf("Nr prea mare\n");exit(1);}
else {s=s+strlen(s)-$3;
$$=s;}
}
| NR '`' str {
char *s=malloc($1+1);
strncpy(s,$3,$1);
$$=s;
}
| '(' str ')' {
$$=$2;
}
| SHR {
char* s=malloc(strlen($1));
strcpy(s,$1);
$$=s;
}
| expr
;
expr : str CMP str {
if(strcmp($1,$3)) $$=0;
else $$=1;
}
| '|' str '|' {
$$=strlen($2);
}
;
%%
int main(){
yyparse();
}
John has the answer for your first error -- only one type in a %type or %token declaration. For the second error (type clash), the problem is your rule str: expr ; -- str is a <strval> while expr is an <intval>, so the default action ({ $$ = $1; } effectively) has a type clash.
You also have a reduce/reduce conflict somewhere -- you'll need to run yacc with -d and look at the resulting y.output file for more detail on what the conflict is.
As best I can tell you can only have one <type> in a %token or %type declaration. You can have multiple tokens or non-terminals but only one type name. Try splitting those lines:
%token <charval> SHR
%token <intval> NR
%token CMP
%type <strval> str
%type <intval> expr

Resources