2016-11-10 37 views
2

我正在解析同时具有<<<的语言。在我的亚历克斯定义我已经得到的东西,它包含类似在Happy和Alex中推回令牌

tokens :- 

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

所以每当我遇到<<,是被符号化的左移和以低于的。这通常是一件好事,因为我最终在标记后抛出空白,并且想区分1 < < 21 << 2。不过,还有其他的时候我希望<<已经被读为两个<。例如,我有事情喜欢

<<A>::B> 

,我想读到这样

< <A> :: B > 

很显然,我可以尝试调整我的快乐的语法规则,以适应额外的案件,但它可以扩展得厉害。在其他命令式解析器生成器中,我可能会尝试执行某些操作,比如推回令牌的“部分”(如push_back("<"),当我遇到<<但我只需要<时)。

有没有其他人有这样的问题,如果是的话,你是如何处理它的?在快乐中有没有“推回”令牌的方法?我是否应该试着保留一个空白符号(我实际上倾向于最后一种选择 - 尽管这是一个非常头痛的问题,但它会让我通过确保两个<之间没有空格来处理<<)。

回答

0

当我最初与@ Jon的答案一起使用时,我最终遇到了各种与优先级相关的问题(认为优先级大约为expr < expr vs 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>>其中最后>>是一个令牌):使用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。这有望展望下一个令牌,其可以以>而不是>开始,并尝试将该令牌转换为一个>令牌以及用于初始令牌的“休息”的另一个令牌。

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 

当解析尖括号中的条款,您同时接受角度令牌和</>运营商。

这依赖于你的语法不含糊不清。你是否应该解析一个操作符名称或括号内的事物。

+0

聪明的主意!虽然我还没有设法找到Alex获得两个代币的方法,但我可以看到这将如何工作。谢谢! – Alec

+0

@Alec:是的,我只在Parsec中使用过这种技术,你可以向前看(比如'try(运算符<$> char'<'<* notFollowedBy symbol)<|> LeftAngle <$> char'<'')看起来不可能直接在Alex中表达。不知怎的,你大概可以对它进行编码。 –