Yacc 不允许传递对象。由于 %union 只能包含 POD 类型,因此必须新建复杂对象并通过指针传递。如果发生语法错误,yacc 解析器就会停止运行,并且对所有这些创建的对象的引用都会丢失。
我提出的唯一解决方案是所有新对象都继承特定的基类,在分配时添加到容器中,如果出现错误,则可以删除该容器中的所有内容。
有谁知道有更好的 yacc 技巧来解决这个问题吗?
请不要告诉我选择不同的解析器。
我喜欢 Yacc,但歧视联合堆栈确实提出了挑战。
不知道你用的是C还是C++。为了我自己的目的,我修改了 Yacc 以生成 C++,但是这个解决方案可以适用于 C。
我的首选解决方案是将接口沿着解析树传递给所有者,而不是沿着堆栈向上传递构造对象。通过在 Yacc 之外创建您自己的堆栈来完成此操作。在调用分配对象的非终端之前,将该对象的所有者推送到此堆栈。
例如:
class IExpressionOwner
{
public:
virtual ExpressionAdd *newExpressionAdd() = 0;
virtual ExpressionSubstract *newExpressionSubtract() = 0;
virtual ExpressionMultiply *newExpressionMultiply() = 0;
virtual ExpressionDivide *newExpressionDivide() = 0;
};
class ExpressionAdd : public Expression, public IExpressionOwner
{
private:
std::auto_ptr<Expression> left;
std::auto_ptr<Expression> right;
public:
ExpressionAdd *newExpressionAdd()
{
ExpressionAdd *newExpression = new ExpressionAdd();
std::auto_ptr<Expression> autoPtr(newExpression);
if (left.get() == NULL)
left = autoPtr;
else
right = autoPtr;
return newExpression;
}
...
};
class Parser
{
private:
std::stack<IExpressionOwner *> expressionOwner;
...
};
Run Code Online (Sandbox Code Playgroud)
所有需要表达式的东西都必须实现 IExpressionOwner 接口,并在调用非终结符表达式之前将自身推送到堆栈。这是很多额外的代码,但它控制对象的生命周期。
更新
表达式示例是一个糟糕的示例,因为只有在减少左操作数之后您才知道该操作。尽管如此,这种技术在许多情况下都有效,并且只需要对表达式进行一些调整。
| 归档时间: |
|
| 查看次数: |
1453 次 |
| 最近记录: |