Flex与Bison编写的语法解析器返回ERROR而非OK问题排查
问题排查与修复方案
1. Flex词法规则顺序错误
tADDRESS的匹配规则被放到了tIDENT规则之后,而Flex会优先匹配顺序更靠前的规则,导致邮箱前缀会被先识别为标识符,无法正确匹配完整邮箱地址。
修复方案:调整规则顺序,把更特殊的tADDRESS规则移动到tIDENT之前:
# Flex规则部分调整顺序 [0-9]{2}:[0-9]{2} return tTIME; {tLOCALPART}"@"({tDOMAIN}"."{tDOMAIN}"."{tDOMAIN}|{tDOMAIN}"."{tDOMAIN}) return tADDRESS; [a-zA-Z\_]+[a-zA-Z0-9\_]* return tIDENT; ["][^\"]*["] return tSTRING; [0-9]{2}"/"[0-9]{2}"/"[0-9]{4} return tDATE;
2. Bison冗余空产生式冲突
你给send、recipient、recipientList、recipientListExtra、sendList、mailBlock这些本身不能为空的非终结符都加了空产生式,会引发大量移进/归约冲突,导致解析逻辑混乱。
修复方案:删除所有不必要的空产生式:
# 修正mailBlock规则,删除空选项 mailBlock: tMAIL tFROM tADDRESS tCOLON tENDMAIL | tMAIL tFROM tADDRESS tCOLON statements tENDMAIL ; # 修正send规则,删除空选项 send: tSEND tLBR tSTRING tRBR tTO recipientListExtra | tSEND tLBR tIDENT tRBR tTO recipientListExtra ; # 修正sendList规则,删除空选项 sendList: send | send sendList ; # 修正recipientList规则,删除空选项 recipientList: recipient | recipient tCOMMA recipientList ; # 修正recipientListExtra规则,删除空选项 recipientListExtra: tLBR recipientList tRBR ; # 修正recipient规则,删除空选项 recipient: tLPR tADDRESS tRPR | tLPR tSTRING tCOMMA tADDRESS tRPR | tLPR tIDENT tCOMMA tADDRESS tRPR ;
3. 多语句匹配规则缺失
原来的statements规则仅支持单个语句,但是测试用例的邮件块内存在多个连续语句(调度、设置、发送),无法匹配。
修复方案:拆分规则支持多语句并列:
# 新增单个语句规则 statement: set | send | schedule ; # 修正statements规则支持多语句 statements: statement | statement statements ;
可选调试优化
可以修改yyerror函数输出错误信息方便定位问题,同时在Flex开头加%option yylineno开启行号统计:
// parser.y中修改yyerror void yyerror (const char *s) { extern int yylineno; fprintf(stderr, "第%d行解析错误: %s\n", yylineno, s); }
编译验证
修改完成后执行以下命令编译运行即可得到预期的OK输出:
flex 你的词法文件名.l bison -d parser.y gcc parser.tab.c lex.yy.c -o mail_parser -lfl ./mail_parser < test.ms
内容的提问来源于stack exchange,提问作者C.Unbay
相关产品推荐
相关产品推荐

