在标记的联盟上派遣
Dispatch on tagged union
我正在使用 C 标记联合样式结构来表示 AST 节点。它们看起来像这样:
struct A_var_ {
enum {
A_simpleVar,
A_fieldVar,
A_subscriptVar
} kind;
A_pos pos;
union {
S_symbol simple;
struct {
A_var var;
S_symbol sym;
} field;
struct {
A_var var;
A_exp exp;
} subscript;
} u;
};
现在,我正在尝试按节点类型进行调度,如下所示:
switch(node->kind) {
case A_simpleVar:
...
}
但是,我遇到了类似 Can't resolve variable A_simpleVar
的错误。我怎样才能做到这一点?我在 windows 上使用 Cmake,编译器是 gcc。
我遇到的具体错误,针对以下代码:
struct expty transExp(S_table venv, S_table tenv, A_exp a)
{
switch (a->kind) {
case A_letExp:
struct expty exp;
A_decList d;
S_beginScope(venv);
S_beginScope(tenv);
for (d = a->u.let.decs; d; d=d->tail) {
transDec(venv, tenv, d->head);
}
exp = transExp(venv, tenv, a->u.let.body);
S_endScope(tenv);
S_endScope(venv);
return exp;
case A_opExp:
A_oper oper = a->u.op.oper;
struct expty left = transExp(venv, tenv, a->u.op.left);
struct expty right = transExp(venv, tenv, a->u.op.right);
if (oper == A_plusOp) {
if (left.ty->kind != Ty_int)
EM_error(a->u.op.left->pos, "integer required");
if (right.ty->kind != Ty_int)
EM_error(a->u.op.right->pos, "integer required");
return expTy(NULL, Ty_Int());
} // I need to cover other operators as well, but not for prototype
}
}
是:
C:\Users\Fotis\Documents\Devel\grimoire\Books\ModernCompilerC\semant.c: In function 'transExp':
C:\Users\Fotis\Documents\Devel\grimoire\Books\ModernCompilerC\semant.c:28:7: error: a label can only be part of a statement and a declaration is not a statement
struct expty exp;
^
C:\Users\Fotis\Documents\Devel\grimoire\Books\ModernCompilerC\semant.c:29:7: error: expected expression before 'A_decList'
A_decList d;
^
C:\Users\Fotis\Documents\Devel\grimoire\Books\ModernCompilerC\semant.c:32:12: error: 'd' undeclared (first use in this function)
for (d = a->u.let.decs; d; d=d->tail) {
注意函数的参数是指向 typedef
ed 结构的指针可能也很重要。即 A_exp
是 A_exp_ *
您正在使用 C++ 编译器进行编译,而不是 C 编译器。两者处理枚举的方式不同。
在 C 中,所有枚举在全局范围内都是可见的。在 C++ 中,它们由包含类型限定(如果有)。因此,您需要在枚举值前加上结构名称前缀:
switch(node->kind) {
case A_var_::A_simpleVar:
...
}
我很久以前就发现了问题所在,但只是抽空指出来,以便其他人在遇到同样的错误时可以得到帮助。
这里要注意的是编译错误:
C:\Users\Fotis\Documents\Devel\grimoire\Books\ModernCompilerC\semant.c: In function 'transExp':
C:\Users\Fotis\Documents\Devel\grimoire\Books\ModernCompilerC\semant.c:28:7: error: a label can only be part of a statement and a declaration is not a statement
struct expty exp;
出于某种原因,在 C 文法中,声明被视为 expression
,并且 C 文法的语法要求将语句作为 case
的主体。将一系列 expressions/statements 变成一个语句的最简单方法是将它们全部括在方括号中。在这种特殊情况下,要走的路是将问题中的错误代码翻译成:
(...snip...)
switch (a->kind) {
case A_letExp: {
struct expty exp;
A_decList d;
S_beginScope(venv);
S_beginScope(tenv);
for (d = a->u.let.decs; d; d=d->tail) {
transDec(venv, tenv, d->head);
}
exp = transExp(venv, tenv, a->u.let.body);
S_endScope(tenv);
S_endScope(venv);
return exp;
}
注意 case A_letExp:
和 return exp;
之后的符号 {
和 }
。
我正在使用 C 标记联合样式结构来表示 AST 节点。它们看起来像这样:
struct A_var_ {
enum {
A_simpleVar,
A_fieldVar,
A_subscriptVar
} kind;
A_pos pos;
union {
S_symbol simple;
struct {
A_var var;
S_symbol sym;
} field;
struct {
A_var var;
A_exp exp;
} subscript;
} u;
};
现在,我正在尝试按节点类型进行调度,如下所示:
switch(node->kind) {
case A_simpleVar:
...
}
但是,我遇到了类似 Can't resolve variable A_simpleVar
的错误。我怎样才能做到这一点?我在 windows 上使用 Cmake,编译器是 gcc。
我遇到的具体错误,针对以下代码:
struct expty transExp(S_table venv, S_table tenv, A_exp a)
{
switch (a->kind) {
case A_letExp:
struct expty exp;
A_decList d;
S_beginScope(venv);
S_beginScope(tenv);
for (d = a->u.let.decs; d; d=d->tail) {
transDec(venv, tenv, d->head);
}
exp = transExp(venv, tenv, a->u.let.body);
S_endScope(tenv);
S_endScope(venv);
return exp;
case A_opExp:
A_oper oper = a->u.op.oper;
struct expty left = transExp(venv, tenv, a->u.op.left);
struct expty right = transExp(venv, tenv, a->u.op.right);
if (oper == A_plusOp) {
if (left.ty->kind != Ty_int)
EM_error(a->u.op.left->pos, "integer required");
if (right.ty->kind != Ty_int)
EM_error(a->u.op.right->pos, "integer required");
return expTy(NULL, Ty_Int());
} // I need to cover other operators as well, but not for prototype
}
}
是:
C:\Users\Fotis\Documents\Devel\grimoire\Books\ModernCompilerC\semant.c: In function 'transExp':
C:\Users\Fotis\Documents\Devel\grimoire\Books\ModernCompilerC\semant.c:28:7: error: a label can only be part of a statement and a declaration is not a statement
struct expty exp;
^
C:\Users\Fotis\Documents\Devel\grimoire\Books\ModernCompilerC\semant.c:29:7: error: expected expression before 'A_decList'
A_decList d;
^
C:\Users\Fotis\Documents\Devel\grimoire\Books\ModernCompilerC\semant.c:32:12: error: 'd' undeclared (first use in this function)
for (d = a->u.let.decs; d; d=d->tail) {
注意函数的参数是指向 typedef
ed 结构的指针可能也很重要。即 A_exp
是 A_exp_ *
您正在使用 C++ 编译器进行编译,而不是 C 编译器。两者处理枚举的方式不同。
在 C 中,所有枚举在全局范围内都是可见的。在 C++ 中,它们由包含类型限定(如果有)。因此,您需要在枚举值前加上结构名称前缀:
switch(node->kind) {
case A_var_::A_simpleVar:
...
}
我很久以前就发现了问题所在,但只是抽空指出来,以便其他人在遇到同样的错误时可以得到帮助。
这里要注意的是编译错误:
C:\Users\Fotis\Documents\Devel\grimoire\Books\ModernCompilerC\semant.c: In function 'transExp':
C:\Users\Fotis\Documents\Devel\grimoire\Books\ModernCompilerC\semant.c:28:7: error: a label can only be part of a statement and a declaration is not a statement
struct expty exp;
出于某种原因,在 C 文法中,声明被视为 expression
,并且 C 文法的语法要求将语句作为 case
的主体。将一系列 expressions/statements 变成一个语句的最简单方法是将它们全部括在方括号中。在这种特殊情况下,要走的路是将问题中的错误代码翻译成:
(...snip...)
switch (a->kind) {
case A_letExp: {
struct expty exp;
A_decList d;
S_beginScope(venv);
S_beginScope(tenv);
for (d = a->u.let.decs; d; d=d->tail) {
transDec(venv, tenv, d->head);
}
exp = transExp(venv, tenv, a->u.let.body);
S_endScope(tenv);
S_endScope(venv);
return exp;
}
注意 case A_letExp:
和 return exp;
之后的符号 {
和 }
。