I have the following code below and I am receiving the following error
parser.y:111.47-48: error: $$ for the midrule at $5 of ‘statement’ has no declared type
111 | REDUCE operator reductions ENDREDUCE {$$ = $3;} ';'|
I know it's generated because I didn't declare a type for something in the statement, I need help understanding line 111. Also the REAL_LITERAL is a float, that I should add a float to the union and create token like this %token <f_value>REAL_LITERAL.
include <iostream>
#include <string>
#include <vector>
#include <map>
using namespace std;
#include "math.h"
#include "values.h"
#include "listing.h"
#include "symbols.h"
int yylex();
void yyerror(const char* message);
Symbols<int> symbols;
int result;
double *params;
%}
%define parse.error verbose
%union
{
CharPtr iden;
Operators oper;
int value;
}
%token <iden> IDENTIFIER
%token <value>INT_LITERAL REAL_LITERAL BOOL_LITERAL CASE TRUE FALSE
%token ARROW
%token <oper> ADDOP MULOP RELOP OROP NOTOP REMOP EXPOP
%token ANDOP
%token BEGIN_ BOOLEAN END ENDREDUCE FUNCTION INTEGER IS REDUCE RETURNS
%token THEN WHEN
%token ELSE ENDCASE ENDIF IF OTHERS REAL
%type <value> body statement_ statement reductions expression binary relation term
factor primary
%type <oper> operator
%left OROP
%left ANDOP
%left RELOP
%left ADDOP
%left MULOP REMOP
%right EXPOP
%left NOTOP
%%
function:
function_header optional_variable body {result = $3;} ;
function_header:
FUNCTION IDENTIFIER parameters RETURNS type ';' |
FUNCTION IDENTIFIER RETURNS type ';' |
FUNCTION IDENTIFIER optional_parameters RETURNS type ';' |
error ';' ;
optional_variable:
optional_variable variable |
error ';' ;
;
variable:
IDENTIFIER ':' type IS statement_ {symbols.insert($1, $5);} ;
variables:
variable variables |
;
type:
INTEGER |
BOOLEAN ;
optional_parameters:
parameters |
;
parameters:
parameter ',' parameters |
parameter ;
parameter:
IDENTIFIER ':' type ;
type:
INTEGER |
REAL |
BOOLEAN ;
body:
BEGIN_ statement_ END ';' {$$ = $2;} ;
statement_:
statement ';' |
error ';' {$$ = 0;} ;
statement:
expression |
REDUCE operator reductions ENDREDUCE {$$ = $3;} ';'|
IF expression THEN statement_ ELSE statement_ ENDIF
{
if ($2 == true) {
$$ = $4;
}
else {
$$ = $6;
}
}';' /*|
CASE expression IS cases OTHERS ARROW statement_ ENDCASE
{$$ = $<value>4 == $1 ? $4 : $7;} ;
cases:
cases case
{$$ = $<value>1 == $1 ? $1 : $2;} |
%empty {$$ = NAN;};
case:
case WHEN INT_LITERAL ARROW statement_ |
;
*/
operator:
ADDOP |
RELOP |
EXPOP |
MULOP ;
reductions:
reductions statement_ {$$ = evaluateReduction($<oper>0, $1, $2);} |
{$$ = $<oper>0 == ADD ? 0 : 1;} ;
expression:
expression OROP binary {$$ = $1 || $3;} |
binary;
binary:
binary ANDOP relation {$$ = $1 && $3;} |
relation ;
relation:
relation RELOP term {$$ = evaluateRelational($1, $2, $3);} |
term ;
term:
term ADDOP factor {$$ = evaluateArithmetic($1, $2, $3);} |
factor ;
factor:
factor MULOP primary {$$ = evaluateArithmetic($1, $2, $3);} |
primary ;
primary:
'(' expression ')' {$$ = $2;} |
INT_LITERAL |
IDENTIFIER {if (!symbols.find($1, $$)) appendError(UNDECLARED, $1);} ;
%%
void yyerror(const char* message)
{
appendError(SYNTAX, message);
}
int main(int argc, char *argv[])
{
firstLine();
yyparse();
if (lastLine() == 0)
cout << "Result = " << result << endl;
return 0;
}
The basic problem is that in-rule actions do not get a default type in bison (unlike yacc). So in your action
REDUCE operator reductions ENDREDUCE {$$ = $3;} ';'
there's no %type for $$ so you need to specify it explicitly -- perhaps something like { $<value>$ = $3; }. That's equivalent to what yacc would do here, as it gives in-rule actions the same type as the lhs, even though there's not really anything connecting them.
The bigger issue is that this really makes no sense -- an in-rule action like this does NOT set the value for the symbol being reduced. That can only happen in the end-of-rule action. So this is just copying a value to a temp and then throwing it away, never doing anything with it. The implicit end-rule action just does { $$ = $1; } which makes no sense as statement and REDUCE have different types.
Related
I am learning Flex/Bison and we are currently on the part about semantics, previously have dealt with lexical and syntax errors. I have googled extensively and haven't been able to find a solution to my error. I am having trouble trying to understand why I need to declare '$4' when I thought it to be automatically done.
When I try to makefile I get this error:
flex scanner.l
mv lex.yy.c scanner.c
bison -d -v parser.y
paser.y:114.71-72: error: $4 of 'case' has no declared type
114 | case WHEN INT_LITERAL ARROW statement_ {case_statements.push_back($4);};
Here is the pseudo code I am trying to follow:
statement:
CASE expression IS cases OTHERS ARROW statement_ ENDCASE
{If the attribute of cases, is a number then
return it as the attribute otherwise return the
attribute of the OTHERS clause};
cases:
cases case
{if the attribute of cases is a number then return it as the
attribute otherwise return the attribute of case} |
%empty
{Set the attribute to the sentinel NAN} ;
case:
WHEN INT_LITERAL ARROW statement_
{$-2 contains the value of the expression after CASE.
It must be compared with the attribute of INT_LITERAL.
If they match the attribute of this production
should become the attribute of statement_
If they don't match, the attribute should be set to the
sentinel value NAN} ;
parser.y:
%{
#include <iostream>
#include <string>
#include <vector>
#include <map>
#include <math.h>
using namespace std;
#include "values.h"
#include "listing.h"
#include "symbols.h"
#include <stdlib.h>
#include <stdio.h>
int yylex();
void yyerror(const char* message);
Symbols<int> symbols;
//----------------------------------------------------------------------------------------------
vector<int> case_statements; //<<<<<<<<<<<<Is this wrong?
//---------------------------------------------------------------------------------------------
int result;
double *params;
%}
%define parse.error verbose
%union
{
CharPtr iden;
Operators oper;
int value;
}
%token <iden> IDENTIFIER
%token <value> INT_LITERAL REAL_LITERAL BOOL_LITERAL CASE TRUE FALSE
%token <oper> ADDOP MULOP RELOP OROP NOTOP REMOP EXPOP
%token ANDOP
%token BEGIN_ BOOLEAN END ENDREDUCE FUNCTION INTEGER IS REDUCE RETURNS
%token THEN WHEN ARROW
%token ELSE ENDCASE ENDIF IF OTHERS REAL
%type <value> body statement_ statement reductions expression relation term
factor case cases exponent unary primary
%type <oper> operator
%%
function:
function_header optional_variable body {result = $3;} ;
function_header:
FUNCTION IDENTIFIER optional_parameter RETURNS type ';' |
FUNCTION IDENTIFIER RETURNS type ';' |
error ';' ;
optional_variable:
optional_variable variable |
error ';' |
%empty ;
variable:
IDENTIFIER ':' type IS statement_ ;
parameters:
parameter optional_parameter;
optional_parameter:
optional_parameter ',' parameter |
%empty ;
parameter:
IDENTIFIER ':' type {symbols.insert($1, params[0]);} ;
type:
INTEGER |
REAL |
BOOLEAN ;
body:
BEGIN_ statement_ END ';' {$$ = $2;} ;
statement_:
statement ';' |
error ';' {$$ = 0;} ;
statement:
expression |
REDUCE operator reductions ENDREDUCE {$$ = $3;} |
IF expression THEN statement_ ELSE statement_ ENDIF {
if ($2 == true) {
$$ = $4;
}
else {
$$ = $6;
}
} ; |
CASE expression IS cases OTHERS ARROW statement_ ENDCASE {$$ = $<value>4 == $1 ? $4 : $7;} ;
cases:
cases case {$$ = $<value>1 == $1 ? $1 : $2;} |
%empty {$$ = NAN;} ;
//-----------------------------------------------------------------------------------------------------------
case:
case WHEN INT_LITERAL ARROW statement_ {case_statements.push_back($4);} ; //<<<<<<<<<How do I declare $4?
//-------------------------------------------------------------------------------------------------------------
operator:
ADDOP |
RELOP |
EXPOP |
MULOP ;
reductions:
reductions statement_ {$$ = evaluateReduction($<oper>0, $1, $2);} |
{$$ = $<oper>0 == ADD ? 0 : 1;} %empty ;
expression:
expression OROP relation {$$ = $1 || $3;} |
relation ;
expression:
expression ANDOP relation {$$ = $1 && $3;} |
relation ;
relation:
relation RELOP term {$$ = evaluateRelational($1, $2, $3);} |
term ;
term:
term ADDOP factor {$$ = evaluateArithmetic($1, $2, $3);} |
factor ;
factor:
factor MULOP primary {$$ = evaluateArithmetic($1, $2, $3);} |
factor REMOP exponent {$$ = $1 % $3;} |
exponent ;
exponent:
unary |
unary EXPOP exponent {$$ = pow($1, $3);} ;
unary:
NOTOP primary {$$ = $2;} |
primary;
primary:
'(' expression ')' {$$ = $2;} |
INT_LITERAL |
REAL_LITERAL |
BOOL_LITERAL |
IDENTIFIER {if (!symbols.find($1, $$)) appendError(UNDECLARED, $1);} ;
%%
void yyerror(const char* message)
{
appendError(SYNTAX, message);
}
int main(int argc, char *argv[])
{
params = new double[argc - 1]
for (int i = 1; i < argc; i++)
{
params[i - 1] = atof(argv[i]);
}
firstLine();
yyparse();
if (lastLine() == 0)
cout << "Result = " << result << endl;
return 0;
}
You need to assign a value/type to statement_:
statement_:
statement ';' {$$ = $1;}|
error ';' {$$ = MISMATCH;} ;
Here's my simple project source code:
bison.y
flex.l
flex_bison.cpp
flex.l:
%option noyywrap
%{
#include <string>
#include <cstring>
#include "bison.tab.hpp"
#define FT_SAVE_TOKEN yylval.literal = strndup(yytext, yyleng)
#define FT_TOKEN(t) (yylval.token = t)
%}
%%
"True" return FT_TRUE;
"False" return FT_FALSE;
"let" return FT_LET;
"Nil" return FT_NIL;
"if" return FT_IF;
"elseif" return FT_ELSEIF;
"else" return FT_ELSE;
"switch" return FT_SWITCH;
"case" return FT_CASE;
"otherwise" return FT_OTHERWISE;
"for" return FT_FOR;
"while" return FT_WHILE;
"break" return FT_BREAK;
"continue" return FT_CONTINUE;
"func" return FT_FUNC;
"class" return FT_CLASS;
"type" return FT_TYPE;
"isinstance" return FT_ISINSTANCE;
"import" return FT_IMPORT;
"return" return FT_RETURN;
"void" return FT_VOID;
"and" return FT_LOGICALAND;
"or" return FT_LOGICALOR;
"not" return FT_LOGICALNOT;
"int" return FT_INTEGER_KEYWORD;
"uint" return FT_UNSIGNED_INTEGER_KEYWORD;
"double" return FT_DOUBLE_KEYWORD;
[ \t\v\n\f\r] ;
[a-zA-Z_][a-zA-Z0-9_]* FT_SAVE_TOKEN; return FT_IDENTIFIER;
[0-9]+"."[0-9]+([Ee][+-]?[0-9]+)? FT_SAVE_TOKEN; return FT_DOUBLE;
[0-9]+([Ee][+-]?[0-9]+)? FT_SAVE_TOKEN; return FT_INTEGER;
\"(\\.|[^\\"])*\" FT_SAVE_TOKEN; return FT_STRING;
"+" return FT_TOKEN(FT_ADD);
"-" return FT_TOKEN(FT_SUB);
"*" return FT_TOKEN(FT_MUL);
"/" return FT_TOKEN(FT_DIV);
"%" return FT_TOKEN(FT_MOD);
"!" return FT_TOKEN(FT_BITNOT);
"&" return FT_TOKEN(FT_BITAND);
"|" return FT_TOKEN(FT_BITOR);
"~" return FT_TOKEN(FT_BITCOMPLEMENT);
"^" return FT_TOKEN(FT_BITXOR);
"=" return FT_TOKEN(FT_ASSIGN);
"+=" return FT_TOKEN(FT_ADDASSIGN);
"-=" return FT_TOKEN(FT_SUBASSIGN);
"*=" return FT_TOKEN(FT_MULASSIGN);
"/=" return FT_TOKEN(FT_DIVASSIGN);
"%=" return FT_TOKEN(FT_MODASSIGN);
"==" return FT_TOKEN(FT_EQ);
"!=" return FT_TOKEN(FT_NEQ);
"<" return FT_TOKEN(FT_LT);
"<=" return FT_TOKEN(FT_LE);
">" return FT_TOKEN(FT_GT);
">=" return FT_TOKEN(FT_GE);
"(" return FT_TOKEN(FT_LPAREN);
")" return FT_TOKEN(FT_RPAREN);
"[" return FT_TOKEN(FT_LBRACKET);
"]" return FT_TOKEN(FT_RBRACKET);
"{" return FT_TOKEN(FT_LBRACE);
"}" return FT_TOKEN(FT_RBRACE);
"," return FT_TOKEN(FT_COMMA);
";" return FT_TOKEN(FT_SEMI);
"?" return FT_TOKEN(FT_QUESTION);
":" return FT_TOKEN(FT_COLON);
"." return FT_TOKEN(FT_DOT);
. printf("Unknown token!n"); yyterminate();
%%
bison.y:
%{
#include <string>
#include <cstring>
#include <cstdio>
extern FILE *yyin;
extern int yylex();
void yyerror(const char *s) { printf("yyerror: %s\n", s); }
%}
/* Represents the many different ways we can access our data */
%union {
char *literal;
int token;
}
/* union.token: eof, keyword */
%token <token> FT_EOF
%token <token> FT_TRUE FT_FALSE FT_LET FT_NIL FT_IF FT_ELSEIF FT_ELSE FT_FOR FT_WHILE FT_BREAK FT_CONTINUE FT_SWITCH FT_CASE FT_OTHERWISE
%token <token> FT_FUNC FT_CLASS FT_TYPE FT_ISINSTANCE FT_IMPORT FT_RETURN FT_VOID FT_LOGICALAND FT_LOGICALOR FT_LOGICALNOT
%token <token> FT_INTEGER_KEYWORD FT_UNSIGNED_INTEGER_KEYWORD FT_DOUBLE_KEYWORD
/* union.literal, identifier, integer, double number, string */
%token <literal> FT_IDENTIFIER FT_INTEGER FT_DOUBLE FT_STRING
/* union.token: operator, comparator, punctuation */
%token <token> FT_ADD FT_SUB FT_MUL FT_DIV FT_MOD FT_BITNOT FT_BITAND FT_BITOR FT_BITCOMPLEMENT FT_BITXOR
%token <token> FT_ASSIGN FT_ADDASSIGN FT_SUBASSIGN FT_MULASSIGN FT_DIVASSIGN FT_MODASSIGN FT_EQ FT_NEQ FT_LT FT_LE FT_GT FT_GE
%token <token> FT_LPAREN FT_RPAREN FT_LBRACKET FT_RBRACKET FT_LBRACE FT_RBRACE FT_COMMA FT_SEMI FT_QUESTION FT_COLON FT_DOT
/*
%type <ident> ident
%type <expr> numeric expr
%type <varvec> func_decl_args
%type <exprvec> call_args
%type <block> program stmts block
%type <stmt> stmt var_decl func_decl
%type <token> comparison
*/
/* operator/comparator precedence */
%left FT_DOT FT_LPAREN FT_RPAREN FT_LBRACKET FT_RBRACKET
%left FT_MUL FT_DIV FT_MOD
%left FT_ADD FT_SUB
%left FT_LT FT_LE FT_GT FT_GE FT_EQ FT_NEQ
%left FT_BITNOT FT_BITAND FT_BITOR FT_BITXOR FT_BITCOMPLEMENT
%left FT_LOGICALNOT FT_LOGICALAND FT_LOGICALOR
%left FT_ASSIGN FT_ADDASSIGN FT_SUBASSIGN FT_MULASSIGN FT_DIVASSIGN FT_MODASSIGN
/*
%start program
*/
%%
primary_expression : FT_IDENTIFIER
| FT_INTEGER
| FT_DOUBLE
| FT_STRING
| '(' expression ')'
;
postfix_expression : primary_expression
/*| postfix_expression '[' expression ']'*/
| postfix_expression '(' ')'
| postfix_expression '(' argument_expression_list ')'
/*| postfix_expression '.' IDENTIFIER*/
;
argument_expression_list : assignment_expression
| argument_expression_list ',' assignment_expression
;
unary_expression : postfix_expression
| unary_operator postfix_expression
;
unary_operator : FT_BITAND
| FT_BITOR
| FT_BITNOT
| FT_BITCOMPLEMENT
| FT_BITXOR
| FT_ADD
| FT_SUB
;
/*
cast_expression : unary_expression
| '(' type_name ')' cast_expression
;
*/
multiplicative_expression : unary_expression
| multiplicative_expression FT_MUL unary_expression
| multiplicative_expression FT_DIV unary_expression
| multiplicative_expression FT_MOD unary_expression
;
additive_expression : multiplicative_expression
| additive_expression FT_ADD multiplicative_expression
| additive_expression FT_SUB multiplicative_expression
;
/*
shift_expression : additive_expression
| shift_expression '<<' additive_expression
| shift_expression '>>' additive_expression
;
*/
relational_expression : additive_expression
| relational_expression FT_LT additive_expression
| relational_expression FT_LE additive_expression
| relational_expression FT_GT additive_expression
| relational_expression FT_GE additive_expression
;
equality_expression : relational_expression
| equality_expression FT_EQ relational_expression
| equality_expression FT_NEQ relational_expression
;
/*
bit_and_expression : equality_expression
| bitand_expression '&' equality_expression
;
bit_xor_expression : bit_and_expression
| bit_xor_expression '^' bit_and_expression
;
bit_or_expression : bit_xor_expression
| bit_or_expression '|' bit_xor_expression
;
*/
logical_not_expression : equality_expression
| logical_not_expression FT_LOGICALNOT equality_expression
;
logical_and_expression : logical_not_expression
| logical_and_expression FT_LOGICALAND logical_not_expression
;
logical_or_expression : logical_and_expression
| logical_or_expression FT_LOGICALOR logical_and_expression
;
assignment_expression : logical_or_expression
| unary_expression assignment_operator assignment_expression
;
assignment_operator : FT_ASSIGN
| FT_MULASSIGN
| FT_DIVASSIGN
| FT_MODASSIGN
| FT_ADDASSIGN
| FT_SUBASSIGN
;
constant_expression : logical_or_expression
;
expression : assignment_expression
;
unit : external_declaration
| unit external_declaration
;
external_declaration : function_declaration
| declaration
;
declaration : FT_LET declaration_init_list FT_SEMI
;
declaration_init_list : declaration_init
| declaration_init_list declaration_init
;
declaration_init : FT_IDENTIFIER FT_ASSIGN constant_expression
;
function_declaration : FT_FUNC FT_IDENTIFIER FT_LPAREN function_arg_list FT_RPAREN compound_statement
| FT_FUNC FT_IDENTIFIER FT_LPAREN FT_RPAREN compound_statement
;
function_arg_list : function_arg
| function_arg_list FT_COMMA function_arg
;
function_arg : FT_IDENTIFIER
;
compound_statement : FT_LBRACE FT_RBRACE
| FT_LBRACE statement_list FT_RBRACE
| FT_LBRACE declaration_list FT_RBRACE
;
statement_list : statement
| statement_list statement
;
declaration_list : declaration
| declaration_list declaration
;
statement : compound_statement
| expression_statement
| selection_statement
| iteration_statement
| jump_statement
;
expression_statement : FT_SEMI
| expression FT_SEMI
;
selection_statement : FT_IF FT_LPAREN expression FT_RPAREN statement
| FT_IF FT_LPAREN expression FT_RPAREN statement FT_ELSE statement
| FT_SWITCH FT_LPAREN expression FT_RPAREN statement
;
iteration_statement : FT_WHILE FT_LPAREN expression FT_RPAREN statement
| FT_FOR FT_LPAREN expression_statement expression_statement FT_RPAREN statement
| FT_FOR FT_LPAREN expression_statement expression_statement expression FT_RPAREN statement
;
jump_statement : FT_CONTINUE FT_SEMI
| FT_BREAK FT_SEMI
| FT_RETURN FT_SEMI
| FT_RETURN expression FT_SEMI
;
%%
flex_bison.cpp:
#include "bison.tab.hpp"
#include <cstdio>
int main(int argc, char **argv) {
if (argc <= 1) {
printf("error! filename missing!\n");
return 0;
}
FILE *fp = fopen(argv[1], "r");
yyin = fp;
int t;
while ((t = yylex()) != 0) {
printf("token: %d", t);
if (t == FT_IDENTIFIER || t == FT_INTEGER || t == FT_DOUBLE ||
t == FT_STRING) {
printf("literal: %s\n", yylval.literal);
} else {
printf("\n");
}
}
fclose(fp);
return 0;
}
generate code through commands:
$ flex -o flex.yy.cpp flex.l
$ bison -d -o bison.tab.hpp bison.y
$ g++ -o test.exe bison.tab.cpp flex.yy.cpp flex_bison.cpp
Here's the error message:
use of undeclared identifier 'yyin'
use of undeclared identifier 'yylex`
Do I have to define yyin and yylex before main function with code below?
extern FILE *yyin;
extern int yylex(void);
Even if the quoted code would be added to the output file, you still would get complaints about undefined yylex and yyin. Your code only declares these things, it does not define them. Neither yacc nor bison define these for you, you have to provide those functions yourself (you can use for example lex or flex to generate them). Take a look at bison documentation. The RPN example has a short example for a yylex function.
Edit after question was edited: as per the documentation of bison, the header generated from the -d option
Pretend that ‘%defines’ was specified, i.e., write an extra output
file containing macro definitions for the token type names defined
in the grammar, as well as a few other declarations.
This does not include the things you specified in the prologue, in particular not the declaration of yyin and yylex. If you need these declarations in multiple files then you may want to declare them in a separate header file and include that header file from bison.y and all other files that require that declaration (like flex_bison.cpp).
I'm trying to pinpoint these error messages, but even when I move code around the error shows up at the same line.
Also why am I still getting "calc.y: In function 'int yyparse()':" and "calc.l: In function 'int yylex()':" even though I have it in my calc.y.
Error Messages
flex calc.l
bison -d calc.y
g++ -o calc calc.tab.c lex.yy.c
calc.y: In function 'int yyparse()':
calc.y:35: error: cannot convert 'double' to 'std::string*' in assignment
calc.tab.c:1490: warning: deprecated conversion from string constant to 'char*'
calc.tab.c:1633: warning: deprecated conversion from string constant to 'char*'
calc.l: In function 'int yylex()':
calc.l:17: error: 'yyerror' was not declared in this scope
calc.l
%{
#include <cstdlib>
#include <string>
#include <string.h>
#include "calc.tab.h"
%}
%%
"print" {return print;}
"exit" {return exit_command;}
[0-9]+ {yylval.num = atof(yytext); return number;}
[_[:alpha:]][_[:alnum:]]* {yylval.index = new std::string(yytext); return identifier; }
[ \t] ;
[\n] {return(CR);}
[-()+*/;=] {return yytext[0];}
. {ECHO; yyerror ("unexpected character");}
%%
int yywrap (void) {return 1;}
calc.y
%{
void yyerror (char *s);
int yylex(void);
#include <stdio.h> /* C declarations used in actions */
#include <stdlib.h>
#include <string>
#include <string.h>
#include <map>
static std::map<std::string, double> vars;
%}
%union {double num; std::string *index;} /* Yacc definitions */
%start line
%token print
%token CR
%token exit_command
%token <num> number
%token <index> identifier
%type <num> line exp term
%type <index> assignment
%%
/* descriptions of expected inputs corresponding actions */
line : assignment CR {;}
| exit_command CR {exit(EXIT_SUCCESS);}
| print exp CR {printf("Printing %f\n", $2);}
| line assignment CR {;}
| line print exp CR {printf("Printing %f\n", $3);}
| line exit_command CR {exit(EXIT_SUCCESS);}
;
assignment : identifier '=' exp {$$ = vars[*$1] = $3; delete $1; }
;
exp : term {$$ = $1;}
| exp '+' term {$$ = $1 + $3;}
| exp '-' term {$$ = $1 - $3;}
| exp '*' term {$$ = $1 * $3;}
| exp '/' term {$$ = $1 / $3;}
| '(' exp ')' {$$ = $2;}
;
term : number {$$ = $1;}
| identifier {$$ = vars[*$1]; delete $1; }
;
%%
int main (void) {
return yyparse();
}
extern int yyparse();
void yyerror (char *s)
{
extern int yylineno; // defined and maintained in lex
extern char *yytext; // defined and maintained in lex
fprintf (stderr, "%s\n", s);
}
Here's one place where the double to std::string* error will be produced:
assignment : identifier '=' exp {$$ = vars[*$1] = $3; delete $1; }
The type of assignment is <index>, which is std::string*. The type of exp is <num>, which is double. So in the action above, $$ is a std::string*, and $3 is a double (as is vars[*$1]).
My best guess is that you didn't intend the semantic type of assignment to be <index>.
As for the fact that yyerror isn't defined in calc.l, that is clearly true. yyerror is defined in calc.y, and the declaration is also in calc.y. The C programs produced by (f)lex and yacc/bison are different programs, and they are compiled independently, so the fact that yyerror is declared in the yacc/bison-generated program does not make it's declaration visible to the (f)lex-generated program. If you need to use it from a (f)lex action, you'll need to declare it in both files.
These warnings:
calc.tab.c:1490: warning: deprecated conversion from string constant to 'char*'
suggest that you should find a newer version of bison. If that is impossible, you can just ignore them; g++ is complaining that the bison template is not C++-clean, because it is assigning a string literal (which is a const char*) to a char* variable without a cast. Newer bison versions avoid the warning.
I have to implement a parser of expression tree (like "(a > b) AND (c <= d)") using flex and bison, but I fails to solve type errors...
The fatal errors occur during the g++ compilation of the parser.y.c file (which is generated by this command : "bison -o parser.y.c -d parser.y") :
parser.y:54:36: erreur: request for member ‘nodeVal’ in ‘*(yyvsp + -8u)’, which is of pointer type ‘Node*’ (maybe you meant to use ‘->’ ?)
parser.y:58:14: erreur: request for member ‘nodeVal’ in ‘yyval’, which is of pointer type ‘Node*’ (maybe you meant to use ‘->’ ?)
parser.y:58:55: erreur: request for member ‘strVal’ in ‘*(yyvsp + -16u)’, which is of pointer type ‘Node*’ (maybe you meant to use ‘->’ ?)
parser.y:58:82: erreur: request for member ‘strVal’ in ‘* yyvsp’, which is of pointer type ‘Node*’ (maybe you meant to use ‘->’ ?)
parser.y:59:14: erreur: request for member ‘nodeVal’ in ‘yyval’, which is of pointer type ‘Node*’ (maybe you meant to use ‘->’ ?)
parser.y:59:55: erreur: request for member ‘strVal’ in ‘*(yyvsp + -16u)’, which is of pointer type ‘Node*’ (maybe you meant to use ‘->’ ?)
There is also a warning that I don't understand :
parser.lex:35: warning, la règle ne peut être pairée [english : "rule cannot be matched"]
I hope someone can help me !
Here, the parser.y file :
%{
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <iostream>
#include "Node.h"
#include "parser.lex.h"
#define YYSTYPE Node*
int yyerror(char *s) {
printf("%s\n",s);
}
extern "C++"
{
int yyparse(void);
int yylex(void);
Node * rootNode;
}
%}
%union {
Node * nodeVal;
char * strVal;
}
%token <strVal> IDENT
%token <strVal> LT GT LE GE EQ NE
%token <strVal> AND OR
%token <strVal> LEFT_PARENTHESIS RIGHT_PARENTHESIS
%token FIN
%left LT GT LE GE EQ NE
%left AND OR
%type<nodeVal> Expression
%start Input
%%
Input:
/* Vide */
| Input Ligne
;
Ligne:
FIN
| Expression FIN { rootNode = $1; }
;
Expression:
IDENT LT IDENT { $$=new Node("<", $1, $3); }
| IDENT GT IDENT { $$=new Node(">", $1, $3); }
| IDENT LE IDENT { $$=new Node("<=", $1, $3); }
| IDENT GE IDENT { $$=new Node(">=", $1, $3); }
| IDENT EQ IDENT { $$=new Node("=", $1, $3); }
| IDENT NE IDENT { $$=new Node("!=", $1, $3); }
| Expression AND Expression { $$=new Node("AND", $1, $3); }
| Expression OR Expression { $$=new Node("OR", $1, $3); }
| LEFT_PARENTHESIS Expression RIGHT_PARENTHESIS { $$=$2; }
;
%%
void parse_string(const std::string & str)
{
yy_scan_string(str.c_str());
yyparse();
}
then the parser.lex file :
%{
#define YYSTYPE Node*
#include <cstdlib>
#include "BooleanNode.h"
#include "AttributeNode.h"
#include "parser.y.h"
extern "C++"
{
int yylex(void);
}
%}
%option noyywrap
blancs [ \t]+
ident [a-zA-Z_]{1}[a-zA-Z0-9_]*
%%
{ident} { return(IDENT); }
"<" return(LT);
">" return(GT);
"<=" return(LE);
">=" return(GE);
"=" return(EQ);
"!=" return(NE);
"AND" return(AND);
"OR" return(OR);
"(" return(LEFT_PARENTHESIS);
")" return(RIGHT_PARENTHESIS);
"\n" return(FIN);
and finally the Node.h file :
#ifndef _NODE_H_
#define _NODE_H_
#include <string>
#include <iostream>
class Node
{
public:
enum E_op
{
AND = 0,
OR,
LT,
GT,
LE,
GE,
EQ,
NE
};
Node(const std::string & op)
{
_op = op;
}
Node(const std::string & op, const std::string & left, const std::string & right)
{
_op = op;
}
Node(const std::string & op, Node * left, Node * right)
{
_op = op;
}
virtual ~Node()
{
}
virtual void print() {}
protected:
std::string _op;
};
#endif
UPDATE
Thanks to Jonathan Leffler and some others corrections (char* instead of std::string in %union), the compilation goes well but the result is not what I expected.
With the "foo < bar" expression, the "IDENT LT IDENT" directive is executed but the value of $1 and $3 is NULL...
** NEW UPDATE **
I corrected the error by splitting the Expression directive :
Expression:
id LT id { $$ = new Node("<", $1, $3); }
| id GT id { $$ = new Node(">", $1, $3); }
| id LE id { $$ = new Node("<=", $1, $3); }
| id GE id { $$ = new Node(">=", $1, $3); }
| id EQ id { $$ = new Node("=", $1, $3); }
| id NE id { $$ = new Node("!=", $1, $3); }
| Expression AND Expression { $$ = new Node("AND", $1, $3); }
| Expression OR Expression { $$ = new Node("OR", $1, $3); }
| LEFT_PARENTHESIS Expression RIGHT_PARENTHESIS { $$ = $2; }
;
id:
IDENT { $$ = strdup(yytext); }
The problem is that you've declared that the Yacc stack contains Node * elements via the #define YYSTYPE Node * define, but your %union, %token and %type declarations say that there are StrVal and NodeVal types within the union.
IIRC, you only use YYSTYPE when you do not use %union. Removing that line should resolve the other problems.
I was teaching myself Bison and headed over to wikipedia for the same and copy-pasted the entire code from the example that was put there [ http://en.wikipedia.org/wiki/GNU_Bison ]. It compiled and works perfect. Then, I OOPed it by adding in a bit of C++. Here's is my new Parser.y file:
%{
#include "TypeParser.h"
#include "ParserParam.h"
#include "addition.h"
%}
%define api.pure
%left '+' TOKEN_PLUS
%left '*' TOKEN_MULTIPLY
%left '-' TOKEN_SUBTRACT
%left '/' TOKEN_DIVIDE
%left '^' TOKEN_EXP
%token TOKEN_LPAREN
%token TOKEN_RPAREN
%token TOKEN_PLUS
%token TOKEN_MULTIPLY
%token <value> TOKEN_NUMBER
%type <expression> expr
%%
input:
expr { ((SParserParam*)data)->expression = $1; }
;
expr:
expr TOKEN_PLUS expr { $$ = new Addition($1, $2); }
| expr TOKEN_MULTIPLY expr { $$ = new Multiplication($1, $2); }
| expr TOKEN_SUBTRACT expr { $$ = new Addition($1, $2); }
| expr TOKEN_DIVIDE expr { $$ = new Multiplication($1, $2); }
| expr TOKEN_EXP expr { $$ = new Addition($1, $2); }
| TOKEN_LPAREN expr TOKEN_RPAREN { $$ = $2; }
| TOKEN_NUMBER { $$ = new Value($1); }
;
%%
But then I keep getting the following errors:
Parser.y:33.52-53: $2 of `expr' has no declared type
Parser.y:34.62-63: $2 of `expr' has no declared type
Parser.y:35.56-57: $2 of `expr' has no declared type
Parser.y:36.60-61: $2 of `expr' has no declared type
Parser.y:37.52-53: $2 of `expr' has no declared type
How do I resolve it? I mean, what have I changed that is causing this? I haven't changed anything from the wikipedia code, the %type% declaration is still there [The union has the same members, with type changed from SExpression to Expression.]. All classes i.e. Addition, Expression, Multiplication are defined and declared. I don't think that is what is causing the problem here, but just saying.
And why exactly does it have a problem only with $2. Even $1 is of type expr, then why do I not get any errors for $1?
Any help is appreciated...
In the rule expr TOKEN_PLUS expr $1 is the first expression, $2 is TOKEN_PLUS, and $3 is the second expression. See the bison manual.
So the semantic action needs to change from your { $$ = new Addition($1, $2); } to { $$ = new Addition($1, $3); }.