编程题目 1:语法高亮转换软件
(1) 问题描述:在我们使用的集成化编译环境(IDE)中,C/C++语言的源代码通常使用高亮语法表示,但是如果我们将这段代码发布到网页中,它的高亮语法表示将消失。这样看起来非常不直观,我们希望在网页中代码仍然能保持原来的高亮语法表示。
(2) 输入:C/C++源代码文件,即后缀为 c/cpp 的文件。
(3) 输出:网页文件,即后缀为 html 的文件。
(4) 实现功能:将 C/C++源代码转换为网页文件,在浏览器中打开网页文件时,网页
中显示 C/C++源代码并以高亮语法表示显示。
(5) 涉及知识点:词法分析。
开始拿到这个题目时,实在是一点思路都没有。后来经过查阅与思考,发现按照上课所讲,先建立一个状态转换图,枚举所有可能出现的状态就好。更详细的内容见代码。要注意部分html的转义字符
//注:输入的源文件需要以Unix格式保存,因为在Windows下换行符为\r\n,会导致结果错误
#include
using namespace std;
bool is_keyword(string str); //关键字
bool is_operator(char ch); //运算符
bool is_seprator(char ch); //分界符
int is_notes(string str); //注释
int is_quotes(char ch); //双引号
char get_ch(ifstream &src); //读入一个字符
void point_back(ifstream &src); //回退光标
void lex(ifstream &src,ofstream &dst); //分析函数
//关键词表
string keyword[45]={"bool", "break", "case", "char",
"cin", "const", "continue", "default", "define",
"delete", "do", "double", "else", "enum", "endl",
"false", "float", "for", "friend", "goto", "if", "void"
"include", "int", "long", "namespace", "new", "while"
"operator", "private", "cout", "printf", "public",
"return", "string", "signed", "sizeof", "static", "struct",
"switch", "template", "this", "true", "typedef", "using"
};
//光标回退
void point_back(ifstream &src)
{
src.seekg(-1,ios::cur);
}
//是否为关键字
bool is_keyword(string str)
{
bool flag=0;
for (int i=0;i<45;i++){
if (str==keyword[i]){
flag=1;
break;
}
}
return flag;
}
//是否为运算符
bool is_operator(char ch)
{
if (strchr("+-*/%><=",ch))
return true;
return false;
}
//是否为分界符
bool is_seprator(char ch)
{
if (strchr(";:{},()!&[]@?\\|~",ch))
return true;
return false;
}
//是否为单双引号
int is_quotes(char ch)
{
if (ch=='\'')
return 1;
else if (ch=='\"')
return 2;
return 0;
}
//是否为注释
int is_notes(string str)
{
if (str=="//")
return 1;
if (str=="/*")
return 2;
return 0;
}
//读入一个字符
char get_ch(ifstream &src)
{
char res=1;
if (src.peek()==EOF)
return res;
src.get(res);
return res;
}
//词法分析
void lex(ifstream &src,ofstream &dst)
{
char ch;
string token;
//读入字符
ch=get_ch(src);
//文件结束
if (ch==1)
return ;
//换行符
if (ch=='\n')
dst<<"
";
//空格
else if (ch==' '||ch=='\t'){
dst<<" ";
}
//关键字或普通字
else if (isalpha(ch)){
while (isalpha(ch)||isdigit(ch)||ch=='_'){
token.push_back(ch);
ch=get_ch(src);
}
if (is_keyword(token))
dst<<""<";
else
dst<"<";
point_back(src);
}
//注释
else if (ch=='/'){
token.push_back(ch);
ch=get_ch(src);
token.push_back(ch);
//不为注释(为除号),跳转到运算符
if (is_notes(token)==0){
point_back(src);
ch='/';
token.clear();
goto a1;
}
//为单行注释
else if (is_notes(token)==1){
while (ch!='\n'){
ch=get_ch(src);
if (ch=='\n')
break;
token.push_back(ch);
}
dst<<""< ";
}
//为多行注释
else {
int f=0;
while (1){
while (ch!='\n'){
ch=get_ch(src);
if (ch=='/'&&token[token.size()-1]=='*'){
f=1;
token.push_back(ch);
break;
}
token.push_back(ch);
}
if (ch=='\n')
dst<<""< ";
else
dst<<""<";
if (f)
break;
token.clear();
ch=get_ch(src);
token.push_back(ch);
}
}
}
//运算符
else if (is_operator(ch)){
//html中无法直接显示<>,需进行转义
a1: if (ch=='<'){
token.push_back('&');
token.push_back('l');
token.push_back('t');
}
else if (ch=='>'){
token.push_back('&');
token.push_back('g');
token.push_back('t');
}
else
token.push_back(ch);
dst<<""<";
}
//字符串或字符
else if (is_quotes(ch)){
token.push_back(ch);
int flag=is_quotes(ch);
//为单引号
if (flag==1){
ch=get_ch(src);
while (ch!='\''){
token.push_back(ch);
ch=get_ch(src);
}
token.push_back(ch);
dst<<""<";
}
//为双引号
else{
ch=get_ch(src);
while (ch!='\"'){
token.push_back(ch);
ch=get_ch(src);
}
token.push_back(ch);
dst<<""<";
}
}
//分界符
else if (is_seprator(ch)){
if (ch=='&'){
token.push_back('&');
token.push_back('a');
token.push_back('m');
token.push_back('p');
}
else
token.push_back(ch);
dst<<""<";
}
//头文件
else if (ch=='#'){
while (ch!='\n'){
if (ch=='<'){
token.push_back('&');
token.push_back('l');
token.push_back('t');
}
else if (ch=='>'){
token.push_back('&');
token.push_back('g');
token.push_back('t');
}
else
token.push_back(ch);
ch=get_ch(src);
}
dst<<""< ";
}
}
int main()
{
ifstream src("in.cpp",ios::in);
ofstream dst("out.html",ios::out);
if (!src.is_open()){
cerr<<"open error"<
效果如下: