2024-06-23 编译原理实验3——语义分析

文章目录

    • 一、实验要求
    • 二、实验设计
    • 三、实验结果
    • 四、附完整代码

补录与分享本科实验,以示纪念。

一、实验要求

基于前面的实验,编写一个程序对使用 C—语言书写的源代码进行语义分析,输出语义分析中发现的错误(涉及 17 种错误类型)并完成实验报告,实验中主要使用 C 语言。

  • 基本要求
    a. 对程序进行语法分析,输出语法分析结果;
    b. 能够识别多个位置的语法错误。
  • 附加要求
    a. 修改假设3在文法中加入函数声明(需要修改文法)并能够检查函数声明涉及的两种错误:函数声明了但没定义、函数多次声明冲突。
    b. 修改假设 4 在假设“变量的定义可受嵌套作用域的影响,外层语句块中定义的变量可以在内层语句块中重复定义,内层语句块中定义的变量到了外层语句块中就会消亡,不同函数体内定义的局部变量可以相互重名”。
    c. 修改前面的C–语言假设5,将结构体间的类型等价机制由名等价改为结构等价。在新的假设5下,完成对错误类型1-17的检查。

二、实验设计

一、文法可视化的建立,方便后续进行语义分析。

在这里插入图片描述
二、sematic.c文件

bool dealWithProgram(Node *node);bool dealWithExtDefList(Node *node);bool dealWithExtDef(Node *node);bool dealWithSpecifier(Node *node, ValueTypes *type, char **name);bool dealWithTYPE(Node *node, ValueTypes *type);bool dealWithStructSpecifier(Node *node, ValueTypes *type, char **name);bool dealWithTag(Node *node, char **name);bool dealWithOptTag(Node *node, char **name);bool dealWithExtDecList(Node *node, ValueTypes *type, char **name);bool dealWithVarDec(Node *node, Symbol *s);bool dealWithDefList(Node *node, Symbol *s);bool dealWithDef(Node *node, Symbol *s);bool dealWithDecList(Node *node, Symbol *s, ValueTypes *type, char **name);bool dealWithDec(Node *node, Symbol *s, Symbol *field);bool dealWithFunDec(Node *node, Symbol *s);bool dealWithVarList(Node *node, Symbol *s);bool dealWithParamDec(Node *node, Symbol *s);bool dealWithCompSt(Node *node);bool dealWithStmtList(Node *node);bool dealWithStmt(Node *node);bool dealWithExp(Node *node, ExpType *expType);bool dealWithArgs(Node *node, ParaType *parameters);

语义分析需要对每个匹配的产生式进行分析,因此需要写专门的函数进行操作。每个函数的操作均不一样,但也拥有相同的操作:

bool checkNode(Node *node, Types type) {if (node == NULL) {addLogNullNode(type);return false;}else if (node->type != type) {addLogTypeDismatch(type);return false;}addLogStartDealing(type);return true;
}bool hasBrothers(Node *node, int n, ...) {va_list vaList;va_start(vaList, n);Types next;for (int i = 0; i < n; ++i) {next = va_arg(vaList, Types);if (node == NULL || next != node->type) return false;node = node->brother;}return node == NULL;
}

checkNode函数检查每个结点是否规范,hasBrothers函数判断某个节点是否只拥有若干个指定的兄弟。
在每个函数中,基本实现为:
(1)判断结点是否合法;
(2)检查孩子结点
(3)匹配文法并做出相应操作
(4)返回操作是否成功
例如:

bool dealWithProgram(Node *node) {if (checkNode(node, _Program) == false) return false;Node *c = node->child;if (c == NULL) {addLogNullChild(_Program);return false;}if (hasBrothers(c, 1, _ExtDefList)) {return dealWithExtDefList(c);}else {addLogWrongChild(_Program);return false;}
}

三、log.c文件
采用单独的日志文件进行输出。我们将需要输出的消息存储在一个消息链表里,在分析完文件后顺序输出消息。链表结构为:

#define MESSAGE_LENGTH 256typedef struct Info {char *content;struct Info *next;
} Info;typedef struct Log {Info *head;Info *tail;
} Log;extern Log *SemanticError;
extern Log *SemanticAnalysisLog;

SemanticError存储语义错误消息,SemanticAnalysisLog存储分析日志,以供调试使用。
其中,日志包含的方法有:

Log *initLog();bool addLogInfo(Log *log, char *content);bool outputLog(Log *log, FILE *file);bool reportError(Log *log, int type, int line, char *message);

在程序中,封装了以下方法,以供显示日志消息:

bool addLogNullNode(Types type) {char message[MESSAGE_LENGTH];sprintf(message, "when dealing with %s, this %s is NULL.\n", typeToString(type), typeToString(type));addLogInfo(SemanticAnalysisLog, message);return true;
}bool addLogTypeDismatch(Types type) {char message[MESSAGE_LENGTH];sprintf(message, "when dealing with %s, this node is not %s.\n", typeToString(type), typeToString(type));addLogInfo(SemanticAnalysisLog, message);return true;
}bool addLogNullChild(Types type) {char message[MESSAGE_LENGTH];sprintf(message, "when dealing with %s, child node is NULL.\n", typeToString(type));addLogInfo(SemanticAnalysisLog, message);return true;
}bool addLogWrongChild(Types type) {char message[MESSAGE_LENGTH];sprintf(message, "when dealing with %s, this %s has a wrong child.\n", typeToString(type), typeToString(type));addLogInfo(SemanticAnalysisLog, message);return true;
}bool addLogStartDealing(Types type) {char message[MESSAGE_LENGTH];sprintf(message, "Start dealing with %s.\n", typeToString(type));addLogInfo(SemanticAnalysisLog, message);return true;
}bool addLogEmptyNode(Types type) {char message[MESSAGE_LENGTH];sprintf(message, "when dealing with %s, this %s is empty.\n", typeToString(type), typeToString(type));addLogInfo(SemanticAnalysisLog, message);return true;
}

四、main函数的改动
在main函数中,之前的操作不变,后面添加:如果词法分析和语法分析正确,则进行语义分析,并输出所有的信息:

int main(int argc, char **argv) {if (argc <= 1) {printf("pass filename to scanner\n");return -1;}else {FILE *f = fopen(argv[1], "r");if (!f) {printf("fopen failed:%s\n", argv[1]);return -1;}yyrestart(f);yyparse();FILE *semanticAnalysisLogFile = fopen("SemanticAnalysisLog.txt", "w");FILE *grammarTreeFile = fopen("grammarTree.txt", "w");FILE *hashTableFile = fopen("hashTable.txt", "w");if (syntax_correct && lexical_correct) {symbolTable = initializeHashSet(HASH_SIZE);SemanticAnalysisLog = initLog();SemanticError = initLog();printTree(root, 0, grammarTreeFile);dealWithProgram(root);checkFunction();outputLog(SemanticAnalysisLog, semanticAnalysisLogFile);outputHashTable(symbolTable, hashTableFile);outputLog(SemanticError, stdout);
//            printFunctions();}destroyTree(root);return 0;}
}

三、实验结果

  1. test1
int fun(){int i;
}int main(){float f = 0.;f = f + 0.1;fun();return 0;
}

该例子无词法、语法、语义错误,故无输出

  1. test2
int main(){int i = 0;int i;                  // error 3j = i + 1;              // error 1inc(i);                 // error 2
}int main(){                     // error 4return 3.5;             // error 8
}

成功检测出所有语义错误,其中第五行符合多个语义错误,将符合的每一个错误都输出出来了。

  1. test3
int main(){int i;float j = 9;            // error 5i = 3.7;                // error 510 = i;                 // error 6i + 3.7;                // error 7return j;               // error 8
}

这里面的float j=9; 这句我们并没有报错,因为我们在词法分析中认为9可以作为一种浮点数。此外,我们使用gcc编译器实测,float j=9;并不会报错。
其他错误均与示例相同。

  1. test4
int func(){}
float func2(int m, float n){}int main(){int i;float j[20];func();func(i);                // error 9func2(8, 8);            // error 9i[0];                   // error 10i();                    // error 11j[1.5] = 3.2;           // error 12
}

其中第12行实际上是不符合语法规范的,我们让语法检查对它“放行”,在语义检查中也能查到问题。

  1. test5
struct sa{int a;float b;int b;          // error 15
}c;
struct sf{int x;
};
struct sf{              // error 16int y;
};int main(){struct sk mm;   // error 17struct sa nn;int a[10];c.f;            //error 14c.b;a.b;			//error 13
}

由于没有实现作用域的附加要求,这里面在第17行多报了一个错。

  1. testfj1
int f1();               // error 18
int f2();
int f2(int f);          // error 19
float f2();
int f3(){int x;{int x;}
}
int f4(){int x;
}

我们实现了对函数冲突声明和只声明不定义的检查,并能成功报错。由于未实现嵌套作用域的附加要求,第7行和第10行多报了两个错。

  1. testfj2
struct A{float a;int c;
};
struct B{float b;float c;
};
struct C{float m; int n;};
int main(){struct A aa;struct B bb;struct C cc;aa = bb;aa = cc;
}

同样地,由于作用域的问题,我们多报了一个错。
在结构体赋值时,由于aa和bb不等价,因此不能赋值,我们给出了报错。
而aa和cc是结构等价的,我们实现了把名等价变成结构等价的附加功能,因此aa和cc之间的赋值没有报错。

四、附完整代码

github 链接:https://github.com/zheliku/byyl---Semantic-Analysis。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/32513.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

mac电脑守护神CleanMyMac2024免费版本下载

&#x1f31f; 电脑的守护神&#xff1a;CleanMyMac&#x1f47e; 亲爱的数码控们&#xff0c;是不是每次看到电脑上满满的垃圾文件和缓慢的运行速度就感到头疼呢&#xff1f;别怕&#xff0c;今天我要来给你们安利一款神奇的小帮手——CleanMyMac&#xff01;它可是我们电脑的…

【驱动篇】龙芯LS2K0300之LED驱动

实验目的 点亮龙芯开发板上面的用户自定义LED灯&#xff0c;编写LED驱动以及测试用例验证实现效果&#xff0c;LED位于开发板左下方&#xff08;靠近USB口&#xff09;第二个 原理图 LED通过电阻上拉至电源P3V3&#xff0c;低电平时LED被点亮 设备树 打开arch/loongarch/boo…

【职场人】如何与同事有效沟通

在职场中&#xff0c;沟通如同桥梁&#xff0c;连接着每一位职场人士的心灵与智慧。有效的沟通不仅能让工作更加顺畅&#xff0c;还能让团队关系更加和谐。那么&#xff0c;如何与同事进行有效沟通呢&#xff1f;下面&#xff0c;我将结合个人经验和一些幽默的比喻&#xff0c;…

音频数据集1--LJSpeech单人语音

LJ Speech Dataset 版本号: 1.1 , 文件大小: 2.6GB 1.简介 1. 1 内容简介 LJS是一个语音数据集&#xff0c;包含 13,100 个音频片段&#xff0c;内容为Linda Johnson(欧美女性)朗读的 7 本书籍段落(非小说类)。每个片段都提供文本转录&#xff0c;片段长度从 1 到 10 秒不等&…

八大排序之希尔排序

一、概念及其介绍 希尔排序(Shell Sort)是插入排序的一种&#xff0c;它是针对直接插入排序算法的改进。 希尔排序又称缩小增量排序&#xff0c;因 DL.Shell 于 1959 年提出而得名。 它通过比较相距一定间隔的元素来进行&#xff0c;各趟比较所用的距离随着算法的进行而减小…

什么是微分和导数?

文章目录 设立问题微分特性指数特性线性特性常数特性 多项式微分导数 在机器学习领域&#xff0c;有多种解决最优化问题的方法&#xff0c;其中之一就是使用微分。 通过微分&#xff0c;可以得知函数在某个点的斜率&#xff0c;也可以了解函数在瞬间的变化。 设立问题 请想象一…

Tortoise 删除文件

1、右击需要删除的文件&#xff0c;选择Delete 2、提交

【查看显卡信息】——Ubuntu和windows

1、VMware虚拟机 VMware虚拟机上不能使用CUDA/CUDNN&#xff0c;也安装不了显卡驱动 查看显卡信息&#xff1a; lspci | grep -i vga 不会显示显卡信息&#xff0c;只会输出VMware SVGA II Adapter&#xff0c;表示这是一个虚拟机&#xff0c;无法安装和使用显卡驱动 使用上…

GitHub 标星 6

美国网友对这个大全给予了很高的评价&#xff1a;这份清单中列出的开源软件&#xff0c;不仅解决了硅谷大厂前员工的难处&#xff0c;也能为其他所有码农解除困惑。 在这套大全的指导下&#xff0c;任何一个工程师&#xff0c;都能获得类似在谷歌内部写代码的体验。xg2xg 上线…

fot循环语句

概念&#xff1a; 循环是一种重复执行一段代码的结构&#xff0c;只要满足循环的条件&#xff0c;会一种执行这个代码。 循环条件&#xff1a;在一定范围内&#xff0c;按照指定的次数来执行循环 循环体&#xff1a;在指定的次数内&#xff0c;执行的命令序列。只要条件满足…

骑马与砍杀-战团mod制作-基础篇-武器模型入骑砍(二)

骑马与砍杀战团mod制作-基础-武器模型入骑砍笔记&#xff08;二&#xff09; 资料来源 学习的资料来源&#xff1a; b站【三啸解说】手把手教你做【骑砍】MOD&#xff0c;基础篇&#xff0c;链接为&#xff1a; https://www.bilibili.com/video/BV19x411Q7No?p4&vd_sour…

【SpringCloud-Seata源码分析2】

文章目录 分支事务注册-客户端分支事务服务端的执行 分支事务注册-客户端 第一篇我们将全局事务启动&#xff0c;以及开启源码分析完成了&#xff0c;现在我们需要看一下分支事务注册。 我们分支事务的开始需要从PreparedStatementProxy#executeUpdate中去看。 public class…

智能物流系统堪比帝王宠信妃子,我给你类比说明一下……

导语 大家好&#xff0c;我是社长&#xff0c;老K。专注分享智能制造和智能仓储物流等内容。 新书《智能物流系统构成与技术实践》人俱乐部 让我们将智能物流系统种涉及出库入库作业完整链条的“货到人”拣选系统的工作流程与古代帝王宠信翻牌妃子的过程进行一个有趣的类比&…

【vue3|第13期】深入了解Vue3生命周期:管理组件的诞生、成长与消亡

日期&#xff1a;2024年6月22日 作者&#xff1a;Commas 签名&#xff1a;(ง •_•)ง 积跬步以致千里,积小流以成江海…… 注释&#xff1a;如果您觉得有所帮助&#xff0c;帮忙点个赞&#xff0c;也可以关注我&#xff0c;我们一起成长&#xff1b;如果有不对的地方&#xf…

【SSM】医疗健康平台-管理端-检查组管理

技能目标 掌握新增检查组功能的实现 掌握查询检查组功能的实现 掌握编辑检查组功能的实现 掌握删除检查组功能的实现 体检的检查项种类繁多&#xff0c;为了方便管理和快速筛选出类别相同的检查项&#xff0c;医疗健康将类别相同的检查项放到同一个检查组中进行管理&#…

【CV炼丹师勇闯力扣训练营 Day8】

CV炼丹师勇闯力扣训练营 代码随想录算法训练营第8天 ● 344.反转字符串 ● 541. 反转字符串II ● 卡码网&#xff1a;54.替换数字 一、344 反转字符串 编写一个函数&#xff0c;其作用是将输入的字符串反转过来。输入字符串以字符数组 s 的形式给出。 不要给另外的数组分配额…

# Kafka_深入探秘者(1):初识 kafka

Kafka_深入探秘者&#xff08;1&#xff09;&#xff1a;初识 kafka 一、kafka 特性 1、Kafka &#xff1a;最初是由 Linkedln 公司采用 Scala 语言开发的一个多分区、多副本并且基于 ZooKeeper 协调的分布式消息系统&#xff0c;现在已经捐献给了 Apache 基金会。目前 Kafka…

如何使用kimi智能助手:您的智能生活小助手

Kimi智能助手是一款功能强大的AI工具&#xff0c;旨在帮助用户提高工作效率和生活品质。下面小编将详细介绍如何使用Kimi智能助手&#xff0c;涵盖其主要功能以及一些实用技巧。 一、Kimi智能助手的主要功能 多语言对话能力&#xff1a;Kimi擅长中文和英文的对话&#xff0c;可…

探索计算机视觉(人工智能重要分支)的发展与应用

引言 在当今快速发展的科技时代&#xff0c;计算机视觉作为人工智能领域的重要分支&#xff0c;正日益成为各行各业不可或缺的关键技术。从简单的图像处理到复杂的智能系统&#xff0c;计算机视觉的发展不仅改变了我们看待世界的方式&#xff0c;也深刻影响着工业、医疗、交通等…

Windows安装配置jdk和maven

他妈的远程连接不上公司电脑&#xff0c;只能在家重新配置一遍&#xff0c;在此记录一下后端环境全部配置 Windows安装配置JDK 1.8一、下载 JDK 1.8二、配置环境变量三、验证安装 Windows安装配置Maven 3.8.8一、下载安装 Maven并配置环境变量二、设置仓库镜像及本地仓库三、测…