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)---词法分析的有关概念以及转换图

    词法分析(1)---词法分析的有关概念以及转换图 2009-09-26 23:52:03 阅读(9) 发表评论 词法分析是编译的第一个阶段,前面简介中也谈到过词法分析器的任务就是: 字符流------ ...

  2. Android 数据库综述(二) 程序计算器与信号量来处理多线程并发问题

    Android 数据库综述(二) 程序计算器与信号量来处理多线程并发问题 多线程操作数据库,为处理并发问题,大家第一想到的是加锁操作 ,SQLite是文件级别的锁.SQLite3对于并发的处理机制是允 ...

  3. BT源代码学习心得(二):程序运行参数的获取 -- 转贴自 wolfenstein (NeverSayNever)

    BT源代码学习心得(二):程序运行参数的获取 发信人: wolfenstein (NeverSayNever), 个人文集 标  题: BT源代码学习心得(二):程序运行参数的获取 发信站: 水木社区 ...

  4. CSDN日报19035——流浪地球 春节十二响程序开源代码

    游戏开发 | [流浪地球]春节十二响程序开源代码 作者:刺客五六柒 前几天看完流浪地球,被李长条的春节十二响惊到了,这几天看了下别的博主写的开源伪代码(借鉴了框架),试着用CMD实现了模拟的行星发动机 ...

  5. 恒压供水一拖二(程序图纸)采用西门子224xp plc ,昆仑通态触摸屏

    恒压供水一拖二(程序图纸) 1.采用西门子224xp plc ,昆仑通态触摸屏: 2.适用于大小功率,工 变频互锁控制,安全,可靠: 3.西门子224xp plc模拟量输出调速,适用市场所有变频器: ...

  6. 机智云代码移植_【机智云Gokit3测评】设备接入-步骤二:程序移植

    [机智云Gokit3测评]设备接入-步骤二:程序移植 [复制链接] 1.写在前面 2.下载软件包 进入机智云官网的开发者中心后,点击"下载中心"(https://download. ...

  7. 恒压供水一拖二(程序图纸) 采用西门子224xp plc ,昆仑通态触摸屏

    恒压供水一拖二(程序图纸) 1.采用西门子224xp plc ,昆仑通态触摸屏: 2.适用于大小功率,工/变频互锁控制,安全,可靠: 3.西门子224xp plc模拟量输出调速,适用市场所有变频器: ...

  8. 二本程序员投简历被公司嘲讽:过面试的可能性不大,别白跑了

    一名毕业于二本院校的程序员曝光了其求职的奇葩遭遇.事情的经过是这样的,这名二本程序员投递了某公司的开发岗位,HR问其毕业于哪一年,高考分数多少,当楼主回答后被告知,过面试的可能性不大,别白跑了云云. ...

  9. 仿淘宝头像上传功能(二)——程序篇

    目录: 仿淘宝头像上传功能(一)--前端篇. 仿淘宝头像上传功能(二)--程序篇. 仿淘宝头像上传功能(三)--兼容 IE6 浏览器 源码下载: 仿淘宝头像上传并裁剪功能.zip 这里先定义了一个类, ...

  10. 解决方案编程苦B和二B程序员别忘了养生

    本篇文章是一篇关于解决方案编程的帖子 经过多年的埋伏视察,我发现世界上的程序员可以分为两类,不论他们使用何种技术: A. 二B程序员(Day Programmers) B. 苦B程序员(Night P ...

最新文章

  1. simulink中错误object[id]!=NULL Component: Simulink | Category:Model error
  2. CDK上安装kube-dashboard
  3. 【poj3070】Fibonacci
  4. CGCKD2021大会报告整理(4)--风格迁移
  5. mysql中in的使用
  6. C语言1013山东理工大学试题,山东理工大学史上最全C语言PPTC程序设计(2基本数据与运算).ppt...
  7. LeetCode 387:first-unique-character-in-a-string
  8. 加精!大型互联网应用基于CAS的SSO架构
  9. [JNI]开发实例(1)封装libjpeg库 保证图片质量压缩图片
  10. 二叉树的四种遍历算法
  11. SQL连接表(内连接、左连接、右连接、交叉连接、全外连接)
  12. presscad图层LIsp_为什么我用统赢软件在CAD里面转完程式后老是出现CAD没有响应的情况?...
  13. 用Python制作fits文件
  14. 管理之旅(01)游学阿里
  15. 第三方支付平台业务分析
  16. android 日历翻页动画,Android 仿日历翻页、仿htc时钟翻页、数字翻页切换效果
  17. Shell ifs 用法
  18. Vue项目中使用Tinymce
  19. wordpress配置SSL证书
  20. linux在3T的分区磁盘上追加空间

热门文章

  1. 学计算机要学数学么,学计算机数学要求高吗 数学不好怎么办?
  2. 传统运维已然淘汰,市场上究竟哪种运维平台适用于变电所场景呢?
  3. kendryte K210开发:关于MAIX BIT 无法使用 kendryte IDE 下载的问题
  4. mysql数据库显示unknown option '-d' 错误的处理办法
  5. 数据库查询时出现 unknown column
  6. 你可得知道物理地址与IP地址
  7. 分离 Alpha 通道
  8. 论文阅读:PVO: Panoptic Visual Odometry
  9. 【条形码识别】基于计算机视觉实现二维条形码识别含Matlab源码
  10. linux centos 最新版本,Linux 发行版