【问题标题】:Bison multi-rule symbol野牛多规则符号
【发布时间】:2023-05-31 05:23:01
【问题描述】:

我有一个符号表,其中包含一个变量/符号的名称、它的数据和它的数据类型(存储为一个字符)。我想要它,以便符号被视为 iexpr(如果它是整数)或 reexpr(如果它是实数)。这些是我现在拥有的规则:

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 文件,以便它为每种类型返回不同的令牌。为此,我需要包含我的符号表头文件,以便我可以检查该名称并根据其类型返回不同的符号。这是代码:

[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;
            }
          }

但是现在我有一个错误,说我有多个头函数定义,因为我将它包含在两个文件中。

【问题讨论】:

    标签: bison flex-lexer


    【解决方案1】:

    如果您希望标记类型根据符号的声明类型而有所不同,则需要在词法分析器中查找符号(因为这是生成标记类型的原因)。

    您实际上需要返回三种不同的令牌类型之一:

    • INT_SYMBOL
    • REAL_SYMBOL
    • UNDECLARED_SYMBOL

    一般来说,最好在解析完成后单独通过 AST 进行类型检查。 (或者,如果您不生成 AST,则可以在进行归约时在语义操作中执行此操作。)这将使您产生更好的错误消息,并且在类型错误后继续解析变得更加容易。

    【讨论】:

    • 谢谢!你能看看我的编辑吗?我认为我应该这样做,但我遇到了更多问题。
    • @cage479:你没有在头文件中定义函数;你只声明它们。如果要定义函数,显然会遇到重复定义错误以及全局变量的重复定义。顺便说一句,如果词法分析器可以访问符号表,它可以返回一个符号表条目而不是符号名称的(副本)。这是一种减少内存分配的经典技术,即使词法分析器不会根据符号表信息修改其行为。
    • 如果不是很明显,我没有太多创建自己的头文件的经验。所以如果我只声明函数(我假设只是“symrec * getsym()”)我在哪里实际定义它们?我必须在我的野牛和 flex 文件中定义它们还是只在其中一个文件中定义它们?
    【解决方案2】:

    如果你想这样做,你需要让词法分析器为 ISYMBOLRSYMBOL 返回不同的标记,否则你会在 SYMBOL 的两个归约之间遇到归约/归约冲突,因为解析器没有不知道是哪个。这意味着您需要在词法分析器操作中进行符号表查找,而不是在解析器操作中。

    一般来说,尝试在解析器中进行这样的类型检查是一个坏主意,因为它会使语法更加复杂,并导致许多难以解决的冲突。

    【讨论】: