在 Happy 和 Alex 中推回令牌
Pushing back tokens in Happy and Alex
我正在解析一种同时具有 <
和 <<
的语言。在我的亚历克斯定义中,我得到了包含类似
的东西
tokens :-
"<" { token Lt }
"<<" { token (BinOp Shl) }
所以每当我遇到 <<
时,它都会被标记为左移, 而不是 小于的。这通常是一件好事,因为我最终在标记化后扔掉了空格并想区分 1 < < 2
和 1 << 2
。但是,有时我希望 <<
被读作两个 <
。例如,我有
<<A>::B>
我想这样读
< < A > :: B >
显然,我可以尝试调整我的 Happy 解析器规则以适应额外的情况,但这很难扩展。在其他命令式解析器生成器中,我可能会尝试做一些事情,比如推回令牌的 "part"(当我遇到 <<
但我只需要 <
时,就像 push_back("<")
一样)。
有没有其他人遇到过这样的问题,如果有,你是如何处理的?兴欣有没有"pushing back"代币的获取方式?我是否应该尝试保留一个空白标记(我实际上倾向于最后一个选择 - 尽管非常头疼,它会让我通过确保两者之间没有空白来处理 <<
<
).
我不知道如何在 Happy 中表达这一点,但你不需要单独的“空白”标记。您可以将 <
或 >
解析为一个独特的“尖括号”标记,当输入中紧跟一个运算符符号时,中间没有空格。
然后,当您想要解析一个运算符时,您可以将一系列角度和运算符连接到一个标记中。当你想把它们当作括号时,你只需照常单独处理即可。
所以 a << b
将被标记为:
identifier "a"
left angle -- joined with following operator
operator "<"
identifier "b"
解析运算符时,将角度标记与以下运算符标记连接起来,生成单个 operator "<<"
标记。
<<A>::B>
将被标记为:
left angle
operator "<" -- accepted as bracket
identifier "A"
right angle
operator "::"
identifier "B"
operator ">" -- accepted as bracket
解析尖括号术语时,您接受尖角标记和 <
/>
运算符。
这取决于您的语法没有歧义。您是否应该解析运算符名称或括号中的内容。
虽然我最初接受了@Jon 的回答,但我最终 运行 陷入了各种与优先级相关的问题(考虑 expr < expr
与 expr << expr
之间的优先级),这给我带来了很多麻烦头痛。我最近(成功地)回到了词法 <<
作为一个标记。解决方案有两个:
我硬着头皮为 <<
添加了额外的规则(之前我只有 <
的规则)。对于问题 (<<A>::B>
) 中的示例,我的规则来自
ty_qual_path
: '<' ty_sum '>' '::' ident
至
ty_qual_path
: '<' ty_sum '>' '::' ident
| '<<' ty_sum '>' '::' ident '>' '::' ident
(实际规则实际上有点复杂,但这不是这个答案)。
我找到了一种巧妙的方法来处理以 >
开头的令牌(这会导致 vector<i32,vector<i32>>
之类的问题,其中最后一个 >>
是令牌):使用 threaded lexer (section 2.5.2), exploit the {%% ... }
RHS of rules which lets you reconsider the lookahead token, and add a pushToken
facility to my parser monad (this turned out to be quite simple - here is exactly what I did)。然后我添加了一个虚拟规则 - 比如
gt :: { () }
: {- empty -} {%% \tok ->
case tok of
Tok ">>" -> pushToken (Tok ">") *> pushToken (Tok ">")
Tok ">=" -> pushToken (Tok "=") *> pushToken (Tok ">")
Tok ">>=" -> pushToken (Tok ">=") *> pushToken (Tok ">")
_ -> pushToken tok
}
每次在其他规则中我都期望 >
但也可能有任何其他以 >
开头的标记,我会在 >
标记之前加上 gt
.这具有向前看可能以 >
开头而不是 >
的下一个标记的效果,并尝试将该标记转换为一个 >
标记和 [= 的另一个标记50=] 的初始令牌。
我正在解析一种同时具有 <
和 <<
的语言。在我的亚历克斯定义中,我得到了包含类似
tokens :-
"<" { token Lt }
"<<" { token (BinOp Shl) }
所以每当我遇到 <<
时,它都会被标记为左移, 而不是 小于的。这通常是一件好事,因为我最终在标记化后扔掉了空格并想区分 1 < < 2
和 1 << 2
。但是,有时我希望 <<
被读作两个 <
。例如,我有
<<A>::B>
我想这样读
< < A > :: B >
显然,我可以尝试调整我的 Happy 解析器规则以适应额外的情况,但这很难扩展。在其他命令式解析器生成器中,我可能会尝试做一些事情,比如推回令牌的 "part"(当我遇到 <<
但我只需要 <
时,就像 push_back("<")
一样)。
有没有其他人遇到过这样的问题,如果有,你是如何处理的?兴欣有没有"pushing back"代币的获取方式?我是否应该尝试保留一个空白标记(我实际上倾向于最后一个选择 - 尽管非常头疼,它会让我通过确保两者之间没有空白来处理 <<
<
).
我不知道如何在 Happy 中表达这一点,但你不需要单独的“空白”标记。您可以将 <
或 >
解析为一个独特的“尖括号”标记,当输入中紧跟一个运算符符号时,中间没有空格。
然后,当您想要解析一个运算符时,您可以将一系列角度和运算符连接到一个标记中。当你想把它们当作括号时,你只需照常单独处理即可。
所以 a << b
将被标记为:
identifier "a"
left angle -- joined with following operator
operator "<"
identifier "b"
解析运算符时,将角度标记与以下运算符标记连接起来,生成单个 operator "<<"
标记。
<<A>::B>
将被标记为:
left angle
operator "<" -- accepted as bracket
identifier "A"
right angle
operator "::"
identifier "B"
operator ">" -- accepted as bracket
解析尖括号术语时,您接受尖角标记和 <
/>
运算符。
这取决于您的语法没有歧义。您是否应该解析运算符名称或括号中的内容。
虽然我最初接受了@Jon 的回答,但我最终 运行 陷入了各种与优先级相关的问题(考虑 expr < expr
与 expr << expr
之间的优先级),这给我带来了很多麻烦头痛。我最近(成功地)回到了词法 <<
作为一个标记。解决方案有两个:
我硬着头皮为
<<
添加了额外的规则(之前我只有<
的规则)。对于问题 (<<A>::B>
) 中的示例,我的规则来自ty_qual_path : '<' ty_sum '>' '::' ident
至
ty_qual_path : '<' ty_sum '>' '::' ident | '<<' ty_sum '>' '::' ident '>' '::' ident
(实际规则实际上有点复杂,但这不是这个答案)。
我找到了一种巧妙的方法来处理以
>
开头的令牌(这会导致vector<i32,vector<i32>>
之类的问题,其中最后一个>>
是令牌):使用 threaded lexer (section 2.5.2), exploit the{%% ... }
RHS of rules which lets you reconsider the lookahead token, and add apushToken
facility to my parser monad (this turned out to be quite simple - here is exactly what I did)。然后我添加了一个虚拟规则 - 比如gt :: { () } : {- empty -} {%% \tok -> case tok of Tok ">>" -> pushToken (Tok ">") *> pushToken (Tok ">") Tok ">=" -> pushToken (Tok "=") *> pushToken (Tok ">") Tok ">>=" -> pushToken (Tok ">=") *> pushToken (Tok ">") _ -> pushToken tok }
每次在其他规则中我都期望
>
但也可能有任何其他以>
开头的标记,我会在>
标记之前加上gt
.这具有向前看可能以>
开头而不是>
的下一个标记的效果,并尝试将该标记转换为一个>
标记和 [= 的另一个标记50=] 的初始令牌。