十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

ClickHouse ANTLR 实验语法解析器:从 .g4 语法文件生成 C++ 解析器源码的完整指南

ClickHouse ANTLR 实验语法解析器:从 .g4 语法文件生成 C++ 解析器源码的完整指南 数据库OLAP列式数据库大数据实时分析数据分析【免费下载链接】ClickHouseClickHouse® is a real-time analytics database management system项目地址https://gitcode.com/GitHub_Trending/cli/ClickHouse点击查看免费下载导读本指南围绕 ClickHouse 仓库中 utils/antlr/README.md 所描述的 ANTLR 实验性解析器展开ClickHouse 将一份独立维护的 ANTLR 语法ClickHouseLexer.g4与ClickHouseParser.g4保留在仓库中并提供了从语法文件生成 C 解析器源码的完整命令行流程。读完本文你将掌握这份语法文件的目录结构与文法设计、如何在本机安装antlr4并生成-package DB -DlanguageCpp的解析器代码、生成产物的取舍规则只提交 git 跟踪的文件以及这套实验性解析器与 ClickHouse 生产环境实际使用的手写解析器之间的本质区别。一、文档定位这是不受支持的实验性解析器仓库在 utils/antlr/README.md 的开篇就给出了非常明确且少见的定位声明This parser is unsupported. We keep it in this repository for your curiosity. But this is not the parser of ClickHouse.也就是说utils/antlr/目录下的 ANTLR 语法文件并不是 ClickHouse 运行时使用的 SQL 解析器它被保留在仓库中主要是为了供对 ClickHouse SQL 语法全貌感兴趣的开发者做参考与学习作为第三方工具链例如语法高亮、格式化、静态分析、IDE 插件等可复用的语法描述为未来的解析器重构提供实验土壤。这是一个关键的事实边界任何基于这份语法构建的解析器都不应被当作 ClickHouse 官方解析行为的权威实现。ClickHouse 生产环境使用的是 src/Parsers/ 下手写的词法分析器Lexer与递归下降解析器如 ParserQuery.cpp二者在错误信息、边界行为和性能特征上都存在差异详见本文第六节。二、语法文件全貌词法与文法各司其职utils/antlr/目录下共有三个文件文件行数作用ClickHouseLexer.g4339 行词法规则lexer grammar负责把 SQL 文本切成 Token 流ClickHouseParser.g4581 行语法规则parser grammar负责把 Token 流规约为语法树README.md15 行使用说明与不支持声明两个.g4文件通过tokenVocab建立依赖关系ClickHouseParser.g4 第 3-5 行的options { tokenVocab ClickHouseLexer; }声明它消费的词法 Token 全部来自ClickHouseLexer。因此修改词法规则后必须重新生成两份源码而只改语法规则时通常只需重新生成解析器源码。2.1 词法规则设计大小写不敏感的关键字ClickHouseLexer.g4 的关键字定义极具特色。例如第 7 行ACCESS: A C C E S S;这种逐字母展开的写法等价于正则A(C)?…其效果是让关键字在 ANTLR 中天然对大小写不敏感SELECT、select、SeLeCt均能匹配同时避免了在 lexer 规则中大量使用fragment定义大小写分支。第 18 行还展示了同义词合并的写法ASCENDING: A S C | A S C E N D I N G;即ASC与ASCENDING归并为同一个 Token 类型简化了 parser 侧的分支。文件中其余规则覆盖了字面量 Token如第 303-333 行的运算符与标点ARROW: -、CONCAT: ||、EQ_SINGLE: 、NOT_EQ: ! | 等数字与标识符片段如第 300-301 行的fragment HEX_DIGIT: [0-9a-fA-F]、fragment BINARY_DIGIT: [0-1]注释与空白第 337-338 行通过- skip直接丢弃/* ... */多行注释与-- ...单行注释保证它们不会进入 Token 流。2.2 语法规则设计语句分类与关键字上下文ClickHouseParser.g4 从第 9 行起定义顶层入口queryStmt它把输入分成查询query、插入insertStmt、删除deleteStmt、更新updateStmt四大类并在query规则第 16-34 行中进一步分发到alterStmt、attachStmt、createStmt、selectUnionStmt、showStmt、systemStmt、truncateStmt等 14 类语句覆盖了 ClickHouse 的主要 DDL/DML/DQL 形态。这份文法的另一设计亮点是关键字与标识符的上下文敏感处理第 551-579 行keyword规则显式列出所有可作为关键字使用的 Token并注明除NULL_SQL、INF、NAN_SQL外keywordForAlias是keyword的一个子集允许被当作别名alias使用alias: IDENTIFIER | keywordForAlias;与identifier: IDENTIFIER | interval | keyword;共同定义了哪些词可以作为标识符/别名出现从而在SELECT的列别名、表别名等场景中兼容保留字。值得注意的是第 4 行注释的提醒dont forget to add new keywords to the parser rule keyword!——即每在词法里新增关键字都必须同步把它补进 parser 的keyword规则否则语法规则将不完整。这是一个在 ANTLR 项目中极易遗漏的耦合点。2.3 ALTER 语句文法表达的典型示例以alterTableClause规则第 42-74 行为例可以看到 ANTLR 用带标签的备选分支# AlterTableClauseAddColumn、# AlterTableClauseModifyTTL等将 20 余种ALTER TABLE操作组织成一份可读性极佳的清单alterTableClause : ADD COLUMN (IF NOT EXISTS)? tableColumnDfnt (AFTER nestedIdentifier)? # AlterTableClauseAddColumn | DROP COLUMN (IF EXISTS)? nestedIdentifier # AlterTableClauseDropColumn | MODIFY ORDER BY columnExpr # AlterTableClauseModifyOrderBy | MODIFY ttlClause # AlterTableClauseModifyTTL | RENAME COLUMN (IF EXISTS)? nestedIdentifier TO nestedIdentifier # AlterTableClauseRename | MOVE partitionClause ( TO DISK stringLiteral | TO VOLUME stringLiteral | TO TABLE tableIdentifier ) # AlterTableClauseMovePartition ...每个分支末尾的#标签会直接映射为 ANTLR 生成的 visitor/listener 方法名如visitAlterTableClauseAddColumn这是理解生成代码命名规律的钥匙。三、从语法生成源码前置条件与完整命令README 给出了两条生成命令这是全文最核心的实操内容必须原样继承cd src/Parsers/New antlr4 -no-listener -visitor -package DB -DlanguageCpp ClickHouseLexer.g4 # 如果修改了词法部分 antlr4 -no-listener -visitor -package DB -DlanguageCpp ClickHouseParser.g43.1 前置条件安装 antlr4 工具README 明确要求install locally theantlr4binary。ANTLR 官方提供了多种安装途径如包管理器、下载antlr-4.x-complete.jar并配置antlr4启动脚本等本仓库不内置该工具。安装完成后建议用以下方式验证可用性antlr4 -version安装antlr4之后还需要在系统上具备可用的C 运行时头文件ANTLR 官方runtime/Cpp/runtime/src中的antlr4-runtime头文件与库生成的 C 代码在编译阶段依赖它们。3.2 逐参数解读参数含义说明-no-listener不生成 parse tree listener减小生成代码体积若不需要遍历语法树做事件回调可关闭-visitor生成 parse tree visitor启用访问者模式便于按#标签派发到visitXxx方法-package DB指定包名/命名空间前缀DB生成的 C 类会放入DB命名空间对应 ClickHouse 源码中广泛使用的DB::命名空间-DlanguageCpp指定目标语言为 C这是生成 C 源码的关键开关3.3 执行顺序与注意事项先词法后语法若同时修改了两份文件务必先执行ClickHouseLexer.g4的生成命令再执行ClickHouseParser.g4的生成命令。因为 parser 依赖 lexer 产出的ClickHouseLexer.h、ClickHouseLexer.cpp及 Token 定义文件。注释中的条件提示README 在第一条命令末尾特别注明if you have changes in a lexer part of grammar——即只有改动词法时才需要重新生成 lexer 源码仅修改 parser 规则时可以直接跳过第一条命令。生成位置README 中的命令以cd src/Parsers/New为前提。需要说明的是在当前仓库快照中并未包含src/Parsers/New目录该目录应是生成物存放地属于构建/生成流程产物而非源码树的一部分因此执行命令前需自行创建该目录或将其替换为你的实际生成目录。这一点与Commit only git-tracked generated files见下节的流程描述相互印证。四、生成产物的取舍规则README 的最后一句是关键的工程实践约束Commit only git-tracked generated files - not all of the generated content is required.它传达了两层含义并非所有生成物都需要入库ANTLR 针对 C 目标会输出多个文件包括*.interp、*.tokens、词法/语法器头文件与实现文件等。其中*.interp与*.tokens通常属于过程产物不应提交真正需要的是可参与编译的.cpp/.h源码。以 git 跟踪状态为准最稳妥的做法是执行生成后运行git status只git add那些原本就处于 git 跟踪状态或按项目约定应跟踪的文件避免把生成器产生的临时文件一并提交进仓库。一个可复用的检查命令是cd src/Parsers/New git status --short # 观察新增/修改的生成文件 git add 需要提交的.cpp/.h # 只提交编译所需的源文件五、生成的源码如何被使用参考方向虽然当前仓库快照未包含src/Parsers/New生成目录但从 ANTLR 生成代码的一般形态可以推断生成的 C 产物会包含ClickHouseLexer.h / .cpp继承antlr4::Lexer的词法分析器类成员函数逐一对应.g4中的 lexer 规则ClickHouseParser.h / .cpp继承antlr4::Parser的语法分析器类每个 parser 规则对应一个xxx()方法ClickHouseParserBaseVisitor.h等因-visitor而生成的 visitor 基类方法名来自#标签如visitAlterTableClauseAddColumn。典型的使用链路是antlr4::ANTLRInputStream装载 SQL 文本 →ClickHouseLexer切分 Token →CommonTokenStream缓冲 →ClickHouseParser以queryStmt()为入口解析 → 通过生成的 visitor 遍历ParseTree提取语义信息。这条链路与 src/Parsers/Lexer.cpp 所代表的生产解析链路是平行的两套实现。六、与生产解析器的关系手写 Lexer 与 ANTLR 的对比README 强调这份 ANTLR 语法不是 ClickHouse 的解析器而 ClickHouse 生产解析器在 src/Parsers/ 下其核心证据包括src/Parsers/Lexer.cpp 实现了手写的词法分析器Lexer通过nextToken()逐字符扫描产出基于TokenType枚举的 Token 流。第 566-575 行的getTokenName通过APPLY_FOR_TOKENS(M)宏将枚举映射为字符串第 578-599 行提供了非常详尽的错误描述如Multiline comment is not closed、Max query size exceeded (can be increased with the max_query_size setting)生产词法分析器还支持 UTF-8 空白跳过第 551-552 行兼容从 MS Word 等工具复制粘贴进 SQL 的 Unicode 空白、反引号/引号/十六进制二进制字面量等 ANTLR 实验语法未覆盖的边界生产解析器提供了面向外部调用的 C API 封装src/Parsers/clickhouse_lexer.h 声明了clickhouse_lexer_create、clickhouse_lexer_next_token、clickhouse_lexer_token_is_significant等函数其实现位于 Lexer.cpp 第 605-644 行的#else分支对应LEXER_STANDALONE_BUILD未定义时的场景可用于 WASM 等无法直接链接 C 对象的平台。两者对比要点维度生产解析器src/Parsers/实验 ANTLR 解析器utils/antlr/实现方式手写 Lexer 递归下降 ParserANTLR 4 文法 工具生成支持状态官方支持、随版本演进明确标注 unsupported仅供好奇与参考错误处理精细化错误枚举与可读消息依赖 ANTLR 默认错误策略更新方式手工维护源码修改 .g4 后重新生成使用场景服务端 SQL 解析执行学习参考、第三方工具链七、给实验者与工具链开发者的建议不要把行为契约押在实验语法上由于官方明确unsupported基于 ClickHouseLexer.g4 / ClickHouseParser.g4 构建的工具应自行补充充分的测试可参照 src/Parsers/tests/ 中生产解析器的 gtest 测试思路并对 ClickHouse 版本升级保持警惕。善用 ANTLR 的工程特性-visitor#标签的组合让文法与代码解耦keywordForAlias/identifier规则展示了如何在上下文敏感的位置复用关键字这是撰写 SQL 类 ANTLR 文法时值得复用的设计模式。遵守生成物纪律严格执行 README 的只提交 git 跟踪的生成文件规则把*.interp、*.tokens等过程产物排除在提交之外避免污染仓库。总而言之utils/antlr/是 ClickHouse 面向外部生态提供的一份语法说明书它以完整的 lexer/parser 文法精确描述了 ClickHouse SQL 的词汇与句法结构并给出了可复现的生成命令。它不参与 ClickHouse 自身的执行路径却是理解 ClickHouse SQL 语法全景、开发语法相关工具的绝佳起点——这正是它在仓库中存在的价值所在。赞分享数据库OLAP列式数据库大数据实时分析数据分析【免费下载链接】ClickHouseClickHouse® is a real-time analytics database management system项目地址https://gitcode.com/GitHub_Trending/cli/ClickHouse点击查看免费下载相关推荐LiteRT-LM 中使用 ANTLR4 生成 Tool Call 解析器从 .g4 语法文件到 Rust 代码的完整实战指南LiteRT LM 中使用 ANTLR4 生成 Tool Call 解析器从 .g4 语法文件到 Rust 代码的完整实战指南 本篇指南以 docs/api/人工智能大模型推理引擎本地部署多模态工具调用模型评测Vim 语法文件生成器解析从 Vim C 源码自动生成 vim.vimVim 语法文件生成器解析从 Vim C 源码自动生成 vim.vim runtime/syntax/vim.vim 是 Vim 自身用于高亮 Vim scr开发工具代码编辑器用ANTLR v4语法解析器解放代码生成元编程实战指南用ANTLR v4语法解析器解放代码生成元编程实战指南 你是否还在为重复编写语法解析代码而烦恼是否希望通过自动化工具提升开发效率本文将带你深入了解如何利用编程语言编译器开发工具上一篇突破交互瓶颈UI-TARS中Mind2Web评测指标的技术解析下一篇CANN通信算子开发API创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表