Bison 野牛多规则符号

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;如果它是实数,那么符号被视为rexpr。以下是我现在的规则:

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文件中定义它们,还是只在其中一个文件中定义它们?