Bison 野牛多规则符号
我有一个符号表,它保存变量/符号的名称、数据和数据类型(存储为字符)。我希望它是这样的:如果它是整数,那么符号被视为iexpr;如果它是实数,那么符号被视为rexpr。以下是我现在的规则:Bison 野牛多规则符号,bison,flex-lexer,Bison,Flex Lexer,我有一个符号表,它保存变量/符号的名称、数据和数据类型(存储为字符)。我希望它是这样的:如果它是整数,那么符号被视为iexpr;如果它是实数,那么符号被视为rexpr。以下是我现在的规则: iexpr: INT_TOKEN | iexpr PLUS iexpr { $$ = $1 + $3; } | iexpr MINUS iexpr { $$ = $1 - $3; } | iexpr DIVIDE iexpr {$$ = $1/$3;} | iexpr MOD
iexpr: INT_TOKEN
| iexpr PLUS iexpr { $$ = $1 + $3; }
| iexpr MINUS iexpr { $$ = $1 - $3; }
| iexpr DIVIDE iexpr {$$ = $1/$3;}
| iexpr MOD iexpr{$$ = $1 % $3;}
| LPARENT iexpr RPARENT{$$=$2;}
| SYMBOL { symrec *s;
s = getsym($1);
if(s!=0){
if(s->type == 'i'){
$$ = atoi(s->data);
}
}
}
;
rexpr: REAL_TOKEN
| rexpr PLUS rexpr { $$ = $1 + $3; }
| rexpr MINUS rexpr { $$ = $1 - $3; }
| iexpr PLUS rexpr { $$ = (double) $1 + $3; }
| iexpr MINUS rexpr { $$ = (double) $1 - $3; }
| rexpr PLUS iexpr { $$ = $1 + (double) $3; }
| rexpr MINUS iexpr { $$ = $1 - (double) $3; }
| rexpr DIVIDE rexpr {$$ = $1/$3;}
| rexpr MULTIPLY rexpr{$$ = $1 * $3;}
| rexpr DIVIDE iexpr {$$ = $1 / (double) $3;}
| rexpr MULTIPLY iexpr {$$= $1 * (double) $3;}
| iexpr DIVIDE rexpr {$$ = (double) $1 / $3;}
| iexpr MULTIPLY rexpr {$$ = (double) $1 * $3;}
| rexpr MOD rexpr {$$ = (int)$1 % (int)$3;}
| rexpr MOD iexpr {$$ = (int)$1 % $3;}
| iexpr MOD rexpr {$$ = $1 % (int)$3;}
| LPARENT rexpr RPARENT{$$ =$2;}
| SYMBOL { symrec *s;
s = getsym($1);
if(s!=0){
if(s->type == 'r'){
$$ = atof(s->data);
}
}
}
;
但是,rexpr中的规则从未使用过,因为它只将其视为iexpr。如何使它根据类型描述符被视为该类型,而不仅仅是一个整数
编辑:所以我尝试更改我的lex文件,以便它为每种类型返回不同的令牌。为此,我需要包含我的symboltable头文件,以便检查该名称并根据其类型返回不同的符号。这是代码:
[a-zA-Z]+ { yylval.string = strdup(yytext);
symrec *s;
s = getsym(yylval.string);
if(s!=0){
if(s->type == 'r'){
return RSYMBOL;
}else if(s->type == 'i'){
return ISYMBOL;
}
}else{
return SYMBOL;
}
}
但是现在我有一个错误,因为我在两个文件中都包含了头函数的多个定义。如果要这样做,需要让lexer为
ISYMBOL
和RSYMBOL
返回不同的标记,否则,您将得到SYMBOL
的两个缩减之间的reduce/reduce冲突,因为解析器不知道它是哪一个。这意味着您需要在lexer操作中查找符号表,而不是在parser操作中
通常,在解析器中尝试这样的类型检查是一个坏主意,因为它会使语法更加复杂,并导致许多难以解决的冲突。如果您希望标记类型根据符号声明的类型而变化,则需要在lexer中查找符号(因为这是生成标记类型的原因) 实际上,您需要返回三种不同令牌类型中的一种:
- 整数符号
- 实数符号
- 未声明的_符号
一般来说,在解析完成后,最好在AST上单独进行一次类型检查。(或者,如果您没有生成AST,您也可以在执行缩减操作的同时执行语义操作。)这将使您能够生成更好的错误消息,并且在发生类型错误后更容易继续解析。谢谢!你能看看我的编辑吗?我想我应该这样做,但我遇到了更多的问题。@cage479:你没有在头文件中定义函数;你只需要申报。如果要定义函数,显然会遇到重复的定义错误,以及全局变量的重复定义。顺便说一下,如果lexer可以访问符号表,它可以返回一个符号表条目,而不是符号名称的(副本)。这是一种减少内存分配的经典技术,即使lexer没有根据符号表信息修改其行为。如果还不明显,我也没有太多创建自己头文件的经验。因此,如果我只是声明函数(我假设只是“symrec*getsym()”),那么我应该在哪里定义它们呢?我需要在bison和flex文件中定义它们,还是只在其中一个文件中定义它们?