编译原理-词法分析(实验 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,一经查实,立即删除!

相关文章

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…

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

目录 一、引言 二、提升乡村旅游服务质量 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;这…

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…

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

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

责任链模式(行为型)

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

第二十一讲:编译和链接

第二十一讲&#xff1a;编译和链接 1.翻译环境和运行环境1.1翻译环境1.2编译1.2.1预编译&#xff08;预处理&#xff09;1.2.2编译1.2.2.1词法分析1.2.2.2语法分析1.2.2.3语义分析 1.2.3汇编 1.3链接1.4运行环境1.5#define符号1.5.1#define的使用和原理1.5.2#define使用的陷阱注…

Python学习从0开始——Kaggle机器学习004总结2

Python学习从0开始——Kaggle机器学习004总结2 一、缺失值二、分类变量2.1介绍2.2实现1.获取训练数据中所有分类变量的列表。2.比较每种方法方法1(删除分类变量)方法2(序数编码)方法3独热编码 三、管道3.1介绍3.2实现步骤1:定义预处理步骤步骤2:定义模型步骤3:创建和评估管道 四…

【JAVA】javadoc,如何生成标准的JAVA API文档

目录 1.什么是JAVA DOC 2.标签 3.命令 1.什么是JAVA DOC 当我们写完JAVA代码&#xff0c;别人要调用我们的代码的时候要是没有API文档是很痛苦的&#xff0c;只能跟进源码去一个个的看&#xff0c;一个个方法的猜&#xff0c;并且JAVA本来就不是一个重复造轮子的游戏&#…

探索LLM 在金融领域有哪些潜在应用——通过使用 GPT-4 测试金融工程、市场预测和风险管理等 11 项任务

概述 近年来&#xff0c;用于自然语言理解和生成的人工智能技术在自然语言处理领域取得了突破性进展&#xff0c;OpenAI 的 GPT 和其他大规模语言模型在该领域取得了显著进步。这些模型通过先进的计算能力和算法&#xff0c;展示了处理复杂任务的能力&#xff0c;如理解复杂语…

vue2组件封装实战系列之tag组件

作为本系列的第一篇文章&#xff0c;不会过于的繁杂&#xff0c;并且前期的组件都会是比较简单的基础组件&#xff01;但是不要忽视这些基础组件&#xff0c;因为纵观elementui、elementplus还是其他的流行组件库&#xff0c;组件库的封装都是套娃式的&#xff0c;很多复杂组件…

关于python中的关键字参数

在python语言中存在两种传参方式&#xff1a; 第一种是按照先后顺序来传参&#xff0c;这种传参风格&#xff0c;称为“位置参数”这是各个编程语言中最普遍的方式。 关键字传参~按照形参的名字来进行传参&#xff01; 如上图所示&#xff0c;在函数中使用关键字传参的最大作…

计算机网络 ——网络层(IPv4地址)

计算机网络 ——网络层&#xff08;IPv4地址&#xff09; 什么是IPv4地址IP地址的分类特殊的IP地址 查看自己的IPv4地址 我们今天来看IPv4地址&#xff1a; 什么是IPv4地址 IPv4&#xff08;Internet Protocol version 4&#xff09;是第四版互联网协议&#xff0c;是第一个被…