编译器
文章平均质量分 73
qq_34851605
这个作者很懒,什么都没留下…
展开
-
动手实现编译器(十七)——局部变量
上一节中,我们已经实现了逻辑运算和负数,在本节中,我们将要实现比较难的局部变量。现在,我们所有的变量对所有函数都是全局可见的。我们想添加一个本地范围对于变量,这样每个函数都有自己的变量,不能被其他函数看到。此外,在递归函数的情况下,同一个函数的每个实例都有自己的局部变量。要为同一函数的多个实例创建本地作用域,为了提供一个地方来存储函数的参数,我们需要一个堆。让我们从局部变量和全局变量之间的区别开始。全局变量必须对所有函数可见,但局部变量只是对一个函数可见。SubC使用一个符号表来存储有关本地和全局变原创 2021-07-06 00:22:08 · 988 阅读 · 1 评论 -
动手实现编译器(十六)——逻辑运算
在上一节中,我们实现了困难的数组定义部分;在这一节中,我们着手实现比较简单的逻辑运算,此外我们也会实现识别负数。SysY语言中包含的逻辑运算符有:一元逻辑运算符 !二元逻辑运算符 &&和||它们语法定义如下单目运算符: UnaryOp → ‘!’ 注:’!'仅出现在条件表达式中逻辑与表达式: LAndExp → EqExp | LAndExp ‘&&’ EqExp逻辑或表达式: LOrExp → LAndExp | LOrExp ‘||’ LAndExp原创 2021-07-04 21:33:27 · 622 阅读 · 2 评论 -
动手实现编译器(十五)——数组(一)
在上一节中,我们实现了注释和变量初始化的功能;在这一节中,我们来实现数组。先来看看,我们要实现的具体功能: int ary[5]; // 定义数组 ary[3]= 63; // 表达式给数组元素赋值 int a; a = ary[4]; // 数组元素赋值变量具体地讲,我们将实现:具有固定大小但没有初始化列表的数组声明数组索引作为赋值中的右值数组索引作为赋值中的左值数组的SysY语法是数组定义 VarDef原创 2021-07-02 01:12:10 · 898 阅读 · 1 评论 -
动手实现编译器(十四)——注释和初始化
在上一节中,我们探讨了左结合和右结合,实现了a=b=3这一类的语句,在这一节中,我们将会实现注释和定义变量时赋值。SysY 语言中注释的规范与 C 语言一致,如下:单行注释:以序列//开始,直到换行符结束,不包括换行符。多行注释:以序列/*开始,直到第一次出现*/时结束,包括结束处*/。修改词法分析这是一个比较简单的问题,我们只需要识别出//、/*和*/然后跳过其中的内容即可。 case '/': c = get_nextchr()原创 2021-06-29 22:36:14 · 336 阅读 · 0 评论 -
动手实现编译器(十三)——左结合和右结合
上一节中,我们实现了真正的全局变量,在这一节中,我们要重新考虑左值和右值的关系。所以,我们可能需要删除我们已经编写的代码并重新编写它以使其更通用,或者修复缺点。我们现在实现的代码:int x;x = 12;这实现得很好,但我知道我们最终必须支持在赋值语句的左侧使用数组元素,例如a[0] = 13;为此,我们必须重新讨论左值和右值。左值是绑定到特定位置的值,而右值是不绑定的值。 左值是持久的,因为我们可以在未来的指令中检索它们的值。另一方面,右值是暂时的:一旦它们使用完毕,我们就可以丢弃它们原创 2021-06-29 21:02:21 · 968 阅读 · 1 评论 -
动手实现编译器(十二)——全局变量
在上一节中,我们实现了函数的调用和返回,在这一节中,我们来处理全局变量。当我们把变量定义的语句放入Block语句分析函数中,我们只能分析Block中的变量定义,即不能处理全局变量。重构变量和常量的汇编我在上一节说过,随着功能的增加,我们会不断修改代码,使功能更加完善和效率更高。首先是ARM汇编中直接MOV操作的立即数最大为11位,超过十一位的立即数将会先储存在内存中,在载入寄存器。我们对立即数载入函数进行修改:#define MAXINTS 1024 // 大整数储存上限int In原创 2021-06-28 00:47:36 · 737 阅读 · 1 评论 -
动手实现编译器(十一)——函数功能(第二部分)
上一节中,我们实现了函数的定义,在这一节中,我们会实现调用函数并返回一个值。具体来说:定义一个函数调用一个目前无法使用的单一值的函数从函数返回一个值将函数调用用作语句和表达式确保void函数永远不会返回值和非void函数必须返回一个值函数调用的SysY语法定义:语句: Stmt → Ident ‘(’ [FuncRParams] ‘)’ ‘;’ | ‘return’ [Exp] ‘;’该函数有一个名称,后跟一对括号,在括号中必须只有一个参数。它既可以作为表达式又可以作为独立语句。修原创 2021-06-21 10:12:29 · 402 阅读 · 1 评论 -
动手实现编译器(十)——函数功能(第一部分)
在上一节中,我们实现了WHILE循环,因为SysY语言没有FOR语句,所以在这一节中,我们将进一步实现简单函数功能。我们在此过程中必须处理的事有:数据类型:char、int、long 等每个函数的返回类型每个函数的参数数量函数局部变量与全局变量对于目前的我们来说,这太难了。所以我们在这里要做的是达到我们可以声明不同的函数。只有我们生成的可执行文件中的 main() 函数会运行,但我们将有能力为多个功能生成代码。首先,我们来看一下简单的函数SysY语法:函数定义: FuncDef → Fu原创 2021-06-19 17:24:30 · 397 阅读 · 0 评论 -
动手实现编译器(九)——WHILE语句
在上一节中,我们实现了IF语句,在这一节中,我们将进一步实现WHILE循环。从某种意义上说,WHILE循环非常类似于IF语句没有“else”子句,除了总是跳回顶部的循环。WHILE语句的SysY语法如下Stmt → ‘while’ ‘(’ Cond ‘)’ Stmt处理流程:Lstart: 条件 如果条件为假跳到Lend 执行语句 跳转到LstartLend:这意味着我们可以借用扫描、解析和代码生成我们与 IF 语句一起使用的结构并进行了一些小的更改还要处理 WHIL原创 2021-06-18 20:02:30 · 579 阅读 · 0 评论 -
动手实现编译器(八)——IF条件语句
在上一节中,我们实现了比较运算符的计算,现在,我们可以容易地实现IF条件语句。首先我们看IF语句的SysY语言的定义:语句: Stmt → LVal ‘=’ Exp ‘;’ | ‘if’ '( Cond ‘)’ Stmt [ ‘else’ Stmt ]修改词法分析首先,我们要增加新的单词类型,表示"{","}","(",")",“if”,"else"六种符号。// 单词类型enum{ T_EOF, T_ADD, T_SUB, T_MUL, T_DIV, T_MOD, T_E原创 2021-06-18 11:52:08 · 1802 阅读 · 1 评论 -
动手实现编译器(七)——比较运算符
上一节中,我们已经实现了全局变量的声明、赋值和计算,本节中我们将会实现计较运算符的计算。==, !=, <, >, <=, >=修改词法分析首先增加新的单词类型// 单词类型enum{ T_EOF, T_ADD, T_SUB, T_MUL, T_DIV, T_MOD, T_EQ, T_NE, T_LT, T_GT, T_LE, T_GE, T_INT, T_SEM, T_PRINT, T_EQU, T_IDENT, T_KEYINT};我们原创 2021-06-17 00:35:19 · 446 阅读 · 1 评论 -
动手实现编译器(六)——实现全局变量
我们在上一节中实现了对语句的编译,在这一节中,我们希望向语句中加入变量。实现以下语句:int a;int b;int c;int d;int e;int f;int g;a = 2;b = 3;c = 4;d = 5;e = 6;f = 7;g = 8;print a + b * c / d % e - f + g;这需要变量有以下功能:声明变量使用变量获取存储值给变量赋值相关语法定义变量声明: VarDecl → ‘int’ Ident ‘;’变量赋值:原创 2021-06-15 20:43:54 · 663 阅读 · 1 评论 -
动手实现编译器(五)——实现语句
在上一节,我们已经实现了一条表达式的计算,在这一节中,我们要真正实现语句。我们来看看SysY语言中对语句的定义:语句: Stmt → LVal ‘=’ Exp ‘;’ | [Exp] ‘;’ | Block| ‘if’ '( Cond ‘)’ Stmt [ ‘else’ Stmt ]| ‘while’ ‘(’ Cond ‘)’ Stmt| ‘break’ ‘;’ | ‘continue’ ‘;’| ‘return’ [Exp] ‘;’为了给明显的输出结果,我们增加一条语法:打印结果:p原创 2021-06-15 00:33:10 · 900 阅读 · 1 评论 -
动手实现编译器(四)——目标代码生成器
在前几节中,我们实现了词法分析器、语法分析器、语义分析器和测试器,可以正确处理一条加减乘除取模运算语句。在这一节中,我们将用目标代码生成器替换测试器,实现真正的编译器。测试器/*测试器代码*/// AST操作符char *ASTop[] = {"+", "-", "*", "/", "%"};// 给定一个AST,返回一个表达式int interpretAST(struct ASTnode *n){ int leftval, rightval; // 获得左、右子树值原创 2021-06-14 20:47:21 · 2310 阅读 · 0 评论 -
动手实现编译器(三)——语义分析
我们在上一节中看到,语法分析器可以识别SysY语言的部分简单语法,并检查编译器的输入是否符合该语法,但不能处理不同的运算符优先级。因为,该代码将所有运算符都视为具有相同的优先级。为了解决这个问题,我们必须在语法分析器中添加代码来执行操作符优先级。至少有两种方法可以做到这一点:在语言的语法中明确运算符优先级使用运算符优先级表影响现有的语法分析器我们来看SysY语言中对于加减乘除取余的语法定义:加减表达式 :AddExp → MulExp | AddExp (’+’ | ‘−’) MulExp原创 2021-06-13 00:16:53 · 2309 阅读 · 1 评论 -
动手实现编译器(二)——语法分析
在这一节中,将介绍语法分析器。在上一节的词法分析上实现SysY语言语法分析,来解析类似2 - 15 / 7 + 3 * 8 T_EOF(T_EOF表示终结符)由于SysY语言的语法是递归的,因此可以递归解析它。可以编写如下所示的伪代码:递归解析函数() { 扫描并检查第一个令牌是一个数字。如果不是,则返回错误。 获取下一个单词。 如果到达输入的末尾,则返回结果。 否则,调用递归解析函数()。}抽象语法树为了进行语义分析,我们需要代码来解释识别的输入,或将其转换为另一种格式,例如汇编代原创 2021-06-12 00:03:39 · 4524 阅读 · 5 评论