【发布时间】:2015-08-13 19:06:56
【问题描述】:
我已经用 Alex 编写了一个词法分析器,我正在尝试将它连接到一个用 Happy 编写的解析器。我会尽量在不粘贴大量代码的情况下总结我的问题。
我从我的词法分析器的单元测试中知道字符串 "\x7" 被词法化为:
[TokenNonPrint '\x7', TokenEOF]
我的令牌类型(由词法分析器吐出)是Token。我已经按照here 的描述定义了lexWrap 和alexEOF,这给了我以下标头和令牌声明:
%name parseTokens
%tokentype { Token }
%lexer { lexWrap } { alexEOF }
%monad { Alex }
%error { parseError }
%token
NONPRINT {TokenNonPrint $$}
PLAIN { TokenPlain $$ }
我使用以下内容调用解析器+词法分析器组合:
parseExpr :: String -> Either String [Expr]
parseExpr s = runAlex s parseTokens
这是我最初的几部作品:
exprs :: { [Expr] }
exprs
: {- empty -} { trace "exprs 30" [] }
| exprs expr { trace "exprs 31" $ $2 : $1 }
nonprint :: { Cmd }
: NONPRINT { NonPrint $ parseNonPrint $1}
expr :: { Expr }
expr
: nonprint {trace "expr 44" $ Cmd $ $1}
| PLAIN { trace "expr 37" $ Plain $1 }
我将省略 Expr 和 NonPrint 的数据类型声明,因为它们很长,这里只有构造函数 Cmd 和 NonPrint 重要。函数parseNonPrint 在 Parse.y 的底部定义为:
parseNonPrint :: Char -> NonPrint
parseNonPrint '\x7' = Bell
另外,我的错误处理函数如下:
parseError :: Token -> Alex a
parseError tokens = error ("Error processing token: " ++ show tokens)
这样写,我希望下面的 hspec 测试通过:
parseExpr "\x7" `shouldBe` Right [Cmd (NonPrint Bell)]
但相反,我看到"exprs 30" print 一次(即使我正在运行 5 个不同的单元测试)并且我对parseExpr 的所有测试都返回Right []。我不明白为什么会这样,但我更改了 exprs 生产以防止它:
exprs :: { [Expr] }
exprs
: expr { trace "exprs 30" [$1] }
| exprs expr { trace "exprs 31" $ $2 : $1 }
现在我的所有测试都在他们命中的第一个令牌上失败 --- parseExpr "\x7" 失败:
uncaught exception: ErrorCall (Error processing token: TokenNonPrint '\a')
我非常困惑,因为我希望解析器采用路径 exprs -> expr -> nonprint -> NONPRINT 并成功。我不明白为什么这个输入会使解析器处于错误状态。没有trace 语句被命中(优化了吗?)。
我做错了什么?
【问题讨论】:
-
你能指出我们的代码 - 即 github repo 吗?
-
@user5402 github.com/pscollins/ansi-parser 拥有所有代码。目前有点草率,尤其是测试的标签。
标签: parsing haskell happy alex