c++ 如何在Flex/野牛中处理这种情况下的优先级

8ehkhllq  于 2023-05-08  发布在  其他
关注(0)|答案(1)|浏览(188)

我正在做一些工作来解析我们项目中的内部配置文件。配置可以是一个简单的字符串,也可以是我们创建的供内部使用的“函数”。该函数可以接受字符串类型的参数和表示“条件”的特殊类型。我的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必须在野牛级别解决?如果是的话,我应该如何处理这宗个案?

hxzsmxv2

hxzsmxv21#

这是由于lex识别器总是识别输入流中可能最长的标记(如您所注意到的),并且只能通过更改lex模式来“修复”。在野牛中你什么也做不了,因为那时已经太晚了--字符串已经被识别为一个TSTRING令牌。
一个明显的可能性是从TSTRING模式中删除=,因为它通常不是名称/标识符中的法律的标记。如果你真的想在它们中允许一些=,你需要确切地决定它们何时应该是TSTRING的一部分,而不是单独的操作符。您可以禁止两个连续的=TSTRING末尾的=

[a-zA-Z](=?[a-zA-Z0-9_/\.])*     SAVE_TOKEN; return TSTRING;

这将导致您输入的arg_cond==condition被识别为3个标记而不是1个。然而,像a==b==c这样的东西会导致语法错误,而理论上它可以被识别为a==b == ca == b==c-但它应该是什么并不清楚。

相关问题