一、简介

一门编程语言的编译器或者解释器通常功能分解为两步:
1、读取源码文件然后分析它的结构
2、处理这些结构,例如生成目标程序
lexer和yacc就是能完成第一步以便生成程序段的工具。而第一步的任务又能分为两个子任务:
1、分割源码文件内容为很多tokens(lexer)
2、分析出程序的分级结构(yacc)

二、lexer(词法分析工具)

lexer的源就是一个正则表达式表,其正则规则符合目标程序的代码片段。正则表达式表读取输入流,并将其根据正则规则转换为分割的字符串,然后输出为输出流,再翻译为一个程序。当 Lex 接收到文件或文本形式的输入时,它试图将文本与常规表达式进行匹配。 它一次读入一个输入字符,直到找到一个匹配的模式。 如果能够找到一个匹配的模式,Lex 就执行相关的动作(可能包括返回一个标记)。 另一方面,如果没有可以匹配的常规表达式,将会停止进一步的处理,Lex 将显示一个错误消息。
  Erlang的lexer工具就是leex模块。

三、yacc(语法分析工具)

是一个用来生成编译器的编译器(编译器代码生成器)。输入词法分析器的流,输出目标语言的代码。
Erlang的yacc工具就是yecc。

四、作用

有了这两个工具,我们可以自定义自己的编程语言,自定义这个语言的语法规则,最终生成相同功能的erlang代码。例如领域特定语言(DSL),我们可以定义个简单类似makefile的mymakefile语法规则,然后生成erlang代码来真正执行功能。

五、初识

这次研究leex和yecc也是在研究erlang protocolbuf时候,发现通用的做法就是书写一个协议字段描述文件,然后来生成erlang文件,例如一条TestRequest协议,定义其协议号10000,编解码文件为test_proto.erl,那么描述关系就是10000,TestRequest,test_proto,然后我们代码中传包解包时,都在协议头带上一个16位的协议号,通过协议号路由到真正的编解码文件也就是test_proto.erl。而看了很多实现,都是用riak官方某个rebar插件,来将这种关系描述文件生成erlang文件。

这个功能很简单,不过想是不是能用leex、yecc完成,最近正好也在研究,于是就产生了试一试的想法。

六、定义leex的.xrl文件

leex需要.xrl文件来描述自定义源文件的正则匹配规则,例如上面的协议描述关系,我们可以用 [0-9]+来匹配出开始的协议号,用 [,][a-zA-Z]([0-9a-zA-Z]*_?)*[,]匹配出协议名。

leex文件需要三个部分:Definitions Rules Erlangcode,Definitions表示正则匹配的变量,Rules表示匹配的规则和匹配后的输出,Erlangcode则是作为辅助的erlang函数。

我们可以按照第五步来编写我们的.xrl文件(假设叫test_lexer.xrl):

Definitions.TypeID = [0-9]+
MsgName = [,][a-zA-Z]([0-9a-zA-Z]*_?)*[,]
MsgModule = [a-zA-Z]([0-9a-zA-Z]*_?)*(\n)?
NoneLine = [\n]Rules.{TypeID} : {token, {msg_number, TokenLine, list_to_integer(TokenChars)}}.
{MsgName} : {token, {msg_name, TokenLine, drop_tokens(TokenChars)}}.
{MsgModule} : {token, {msg_module, TokenLine, drop_tokens(TokenChars)}}.
{NoneLine} : skip_token.Erlang code.drop_tokens(TokenChars) ->[Chars] = string:tokens(TokenChars, ","),[Chars1] = string:tokens(Chars, "\s"),[Chars2] = string:tokens(Chars1, "."),[Chars3] = string:tokens(Chars2, "\n"),Chars3.

上面的代码还是容易看懂的。

使用方法则是先编写一个协议描述的文件test_pb_desc.csv,随便输入个关系:

10000,fdsfds_232,fdsf_REWr
10001,fwefsd,terterr

然后通过leex编译出我们的词法分析器:

 leex:file("test_lexer.xrl").

不出意外,当前目录就会多一个test_lexer.erl,然后来分析我们的描述文件:

 {ok, Lines} = file:read_file("test_pb_desc.csv"),{_, Tokens, _} = test_lexer:string(binary_to_list(Lines)),

这里得到的Tokens就是我们的词法分析结果,可以输入到下一步的语法分析器里生成erlang代码。

七、定义yecc的.yrl文件

yecc需要.yrl文件来描述词法分析的分析方法以及分析的产出。

yecc文件需要四个部分:Nonterminals Terminals Rootsymbol Erlangcode,Nonterminals表示每次输入的流,Terminals表示输入流里面的tokens关键字,Rootsymbol表示输入的根(源),Erlangcode照例是辅助的erlang函数,
我们可以按照第六步的生成来编写yrl文件(例如叫test_parser.yrl):

Nonterminals
combines combine.Terminals msg_number msg_name msg_module.Rootsymbol combines.combines -> combine : '$1'.
combines -> combine combines : '$1' ++ '$2'.
combine -> msg_number msg_name msg_module :[{{save('$1'), save('$2')}, {save('$2'), save('$1')}, {save('$1'), save('$3')}}].Erlang code.save({msg_number, _, Value}) -> Value;
save({msg_name, _, Value}) -> list_to_atom(Value);
save({msg_module, _, Value}) -> list_to_atom(Value).

这里的combines语法有点像[H | Rest]语法,第一个combines -> combine : '$1'表示整个输入的词法分析流列表只剩一个元素的做法,combines -> combine combines : ... 表示匹配出单个元素combine 以及剩下的combines,而combine又寻找到单个规则combine -> msg_number msg_name ....,这样递归地处理输入源。

使用方法是:

yecc:file("test_parser.yrl").

然后编译生成的test_parser.erl文件,再调用test_parser:parse(Tokens).就生成erlang的目标代码了,这里我只生成了一个列表。

八、完整代码

我将完整代码用来编写了一个rebar3插件,用户定义协议描述文件xxx,然后里面的内容是协议描述关系:数字,协议名,协议编解码文件 这样的内容,插件就能输出成一个erlang文件。

完整代码参照我的git repo: rebar3_pb_msgdesc

Erlang词法分析器、语法分析器(lexer-leex,yac-yecc)相关推荐

  1. 【编译原理】词法分析器语法分析器

    简单编译器设计 采用Java语言对C++语言进行编译,具体的简单编译器设计 词法分析器-扫描器的设计与实现 基本符号表 状态转换图 代码实现 import java.io.*; import java ...

  2. mysql词法分析antlr4_词法分析器和语法分析器的界线 - ANTLR 4 简明教程

    因为词法规则可以使用递归,所以词法解析器在技术上和语法解析器一样强大.那意味着我们甚至可以在词法分析器中匹配语法结构.或者,在另一个极端,我们可以把字符当作记号,使用语法分析器去把语法结构应用到字符流 ...

  3. C-语言词法分析器与语法分析器(一)

    说明: 为实践<编译原理>中的相关知识,认真完成了课程设计,实现了C-语言的词法分析器与语法分析器 C-语言是C语言的一个子集,语法包括: 整型变量与函数的声明 if else 分支语句 ...

  4. 南华大学编译原理----词法分析器的设计与实现、语法分析器的设计与实现

    下载链接:(各位同学不需要充钱哈,这种我也没有收益,去淘宝上面找个代下,大概0.5元就能下载实验报告,用来给同学们参考,下载积分不是我设置的,是网站自己默认的) ------------------- ...

  5. 词法分析器flex和语法分析器lemon的初步使用

    自己手写词法分析器和语法分析器是很麻烦的一件事,而且这里面的逻辑非常复杂很容易出错.flex和lemon就是用来帮助生成词法分析器和语法分析器的,只需要写少量规则代码,就可以生成解析的c代码.现在先不 ...

  6. Vczh Library++ 语法分析器开发指南

    Vczh Library++ 语法分析器开发指南 陈梓瀚 前言 在日常的开发工作中我们总是时不时需要写一些语法分析器.语法分析器不一定指的是一门语言的编译器前端,也有可能仅仅是一个自己设计格式的配置文 ...

  7. 自制编译器:语法分析器(二)

    这篇博文拖了好久才写完,其一是语法分析器本身的难度实在有点超出我的预料,以至于反复重构多次才完成,其二是因为弄了个xbox玩,占用了一部分的课余时间= =!. 本篇博文将分为以下几个部分来描述一下语法 ...

  8. 简易编译器实现(二)使用Bison创建语法分析器

    你也可以通过我的独立博客 -- www.huliujia.com 获取本篇文章 简易编译器实现(一)使用Flex创建词法分析器一文介绍了编译器的概念和七个阶段,并说明了如何使用Flex创建词法分析器. ...

  9. C++轻量级可配置语法分析器(开源) - λ-calculus(惊愕到手了欧耶,GetBlogPostIds.aspx) - C++博客...

    C++轻量级可配置语法分析器(开源) - λ-calculus(惊愕到手了欧耶,GetBlogPostIds.aspx) - C++博客 C++轻量级可配置语法分析器(开源) - λ-calculus ...

最新文章

  1. 重磅丨国资委下发通知,加快推进国有企业数字化转型
  2. markdown设置字体颜色大小、目录、列举和横线
  3. java接口关于interface关键字
  4. Linux中的可重入函数和不可重入函数
  5. mysql怎么用命令行导出sql文件_使用mysql命令行导出sql_MySQL
  6. 201671010144 2016-2017-2 《java程序设计》--认识java!
  7. hash_hmac函数使用不当造成的安全问题
  8. 单片机c语言位运算写法,单片机与嵌入式系统中C语言的位运算小记
  9. mysql锁表查询_Mysql数据库锁情况下开启备份导致数据库无法访问处理分享
  10. 【canvas系列】canvas实现“ 简单的Amaziograph效果”--画对称图【强迫症福利】
  11. 《Java并发编程实践-第一部分》-读书笔记
  12. 从714里连续减去6减几次得0_小学数学1—6年级基础知识整理 ,预习复习都能用...
  13. 如何理解通配符类型参数/协变性/逆变性?
  14. WINDBG常用方法
  15. pyspark 数据写入hive_美团是如何应用Spark处理大数据的?
  16. MacBook 运维软件
  17. 对PNG图像进行编码 Encoding the PNG image
  18. 达梦MPP 环境搭建
  19. darknet源码理解(二)---图片的读取
  20. navigationBar的控制

热门文章

  1. IBM MessageBroker笔记系列(一)
  2. SAP-ABAP性能优化之构建嵌套结构的哈希表
  3. 异地远程访问连接家里的群晖NAS【内网穿透】
  4. 拉勾网数据分析师职位分析
  5. 邬贺铨院士:5G技术影响智联网的关键点
  6. 几种抠象技术理论试验-1 (Luma-Key,Chroma-Key)
  7. 程序员应该避开的20个低级不良用户体验
  8. flash源文件小,导出后变大的问题
  9. 电子计算机工作最主要特征,电子计算机最重要的工作特征是( )
  10. 【M】⽴项or申报书中的重点难点咋写?