在Happy和Alex推回令牌

时间:2016-11-10 22:27:26

标签: haskell ghc happy

我正在解析同时具有<<<的语言。在我的Alex定义中,我有一些包含类似

的内容
tokens :-

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

因此,每当遇到<<时,它都会被标记为左移,而不是,而不是“。这通常是一件好事,因为我最终会在标记化后丢弃空白并希望区分1 < < 21 << 2。但是,有时我希望<<被视为两个<。例如,我有像

这样的东西
<<A>::B> 

我希望阅读

< < A > :: B >

显然,我可以尝试调整我的快乐解析器规则以适应额外的情况,但这种情况会严重缩放。在其他命令式解析器生成器中,我可能会尝试执行诸如推回&#34; part&#34;令牌{(push_back("<")当我遇到<<但我只需要<)。

有没有其他人有这样的问题,如果有的话,你是怎么处理它的?有没有什么方法可以推迟&#34;快乐的代币?我是否应该尝试保留一个空格标记(我实际上倾向于最后一个选择 - 尽管是一个巨大的头痛,它会让我通过确保之间没有空格来处理<<。两个<)。

2 个答案:

答案 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 <<作为一个标记。解决方案有两个方面:

  1. 我咬了一下子弹并为<<添加了额外的规则(之前我只有<的规则)。对于问题(<<A>::B>)中的示例,我的规则来自

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

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

    (实际的规则实际上有点涉及,但这不是这个答案)。

  2. 我找到了一种聪明的方式来处理以>开头的令牌(这些会导致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 。这样做可以提前查看下一个令牌,该令牌可能从>开始而不是>,并尝试将该令牌转换为一个>令牌,另一个令牌用于“休息” “最初的令牌。