我正在研究模板系统的语法。我在构建中遇到了障碍,我无法弄清楚如何解决这个问题。我已经简化了测试用例,以便最好地强调我正在做的事情。
示例字符串:
(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;
答案 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;
然后嵌套括号没问题。
突出的变化:
用INVALID
替换WHATEVER
。添加了规则,以便在开头和结尾都有一系列WHATEVER
标记。这允许包含blah (foo) blah
。
将parenInterior
替换为parenInteriorSeq
,以便您可以在括号内包含parenInterior
个令牌序列。这是必要的,因为在(foo())
之类的字符串中,foo
是一个标记,下一个(
是另一个标记,下一个)
是另一个标记。所以你必须接受一个令牌列表。