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

Javascript 使用JISON匹配但忽略嵌套括号,javascript,parsing,jison,Javascript,Parsing,Jison,我正在为模板系统编写语法。我在构建过程中遇到了一个障碍,我不太明白如何解决这个问题。我简化了测试用例,以便更好地强调我正在做的事情 示例字符串: (foo)-有效 (foo())-失败应为'parenEnd',获得'parenterior' foo(foo)条 foo(foo(function(){console.log('stuff');}))条 foo(foo.bar.baz(“东西”))条 规则是,在插入语中,任何内容都可以是任何字符。我不需要验证,也不需要确保它们匹配正确的格式。另一

我正在为模板系统编写语法。我在构建过程中遇到了一个障碍,我不太明白如何解决这个问题。我简化了测试用例,以便更好地强调我正在做的事情

示例字符串:

  • (foo)
    -有效
  • (foo())
    -失败
    应为'parenEnd',获得'parenterior'
  • foo(foo)条
  • foo(foo(function(){console.log('stuff');}))条
  • foo(foo.bar.baz(“东西”))条
规则是,在插入语中,任何内容都可以是任何字符。我不需要验证,也不需要确保它们匹配正确的格式。另一方面,根据我的理解,为了让解析器正常工作,我确实需要跟踪打开和关闭
,否则lexer无法知道一个插入语句的开始和另一个结束,例如
(foo())(bar)
。为了跟踪这一点,我使用了一个
paren
start条件,每当在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;
%lex
%x帕伦
%%
\s+/*跳过空格*/
({this.begin(“paren”);parenCount=1;返回“parenStart”;};
({console.log(“parenStart”,parenCount);parenCount++;返回“parenInterior”;};
“{console.log(“parenEnd”,parenCount);parenCount--;if(parenCount==0){this.popState();return“parenEnd”;}否则{return“parenterior”;};
[^\)\(]+{console.log(this);返回“parenterior”;};
返回“EOF”;
。返回“无效”;
/莱克斯
%起始表达式
%%/*语言语法*/
表达
:parenStart parenterior parenEnd{返回$1+$2+$3;}
;
%%
parenCount=0;

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

%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;
%lex
%x帕伦
%%
\s+/*跳过空格*/
({this.begin(“paren”);parenCount=1;返回“parenStart”;};
({console.log(“parenStart”,parenCount);parenCount++;返回“parenInterior”;};
“{console.log(“parenEnd”,parenCount);parenCount--;if(parenCount==0){this.popState();return“parenEnd”;}否则{return“parenterior”;};
[^\)\(]+{console.log(this);返回“parenterior”;};
返回“EOF”;
.返回“无论什么”;
/莱克斯
%起始表达式
%%/*语言语法*/
表达
:whateverSeq parenStart parenInteriorSeq Parenen和whateverSeq EOF{返回$1+$2+$3+$4+$5;}
;
帕累尼蒂罗塞克
:第九层
|parenInteriorSeq parenInterior->1.concat(2美元)
;
whateverSeq
:->=“//空序列。
|whatevers//一个或多个任意标记。
;
无论如何
:随便
|whateverSeq无论什么->1美元。concat($2)
;
%%
parenCount=0;
那么嵌套括号就没有问题了

显著变化:

  • 无效的
    替换为
    WHATEVER
    。添加规则以在开始和结束处具有一系列的
    WHATEVER
    标记。这允许使用类似
    的blah(foo)blah

  • parenInterior
    替换为
    parenInteriorSeq
    ,这样可以在括号内有
    parenInterior
    标记序列。这是必要的,因为在类似
    (foo())
    的字符串中,
    foo
    是一个标记,下一个
    是另一个标记,下一个
    是另一个令牌。因此您必须接受令牌列表


  • 我不知道更多关于吉森的信息,从阅读本文中我可以了解到,所以我可能错了。当你说“失败
    期望'parenEnd',得到'parenterior'
    ”,它怎么知道会发生什么?它是否期望输出是
    parenStart
    parenterior
    parenEnd
    ,就像在
    表达式中一样?如果我没有读错的话,
    的实际输出(foo())
    将是
    parenStart
    parenterior
    parenterior
    parenterior
    parennd
    。因此,在第三次输出之前,它的行为与预期一致,这是
    parenterior
    预期的时间。我很确定你是正确的,但我如何更正它?早些时候,我尝试了
    parenteriors:parenteriors parenterior | parenterior
    规则,但一开始它就阻塞了。这有什么意义吗?你可以在上在线测试语法,如果有帮助的话,可以复制并粘贴我的规则。我想路易斯的答案是我们能得到的最接近的答案,而这个问题没有更多的明确性。你说“规则是在括号内,任何内容都可以,任何字符都可以。”,你说括号必须匹配,但我认为你没有提供更多信息。例如,带有两对非嵌套括号的字符串,如
    ()()
    ,或者根本没有括号,在这个答案下会失败;这可能不是您想要的。此外,如果您想确保花括号也成对排列,同时避免字符串,例如
    ({}
    ,整数值变量
    paren
    是不够的。您需要用堆栈(或数组)替换它一组括号符号,每一个都可以是
    {
    。当你遇到一个打开的括号时,将其推到堆栈中;当你得到一个关闭的括号时,从堆栈中弹出一个,并确保它与你刚才看到的括号匹配