赞
踩
1、文件输入(待分析文本拖入控制台或屏幕输入)
2、划分字符集成7个大类
3、预处理(去除空格、回车换行和非法字符)
4、词法分析
5、打印输出识别的终结符及其类别
- //程序无法识别出double,因为它的前缀子串与do重复(如有需要自主修改)
- /*
- 编译原理实验一:词法分析器
- 要求:编制一个读单词过程,从输入的C语言源程序中,识别出各个具有独立意义的单词,
- 即基本保留字、标识符、常数、运算符、分隔符、特殊字符、控制命令七大类。
- 并依次输出各个单词的内部编码及单词符号自身值的二元组。
- */
-
- /*
- 一、复习c语言字符串数组相关处理,文件相关处理
- //用字符数组存放一个字符串
- char str[ ]="";
- //用字符指针指向一个字符串
- char * s="I love China";
- //二维数组存放字符串数组
- const int N = 5;
- char frd[N][10]={"Hello","World","My","Dear","Friends"};
- //字符指针的数组存放字符串数组
- char *p[]={"This","is","a","char*","array"};
- //文件读写函数原型:FILE *fopen(const char *filename, const char *mode);`头文件:#include <stdio.h>`
- 二、词法分析器
- */
- #include <stdio.h>
- #include <stdlib.h>
- #include <math.h>
- #include <string.h>
- #include <sys/types.h>
- #define MAX_LINE 1024*10
-
- //编码,保留字:1、标识符:2、常数:3、运算符:4、分隔符: 5
-
- //控制命令表
- static char *contCommands[]={"#include","#define","#undef","#asm","#endasm","#ifdef","#ifndef","#else","#endif"};
-
- //关键字表
- static char *keyWords[]={"main","int","double","struct","if","else","char","return","const","float",
- "short","void","while","for","break","then","long","switch","case","do","static","typedef","continue",
- "default","sizeof","do","extern","static","auto","register","sizeof"};
-
- //运算符表
- static char *operators[]={"+","-","*","\/","=","%",">","<","^","&","|","!"};
-
- //分隔符表
- static char *delimiters[]={",","(",")","{","}","[","]",";","\""};
-
- //特殊符号表
- static char *Spesymbols[]={".","$","?","~","^","%","\\","#","&",":","`","@"};
-
- //科学计数法
- // 数字
- //const char* number_rule="^([+-]?\\d+\\.\\d+)|([+-]?\\d+)|([+-]?\\.\\d+)$";
- //const std::regex pattern_number(number_rule, regex::icase);
- //
- 科学计数
- //const char* scientific_rule="^[+-]?((\\d+\\.?\\d*)|(\\.\\d+))[Ee][+-]?\\d+$";
- //const regex pattern_scientific(scientific_rule, regex::icase);
- //
- 十六进制
- //const char* hex_rule="^[+-]?0[xX]([A-Fa-f0-9])+$";
- //const regex pattern_hex(hex_rule, regex::icase);
- //
- 八进制
- //const char* oct_rule="^0([0-7])+$";
- //const regex pattern_oct(oct_rule, regex::icase);
-
- //输入的源程序存放处,最大可以存放MAX_LINE个字符
- static char *resourceProject = (char*)malloc(MAX_LINE * sizeof(char));
- //p = (int*)realloc(p, sizeof(int)* 20);扩容
-
- //存放注释
- static char *commentStr = (char*)malloc(MAX_LINE * sizeof(char));
- static char *commentStr2 = (char*)malloc(MAX_LINE * sizeof(char));
-
- //从str中删除目标字符
- void delete_char(char str[],char target){
- int i,j;
- for(i=j=0;str[i]!='\0';i++){
- if(str[i]!=target){
- str[j++]=str[i];
- }
- }
- str[j]='\0';
- //i-j即为串中存在的目标字符个数
- }
-
- //处理"//,/* */"注释
- void proComment(char str[]){
- int j=0;
- int p=0;
- //遍历resourceProject,记录注释
- for(int i=0; i<strlen(str); i++) {
- if(str[i]=='/'&&str[i+1]=='/') {
- int k=i-1;
- while(str[++k]!='\n') {
- commentStr[p++]=str[k];
- }
- i=k;
- }
- }
- printf("\n单行注释为:%s\n",commentStr);
- //遍历resourceProject,原地删除单行注释
- j=0;
- p=0;
- int i;
- for(i=0; i<strlen(str); i++){
- if(str[i]=='/'&&str[i+1]=='/') {
- p=i;
- while(str[++p]!='\n');
- i=p;
- }else{
- str[j++]=str[i];
- }
- }
- while(j<=i)
- {
- str[j++]='\0';
- }
- printf("\n单行注释处理后的源程序为:\n%s",str);
-
- //处理多行注释“/* 。。。*/”则去除该内容
- int count = 0;
- p=0;
- int k=0;
- for (int i=0;i<strlen(str);i++){
- if(str[i]=='/'&&str[i+1]=='*')
- {
- k=i;
- while(str[k]!='*'||str[k+1]!='/')
- {
- commentStr2[p++]=str[k++];
- }
- commentStr2[p++]='*';
- commentStr2[p++]='/';
- i=k+2;
- }
- // printf("\n多行注释处理后的源程序为:%s\n",str);
- }
- printf("\n多行注释为:%s\n",commentStr2);
- //遍历resourceProject,原地删除多行注释
- j=0;
- p=0;
- for(i=0;str[i]!='\0';i++){
- if(str[i]=='/'&&str[i+1]=='*'){
- i=i+2;
- p=i;
- while(str[p++]!='*'&&str[p+1]!='/');
- i=p+2;
- }else{
- str[j++]=str[i];
- }
- }
- printf("end\n");
- while(j<=i)
- {
- str[j++]='\0';
- }
- printf("\n多行注释处理后的源程序为:\n%s",str);
-
- }//endproComment
-
- //预处理函数(可以写个target数组传进来)
- void preProcessing(){
- //先处理注释,再处理宏定义等预处理,最后处理空格、换行、制表符
- proComment(resourceProject);
- char target1=' ';
- char target2='\t';
- char target3='\n';
- delete_char(resourceProject,target1);
- delete_char(resourceProject,target2);
- delete_char(resourceProject,target3);
- }
-
- //判断是否为字母
- bool isChar(char ch){
- if((ch>='a'&&ch<='z')||(ch>='A'&&ch<='Z'))
- return true;
- return false;
- }
-
- //判断是否为数字
- bool isDigit(char ch){
- if(ch>='0'&&ch<='9')
- return true;
- return false;
- }
-
- //判断是否为定界符等
- bool isDelimiters(char ch){
- for(int i=0;i<sizeof(delimiters)/sizeof(delimiters[0]);i++)
- if(ch==*delimiters[i])
- return true;
- return false;
- }
-
- //判断是否为控制命令
- int isContCommands(char *str){
- for(int i=0;i<sizeof(contCommands)/sizeof(contCommands[0]);i++) {
- if(strcmp(str,contCommands[i])==0){//匹配
- return i;
- }
- }
- //不是关键字即为404
- return 404;
- }
-
- //判断是否为关键字
- int isKeyword(char *str){
- for(int i=0;i<sizeof(keyWords)/sizeof(keyWords[0]);i++) {
- if(strcmp(str,keyWords[i])==0){//匹配
- return i;
- }
- }
- //不是关键字即为404
- return 404;
- }
-
- //判断是否为运算符
- int isOperators(char str){
- for(int i=0; i<sizeof(operators)/sizeof(operators[0]); i++) {
- if(str==*operators[i]){
- return i;
- }
- }
- //不是关键字即为404
- return 404;
- }
-
- //判断是否为特殊字符
- int isSpesymbols(char str){
- for(int i=0; i<sizeof(Spesymbols)/sizeof(Spesymbols[0]); i++) {
- if(str==*Spesymbols[i]){
- return i;
- }
- }
- //不是关键字即为404
- return 404;
- }
-
-
- FILE * readTxt(){
- FILE *fp;
- char filename[100]; //文件名
- char tempstr[1024]; //读文件的缓冲
- bool flag = true; //文件读取成功标志
- printf("请输入或拖入想要打开的文本文件名及其路径,如c:\\temp.txt\n");
- while(flag){
- gets(filename); //这句要用户输入文件名
- char target='"';
- delete_char(filename,target);
- //getchar();
- if ((fp=fopen(filename,"r"))==NULL){//打开文件,并判断是否有打开错误
- printf("打开文件%s出现错误\n",filename);
- memset(filename,0, sizeof filename); //清空数组
- fclose(fp); //关闭文件
- printf("请在检查文件路径后再次输入: \n");
- }
- else
- {
- flag = false;
- //文件读入resourceProject
- int cnt=0;
- // while(!feof(fp)) //读文件,直到文件末尾
- // {
- // resourceProject[cnt++] = fgetc(fp); //将文件内容读入resourceProject
- // }
- printf("文件%s已读取,请检查以下txt文件内容:\n",filename);
- }
- }
-
- if (fp == NULL )
- return 0;
- //以下显示文件内容
- memset(resourceProject,0,sizeof resourceProject);
- while(fgets(tempstr,1024,fp)!=NULL) //读文件一行内容,最多1024字符到缓冲区,并判断是否文件已经结束
- {
- printf("%s",tempstr); //显示缓冲区内容
- strcat(resourceProject,tempstr);//统一读入resourceProject
- }
-
- // fclose(fp); //关闭文件
- return fp;
- }//endRead
-
-
- //读入下一个字符
- char getChar(int p,char str[])
- {
- return str[p];
- }
-
-
- //分析函数
- char textAnalyze(char str[]){
- char* elements[strlen(str)]; //文本元素拆分
- int tag[strlen(str)];//1:关键字 2:标识符 3:常量 4:运算符 5:分隔符 6:特殊字符 7:控制命令
- memset(tag,'\0',sizeof(tag)/sizeof(tag[0]));
- int indTag=0;//tag的index
- int Tag=0;
- memset(elements,'\0',sizeof elements);
- memset(elements,'\0',(sizeof tag)/sizeof tag[0]);
- char ch;//读入的字符
- int p=0;//str的指针
- char token[128]={};//记录变量名
- int m=0;
- while((ch=getChar(p++,str))!='\0'){
- Tag=0;
- //printf("\ngetFirstChar:%c\n",ch);
- memset(token,'\0',sizeof(token)/sizeof(token[0]));
- if(isChar(ch)||ch=='_') //可能是标示符或者关键字
- {
- m=0;
- token[m++]=ch;
- token[m]='\0';
- bool isKey=false;
- int tmp=p;
- bool While=false;
- while(isChar((ch=getChar(tmp++,str)))||isDigit((ch=getChar(--tmp,str))))
- {
- While=true;
- //printf("while:%c\n",ch);
- if(isDigit(ch))
- tmp++;
- token[m++]=ch;
- token[m]='\0';
- p++;
- if(isKeyword(token)!=404)
- {
- tag[indTag++]=1;//关键字
- Tag=1;
- isKey=true;
- // p--;
- break;
- }
-
- }
-
- // token[m++]='\0';
- if(!isKey)
- {
- //p++;
- tag[indTag++]=2;//标识符
- Tag=2;
- }
- //else
- //p++;
-
- //printf("(%d,\"%s\")\n",tag[indTag-1],token);
- printf("(%d,\"%s\")\n",Tag,token);
- }
- else if((ch=='-')||isDigit(ch)||(ch=='.'))//数字
- {
- bool sym=false;
- int m=0;
- char digit[128]={};
- memset(digit,'\0',sizeof(digit)/sizeof(digit[0]));
- digit[m++]=ch;
- digit[m]='\0';
- int tmp=p;
- if((ch=='-')&&isDigit((ch=getChar(tmp+1,str))))
- {
- sym=true;
- }
- long long constNum=0;
- while(isDigit(ch=getChar(tmp,str))||(ch=getChar(tmp,str))=='.'||(ch=getChar(tmp,str))=='e'||(ch=getChar(tmp,str))=='E')
- {
- digit[m++]=ch;
- digit[m]='\0';
- constNum=constNum*10+ch-'0';
- tmp++;
- p++;
- }
- digit[m++] = '\0';//结束符
- if(!sym)
- {
- Tag=3;
- tag[indTag++]=3;//正数常量
- }
- else
- {
- tag[indTag++]=13;//负数常量
- Tag=13;
- }
- if(constNum>9223372036854775807)
- {
- tag[indTag++]=23;//大数常量
- Tag=23;
- }
- printf("(%d,\"%s\")\n",tag[indTag-1],digit);
- }
- else if(isDelimiters(ch))
- {
- // printf("%c\n",ch);
- token[0]=ch;
- token[1]='\0';
- tag[indTag++]=5;
- printf("(%d,\"%s\")\n",tag[indTag-1],token);
- }
- else if(isOperators(ch)!=404)//操作符
- {
- switch(ch) //其他字符
- {
- case'<':
- m=0;
- token[m++]=ch;
- ch=getChar(p++,str);
- if(ch=='='){
- Tag=4;
- tag[indTag++]=4;
- token[m++]=ch;
- token[m++]='\0';
- printf("(%d,\"%s\")\n",tag[indTag-1],token);
- }
- else{
- Tag=4;
- tag[indTag++]=4;
- token[m++]='\0';
- p--;
- printf("(%d,\"%s\")\n",tag[indTag-1],token);
- }
- break;
- case'>':
- m=0;
- token[m++]=ch;
- ch=getChar(p++,str);//取字符
- if(ch=='=')
- {
- Tag=4;
- tag[indTag++]=4;
- token[m++]=ch;
- token[m++]='\0';
- printf("(%d,\"%s\")\n",tag[indTag-1],token);
- }
- else
- {
- p--;
- Tag=4;
- tag[indTag++]=4;
- token[m++]='\0';
- printf("(%d,\"%s\")\n",tag[indTag-1],token);
- }
- break;
- case'|':
- m=0;
- token[m++]=ch;
- ch=getChar(p++,str);//取字符
- if(ch=='|')
- {
- Tag=4;
- tag[indTag++]=4;
- token[m++]=ch;
- token[m++]='\0';
- printf("(%d,\"%s\")\n",tag[indTag-1],token);
- }
- else
- {
- p--;
- Tag=4;
- tag[indTag++]=4;
- token[m++]='\0';
- printf("(%d,\"%s\")\n",tag[indTag-1],token);
- }
- break;
- case'&':
- m=0;
- token[m++]=ch;
- ch=getChar(p++,str);//取字符
- if(ch=='&')
- {
- Tag=4;
- tag[indTag++]=4;
- token[m++]=ch;
- token[m++]='\0';
- printf("(%d,\"%s\")\n",tag[indTag-1],token);
- }
- else
- {
- p--;
- Tag=4;
- tag[indTag++]=4;
- token[m++]='\0';
- printf("(%d,\"%s\")\n",tag[indTag-1],token);
- }
- break;
- case'!':
- m=0;
- token[m++]=ch;
- ch=getChar(p++,str);//取字符
- if(ch=='=')
- {
- tag[indTag++]=4;
- token[m++]=ch;
- token[m++]='\0';
- printf("(%d,\"%s\")\n",tag[indTag-1],token);
- }
- else
- {
- p--;
- tag[indTag++]=4;
- token[m++]='\0';
- printf("(%d,\"%s\")\n",tag[indTag-1],token);
- }
- break;
- default:
- {
- m=0;
- token[m++]=ch;
- token[m++]='\0';
- tag[indTag++]=4;
- printf("(%d,\"%s\")\n",tag[indTag-1],token);
- break;
- }
- }//endSwitch
- }//endIfEls
- else//特殊字符或控制命令
- {
- // printf("%c\n",ch);
- if(isSpesymbols(ch)!=404){
- //printf("%c\n",ch);
- bool isControl=false;
- if(ch=='#')
- {
- m=0;
- token[m++]=ch;
- token[m]='\0';
- int t=p;
- while(isChar((ch=getChar(t++,str))))
- {
- p++;
- token[m++]=ch;
- token[m]='\0';
- if(isContCommands(token)!=404)
- {
- Tag=7;
- tag[indTag++]=7;//控制命令
- isControl=true;
- break;
- }
-
- }
- // p++;
- if(isControl)
- {
- token[m++]='\0';
- // printf("(%d,\"%s\")\n",tag[indTag-1],token);
- printf("(%d,\"%s\")\n",Tag,token);
- }
- }
- else
- {
- m=0;
- token[m++]=ch;
- token[m++]='\0';
- tag[indTag++]=6;//特殊符号符
- printf("(%d,\"%s\")\n",tag[indTag-1],token);
- }
-
- }
- }//endElse
- }//endWhile
- }//endfunc
-
- //主函数
- int main(){
- char buf[MAX_LINE]; /*缓冲区*/
- char ch,sh;
- FILE* fp; /*文件指针*/
-
- //下面是写数据,将数字0~9写入到data.txt文件中
-
- printf("***请选择读取待编译程序的方式***\n");
- printf("***输入 1:屏幕输入;输入 2:已放入记事本***\n");
- int tmp;
- scanf("%d",&tmp);
- getchar();//吞掉空格
- if (tmp==1)
- {
- FILE *fpWrite=fopen("data.txt","a");
- if(fpWrite==NULL)
- {
- perror("fail to read");
- exit(1);
- return 0;
- }
- printf("您输入的是 1,请继续输入待编译程序,并以@加回车结束!\n");
- printf("输入内容将同步显示..\n");
- ch = getchar();
- while (ch != '@') {
- fputc(ch,fpWrite); //写入文件
- putchar(ch); //输出到屏幕
- ch = getchar();
- }
- fclose(fpWrite);//关闭文件
- printf("程序已读入文件data.txt..");
- //已经获取文件处理程序
- //fpWrite=fopen("data.txt","a");//重新打开文件,重置文件指针
- //fclose(fpWrite);//关闭文件
- getchar();
- fp=readTxt();//获取文件指针
- printf("文件读取完毕..\n");
- printf("resourceProject中的程序为:\n");
- printf("%s",resourceProject);
- fclose(fp);//关闭文件
- }
- else if(tmp==2)
- {
- printf("您输入的是 2,接下来将进入文件读取程序..\n");
- fp=readTxt();//获取文件指针
- printf("文件读取完毕..\n");
- printf("resourceProject中的程序为:\n");
- printf("%s",resourceProject);
- fclose(fp);//关闭文件
- }
- //开始处理读入的程序
- preProcessing();//预处理
- printf("\n预处处理完成后的程序为:\n");
- printf("%s",resourceProject);
- printf("\n下面开始词法分析:\n");
- textAnalyze(resourceProject);
- //下面是读数据,将读到的数据存到数组a[10]中,并且打印到控制台上
- // int a[10]={0};
- // FILE *fpRead=fopen("data.txt","r");
- // if(fpRead==NULL)
- // {
- // return 0;
- // }
- // for(int i=0;i<10;i++)
- // {
- // fscanf(fpRead,"%d ",&a[i]);
- // printf("%d ",a[i]);
- // }
- // getchar();//等待
- //
- // fclose(fpRead);
-
- free(commentStr);
- free(resourceProject);
- return 0;
- }
运行结果:
对编译原理中的词法分析实验进行了记录,但需要说明的是,本次实验面向测试集编程,处理方式分为两遍,并非一遍扫描处理。
编写代码时需十分小心指针的位置,符号的提前读入、回溯等。
程序逻辑划分较为明显,有需要的可主要对进行词法分析的 char textAnalyze(char str[]) 函数进行改写。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。