编译原理-词法分析(实验 C语言)

编译原理-词法分析


1. 实验目的

设计、编写并调试一个词法分析程序,加深对词法分析原理的理解

2. 实验要求

2.1 待分析的简单语言的词法

  1. 关键字:begin,if,then,while,do,end
    所有关键字都是小写
  2. 运算符和界符::,=,+,-,*,/,<,<=,<>,>,>=,=,;,(,),#
  3. 其他单词是标识符(id)和整型常数(NUM),通过以下正规式定义:
    ID = letter(letter|digit)*
    NUM = digit digit*
  4. 空格由空白、制表符和换行符组成。空格一般用来分隔ID、NUM、运算符、界符和关键字,词法分析阶段通常被忽视

2.2 各种单词符号对应的种别码

单词符号种别码单词符号种别码
begin1:17
if2:=18
then3<20
while4<>21
do5<=22
end6>23
letter(letter digit)*10>=24
digit digit*11=25
+13;26
-14(27
*15)28
/16#0
[29]30
{31}32
,33!=40
==39

2.3 词法分析程序的功能

输入:所给文法的源程序字符串
输出:二元组(syn,token或sum)构成的序列

其中:syn为单词种别码;token为存放的单词自身字符串;sum为整型常数
例如: 对源程序
begin x:=9; if x > 0 then x:=2 * x + 1 / 3; end #
的源文件,经词法分析后输出如下序列:
(1,begin)(10,‘x’)(18,:=)(11,9)(26,😉(2,if)…

3. 词法分析程序的算法思想

算法的基本任务是从字符串表示的源程序中识别出具有独立意义的单词符号,其基本思想是根据扫描到单词符号的第一个字种类,拼出相应地单词符号

3.1 主程序示意图

主程序示意图如图所示,其中初值包括如下两个方面

  1. 关键字表的初值
    关键字作为特殊标识符处理,把它们预先安排在一张表各中(称为关键字表),当扫描程序识别出标识符时,查关键字表。如能查到匹配的单词,则该单词为关键字,否则为一般标识符,关键字表为一个字符串数组,描述如下:

    char* rwtab[] = {“begin”,“if”,“then”,“while”,“do”,“end”,_KEY_WORD_END}; //关键字数组

  2. 程序中需要用到的主要变量为syn,token和sum
    在这里插入图片描述

3.2 扫描子程序的算法思想

首先设置3个变量:

  1. token用来存放构成单词符号的字符串
  2. sum用来存放整型单词
  3. syn用来存放单词符号的 种别码

扫描子程序主要部分流程如图:
在这里插入图片描述

4. 词法分析程序的C语言程序框架

最终代码:

#include <stdio.h> 
#include <stdlib.h>
#include <string.h>
// #include <iostream>#define _KEY_WORD_END "waiting for your expanding"  // 定义关键字结束标志// 单词二元组的结构
typedef struct 
{int typenum;char* word;
}WORD;//函数声明
char m_getch();
void getbc();
void concat();
int letter();
int digit();
int reserve();
void retract();
char *dtb();
WORD *scaner();char input[255];  //输入换缓冲区
char token[255] = "";  //单词缓冲区
int p_input;  //输入换缓冲区指针
int p_token;  //单词缓冲区指针char ch;  //当前读入字符
char* rwtab[] = {"begin","if","then","while","do","end",_KEY_WORD_END};  //关键字数组WORD* scaner();  //词法扫描函数,获得一个单词int main(void)
{// printf("111");int over = 1;WORD* oneword = new WORD;  //new为c++中的关键字 在使用new进行内存分配时,需要包含相关类型的头文件。#include <iostream>while (1){printf("Enter Your words(end with #):");scanf("%[^#]s",input);  //读入源程序字符串到缓冲区,以#结束,允许多行输入p_input = 0;printf("Your words: \n %s \n",input);while (over < 1000 && over != -1) {oneword = scaner();  //获得新单词 if(oneword -> typenum < 1000){printf("(%d,%s)",oneword -> typenum,oneword -> word);  //打印种别码和单词本身的值}over = oneword -> typenum;free(oneword);}over = 1;// printf("\n press # to exit: \n");  //#号退出程序// scanf("%[^#]s",input);while(getchar() != '\n'){}printf("\npress # to exit:");if(getchar() == 35){return 0;}while(getchar() != '\n'){}}      
}// 从输入缓冲区读取一个字符到ch中
char m_getch()
{ch = input[p_input];p_input = p_input + 1;return(ch);
}// 去掉空白符号
void getbc()
{while(ch == ' ' || ch == 10){ch = input[p_input];p_input = p_input + 1;}
}//拼写单词
void concat()
{token[p_token] = ch;p_token = p_token + 1;token[p_token] = '\0';
}//判断是否字母
int letter()
{if(ch >= 'a' && ch <= 'z' || ch >= 'A' && ch <= 'Z')return 1;else return 0;
}//判断是否数字
int digit()
{if(ch >= '0' && ch <= '9')return 1;else return 0;
}// 检索关键字表格
int reserve(){int i = 0;while(strcmp(rwtab[i],_KEY_WORD_END)){if(!strcmp(rwtab[i],token)){return i + 1;}i = i + 1;}return 10;
}//回退一个字符
void retract()
{p_input = p_input - 1;
}//数字转换成二进制
char* dtb(char *buffer)
{int j = 0;int flag = 0;int k = (sizeof(char)<<3) - 1;char temp = ch - '0';for(int i = 0; i < (sizeof(char)<<3); i++,k--){if((temp >> k & 0x01) == 0){if(flag == 1){buffer[j++] = 0 + '0';}	}else{flag = 1;buffer[j++] = (temp >> k & 0x01) + '0';}}buffer[j] = 0;return buffer;
}WORD* scaner()
{WORD* myword = new WORD;myword -> typenum = 10;myword -> word = "";p_token = 0;m_getch();getbc();if(letter()){while (letter() || digit()){concat();m_getch();}retract();myword -> typenum = reserve();myword -> word = token;return (myword);}else if(digit()){while (digit()){concat();m_getch();}retract();myword ->typenum = 11;myword -> word = token;return (myword);}else switch (ch){case '=' : m_getch();if(ch == '='){myword -> typenum = 39; // == 的种别码为39myword -> word = "==";return (myword);}retract();myword -> typenum = 25; // = 的种别码为25myword -> word = "=";return (myword);break;case '+' : myword -> typenum = 13; // + 的种别码为13myword -> word = "+";return (myword);break;case '-' : myword -> typenum = 14; // - 的种别码为14myword -> word = "-";return (myword);break;case '*' : myword -> typenum = 15; // * 的种别码为15myword -> word = "*";return (myword);break;case '/' : myword -> typenum = 16; // / 的种别码为16myword -> word = "/";return (myword);break;case '(' : myword -> typenum = 27;myword -> word = "(";return (myword);break;case ')' : myword -> typenum = 28;myword -> word = ")";return (myword);break;case '[' : myword -> typenum = 29;myword -> word = "[";return (myword);break;case ']' : myword -> typenum = 30;myword -> word = "]";return (myword);break;case '{' : myword -> typenum = 31;myword -> word = "{";return (myword);break;case '}' : myword -> typenum = 32;myword -> word = "}";return (myword);break;case ',' : myword -> typenum = 33;myword -> word = ",";return (myword);break;case ':' : m_getch();if(ch == '='){myword -> typenum = 18;myword -> word = ":=";return (myword);}retract();myword -> typenum = 17;myword -> word = ":";return (myword);break;case ';' : myword -> typenum = 26;myword -> word = ";";return (myword);break;case '>' : m_getch();if(ch == '='){myword -> typenum = 24;myword -> word = ">=";return (myword);}retract();myword -> typenum = 23;myword -> word = ">";return (myword);break;case '<' : m_getch();if(ch == '='){myword -> typenum = 22;myword -> word = "<=";return (myword);}retract();myword -> typenum = 20;myword -> word = "<";return (myword);break;case '!' : m_getch();if(ch == '='){myword -> typenum = 40;myword -> word = "!=";return (myword);}retract();myword -> typenum = -1;myword -> word = "ERROR";return (myword);break;case '\0' : myword -> typenum = 1000;myword -> word = "OVER";return (myword);break;default:myword -> typenum = 0;myword -> word = "#";return (myword);}
}

5. 实验结果

输入源程序后得出结果:
在这里插入图片描述

press # to exit:
在这里插入图片描述

输入其他字符,继续输入源程序:
在这里插入图片描述

6. 实验小结

  1. 关键词new出错
    改进:将c源程序改为c++
    原因:new为c++中的关键字 在使用new进行内存分配时,需要包含相关类型的头文件。#include <iostream>

  2. void main()出错 error: '::main' must return 'int'
    解决方式:将void main改为int main(void)

  3. 数字转换二进制
    十进制转二进制代码

    //数字转换成二进制
    char* dtb(char *buffer)
    {int j = 0;int flag = 0;int k = (sizeof(char)<<3) - 1;char temp = ch - '0';for(int i = 0; i < (sizeof(char)<<3); i++,k--){if((temp >> k & 0x01) == 0){if(flag == 1){buffer[j++] = 0 + '0';}	}else{flag = 1;buffer[j++] = (temp >> k & 0x01) + '0';}}buffer[j] = 0;return buffer;
    }
    
  4. 增加:=的判断

    case ':' : m_getch();if(ch == '='){myword -> typenum = 18;myword -> word = ":=";return (myword);}retract();myword -> typenum = 17;myword -> word = ":";return (myword);break;
    
  5. 程序运行后会自动退出,无法满足按#退出
    解决方式:

    修改main函数int main(void)
    {// printf("111");int over = 1;WORD* oneword = new WORD;  //new为c++中的关键字 在使用new进行内存分配时,需要包含相关类型的头文件。#include <iostream>while (1){printf("Enter Your words(end with #):");scanf("%[^#]s",input);  //读入源程序字符串到缓冲区,以#结束,允许多行输入p_input = 0;printf("Your words: \n %s \n",input);while (over < 1000 && over != -1) {oneword = scaner();  //获得新单词 if(oneword -> typenum < 1000){printf("(%d,%s)",oneword -> typenum,oneword -> word);  //打印种别码和单词本身的值}over = oneword -> typenum;free(oneword);}over = 1;// printf("\n press # to exit: \n");  //#号退出程序// scanf("%[^#]s",input);while(getchar() != '\n'){}printf("\npress # to exit:");if(getchar() == 35){return 0;}while(getchar() != '\n'){}}      
    }

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

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

相关文章

前端如何封装自己的npm包并且发布到npm注册源

前言 在前端开发中&#xff0c;复用代码是一种常见且高效的实践。通过封装和发布自己的npm包&#xff0c;你可以轻松地在多个项目之间共享代码&#xff0c;并且贡献给社区。以下是一步一步指导你如何封装自己的npm包并发布到npm注册源。 步骤一&#xff1a;创建并设置项目 首…

智驾”IT运维,探索企业高效管理新航道——运维智慧驾驶舱

在信息化高速发展的今天&#xff0c;企业对于稳定、高效的IT运维管理需求日益迫切。运维智慧驾驶舱&#xff0c;作为新一代的运维解决方案&#xff0c;正以其独特的优势&#xff0c;引领着企业IT运维的新方向。当它与优秀的监控系统相结合时&#xff0c;比如监控易&#xff0c;…

28-unittest批量执行(discover)

unittest框架提供了创建测试用例、测试套件以及批量执行的解决方案。 利用单元测试框架创建测试类&#xff0c;可以把每个测试方法看成是一个最小的单元&#xff0c; 由测试容器组装打包起来&#xff0c;然后可以统一执行&#xff0c;最后输出测试报告。 一、UnitTest核心要素…

最新区块链论文速读--CCF A会议 CCS 2023 共25篇 附pdf下载(3/4)

Conference&#xff1a;ACM Conference on Computer and Communications Security (CCS) CCF level&#xff1a;CCF A Categories&#xff1a;network and information security Year&#xff1a;2023 Num&#xff1a;25 第1~7篇区块链文章请点击此处查看 第8~13篇区块链文…

【2024】Kafka Streams详细介绍与具体使用(1)

目录 介绍关键特性应用场景核心概念部署方式kafka streams的处理模式 具体使用1、准备工作2、添加依赖3、代码实现3、测试 介绍 Kafka Streams是构建在Apache Kafka之上的客户端库&#xff0c;用于构建高效、实时的流处理应用。它允许你以高吞吐量和低延迟的方式处理记录流&am…

TypeScript算法每日一题:赎金信(383)

作者&#xff1a;前端小王hs 阿里云社区博客专家/清华大学出版社签约作者✍/CSDN百万访问博主/B站千粉前端up主 题库&#xff1a;力扣 题目序号&#xff1a;383&#xff08;简单&#xff09; 题目&#xff1a;赎金信 给你两个字符串ransomNote 和 magazine&#xff0c;判断ran…

前端工程化工具系列(十三)—— Rollup(v4.18.0):专注于库构建的 JavaScript 打包器

1 安装 1.1 针对 JavaScript pnpm add -D rollup rollup/plugin-node-resolve rollup/plugin-commonjs rollup/plugin-babel rollup-plugin-postcss rollup/plugin-terser1.2 针对 TypeScript 在 JavaScript 基础上添加一些插件&#xff1a; pnpm add -D rollup-plugin-typ…

Mybatis06-动态SQL

动态SQL 1.什么是动态SQL 什么是动态SQL&#xff1a;动态SQL指的是根据不同的查询条件 , 生成不同的Sql语句. 类似JSTL标签 官网描述&#xff1a; MyBatis 的强大特性之一便是它的动态 SQL。如果你有使用 JDBC 或其它类似框架的经验&#xff0c;你就能体会到根据不同条件拼接…

乡村振兴的乡村旅游品质提升:提升乡村旅游服务质量,打造乡村旅游品牌,增强乡村旅游吸引力,打造具有旅游特色的美丽乡村

目录 一、引言 二、提升乡村旅游服务质量 1、完善基础设施建设 2、提升服务人员素质 3、规范服务流程 三、打造乡村旅游品牌 1、挖掘乡村文化特色 2、打造特色旅游产品 3、加强品牌宣传和推广 四、增强乡村旅游吸引力 1、创新旅游体验方式 2、打造旅游精品线路 3、…

【进阶篇-Day2:JAVA包、抽象类、接口、多态】

目录 1、包2、抽象类2.1 抽象类的定义2.2 抽象类的注意事项2.3 abstract关键字的冲突 3、接口3.1 接口的介绍3.2 接口中的成员特点3.2.1 接口中的成员特点3.2.2 类和接口之间的各种关系 3.3 抽象类和接口的对比 4、多态4.1 多态的介绍4.2 多态的前提4.3 多态的成员访问特点4.4 …

vuInhub靶场实战系列--Kioptrix Level #1

免责声明 本文档仅供学习和研究使用,请勿使用文中的技术源码用于非法用途,任何人造成的任何负面影响,与本人无关。 目录 免责声明前言一、环境配置1.1 靶机信息1.2 靶场配置 二、信息收集2.1 主机发现2.2 端口扫描2.2.1 masscan2.2.2 nmap 2.3 指纹识别2.4 目录扫描2.4.1 dirb…

华为云服务器-云容器引擎 CCE环境构建及项目部署

1、切换地区 2、搜索云容器引擎 CCE 3、购买集群 4、创建容器节点 通过漫长的等待(五分钟左右)&#xff0c;由创建中变为运行中&#xff0c;则表明容器已经搭建成功 购买成功后&#xff0c;返回容器控制台界面 5、节点容器管理 6、创建redis工作负载 7、创建mysql工作负载 8、…

E: 仓库 “http://download...graphics:/darktable/xUbuntu_22.04 InRelease” 没有数字签名

问题 Ubuntu22.04装了darktable软件没装好&#xff0c;已经卸载了但是没卸载干净,终端使用 sudo apt update 出现的问题&#xff1a; 解决&#xff1a; sudo nano /etc/apt/sources.list.d/*darktable*.list找到了该软件的相关仓库条目&#xff1a;直接给他注释掉就行了。

重构大学数学基础_week04_从点积理解傅里叶变换

这周我们来看一下傅里叶变换。傅里叶变换是一种在数学和许多科学领域中广泛应用的分析方法&#xff0c;它允许我们将信号或函数从其原始域&#xff08;通常是时间域或空间域&#xff09;转换到频域表示。在频域中&#xff0c;信号被表示为其组成频率的幅度和相位&#xff0c;这…

Android13 Settings 左上角箭头图标点击无效

最近在修改A311D2方案固件&#xff0c;系统Settings发现很多bug 最明显的是左上角有个箭头样子的图标&#xff0c;通常认为是返回键&#xff0c;点击之后没有任何效果&#xff0c;目测这个是ActionBar的按键。 SettingsBaseActivity里面有一段这样的代码&#xff1a; // Th…

Nvidia/算能 +FPGA+AI大算力边缘计算盒子:大疆RoboMaster AI挑战赛

NVIDIA Jetson TX2助力机器人战队斩获RoboMaster AI挑战赛冠亚军 一个汇聚数百万机器人专家与研究人员的赛场&#xff0c;一场兼具工程、策略和团队挑战的较量&#xff0c;说的正是近日刚刚在澳大利亚布里斯本ICRA大会上闭幕的大疆RoboMaster AI挑战赛今年的冠军I Hiter以及亚军…

进程通信(IPC-Inter Process Communication)

进程之间的通信通过内核空间实现 IPC技术 ①管道(匿名管道/命名管道-FIFO队列) ②System V IPC(消息队列、信号量和共享内存) ③套接字(UNIX套接字&Internet套接字) ※信号 软中断&#xff0c;信号提供了一种处理异步事件的方法&#xff0c;作为进程通信的一种机制&am…

作文笔记11推荐一本书

what介绍书名作者出版社 why推荐理由挑一两点&#xff08;内容&#xff0c;语言&#xff0c;情节&#xff0c;人物&#xff0c;思想&#xff09;&#xff0c;几点就分几段 how具体1、可以转述摘录精彩片段 2、结合书的情节、人物对话、插图来说明 3、引用别人评价 how如何挑选…

LeetCode714买卖股票的最佳时机含手续费

题目描述 给定一个整数数组 prices&#xff0c;其中 prices[i]表示第 i 天的股票价格 &#xff1b;整数 fee 代表了交易股票的手续费用。你可以无限次地完成交易&#xff0c;但是你每笔交易都需要付手续费。如果你已经购买了一个股票&#xff0c;在卖出它之前你就不能再继续购买…

责任链模式(行为型)

目录 一、前言 二、责任链模式 三、总结 一、前言 责任链模式&#xff08;Chain of Responsibility Pattern&#xff09;也叫职责链模式&#xff0c;是一种行为型设计模式&#xff0c;职责链模式使多个对象都有机会处理请求&#xff0c;从而避免请求的发送者和接收者之间的耦…