我正在解析同时具有<
和<<
的语言。在我的Alex定义中,我有一些包含类似
tokens :-
"<" { token Lt }
"<<" { token (BinOp Shl) }
因此,每当遇到<<
时,它都会被标记为左移,而不是,而不是“。这通常是一件好事,因为我最终会在标记化后丢弃空白并希望区分1 < < 2
和1 << 2
。但是,有时我希望<<
被视为两个<
。例如,我有像
<<A>::B>
我希望阅读
< < A > :: B >
显然,我可以尝试调整我的快乐解析器规则以适应额外的情况,但这种情况会严重缩放。在其他命令式解析器生成器中,我可能会尝试执行诸如推回&#34; part&#34;令牌{(push_back("<")
当我遇到<<
但我只需要<
)。
有没有其他人有这样的问题,如果有的话,你是怎么处理它的?有没有什么方法可以推迟&#34;快乐的代币?我是否应该尝试保留一个空格标记(我实际上倾向于最后一个选择 - 尽管是一个巨大的头痛,它会让我通过确保之间没有空格来处理<<
。两个<
)。
答案 0 :(得分:2)
我不知道如何在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
在解析包含角度括号的术语时,您同时接受角度令牌和<
/ >
运算符。
这取决于你的语法不是模棱两可的。是否应该解析运营商名称或括号内的东西。
答案 1 :(得分:0)
虽然我最初使用@ Jon的答案,但我最终遇到了各种与优先级相关的问题(认为优先于expr < expr
vs expr << expr
)这引起了很多麻烦。我最近(成功地)回到lexing <<
作为一个标记。解决方案有两个方面:
我咬了一下子弹并为<<
添加了额外的规则(之前我只有<
的规则)。对于问题(<<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),利用{%% ... }
RHS规则,让您重新考虑前瞻标记,并将pushToken
工具添加到我的解析器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
。这样做可以提前查看下一个令牌,该令牌可能从>
开始而不是>
,并尝试将该令牌转换为一个>
令牌,另一个令牌用于“休息” “最初的令牌。