1. 程式人生 > >C++寫的一個簡單的語法分析器(分析C語言)

C++寫的一個簡單的語法分析器(分析C語言)

本程式實現一個分析C語言的詞法分析+語法分析。

注意:

1.文法簡略,沒有實現的部分,可以在此文法的基礎上進行擴充,本程式的採用自頂向下的LL(1)文法。

2.可以自動實現求First 集和 Follow 集。

3.處終結符外(有些硬編碼的成分),終結符的文法可以自定義,也就是說讀者可以自定義文法。

4.為方便理解,C語言的文法描述寫成中文。

5.程式將詞法分析和語法分析結合起來,詞法分析的結果作為語法分析的輸入。

6.最終結果在控制檯顯示的有:詞法分析、First集、Follow集、Select集,在preciateResult.txt 中寫入了語法分析結果,在preciateTable.txt 中寫入了預測分析表。

7.文法的詞素之間必須有空格分開。

專案結構如下:


文法如下:

wenfa.txt:

<函式定義> -> <修飾詞閉包> <型別> <變數> ( <引數宣告> ) { <函式塊> }
<修飾詞閉包> -> <修飾詞> <修飾詞閉包> | $
<修飾詞> -> describe
<型別> -> type <取地址>
<取地址> -> <星號閉包>
<星號閉包> -> <星號> <星號閉包> | $
<星號> -> *
<變數> -> <標誌符> <陣列下標>
<標誌符> -> id
<陣列下標> -> [ <因式> ] | $
<因式> -> ( <表示式> ) | <變數> | <數字>
<數字> -> digit
<表示式> -> <因子> <項>
<因子> -> <因式> <因式遞迴>
<因式遞迴> -> * <因式> <因式遞迴> | / <因式> <因式遞迴> | $
<項> -> + <因子> <項> | - <因子> <項> | $
<引數宣告> -> <宣告> <宣告閉包> | $
<宣告> -> <修飾詞閉包> <型別> <變數> <賦初值>
<賦初值> -> = <右值> | $
<右值> -> <表示式> | { <多個數據> }
<多個數據> -> <數字> <數字閉包>
<數字閉包> -> , <數字> <數字閉包> | $
<宣告閉包> -> , <宣告> <宣告閉包> | $
<函式塊> -> <宣告語句閉包> <函式塊閉包>
<宣告語句閉包> -> <宣告語句> <宣告語句閉包> | $
<宣告語句> -> <宣告> ;
<函式塊閉包> -> <賦值函式> <函式塊閉包> | <for迴圈> <函式塊閉包> | <條件語句> <函式塊閉包> | <函式返回> <函式塊閉包> | $
<賦值函式> -> <變數> <賦值或函式呼叫>
<賦值或函式呼叫> -> = <右值> ; | ( <引數列表> ) ;
<引數列表> -> <引數> <引數閉包>
<引數閉包> -> , <引數> <引數閉包> | $
<引數> -> <標誌符> | <數字> | <字串>
<字串> -> string
<for迴圈> -> for ( <賦值函式> <邏輯表示式> ; <字尾表示式> ) { <函式塊> }
<邏輯表示式> -> <表示式> <邏輯運算子> <表示式>
<邏輯運算子> -> < | > | == | !=
<字尾表示式> -> <變數> <字尾運算子>
<字尾運算子> -> ++ | --
<條件語句> -> if ( <邏輯表示式> ) { <函式塊> } <否則語句>
<否則語句> -> else { <函式塊> } | $
<函式返回> -> return <因式> ;
詞法分析標頭檔案:

LexAnalysis.h

//LexAnalysis.h
#ifndef _LEXANALYSIS_H
#define _LEXANALYSIS_H

//關鍵字
#define AUTO 1
#define BREAK 2
#define CASE 3
#define CHAR 4
#define CONST 5
#define CONTINUE 6
#define DEFAULT 7
#define DO 8
#define DOUBLE 9
#define ELSE 10
#define ENUM 11
#define EXTERN 12
#define FLOAT 13
#define FOR 14
#define GOTO 15
#define IF 16
#define INT 17
#define LONG 18
#define REGISTER 19
#define RETURN 20
#define SHORT 21
#define SIGNED 22
#define SIZEOF 23
#define STATIC 24
#define STRUCT 25
#define SWITCH 26
#define TYPEDEF 27
#define UNION 28
#define UNSIGNED 29
#define VOID 30
#define VOLATILE 31
#define WHILE 32
#define KEY_DESC "關鍵字"

//標誌符
#define IDENTIFER 40
#define IDENTIFER_DESC "標誌符"

//常量
#define INT_VAL 51 //整形常量
#define CHAR_VAL 52 //字元常量
#define FLOAT_VAL 53 //浮點數常量
#define STRING_VAL 54 //雙精度浮點數常量
#define MACRO_VAL 55 //巨集常量
#define CONSTANT_DESC "常量"

//運算子
#define NOT 61   // !
#define BYTE_AND 62 //&
#define COMPLEMENT 63 // ~
#define BYTE_XOR  64 // ^
#define MUL 65 // *
#define DIV 66// /
#define MOD 67 // %
#define ADD 68 // +
#define SUB 69 // -
#define LES_THAN 70 // <
#define GRT_THAN 71 // >
#define ASG 72 // =
#define ARROW 73 // ->
#define SELF_ADD 74 // ++
#define SELF_SUB 75 // --
#define LEFT_MOVE 76 // <<
#define RIGHT_MOVE 77 // >>
#define LES_EQUAL 78 // <=
#define GRT_EQUAL 79 // >=
#define EQUAL 80 // ==
#define NOT_EQUAL 81 // !=
#define AND 82 // &&
#define OR 83 // ||
#define COMPLETE_ADD 84 // +=
#define COMPLETE_SUB 85 // -=
#define COMPLETE_MUL 86 // *=
#define COMPLETE_DIV 87 // /=
#define COMPLETE_BYTE_XOR 88 // ^=
#define COMPLETE_BYTE_AND 89 // &=
#define COMPLETE_COMPLEMENT 90 // ~=
#define COMPLETE_MOD 91 //%=
#define BYTE_OR 92 // |

#define OPE_DESC "運算子"

//限界符
#define LEFT_BRA 100 // (
#define RIGHT_BRA 101 // )
#define LEFT_INDEX 102 // [
#define RIGHT_INDEX 103 // ]
#define L_BOUNDER 104 //  {
#define R_BOUNDER 105 // }
#define POINTER 106 // .
#define JING 107 // #
#define UNDER_LINE 108 // _
#define COMMA 109 // ,
#define SEMI 110 // ;
#define SIN_QUE 111 // '
#define DOU_QUE 112 // "

#define CLE_OPE_DESC "限界符"

#define NOTE1 120 // "/**/"註釋
#define NOTE2 121 // "//"註釋
#define NOTE_DESC "註釋"


#define HEADER 130 //標頭檔案
#define HEADER_DESC "標頭檔案"

//錯誤型別
#define FLOAT_ERROR "float表示錯誤"
#define FLOAT_ERROR_NUM 1
#define DOUBLE_ERROR "double表示錯誤"
#define DOUBLE_ERROR_NUM 2
#define NOTE_ERROR "註釋沒有結束符"
#define NOTE_ERROR_NUM 3
#define STRING_ERROR "字串常量沒有結束符"
#define STRING_ERROR_NUM 4
#define CHARCONST_ERROR "字元常量沒有結束符"
#define CHARCONST_ERROR_NUM 5
#define CHAR_ERROR "非法字元"
#define CHAR_ERROR_NUM 6
#define LEFT_BRA_ERROR "'('沒有對應項"
#define LEFT_BRA_ERROR_NUM 7
#define RIGHT_BRA_ERROR "')'沒有對應項"
#define RIGHT_BRA_ERROR_NUM 8
#define LEFT_INDEX_ERROR "'['沒有對應項"
#define LEFT_INDEX_ERROR_NUM 9
#define RIGHT_INDEX_ERROR "']'沒有對應項"
#define RIGHT_INDEX_ERROR_NUM 10
#define L_BOUNDER_ERROR "'{'沒有對應項"
#define L_BOUNDER_ERROR_NUM 11
#define R_BOUNDER_ERROR "'}'沒有對應項"
#define R_BOUNDER_ERROR_NUM 12
#define PRE_PROCESS_ERROR "預處理錯誤" //標頭檔案或者巨集定義錯誤
#define PRE_PROCESS_ERROR_NUM  13

#define _NULL "無"

#define DESCRIBE 4000
#define TYPE 4001
#define STRING 4002
#define DIGIT 4003

struct NormalNode
{
    char content[30];//內容
    char describe[30];//描述
    int type;//種別碼
    int addr;//入口地址
    int line;//所在行數
    NormalNode * next;//下一個節點
};

void initKeyMapping();
void initOperMapping();
void initLimitMapping();

void initNode();
void createNewNode(char * content,char *descirbe,int type,int addr,int line);
void createNewError(char * content,char *descirbe,int type,int line);
int createNewIden(char * content,char *descirbe,int type,int addr,int line);
void printNodeLink();
void printErrorLink();
void printIdentLink();
int mystrlen(char * word);
void preProcess(char * word,int line);
void close();
int seekKey(char * word);
void scanner();
void BraMappingError();


#endif

語法分析標頭檔案:

SynAnalysis.h

//SynAnalysis.h
#ifndef _SYNANALYSIS_H
#define _SYNANALYSIS_H

#define GRAMMAR_ARROW 2000 //->
#define GRAMMAR_OR 2001 // |
#define GRAMMAR_NULL 2002 //空值
#define GRAMMAR_SPECIAL 2003 //特殊符號#
#define GRAMMAR_BASE 2010 //動態生成的基值

#define Stack_Size 5000

typedef struct
{
    int elem[Stack_Size];
    int top;
} SeqStack;

void initGrammer();
int seekCodeNum(char * word);
void ceshi();
void First();
void Follow();
void Select();
void MTable();
void Analysis();
#endif

詞法分析Cpp檔案:(與先前寫過的一片部落格相類似,改了部分)

LexAnalysis.cpp

//LexAnalysis.cpp
#include <iostream>
#include <fstream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <vector>
#include <iomanip>
#include "LexAnalysis.h"

using namespace std;

int leftSmall = 0;//左小括號
int rightSmall = 0;//右小括號
int leftMiddle = 0;//左中括號
int rightMiddle = 0;//右中括號
int leftBig = 0;//左大括號
int rightBig = 0;//右大括號
int lineBra[6][1000] = {0};//括號和行數的對應關係,第一維代表左右6種括號
int static_iden_number = 0;//模擬標誌符的地址,自增
//Token節點


NormalNode * normalHead;//首結點

//錯誤節點
struct ErrorNode
{
    char content[30];//錯誤內容
    char describe[30];//錯誤描述
    int type;
    int line;//所在行數
    ErrorNode * next;//下一個節點
};

ErrorNode * errorHead;//首節點

//標誌符節點
struct IdentiferNode
{
    char content[30];//內容
    char describe[30];//描述
    int type;//種別碼
    int addr;//入口地址
    int line;//所在行數
    IdentiferNode * next;//下一個節點
};
IdentiferNode * idenHead;//首節點

vector<pair<const char *,int> > keyMap;
vector<pair<const char *,int> > operMap;
vector<pair<const char *,int> > limitMap;



//初始化C語言的關鍵字的集合
void initKeyMapping()
{
    keyMap.clear();
    keyMap.push_back(make_pair("auto",AUTO));
    keyMap.push_back(make_pair("break",BREAK));
    keyMap.push_back(make_pair("case",CASE));
    keyMap.push_back(make_pair("char",CHAR));
    keyMap.push_back(make_pair("const",CONST));
    keyMap.push_back(make_pair("continue",CONTINUE));
    keyMap.push_back(make_pair("default",DEFAULT));
    keyMap.push_back(make_pair("do",DO));
    keyMap.push_back(make_pair("double",DOUBLE));
    keyMap.push_back(make_pair("else",ELSE));
    keyMap.push_back(make_pair("enum",ENUM));
    keyMap.push_back(make_pair("extern",EXTERN));
    keyMap.push_back(make_pair("float",FLOAT));
    keyMap.push_back(make_pair("for",FOR));
    keyMap.push_back(make_pair("goto",GOTO));
    keyMap.push_back(make_pair("if",IF));
    keyMap.push_back(make_pair("int",INT));
    keyMap.push_back(make_pair("long",LONG));
    keyMap.push_back(make_pair("register",REGISTER));
    keyMap.push_back(make_pair("return",RETURN));
    keyMap.push_back(make_pair("short",SHORT));
    keyMap.push_back(make_pair("signed",SIGNED));
    keyMap.push_back(make_pair("sizeof",SIZEOF));
    keyMap.push_back(make_pair("static",STATIC));
    keyMap.push_back(make_pair("struct",STRUCT));
    keyMap.push_back(make_pair("switch",SWITCH));
    keyMap.push_back(make_pair("typedef",TYPEDEF));
    keyMap.push_back(make_pair("union",UNION));
    keyMap.push_back(make_pair("unsigned",UNSIGNED));
    keyMap.push_back(make_pair("void",VOID));
    keyMap.push_back(make_pair("volatile",VOLATILE));
    keyMap.push_back(make_pair("while",WHILE));

    keyMap.push_back(make_pair("describe",DESCRIBE));
    keyMap.push_back(make_pair("type",TYPE));
    keyMap.push_back(make_pair("string",STRING));
    keyMap.push_back(make_pair("digit",DIGIT));
}
void initOperMapping()
{
    operMap.clear();
    operMap.push_back(make_pair("!",NOT));
    operMap.push_back(make_pair("&",BYTE_AND));
    operMap.push_back(make_pair("~",COMPLEMENT));
    operMap.push_back(make_pair("^",BYTE_XOR));
    operMap.push_back(make_pair("*",MUL));
    operMap.push_back(make_pair("/",DIV));
    operMap.push_back(make_pair("%",MOD));
    operMap.push_back(make_pair("+",ADD));
    operMap.push_back(make_pair("-",SUB));
    operMap.push_back(make_pair("<",LES_THAN));
    operMap.push_back(make_pair(">",GRT_THAN));
    operMap.push_back(make_pair("=",ASG));
    operMap.push_back(make_pair("->",ARROW));
    operMap.push_back(make_pair("++",SELF_ADD));
    operMap.push_back(make_pair("--",SELF_SUB));
    operMap.push_back(make_pair("<<",LEFT_MOVE));
    operMap.push_back(make_pair(">>",RIGHT_MOVE));
    operMap.push_back(make_pair("<=",LES_EQUAL));
    operMap.push_back(make_pair(">=",GRT_EQUAL));
    operMap.push_back(make_pair("==",EQUAL));
    operMap.push_back(make_pair("!=",NOT_EQUAL));
    operMap.push_back(make_pair("&&",AND));
    operMap.push_back(make_pair("||",OR));
    operMap.push_back(make_pair("+=",COMPLETE_ADD));
    operMap.push_back(make_pair("-=",COMPLETE_SUB));
    operMap.push_back(make_pair("*=",COMPLETE_MUL));
    operMap.push_back(make_pair("/=",COMPLETE_DIV));
    operMap.push_back(make_pair("^=",COMPLETE_BYTE_XOR));
    operMap.push_back(make_pair("&=",COMPLETE_BYTE_AND));
    operMap.push_back(make_pair("~=",COMPLETE_COMPLEMENT));
    operMap.push_back(make_pair("%=",COMPLETE_MOD));
    operMap.push_back(make_pair("|",BYTE_OR));
}
void initLimitMapping()
{
    limitMap.clear();
    limitMap.push_back(make_pair("(",LEFT_BRA));
    limitMap.push_back(make_pair(")",RIGHT_BRA));
    limitMap.push_back(make_pair("[",LEFT_INDEX));
    limitMap.push_back(make_pair("]",RIGHT_INDEX));
    limitMap.push_back(make_pair("{",L_BOUNDER));
    limitMap.push_back(make_pair("}",R_BOUNDER));
    limitMap.push_back(make_pair(".",POINTER));
    limitMap.push_back(make_pair("#",JING));
    limitMap.push_back(make_pair("_",UNDER_LINE));
    limitMap.push_back(make_pair(",",COMMA));
    limitMap.push_back(make_pair(";",SEMI));
    limitMap.push_back(make_pair("'",SIN_QUE));
    limitMap.push_back(make_pair("\"",DOU_QUE));
}
void initNode()
{
    normalHead = new NormalNode();
    strcpy(normalHead->content,"");
    strcpy(normalHead->describe,"");
    normalHead->type = -1;
    normalHead->addr = -1;
    normalHead->line = -1;
    normalHead->next = NULL;

    errorHead = new ErrorNode();
    strcpy(errorHead->content,"");
    strcpy(errorHead->describe,"");
    errorHead->line = -1;
    errorHead->next = NULL;

    idenHead = new IdentiferNode();
    strcpy(idenHead->content,"");
    strcpy(idenHead->describe,"");
    idenHead->type = -1;
    idenHead->addr = -1;
    idenHead->line = -1;
    idenHead->next = NULL;
}

void createNewNode(char * content,char *descirbe,int type,int addr,int line)
{
    NormalNode * p = normalHead;
    NormalNode * temp = new NormalNode();

    while(p->next!=NULL)
    {
        p = p->next;
    }

    strcpy(temp->content,content);
    strcpy(temp->describe,descirbe);
    temp->type = type;
    temp->addr = addr;
    temp->line = line;
    temp->next = NULL;

    p->next = temp;
}
void createNewError(char * content,char *descirbe,int type,int line)
{
    ErrorNode * p = errorHead;
    ErrorNode * temp = new ErrorNode();

    strcpy(temp->content,content);
    strcpy(temp->describe,descirbe);
    temp->type = type;
    temp->line = line;
    temp->next = NULL;
    while(p->next!=NULL)
    {
        p = p->next;
    }
    p->next = temp;
}
//返回值是新的標誌符的入口地址
int createNewIden(char * content,char *descirbe,int type,int addr,int line)
{
    IdentiferNode * p = idenHead;
    IdentiferNode * temp = new IdentiferNode();
    int flag = 0;
    int addr_temp = -2;
    while(p->next!=NULL)
    {
        if(strcmp(content,p->next->content) == 0)
        {
            flag = 1;
            addr_temp = p->next->addr;
        }
        p = p->next;
    }
    if(flag == 0)
    {
        addr_temp = ++static_iden_number;//用自增來模擬入口地址
    }
    strcpy(temp->content,content);
    strcpy(temp->describe,descirbe);
    temp->type = type;
    temp->addr = addr_temp;
    temp->line = line;
    temp->next = NULL;
    p->next = temp;
    return addr_temp;
}

void printNodeLink()
{
    NormalNode * p = normalHead;
    p = p->next;
    cout<<"************************************分析表******************************"<<endl<<endl;
    cout<<setw(30)<<"內容"<<setw(10)<<"描述"<<"\t"<<"種別碼"<<"\t"<<"地址"<<"\t"<<"行號"<<endl;
    while(p!=NULL)
    {
        if(p->type == IDENTIFER)
        {
            cout<<setw(30)<<p->content<<setw(10)<<p->describe<<"\t"<<p->type<<"\t"<<p->addr<<"\t"<<p->line<<endl;
        }
        else
        {
            cout<<setw(30)<<p->content<<setw(10)<<p->describe<<"\t"<<p->type<<"\t"<<"\t"<<p->line<<endl;
        }
        p = p->next;
    }
    cout<<endl<<endl;
}
/*
錯誤種類:
1.float表示錯誤
2.double表示錯誤
3.註釋沒有結束符
4.字串常量沒有結束符
5.字元常量沒有結束符
6.非法字元
7.'('沒有對應項
8.預處理錯誤
*/
void printErrorLink()
{
    ErrorNode * p = errorHead;
    p = p->next;
    cout<<"************************************錯誤表******************************"<<endl<<endl;
    cout<<setw(10)<<"內容"<<setw(30)<<"描述"<<"\t"<<"型別"<<"\t"<<"行號"<<endl;
    while(p!=NULL)
    {
        cout<<setw(10)<<p->content<<setw(30)<<p->describe<<"\t"<<p->type<<"\t"<<p->line<<endl;
        p = p->next;
    }
    cout<<endl<<endl;
}
//標誌符表,有重複部分,暫不考慮
void printIdentLink()
{
    IdentiferNode * p = idenHead;
    p = p->next;
    cout<<"************************************標誌符表******************************"<<endl<<endl;
    cout<<setw(30)<<"內容"<<setw(10)<<"描述"<<"\t"<<"種別碼"<<"\t"<<"地址"<<"\t"<<"行號"<<endl;
    while(p!=NULL)
    {
        cout<<setw(30)<<p->content<<setw(10)<<p->describe<<"\t"<<p->type<<"\t"<<p->addr<<"\t"<<p->line<<endl;
        p = p->next;
    }
    cout<<endl<<endl;
}
int mystrlen(char * word)
{
    if(*word == '\0')
    {
        return 0;
    }
    else
    {
        return 1+mystrlen(word+1);
    }
}
//預處理,處理標頭檔案和巨集定義
void preProcess(char * word,int line)
{
    const char * include_temp = "include";
    const char * define_temp = "define";
    char * p_include,*p_define;
    int flag = 0;
    p_include = strstr(word,include_temp);
    if(p_include!=NULL)
    {
        flag = 1;
        int i;
        for(i=7;;)
        {
            if(*(p_include+i) == ' ' || *(p_include+i) == '\t')
            {
                i++;
            }
            else
            {
                break;
            }
        }
        createNewNode(p_include+i,HEADER_DESC,HEADER,-1,line);
    }
    else
    {
        p_define = strstr(word,define_temp);
        if(p_define!=NULL)
        {
            flag = 1;
            int i;
            for(i=7;;)
            {
                if(*(p_define+i) == ' ' || *(p_define+i) == '\t')
                {
                    i++;
                }
                else
                {
                    break;
                }
            }
            createNewNode(p_define+i,CONSTANT_DESC,MACRO_VAL,-1,line);
        }
    }
    if(flag == 0)
    {
        createNewError(word,PRE_PROCESS_ERROR,PRE_PROCESS_ERROR_NUM,line);
    }
}

void close()
{
    //delete idenHead;
    //delete errorHead;
    //delete normalHead;
}

int seekKey(char * word)
{
    for(int i=0; i<keyMap.size(); i++)
    {
        if(strcmp(word,keyMap[i].first) == 0)
        {
            return i+1;
        }
    }
    return IDENTIFER;
}

void scanner()
{
    char filename[30];
    char ch;
    char array[30];//單詞長度上限是30
    char * word;
    int i;
    int line = 1;//行數


    FILE * infile;
    printf("請輸入要進行語法分析的C語言程式:\n");
    scanf("%s",filename);
    infile = fopen(filename,"r");
    while(!infile)
    {
        printf("開啟檔案失敗!\n");
        return;
    }
    ch = fgetc(infile);
    while(ch!=EOF)
    {

        i = 0;
        //以字母或者下劃線開頭,處理關鍵字或者識別符號
        if((ch>='A' && ch<='Z') || (ch>='a' && ch<='z') || ch == '_')
        {
            while((ch>='A' && ch<='Z')||(ch>='a' && ch<='z')||(ch>='0' && ch<='9') || ch == '_')
            {
                array[i++] = ch;
                ch = fgetc(infile);
            }
            word = new char[i+1];
            memcpy(word,array,i);
            word[i] = '\0';
            int seekTemp = seekKey(word);
            if(seekTemp!=IDENTIFER)
            {
                createNewNode(word,KEY_DESC,seekTemp,-1,line);
            }
            else
            {
                int addr_tmp = createNewIden(word,IDENTIFER_DESC,seekTemp,-1,line);
                createNewNode(word,IDENTIFER_DESC,seekTemp,addr_tmp,line);
            }
            fseek(infile,-1L,SEEK_CUR);//向後回退一位
        }
        //以數字開頭,處理數字
        else if(ch >='0' && ch<='9')
        {
            int flag = 0;
            int flag2 = 0;
            //處理整數
            while(ch >='0' && ch<='9')
            {
                array[i++] = ch;
                ch = fgetc(infile);
            }
            //處理float
            if(ch == '.')
            {
                flag2 = 1;
                array[i++] = ch;
                ch = fgetc(infile);
                if(ch>='0' && ch<='9')
                {
                    while(ch>='0' && ch<='9')
                    {
                        array[i++] = ch;
                        ch = fgetc(infile);
                    }
                }
                else
                {
                    flag = 1;
                }

                //處理Double
                if(ch == 'E' || ch == 'e')
                {
                    array[i++] = ch;
                    ch = fgetc(infile);
                    if(ch == '+' || ch == '-')
                    {
                        array[i++] = ch;
                        ch = fgetc(infile);
                    }
                    if(ch >='0' && ch<='9')
                    {
                        array[i++] = ch;
                        ch = fgetc(infile);
                    }
                    else
                    {
                        flag = 2;
                    }
                }

            }
            word = new char[i+1];
            memcpy(word,array,i);
            word[i] = '\0';
            if(flag == 1)
            {
                createNewError(word,FLOAT_ERROR,FLOAT_ERROR_NUM,line);
            }
            else if(flag == 2)
            {
                createNewError(word,DOUBLE_ERROR,DOUBLE_ERROR_NUM,line);
            }
            else
            {
                if(flag2 == 0)
                {
                    createNewNode(word,CONSTANT_DESC,INT_VAL,-1,line);
                }
                else
                {
                    createNewNode(word,CONSTANT_DESC,FLOAT_VAL,-1,line);
                }
            }
            fseek(infile,-1L,SEEK_CUR);//向後回退一位
        }
        //以"/"開頭
        else if(ch == '/')
        {
            ch = fgetc(infile);
            //處理運算子"/="
            if(ch == '=')
            {
                createNewNode("/=",OPE_DESC,COMPLETE_DIV,-1,line);
            }
            //處理"/**/"型註釋
            else if(ch == '*')
            {
                ch =  fgetc(infile);
                while(1)
                {
                    while(ch != '*')
                    {
                        if(ch == '\n')
                        {
                            line++;
                        }
                        ch = fgetc(infile);
                        if(ch == EOF)
                        {
                            createNewError(_NULL,NOTE_ERROR,NOTE_ERROR_NUM,line);
                            return;
                        }
                    }
                    ch = fgetc(infile);
                    if(ch == '/')
                    {
                        break;
                    }
                    if(ch == EOF)
                    {
                        createNewError(_NULL,NOTE_ERROR,NOTE_ERROR_NUM,line);
                        return;
                    }
                }
                createNewNode(_NULL,NOTE_DESC,NOTE1,-1,line);
            }
            //處理"//"型註釋
            else if(ch == '/')
            {
                while(ch!='\n')
                {
                    ch = fgetc(infile);
                    if(ch == EOF)
                    {
                        createNewNode(_NULL,NOTE_DESC,NOTE2,-1,line);
                        return;
                    }
                }
                line++;
                createNewNode(_NULL,NOTE_DESC,NOTE2,-1,line);
                if(ch == EOF)
                {
                    return;
                }
            }
            //處理除號
            else
            {
                createNewNode("/",OPE_DESC,DIV,-1,line);
            }
        }
        //處理常量字串
        else if(ch == '"')
        {
            createNewNode("\"",CLE_OPE_DESC,DOU_QUE,-1,line);
            ch = fgetc(infile);
            i = 0;
            while(ch!='"')
            {
                array[i++] = ch;
                if(ch == '\n')
                {
                    line++;
                }
                ch = fgetc(infile);
                if(ch == EOF)
                {
                    createNewError(_NULL,STRING_ERROR,STRING_ERROR_NUM,line);
                    return;
                }
            }
            word = new char[i+1];
            memcpy(word,array,i);
            word[i] = '\0';
            createNewNode(word,CONSTANT_DESC,STRING_VAL,-1,line);
            createNewNode("\"",CLE_OPE_DESC,DOU_QUE,-1,line);
        }
        //處理常量字元
        else if(ch == '\'')
        {
            createNewNode("\'",CLE_OPE_DESC,SIN_QUE,-1,line);
            ch = fgetc(infile);
            i = 0;
            while(ch!='\'')
            {
                array[i++] = ch;
                if(ch == '\n')
                {
                    line++;
                }
                ch = fgetc(infile);
                if(ch == EOF)
                {
                    createNewError(_NULL,CHARCONST_ERROR,CHARCONST_ERROR_NUM,line);
                    return;
                }
            }
            word = new char[i+1];
            memcpy(word,array,i);
            word[i] = '\0';
            createNewNode(word,CONSTANT_DESC,CHAR_VAL,-1,line);
            createNewNode("\'",CLE_OPE_DESC,SIN_QUE,-1,line);
        }
        else if(ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n')
        {
            if(ch == '\n')
            {
                line++;
            }
        }
        else
        {
            if(ch == EOF)
            {
                return;
            }
            //處理標頭檔案和巨集常量(預處理)
            else if(ch == '#')
            {
                while(ch!='\n' && ch!=EOF)
                {
                    array[i++] = ch;
                    ch = fgetc(infile);
                }
                word = new char[i+1];
                memcpy(word,array,i);
                word[i] = '\0';
                preProcess(word,line);

                fseek(infile,-1L,SEEK_CUR);//向後回退一位
            }
            //處理-開頭的運算子
            else if(ch == '-')
            {
                array[i++] = ch;
                ch = fgetc(infile);
                if(ch >='0' && ch<='9')
                {
                    int flag = 0;
                    int flag2 = 0;
                    //處理整數
                    while(ch>='0' && ch<='9')
                    {
                        array[i++] = ch;
                        ch = fgetc(infile);
                    }
                    //處理float
                    if(ch == '.')
                    {
                        flag2 = 1;
                        array[i++] = ch;
                        ch = fgetc(infile);
                        if(ch>='0' && ch<='9')
                        {
                            while(ch>='0' && ch<='9')
                            {
                                array[i++] = ch;
                                ch = fgetc(infile);
                            }
                        }
                        else
                        {
                            flag = 1;
                        }
                        //處理Double
                        if(ch == 'E' || ch == 'e')
                        {
                            array[i++] = ch;
                            ch = fgetc(infile);
                            if(ch == '+' || ch == '-')
                            {
                                array[i++] = ch;
                                ch = fgetc(infile);
                            }
                            if(ch >='0' && ch<='9')
                            {
                                array[i++] = ch;
                                ch = fgetc(infile);
                            }
                            else
                            {
                                flag = 2;
                            }
                        }
                    }
                    word = new char[i+1];
                    memcpy(word,array,i);
                    word[i] = '\0';
                    if(flag == 1)
                    {
                        createNewError(word,FLOAT_ERROR,FLOAT_ERROR_NUM,line);
                    }
                    else if(flag == 2)
                    {
                        createNewError(word,DOUBLE_ERROR,DOUBLE_ERROR_NUM,line);
                    }
                    else
                    {
                        if(flag2 == 0)
                        {
                            createNewNode(word,CONSTANT_DESC,INT_VAL,-1,line);
                        }
                        else
                        {
                            createNewNode(word,CONSTANT_DESC,FLOAT_VAL,-1,line);
                        }
                    }
                    fseek(infile,-1L,SEEK_CUR);//向後回退一位
                }
                else if(ch == '>')
                {
                    createNewNode("->",OPE_DESC,ARROW,-1,line);
                }
                else if(ch == '-')
                {
                    createNewNode("--",OPE_DESC,SELF_SUB,-1,line);
                }
                else if(ch == '=')
                {
                    createNewNode("--",OPE_DESC,SELF_SUB,-1,line);
                }
                else
                {
                    createNewNode("-",OPE_DESC,SUB,-1,line);
                    fseek(infile,-1L,SEEK_CUR);
                }
            }
            //處理+開頭的運算子
            else if(ch == '+')
            {
                ch = fgetc(infile);
                if(ch == '+')
                {
                    createNewNode("++",OPE_DESC,SELF_ADD,-1,line);
                }
                else if(ch == '=')
                {
                    createNewNode("+=",OPE_DESC,COMPLETE_ADD,-1,line);
                }
                else
                {
                    createNewNode("+",OPE_DESC,ADD,-1,line);
                    fseek(infile,-1L,SEEK_CUR);
                }
            }
            //處理*開頭的運算子
            else if(ch == '*')
            {
                ch = fgetc(infile);
                if(ch == '=')
                {
                    createNewNode("*=",OPE_DESC,COMPLETE_MUL,-1,line);
                }
                else
                {
                    createNewNode("*",OPE_DESC,MUL,-1,line);
                    fseek(infile,-1L,SEEK_CUR);
                }
            }
            //處理按^開頭的運算子
            else if(ch == '^')
            {
                ch = fgetc(infile);
                if(ch == '=')
                {
                    createNewNode("^=",OPE_DESC,COMPLETE_BYTE_XOR,-1,line);
                }
                else
                {
                    createNewNode("^",OPE_DESC,BYTE_XOR,-1,line);
                    fseek(infile,-1L,SEEK_CUR);
                }
            }
            //處理%開頭的運算子
            else if(ch == '%')
            {
                ch = fgetc(infile);
                if(ch == '=')
                {
                    createNewNode("%=",OPE_DESC,COMPLETE_MOD,-1,line);
                }
                else
                {
                    createNewNode("%",OPE_DESC,MOD,-1,line);
                    fseek(infile,-1L,SEEK_CUR);
                }
            }
            //處理&開頭的運算子
            else if(ch == '&')
            {
                ch = fgetc(infile);
                if(ch == '=')
                {
                    createNewNode("&=",OPE_DESC,COMPLETE_BYTE_AND,-1,line);
                }
                else if(ch == '&')
                {
                    createNewNode("&&",OPE_DESC,AND,-1,line);
                }
                else
                {
                    createNewNode("&",OPE_DESC,BYTE_AND,-1,line);
                    fseek(infile,-1L,SEEK_CUR);
                }
            }
            //處理~開頭的運算子
            else if(ch == '~')
            {
                ch = fgetc(infile);
                if(ch == '=')
                {
                    createNewNode("~=",OPE_DESC,COMPLETE_COMPLEMENT,-1,line);
                }
                else
                {
                    createNewNode("~",OPE_DESC,COMPLEMENT,-1,line);
                    fseek(infile,-1L,SEEK_CUR);
                }
            }
            //處理!開頭的運算子
            else if(ch == '!')
            {
                ch = fgetc(infile);
                if(ch == '=')
                {
                    createNewNode("!=",OPE_DESC,NOT_EQUAL,-1,line);
                }
                else
                {
                    createNewNode("!",OPE_DESC,NOT,-1,line);
                    fseek(infile,-1L,SEEK_CUR);
                }
            }
            //處理<開頭的運算子
            else if(ch == '<')
            {
                ch = fgetc(infile);
                if(ch == '<')
                {
                    createNewNode("<<",OPE_DESC,LEFT_MOVE,-1,line);
                }
                else if(ch == '=')
                {
                    createNewNode("<=",OPE_DESC,LES_EQUAL,-1,line);
                }
                else
                {
                    createNewNode("<",OPE_DESC,LES_THAN,-1,line);
                    fseek(infile,-1L,SEEK_CUR);
                }
            }
            //處理>開頭的運算子
            else if(ch == '>')
            {
                ch = fgetc(infile);
                if(ch == '>')
                {
                    createNewNode(">>",OPE_DESC,RIGHT_MOVE,-1,line);
                }
                else if(ch == '=')
                {
                    createNewNode(">=",OPE_DESC,GRT_EQUAL,-1,line);
                }
                else
                {
                    createNewNode(">",OPE_DESC,GRT_THAN,-1,line);
                    fseek(infile,-1L,SEEK_CUR);
                }
            }
            //處理|開頭的運算子
            else if(ch == '|')
            {
                ch = fgetc(infile);
                if(ch == '|')
                {
                    createNewNode("||",OPE_DESC,OR,-1,line);
                }
                else
                {
                    createNewNode("|",OPE_DESC,BYTE_OR,-1,line);
                    fseek(infile,-1L,SEEK_CUR);
                }
            }
            else if(ch == '=')
            {
                ch = fgetc(infile);
                if(ch == '=')
                {
                    createNewNode("==",OPE_DESC,EQUAL,-1,line);
                }
                else
                {
                    createNewNode("=",OPE_DESC,ASG,-1,line);
                    fseek(infile,-1L,SEEK_CUR);
                }
            }
            else if(ch == '(')
            {
                leftSmall++;
                lineBra[0][leftSmall] = line;
                createNewNode("(",CLE_OPE_DESC,LEFT_BRA,-1,line);
            }
            else if(ch == ')')
            {
                rightSmall++;
                lineBra[1][rightSmall] = line;
                createNewNode(")",CLE_OPE_DESC,RIGHT_BRA,-1,line);
            }
            else if(ch == '[')
            {
                leftMiddle++;
                lineBra[2][leftMiddle] = line;
                createNewNode("[",CLE_OPE_DESC,LEFT_INDEX,-1,line);
            }
            else if(ch == ']')
            {
                rightMiddle++;
                lineBra[3][rightMiddle] = line;
                createNewNode("]",CLE_OPE_DESC,RIGHT_INDEX,-1,line);
            }
            else if(ch == '{')
            {
                leftBig++;
                lineBra[4][leftBig] = line;
                createNewNode("{",CLE_OPE_DESC,L_BOUNDER,-1,line);
            }
            else if(ch == '}')
            {
                rightBig++;
                lineBra[5][rightBig] = line;
                createNewNode("}",CLE_OPE_DESC,R_BOUNDER,-1,line);
            }
            else if(ch == '.')
            {
                createNewNode(".",CLE_OPE_DESC,POINTER,-1,line);
            }
            else if(ch == ',')
            {
                createNewNode(",",CLE_OPE_DESC,COMMA,-1,line);
            }
            else if(ch == ';')
            {
                createNewNode(";",CLE_OPE_DESC,SEMI,-1,line);
            }
            else
            {
                char temp[2];
                temp[0] = ch;
                temp[1] = '\0';
                createNewError(temp,CHAR_ERROR,CHAR_ERROR_NUM,line);
            }
        }
        ch = fgetc(infile);
    }
}
void BraMappingError()
{
    if(leftSmall != rightSmall)
    {
        int i = (leftSmall>rightSmall) ? (leftSmall-rightSmall) : (rightSmall - leftSmall);
        bool  flag = (leftSmall>rightSmall) ? true : false;
        if(flag)
        {
            while(i--)
            {
                createNewError(_NULL,LEFT_BRA_ERROR,LEFT_BRA_ERROR_NUM,lineBra[0][i+1]);
            }
        }
        else
        {
            while(i--)
            {
                createNewError(_NULL,RIGHT_BRA_ERROR,RIGHT_BRA_ERROR_NUM,lineBra[1][i+1]);
            }
        }
    }
    if(leftMiddle != rightMiddle)
    {
        int i = (leftMiddle>rightMiddle) ? (leftMiddle-rightMiddle) : (rightMiddle - leftMiddle);
        bool flag = (leftMiddle>rightMiddle) ? true : false;
        if(flag)
        {
            while(i--)
            {
                createNewError(_NULL,LEFT_INDEX_ERROR,LEFT_INDEX_ERROR_NUM,lineBra[2][i+1]);
            }
        }
        else
        {
            while(i--)
            {
                createNewError(_NULL,RIGHT_INDEX_ERROR,RIGHT_INDEX_ERROR_NUM,lineBra[3][i+1]);
            }
        }
    }
    if(leftBig != rightBig)
    {
        int i = (leftBig>rightBig) ? (leftBig-rightBig) : (rightBig - leftSmall);
        bool flag = (leftBig>rightBig) ? true : false;
        if(flag)
        {
            while(i--)
            {
                createNewError(_NULL,L_BOUNDER_ERROR,L_BOUNDER_ERROR_NUM,lineBra[4][i+1]);
            }
        }
        else
        {
            while(i--)
            {
                createNewError(_NULL,R_BOUNDER_ERROR,R_BOUNDER_ERROR_NUM,lineBra[5][i+1]);
            }
        }
    }
}


語法分析Cpp程式碼:
//SynAnalysis.cpp
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <conio.h>
#include <fstream>
#include <vector>
#include <conio.h>
#include "LexAnalysis.h"
#include "SynAnalysis.h"

using namespace std;

#define Max_Proc 500
#define Max_Length 500

#define Max_NonTer 60
#define Max_Ter 60
#define Max_Length2 100

int procNum = 0;
//proc的維數都是從1開始的
int proc[Max_Proc][Max_Length];//產生式的陣列,裡邊儲存了終結符或者非終結符對應的編號
int first[Max_Proc][Max_Length];
int follow[Max_Proc][Max_Length];
int select[Max_Proc][Max_Length];
int M[Max_NonTer][Max_Ter][Max_Length2];

int connectFirst[Max_Length];//將某些First集結合起來的集合


int firstVisit[Max_Proc];//記錄某非終結符的First集是否已經求過
int followVisit[Max_Proc];//記錄某非終結符的Follow集是否已經求過

int empty[Max_Proc];//可推出空的非終結符的編號
int emptyRecu[Max_Proc];//在求可推出空的非終結符的編號集時使用的防治遞迴的集合
int followRecu[Max_Proc];//在求Follow集時使用的防治遞迴的集合

//extern的部分代表可能出現的終結符和其編號
extern vector<pair<const char *,int> > keyMap;
extern vector<pair<const char *,int> > operMap;
extern vector<pair<const char *,int> > limitMap;

extern NormalNode * normalHead;//首結點

fstream resultfile;

vector<pair<const char *,int> > nonTerMap;//非終結符對映表,不可重複的
vector<pair<const char *,int> > terMap;//終結符對映表,不可重複的
vector<pair<const char *,int> > specialMap;//文法中的特殊符號對映表,包括-> | $(空)


void initSpecialMapping()
{
    specialMap.clear();
    specialMap.push_back(make_pair("->",GRAMMAR_ARROW));
    specialMap.push_back(make_pair("|",GRAMMAR_OR));
    specialMap.push_back(make_pair("$",GRAMMAR_NULL));
    specialMap.push_back(make_pair("#",GRAMMAR_SPECIAL));

}
const char * searchMapping(int num)
{
    //標誌符
    if(num == IDENTIFER)
    {
        return "id";
    }
    //處理文法中的特殊符號
    for(int i = 0; i<specialMap.size(); i++)
    {
        if(specialMap[i].second == num)
        {
            return specialMap[i].first;
        }
    }
    //處理非終結符
    for(int i=0; i<nonTerMap.size(); i++)
    {
        if(nonTerMap[i].second == num)
        {
            return nonTerMap[i].first;
        }
    }
    //處理終結符
    for(int i=0; i<terMap.size(); i++)
    {
        if(terMap[i].second == num)
        {
            return terMap[i].first;
        }
    }

}

//動態生成非終結符,在基點的基礎上,確保不和終結符衝突
int dynamicNonTer(char *word)
{
    int i = 0;
    int dynamicNum;
    for(i=0; i<nonTerMap.size(); i++)
    {
        if(strcmp(word,nonTerMap[i].first) == 0)
        {
            return nonTerMap[i].second;
        }
    }
    if(i == nonTerMap.size())
    {
        if(i == 0)
        {
            dynamicNum = GRAMMAR_BASE;
            nonTerMap.push_back(make_pair(word,dynamicNum));
        }
        else
        {
            dynamicNum = nonTerMap[nonTerMap.size()-1].second + 1;
            nonTerMap.push_back(make_pair(word,dynamicNum));
        }
    }
    return dynamicNum;
}
//判斷某個標號是不是非終結符的標號,1代表是,0代表否
int inNonTer(int n)
{
    for(int i=0; i<nonTerMap.size(); i++)
    {
        if(nonTerMap[i].second == n)
        {
            return 1;
        }
    }
    return 0;
}
//判斷某個標號是不是終結符的標號,1代表是,0代表否
int inTer(int n)
{
    for(int i=0; i<terMap.size(); i++)
    {
        if(terMap[i].second == n)
        {
            return 1;
        }
    }
    return 0;
}
//判斷某個標號在不在此時的empty集中,1代表是,0代表否
int inEmpty(int n)
{
    //當前Empty集的長度
    int emptyLength = 0;
    for(emptyLength = 0;; emptyLength++)
    {
        if(empty[emptyLength] == -1)
        {
            break;
        }
    }
    for(int i = 0; i<emptyLength; i++)
    {
        if(empty[i] == n)
        {
            return 1;
        }
    }
    return 0;

}
//判斷某個標號在不在此時的emptyRecu集中,1代表是,0代表否
int inEmptyRecu(int n)
{
    //當前Empty集的長度
    int emptyLength = 0;
    for(emptyLength = 0;; emptyLength++)
    {
        if(emptyRecu[emptyLength] == -1)
        {
            break;
        }
    }
    for(int i = 0; i<emptyLength; i++)
    {
        if(emptyRecu[i] == n)
        {
            return 1;
        }
    }
    return 0;
}
//判斷某個標號在不在此時的followRecu集中,1代表是,0代表否
int inFollowRecu(int n)
{
    int followLength = 0;
    for(followLength = 0;; followLength++)
    {
        if(followRecu[followLength] == -1)
        {
            break;
        }
    }
    for(int i = 0; i<followLength; i++)
    {
        if(followRecu[i] == n)
        {
            return 1;
        }
    }
    return 0;
}

//判斷某個標號是不是在產生式的右邊
int inProcRight(int n,int * p)
{
    //注意這裡預設是從3開始
    for(int i=3;; i++)
    {
        if(p[i] == -1)
        {
            break;
        }
        if(p[i] == n)
        {
            return 1;
        }
    }
    return 0;
}

int seekCodeNum(char * word)
{
    //處理文法中的特殊符號
    for(int i = 0; i<specialMap.size(); i++)
    {
        if(strcmp(word,specialMap[i].first) == 0)
        {
            return specialMap[i].second;
        }
    }
    //先搜尋終結符對映表中有沒有此終結符
    for(int i=0; i<terMap.size(); i++)
    {
        if(strcmp(word,terMap[i].first) == 0)
        {
            return terMap[i].second;
        }
    }
    for(int i = 0; i<keyMap.size(); i++)
    {
        if(strcmp(word,keyMap[i].first) == 0)
        {
            terMap.push_back(make_pair(word,keyMap[i].second));
            return keyMap[i].second;
        }
    }

    for(int i = 0; i<operMap.size(); i++)
    {
        if(strcmp(word,operMap[i].first) == 0)
        {
            terMap.push_back(make_pair(word,operMap[i].second));
            return operMap[i].second;
        }
    }

    for(int i = 0; i<limitMap.size(); i++)
    {
        if(strcmp(word,limitMap[i].first) == 0)
        {
            terMap.push_back(make_pair(word,limitMap[i].second));
            return limitMap[i].second;
        }
    }

    if(strcmp(word,"id")==0)
    {
        //處理標誌符
        terMap.push_back(make_pair(word,IDENTIFER));
        return IDENTIFER;
    }
    else
    {
        //處理關鍵字、運算子、限界符表,即非終結符
        return dynamicNonTer(word);
    }
}
//分割" | "文法
void splitProc(int p[][Max_Length],int &line,int orNum)
{
    if(p[line][1] == -1 || orNum == 0)
    {
        return;
    }
    int head = p[line][1];
    int push = p[line][2];
    int length = 0;
    int right,left;
    int lineTrue = line + orNum;
    for(length = 3;;length++)
    {
        if(p[line][length] == -1)
        {
            break;
        }
    }
    length--;
    for(left = length,right = length;left>=2;)
    {
        if(p[line][left] == GRAMMAR_OR || left == 2)
        {
            p[line + orNum][1] = head;
            p[line + orNum][2] = push;
            for(int i=left+1;i<=right;i++)
            {
                p[line+orNum][i-left+2] = p[line][i];
            }
            p[line+orNum][right-left+3] = -1;
            right = left = left-1;
            orNum--;
        }
        else
        {
            left--;
        }
    }
    line = lineTrue;
}
void initGrammer()
{
    FILE * infile;
    char ch;
    char array[30];
    char * word;
    int i;
    int codeNum;
    int line = 1;
    int count = 0;
    int orNum = 0;
    infile = fopen("wenfa.txt","r");
    if(!infile)
    {
        printf("文法開啟失敗!\n");
        return;
    }
    initSpecialMapping();
    nonTerMap.clear();
    terMap.clear();

    memset(proc,-1,sizeof(proc));
    memset(first,-1,sizeof(first));
    memset(follow,-1,sizeof(follow));
    memset(select,-1,sizeof(select));

    memset(connectFirst,-1,sizeof(connectFirst));

    memset(firstVisit,0,sizeof(firstVisit));//非終結符的first集還未求過
    memset(followVisit,0,sizeof(followVisit));//非終結符的follow集還未求過

    memset(empty,-1,sizeof(empty));
    memset(emptyRecu,-1,sizeof(emptyRecu));
    memset(followRecu,-1,sizeof(followRecu));

    memset(M,-1,sizeof(M));

    ch = fgetc(infile);
    i = 0;
    while(ch!=EOF)
    {
        i = 0;
        while(ch == ' ' || ch == '\t')
        {
            ch = fgetc(infile);
        }
        while(ch!=' ' && ch!= '\n' && ch!=EOF)
        {
            array[i++] = ch;
            ch = fgetc(infile);
        }
        while(ch == ' ' || ch == '\t')
        {
            ch = fgetc(infile);
        }
        word = new char[i+1];
        memcpy(word,array,i);
        word[i] = '\0';
        codeNum = 0;
        codeNum = seekCodeNum(word);
        if(codeNum!=0)
        {
            count++;
            if(codeNum == GRAMMAR_OR)
            {
                orNum++;
            }
            proc[line][count] = codeNum;

        }
        //原本需要回退一個字元,由於是冗餘字元,不回退
        if(ch == '\n')
        {
            splitProc(proc,line,orNum);//將" | "文法進行拆分
            count = 0;
            orNum = 0;
            line++;
            ch = fgetc(infile);
        }
    }
    procNum = line - 1;
    printf("************************************C語言文法******************************\n\n");
    for(int i=1; i<line; i++)
    {
        for(int j=1; j<Max_Length; j++)
        {
            if(proc[i][j]!=-1)
            {
                printf("%s ",searchMapping(proc[i][j]));
            }
            else
            {
                break;
            }
        }
        printf("\n");
    }
    printf("\n************************************文法終結符******************************\n\n");
    for(int i=0; i<terMap.size(); i++)
    {
        printf("%s ",terMap[i].first);
    }
    printf("\n");
    printf("\n************************************文法非終結符******************************\n\n");
    for(int i=0; i<nonTerMap.size(); i++)
    {
        printf("%s ",nonTerMap[i].first);
    }
    printf("\n");
}
//將s集合合併至d集合中,type = 1代表包括空($),type = 2代表不包括空
void merge(int *d,int *s,int type)
{
    int flag = 0;
    for(int i = 0;; i++)
    {
        flag = 0;
        if(s[i] == -1)
        {
            break;
        }
        int j = 0;
        for(j = 0;; j++)
        {
            if(d[j] == -1)
            {
                break;
            }
            if(d[j] == s[i])
            {
                flag = 1;
                break;
            }
        }
        if(flag == 1)
        {
            continue;
        }
        if(type == 1)
        {
            d[j] = s[i];
        }
        else
        {
            if(s[i] != GRAMMAR_NULL)
            {
                d[j] = s[i];
            }
        }
        d[j + 1] = -1;
    }
}

void nullSet(int currentNum)
{
    int temp[2];
    for(int j = 1; j<=procNum; j++)
    {
        //如果右邊的第一個是該字元,並且長度只有1
        if(proc[j][3] == currentNum && proc[j][4] == -1)
        {
            temp[0] = proc[j][1];
            temp[1] = -1;
            merge(empty,temp,1);
            nullSet(proc[j][1]);
        }
    }
}
//判斷該非終結符是否能推出空,但終結符也可能傳入,但沒關係
int reduNull(int currentNon)
{
    int temp[2];
    int result = 1;
    int mark = 0;
    temp[0] = currentNon;
    temp[1] = -1;
    merge(emptyRecu,temp,1);//先將此符號併入防遞迴集合中
    if(inEmpty(currentNon) == 1)
    {
        return 1;
    }

    for(int j = 1; j<=procNum; j++)
    {
        if(proc[j][1] == currentNon)
        {
            int rightLength = 0;
            //先求出右部的長度
            for(rightLength = 3;; rightLength++)
            {
                if(proc[j][rightLength] == -1)
                {
                    break;
                }
            }
            rightLength--;
            //如果長度為1,並且已經求過
            if(rightLength - 2 == 1 && inEmpty(proc[j][rightLength]))
            {
                return 1;
            }
            //如果長度為1,並且是終結符
            else if(rightLength -2 == 1 && inTer(proc[j][rightLength]))
            {
                return 0;
            }
            //如果長度超過了2
            else
            {
                for(int k=3; k<=rightLength; k++)
                {
                    if(inEmptyRecu(proc[j][k]))
                    {
                        mark = 1;
                    }
                }
                if(mark == 1)
                {
                    continue;
                }
                else
                {
                    for(int k=3; k<=rightLength; k++)
                    {
                        result*= reduNull(proc[j][k]);
                        temp[0] = proc[j][k];
                        temp[1] = -1;
                        merge(emptyRecu,temp,1);//先將此符號併入防遞迴集合中
                    }
                }
            }
            if(result == 0)
            {
                continue;
            }
            else if(result == 1)
            {
                return 1;
            }
        }
    }
    return 0;
}

//求first集,傳入的引數是在非終結符集合中的序號
void firstSet(int i)
{
    int k = 0;
    int currentNon = nonTerMap[i].second;//當前的非終結符標號
    //依次遍歷全部產生式
    for(int j = 1; j<=procNum; j++) //j代表第幾個產生式
    {
        //找到該非終結符的產生式
        if(currentNon == proc[j][1])//注意從1開始
        {
            //當右邊的第一個是終結符或者空的時候
            if(inTer(proc[j][3]) == 1 || proc[j][3] == GRAMMAR_NULL)
            {
                //併入當前非終結符的first集中
                int temp[2];
                temp[0] = proc[j][3];
                temp[1] = -1;//其實是模擬字串操作的手段
                merge(first[i],temp,1);
            }
            //當右邊的第一個是非終結符的時候
            else if(inNonTer(proc[j][3]) == 1)
            {
                //如果遇到左遞迴形式的,直接放過?
                if(proc[j][3] == currentNon)
                {
                    continue;
                }
                //記錄下右邊第一個非終結符的位置
                for(k=0;; k++)
                {
                    if(nonTerMap[k].second == proc[j][3])
                    {
                        break;
                    }

                }
                //當右邊第一個非終結符還未訪問過的時候
                if(firstVisit[k] == 0)
                {
                    firstSet(k);
                    firstVisit[k] = 1;
                }
                merge(first[i],first[k],2);//如果first[k]此時有空值的話,暫時不把空值併入first[i]中
                int rightLength = 0;
                //先求出右部的長度

                for(rightLength = 3;; rightLength++)
                {
                    if(proc[j][rightLength] == -1)
                    {
                        break;
                    }
                }
                //到目前為止,只求出了右邊的第一個(還不包括空的部分),For迴圈處理之後的
                for(k = 3; k<rightLength; k++)
                {
                    emptyRecu[0] = -1;//相當於初始化這個防遞迴集合

                    //如果右部的當前字元能推出空並且還不是最後一個字元,就將之後的一個字元併入First集中
                    if(reduNull(proc[j][k]) == 1 && k<rightLength -1)
                    {
                        int u = 0;
                        for(u=0;; u++)
                        {
                            //注意是記錄下一個符號的位置
                            if(nonTerMap[u].second == proc[j][k+1])
                            {
                                break;
                            }
                        }
                        if(firstVisit[u] == 0)
                        {
                            firstSet(u);
                            firstVisit[u] = 1;
                        }
                        merge(first[i],first[u],2);
                    }
                    //到達最後一個字元,並且產生式右部都能推出空,將$併入First集中
                    else if(reduNull(proc[j][k]) == 1 && k == rightLength -1)
                    {
                        int temp[2];
                        temp[0] = GRAMMAR_NULL;
                        temp[1] = -1;//其實是模擬字串操作的手段
                        merge(first[i],temp,1);
                    }
                    else
                    {
                        break;
                    }
                }
            }
        }
    }
    firstVisit[i] = 1;
}
void First()
{
    //先求出能直接推出空的非終結符集合
    nullSet(GRAMMAR_NULL);
    printf("\n");
    for(int i=0; i<nonTerMap.size(); i++)
    {
        firstSet(i);
    }
    printf("\n************************************First集******************************\n\n");
    for(int i=0; i<nonTerMap.size(); i++)
    {
        printf("First[%s] = ",nonTerMap[i].first);
        for(int j=0;; j++)
        {
            if(first[i][j] == -1)
            {
                break;
            }
            printf("%s ",searchMapping(first[i][j]));
        }
        printf("\n");
    }
}
//將First結合起來的函式
void connectFirstSet(int *p)
{
    int i = 0;
    int flag = 0;
    int temp[2];
    //如果P的長度為1
    if(p[1] == -1)
    {
        if(p[0] == GRAMMAR_NULL)
        {
            connectFirst[0] = GRAMMAR_NULL;
            connectFirst[1] = -1;
        }
        else
        {
            for(i=0; i<nonTerMap.size(); i++)
            {
                if(nonTerMap[i].second == p[0])
                {
                    flag = 1;
                    merge(connectFirst,first[i],1);
                    break;
                }
            }
            //也可能是終結符
            if(flag == 0)
            {
                for(i=0; i<terMap.size(); i++)
                {
                    if(terMap[i].second == p[0])
                    {
                        temp[0] = terMap[i].second;
                        temp[1] = -1;
                        merge(connectFirst,temp,2);//終結符的First集就是其本身
                        break;
                    }
                }
            }
        }
    }
    //如果p的長度大於1
    else
    {
        for(i=0; i<nonTerMap.size(); i++)
        {
            if(nonTerMap[i].second == p[0])
            {
                flag = 1;
                merge(connectFirst,first[i],2);
                break;
            }
        }
        //也可能是終結符
        if(flag == 0)
        {
            for(i=0; i<terMap.size(); i++)
            {
                if(terMap[i].second == p[0])
                {
                    temp[0] = terMap[i].second;
                    temp[1] = -1;
                    merge(connectFirst,temp,2);//終結符的First集就是其本身
                    break;
                }
            }
        }
        flag = 0;
        int length = 0;
        for(length = 0;; length++)
        {
            if(p[length] == -1)
            {
                break;
            }
        }
        for(int k=0; k<length; k++)
        {
            emptyRecu[0] = -1;//相當於初始化這個防遞迴集合

            //如果右部的當前字元能推出空並且還不是最後一個字元,就將之後的一個字元併入First集中
            if(reduNull(p[k]) == 1 && k<length -1)
            {
                int u = 0;
                for(u=0; u<nonTerMap.size(); u++)
                {
                    //注意是記錄下一個符號的位置
                    if(nonTerMap[u].second == p[k+1])
                    {
                        flag = 1;
                        merge(connectFirst,first[u],2);
                        break;
                    }
                }
                //也可能是終結符
                if(flag == 0)
                {
                    for(u=0; u<terMap.size(); u++)
                    {
                        //注意是記錄下一個符號的位置
                        if(terMap[u].second == p[k+1])
                        {
                            temp[0] = terMap[i].second;
                            temp[1] = -1;
                            merge(connectFirst,temp,2);
                            break;
                        }
                    }
                }
                flag = 0;
            }
            //到達最後一個字元,並且產生式右部都能推出空,將$併入First集中
            else if(reduNull(p[k]) == 1 && k == length -1)
            {
                temp[0] = GRAMMAR_NULL;
                temp[1] = -1;//其實是模擬字串操作的手段
                merge(connectFirst,temp,1);
            }
            else
            {
                break;
            }
        }
    }
}
void followSet(int i)
{
    int currentNon = nonTerMap[i].second;//當前的非終結符標號
    int temp[2];
    int result = 1;
    temp[0] = currentNon;
    temp[1] = -1;
    merge(followRecu,temp,1);//將當前標號加入防遞迴集合中

    //如果當前符號就是開始符號,把特殊符號加入其Follow集中
    if(proc[1][1] == currentNon)
    {
        temp[0] = GRAMMAR_SPECIAL;//這個也是要處理的
        temp[1] = -1;
        merge(follow[i],temp,1);
    }
    for(int j = 1; j<=procNum; j++) //j代表第幾個產生式
    {
        //如果該非終結符在某個產生式的右部存在
        if(inProcRight(currentNon,proc[j]) == 1)
        {
            int rightLength = 1;
            int k = 0;//k為該非終結符在產生式右部的序號
            int flag = 0;
            int leftNum = proc[j][1];//產生式的左邊
            int h = 0;
            int kArray[Max_Length2];
            memset(kArray,-1,sizeof(kArray));
            for(h = 0; h < nonTerMap.size(); h++)
            {
                if(nonTerMap[h].second == leftNum)
                {
                    break;
                }
            }

            for(rightLength = 1;; rightLength++)
            {
                if(currentNon == proc[j][rightLength+2])
                {
                    kArray[k++] = rightLength;
                }
                if(proc[j][rightLength+2] == -1)
                {
                    break;
                }
            }
            rightLength--;
            for(int y=0;; y++)
            {
                if(kArray[y] == -1)
                {
                    break;
                }
                //如果該非終結符在右部產生式的最後
                if(kArray[y] == rightLength)
                {

                    if(inFollowRecu(leftNum) == 1)
                    {
                        merge(follow[i],follow[h],1);
                        continue;
                    }
                    if(fo