Page 115 - 《软件学报》2026年第2期
P. 115

594                                                        软件学报  2026  年第  37  卷第  2  期


                    改写模块中的抽象语法树改写器会递归遍历抽象语法树解析模块传递过来的源框架下的抽象语法树, 在此过
                 程中迁移程序中的       VISIT  函数会根据当前遍历到的节点类型来动态地调用相应的访问方法来处理该节点, 这些节
                 点如表所示, 包括     Import 节点、FunctionDef 节点、Call 节点等, 分别对应本节上文所述的框架间差异信息的导入
                 模块、方法名称、算子名称及其参数等.
                    在处理   Import 节点和  ImportFrom  节点时, 代码依赖生成器会根据       AST  生成前述的通用依赖信息        UDepInfo;
                 在处理其他节点如       FunctionDef 和  Call 等节点时, 抽象语法树改写器会根据       UDepInfo  生成当前遍历算子的完整
                 算子名称, 并构建该算子的特定算子信息             SOpInfo (specific operator information), 包括存储完整算子名称的  name、
                 存储算子位置和缩进信息的          lineno  和  col_offset、存储算子参数信息的   args 和  keywords 等, 此外, 若该算子赋值
                 给了变量, 则还需要存储该算子赋值变量名称的               var, 如表  5  所示. 通过特定算子信息, 抽象语法树改写器就可以利
                 用其中的完整算子名称及参数信息到领域知识图谱中获取目标框架下对应的算子名称及参数信息, 通过构建新节
                 点并覆盖原节点来改写抽象语法树.

                                                   表 5 特定算子信息说明

                                    SOpInfo单元                            说明
                                      name                           算子的完整名称
                                  lineno/end_lineno                   算子位置信息
                                col_offset/end_col_offset             算子缩进信息
                                       var                          算子赋值的变量名称
                                       args                      按位置传入的参数组成的列表
                                     keywords              代表以关键字传入的参数的keyword对象的列表

                    此外, 可能存在源框架算子与目标框架下对应算子的参数用法不一致的问题, 例如所支持的参数类型不一致、
                 参数含义不一致等, 因此需要针对某些特定算子存储相关映射信息并进行针对性的改写. 在本文中, 辅助映射转换
                 规则中存储了上述特定信息, 抽象语法树改写器会利用反射及特定算子信息, 到辅助映射转换规则中获取当前算
                 子的辅助映射函数, 并据此获得目标算子及其特殊参数值. 综上所述, 自顶向下的抽象语法树改写算法如算法                               1 所示.

                 算法  1. 基于抽象语法树的模型代码迁移算法.
                 Input: 源抽象语法树   T, 目标框架名称    TARGET_FRAMEWORK.

                 1. /* 初始化通用依赖信息和特定算子信息 */
                 2. init UDepInfo and SOpInfo;
                 3. /* 获取  T  的根节点 */
                 4. root ← getRoot(T);
                 5. VISIT(root);
                 6. Function VISIT(node)
                 7.   for value in ast.iter_fields(node) do
                 8.     /* 遍历节点    node 的子节点, 根据子节点      value 的分类进行对应的处理 */
                 9.     if value is list then
                 10.       /* 新建临时列表来存储          value 列表中经过递归改写后的元素 */
                 11.       new_values = []
                 12.       for child_value in value do
                 13.          child_value = VISIT(child_value)
                 14.          new_values.add(child_value)
                 15.       end
   110   111   112   113   114   115   116   117   118   119   120