【问题标题】:Typechecker for a C/C++ like language用于类似 C/C++ 的语言的类型检查器
【发布时间】:2021-05-19 11:00:14
【问题描述】:

目前我正在为类似 C/C++ 的语言开发一个编译器,以便更具体地作为类型检查器。 我已经生成了一个带有语法和 bnfc 工具的解析器。对于我的类型检查器,我需要推断表达式的类型。所有表达式都派生自抽象基类 Exp,如下所示:

class Exp {
...
}

class ExpPlus : public {
 ...
}

class ExpAnd : public {
 ...
} 
...

ExpPlus 指的是Exp + Exp,ExpAnd 指的是Exp && Exp。 我的推断函数接受一个表达式并返回它的类型,如下所示:

ype *TypeChecker::infer(Exp *exp)
{
    // check for kind of expression
    /* Base cases */
    if(dynamic_cast<ETrue*>(exp))
    {
        Type *tBool = new Type_bool;
        return tBool;
    }
    if(dynamic_cast<EFalse*>(exp))
    {
        Type *tBool = new Type_bool;
        return tBool;
    }
    if(dynamic_cast<EInt*>(exp))
    {
        Type *tInt = new Type_int;
        return tInt;
    }
    if(dynamic_cast<EDouble*>(exp))
    {
        Type *tDouble = new Type_double;
        return tDouble;
    }
    if(dynamic_cast<EId*>(exp))   // search for type of given Id in contexts
    {
        EId *eId = dynamic_cast<EId*>(exp);

        Type *typeOfSearchedId = env_->lookupVarTypeFromContext(eId->id_);
        return typeOfSearchedId;
    }
    /* Base cases end*/

    /* check expressions */
    if(dynamic_cast<EApp*>(exp))
    {
        EApp *eApp = dynamic_cast<EApp*>(exp);
        Type *retType = env_->lookupFunTypeFromSymbolTable(eApp->id_).returnType;

        return retType;
    }
    if(dynamic_cast<EUPlus*>(exp))
    {
        // cast exp to type of exp
        EUPlus *eu_plus = dynamic_cast<EUPlus*>(exp);

        // infer till base case is derived
        Type *typeExp = infer(eu_plus->exp_);

        // if type is int or double
        if(dynamic_cast<Type_int*>(typeExp) || dynamic_cast<Type_double*>(typeExp))
            return typeExp;

        throw TypeException("Trying to unary add wrong type: " + env_->getStringRepresentationOfType(typeExp));
    }
...

如您所见,我有一长串 If 语句,用于检查表达式是哪种具体表达式类型,它可以正常工作,但我想知道是否有更优雅的方式来执行此操作。

【问题讨论】:

  • chain of if(dynamic_cast&lt;.... 表示你仍然不知道应该如何使用多态性。
  • 使用虚函数而不是动态转换
  • 请注意,您发布的代码没有冒犯,有点混乱。 : public 没有提到基类,; 在类定义之后丢失,infer 是如此不完整,以至于很难理解它实际上做了什么。请阅读minimal reproducible example
  • 您应该研究访问者模式。

标签: c++ casting compiler-construction typechecking bnfc


【解决方案1】:

你弄错了多态性。

而不是这个:

class Base {};

class Derived1 : public Base {};
class Derived2 : public Base {};
class Derived3 : public Base {};
//...

void foo(Base* b) {
    if(dynamic_cast<Derived1*>(b)) {
        do_something( dynamic_cast<Derived1*>(b));
    } else if (dynamic_cast<Derived2*>(b)) {
        do_something( dynamic_cast<Derived2*>(b));
    } else if ....
}

你应该通过使用虚方法来真正利用多态性:

class Base {
    virtual void do_something() = 0;
    virtual ~Base() {}
};

class Derived1 : public Base {
    void do_something() override { /*...*/ }
};
class Derived2 : public Base {
    void do_something() override { /*...*/ }
};
//...

void foo(Base* b) {
    b->do_something();
}

请注意,现在并不是每个使用Base* 并根据动态类型期望不同行为的方法都必须真正知道动态类型。 foo 只是调用do_something 并且虚拟调度选择正确的方法被调用。如果你写了一些bar(Base*),你不需要第二块if-else,而是再次调用虚方法。

我对示例进行了很多简化,尽管在您的代码中似乎所有分支都返回type,唯一的区别是不同派生类的不同实现。

【讨论】:

  • 通常首选使用访问者模式,而不是让 AST 类包含每个编译阶段的方法。在我看来,将所有类型检查逻辑放在一个专用于类型检查的文件中,并将所有代码生成逻辑放在一个专用于代码生成等的文件中,而不是将其分布在所有不同的 AST 类中更有意义。
  • @sepp2k 我承认我只关注多态性的使用而忽略了实际用例。 tbh 我认为任何东西都比 OP 目前拥有的更好;)
猜你喜欢
  • 2023-02-23
  • 1970-01-01
  • 2011-09-05
  • 1970-01-01
  • 2018-03-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多