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

news2024/11/26 14:36:10

编译原理-词法分析


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; // == 的种别码为39
                myword -> word = "==";
                return (myword);
            }
            retract();
            myword -> typenum = 25; // = 的种别码为25
            myword -> word = "=";
            return (myword);
            break;
        case '+' : 
            myword -> typenum = 13; // + 的种别码为13
            myword -> word = "+";
            return (myword);
            break;
        case '-' : 
            myword -> typenum = 14; // - 的种别码为14
            myword -> word = "-";
            return (myword);
            break;
        case '*' : 
            myword -> typenum = 15; // * 的种别码为15
            myword -> word = "*";
            return (myword);
            break;
        case '/' : 
            myword -> typenum = 16; // / 的种别码为16
            myword -> 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.coloradmin.cn/o/1803293.html

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

相关文章

uc_os操作练习

目录 一、CubeMX配置 二、获取uc-os源码 三、代码移植 四、代码修改 五、总结 六、参考资料 一、CubeMX配置 首先进入CubeMX&#xff0c;&#xff0c;新建工程&#xff0c;选择STM32F103C8T6芯片&#xff0c;照例配置好RCC和SYS。 然后配置GPIO输出&#xff0c;这里选择P…

HarmonyOS(二十三)——HTTP请求实战一个可切换的头条列表

在前一篇文章&#xff0c;我们已经知道如何实现一个http请求的完整流程&#xff0c;今天就用官方列子实战一个简单的新闻列表。进一步掌握ArkTS的声明式开发范式&#xff0c;数据请求&#xff0c;常用系统组件以及touch事件的使用。 主要包含以下功能&#xff1a; 数据请求。…

matplotlib 动态显示梯度下降过程

文章目录 简介曲线下降曲面下降 简介 梯度下降是一种优化算法&#xff0c;常用于寻找函数的最小值或最大值。它通过迭代更新参数的方式逐步减小&#xff08;或增大&#xff09;目标函数的值&#xff0c;直到达到某个停止条件为止。梯度下降的基本思想是沿着目标函数的负梯度方…

BeagleBone Black入门总结

文章目录 参考连接重要路径系统镜像下载访问 BeagleBone 参考连接 镜像下载启动系统制作&#xff1a;SD卡烧录工具入门书籍推荐&#xff1a;BeagleBone cookbookBeagleBone概况&#xff1f; 重要路径 官方例程及脚本路径&#xff1a;/var/lib/cloud9 系统镜像下载 疑问&am…

电子设计教学新篇章:SmartEDA引领学校教学升级风潮

在数字化时代的浪潮中&#xff0c;电子设计教学领域正迎来一场革命性的变革。SmartEDA&#xff0c;作为电子设计课程的新宠&#xff0c;以其高效、智能的特性&#xff0c;正成为学校教学升级的重要推手。它不仅极大地提升了电子设计的效率&#xff0c;还为学生们带来了更为深入…

TOGAF数字化转型的关键(文尾附在线TOGAF免费测试)

业务架构驱动数据架构和应用架构的设计&#xff0c;而应用架构又依赖于数据架构和技术架构的支持。技术架构则为整个架构提供了稳定的基础设施。 在数字化转型中&#xff0c;协调和整合这四种架构是至关重要的。通过确保它们之间的一致性和协同工作&#xff0c;可以实现企业业务…

使用OpenPCDet训练与测试Transformer模型:如何加载自己的数据集

引言 Transformer架构因其强大的序列处理能力和长距离依赖捕捉能力&#xff0c;在自然语言处理领域取得了巨大成功。近年来&#xff0c;这一架构也被引入3D物体检测领域&#xff0c;如Voxel Transformer等&#xff0c;显著提升了模型在复杂场景下的检测性能。OpenPCDet整合了多…

K8s速览

k8s的核心能力 ● 服务发现与负载均衡 ● 服务恢复 ● 服务伸缩 ● 自动发布与回滚 ● 批量执行 架构 server-client两层架构&#xff0c;Master作为中央管控节点&#xff0c;会和每一个Node进行一个连接&#xff1b; 所有UI层&#xff0c;client的操作&#xff0c;只会和Mat…

英伟达Docker 安装与GPu镜像拉取

获取nvidia_docker压缩包nvidia_docker.tgz将压缩包上传至服务器指定目录解压nvidia_docker.tgz压缩包 tar -zxvf 压缩包执行rpm安装命令&#xff1a; #查看指定rpm包安装情况 rpm -qa | grep libstdc #查看指定rpm包下的依赖包的版本情况 strings /lib64/libstdc |grep GLI…

酒店旅游API服务汇总

各大旅游平台常用API服务汇总&#xff1a; 实时房源服务【Airbnb】飞猪旅行开放服务途牛旅行开放平台API华为云数字差旅【差旅管理】动态信息接口【美团酒店】旅行商城商家管理API【马蜂窝】交易流程接口【美团酒店】电子导游【携程旅行】

STM32编程:实现LED灯闪烁(基于手写SDK的方式)

项目结构 stm32f10x.h 文件 //寄存器的值常常是芯片外设自动更改的&#xff0c;即使CPU没有执行程序&#xff0c;也有可能发生变化 //编译器有可能会对没有执行程序的变量进行优化//volatile表示易变的变量&#xff0c;防止编译器优化&#xff0c; #define __IO volati…

CSAPP Lab02——Bomb Lab完成思路详解

看见的看不见的 瞬间的永恒的 青草长啊大雪飘扬 ——月亮之上 完整代码见&#xff1a;CSAPP/bomb at main SnowLegend-star/CSAPP (github.com) 01 字符串比较 简单的把输入的字符串和地址“0x402400”内早已存储的字符串相比较。如果两个字符串相等则函数返回&#xff0c;否…

SpringBoot+Vue甘肃非物质文化网站(前后端分离)

技术栈 JavaSpringBootMavenMySQLMyBatisVueShiroElement-UI 系统角色对应功能 用户管理员 系统功能截图

SpringBoot Elasticsearch07-以黑马商场为例-黑马程序员学习笔记

06篇已经导入了大量数据到elasticsearch中&#xff0c;实现了商品数据的存储。不过查询商品数据时依然采用的是根据id查询&#xff0c;而非模糊搜索。 接下来研究下elasticsearch的数据搜索功能。Elasticsearch提供了基于JSON的DSL&#xff08;Domain Specific Language&#…

2024年06月数据库流行度最新排名

点击查看最新数据库流行度最新排名&#xff08;每月更新&#xff09; 2024年06月数据库流行度最新排名 TOP DB顶级数据库索引是通过分析在谷歌上搜索数据库名称的频率来创建的 一个数据库被搜索的次数越多&#xff0c;这个数据库就被认为越受欢迎。这是一个领先指标。原始数…

09-数组的含义以及零长数组变长数组与多维数组

09-数组的含义以及零长数组变长数组与多维数组 文章目录 09-数组的含义以及零长数组变长数组与多维数组一、数组名的含义1.1 表示整个数组的首地址1.2 表示整个数组首元素的首地址 二、数组下标字符串常量 三、零长数组3.1 示例 四、变长数组4.1 示例 五、多维数组5.1 定义与初…

UML实现图-部署图

概述 部署图(Deployent Diagram)描述了运行软件的系统中硬件和软件的物理结构。部署图中通常包含两种元素:节点和关联关系&#xff0c;部署图中每个配置必须存在于某些节点上。部署图也可以包含包或子系统。 节点是在运行时代表计算机资源的物理元素。节点名称有两种:简单名和…

APP开发技术的变迁史

随着移动互联网的迅猛发展&#xff0c;APP&#xff08;应用程序&#xff09;已经成为人们日常生活中不可或缺的一部分。从最初的简单工具到如今的智能平台&#xff0c;APP开发技术在这十年间经历了翻天覆地的变化。本文将从多个维度探讨近十年来APP开发技术的变迁史&#xff0c…

NVeloDocx一个基于NVelocity的word模版引擎

NVeloDocx是一个基于NVelocity的Word模版引擎&#xff0c;目前主要是用于E6低代码开发平台供用户轻松制作各种Word报告模版。 有以下优点&#xff1a; 1、完全的NVelocity语法&#xff1b; 2、直接在Word中写NVelocity脚本&#xff0c;使用非常非常方便&#xff1b; 3、完全兼…

阅读笔记:Life of a Pixel

PPT地址&#xff1a;​​​​​​​​​​​​​​https://docs.google.com/presentation/d/1boPxbgNrTU0ddsc144rcXayGA_WF53k96imRH8Mp34Y/edit?uspsharing 这份PPT讲述了Chromium浏览器内核中html文档渲染成像素的主要过程。网上有很多介绍和转载&#xff0c;内容非常硬核。…