编译原理:编写一个语法高亮程序

编程题目 1:语法高亮转换软件 
(1) 问题描述:在我们使用的集成化编译环境(IDE)中,C/C++语言的源代码通常使用高亮语法表示,但是如果我们将这段代码发布到网页中,它的高亮语法表示将消失。这样看起来非常不直观,我们希望在网页中代码仍然能保持原来的高亮语法表示。 
(2) 输入:C/C++源代码文件,即后缀为 c/cpp 的文件。 
(3) 输出:网页文件,即后缀为 html 的文件。 
(4) 实现功能:将 C/C++源代码转换为网页文件,在浏览器中打开网页文件时,网页
中显示 C/C++源代码并以高亮语法表示显示。 

 

(5) 涉及知识点:词法分析。

 

 

 开始拿到这个题目时,实在是一点思路都没有。后来经过查阅与思考,发现按照上课所讲,先建立一个状态转换图,枚举所有可能出现的状态就好。更详细的内容见代码。要注意部分html的转义字符

 

 

//注:输入的源文件需要以Unix格式保存,因为在Windows下换行符为\r\n,会导致结果错误
#include <bits/stdc++.h>
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<<"<br>";
    //空格
    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<<"<font color=#32CD99>"<<token<<"</font>";
        else
            dst<<token;
        point_back(src);
    }
    //数字
    else if (isdigit(ch)){
        while (isdigit(ch)||ch=='.'){
            token.push_back(ch);
            ch=get_ch(src);

        }
        dst<<"<font color=#DB70DB>"<<token<<"</font>";
        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<<"<font color=#C0C0C0>"<<token<<"<br></font>";
        }
        //为多行注释
        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<<"<font color=#C0C0C0>"<<token<<"<br></font>";
                else
                    dst<<"<font color=#C0C0C0>"<<token<<"</font>";
                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<<"<font color=#FF000>"<<token<<"</font>";
    }
    //字符串或字符
    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<<"<font color=#6B4226>"<<token<<"</font>";
        }
        //为双引号
        else{
            ch=get_ch(src);
            while (ch!='\"'){
                token.push_back(ch);
                ch=get_ch(src);

            }
            token.push_back(ch);
            dst<<"<font color=#6B4226>"<<token<<"</font>";
        }
    }
    //分界符
    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<<"<font color=#97694F>"<<token<<"</font>";
    }
    //头文件
    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<<"<font color=#32CD99>"<<token<<"<br></font>";
    }

}

int main()
{
    ifstream src("in.cpp",ios::in);
	ofstream dst("out.html",ios::out);
	if (!src.is_open()){
        cerr<<"open error"<<endl;
        exit(1);
    }
    cout<<"start building"<<endl;
	while (src.peek()!=EOF)
        lex(src,dst);

    src.close();
    dst.close();
    cout<<"building success"<<endl;

    return 0;
}

效果如下:

 

展开阅读全文

没有更多推荐了,返回首页