ANTLR(ANother Tool for Language Recognition)是一个功能强大的解析器生成器,用于读取,处理,执行或翻译结构化文本或二进制文件。它被广泛用于构建语言,工具和框架。ANTLR从语法上生成一个解析器,该解析器可以构建解析树,还可以生成一个侦听器接口(或访问者),从而可以轻松地对所关注短语的识别做出响应。
ANTLR (ANother Tool for Language Recognition) is a powerful parser generator for reading, processing, executing, or translating structured text or binary files. It’s widely used to build languages, tools, and frameworks. From a grammar, ANTLR generates a parser that can build parse trees and also generates a listener interface (or visitor) that makes it easy to respond to the recognition of phrases of interest.
Because we specify phrase structure with a set of rules, parse tree subtree roots correspond to grammar rule names. ANTLR has a ParseTreeWalker that knows how to walk these parse trees and trigger events in listener implementation objects that you can create. The ANTLR tool generates listener interfaces for you also, unless you turn that off with a commandline option. You can also have it generate visitors. For example from a Java.g4 grammar, ANTLR generates:
where there is an enter and exit method for each rule in the parser grammar. ANTLR also generates a base listener with the fall empty implementations of all listener interface methods, in this case called JavaBaseListener. You can build your listener by subclassing this base and overriding the methods of interest.
Listeners and visitors are great because they keep application-specific code out of grammars, making grammars easier to read and preventing them from getting entangled with a particular application.
from antlr4 import FileStream, CommonTokenStream, ParseTreeWalker from ast_java.JavaLexer import JavaLexer from ast_java.JavaParser import JavaParser from pprint import pformat
# Enter a parse tree produced by JavaParser#packageDeclaration. defenterPackageDeclaration(self, ctx: JavaParser.PackageDeclarationContext): self.ast_info['packageName'] = ctx.qualifiedName().getText()
# Enter a parse tree produced by JavaParser#importDeclaration. defenterImportDeclaration(self, ctx: JavaParser.ImportDeclarationContext): import_class = ctx.qualifiedName().getText() self.ast_info['imports'].append(import_class)
# Enter a parse tree produced by JavaParser#methodDeclaration. defenterMethodDeclaration(self, ctx: JavaParser.MethodDeclarationContext):
# Exit a parse tree produced by JavaParser#methodDeclaration. defexitMethodDeclaration(self, ctx: JavaParser.MethodDeclarationContext): c1 = ctx.getChild(0).getText() # ---> return type c2 = ctx.getChild(1).getText() # ---> method name params = self.parse_method_params_block(ctx.getChild(2))
# Enter a parse tree produced by JavaParser#methodCall. defenterMethodCall(self, ctx: JavaParser.MethodCallContext): line_number = str(ctx.start.line) column_number = str(ctx.start.column) self.call_methods.append(line_number + ' ' + column_number + ' ' + ctx.parentCtx.getText())
# Enter a parse tree produced by JavaParser#classDeclaration. defenterClassDeclaration(self, ctx: JavaParser.ClassDeclarationContext): child_count = int(ctx.getChildCount()) if child_count == 7: # class Foo extends Bar implements Hoge # c1 = ctx.getChild(0) # ---> class c2 = ctx.getChild(1).getText() # ---> class name # c3 = ctx.getChild(2) # ---> extends c4 = ctx.getChild(3).getChild(0).getText() # ---> extends class name # c5 = ctx.getChild(4) # ---> implements # c7 = ctx.getChild(6) # ---> method body self.ast_info['className'] = c2 self.ast_info['implements'] = self.parse_implements_block(ctx.getChild(5)) self.ast_info['extends'] = c4 elif child_count == 5: # class Foo extends Bar # or # class Foo implements Hoge # c1 = ctx.getChild(0) # ---> class c2 = ctx.getChild(1).getText() # ---> class name c3 = ctx.getChild(2).getText() # ---> extends or implements
# c5 = ctx.getChild(4) # ---> method body self.ast_info['className'] = c2 if c3 == 'implements': self.ast_info['implements'] = self.parse_implements_block(ctx.getChild(3)) elif c3 == 'extends': c4 = ctx.getChild(3).getChild(0).getText() # ---> extends class name or implements class name self.ast_info['extends'] = c4 elif child_count == 3: # class Foo # c1 = ctx.getChild(0) # ---> class c2 = ctx.getChild(1).getText() # ---> class name # c3 = ctx.getChild(2) # ---> method body self.ast_info['className'] = c2
# Enter a parse tree produced by JavaParser#fieldDeclaration. defenterFieldDeclaration(self, ctx: JavaParser.FieldDeclarationContext): field = { 'fieldType': ctx.getChild(0).getText(), 'fieldDefinition': ctx.getChild(1).getText() } self.ast_info['fields'].append(field)
defparse_implements_block(self, ctx): implements_child_count = int(ctx.getChildCount()) result = [] if implements_child_count == 1: impl_class = ctx.getChild(0).getText() result.append(impl_class) elif implements_child_count > 1: for i inrange(implements_child_count): if i % 2 == 0: impl_class = ctx.getChild(i).getText() result.append(impl_class) return result
defparse_method_params_block(self, ctx): params_exist_check = int(ctx.getChildCount()) result = [] # () ---> 2 # (Foo foo) ---> 3 # (Foo foo, Bar bar) ---> 3 # (Foo foo, Bar bar, int count) ---> 3 if params_exist_check == 3: params_child_count = int(ctx.getChild(1).getChildCount()) if params_child_count == 1: param_type = ctx.getChild(1).getChild(0).getChild(0).getText() param_name = ctx.getChild(1).getChild(0).getChild(1).getText() param_info = { 'paramType': param_type, 'paramName': param_name } result.append(param_info) elif params_child_count > 1: for i inrange(params_child_count): if i % 2 == 0: param_type = ctx.getChild(1).getChild(i).getChild(0).getText() param_name = ctx.getChild(1).getChild(i).getChild(1).getText() param_info = { 'paramType': param_type, 'paramName': param_name } result.append(param_info) return result