我正在C中为一个简单的玩具语言实现一个编译器.我有一个工作的扫描器和解析器,以及关于AST的概念功能/构造的合理背景.我的问题与在C中表示AST的具体方式有关.我在网上不同的文本/资源中经常遇到三种风格:
每种类型的节点一个结构.
它有一个基节点"class"(struct),它是所有子结构中的第一个字段.基节点包含一个存储节点类型的枚举(常量,二元运算符,赋值等).使用一组宏访问结构的成员,每个结构一个集.它看起来像这样:
struct ast_node_base {
enum {CONSTANT, ADD, SUB, ASSIGNMENT} class;
};
struct ast_node_constant {
struct ast_node_base *base;
int value;
};
struct ast_node_add {
struct ast_node_base *base;
struct ast_node_base *left;
struct ast_node_base *right;
};
struct ast_node_assign {
struct ast_node_base *base;
struct ast_node_base *left;
struct ast_node_base *right;
};
#define CLASS(node) ((ast_node_base*)node)->class;
#define ADD_LEFT(node) ((ast_node_add*)node)->left;
#define ADD_RIGHT(node) ((ast_node_add*)node)->right;
#define ASSIGN_LEFT(node) ((ast_node_assign*)node)->left;
#define ASSIGN_RIGHT(node) ((ast_node_assign*)node)->right;
Run Code Online (Sandbox Code Playgroud)
每个节点布局一个结构.
这似乎与上面的布局大致相同,除了没有ast_node_add和ast_node_assign它将有一个ast_node_binary来表示两者,因为两个结构的布局是相同的,它们只是由base-> class的内容不同.这样做的好处似乎是一组更加统一的宏(左侧和右侧所有节点的LEFT(节点),而不是每对一对宏),但缺点似乎是C类型检查不会有用(例如,没有办法检测到只有ast_node_add的ast_node_assign).
一个结构总数,带有用于保存不同类型节点数据的联合.
可以在这里找到比我能给出的更好的解释.使用上一个示例中的类型,它看起来像:
struct ast_node {
enum { CONSTANT, ADD, SUB, ASSIGNMENT } …Run Code Online (Sandbox Code Playgroud) 在阅读ANSI C Yacc语法规范后,我注意到以下内容都是有效的:
register x;
auto y;
static z;
extern q;
Run Code Online (Sandbox Code Playgroud)
这对我来说似乎很奇怪,因为我对类型的理解表明这些变量都没有类型.这些是什么意思?他们如何打字?分配了多少内存?
编辑:以下代码有一个简单的错误,实际上没有说明问题.我把它留在这里(未经修正),但我仍然对底部问题的答案感到好奇.
我在Python中有以下对象,应该总是为相等测试返回true:
class Wildcard(object):
def __eq__(self, other):
return True
Run Code Online (Sandbox Code Playgroud)
它在某些情况下有效,但不是全部:
>>> w = Wildcard()
>>> w == 'g'
True
>>> 'g' == w
True
>>> w == 10
True
>>> 10 == 'w'
False
Run Code Online (Sandbox Code Playgroud)
根据我的理解,==运算符将第二个操作数传递给第一个操作符的__ eq__方法,这解释了为什么w == 10有效但10 == w没有.这提出了两个问题.首先,是否可以构造具有此属性的对象,而不管它是哪个操作数?其次,为什么这对字符串起作用,而不是int?String的__ eq__方法如何将'g'== w评估为True?