news 2026/8/23 11:25:11

一份文法,9种语言输出:syntax多语言插件生态实战指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
一份文法,9种语言输出:syntax多语言插件生态实战指南

一份文法,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模块内置于核心模板
Pythonexamples/calc.py.gcalcparser.pysrc/plugins/python/
PHPexamples/calc.php.gCalcParser.phpsrc/plugins/php/
Rubyexamples/calc.rb.gCalcParser.rbsrc/plugins/ruby/
C++examples/calc.cpp.gCalcParser.hsrc/plugins/cpp/
C#examples/calc.cs.gCalcParser.cssrc/plugins/csharp/
Rustexamples/calc.rs.glib.rssrc/plugins/rust/
Javaexamples/calc.java.gCalcParser.javasrc/plugins/java/
Juliaexamples/calc.jl.gSyntaxParser.jlsrc/plugins/julia/

各语言生成器还内置了对应的 AST 生成示例,例如 Rust 的examples/calc-ast.rs.g(递归 AST 结构)和 Java 的examples/calc-ast-java.bnf,方便你从"求值"平滑过渡到"构建语法树"。

插件架构:解析表计算与代码生成为何能解耦 🧩

syntax 的核心设计是分层:

  1. 语法解析层:把文法解析成统一的 AST(其 BNF 文法见examples/bnf.bnf),词法部分由src/grammar/lex-grammar.js等模块处理;
  2. 解析表计算层:LR 算法在src/lr/目录(如src/lr/canonical-collection.js计算规范 LR 项目集族),LL 算法在src/ll/目录,与目标语言完全无关;
  3. 代码生成层(插件):每个语言插件只做一件事——消费解析表,吐出目标语言代码

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.mdsrc/plugins/java/README.md

各语言插件使用要点速查 ⚡

Python / PHP / Ruby(动态语言组):用法高度一致,-o指定扩展名即可,PHP 与 Ruby 的类名跟随输出文件名;钩子函数(如on_parse_beginon_parse_end)可参考examples/module-include.py.gexamples/module-include.php.gexamples/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 解析器依赖oniglazy_static两个 crate,测试工程可直接参考src/__tests__/rust-calc/

Julia(科学计算组):生成的解析器依赖DataStructures.jl包;官方建议复杂文法优先使用 JSON-like 记法定义词法,以避免 JS → Julia 之间的转义序列问题(见examples/letter.jl.bnf)。

如何为 syntax 新增一门语言插件:5 步教程 🛠️

  1. 建目录:按src/plugins/example/的结构创建src/plugins/<your-language>/
  2. 移植模板:将 example 插件的三个模板翻译成目标语言,模板内注释详尽,基本可 1:1 对照;
  3. 实现生成器:移植lr/目录下的生成器,并实现 trait 文件中的语言专属代码生成;
  4. 注册构建:把新插件加入构建脚本的PLUGINS数组和bin/syntax_genericLRGENERATORS对象;
  5. 跑通测试:把examples/calc.example.g移植到目标语言并执行生成命令,验证2 + 2 * 2 === 6即可提交 PR。

常见问题 FAQ ❓

Q:解析模式选哪个?优先使用--mode lalr1,这是自动解析器的事实标准;LL(1) 目前只做语法校验。

Q:遇到 shift-reduce 冲突怎么办?用优先级与结合性声明解决,例如给+*声明%left;也可先用--validate选项查看冲突报告与修复建议(示例见examples/calculator-assoc-conflict.gexamples/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),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/23 11:23:46

数学建模实战:疫情物资配送的选址-路径优化模型与算法详解

1. 项目概述&#xff1a;从赛题到现实问题的映射看到“COVID-19疫情期间生活物资的科学管理问题”这个题目&#xff0c;很多参加过数学建模竞赛的朋友可能会心一笑&#xff0c;这确实是2022年研赛F题的经典再现。这道题之所以让人印象深刻&#xff0c;是因为它完美地将一个全球…

作者头像 李华
网站建设 2026/8/23 11:23:11

HACS 默认仓库完整指南:Home Assistant 社区扩展装什么、怎么装

HACS 默认仓库完整指南&#xff1a;Home Assistant 社区扩展装什么、怎么装 【免费下载链接】default The home of the default HACS repositories. 项目地址: https://gitcode.com/gh_mirrors/def/default HACS 是 Home Assistant 的“应用商店”&#xff0c;而这个默认…

作者头像 李华
网站建设 2026/8/23 11:22:58

离散优化实战指南:从0-1规划到VRP的建模与求解

1. 项目概述&#xff1a;从“离散”二字说起看到“离散优化”这个词&#xff0c;很多刚接触数学建模的同学可能会有点发怵&#xff0c;觉得它比连续优化更抽象、更复杂。其实恰恰相反&#xff0c;离散优化处理的问题&#xff0c;恰恰是我们日常生活中最常遇到的那一类&#xff…

作者头像 李华
网站建设 2026/8/23 11:22:20

46个现成Dify工作流:导入即可运行,省掉搭节点的功夫

46个现成Dify工作流&#xff1a;导入即可运行&#xff0c;省掉搭节点的功夫 【免费下载链接】Awesome-Dify-Workflow 分享一些好用的 Dify DSL 工作流程&#xff0c;自用、学习两相宜。 Sharing some Dify workflows. 项目地址: https://gitcode.com/GitHub_Trending/aw/Awes…

作者头像 李华
网站建设 2026/8/23 11:18:59

Pandas TA 入门教程:三分钟跑通 130+ 技术指标计算

Pandas TA 入门教程&#xff1a;三分钟跑通 130 技术指标计算 【免费下载链接】pandas-ta Technical Analysis Indicators - Pandas TA is an easy to use Python 3 Pandas Extension with 130 Indicators 项目地址: https://gitcode.com/gh_mirrors/pa/pandas-ta Panda…

作者头像 李华