-1

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

class Exp {
...
}

class ExpPlus : public {
 ...
}

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

ExpPlus 分别是指Exp + Exp和 ExpAnd to 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 语句,用于检查表达式是哪种具体表达式类型,它工作得很好,但我想知道是否有更优雅的方式来做到这一点。

4

1 回答 1

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而是再次调用虚拟方法。

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

于 2021-05-19T11:11:06.310 回答