如何在不修改原有正则的前提下让Flex正确识别表达式中的.:
问题描述
现有一个Lex文件,需添加对.:的识别支持,已完成初步修改,代码如下:
%option caseless ALP [a-z]+ NUM [0-9]+ REF {ALP}{NUM} _NAME_0 [^\-\^\]`~!@#$%&*()+=|{}[;:'",<>/ .1234567890?\n] _NAME_1 {_NAME_0}|[0-9.?] NAME {_NAME_0}{_NAME_1}* OP_1 ":" OP_2 ".:" T (" "|\n)* %s S1 S2 %% <S1>{ {T}{OP_1} { printf(": "); } {T}{OP_2} { printf(".: "); } {T}{NAME} { BEGIN(S2); yyless(0); } } <S2>{ {T}{REF} { printf("tokRef "); BEGIN(S1); } {T}{NAME} { printf("tokName "); BEGIN(S1); } } %% int main() { BEGIN(S1); yylex(); return 0; } int yywrap() { return 1; }
当前规则对部分输入的解析结果如下:
input output a1:b1 --> tokRef : tokRef a1 : b1 --> tokRef : tokRef a1. : b1 --> tokName : tokRef a1 .: b1 --> tokRef .: tokRef a1.:b1 --> tokName : tokRef
其中最后一条输入a1.:b1的输出不符合预期,期望结果为:
a1.:b1 --> tokRef .: tokRef
因应用限制,原有正则表达式定义(如REF、NAME、OP_1、T)不可修改,需通过修改新增的OP_2或状态机规则实现预期效果。
解决方案
可以通过在<S1>状态下新增一条优先匹配{REF}{OP_2}的规则来解决问题,利用Lex的最长匹配优先级特性,让a1.:这类输入被优先识别为REF+OP_2,而非被NAME规则误匹配为a1.。
修改后的<S1>状态规则如下:
<S1>{ {T}{OP_1} { printf(": "); } {T}{OP_2} { printf(".: "); } {T}{REF}{OP_2} { printf("tokRef .: "); BEGIN(S1); } {T}{NAME} { BEGIN(S2); yyless(0); } }
原理说明
- 当输入为
a1.:b1时,新增的{T}{REF}{OP_2}规则会匹配整个a1.:片段(匹配长度为4),比NAME规则匹配a1.(长度为3)更长,因此会被优先触发,直接输出tokRef .:。 - 剩余的
b1会进入<S2>状态,被REF规则识别为tokRef,最终得到预期输出。 - 原有其他输入的解析逻辑不受影响:
a1. : b1中a1.与:之间有空格,不会触发新增规则,仍按原逻辑输出tokName : tokRef;a1 .: b1中a1与.:之间有空格,会先在<S2>识别a1为tokRef,再在<S1>识别.:为.:,输出不变。
内容的提问来源于stack exchange,提问作者lijiang99
相关产品推荐
相关产品推荐

