课程主页:

https://www.edx.org/course/compilers

课程视频:

https://www.bilibili.com/video/BV1NE411376V?p=20&t=6

参考资料:

https://github.com/dychen/compilers/tree/master/PA4

https://github.com/yifanyang96/Compiler/tree/master/PA4

https://github.com/skyzluo/CS143-Compilers-Stanford

https://github.com/afterthat97/cool-compiler

这次回顾作业4——语义分析,这次作业难度很大,主要参考了第一份资料。

由于作业5的难度更大,所以暂时搁置课程的学习,待以后有机会再完成剩余部分的内容。

准备工作

文件介绍

  • $\text{cool-tree.h}$

    • 抽象语法树节点的定义,添加了类Env,对应类型环境:

      为了捕获有关标识符类型的信息,我们使用类型环境(type environment)。 该环境由三部分组成:方法环境$M$,对象环境$O$和表达式在其中出现的当前类的名称$C$。

  • $\text{semant.h}$

    • 添加了ClassTable,包含继承图以及符合和类对应的关系,对应类型环境中的$M, O$
  • $\text{semant.cc}$

    • 具体实现

具体流程

程序的整体流程如下:

  1. 扫描类,构造继承图,判断继承图是否合法。
  2. 检查语义条件。

分析

步骤1

分析classes

程序的开始为如下语句:

/* ClassTable constructor may do some semantic analysis */
ClassTable *classtable = new ClassTable(classes);

经过分析后不难得到如下继承关系:

class class__class : public Class__class
class Class__class : public tree_node
typedef Class__class *Class_;
typedef list_node<Class_> Classes_class;
typedef Classes_class *Classes;

template <class Elem> class list_node : public tree_node

所以classes为指向类列表的指针。

再回顾前一次作业中语法分析的内容:

%union {
    Boolean boolean;
    Symbol symbol;
    Program program;
    Class_ class_;
    Classes classes;
    Feature feature;
    Features features;
    Formal formal;
    Formals formals;
    Case case_;
    Cases cases;
    Expression expression;
    Expressions expressions;
    char *error_msg;
}

Program ast_root;	      /* the result of the parse  */
Classes parse_results;        /* for use in semantic analysis */

%type <program> program
%type <classes> class_list
%type <class_> class

program	
: class_list	
{ @$ = @1;
ast_root = program($1); };

/* [[class;]]+ */
class_list

不难看出这里的classes即对应class_list。

继承关系的注意事项

根据cool-manual 8.4, 8.5以及https://doraemonzzz.com/2021/04/15/2021-4-15-Stanford-Compiler-Week-5-Cool-Type-Checking/可得

  • 继承或重定义Bool是错误的。
  • 继承或重定义String是错误的。
  • 不能从self_type继承。

错误处理

错误处理需要使用semant_error,其定义如下:

// semant_error is an overloaded function for reporting errors
// during semantic analysis.  There are three versions:
//
//    ostream& ClassTable::semant_error()                
//
//    ostream& ClassTable::semant_error(Class_ c)
//       print line number and filename for `c'
//
//    ostream& ClassTable::semant_error(Symbol filename, tree_node *t)  
//       print a line number and filename

特殊的类Object

在Cool中,Object是所有类的基类,所以没有父类;在semant.cc中,定义其父类为No_class,这也是判断节点是否为根节点的依据,Object_class的定义如下:

Class_ Object_class =
class_(Object, 
        No_class,
        append_Features(
                append_Features(
                        single_Features(method(cool_abort, nil_Formals(), Object, no_expr())),
                        single_Features(method(type_name, nil_Formals(), Str, no_expr()))),
                single_Features(method(copy, nil_Formals(), SELF_TYPE, no_expr()))),
        filename);

核心代码

核心代码如下,其中继承图检验包含在步骤2中:

ClassTable *classtable = new ClassTable(classes);

ClassTable::ClassTable(Classes classes) : semant_errors(0) , error_stream(cerr) {
    /* Fill this in */
    install_basic_classes();
    
    for (int i = classes->first(); classes->more(i); i = classes->next(i)){
        add_to_class_table(classes->nth(i));
    }
}

void ClassTable::add_to_class_table(Class_ c){
    Symbol name = c->get_name();
    Symbol parent = c->get_parent();
    Features features = c->get_features();
    Symbol filename = c->get_filename();
    if ((parent == Bool) || (parent == Str) || (parent == SELF_TYPE)){
        // 不能从bool, string, self_type继承
        semant_error(c) << name << "Can't inherent from " << parent << "!" << endl; 
    }else if (name == SELF_TYPE){
        // 不能定义self_type
        semant_error(c) << "Can't define SELF_TYPE!" << endl;
    }else if ((class_table.find(name) != class_table.end()) ||
              (inhert_graph.find(name) != inhert_graph.end())){
        // 不能重复定义
        semant_error(c) << "Can't be defined multiple times!" << endl;
    }else{
        class_table[name] = c;
        inhert_graph[name] = parent;
    }
}

步骤2

核心代码

核心代码如下,其中feature表示method或者attr:

// second pass
if ((!classtable->errors()) && (classtable->is_valid())){
    Env env(classtable);
    for (int i = classes->first(); classes->more(i); i = classes->next(i)){
        env.om->enterscope();
        env.cur_class = classes->nth(i);
        classes->nth(i)->init(env);
        classes->nth(i)->type_check(env);
        env.om->exitscope();
    }
}

// class__class, 初始化, 递归处理, 先设置父节点
void class__class::init(Env env){
    if (name != Object){
        // 先设置父节点
        env.ct->get_class(parent)->init(env);
    }

    // 设置feature
    for (int i = features->first(); features->more(i); i = features->next(i)){
        features->nth(i)->add_to_env(env);
    }
}

// class__class
Class_ class__class::type_check(Env env){
    for (int i = features->first(); features->more(i); i = features->next(i)){
        features->nth(i)->type_check(env);
    }

    return this;
}

/**
 * 1. 进入新的作用域
 * 2. 添加当前类到环境
 * 3. 遍历变量
 * 4. 判断方法是是否继承正确
 * 5. 判断实际返回类型
 *    1. 如果返回类型是SELF_TYPE, 实际返回类型也为SELF_TYPE
 *    2. 返回类型存在
 *    3. 实际返回类型是声明类型的子类
 **/
Feature method_class::type_check(Env env){
    
}

/**
 * 1. 进入新的作用域
 * 2. 添加当前类到环境
 * 3. 计算init,
 *    1. 判断不是self
 *    2. 如果返回类型为SELF_TYPE, 则返回类型为当前类
 *    3. 判断其返回类型是否为type_decl子类
 **/
Feature attr_class::type_check(Env env){

}

后续是每种class对应的type_check,其中每个class对应抽象语法树节点,以下是详细信息。

类对应的接口

这部分可以对照如下资料查看:

https://doraemonzzz.com/2021/04/14/2021-4-14-Stanford-Compiler-Week-5-Semantic-Analysis-and-Type-Checking/#text-lub

method
class method_class : public Feature_class {
protected:
   Symbol name;
   Formals formals;
   Symbol return_type;
   Expression expr;
}

类型检查规则:

attr
class attr_class : public Feature_class {
protected:
   Symbol name;
   Symbol type_decl;
   Expression init;
}

类型检查规则:

formal
class formal_class : public Formal_class {
protected:
   Symbol name;
   Symbol type_decl;
}
branch_class
class branch_class : public Case_class {
protected:
   Symbol name;
   Symbol type_decl;
   Expression expr;
}
assign
class assign_class : public Expression_class {
protected:
   Symbol name;
   Expression expr;
}
static_dispatch_class
class static_dispatch_class : public Expression_class {
protected:
   Expression expr;
   Symbol type_name;
   Symbol name;
   Expressions actual;
}

类型检查规则:

dispatch
class dispatch_class : public Expression_class {
protected:
   Expression expr;
   Symbol name;
   Expressions actual;
}

类型检查规则:

cond
class cond_class : public Expression_class {
protected:
   Expression pred;
   Expression then_exp;
   Expression else_exp;
}

类型检查规则:

loop
class loop_class : public Expression_class {
protected:
   Expression pred;
   Expression body;
}

类型检查规则:

case
class typcase_class : public Expression_class {
protected:
   Expression expr;
   Cases cases;
}

类型检查规则:

block class
class block_class : public Expression_class {
protected:
   Expressions body;
}
let
class let_class : public Expression_class {
protected:
   Symbol identifier;
   Symbol type_decl;
   Expression init;
   Expression body;
}

类型检查规则:

其中$\mathrm{x}$不能是$\mathrm{self}$, $\mathrm{T_0}$可以$\text{self_type}$。

加减乘除的类型检查规则:

plus
class plus_class : public Expression_class {
protected:
   Expression e1;
   Expression e2;
}
sub
class sub_class : public Expression_class {
protected:
   Expression e1;
   Expression e2;
}
mul
class mul_class : public Expression_class {
protected:
   Expression e1;
   Expression e2;
}
divide
class divide_class : public Expression_class {
protected:
   Expression e1;
   Expression e2;
}
neg
class neg_class : public Expression_class {
protected:
   Expression e1;
}

类型检查规则:

lt
class lt_class : public Expression_class {
protected:
   Expression e1;
   Expression e2;
 }

类型检查规则:

eq
class eq_class : public Expression_class {
protected:
   Expression e1;
   Expression e2;
}

类型检查规则:

注意事项:

可以自由比较任何类型,但Int,String和Bool除外,这些类只能与相同类型的对象进行比较。

comp_class
class comp_class : public Expression_class {
protected:
   Expression e1;
}

类型检查规则:

int
class int_const_class : public Expression_class {
protected:
   Symbol token;
}
bool
class bool_const_class : public Expression_class {
protected:
   Boolean val;
}
string
class string_const_class : public Expression_class {
protected:
   Symbol token;
}
new
class new__class : public Expression_class {
protected:
   Symbol type_name;
}

类型检查规则:

isvoid
class isvoid_class : public Expression_class {
protected:
   Expression e1;
}

类型检查规则:

no_expr
class no_expr_class : public Expression_class {

}
object
class object_class : public Expression_class {
protected:
   Symbol name;
}

补充信息

树程序包中的类回顾:

// 类
Class_ class_(Symbol name, Symbol parent, Features features, Symbol filename)
{
  return new class__class(name, parent, features, filename);
}

// 方法
Feature method(Symbol name, Formals formals, Symbol return_type, Expression expr)
{
  return new method_class(name, formals, return_type, expr);
}

// 属性
Feature attr(Symbol name, Symbol type_decl, Expression init)
{
  return new attr_class(name, type_decl, init);
}

// 参数: 名称, 类型
Formal formal(Symbol name, Symbol type_decl)
{
  return new formal_class(name, type_decl);
}

完整代码

cool-tree.h

#ifndef COOL_TREE_H
#define COOL_TREE_H
//////////////////////////////////////////////////////////
//
// file: cool-tree.h
//
// This file defines classes for each phylum and constructor
//
//////////////////////////////////////////////////////////


#include "tree.h"
#include "cool-tree.handcode.h"
#include <symtab.h>

// add begin
class ClassTable;

// 环境信息, 对应类型环境中的(O, M, C)
class Env {
public:
   // 符号表, 对应O, M
   SymbolTable<Symbol, Symbol> *om;
   // 类表, 补充信息
   ClassTable *ct;
   // 环境的当前类, 对应C
   Class_ cur_class;
   Env() {
      om = new SymbolTable<Symbol, Symbol>();
      ct = NULL;
      cur_class = NULL;
   }

   Env(ClassTable *ct) {
      om = new SymbolTable<Symbol, Symbol>();
      this->ct = ct;
      cur_class = NULL;
   }
};

// add end


// define the class for phylum
// define simple phylum - Program
typedef class Program_class *Program;

class Program_class : public tree_node {
public:
   tree_node *copy()		 { return copy_Program(); }
   virtual Program copy_Program() = 0;

#ifdef Program_EXTRAS
   Program_EXTRAS
#endif
};


// define simple phylum - Class_
typedef class Class__class *Class_;

class Class__class : public tree_node {
public:
   tree_node *copy()		 { return copy_Class_(); }
   virtual Class_ copy_Class_() = 0;   

   // add begin
   virtual Symbol get_name() = 0; 	       
   virtual Symbol get_parent() = 0;
   virtual Features get_features() = 0;
   virtual void init(Env env) = 0;
   virtual Class_ type_check(Env env) = 0;
   virtual bool has_method(Symbol name) = 0;
   virtual Feature get_method(Symbol name) = 0;
   // add end

#ifdef Class__EXTRAS
   Class__EXTRAS
#endif
};


// define simple phylum - Feature
typedef class Feature_class *Feature;

class Feature_class : public tree_node {
public:
   tree_node *copy()		 { return copy_Feature(); }
   virtual Feature copy_Feature() = 0;
   // add begin
   virtual void add_to_env(Env env) = 0;
   virtual Feature type_check(Env env) = 0;
   virtual bool is_method() = 0;
   virtual Symbol get_name() = 0;
   virtual Formals get_formals() = 0;
   virtual Symbol get_return_type() = 0;
   virtual Expression get_expr() = 0;
   virtual Symbol get_type_decl() = 0;
   virtual Expression get_init() = 0;
   // add end

#ifdef Feature_EXTRAS
   Feature_EXTRAS
#endif
};


// define simple phylum - Formal
typedef class Formal_class *Formal;

class Formal_class : public tree_node {
public:
   tree_node *copy()		 { return copy_Formal(); }
   virtual Formal copy_Formal() = 0;
   // add begin
   virtual Formal type_check(Env env) = 0;
   virtual Symbol get_name() = 0;
   virtual Symbol get_type() = 0;
   // add end

#ifdef Formal_EXTRAS
   Formal_EXTRAS
#endif
};


// define simple phylum - Expression
typedef class Expression_class *Expression;

class Expression_class : public tree_node {
public:
   tree_node *copy()		 { return copy_Expression(); }
   virtual Expression copy_Expression() = 0;
   // add begin
   virtual Expression type_check(Env env) = 0;
   // add end

#ifdef Expression_EXTRAS
   Expression_EXTRAS
#endif
};


// define simple phylum - Case
typedef class Case_class *Case;

class Case_class : public tree_node {
public:
   tree_node *copy()		 { return copy_Case(); }
   virtual Case copy_Case() = 0;
   // add begin
   virtual Symbol type_check(Env env) = 0;
   virtual Symbol get_type() = 0;
   // add end

#ifdef Case_EXTRAS
   Case_EXTRAS
#endif
};


// define the class for phylum - LIST
// define list phlyum - Classes
typedef list_node<Class_> Classes_class;
typedef Classes_class *Classes;


// define list phlyum - Features
typedef list_node<Feature> Features_class;
typedef Features_class *Features;


// define list phlyum - Formals
typedef list_node<Formal> Formals_class;
typedef Formals_class *Formals;


// define list phlyum - Expressions
typedef list_node<Expression> Expressions_class;
typedef Expressions_class *Expressions;


// define list phlyum - Cases
typedef list_node<Case> Cases_class;
typedef Cases_class *Cases;


// define the class for constructors
// define constructor - program
class program_class : public Program_class {
protected:
   Classes classes;
public:
   program_class(Classes a1) {
      classes = a1;
   }
   Program copy_Program();
   void dump(ostream& stream, int n);

#ifdef Program_SHARED_EXTRAS
   Program_SHARED_EXTRAS
#endif
#ifdef program_EXTRAS
   program_EXTRAS
#endif
};


// define constructor - class_
class class__class : public Class__class {
protected:
   Symbol name;
   Symbol parent;
   Features features;
   Symbol filename;
public:
   class__class(Symbol a1, Symbol a2, Features a3, Symbol a4) {
      name = a1;
      parent = a2;
      features = a3;
      filename = a4;
   }
   Class_ copy_Class_();
   void dump(ostream& stream, int n);

   //add
   Symbol get_name()   { return name; };		       
   Symbol get_parent() { return parent; };
   Features get_features() { return features; };
   //Symbol get_filename() { return filename; };
   void init(Env env);
   Class_ type_check(Env env);
   bool has_method(Symbol name);
   Feature get_method(Symbol name);


#ifdef Class__SHARED_EXTRAS
   Class__SHARED_EXTRAS
#endif
#ifdef class__EXTRAS
   class__EXTRAS
#endif
};


// define constructor - method
class method_class : public Feature_class {
protected:
   Symbol name;
   Formals formals;
   Symbol return_type;
   Expression expr;
public:
   method_class(Symbol a1, Formals a2, Symbol a3, Expression a4) {
      name = a1;
      formals = a2;
      return_type = a3;
      expr = a4;
   }
   Feature copy_Feature();
   void dump(ostream& stream, int n);

   // add begin
   void add_to_env(Env env);
   Feature type_check(Env env);
   bool is_method() { return true; };
   Symbol get_name() { return name; };
   Formals get_formals() { return formals; };
   Symbol get_return_type() { return return_type; };
   Expression get_expr() { return expr; };
   Symbol get_type_decl() { return NULL; };
   Expression get_init() { return NULL; };
   // add end

#ifdef Feature_SHARED_EXTRAS
   Feature_SHARED_EXTRAS
#endif
#ifdef method_EXTRAS
   method_EXTRAS
#endif
};


// define constructor - attr
class attr_class : public Feature_class {
protected:
   Symbol name;
   Symbol type_decl;
   Expression init;
public:
   attr_class(Symbol a1, Symbol a2, Expression a3) {
      name = a1;
      type_decl = a2;
      init = a3;
   }
   Feature copy_Feature();
   void dump(ostream& stream, int n);

   // add begin
   void add_to_env(Env env);
   Feature type_check(Env env);
   bool is_method() { return false; };
   Symbol get_name() { return name; };
   Formals get_formals() { return NULL; };
   Symbol get_return_type() { return NULL; };
   Expression get_expr() { return NULL; };
   Symbol get_type_decl() { return type_decl; };
   Expression get_init() { return init; };
   // add end

#ifdef Feature_SHARED_EXTRAS
   Feature_SHARED_EXTRAS
#endif
#ifdef attr_EXTRAS
   attr_EXTRAS
#endif
};


// define constructor - formal
class formal_class : public Formal_class {
protected:
   Symbol name;
   Symbol type_decl;
public:
   formal_class(Symbol a1, Symbol a2) {
      name = a1;
      type_decl = a2;
   }
   Formal copy_Formal();
   void dump(ostream& stream, int n);
   // add begin
   Formal type_check(Env env);
   Symbol get_name() { return name; };
   Symbol get_type() { return type_decl; };
   // add end

#ifdef Formal_SHARED_EXTRAS
   Formal_SHARED_EXTRAS
#endif
#ifdef formal_EXTRAS
   formal_EXTRAS
#endif
};


// define constructor - branch
class branch_class : public Case_class {
protected:
   Symbol name;
   Symbol type_decl;
   Expression expr;
public:
   branch_class(Symbol a1, Symbol a2, Expression a3) {
      name = a1;
      type_decl = a2;
      expr = a3;
   }
   Case copy_Case();
   void dump(ostream& stream, int n);
   // add begin
   Symbol type_check(Env env);
   Symbol get_type() { return type_decl; };
   // add end

#ifdef Case_SHARED_EXTRAS
   Case_SHARED_EXTRAS
#endif
#ifdef branch_EXTRAS
   branch_EXTRAS
#endif
};


// define constructor - assign
class assign_class : public Expression_class {
protected:
   Symbol name;
   Expression expr;
public:
   assign_class(Symbol a1, Expression a2) {
      name = a1;
      expr = a2;
   }
   Expression copy_Expression();
   void dump(ostream& stream, int n);
   // add begin
   Expression type_check(Env env);
   // add end

#ifdef Expression_SHARED_EXTRAS
   Expression_SHARED_EXTRAS
#endif
#ifdef assign_EXTRAS
   assign_EXTRAS
#endif
};


// define constructor - static_dispatch
class static_dispatch_class : public Expression_class {
protected:
   Expression expr;
   Symbol type_name;
   Symbol name;
   Expressions actual;
public:
   static_dispatch_class(Expression a1, Symbol a2, Symbol a3, Expressions a4) {
      expr = a1;
      type_name = a2;
      name = a3;
      actual = a4;
   }
   Expression copy_Expression();
   void dump(ostream& stream, int n);
   // add begin
   Expression type_check(Env env);
   // add end

#ifdef Expression_SHARED_EXTRAS
   Expression_SHARED_EXTRAS
#endif
#ifdef static_dispatch_EXTRAS
   static_dispatch_EXTRAS
#endif
};


// define constructor - dispatch
class dispatch_class : public Expression_class {
protected:
   Expression expr;
   Symbol name;
   Expressions actual;
public:
   dispatch_class(Expression a1, Symbol a2, Expressions a3) {
      expr = a1;
      name = a2;
      actual = a3;
   }
   Expression copy_Expression();
   void dump(ostream& stream, int n);
   // add begin
   Expression type_check(Env env);
   // add end

#ifdef Expression_SHARED_EXTRAS
   Expression_SHARED_EXTRAS
#endif
#ifdef dispatch_EXTRAS
   dispatch_EXTRAS
#endif
};


// define constructor - cond
class cond_class : public Expression_class {
protected:
   Expression pred;
   Expression then_exp;
   Expression else_exp;
public:
   cond_class(Expression a1, Expression a2, Expression a3) {
      pred = a1;
      then_exp = a2;
      else_exp = a3;
   }
   Expression copy_Expression();
   void dump(ostream& stream, int n);
   // add begin
   Expression type_check(Env env);
   // add end

#ifdef Expression_SHARED_EXTRAS
   Expression_SHARED_EXTRAS
#endif
#ifdef cond_EXTRAS
   cond_EXTRAS
#endif
};


// define constructor - loop
class loop_class : public Expression_class {
protected:
   Expression pred;
   Expression body;
public:
   loop_class(Expression a1, Expression a2) {
      pred = a1;
      body = a2;
   }
   Expression copy_Expression();
   void dump(ostream& stream, int n);
   // add begin
   Expression type_check(Env env);
   // add end

#ifdef Expression_SHARED_EXTRAS
   Expression_SHARED_EXTRAS
#endif
#ifdef loop_EXTRAS
   loop_EXTRAS
#endif
};


// define constructor - typcase
class typcase_class : public Expression_class {
protected:
   Expression expr;
   Cases cases;
public:
   typcase_class(Expression a1, Cases a2) {
      expr = a1;
      cases = a2;
   }
   Expression copy_Expression();
   void dump(ostream& stream, int n);
   // add begin
   Expression type_check(Env env);
   // add end

#ifdef Expression_SHARED_EXTRAS
   Expression_SHARED_EXTRAS
#endif
#ifdef typcase_EXTRAS
   typcase_EXTRAS
#endif
};


// define constructor - block
class block_class : public Expression_class {
protected:
   Expressions body;
public:
   block_class(Expressions a1) {
      body = a1;
   }
   Expression copy_Expression();
   void dump(ostream& stream, int n);
   // add begin
   Expression type_check(Env env);
   // add end

#ifdef Expression_SHARED_EXTRAS
   Expression_SHARED_EXTRAS
#endif
#ifdef block_EXTRAS
   block_EXTRAS
#endif
};


// define constructor - let
class let_class : public Expression_class {
protected:
   Symbol identifier;
   Symbol type_decl;
   Expression init;
   Expression body;
public:
   let_class(Symbol a1, Symbol a2, Expression a3, Expression a4) {
      identifier = a1;
      type_decl = a2;
      init = a3;
      body = a4;
   }
   Expression copy_Expression();
   void dump(ostream& stream, int n);
   // add
   Expression type_check(Env env);

#ifdef Expression_SHARED_EXTRAS
   Expression_SHARED_EXTRAS
#endif
#ifdef let_EXTRAS
   let_EXTRAS
#endif
};


// define constructor - plus
class plus_class : public Expression_class {
protected:
   Expression e1;
   Expression e2;
public:
   plus_class(Expression a1, Expression a2) {
      e1 = a1;
      e2 = a2;
   }
   Expression copy_Expression();
   void dump(ostream& stream, int n);
   // add begin
   Expression type_check(Env env);
   // add end

#ifdef Expression_SHARED_EXTRAS
   Expression_SHARED_EXTRAS
#endif
#ifdef plus_EXTRAS
   plus_EXTRAS
#endif
};


// define constructor - sub
class sub_class : public Expression_class {
protected:
   Expression e1;
   Expression e2;
public:
   sub_class(Expression a1, Expression a2) {
      e1 = a1;
      e2 = a2;
   }
   Expression copy_Expression();
   void dump(ostream& stream, int n);
   // add begin
   Expression type_check(Env env);
   // add end

#ifdef Expression_SHARED_EXTRAS
   Expression_SHARED_EXTRAS
#endif
#ifdef sub_EXTRAS
   sub_EXTRAS
#endif
};


// define constructor - mul
class mul_class : public Expression_class {
protected:
   Expression e1;
   Expression e2;
public:
   mul_class(Expression a1, Expression a2) {
      e1 = a1;
      e2 = a2;
   }
   Expression copy_Expression();
   void dump(ostream& stream, int n);
   // add begin
   Expression type_check(Env env);
   // add end

#ifdef Expression_SHARED_EXTRAS
   Expression_SHARED_EXTRAS
#endif
#ifdef mul_EXTRAS
   mul_EXTRAS
#endif
};


// define constructor - divide
class divide_class : public Expression_class {
protected:
   Expression e1;
   Expression e2;
public:
   divide_class(Expression a1, Expression a2) {
      e1 = a1;
      e2 = a2;
   }
   Expression copy_Expression();
   void dump(ostream& stream, int n);
   // add begin
   Expression type_check(Env env);
   // add end

#ifdef Expression_SHARED_EXTRAS
   Expression_SHARED_EXTRAS
#endif
#ifdef divide_EXTRAS
   divide_EXTRAS
#endif
};


// define constructor - neg
class neg_class : public Expression_class {
protected:
   Expression e1;
public:
   neg_class(Expression a1) {
      e1 = a1;
   }
   Expression copy_Expression();
   void dump(ostream& stream, int n);
   // add begin
   Expression type_check(Env env);
   // add end

#ifdef Expression_SHARED_EXTRAS
   Expression_SHARED_EXTRAS
#endif
#ifdef neg_EXTRAS
   neg_EXTRAS
#endif
};


// define constructor - lt
class lt_class : public Expression_class {
protected:
   Expression e1;
   Expression e2;
public:
   lt_class(Expression a1, Expression a2) {
      e1 = a1;
      e2 = a2;
   }
   Expression copy_Expression();
   void dump(ostream& stream, int n);
   // add begin
   Expression type_check(Env env);
   // add end

#ifdef Expression_SHARED_EXTRAS
   Expression_SHARED_EXTRAS
#endif
#ifdef lt_EXTRAS
   lt_EXTRAS
#endif
};


// define constructor - eq
class eq_class : public Expression_class {
protected:
   Expression e1;
   Expression e2;
public:
   eq_class(Expression a1, Expression a2) {
      e1 = a1;
      e2 = a2;
   }
   Expression copy_Expression();
   void dump(ostream& stream, int n);
   // add begin
   Expression type_check(Env env);
   // add end

#ifdef Expression_SHARED_EXTRAS
   Expression_SHARED_EXTRAS
#endif
#ifdef eq_EXTRAS
   eq_EXTRAS
#endif
};


// define constructor - leq
class leq_class : public Expression_class {
protected:
   Expression e1;
   Expression e2;
public:
   leq_class(Expression a1, Expression a2) {
      e1 = a1;
      e2 = a2;
   }
   Expression copy_Expression();
   void dump(ostream& stream, int n);
   // add begin
   Expression type_check(Env env);
   // add end

#ifdef Expression_SHARED_EXTRAS
   Expression_SHARED_EXTRAS
#endif
#ifdef leq_EXTRAS
   leq_EXTRAS
#endif
};


// define constructor - comp
class comp_class : public Expression_class {
protected:
   Expression e1;
public:
   comp_class(Expression a1) {
      e1 = a1;
   }
   Expression copy_Expression();
   void dump(ostream& stream, int n);
   // add begin
   Expression type_check(Env env);
   // add end

#ifdef Expression_SHARED_EXTRAS
   Expression_SHARED_EXTRAS
#endif
#ifdef comp_EXTRAS
   comp_EXTRAS
#endif
};


// define constructor - int_const
class int_const_class : public Expression_class {
protected:
   Symbol token;
public:
   int_const_class(Symbol a1) {
      token = a1;
   }
   Expression copy_Expression();
   void dump(ostream& stream, int n);
   // add begin
   Expression type_check(Env env);
   // add end

#ifdef Expression_SHARED_EXTRAS
   Expression_SHARED_EXTRAS
#endif
#ifdef int_const_EXTRAS
   int_const_EXTRAS
#endif
};


// define constructor - bool_const
class bool_const_class : public Expression_class {
protected:
   Boolean val;
public:
   bool_const_class(Boolean a1) {
      val = a1;
   }
   Expression copy_Expression();
   void dump(ostream& stream, int n);
   // add begin
   Expression type_check(Env env);
   // add end

#ifdef Expression_SHARED_EXTRAS
   Expression_SHARED_EXTRAS
#endif
#ifdef bool_const_EXTRAS
   bool_const_EXTRAS
#endif
};


// define constructor - string_const
class string_const_class : public Expression_class {
protected:
   Symbol token;
public:
   string_const_class(Symbol a1) {
      token = a1;
   }
   Expression copy_Expression();
   void dump(ostream& stream, int n);
   // add begin
   Expression type_check(Env env);
   // add end

#ifdef Expression_SHARED_EXTRAS
   Expression_SHARED_EXTRAS
#endif
#ifdef string_const_EXTRAS
   string_const_EXTRAS
#endif
};


// define constructor - new_
class new__class : public Expression_class {
protected:
   Symbol type_name;
public:
   new__class(Symbol a1) {
      type_name = a1;
   }
   Expression copy_Expression();
   void dump(ostream& stream, int n);
   // add begin
   Expression type_check(Env env);
   // add end

#ifdef Expression_SHARED_EXTRAS
   Expression_SHARED_EXTRAS
#endif
#ifdef new__EXTRAS
   new__EXTRAS
#endif
};


// define constructor - isvoid
class isvoid_class : public Expression_class {
protected:
   Expression e1;
public:
   isvoid_class(Expression a1) {
      e1 = a1;
   }
   Expression copy_Expression();
   void dump(ostream& stream, int n);
   // add begin
   Expression type_check(Env env);
   // add end

#ifdef Expression_SHARED_EXTRAS
   Expression_SHARED_EXTRAS
#endif
#ifdef isvoid_EXTRAS
   isvoid_EXTRAS
#endif
};


// define constructor - no_expr
class no_expr_class : public Expression_class {
protected:
public:
   no_expr_class() {
   }
   Expression copy_Expression();
   void dump(ostream& stream, int n);
   // add begin
   Expression type_check(Env env);
   // add end

#ifdef Expression_SHARED_EXTRAS
   Expression_SHARED_EXTRAS
#endif
#ifdef no_expr_EXTRAS
   no_expr_EXTRAS
#endif
};


// define constructor - object
class object_class : public Expression_class {
protected:
   Symbol name;
public:
   object_class(Symbol a1) {
      name = a1;
   }
   Expression copy_Expression();
   void dump(ostream& stream, int n);
   // add begin
   Expression type_check(Env env);
   // add end

#ifdef Expression_SHARED_EXTRAS
   Expression_SHARED_EXTRAS
#endif
#ifdef object_EXTRAS
   object_EXTRAS
#endif
};


// define the prototypes of the interface
Classes nil_Classes();
Classes single_Classes(Class_);
Classes append_Classes(Classes, Classes);
Features nil_Features();
Features single_Features(Feature);
Features append_Features(Features, Features);
Formals nil_Formals();
Formals single_Formals(Formal);
Formals append_Formals(Formals, Formals);
Expressions nil_Expressions();
Expressions single_Expressions(Expression);
Expressions append_Expressions(Expressions, Expressions);
Cases nil_Cases();
Cases single_Cases(Case);
Cases append_Cases(Cases, Cases);
Program program(Classes);
Class_ class_(Symbol, Symbol, Features, Symbol);
Feature method(Symbol, Formals, Symbol, Expression);
Feature attr(Symbol, Symbol, Expression);
Formal formal(Symbol, Symbol);
Case branch(Symbol, Symbol, Expression);
Expression assign(Symbol, Expression);
Expression static_dispatch(Expression, Symbol, Symbol, Expressions);
Expression dispatch(Expression, Symbol, Expressions);
Expression cond(Expression, Expression, Expression);
Expression loop(Expression, Expression);
Expression typcase(Expression, Cases);
Expression block(Expressions);
Expression let(Symbol, Symbol, Expression, Expression);
Expression plus(Expression, Expression);
Expression sub(Expression, Expression);
Expression mul(Expression, Expression);
Expression divide(Expression, Expression);
Expression neg(Expression);
Expression lt(Expression, Expression);
Expression eq(Expression, Expression);
Expression leq(Expression, Expression);
Expression comp(Expression);
Expression int_const(Symbol);
Expression bool_const(Boolean);
Expression string_const(Symbol);
Expression new_(Symbol);
Expression isvoid(Expression);
Expression no_expr();
Expression object(Symbol);


#endif

semant.h

#ifndef SEMANT_H_
#define SEMANT_H_

#include <assert.h>
#include <iostream>
#include <unordered_map>
#include <vector>
#include "cool-tree.h"
#include "stringtab.h"
#include "symtab.h"
#include "list.h"

#define TRUE 1
#define FALSE 0

class ClassTable;
typedef ClassTable *ClassTableP;

// This is a structure that may be used to contain the semantic
// information such as the inheritance graph.  You may use it or not as
// you like: it is only here to provide a container for the supplied
// methods.




class ClassTable {
private:
  int semant_errors;
  void install_basic_classes();
  ostream& error_stream;
  // add begin
  // 符号和类对应的关系
  std::unordered_map<Symbol, Class_> class_table;
  // 继承图
  std::unordered_map<Symbol, Symbol> inhert_graph;
  // add end

public:
  ClassTable(Classes);
  int errors() { return semant_errors; }
  ostream& semant_error();
  ostream& semant_error(Class_ c);
  ostream& semant_error(Symbol filename, tree_node *t);
  // add begin
  void add_to_class_table(Class_ c);
  bool is_valid();
  Class_ get_class(Symbol s);
  Symbol get_parent(Symbol child, Symbol name);
  bool check_method(Symbol s1, Symbol s2, Symbol name);
  bool is_class_exit(Symbol s);
  bool is_sub_class(Symbol s1, Symbol s2);
  Symbol lub(Symbol s1, Symbol s2);
  Symbol get_parents(Symbol s, std::vector<Symbol> &v);
  Formals get_formals(Symbol name, Symbol method);
  Symbol get_return_type(Symbol name, Symbol method);
  bool check(Formals formals, std::vector<Symbol> return_type);
  // add end
};



#endif

semant.cc

#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include <stack>
#include <unordered_set>
#include <vector>
#include "semant.h"
#include "utilities.h"


extern int semant_debug;
extern char *curr_filename;

//////////////////////////////////////////////////////////////////////
//
// Symbols
//
// For convenience, a large number of symbols are predefined here.
// These symbols include the primitive type and method names, as well
// as fixed names used by the runtime system.
//
//////////////////////////////////////////////////////////////////////
static Symbol 
    arg,
    arg2,
    Bool,
    concat,
    cool_abort,
    copy,
    Int,
    in_int,
    in_string,
    IO,
    length,
    Main,
    main_meth,
    No_class,
    No_type,
    Object,
    out_int,
    out_string,
    prim_slot,
    self,
    SELF_TYPE,
    Str,
    str_field,
    substr,
    type_name,
    val;
//
// Initializing the predefined symbols.
//
static void initialize_constants(void)
{
    arg         = idtable.add_string("arg");
    arg2        = idtable.add_string("arg2");
    Bool        = idtable.add_string("Bool");
    concat      = idtable.add_string("concat");
    cool_abort  = idtable.add_string("abort");
    copy        = idtable.add_string("copy");
    Int         = idtable.add_string("Int");
    in_int      = idtable.add_string("in_int");
    in_string   = idtable.add_string("in_string");
    IO          = idtable.add_string("IO");
    length      = idtable.add_string("length");
    Main        = idtable.add_string("Main");
    main_meth   = idtable.add_string("main");
    //   _no_class is a symbol that can't be the name of any 
    //   user-defined class.
    No_class    = idtable.add_string("_no_class");
    No_type     = idtable.add_string("_no_type");
    Object      = idtable.add_string("Object");
    out_int     = idtable.add_string("out_int");
    out_string  = idtable.add_string("out_string");
    prim_slot   = idtable.add_string("_prim_slot");
    self        = idtable.add_string("self");
    SELF_TYPE   = idtable.add_string("SELF_TYPE");
    Str         = idtable.add_string("String");
    str_field   = idtable.add_string("_str_field");
    substr      = idtable.add_string("substr");
    type_name   = idtable.add_string("type_name");
    val         = idtable.add_string("_val");
}


// change
ClassTable::ClassTable(Classes classes) : semant_errors(0) , error_stream(cerr) {
    /* Fill this in */
    install_basic_classes();
    
    for (int i = classes->first(); classes->more(i); i = classes->next(i)){
        add_to_class_table(classes->nth(i));
    }
}

void ClassTable::install_basic_classes() {

    // The tree package uses these globals to annotate the classes built below.
   // curr_lineno  = 0;
    Symbol filename = stringtable.add_string("<basic class>");
    
    // The following demonstrates how to create dummy parse trees to
    // refer to basic Cool classes.  There's no need for method
    // bodies -- these are already built into the runtime system.
    
    // IMPORTANT: The results of the following expressions are
    // stored in local variables.  You will want to do something
    // with those variables at the end of this method to make this
    // code meaningful.

    // 
    // The Object class has no parent class. Its methods are
    //        abort() : Object    aborts the program
    //        type_name() : Str   returns a string representation of class name
    //        copy() : SELF_TYPE  returns a copy of the object
    //
    // There is no need for method bodies in the basic classes---these
    // are already built in to the runtime system.

    Class_ Object_class =
	class_(Object, 
	       No_class,
	       append_Features(
			       append_Features(
					       single_Features(method(cool_abort, nil_Formals(), Object, no_expr())),
					       single_Features(method(type_name, nil_Formals(), Str, no_expr()))),
			       single_Features(method(copy, nil_Formals(), SELF_TYPE, no_expr()))),
	       filename);

    // 
    // The IO class inherits from Object. Its methods are
    //        out_string(Str) : SELF_TYPE       writes a string to the output
    //        out_int(Int) : SELF_TYPE            "    an int    "  "     "
    //        in_string() : Str                 reads a string from the input
    //        in_int() : Int                      "   an int     "  "     "
    //
    Class_ IO_class = 
	class_(IO, 
	       Object,
	       append_Features(
			       append_Features(
					       append_Features(
							       single_Features(method(out_string, single_Formals(formal(arg, Str)),
										      SELF_TYPE, no_expr())),
							       single_Features(method(out_int, single_Formals(formal(arg, Int)),
										      SELF_TYPE, no_expr()))),
					       single_Features(method(in_string, nil_Formals(), Str, no_expr()))),
			       single_Features(method(in_int, nil_Formals(), Int, no_expr()))),
	       filename);  

    //
    // The Int class has no methods and only a single attribute, the
    // "val" for the integer. 
    //
    Class_ Int_class =
	class_(Int, 
	       Object,
	       single_Features(attr(val, prim_slot, no_expr())),
	       filename);

    //
    // Bool also has only the "val" slot.
    //
    Class_ Bool_class =
	class_(Bool, Object, single_Features(attr(val, prim_slot, no_expr())),filename);

    //
    // The class Str has a number of slots and operations:
    //       val                                  the length of the string
    //       str_field                            the string itself
    //       length() : Int                       returns length of the string
    //       concat(arg: Str) : Str               performs string concatenation
    //       substr(arg: Int, arg2: Int): Str     substring selection
    //       
    Class_ Str_class =
	class_(Str, 
	       Object,
	       append_Features(
			       append_Features(
					       append_Features(
							       append_Features(
									       single_Features(attr(val, Int, no_expr())),
									       single_Features(attr(str_field, prim_slot, no_expr()))),
							       single_Features(method(length, nil_Formals(), Int, no_expr()))),
					       single_Features(method(concat, 
								      single_Formals(formal(arg, Str)),
								      Str, 
								      no_expr()))),
			       single_Features(method(substr, 
						      append_Formals(single_Formals(formal(arg, Int)), 
								     single_Formals(formal(arg2, Int))),
						      Str, 
						      no_expr()))),
	       filename);

    // add
    add_to_class_table(Object_class);
    add_to_class_table(IO_class);
    add_to_class_table(Int_class);
    add_to_class_table(Bool_class);
    add_to_class_table(Str_class);
}

////////////////////////////////////////////////////////////////////
//
// semant_error is an overloaded function for reporting errors
// during semantic analysis.  There are three versions:
//
//    ostream& ClassTable::semant_error()                
//
//    ostream& ClassTable::semant_error(Class_ c)
//       print line number and filename for `c'
//
//    ostream& ClassTable::semant_error(Symbol filename, tree_node *t)  
//       print a line number and filename
//
///////////////////////////////////////////////////////////////////

ostream& ClassTable::semant_error(Class_ c)
{                                                             
    return semant_error(c->get_filename(), c);
}    

ostream& ClassTable::semant_error(Symbol filename, tree_node *t)
{
    error_stream << filename << ":" << t->get_line_number() << ": ";
    return semant_error();
}

ostream& ClassTable::semant_error()                  
{                                                 
    semant_errors++;                            
    return error_stream;
} 

// start
// add class to classtable
void ClassTable::add_to_class_table(Class_ c){
    Symbol name = c->get_name();
    Symbol parent = c->get_parent();
    Features features = c->get_features();
    Symbol filename = c->get_filename();
    if ((parent == Bool) || (parent == Str) || (parent == SELF_TYPE)){
        // 不能从bool, string, self_type继承
        semant_error(c) << name << "Can't inherent from " << parent << "!" << endl; 
    }else if (name == SELF_TYPE){
        // 不能定义self_type
        semant_error(c) << "Can't define SELF_TYPE!" << endl;
    }else if ((class_table.find(name) != class_table.end()) ||
              (inhert_graph.find(name) != inhert_graph.end())){
        // 不能重复定义
        semant_error(c) << "Can't be defined multiple times!" << endl;
    }else{
        class_table[name] = c;
        inhert_graph[name] = parent;
    }
}

/**
 * 判断定义是否合理:
 * 1. 不含环。
 * 2. 判断是否包含Main。
 * 3. 判断父类是否都已定义。
 **/
bool ClassTable::is_valid(){
    bool cycle_flag = true;
    bool main_flag = false;
    bool define_flag = true;
    for (auto it = inhert_graph.begin(); it != inhert_graph.end(); it++){
        Symbol child = it->first;
        Symbol parent = it->second;
        // 判断是否包含main
        if (child == Main){
            main_flag = true;
        }
        // Object的parent为No_class, 该条件判断是否为根
        while (parent != No_class){
            // 环
            if (parent == child){
                semant_error(class_table[child]) << "Has cycle!" << endl;
                return false;
            }
            // 不存在父节点
            if (!inhert_graph.count(parent)){
                semant_error(class_table[child]) << "Doesn't contain parent!" << endl;
                return false;
            }
            parent = inhert_graph[parent];
        }
    }

    if (main_flag){
        return true;
    }else{
        semant_error() << "Class Main is not defined." << endl;
        return false;
    }
}

// 获得s对应的类
Class_ ClassTable::get_class(Symbol s){
    return class_table[s];
}

// 找到有方法name的父类
Symbol ClassTable::get_parent(Symbol child, Symbol name){
    Symbol parent = inhert_graph[child];
    // 保证
    while (parent != No_class){
        // test 4
        Class_ parent_class = class_table[parent];
        if (parent_class->get_method(name)){
            return parent_class->get_name();
        }
        parent = inhert_graph[parent];
    }

    return NULL;
};

// 判断s1和s2的方法name是否相同
bool ClassTable::check_method(Symbol s1, Symbol s2, Symbol name){
    Class_ c1 = class_table[s1];
    Class_ c2 = class_table[s2];
    Feature f1 = c1->get_method(name);
    Feature f2 = c2->get_method(name);
    Formals fo1 = f1->get_formals();
    Formals fo2 = f2->get_formals();
    Symbol rt1 = f1->get_return_type();
    Symbol rt2 = f2->get_return_type();

    // 返回类型
    if (rt1 != rt2){
        return false;
    }

    // 判断输入参数类型
    int i = fo1->first();
    int j = fo2->first();

    while ((fo1->more(i)) && (fo2->more(j))) {
        if (fo1->nth(i)->get_type() != fo2->nth(j)->get_type()){
            return false;
        }
        i = fo1->next(i);
        j = fo2->next(j);
    }

    if (fo1->more(i) || fo2->more(j)){
        return false;
    }

    return true;
}

// 判断类是否存在
bool ClassTable::is_class_exit(Symbol s){
    return inhert_graph.count(s);
}

// 判断s1是否是s2的子类
bool ClassTable::is_sub_class(Symbol s1, Symbol s2){
    if (s2 == Object){
        return true;
    }
    // 判断s1是否为空
    while (s1 != NULL){
        if (s1 == s2){
            return true;
        }
        s1 = inhert_graph[s1];
    }

    return false;
}

// 获得所有父节点
Symbol ClassTable::get_parents(Symbol s, std::vector<Symbol> &v){
    while (s != No_class){
        v.push_back(s);
        s = inhert_graph[s];
    }
}

// 层数最低的公共祖先
Symbol ClassTable::lub(Symbol s1, Symbol s2){
    Symbol res = Object;
    std::vector<Symbol> v1;
    std::vector<Symbol> v2;
    get_parents(s1, v1);
    get_parents(s2, v2);
    int n1 = v1.size();
    int n2 = v2.size();
    int i = n1 - 1;
    int j = n2 - 1;
    while ((i >= 0) && (j >= 0) && (v1[i] == v2[j])){
        res = v1[i];
        i--;
        j--;
    }

    return res;
}

// 找到类名为name, 方法名为method的formals
Formals ClassTable::get_formals(Symbol name, Symbol method){
    Symbol c = name;
    while (c != No_class){
        // 获得类
        Class_ c_class = class_table[c];
        // 判断是否有方法
        if (c_class->get_method(method)){
            Formals f = c_class->get_method(method)->get_formals();
            if (f != NULL){
                return f;
            }
        }

        c = inhert_graph[c];
    }

    return NULL;
}

// 找到类名为name, 方法名为method的return_type
Symbol ClassTable::get_return_type(Symbol name, Symbol method){
    Symbol c = name;
    while (c != No_class){
        // 获得类
        Class_ c_class = class_table[c];
        // 判断是否有方法
        if (c_class->get_method(method)){
            Symbol f = c_class->get_method(method)->get_return_type();
            if (f != NULL){
                return f;
            }
        }

        c = inhert_graph[c];
    }

    return NULL;
}

// 判断par_types中元素是否为formals中对应元素的子类
bool ClassTable::check(Formals formals, std::vector<Symbol> par_types){
    int i = formals->first();
    int j = 0;
    int n = par_types.size();
    while (formals->more(i) && (j < n)){
        if (!is_sub_class(par_types[j], formals->nth(i)->get_type())){
            return false;
        }
        j++;
        i = formals->next(i);
    }
    if ((j < n) || (formals->more(i))){
        return false;
    }

    return true;
}

// class__class, 初始化, 递归处理, 先设置父节点
void class__class::init(Env env){
    if (name != Object){
        // 先设置父节点
        env.ct->get_class(parent)->init(env);
    }

    // 设置feature
    for (int i = features->first(); features->more(i); i = features->next(i)){
        features->nth(i)->add_to_env(env);
    }
}

// not use
bool class__class::has_method(Symbol name) {
    for (int i = features->first(); features->more(i); i = features->next(i)){
        if ((features->nth(i)->is_method()) && (features->nth(i)->get_name() == name)){
            return true;
        }
    }

    return false;
}

// 获得方法
Feature class__class::get_method(Symbol name) {
    for (int i = features->first(); features->more(i); i = features->next(i)){
        if ((features->nth(i)->is_method()) && (features->nth(i)->get_name() == name)){
            return features->nth(i);
        }
    }

    return NULL;
}

// method_class
void method_class::add_to_env(Env env){

}

// attr_class
void attr_class::add_to_env(Env env){
    if (env.om->probe(name) == NULL){
        // 如果scope中属性未定义, 则直接定义
        env.om->addid(name, &type_decl);
    }else{
        // 如果scope中属性已定义, 则报错
        env.ct->semant_error(env.cur_class) << "Can't be defined multiple times!" << endl;
    }
}

/** type_check **/
// class__class
Class_ class__class::type_check(Env env){
    for (int i = features->first(); features->more(i); i = features->next(i)){
        features->nth(i)->type_check(env);
    }

    return this;
}

/**
 * 1. 进入新的作用域
 * 2. 添加当前类到环境
 * 3. 遍历变量
 * 4. 判断方法是是否继承正确
 * 5. 判断实际返回类型
 *    1. 如果返回类型是SELF_TYPE, 实际返回类型也为SELF_TYPE
 *    2. 返回类型存在
 *    3. 实际返回类型是声明类型的子类
 **/
Feature method_class::type_check(Env env){
    // step1
    env.om->enterscope();
    // step2
    Symbol cur_class = env.cur_class->get_name();
    env.om->addid(self, &cur_class);
    // step3
    for (int i = formals->first(); formals->more(i); i = formals->next(i)){
        formals->nth(i)->type_check(env);
    }
    // step4
    // 首先获得包含当前method的父类, 然后查看是否和父类method匹配
    // 获得包含method的父类
    Symbol parent_class = env.ct->get_parent(cur_class, name);
    if (parent_class != NULL){
        // 判断方法是否继承正确
        if(!env.ct->check_method(cur_class, parent_class, name)){
            env.ct->semant_error(env.cur_class) << "Method " << name << "inherent wrong!" << endl;
        }
    }
    // step5
    Symbol true_return_type = expr->type_check(env)->type;
    if (return_type == SELF_TYPE){
        // 5.1
        if (true_return_type != SELF_TYPE){
            env.ct->semant_error(env.cur_class) << "True return type should be SELF_TYPE!" << endl;
        }
    }else if (!env.ct->is_class_exit(return_type)){
        // 5.2
        env.ct->semant_error(env.cur_class) << "Return type doesn't exist!" << endl;
    }else{
        // 5.3
        if (true_return_type == SELF_TYPE){
            true_return_type = env.cur_class->get_name();
        }
        if (!env.ct->is_sub_class(true_return_type, return_type)){
            env.ct->semant_error(env.cur_class->get_filename(), this) << "True return type isn't subclass of return type!" << endl;
        }
    }
    
    // step1
    env.om->exitscope();

    return this;
}

/**
 * 1. 进入新的作用域
 * 2. 添加当前类到环境
 * 3. 计算init,
 *    1. 判断不是self
 *    2. 如果返回类型为SELF_TYPE, 则返回类型为当前类
 *    3. 判断其返回类型是否为type_decl子类
 **/
Feature attr_class::type_check(Env env){
    // step1
    env.om->enterscope();
    // step2
    Symbol cur_class = env.cur_class->get_name();
    env.om->addid(self, &cur_class);
    // step3
    Symbol true_return_type = init->type_check(env)->type;
    // 3.1
    if (name == self){
        env.ct->semant_error(env.cur_class->get_filename(), this) << "Attr shouldn't be self!" << endl;
    }
    // 3.2
    // SELF_TYPE的类型为自身
    if (true_return_type == SELF_TYPE){
        true_return_type = env.cur_class->get_name();
    }
    // 3.3
    // 判断是否为type_decl的子类, 排除No_type
    if (true_return_type != No_type){
        if (!(env.ct->is_sub_class(true_return_type, type_decl))){
            env.ct->semant_error(env.cur_class) << "True attr type isn't subcalss of type_decl!" << endl;
        }
    }

    // step1
    env.om->exitscope();

    return this;
}

/**
 * 1. 判断参数是否存在
 * 2. 判断类型是否为SELF_TYPE
 * 3. 添加到om中
 **/
Formal formal_class::type_check(Env env){
    if (env.om->probe(name)){
        env.ct->semant_error(env.cur_class) << "Name already exist!" << endl;
    }else if (type_decl == SELF_TYPE){
        env.ct->semant_error(env.cur_class) << "Type shouldn't be SELF_TYPE!" << endl;
    }else{
        env.om->addid(name, &type_decl);
    }

    return this;
}

/**
 * branch
 * ID : TYPE => expr
 * name : type_decl => expr
 **/
Symbol branch_class::type_check(Env env){
    if (env.om->probe(name)){
        env.ct->semant_error(env.cur_class) << "Name already exist!" << endl;
        return Object;
    }
    env.om->addid(name, &type_decl);

    return expr->type_check(env)->type;
}

/**
 * assign
 * OBJECTID ASSIGN expr
 * name = expr
 **/
Expression assign_class::type_check(Env env){
    Symbol expect_type = *env.om->lookup(name);
    Symbol true_type = expr->type_check(env)->type;
    if (env.ct->is_sub_class(true_type, expect_type)){
        type = true_type;
    }else{
        env.ct->semant_error(env.cur_class) << "Assign error!" << endl;
        type = Object;
    }

    return this;
}

/**
 * static_dispatch
 * expr@TYPEID.OBJECTID(actual)
 * expr@name.name(actual)
 **/
Expression static_dispatch_class::type_check(Env env){
    // step1
    Symbol t0 = expr->type_check(env)->type;
    if (env.ct->is_sub_class(t0, type_name)){
        // 当前类型
        Symbol cur_class = t0;
        if (t0 == SELF_TYPE){
            cur_class = env.cur_class->get_name();
        }
        // step2
        // 获得参数的类型
        std::vector<Symbol> par_types;
        for (int i = actual->first(); actual->more(i); i = actual->next(i)){
            Symbol t = actual->nth(i)->type_check(env)->type;
            if (t == SELF_TYPE){
                t = env.cur_class->get_name();
            }
            par_types.push_back(t);
        }
        // 获得参数列表
        Formals formals = env.ct->get_formals(cur_class, name);
        Symbol return_type = env.ct->get_return_type(cur_class, name);
        // 方法定义有误
        if ((formals == NULL) || (return_type == NULL)){
            env.ct->semant_error(env.cur_class) << "Method define wrong!" << endl;
            type = Object;

            return this;
        }
        // step4
        if (!env.ct->check(formals, par_types)){
            env.ct->semant_error(env.cur_class) << "Par type define wrong!" << endl;
            type = Object;

            return this;
        }
        // 更新type
        if (return_type == SELF_TYPE){
            type = t0;
        }else{
            type = return_type;
        }

        return this;
    }else{
        env.ct->semant_error(env.cur_class) << "Wrong class!" << endl;
        type = Object;

        return this;
    }
}

/**
 * dispatch
 * expr.name(actual)
 * 1. eval expr, 判断是否存在
 * 2. eval actual, 获得参数类型
 * 3. 判断方法是否定义有误
 * 4. 判断actual的类型是否匹配
 **/ 
Expression dispatch_class::type_check(Env env){
    // step1
    Symbol t0 = expr->type_check(env)->type;
    // 当前类型
    Symbol cur_class = t0;
    if (t0 == SELF_TYPE){
        cur_class = env.cur_class->get_name();
    }
    // step2
    // 获得参数的类型
    std::vector<Symbol> par_types;
    for (int i = actual->first(); actual->more(i); i = actual->next(i)){
        Symbol t = actual->nth(i)->type_check(env)->type;
        if (t == SELF_TYPE){
            t = env.cur_class->get_name();
        }
        par_types.push_back(t);
    }
    // 获得参数列表
    Formals formals = env.ct->get_formals(cur_class, name);
    Symbol return_type = env.ct->get_return_type(cur_class, name);
    // 方法定义有误
    if ((formals == NULL) || (return_type == NULL)){
        env.ct->semant_error(env.cur_class) << "Method define wrong!" << endl;
        type = Object;

        return this;
    }
    // step4
    if (!env.ct->check(formals, par_types)){
        env.ct->semant_error(env.cur_class) << "Par type define wrong!" << endl;
        type = Object;

        return this;
    }

    // 更新type
    if (return_type == SELF_TYPE){
        type = t0;
    }else{
        type = return_type;
    }

    return this;
}

/**
 * cond
 * IF expr THEN expr ELSE expr FI
 * if pred then then_exp else else_exp fi
 **/
Expression cond_class::type_check(Env env){
    Symbol t0 = pred->type_check(env)->type;
    Symbol t1 = then_exp->type_check(env)->type;
    Symbol t2 = else_exp->type_check(env)->type;
    if (t1 == SELF_TYPE){
        t1 = env.cur_class->get_name();
    }
    if (t2 == SELF_TYPE){
        t2 = env.cur_class->get_name();
    }
    if (t0 != Bool){
        env.ct->semant_error(env.cur_class) << "Pre type should be bool!" << endl;
        type = Object;
    }else{
        type = env.ct->lub(t1, t2);
    }

    return this;
}

/**
 * loop
 * while expr loop expr pool
 * while pred loop body pool
 **/
Expression loop_class::type_check(Env env){
    Symbol pred_type = pred->type_check(env)->type;
    Symbol body_type = body->type_check(env)->type;

    type = Object;
    if (pred_type != Bool){
        env.ct->semant_error(env.cur_class) << "Pre type should be bool!" << endl;
    }

    return this;
}

/**
 * case
 * case expr of [[ID : TYPE => expr; ]]+ esac
 * case expr of cases esac
 **/
Expression typcase_class::type_check(Env env){
    Symbol expr_type = expr->type_check(env)->type;
    // case不能相同
    for (int i = cases->first(); cases->more(i); i = cases->next(i)){
        for (int j = cases->first(); cases->more(j); j = cases->next(j)){
            if ((i != j) && (cases->nth(i)->get_type() == cases->nth(j)->get_type())){
                env.ct->semant_error(env.cur_class) << "Case should be different!" << endl;
                type = Object;
                return this;
            }
        }
    }
    // lub
    int i = cases->first();
    Symbol s = cases->nth(i)->type_check(env);
    for (; cases->more(i); i = cases->next(i)){
        env.om->enterscope();
        Symbol s1 = cases->nth(i)->type_check(env);
        s = env.ct->lub(s, s1);
        env.om->exitscope();
    }
    type = s;

    return this;
}

/**
 * block class
 * [[expr;]]+
 * body
 **/
Expression block_class::type_check(Env env){
    Symbol s = NULL;
    for (int i = body->first(); body->more(i); i = body->next(i)){
        s = body->nth(i)->type_check(env)->type;
    }
    type = s;

    return this;
}

/**
 * let
 * let ID : TYPE [ <- expr ] [[; ID : TYPE [ <- expr ]]]* in expr
 * let identifier : type_decl <- init in body
 **/
Expression let_class::type_check(Env env){
    if (identifier == self){
        env.ct->semant_error(env.cur_class) << "Self can't be used in let!" << endl;
        type = Object;
    }else{
        Symbol expect_type = type_decl;
        Symbol true_type = init->type_check(env)->type;
        // no init
        if (true_type == No_type){
            env.om->enterscope();
            env.om->addid(identifier, &expect_type);
            Symbol s = body->type_check(env)->type;
            type = s;
            env.om->exitscope();
        }else{
            // 检查返回类型
            if (!env.ct->is_sub_class(true_type, expect_type)){
                env.ct->semant_error(env.cur_class) << "True return type isn't subcalss of return type!" << endl;
                type = Object;
            }else{
                env.om->enterscope();
                env.om->addid(identifier, &expect_type);
                Symbol s = body->type_check(env)->get_type();
                type = s;
                env.om->exitscope();
            }
        }

        return this;
    }
}

// 这部分类规则比较简单, 略过注释
Expression plus_class::type_check(Env env){
    Symbol s1 = e1->type_check(env)->type;
    Symbol s2 = e2->type_check(env)->type;
    if ((s1 == Int) && (s2 == Int)){
        type = Int;
    }else{
        env.ct->semant_error(env.cur_class) << "Type should both be int!" << endl;
        type = Object;
    }

    return this;
}

Expression sub_class::type_check(Env env){
    Symbol s1 = e1->type_check(env)->type;
    Symbol s2 = e2->type_check(env)->type;
    if ((s1 == Int) && (s2 == Int)){
        type = Int;
    }else{
        env.ct->semant_error(env.cur_class) << "Type should both be int!" << endl;
        type = Object;
    }

    return this;
}

Expression mul_class::type_check(Env env){
    Symbol s1 = e1->type_check(env)->type;
    Symbol s2 = e2->type_check(env)->type;
    if ((s1 == Int) && (s2 == Int)){
        type = Int;
    }else{
        env.ct->semant_error(env.cur_class) << "Type should both be int!" << endl;
        type = Object;
    }

    return this;
}

Expression divide_class::type_check(Env env){
    Symbol s1 = e1->type_check(env)->type;
    Symbol s2 = e2->type_check(env)->type;
    if ((s1 == Int) && (s2 == Int)){
        type = Int;
    }else{
        env.ct->semant_error(env.cur_class) << "Type should both be int!" << endl;
        type = Object;
    }

    return this;
}

Expression neg_class::type_check(Env env){
    Symbol s1 = e1->type_check(env)->type;
    if (s1 == Int){
        type = Int;
    }else{
        env.ct->semant_error(env.cur_class) << "Type should be int!" << " " << s1 << endl;
        type = Object;
    }

    return this;
}

Expression lt_class::type_check(Env env){
    Symbol s1 = e1->type_check(env)->type;
    Symbol s2 = e2->type_check(env)->type;
    if ((s1 == Int) && (s2 == Int)){
        type = Bool;
    }else{
        env.ct->semant_error(env.cur_class) << "Type should both be int!" << endl;
        type = Object;
    }

    return this;
}

Expression eq_class::type_check(Env env){
    Symbol s1 = e1->type_check(env)->type;
    Symbol s2 = e2->type_check(env)->type;
    if ((s1 == Int && s2 != Int) || (s1 != Int && s2 == Int) ||
        (s1 == Str && s2 != Str) || (s1 != Str && s2 == Str) ||
        (s1 == Bool && s2 != Bool) || (s1 != Bool && s2 == Bool)){
        env.ct->semant_error(env.cur_class) << "Can't compare " << s1 << " = " << s2 << endl;
        type = Object;
    }else{
        type = Bool;
    }

    return this;
}

Expression leq_class::type_check(Env env){
    Symbol s1 = e1->type_check(env)->type;
    Symbol s2 = e2->type_check(env)->type;
    if (((s1 == Int) && (s2 == Int)) ||
        ((s1 == Str) && (s2 == Str)) ||
        ((s1 == Bool) && (s2 == Bool))){
        type = Bool;
    }else{
        env.ct->semant_error(env.cur_class) << "Wrong type!" << endl;
        type = Object;
    }

    return this;
}

Expression comp_class::type_check(Env env){
    Symbol s1 = e1->type_check(env)->type;
    if (s1 == Bool){
        type = Bool;
    }else{
        env.ct->semant_error(env.cur_class) << "Type should be bool!" << endl;
        type = Object;
    }

    return this;
}

Expression int_const_class::type_check(Env env){
    type = Int;

    return this;
}

Expression bool_const_class::type_check(Env env){
    type = Bool;

    return this;
}

Expression string_const_class::type_check(Env env){
    type = Str;

    return this;
}

/**
 * new
 * new TYPE
 * type_name
 **/
Expression new__class::type_check(Env env){
    Symbol s = type_name;
    if (s == SELF_TYPE){
        type = s;
    }else if (env.ct->is_class_exit(s)){
        type = s;
    }else{  
        env.ct->semant_error(env.cur_class) << "Doesn't have class!" << endl;
        type = Object;
    }

    return this;
}

/**
 * isvoid
 * isvoid expr
 * isvoid e1
 **/
Expression isvoid_class::type_check(Env env){
    Symbol s = e1->type_check(env)->type;
    if (!env.ct->is_class_exit(s)){
        env.ct->semant_error(env.cur_class) << "Doesn't have class!" << endl;
        type = Object;
    }
    type = Bool;

    return this;
}

/**
 * no_expr
 * type = No_type
 **/
Expression no_expr_class::type_check(Env env){
    type = No_type;

    return this;
}

/**
 * object(实例化一个类)
 * OBJECTID
 * name
 **/
Expression object_class::type_check(Env env){
    // 重要
    if (name == self){
        type = SELF_TYPE;
    }else if (env.om->lookup(name) != NULL){
        type = *(env.om->lookup(name));
    }else{
        env.ct->semant_error(env.cur_class) << "Doesn't have class!" << endl;
        type = Object;
    }

    return this;
}

/*   This is the entry point to the semantic checker.

     Your checker should do the following two things:

     1) Check that the program is semantically correct
     2) Decorate the abstract syntax tree with type information
        by setting the `type' field in each Expression node.
        (see `tree.h')

     You are free to first do 1), make sure you catch all semantic
     errors. Part 2) can be done in a second stage, when you want
     to build mycoolc.
 */
void program_class::semant()
{
    initialize_constants();

    /* ClassTable constructor may do some semantic analysis */
    // Classes : classes
    // first pass
    ClassTable *classtable = new ClassTable(classes);

    /* some semantic analysis code may go here */
    // second pass
    if ((!classtable->errors()) && (classtable->is_valid())){
        Env env(classtable);
        for (int i = classes->first(); classes->more(i); i = classes->next(i)){
            env.om->enterscope();
            env.cur_class = classes->nth(i);
            classes->nth(i)->init(env);
            classes->nth(i)->type_check(env);
            env.om->exitscope();
        }
    }

    if (classtable->errors()) {
        cerr << "Compilation halted due to static semantic errors." << endl;
        exit(1);
    }
}

测试

下载测试脚本:

wget https://courses.edx.org/assets/courseware/v1/2aa4dec0c84ec3a8d91e0c1d8814452b/asset-v1:StanfordOnline+SOE.YCSCS1+1T2020+type@asset+block/pa3-grading.pl

在PA4目录下运行如下命令:

make clean && make semant && perl pa3-grading.pl

结果:

You got a score of 74 out of 74