Java使用ANTLR4解析IDL文件
文章目录
- 前言
- 解析IDL文件
- 准备两个IDL文件
- 准备一个IDL Grammar文件
- maven配置
- 生成Lexer Parser Listener Visitor代码
- 新建实体类
- IDL解析遍历器
- 单元测试
- 参考
前言
接着上篇:Java使用ANTLR4对Lua脚本语法校验,介绍了什么是ANTLR?/ 举了一个hello world示例 / ANTLR4 的工作流程。
解析IDL文件
准备两个IDL文件
V1.idl
为架构的第一版约定文件
#ifndef xxx
#define xxxmodule aaa {module bbb {module ccc {struct ddd {unsigned short xxx1;unsigned long long xxx2;octet xxx3;};}; // module ccc}; // module bbb}; // module aaa#endif
V2.idl
为架构的第二版约定文件
#ifndef xxx
#define xxxconst short aaa = 1;
module bbb {struct ccc {@default(0) uint8 xxx;};};module bbb {struct ddd {@default(255) uint8 xxx;};};
#endif
准备一个IDL Grammar文件
https://github.com/antlr/grammars-v4/tree/master/idl
maven配置
使用JDK8的注意:antlr4最高版本为4.9.3
,原因如下:
来源:https://github.com/antlr/antlr4/releases/tag/4.10
Increasing minimum java version
Going forward, we are using Java 11 for the source code and the compiled .class files for the ANTLR tool. The Java runtime target, however, and the associated runtime tests use Java 8 (bumping up from Java 7).
<dependencies><dependency><groupId>org.antlr</groupId><artifactId>antlr4-runtime</artifactId><version>${antlr.version}</version></dependency>
</dependencies><build><plugins><plugin><groupId>org.antlr</groupId><artifactId>antlr4-maven-plugin</artifactId><version>${antlr.version}</version><configuration><visitor>true</visitor><listener>true</listener></configuration><executions><execution><goals><goal>antlr4</goal></goals></execution></executions></plugin></plugins>
</build><properties><!-- https://mvnrepository.com/artifact/org.antlr/antlr4-runtime --><!-- Antlr4 4.9.3 is the last version compatible with Java 8 --><antlr.version>4.9.3</antlr.version>
</properties>
生成Lexer Parser Listener Visitor代码
mvn clean compile
新建实体类
不知道咋出来这个界面的,看Java使用ANTLR4对Lua脚本语法校验 > 第一个例子
由上图,不难看出对象间对应关系:Specification对应多个Definition(Module/TypeDeclaration),TypeDeclaration对应多个Member。
package com.baeldung.antlr.idl;import java.util.ArrayList;
import java.util.List;/*** 规范** @author duhongming* @see* @since 1.0.0*/
public class Specification {private List<Definition> definitions;public Specification() {definitions = new ArrayList<>();}public void setDefinitions(List<Definition> children) {definitions = children;}public List<Definition> getDefinitions() {return definitions;}public void addChild(Definition child) {definitions.add(child);}
}
package com.baeldung.antlr.idl;/*** 定义** @author duhongming* @see* @since 1.0.0*/
public interface Definition {enum Kind {MODULE,INTERFACE,EXCEPTION,TYPE_DECLARATION,CONST_DECLARATION,ANNOTATION}boolean isIsModule();boolean isIsInterface();boolean isIsException();boolean isIsTypeDeclaration();boolean isIsConstDeclaration();boolean isIsAnnotation();
}
package com.baeldung.antlr.idl;/*** 模块** @author duhongming* @see* @since 1.0.0*/
public class Module implements Definition {private String name;private Definition child;public String getName() {return name;}public void setName(String name) {this.name = name;}public Definition getChild() {return child;}public void setChild(Definition child) {this.child = child;}@Overridepublic boolean isIsModule() {return true;}@Overridepublic boolean isIsInterface() {return false;}@Overridepublic boolean isIsException() {return false;}@Overridepublic boolean isIsTypeDeclaration() {return false;}@Overridepublic boolean isIsConstDeclaration() {return false;}@Overridepublic boolean isIsAnnotation() {return false;}
}
package com.baeldung.antlr.idl;import java.util.List;/*** 类型声明** @author duhongming* @see* @since 1.0.0*/
public class TypeDeclaration implements Definition {private String name;private List<Member> members;public String getName() {return name;}public void setName(String name) {this.name = name;}public List<Member> getMembers() {return members;}public void setMembers(List<Member> members) {this.members = members;}@Overridepublic boolean isIsModule() {return false;}@Overridepublic boolean isIsException() {return false;}@Overridepublic boolean isIsInterface() {return false;}@Overridepublic boolean isIsTypeDeclaration() {return true;}@Overridepublic boolean isIsConstDeclaration() {return false;}@Overridepublic boolean isIsAnnotation() {return false;}
}
package com.baeldung.antlr.idl;/*** 成员变量或方法** @author duhongming* @see* @since 1.0.0*/
public class Member {private String name;private String typeCode;public Member(String typeCode, String name) {super();this.typeCode = typeCode;this.name = name;}public String getName() {return name;}public void setName(String m_name) {this.name = m_name;}public String getTypeCode() {return typeCode;}public void setTypeCode(String typeCode) {this.typeCode = typeCode;}
}
IDL解析遍历器
package com.baeldung.antlr.idl;import com.baeldung.antlr.IDLBaseVisitor;
import com.baeldung.antlr.IDLParser;
import org.antlr.v4.runtime.tree.ParseTree;import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Optional;public class IDLVisitor extends IDLBaseVisitor {@Overridepublic TypeDeclaration visitType_decl(IDLParser.Type_declContext ctx) {TypeDeclaration typeDeclaration = new TypeDeclaration();Optional<String> optional = Optional.ofNullable(ctx).map(IDLParser.Type_declContext::struct_type).map(IDLParser.Struct_typeContext::identifier).map(IDLParser.IdentifierContext::ID).map(ParseTree::getText);if (!optional.isPresent()) {return null;}typeDeclaration.setName(optional.get());List<IDLParser.MemberContext> members = ctx.struct_type().member_list().member();List<Member> memberList = new ArrayList<>();for (IDLParser.MemberContext member : members) {String type = member.type_spec().getText();String name = member.declarators().getText();Member m = new Member(type.replace("unsigned", ""), name);memberList.add(m);}typeDeclaration.setMembers(memberList);return typeDeclaration;}@Overridepublic Module visitModule(IDLParser.ModuleContext ctx) {Optional<String> optional = Optional.ofNullable(ctx).map(IDLParser.ModuleContext::identifier).map(IDLParser.IdentifierContext::ID).map(ParseTree::getText);if (!optional.isPresent()) {return null;}Module module = new Module();String moduleName = optional.get();module.setName(moduleName);List<IDLParser.DefinitionContext> definitions = ctx.definition();for (IDLParser.DefinitionContext definition : definitions) {Module subModule = visitModule(definition.module());if (Objects.nonNull(subModule)) {module.setChild(subModule);}TypeDeclaration typeDeclaration = visitType_decl(definition.type_decl());if (Objects.nonNull(typeDeclaration)) {module.setChild(typeDeclaration);}}return module;}@Overridepublic Specification visitSpecification(IDLParser.SpecificationContext ctx) {Specification specification = new Specification();if (ctx != null) {for (IDLParser.DefinitionContext definition : ctx.definition()) {Module module = visitModule(definition.module());if (Objects.nonNull(module)) {specification.addChild(module);}}}return specification;}
}
单元测试
package com.baeldung.antlr;import com.baeldung.antlr.idl.IDLVisitor;
import com.baeldung.antlr.idl.Specification;
import org.antlr.v4.runtime.CharStream;
import org.antlr.v4.runtime.CharStreams;
import org.antlr.v4.runtime.CommonTokenStream;
import org.antlr.v4.runtime.Lexer;
import org.antlr.v4.runtime.tree.ParseTree;
import org.junit.Test;import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Paths;public class IDLParserUnitTest {public static Specification parseIdl(InputStream inputStream) throws IOException {return parseIdl(CharStreams.fromStream(inputStream));}public static Specification parseIdl(CharStream charStream) {// 用 in 构造词法分析器 lexer,词法分析的作用是将字符聚集成单词或者符号Lexer lexer = new IDLLexer(charStream);// 用词法分析器 lexer 构造一个记号流 tokensCommonTokenStream tokens = new CommonTokenStream(lexer);// 再使用 tokens 构造语法分析器 parser,至此已经完成词法分析和语法分析的准备工作IDLParser parser = new IDLParser(tokens);ParseTree tree = parser.specification();IDLVisitor visitor = new IDLVisitor();return (Specification) visitor.visit(tree);}@Testpublic void testV1() throws IOException {InputStream inputStream = Files.newInputStream(Paths.get("src/test/resources/V1.idl"));Specification specification = parseIdl(inputStream);System.out.println(specification);}@Testpublic void testV2() throws IOException {InputStream inputStream = Files.newInputStream(Paths.get("src/test/resources/V2.idl"));Specification specification = parseIdl(inputStream);System.out.println(specification);}
}
最终目录情况及单元测试情况如下:
参考
https://github.com/eProsima/IDL-Parser