题目描述
把C的多行注释转换为C++的单行注释
如:把
/*
* int a;
*/
转换为
//
// int a;
//
利用状态转换
AnnotationConvert.h (状态划分)
分为四个状态
#ifndef __ANNOTATION_CONVERT_H__
#define __ANNOTATION_CONVERT_H__
#include <stdio.h>
#include <stdlib.h>
// C语言风格的注释 /**/
// C++语言风格的注释 //
// 本程序的目标:将C语言风格的注释转换为C++风格的注释
// 待测试数据存在test_in.c文件中 输出结果到test_out.c文件中
#define InputFileName "test_in"
#define OutputFileName "test_out"
enum STATE
{
NUL_STATE, // 空状态
C_STATE, // C语言注释状态
CPP_STATE, // C++语言注释状态
END_STATE // 结束状态
};
void Convert(FILE *fR, FILE *fW);
void Do_NUL_State(FILE *fR, FILE *fW);
void Do_C_State(FILE *fR, FILE *fW);
void Do_Cpp_State(FILE *fR, FILE *fW);
#endif
AnnotationConvert.c (处理每个字符)
具体的状态转换
#include "AnnotationConvert.h"
enum STATE state = NUL_STATE; //初识状态为:NUL 未知态
void Convert(FILE *fR, FILE *fW)
{
while (state != END_STATE) //扫描到文件尾 跳出循环
{
switch (state)
{
case NUL_STATE:
Do_NUL_State(fR, fW);
break;
case C_STATE:
Do_C_State(fR, fW);
break;
case CPP_STATE:
Do_Cpp_State(fR, fW);
break;
default:
break;
}
}
}
void Do_NUL_State(FILE *fR, FILE *fW)
{
int first = 0;
int second = 0;
first = fgetc(fR); //fgetc返回字符对应的unsigneint
switch (first)
{
case '/':
second = fgetc(fR);
if (second == '*') // 遇到/* 转为C状态
{
fputc('/', fW);
fputc('/', fW);
state = C_STATE;
}
else if (second == '/') // 遇到 // 转为C++状态
{
fputc(first, fW); // '/'
fputc(second, fW); // '/'
state = CPP_STATE;
}
else //表示 first只是一个简单的'/'字符,输出即可
{
fputc(first, fW);
fputc(second, fW);
}
break;
case EOF: //文件尾
// fputc(EOF, fW);
state = END_STATE;
break;
default: //状态不变,正常输出
fputc(first, fW);
break;
}
}
void Do_C_State(FILE *fR, FILE *fW) //C状态
{
int first = 0;
int second = 0;
int third = 0;
first = fgetc(fR);
switch (first)
{
case '*':
second = fgetc(fR);
switch (second)
{
case '/':
third = fgetc(fR);
if (third != '\n') // *等到了/ 一次C注释结束了,期待一个换行符'\n'
{
fputc('\n', fW); //若是没有遇到换行符,帮它换行
ungetc(third, fR); //并将字符放回去,用于下一次的判断
state = NUL_STATE;
}
else
{
fputc(third, fW); //若是遇到了换行符,换行即可
state = NUL_STATE;
}
break;
case '*':
//second=='*'在等'/'的到来,所以first已经没用了 舍弃first=='*' ,所以不输出first=='*'
//把second放回去,是因为second=='*'在C状态下,下一个字符可能是'/' ,这样就扫描到来注释尾
//把second=='*'放回去,是为了检测下一个字符是否是'/'
ungetc(second, fR);
break;
default:
//'*'没有等到'/' ; 那么舍弃这个first=='*' , 并输出这个second( !='*' !='/' )(是个普通字符)
ungetc(second, fR);
break;
}
break;
case '\n':
fputc(first, fW); // '\n'
fputc('/', fW); //
fputc('/', fW); //
break;
case EOF:
// fputc(EOF, fW);
state = END_STATE;
break;
default:
fputc(first, fW);
break;
}
}
void Do_Cpp_State(FILE *fR, FILE *fW)
{
int first = 0;
first = fgetc(fR);
switch (first)
{
case '\n':
fputc(first, fW);
state = NUL_STATE;
break;
case EOF:
// fputc(EOF, fW);
state = END_STATE;
break;
default:
fputc(first, fW);
break;
}
}
main.c (测试代码)
#include <stdio.h>
#include "AnnotationConvert.h"
int main()
{
FILE *pR = fopen(InputFileName, "r");
if (NULL == pR)
{
perror("fopen file for read!");
exit(EXIT_FAILURE);
}
FILE *pW = fopen(OutputFileName, "w");
if (NULL == pW)
{
fclose(pR);
perror("fopen file for write!");
exit(EXIT_FAILURE);
}
printf("Start conversion!\n");
Convert(pR, pW);
printf("End of conversion!\n");
fclose(pR);
fclose(pW);
return 0;
}
Makefile (编译)
#------------------目标 ------------------
EXECUTABLE := out
#------------------文件后缀 ------------------
# .o文件
SrcSuf = c
ObjSuf = o
.SUFFIXES: .$(SrcSuf) .$(ObjSuf)
#------------------源文件 ------------------
OBJFILES += ./main.$(ObjSuf) \
./AnnotationConvert.$(ObjSuf) \
#------------------编译选项 ------------------
# 头文件目录
INCLUDEPATH += -I /usr/include/ \
-I /usr/local/include
# C编译选项
CFlag += $(INCLUDEPATH) \
-w -g -ggdb -fshort-wchar \
-std=c11
#------------------ ------------------
CC = gcc
all: $(EXECUTABLE) clean
#------------------生成可执行文件 ------------------
$(EXECUTABLE):$(OBJFILES)
@echo "creating $(EXECUTABLE) start..."
$(CC) $(OBJFILES) -o $(EXECUTABLE)
@echo "creating $(EXECUTABLE) end"
#------------------.c 生成 .o 文件
.$(SrcSuf).$(ObjSuf):
@echo "Compiling $(EXECUTABLE) $<"
$(CC) $(CFlag) -c $< -o $@
#---------------------------------------------------------
.PHONY:clean
clean:
rm -f *.o
.PHONY:cleanall
cleanall:
rm -f $(EXECUTABLE) *.o
#---------------------------------------------------------
test_in (待测试数据)
// 1.一般情况
/* int a = 0; */
int a = 0;
// 2.换行问题
/* int b = 0; */int b2 = 0;
// 3.匹配问题
/*int c = 0;/*xxxxx*/
// 4.多行注释问题
/*
int d1=0;
*/int d12 = 0;
/**
*** int d21 = 0;
***
**/int d22 = 0;
// 5.连续注释问题
/* *//* */
// 6.连续的**/问题
/***/
// 7.C++注释问题
// /*xxxxxxxxxxxx*/
test_out (输出)
// 1.一般情况
// int a = 0;
int a = 0;
// 2.换行问题
// int b = 0;
int b2 = 0;
// 3.匹配问题
//int c = 0;/xxxxx
// 4.多行注释问题
//
// int d1=0;
//
int d12 = 0;
//
// int d21 = 0;
//
//
int d22 = 0;
// 5.连续注释问题
//
//
// 6.连续的**/问题
//
// 7.C++注释问题
// /*xxxxxxxxxxxx*/