如何从BNF设计抽象语法树(AST)

时间:2012-10-22 09:24:34

标签: compiler-construction translation abstract-syntax-tree bnf

我已经定义了我的语言的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的书籍?

1 个答案:

答案 0 :(得分: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函数。或者,这可能是一个更好的主意,您将需要访问器和树遍历来生成代码。

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