Как избежать чрезмерного использования динамического c приведения типов, когда речь идет о полиморфных c типах / правильно ли я их использую для своего AST? - PullRequest
0 голосов
/ 08 января 2020

Я написал компилятор, который работает в его текущей форме. Однако я чувствую, что чрезмерно использую динамическое приведение c при разграничении различных подклассов для узлов при посещении узлов в AST. Вот пример:

У меня есть рекурсивный метод с именем visit, который динамически приводит параметр узла для каждого подкласса узла. Он проверит, если приведение прошло успешно, и затем предпримет соответствующие действия следующим образом:

VariableValue visit(Node *node) {
    Num* num = dynamic_cast<Num*>(node);
    if (num != NULL) {
        return visit_Num(num);
    }
    delete num;
    BinOp* binop = dynamic_cast<BinOp*>(node);
    if (binop != NULL) {
        return visit_BinOp(binop);
    }
    delete binop;
    UnOp* unop = dynamic_cast<UnOp*>(node);
    if (unop != NULL) {
        return visit_UnaryOp(unop);
    }
    delete unop;
    ...

Проблема в том, что у меня много разных подклассов узлов, поэтому эти блоки операторов if go on для пока. Я чувствую, что этот подход не очень эффективен на процессоре и памяти, так как приведение будет создано для каждого подкласса узла и должно быть проверено для каждого из них. Я пытался улучшить это, используя delete, когда произойдет сбой приведения.

Есть ли лучший способ достичь желаемых результатов в среде polymorphi c?

Для некоторого контекста здесь классы узлов, включая родительский:

class Node {
    public:
        virtual std::string toString() = 0;
        virtual int getNodeAttribute() { return 0; }
        Token token;
        Node(){}
};

class BinOp : public Node{
    public:
        Node *left, *right; 
        Token op;
        BinOp(Node *cleft, Token cop, Node *cright) {
            left = cleft;
            Node::token = cop;
            op = cop;
            right = cright;
        }
        std::string toString() {
            return "BinOp Node";
        }
};

class Num : public Node{
    public:
        TokenValue value;
        Num(Token ctoken) {
            Node::token = ctoken;
            value = ctoken.value;
        }
        std::string toString() {
            return "Num Node";
        }
};

class UnOp : public Node {
    public:
        Node *expr;
        UnOp(Token ctoken, Node *cexpr) {
            Node::token = ctoken;
            expr = cexpr;
        }
        std::string toString() {
            return "UnOp Node";
        }
};

...

А вот как генерируется узел в синтаксическом анализаторе (например, Num узел)

Node* Parser::factor() {
    ...
    else if (token.type == TOKENTYPE::INTEGER) {
        eat(TOKENTYPE::INTEGER);
        Num* numNode = new Num(token);
        return numNode;
    }
    ...

...