Flex&Bison逻辑表达式工具异常:输入无响应且报语法错误
问题分析与修复方案
核心问题
你的代码存在两个关键错误,导致程序无输出或报错:
重复定义函数引发编译问题
Bison文件中重复定义了main和yyerror函数,位于两个%%块之后,这会触发编译器的「重复定义」错误(你当前的编译步骤理论上会失败,可能是你粘贴代码时的冗余内容)。Lexer吃掉换行符,Parser无法触发输出
Flex规则里[ \t\n]+将换行符视为空白字符直接跳过,但Bison的输入规则input: input expr '\n'需要接收换行符来触发结果打印,导致输入表达式后按回车无任何输出。
修正后的代码
1. 修正Flex文件 lexer.l
调整空白字符处理规则,仅跳过空格和制表符,把换行符返回给Parser:
%{ #include "parser.tab.h" %} %% "&&" { return AND; } "||" { return OR; } "!" { return NOT; } "==" { return EQ; } "!=" { return NEQ; } "<=" { return LEQ; } ">=" { return GEQ; } "<" { return LT; } ">" { return GT; } "(" { return LPAREN; } ")" { return RPAREN; } [0-9]+ { yylval = atoi(yytext); return NUM; } "true" { return TRUE; } "false" { return FALSE; } [ \t]+ { /* 仅跳过空格和制表符 */ } "\n" { return '\n'; } // 将换行符返回给Parser,触发输出动作 . { return yytext[0]; } %% int yywrap() { return 1; }
2. 修正Bison文件 parser.y
删除重复的main和yyerror定义,同时添加计数重置逻辑,避免多次输入后累计计数:
%{ #include <stdio.h> int comparisons = 0; int actual_comparisons = 0; void yyerror(const char *s); int yylex(void); %} %token AND OR NOT EQ NEQ LEQ GEQ LT GT LPAREN RPAREN NUM TRUE FALSE %left OR %left AND %right NOT %nonassoc EQ NEQ LEQ LT GT GEQ %% input: input expr '\n' { printf("%s, %d, %d\n", $2 ? "TRUE" : "FALSE", comparisons, actual_comparisons); // 每次求值后重置计数,避免累计 comparisons = 0; actual_comparisons = 0; } | /* empty */ { /* 空规则,处理初始输入 */ } ; expr: expr OR expr { $$ = $1 || $3; comparisons += 1; actual_comparisons += ($1 ? 0 : 1); } | expr AND expr { $$ = $1 && $3; comparisons += 1; actual_comparisons += ($1 ? 1 : 0); } | NOT expr { $$ = !$2; } | expr EQ expr { $$ = $1 == $3; comparisons += 1; actual_comparisons += 1; } | expr NEQ expr { $$ = $1 != $3; comparisons += 1; actual_comparisons += 1; } | expr LEQ expr { $$ = $1 <= $3; comparisons += 1; actual_comparisons += 1; } | expr GEQ expr { $$ = $1 >= $3; comparisons += 1; actual_comparisons += 1; } | expr LT expr { $$ = $1 < $3; comparisons += 1; actual_comparisons += 1; } | expr GT expr { $$ = $1 > $3; comparisons += 1; actual_comparisons += 1; } | LPAREN expr RPAREN { $$ = $2; } | NUM { $$ = $1; } | TRUE { $$ = 1; } | FALSE { $$ = 0; } ; %% void yyerror(const char *s) { fprintf(stderr, "Error: %s\n", s); // 错误后重置计数 comparisons = 0; actual_comparisons = 0; } int main(void) { return yyparse(); }
编译与测试
使用你原来的编译步骤即可:
bison -d parser.y flex lexer.l gcc parser.tab.c lex.yy.c -o logic_eval -lm ./logic_eval
测试示例:
- 输入
true && false并回车,输出FALSE, 1, 1 - 输入
10 > 5 || false并回车,输出TRUE, 2, 1
内容的提问来源于stack exchange,提问作者Overstacked
相关产品推荐
相关产品推荐

