如何在Parsec / Megaparsec中重载运算符?

时间:2019-07-04 00:32:09

标签: haskell parsec megaparsec

我正在使用Parsec/Megaparsec as parser实现编译器。我找不到重载运算符+的方法,我想将其用于整数加法和字符串连接。有可能吗?

1 个答案:

答案 0 :(得分:0)

首先,编写编译器以使用其他运算符进行字符串连接,例如@。当它运行并经过良好的测试后,请看一下您的代码。您可能会发现发生了两件事之一,具体取决于您要解析的语言和所使用的编译器体系结构。

第一个可能性是解析器解析+的部分与解析@的解析器的部分完全分开(例如,它们分为两个部分)不同的解析器函数,一个用于解析数字表达式,另一个用于解析字符串表达式。祝贺您,如果发生这种情况,您只需将"@"替换为"+",运行一些测试,就可以了。

第二次的可能性是,+@在同一位置被解析并产生具有不同构造函数的AST节点:

data Expr ... =
  ...
  | Plus Expr Expr     -- the '+' operator
  | Concat Expr Expr   -- the '@' operator
  ...

在这种情况下,您可能还会在编译器中生成代码的一部分(并希望有一些类型信息):

codeGen (Plus e1 e2)
  = do (code1, typ1) <- codeGen e1
       (code2, typ2) <- codeGen e2
       if (typ1 == Num && typ2 == Num)
         then genPlus code1 code2
         else typeError "'+' needs numbers"
codeGen (Concat e1 e2)
  = do (code1, typ1) <- codeGen e1
       (code2, typ2) <- codeGen e2
       if (typ1 == Str && typ2 == Str)
         then genConcat code1 code2
         else typeError "'@' needs strings"

在这种情况下,您应该修改解析器/ AST以将AST折叠为一个共享的构造函数:

data Expr ... =
  ...
  | ConcatPlus Expr Expr     -- the '+' operator for numbers and strings
  ...

并根据可用的类型信息在代码生成器中处理这两种情况:

codeGen (ConcatPlus e1 e2)
  = do (code1, typ1) <- codeGen e1
       (code2, typ2) <- codeGen e2
       case (typ1, typ2) of
           (Num, Num) -> genPlus code1 code2
           (Str, Str) -> genConcat code1 code2
           _ -> typeError "'+' arguments must have same type (numbers or strings)"

如果您的编译器看起来不像这些示例,则您必须发布一些代码,以便我们确实看到它。