南京航空航天大学《编译原理》课程设计实验报告书

本文主要是介绍南京航空航天大学《编译原理》课程设计实验报告书,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

作者:shmily

文章目录

    • C-语言的语法图描述
    • 系统设计
      • 系统亮点
        • 符号表的实现
        • 中间代码生成
      • 系统的总体结构
      • 主要功能模块的设计
      • 系统运行流程
    • 系统实现
      • 系统主要函数说明(主要功能、输入\输出、实现思想)
        • cminus.l
        • cminus.y
        • buildSymtab
        • st_insert()、st_create()
        • st_lookup()、st_lookup_top()
        • typeCheck()
        • codeGen()
        • insertQuad()
        • cGen()
    • 课程设计心得
    • 源码

C-语言的语法图描述

在这里插入图片描述

系统设计

系统亮点

符号表的实现

符号表采用了哈希表的形式,可以方便地查找、插入和删除,但是问题也随之而来,就是符号的作用于较难跟踪。很有可能同一名称的变量在不同作用于出现,如果孤立地对待每一个变量便会出现变量冲突。因此我们的符号表将作用域做了栈式处理,例如下图:

在这里插入图片描述

再将栈中每一个元素,即每一个作用域做延伸,对每一个作用域建立一个哈希表,将范围缩小。这样一来可以对每一个变量框在一个作用域中进行跟踪。总体数据结构如下:

在这里插入图片描述

中间代码生成

我们的中间代码生成运用一遍扫描的方法自下而上归约,但是和课本的方法有出入,进行了一些改变。首先,建立一个链表存储所有的生成的四元式,每个四元式的本质是一个结构体。其中,在对if-else或是while这种需要回填的部分处理时,先对判断条件进行判断,结果存在一个临时变量t之中,这个变量的值非0即1.

当面临if语句规约时,判断的是t的值,真出口就是继续执行的下一条语句,执行完语句之后,我们生成了又一个临时变量L,并且新增一个操作叫做label,它用来指示整个if-else语句的结尾,这个label四元式是在控制语句的结尾,当生成(label,L2,-,-)的同时,顺序查找四元式链表中j_if_false后紧跟的(j,-,-,-),并将其填为(j,L2,-,-),代表无条件跳转到L2。

对于假出口的处理同理,只不过是在else语句开始之前就生成一个(label,L1,-,-),记下标号,并且在生成之后顺序查找四元式链表,找到j_if_false开头的代码进行回填。这样,真假出口的回填就完成了。

其他的四元式根据不同节点的类型直接生成不同的四元式,最后将四元式链表输出到文件当中即可。
在这里插入图片描述

系统的总体结构

结构框图如图所示,共分为五大部分以及两个辅佐部分,五大部分为词法分析、语法分析、建立符号表、类型检查和中间代码,辅佐部分为符号表和语法树。

在这里插入图片描述

主要功能模块的设计

**词法分析和语法分析:**利用flex & bison工具实现,在cminus.l文件中写好词法规则和getToken函数,在cminus.y文件中写好BNF语法和其他相关函数即可,flex和bison可以帮助我们生成lex.yy.c文件和.tab.文件。

**语义分析:**生成语法分析树和符号表,借助这两个数据结构分析语义。

**中间代码生成:**通过一遍扫描和回填技术实现中间代码生成。

系统运行流程

C-minus编译器运行于Linux系统,在/compiler文件下执行sh脚本即可编译运行整个项目,例如测试gcd.c文件:

./compiler.sh ../testcase/gcd.c

之后在/testcase文件中可以查看该测试样例对应生成的中间代码,记录在一个.txt文件中。

在这里插入图片描述

系统共分为三个部分:词法分析器、语法分析器、语义分析与中间代码产生器。

首先,编译器会对输入的文件进行词法分析,分割成一个个的单词符号,其次,进行语法分析,识别出各类语法单位,判断输入串是否构成语法上正确的“程序”,最后按照语义规则对语法分析器归约出的语法单位进行语义分析并把他们翻译成一定形式的中间代码。

系统实现

系统主要函数说明(主要功能、输入\输出、实现思想)

cminus.l

这一文件的主要功能为flex分析器的文件。第一部分为定义,flex工具在处理这一部分的时候,会将第一部分的所有代码原封不动的插入到 lex.yy.c(词法分析代码)中,我们在这一部分中插入了程序需要用到的头文件等内容。第二部分是词法规则部分:正则表达式+代码片段。当匹配相对应的正则表达式时,这些代码片段就会被执行。我们的代码片段为一个单词符号的编码。最后一个部分包括辅助函数,它们用于在第2个部分被调用且不在任何地方被定义的辅助程序。

cminus.y

这一文件的主要功能是产生语法分析代码。首先是定义部分:定义部分包括bison需要用来建立分析程序的有关记号、数据类型以及文法规则的信息,还包括了一些头文件。规则部分:包括修改的BNF格式中的文法规则以及将在识别出相关的文法规则时被执行的C代码中的动作。我们根据每一条产生式执行不同的语义动作,例如生成节点、赋上相应属性等等。最后是用户自定义函数部分,我们定义了几个插入节点的函数,可以和语义动作对应起来。最后这个文件会被建立成两个.tab.程序,实现语法分析和语法树的建立。

具有一定的检错能力:例如对这样一行代码

rem = x-(div*10;

缺少匹配的右括号,在编译器中便停在了这一行的;处,并报语法错误。

在这里插入图片描述

buildSymtab

Cminus的语义分析器在analyze.csymtab.c中,其对应的主要功能,analyse.c是用于语义分析本身,而symtab.c则是用于生成其对应的符号表。

进入语义分析部分的代码在main.c中:

#if !NO_ANALYZEif (! Error) {if (TraceAnalyze) fprintf(listing, "\nBuilding the symbol table...\n");buildSymtab(syntaxTree);if (TraceAnalyze) fprintf(listing, "\nChecking type...\n");typeCheck(syntaxTree);if (TraceAnalyze) fprintf(listing, "\nType check completed!\n");}

在语义分析之前,编译器最开始的输入是一段代码,经过词法分析,输出的是词法单元,从而被语法分析单元所识别;语法分析的输入是一个个词法单元,通过分析这些词法单元之间的逻辑,利用递归下降等方法,形成一棵语法树,并将语法树的根结点存储在一个TreeNode类中,从而通过根结点就可以实现对于整个语法树的遍历(一般是前序遍历);之后,来到了语义分析部分,语义分析的输入是一个语法树,这里我们的输入是根结点;语义分析的输出,则是符号表和语法报错信息。

符号表的意义在于,分析代码中所有的声明,比如变量函数等内容;而语法报错信息,则会通过语法树结点关系,检测相邻词法单元是否符合文法规则:比如,int 1和int a两种输入,在语法分析阶段均可通过,但是在语义分析阶段,int 1会被识别为一个错误,因为根据语法规则,int是一个声明,声明后面只能跟着一个变量名ID,而词法单元1的属性是NUM,int后面是不允许接着一个NUM的。

函数buildSymtab构造符号,通过语法树的遍历构建。

/* Function buildSymtab constructs the symbol* table by preorder traversal of the syntax tree*/
void buildSymtab(TreeNode * syntaxTree) {globalScope = sc_create((char *) "ESCOPO_GLOBAL");sc_push(globalScope);traverse(syntaxTree, insertNode, afterInsertNode);sc_pop();sys_free();if(mainDeclaration == FALSE) {fprintf(listing, "Declaration Error: Undeclared main function\n");return;}if (TraceAnalyze) {fprintf(listing,"\nSymbol Table:\n");printSymTab(listing);}
}

该函数共分为四个步骤,首先调用sc_create()函数创建一个作用域栈,作用域栈用于储存一个符号的作用域,如果给出作用域名称作为参数,它将分配内存并填写每个属性。在初始化的时候,如果是全局变量,则它就是最大的全局作用域,如果不是,则把指针设置为该作用域所属的较大作用域的父作用域。
在这里插入图片描述

例如,名为main的作用域将global作为其父作用域。 在main中创建另一个作用域时,它以相同的方式堆叠在栈上。 当main结束时(遇到复合语句时),main作用域弹出并查看全局作用域中的其余TreeNodes。

Scope sc_create(char * funcName) {Scope newScope = (Scope) malloc(sizeof

这篇关于南京航空航天大学《编译原理》课程设计实验报告书的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/821562

相关文章

Redis主从/哨兵机制原理分析

《Redis主从/哨兵机制原理分析》本文介绍了Redis的主从复制和哨兵机制,主从复制实现了数据的热备份和负载均衡,而哨兵机制可以监控Redis集群,实现自动故障转移,哨兵机制通过监控、下线、选举和故... 目录一、主从复制1.1 什么是主从复制1.2 主从复制的作用1.3 主从复制原理1.3.1 全量复制

Redis主从复制的原理分析

《Redis主从复制的原理分析》Redis主从复制通过将数据镜像到多个从节点,实现高可用性和扩展性,主从复制包括初次全量同步和增量同步两个阶段,为优化复制性能,可以采用AOF持久化、调整复制超时时间、... 目录Redis主从复制的原理主从复制概述配置主从复制数据同步过程复制一致性与延迟故障转移机制监控与维

SpringCloud配置动态更新原理解析

《SpringCloud配置动态更新原理解析》在微服务架构的浩瀚星海中,服务配置的动态更新如同魔法一般,能够让应用在不重启的情况下,实时响应配置的变更,SpringCloud作为微服务架构中的佼佼者,... 目录一、SpringBoot、Cloud配置的读取二、SpringCloud配置动态刷新三、更新@R

Redis主从复制实现原理分析

《Redis主从复制实现原理分析》Redis主从复制通过Sync和CommandPropagate阶段实现数据同步,2.8版本后引入Psync指令,根据复制偏移量进行全量或部分同步,优化了数据传输效率... 目录Redis主DodMIK从复制实现原理实现原理Psync: 2.8版本后总结Redis主从复制实

深入探索协同过滤:从原理到推荐模块案例

文章目录 前言一、协同过滤1. 基于用户的协同过滤(UserCF)2. 基于物品的协同过滤(ItemCF)3. 相似度计算方法 二、相似度计算方法1. 欧氏距离2. 皮尔逊相关系数3. 杰卡德相似系数4. 余弦相似度 三、推荐模块案例1.基于文章的协同过滤推荐功能2.基于用户的协同过滤推荐功能 前言     在信息过载的时代,推荐系统成为连接用户与内容的桥梁。本文聚焦于

hdu4407(容斥原理)

题意:给一串数字1,2,......n,两个操作:1、修改第k个数字,2、查询区间[l,r]中与n互质的数之和。 解题思路:咱一看,像线段树,但是如果用线段树做,那么每个区间一定要记录所有的素因子,这样会超内存。然后我就做不来了。后来看了题解,原来是用容斥原理来做的。还记得这道题目吗?求区间[1,r]中与p互质的数的个数,如果不会的话就先去做那题吧。现在这题是求区间[l,r]中与n互质的数的和

maven 编译构建可以执行的jar包

💝💝💝欢迎莅临我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 推荐:「stormsha的主页」👈,「stormsha的知识库」👈持续学习,不断总结,共同进步,为了踏实,做好当下事儿~ 专栏导航 Python系列: Python面试题合集,剑指大厂Git系列: Git操作技巧GO

hdu4407容斥原理

题意: 有一个元素为 1~n 的数列{An},有2种操作(1000次): 1、求某段区间 [a,b] 中与 p 互质的数的和。 2、将数列中某个位置元素的值改变。 import java.io.BufferedInputStream;import java.io.BufferedReader;import java.io.IOException;import java.io.Inpu

hdu4059容斥原理

求1-n中与n互质的数的4次方之和 import java.io.BufferedInputStream;import java.io.BufferedReader;import java.io.IOException;import java.io.InputStream;import java.io.InputStreamReader;import java.io.PrintWrit

STM32(十一):ADC数模转换器实验

AD单通道: 1.RCC开启GPIO和ADC时钟。配置ADCCLK分频器。 2.配置GPIO,把GPIO配置成模拟输入的模式。 3.配置多路开关,把左面通道接入到右面规则组列表里。 4.配置ADC转换器, 包括AD转换器和AD数据寄存器。单次转换,连续转换;扫描、非扫描;有几个通道,触发源是什么,数据对齐是左对齐还是右对齐。 5.ADC_CMD 开启ADC。 void RCC_AD