热门标签 | 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;方便我们进行语法分析。



推荐阅读
  • 字符串学习时间:1.5W(“W”周,下同)知识点checkliststrlen()函数的返回值是什么类型的?字 ... [详细]
  • 本文详细介绍了 PHP 中对象的生命周期、内存管理和魔术方法的使用,包括对象的自动销毁、析构函数的作用以及各种魔术方法的具体应用场景。 ... [详细]
  • [转]doc,ppt,xls文件格式转PDF格式http:blog.csdn.netlee353086articledetails7920355确实好用。需要注意的是#import ... [详细]
  • 在尝试对 QQmlPropertyMap 类进行测试驱动开发时,发现其派生类中无法正常调用槽函数或 Q_INVOKABLE 方法。这可能是由于 QQmlPropertyMap 的内部实现机制导致的,需要进一步研究以找到解决方案。 ... [详细]
  • String字符串与字符数组#includeStringintmain(){char*strhello;字符串与字符数组的关系:字符串是 ... [详细]
  • 本文介绍如何使用线段树解决洛谷 P1531 我讨厌它问题,重点在于单点更新和区间查询最大值。 ... [详细]
  • 在分析Android的Audio系统时,我们对mpAudioPolicy->get_input进行了详细探讨,发现其背后涉及的机制相当复杂。本文将详细介绍这一过程及其背后的实现细节。 ... [详细]
  • poj 3352 Road Construction ... [详细]
  • 开机自启动的几种方式
    0x01快速自启动目录快速启动目录自启动方式源于Windows中的一个目录,这个目录一般叫启动或者Startup。位于该目录下的PE文件会在开机后进行自启动 ... [详细]
  • 详解 Qt 串口通信程序全程图文 (4)
    Qt串口通信程序全程图文是本文介绍的内容,本文一开始先讲解对程序的改进,在文章最后将要讲解一些重要问题。1、在窗口中加入一些组合框ComboBox&# ... [详细]
  • 单片机入门指南:基础理论与实践
    本文介绍了单片机的基础知识及其应用。单片机是一种将微处理器(类似于CPU)、存储器(类似硬盘和内存)以及多种输入输出接口集成在一块硅片上的微型计算机系统。通过详细解析其内部结构和功能,帮助初学者快速掌握单片机的基本原理和实际操作方法。 ... [详细]
  • 在软件开发过程中,经常需要将多个项目或模块进行集成和调试,尤其是当项目依赖于第三方开源库(如Cordova、CocoaPods)时。本文介绍了如何在Xcode中高效地进行多项目联合调试,分享了一些实用的技巧和最佳实践,帮助开发者解决常见的调试难题,提高开发效率。 ... [详细]
  • 类加载机制是Java虚拟机运行时的重要组成部分。本文深入解析了类加载过程的第二阶段,详细阐述了从类被加载到虚拟机内存开始,直至其从内存中卸载的整个生命周期。这一过程中,类经历了加载(Loading)、验证(Verification)等多个关键步骤。通过具体的实例和代码示例,本文探讨了每个阶段的具体操作和潜在问题,帮助读者全面理解类加载机制的内部运作。 ... [详细]
  • 本文详细解析了Java类加载系统的父子委托机制。在Java程序中,.java源代码文件编译后会生成对应的.class字节码文件,这些字节码文件需要通过类加载器(ClassLoader)进行加载。ClassLoader采用双亲委派模型,确保类的加载过程既高效又安全,避免了类的重复加载和潜在的安全风险。该机制在Java虚拟机中扮演着至关重要的角色,确保了类加载的一致性和可靠性。 ... [详细]
  • 你的问题在于:1. 代码格式混乱,缺乏必要的缩进,导致可读性极低;2. 使用 `strlen()` 和 `malloc()` 函数时,必须包含相应的头文件;3. `write()` 函数的返回值处理不当,建议检查并处理其返回值以确保程序的健壮性。此外,建议在编写代码时遵循良好的编程规范,增加代码的可维护性和可读性。 ... [详细]
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社区 版权所有