Flex/Bison语法解析器无法正确打印变量名的问题排查
核心问题定位
变量名无法打印、本该输出变量名的位置显示Data: 0的问题,是多个逻辑错误叠加导致的,按影响优先级排序:
- 符号表索引判断边界错误
符号表的存储索引从0开始,首次存入的变量(如测试用例中的x)对应索引为0。但printTree函数中判断IDVAL节点的条件为tree->item > 0 && tree->item < SYMBOLTABLESIZE,直接将索引0的合法变量排除在变量名打印逻辑外。由于0不等于定义的NOTHING(-1),代码会直接走通用打印逻辑输出Data: 0,和观测到的现象完全匹配。 - main函数的文件读取参数索引错误
程序调用为./frontEnd data.txt时,命令行参数索引规则为:argv[0]是程序名,argv[1]是传入的文件名。但代码中写的是yyin = fopen(argv[2], "r"),直接读取不存在的第三个参数,根本无法加载输入文件。 - Flex词法规则的括号符号映射完全相反
词法规则中:- 左括号
(被错误映射为RPAREN(右括号) - 右括号
)被错误映射为LPAREN(左括号) - 左大括号
{被错误映射为RBRACE(右大括号) - 右大括号
}被错误映射为LBRACE(左大括号)
这会直接导致块语法的匹配逻辑完全错位。
- 左括号
- 语法树打印的节点判断错配
枚举值中,语法树的数字节点类型为NUMVAL,但打印函数中判断数字节点的条件写的是和终结符同名的NUMBER,导致数字节点永远不会走专门的数值打印分支。 - 无效的类型不匹配赋值
词法规则处理标识符时,先把strdup返回的字符串指针赋值给int类型的yylval.iVal,下一行又用符号表索引的整数值覆盖该变量。这行代码不仅无实际作用,还会在64位编译环境下触发指针截断告警。 - 语法规则的Token名称不匹配
词法分析器遇到赋值符号=时返回的token是ASSIGN,但语法规则中赋值语句的规则写的是ASSIGNS,该token从未被定义返回,会直接触发语法匹配错误。 - yyparse调用方式错误
yyparse的函数签名是无参函数,内部固定从全局变量yyin读取输入内容。代码中给yyparse传入文件指针参数的写法是无效的,传入的参数会被直接忽略。 - 数组越界判断逻辑错误
打印函数中判断节点ID是否越界时,用sizeof(NodeName)获取数组总字节数,而非数组元素个数,会导致越界判断完全失效。
修复方案
按照对应错误逐一调整:
- 修正符号表的判断边界
把printTree中的IDVAL判断条件修改为tree->item >= 0 && tree->item < SYMBOLTABLESIZE,让索引0的合法变量可以正常命中变量名打印逻辑。 - 修正命令行参数索引
把main函数中的fopen(argv[2], "r")改为fopen(argv[1], "r"),正确读取传入的输入文件。 - 修正词法规则的括号映射
调整lex.l中括号的返回值:
"(" return LPAREN; ")" return RPAREN; "{" return LBRACE; "}" return RBRACE;
同步调整parser.y中块规则的括号顺序,匹配左大括号开始、右大括号结束的逻辑:
block : LBRACE vars stats RBRACE
- 修正语法树打印的节点判断
把打印函数里的if(tree->nodeID == NUMBER)修改为if(tree->nodeID == NUMVAL),正确匹配数字节点的打印逻辑。 - 删除无效的指针赋值代码
移除lex.l中yylval.iVal = strdup(yytext);这行冗余代码,解决类型不匹配问题。 - 统一赋值符号的token名称
把parser.y中赋值语句规则里的ASSIGNS改为和词法规则匹配的ASSIGN,保证语法匹配正常。 - 修正yyparse的调用方式
把main函数里所有带参数的yyparse(fp)、yyparse(yyin)都改为无参的yyparse()。 - 修正数组越界判断逻辑
把打印函数中的节点越界判断修改为if (tree->nodeID < 0 || tree->nodeID >= sizeof(NodeName)/sizeof(NodeName[0])),正确判断数组边界。
修复后预期效果
运行./frontEnd data.txt时,语法树中对应变量x的IDVAL节点会正常打印变量名,不再输出无意义的Data: 0;数字节点会正确输出存储的整数值,块语法、赋值语句等规则可以正常匹配。
内容的提问来源于stack exchange,提问作者shawn brown
相关产品推荐
相关产品推荐

