编译原理-词法分析(实验 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.rhkb.cn/news/344895.html

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

相关文章

DevOps入门

DevOps: 让技术团队、运维、测试等团队实现一体式流程自动化 CICD: CI:持续集成 CD:持续交付持续集成:从编码、编译、测试、发布项目到仓库的自动化流程持续交付:包含持续集成&#xff0c;并且增加将项目部署到对应的环境的自动化流程 传统项目闭环流程: DevOps闭环流程…

基于非下采样小波包分析的滚动轴承故障诊断(MATLAB R2021B)

小波变换具有良好的时频局部化特性和多分辨率特性&#xff0c;可准确定位信号的突变点并可在不同尺度上描述信号的局部细节特征&#xff0c;被广泛应用于信号降噪。但标准正交小波变换不具有平移不变性&#xff0c;采用标准正交小波对信号消噪后&#xff0c;会在脉冲尖峰处产生…

VSCode调试揭秘:Live Server助力完美测试Cookie与Session,远超“Open in Browser“!

文章目录 一、项目场景&#xff1a;二、问题描述1. open in browser&#xff1a;2. open with live server 三、原因分析&#xff1a;先了解一下open in browser和open with live server的区别两者的优缺点open in browseropen with live server 四、解决方案&#xff1a;总结 …

Java开发-面试题-0005-==和String的equals()和String的intern()方法的区别

Java开发-面试题-0005-和String的equals()和String的intern()方法的区别 更多内容欢迎关注我&#xff08;持续更新中&#xff0c;欢迎Star✨&#xff09; Github&#xff1a;CodeZeng1998/Java-Developer-Work-Note 技术公众号&#xff1a;CodeZeng1998&#xff08;纯纯技术…

前端多人项目开发中,如何保证CSS样式不冲突?

在前端项目开发中&#xff0c;例如突然来了一个大项目&#xff0c;很可能就需要多人一起开发&#xff0c;领导说了&#xff0c;要快&#xff0c;要快&#xff0c;要快&#xff0c;你们给我快。然后下面大伙就一拥而上&#xff0c;干着干着发现&#xff0c;一更新代码&#xff0…

转型AI产品经理(5):“锚定效应”如何应用在Chatbot产品中

锚定效应是认知心理学中一个重要的概念&#xff0c;它描述了人们在进行判断或决策时&#xff0c;往往过于依赖最先接收到的信息或数字&#xff08;即“锚点”&#xff09;&#xff0c;即使后续信息与初始锚点无关甚至相反&#xff0c;这个初始信息也会显著地影响最终的判断结果…

【下篇】从 YOLOv1 到 YOLOv8 的 YOLO 物体检测模型历史

YOLO 型号之所以闻名遐迩,主要有两个原因:其速度和准确性令人印象深刻,而且能够快速、可靠地检测图像中的物体。上回我解释了YoloX, 今天从Yolov6开始。 YOLOv6:面向工业应用的单级物体检测框架 美团视觉人工智能事业部(Meituan Vision AI Department)于 2022 年 9 月在…

拯救者Legion Y9000X IRX9 2024(83FD)原装出厂Windows11系统镜像下载

lenovo联想2024款拯救者Y9000X IRX9 笔记本电脑【83FD】OEM预装Win11系统安装包&#xff0c;恢复开箱状态&#xff0c;自带恢复重置还原功能 链接&#xff1a;https://pan.baidu.com/s/1i_sVcnXF4qgsuj02rebe-Q?pwdyefp 提取码&#xff1a;yefp 联想原装WIN11系统自带所有…

Junit 单元测试 详解,包你掌握

Java单元测试----Junit详解 1 什么是 Junit JUnit 是一个广泛使用的 Java 单元测试框架。它用于编写和运行可重复的测试&#xff0c;以验证 Java 程序的行为是否符合预期 也许有人会好奇&#xff0c;之前学的 Selenium 和 Junit 有什么关系&#xff1f;答案就是没关系&#…

htb-linux-6-beep

nmap web渗透 目录扫描 漏洞关键词 shell py脚本执行 flag root 目前的权限 nmap root

《精通ChatGPT:从入门到大师的Prompt指南》第4章:避免常见错误

第4章&#xff1a;避免常见错误 在使用ChatGPT进行Prompt编写时&#xff0c;常见的错误可能会大大影响生成内容的质量和准确性。本章将详细讨论这些错误&#xff0c;并提供如何避免它们的建议。 4.1 不明确的指令 在使用ChatGPT时&#xff0c;一个常见的问题是指令不够明确。…

使用proteus仿真51单片机的流水灯实现

proteus介绍&#xff1a; proteus是一个十分便捷的用于电路仿真的软件&#xff0c;可以用于实现电路的设计、仿真、调试等。并且可以在对应的代码编辑区域&#xff0c;使用代码实现电路功能的仿真。 汇编语言介绍&#xff1a; 百度百科介绍如下&#xff1a; 汇编语言是培养…

Spring boot+vue前后端分离

目录 1、前端vue的搭建 2、后端项目的构建 pom文件中引入的jar包 yml文件用来配置连接数据库和端口的设置 application.property进行一些整合 service层 imp层 mapper 实体类 额外写一个类、解决跨域问题 3、测试 1、前端vue的搭建 建立项目的过程略 开启一个建立好…

JDK下载安装Java SDK

Android中国开发者官网 Android官网 (VPN翻墙) 通过brew命令 下载OracleJDK(推荐) 手动下载OracleJDK(不推荐) oracle OracleJDK下载页 查找硬件设备是否已存在JDK环境 oracle官网 备注&#xff1a; JetPack JavaDevelopmentKit Java开发的系统SDK OpenJDK 开源免费SDK …

unity3d:GameFramework+xLua+Protobuf+lua-protobuf,生成.cs,.pb工具流

概述 1.区分lua&#xff0c;cs用的proto 2.proto生成cs&#xff0c;使用protogen.exe&#xff0c;通过csharp.xslt修改生成cs样式 3.proto生成lua加载.pb二进制文件&#xff0c;并生成.pb列表文件&#xff0c;用于初始化加载 4.协议id生成cs&#xff0c;lua中枚举 区分cs&…

spring boot3登录开发-2(3邮件验证码接口实现)

⛰️个人主页: 蒾酒 &#x1f525;系列专栏&#xff1a;《spring boot实战》 目录 写在前面 上文衔接 接口设计与实现 1.接口分析 2.实现思路 3.代码实现 1.定义验证码短信HTML模板枚举类 2.定义验证码业务接口 3. 验证码业务接口实现 4.控制层代码 4.测试 写…

【原创】springboot+mysql农业园区管理系统设计与实现

个人主页&#xff1a;程序猿小小杨 个人简介&#xff1a;从事开发多年&#xff0c;Java、Php、Python、前端开发均有涉猎 博客内容&#xff1a;Java项目实战、项目演示、技术分享 文末有作者名片&#xff0c;希望和大家一起共同进步&#xff0c;你只管努力&#xff0c;剩下的交…

【物联网实战项目】STM32C8T6+esp8266/mqtt+dht11+onenet+uniapp

一、实物图 前端uniapp效果图&#xff08;实现与onenet同步更新数据&#xff09; 首先要确定接线图和接线顺序&#xff1a; 1、stm32c8t6开发板连接stlinkv2下载线 ST-LINK V2STM323.3V3.3VSWDIOSWIOSWCLKSWCLKGNDGND 2、ch340串口连接底座&#xff08;注意RXD和TXD的连接方式…

数据结构之计数排序算法【图文详解】

P. S.&#xff1a;以下代码均在VS2019环境下测试&#xff0c;不代表所有编译器均可通过。 P. S.&#xff1a;测试代码均未展示头文件stdio.h的声明&#xff0c;使用时请自行添加。 博主主页&#xff1a;LiUEEEEE                        …

贪心算法-加油站

一、题目描述 二、解题思路 1.运动过程分析 这里需要一个油箱剩余油量的变量resGas&#xff0c;初始化resGas0&#xff1b;还需要一个标记从什么位置当做初始位置的startIdx&#xff0c;初始化startIdx0。 我们从数组下标idx0处开始向后遍历&#xff0c;初始时startIdx0&#…