近期由于学校项目接触到了ANTLR4这一语法解析分析器。通过ANTLR4我们可以把各种语言文件细分拆解到每一句话,每一个组成子项。因此可以使用ANTLR4对程序的内容进行监控和排查。比如,当一个大型项目中堆栈出现bug时,可以通过这样的语法解析工具将出错的程序段追溯的其源头是哪一个文件修改所导致的,并且可以具体到某一函数、类。
使用ANTLR4首先需要安装到环境中,可以参考之前的安装文章https://blog.youkuaiyun.com/a12as3d7/article/details/118855872?spm=1001.2014.3001.5501
安装完成并生成出相应语言的分析器后,就可以开始对解析语言文件的实现啦。查看各种语言的g4语法生成文件中,我们可以看到,无论是哪种语言,都有Lexer和Parser以及ParserListener文件,Parser是解析器,Lexer是语法分析器,ParserListener是解析器监听器。(我这里使用的是.py的版本,可以在g4文件输出分析文件时自由更改成其他语言的)
#include <iostream>
using namespace std;
class Testclass{
int a;
public:
void Testmethod(double XingCan,int XingCan2){
int metval=1;
int val2=metval;
}
};
class TestclassB:public Testclass{
int b;
public:
void BFuction(string words){
cout<<"Thank You For Reading My Blog!"<<endl;
}
}
int main(){
cout<<"Hello World!"<<endl;
}
以一cpp文件为例,当我们要分析这个文件时,Parser对内容进行解析,它会分辨出哪些是类,哪些是参数,哪些是函数等,Lexer对语法进行分析,它分析哪些内容具有包含关系,哪一部分会跳转到哪里等。ParserListener内定义了许多接口,这些接口会在其名称对应的时刻被调用,比如,有一个接口叫做enterFunctionDefinition(self, ctx:CPP14Parser.FunctionDefinitionContext)那么这个接口将会在解析器进入到分析文件的一个函数定义时触发,这个接口的参数CPP14Parser.FunctionDefinitionContext是一个静态类,可以通过它获取到对应目标的一些信息(这里是函数,所以里面包含了比如函数类型,函数名,函数体内容等数据),我们通过重写定义这个接口,然后就能在其调用的时机做一些我们希望的事情。可以用getChild()函数获取对应位置的部分,比如在void Testmethod(double XingCan,int XingCan2){...}中,getChild(0)就指向了"void"这一部分,想要将这些部分转化为字符还需要加上.getText()函数。
def enterFunctionDefinition(self, ctx:CPP14Parser.FunctionDefinitionContext):
mName=ctx.getChild(1).getText()
methods_info={
'startLine': ctx.start.line,
'methodName': mName,
'masterObject': {},
}
print(ctx.getChild(0).getText(),ctx.getChild(1).getText(),ctx.getChild(2).getText())
self.check_masterObject(ctx,methods_info)
self.ast_info['methods'].append(methods_info)