2012-11-21 69 views
1

我目前正在为该主题编写个人教育的编译器前端,并且遇到了有关我通过运算符重载处理C++中的BNF定义的方式的问题。在堆栈上处理对象破坏

目前我的设置如下:

Rule.h:

class Rule 
{ 
public: 
    ChainRule operator>>(Rule& right); 
    OrRule operator|(Rule& right); 
    KleeneRule operator*(); 
    OptionalRule Rule::operator+(); 

    virtual bool parse(TokenList::iterator& begin, TokenList::iterator end) = 0; 
}; 

Rule.cpp:

ChainRule Rule::operator>>(Rule& right) { 
    return ChainRule(this, &right); 
} 

OrRule Rule::operator|(Rule& right) { 
    return OrRule(this, &right); 
} 

KleeneRule Rule::operator*() { 
    return KleeneRule(this); 
} 

OptionalRule Rule::operator+() { 
    return OptionalRule(this); 
} 

链式法则,OrRule,KleeneRule,OptionalRule和EmptyRule是平凡定义如下所以:

class ChainRule : public Rule 
{ 
private: 
    Rule* next; 
    Rule* _this; 

public: 
    ChainRule(); 
    ChainRule(Rule* _this, Rule* right); 

    bool parse(TokenList::iterator& begin, TokenList::iterator end) override; 
}; 

Rule的每个子类显然都定义了parse()的合理实现。使用这些类我可以定义我的语法如下:

OrRule assignment_exp = logical_or_exp 
         | unary_exp >> StringRule("=") >> assignment_exp 
         ; 

现在问题是这样的:每个重载操作符通过值返回一个新对象。这意味着每当我使用操作符>>或操作符|时从Rule类中,一旦我从调用操作符>>或操作符|返回,这些指针就会被垃圾回收因为堆栈已经被清理并且对象不见了。

既不能在我的Rule子类的构造函数中使用按值传递,因为这不允许我定义递归语法。

所以我没有选择通过值传递对象,也没有通过指针传递对象的选项。任何人都可以指出我的解决方案,不会强迫我像这样定义我的语法吗?

StringRule s = StringRule("="); 
OrRule assignment_exp; 
ChainRule temp1 = s >> assignment_exp; 
ChainRule temp2 = unary_exp >> temp1; 
assignment_exp = logical_or_exp | temp2; 

P.S.我意识到各种解析器生成器和Boost.Spirit,但我的目标是编写我自己的解析器。

回答

1

您可以在堆上分配返回对象(通过工厂)并将它们作为参考返回。工厂可以跟踪它们,所以你不会泄漏。就语法而言,它的工作原理与按价值归还它们时一样。

1

您可以通过用包装对象替换您的Rule*(其中存在无法为它们重载操作符的问题)来解决此问题。即ChainRule将包含RuleRef next而不是Rule * next等,并且所有运营商将被定义为RuleRefRuleRef只包含Rule*,并且可以从Rule*构建。为了简化内存处理,您可以从智能指针类继承。