我已经定义了我的语言的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的书籍?
答案 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
函数。或者,这可能是一个更好的主意,您将需要访问器和树遍历来生成代码。
有很多关于解析器的书籍,其中一本将是经典的“龙书”,虽然重点实际上是那里的编译器。