Compiler construction 类似c语言的良好AST设计(用于llvm)

Compiler construction 类似c语言的良好AST设计(用于llvm),compiler-construction,llvm,abstract-syntax-tree,Compiler Construction,Llvm,Abstract Syntax Tree,我正在尝试使用llvm实现一种简单、愚蠢的c语言。 而且我在设计一个好的AST方面很笨拙 例如,我想知道将一个变量分成两类节点是否是一个好主意: 一个用于分配,一个用于加载。我试过了,但遇到了一些障碍: Foo = asd = 3; 在这种情况下,Foo和add将是一个分配,而add也将是一个加载。 但是ast节点通过其code()方法连接 在设计ast方面有什么好的资源吗? (我试图找到clang的,但从它的源文件中很容易理解它有点复杂。)在大多数允许这种输入的语言中,这将被解析为 Foo

我正在尝试使用llvm实现一种简单、愚蠢的c语言。 而且我在设计一个好的AST方面很笨拙

例如,我想知道将一个变量分成两类节点是否是一个好主意: 一个用于分配,一个用于加载。我试过了,但遇到了一些障碍:

Foo = asd = 3; 
在这种情况下,Foo和add将是一个分配,而add也将是一个加载。 但是ast节点通过其code()方法连接

在设计ast方面有什么好的资源吗?
(我试图找到clang的,但从它的源文件中很容易理解它有点复杂。)

在大多数允许这种输入的语言中,这将被解析为

Foo = (asd = 3);
Foo
将被分配表达式
asd=3
的结果。这通常恰好是asd的值,但AST不需要表示该值

AST通常并不表示“读取访问”之类的语义。它是语法的图形表示,语法只是“使用左侧变量
Foo
和右侧赋值(使用左侧变量
asd
和右侧整数常量
3
赋值)”


如果我正确地记住了万花筒示例,您将看到它们让每条语句都返回一个值。其中大多数都将在链的下游进行优化,但它们是获得嵌套赋值等有用行为的最简单方法。显然,作业的左侧需要特殊处理,但没有什么是难以理解或难以实现的。

在大多数允许这种输入的语言中,这将被解析为

Foo = (asd = 3);
Foo
将被分配表达式
asd=3
的结果。这通常恰好是asd的值,但AST不需要表示该值

AST通常并不表示“读取访问”之类的语义。它是语法的图形表示,语法只是“使用左侧变量
Foo
和右侧赋值(使用左侧变量
asd
和右侧整数常量
3
赋值)”


如果我正确地记住了万花筒示例,您将看到它们让每条语句都返回一个值。其中大多数都将在链的下游进行优化,但它们是获得嵌套赋值等有用行为的最简单方法。显然,作业的左侧需要特殊处理,但没有什么是难以理解或难以实施的。

您可以从Go的AST软件包中获得一些灵感:

这是一种类似C的语言,尽管您的示例不适用,因为Go中的赋值是一个语句,并且不返回值。如果有,您的代码将解析为如下内容: (这是伪围棋,但希望不知道的人能够理解)


您可能会从Go的AST软件包中获得一些灵感:

这是一种类似C的语言,尽管您的示例不适用,因为Go中的赋值是一个语句,并且不返回值。如果有,您的代码将解析为如下内容: (这是伪围棋,但希望不知道的人能够理解)


对左值和右值有不同的表示是有意义的。在这里,您的AST可以是这样的:
(AssignExpr(LVar Foo)(AssignExpr(LVar asd)(IntLiteral 3))
,注意赋值的正确关联性,注意它是一个表达式,而不是一个语句。对左值和右值使用不同的表示是有意义的。这里,您的AST可以是这样的:
(AssignExpr(LVar Foo)(AssignExpr(LVar asd)(IntLiteral 3))
,注意赋值的正确关联性,注意它是一个表达式,而不是一个语句。