我正在编写一个编译器(在Haskell中),并且在语言的语法中有添加中缀运算符的规则(以添加为例):
EAdd . Expr ::= Expr "+" Expr
表示EAdd
是一个表达式,它由表达式,字符串"+"
和另一个表达式组成。
Parser返回抽象语法树(AST):
data Expr = ... | EAdd Expr Expr
如果检查函数的调用是否给出了正确类型的参数,我想创建一个类型检查器。
注意,“+”是一个取两个整数并返回整数的函数。其他运营商也很相似。
目前我提出了三种类型检查EAdd
的方法,所有这些方法都包括将“+”作为函数添加到初始符号表中:
声明infix plus是用两个参数调用函数“+”的语法糖。将“desugarizer”放入解析器和类型检查器之间,将解析器中的AST转换为另一个数据类型(不含EAdd
)。
(类似于第一个)声明infix plus是语法糖,但desugarizer使用相同的AST数据类型。当Typechecker给出EAdd
时会返回错误。
将“desugarizer”内联到typechecker。与此类似:
...
typecheck (EAdd a b) = typecheck (ECall infixPlus [a, b])
...
请注意,所有二进制中缀运算符都受此限制(其他算术,布尔运算,比较运算符)。
似乎第一种方法是正确的方法。但这意味着稍后在编译器管道中,特别是在代码生成器中,那些ECalls
应该作为特殊情况处理,因为在编译器输出(在我的例子中是llvm)这些函数应该被内联(与通常的函数调用不同)。
这意味着codegen有一个函数列表,其调用的处理方式与其他函数调用不同。
解决此问题的最佳方法是什么?
UPD
如何在Haskell中处理此类似问题(来自https://ghc.haskell.org/trac/ghc/wiki/Commentary/Compiler/Renamer):
... renamer做了以下事情:
- 整理出固定内容。无论固定性如何,解析器都会将所有中缀应用程序解析为左关联。例如,“a + b * c”被解析为“(a + b)* c”。重命名器使用模块中声明的固定重新关联这些嵌套的操作员应用程序。
答案 0 :(得分:1)