7

我正在使用 Alex + Happy 为 Haskell 中的 DSL 制作解析器。我的 DSL 使用掷骰子作为可能表达式的一部分。

有时我有一个要解析的表达式,如下所示:

[some code...]  3D6  [... rest of the code]

这应该大致翻译为:

TokenInt {... value = 3}, TokenD, TokenInt {... value = 6}

我的 DSL 也使用变量(基本上是字符串),所以我有一个特殊的标记来处理变量名。所以,有了这个令牌:

"D"                                 { \pos str -> TokenD pos }
$alpha [$alpha $digit \_ \']*       { \pos str -> TokenName pos str}
$digit+                             { \pos str -> TokenInt pos (read str) }

我现在使用解析时得到的结果是:

TokenInt {... value = 3}, TokenName { ... , name = "D6"}

这意味着我的词法分析器“读取”了一个整数和一个名为“D6”的变量。

我尝试了很多东西,例如,我将令牌D更改为:

$digit "D" $digit                   { \pos str -> TokenD pos }

但这只是消耗数字:(

  • 我可以用数字解析骰子吗?
  • 或者至少解析TokenInt-TokenD-TokenInt?

PS:我使用 PosN 作为包装器,不确定是否相关。

4

2 回答 2

1

我将采取的方法是将TokenD类型扩展为TokenD Int Int以便使用basic包装器为方便起见

$digit+ D $digit+ { dice }
...
dice :: String -> Token
dice s = TokenD (read $ head ls) (read $ last ls)
  where ls = split 'D' s

split可以在这里找到。

这是一个额外的步骤,通常在句法分析期间完成,但在这里并没有太大的伤害。

我也不能让 Alex 解析$alphaTokenD而不是TokenName. 如果我们有Di而不是那样,D那就没问题了。来自 Alex 的文档:

当输入流匹配多个规则时,匹配输入流最长前缀的规则获胜。如果仍有多个规则匹配相同数量的字符,则文件中最早出现的规则获胜。

但是你的代码应该可以工作。我不知道这是否是 Alex 的问题。

于 2020-07-13T21:11:13.253 回答
0

我决定我可以使用以小写字母开头的变量(如 Haskell 变量),因此我将词法分析器更改为仅在变量以小写字母开头时才解析变量。这也解决了一些其他保留字可能出现的问题。

我仍然很想知道是否有其他解决方案,但问题本身已经解决了。

谢谢你们!

于 2020-07-14T01:34:05.777 回答