前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >用c语言手搓一个600行的类c语言解释器: 给编程初学者的解释器教程(2)- 简介和设计

用c语言手搓一个600行的类c语言解释器: 给编程初学者的解释器教程(2)- 简介和设计

作者头像
云微
发布于 2023-02-24 11:33:05
发布于 2023-02-24 11:33:05
63900
代码可运行
举报
运行总次数:0
代码可运行

用c语言手搓一个600行的类c语言解释器: 给编程初学者的解释器教程(2)- 简介和设计

用c语言手搓一个600行的类c语言解释器: 给编程初学者的解释器教程(1)- 目标和前言

用c语言手搓一个600行的类c语言解释器: 给编程初学者的解释器教程(2)- 简介和设计

用c语言手搓一个600行的类c语言解释器: 给编程初学者的解释器教程(3)- 词法分析

用c语言手搓一个600行的类c语言解释器: 给编程初学者的解释器教程(4)- 语法分析1:EBNF和递归下降文法

用c语言手搓一个600行的类c语言解释器: 给编程初学者的解释器教程(5)- 语法分析2: tryC的语法分析实现

用c语言手搓一个600行的类c语言解释器: 给编程初学者的解释器教程(6)- 语义分析:符号表和变量、函数

项目github地址及源码:

https://github.com/yunwei37/tryC

需要了解的一些基本概念

编译器和解释器的区别不同

通常我们说的 “编译器” 是一种计算机程序,负责把一种编程语言编写的源码转换成另外一种计算机代码,后者往往是以二进制的形式被称为目标代码(object code)。这个转换的过程通常的目的是生成可执行的程序。

解释器是一种计算机程序,它直接执行由编程语言或脚本语言编写的代码,它并不会把源代码预编译成机器码,而是一行一行地分析源代码并且直接执行,相对编译器而言可能效率较为低下,但实现也相对简单,并且容易在不同的机器上进行移植(比如x86和mips指令集的机器)。

先来看看通常的编译器是如何实现的:

编译器从源码翻译为目标代码大致需要这样几个步骤,每个步骤都依赖于上一个步骤的结果:

词法分析:

编译器对源程序进行阅读,并将字符序列,也就是源代码中一个个符号收集到称作记号(token)的单元中;比如:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    num = 123.4;

这样个赋值语句中,变量num算是一个token,“=”符号算是一个token,“123.4”算是一个token;每个token有自己的类别和属性,比如“123.4”的类别是数字,属性(值)是123.4

语法分析:

语法分析指将词法分析得到的标记流(token)进行分析,组成事先定义好的有意义的语句,这与自然语言中句子的语法分析类似。通常可以用抽象语法树表示语法分析的结果,比如赋值语句:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    num = 123.4 * 3;

可以用这样一个抽象语法树来表示:

语义分析

程序的语义就是它的“意思”,程序的语义确定程序的运行方式。语义分析阶段通常包括声明和类型检查、计算需要的一些属性值等等。编译器在这个阶段中通常会维护一个叫做“符号表”的东西,保存变量的值、属性和名称。同样以

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    num = 123.4 * 3;

为例,假如我们是第一次在这里遇见“num”,就将num的名称字符串“num” 和当前计算出来的初始值370.2插入符号表中,当下次再遇见num时。我们就知道它是一个数字,已经初始化完毕,并且当前值是370.2;

目标代码生成:

在语义分析之后,我们就可以将语法分析和语义分析的结果(通常是抽象语法树)转换成可执行的目标代码。

解释器与编译器仅在代码生成阶段有区别,而在前三个阶段如词法分析、语法分析、语义分析基本是一样的。

当然,已经有许多工具可以帮助我们处理阶段1和2,如 flex 用于词法分析,bison 用于语法分析;但它们的功能都过于强大,屏蔽了许多实现上的细节,对于学习构建编译器帮助不大,所以我们要完全手写这些功能。

(实际上完成一个可以跑起来的解释器并不难,而且还是一件很有成就感的事,不是嘛?)

tryC编译器的设计:

从上面可以看出,我们的tryC解释器需要这三个模块:

  1. 词法分析
  2. 语法分析
  3. 语义分析和解释执行

需要这两个数据结构(用来在阶段之间保存或传递值):

  1. token,用来在词法分析和语法分析之间传递标记;
  2. 符号表,保存语义分析阶段遇见的变量值,使用一个数组存储;

在了解过这些之后,我们先来大概看看代码的基本结构:

(从上往下在代码中依次对应,“…”表示省略的相关代码,在后续文章中会详细讲解)

  • 数据结构的声明部分:token类型、符号表结构:
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#include <stdio.h>
...

typedef struct symStruct {  
    int type;                
    char name[MAXNAMESIZE];    
    double value;             
    ..........
} symbol;
symbol symtab[SYMTABSIZE];          // 符号表
int symPointer = 0;             

char* src, * old_src;               // 当前分析的源代码位置指针

// tokens 的枚举类型
enum {
    Num = 128, Char, Str, Array, Func,
    ........
};

// token 的表示形式
int token;                      // current token type
union tokenValue {
    symbol* ptr;               
    double val;                 
} token_val;
  • 词法分析的两个函数:
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 获取输入流中的下一个记号:
void next() {
    char* last_pos;

    while (token = *src) {
        ++src;
        if(token == AAA ){
            .....
        }else if(token == BBB ){
            .....
        }
    }
}

// 匹配一个记号,并获取下一个token:
void match(int tk) {
    if (token == tk) {
        next();
    }
    else {          // 遇到了一个错误
        exit(-1);
    }
}
  • 语法分析和语义分析,以及执行阶段:使用递归下降法实现(后面会再提到什么是递归下降法啦)
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 计算表达式的值:
double expression(){}
double factor(){}
double term(){}

// 计算布尔表达式的值:
int boolOR();
int boolAND();
int boolexp();

// 执行一个语句;
double statement();

// 执行一个函数:
double function();
  • main() 函数,代码的入口,并
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
int main(int argc, char** argv)
{   
    // 往符号表里面添加关键词
    int i, fd;
    src = "array func else if return while print puts read";
    for (i = Array; i <= Read; ++i) {
        next();
        symtab[symPointer -1].type = i;
    }

    src = old_src = (char*)malloc(POOLSIZE); // 分配空间

    ....

    fd = open(*argv, 0);        // 打开读取文件

    read(fd, src, POOLSIZE - 1);

    src[i] = 0; 
    close(fd);
    next();
    while (token != 0) {        // 一条一条语句执行
        statement();
    }
    return 0;
}

重要概念

  • 编译器/解释器
  • 词法分析
  • 语法分析
  • 语义分析
  • token
  • 符号表

可参照github源码查看

https://github.com/yunwei37/tryC

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2020-05-05,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
用c语言手搓一个600行的类c语言解释器: 给编程初学者的解释器教程(4)- 语法分析1:EBNF和递归下降文法
用c语言手搓一个600行的类c语言解释器: 给编程初学者的解释器教程(1)- 目标和前言 用c语言手搓一个600行的类c语言解释器: 给编程初学者的解释器教程(2)- 简介和设计 用c语言手搓一个600行的类c语言解释器: 给编程初学者的解释器教程(3)- 词法分析 用c语言手搓一个600行的类c语言解释器: 给编程初学者的解释器教程(4)- 语法分析1:EBNF和递归下降文法 用c语言手搓一个600行的类c语言解释器: 给编程初学者的解释器教程(5)- 语法分析2: tryC的语法分析实现 用c语言手搓一个600行的类c语言解释器: 给编程初学者的解释器教程(6)- 语义分析:符号表和变量、函数
云微
2023/02/11
5950
用c语言手搓一个600行的类c语言解释器: 给编程初学者的解释器教程(1)- 目标和前言
用c语言手搓一个600行的类c语言解释器: 给编程初学者的解释器教程(1)- 目标和前言 用c语言手搓一个600行的类c语言解释器: 给编程初学者的解释器教程(2)- 简介和设计 用c语言手搓一个600行的类c语言解释器: 给编程初学者的解释器教程(3)- 词法分析 用c语言手搓一个600行的类c语言解释器: 给编程初学者的解释器教程(4)- 语法分析1:EBNF和递归下降文法 用c语言手搓一个600行的类c语言解释器: 给编程初学者的解释器教程(5)- 语法分析2: tryC的语法分析实现 用c语言手搓一个600行的类c语言解释器: 给编程初学者的解释器教程(6)- 语义分析:符号表和变量、函数
云微
2023/02/11
5170
用c语言手搓一个500+行的类c语言解释器: 给编程初学者的解释器教程(2)- 简介和设计
通常我们说的 “编译器” 是一种计算机程序,负责把一种编程语言编写的源码转换成另外一种计算机代码,后者往往是以二进制的形式被称为目标代码(object code)。这个转换的过程通常的目的是生成可执行的程序。
云微
2020/06/05
1.7K0
用c语言手搓一个600行的类c语言解释器: 给编程初学者的解释器教程(5)- 语法分析2: tryC的语法分析实现
用c语言手搓一个600行的类c语言解释器: 给编程初学者的解释器教程(1)- 目标和前言 用c语言手搓一个600行的类c语言解释器: 给编程初学者的解释器教程(2)- 简介和设计 用c语言手搓一个600行的类c语言解释器: 给编程初学者的解释器教程(3)- 词法分析 用c语言手搓一个600行的类c语言解释器: 给编程初学者的解释器教程(4)- 语法分析1:EBNF和递归下降文法 用c语言手搓一个600行的类c语言解释器: 给编程初学者的解释器教程(5)- 语法分析2: tryC的语法分析实现 用c语言手搓一个600行的类c语言解释器: 给编程初学者的解释器教程(6)- 语义分析:符号表和变量、函数
云微
2023/02/11
3850
用c语言手搓一个500+行的类c语言解释器: 给编程初学者的解释器教程(3)- 词法分析
帮编译器执行词法分析阶段的模块,就叫词法分析器啦。词法分析器能够对源码字符串做预处理,以减少语法分析器的复杂程度。
云微
2020/06/05
1.4K0
用c语言手搓一个500+行的类c语言解释器: 给编程初学者的解释器教程(1)- 目标和前言
这一系列教程希望面向初学者,使用c语言手工实现一个简单的解释器来玩,不需要您掌握除了c语言以外的其他前置知识,也不需要您学习过编译原理的相关知识(当然如果能对简单的数据结构有所了解的话会更好,比如树、栈等)。
云微
2020/06/05
1.5K0
用c语言手搓一个500+行的类c语言解释器: 给编程初学者的解释器教程(4)- 语法分析1
我们来看看两个概念,EBNF和递归下降文法,以及如何用这两个方法来计算tryC中的表达式。
云微
2020/06/05
1.8K0
用c语言手搓一个500+行的类c语言解释器: 给编程初学者的解释器教程(6)- 语义分析
这一部分,我们再回过头来看看变量、函数是怎样存储和处理的、以及符号表是怎样构建的。
云微
2020/06/05
1.2K0
编译器架构 ( Compiler Architecture )
简单讲,编译器就是将“一种语言(通常为高级语言)”翻译为“另一种语言(通常为低级语言)”的程序。一个现代编译器的主要工作流程:
一个会写诗的程序员
2021/06/29
1.9K0
【C语言】编译和链接深度剖析
本小节,我们学习翻译环境和运行环境,其中我们将学习编译环境的4个阶段:预编译,编译(词法分析,语法分析,语义分析),汇编,链接,文章干货满满!学习起来吧😃!
学习起来吧
2024/02/29
2130
【C语言】编译和链接深度剖析
【C语言】编译与链接
2.1.1翻译环境是由编译与链接两个大过程组成的,编译又可以分为预处理(预编译)、编译、汇编三个过程。
ZLRRLZ
2024/12/13
1670
【C语言】编译与链接
C语言编译和链接超详解
第1种是翻译环境,在这个环境中源代码被转换为可执行的机器指令(二进制指令) 第2种是执行环境,它用于实际执行代码。
fhvyxyci
2024/09/24
1500
C语言编译和链接超详解
C语言---编译和链接
那翻译环境是怎么将源代码转换为可执⾏的机器指令的呢?这⾥我们就得展开开讲解⼀下翻译环境所
Undoom
2024/09/23
1590
C语言---编译和链接
【C语言】编译和链接(编译环境和运行环境)
   上面讲到了,翻译环境是用来将源代码转换为可执⾏的机器指令(⼆进制指令),生成可执行程序的,那么它到底是怎么将源代码转换成可执行的机器指令,又是怎么把机器指令生成可执行程序呢?我们一起来学习一下    翻译环境是由编译和链接两个⼤的过程组成的,⽽编译⼜可以分解成:预处理(有些书也叫预编译)、编译、汇编三个过程,接下来我们就来学习它们
TANGLONG
2024/11/19
2380
【C语言】编译和链接(编译环境和运行环境)
夯实基础,编译器原理前端部分浅析
携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第26天,点击查看活动详情
掘金安东尼
2022/09/22
5980
夯实基础,编译器原理前端部分浅析
为什么编译原理被称为龙书?
这本书很有意思,它的书名是 《Compilers: Principles, Techniques, and Tools》,也就是编译器的原则、技术和工具。但它却画出了一个恐龙和骑士,恐龙身上写的是 Complexity of Compiler Design,也就是复杂的编译器设计,骑士的盾上写的是 Syntax Directed Granslation,也就是语法翻译。骑士的剑上看的不是很清楚,我猜测应该是优秀的编译器的意思。这是征服复杂性的隐喻。优秀的编译器会直接征服复杂的编译,复杂的编译设计永远无法攻破语法翻译。
cxuan
2020/07/17
1.4K0
【C语言篇】编译和链接以及预处理介绍(上篇)
本篇博客只是针对上层应用对编译链接过程进行一个笼统的介绍,让C语言初学者对于编译和链接有一个基本的印象轮廓,具体的内容学校计算机专业会有专门这样一节课,需要学的东西还是很多的哈😘
半截诗
2024/10/09
1750
【C语言篇】编译和链接以及预处理介绍(上篇)
C语言从入门到实战——编译和链接
在编译和链接过程中,可以使用不同的编译器和链接器来完成这些步骤。常见的C语言编译器包括GCC、Clang和MSVC等,而常见的链接器包括GNU ld和Microsoft Linker等。
鲜于言悠
2024/03/20
2310
C语言从入门到实战——编译和链接
用c语言手搓一个500+行的类c语言解释器: 给编程初学者的解释器教程(5)- 语法分析2
布尔表达式和算术表达式的代码之前已经讲过了,这里看看statement的实现,以及如何在语法分析的同时解释执行:
云微
2020/06/05
8600
《软考高分必备!程序语言设计6分速通:编译VS解释全拆解+函数调用通关秘籍,词法/语法/语义三阶冲刺!》【附真题解析】
本文旨在从题目出发,只保留真题考到的相关的概念,都是浓缩过的知识点,所以简练而精髓,每一个知识点后都附带真题解析,各位小伙伴可以自行点开观看,方便复习。
摘星.
2025/05/20
1270
《软考高分必备!程序语言设计6分速通:编译VS解释全拆解+函数调用通关秘籍,词法/语法/语义三阶冲刺!》【附真题解析】
推荐阅读
用c语言手搓一个600行的类c语言解释器: 给编程初学者的解释器教程(4)- 语法分析1:EBNF和递归下降文法
5950
用c语言手搓一个600行的类c语言解释器: 给编程初学者的解释器教程(1)- 目标和前言
5170
用c语言手搓一个500+行的类c语言解释器: 给编程初学者的解释器教程(2)- 简介和设计
1.7K0
用c语言手搓一个600行的类c语言解释器: 给编程初学者的解释器教程(5)- 语法分析2: tryC的语法分析实现
3850
用c语言手搓一个500+行的类c语言解释器: 给编程初学者的解释器教程(3)- 词法分析
1.4K0
用c语言手搓一个500+行的类c语言解释器: 给编程初学者的解释器教程(1)- 目标和前言
1.5K0
用c语言手搓一个500+行的类c语言解释器: 给编程初学者的解释器教程(4)- 语法分析1
1.8K0
用c语言手搓一个500+行的类c语言解释器: 给编程初学者的解释器教程(6)- 语义分析
1.2K0
编译器架构 ( Compiler Architecture )
1.9K0
【C语言】编译和链接深度剖析
2130
【C语言】编译与链接
1670
C语言编译和链接超详解
1500
C语言---编译和链接
1590
【C语言】编译和链接(编译环境和运行环境)
2380
夯实基础,编译器原理前端部分浅析
5980
为什么编译原理被称为龙书?
1.4K0
【C语言篇】编译和链接以及预处理介绍(上篇)
1750
C语言从入门到实战——编译和链接
2310
用c语言手搓一个500+行的类c语言解释器: 给编程初学者的解释器教程(5)- 语法分析2
8600
《软考高分必备!程序语言设计6分速通:编译VS解释全拆解+函数调用通关秘籍,词法/语法/语义三阶冲刺!》【附真题解析】
1270
相关推荐
用c语言手搓一个600行的类c语言解释器: 给编程初学者的解释器教程(4)- 语法分析1:EBNF和递归下降文法
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验