- 编程语言
- 编译器
- 开发工具
【免费下载链接】grammars-v4
Grammars written for ANTLR v4; expectation that the grammars are free of actions.
本指南以 grammars-v4 仓库中的 muparser 模块为核心,介绍如何用 ANTLR4 为 muParser 数学表达式语言构建无 action 的纯文法解析器。通过阅读本文,你将掌握该文法的完整语法结构(含运算符优先级、内置函数与常量)、示例表达式的写法,以及如何用mvn clean test一键验证文法在 10 种目标语言下的正确性。
MuParser 模块概览
MuParser 是一个轻量级的 C++ 数学表达式解析库,其表达式语言支持四则运算、幂运算、比较与逻辑运算、条件表达式、内置函数以及用户变量与常量。grammars-v4 仓库中的 muparser 模块 用 ANTLR4 文法完整描述了这套表达式语言,且遵循仓库"文法中不含 action"(free of actions)的约定——文法文件只描述语法结构,不嵌入任何目标语言代码,因此可以被干净地翻译为 Java、C#、C++、Go、Python 等多种语言。
模块目录结构如下:
muparser/ ├── MuParser.g4 # 合并式文法(parser + lexer) ├── examples/ │ └── example1.txt # 示例表达式集合 ├── desc.xml # 目标语言声明 ├── pom.xml # Maven 构建与测试配置 └── README.md # 模块说明按照仓库约定,每个文法模块都必须通过 desc.xml 声明支持的目标语言。本模块声明支持CSharp、Cpp、Dart、Go、Java、JavaScript、PHP、Python3、TypeScript、Antlr4ng共 10 种目标,具体见 muparser/desc.xml。
文法的顶层结构:从表达式序列到原子
MuParser.g4 是一个合并式(combined)文法,即词法规则与语法规则写在同一个文件中。它没有 import 任何子文法,全部规则自包含。
文法的入口规则prog非常简单——它接受一个或多个表达式直到文件结束:
prog : expr+ EOF # progExpr ;语法规则expr是整个文法的核心,它以递归下降的方式定义了 muParser 表达式的全部运算层级;atom则定义了表达式的最基本构成单元。这两条规则共同支撑起从"原始表达式"到"可求值单元"的完整层级。
运算符优先级与结合性
expr规则通过多分支 + 标签(label)的方式精确复刻了 muParser 的运算符优先级,优先级从高到低依次为:
| 优先级 | 分支 | 标签 | 说明 |
|---|---|---|---|
| 最高 | expr POW expr | powExpr | 幂运算^,右结合(<assoc = right>) |
SUB expr | unaryMinusExpr | 一元负号-x | |
expr op = (MUL \| DIV) expr | mulDivExpr | 乘除*/ | |
expr op = (ADD \| SUB) expr | addSubExpr | 加减+- | |
expr op = (LTEQ \| GTEQ \| LT \| GT) expr | relationalExpr | 关系比较<=>=<> | |
expr op = (EQ \| NEQ) expr | equalityExpr | 相等比较==!= | |
expr AND expr | andExpr | 逻辑与&& | |
expr OR expr | orExpr | 逻辑或\|\| | |
expr QUESTION expr COLON expr | iteExpr | 三目条件? : | |
op = FUNCTION OPAR expr CPAR | functionExpr | 单参数函数调用 | |
op = FUNCTIONMULTI OPAR expr (',' expr)* CPAR | functionMultiExpr | 多参数函数调用 | |
atom | atomExpr | 原子表达式 | |
| 最低 | ID op = (ASSIGN \| ASSIGNADD \| ASSIGNSUB \| ASSIGNMUL \| ASSIGNDIV) expr | assignExpr | 赋值与复合赋值 |
几个值得注意的设计点:
- 幂运算右结合:
<assoc = right>使2^3^2解析为2^(3^2),与数学惯例一致;而其余二元运算(乘除、加减、比较、逻辑)都保持 ANTLR 默认的左结合。 - 一元负号显式成规则:
SUB expr是优先级第二高的分支,保证了-2^2被解析为-(2^2)而非(-2)^2。 - 复合赋值支持:除
=外,文法还支持+=、-=、*=、/=,对应词法规则ASSIGNADD、ASSIGNSUB、ASSIGNMUL、ASSIGNDIV,这与 muParser 的变量赋值语法保持一致。 NOT词法规则已定义但未使用:词法层定义了NOT: '!'(见 MuParser.g4),但语法规则expr中目前没有引用它。从源码结构看,这可能是为将来扩展逻辑非运算预留的记号,当前版本的文法并不接受!x形式的表达式。
每个分支都带有语义标签(如# powExpr、# iteExpr),这意味着生成的监听器(Listener)与访问器(Visitor)接口中会为每个运算符层级生成独立的enterXxx/exitXxx或visitXxx回调方法,便于在后续遍历 AST 时按运算类别分别处理。
原子表达式 atom
atom定义了表达式中不可再分的"叶子":
atom : OPAR expr CPAR # parExpr | (INT | FLOAT) # numberAtom | (TRUE | FALSE) # booleanAtom | (E | PI) # predefinedConstantAtom | ID # idAtom ;- 括号分组
( expr )可覆盖任何优先级; - 数字字面量:
INT匹配[0-9]+,FLOAT匹配[0-9]+ '.' [0-9]*或'.' [0-9]+(因此3.、.5都是合法的浮点数写法); - 布尔字面量:
true/false; - 预定义常量:
_e(自然常数 e)与_pi(圆周率 π)——注意其标识符以下划线开头,这是 muParser 预定义常量的书写习惯,文法通过专门的词法规则E、PI将其与普通变量ID区分开来; - 变量:
ID匹配[a-zA-Z_] [a-zA-Z_0-9]*,即 C 风格标识符,muParser 表达式中的用户变量均由此规则承载。
空白字符(空格、制表符、换行)通过SPACE: [ \t\r\n] -> skip直接跳过,不影响解析结果。
词法规则:内置函数与运算符记号
文法将 muParser 的全部内置函数拆成两个词法规则,这与 muParser 的函数分类一一对应:
单参数函数FUNCTION(21 个):
FUNCTION : 'sin' | 'cos' | 'tan' | 'asin' | 'acos' | 'atan' | 'sinh' | 'cosh' | 'tanh' | 'asinh' | 'acosh' | 'atanh' | 'log2' | 'log10' | 'log' | 'ln' | 'exp' | 'sqrt' | 'sign' | 'rint' | 'abs' ;覆盖了三角函数族(sin/cos/tan 及其反函数与双曲函数)、对数族(log2/log10/log/ln)、指数与开方(exp/sqrt)、取整与符号(sign/rint/abs)。
多参数函数FUNCTIONMULTI(4 个):
FUNCTIONMULTI : 'min' | 'max' | 'sum' | 'avg' ;min、max、sum、avg接受两个及以上参数,由语法规则functionMultiExpr中的(',' expr)*保证参数列表的任意长度。
其余运算符记号均为单字符或双字符字面量词法规则:POW('^')、MUL('*')、DIV('/')、ADD('+')、SUB('-')、LTEQ('<=')、GTEQ('>=')、LT('<')、GT('>')、EQ('==')、NEQ('!=')、AND('&&')、OR('||')、QUESTION('?')、COLON(':')、OPAR('(')、CPAR(')')以及五种赋值运算符ASSIGN('=')、ASSIGNADD('+=')、ASSIGNSUB('-=')、ASSIGNMUL('*=')、ASSIGNDIV('/=')。
由于 ANTLR 的词法规则按定义顺序进行最长匹配优先、相同时先定义者优先,FUNCTION与FUNCTIONMULTI排在ID之前,因此sin、max等关键字不会落入ID规则,函数调用与变量引用在词法层面即被正确区分。
示例表达式实战解析
仓库自带的 examples/example1.txt 包含 5 行示例表达式,覆盖了文法的主要特性:
max(sign(20),rint(3.73),abs(-9),sqrt(16)) (5>3?true:false)?log(5)+sin(0.9+3)^4+log2(6)-asinh(0.2):(2-1) sum(sin(0.1*_pi),cos(0.2),tan(0.2),asin(0.2),acos(0.2),atan(0.2)) min(sinh(0.2), cosh(0.2), tanh(0.2), asinh(0.2), acosh(1.2), atanh(0.2)) sin(_pi/6)逐行解读其覆盖的语法点:
- 第 1 行
max(sign(20),rint(3.73),abs(-9),sqrt(16)):多参数函数max嵌套调用四个单参数函数,其中abs(-9)演示了一元负号SUB expr作为函数实参的用法。 - 第 2 行
(5>3?true:false)?log(5)+sin(0.9+3)^4+log2(6)-asinh(0.2):(2-1):这是最复杂的一行——外层是iteExpr三目表达式,条件分支(5>3?true:false)本身又是一个嵌套三目;真值分支则综合了加法、POW幂运算(sin(0.9+3)^4,注意在 muParser 语义中^是幂而非按位异或)以及log、log2、asinh三种单参数函数。 - 第 3 行
sum(sin(0.1*_pi),...):sum多参数求和,实参中用到预定义常量_pi与乘法优先级。 - 第 4 行
min(sinh(0.2), cosh(0.2), ...):双曲函数族 +min多参数函数,演示了函数实参间的空格分隔(SPACE规则会安全跳过)。 - 第 5 行
sin(_pi/6):常量与除法组合,对应sin(π/6)=0.5的经典用例。
这些示例同时充当了回归测试用例:任何对文法的修改都必须保证这 5 行表达式仍能被prog规则完整接受。
用 Maven 一键测试文法
README 中给出的测试方式非常简单:在 bash 提示符下执行
mvn clean test即可用仓库根目录下的 pom.xml 作为父 POM 驱动本模块的完整构建与测试流程。其内部机制由 muparser/pom.xml 中的两个插件协作完成:
1. antlr4-maven-plugin(文法生成)
<plugin> <groupId>org.antlr</groupId> <artifactId>antlr4-maven-plugin</artifactId> <version>${antlr.version}</version> <configuration> <sourceDirectory>${basedir}</sourceDirectory> <includes> <include>MuParser.g4</include> </includes> <visitor>true</visitor> <listener>true</listener> </configuration> </plugin>该插件从MuParser.g4生成目标语言的解析器代码。根 POM 将 ANTLR 版本锁定为4.13.2(见 pom.xml)。<visitor>true</visitor>与<listener>true</listener>确保同时生成 Visitor 与 Listener 接口,方便上层应用按需选择遍历方式。
2. antlr4test-maven-plugin(示例回归测试)
<plugin> <groupId>com.khubla.antlr</groupId> <artifactId>antlr4test-maven-plugin</artifactId> <version>${antlr4test-maven-plugin.version}</version> <configuration> <verbose>false</verbose> <showTree>false</showTree> <entryPoint>prog</entryPoint> <grammarName>MuParser</grammarName> <packageName></packageName> <exampleFiles>examples/</exampleFiles> </configuration> </plugin>该插件以prog为入口规则(entryPoint),加载MuParser文法(grammarName),逐条解析 examples/ 目录下的所有示例文件;任何一条示例解析失败都会导致mvn clean test失败。插件版本由根 POM 的antlr4test-maven-plugin.version属性统一管理(1.22),且根 POM 注释明确说明其必须与 ANTLR 运行时的版本配套使用(见 pom.xml)。
值得注意的是,ANTLR 生成的目标语言代码由 Maven 的packaging=jar与父 POM 的多语言 profile 决定,配合 desc.xml 声明的 10 种目标,测试会验证文法在全部目标语言下都能正确生成与解析。
文法的适用前提与局限
- 无 action 纯文法:本模块完全遵循 grammars-v4 仓库"grammars are free of actions"的约定,文法不包含任何语义动作,语义处理(如求值、类型检查)需由使用方在生成的 Listener/Visitor 中自行实现。
- 无词法模式:文法不使用 ANTLR 的 Lexer Mode 特性,全部记号由单一默认模式匹配,结构简单、易于移植。
- 逻辑非暂未接入:
NOT: '!'记号已定义但未在语法规则中引用,当前版本不接受!x形式的逻辑非表达式。 - 变量与赋值语法:变量以 C 风格标识符书写,预定义常量固定为
_e与_pi;复合赋值+=等已获支持,与 muParser 的变量机制对应。
对于需要在自己项目中嵌入数学表达式解析能力的开发者,可以直接复用 MuParser.g4 生成目标语言解析器,并借助 example1.txt 中的表达式作为验收用例,快速验证解析结果是否符合 muParser 的语义预期。
- 编程语言
- 编译器
- 开发工具
【免费下载链接】grammars-v4
Grammars written for ANTLR v4; expectation that the grammars are free of actions.
相关推荐
muparser:高性能数学表达式解析库的终极指南
数学表达式解析库是现代软件开发中的重要工具,而muparser作为一款快速数学解析库,凭借其卓越的性能和易用性在C/C++开发领域广受好评。无论你是编程新手还是
tchMaterial-parser 完整指南:国家中小学智慧教育平台电子教材一键下载
tchMaterial parser 完整指南:国家中小学智慧教育平台电子教材一键下载 tchMaterial parser 是一款面向国家中小学智慧教育平台的
网页爬虫教育AI Powered Knowledge Graph Generator实战案例:工业革命文本如何转化为交互式知识图谱?
AI Powered Knowledge Graph Generator实战案例:工业革命文本如何转化为交互式知识图谱? AI Powered Knowledg
人工智能知识图谱数据可视化NLP
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考