词法分析二(词法分析程序)
1、词法分析功能
输入:所给文法的源程序字符串。
输出:二元组(syn,token或sum)构成的序列。其中,
syn为单词种别码。
Token为存放的单词自身字符串。
Sum为整型常量。
具体实现时,可以将单词的二元组用结构进行处理。
2、待分析的C语言子集的词法
1)关键字
main if then while do static int double struct break else long switch case typedef char return const float short continue for void default sizeof
所有的关键字都是小写。
2)运算符和界符
+ - * / : < <> <= > >= = ; ( ) #
3)其他标记ID和NUM
通过以下正规式定义其他标记:
ID→letter(letter|digit)*
NUM→digit digit*
letter→a|…|z|A|…|Z
digit→0|…|9…
4)空格由空白、制表符和换行符组成
空格一般用来分隔ID、NUM、专用符号和关键字,词法分析阶段通常被忽略。
3、各种单词符号对应的种别码
表1 各种单词符号的种别码
单词符号 种别码 单词符号 种别码 单词符号 种别码 单词符号 种别码 单词符号 种别码
# 0 else 11 for 22 == 33 ) 44
main 1 long 12 void 23 < 34 { 45
if 2 switch 13 default 24 <> 35 } 46
then 3 case 14 sizeof 25 <= 36 , 47
while 4 typedef 15 ID 26 > 37
do 5 char 16 NUM 27 >= 38
static 6 return 17 + 28 = 39
int 7 const 18 - 29 [ 40
double 8 float 19 * 30 ] 41
struct 9 short 20 / 31 ; 42
break 10 continue 21 ** 32 ( 43
上述为一些基本符号,可以自己另加。
状态转换图:
代码:
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <cstring>
#include <string>
using namespace std;FILE *fp; // 文件指针,处理源文件
char *ScanBuffer; // 扫描缓冲区,一分为二,每次一半存放预处理后的字符串
int capacity; // 扫描缓冲区容量
int BufferFlag; // 状态标志,0 表示使用缓冲区的左半区,1 表示使用右半区
int PreprocessFlag; // 预处理的状态标志
string rwtab[25]={"main","if","then","while","do"," static","int"," double","struct","break","else","long","switch","case","typedef","char","return","const","float","short","continue","for","void","default","sizeof"};// init fp, ScanBuffer, BufferFlag,SP,EP,PreprocessFlag
void init(){fp = fopen("test.txt","r");if(fp == NULL) exit(0);capacity = 120; ScanBuffer = new char[capacity]; // 缓冲区分配长度 :120。 memset(ScanBuffer,0,sizeof(ScanBuffer));BufferFlag = 0; PreprocessFlag = 0;
}void close(){fclose(fp);delete ScanBuffer;
}void Preprocess(){//参见词法分析一
}/*
分析器变量 SP: 分析器的起点指示器 EP: 分析器的搜索指示器syn: 种别编码token: 存放一个处理的字符串sum: 常量status:状态
*/int SP = 0; int EP = 0;
int syn = -1; string token = "";
int sum = 0; int status = 0;// 字母
int IsLetter(char c){if(c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z') return 1;return 0;
}//数字
int IsDigit(char c){if(c >= '0' && c <= '9') return 1;return 0;
} // 关键字或者是变量
void Key(){token = "";if(SP < EP){for(int i = SP; i < EP; i++) token.push_back(ScanBuffer[i]);}else{for(int i = SP; i < capacity; i++) token.push_back(ScanBuffer[i]);for(int i = 0; i < EP; i++) token.push_back(ScanBuffer[i]);}for(int i = 0; i < 25; i++) if(token.compare(rwtab[i]) == 0) {syn = i+1; return;}syn = 26; return;
}void Number(){sum = 0;if(SP < EP){for(int i = SP; i < EP; i++) sum = sum * 10 + ScanBuffer[i] - '0';}else{for(int i = SP; i < capacity; i++) sum = sum * 10 + ScanBuffer[i] - '0';for(int i = 0; i < EP; i++) sum = sum * 10 + ScanBuffer[i] - '0';}syn = 27;
}// 不合法变量的处理,例如以数字开头的变量
void InvalidToken(){token = "";if(SP < EP){for(int i = SP; i < EP; i++) token.push_back(ScanBuffer[i]);}else{for(int i = SP; i < capacity; i++) token.push_back(ScanBuffer[i]);for(int i = 0; i < EP; i++) token.push_back(ScanBuffer[i]);}while(IsLetter(ScanBuffer[EP]) || IsDigit(ScanBuffer[EP])) {token.push_back(ScanBuffer[EP]); EP++;}
}// 单个字符 ,例如‘<’
void OneCharacter(){switch(status){case 11: syn = 39; break;case 16: syn = 30; break;case 22: syn = 34; break;case 24: syn = 37; break;}
}
// 双字符 ,例如‘<=’
void TwoCharacter(){switch(status){case 12: syn = 33; break;case 17: syn = 32; break;case 20: syn = 35; break;case 21: syn = 36; break;case 25: syn = 38; break;}
}void CharacterMatch(char ch){switch(ch){case ' ': break;case ';': {status = 5; syn = 42; break;}case '(': {status = 6; syn = 43; break;}case ')': {status = 7; syn = 44; break;}case '[': {status = 8; syn = 40; break;}case ']': {status = 9; syn = 41; break;}case '{': {status = 27;syn = 45; break;}case '}': {status = 28;syn = 46; break;}case ',': {status = 29;syn = 47; break;}case '+': {status = 13;syn = 28; break;}case '-': {status = 14;syn = 29; break;}case '/': {status = 18;syn = 31; break;}case '#': {status = 26;syn = 0; break;}case '=': {status = 10; break;}case '*': {status = 15; break;}case '<': {status = 19; break;}case '>': {status = 23; break;}default: {status = -1; break;}}
}void StatusHandle(){switch(status){case -2: {InvalidToken(); cout<<"invalid token: "<<token<<endl; status = 0; SP = EP;break;}case -1: {printf("invalid character: %c\n",ScanBuffer[EP]); EP++; status = 0; SP = EP;break;}case 1: case 3: case 10: case 15: case 19: case 23:{EP++; break;}case 0:{EP++; SP = EP; break;}case 2:{Key(); cout<<"("<<syn<<","<<token<<")"<<endl; SP = EP; status = 0; break;}case 4:{Number();cout<<"("<<syn<<","<<sum<<")"<<endl; SP = EP; status = 0; break;}case 5:case 6:case 7:case 8:case 9:case 13:case 14:case 18:case 26:case 27:case 28:case 29:{cout<<"("<<syn<<","<<ScanBuffer[SP]<<")"<<endl; EP++; SP = EP; status = 0; break;}case 11: case 16: case 22: case 24:{OneCharacter(); cout<<"("<<syn<<","<<ScanBuffer[SP]<<")"<<endl; SP++; EP = SP; status = 0; break;}case 12: case 17: case 20: case 21: case 25:{TwoCharacter(); cout<<"("<<syn<<","<<ScanBuffer[SP]<<ScanBuffer[EP]<<")"<<endl; EP++; SP = EP; status = 0; break;}}
}// 状态转换图
void Analyse(char ch){switch(status){case 0:{if(IsLetter(ch)) status = 1;else if(IsDigit(ch)) status = 3;else CharacterMatch(ch);break;}case 1:{if(IsLetter(ch) || IsDigit(ch)) break;else status = 2; break;}case 3:{if(IsDigit(ch)) break;else if(IsLetter(ch)){status = -2; break;}else {status = 4; break;}}case 10:{if(ch == '=') {status = 12; break;}else status = 11; break;}case 15:{if(ch == '*') {status = 17; break;}else status = 16; break;}case 19:{if(ch == '>') {status = 20; break;}else if(ch == '='){status = 21; break;}else status = 23;break;}case 23:{if(ch == '=') {status = 25; break;}else status = 24; break;}}StatusHandle();
}void Analyzer(){while(!feof(fp)){Preprocess(); BufferFlag = BufferFlag ^ 1;if(BufferFlag){EP = 0; // 使用左半缓冲区if(SP == capacity) SP = 0; // 防止SP越界while(ScanBuffer[EP] != -1 && EP < capacity/2){Analyse(ScanBuffer[EP]);}}else{while(ScanBuffer[EP] != -1 && EP < capacity){Analyse(ScanBuffer[EP]);}}}
}int main(){init();Analyzer();close();return 0;
}
测试用例:
// 单行注释
/*
多行注释
*/
int ArraySum(int **a, int m, int n){
int 9sum = 0;
for(int i = 0; i < m; i = i + 1){
for(int j = 0; j < n; j = j + 1){
sum = sum + a[i][j];
}
}
return sum;
}
测试结果:
词法分析二(词法分析程序)相关推荐
- 词法分析(1)---词法分析的有关概念以及转换图
词法分析(1)---词法分析的有关概念以及转换图 2009-09-26 23:52:03 阅读(9) 发表评论 词法分析是编译的第一个阶段,前面简介中也谈到过词法分析器的任务就是: 字符流------ ...
- Android 数据库综述(二) 程序计算器与信号量来处理多线程并发问题
Android 数据库综述(二) 程序计算器与信号量来处理多线程并发问题 多线程操作数据库,为处理并发问题,大家第一想到的是加锁操作 ,SQLite是文件级别的锁.SQLite3对于并发的处理机制是允 ...
- BT源代码学习心得(二):程序运行参数的获取 -- 转贴自 wolfenstein (NeverSayNever)
BT源代码学习心得(二):程序运行参数的获取 发信人: wolfenstein (NeverSayNever), 个人文集 标 题: BT源代码学习心得(二):程序运行参数的获取 发信站: 水木社区 ...
- CSDN日报19035——流浪地球 春节十二响程序开源代码
游戏开发 | [流浪地球]春节十二响程序开源代码 作者:刺客五六柒 前几天看完流浪地球,被李长条的春节十二响惊到了,这几天看了下别的博主写的开源伪代码(借鉴了框架),试着用CMD实现了模拟的行星发动机 ...
- 恒压供水一拖二(程序图纸)采用西门子224xp plc ,昆仑通态触摸屏
恒压供水一拖二(程序图纸) 1.采用西门子224xp plc ,昆仑通态触摸屏: 2.适用于大小功率,工 变频互锁控制,安全,可靠: 3.西门子224xp plc模拟量输出调速,适用市场所有变频器: ...
- 机智云代码移植_【机智云Gokit3测评】设备接入-步骤二:程序移植
[机智云Gokit3测评]设备接入-步骤二:程序移植 [复制链接] 1.写在前面 2.下载软件包 进入机智云官网的开发者中心后,点击"下载中心"(https://download. ...
- 恒压供水一拖二(程序图纸) 采用西门子224xp plc ,昆仑通态触摸屏
恒压供水一拖二(程序图纸) 1.采用西门子224xp plc ,昆仑通态触摸屏: 2.适用于大小功率,工/变频互锁控制,安全,可靠: 3.西门子224xp plc模拟量输出调速,适用市场所有变频器: ...
- 二本程序员投简历被公司嘲讽:过面试的可能性不大,别白跑了
一名毕业于二本院校的程序员曝光了其求职的奇葩遭遇.事情的经过是这样的,这名二本程序员投递了某公司的开发岗位,HR问其毕业于哪一年,高考分数多少,当楼主回答后被告知,过面试的可能性不大,别白跑了云云. ...
- 仿淘宝头像上传功能(二)——程序篇
目录: 仿淘宝头像上传功能(一)--前端篇. 仿淘宝头像上传功能(二)--程序篇. 仿淘宝头像上传功能(三)--兼容 IE6 浏览器 源码下载: 仿淘宝头像上传并裁剪功能.zip 这里先定义了一个类, ...
- 解决方案编程苦B和二B程序员别忘了养生
本篇文章是一篇关于解决方案编程的帖子 经过多年的埋伏视察,我发现世界上的程序员可以分为两类,不论他们使用何种技术: A. 二B程序员(Day Programmers) B. 苦B程序员(Night P ...
最新文章
- simulink中错误object[id]!=NULL Component: Simulink | Category:Model error
- CDK上安装kube-dashboard
- 【poj3070】Fibonacci
- CGCKD2021大会报告整理(4)--风格迁移
- mysql中in的使用
- C语言1013山东理工大学试题,山东理工大学史上最全C语言PPTC程序设计(2基本数据与运算).ppt...
- LeetCode 387:first-unique-character-in-a-string
- 加精!大型互联网应用基于CAS的SSO架构
- [JNI]开发实例(1)封装libjpeg库 保证图片质量压缩图片
- 二叉树的四种遍历算法
- SQL连接表(内连接、左连接、右连接、交叉连接、全外连接)
- presscad图层LIsp_为什么我用统赢软件在CAD里面转完程式后老是出现CAD没有响应的情况?...
- 用Python制作fits文件
- 管理之旅(01)游学阿里
- 第三方支付平台业务分析
- android 日历翻页动画,Android 仿日历翻页、仿htc时钟翻页、数字翻页切换效果
- Shell ifs 用法
- Vue项目中使用Tinymce
- wordpress配置SSL证书
- linux在3T的分区磁盘上追加空间
热门文章
- 学计算机要学数学么,学计算机数学要求高吗 数学不好怎么办?
- 传统运维已然淘汰,市场上究竟哪种运维平台适用于变电所场景呢?
- kendryte K210开发:关于MAIX BIT 无法使用 kendryte IDE 下载的问题
- mysql数据库显示unknown option '-d' 错误的处理办法
- 数据库查询时出现 unknown column
- 你可得知道物理地址与IP地址
- 分离 Alpha 通道
- 论文阅读:PVO: Panoptic Visual Odometry
- 【条形码识别】基于计算机视觉实现二维条形码识别含Matlab源码
- linux centos 最新版本,Linux 发行版