我正在做一些工作来解析我们项目中的内部配置文件。配置可以是一个简单的字符串,也可以是我们创建的供内部使用的“函数”。该函数可以接受字符串类型的参数和表示“条件”的特殊类型。我的flex token文件的一部分看起来像这样:
[a-zA-Z][a-zA-Z0-9_/=\.]* SAVE_TOKEN; return TSTRING;
"(" SAVE_TOKEN; return TLPAREN;
")" SAVE_TOKEN; return TRPAREN;
"," SAVE_TOKEN; return TCOMMA;
"==" SAVE_TOKEN; return TIFEQUAL;
"!=" SAVE_TOKEN; return TIFNEQUAL;
我的野牛解析器文件的一部分看起来像这样:
condition: expr TIFEQUAL expr { $$ = new NCondition($1, TIFEQUAL, $3);}
|expr TIFNEQUAL expr { $$ = new NCondition($1, TIFNEQUAL, $3);}
;
sring: TSTRING { $$ = new NString(*$1); }
;
expr: string {$<nstring>$ = $1;}
| string TLPAREN call_args TRPAREN { $$ = new NFunction($1, *$3); }
;
call_args: { $$ = new CallArg(); }
| expr { $$ = new CallArg(); }
| call_args TCOMMA condition { $1->conds.push_back($3); }
| call_args TCOMMA expr { $1->exprs.push_back($3); }
;
这里的冲突是,字符串类型允许等号“=”,它也是令牌TIFEQUA的一部分。考虑这样一个函数:
function(arg1, arg2, arg_cond==condition)
解析器将尝试匹配TSTRING标记而不是TIFEQUAL。我做了一些研究,我意识到Flex是贪婪的,如果两个模式都匹配,它会尝试匹配最长的一个。这是否意味着我的conflist必须在野牛级别解决?如果是的话,我应该如何处理这宗个案?
1条答案
按热度按时间hxzsmxv21#
这是由于lex识别器总是识别输入流中可能最长的标记(如您所注意到的),并且只能通过更改lex模式来“修复”。在野牛中你什么也做不了,因为那时已经太晚了--字符串已经被识别为一个
TSTRING
令牌。一个明显的可能性是从
TSTRING
模式中删除=
,因为它通常不是名称/标识符中的法律的标记。如果你真的想在它们中允许一些=
,你需要确切地决定它们何时应该是TSTRING
的一部分,而不是单独的操作符。您可以禁止两个连续的=
或TSTRING
末尾的=
:这将导致您输入的
arg_cond==condition
被识别为3个标记而不是1个。然而,像a==b==c
这样的东西会导致语法错误,而理论上它可以被识别为a==b == c
或a == b==c
-但它应该是什么并不清楚。