凹语言版本 yacc 简介 - 以表达式解析为例
yacc 是用于生成语法解析器的程序,是编译器爱好者的工具。凹语言的 yacc 从 goyacc 移植而来,目前可以初步支持输出 凹语言 版本解析器代码。本文以以表达式解析为例展示下用法。
完整的例子可以参考(这里使用的是expr
前缀):https://gitee.com/wa-lang/wa/blob/master/_examples/expr/expr.y。
如果对 yacc 不太了解可以先参考以下图书:
1. yacc 文件结构简介
yacc 文件一般以 *.y
格式命名,其格式如下:
// *.y 文件本身的注释%{
// 生成解析器代码的头部,一般是 import 等语句
%}// yacc 语法对应的词法类似、语法树节点等%%// BNF 语法定义%%// 生成解析器代码的尾部
简单来说,y 文件由两个 %%
行分隔为三个部分(类似文章的凤头、猪肚、豹尾):
凤头:对应生成的解析器的头部,其中
%{ ... %}
包含的部分为原样输出,其他部分是 yacc 语法定义的词法类型和语法树节点等猪肚:是 yacc 文件等核心,通过 BNF 语法定义了语法结构,这里主要是针对
LALR(1)
语法豹尾:如果是独立的程序,可以在这个部分引入词法解析器和 main 函数;如果是 package 则是可以省略的
2. 定义expr.y
文件 - 凤头部分
创建表达式语法文件如下:
// 版权 @2023 凹语言 作者。保留所有权利。%{
// 这是 凹语言 yacc 的例子, 用于对表达式进行解析, 为了简化词法部分暂时通过手工录入.
%}%union {num :int
}%type <num> expr expr1 expr2 expr3
%token '+' '-' '*' '/' '(' ')'
%token <num> NUM%%
其中%union
定义了词法和语法解析器对接的结构体类型。%type
语句定义了expr expr1 expr2 expr3
几种语法节点,都是对应<num>
类型值,而数字的值需要填充到%union
定义的num
属性部分。%token
语句定义的运算符和NUM
类型的数字。
3. 定义expr.y
文件 - 猪肚部分
猪肚部分对应表达式的语法结构:
%%top:expr { println($1) }expr:expr1| '+' expr { $$ = $2 }| '-' expr { $$ = -$2 }expr1:expr2| expr1 '+' expr2 { $$ = $1 + $3 }| expr1 '-' expr2 { $$ = $1 - $3 }expr2:expr3| expr2 '*' expr3 { $$ = $1 * $3 }| expr2 '/' expr3 { $$ = $1 / $3 }expr3:NUM| '(' expr ')' { $$ = $2 }%%
当遇到expr
语法规则是直接输出结果,expr1
表示加减法、expr2
表示乘除法、expr3
表示数字或小括弧。在每个最终后面的{}
中包含的是动作代码,它们根据不同的语法规则选择不同的计算方式得到结果,结果赋值给$$
(也就是对应%type <num> expr expr1 expr2 expr3
语句中的<num>
部分类型,也对应%union
定义的num
成员)。
4. 定义expr.y
文件 - 豹尾部分 - 01
有了凤头和猪肚部分,yacc就可以生成必要的解析器代码了。默认后生成以下格式的解析器函数yyParse
:
func yyParse(yylex: *yyLexer) => int {return yyNewParser().Parse(yylex)
}
而yyLexer
词法解析器则是用户需要自行实现的(词法解析实现相对简单),主要包含以下2个方法:
type yyLexer struct {}func yyLexer.Lex(yylval *yySymType) => int {// 返回 Token 类型, 并且将对应的值填充到 yylval 相应的属性中
}func yyLexer.Error(s string) {// 遇到错误
}
yyLexer.Lex
返回 Token 类型,并且将对应的值填充到 yylval
相应的属性中,遇到文件结尾时返回0
表示文件结束。方法参数对应的yySymType
类型由yacc工具生成,对应如下的代码:
type yySymType struct {yys :intnum :int
}
其中num
对应对应%union
定义的属性,也就是数字的值。
5. 定义expr.y
文件 - 豹尾部分 - 02
为了简化演示代码,我们先手工构造词法序列,然后通过yyLexer.Lex
返回。
// Lex 结束标志
const eof = 0type yyToken struct {Kind :intValue :int
}type yyLexer struct {tokens :[]yyTokenpos :int
}func yyLexer.Lex(yylval *yySymType) => int {if this.pos >= len(this.tokens) {return eof}tok := this.tokens[this.pos]this.pos++yylval.num = tok.Valuereturn tok.Kind
}func yyLexer.Error(s string) {println("ERROR:", s)
}
首先定义yyToken
,对应token的类型和值信息。然后yyLexer
定义全部的token列表和当前的pos信息。yyLexer.Lex
方法每次从this.tokens
列表对应的this.pos
位置返回一个token,如果是结束则返回eof
。
然后就可以构造main函数启动了:
func main {print("1+2*3 = ")yyParse(&yyLexer{tokens: []exprToken{{Kind: NUM, Value: 1},{Kind: '+'},{Kind: NUM, Value: 2},{Kind: '*'},{Kind: NUM, Value: 3},},})
}
6. 生成解析器代码
在生成解析器代码前再准备一个copyright.txt
文件,比如“保留所有权利”或者“自由使用”之类的。然后通过以下命令生成解析器代码:
$ wa yacc -l -p=yy -c="copyright.txt" -o="y.wa" expr.y
其中-l
表示生成的代码禁止映射到*.y
文件行列号(用生成代码的位置),-p=yy
表示生成的解析器函数和类型等用yy
前缀(这也是默认值),-c="copyright.txt"
为生成代码指定版权信息,-o="y.wa"
指定输出文件,最后的expr.y
对熟人的yacc规则文件。
生成代码成功之后可以执行:
$ wa y.wa
1+2*3 = 7
7. 下一步
目前的凹语言版 yacc 工具还是Go语言实现的,只是输出的解析器是凹语言代码。我们希望下一步可以将 yacc 工具本身移植到凹语言实现,最终可以通过 wasm 模块执行。
凹语言版本 yacc 简介 - 以表达式解析为例相关推荐
- 数学表达式解析器简介
2019独角兽企业重金招聘Python工程师标准>>> 在实际项目开发中如果需要解析数学公式,无须再运用解释器模式进行设计,可以直接使用一些第三方解析工具包,它们可以统称为数学表达式 ...
- C语言 科学计算器 后缀表达式 解析字符串 仿JS的eval函数
C语言 利用后缀表达式解析字符串 最近用98标准的C语言写了个解析字符串,类似于JavaScript中的eval函数,感觉挺实用(移植到了计算器上,可以画F(X,Y)==0这种图像了),特此分享一下, ...
- 【包】R语言rvest包简介
以下翻译自:rvest包github项目主页 R语言rvest包简介 rvest包可以帮助我们从网页上抓取信息,它通常与magrittr包配合使用,便于进行常见的网络抓取任务.revest包的开发主要 ...
- 京东“百亿补贴”提前20小时上线,电商价格战开打; iPhone 15 Pro玻璃面板泄露;凹语言 0.5.0发布|极客头条
「极客头条」-- 技术人员的新闻圈! CSDN 的读者朋友们早上好哇,「极客头条」来啦,快来看今天都有哪些值得我们技术人关注的重要新闻吧. 整理 | 梦依丹 出品 | CSDN(ID:CSDNnews ...
- python中set()函数的用法,python中set()函数简介及实例解析
python中set()函数简介及实例解析 set函数也是python内置函数的其中一个,属于比较基础的函数.其具体介绍和使用方法,下面进行介绍. set() 函数创建一个无序不重复元素集,可进行关系 ...
- 表达式解析器(MVEL)
Jeval 在运行时解析计算静态和动态表达式:支持数学,布尔,字符串,函数表达式:支持大部分的数学和布尔运算符:支持自定义函数:支持嵌套函数:支持解析:支持自定义变量解析器: 官网:http://je ...
- c++ _int64转字符串_C语言 仿JS的eval函数 解析字符串
C语言 利用后缀表达式解析字符串(符合c98标准,很容易移植到计算器上) 最近用98标准的C语言写了个解析字符串,类似于JavaScript中的eval函数,感觉挺实用(移植到了计算器上,可以画F(X ...
- c语言计算机编程例题详解,计算机C语言编写程序题及答案解析精选.doc
计算机C语言编写程序题及答案解析精选 2011年计算机二级C语言编写程序题及答案解析精选 [4.1]已知银行整存整取存款不同期限的月息利率分别为:0.315% 期限一年0.330% 期限二年月息利率 ...
- Crontab中文表达式解析
简介 最近工作中在使用调度框架,经常和定时表达式打交道,并且有查看表达式中文解释的需求,于是在网上搜集资料和自己进行一定的修改,写了一个Crontab表达式解析的工具类 详解 这个没啥好解释,看资料, ...
最新文章
- 【百度地图API】如何区分地址解析和智能搜索?
- PyTorch 《动手学深度学习》学习笔记(Dive-into-DL-Pytorch)
- express中get和post的区别
- 配置msf连接postgresql数据库
- 基于JAVA+SpringMVC+Mybatis+MYSQL的物流管理系统
- linux软件包管理rpm
- BZOJ 1067 降雨量(RMQ-ST+有毒的分类讨论)
- mysql 附近3公里的,mysql 查询附近N公里内数据
- 早教机器人刷固件_E-puck2机器人系列教程-固件修复升级
- 学习阮一峰老师-互联网协议笔记(IP/UDP/TCP/HTTP)
- rubyinstaller下载安装 redis集群
- android pc摄像头驱动,Android 驱动USB摄像头
- 利用canvas的rotate创建一个简易的风车动画
- c语言 ZZ转字符串,C语言 字符串中的转义字符与字符串的长度 zz
- Linux – cp: omitting directory 复制文件失败
- 如何成为一个高情商的员工(附全书思维导图)
- 蚂蚁金服 g6 用法
- APP测试面试题汇总
- 卸载已有navicat for mysql,安装破解版。
- Java中使用json时java.lang.NoClassDefFoundError: net/sf/ezmorph/Morpher问题解决