【編譯原理】實驗一 詞法分析器的構造(預處理去註釋空格Tab換行)

1、實驗目的

設計、編制、調試一個詞法分析程序,對單詞進行識別和編碼,加深對詞法分析原理的理解。ios

2、設計內容
設計並實現一個詞法分析器,實現對指定位置的類C 語言源程序文本文件的讀取,並可以對該源程

序中的全部單詞進行分類,指出其所屬類型,實現簡單的詞法分析操做。git

3、實驗要求
一、容許用戶本身輸入程序並保存爲文件
二、系統可以輸出通過預處理後的源程序(去掉註釋、換行、空格等)
三、可以將該源程序中全部的單詞根據其所屬類型(整數、保留字、運算符、標識符等。定義的類
C 語言中的標識符只能以字母或下劃線開頭)進行歸類顯示,例如:識別保留字:if、int、for、while、
do、return、break、continue 等,其餘的都識別爲標識符;常數爲無符號整形數;運算符包括:+、-、
*、/、=、>、<、>=、<=、!=等;分隔符包括:,、;、{、}、(、)等。
算法

四、實現文件的讀取操做,而不是將文本以字符串形式預存於程序中。文本內容爲待分析的類C 語
言程序。
數組

解決方案:函數

關於實驗要求1:主要涉及的是文件的寫入和保存,寫入和保存的內容是用戶輸入的程序。怎麼處理的?個人方法是在這部分寫兩個函數,一個函數用來輸入程序:,另外一個函數用來保存文件。測試

關於實驗要求2:一個函數,用來清除文本信息中的空格 換行 Tab,同時調用該函數後,將通過預處理的內容保存下來,我是在本地又新建了一個文本文件。編碼

關於實驗要求3:這部分是整個實驗的關鍵部分,涉及到對預處理文本的處理。關於這部分的算法思路,在編譯原理書上有提到,可是使用Pascal語言寫的,可是思想是基本不變的,理解下就比較好些了。我想提的一點是,關於RETRACT函數,即實現「將字符數組指針向前移動一個位置」的功能,請查找fseek()函數的使用。spa

關於實驗要求4:文件的讀取函數,readFile()。設計

本身寫的代碼實驗要求基本都實現了,測了幾組也沒bug,不過感受還須要改進,過些日子再貼上來,暫時留這。指針


--------------------------------------------------------------------2015.10.23更新--------------------------------------------------------------------

以前寫的代碼不具有處理註釋的功能,後來加進去了,須要對上述解決方案作下改動,主要是函數和結構,改動以下:

函數說明:

對讀文件函數和寫文件函數、預處理文件函數進行了改動,增長註釋預處理部分dealNote()。

程序運行過程:先由用戶在鍵盤上寫程序,保存文件至G:\\contextfile.txt,對註釋部分進行處理,保存處理後的文件至G:\\nonotecontextfile.txt,再對該文件進行在空格、Tab鍵和空格上的預處理,最後進行judge判斷。

測試數據以下:

/*

main()
{
int a,b;
a = 10;
b = a + 20;   /*dsdsdsdsd*/

}

*/

代碼:

#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <string>
#include <cmath>
#include <vector>
#include <fstream>
#include <string.h>
#include <math.h>

using namespace std;

const int LEN = 0Xfff;

char fsm[8][128];  //清除註釋,作一個狀態機

FILE *fp;     //文件指針

char CHAR;    //字符變量CHAR,它存放着新讀入的源程序字符

string TOKEN;  //字符串TOKEN,它存放着構成單詞符號的字符串

string afterPreDeal;  //存放着通過預處理後的程序內容

string TABLE[LEN] = {"if", "int", "for", "while", "do", "return", "break", "continue", "else"};  //保留字

void inputFile();  //輸入程序內容(容許換行、空格和Tab鍵)

void dealNote();

void saveToFile(char *p, char * filename); //將輸入的程序內容保存到文件裏

void judge(char * filename);  //對單詞進行歸類顯示

string& trim(string &str, string::size_type pos = 0); //去除文本文件中的空格、Tab和換行

void readFile(char * filename);  //讀取文件內容並輸出

void preDeal(char * filename);   //對程序文件作預處理,並將預處理後的內容保存在新文件G:\\newcontextfile.txt中

void GETCHAR();   //用於讀取下一個原程序字符至CHAR中,並把字符指針向後移一位

void GETNBC();   //先檢查CHAR是否爲空白字符,如果則反覆調用GETCHAR直到CHAR讀入的是一個非空白字符

void CONCAT();   //將CHAR字符鏈接到TOKEN後面

bool LETTER(char CHAR);  //布爾函數,若CHAR爲字母則返回TRUE,反之返回FALSE;

bool DIGIT(char CHAR);   //布爾函數,若CHAR爲數字則返回TRUE,反之返回FALSE;

bool UNDERLINE(char CHAR);  //布爾函數,若CHAR爲下劃線則返回TRUE,反之返回FALSE;

int RESERVE();   //由TOKEN字符串查保留字表,若TOKEN中字符串爲保留字則返回其種別編碼,不然返回值爲0

void RETRACT();  //將字符指針向前移動一個位置,CHAR置爲空白字符

void initfsm();

int main()
{
    //保存內容
    cout << "*********你好,請輸入程序內容(以Ctrl+Z結束)*********" << endl;

    inputFile();

    dealNote(); //清除註釋

    preDeal("G:\\nonotecontextfile.txt");  //對清除註釋後的文件進行其餘預處理,好比去空格,去tab,去換行

    cout << "*********輸出判斷結果*********" << endl;

    judge("G:\\newcontextfile.txt");

    cout << endl;

    return 0;
}

void inputFile()
{
    char s[10] = {'\0'};
    fstream file("G:\\contextfile.txt", ios::out);
    while((scanf("%c",&s))!=EOF)
    {
        file.write(s, strlen(s));
    }
    file.close();
}

void dealNote()
{
    int state=0;
    char c;
    std::string s;
    FILE *fin=fopen("G:\\contextfile.txt","r");
    FILE *fout=fopen("G:\\nonotecontextfile.txt","w");
    initfsm();
    while(fscanf(fin,"%c",&c)!=EOF)
    {
        state=fsm[state][c];
        s+=c;
        switch(state)
        {
            case 0:
                fprintf(fout,"%s",s.c_str());
                s="";
                break;
            case 7:
                s="";
                if(c=='\n')
                {
                    fputc(c,fout);
                }
                break;
        }
    }
    fclose(fin);
    fclose(fout);
}

void saveToFile(char *p, char * filename)
{
    if ((fp = fopen(filename, "wb")) == NULL )
    {
        return;
    }
    else
    {
        fwrite(p, strlen(p), 1, fp);
    }
    fclose(fp);
}

void judge(char *filename)
{
    fp = fopen(filename, "r+");
    while(!feof(fp))
    {
        TOKEN.clear();
        GETCHAR();
        if(LETTER(CHAR))
        {
            int c;
            int flag = 0;
            while(LETTER(CHAR) || DIGIT(CHAR) || UNDERLINE(CHAR))
            {
                CONCAT();
                GETCHAR();
                {
                    c = RESERVE();
                    if(c == 2)
                    {
                        cout << "(1," << "\"" << TOKEN << "\"" << ")" << endl;
                        flag = 1;
                        break;
                    }
                }
            }
            RETRACT();
            if(flag == 0)
            {
                c = RESERVE();
                if(c == 0)
                    cout << "(2," << "\"" << TOKEN  << "\"" << ")" << endl;
                else
                      cout << "(1," << "\"" << TOKEN  << "\"" << ")" << endl;
            }
            continue;
        }
        else if(UNDERLINE(CHAR))
        {
           int c;
            int flag = 0;
            while(LETTER(CHAR) || DIGIT(CHAR) || UNDERLINE(CHAR))
            {
                CONCAT();
                GETCHAR();
                {
                    c = RESERVE();
                    if(c == 2)
                    {
                          cout << "(1," << "\"" << TOKEN << "\"" << ")" << endl;
                        flag = 1;
                        break;
                    }
                }
            }
            RETRACT();
            if(flag == 0)
            {
                c = RESERVE();
                if(c == 0)
                      cout << "(2," << "\"" << TOKEN << "\"" << ")" << endl;
                else
                    cout << "(1," << "\"" << TOKEN << "\"" << ")" << endl;
            }
            continue;
        }
        else if(DIGIT(CHAR))
        {
             while(DIGIT(CHAR))
             {
                 CONCAT();
                 GETCHAR();
             }
             RETRACT();

             cout << "(3," << "\"" << TOKEN << "\"" << ")" << endl;

             continue;
        }
        else if(CHAR == ',' || CHAR == ';' || CHAR == '{' || CHAR == '}' || CHAR == '(' || CHAR == ')')
        {
              cout << "(5," << "\"" << CHAR << "\"" << ")" << endl;
              continue;
        }
        else if( CHAR == '+' || CHAR == '-' || CHAR == '*' || CHAR == '\\' || CHAR == '=' )
        {
              char mmd = CHAR;
              GETCHAR();
              if(CHAR == '=')
              {
                  cout << "(4," << "\"" << mmd << "\"" << "=)" << endl;
              }
              else
              {
                 RETRACT();
                 cout << "(4," << "\"" << mmd << "\"" << ")" << endl;
              }
              continue;
        }
        else if(CHAR == ' '|| CHAR == '\n' || CHAR == '\t')
        {
            continue;
        }
        else
        {
              if((int)CHAR == -1)
                return;
          //    cout << "ERROR Message" << endl;
        }

    }
    fclose(fp);/*關閉文件*/
}

string& trim(string &str, string::size_type pos)
{
    static const string delim = " \t\n"; //刪除空格或者tab字符
    pos = str.find_first_of(delim, pos);
    if (pos == string::npos)
       return str;
    return trim(str.erase(pos, 1));
}

void readFile(char * filename)
{
    FILE *pFile=fopen(filename, "r"); //獲取文件的指針
    char *pBuf;  //定義文件指針
    fseek(pFile, 0, SEEK_END); //把指針移動到文件的結尾 ,獲取文件長度
    int len = ftell(pFile); //獲取文件長度
    pBuf = new char[len+1]; //定義數組長度
    rewind(pFile); //把指針移動到文件開頭 由於咱們一開始把指針移動到結尾,若是不移動回來 會出錯
    fread(pBuf,1,len,pFile); //讀文件
    pBuf[len]=0; //把讀到的文件最後一位 寫爲0 要否則系統會一直尋找到0後才結束
    printf("%s", pBuf);  //顯示讀到的數據
    fclose(pFile); // 關閉文件
}

void preDeal(char * filename)   //對程序文件作預處理,保存在新文件G:\\newcontextfile.txt中
{
  //  dealNote();
    FILE *pFile=fopen(filename, "r"); //獲取文件的指針
    char *pBuf;  //定義文件指針
    fseek(pFile, 0, SEEK_END); //把指針移動到文件的結尾 ,獲取文件長度
    int len = ftell(pFile); //獲取文件長度
    pBuf = new char[len+1]; //定義數組長度

    string predeal;

    int n = len;

    if ((fp = fopen(filename, "rb")) == NULL )
    {
        return;
    }
    else
    {
        char p[100];
        fread(p, n, 1, fp);
        p[n]='\0';
        predeal = p;
    }
    predeal = trim(predeal);
    char *con = new char[predeal.length() + 10];
    strcpy(con, predeal.c_str());

    saveToFile(con, "G:\\newcontextfile.txt");  //將新文件內容保存爲G:\\newcontextfile.txt
    cout << endl;

    afterPreDeal = predeal;

    fclose(fp);/*關閉文件*/
}

void GETCHAR()
{
    CHAR = fgetc(fp);
   // cout << "*" << CHAR << "*" << endl;
}

void GETNBC()
{
    while(CHAR == ' ' || CHAR == '\n' || CHAR == '\t')
    {
        GETCHAR();
    }
}

void CONCAT()
{
    TOKEN += CHAR;
}

bool LETTER(char CHAR)
{
    bool isLetter = isalpha(CHAR);
    return isLetter;
}

bool DIGIT(char CHAR)
{
    bool isDigit = isdigit(CHAR);
    return isDigit;
}

bool UNDERLINE(char CHAR)
{
    if(CHAR == '_')
        return true;
    else
        return false;
}

int RESERVE()
{
    int i = 0;
    int N = 9;
    int val = 0;
    for(i = 0; i < N; i++)
    {
        if(TOKEN == TABLE[i])
        {
            val = 2;
            break;
        }
    }
    return val;
}

void RETRACT()
{
    CHAR = ' ';
    fseek(fp,-1,SEEK_CUR);
}

void initfsm()
{
	const int line_len = sizeof(char)*128;
	memset(fsm[0],0,line_len);
	memset(fsm[1],0,line_len);
	memset(fsm[2],2,line_len);
	memset(fsm[3],3,line_len);
	memset(fsm[4],3,line_len);
	memset(fsm[5],5,line_len);
	memset(fsm[6],5,line_len);
	memset(fsm[7],0,line_len);
	fsm[0]['/'] = 1;
	fsm[0]['"'] = 5;
	fsm[1]['/'] = 2;
	fsm[1]['*'] = 3;
	fsm[1]['"'] = 5;
	fsm[2]['\n'] = 7;
	fsm[3]['*'] = 4;
	fsm[4]['/'] = 7;
	fsm[4]['*'] = 4;
	fsm[5]['"'] = 0;
	fsm[5]['\\'] = 6;
	fsm[7]['/'] = 1;
	fsm[7]['"'] = 5;
}
相關文章
相關標籤/搜索