I'm working on a Lex+Yacc calculator that is capable of performing basic arithmetic operations, as well as supporting usage of parentheses. From my testing, it is capable of handling essentially every scenario, providing an integer solution for valid inputs, and indicating an input was invalid if invalid input is provided.
However, in my testing I found that if I simply type in: 5) or 99+22+33) or basically anything where ')' is the final character, it'll still be deemed valid. In fact, I could even type in "7)asdfghjk", and it would deem it valid and still output 7. It seems like when there is a lone ')' at the end it does not care. Whereas if I had (5 it would error out.
My Lex file and Yacc file are provided below. Any help would be greatly appreciated. Thank you so much.
Lex File:
/* ========== DECLARATIONS SECTION ========== */
%{
#include <stdio.h>
#include <stdlib.h>
#include "y.tab.h"
extern int yylval;
%}
/* ========================================== */
/* ========== SHORTHAND DEFINITIONS ========= */
/* ========================================== */
/* ================== RULES ================= */
%%
([1-9][0-9]*|0) {
yylval = atoi(yytext);
return INT;
}
[+] {return PLUS;}
[-] {return MINUS;}
[*] {return MULT;}
[/] {return DIV;}
[(] {return LPAREN;}
[)] {return RPAREN;}
[ \t] {;}
[\n] {return 0;}
. {yyerror();}
%%
/* ========================================== */
/* ================ USER CODE =============== */
int yywrap() {
return 1;
}
/* ========================================== */
Yacc File:
/* ========== DECLARATIONS SECTION ========== */
%{
#include <stdio.h>
#include <stdlib.h>
%}
%token INT
%left PLUS MINUS
%left MULT DIV
%left UMINUS
%left LPAREN RPAREN
/* ========================================== */
/* ============ GRAMMAR SECTION ============= */
%%
ResultantExpression: E{
printf("Result = %d\n", $$);
return 0;
};
E: E PLUS T {$$ = $1 + $3;}
| E MINUS T {$$ = $1 - $3;}
| MINUS E %prec UMINUS {$$ = -$2;}
| T {$$ = $1;}
;
T: T MULT F {$$ = $1 * $3;}
| T DIV F {if ($3 == 0) {yyerror();} else {$$ = $1 / $3;}}
| F {$$ = $1;}
;
F: INT {$$ = $1;}
| LPAREN E RPAREN {$$ = ($2);}
;
%%
/* ========================================== */
/* ============ USER CODE SECTION =========== */
int main() {
printf("Enter the expression:\n");
yyparse();
return 0;
}
void yyerror() {
printf("The entered expression is invalid!\n");
exit(1);
}
/* ========================================== */
Because you have a return 0; in your ResultExpression action, it will exit successfully after recognizing a ResultExpression, even if there is more input. If you want to check for a correct EOF after that, remove the return 0; and let it continue parsing -- it will give a syntax error message if there's any garbage left in the input, or return successfully if there is the expected newline (which your lexer returns as EOF).
I'm editing my first parser and I'm very new to compiler design. I'm using a hashtable to store tokens. I have created a struct called struct_t in my symboletable.h file.
When I try to create a new entry_t in .y file under %union to be used in lex file. But it gives an error in compile time as:
parser.y:17:2: error: unknown type name 'entry_t' entry_t** entry;
parser.y file :
%{
#include <stdlib.h>
#include <stdio.h>
#include "symboltable.h"
entry_t** symbol_table;
entry_t** constant_table;
double Evaluate (double lhs_value,int assign_type,double rhs_value);
int current_dtype;
int yyerror(char *msg);
%}
%union
{
double dval;
entry_t** entry;
int ival;
}
%token <entry> IDENTIFIER
/* Constants */
%token <dval> DEC_CONSTANT HEX_CONSTANT
%token STRING
/* Logical and Relational operators */
%token LOGICAL_AND LOGICAL_OR LS_EQ GR_EQ EQ NOT_EQ
/* Short hand assignment operators */
%token MUL_ASSIGN DIV_ASSIGN MOD_ASSIGN ADD_ASSIGN SUB_ASSIGN
%token LEFT_ASSIGN RIGHT_ASSIGN AND_ASSIGN XOR_ASSIGN OR_ASSIGN
%token INCREMENT DECREMENT
/* Data types */
%token SHORT INT LONG LONG_LONG SIGNED UNSIGNED CONST
/* Keywords */
%token IF FOR WHILE CONTINUE BREAK RETURN
%type <dval> expression
%type <dval> sub_expr
%type <dval> constant
%type <dval> unary_expr
%type <dval> arithmetic_expr
%type <dval> assignment_expr
%type <entry> lhs
%type <ival> assign_op
%start starter
%left ','
%right '='
%left LOGICAL_OR
%left LOGICAL_AND
%left EQ NOT_EQ
%left '<' '>' LS_EQ GR_EQ
%left '+' '-'
%left '*' '/' '%'
%right '!'
%nonassoc UMINUS
%nonassoc LOWER_THAN_ELSE
%nonassoc ELSE
%%
/* Program is made up of multiple builder blocks. */
starter: starter builder
|builder;
/* Each builder block is either a function or a declaration */
builder: function|
declaration;
/* This is how a function looks like */
function: type IDENTIFIER '(' argument_list ')' compound_stmt;
/* Now we will define a grammar for how types can be specified */
type :data_type pointer
|data_type;
pointer: '*' pointer
|'*'
;
data_type :sign_specifier type_specifier
|type_specifier
;
sign_specifier :SIGNED
|UNSIGNED
;
type_specifier :INT {current_dtype = INT;}
|SHORT INT {current_dtype = SHORT;}
|SHORT {current_dtype = SHORT;}
|LONG {current_dtype = LONG;}
|LONG INT {current_dtype = LONG;}
|LONG_LONG {current_dtype = LONG_LONG;}
|LONG_LONG INT {current_dtype = LONG_LONG;}
;
/* grammar rules for argument list */
/* argument list can be empty */
argument_list :arguments
|
;
/* arguments are comma separated TYPE ID pairs */
arguments :arguments ',' arg
|arg
;
/* Each arg is a TYPE ID pair */
arg :type IDENTIFIER
;
/* Generic statement. Can be compound or a single statement */
stmt:compound_stmt
|single_stmt
;
/* The function body is covered in braces and has multiple statements. */
compound_stmt :'{' statements '}'
;
statements:statements stmt
|
;
/* Grammar for what constitutes every individual statement */
single_stmt :if_block
|for_block
|while_block
|declaration
|function_call ';'
|RETURN ';'
|CONTINUE ';'
|BREAK ';'
|RETURN sub_expr ';'
;
for_block:FOR '(' expression_stmt expression_stmt ')' stmt
|FOR '(' expression_stmt expression_stmt expression ')' stmt
;
if_block:IF '(' expression ')' stmt %prec LOWER_THAN_ELSE
|IF '(' expression ')' stmt ELSE stmt
;
while_block: WHILE '(' expression ')' stmt
;
declaration:type declaration_list ';'
|declaration_list ';'
| unary_expr ';'
declaration_list: declaration_list ',' sub_decl
|sub_decl;
sub_decl: assignment_expr
|IDENTIFIER {$1 -> data_type = current_dtype;}
|array_index
/*|struct_block ';'*/
;
/* This is because we can have empty expession statements inside for loops */
expression_stmt:expression ';'
|';'
;
expression:
expression ',' sub_expr {$$ = $1,$3;}
|sub_expr {$$ = $1;}
;
sub_expr:
sub_expr '>' sub_expr {$$ = ($1 > $3);}
|sub_expr '<' sub_expr {$$ = ($1 < $3);}
|sub_expr EQ sub_expr {$$ = ($1 == $3);}
|sub_expr NOT_EQ sub_expr {$$ = ($1 != $3);}
|sub_expr LS_EQ sub_expr {$$ = ($1 <= $3);}
|sub_expr GR_EQ sub_expr {$$ = ($1 >= $3);}
|sub_expr LOGICAL_AND sub_expr {$$ = ($1 && $3);}
|sub_expr LOGICAL_OR sub_expr {$$ = ($1 || $3);}
|'!' sub_expr {$$ = (!$2);}
|arithmetic_expr {$$ = $1;}
|assignment_expr {$$ = $1;}
|unary_expr {$$ = $1;}
/* |IDENTIFIER {$$ = $1->value;}
|constant {$$ = $1;} */
//|array_index
;
assignment_expr :lhs assign_op arithmetic_expr {$$ = $1->value = Evaluate($1->value,$2,$3);}
|lhs assign_op array_index {$$ = 0;}
|lhs assign_op function_call {$$ = 0;}
|lhs assign_op unary_expr {$$ = $1->value = Evaluate($1->value,$2,$3);}
|unary_expr assign_op unary_expr {$$ = 0;}
;
unary_expr: lhs INCREMENT {$$ = $1->value = ($1->value)++;}
|lhs DECREMENT {$$ = $1->value = ($1->value)--;}
|DECREMENT lhs {$$ = $2->value = --($2->value);}
|INCREMENT lhs {$$ = $2->value = ++($2->value);}
lhs:IDENTIFIER {$$ = $1; if(! $1->data_type) $1->data_type = current_dtype;}
//|array_index
;
assign_op:'=' {$$ = '=';}
|ADD_ASSIGN {$$ = ADD_ASSIGN;}
|SUB_ASSIGN {$$ = SUB_ASSIGN;}
|MUL_ASSIGN {$$ = MUL_ASSIGN;}
|DIV_ASSIGN {$$ = DIV_ASSIGN;}
|MOD_ASSIGN {$$ = MOD_ASSIGN;}
;
arithmetic_expr: arithmetic_expr '+' arithmetic_expr {$$ = $1 + $3;}
|arithmetic_expr '-' arithmetic_expr {$$ = $1 - $3;}
|arithmetic_expr '*' arithmetic_expr {$$ = $1 * $3;}
|arithmetic_expr '/' arithmetic_expr {$$ = ($3 == 0) ? yyerror("Divide by 0!") : ($1 / $3);}
|arithmetic_expr '%' arithmetic_expr {$$ = (int)$1 % (int)$3;}
|'(' arithmetic_expr ')' {$$ = $2;}
|'-' arithmetic_expr %prec UMINUS {$$ = -$2;}
|IDENTIFIER {$$ = $1 -> value;}
|constant {$$ = $1;}
;
constant: DEC_CONSTANT {$$ = $1;}
|HEX_CONSTANT {$$ = $1;}
;
array_index: IDENTIFIER '[' sub_expr ']'
function_call: IDENTIFIER '(' parameter_list ')'
|IDENTIFIER '(' ')'
;
parameter_list:
parameter_list ',' parameter
|parameter
;
parameter: sub_expr
|STRING
;
%%
#include "lex.yy.c"
#include <ctype.h>
double Evaluate (double lhs_value,int assign_type,double rhs_value)
{
switch(assign_type)
{
case '=': return rhs_value;
case ADD_ASSIGN: return (lhs_value + rhs_value);
case SUB_ASSIGN: return (lhs_value - rhs_value);
case MUL_ASSIGN: return (lhs_value * rhs_value);
case DIV_ASSIGN: return (lhs_value / rhs_value);
case MOD_ASSIGN: return ((int)lhs_value % (int)rhs_value);
}
}
int main(int argc, char *argv[])
{
symbol_table = create_table();
constant_table = create_table();
yyin = fopen(argv[1], "r");
if(!yyparse())
{
printf("\nParsing complete\n");
}
else
{
printf("\nParsing failed\n");
}
printf("\n\tSymbol table");
display(symbol_table);
fclose(yyin);
return 0;
}
int yyerror(char *msg)
{
printf("Line no: %d Error message: %s Token: %s\n", yylineno, msg, yytext);
}
lexl.l file
%{
#include <stdlib.h>
#include <stdio.h>
#include <limits.h>
#include "y.tab.h"
int cmnt_strt = 0;
%}
%option yylineno
letter [a-zA-Z]
digit [0-9]
ws [ \t\r\f\v]+
identifier (_|{letter})({letter}|{digit}|_){0,31}
hex [0-9a-f]
/* Exclusive states */
%x CMNT
/*%x PREPROC*/
%%
/* Keywords*/
"int" {return INT;}
"long" {return LONG;}
"long long" {return LONG_LONG;}
"short" {return SHORT;}
"signed" {return SIGNED;}
"unsigned" {return UNSIGNED;}
"for" {return FOR;}
"while" {return WHILE;}
"break" {return BREAK;}
"continue" {return CONTINUE;}
"if" {return IF;}
"else" {return ELSE;}
"return" {return RETURN;}
{identifier} {yylval.entry = insert(symbol_table, yytext, INT_MAX); return IDENTIFIER;}
{ws} ;
[+\-]?[0][x|X]{hex}+[lLuU]? { yylval.dval = (int)strtol(yytext, NULL, 16); return HEX_CONSTANT;}
[+\-]?{digit}+[lLuU]? {yylval.dval = atoi(yytext); return DEC_CONSTANT;}
"/*" {cmnt_strt = yylineno; BEGIN CMNT;}
<CMNT>.|{ws} ;
<CMNT>\n {yylineno++;}
<CMNT>"*/" {BEGIN INITIAL;}
<CMNT>"/*" {printf("Line %3d: Nested comments are not valid!\n",yylineno);}
<CMNT><<EOF>> {printf("Line %3d: Unterminated comment\n", cmnt_strt); yyterminate();}
/*^"#include" {BEGIN PREPROC;}*/
/*<PREPROC>"<"[^<>\n]+">" {return HEADER_FILE;}*/
/*<PREPROC>{ws} ;*/
/*<PREPROC>\"[^"\n]+\" {return HEADER_FILE;}*/
/*<PREPROC>\n {yylineno++; BEGIN INITIAL;}*/
/*<PREPROC>. {printf("Line %3d: Illegal header file format \n",yylineno);}*/
"//".* ;
\"[^\"\n]*\" {
if(yytext[yyleng-2]=='\\') /* check if it was an escaped quote */
{
yyless(yyleng-1); /* push the quote back if it was escaped */
yymore();
}
else{
insert( constant_table, yytext, INT_MAX);
return STRING;
}
}
\"[^\"\n]*$ {printf("Line %3d: Unterminated string %s\n",yylineno,yytext);}
{digit}+({letter}|_)+ {printf("Line %3d: Illegal identifier name %s\n",yylineno,yytext);}
\n {yylineno++;}
"--" {return DECREMENT;}
"++" {return INCREMENT;}
/* "->" {return PTR_SELECT;} */
"+=" {return ADD_ASSIGN;}
"-=" {return SUB_ASSIGN;}
"*=" {return MUL_ASSIGN;}
"/=" {return DIV_ASSIGN;}
"%=" {return MOD_ASSIGN;}
"&&" {return LOGICAL_AND;}
"||" {return LOGICAL_OR;}
"<=" {return LS_EQ;}
">=" {return GR_EQ;}
"==" {return EQ;}
"!=" {return NOT_EQ;}
. {return yytext[0];}
%%
/*
int main()
{
yyin=fopen("test2.c","r");
constant_table=create_table();
symbol_table = create_table();
yylex();
printf("\n\tSymbol table");
display(symbol_table);
printf("\n\tConstants Table");
display(constant_table);
printf("NOTE: Please refer tokens.h for token meanings\n");
} */
symboltable.h file
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include <limits.h>
#include <string.h>
#define HASH_TABLE_SIZE 100
/* struct to hold each entry */
struct entry_s
{
char* lexeme;
double value;
int data_type;
struct entry_s* successor;
};
typedef struct entry_s entry_t;
/* Create a new hash_table. */
entry_t** create_table()
{
entry_t** hash_table_ptr = NULL; // declare a pointer
/* Allocate memory for a hashtable array of size HASH_TABLE_SIZE */
if( ( hash_table_ptr = malloc( sizeof( entry_t* ) * HASH_TABLE_SIZE ) ) == NULL )
return NULL;
int i;
// Intitialise all entries as NULL
for( i = 0; i < HASH_TABLE_SIZE; i++ )
{
hash_table_ptr[i] = NULL;
}
return hash_table_ptr;
}
/* Generate hash from a string. Then generate an index in [0, HASH_TABLE_SIZE) */
uint32_t hash( char *lexeme )
{
size_t i;
uint32_t hash;
/* Apply jenkin's hash function
* https://en.wikipedia.org/wiki/Jenkins_hash_function#one-at-a-time
*/
for ( hash = i = 0; i < strlen(lexeme); ++i ) {
hash += lexeme[i];
hash += ( hash << 10 );
hash ^= ( hash >> 6 );
}
hash += ( hash << 3 );
hash ^= ( hash >> 11 );
hash += ( hash << 15 );
return hash % HASH_TABLE_SIZE; // return an index in [0, HASH_TABLE_SIZE)
}
/* Create an entry for a lexeme, token pair. This will be called from the insert function */
entry_t *create_entry( char *lexeme, int value )
{
entry_t *newentry;
/* Allocate space for newentry */
if( ( newentry = malloc( sizeof( entry_t ) ) ) == NULL ) {
return NULL;
}
/* Copy lexeme to newentry location using strdup (string-duplicate). Return NULL if it fails */
if( ( newentry->lexeme = strdup( lexeme ) ) == NULL ) {
return NULL;
}
newentry->value = value;
newentry->successor = NULL;
return newentry;
}
/* Search for an entry given a lexeme. Return a pointer to the entry of the lexeme exists, else return NULL */
entry_t* search( entry_t** hash_table_ptr, char* lexeme )
{
uint32_t idx = 0;
entry_t* myentry;
// get the index of this lexeme as per the hash function
idx = hash( lexeme );
/* Traverse the linked list at this idx and see if lexeme exists */
myentry = hash_table_ptr[idx];
while( myentry != NULL && strcmp( lexeme, myentry->lexeme ) != 0 )
{
myentry = myentry->successor;
}
if(myentry == NULL) // lexeme is not found
return NULL;
else // lexeme found
return myentry;
}
/* Insert an entry into a hash table. */
entry_t* insert( entry_t** hash_table_ptr, char* lexeme, int value )
{
entry_t* finder = search( hash_table_ptr, lexeme );
if( finder != NULL) // If lexeme already exists, don't insert, return
return finder ;
uint32_t idx;
entry_t* newentry = NULL;
entry_t* head = NULL;
idx = hash( lexeme ); // Get the index for this lexeme based on the hash function
newentry = create_entry( lexeme, value ); // Create an entry using the <lexeme, token> pair
if(newentry == NULL) // In case there was some error while executing create_entry()
{
printf("Insert failed. New entry could not be created.");
exit(1);
}
head = hash_table_ptr[idx]; // get the head entry at this index
if(head == NULL) // This is the first lexeme that matches this hash index
{
hash_table_ptr[idx] = newentry;
}
else // if not, add this entry to the head
{
newentry->successor = hash_table_ptr[idx];
hash_table_ptr[idx] = newentry;
}
return hash_table_ptr[idx];
}
// Traverse the hash table and print all the entries
void display(entry_t** hash_table_ptr)
{
int i;
entry_t* traverser;
printf("\n====================================================\n");
printf(" %-20s %-20s %-20s\n","lexeme","value","data-type");
printf("====================================================\n");
for( i=0; i < HASH_TABLE_SIZE; i++)
{
traverser = hash_table_ptr[i];
while( traverser != NULL)
{
printf(" %-20s %-20d %-20d \n", traverser->lexeme, (int)traverser->value, traverser->data_type);
traverser = traverser->successor;
}
}
printf("====================================================\n");
}
I cant figure out why unknown file type error is given. If you can please point me in the right direction.
Assuming you are the same Shehan who yesterday asked this question with remarkably similar code, what I said then still applies:
If this is the first time you've attempted to write a C application with more than one source file, you should probably take a few minutes to review how linking multiple files works in C. That will save you a lot of frustration later.
This is precisely the sort of frustration I was referring to.
The error you are receiving comes from attempting to compile lex.yy.c. That file, which is generated from lexl.l, does not #include "symboltable.h", but it does #include "y.tab.h". In y.tab.h, entry_t is used in the declaration of the union semantic type, but since symboltable.h has not been included, entry_t has not been defined.
But just adding #include "symboltable.h" won't work, so please don't do it.
symboltable.h is not a correct header file, as has been mentioned in a comment by #JonathanLeffler. Header files must not contain function definitions, only declarations. Furthermore, symboltable.h does not have inclusion guards, so nothing stops it from being included twice, resulting in duplicate definition errors.
But the way your files are set up, you shouldn't be compiling lex.yy.c in the first place. Your parser.y file includes the line
#include "lex.yy.c"
which, as might be expected, includes the entire text of lex.yy.c in the source being compiled when you compile y.tab.c. I don't believe you thought this trick up yourself; I think you copied it from some tutorial written by someone who was too lazy to attempt to explain how to set up a project with multiple sources. Although it is possible to make things work for simple parsers, it's not going to serve you well in the future, and you should not start your learning about parsers by learning bad habits.
So I say once again: please start by learning how to create a C project with multiple source and header files. Otherwise, your attempt to learn how to use bison and flex will be much harder and more frustrating than necessary.
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");
}
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;}
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.