【问题标题】:FLEX/YACC program not behaving as expected : can't grab int value from sequence of intsFLEX/YACC 程序未按预期运行:无法从整数序列中获取整数值
【发布时间】:2020-11-20 20:00:03
【问题描述】:

我正在尝试构建一个解析器,它采用以下格式的字符串列表并对其所有元素执行加法或乘法:

prod 5-6_
sum _
sum 5_
sum 5-6-7_
$

应该在屏幕上打印以下内容:

prod = 30
sum = 0
sum = 5
sum = 18

我实际得到的输出是这样的:

prod = 0
sum = 0
sum = 5
sum = 5

我的 lex 文件如下所示:

%{
        #include <iostream>
        #include "y.tab.h"
        using namespace std;
        extern "C" int yylex();
%}

%option yylineno

digit    [0-9]
integer  {digit}+
operator "sum"|"prod"

%%

{integer}   { return number; }
{operator}  { return oper; }
"-"         { return '-'; }
"_"         { return '_'; }
"$"         { return '$'; }
\n          { ; }
[\t ]+      { ; }
.           { cout << "unknown char" << endl; }

%%

我的 yacc 文件如下所示:

%token oper
%token number
%token '-'
%token '_'
%token '$'

%start valid


%{
        #include <iostream>
        #include <string>
        #include <cstdio>
        #include <cstdlib>
        using namespace std;

        #define YYSTYPE int 

        extern FILE *yyin;
        extern char yytext[];
        extern "C" int yylex();
        int yyparse();
        extern int yyerror(char *);

        char op;
%}

%%

valid           : expr_seq endfile      {}
                | {}
                ;

expr_seq        : expr                  {}
                | expr_seq expr         {}
                ;

expr            : op sequence nl        {if (op == '+') cout << "sum = " ; else cout << "prod =  ";}
                | op nl                 {if (op == '+') cout << "sum = 0"; else  cout <<"prod = 1";}                    
                ;

op              : oper                      { if (yytext[0] == 's') op = '+'; else op = '*';}
                ;

sequence        : number                    { $$ = atoi(yytext);}
                | sequence '-' number        { if (op == '+') $$ = $1 + $3; else $$ = $1 * $3;}
                ;

nl              : '_'                   { cout << endl;}
                ;

endfile         : '$'                   {}
                ;

%%

int main(int argc, char *argv[])
{
        ++argv, --argc;
        if(argc > 0)    yyin = fopen(argv[0], "r");
        else            yyin = stdin;

        yyparse(); 

        return 0;
} 

int yyerror(char * msg)
{
        extern int yylineno;
        cerr << msg << "on line # " << yylineno  << endl;

        return 0;
} 

我对 yacc 逻辑的推理如下:

  • 文件只有在包含一系列表达式且后跟 endfile 符号时才有效。
  • 表达式序列是单个表达式或多个表达式。
  • 表达式可以是一个运算符,后跟一个换行符,或者是一个运算符,后跟一个数字列表,然后是一个换行符。
  • 运算符是“sum”或“prod”
  • 数字列表可以是一个数字,也可以是由“-”符号分隔的多个数字。

从我的角度来看,这应该可以,但由于某种原因,它不能正确解释第一个元素之后的数字序列。任何提示都会有所帮助。

谢谢

【问题讨论】:

    标签: parsing flex-lexer yacc


    【解决方案1】:

    您不得在您的 yacc 操作中使用 yytextyytext 仅在扫描器操作期间有效,解析器通常会提前读取到下一个令牌。 (事实上​​,yacc 总是读取下一个标记。Bison 有时不会,但它并不总是很容易预测。)

    您可以将语义值与每个标记(和非终结符)相关联,并且可以在您的 yacc 操作中使用 $1$2 等来引用这些语义值。您甚至可以将不同类型的语义值与不同的语法符号相关联。如果你使用 bison——而且你可能正在使用 bison——你可以给语法符号命名,以便更容易地引用它们的语义值。

    这一切都在bison manual 中通过示例进行了深入解释。

    【讨论】:

    • @bulbassar:在野牛行动中仅使用$n 是不够的。您还必须在 flex 操作中为 yylval 分配一个值。 您不得在野牛动作中使用 yytext。即使它似乎在某些情况下有效,它最终也会失败。
    【解决方案2】:

    有效的解决方案只是更改以下几行:

    sequence        : number                    { $$ = atoi(yytext);}
                    | sequence '-' number        { if (op == '+') $$ = $1 + $3; else $$ = $1 * $3;}
                    ;
    

    到这里:

     sequence        : number                    { $$ = atoi(yytext);}
                        | sequence '-' number        { if (op == '+') $$ = $1 + atoi(yytext); else $$ = $1 * atoi(yytext);}
                        ;
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2022-12-10
      • 1970-01-01
      • 2018-04-17
      • 1970-01-01
      • 1970-01-01
      • 2020-01-14
      • 1970-01-01
      相关资源
      最近更新 更多