"end" { return 'END'; }
...
0[xX][0-9a-fA-F]+ { return 'NUMBER'; }
[A-Za-z_$][A-Za-z0-9_$]* { return 'IDENT'; }
...
Call
: IDENT ArgumentList
{{ $$ = ['CallExpr', $1, $2]; }}
| IDENT
{{ $$ = ['CallExprNoArgs', $1]; }}
;
CallArray
: CallElement
{{ $$ = ['CallArray', $1]; }}
;
CallElement
: CallElement "." Call
{{ $$ = ['CallElement', $1, $3]; }}
| Call
;
你好!所以,在我的语法中,我希望"res.end((;"不检测 end 作为关键字,而是检测为标识。我已经考虑了一段时间,但无法解决。有人有什么想法吗?谢谢!
编辑:这是一种类似C的编程语言。
问题中没有足够的信息来证明我在这里所做的假设,所以这个答案可能不准确。
假设我们有一种有点类似Lua的语言,其中a.b
是a["b"]
的句法糖。此外,由于 . 必须后跟一个词法标识符 - 换句话说,它永远不会跟有句法关键字 - 我们希望在此上下文中禁止关键字识别。
这是一个非常简单的规则。它非常简单,词法分析器可以在没有任何语义信息的情况下实现它;它所说的只是 . 后面的令牌必须是标识符。在这种情况下,关键字应被视为标识符,标识符以外的任何其他内容都是错误。
我们可以在启动条件下做到这一点。具体来说,我们定义了一个仅在 . 令牌之后使用的开始条件:
%x selector
%%
/* White space and comment rules need to explicitly include
* the selector condition
*/
<INITIAL,selector>s+ ;
/* Other rules, including keywords, are unmodified */
"end" return "END";
/* The dot rule triggers a new start condition */
"." this.begin("selector"); return ".";
/* Outside of the start condition, identifiers don't change state. */
[A-Za-z_]w* yylval = yytext; return "ID";
/* Only identifiers are valid in this start condition, and if found
* the start condition is changed back. Anything else is an error.
*/
<selector>[A-Za-z_]w* yylval = yytext; this.popState(); return "ID";
<selector>. parse_error("Expecting identifier");
修改你的解析器,让它总是知道它接下来要读取什么(这将是一组令牌,你可以使用 First(x( 的概念来计算它,因为 x 是任何非终端(。
进行词法分析时,让词法分析器询问解析器接下来需要哪组标记。"end"的键工作协调器会询问解析器,它要么以"期望'end'"的方式"期望'end'",词法分析器只是在'end'词法上交出哪个指针,要么说"期望ID",此时它会向解析器递给一个名称文本为"end"的ID。
这可能方便也可能不方便让你的解析器做。 但是你需要这样的东西。
我们使用 GLR 解析器;我们的解析器在同一位置接受多个令牌。 我们的解决方案是生成"end"关键字和带有文本"end"的标识符,并将它们都塞入GLR解析器中。 它可以处理局部歧义;由此引起的多次解析继续进行,直到具有错误假设的解析器遇到语法错误,然后它就会消失,通过命令。 最后一个常设解析器是具有正确假设集的解析器。 这个方案有点像第一个方案,只是我们把选择交给解析器,它决定而不是让词法分析器决定。
你也许可以向解析器发送一个"双解释"词法,例如,一个上下文中的关键字词法,它本质上声称它既是关键字又是标识符。 通过内部的单个令牌前瞻,解析器可能可以轻松决定并重新标记词法。 不像 GLR 解决方案那样通用,但可能在很多情况下都有效。