【问题标题】:Nested parsers in happy / infinite loop?快乐/无限循环中的嵌套解析器?
【发布时间】:2011-01-02 17:50:42
【问题描述】:

我正在努力为一种简单的标记语言编写解析器。目前,我在使用无限循环和嵌套元素时遇到了一些问题。

我的标记语言基本上由两种元素组成,一种用于“普通”文本,另一种用于粗体/强调文本。

data Markup
    = MarkupText   String
    | MarkupEmph   [Markup]

例如,像Foo *bar* 这样的文本应该被解析为[MarkupText "Foo ", MarkupEmph [MarkupText "bar"]]。

该示例的词法分析工作正常,但解析它会导致无限循环 - 我不明白为什么。这是我目前的做法:

-- The main parser: Parsing a list of "Markup"
Markups     :: { [Markup] }
            : Markups Markup                    { $1 ++ [$2] }
            | Markup                            { [$1]       }

-- One single markup element
Markup      :: { Markup }
            : '*' Markups1 '*'                  { MarkupEmph $2 }
            | Markup1                           { $1            }

-- The nested list inside *..*
Markups1    :: { [Markup] }
            : Markups1 Markup1                  { $1 ++ [$2] }
            | Markup1                           { [$1]       }

-- Markup which is always available:
Markup1     :: { Markup }
            : String                            { MarkupText $1 }

这种方法有什么问题?怎么解决?

更新:抱歉。 Lexing 没有按预期工作。无限循环在词法分析器内部。对不起。 :)

更新 2: 应要求,我将其用作词法分析器:

lexer :: String -> [Token]
lexer [] = []
lexer str@(c:cs)

    | c == '*'              = TokenSymbol "*"   : lexer cs
    -- ...more rules...
    | otherwise             = TokenString val   : lexer rest

  where (val, rest) = span isValidChar str
        isValidChar = (/= '*')

发生无限递归是因为我在'*' 的第一条规则中使用了lexer str 而不是lexer cs。没有看到它,因为我的实际代码有点复杂。 :)

【问题讨论】:

  • 为了确保这个问题的完整性,您可以发布词法分析器的前后。这样其他人就可以看到出了什么问题。谢谢。

标签: haskell happy


【解决方案1】:

只是一个警告,自从我处理解析器生成器以来已经有一段时间了。

看来您需要一个 LR(1) 解析器,我不确定 Happy 是否。我很肯定,一旦我写了这篇文章,有人将能够纠正我。

如果你的解析器不能向前看,它将永远停留在这条语句上

Markups1    :: { [Markup] }
        : Markups1 Markup1 
        | Markup1

它将查找 Markups1,然后再查找 Markups1。最好的我能猜到,它并没有对 Markup1 执行前瞻来查看它是否是一个字符串。

尝试像这样重写它

Markups1    :: { [Markup] }
        : Markup1 Markups1
        | 

基本上你希望它先找到字符串,然后尝试寻找另一个字符串,如果找不到它需要结束该语句。

【讨论】:

  • 我同意这些列表是可疑的 - 我通常写它: x xs { $1 : $2 } | { [] }。
  • 哦,关于LR解析的话题,see this manual page
  • “经典”快乐是 LALR(1)。 @TomMD - 我不确定 GLR 扩展的状态 - 虽然它在代码库中,但我上次尝试它时不确定它是否正常工作。另外我认为 GLR 扩展更多是为自然语言解析而不是解析(歧义)编程语言编写的。
  • 实际上,我认为我的“风格”是必要的,如果你想做类似: Expressions ';' Expression | Expression 的事情,它不是必须有一个最终的;,但你想确保至少有 一个 Expression。我不确定那是什么解析风格,但我只是习惯了它,不认为我会改回来。 :)
  • 啊,有趣。为此,我习惯了制定相互递归的非空 (NN) 规则和可能为空的规则。 listNN : elem list { $1 : $2 } 和 list : listNN { $1 } | {}
猜你喜欢
  • 2018-05-22
  • 1970-01-01
  • 2021-04-23
  • 1970-01-01
  • 1970-01-01
  • 2015-06-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多