Page 28 - 《软件学报》2024年第4期
P. 28

1606                                                       软件学报  2024 年第 35 卷第 4 期

             REcomp 是一种基于多模态对比学习的代码表征增强的编程语言预训练模型,  是基于 Transformer                         [23] 的,
         能够以多种编程语言预训练模型(如 CodeBERT             [29] , GraphCodeBERT [30] 和 UniXcoder [32] )为初始化标准.  下面将
         依次介绍多模态特征提取、REcomp 的编码器、多模态对比学习的预训练任务(包含数据增强)和下游任务.
         2.1   多模态特征提取

             如图 2(a)多模态特征提取模块所示,  需要提取源代码 4 个层次的特征,  分别是文本级的代码注释、语义级
         -结构级的融合特征序列和功能级的函数名.  下面将详细阐述需要提取源代码多个模态特征的原因以及获取
         语义级-结构级融合的方法(见算法 1).
             图 3 给出了一个带有注释和 AST 的 Python 代码示例.  注释“Return the sum of two numbers”高度概括了源
         代码的功能,  提供了关键的语义信息.  函数名称“sum”简明扼要的描述了源代码主体函数的功能,  也是表征源
         代码语义信息的另一重要而不可忽视的特征.  此外,  解析源代码后得到的 AST 包含丰富的句法相关的结构信
         息,例如:  非叶结点(控制结点)“return_statement”控制了其叶结点“return”和“result”整体行为;  非叶结点
         “parameters”指出来了“(x,y)”的类型是“参数”.  这里的“x”和“y”的结构是等价的.  这也是编程语言区别于自然
         语言的特殊的点:  编程语言中字符的语义和结构信息共同决定了它的表征,  存在同一字符表示不同语义和不
         同字符表示相同语义的现象.  因此,  不仅要关注语义级代码字符的信息,  也要关注隐藏的结构信息,  才能更加
         准确地表示源代码.

















                               图 3   一个 Python 的 AST 与代码字符的融合序列示例

             算法 1 描述了代码的语义级-结构级特征的融合的过程.  算法的输入是编程语言的类型 Language∈{php,
         java,python,ruby,go,javascript},  以及程序 Code  S=(s 1 ,s 2 ,…,s i ,…,s |S| ),  输出是所有语义级和结构级特征的集合
         TokensAST.  将 Code S 相应的 AST 表示为六元组τ=(N,N leaf ,N nonleaf ,c(⋅),t(⋅),r), N 是 AST 所有结点的集合, N leaf =(l 1 ,
         l 2 ,...,l |leaf| )⊂N 是叶子结点的集合, N nonleaf =(nol 1 ,nol 2 ,...,nol |nonleaf| )⊂N 是非叶子结点的集合, r∈N 是 AST 的根结点,
         c(⋅)是 AST 的 N leaf 与代码 tokenss i ∈S 对齐的映射函数(第 18−27 行), t(⋅)是 AST 的 N nonleaf 与其结点的 type 属性映
         射的函数(第 15 行).
             算法 1 的核心是_SemanticsStructureFusion 函数(第 7−17 行),  它将 t(N nonleaf   )与 c(N leaf )依次添加到集合
         TokensAST,  即 ca(见公式(1))中.  整个算法自顶向下的遍历 AST,  融合了代码的语义信息和结构信息.
             算法 1.  语义级-结构级特征融合(SemanticsStructureFusion).
             输入:  编程语言 Language,  源代码 Code;
             输出:  所有语义级和结构级特征的集合 TokensAST.
             1.   Function SemanticsStructureFusion(Langauge,Code)
             2.   TokensAST←∅
             3.        get the AST parser of Code depending on different Language
             4.        parse the Code to AST then get the root of the AST
   23   24   25   26   27   28   29   30   31   32   33