HTML4基本编译原理,Stanford公开课《编译原理》学习笔记(1~4课)

课程里涉及到的内容讲的还是很清楚的,但个别地方有点脱节,任何看不懂卡住的地方,请自行查阅经典著作《Compilers——priciples, Techniques and Tools》(也就是大名鼎鼎的龙书)的对应章节。

一. 编译的基本流程

完整的编译的5个基本步骤包括lexcical anlysis,parse,sematic,optimize,code generate。课程中并没有使用复杂的编程语言,而是一种用于课堂教学的自发明语言COOL,很明显老师为它写好了编译器程序。

二. Lexical Analysis(词法分析阶段)

任务:将字符串分解成为[Type, (Value)]元组的形式的词法单元。

“龙书”里的示例更为直观,例如表达式语句 E = M * C ** 2进行词法分析后会得到如下的类似结果:

[id,指向符号表中E的条目的指针]

[assign_op]

[id,指向符号表中M的条目的指针]

[mult_op]

[id,指向符号表中C的条目的指针]

[exp_op]

[number,整数值2]

词法分析基本需要经历如下几个阶段:

Lexical Specification——>Regular expressions——>NFA——>DFA——>Table-driven Implementation of DFA

2.1 Lexical Specification(分词原则)

COOL中的基本Type包括如下几个类别:

Indentifier标识符-指以字母开头后续为若干个字母或数字的字符组

Integer-指一组非空的数字字符

Keyword- 指语言中的关键词,例如if,else等

Whitespace- 指一组非空的空格字符或换行符或制表符

很多程序设计语言中的分词原则基本都会覆盖关键字,运算符,标识符,常量,标点符号,他们也会在后面的实现中被作为终止符集合,课程板书中也提供了COOL分词原则的类正则形式。

73cc0d00af08a2702c5c66e1261d2d4a.png

分词时类型的正则匹配默认为贪婪模式,即匹配更多的字符。词法单元也具备一定的优先级次序(通常也是代码逻辑的实现顺序),例如if从正则上来判断既符合Keywords也符合Identifier,此时该单元的类型就应该标记为Keywords。这个阶段就完成了从Lecical Specification——>Regular expressions的部分。

2.2 Finite Automata (典型分词算法-有穷自动机)

FA是一个可以自动识别词法单元的机器,它是一个状态转换图,“有限”是指它包含的状态是有限的,一个状态读入一个字符后,后继的状态可能为:

后继状态为自身

后继状态只有一个

后继状态有多个

如果每次转换后的后继状态都是唯一的,则称为DFA(确定有限自动机),如果后继状态可能有多个则称为NFA(不确定有限状态机)。由于DFA的状态转移路径是唯一的,所以作为状态查询图时,无论成功或者失败只需要运行一次,但NFA就可能需要运行多次。

正则表达式是可以转换为NFA形式的,或许你已经在一些可视化正则表达式的网站上[https://regexper.com ]见过类似的形式。下图比较清晰地展示了从正则表达式到NFA状态图的转换规则(Regular expressions——>NFA):

d830065823377c0e1ae72433d97d7442.png

如果一个DFA和一个NFA能够识别的字符集是一致的,则称它们为等价的,对于任意NFA,一定存在一个DFA与其等价,由NFA构建DFA的过程被称为DFA的确定化,也就是NFA——>DFA的过程。这个过程是围绕ε -closure状态集合的概念展开的,大致的过程就是从起点开始,每次将当前状态和通过若干次ε转换(它是一个特殊的状态转移函数,表示转换后的状态还是当前状态)作为一个新的ε -closure状态集合 ,使用矩阵记录每个ε -closure集合转换前后的集合,最后对整个状态转移矩阵进行标记重命名,就可以得到一个DFA,事实上转化后的DFA中的每一个状态,就是NFA中的一个ε -closure集合,你可以将它理解成一个通过分组来简化表达方式的过程,相关的过程可以参考下面这个文章西北农林科技大学编译原理课程PPT【词法分析】,里面图比较多,能够辅助理解,本文不再赘述。

三. 手动实现分词器

至此1-4课就结束了,估计看视频课程的人也是一脸懵逼,因为课程并没有讲解如何利用DFA得到最终期望的形式——Token元组,那么最后我们就自己手动来实现一下。

3.1 基本定义

假设我们需要对下面这段代码进行分词解析:

let snippet = `

var b3 = 2;

a = 1 + ( b3 + 4);

return a;

`;

那么先来进行一些基本类型集合定义:

//解析结束标记

const EOF = undefined;

//Token Type 可识别的Token类型,

const TT = {

num: 'num',

id: 'id',

keywords: 'keywords', //var | return

lparen: 'lparen',// (

rparen: 'rparen',// )

semicolon: 'semicolon', //;

whitespace: 'whitespace', // \n | \t | \s (空格,制表符,换行符)

plus: 'plus', // +

assign: 'assign',// =

}

// 状态集类型,除开始和结束外,其他可以与Token支持的类型相对应,每次分词从start状态开始,接收一个字符后改变状态,直到在done状态结束时,可以得到一个token

const S = {

start: 'start',

done: 'done',

...TT

}

进行工具函数定义:

//判断是否为关键词(为简化流程,仅检测上面示例中包含的关键词)

const isKeywords = (token) => ['function', 'return', 'if', 'var'].includes(token);

//判断是否为数字

const isDigit = c => /\d/.test(c);

//判断是否为合法的标识符字符

const isValidId = c => /[A-Za-z0-9]/.test(c);

//判断是否为空格

const isBlank = c => /(\s|\t|\n)/.test(c);

3.2 构建DFA

以上面定义的状态集合和token类别为依据构建DFA:

d8115736ea1817ba458cba1f478a812b.png

3.3 开始分词

分词的逻辑实际上就是,每次先将状态置为start,然后读入一个字符,根据该字符判断下一个状态,只要没有到达完成状态done就继续读入字符,每次到达done状态时,就可以得到一个token,将其记录下来,然后重新将状态置为start,开始寻找下一个token直到分析完整个代码段。也就是说DFA状态机每运行一轮,就得到一个token。参考代码如下:

/**

* 词法分析

*/

function tokenize(code) {

let state = S.start;

let currentToken;//标记当前寻找到的token

let index = 0;//起始指针,每次分析指向start状态

let lookup = 0;//前探指针,每次分析最终指向done状态,start->done之间的字符即为token

while (code[lookup] !== EOF) { //如果还有字符

while (state !== S.done) { //开始拆分token

//获取下一个字符

let c = code[lookup++];

//根据当前状态和下一个字符判断DFA如何跳转

switch (state) {

case S.start: //开始为空集,实现DFA中各个状态转移分支

if (isDigit(c)) {

state = S.num;

} else if (isValidId(c)) {

state = S.id;

} else if (isBlank(c)) {

state = S.done;

} else if (c === '=') {

currentToken = [TT.assign, '=']

state = S.done;

} else if (c === '+') {

currentToken = [TT.plus, '+']

state = S.done;

} else if (c === ';') {

currentToken = [TT.semicolon, ';']

state = S.done;

};

break;

case S.num: //如果是整数

if (isDigit(c)) {

state = S.num;

} else {

currentToken = [TT.num, code.slice(index,lookup - 1)];

lookup -= 1; //从数字状态跳出后,最后一位需要参与下一轮分词,故回退一位

state = S.done;

}

break;

case S.id: //如果是标识符状态

if (isValidId(c)) {

state = S.id;

} else {

let tempToken = code.slice(index,lookup - 1);

lookup -= 1; //从标识符状态跳出后,最后一位需要参与下一轮分词,故回退一位

if (isKeywords(tempToken)) {

currentToken = [TT.keywords, tempToken];

}else{

currentToken = [TT.id, tempToken];

}

state = S.done;

}

break;

}

}

//state = S.done时跳出

currentToken && console.log(currentToken);

currentToken = undefined;

//起指针跟上末指针

index = lookup;

//开始下一轮分词

state = S.start;

}

}

3.4 查看分词结果

运行上述代码即可看到目标程序片段的分词结果:

79d7faa223718c3180f2e9083e51908f.png

四. 小结

至此,我们就得到了元组形式的分词结果,完成了编译中第一步lexical analysis的部分,笔者同时提供了一份包含token所在行列信息的版本,你可以从附件或【我的github仓库】中拿到示例代码,如果觉得对你有帮助,可以在github上为我加个星星哦~

b739ec46bb5c46d9c0aa4ce35ba1ea56.png

关于找一找教程网

本站文章仅代表作者观点,不代表本站立场,所有文章非营利性免费分享。

本站提供了软件编程、网站开发技术、服务器运维、人工智能等等IT技术文章,希望广大程序员努力学习,让我们用科技改变世界。

[Stanford公开课《编译原理》学习笔记(1~4课)]http://www.zyiz.net/tech/detail-91416.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/534081.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

rocketmq 消息指定_SpringBoot 整合 RocketMQ 如何实现消息生产消费?

有时候我们在使用消息队列的时候,往往需要能够保证消息的顺序消费,而RocketMQ是可以支持消息的顺序消费的。RocketMQ在发送消息的时候,是将消息发送到不同的队列中,然后消费端从多个队列中读取消息进行消费,很明显&…

mysql怎么看实例名_南方“中看不中吃”的前4名水果,莲雾只是垫底,你怎么看?...

水果很多人都喜欢吃,南方人可以说是最幸福的,因为南方的水果种类有很多种,而且水果的价格也很便宜,一年四季都能吃到便宜又好吃的水果,南方的很多水果,北方人可能都没有吃过,虽然南方的水果种类…

vuex中的值变化 页面重新渲染_浅谈浏览器的渲染过程,重绘与回流

浏览器的渲染过程 首先,我们先来了解一下浏览器的渲染过程是什么样的,也就是说浏览器把一堆代码呈现到页面上的过程是什么样子的,浏览器采用流式布局模型(Flow Bsaed Layout),根据下图,我们可以总结出浏览器的渲染步骤…

vc 将已有项目打包成dll 并应用于其他项目_.NET混淆器 Dotfuscator使用教程:保护你的应用之存档报告文件...

Dotfuscator是一款.NET混淆器和压缩器,防止你的应用程序被反编译。本篇文章将继续上一篇文章与大家分享保护应用程序的后续三个部分:存档报告文件、加强保护和替代方法。存档报告文件作为构建的一部分,Dotfuscator会生成报告文件(在Dotfuscat…

html文件内容搜索,html读出文本文件内容

html读出文本文件内容更新时间:2007年01月22日 00:00:00 作者:Function bytes2BSTR(vIn)strReturn ""For i 1 To LenB(vIn)ThisCharCode AscB(MidB(vIn,i,1))If ThisCharCode strReturn strReturn & Chr(ThisCharCode)ElseNextCharC…

python 定义变量_python-003-变量

1.变量的定义python中,在程序运行时,可以随着程序的运行更改的量成为变量.简单理解: 变量就是用来临时存储数据的容器.可以认为好比是 逛超市 买面条 使用购物车 装面条变量 -> 购物车数据 -> 面条2.变量的使用# 第一次输入一个10 num1 10 # 第二次输入一个20 num2 20 …

苹果11是高通基带吗_最强对抗!小米11对抗三星、苹果华为等最高旗舰|喜欢小米吗?...

哈喽,您好!我是原呵呵,点点关注吧,更多精彩内容等着您小米很快就会展示了2021年的手机,该公司通常会在2月份推出该季节的首个旗舰,但新的小米米11已向前推进了几个月,并成为了首个采用骁龙888处…

python split函数 空格_python上手--10行代码读懂红楼梦

取名10行代码看懂红楼梦,是将介绍使用python代码来读红楼梦获取其主要人物。这里的思想就是词频统计,通过分析红楼梦小说文字中出现最多的词语,来概括说明红楼梦的核心人物和事情。实际上如果你能跟着往下看,就开始进入了自然语言…

k8s 安装nfs_K8s--06 K8s数据持久化

K8s数据持久化数据持久化 Volume介绍Volume介绍:Volume是Pad中能够被多个容器访问的共享目录Kubernetes中的Volume不Pad生命周期相同,但不容器的生命周期丌相关Kubernetes支持多种类型的Volume,并且一个Pod可以同时使用任意多个VolumeVolume类…

matlab为自定义后缀文件设置图标_【V3.0更新】| 这可能是全网最好用的文件管理神器了......

?点击关注Excel表哥公众号使用Excel制作自带超链接的文件目录索引确实可以很好地帮忙大家管理电脑里的文件。在此分享几个各行各业朋友们的使用截图:▲一个硬件工程师朋友的使用截图▲一个医院工作人员的数据统计文件管理▲学生朋友用来管理论文文献▲VBA编程爱好者…

#中队列的数据结构_数据结构与算法拓展(一)

栈与队列申明:由于篇幅限制,文章可能有些简略,如果大家想要详细了解,请一定要百度一下,并阅读例题,完成习题绪言:计算机科学在过去的数十年内发展飞速,各种新颖的技术纷至沓来&#…

display属性_Numpy知识点(1)讲解实操安装/属性/数组创建/运算

# 1、安装包# pip install numpy #原生python安装# conda install numpy #Anaconda的安装# 使用Numpyimport numpy as np a np.arange(15) #生成0-14的一维数组display(a)display( )和print( )都是打印,在大多数编程软件上都使用print,jupyter notebook中我们可以使用d…

springboot怎么设置多个路径全部跳转首页_SpringBoot(四)—Web开发(二)

这篇文章准备来记录一下一个restful风格小项目的流程,上篇文章为它做了一个基础,如果有什么错误希望大家能够指出。目录首页国际化登录拦截器CRUD一、首页在访问localhost:8080/的时候,默认访问首页在自己配置的SpringMVC的配置类中Configura…

计算机英语六级,英语六级作文范文:计算机

英语六级考试时间越来越近了,所以在备考的时候就更要掌握技巧,勤加练习。在备考英语六级写作时,学习一篇好的范文,会给复习带来事半功倍的效果。Using a computer every day can have more negative than positive effects on you…

python软件_Python自制照片美颜软件~

下午被一个骗子恶心到了,本来听公开课听得好好的,搞得心情极差,于是就中断了网课,听听音乐,写一下文章吧!前期准备①Python编译环境以及Python代码编辑器Pycharm的安装:请在【微信公众后台】找到…

数据集怎么导出_PCA算法 | 数据集特征数量太多怎么办?用这个算法对它降维打击...

今天是机器学习专题的第27文章,我们一起来聊聊数据处理领域的降维(dimensionality reduction)算法。我们都知道,图片格式当中有一种叫做svg,这种格式的图片无论我们将它放大多少倍,也不会失真更不会出现边缘模糊的情况。原因也很简…

常用命令_GIT常用命令大全

Git 是一个很强大的分布式版本控制系统。它不但适用于管理大型开源软件的源代码,管理私人的文档和源代码也有很多优势。克隆远程文件:git clone https://gitee.com/abcd/codefile.git projectgit checkout -b dev(本地分支名称) origin/dev(远程分支名称…

nvidia显示设置不可用_Nvidia显示设置不可用,您当前未使用连接到NVIDIA GPU的显示器的解决方法...

相信不少用户遇到这样一个问题,就是新购买的台式机电脑,配置达标的情况下,玩游戏出现卡顿不流畅的现象,准备在NVIDIA控制面板查看是否设置的问题,在打开NVIDIA控制面板的时候,提示了“Nvidia显示设置不可用…

oracle tns 代理配置_Toad for oracle安装配置与使用

一.toad安装与配置注意:toad的使用本机电脑必须安装完整版oracle客户端,不能是精简版的.1.1完整版oracle客户端的安装.1.解压文件,安装oracle客户端打开安装包,找到setup.ext,开始安装。提示下图弹窗,可根据此网址内容进行更改(https://blog.…

吴枫 python小课账号_无门槛速学编程——Python小短课,自上而下分而治之

【Python小短课 11】自上而下,分而治之 做任何事都需计划,编程也是。 譬如写文章要列大纲、作画要想布局,编程也需先谋全局,而后思虑细节。 就以上回说到的“找宝藏”这个程序举例,最顶层的需求自然就是“找宝藏”&…