ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

基于 ANTLR v4 的 Apache Thrift IDL 文法解析:从 .thrift 源文件到语法树

基于 ANTLR v4 的 Apache Thrift IDL 文法解析:从 .thrift 源文件到语法树 编程语言编译器开发工具【免费下载链接】grammars-v4Grammars written for ANTLR v4; expectation that the grammars are free of actions.项目地址https://gitcode.com/gh_mirrors/gr/grammars-v4点击查看免费下载本指南以 grammars-v4 仓库中的 thrift/Thrift.g4 文法为核心系统讲解 Apache Thrift 接口定义语言IDL的完整语法结构从document顶层规则到 header、definition、字段、函数、容器类型、注解与常量再到词法层的注释与字面量处理。读者将掌握 Thrift IDL 文法的组成脉络、每个语法要素的书写规则以及如何借助仓库内置的 示例文件 与 Maven 测试配置 验证文法并驱动代码生成。背景为 Thrift IDL 编写 ANTLR v4 文法Apache Thrift 是一套跨语言的 RPC 与序列化框架服务接口与数据结构使用专门的接口描述语言IDL书写通常保存在扩展名为.thrift的源文件中。Thrift 官方编译器compiler/cpp内部使用 Bison 文法thrifty.yy解析这类文件而 grammars-v4 仓库则提供了这套 IDL 的 ANTLR v4 实现即 thrift/Thrift.g4。该文法是仓库中无内嵌动作free of actions风格文法的典型代表文法文件只描述语言的语法结构不包含任何目标语言Java、Go、Python 等的语义动作生成代码后由用户自行通过 Listener 或 Visitor 遍历语法树。从 thrift/desc.xml 可以看到仓库针对该文法验证了Go;Java;JavaScript;PHP;Python3五类目标而 thrift/pom.xml 则声明其模块名为thrift描述为 Apache Thrift IDL grammar。顶层结构document header* definition* EOF文法的入口规则非常简洁见 Thrift.g4document : header* definition* EOF ;即一个合法的.thrift文件由零个或多个header文件头声明和零个或多个definition类型与服务定义组成必须以文件结尾EOF结束。header与definition之间没有强制顺序完全符合 Thrift IDL先声明、后定义的书写习惯同时也允许空文件存在例如EmptyStruct {}所在的测试文件仍以空 header 通过解析。header仅包含三种声明见 Thrift.g4header : include_ | namespace_ | cpp_include ;Header 声明include、namespace 与 cpp_includeinclude引用其他 thrift 文件include_ : include LITERAL ;include后跟一个字符串字面量LITERAL即被引用文件的路径。仓库示例 thrift/examples/thrift_project/Include.thrift 展示了其用法include ThriftTest.thrift struct IncludeTest { 1: required ThriftTest.Bools bools }被引用文件中的类型通过文件名.类型名的方式引用ThriftTest.Bools。namespace目标语言命名空间namespace_ : namespace * (IDENTIFIER | LITERAL) | namespace IDENTIFIER (IDENTIFIER | LITERAL) type_annotations? | cpp_namespace IDENTIFIER | php_namespace IDENTIFIER ;namespace是 Thrift IDL 中控制代码生成的关键指令文法支持三种形态通配命名空间namespace * thrift.test表示对所有语言生效指定语言命名空间namespace java thrift.test、namespace go thrifttest等其中第二个 token 可以是普通标识符也可以是字符串字面量并允许跟随可选注解type_annotations?兼容旧写法cpp_namespace与php_namespace作为单独的 token 序列保留。官方 ThriftTest.thrift 文件一口气声明了c_glib、cpp、delphi、go、java、js、lua、netstd、perl、php、py、py.twisted、rb、st、xsd十余种命名空间并测试了namespace noexist ThriftTest对应不存在生成器的语言仅产生告警以及带注解的写法namespace xsd test (uri http://thrift.apache.org/ns/ThriftTest)覆盖了文法中type_annotations?分支。cpp_include向 C 生成代码插入头文件cpp_include : cpp_include LITERAL ;cpp_include用于在生成的 C 代码中额外包含指定头文件后跟字符串字面量。定义类型const、typedef、enum、senum、struct、union、exception、servicedefinition是文法的核心见 Thrift.g4共八种definition : const_rule | typedef_ | enum_rule | senum | struct_ | union_ | exception | service ;const常量定义const_rule : const field_type IDENTIFIER ( const_value)? list_separator? ;const声明一个具名常量语法为const 类型 名称 常量值其中 常量值可选即允许仅声明且末尾允许一个可选的list_separator逗号或分号见下文。典型示例const i32 INT32CONSTANT 9853 const mapstring,string MAPCONSTANT {hello:world, goodnight:moon} const string VERSION 19.33.0 const Numberz myNumberz Numberz.ONE前两例取自 DocTest.thriftVERSION取自 cassandra.thriftmyNumberz取自 ThriftTest.thrift可见常量值既可以是基本类型、map 字面量也可以引用已定义的枚举值Numberz.ONE。typedef类型别名typedef_ : typedef field_type IDENTIFIER type_annotations? ;typedef将已有类型重命名为新标识符并允许附加注解。仓库示例覆盖了多种形态typedef i64 UserId typedef mapstring,Bonk MapType typedef mapstring, mapstring, i16 T1 typedef listi32 ( cpp.template std::list ) int_linked_list typedef string ( unicode.encoding UTF-16 ) non_latin_string (foobar) typedef list double ( cpp.fixed_point 16 ) tiny_float_list前两个来自 ThriftTest.thriftT1来自 eleme_test.thrift后三个来自 AnnotationTest.thrift。注意文法允许typedef时同时给容器元素类型加注解list double (cpp.fixed_point 16) 并且type_annotations?既出现在typedef规则尾部的类型名之后也允许在field_type/container_type中内嵌。enum 与 senum枚举enum_rule : enum IDENTIFIER { enum_field* } type_annotations? ; enum_field : IDENTIFIER ( integer)? type_annotations? list_separator? ;enum定义枚举成员是标识符可带 整数显式赋值、可选注解与可选列表分隔符。经典示例ThriftTest.thriftenum Numberz { ONE 1, TWO, THREE, FIVE 5, SIX, EIGHT 8 }未赋值的成员TWO、THREE由编译器按顺序自动编号这符合 Thrift IDL 语义。enum整体还允许尾部注解如 AnnotationTest.thrift 中的enum weekdays {...} (foo.barbaz)与成员级注解SUNDAY ( weekend yes )。senum是 Thrift 的字符串枚举已废弃但文法仍支持senum : senum IDENTIFIER { (LITERAL list_separator?)* } type_annotations? ;即枚举成员是字符串字面量而非标识符AnnotationTest.thrift 给出了senum seasons { Spring, Summer, Fall, Winter } ( foo bar )的完整示例并在注释中特别说明 senum 成员不支持注解。struct、union、exception复合数据结构三者语法结构完全相同见 Thrift.g4只是关键字不同struct_ : struct IDENTIFIER { field* } type_annotations? ; union_ : union IDENTIFIER { field* } type_annotations? ; exception : exception IDENTIFIER { field* } type_annotations? ;struct普通结构体字段可有required/optional约束union联合体同一时刻只允许一个字段被赋值如 ThriftTest.thrift 中的SomeUnionexception异常类型用于 service 方法抛出如exception Xception { 1: i32 errorCode, 2: string message }三者都允许在}之后附加type_annotations?例如 ThriftTest.thrift 的struct Insanity {...} (python.immutable )。service服务接口service : service IDENTIFIER (extends IDENTIFIER)? { function_* } type_annotations? ;service定义 RPC 服务可继承另一个 serviceextends函数列表放在花括号内整体支持注解。文法中(extends IDENTIFIER)?是可选的继承分支配合function_*表示服务可以没有方法。字段与函数field、function_、oneway、throws字段fieldfield : field_id? field_req? field_type IDENTIFIER ( const_value)? type_annotations? list_separator? ; field_id : integer : ; field_req : required | optional ;字段由五个可选/必选部分组成字段编号field_id?形如1:的整数加冒号这是 Thrift 二进制协议的传输标识必须全局唯一约束field_req?required必填或optional可选也可缺省默认default语义类型field_type必选名称IDENTIFIER必选默认值( const_value)?、注解type_annotations?、列表分隔符list_separator?均可选。综合示例eleme_test.thrift 与 ThriftTest.thriftexception E1 { 1: required string name, 2: required string message } struct CrazyNesting { 1: string string_field, 2: optional setInsanity set_field, 3: required listmapseti32 (python.immutable ), mapi32,setlistmapInsanity,string(python.immutable ) (python.immutable ) list_field, 4: binary binary_field }CrazyNesting展示了注解内嵌在容器类型参数中的深层嵌套写法是文法对field_type递归能力的重要验证用例。函数function_与 oneway、throwsfunction_ : oneway? function_type IDENTIFIER ( field* ) throws_list? type_annotations? list_separator? ; oneway : (oneway | async) ; function_type : field_type | void ; throws_list : throws ( field* ) ;service 中的每个方法包含可选的oneway修饰同时接受oneway与async两种关键字表示异步单向调用不等待响应返回类型function_type普通field_type或void方法名IDENTIFIER参数列表( field* )参数同样是完整 field 语法可选的throws_list异常列表可选的注解与列表分隔符。例如 eleme_test.thrift 中的 serviceservice Test { Args test(1: listS1 list1, 2: T1 map1, 3: T2 map2) throws (1: E1 exception1); void void_call(); oneway void oneway_set_hehe(1: double hehe); binary bin(1: binary data); mapi32,string def_req_arg(1: i32 i 233, 2: string s hehe); }其中oneway void oneway_set_hehe(...)直接对应文法oneway?function_type分支参数默认值1: i32 i 233对应field规则中的( const_value)?。类型系统base_type、container_type 与 cpp_typefield_type归纳为三种见 Thrift.g4field_type : base_type // 基础类型 | IDENTIFIER // 引用已定义类型struct/typedef/enum 名称 | container_type // 容器类型 ;基础类型base_typebase_type : real_base_type type_annotations? ; real_base_type : TYPE_BOOL | TYPE_BYTE | TYPE_I16 | TYPE_I32 | TYPE_I64 | TYPE_DOUBLE | TYPE_STRING | TYPE_BINARY ;词法上对应 8 个关键字 tokenThrift.g4bool、byte、i16、i32、i64、double、string、binary。其中binary用于原始字节串。基础类型之后允许直接附加type_annotations?如string ( unicode.encoding UTF-16 )。容器类型container_typecontainer_type : (map_type | set_type | list_type) type_annotations? ; map_type : map cpp_type? field_type COMMA field_type ; set_type : set cpp_type? field_type ; list_type : list field_type cpp_type? ; cpp_type : cpp_type LITERAL ;三种容器在文法细节上略有差异mapkey, valuecpp_type?出现在之前键值类型之间用COMMA分隔setelemcpp_type?同样出现在尖括号前listelemcpp_type?反而出现在尖括号之后list field_type cpp_type?。cpp_type用于覆盖 C 生成代码中的容器实现例如map加cpp_type时可指定std::unordered_map等其值是字符串字面量。容器类型整体还可以再带注解例如 AnnotationTest.thrift 中的typedef listi32 ( cpp.template std::list ) int_linked_list。常量与字面量const_value、integer、DOUBLE、LITERALconst_valueconst_value : integer | DOUBLE | LITERAL | IDENTIFIER | const_list | const_map ;常量值可以是整数、浮点数、字符串字面量、标识符引用如Numberz.ONE、列表或 map。列表与 map 的定义如下const_list : [ (const_value list_separator?)* ] ; const_map_entry : const_value : const_value list_separator? ; const_map : { const_map_entry* } ;列表使用方括号[...]map 使用花括号{key:value, ...}元素之间允许可选的逗号或分号。DocTest.thrift中的MAPCONSTANT {hello:world, goodnight:moon}即对应const_map规则。数值与字符串词法整数分十进制与十六进制两种Thrift.g4integer : INTEGER | HEX_INTEGER ; INTEGER : ( | -)? DIGIT ; HEX_INTEGER : -? 0x HEX_DIGIT ; DOUBLE : ( | -)? (DIGIT (. DIGIT)? | . DIGIT) ((E | e) INTEGER)? ;INTEGER允许正负号HEX_INTEGER允许负数十六进制-0x...DOUBLE支持小数、1.与.5这类写法以及科学计数法E/e。字符串字面量Thrift.g4支持单引号与双引号两种定界符内部可包含转义序列LITERAL : (ESC_SEQ | ~[\\])* | \ ( ESC_SEQ | ~[\\])* \ ; fragment ESC_SEQ : \\ [rnt\\] ;转义字符集合为\r \n \t \ \ \\五种。仓库专门准备了 thrift/examples/literal.thrift 验证转义嵌套场景const string default_user \default_user\ ; const string default_name abc\s ;第一行是双引号字符串内转义单引号第二行是双引号字符串内直接包含单引号均属于合法输入。注解type_annotations 与 type_annotation注解是 Thrift IDL 扩展元数据的主要机制文法中几乎每个定义末尾都预留了type_annotations?type_annotations : ( type_annotation* ) ; type_annotation : IDENTIFIER ( annotation_value)? list_separator? ; annotation_value : integer | LITERAL ;注解是圆括号包裹的名称或名称值列表值只能是整数或字符串字面量条目之间可用逗号或分号。仓库中最全面的注解示例是 AnnotationTest.thrift它验证了结构体级注解( cpp.type DenseFoo, python.type DenseFoo, java.final , annotation.without.value, )——注意最后一个注解annotation.without.value没有值对应文法IDENTIFIER ( annotation_value)?的可选分支字段级注解1: i32 bar ( presence required )枚举级与枚举成员级注解容器元素级注解list double ( cpp.fixed_point 16 ) 。词法层标识符、空白与三种注释标识符IDENTIFIER : (LETTER | _) (LETTER | DIGIT | . | _)* ; fragment LETTER : A ..Z | a ..z ; fragment DIGIT : 0 ..9 ;标识符以字母或下划线开头后续可包含字母、数字、.与_。因此像ThriftTest.Bools、cpp.template作为注解名这样的带点写法在词法上就是一个完整的IDENTIFIER由文法层按语境解释。空白与注释WS : ( | \t | \r \n | \n) - channel(HIDDEN) ; SL_COMMENT : (// | #) (~\n)* (\r)? \n - channel(HIDDEN) ; ML_COMMENT : /* .*? */ - channel(HIDDEN) ;空白与注释全部进入HIDDEN通道语法规则无需关心它们的分布。注释风格非常贴近 Thrift 实际文件行注释// ...与# ...两种前缀#是 Unix 风格注释常见于 thrift 文件头部的#!/usr/local/bin/thriftshebang 行见 cassandra.thrift块注释/* ... */非贪婪匹配文档注释/** ... */在词法上属于块注释例如 DocTest.thrift 中大量/** ... */形式都被ML_COMMENT吸收而不会干扰解析。仓库内的实战验证资源要验证文法行为无需额外搭建环境仓库已提供完整的示例与自动化测试配置。示例文件thrift/examples 目录下有两类素材散落的独立文件ThriftTest.thrift418 行来自 Thrift 官方测试套件、cassandra.thrift764 行来自 Cassandra 的真实接口定义、eleme_test.thrift、eleme_test2.thrift 以及 literal.thriftthrift_project 子目录21 个针对特定语法点的测试文件包括AnnotationTest.thrift注解全集、DocTest.thrift文档注释、Include.thriftinclude 引用、EnumContainersTest.thrift、ManyTypedefs.thrift、OptionalRequiredTest.thrift、DenseLinkingTest.thrift、DebugProtoTest.thrift等几乎覆盖文法每一条规则。Maven 测试链路thrift/pom.xml 展示了从文法生成到回归测试的完整配置antlr4-maven-plugin将Thrift.g4作为唯一文法源includeThrift.g4/include并开启visitor与listener两种代码生成模式antlr4test-maven-plugin来自 com.khubla.antlr以document为入口规则、Thrift为文法名把examples/目录下所有.thrift文件作为测试输入逐一解析任何一条规则匹配失败都会导致测试失败。configuration entryPointdocument/entryPoint grammarNameThrift/grammarName exampleFilesexamples//exampleFiles /configuration这实际上把整套示例变成了文法的回归测试套件ThriftTest.thrift与cassandra.thrift这类大型真实文件能通过解析本身就是对文法覆盖度的强有力证明。此外 thrift/desc.xml 声明了Go;Java;JavaScript;PHP;Python3五个验证目标说明该文法在这几种生成目标下均通过了仓库的静态检查与构建验证。本地快速试用在已安装 ANTLR 工具链仓库根目录的 _scripts/antlr4-tools 提供了相应脚本的前提下可按如下流程本地体验# 1. 生成解析器Java 目标 antlr4 Thrift.g4 # 2. 编译生成的 Java 代码 javac Thrift*.java # 3. 用 grun 以 document 为入口解析某个 thrift 文件并打印语法树 grun Thrift document -tree examples/ThriftTest.thrift若使用仓库的 Maven 结构则直接执行mvn test根 pom.xml 的grammarsv4父工程已集成上述插件即可看到 antlr4test 插件逐文件解析examples/下全部样例的结果。注意本仓库只读以上命令仅用于本地查看与运行验证。词法注意点与文法局限从源码结构可以推断出该文法在覆盖范围上的一些特点使用时值得留意关键字采用词法 token 而非解析器字符串bool、i16、map、struct等都以词法规则TYPE_BOOL、TYPE_I16、map_type内的字面量等形式出现因此在 Thrift IDL 中它们不能作为普通标识符使用不支持i8关键字Thrift 新版本将byte与i8视为同义词并鼓励使用i8见 ThriftTest.thrift 的注释但本文法real_base_type只收录了TYPE_BYTEbyte未包含i8token。相应地示例中的1: i8 byte_thing字段会被词法层解析为普通IDENTIFIER而非基础类型这一点与 Thrift 官方编译器存在差异从文法当前实现看应视为一个覆盖缺口列表分隔符双轨制list_separator同时接受,与;这兼容了 Thrift 历史文件中的两种写法但也意味着解析时不会强制逗号const_rule允许省略默认值( const_value)?为可选这与 Thrift 官方语法要求常量必须初始化的语义略有出入属于文法相对宽松的体现。上述推断均以 Thrift.g4 现有规则为准若实际使用中遇到i8、async等扩展语法需在文法层自行确认。总结grammars-v4 的 thrift/Thrift.g4 是一份无内嵌动作的 ANTLR v4 文法完整覆盖了 Apache Thrift IDL 的 headerinclude/namespace/cpp_include、八类定义const、typedef、enum、senum、struct、union、exception、service、字段与函数含oneway、throws、基础与容器类型、注解、常量字面量以及三种注释风格。它与 Thrift 官方 Bison 文法thrifty.yy功能对位可用于构建独立的 IDL 解析、校验、代码生成或文档化工具链。仓库附带的 examples 目录含官方 ThriftTest 与 Cassandra 真实接口文件配合 pom.xml 的 antlr4test 配置为文法的正确性与回归稳定性提供了可复现的验证路径。许可本仓库中的该模块遵循 Apache License 2.0见 thrift/README.md 的 License 声明与各示例文件头部的 Apache 版权头使用时请遵守相应许可条款。赞分享编程语言编译器开发工具【免费下载链接】grammars-v4Grammars written for ANTLR v4; expectation that the grammars are free of actions.项目地址https://gitcode.com/gh_mirrors/gr/grammars-v4点击查看免费下载相关推荐Apache Thrift教程从IDL文件到跨语言服务开发Apache Thrift教程从IDL文件到跨语言服务开发 前言 Apache Thrift作为一种高效的跨语言服务开发框架其核心在于使用简单的接口定义语言后端RPC框架序列化代码生成Apache Thrift IDL 语法完全指南.thrift 接口描述语言规范与源码级解析Apache Thrift IDL 语法完全指南.thrift 接口描述语言规范与源码级解析 本指南以 Apache Thrift 官方 IDL 规范文档后端RPC框架序列化代码生成OpenWorker Coworker Google Docs Sheets 连接器设计规格解析按 URL 读取、分级授权的 Sheets 写入OpenWorker Coworker Google Docs Sheets 连接器设计规格解析按 URL 读取、分级授权的 Sheets 写入 本篇技术编程语言编译器开发工具上一篇adk-python 工具级自愈重试机制ReflectAndRetryToolPlugin 源码解析与实战指南下一篇wgpu-hal 深度解析wgpu 跨平台硬件抽象层的设计理念与后端架构创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表