9.1 语义分析概要
本章目的
- 引用消解
- 类型名称消解: TypeRef->Type
- 类型定义检查:比如不能新建void的数组,void的成员结构体,直接将自身类型作为子成员的结构体等问题
- 表达式有效性检查: 比如1++
- 静态类型检查,比如在结构体间进行了未定义的+操作,或者是将int类型的值直接赋给指针类型的变量等
介绍了Vistor模式来做类型检查,比如:
public class VariableNode extends LHSNode {
public <S,E> E accept(ASTVisitor<S,E> visitor) {
return visitor.visit(this);
}
class IRGenerator implements ASTVisitor<Void, Expr> {
public Void visit(CaseNode node) {
throw new Error("must not happen");
}
// #@@range/While{
public Void visit(WhileNode node) {
Label begLabel = new Label();
Label bodyLabel = new Label();
Label endLabel = new Label();
label(begLabel);
cjump(node.location(),
transformExpr(node.cond()), bodyLabel, endLabel);
label(bodyLabel);
pushContinue(begLabel);
pushBreak(endLabel);
transformStmt(node.body());
popBreak();
popContinue();
jump(begLabel);
label(endLabel);
return null;
}
// #@@}
9.2 变量引用的消解
目的: 确定变量及函数具体指向哪个作用域Scope
作用域类Scope: Scope/TopLevelScope/LocalScope
abstract public class Scope {
protected List<LocalScope> children;
public Scope() {
children = new ArrayList<LocalScope>();
}
abstract public boolean isToplevel();
abstract public ToplevelScope toplevel();
abstract public Scope parent();
protected void addChild(LocalScope s) {
children.add(s);
}
abstract public Entity get(String name) throws SemanticException;
}
public class ToplevelScope extends Scope {
protected Map<String, Entity> entities;
protected List<DefinedVariable> staticLocalVariables; // cache
...
}
public class LocalScope extends Scope {
protected Scope parent;
protected Map<String, DefinedVariable> variables;
...
}
Scope可以被认为是符号表的一种,因此cb直接在引用消解这一步传出了符号表。
主逻辑:
public class LocalResolver extends Visitor {
// #@@range/ctor{
private final LinkedList<Scope> scopeStack;
private final ConstantTable constantTable;
private final ErrorHandler errorHandler;
public LocalResolver(ErrorHandler h) {
this.errorHandler = h;
this.scopeStack = new LinkedList<Scope>();
this.constantTable = new ConstantTable();
}
// #@@}
private void resolve(StmtNode n) {
n.accept(this);
}
private void resolve(ExprNode n) {
n.accept(this);
}
// #@@range/resolve{
public void resolve(AST ast) throws SemanticException {
ToplevelScope toplevel = new ToplevelScope();
scopeStack.add(toplevel);
// #@@range/declareToplevel{
for (Entity decl : ast.declarations()) {
toplevel.declareEntity(decl);
}
for (Entity ent : ast.definitions()) {
toplevel.defineEntity(ent);
}
// #@@}
// #@@range/resolveRefs{
resolveGvarInitializers(ast.definedVariables());
resolveConstantValues(ast.constants());
resolveFunctions(ast.definedFunctions());
// #@@}
toplevel.checkReferences(errorHandler);
if (errorHandler.errorOccured()) {
throw new SemanticException("compile failed.");
}
ast.setScope(toplevel);
ast.setConstantTable(constantTable);
}
// #@@}
// #@@range/resolveGvarInitializers{
private void resolveGvarInitializers(List<DefinedVariable> gvars) {
for (DefinedVariable gvar : gvars) {
if (gvar.hasInitializer()) {
resolve(gvar.initializer());
}
}
}
// #@@}
private void resolveConstantValues(List<Constant> consts) {
for (Constant c : consts) {
resolve(c.value());
}
}
// #@@range/resolveFunctions{
private void resolveFunctions(List<DefinedFunction> funcs) {
for (DefinedFunction func : funcs) {
pushScope(func.parameters());
resolve(func.body());
func.setScope(popScope());
}
}
// #@@}
// #@@range/BlockNode{
public Void visit(BlockNode node) {
pushScope(node.variables());
super.visit(node);
node.setScope(popScope());
return null;
}
// #@@}
// #@@range/pushScope{
private void pushScope(List<? extends DefinedVariable> vars) {
LocalScope scope = new LocalScope(currentScope());
for (DefinedVariable var : vars) {
if (scope.isDefinedLocally(var.name())) {
error(var.location(),
"duplicated variable in scope: " + var.name());
}
else {
scope.defineVariable(var);
}
}
scopeStack.addLast(scope);
}
// #@@}
// #@@range/popScope{
private LocalScope popScope() {
return (LocalScope)scopeStack.removeLast();
}
// #@@}
// #@@range/currentScope{
private Scope currentScope() {
return scopeStack.getLast();
}
// #@@}
// #@@range/StringLiteralNode{
public Void visit(StringLiteralNode node) {
node.setEntry(constantTable.intern(node.value()));
return null;
}
// #@@}
// #@@range/VariableNode{
public Void visit(VariableNode node) {
try {
Entity ent = currentScope().get(node.name());
ent.refered();
node.setEntity(ent);
}
catch (SemanticException ex) {
error(node, ex.getMessage());
}
return null;
}
// #@@}
private void error(Node node, String message) {
errorHandler.error(node.location(), message);
}
private void error(Location loc, String message) {
errorHandler.error(loc, message);
}
}
这里的设计:在Visitor内部避免抛出异常继续向前处理。
注意visit(BlockNode node),对于BlockNode,需要建立临时作用域。
9.3 类型名称消解
目的: TypeRef指向具体Type
Scope: 认为只有一个作用域-TopScope,所以无需使用Scope树
public class TypeResolver extends Visitor
implements EntityVisitor<Void>, DeclarationVisitor<Void> {
// #@@range/ctor{
private final TypeTable typeTable;
private final ErrorHandler errorHandler;
public TypeResolver(TypeTable typeTable, ErrorHandler errorHandler) {
this.typeTable = typeTable;
this.errorHandler = errorHandler;
}
// #@@}
// #@@range/resolveProgram{
public void resolve(AST ast) {
//先处理Type定义,再t.accept处理成员变量以防止无限递归
defineTypes(ast.types());
// #@@range/resolveProgram_core{
for (TypeDefinition t : ast.types()) {
t.accept(this);
}
//处理外部引用
for (Entity e : ast.entities()) {
e.accept(this);
}
// #@@}
}
// #@@}
// #@@range/defineTypes{
private void defineTypes(List<TypeDefinition> deftypes) {
for (TypeDefinition def : deftypes) {
if (typeTable.isDefined(def.typeRef())) {
error(def, "duplicated type definition: " + def.typeRef());
}
else {
typeTable.put(def.typeRef(), def.definingType());
}
}
}
// #@@}
// #@@range/bindType{
private void bindType(TypeNode n) {
if (n.isResolved()) return;
n.setType(typeTable.get(n.typeRef()));
}
// #@@}
//
// Declarations
//
// #@@range/StructNode{
public Void visit(StructNode struct) {
resolveCompositeType(struct);
return null;
}
// #@@}
// #@@range/UnionNode{
public Void visit(UnionNode union) {
resolveCompositeType(union);
return null;
}
// #@@}
// #@@range/resolveCompositeType{
public void resolveCompositeType(CompositeTypeDefinition def) {
CompositeType ct = (CompositeType)typeTable.get(def.typeNode().typeRef());
if (ct == null) {
throw new Error("cannot intern struct/union: " + def.name());
}
for (Slot s : ct.members()) {
bindType(s.typeNode());
}
}
// #@@}
// #@@range/TypedefNode{
public Void visit(TypedefNode typedef) {
bindType(typedef.typeNode());
bindType(typedef.realTypeNode());
return null;
}
// #@@}
//
// Entities
//
// #@@range/DefinedVariable{
public Void visit(DefinedVariable var) {
bindType(var.typeNode());
if (var.hasInitializer()) {
visitExpr(var.initializer());
}
return null;
}
// #@@}
public Void visit(UndefinedVariable var) {
bindType(var.typeNode());
return null;
}
public Void visit(Constant c) {
bindType(c.typeNode());
visitExpr(c.value());
return null;
}
// #@@range/DefinedFunction{
public Void visit(DefinedFunction func) {
resolveFunctionHeader(func);
visitStmt(func.body());
return null;
}
// #@@}
public Void visit(UndefinedFunction func) {
resolveFunctionHeader(func);
return null;
}
// #@@range/resolveFunctionHeader{
private void resolveFunctionHeader(Function func) {
bindType(func.typeNode());
for (CBCParameter param : func.parameters()) {
// arrays must be converted to pointers in a function parameter.
Type t = typeTable.getParamType(param.typeNode().typeRef());
param.typeNode().setType(t);
}
}
// #@@}
//
// Expressions
//
public Void visit(BlockNode node) {
for (DefinedVariable var : node.variables()) {
var.accept(this);
}
visitStmts(node.stmts());
return null;
}
public Void visit(CastNode node) {
bindType(node.typeNode());
super.visit(node);
return null;
}
public Void visit(SizeofExprNode node) {
bindType(node.typeNode());
super.visit(node);
return null;
}
public Void visit(SizeofTypeNode node) {
bindType(node.operandTypeNode());
bindType(node.typeNode());
super.visit(node);
return null;
}
public Void visit(IntegerLiteralNode node) {
bindType(node.typeNode());
return null;
}
public Void visit(StringLiteralNode node) {
bindType(node.typeNode());
return null;
}
private void error(Node node, String msg) {
errorHandler.error(node.location(), msg);
}
}