热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

词法分析c语言,简单的C语言解释运行器实现(一)——词法分析

引入编译器的构造想必度过编译原理的同学已经了解了。大概分为预处理器-编译器-汇编器-链接器,4个阶段。编译器又可以分为词法分析-语法分析-语义分析-中间代

引入

编译器的构造想必度过编译原理的同学已经了解了。大概分为

预处理器 -> 编译器 -> 汇编器 -> 链接器,4个阶段。

编译器又可以分为词法分析 -> 语法分析 -> 语义分析 -> 中间代码生成 -> 代码优化 ->生成目标代码等阶段。

阶段

功能

预处理器

处理宏定义,如#include表示引入其他源文件的代码,#define表示定义宏,对代码片进行一个替换,#if系列命令可以控制预处理器的功能做到面向不同环境的代码等等。

编译器

生成中间代码,生成中间代码的意义是方便该阶段以后的所有阶段共用一个后端,比如LLVM,这样不同的语言能共享同一套优化系统

词法分析

将高级语言代码文本切割成词汇,输出单词流,删除注释、空格、空行等

语法分析

根据单词流生成语法树

语义分析

构建带类型和符号表的语法树、检查类型是否匹配、检查等号左侧是否为左值等

中间代码生成

生成中间代码

代码优化

优化中间代码

汇编器

根据中间代码生成汇编命令

链接器

将多个目标代码库链接成可执行文件

目前本系列文章,我们只做词法分析到中间代码生成4个阶段,以及解释执行中间代码的一个解释器。

一个小例子

比如我们有一个语句:x = a + b * c;。

经过词法分析后得到x|=|a|+|2|*|c|;,其中用|表示分隔符。更加抽象地:id|=|id|+|constant|*|id|;,其中id表示标识符。

我们定义文法:

S ::= ID = E

E ::= T | E + T

T ::= F | T * F

F ::= ID | CONSTANT

经过语法分析后,我们可以得到一棵语法树:

S

/|\

F = E

| /|\

i F + T

| /|\

i F * F

| |

2 i

其中字母表示文法的名字,i表示id。

然后我们根据语法树生成字节码:

iconst 2

iload c

imul

iload a

iadd

istore x

然后解释器解释执行就可以得到答案了。

我将在接下来的博文中解释执行过程。

词汇分析

首先切割文本,显然比需要有意义地切割才行,也就是连续的有意义的一个单词不能被切开,比如int就不能被切成i和nt这种。因此对于下列程序:

int max(int a, int b) {

// find the maximum of a and b.

return a > b ? a : b;

}

printf("%d %d %c %d", &a, &b, &#39;c&#39;, 1 <<2);

我们可以这么切割&#xff1a;

int|max|(|int|a|,|int|b|)|{

|return|a|>|b|?|a|:|b|;|

}

printf|(|"%d %d %c %d"|,|&|a|,|&|b|,|&#39;c&#39;|,|1|<

词汇分析阶段我们需要将注释全部清除。同时要注意字符和字符串都是完整的单词不能被切开&#xff0c;这将方便语法分析阶段进行处理。而且两个字符的符号如<

那么编写这样简化的词法分析就相当简单了&#xff0c;我们只需要遇到引号就按字符串处理&#xff0c;注意转义&#xff1b;遇到数字就按数字处理&#xff0c;注意科学计数法和16进制数以及类型标识(1LL, 1L, 1.0F等)&#xff1b;遇到//和/*就按注释处理即可。

最后我们应该得到这样4种单词&#xff1a;

关键字/保留字&#xff1a;如if、for、while等

标识符&#xff1a;字母开头的字母数字下划线串

常量&#xff1a;小数(1.2)、科学计数法(1.2e&#43;9、7.7e-5、6.666e2)整数(19)、八进制数(012)、十六进制数(0x7FFFFFFF)、字符常量(&#39;a&#39;)、字符串常量("String")

符号&#xff1a;&#43;、-、*、/、%、&、|、^、&&、||、!、~、>>、<>、&#43;&#61;、-&#61;、*&#61;、/&#61;、&&#61;、|&#61;、^&#61;、%&#61;、,、;、>、&#61;、<&#61;、!&#61;、&#61;&#61;、::

我们可以在输出单词流的时候标注是哪种标记&#xff0c;方便我们进行语法分析。



推荐阅读
  • 向QTextEdit拖放文件的方法及实现步骤
    本文介绍了在使用QTextEdit时如何实现拖放文件的功能,包括相关的方法和实现步骤。通过重写dragEnterEvent和dropEvent函数,并结合QMimeData和QUrl等类,可以轻松实现向QTextEdit拖放文件的功能。详细的代码实现和说明可以参考本文提供的示例代码。 ... [详细]
  • 本文讨论了使用差分约束系统求解House Man跳跃问题的思路与方法。给定一组不同高度,要求从最低点跳跃到最高点,每次跳跃的距离不超过D,并且不能改变给定的顺序。通过建立差分约束系统,将问题转化为图的建立和查询距离的问题。文章详细介绍了建立约束条件的方法,并使用SPFA算法判环并输出结果。同时还讨论了建边方向和跳跃顺序的关系。 ... [详细]
  • Android源码深入理解JNI技术的概述和应用
    本文介绍了Android源码中的JNI技术,包括概述和应用。JNI是Java Native Interface的缩写,是一种技术,可以实现Java程序调用Native语言写的函数,以及Native程序调用Java层的函数。在Android平台上,JNI充当了连接Java世界和Native世界的桥梁。本文通过分析Android源码中的相关文件和位置,深入探讨了JNI技术在Android开发中的重要性和应用场景。 ... [详细]
  • C++字符字符串处理及字符集编码方案
    本文介绍了C++中字符字符串处理的问题,并详细解释了字符集编码方案,包括UNICODE、Windows apps采用的UTF-16编码、ASCII、SBCS和DBCS编码方案。同时说明了ANSI C标准和Windows中的字符/字符串数据类型实现。文章还提到了在编译时需要定义UNICODE宏以支持unicode编码,否则将使用windows code page编译。最后,给出了相关的头文件和数据类型定义。 ... [详细]
  • 开发笔记:实验7的文件读写操作
    本文介绍了使用C++的ofstream和ifstream类进行文件读写操作的方法,包括创建文件、写入文件和读取文件的过程。同时还介绍了如何判断文件是否成功打开和关闭文件的方法。通过本文的学习,读者可以了解如何在C++中进行文件读写操作。 ... [详细]
  • 本文介绍了深入浅出Linux设备驱动编程的重要性,以及两种加载和删除Linux内核模块的方法。通过一个内核模块的例子,展示了模块的编译和加载过程,并讨论了模块对内核大小的控制。深入理解Linux设备驱动编程对于开发者来说非常重要。 ... [详细]
  • Iamtryingtomakeaclassthatwillreadatextfileofnamesintoanarray,thenreturnthatarra ... [详细]
  • VScode格式化文档换行或不换行的设置方法
    本文介绍了在VScode中设置格式化文档换行或不换行的方法,包括使用插件和修改settings.json文件的内容。详细步骤为:找到settings.json文件,将其中的代码替换为指定的代码。 ... [详细]
  • C语言注释工具及快捷键,删除C语言注释工具的实现思路
    本文介绍了C语言中注释的两种方式以及注释的作用,提供了删除C语言注释的工具实现思路,并分享了C语言中注释的快捷键操作方法。 ... [详细]
  • 本文讨论了一个关于cuowu类的问题,作者在使用cuowu类时遇到了错误提示和使用AdjustmentListener的问题。文章提供了16个解决方案,并给出了两个可能导致错误的原因。 ... [详细]
  • 本文介绍了UVALive6575题目Odd and Even Zeroes的解法,使用了数位dp和找规律的方法。阶乘的定义和性质被介绍,并给出了一些例子。其中,部分阶乘的尾零个数为奇数,部分为偶数。 ... [详细]
  • CF:3D City Model(小思维)问题解析和代码实现
    本文通过解析CF:3D City Model问题,介绍了问题的背景和要求,并给出了相应的代码实现。该问题涉及到在一个矩形的网格上建造城市的情景,每个网格单元可以作为建筑的基础,建筑由多个立方体叠加而成。文章详细讲解了问题的解决思路,并给出了相应的代码实现供读者参考。 ... [详细]
  • Linux环境变量函数getenv、putenv、setenv和unsetenv详解
    本文详细解释了Linux中的环境变量函数getenv、putenv、setenv和unsetenv的用法和功能。通过使用这些函数,可以获取、设置和删除环境变量的值。同时给出了相应的函数原型、参数说明和返回值。通过示例代码演示了如何使用getenv函数获取环境变量的值,并打印出来。 ... [详细]
  • Java学习笔记之面向对象编程(OOP)
    本文介绍了Java学习笔记中的面向对象编程(OOP)内容,包括OOP的三大特性(封装、继承、多态)和五大原则(单一职责原则、开放封闭原则、里式替换原则、依赖倒置原则)。通过学习OOP,可以提高代码复用性、拓展性和安全性。 ... [详细]
  • 本文介绍了最长上升子序列问题的一个变种解法,通过记录拐点的位置,将问题拆分为左右两个LIS问题。详细讲解了算法的实现过程,并给出了相应的代码。 ... [详细]
author-avatar
xxyyxx1952
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有