Tôi đang cố gắng sử dụng mẫu khách truy cập để thực hiện các hoạt động cho AST của trình biên dịch của tôi nhưng tôi dường như không thể tìm ra một triển khai sẽ hoạt động đúng.Mô hình khách truy cập cho AST
lớp AST trích đoạn:
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>&);
};
khách (thực hiện một phần):
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&);
};
Làm thế nào tôi đang sử dụng nó:
AstNodePrintVisitor print;
ast_root->accept(print); // ast_root is a shared_ptr<Program>
Vấn đề:
Các Phương thức Node chứa một bo dy thành viên của loại Expression - đó là một lớp cơ sở. Làm thế nào tôi sẽ ghé thăm nó?
Tôi nghĩ có lẽ tôi chỉ đơn giản có thể viết một phương thức chấp nhận cho mỗi nút AST và thực hiện chuyển đổi ở đó. (ví dụ: thay vì gọi số lượt truy cập() trong khách truy cập, hãy gọi chấp nhận() trong lượt truy cập, sau đó gọi đến (* this) để các cuộc gọi sẽ được đa hình và phương thức truy cập() của khách truy cập được gọi là
Tuy nhiên, nếu tôi làm điều này, tôi sẽ không có tùy chọn để đi qua từ trên xuống (hoạt động sau đó recurse) hoặc từ dưới lên (recurse sau đó hoạt động) vì tôi phải chọn chỉ một.Vì điều này tôi có nghĩa là một PrintVisitor ví dụ sẽ cần một từ trên xuống dưới của AST nhưng một TypeCheck sẽ cần một phương pháp tiếp cận từ dưới lên
Có cách nào khác không? Hay tôi là kỹ thuật quá mức? Bây giờ tôi nghĩ cách nhanh nhất là thực hiện các phương pháp trong các nút của chính mình.
Hoặc chỉ sử dụng Bison. –
@ H2CO3 Vâng, tôi đã sử dụng Bison để phân tích cú pháp và đó là cách AST được tạo ra. Tôi hiện đang thực hiện phân tích ngữ nghĩa (kiểm tra kiểu, phạm vi, ..) và sẽ cần phải suy nghĩ về gen mã là tốt. –
oh OK :) Và btw bạn không thể sử dụng phương pháp tiếp cận từ trên xuống để kiểm tra kiểu? –