预处理和词法分析器

 |
总阅读量


结合课程实验和课程设计,时间跨度为一个月,完成预处理,词法分析器。(词法分析器已作为JavaSwing项目上传至GitHub。)

预处理程序

#include<cstdio>
#include<iostream>
#include<fstream>
using namespace std;

void processSpace(ifstream &fin, const char);    // 处理空格
void processMargin(ifstream &fin, const char);    // 处理注释
void processCrLf(ifstream &fin, const char);    // 处理回车换行
int main()
{
    ifstream fin("F:\\CompilerPrinciple\\Test1\\demo.cpp", ios::in);    // 预处理源代码文件
    freopen("F:\\CompilerPrinciple\\Test1\\out.cpp","w",stdout);    // 输出结果文件
    char now, last;
    fin.get(last);

    while(!fin.eof() && isspace(last))    // 一个字符测试空文件
        fin.get(last);
    fin.unget();
    while(!fin.eof())
    {
        fin.get(now);
        switch(now)
        {
        case ' ':
            processSpace(fin, last);
            fin.unget();    // 超前搜索回退
            break;
        case '/':
            processMargin(fin, last);
            break;
        case '\n':          // 只存在Mac和windows下\r\n,\r
            processCrLf(fin, last);
            last = '\n';
            break;
        case '\t': break;
        default:
            putchar(now);
        }
        last = now;
    }
    return 0;
}
void processSpace(ifstream &fin, const char st)
{
    /*         一.去多余空格:
    *            1.判定当前字符,是空格则转第二步;否则输出
    *            2.判定记录的上一个字符,如果是换行符,则是行首空格,不输出;
    *                   如果是赋值号,则是多余空格,不输出
    *                   继续判定下一个字符,如果是斜线,则是行末与注释间的空格,不输出
    *                   如果是分号,则是行末多余字符,不输出。
    *                   如果是空格,则是多余空格,不输出
    */

    char next;
    fin.get(next);
    while(!fin.eof() && isspace(next))  // 去多个连续空格
        fin.get(next);
    if(st != '\n' && st != '='
        && next != '/' && next != ';' && next != '=')
        putchar(' ');
}

void processCrLf(ifstream &fin, const char st)
{
    /* 二. 去回车换行
    *    1.超前搜索:如果下一个字符不是换行符,为Mac下源文件,回退文件指针,输出一个空格。否则
    *      不回退,输出一个空格
    *   考虑到兼容性,windows下\r\n,unix下 \n ,Mac下是 \r,过滤
    */
    char next;
    if(!fin.eof())
    {
        fin.get(next);
        if(next != '\n')
            fin.unget();
        putchar(' ');
    }
}

void processMargin(ifstream &fin, const char st)
{
    /*          三. 去注释
    *             1.判定当前字符是否为  / ,是则进入第2步;否则输出
    *             2.超前搜索下一个字符是否为  / ,是则为单行注释,直接结束本行;否则转第3步
    *             3.超前搜索下一个字符是否为  * ,进入下一次循环,转第4步
    *             4.判定当前字符是否为  *  ,是则进入第5步;否则放弃当前字符,进入下一次循环
    *             5.超前搜索下一个字符是否为 '/',是则结束循环退出子程序;
    *               否则进入下一次循环,转第4步
    */
    char next, now;
    fin.get(next);
    if(!fin.eof())
    {
        if(next == '/')     // 单行注释
        {
            while(!fin.eof())
            {
                fin.get(now);
                if(now == '\r' || now == '\n')
                    break;
            }
            if(now == '\n')     // 不是回车换行符,回退
                fin.unget();
        }
        else if(next == '*')    //多行注释
        {
            while(!fin.eof())
            {
                fin.get(next);
                if(next == '*')
                {
                    fin.get(next);
                    if(next == '/')
                        break;
                }
            }
        }
    }
}