使用JISON匹配但忽略嵌套括号

时间:2014-10-14 21:43:56

标签: javascript parsing jison

我正在研究模板系统的语法。我在构建中遇到了障碍,我无法弄清楚如何解决这个问题。我已经简化了测试用例,以便最好地强调我正在做的事情。

示例字符串:

  • (foo) - 作品
  • (foo()) - 失败Expecting 'parenEnd', got 'parenInterior'
  • foo (foo) bar
  • foo (foo(function() { console.log('stuff'); })) bar
  • foo (foo.bar.baz("stuff")) bar

规则是在括号内,任何内容,任何字符。我不需要验证,我也不需要确保它们匹配正确的格式。另一方面,根据我的理解,为了使解析器起作用,我需要跟踪打开和关闭(),否则词法分析器无法知道一个括号语句的开始位置和另一个结束,例如(foo()) (bar)。为了跟踪我正在使用paren启动条件,只要在paren语句中遇到paren就递增一个值,并在关闭paren时删除它。

问题是它不起作用。主要的罪魁祸首是它似乎永远不会达到我的<paren>")"规则,但我正好点击<paren>"("规则。它们在语法上看起来是一样的,为什么一个工作而另一个不工作?

语法

%lex

%x paren

%%

\s+                   /* skip whitespace */
<INITIAL>"("         { this.begin("paren"); parenCount = 1; return "parenStart"; };
<paren>"("            { console.log("parenStart", parenCount); parenCount++; return "parenInterior"; };
<paren>")"            { console.log("parenEnd", parenCount); parenCount--; if (parenCount === 0) { this.popState(); return "parenEnd"; } else { return "parenInterior"; } };
<paren>[^\)\(]+       { console.log(this); return "parenInterior"; };
<<EOF>>               return 'EOF';
.                     return 'INVALID';

/lex

%start expressions

%% /* language grammar */

expressions
    : parenStart parenInterior parenEnd { return $1 + $2 + $3; }
    ;

%%

parenCount = 0;

1 个答案:

答案 0 :(得分:1)

我相信你的问题是你的语法不接受令牌的序列。如果我将你的语法改为这个,那么我会得到一些可以处理你在问题中显示的字符串的东西:

%lex

%x paren

%%

\s+                   /* skip whitespace */
<INITIAL>"("         { this.begin("paren"); parenCount = 1; return "parenStart"; };
<paren>"("            { console.log("parenStart", parenCount); parenCount++; return "parenInterior"; };
<paren>")"            { console.log("parenEnd", parenCount); parenCount--; if (parenCount === 0) { this.popState(); return "parenEnd"; } else { return "parenInterior"; } };
<paren>[^\)\(]+       { console.log(this); return "parenInterior"; };
<<EOF>>               return 'EOF';
.                     return 'WHATEVER';

/lex

%start expressions

%% /* language grammar */

expressions
    : whateverSeq parenStart parenInteriorSeq parenEnd whateverSeq EOF { return $1 + $2 + $3 + $4 + $5; }
    ;

parenInteriorSeq
    : parenInterior 
    | parenInteriorSeq parenInterior -> $1.concat($2)
    ;

whateverSeq
    : -> ""      // Empty sequence.
    | whatevers  // One or more WHATEVER tokens.
    ;

whatevers
    : whatever
    | whateverSeq WHATEVER -> $1.concat($2)
    ;

%%

parenCount = 0;

然后嵌套括号没问题。

突出的变化:

  1. INVALID替换WHATEVER。添加了规则,以便在开头和结尾都有一系列WHATEVER标记。这允许包含blah (foo) blah

  2. 之类的内容
  3. parenInterior替换为parenInteriorSeq,以便您可以在括号内包含parenInterior个令牌序列。这是必要的,因为在(foo())之类的字符串中,foo是一个标记,下一个(是另一个标记,下一个)是另一个标记。所以你必须接受一个令牌列表。