0

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

示例字符串:

  • (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>"("规则。它们在语法上看起来相同,为什么一个有效而另一个无效?

语法

%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;
4

1 回答 1

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. 替换INVALIDWHATEVERWHATEVER添加了规则以在开始和结束处具有一系列标记。这允许拥有类似blah (foo) blah.

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

于 2014-10-15T01:40:24.020 回答