预处理功能描述:
源程序中可能包含有对程序执行无意义的符号,要求将其剔除。
首先编制一个源程序的输入过程,从键盘、文件或文本框输入若干行语句,依次存入输入缓冲区(字符型数据);然后编制一个预处理子程序,去掉输入串中的回车符、换行符和跳格符等编辑性文字;把多个空白符合并为一个;去掉注释。
状态转换图:
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;
}
结果: