flex / bison解析器是否可以按任何顺序从集合中接受最多一个令牌

时间:2015-01-21 01:43:23

标签: bison yacc flex-lexer lex

在我的语言中,在特定点我需要从一组令牌中接受最多一个令牌。举一个例子,带括号的表达式后面的任何顺序最多可以跟!^&一个,所以下面两行应该是等价的

(foo)!^
(foo)^!

以下一个是非法的(令牌重复两次)

(foo)^!^

这是否可行,当然不能用CFG规则耗尽所有可能性?无论是词汇(flex)还是句法(bison)等级都可以。

1 个答案:

答案 0 :(得分:1)

除了枚举所有可能性之外,无法使用正则表达式或CFG执行此操作,这是一个因子量的工作。 (通过分组,可以减小实际大小,但它仍然是指数级。)如果您只有一个实例,并且只有三个令牌,那么列表可能是最简单的解决方案。

但是如果存在各种令牌,并且您可能希望将来扩展列表,则可能更容易允许所有令牌组合,但将位图与令牌列表相关联以使其易于检查是否有重复,这可能会导致错误消息。

对于您提到的具体案例,这是一个简单的flex解决方案。 (在我原来,我复制了很多代码,但我认为以下内容更容易阅读。)<MODS>开始条件是由[&^!]的第一次出现触发的,用于吸收其余的他们;遇到任何其他字符时,会将其标记为重新扫描(yyless(0)),并返回修饰符的当前掩码。

%{
  // The MODS token has %type <ModMask>, and the associated
  // semantic value will be the union of the enum bits.
  typedef unsigned int ModMask;
  enum { MOD_HAT=1, MOD_BANG=2, MOD_AMP=4 };
  // This function maps a character to a modmask value.
  // A real implementation would use a lookup table. I just included
  // this definition so the snippet is usable.
  ModMask tokenToMask(unsigned char c) {
    return c == '^' ? MOD_HAT : 
           c == '!' ? MOD_BANG :
           c == '&' ? MOD_AMP : 0;
%}

%x SC_MODS

%%

[&^!]       { yylval.modmask = tokenToMask(yytext[0]; BEGIN(MODS); }
<MODS>[&^!] { ModMask m = tokenToMask(yytext[0];
              if (yylval.modmask & m) {
                yyerror("Duplicate modifier");
              }
              yylval.modmask |= m;
            }
<MODS>.|\n  { yyless(0); BEGIN(INITIAL); return MODS; }