2

我正在解析一种同时具有<和的语言<<。在我的亚历克斯定义中,我有一些包含类似的东西

tokens :-

"<"             { token Lt }
"<<"            { token (BinOp Shl) }

所以每当我遇到 时<<,它都会被标记为左移而不是小于。这通常是一件好事,因为我最终在标记化后丢弃了空格并想要区分1 < < 21 << 2。然而,还有其他时候我希望<<被读为两个<。例如,我有类似的东西

<<A>::B> 

我想读

< < A > :: B >

显然,我可以尝试调整我的 Happy 解析器规则以适应额外的情况,但这扩展性很差。在其他命令式解析器生成器中,我可能会尝试执行诸如推回令牌的“部分”之类的操作(例如push_back("<")当我遇到<<但我只需要时<)。

有没有其他人遇到过这样的问题,如果有,您是如何处理的?兴欣中是否有“推回”代币的方法?我是否应该尝试保留一个空格标记(我实际上倾向于最后一种选择 - 尽管这是一个非常令人头疼的问题,但它会让我<<通过确保两者之间没有空格来处理<)。

4

2 回答 2

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

解析带尖括号的术语时,您接受角度标记和</>运算符。

这取决于您的语法不模棱两可。您是否应该解析运算符名称或括号中的内容。

于 2016-11-10T23:51:31.133 回答
0

虽然我最初选择了@Jon 的答案,但最终遇到了各种与优先级相关的问题(想想expr < exprvs周围的优先级expr << expr),这让我很头疼。我最近(成功地)回到词法<<作为一个标记。解决方案是双重的:

  1. 我硬着头皮添加了额外的规则<<(以前我只有规则<)。对于问题 ( <<A>::B>) 中的示例,我的规则来自类似

    ty_qual_path
      : '<' ty_sum '>' '::' ident
    

    ty_qual_path
      : '<' ty_sum '>' '::' ident
      | '<<' ty_sum '>' '::' ident '>' '::' ident
    

    (实际规则实际上涉及更多,但这不适用于此答案)。

  2. 我找到了一种巧妙的方法来处理开头的标记>(这些会导致诸如vector<i32,vector<i32>>最后>>一个标记的位置出现问题):使用线程词法分析器(第 2.5.2 节),利用{%% ... }规则的 RHS 让您重新考虑前瞻令牌,并pushToken在我的解析器 monad 中添加一个工具(结果证明这很简单——这正是我所做的)。然后我添加了一个虚拟规则 - 比如

    gt :: { () }
      : {- empty -}   {%% \tok ->
          case tok of
            Tok ">>"  -> pushToken (Tok ">")  *> pushToken (Tok ">")
            Tok ">="  -> pushToken (Tok "=")  *> pushToken (Tok ">")
            Tok ">>=" -> pushToken (Tok ">=") *> pushToken (Tok ">")
            _         -> pushToken tok
        }
    

    每次在其他规则中,我期望 a>但也可能有任何其他以 开头的标记>,我会在>标记前面加上gt。这具有展望下一个可能以>没有 is开头的令牌的效果>,并尝试将该令牌转换为一个>令牌和另一个令牌以作为初始令牌的“其余”。

于 2017-03-09T03:47:36.453 回答