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

server/2024/9/24 2:00:28/

一、实验目的

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

编制一个读单词过程,从输入的源程序中,识别出各个具有独立意义的单词,即基本保留字、标识符、常数、运算符、分隔符五大类。并依次输出各个单词的类型码及单词符号的自身值。(遇到错误时可显示“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.ppmy.cn/server/42871.html

相关文章

kafka调优参考建议 —— 筑梦之路

这里主要是从不同使用场景来调优&#xff0c;仅供参考。 吞吐量优先 吞吐量优先使用场景如采集日志。 1. broker配置调优 num.partitions&#xff1a;分区个数&#xff0c;设置为与消费者的线程数基本相等 2. producer配置调优 batch.size 批量提交消息的字节数&#xff0c;…

GitHub的原理及应用详解(一)

本系列文章简介&#xff1a; GitHub是一个基于Git版本控制系统的代码托管平台&#xff0c;为开发者提供了一个方便的协作和版本管理的工具。它广泛应用于软件开发项目中&#xff0c;包括但不限于代码托管、协作开发、版本控制、错误追踪、持续集成等方面。 GitHub的原理可以简单…

【无标题】亚马逊5月24日宣布推出2024出口跨境物流加速器计划

亚马逊中国5月24日郑重宣布启动“2024亚马逊出口跨境物流加速器计划”&#xff0c;旨在依托其世界领先的物流网络和前沿技术&#xff0c;结合本土资源&#xff0c;不断优化跨境物流服务&#xff0c;以强化中国卖家在跨境物流供应链管理方面的能力&#xff0c;进而提升整体效率&…

MySQL 字段截取拼接

文章目录 前言需求&#xff1a;拼接函数&#xff1a;截取函数&#xff1a; 总结 前言 请各大网友尊重本人原创知识分享&#xff0c;谨记本人博客&#xff1a;南国以南i、 提示&#xff1a;以下是本篇文章正文内容&#xff0c;下面案例可供参考 需求&#xff1a; 将数据库中的…

datagridview复选框选中响应

winform经常用datagridview来处理相关的数据显示&#xff0c;如果datagridview有复选框&#xff0c;我们应该如何处理相关选中响应。选择datagridview的cellcontentclick事件&#xff0c;代码如下&#xff1a; bool isSelectedGridViewRow false&#xff1b; private void da…

linux常用软件源码安装-2

jdk、tomcat、Apache、nginx、mysql、redis、maven、nexus安装文档&#xff1a;linux常用软件源码安装 9.sonarqube安装 前置条件&#xff1a;mysql5.6和jdk8 1.下载 官网 2.安装unzip并解压sonarqube&#xff0c;然后移动到/usr/local yum install -y unzip unzip sonarq…

CSRF 攻击

概述 CSRF(Cross-site request forgery,跨站请求伪造)。 它是指攻击者利用了用户的身份信息&#xff0c;执行了用户非本意的操作。 它首先引导用户访问一个危险网站&#xff0c;当用户访问网站后&#xff0c;网站会发送请求到被攻击的站点&#xff0c;这次请求会携带用户的c…

python低阶基础100题(上册)

** python低阶基础100题&#xff08;上册&#xff09; ** 1. 请打印出字符串 Hello World print("Hello World")2. 请打印出字符串 爸爸妈妈&#xff0c;你们辛苦啦 print("爸爸妈妈&#xff0c;你们辛苦啦")3. 请打印出字符串 人生苦短&#xff0c;我…