【问题标题】:A good AST design for a c-like language (for llvm)类 c 语言的良好 AST 设计(适用于 llvm)
【发布时间】:2011-09-14 05:01:52
【问题描述】:

我正在尝试使用 llvm 来实现一种简单、愚蠢的类 c 语言。 而且我一直致力于设计一个好的 AST。

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

Foo = asd = 3; 

在这种情况下 Foo 和 add 将是一个分配,但 add 也将是一个加载。 但是 ast 节点是在它们的 code() 方法中加入的。

有没有关于设计 ast 的好资源? (我试图找到 clang 的,但从它的源文件中轻松理解有点复杂。)

【问题讨论】:

  • 对左值和右值有不同的表示是有意义的。在这里,您的 AST 可能类似于:(AssignExpr (LVar Foo) (AssignExpr (LVar asd) (IntLiteral 3))),注意赋值的右关联性,并注意它是一个表达式,而不是一个语句。

标签: compiler-construction llvm abstract-syntax-tree


【解决方案1】:

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

Foo = (asd = 3);

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

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

如果我没记错万花筒的例子,你会发现它们的每条语句都返回一个值。其中大多数将在链条的下游进一步优化,但它们是为嵌套分配等获得有用行为的最简单方法。显然,作业的左侧需要特殊处理,但没有什么难以理解或难以实施。

【讨论】:

    【解决方案2】:

    你或许可以从 Go 的 AST 包中获得一些灵感:http://golang.org/pkg/go/ast/

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

    AssignExpr{
        Lhs: Ident{
            Name: "Foo",
        },
        Tok: token.ASSIGN
        Rhs: AssignExpr{
            Lhs: Ident{
                Name: "asd",
            },
            Rhs: BasicLit{
                Kind: token.INT,
                Value: "3",
            },
        },
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-06-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-05-06
      • 2022-09-18
      相关资源
      最近更新 更多