词法分析器(分析C语言)

2023-11-12

问题描述:

用C或C++语言编写一个简单的词法分析程序,扫描C语言小子集的源程序,根据给定的词法规则,识别单词,填写相应的表。如果产生词法错误,则显示错误信息、位置,并试图从错误中恢复。简单的恢复方法是忽略该字符(或单词)重新开始扫描。
相关词法规则
<标识符>::=<字母>
<标识符>::=<标识符><字母>
<标识符>::=<标识符><数字>
<常量>::=<无符号整数>
<无符号整数>::=<数字序列>
<数字序列>::=<数字序列><数字>
<数字序列>::=<数字>
<字母>::=a|b|c|……|x|y|z
<数字>::=0|1|2|3|4|5|6|7|8|9
<加法运算符>::=+|-
<乘法运算符>::=*|/
<关系运算符>::=<|>|!=|>=|<=|==
<分界符>::=,|;|(|)|{|}
<保留字>::=main|int|if|else|while|do

编写词法分析程序的步骤:

(1)确定所要翻译的语言(或其子集)。
C语言
(2)设计属性字,及各类表格,如标识符表、常量表、符号及其机内表示对照表等。
与词法分析有关的表格:
1. 字符表

保留字:main,int,if,else,while,do
字母(全小写):a|b|c|……|x|y|z
数字:0,1,2,3,4,5,6,7,8,9
运算符和界符:<,>,!=,>=,<=,==,,,;,(,),{,}

2. 特定单词机内表示表
这里写图片描述

3.画出总控流程图及各个子程序的流程图。
这里写图片描述
4. 程序
输入:一个存放C语言程序的s.txt文件
输出:存放以(单词,种别码)形式输出的result.txt文件

需要6个数组:

  1. 存储关键字 key[6]
  2. 存储对应下标关键字的种别码 keyNum[6]
  3. 存储运算符和界符 symbol[17]
  4. 存储运算符对应下标的种别码 symbolNum[17]
  5. 存储从文件中取出的每个字符(不包括括号)letter[1000]

主要函数:
TakeWord();
功能:将文件letter[]中每个字符进行提取,找出关键字,输出种别码
Num作为全局变量保存提取到字符的哪个下标

  1. 先提取一个字符,如果是字母,进入case1,调用identifier(),不断的提取字母或数字进行连接,没连接一个字符用int isKeyWord()程序(返回关键字种别码)判断是否为关键字,是就退出函数返回string,不是就继续执行函数,直到连接的字符不再是字母或数字,即此时字符串为标识符
  2. 如果是数字,进入case 2,调用Number()函数,不断进行字符串连接,知道下一个连接字符不再是数字
  3. 如果是符号,进入case 3,调用symbolStr()函数,如果是=,>,<,!,则要继续进行下个字符判断,其余符号可以直接返回
    其他辅助函数:
    int isSymbol()判断运算符和界符,并返回种别码
    bool isNum() 判断是否为数字
    bool isLetter()判断是否为字母
    int isKeyWord()判断是否为关键字,是返回种别码
    int typeword()返回单个字符的类型
    string identifier()标识符的连接
    string symbolStr()符号和界符的连接
    string Number()数字的连接
    void print()输出

程序:

#include <iostream>
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
using namespace std;

//关键字 
string key[6]={"main","int","if","else","while","do"};    
//关键字的种别码
int keyNum[6]={1,2,3,4,5,6}; 
//运算符和界符 
string symbol[17]={"<",">","!=",">=","<=","==",",",";","(",")","{","}","+","-","*","/","="};
//char symbol[12]={'<','>','!=','>=','<=','==',',',';','(',')','{','}'};
//运算符和界符的种别码 
int symbolNum[17]={7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23};
//存放文件取出的字符 
string letter[1000];
//将字符转换为单词
string  words[1000];
int length;  //保存程序中字符的数目 
int num;

int isSymbol(string s){ //判断运算符和界符 
	int i;
    for(i=0;i<17;i++){
        if(s==symbol[i])
            return symbolNum[i]; 
    }
    return 0;
} 

//判断是否为数字 
bool isNum(string s){
	if(s>="0" && s<="9")
        return true;
    return false;
}

//判断是否为字母 
bool isLetter(string s)
{
    if(s>="a" && s<="z")
        return true;
    return false;
}

//判断是否为关键字,是返回种别码 
int isKeyWord(string s){
	int i;
	for(i=0;i<6;i++){
		if(s==key[i])
			return keyNum[i];
	}
	return 0;
}
 
//返回单个字符的类型 
int typeword(string str){
	if(str>="a" && str<="z")   //	字母 
        return 1;
        
    if(str>="0" && str<="9")   //数字 
        return 2;
        
    if(str==">"||str=="="||str=="<"||str=="!"||str==","||str==";"||str=="("||str==")"||str=="{"||str=="}"
		||str=="+"||str=="-"||str=="*"||str=="/")   //判断运算符和界符 
        return 3; 

}

string identifier(string s,int n){
	int j=n+1;
	int flag=1;
	
	while(flag){
		if(isNum(letter[j]) || isLetter(letter[j])){
			s=(s+letter[j]).c_str();
			if(isKeyWord(s)){
				j++;
				num=j;
				return s;
			}
			j++;
		}
		else{
			flag=0;
		}
	} 
	
	num=j;
	return s;
}

string symbolStr(string s,int n){
	int j=n+1;
	string str=letter[j];
	if(str==">"||str=="="||str=="<"||str=="!") {
		s=(s+letter[j]).c_str();
		j++;
	}
	num=j;
	return s;
}

string Number(string s,int n){
	int j=n+1;
	int flag=1;
	
	while(flag){
		if(isNum(letter[j])){
			s=(s+letter[j]).c_str();
			j++;
		}
		else{
			flag=0;
		}
	}
	
	num=j;
	return s;
}

void print(string s,int n){
	cout<<"("<<s<<","<<n<<")"<<endl;
}

void TakeWord(){  //取单词 
    int k;
    
	for(num=0;num<length;){
		string str1,str;
		str=letter[num];
		k=typeword(str);
		switch(k){
			case 1:
				{
					str1=identifier(str,num);
					if(isKeyWord(str1))
						print(str1,isKeyWord(str1));
					else
						print(str1,0);
					break;
				}
			
		    case 2:
		    	{
		    		str1=Number(str,num);
			    	print(str1,24);
			    	break;
				}

		    case 3:
		    	{
			    	str1=symbolStr(str,num);
			    	print(str1,isSymbol(str1));
			    	break;	
				}
		    	
		}
		
	} 
}

int main(){
	char w;
	int i,j;

	freopen("s.txt","r",stdin);
	freopen("result.txt","w",stdout); //从控制台输出,而不是文本输出
	
	length=0;
	while(cin>>w){
		if(w!=' '){
			letter[length]=w;
			length++;
		}   //去掉程序中的空格
	}
	
	TakeWord();
//	for(j=0;j<length;j++){
//		cout<<letter[j]<<endl;
//	} 

	fclose(stdin);//关闭文件 
    fclose(stdout);//关闭文件 
	return 0;
} 

运行结果:

s.txt

这里写图片描述

Result.txt

这里写图片描述

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

词法分析器(分析C语言) 的相关文章

随机推荐

  • 如何在win11上运行VC6.0

    说明 win11是在win10的基础上开发的不完全 体 VC6 0在win11上不能正常运行 方法 1 下载安装软件 安装包链接 https pan baidu com s 17cV V9BqOCEhqm5Ss8i8Zw 提取码 64mz
  • 抓取餐厅菜单信息 - 从餐饮网站获取餐厅菜单信息及价格

    目录 1 分析目标网站的结构 2 安装所需库 3 编写爬虫程序 4 提取所需数据并保存结果
  • Android Studio支持系统签名(证书)

    让Android Studio集成系统签名 需要用到一个工具keytool importkeypair 这个工具的作用是将系统签名的相关信息导入到已有的签名文件里 可从这里下载 相关文件 platform x509 pem platform
  • Java WebService _CXF、Xfire、AXIS2、AXIS1_四种发布方式(优缺点对比)

    xis axis2 Xfire以及cxf对比 http ws apache org axis http axis apache org axis2 java core http xfire codehaus org http cxf apa
  • DVP,LVDS和MIPI

    Mipi 接口 和 LVDS 接口区别 主要区别 1 LVDS接口只用于传输视频数据 MIPI DSI不仅能够传输视频数据 还能传输控制指令 2 LVDS接口主要是将RGB TTL信号按照SPWG JEIDA格式转换成LVDS信号进行传输
  • 记录自己在结构光三维重建领域的学习过程(五)

    读了一篇论文 Domain randomization for transferring deep neural networks from simulation to the real world 讲的是域随机化 但其实我没有认真看 其实
  • html转pdf

    html转pdf 本地安装wkhtmltopdf Java操作wkhtmltopdf实现Html转PDF 本地测试
  • sqlite3的交叉编译

    比如说我们在qtcreator中编写程序的时候想用到sqlite3数据库 但是因为qtcreator中的编译器中的库中并没有sqlite3的库 所以肯定编译不了 所以若想在qtcreator中编译sqlite3的程序 首先的将sqlite3
  • 初级python爬虫薪资-月薪2万的爬虫工程师,Python需要学到什么程度?

    Python 爬虫学到什么样就可以找工作了 非计算机专业 正在自学python 很多教程里提到的网站的爬虫都会写了 比如拉勾网 豆瓣 实习僧 京东 淘宝 某妹子图等等 但是因为不是计算机专业的 也没学所谓的四大名著 不知道那四大对找工作重要
  • 残体字符设计:INVETA

    残体字符设计是logo设计中很常见的一种风格 它通过删减 多余 的笔画来实现残缺的字符 让读者通过 脑补 还原出原来的文字 以此独特的风格加深用户的产品印象 Github支持STL文本格式的3D模型预览 奈何STL格式非常简陋 难以表示复杂
  • android 的 Testing Support Library 测试支持包(库)

    Testing Support Library 测试支持包 库 这个库提供了一系列的api来快速的创建和运行测试对于你的app 包括jUnit 4 和用户 UI 的测试 创建可以使用android studio IDE 或者通过命令行 两种
  • 日志:slf4j+logback 的配置与使用

    1 常用日志组件和选择 java开发日志处理是发现和调试bug所 必不可少的 那么现在企业中常用的日志组件有哪些呢 JCL JUL SLF4j Log4j Log4j2 Logback jboss loggin 等 一般日志是配套出现的 一
  • 内存请求分页实验java_请求分页内存管理的模拟

    一 实验题目 二 代码 1 Main java package OS import java util Scanner public class Main public static int pageSize blockSize procS
  • CentOS8提高篇11:centos8软件安装dnf命令

    DNF是新一代的rpm软件包管理器 它首先出现在 Fedora 18 这个发行版中 而目前 它取代了yum 正式成为从 Fedora 22 起 Fedora 版本的包管理器 DNF包管理器克服了YUM包管理器的一些瓶颈 提升了包括用户体验
  • SE0、J、K 、Chirp J、Chirp K

    SE0 J K Chirp J Chirp K 是 USB 总线上常见的信号状态 用于表示不同的电平和信号类型 SE0 Single Ended Zero 是 USB 总线上的空闲状态 表示逻辑低电平 在 SE0 状态下 数据线 D 和 D
  • Git 强制回退到某个历史版本再推送到远程

    1 使用 git log 命令历史版本记录回退版本 git reset hard f6a7c803a6931a9eca011d4e097389e0845cbe49 2 推送到远程 git push f u origin master ps
  • sqli-labs18、19关详解

    18关 对两个输入框都进行了设置 所以只能寻找其他注入点 看到insert语句从uagents插入 我们可以用http header live插件得到post内容放进hackbar中 再在user agent里面添加修改
  • [382]定时任务JoBX(opencron升级版)

    opencron文章链接 https blog csdn net xc zhou article details 80950811 升级日志 V1 2 0 by 2018 xx xx 1 支持Window端 实现全平台编译和安装 2 简化安
  • 八大排序算法总结Java代码实现(建议收藏后食用)

    目录 排序算法介绍 相关术语 排序的稳定性 排序分类 内排序与外排序 算法时间复杂度 度量一个程序 算法 执行时间的两种方法 时间频度 忽略常数项 忽略低次项 忽略系数 时间复杂度 常数阶O 1 对数阶O log2n 线性阶O n 线性对数
  • 词法分析器(分析C语言)

    问题描述 用C或C 语言编写一个简单的词法分析程序 扫描C语言小子集的源程序 根据给定的词法规则 识别单词 填写相应的表 如果产生词法错误 则显示错误信息 位置 并试图从错误中恢复 简单的恢复方法是忽略该字符 或单词 重新开始扫描 相关词法