词法分析一(源文件预处理)

预处理功能描述:

源程序中可能包含有对程序执行无意义的符号,要求将其剔除。

首先编制一个源程序的输入过程,从键盘、文件或文本框输入若干行语句,依次存入输入缓冲区(字符型数据);然后编制一个预处理子程序,去掉输入串中的回车符、换行符和跳格符等编辑性文字;把多个空白符合并为一个;去掉注释。

 

状态转换图:

    0 :初态
    1:读入空格
    2:读入 '/'
    3:读入其他字符
    4:读入 "//" 单行注释 
    5:读入 "/*" 多行开始注释

上图中:状态5在Dev c++ 中不能是终态,其他编译器未知。

 

 

代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

FILE *fp;			// 文件指针,处理源文件 
char *ScanBuffer;	// 扫描缓冲区,一分为二,每次一半存放预处理后的字符串 
int capacity;		// 扫描缓冲区容量 
int BufferFlag;		// 状态标志,0 表示使用缓冲区的左半区,1 表示使用右半区 
int SP;				// 分析器的起点指示器 
int EP;				// 分析器的搜索指示器
int	PreprocessFlag;	// 预处理的状态标志 

// init fp, ScanBuffer, BufferFlag,SP,EP,PreprocessFlag 
void init(){
	fp = fopen("source.txt","r");
	if(fp == NULL) exit(0);
        capacity = 120;
	ScanBuffer = new char[capacity];				// 缓冲区分配长度 :120。 
	memset(ScanBuffer,0,sizeof(ScanBuffer));
	BufferFlag = 0; 
	SP = EP = 0;
	PreprocessFlag = 0; 
}

// 关闭文件 
void close(){
	fclose(fp);
	delete ScanBuffer;
}

/*
ASCII码: 
	9:  水平制表符 
	10: 换行 
	13: 回车

PreprocessFlag表状态:
	0 :初态
	1:读入空格
	2:读入 '/'
	3:读入其他字符
	4:读入 "//" 单行注释
	5:读入 "/*" 多行开始注释
*/ 


void Preprocess(){
	char cur; int index;	//cur:读取文件字符;index:当前缓冲区存放位置 
	int length = 0;			// length:读取到字符长度 
	if(BufferFlag) index = capacity/2; else index = 0; // 预处理的内容存放在左半区还是右半区 
	while(!feof(fp)){
		cur = fgetc(fp);
		if(cur == 9 || cur == 10 || cur == 13) continue;	// 跳过制表符、换行、回车 
		// 状态转换 
		switch(PreprocessFlag){
			case 0:{
				if(cur == ' ') break;
				if(cur == '/') PreprocessFlag = 2;
				else PreprocessFlag = 3;
				break;
			}
			case 1:{
				if(cur == ' ') PreprocessFlag = 0;
				else if(cur == '/') PreprocessFlag = 2;
				else PreprocessFlag = 3;
				break;
			}
			case 2:{
				if(cur == ' ') PreprocessFlag = 1;
				else if(cur == '/') PreprocessFlag = 4;
				else if(cur == '*') PreprocessFlag = 5;
				else PreprocessFlag = 3;
				break;
			}
			case 3:{
				if(cur == ' ') PreprocessFlag = 1;
				else if(cur == '/') PreprocessFlag = 2;
				break;
			}	
		}
		// 状态转换后的处理 
		if(PreprocessFlag == 3 || PreprocessFlag == 1 || PreprocessFlag == 2) {ScanBuffer[index++] = cur; length++;}
		else if(PreprocessFlag == 4) {				//单行注释 
			char buff[1024]; fgets(buff, 1024, fp);
			index--; length--; PreprocessFlag = 0;
		}else if(PreprocessFlag == 5) {				//多行注释 
			char pre;
			while(!feof(fp)) {
				pre = fgetc(fp);
				if(pre == '*' && (cur = fgetc(fp)) == '/') {
					index--; length--; PreprocessFlag = 0; break;
				}
			}
		}
		if(length == capacity/2) break;			// 每次处理60字节 
	}
}

int main(){
	init();
	while(!feof(fp)){
		Preprocess(); BufferFlag = BufferFlag ^ 1;
		if(SP == capacity) SP = 0;		// 起点指针走到末尾要转到 0  
		if(SP < capacity/2){
			while(ScanBuffer[SP] != -1 && SP < capacity/2) putchar(ScanBuffer[SP++]);
		}else{
			while(ScanBuffer[SP] != -1 && SP < capacity) putchar(ScanBuffer[SP++]);
		}
	}
	close();
	return 0;
}  

测试用例:

#include <iostream>
using namespace std;

int m, 			// m种颜色 
	n, 			// 	n个顶点 
	**a,		// 邻接矩阵 
	*x;			// 记录颜色	
char **str; 	// 颜色数组 

/*
	多行注释
*/	
int OK(int k){
	for(int i=1; i<=n; i++){
		if(a[k][i] == 1 && x[k] == x[i]) return 0;
	}
	return 1;
}
	
	
void BackTrack(int t){
	if(t > n){
		cout<<"着色方案: "; 
		for(int i = 1; i <= n; i++) cout<<str[x[i]]<<" ";
		cout<<endl;
		return; 
	}else{
		for(int i=1; i<=m; i++){
			x[t] = i;
			if(OK(t)) BackTrack(t+1);
			x[t] = 0;
		}		
	}
} 

int  main(){
	FILE *file = fopen("test.txt","r");
	str = new char *[8]; 
	for(int i = 1;i<=7;i++){
    	str[i] = new char [7];
    	fscanf(file,"%s",str[i]);
    } 
    fscanf(file,"%d",&m); 
    fscanf(file,"%d",&n); 
    printf("颜色数:%d\n",m);
    printf("顶点数:%d\n",n);
    x = new int [n+1];
    a = new int *[n+1];
    for(int i = 1;i<=n;i++){
    	a[i] = new int [n+1];
    }
    for(int i = 1;i<=n;i++){
    	for(int j = 1; j<=n; j++) fscanf(file,"%d",&a[i][j]);
    }
    fclose(file);
    BackTrack(1);
	delete[] x,a,str;
	return 0;
}

 

结果:

  • 0
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值