您好我是编译器开发的新手,我想知道AST是怎样的。我有一小段代码,我使用Clang生成AST。我没有得到太多的信息。 从它的外观来看,语法树与源完全相同,除了一个结构添加到我测试的几乎任何样本中。
来源:
class A {
public:
int *a, *b, *c;
int i;
void sum() {
a = new int[5];
b = new int[5];
c = new int[5];
for (i = 0; i < 5; i++) {
a[i] = i;
b[i] = i;
}
for (i = 0; i < 5; i++) {
c[i] = a[i] + b[i];
}
delete[] a; delete[] b; delete[] c;
}
};
class B : public A {
};
int main() {
B bclass;
bclass.sum();
return 0;
}
生成AST的命令:
clang++ -cc1 -ast-print ~/sum.cpp
AST输出:
struct __va_list_tag {
unsigned int gp_offset;
unsigned int fp_offset;
void *overflow_arg_area;
void *reg_save_area;
};
typedef struct __va_list_tag __va_list_tag;
class A {
public:
int *a;
int *b;
int *c;
int i;
void sum() {
this->a = new int [5];
this->b = new int [5];
this->c = new int [5];
for (this->i = 0; this->i < 5; this->i++) {
this->a[this->i] = this->i;
this->b[this->i] = this->i;
}
for (this->i = 0; this->i < 5; this->i++) {
this->c[this->i] = this->a[this->i] + this->b[this->i];
}
delete [] this->a;
delete [] this->b;
delete [] this->c;
}
};
class B : public A {
};
int main() {
B bclass;
bclass.sum();
return 0;
}
由于
答案 0 :(得分:16)
各种选择之间存在一点混淆:
-ast-print
将打印当前的AST,也就是说,它会尽可能地将它理解的代码呈现给它所解析的内容(但是使一些事情变得明确,就像{{1}的幻象一样。 })this
将生成当前AST的类似lisp的表示漂亮的打印机可以用来检查AST是无损的(即,保留-ast-dump
- 这样的表达式等等......)但实际上并不是关于开发。
如果你想破解编译器,你需要const
,它将生成一个直接映射已解析代码的内存中表示的输出。
答案 1 :(得分:5)
AST是内存中的一个链接结构(“树”并不能解决事物的复杂性,但它是人们使用的名称)。 -ast-print
产生的是AST的文本表示。由于设置选项的人已经熟悉类似C / C ++的语法,因此它将以遵循该语法的表示形式打印。这是一个设计选择,而非巧合。
如果您希望看到AST在熟悉的语法中没有按意图打印时的样子,您可以查看GIMPLE,GCC的内部表示。
答案 2 :(得分:3)
如果您想玩GIMPLE,您甚至可以使用GCC MELT来实现此目的。 MELT是一种处理GIMPLE的高级域特定语言!
在编译器内部,内部表示通常不是树,而是某种循环结构。在GCC中,一个基本块知道它是gimple-s,但是gimple-s可能知道它们的基本块....(它有点复杂,但你已经有了这个想法)。