一份文法,9种语言输出:syntax多语言插件生态实战指南
【免费下载链接】syntaxSyntactic analysis toolkit, language-agnostic parser generator.项目地址: https://gitcode.com/gh_mirrors/sy/syntax
syntax是一款语言无关的语法分析工具包与解析器生成器(parser generator)。它内置 LR 和 LL 两套解析算法,只需编写一份文法,就能为 JavaScript、Python、PHP、Ruby、C++、C#、Rust、Java、Julia 共9 种语言生成可直接使用的解析器代码,是构建 DSL、配置语言、表达式引擎时的实用选择。
为什么需要多语言解析器生成器?🤔
手写词法分析器和语法解析器既费时又容易出错;而传统工具(如 Yacc/Bison)通常只输出 C 代码。syntax 的思路是:文法只写一遍,解析表计算一次,代码生成可以面向任意目标语言。
- 文法支持JSON-like 记法和Yacc/Bison 记法两种风格
- 解析模式覆盖 LR(0)、SLR(1)、LALR(1)、CLR(1) 与 LL(1)
- 内置词法生成器,支持宏、起始条件(词法器状态机)、大小写不敏感匹配
- 支持优先级与结合性声明(
%left、%right、%nonassoc),自动解决移位-归约冲突
安装与快速上手:3 条命令跑通 🚀
首先全局安装 CLI 工具(npm 包名为syntax-cli):
npm install -g syntax-cli以 Python 目标为例,直接生成一个计算器解析器:
syntax-cli -g examples/calc.py.g -m lalr1 -o calcparser.py在 Python 中即可调用:
>>> import calcparser >>> calcparser.parse('2 + 2 * 2') 6关键点:目标语言由输出文件扩展名决定(-o calcparser.py中的.py),文法内容本身无需为任何语言做任何改动。
9 种语言插件一览:同一文法,不同产出 🌍
项目内置 JavaScript(默认)+ 8 个语言插件,示例文法都放在 examples/ 目录下:
| 目标语言 | 示例文法 | 输出示例 | 插件源码位置 |
|---|---|---|---|
| JavaScript(默认) | examples/calc.example.g | .js模块 | 内置于核心模板 |
| Python | examples/calc.py.g | calcparser.py | src/plugins/python/ |
| PHP | examples/calc.php.g | CalcParser.php | src/plugins/php/ |
| Ruby | examples/calc.rb.g | CalcParser.rb | src/plugins/ruby/ |
| C++ | examples/calc.cpp.g | CalcParser.h | src/plugins/cpp/ |
| C# | examples/calc.cs.g | CalcParser.cs | src/plugins/csharp/ |
| Rust | examples/calc.rs.g | lib.rs | src/plugins/rust/ |
| Java | examples/calc.java.g | CalcParser.java | src/plugins/java/ |
| Julia | examples/calc.jl.g | SyntaxParser.jl | src/plugins/julia/ |
各语言生成器还内置了对应的 AST 生成示例,例如 Rust 的examples/calc-ast.rs.g(递归 AST 结构)和 Java 的examples/calc-ast-java.bnf,方便你从"求值"平滑过渡到"构建语法树"。
插件架构:解析表计算与代码生成为何能解耦 🧩
syntax 的核心设计是分层:
- 语法解析层:把文法解析成统一的 AST(其 BNF 文法见
examples/bnf.bnf),词法部分由src/grammar/lex-grammar.js等模块处理; - 解析表计算层:LR 算法在
src/lr/目录(如src/lr/canonical-collection.js计算规范 LR 项目集族),LL 算法在src/ll/目录,与目标语言完全无关; - 代码生成层(插件):每个语言插件只做一件事——消费解析表,吐出目标语言代码。
以src/plugins/example/这个"示例插件"为模板,一个完整插件包含:
plugins/ └── <your-language>/ ├── ll/ll-parser-generator-<your-language>.js ├── lr/lr-parser-generator-<your-language>.js ├── <your-language>-parser-generator-trait.js └── templates/ ├── ll.template.<ext> ├── lr.template.<ext> └── tokenizer.template.<ext>- templates:把模板代码移植到目标语言(LR 模板、LL 模板、词法器模板);
- trait(特征):写死目标语言特性的代码生成逻辑,如词法规则处理函数、解析表的目标语言序列化;
- generator:按 LR/LL 两种解析模式组装生成流程。
完整的插件开发指南见src/plugins/README.md,Rust 和 Java 插件还有各自的独立文档:src/plugins/rust/README.md、src/plugins/java/README.md。
各语言插件使用要点速查 ⚡
Python / PHP / Ruby(动态语言组):用法高度一致,-o指定扩展名即可,PHP 与 Ruby 的类名跟随输出文件名;钩子函数(如on_parse_begin、on_parse_end)可参考examples/module-include.py.g、examples/module-include.php.g、examples/module-include.rb.g。
C++ / C# / Java(编译型语言组):C++ 生成单头文件CalcParser.h直接 include 使用;C# 生成CalcParser.cs后实例化类调用parse();Java 默认生成到com/syntax包路径(如com/syntax/CalcParser.java),解析异常通过ParseException抛出。
Rust(强类型组):唯一需要额外书写的是闭包类型标注。因为 Rust 是静态类型语言,语义动作中参与运算的参数需显式声明类型,例如:
Expr + Expr { |$1: i32, $3: i32| -> i32; $$ = $1 + $3 }生成的 Rust 解析器依赖onig与lazy_static两个 crate,测试工程可直接参考src/__tests__/rust-calc/。
Julia(科学计算组):生成的解析器依赖DataStructures.jl包;官方建议复杂文法优先使用 JSON-like 记法定义词法,以避免 JS → Julia 之间的转义序列问题(见examples/letter.jl.bnf)。
如何为 syntax 新增一门语言插件:5 步教程 🛠️
- 建目录:按
src/plugins/example/的结构创建src/plugins/<your-language>/; - 移植模板:将 example 插件的三个模板翻译成目标语言,模板内注释详尽,基本可 1:1 对照;
- 实现生成器:移植
lr/目录下的生成器,并实现 trait 文件中的语言专属代码生成; - 注册构建:把新插件加入构建脚本的
PLUGINS数组和bin/syntax中_genericLR的GENERATORS对象; - 跑通测试:把
examples/calc.example.g移植到目标语言并执行生成命令,验证2 + 2 * 2 === 6即可提交 PR。
常见问题 FAQ ❓
Q:解析模式选哪个?优先使用--mode lalr1,这是自动解析器的事实标准;LL(1) 目前只做语法校验。
Q:遇到 shift-reduce 冲突怎么办?用优先级与结合性声明解决,例如给+、*声明%left;也可先用--validate选项查看冲突报告与修复建议(示例见examples/calculator-assoc-conflict.g与examples/calculator-assoc.g的对比)。
Q:词法部分可以只取 token 列表吗?可以,--lex指定词法文件加--tokenize即可输出带行列信息的 token 流,无需完整生成解析器。
小结:一份文法,多端复用 ✅
syntax 用"解析表计算 + 可插拔代码生成"的架构,把一份 BNF 文法放大为 9 种语言的生产级解析器。无论你要做表达式引擎、领域特定语言,还是跨语言项目的统一语法定义,都值得把它装进工具箱:安装syntax-cli,挑一个examples/下的文法改起来,十分钟就能跑通第一个多语言解析器。
【免费下载链接】syntaxSyntactic analysis toolkit, language-agnostic parser generator.项目地址: https://gitcode.com/gh_mirrors/sy/syntax
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考