在 Flex/Bison 中如何处理这种情况下的优先级

问题描述 投票:0回答:1

我正在做一些工作来解析我们项目中的内部配置文件。配置可以是一个简单的字符串,也可以是我们为内部使用而创建的“函数”。该函数可以采用字符串类型参数和表示“条件”的特殊类型。我的 flex 令牌文件的一部分如下所示:

[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); }
        ;

这里的冲突是,一个字符串类型允许使用相等的符号“=”,这也是token TIFEQUA的一部分。考虑这样一个函数:

function(arg1, arg2, arg_cond==condition)

解析器将尝试匹配 TSTRING 标记而不是 TIFEQUAL。我做了一些研究,我意识到 flex 是贪婪的,如果两个模式都匹配,它会尝试匹配最长的一个。这是否意味着我的 conflist 必须在野牛级别解决?如果是,我该如何处理?

c++ bison flex-lexer yacc
1个回答
0
投票

这是由于 lex 识别器始终识别输入流中可能最长的标记(正如您所注意到的),并且只能通过更改 lex 模式来“修复”。在 bison 中您无能为力,因为到那时为时已晚——该字符串已被识别为单个

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 == c
a == b==c
时会导致语法错误 - - 但它应该是什么还不清楚。

© www.soinside.com 2019 - 2024. All rights reserved.