快速上手 gocc:10 分钟创建你的第一个 BNF 语法文件并生成解析器
2026/8/21 13:05:27 网站建设 项目流程

快速上手 gocc:10 分钟创建你的第一个 BNF 语法文件并生成解析器

【免费下载链接】goccParser / Scanner Generator项目地址: https://gitcode.com/gh_mirrors/go/gocc

gocc 是一款用 Go 语言编写的解析器生成器(Parser / Scanner Generator)。你只需写好一份 BNF 语法文件,gocc 就能自动生成词法分析器(lexer)和 LR(1) 语法分析器(parser),再也不用手写一堆繁琐的解析代码。本文将从零开始,带你用 10 分钟完成 gocc 安装、编写 BNF 语法文件、生成解析器并跑通测试,新手也能快速掌握这门"用语法换代码"的高效技能。

gocc 是什么?新手为什么要学解析器生成器

gocc 本质是一个"编译器生成器"(Compiler Compiler):你把语法规则写进 BNF 语法文件,它帮你把词法分析器和语法分析器全部生成出来。它生成的词法分析器是能识别正则语言的 DFA(支持 UTF-8 输入),语法分析器是识别 LR(1) 语言的 PDA,并且可以自动解决 shift/reduce 和 reduce/reduce 冲突。

很多知名 Go 项目都在用它处理复杂文本格式,例如 Graphviz DOT 语言解析、LLVM IR 解析等。学会 gocc,意味着任何"自定义语言、配置文件、DSL"你都能自己快速实现。

gocc 快速安装:一条命令编译出命令行工具

首先确保本机已安装 Go(建议 1.20+),然后把 gocc 源码克隆到本地并编译安装:

git clone https://gitcode.com/gh_mirrors/go/gocc cd gocc go install

安装完成后,把$(go env GOPATH)/bin加入 PATH 环境变量,执行gocc -h看到用法说明即代表安装成功。后续我们只需调用gocc xxx.bnf一个命令即可。

编写 BNF 语法文件:从一个计算器语法开始

BNF 语法文件是整个流程的核心输入。以项目自带的计算器为例,文件内容位于example/calc/calc.bnf,分为词法部分语法部分

/* Lexical part */ _digit : '0'-'9' ; int64 : '1'-'9' {_digit} ; !whitespace : ' ' | '\t' | '\n' | '\r' ; /* Syntax part */ Calc : Expr; Expr : Expr "+" Term << $0.(int64) + $2.(int64), nil >> | Term ; Term : Term "*" Factor << $0.(int64) * $2.(int64), nil >> | Factor ; Factor : "(" Expr ")" << $1, nil >> | int64 << util.IntValue($0.(*token.Token).Lit) >> ;

要点速记:

  • 词法部分用引号字面量、'a'-'z'字符区间和{}重复来定义记号,以!开头的规则会被忽略(如空白符);
  • 语法部分用:定义产生式,|表示多个候选分支;
  • << ... >>是语义动作(SDT 规则),$0$1代表对应位置的语法符号值,你可以在这里直接拼接出结果。

完整的 BNF 语法规范见spec/gocc2.ebnf,更多写法可参考example/bools/example.bnf

用 gocc 生成解析器:一条命令自动产出五个包

在存放calc.bnf的目录下执行:

gocc calc.bnf

gocc 会自动生成lexerparsertokenutilerrors等 Go 包,对应项目示例example/calc/下的目录结构。生成完毕直接go build ./...即可编译通过,无需任何手工改动。

如果你只需要语法分析、不需要词法分析(例如输入已经由别的工具切分好),可以加-no_lexer参数,参考example/nolexer/

在 Go 代码中调用 gocc 生成的解析器

生成之后,调用方式非常简单——先创建 lexer,再喂给 parser 解析。参考example/calc/calc_test.go的写法:

p := parser.NewParser() s := lexer.NewLexer([]byte("1 + 2 * 3")) sum, err := p.Parse(s)

p.Parse返回的sum就是你 BNF 中语义动作算出的结果(这里是7)。如果语法错误,会返回包含行列号的错误信息,错误处理包在errors/目录中。

运行测试:验证你的解析结果

在项目目录下执行:

go test -v ./...

gocc 项目自带大量可运行示例,每个示例都有测试文件。建议你逐个运行example/下的make regenerate(重新生成解析器)和go test(跑测试),亲眼看看 BNF 与生成代码之间的对应关系。

gocc 常用命令行参数速查表

参数作用
-a自动解决 LR(1) 冲突
-o <目录>指定输出目录
-p <包名>指定生成的 Go 包名
-no_lexer不生成词法分析器
-debug_parser开启解析器调试日志
-v输出详细过程(含 LR(1) 项集)
-u允许存在不可达的产生式
-zip压缩 action 表与 goto 表

参数定义可查看源码internal/config/config.go

进阶玩法:语义动作、AST 与更多内置示例

  • 构建 AST:复杂项目建议用语义动作构造抽象语法树,参考example/astx/example/bools/ast/ast.go
  • 错误恢复:想让解析器在出错后继续解析?参考example/errorrecovery/
  • 自定义上下文:通过$Context在解析时传递上下文数据(如符号表),参考example/usercontext/及其README.md
  • 冲突处理:gocc 生成的 LR(1) 冲突报告与自动解决,可对比example/sr/(shift/reduce)与example/rr/(reduce/reduce)两个示例;
  • 调试利器:加-v参数会输出LR1_sets.txtfirst.txtterminals.txt等中间文件,帮你看清分析表的每一步。

详细的原理与语法说明可阅读官方文档doc/gocc_user_guide.pdf(源码为doc/gocc_user_guide.tex)。

总结

gocc 让"写一个自己的解析器"从数周的苦工变成 10 分钟的小任务:写好 BNF 语法文件 → 执行gocc→ 调用生成的解析器,三步即可完成。无论你是想解析配置格式、做一个小型 DSL,还是学习编译原理,gocc 都是绝佳的起点。现在就打开example/calc/calc.bnf,动手改一个属于自己的语法吧!

【免费下载链接】goccParser / Scanner Generator项目地址: https://gitcode.com/gh_mirrors/go/gocc

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询