Ich versuche, das Besuchermuster zu verwenden, um Operationen für den AST meines Compilers durchzuführen, aber ich kann nicht scheinen, eine Implementierung zu finden, die richtig funktioniert.Besuchermuster für AST
AST Klassen Auszug:
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>&);
};
Visitor (teilweise Umsetzung):
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&);
};
Wie ich es bin mit:
AstNodePrintVisitor print;
ast_root->accept(print); // ast_root is a shared_ptr<Program>
Das Problem:
Die Methodenknoten enthält einen bo dy Mitglied des Typs Ausdruck - was eine Basisklasse ist. Wie werde ich es besuchen?
Ich dachte, vielleicht könnte ich einfach eine Annahme-Methode für jeden AST-Knoten schreiben und die Traversierung stattdessen tun. (z. B. statt visit() im Besucher anzurufen, accept() im visitable anzurufen, dann call visit (* this), damit die Aufrufe polymorph werden und die richtige visit() -Methode des Besuchers aufgerufen wird.
Aber wenn ich das tue, habe ich keine Möglichkeit, Top-Down (Operation, dann Rekurse) oder Bottom-Up (Rekurse und Operation) zu durchlaufen, da ich nur einen auswählen muss Top-Down-Traversal des AST, aber ein TypeCheck wird einen Bottom-Up-Ansatz benötigen
Gibt es einen Weg um das? Oder bin ich over-Engineering Dinge? Im Moment denke ich, der schnellste Weg ist, nur die Methoden zu implementieren in den Knoten selbst.
Oder verwenden Sie einfach Bison. –
@ H2CO3 Ja, ich habe Bison zum Parsen verwendet und so wird der AST erstellt. Ich führe gerade eine semantische Analyse durch (Typprüfung, Scope, ..) und werde auch über Code-Gen denken müssen. –
oh OK :) Und BTW können Sie nicht den Top-Down-Ansatz für die Typprüfung verwenden? –