Jison Lexer - 在特定时间将特定关键字检测为标识符
Jison Lexer - Detect Certain Keyword as an Identifier at Certain Times
"end" { return 'END'; }
...
0[xX][0-9a-fA-F]+ { return 'NUMBER'; }
[A-Za-z_$][A-Za-z0-9_$]* { return 'IDENT'; }
...
Call
: IDENT ArgumentList
{{ $$ = ['CallExpr', , ]; }}
| IDENT
{{ $$ = ['CallExprNoArgs', ]; }}
;
CallArray
: CallElement
{{ $$ = ['CallArray', ]; }}
;
CallElement
: CallElement "." Call
{{ $$ = ['CallElement', , ]; }}
| Call
;
您好!因此,在我的语法中,我希望 "res.end();" 不将 end 检测为关键字,而是检测为标识。我一直在想这个问题,但无法解决。有人有什么想法吗?谢谢!
编辑:这是一种类 C 的编程语言。
修改您的解析器,使其始终知道接下来要读取的内容(这将是一些标记集,您可以使用 First(x) 的概念来计算它,因为 x 是任何非终结符)。
进行词法分析时,让词法分析器询问解析器接下来需要哪一组标记。
'end' 的 keywork reconizer 询问解析器,它要么 "expecting 'end'" 词法分析器在哪个指针上简单地传递 'end' 词素,要么它说 "expecting ID" 在哪个点上它向解析器提供一个名称为文本 "end".
的 ID
让您的解析器执行此操作可能方便也可能不方便。但是你需要这样的东西。
我们使用 GLR 解析器;我们的解析器在同一个地方接受多个标记。我们的解决方案是同时生成 'end' 关键字和带有文本 "end" 的标识符,并将它们都推送到 GLR 解析器中。它可以处理局部歧义;由此引起的多次解析一直持续到假设错误的解析器遇到语法错误,然后它就消失了。最后一个解析器是具有正确假设集的解析器。这个方案有点像第一个,只是我们将选择交给解析器,由它来决定,而不是让词法分析器来决定。
您可以向您的解析器发送一个 "two-interpretation" 词素,例如上下文中的关键字词素,它在本质上声称它既是关键字 and/or 又是标识符。通过内部单个标记前瞻,解析器很可能可以轻松决定并重新标记词位。不像 GLR 解决方案那样通用,但可能适用于很多情况。
问题中没有足够的信息来证明我在这里所做的假设是正确的,所以这个答案可能不准确。
假设我们有一种有点像 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");
"end" { return 'END'; }
...
0[xX][0-9a-fA-F]+ { return 'NUMBER'; }
[A-Za-z_$][A-Za-z0-9_$]* { return 'IDENT'; }
...
Call
: IDENT ArgumentList
{{ $$ = ['CallExpr', , ]; }}
| IDENT
{{ $$ = ['CallExprNoArgs', ]; }}
;
CallArray
: CallElement
{{ $$ = ['CallArray', ]; }}
;
CallElement
: CallElement "." Call
{{ $$ = ['CallElement', , ]; }}
| Call
;
您好!因此,在我的语法中,我希望 "res.end();" 不将 end 检测为关键字,而是检测为标识。我一直在想这个问题,但无法解决。有人有什么想法吗?谢谢!
编辑:这是一种类 C 的编程语言。
修改您的解析器,使其始终知道接下来要读取的内容(这将是一些标记集,您可以使用 First(x) 的概念来计算它,因为 x 是任何非终结符)。
进行词法分析时,让词法分析器询问解析器接下来需要哪一组标记。 'end' 的 keywork reconizer 询问解析器,它要么 "expecting 'end'" 词法分析器在哪个指针上简单地传递 'end' 词素,要么它说 "expecting ID" 在哪个点上它向解析器提供一个名称为文本 "end".
的 ID让您的解析器执行此操作可能方便也可能不方便。但是你需要这样的东西。
我们使用 GLR 解析器;我们的解析器在同一个地方接受多个标记。我们的解决方案是同时生成 'end' 关键字和带有文本 "end" 的标识符,并将它们都推送到 GLR 解析器中。它可以处理局部歧义;由此引起的多次解析一直持续到假设错误的解析器遇到语法错误,然后它就消失了。最后一个解析器是具有正确假设集的解析器。这个方案有点像第一个,只是我们将选择交给解析器,由它来决定,而不是让词法分析器来决定。
您可以向您的解析器发送一个 "two-interpretation" 词素,例如上下文中的关键字词素,它在本质上声称它既是关键字 and/or 又是标识符。通过内部单个标记前瞻,解析器很可能可以轻松决定并重新标记词位。不像 GLR 解决方案那样通用,但可能适用于很多情况。
问题中没有足够的信息来证明我在这里所做的假设是正确的,所以这个答案可能不准确。
假设我们有一种有点像 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");