Page 81 - 《软件学报》2021年第6期
P. 81

苏卓  等:基于分支标记的数据流模型的代码生成方法                                                        1655


             27: return CGLT
             算法 3 的主体流程是:首先构造一个空的代码生成位置表 CGLT,如第 1 行、第 2 行所示;然后,逐层逐组件
         地根据组件地分支信息向代码生成位置表中添加元素.这里很重要的一点是,每一层在执行的时候会使用上一
         层计算得到的 CGLT.也就是说,组件寻找 Inserter 和插入 Inserter 以及 Branch 不会影响到当前层的其他组件.
         在每一层计算完之后,由算法第 23 行的 CGLT.update(⋅)来整理在这一层中插入的各种元素,让它们能够在下一
         层的计算中生效.第 5 行~第 21 行为针对每个组件的处理代码,首先获得组件的分支路径集合,如第 5 行、第 6
         行所示;之后,根据该组件的分支路径来确定如何修改代码生成位置表.若该组件的所有分支路径不存在冲突,
         也就是这些分支路径的条件不会同时成立,就对这些分支路径分别处理,如第 8 行~第 16 行所示.对于每条分支
         路径,若在代码生成位置表中可以直接找到带有该分支路径的 Inserter,就直接在该 Inserter 位置插入组件的执
         行代码;如果没有,则去掉分支路径的最后一个分支作为 subBranchPath 去寻找 Inserter;如果去掉一个分支后仍
         然找不到,就再去掉最后一个分支作为新的 subBranchPath,直到找到存在的 Inserter.这个迭代是有限次数的,因
         为至少最后会找到带有{{0}}的 Inserter.在迭代过程中,如果找到了满足条件的 Inserter,首先移除代码生成位置
         表中所有该 Inserter 所在的分支之内的所有 Inserter;之后,在该 Inserter 位置创建多层的分支结构,并在每个分
         支结构中添加对应的 Inserter.例如,迭代寻找前的分支路径为{0,0B,0F},最终找到了带有{{0}}的 Inserter,那么
         就在这个 Inserter 的位置依次插入{0,0B}, {0,0B,0F},{0,0B,1F},{0,1B},{0,1B,0F},{0,1B,1F}这些分支和对应的
         Inserter.然后,将当前组件的执行代码插入到{0,0B,0F}对应的 Inserter 位置.针对组件的分支路径存在冲突的情
         况,我们直接在带有{{0}}的 Inserter 位置插入这些分支路径的全部组合的分支及对应的 Inserter,如第 18 行~第
         20 行所示.这种情况适用于复杂的分支交叉的情况.比如某个组件的分支路径集合为{{0,1X},{0,0Y}}(其中,X 组
         件的 1 分支和 Y 组件的 0 分支可能会同时执行),则创建{{0,1X} && {0,0Y}},{{0,1X}},{{0,0Y}}这 3 种分支及对
         应的 Inserter,其中,“&&”表示逻辑与,意为两个分支都成立.这个例子最终会生成如代码片段 1 所示代码.在该算
         法的最后,移除那些分支内容为空的 Branch 元素,并移除所有的 Inserter,因为它们并不会生成实际的代码.
             代码片段 1.  多分支路径组件对应生成的代码示意.
             1:   if (1X && 0Y){  //Branch
             2:      Actor(1X,0Y)    //ActorExe
             3:   }
             4:   else if (1X){   //Branch
             5:      Actor(1X)    //ActorExe
             6:   }
             7:   else if (0Y){   //Branch
             8:      Actor(0Y)    //ActorExe
             9:   }
             接下来,我们仍然以图 2 中的模型为例,根据图 3 中计算好的分支标记来构建一个完整的 CGLT.由于受到篇
         幅和排版的限制,我们没有办法将构造 CGLT 的每一步都罗列出来.代码片段 2 中展示了最终生成的 CGLT,其
         中,用删除线划掉的代表最终被删掉的元素,在注释中注明了该元素是在什么时候创建和删除的.对于图 2 中的
         模型,一开始我们构建一个空的 CGLT,并插入带有{{0}}分支路径的 Inserter,用于指定后续元素插入的位置,对
         应到代码片段 2 的第 31 行.之后,逐层遍历模型.首先是 A 组件,A 组件具有{{0}}分支标记,所以直接将 A 组件的
         执行语句插入到带有{{0}}的 Inserter 前面,对应到代码片段 2 的第 1 行.第 2 层的 B 组件也是同理,只不过 B 组
         件的执行参数为 A 组件的输出,对应到代码片段 2 的第 2 行.虽然 B 组件是分支组件,但是它对应的分支不在这
         里创建,而是在后面的组件遍历中按需要创建的.接下来,遍历到第 3 层的 C 组件,这时我们发现,C 组件的分支标
         记{{0,0B}}在 CGLT 中查不到对应的 Inserter,而且 C 组件的分支标记中也只有一个分支路径{0,0B},所以,这里
         按照算法 3 的第 9 行~第 15 行进行处理.去掉分支路径上的最后一个分支,继续查找子分支路径{0},找到带有
         {{0}}的 Inserter,在该 Inserter 前插入 B 组件的所有分支,并将 C 组件的执行语句插入到新的带有{{0,0B}}的
   76   77   78   79   80   81   82   83   84   85   86