如何用ANTLR4与Python提取多语言文件中的函数、类及文档注释
用ANTLR4 + Python实现跨语言函数/类及注释提取
完全可以实现,既然已经有主流编程语言的ANTLR4解析器和词法分析器,只需要基于这些语法文件,结合Python的ANTLR4库,通过语法树遍历提取目标内容,最终整理成你需要的格式。具体步骤如下:
核心思路
ANTLR4通过语法文件生成词法分析器和解析器,将源代码转换成抽象语法树(AST);我们通过自定义**监听器(Listener)或访问器(Visitor)**遍历AST,定位到类、函数的节点,同时关联提取对应的文档注释,最后按要求格式输出。
具体实现步骤
1. 按文件后缀匹配对应语法
不同后缀的文件对应不同编程语言,先建立后缀与ANTLR4语法组件的映射:
.js→ JavaScriptLexer/JavaScriptParser.java→ JavaLexer/JavaParser.rs→ RustLexer/RustParser
2. 编写自定义监听器/访问器
针对每种语言,编写对应的监听器,重写节点进入/退出的方法,完成以下操作:
- 定位类/结构体、函数/方法的语法节点(比如Java的
classDeclaration、Rust的fn_item) - 从原代码中截取节点对应的代码片段(通过Token的起止索引)
- 提取关联的文档注释:ANTLR会把注释放入隐藏通道(HIDDEN Channel),需要从目标节点的前置Token中筛选出注释内容,拼接到代码前
以JavaScript为例,监听器核心逻辑示例:
import antlr4 from JavaScriptLexer import JavaScriptLexer from JavaScriptParser import JavaScriptParser from JavaScriptListener import JavaScriptListener class JSCodeExtractor(JavaScriptListener): def __init__(self, raw_code): self.raw_code = raw_code self.output = [] self.current_class = None # 记录当前遍历的类 # 进入函数声明节点时触发 def enterFunctionDeclaration(self, ctx): # 获取函数代码的起止位置 start_idx = ctx.start.start end_idx = ctx.stop.stop # 提取函数上方关联的注释 comments = self._fetch_associated_comments(ctx.start) # 拼接注释与函数代码 full_func_code = comments + self.raw_code[start_idx:end_idx+1] if self.current_class: # 如果是类的方法,加入当前类的方法列表 self.current_class["methods"].append(f'"{full_func_code}"') else: # 独立函数直接加入输出列表 self.output.append(f'"{full_func_code}"') # 进入类声明节点时触发 def enterClassDeclaration(self, ctx): class_name = ctx.Identifier().getText() self.current_class = {"name": class_name, "methods": []} # 退出类声明节点时触发,将类整理成要求的格式 def exitClassDeclaration(self, ctx): class_entry = f'"class {self.current_class["name"]}": [{", ".join(self.current_class["methods"])}]' self.output.append(class_entry) self.current_class = None # 从隐藏通道提取目标节点的关联注释 def _fetch_associated_comments(self, start_token): comments = [] prev_token = start_token.previousToken() # 往前遍历隐藏通道的Token,收集注释 while prev_token and prev_token.channel == antlr4.Lexer.HIDDEN: if prev_token.type in [JavaScriptLexer.LINE_COMMENT, JavaScriptLexer.BLOCK_COMMENT]: comments.insert(0, prev_token.text) prev_token = prev_token.previousToken() return "\n".join(comments) + "\n" if comments else "" # 处理单个JS文件的函数 def process_js_file(file_path): with open(file_path, 'r', encoding='utf-8') as f: raw_code = f.read() input_stream = antlr4.InputStream(raw_code) lexer = JavaScriptLexer(input_stream) token_stream = antlr4.CommonTokenStream(lexer) parser = JavaScriptParser(token_stream) ast = parser.program() # 生成AST extractor = JSCodeExtractor(raw_code) walker = antlr4.ParseTreeWalker() walker.walk(extractor, ast) # 遍历AST return extractor.output
3. 多语言适配与格式整合
针对Java、Rust等语言,只需要替换对应的Lexer/Parser,调整监听的节点类型(比如Java的methodDeclaration、Rust的struct_item),并适配注释提取逻辑(比如Rust的///注释、Java的/** */文档注释)。
最后将所有文件的提取结果整合,加上外层的output: [和],用逗号分隔各个元素,即可得到你要求的格式。
注意事项
- 不同语言的语法细节差异:比如Rust的函数可能有不同的修饰符、Java的内部类嵌套,需要对应调整节点监听逻辑
- 注释关联的准确性:部分语言注释可能与代码间隔空行,需要处理Token的位置判断,确保注释属于目标函数/类
- 代码截取的准确性:注意Token的起止索引是否包含完整的代码块(比如函数的大括号)
内容的提问来源于stack exchange,提问作者PipEvangelist
相关产品推荐
相关产品推荐

