一、编译概述

计算机科学研究方向众多,我们不可能精通所有,但是如果明白了本质,我们就能进行交叉学习,理顺思路,也就不至于觉得某项技术特别难,无从下手。

最原始的计算机是靠机器代码(Machine Code)来工作的,而计算机使用的是我们熟知的冯诺依曼体系结构,计算模型就是图灵机。冯诺依曼结构决定了计算机的控制,存储和运算单元,而图灵机则揭示了计算机是怎么进行运算的。说得简单一点,图灵机就是如下图的一串序列:

我们在此忽略图灵机的其他细节和各种理论,简言之,输入计算机的就是一串01序列,加上一些开始,接受,中止的状态来执行代码。

但是为了开发方便,提高效率,更多的易于理解的编程语言诞生了,我们用类似于人类语言一样,带有特定语法规则的符号和标记来简化和约束代码。可是不管怎样,我们至少目前改变不了计算机的工作方式,我们必须能够把代码转换成机器码才能让计算机执行,这样一个必然产生必然需要使用的工具就是编译器。

为了完成语言编译的工作,需要六个主要步骤:词法分析,语法分析,语义分析,代码优化,代码生成。前三个步骤一般又称为编译器前端工作

词法分析(Scanning):这个过程的输入是我们的源代码,它的工作是对我们编程语言规则的第一次也是最简单解析,也就是把关键字、变量、常量等单词读取并区分开来,最终得到一个Token table。

语法分析(Syntax Analysis):这个过程接受词法分析得到的符号表,根据编程语言的语法规则,将符号按照规则组合成语句,并检测输入是否符合文法。一般是上下文无关文法。例如一个赋值语句是否完整。

语义分析(Semantic Analysis):这个是语言的一个逻辑分析过程,比如将数组赋值给了一个整数变量。


二、词法分析

本篇文章主要将词法分析中的过程,在编程语言中,变量和关键字,一般都是字母,数字或者下划线,所有单词都是按照一定的规则构成,可以用正则表达式来描述。例如[0-9],[a-zA-Z],s*等等。

所有的这样的正则序列都可以用不确定有限状态自动机(NFA)来验证,也就是说我们输入的源程序,可以通过NFA来判断能不能被编译器接受。由正则语言到NFA的转换是直观的,简单的,但是由于机器更接近于确定性有限状态自动机这种更为严格的定义形式,所以我们需要把NFA转换为DFA,最后完成词法分析。

因此在词法分析中,最关键的步骤是NFA到DFA的转换。


三、NFA to DFA

NFA: 由一系列的状态和转移函数组成,并且允许epsilon-转换,而且某个状态可能转移到两个或者更多的下一状态,由此你不知道在遇到此状态时,到底该选择哪一个进行转换,这就是为什么叫做不确定性有限状态自动机。

DFA也是由状态和转移函数组成,但是不允许epsilon-转换,而且每个状态只能转移到一个确定的下一状态。

下面通过例子说明转换过程:


这是一个NFA

转换的第一步,起始状态是这么定义的:

epsilon-closure(0)={0,1,2,4,7}=A,A就是DFA的起始状态

这里转移路径只有两种,通过a或者b,于是第二步

DFA_Move(A,a)= epsilon-closure(NFA_Move(A,a))=epsilon-closure({3,8})={1,3,6,7,8}=B

这就得到了DFA的第二个状态

接下来DFA_Move(A,b)= epsilon-closure(NFA_Move(A,b))=epsilon-closure({5})={1,5,8}=C

这是DFA的第三个状态

A的状态转换已经结束,但是由于新增添了B,C状态,我们要按照A之前的方式,继续转换B和C

DFA_Move(B,a)= epsilon-closure(NFA_Move(B,8}=B,这是一个到自身的转换

DFA_Move(B,b)= epsilon-closure(NFA_Move(B,b))=epsilon-closure({5,9})={1,9}=D,增加了新状态D

接着DFA_Move(C,a)= B, DFA_Move(C,b)= C

DFA_Move(D,a)= B, DFA_Move(D,b)= E

DFA_Move(E,a)= B, DFA_Move(E,b)= C

到此,所有的状态都转换完毕。得到的DFA如下图所示:



最后我们发现,A-C的转换还可以进行简化,我们必须得到一个最简的DFA:



结束!

编译器技术简析一- Lexical Analysis之NFA-DFA的更多相关文章

  1. css绝对定位如何在不同分辨率下的电脑正常显示定位位置?(一定要看!)

    这篇文章主要介绍了css绝对定位如何在不同分辨率下的电脑正常显示定位位置,本文首先解释了常见的电脑分辨率,为了页面在不同的分辨率下正常显示,要给页面一个安全宽度,再去使用绝对定位,具体操作步骤大家可查看下文的详细讲解,感兴趣的小伙伴们可以参考一下。

  2. ios – Xcode项目在文档大纲中显示为灰色

    我一直在使用iCloud来“同步”我正在从我的笔记本电脑到桌面的Xcode项目.不幸的是,它似乎没有那么好用.我今天在台式机上打开了一个项目,我昨天在笔记本电脑上工作.如果我在桌面上打开文件,则会丢失故事板中的某些按钮和标签.看看文档,我可以看到这些,但它们是灰色的(见图).但是,当我构建文件时,它们在模拟器中显示为正常.知道为什么或如何让它们正常出现?

  3. ios – Xcode 9.2模拟器调试中断;无法附加到进程ID

    iOS模拟器上的Xcode9.2调试对我来说已经彻底破坏了.我花了几个小时研究这个问题并尝试了大量的建议,但没有完全擦除我的硬盘并开始安装新的操作系统.我最终向Apple提交了一个错误.如果有人遇到此问题并有任何建议,请在此处发布.摘要:尝试使用调试可执行文件在调试模式下构建和运行时.模拟器只将应用程序打开到白色屏幕,然后Xcode弹出错误:重现步骤:制作任何项目并尝试在任何模拟器上运行.预期成绩

  4. ios – Swift编译器是否忽略未使用的函数?

    Swift编译器是编译未使用的函数还是忽略它们?

  5. 在Xcode服务器中找不到代码签名标识

    使用Xcode7B4和Server5B4与Carthage项目.要构建项目,我需要首先构建它的依赖项.所以我使用以下代码向bot添加了BeforeIntegration步骤:自己运行一切都有效.但是当机器人运行时,我得到了这个:CodeSignerror:Nocodesigningidentitiesfound:Novalidsigningidentities(i.e.certificateand

  6. 可可 – NSTimer中的代码可防止自动睡眠

    我在我的应用程序中运行了一个NSTimer,它收集一些数据并定期发送到服务器.在生产中,计时器将每隔几个小时发射一次.我担心干扰自动睡眠.在测试中,计时器和睡眠时间的某些组合完全阻止自动睡眠–显示器休眠,系统保持运行.将我的NSTimer设置为一分钟始终会停止它.一些Mac应用程序因运行时干扰自动睡眠而臭名昭着.什么操作会阻止系统进入睡眠状态?

  7. xcode – 今天OS X上的Widget无法正常工作

    解决方法好的终于找到了问题.我手工编写了我的应用程序,因为我有一个应用程序依赖的复杂框架,需要使用copy/Runscript后构建脚本手工复制它们.无论如何,它似乎至少从Xcode7开始,这不再像预期的那样工作.应用程序的工作原理和协同设计说应用程序已经正确签名,但很明显,幕后发生的事情正在打破代码签名.我最终删除了所有手动代码签名的东西,只需使用Xcode的“复制框架”构建后步骤并选中“登录复制”.它现在终于按预期工作了.

  8. 反应原生 – 如何通过Xcode构建React Native iOS应用程序到设备?

    我试图将AwesomeProject应用程序构建到设备上.构建成功并启动屏幕显示,但后来我看到一个红色的“无法连接到开发服务器”屏幕.它表示“确保节点服务器正在运行–从Reactroot运行”npmstart“.看起来节点服务器已经运行,因为当我做npm启动时,我收到一个EADDRINUSE消息,表示该端口已经在使用.解决方法从设备访问开发服务器您可以使用开发服务器快速迭代设备.要做到这一点,你的

  9. ios – LLVM,GCC 4.2和Apple LLVM编译器之间的区别3.1

    LLVMGCC4.2和AppleLLVM编译器3.1之间的主要区别是什么?

  10. xcode – Mac OSX Lion / X11 / CImg库

    所以我试图将CImg图像编写库并入到我的XCodeproject中但是,库的头文件包含以下包含,XCode给出了此错误警告:我的笔记本电脑正在运行OSXLion10.8.2,显然,苹果拿走了X11的Lion,所以我去了thissite,下载了XQuartz,因为这是AppleSupportpage所说的.所以在安装之后,我重新启动了我的电脑,并尝试运行我的XCode项目,但我仍然得到相同的确切的错

随机推荐

  1. 法国电话号码的正则表达式

    我正在尝试实施一个正则表达式,允许我检查一个号码是否是一个有效的法国电话号码.一定是这样的:要么:这是我实施的但是错了……

  2. 正则表达式 – perl分裂奇怪的行为

    PSperl是5.18.0问题是量词*允许零空间,你必须使用,这意味着1或更多.请注意,F和O之间的空间正好为零.

  3. 正则表达式 – 正则表达式大于和小于

    我想匹配以下任何一个字符:或=或=.这个似乎不起作用:[/]试试这个:它匹配可选地后跟=,或者只是=自身.

  4. 如何使用正则表达式用空格替换字符之间的短划线

    我想用正则表达式替换出现在带空格的字母之间的短划线.例如,用abcd替换ab-cd以下匹配字符–字符序列,但也替换字符[即ab-cd导致d,而不是abcd,因为我希望]我如何适应以上只能取代–部分?

  5. 正则表达式 – /bb | [^ b] {2} /它是如何工作的?

    有人可以解释一下吗?我在t-shirt上看到了这个:它似乎在说:“成为或不成为”怎么样?我好像没找到’e’?

  6. 正则表达式 – 在Scala中验证电子邮件一行

    在我的代码中添加简单的电子邮件验证,我创建了以下函数:这将传递像bob@testmymail.com这样的电子邮件和bobtestmymail.com之类的失败邮件,但是带有空格字符的邮件会漏掉,就像bob@testmymail也会返回true.我可能在这里很傻……当我测试你的正则表达式并且它正在捕捉简单的电子邮件时,我检查了你的代码并看到你正在使用findFirstIn.我相信这是你的问题.findFirstIn将跳转所有空格,直到它匹配字符串中任何位置的某个序列.我相信在你的情况下,最好使用unapp

  7. 正则表达式对小字符串的暴力

    在测试小字符串时,使用正则表达式会带来性能上的好处,还是会强制它们更快?不会通过检查给定字符串的字符是否在指定范围内比使用正则表达式更快来强制它们吗?

  8. 正则表达式 – 为什么`stoutest`不是有效的正则表达式?

    isthedelimiter,thenthematch-only-onceruleof?PATTERN?

  9. 正则表达式 – 替换..与.在R

    我怎样才能替换..我尝试过类似的东西:但它并不像我希望的那样有效.尝试添加fixed=T.

  10. 正则表达式 – 如何在字符串中的特定位置添加字符?

    我正在使用记事本,并希望使用正则表达式替换在字符串中的特定位置插入一个字符.例如,在每行的第6位插入一个逗号是什么意思?如果要在第六个字符后添加字符,请使用搜索和更换从技术上讲,这将用MatchGroup1替换每行的前6个字符,后跟逗号.

返回
顶部