Javascript 用下划线检测变量;为什么这不起作用?

Javascript 用下划线检测变量;为什么这不起作用?,javascript,parsing,grammar,pegjs,Javascript,Parsing,Grammar,Pegjs,我正在尝试编写一个PEGjs规则来转换 Return _a_b_c_. 到 及 但这辆车出了点问题 Return _a_b_c_. 例如 我不太明白为什么会这样,我希望能解释一下为什么会这样。(我甚至不需要这个问题的解决方案;最大的问题是我的PEGjs语法心智模型有缺陷。)解析器将最后一个.解释为variableSecgment。如果将点从variableSegmentRegExp中排除,则代码将按预期工作。稍微重新排列语法会使其工作: root = atoms:atom+ { return

我正在尝试编写一个PEGjs规则来转换

Return _a_b_c_.

但这辆车出了点问题

Return _a_b_c_.
例如


我不太明白为什么会这样,我希望能解释一下为什么会这样。(我甚至不需要这个问题的解决方案;最大的问题是我的PEGjs语法心智模型有缺陷。)

解析器将最后一个
.
解释为variableSecgment。如果将点从
variableSegment
RegExp中排除,则代码将按预期工作。

稍微重新排列语法会使其工作:

root = atoms:atom+
{ return atoms.join(''); }

atom = variable
     / normalText

variable = "_" first:$(variableSegment "_") rest:$(variableSegment "_")*
{ return '<>' + first + rest + '</>'; }

variableSegment = seg:$[^\n_ ]+

normalText = normal:$[^\n]

现在,贪婪的
*
组在向前窥视

失败时将回溯。
匹配
“\u”变量段
部分,但随后的
丢失,这就是使用
normalText
规则的原因。(
Return\u a\u b\u c.
Return\u a\u b\u c\u d
相同)为什么它没有看到规则在以这种方式解释时不匹配,而是将最后一个解释为尾随?如果在
之后没有看到尾随
时失败,它会通过假设前导的
\u a
是“正常”。我不知道为什么。哦-如果您不想看到尾随的
\uuu
我不认为“.”字符有任何特殊意义,请添加更多详细信息VariableSegment=$[^\n\u\.]+正如fgnas所说,排除.fixed可以解决问题。您是否尝试过使用?是的,但是
Return\u a\u b\u c\d
仍然无法按预期工作。据我所知@Domenic的语法变量应该始终以下划线结尾?这是因为规则不再含糊不清。否则它将找到另一个
variablesgment”_“
或变量已完成(它是该规则的最后一部分)。PEG.js在
变量
中没有后退一步。它试图一步一步地匹配它,要么是实现(在您的情况下),要么是原始代码中的失败。(很抱歉解释得不好)@t.niese是的,这就是我刚才编辑的部分的意思。一旦其中一个子表达式匹配,它就不会在列表中回溯。我不太明白为什么,但我认为这只是元语法的语义。我认为PEG.js就是这样定义的,以避免出现无法确定文本的某一部分为什么与语法匹配的情况。语法分析器越灵活,调试规则就越困难。@t.niese是的,它不愿意主动回溯,这是有道理的,因为它可能在语法中更明确。这非常有用。我在原稿中犯了一个错误;输出应为
返回a_b_c
(无尾随
)。我编辑了我的文章,你可能想编辑你的答案,以免让未来的人感到困惑,但你对这个问题的剖析非常有帮助。
Return _a_b_c_ .
Return _a_b_c_
Return _a_b_c_.
root = atoms:atom+
{ return atoms.join(''); }

atom = variable
     / normalText

variable = "_" first:$(variableSegment "_") rest:$(variableSegment "_")*
{ return '<>' + first + rest + '</>'; }

variableSegment = seg:$[^\n_ ]+

normalText = normal:$[^\n]
root = atoms:atom+
{ return atoms.join(''); }

atom = variable
     / normalText

variable = "_" first:variableSegment rest:$("_" variableSegment & "_")* "_"
{ return '<>' + first + rest + '</>'; }

variableSegment = $[^\n_ ]+

normalText = $[^\n]