一种基于双AST序列的代码补全方法及系统与流程

文档序号:17317634发布日期:2019-04-05 21:21阅读:622来源:国知局
一种基于双AST序列的代码补全方法及系统与流程
本发明涉及计算机软件工程
技术领域
,尤其是涉及一种基于双ast序列的代码补全方法及系统。
背景技术
:一个程序往往具有不同层次的结构,每个层次的结构对应着相应的程序分析过程,因而可以从不同的分析过程中获取不同抽象程度的程序信息。很多程序需要编译才能运行,如c、c++、c#、java等,而编译中的各种技术也常用于程序分析任务中;编译大致流程如图1所示。典型的,由词法分析(lexicalanalysis)、语法分析(syntaxanalysis)和语义分析(semanticanalysis),可以得到程序的词法信息和语法、语义信息,不确切的说,也可以将其理解为程序的“字面”信息和“结构”信息。显然,两者对于理解分析一个程序的功能都是十分重要的。现在有很多研究利用深度学习模型来进行程序分析,直观的想法是利用循环神经网络(recurrentneuralnetwork,rnn)对程序源代码(或者源程序的词序列,即token序列)建立语言模型。而这样的做法仅仅运用了程序最底层的信息——词法信息——来分析程序。然而,和自然语言不同,程序的结构信息包含了更本质的信息,直接利用程序的源代码/词序列进行建模,不能很好地反映程序本身的信息。换言之,仅利用词法信息对程序进行分析不够完善,没有充分利用程序源代码各方面的信息。再者,不同的任务对不同的程序信息敏感程度不同,某些程序分析任务即便只利用更抽象的程序信息也更加有效,而如程序分类任务就对程序结构更敏感,这是因为程序结构反映了程序的功能。如把程序中的自定义标识符i替换成iii,程序的结构是完全不改变的,即程序的功能不改变。绝大多数的程序员在进行软件开发的过程中会使用框架或库api来复用代码。但程序员几乎不可能记住所有的api,因为现有的api数量已经很庞大。因此,代码自动补全机制已经成为现代集成开发环境(integrateddevelopmentenvironment,ide)中的不可或缺的组成部分。据统计,代码补全是开发者最常使用的十个指令之一。代码补全机制在程序员输入代码时会尝试补全程序的剩余部分。智能的代码补全可以通过消除编程时的输入错误和推荐合适的api来加快软件开发过程。目前,把代码转换为ast(abstractsyntaxtree,抽象语法树),然后再把抽象语法树转换为一个token(标识符)序列并使用得到的ast序列数据训练lstm是一种代码生成的方法。然而,根据数据结构的基础理论,只使用一个单一的序列如只使用“前序序列”是难以描述清楚原始的ast树结构的。也就是说,当把一个ast转换为一个序列的时候,损失掉了很多树结构的信息(也就是说,仅仅依赖一个序列,无法转换回原始的ast)。要完整的保存一棵语法树的全部信息,必须同时至少使用两个序列(如,同时使用“前序序列”和“中序序列”才能完整地保存一棵树的信息。技术实现要素:为解决以上问题,本发明将待学习的程序代码的抽象语法树(ast)同时转换为两个序列(如“前序序列”和“中序序列”),并同时利用这两个序列的信息训练一个lstm模型。具体的,本发明提供了一种基于双ast序列的代码补全方法,包括:源代码处理步骤,使用抽象语法树解析源代码;序列生成步骤,将上述抽象语法树同时转换为两个不同序列;模型训练步骤,将所述两个不同序列输入lstm模型,训练语言模型;预测补全步骤,根据训练过的语言模型补全代码。优选的,在源代码处理步骤中,所述源代码被解析为不同形式,以获得代码的类、方法列表、代码标识符。优选的,所述序列生成步骤包括:通过前序遍历和中序遍历得到前序序列和中序序列,拼接前序序列和中序序列,当作后续lstm网络的输入。优选的,所述序列生成步骤进一步包括:通过中序遍历和后序遍历得到中序序列和后序序列,拼接中序序列和后序序列,当作后续lstm网络的输入。优选的,所述lstm模型为串联的lstm模型,所述lstm模型位于rnn模型的隐藏层。优选的,在预测补全步骤中,将部分代码片段输入已经训练过的语言模型,从而根据上下文输出推荐的代码元素。根据本发明的另一个方面,还提供了一种基于双ast序列的代码补全系统,包括顺序连接的如下模块:源代码处理模块,使用抽象语法树解析源代码;序列生成模块,将上述抽象语法树同时转换为两个不同序列;模型训练模块,将所述两个不同序列输入lstm模型,训练语言模型;预测补全模块,用于根据训练过的语言模型补全代码。优选的,所述源代码处理模块将所述源代码解析为不同形式,以获得代码的类、方法列表、代码标识符。优选的,所述序列生成模块通过前序遍历和中序遍历得到前序序列和中序序列,拼接前序序列和中序序列,当作后续lstm网络的输入。优选的,序列生成模块进一步通过中序遍历和后序遍历得到中序序列和后序序列,拼接中序序列和后序序列,当作后续lstm网络的输入。本发明的方法训练出的lstm具有更高的准确率。本发明的技术方案具有简单、快速的特点,能够较好地提高代码推荐的准确率和推荐效率。附图说明通过阅读下文优选实施方式的详细描述,各种其他的优点和益处对于本领域普通技术人员将变得清楚明了。附图仅用于示出优选实施方式的目的,而并不认为是对本发明的限制。而且在整个附图中,用相同的参考符号表示相同的部件。在附图中:图1为现有程序的编译流程图。图2为本发明基于双ast序列的代码补全方法流程图。图3为本发明基于双ast序列的代码补全系统结构图。图4为本发明“前序+中序”拼接输入序列的实验训练结果示意图。图5为本发明“中序+后序”拼接输入序列的实验训练结果示意图。图6为四种不同的lstm输入序列的实验训练结果示意图。具体实施方式下面将参照附图更详细地描述本发明的示例性实施方式。虽然附图中显示了本发明的示例性实施方式,然而应当理解,可以以各种形式实现本发明而不应被这里阐述的实施方式所限制。相反,提供这些实施方式是为了能够更透彻地理解本发明,并且能够将本发明的范围完整的传达给本领域的技术人员。本发明将ast(abstractsyntaxtree,抽象语法树)进行序列化,并对ast序列化结果进行建模,这样就可以用lstm序列模型(长短期记忆网络,循环神经网络的一种)对程序的结构信息进行分析,进而完成程序分类任务。换言之,本发明在利用lstm序列模型进行程序分类任务的基础上进行了改进,将原始语言模型的词法级别输入(token序列)替换成了ast序列化结果,主要利用程序的结构信息进行分析,并取得了理想的结果。rnn(循环神经网络)是一类常用的人工神经网络,适合用于处理时序输入序列,输出可以设定为不同长度的序列(甚至为1);早期rnn不能处理长期依赖问题,即rnn会“遗忘”信息。lstm(长短期记忆网络)是rnn一种变体,解决了长期依赖问题,具备一定的记忆能力,适合处理预测时间序列中间隔和延迟较长的事件。但不论是哪种类型的rnn,输入都必须是序列,如果要利用lstm分析程序的结构,就必须考虑序列化体现程序信息的结构——这里本发明使用ast。程序的结构常为树状结构,而lstm为线性结构的序列模型。根据数据结构的知识:1、多叉树和二叉树一一对应。2、二叉树和中序遍历序列、前序/后序遍历序列一一对应;或者说,中序遍历序列和前序/后序遍历序列唯一确定一棵二叉树。从而,有源代码和ast转二叉树的前序/后序遍历序列、中序遍历序列的拼接序列一一对应的结论。所以本发明提出两种序列化方式并进行了实验:第一种:ast转二叉树,通过前序遍历和中序遍历得到前序序列和中序序列,拼接前序序列和中序序列,当作网络的输入;第二种:ast转二叉树,通过中序遍历和后序遍历得到中序序列和后序序列,拼接中序序列和后序序列,当作网络的输入。图2为本发明基于双ast序列的代码补全方法流程图。包括如下步骤:s1、源代码处理步骤,使用抽象语法树来解析源代码。在这个步骤中,所述源代码被解析为不同形式,以获得代码的类、方法列表、代码标识符等。抽象语法树(abstractsyntaxtree或者缩写为ast),或者语法树(syntaxtree),是源代码的抽象语法结构的树状表现形式,这里特指编程语言的源代码。和抽象语法树相对的是具体语法树(concretesyntaxtree),通常称作分析树(parsetree)。一般的,在源代码的翻译和编译过程中,语法分析器创建出分析树。一旦ast被创建出来,在后续的处理过程中,比如语义分析阶段,会添加一些信息。随后,抽象语法树转为二叉树。s2、序列生成步骤,将上述抽象语法树(ast)同时转换为两个不同序列。具体的,本发明采用两种转换方式,如下:第一种:通过前序遍历和中序遍历得到前序序列和中序序列,拼接前序序列和中序序列,当作后续lstm网络的输入;第二种:通过中序遍历和后序遍历得到中序序列和后序序列,拼接中序序列和后序序列,当作后续lstm网络的输入。s3、模型训练步骤,将所述两个不同序列输入lstm模型,训练语言模型。步骤s2解析后得到的两个序列将被用于基于长短时记忆(longshorttermmemory,lstm)的循环神经网络语言模型。所述lstm模型为串联的lstm模型,所述lstm模型位于rnn模型的隐藏层。s4、预测补全步骤,根据训练过的语言模型补全代码。在这个步骤中,将部分代码片段输入已经训练过的语言模型,从而根据上下文输出推荐的代码元素。如图3所示,根据本发明的另一个方面,还提供了一种基于双ast序列的代码补全系统100,包括顺序连接的如下模块:源代码处理模块110,使用抽象语法树解析源代码;优选的,所述源代码处理模块将所述源代码解析为不同形式,以获得代码的类、方法列表、代码标识符。序列生成模块120,将上述抽象语法树(ast)同时转换为两个不同序列。模型训练模块130,将所述两个不同序列输入lstm模型,训练语言模型;预测补全模块140,用于根据训练过的语言模型补全代码。在图2所述的具体实施方式中,本发明用到的数据集是poj(北京大学程序在线评测系统)的104类c/c++语言程序源代码,每一类对应于该系统的一道题,包含了500份该题的学生提交的完整的符合要求源代码,已经由1-104标出了各类文件的类别。预处理部分首先通过pycparser工具得到c/c++语言的ast,再通过统一方式将ast转换成二叉树,通过前序/中序/后序遍历得到前序/中序/后序序列(遍历结果是ast中各类结点node的序列),通过拼接(concatenate)序列得到输入序列:前序序列+中序序列,或中序序列+后序序列。如上文所述,无论是哪种拼接输入序列,都与源程序一一对应。网络部分首先将输入序列过一个嵌入层,每一个node转为一个one-hot向量(one-hot长度为词表大小),而这样的每个one-hot向量将作为每一个时间步的真实输入;当输入序列的最后一个node的one-hot输入后,得到一个预测的输出one-hot向量,该结果再过一个softmax层(图中未画出),取值最大的一位(长度为程序类别数,即104)的下标加一作为输入序列的预测类别。训练时,label向量化为one-hot向量(长度104),仅对应类别的一位为1;采用的损失函数为交叉熵。图2中xi表示当前时间步的输入,即ast中节点的嵌入的one-hot,hi表示当前时间步的隐藏层状态,y表示当前的输出——由于是程序分类任务,本发明只需要在读入最后一个输入时的时间步输出相应的预测程序类别即可,实际上y还需要再过一个softmax层取argmax来确定相应的类别。实验及结果为了展示模型效果,本发明还做了两组对照实验。其一是原始版本的实验,输入序列是程序的词法分析结果,即直接将源代码的token序列/词序列当作输入;其二是采用非一一对应的遍历序列组合方式当作输入,为简单起见本发明采用ast的深度优先遍历的node序列当作输入。实验设置(超参数):hiddensize=300batchsize=22learningrate=1e-4实验结果:两种拼接输入序列的实验训练过程如图4、5所示:“前序+中序”作为输入的实验最终收敛于90.08%的预测准确率(图4),“中序+后序”作为输入最终收敛于88.43%的准确率(图5)。加上另外两组对照实验的结果如图6所示:其中,ast2bt_iap指的是中序拼接后序序列作为输入,ast2bt_pai指的是前序拼接中序序列作为输入,ast_dfs指的是ast的深度优先遍历序列作为输入,src_code指源代码的tokens序列直接作为输入。下表1是四种方法模型输入得到的测试准确率对应表格。表1模型输入测试准确率ast转二叉树:前序+中序90.08%ast转二叉树:中序+后序88.43%ast的深度优先遍历序列88.60%sourcecode的token序列91.87%可以看到,即便是粗浅的利用程序的结构信息,在程序分类任务上也能达到很好的效果。其中,ast_dfs(深度优先遍历作序列为输入)方法明显收敛要慢一些,这是因为深度优先遍历序列和源程序并非一一对应,所以程序的区分度会因此而损失,模型的学习速度就自然慢一些,而且准确率也较别的方法低一些。而src_code的收敛速度要快一些,这一方面是由于输入序列要短一些(不到拼接序列作为输入方式的一半长度),模型能学习得更快;此外,由于lstm模型本身能提取程序的高层抽象信息,所以其实利用双ast序列拼接作为输入序列的模型,也尚未很好地利用程序的结构信息。关键在于,光是利用程序的不完整的结构信息(双ast拼接序列并不能完整地反映整个程序的结构,但为了用于lstm的序列化模型我们不得不考虑这类的序列化操作),在程序分类任务上都能取得很好的结果,和源代码作输入的实验相差不到2%,这已经证明了模型的能力。总体来说,本发明的模型良好地运用了程序的结构信息进行了建模。进一步的,该模型还可以用于其他任务,只要该模型能取得完整的ast结构,做类似的流程。另一方面,如果能采用更加结构化的网络,更完整地运用原始的ast或者相应的反映程序结构的数据结构作为输入,可能实验结果会更加理想。需要说明的是:在此提供的算法和显示不与任何特定计算机、虚拟装置或者其它设备固有相关。各种通用装置也可以与基于在此的示教一起使用。根据上面的描述,构造这类装置所要求的结构是显而易见的。此外,本发明也不针对任何特定编程语言。应当明白,可以利用各种编程语言实现在此描述的本发明的内容,并且上面对特定语言所做的描述是为了披露本发明的最佳实施方式。在此处所提供的说明书中,说明了大量具体细节。然而,能够理解,本发明的实施例可以在没有这些具体细节的情况下实践。在一些实例中,并未详细示出公知的方法、结构和技术,以便不模糊对本说明书的理解。类似地,应当理解,为了精简本公开并帮助理解各个发明方面中的一个或多个,在上面对本发明的示例性实施例的描述中,本发明的各个特征有时被一起分组到单个实施例、图、或者对其的描述中。然而,并不应将该公开的方法解释成反映如下意图:即所要求保护的本发明要求比在每个权利要求中所明确记载的特征更多的特征。更确切地说,如下面的权利要求书所反映的那样,发明方面在于少于前面公开的单个实施例的所有特征。因此,遵循具体实施方式的权利要求书由此明确地并入该具体实施方式,其中每个权利要求本身都作为本发明的单独实施例。本领域那些技术人员可以理解,可以对实施例中的设备中的模块进行自适应性地改变并且把它们设置在与该实施例不同的一个或多个设备中。可以把实施例中的模块或单元或组件组合成一个模块或单元或组件,以及此外可以把它们分成多个子模块或子单元或子组件。除了这样的特征和/或过程或者单元中的至少一些是相互排斥之外,可以采用任何组合对本说明书(包括伴随的权利要求、摘要和附图)中公开的所有特征以及如此公开的任何方法或者设备的所有过程或单元进行组合。除非另外明确陈述,本说明书(包括伴随的权利要求、摘要和附图)中公开的每个特征可以由提供相同、等同或相似目的的替代特征来代替。此外,本领域的技术人员能够理解,尽管在此所述的一些实施例包括其它实施例中所包括的某些特征而不是其它特征,但是不同实施例的特征的组合意味着处于本发明的范围之内并且形成不同的实施例。例如,在下面的权利要求书中,所要求保护的实施例的任意之一都可以以任意的组合方式来使用。本发明的各个部件实施例可以以硬件实现,或者以在一个或者多个处理器上运行的软件模块实现,或者以它们的组合实现。本领域的技术人员应当理解,可以在实践中使用微处理器或者数字信号处理器(dsp)来实现根据本发明实施例的虚拟机的创建装置中的一些或者全部部件的一些或者全部功能。本发明还可以实现为用于执行这里所描述的方法的一部分或者全部的设备或者装置程序(例如,计算机程序和计算机程序产品)。这样的实现本发明的程序可以存储在计算机可读介质上,或者可以具有一个或者多个信号的形式。这样的信号可以从因特网网站上下载得到,或者在载体信号上提供,或者以任何其他形式提供。应该注意的是上述实施例对本发明进行说明而不是对本发明进行限制,并且本领域技术人员在不脱离所附权利要求的范围的情况下可设计出替换实施例。在权利要求中,不应将位于括号之间的任何参考符号构造成对权利要求的限制。单词“包含”不排除存在未列在权利要求中的元件或步骤。位于元件之前的单词“一”或“一个”不排除存在多个这样的元件。本发明可以借助于包括有若干不同元件的硬件以及借助于适当编程的计算机来实现。在列举了若干装置的单元权利要求中,这些装置中的若干个可以是通过同一个硬件项来具体体现。单词第一、第二、以及第三等的使用不表示任何顺序。可将这些单词解释为名称。以上所述,仅为本发明较佳的具体实施方式,但本发明的保护范围并不局限于此,任何熟悉本
技术领域
的技术人员在本发明揭露的技术范围内,可轻易想到的变化或替换,都应涵盖在本发明的保护范围之内。因此,本发明的保护范围应以所述权利要求的保护范围为准。当前第1页12
当前第1页1 2 
网友询问留言 已有0条留言
  • 还没有人留言评论。精彩留言会获得点赞!
1