Шаблон посетителя для AST

Я пытаюсь использовать шаблон посетителя для выполнения операций для AST моего компилятора, но я не могу найти реализацию, которая будет работать правильно.

Выдержка из классов AST:

class AstNode
{
public:
    AstNode() {}
};

class Program : public AstNode
{
public:
    std::vector<std::shared_ptr<Class>> classes;

    Program(const std::vector<std::shared_ptr<Class>>&);
    void accept(AstNodeVisitor& visitor) const { visitor.visit(*this); }
};

class Expression : public AstNode
{
public:
    Expression() {}
};

class Method : public Feature
{
public:
    Symbol name;
    Symbol return_type;
    std::vector<std::shared_ptr<Formal>> params;
    std::shared_ptr<Expression> body;

    Method(const Symbol&, const Symbol&, const std::vector<std::shared_ptr<Formal>>&,
            const std::shared_ptr<Expression>&);
    feature_type get_type() const;
};

class Class : public AstNode
{
public:
    Symbol name;
    Symbol parent;
    Symbol filename;
    std::vector<std::shared_ptr<Feature>> features;

    Class(const Symbol&, const Symbol&, const Symbol&, 
           const std::vector<std::shared_ptr<Feature>>&); 
};

class Assign : public Expression
{
public:
    Symbol name;
    std::shared_ptr<Expression> rhs;

    Assign(const Symbol&, const std::shared_ptr<Expression>&);
};

Посетитель (частичная реализация):

class AstNodeVisitor 
{
public:
    virtual void visit(const Program&) = 0;
    virtual void visit(const Class&) = 0;
    virtual void visit(const Attribute&) = 0;
    virtual void visit(const Formal&) = 0;
    virtual void visit(const Method&) = 0;
};

class AstNodePrintVisitor : public AstNodeVisitor
{
private:
    size_t depth;

public:
    void visit(const Program& node) { 
        for (auto cs : node.classes)
            visit(*cs);
    }

    void visit(const Class&);
    void visit(const Attribute&);
    void visit(const Formal&);
    void visit(const Method&);
};

Как я это использую:

AstNodePrintVisitor print;
ast_root->accept(print); // ast_root is a shared_ptr<Program>

Вопрос:

Узел метода содержит член тела типа Expression -, который является базовым классом. Как я буду его посещать?

Я подумал, может быть, я мог бы просто написать метод accept для каждого узла AST и вместо этого выполнять обход там. (т.е. вместо того, чтобы вызывать визит ()в посетителе, вызовите accept ()в посещаемом объекте, затем вызовите визит (*это ), чтобы вызовы были полиморфными и вызывался правильный метод посещения ()посетителя.

Однако, если я сделаю это, у меня не будет возможности пройти сверху -вниз (операцию, затем рекурсию )или снизу -вверх (рекурсию, затем операцию ), поскольку мне нужно выбрать только одну. Под этим я подразумеваю, что для PrintVisitor, например, потребуется обход AST сверху -вниз, а для TypeCheck потребуется подход снизу -вверх.

Есть ли способ обойти это? Или я переборщил -с инженерными вещами? Прямо сейчас я думаю, что самый быстрый способ — просто реализовать методы в самих узлах.

8
задан Coding District 13 July 2012 в 05:38
поделиться