3

我已经定义了我的语言的 BNF,但不知道如何从中设计 AST。

例如,从我的 BNF 的前几行:

<program> ::= <import declarations>? <class declaration>?
<import declarations> ::= <import declaration> | <import declarations> <import declaration>
<class declaration> ::= class <identifier> <class body>
<import declaration> ::= import <type name> ';'

我如何从我的 AST 中表达这一点?我应该这样设计吗?

typedef vector<ImportDeclaration*> ImportDeclarationList;

class Program {
    ImportDeclarationList importDeclarations;
    ClassDeclaration classDeclaration;
};

class ImportDeclaration {
    TypeName typeName;
};

class ClassDeclaration {
    Identifier identifer;
    ClassBody classbody;
};

我需要在这些类之间添加一些继承吗?

是否有一些关于如何从 BNF 设计 AST 的书籍?

4

1 回答 1

3

你只需要实现一个树数据结构。这意味着您将需要某个类,例如 Node,AST 的所有其他可能元素都必须从该类继承。然后,您可以使用成员指针 (Node*)。如果孩子的数量可能不同,您可以将它们存储在 std::vector 中。例如。对于一个非常简单的产品(假设 IntLiteral 是一个终端):

Addition := IntLiteral + IntLiteral

可以为 AST 编写以下代码:

struct Node {
    virtual Node* clone() { return new Node(*this);};
    virtual ~Node() {}
};
class IntLiteral : Node {
    int value;
public:
    IntLiteral(int v) : value(v) {}
    virtual IntLiteral* clone()
    {
        return new IntLiteral(*this);
    }
};
class Addition : Node {
    Node* left;
    Node* right;
public:
    Addition(Node* l, Node* r)
        : Node(), left(l->clone()), right(r->clone()) {}
    virtual Addition* clone()
    {
        return new Addition(*this);
    }
};

假设您是手动实现的,您可以在解析器代码的接受函数中将节点添加到根节点(在本例中为 Addition* 类型)。

实际上,您可能希望generate每个节点都有一个函数。或者,这可能是一个更好的主意,您将需要访问器和树遍历器来生成代码。

有很多关于解析器的书籍,其中一本将是经典的“龙书”,尽管重点实际上是那里的编译器。

于 2012-10-27T12:02:01.577 回答