【问题标题】:Boost::Spirit::Qi autorules -- avoiding repeated copying of AST data structuresBoost::Spirit::Qi 自动规则——避免重复复制 AST 数据结构
【发布时间】:2011-01-10 03:03:03
【问题描述】:

我一直在使用 Qi 和 Karma 对几种小语言进行一些处理。大多数语法都很小(20-40 条规则)。我几乎完全可以使用自动规则,所以我的解析树完全由变体、结构和 std::vectors 组成。

此设置适用于常见情况:
1) 解析某些东西 (Qi),
2) 对解析树(访问者)进行少量操作,并且
3)输出一些东西(业力)。

但是,我担心如果我想对语法树进行复杂的结构更改(例如移动大子树)会发生什么。考虑以下玩具示例:

使用自动规则的 s-expr 样式逻辑表达式的语法...

// Inside grammar class; rule names match struct names...
pexpr %= pand | por | var | bconst;
pand  %= lit("(and ") >> (pexpr % lit(" ")) >> ")";
por   %= lit("(or ") >>  (pexpr % lit(" ")) >> ")";
pnot  %= lit("(not ") >> pexpr >> ")";

...这导致解析树表示看起来像这样...

struct var {
   std::string name;
};
struct bconst {
   bool val;
};

struct pand;
struct por;
struct pnot;                               

typedef boost::variant<bconst,
                       var,
                       boost::recursive_wrapper<pand>,
                       boost::recursive_wrapper<por>,
                       boost::recursive_wrapper<pnot> > pexpr;
struct pand {
   std::vector<pexpr> operands;                    
};

struct por {
   std::vector<pexpr> operands;                    
};

struct pnot {
   pexpr victim;
};

// Many Fusion Macros here

假设我有一个看起来像这样的解析树:

       pand
      / ... \
   por      por
   / \      / \
 var var   var var

(省略号表示“pand 有更多形状相似的孩子。”)

现在,假设我想否定每个 por 节点,所以最终结果是:

       pand
      / ... \
   pnot     pnot
    |        |
   por      por
   / \      / \
 var var   var var

直接的方法是,对于每个 por 子树:
- 创建pnot 节点
(复制 por 正在建设中);
- 在pand 节点中重新分配适当的向量槽
(复制pnot 节点及其por 子树)。

或者,我可以构建一个单独的向量,然后替换(交换)pand 向量批发,消除第二轮复制。

与基于指针的树表示相比,所有这些似乎都很麻烦,这将允许在不复制现有节点的情况下插入 pnot 节点。我的问题:

有没有办法避免使用符合自动规则的数据结构进行大量复制的树操作?我是否应该硬着头皮只使用非自动规则来构建基于指针的 AST(例如,http://boost-spirit.com/home/2010/03/11/s-expressions-and-variants/)?

【问题讨论】:

    标签: copy scalability boost-spirit parse-tree


    【解决方案1】:

    复制子树不应该像你想象的那么昂贵,因为 recursive_variant 本质上是一个 shared_ptr 的包装器。我相信,这不仅是最好的,也是最简单的解决方案。

    【讨论】:

    • 感谢您的见解。我没有过多关注变体的实现。我进行了一个快速实验来验证哪些操作会导致复制: - 在两个现有节点之间插入一个节点会导致恒定数量的复制操作(它不会随着插入下方子树的大小而增长); - 大多数复制是由向量调整大小引起的,话虽如此,如果不需要样板语义操作,直接支持池分配的基于指针的 AST 节点可能会很好。该设置的一个很好的特性是可以将节点地址用作廉价的唯一哈希。
    猜你喜欢
    • 1970-01-01
    • 2012-12-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多