我正在努力为一个简单的标记语言编写解析器。目前,我在infinit循环和嵌套元素方面遇到了一些问题。
我的标记语言基本上由两个元素组成,一个用于“普通”文本,另一个用于粗体/强调文本。
data Markup
= MarkupText String
| MarkupEmph [Markup]
例如,像Foo *bar*
这样的文字应该被解析为[MarkupText "Foo ", MarkupEmph [MarkupText "bar"]]
。
该示例的Lexing工作正常,但解析它导致无限循环 - 我无法理解为什么。这是我目前的做法:
-- 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
而不是'*'
。没有看到它,因为我的实际代码有点复杂。 :)
答案 0 :(得分:1)
自从我处理解析器生成器以来,已经有一段时间了。
看起来你需要一个LR(1)解析器,我不确定Happy是什么。一旦我写这个,我就是肯定的,有人可以纠正我。
如果您的解析器无法向前看,它将永远停留在此声明
Markups1 :: { [Markup] }
: Markups1 Markup1
| Markup1
它会查找Markups1,然后查找Markups1。我可以猜到最好的,它不是向Markup1展望它是否是一个字符串。
尝试像这样重写
Markups1 :: { [Markup] }
: Markup1 Markups1
|
基本上你希望它首先找到字符串,然后尝试查找另一个字符串,如果找不到它需要结束该语句。