atitit.自己动手开发编译器and解释器(1) ------词法分析--attilax总结
atitit.自己动手开发编译器and解释器(1) ------词法分析--attilax总结
2. 2. 流程如下::: 词法分析(生成token流) >>>>语法分析(生成ast) >>解释执行... 2
4. 使用状态模式构建FSM (简单,易用。。推荐首选) 2
6.1. 词法分析(英语:lexical analysis)跟token
4
7.3. 使用NFA、DFA构建FSM( 专业方法,难度大) 6
1. 应用场景:::DSL 大大提升开发效率
为了大大提升开发效率,使用了大量DSL ,就需要实现自己的编译器、解释器了。。
String s = "@QueryAdptr(sqlwhere=\" clo1='@p' \",prop2=\"v2\") @Nofilt";
// 创建环境
所以,要解析注解...
网上马,,子能嘎自实现兰....
要是java 源码中的注解能使用java api读取了...
html中的注解嘎自实现兰.
作者:: 老哇的爪子 Attilax 艾龙, EMAIL:1466519819@qq.com
转载请注明来源: http://blog.csdn.net/attilax
2. 2. 流程如下::: 词法分析(生成token流) >>>>语法分析(生成ast) >>解释执行...
3. 如何进行词法分析?Fsm状态机(自动机)
A: 一种很简单的思路就是,用一个状态保存在处理到各个字符时的状态,比如是标识符或者数字或者空格等等,直到状态改变到可以认定是不同token的时候结束。
可以肯定的是,必然要对需要处理的数据挨个字符判断,然后在恰当的位置截断,得到一个个的token.
这里的核心在于将不同符号对应的字符给区别开,在一个字符无法表达此符号时将它截断,token形成。
4. 使用状态模式构建FSM (简单,易用。。推荐首选)
这种模式使用代码实现fsm 简单,易用。。推荐首选
使用这种方法,attilax初次实现词法分析,也只用一天时间
5. ---代码( 状态模式构建FSM )
public static List getTokenList() {
String s = "@QueryAdptr(sqlwhere=\" clo1='@p' \",prop2=\"v2\") @Nofilt";
s="@qu(at1=\"v1\" , at2 = \" v2 abc \",at3=\"v3\" ) ";
// 创建环境
AnnoPaserContext context = new AnnoPaserContext();
// 将状态设置到环境中
// 创建状态
context.setState(new iniState());
int n=0;
while(!( context.state instanceof FinishState))
{
// System.out.println(n);
// 请求
context.request(s);
n++;
if(n>200)
break;
}
for (Token tk : context.tokenList) {
//if(tk.value.trim().length()>0)
System.out.println(tk.value+"");
}
return (List) context.tokenList;
}
6. 词法分析概念
6.1. 词法分析(英语:lexical analysis)跟token
是计算机科学中将字符序列转换为单词(Token)序列的过程。进行词法分析的程序或者函数叫作词法分析器(Lexical analyzer,简称Lexer),也叫扫描器(Scanner)。词法分析器一般以函数的形式存在,供语法分析器调用。
这里的单词是一个字符串,是构成源代码的最小单位。从输入字符流中生成单词的过程叫作单词化(Tokenization),在这个过程中,词法分析器还会对单词进行分类。
词法分析器通常不会关心单词之间的关系(属于语法分析的范畴),举例来说:词法分析器能够将括号识别为单词,但并不保证括号是否匹配。
词法分析(lexical analysis)或扫描(scanning)是编译器的第一个步骤。词法分析器读入组成源程序的字符流,并且将它们组织成有意义的词素(lexeme)的序列,并对每个词素产生词法单元(token)作为输出。
简单的来说,词法分析就是将源程序(可以认为是一个很长的字符串)读进来,并且“切”成小段(每一段就是一个词法单元 token),每个单元都是有具体的意义的,例如表示某个特定的关键词,或者代表一个数字。而这个词法单元在源程序中对应的文本,就叫做“词素”。
token就是把程序的语句进行类似分词得到的单词。
6.2. 五种token类型
下面就是上述单词的正则表达式定义。
类型 |
正则表达式 |
例子 |
关键字string |
string |
string |
标识符(变量名) |
[a-z][a-z0-9]* |
str |
等号 |
= |
= |
字符串字面常量 |
"[^"]*" |
"hello world" |
分号 |
; |
; |
接下来的问题是,怎么用正则表达式表示的规则来进行词法分析呢?正则表达式利于我们理解单词的规则,但并不能拿来直接解析字符串。为此我们要引入有穷自动机的概念来真正处理输入字符串。
7. 其他词法分析方法
7.1. switchcase或者ifelse
这无意是最直观的方式,使用一堆条件判断,会编程的人都可以做到,对简单小巧的状态机来说最合适,但是毫无疑问,这样的方式比较原始,对庞大的状态机难以维护。
但checkStateChange()和performStateChange()这两个函数本身依然会在面对很复杂的状态机时,内部逻辑变得异常臃肿,甚至可能是难以实现。
在很长一段时期内,使用switch语 句一直是实现有限状态机的唯一方法,甚至像编译器这样复杂的软件系统,大部分也都直接采用这种实现方式。但 之后随着状态机应用的逐渐深入,构造出来的状态 机越来越复杂,这种方法也开始面临各种严峻的考验,其中最令人头痛的是如果状态机中的状态非常多,或者状 态之间的转换关系异常复杂,那么简单地使用switch语句构造出来的状态机将是不可维护的。
7.2. 状态表
,介绍了正则表达式、正则语言和DFA等工具。今次我们要开始涉及编译器前端最重要的阶段——语法分析。简单而言,这一步就要完整地分析整个编程语言的语法结构。上回说到词法分析的结果是将输入的字符串分解成一个个的单词流,也就是诸如关键字、标识符这样有特定意义的单词
7.3. 使用NFA、DFA构建FSM( 专业方法,难度大)
DFA实际上就是高级版的状态表
使用DFA的方法完成的可配置词法分析器的性能是相当好
一般来说,比较高性能的DFA的实现是一张二维的表。行代表字符,列代表DFA 的状态,单元格代表该状态经输入某个字符之后进行转移的目标状态。此外还有一张表用来记录哪些状态对应哪些规则的结束状态
确定有限自动机(英语:deterministic finite automaton, DFA)是一个能实现状态转移的自动机。对于一个给定的属于该自动机的状态和一个属于该自动机字母表的字符,它都能根据事先给定的转移函数转移到下一个状态(这个状态可以是先前那个状态)
这种模型就叫做有穷自动机(finite automation,FA),有时也叫有穷状态机(finite state machine)。
,还有一种非确定性有穷自动机(NFA),
string1 = null; 这句代码中的string1是一个标识符,代表一个变量。如果词法扫描器刚刚扫描到string,就报告发现了“关键字string”,那这里逻辑就不对 了。而如果等到DFA状态抓换到停机状态时再判断,就能判断到最长可能的的单词。比如,当词法分析器分析到了string时,它仍然没有停机,于是就输入 了下一个字符"1",这时词法分析的状态就从接受“关键字string”的状态转换到接受“标识符”的状态;然后词法分析器发现下一个字符是空格,而空格 接在string1后面并不是任何合法的单词,所以它就会转到停机状态。最后我们判断停机前最后一个状态是接受“标识符”的状态,于是报告成功扫描标识符 string1。这样就实现了最长匹配的目的。
先来看miniSharp的词法分析。miniSharp语言的单词根据优先级和不同种类可以分成以下五类:
1. 关键字
2. 标识符
3. 整型数字常量
4. 各种标点符号
5. 空白符、换行符和注释
必须识别为保留字,标识符(变量),常量,操作符(运算符 )和界符五大类 2
我们现在需要寻找一种可以描述token类型的工具,在此之前我们首先研究一下常见的记号的结构。为了表示出具有某种共性的字符串的集合,我们需要书写出一些能代表字符串集合的规则。这个集合中的所有成员都将被认为是一种特定类型的记号。
,直接使用正则表达式进行匹配配的话,不仅工作量大,而且速度缓慢。因此我们还需要另外一种专门为机器设计的表达方式。本文在以后的章节中会给出 一种算法把正则表达式转换为机器可以阅读的形式,就是这一章节所描述的有穷状态自动机。
从正则表达式到ε-NFA
7.3.1. DFA的局限
DFA是一種实际的计算模型,因为有平凡的线性时间、恒定空间的在线算法模拟在输入流上的DFA。给定两个DFA有有效算法找到识别它们所识别语言的并集、交集和补集的DFA。还有有效算法确定一个DFA是否接受任何给定字符串,一个DFA是否接受所有字符串,两个DFA是否识别同样的语言,和对特定正则语言找到状态数目最小的DFA(最小DFA)。
在另一方面,DFA在可识别的语言上有严格的限制—很多简单的语言,包括需要多于恒定空间来解决的任何问题,不能被DFA识别。经典的DFA不能识别的简单语言的例子是括号语言,就是由正确配对的括号组成的语言,比如 (()())。由形如anbn的字符串组成的语言,就是有限数目个a,随后是相等数目个b。可以证明没有DFA有足够状态来识别这种语言(通俗地说,因为需要至少2n个状态,而n是不恒定的)。
8. 参考
NFA_DFA算法 - 于公摊的杂货铺 - 博客频道 - CSDN.NET.htm
自己动手开发编译器(二)正则语言和正则表达式 - 装配脑袋 - 博客园.htm
Atitit. 有限状态机 fsm 状态模式 - attilax的专栏 - 博客频道 - CSDN.NET.htm
atitit.词法分析的实现token attilax总结 - attilax的专栏 - 博客频道 - CSDN.NET.htm
Atitit.注解解析(1)---------词法分析 attilax总结 java .net - attilax的专栏 - 博客频道 - CSDN.NET.htm
atitit.自己动手开发编译器and解释器(1) ------词法分析--attilax总结的更多相关文章
- atitit.自己动手开发编译器and解释器(2) ------语法分析,语义分析,代码生成--attilax总结
atitit.自己动手开发编译器and解释器(2) ------语法分析,语义分析,代码生成--attilax总结 1. 建立AST 抽象语法树 Abstract Syntax Tree,AST) 1 ...
- 自己动手开发编译器(五)miniSharp语言的词法分析器
稍微说明一点,整型常量和上面的标识符的词法,在调用lex.DefineToken时都多传了一个参数.这个参数是可选的描述信息,如果不传会直接使用正则表达式的字符串形式.而标识符的正则表达式有4万多个字 ...
- 自己动手开发编译器(四)利用DFA转换表建立扫描器
上回我们介绍了两种有穷自动机模型——确定性有穷自动机DFA和非确定性有穷自动机,以及从正则表达式经过NFA最终转化为DFA的算法.有些同学表示还是难以理解NFA到底怎么转化为DFA.所以本篇开头时我想 ...
- atitit.提升软件开发的效率and 质量的那些强大概念and方法总结
atitit.提升软件开发的效率and 质量的那些强大概念and方法总结 1. 主流编程中三个最糟糕的问题 1 1.1. 从理解问题后到实现的时间很长 1 1.2. 理解和维护代码 2 1.3. 学 ...
- Atitit. 提升软件开发效率and 开发质量---java 实现dsl 4gl 的本质and 精髓 O725
Atitit. 提升软件开发效率and 开发质量---java 实现dsl 4gl 的本质and 精髓 O725 1. DSL主要分为三类:外部DSL.内部DSL,以及语言工作台. 1 2. DSL ...
- Linux 小知识翻译 - 「编译器和解释器」
这次聊聊「编译器和解释器」. 编程语言中,有以C为代表的编译型语言和以Perl为代表的解释型语言.不管是哪种,程序都是以人类能够理解的形式记录的,这种形式计算机是无法理解的. 因此,才会有编译器和解释 ...
- 学了编译原理能否用 Java 写一个编译器或解释器?
16 个回答 默认排序 RednaxelaFX JavaScript.编译原理.编程 等 7 个话题的优秀回答者 282 人赞同了该回答 能.我一开始学编译原理的时候就是用Java写了好多小编译器和 ...
- Atitit codeblock c++开发环境建立attilax总结
Atitit codeblock c++开发环境建立attilax总结 1.1. C++的重要意义 1 1.2. 项目ide的选项 1 1.3. 安装MinGW (基于GCC的C++编译器) 50 ...
- java编写编译器和解释器
on 2012-07-14 21:24 Bang 阅读(102) 评论(0) 编辑 收藏 续 第二部分 初始后端实现 框架后端支持编译器和解释器.现在框架抽象类Backend有两个极简版实现,一个 ...
随机推荐
- 使button的背景色变为半透明的但不影响字体的透明度
效果如图: 然而做出这样的效果并不顺利, 刚开始的时候代码如下: UIButton *backButton = [UIButton buttonWithType:UIButtonTypeSystem] ...
- ECMAScript新特性【一】--Object.create
Object.create(prototype, descriptors) :创建一个具有指定原型且可选择性地包含指定属性的对象 参数: prototype 必需. 要用作原型的对象. 可以为 nu ...
- 数学图形(1.35)Kappa curve
不知道这个曲线和那个运动品牌背靠背有什么关系.阿迪原先的商标是个三叶草,难道背靠背也是由数学图形来的? 以下是维基上的解释. In geometry, the kappa curve or Gutsc ...
- go语言基础之普通函数的调用流程
函数调用流程:先调用后返回,先进后出,函数递归,函数调用自己本分,利用此物点 1.普通函数的调用流程 package main //必须 import "fmt" func fun ...
- J2EE 中 用 El表达式 和 Jsp 方式 取得 URL 中的参数方法
使用 el表达式方法: var urlParamValue = "${param.urlVarName}"; 使用 Jsp 表达式 var urlParamValue2 = &qu ...
- MySQL服务器安装完之后如何调节性能
原文作者: Peter Zaitsev原文来源: http://www.mysqlperformanceblog.com/2006/09/29/what-to-tune-in-mysql-server ...
- [React] Ensure all React useEffect Effects Run Synchronously in Tests with react-testing-library
Thanks to react-testing-library our tests are free of implementation details, so when we refactor co ...
- JQuery 控制div滚动条保持最下
$("#session_show").animate({ scrollTop: $("#session_show").scrollHeight },1000); ...
- onvif杂项
onvif规范 中文介绍 什么是ONVIF ? ONVIF规范描述了网络视频的模型.接口.数据类型以及数据交互的模式.并复用了一些现有的标准,如WS系列标准等.ONVIF规范的目标是实现一个网络视频框 ...
- BNU 26480 Horror List【最短路】
链接: http://www.bnuoj.com/bnuoj/problem_show.php?pid=26480 http://www.bnuoj.com/bnuoj/contest_show.ph ...