【编译原理】词法分析器的设计与实现

一、实验目的

通过设计编制调试一个具体的词法分析程序,加深对词法分析原理的理解。并掌握在对程序设计语言源程序进行扫描过程中将其分解为各类单词的词法分析方法。

编制一个读单词过程,从输入的源程序中,识别出各个具有独立意义的单词,即基本保留字、标识符、常数、运算符、分隔符五大类。并依次输出各个单词的类型码及单词符号的自身值。(遇到错误时可显示“Error”,然后跳过错误部分继续显示)

二、实验要求

C或C++或其他程序设计语言写一个简单的词法分析程序,程序可以满足下列要求:

1、能分析如下几种简单的语言词法

(1) 标识符: ID=letter(letter|digit)*

(2) 关键字(全部小写)

main int float double char if  then  else switch case break continue while do for

(3)整型常量:NUM=digit digit*

(4)运算符

   = + - * / < <= == != > >= ; ( )? :

(5)空格由空白、制表符和换行符组成,用以分隔ID、NUM、运算符等,字符分析时被忽略。

2、单词符号和相应的类别码

假定单词符号和相应的类别码如下:

| 单词符号 | 种别码 |

|---------|--------|

| int     | 1      |

| =       | 17     |

| float   | 2      |

| <       | 20     |

| if      | 3      |

| <=      | 21     |

| switch  | 4      |

| ==      | 22     |

| while   | 5      |

| !=      | 23     |

| do      | 6      |

| >       | 24     |

| 标识符  | 10     |

| >=      | 25     |

| 整型常量| 11     |

| ;       | 26     |

| +       | 13     |

| (       | 27     |

| -       | 14     |

| )       | 28     |

| *       | 15     |

| ?       | 29     |

| /       | 16     |

| :       | 30     |

3、词法分析程序实现的功能

输入:单词序列(以文件形式提供),输出识别的单词的二元组序列到文件和屏幕

输出:二元组构成: (syn,token或sum)

其中: syn 为单词的种别码

token 为存放的单词自身符号串

sum 为整型常数

例:

源程序: int ab; float ef=20;

ab=10+ef;

输出:

(保留字--1,int)

(标识符--10,ab)

(分号--26,;)

(保留字--2,float)

(标识符--10,ef)

(等号--17,=)

(整数--11,20)

(分号--26,;)

(标识符--10,ab)

(等号--17,=)

(整数--11,10)

(加号--13,+)

(标识符--10,ef)

(分号--26,;)

三、实验过程:

  • 算法分析:
    • 读取输入文件中的单词序列。
    • 根据给定的词法规则,识别并分类单词符号。
    • 输出识别的单词的二元组序列到文件和屏幕。
  • 程序流程图:

  • 程序代码:
#include <iostream>#include <fstream>#include <string>#include <map>using namespace std;// Token codes#define RESERVED 1#define FLOAT_TYPE 2#define IF_KEYWORD 3#define LESS_THAN 20#define LESS_THAN_OR_EQUAL 21#define SWITCH_KEYWORD 4#define EQUAL_EQUAL 22#define WHILE_KEYWORD 5#define NOT_EQUAL 23#define DO_KEYWORD 6#define GREATER_THAN 24#define GREATER_THAN_OR_EQUAL 25#define IDENTIFIER 10#define INTEGER_CONSTANT 11#define SEMICOLON 26#define PLUS 13#define LEFT_PAREN 27#define MINUS 14#define RIGHT_PAREN 28#define MULTIPLY 15#define QUESTION_MARK 29#define DIVIDE 16#define COLON 30#define ASSIGNMENT 17// Token mapmap<string, int> tokenMap = {{"int", RESERVED},{"float", FLOAT_TYPE},{"double", RESERVED},{"char", RESERVED},{"if", IF_KEYWORD},{"then", RESERVED},{"else", RESERVED},{"switch", SWITCH_KEYWORD},{"case", RESERVED},{"break", RESERVED},{"continue", RESERVED},{"while", WHILE_KEYWORD},{"do", DO_KEYWORD},{"for", RESERVED}};bool isLetter(char c) {return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');}bool isDigit(char c) {return c >= '0' && c <= '9';}void analyzeToken(const string &word, ofstream &outFile) {if (tokenMap.find(word) != tokenMap.end()) {outFile << "(保留字--" << tokenMap[word] << "," << word << ")" << endl;} else if (word == ";") {outFile << "(分号--26," << word << ")" << endl;} else if (word == "=") {outFile << "(等号--17," << word << ")" << endl;} else if (word == "+") {outFile << "(加号--13," << word << ")" << endl;} else if (word == "-") {outFile << "(减号--14," << word << ")" << endl;} else if (word == "*") {outFile << "(乘号--15," << word << ")" << endl;} else if (word == "/") {outFile << "(除号--16," << word << ")" << endl;} else if (word == "<") {outFile << "(小于--20," << word << ")" << endl;} else if (word == ">") {outFile << "(大于--24," << word << ")" << endl;} else if (word == "==") {outFile << "(等于--22," << word << ")" << endl;} else if (word == "!=") {outFile << "(不等于--23," << word << ")" << endl;} else if (word == "<=") {outFile << "(小于等于--21," << word << ")" << endl;} else if (word == ">=") {outFile << "(大于等于--25," << word << ")" << endl;} else if (isdigit(word[0])) {outFile << "(整数--11," << word << ")" << endl;} else {bool isID = true;for (char c : word.substr(1)) {if (!isalnum(c)) {isID = false;break;}}if (isID && isalpha(word[0])) {outFile << "(标识符--10," << word << ")" << endl;}}}int main() {ifstream inFile("TestData.txt");ofstream outFile("Result.txt");if (!inFile.is_open()) {cout << "Error opening input file!" << endl;return 1;}if (!outFile.is_open()) {cout << "Error opening output file!" << endl;return 1;}string line, word;while (inFile >> word) {size_t pos = word.find_first_of(";=+-*/<>"); // Find operator symbols in the wordif (pos != string::npos) {if (pos != 0) {analyzeToken(word.substr(0, pos), outFile);}string op = string(1, word[pos]); // Get operator symbolanalyzeToken(op, outFile);if (pos < word.size() - 1) {analyzeToken(word.substr(pos + 1), outFile);}} else {analyzeToken(word, outFile);}}inFile.close();outFile.close();return 0;}
  • 程序运行结果截图:

4、自己准备测试数据存放于TestData.txt文件中,测试数据中应覆盖有以上5种数据,测试结果要求以原数据与结果对照的形式输出并保存在Result.txt中,同时要把结果输出到屏幕。

5、提前准备

① 实验前,先编制好程序,上机时输入并调试程序。

  • 准备好多组测试数据(存放于文件TestData.txt中)。

四、思考题:

词法分析中如何识别单词?请具体描述识别过程。

在词法分析中,识别单词通常需要遵循以下步骤:

  1. 读取字符序列: 从输入源(如文件或输入流)中逐个读取字符,构成一个字符序列。
  2. 判断字符类型: 对于每个读取到的字符,判断其类型,比如是字母、数字、特殊符号等。
  3. 构建单词: 在字符序列中,如果连续的字符满足某种规则形成的序列能够被认定为一个单词,就将这些字符组合成一个单词。这可能包括关键字、标识符、数字、运算符等。
  4. 识别单词类型: 将构建好的单词与预先定义的词法规则进行匹配,确定该单词的类型。
  5. 输出结果: 根据单词的类型,生成相应的输出,通常是一个标识符和其对应的类型。
  6. 处理下一个单词: 继续以上步骤,直到完成所有字符的扫描。

具体描述识别过程时,识别单词的算法一般会根据编程语言的词法规则进行设计,通过状态机、正则表达式等方式来实现各种单词的识别。例如,针对不同类型的单词可能会有不同的识别逻辑和判断条件。在实现中,需要考虑边界情况、错误处理、特殊字符处理等方面,以确保正确地识别并分类单词。

五、实验小结:

通过本次实验,我学会了设计和实现一个简单的词法分析器。这为我理解编程语言中单词和符号的识别提供了良好的基础。扩展词法分析器的功能可以通过添加更多的词法规则和相应的分类逻辑来实现,从而适应更复杂的编程语言要求。

以上是对本次实验的总结和反思。词法分析是编译原理中的重要内容,通过实践可以更深入地理解编程语言的内部机制。

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

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

相关文章

SQLmap学习以及题解运用

1.简介 SQLmap是一款开源的SQL注入工具&#xff0c;用于检测和利用Web应用程序的SQL注入漏洞。SQLmap支持多种数据库管理系统&#xff0c;包括MySQL、Oracle、PostgreSQL、Microsoft SQL Server、SQLite等&#xff0c;并支持各种不同的操作系统和平台。 这里主要分为四大部分…

同余定理性质

在算法题中碰到的这个同余定理定理&#xff0c;记录一下性质

机器学习之常用算法与数据处理

一、机器学习概念&#xff1a; 机器学习是一门多领域交叉学科&#xff0c;涉及概率论、统计学、计算机科学等多门学科。它的核心概念是通过算法让计算机从数据中学习&#xff0c;改善自身性能。机器学习专门研究计算机怎样模拟或实现人类的学习行为&#xff0c;以获取新的知识…

Android Low Storage机制之DeviceStorageMonitorService

一、Android 版本 Android 13 二、low storage简介(DeviceStorageMonitorService) 设备存储监视器服务是一个模块&#xff0c;主要用来&#xff1a; 1.监视设备存储&#xff08;“/ data”&#xff09;。 2.每60秒扫描一次免费存储空间(谷歌默认值) 3.当设备的存储空间不足…

【项目】教你手把手完成博客系统(三)显示用户信息 | 实现退出登录 | 实现发布博客

文章目录 教你手把手完成博客系统&#xff08;三&#xff09;7.实现显示用户信息1.约定前后端交互接口2.前端通过ajax发起请求3.服务器处理请求 8.实现退出登录1.约定前后端的接口2.前端发起请求3.服务器处理请求 9.实现发布博客1.约定前后端的交互接口2.前端构造请求3.服务器处…

齐护K210系列教程(三十)_多任务切换

多任务切换 1&#xff0c;任务1的设定2&#xff0c;任务2的设定3&#xff0c;主程序4&#xff0c; 课程资源联系我们 在开发项目时&#xff0c;我们常会用到AIstart的多个任务来切换应用&#xff0c;比如当我识别到某种卡片时&#xff0c;要切换到别的任务&#xff0c;这样就要…

CentOS-7安装教程

目录 安装 修改主机名 配置静态IP 镜像下载地址 https://mirrors.aliyun.com/centos/7.9.2009/isos/x86_64/CentOS-7-x86_64-DVD-2009.iso VMware Workstation Pro下载 VMware Workstation Pro各版本下载&#xff08;2024.5.5之后&#xff09;(Windows与Linux安装包不限…

【okhttp】小问题记录合集

can’t create native thread 问题描述 OkHttpClient 每次使用都new创建&#xff0c;造成OOM&#xff0c;提示can’t create native thread… 问题分析 没有将OkHttpClient单例化. 每个client对象都有自己的线程池和连接池&#xff0c;如果为每个请求都创建一个client对象&a…

视频推拉流EasyDSS系统如何在清理缓存文件的同时不影响缓存读写?

视频推拉流EasyDSS视频直播点播平台可提供一站式的视频转码、点播、直播、视频推拉流、播放H.265视频等服务&#xff0c;搭配RTMP高清摄像头使用&#xff0c;可将无人机设备的实时流推送到平台上&#xff0c;实现无人机视频推流直播、巡检等应用。 有用户咨询&#xff0c;视频推…

Git 的安装和使用

一、Git 的下载和安装 目录 一、Git 的下载和安装 1. git 的下载 2. 安装 二、Git 的基本使用-操作本地仓库 1 初始化仓库 1&#xff09;创建一个空目录 2&#xff09;git init 2 把文件添加到版本库 1&#xff09;创建文件 2&#xff09;git add . 3&#xff09;g…

在SpringBoot自定义指标并集成Prometheus和Grafana监控

前沿 写这篇文章的目的是发现自己整天埋头写业务代码但忽略了主动发现问题的能力&#xff0c;这里指的是监控和报警。结合工作中发现Prometheus和Grafana还是主流一些。本文介绍如何使用自定义指标&#xff0c;并使用Prometheus进行监控并报警&#xff0c;同时在 Grafana 进行…

重学java 40.多线程 — 死锁和线程状态

—— 24.5. 一、死锁 1.死锁介绍&#xff08;锁嵌套就有可能产生死锁&#xff09; 指的是两个或者两个以上的线程在执行的过程中由于竞争同步锁而产生的一种阻塞现象;如果没有外力的作用,他们将无法继续执行下去,这种情况称之为死锁 例&#xff1a; 两线程处于互相等待的状态&a…

上位机图像处理和嵌入式模块部署(mcu常见三种烧录方法)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 和单纯的windows上位机开发、嵌入式linux开发不一样&#xff0c;mcu的开发&#xff0c;是需要通过烧录器把编译好的镜像烧入到开发板里面的。这是很…

STM32通用定时器的应用实例(基于STM32F103)

目录 概述 1 STM32Cube配置项目 1.1 准备环境 1.2 配置项目参数 1.3 生成Project 2 HAL函数 2.1 初始化函数&#xff1a;HAL_TIM_Base_Init 2.2 中断模式启动定时器函数&#xff1a;HAL_TIM_Base_Start 2.3 定时器回调函数&#xff1a; HAL_TIM_PeriodElapsedCallback…

ElasticSearch操作之重置密码脚本

ElasticSearch操作之重置密码脚本 #!/bin/bash # 使用样例 ./ES密码重置.sh 旧密码 新密码# 输入旧密码 es_old_password$1# 设置新的密码变量 es_password$2# 正确响应 es_reponse{"acknowledged":true}# 检查Elasticsearch是否在运行 if pgrep -f elasticsearch &g…

2024年5月计算机视觉论文推荐:包括扩散模型、视觉语言模型、图像编辑和生成、视频处理和生成以及图像识别等各个主题

我们今天总结下2024年5月发表的最重要的论文&#xff0c;重点介绍了计算机视觉领域的最新研究和进展&#xff0c;包括扩散模型、视觉语言模型、图像编辑和生成、视频处理和生成以及图像识别等各个主题。 Diffusion Models 1、Dual3D: Efficient and Consistent Text-to-3D Ge…

【C++题解】1697. 请输出n~1之间所有的整数

问题:1697. 请输出n~1之间所有的整数 类型&#xff1a;循环 题目描述&#xff1a; 从键盘读入一个整数 n &#xff0c;请输出 n∼1 之间所有的整数&#xff0c;每行输出 1 个。 比如&#xff0c;假设读入 n5 &#xff0c;输出结果如下&#xff1a; 5 4 3 2 1 输入&#xff1…

Java进阶学习笔记4——Static应用知识:代码块

代码块&#xff1a; 代码块是类的五大成员之一&#xff08;成员变量、构造器、方法、代码块、内部类&#xff09;。 Java类生命周期&#xff1a;加载、验证、准备、初始化、卸载。 代码块分为两种&#xff1a; 静态代码块&#xff1a; 格式&#xff1a;static {} 特点&…

SpringBoot 集成 Nebula

工作需求&#xff0c;开始了解图数据库&#xff0c;经过工具选型&#xff0c;最终选择nebula graph&#xff0c;并集成到springboot&#xff0c;java 环境下如何对 Nebula Graph 进行操作&#xff0c;本文整理下过程。 1、首先引入 pom 依赖 <dependency><groupId&g…

鸿蒙系统与OpenHarmony:中国科技行业的新动力与就业前景

背景 经历近年来的迅猛发展&#xff0c;鸿蒙原生应用数量已突破4000款&#xff0c;生态设备数量超过8亿台&#xff0c;开发者群体壮大至220万人。更为显著的是&#xff0c;鸿蒙系统在中国市场的份额已经超过了15%&#xff0c;稳居第三大操作系统&#xff0c;其生态之树已然枝繁…