我正在使用flex和bison实现计算器,但是将double值解释为整数,然后我在互联网上寻找答案,我意识到错误可能是bison将数字解释为整数,所以如果我输入“ 1.2”在* yylval = atof(yytext)中为1而不是1.2。因此,我尝试在parser.ypp中添加#define YYSTYPE double,但出现编译错误。我知道有几个类似的问题,但没有一个真正帮助过我。这是我的lex和ypp文件以及编译错误。提前致谢。
lexer.lex:
%option noyywrap
%option noinput
%option nounput
%{
#include <iostream>
#include <cstdlib>
#include <string>
#include <fstream>
#include "parser.tab.hpp"
%}
%%
[0-9]+([.][0-9]+)? {
*yylval = atof(yytext);
return NUMBER;
}
sin {
return SIN;
}
cos {
return COS;
}
tan {
return TG;
}
tg {
return TG;
}
ctan {
return CTG;
}
ctg {
return CTG;
}
asin {
return ASIN;
}
acos {
return ACOS;
}
atan {
return ATG;
}
actan {
return ACTG;
}
ln {
return LN;
}
log {
return LOG;
}
exp {
return EXP;
}
sqrt {
return SQRT;
}
abs {
return ABS;
}
mod {
return MOD;
}
[a-z] {
return VARIABLE;
}
[-+*/^()%!,] {
return *yytext;
}
[ \t\n] ;
. {
}
parser.ypp:
%{
#define YYSTYPE double
#include <iostream>
#include <cstdlib>
#include <string>
#include <cmath>
bool indicator_calculating_value ;
extern int yylex();
void yyerror(double *return_value, std::string s);
%}
%parse-param { double *return_value}
%left '+' '-'
%left '*' '/' '%'
%left SIN COS TG CTG ASIN ACOS ATG ACTG LN LOG MOD
%left UMINUS
%left '^' EXP SQRT
%left ABS
%left '!'
%type <double> E
%token <double> NUMBER
%token <char> VARIABLE;
%start pocetak
%%
pocetak
: E {
*return_value = $1;
};
E
: E '+' E {
if (indicator_calculating_value) {
$$ = $1 + $3;
}
}
| E '*' E {
if (indicator_calculating_value) {
$$ = $1 * $3;
}
}
| E '-' E {
if (indicator_calculating_value) {
$$ = $1 - $3;
}
}
| E '/' E {
if(indicator_calculating_value) {
if ($3 == 0) {
yyerror(0, "divide by zero");
}
$$ = $1 / $3;
}
}
| MOD '(' E ',' E ')' {
if(indicator_calculating_value) {
if ($5 == 0) {
yyerror(0, "divide by zero");
}
$$ = static_cast<int>($3) % static_cast<int>($5);
}
}
| SIN '(' E ')' {
if(indicator_calculating_value) {
$$ = sin($3);
}
}
| COS '(' E ')' {
if(indicator_calculating_value) {
$$ = cos($3);
}
}
| TG '(' E ')' {
if(indicator_calculating_value) {
$$ = tan($3);
}
}
| CTG '(' E ')' {
if(indicator_calculating_value) {
$$ = 1 / tan($3);
}
}
| ASIN '(' E ')' {
if(indicator_calculating_value) {
$$ = asin($3);
}
}
| ACOS '(' E ')' {
if(indicator_calculating_value) {
$$ = acos($3);
}
}
| ATG '(' E ')' {
if(indicator_calculating_value) {
$$ = atan($3);
}
}
| ACTG '(' E ')' {
if(indicator_calculating_value) {
$$ = 1 / atan($3);
}
}
| LN '(' E ')' {
if(indicator_calculating_value) {
$$ = log($3);
}
}
| LOG '(' E ',' E ')' {
if(indicator_calculating_value) {
$$ = log($5) / log($3);
}
}
| EXP '(' E ')' {
if(indicator_calculating_value) {
$$ = exp($3);
}
}
| SQRT '(' E ')' {
if(indicator_calculating_value) {
$$ = sqrt($3);
}
}
| E '^' E {
if(indicator_calculating_value) {
$$ = pow($1, $3);
}
}
| '-' E %prec UMINUS {
if(indicator_calculating_value) {
$$ = -$2;
}
}
| ABS '(' E ')' {
if(indicator_calculating_value) {
$$ = fabs($3);
}
}
| E '!' {
if(indicator_calculating_value) {
$$ = 1;
for (int i = 1; i <= static_cast<int>($1); i++) {
$$ = $$ * i;
}
}
}
| '(' E ')' {
if(indicator_calculating_value) {
$$ = $2;
}
}
| NUMBER {
if(indicator_calculating_value) {
$$ = $1;
}
}
| VARIABLE {
}
;
%%
void yyerror(double *return_value, std::string s)
{
std::cout << s << std::endl;
}
int main() {
indicator_calculating_value = true;
double value = 0.0;
yyparse(&value);
std::cout << value << std::endl;
return 0;
}
错误:
make
bison -d -v parser.ypp
g++ -Wall -L/usr/local/lib -lmgl-qt5 -lmgl -lm -c -o parser.tab.o parser.tab.cpp
parser.ypp: In function ‘int yyparse(double*)’:
parser.ypp:42:34: error: expected unqualified-id before ‘double’
*return_value = $1;
^
parser.ypp:42:34: error: expected ‘)’ before ‘double’
parser.ypp:49:20: error: expected unqualified-id before ‘double’
$$ = $1 + $3;
^~~~~~
parser.ypp:49:20: error: expected ‘)’ before ‘double’
parser.ypp:55:20: error: expected unqualified-id before ‘double’
$$ = $1 * $3;
^~~~~~
parser.ypp:55:20: error: expected ‘)’ before ‘double’
parser.ypp:60:20: error: expected unqualified-id before ‘double’
$$ = $1 - $3;
^~~~~~
parser.ypp:60:20: error: expected ‘)’ before ‘double’
parser.ypp:66:27: error: expected unqualified-id before ‘double’
if ($3 == 0) {
^
parser.ypp:66:27: error: expected ‘)’ before ‘double’
parser.ypp:69:20: error: expected unqualified-id before ‘double’
$$ = $1 / $3;
^~~~~~
parser.ypp:69:41: error: expected unqualified-id before ‘double’
$$ = $1 / $3;
^
parser.ypp:69:41: error: expected ‘)’ before ‘double’
parser.ypp:69:68: error: expected ‘)’ before ‘;’ token
$$ = $1 / $3;
^
parser.ypp:74:28: error: expected unqualified-id before ‘double’
if ($5 == 0) {
^
parser.ypp:74:28: error: expected ‘)’ before ‘double’
parser.ypp:77:20: error: expected unqualified-id before ‘double’
$$ = static_cast<int>($3) % static_cast<int>($5);
^~~~~~
parser.ypp:77:58: error: expected unqualified-id before ‘double’
$$ = static_cast<int>($3) % static_cast<int>($5);
^~~~
parser.ypp:77:58: error: expected ‘)’ before ‘double’
parser.ypp:77:105: error: expected ‘)’ before ‘;’ token
$$ = static_cast<int>($3) % static_cast<int>($5);
^
parser.ypp:77:105: error: expected ‘)’ before ‘;’ token
parser.ypp:82:20: error: expected unqualified-id before ‘double’
$$ = sin($3);
^~~~~~
parser.ypp:82:20: error: expected ‘)’ before ‘double’
parser.ypp:87:20: error: expected unqualified-id before ‘double’
$$ = cos($3);
^~~~~~
parser.ypp:87:20: error: expected ‘)’ before ‘double’
parser.ypp:92:20: error: expected unqualified-id before ‘double’
$$ = tan($3);
^~~~~~
parser.ypp:92:20: error: expected ‘)’ before ‘double’
parser.ypp:97:20: error: expected unqualified-id before ‘double’
$$ = 1 / tan($3);
^~~~~~
parser.ypp:97:20: error: expected ‘)’ before ‘double’
parser.ypp:102:20: error: expected unqualified-id before ‘double’
$$ = asin($3);
^~~~~~
parser.ypp:102:20: error: expected ‘)’ before ‘double’
parser.ypp:107:20: error: expected unqualified-id before ‘double’
$$ = acos($3);
^~~~~~
parser.ypp:107:20: error: expected ‘)’ before ‘double’
parser.ypp:112:20: error: expected unqualified-id before ‘double’
$$ = atan($3);
^~~~~~
parser.ypp:112:20: error: expected ‘)’ before ‘double’
parser.ypp:117:20: error: expected unqualified-id before ‘double’
$$ = 1 / atan($3);
^~~~~~
parser.ypp:117:20: error: expected ‘)’ before ‘double’
parser.ypp:122:20: error: expected unqualified-id before ‘double’
$$ = log($3);
^~~~~~
parser.ypp:122:20: error: expected ‘)’ before ‘double’
parser.ypp:127:20: error: expected unqualified-id before ‘double’
$$ = log($5) / log($3);
^~~~~~
parser.ypp:127:20: error: expected ‘)’ before ‘double’
parser.ypp:132:20: error: expected unqualified-id before ‘double’
$$ = exp($3);
^~~~~~
parser.ypp:132:20: error: expected ‘)’ before ‘double’
parser.ypp:137:20: error: expected unqualified-id before ‘double’
$$ = sqrt($3);
^~~~~~
parser.ypp:137:20: error: expected ‘)’ before ‘double’
parser.ypp:142:20: error: expected unqualified-id before ‘double’
$$ = pow($1, $3);
^~~~~~
parser.ypp:142:20: error: expected ‘)’ before ‘double’
parser.ypp:147:20: error: expected unqualified-id before ‘double’
$$ = -$2;
^~
parser.ypp:147:20: error: expected ‘)’ before ‘double’
parser.ypp:152:20: error: expected unqualified-id before ‘double’
$$ = fabs($3);
^~~~~~
parser.ypp:152:20: error: expected ‘)’ before ‘double’
parser.ypp:157:20: error: expected unqualified-id before ‘double’
$$ = 1;
^
parser.ypp:157:20: error: expected ‘)’ before ‘double’
parser.ypp:158:62: error: expected unqualified-id before ‘double’
for (int i = 1; i <= static_cast<int>($1); i++) {
^
parser.ypp:158:62: error: expected ‘)’ before ‘double’
parser.ypp:158:70: error: expected ‘)’ before ‘;’ token
for (int i = 1; i <= static_cast<int>($1); i++) {
^
parser.ypp:159:24: error: expected unqualified-id before ‘double’
$$ = $$ * i;
^~~~~
parser.ypp:159:24: error: expected ‘)’ before ‘double’
parser.ypp:165:20: error: expected unqualified-id before ‘double’
$$ = $2;
^
parser.ypp:165:20: error: expected ‘)’ before ‘double’
parser.ypp:170:20: error: expected unqualified-id before ‘double’
$$ = $1;
^
parser.ypp:170:20: error: expected ‘)’ before ‘double’
Makefile:15: recipe for target 'parser.tab.o' failed
make: *** [parser.tab.o] Error 1
您的野牛文件定义了两种不同类型的符号:
%type <double> E
%token <double> NUMBER
%token <char> VARIABLE;
((第三行末尾的分号是错误的,尽管我认为野牛只会忽略它。)
如bison manual中所述,最常见的实现方法是使用%union
野牛声明,该声明将YYSTYPE
声明为C并集。这与使用预处理器将#define YYSTYPE
作为单一类型不兼容。
如果使用%union
声明,则为YYSTYPE
的每个变体指定C类型和标记。然后放在尖括号之间的是tag,而不是类型。例如,
%union {
double number;
char id;
}
%token <number> NUMBER
[使用该声明,野牛将声明一个具有两个名为union
和number
的成员的id
类型。通过附加成员选择器,它将自动使$n
引用正确的成员(如果符号$n
所指的类型已知)。换句话说,如果$1
指向NUMBER
,野牛将在生成的代码中将其替换为stack[top - 2 + 1].number
。 (如果没有%union
和类型声明,则替换将类似于stack[top - 2 + 1]
。)
野牛不需要您使用%union
。如果您不这样做,但仍然声明令牌和非终结符的类型,那么bison会假设您知道自己在做什么,并且已经以某种方式声明了YYSTYPE
作为复合类型。它将执行完全相同的替换,将成员选择器添加到引用中以使用已知类型的堆栈值。
因此,在您的情况下,您已声明%type <double> E
,因此在$1
指向符号$1
的动作中,例如E
,野牛将替换stack[top - 4 + 1].double
。
当然,这将导致编译器阻塞。 double
是保留字,不能用作复合成员名称,并且无论如何YYSTYPE
是标量(double
),因为这是您定义它的方式。
您尚未尝试编译扫描仪,但是在那里您会遇到类似的问题。显然,YYSTYPE
在扫描器和解析器中必须是相同的类型,它们是独立的C转换单元。如果您使用了%union
声明,那么bison会将C union
放入生成的标头中,您在生成的扫描器中将其标为#include
。这样可以保证一致性。如果不使用%union
,则必须确保扫描仪具有正确的定义。
由于您在flex文件中不执行任何操作来声明YYSTYPE
,因此生成的代码将回退到int
。它通过包含如下代码块来做到这一点:
#ifndef YYSTYPE
#define YYSTYPE int
#endif
《野牛手册》包含许多简单的示例。除了我在此提供的选项外,还有很多其他选择,建议您花一些时间阅读本手册。