阅读背景:

C语言简单子集编译器源码(第一版)

来源:互联网 
预处理器:
/** scmppre.c
====================================================================
This is the base source file for pre-compiler


====================================================================
 */

#include "scmppre.h"


static int report_pre_error(char *msg, int code){
    printf("Error : %s\nCode : %d\n", msg, code);
    return 0;
}

#define CHECK_INDEX( index )    \
    if( index >= MAX_SRC_LINE ){\
        report_pre_error("Too long line.", index);\
        return 0;\
    }
/*=======================================================
The main function of pre-compiler.
return     1 : success
           0 : fail
========================================================*/
int pre_compiler(FILE * fpInput, FILE * fpOutput){
    char str_line_buffer[MAX_SRC_LINE + 1];
    int index = 0;
    char current_char;
    current_char = fgetc(fpInput);
    while( current_char != EOF ){
        /*========================================================
        search the '//' . if exists, jump the rest of the line.
        ========================================================*/
        if( '/' == current_char ){
            current_char = fgetc(fpInput);
            if( '/' == current_char ){
                while( current_char != EOF ){
                    current_char =  fgetc(fpInput);
                    if( '\n' == current_char ){
                        /* end of a line */
                        str_line_buffer[index] = '\n';
                        index++;
                        CHECK_INDEX( index )
                        break;/* stop loop */
                    }
                }
                /* output a line */
                str_line_buffer[index] = '
预处理器:
/** scmppre.c
====================================================================
This is the base source file for pre-compiler


====================================================================
 */

#include "scmppre.h"


static int report_pre_error(char *msg, int code){
    printf("Error : %s\nCode : %d\n", msg, code);
    return 0;
}

#define CHECK_INDEX( index )    \
    if( index >= MAX_SRC_LINE ){\
        report_pre_error("Too long line.", index);\
        return 0;\
    }
/*=======================================================
The main function of pre-compiler.
return     1 : success
           0 : fail
========================================================*/
int pre_compiler(FILE * fpInput, FILE * fpOutput){
    char str_line_buffer[MAX_SRC_LINE + 1];
    int index = 0;
    char current_char;
    current_char = fgetc(fpInput);
    while( current_char != EOF ){
        /*========================================================
        search the '//' . if exists, jump the rest of the line.
        ========================================================*/
        if( '/' == current_char ){
            current_char = fgetc(fpInput);
            if( '/' == current_char ){
                while( current_char != EOF ){
                    current_char =  fgetc(fpInput);
                    if( '\n' == current_char ){
                        /* end of a line */
                        str_line_buffer[index] = '\n';
                        index++;
                        CHECK_INDEX( index )
                        break;/* stop loop */
                    }
                }
                /* output a line */
                str_line_buffer[index] = '\0';
                fputs(str_line_buffer, fpOutput);
                index = 0;
            } else{
                /* a single '/', just store it and its following byte */
                str_line_buffer[index] = '/';
                index++;
                CHECK_INDEX( index )
                if( EOF == current_char ){ /* end of file */
                    str_line_buffer[index] = '\0';
                    fputs(str_line_buffer, fpOutput);
                    index = 0;
                    return 1;
                } else if( '\n' == current_char ){
                    str_line_buffer[index] = current_char;
                    index++;
                    CHECK_INDEX( index )
                    str_line_buffer[index] = '\0';
                    fputs(str_line_buffer, fpOutput);
                    index = 0;
                } else{
                    str_line_buffer[index] = current_char;
                    index++;
                    CHECK_INDEX( index )
                }
            }
        } else if( '\n' == current_char ){
            str_line_buffer[index] = current_char;
            index++;
            CHECK_INDEX( index )
            str_line_buffer[index] = '\0';
            fputs(str_line_buffer, fpOutput);
            index = 0;
        } else{
            str_line_buffer[index] = current_char;
            index++;
            CHECK_INDEX( index )
        }
        current_char = fgetc(fpInput);
    }

    str_line_buffer[index] = '\0';
    fputs(str_line_buffer, fpOutput);
    index = 0;

    return 1;
}


语法分析器

 

/** scmpstx.c
====================================================================
This is the base source file for Syntax Analyze


====================================================================
 */
#include "scmpstx.h"

int DEFINITION(FileField *fileField, int left_brother_ID, int father_ID);
int VAR_DEF(FileField *fileField, int left_brother_ID, int father_ID);
int FUNC_DEF(FileField *fileField, int left_brother_ID, int father_ID);
int IDENTIFY(FileField *fileField, int left_brother_ID, int father_ID);
int BODY(FileField *fileField, int left_brother_ID, int father_ID);
int VAR_DEFINITION(FileField *fileField, int left_brother_ID, int father_ID);
int STATEMENT_LIST(FileField *fileField, int left_brother_ID, int father_ID);
int ASSIGN_STMT(FileField *fileField, int left_brother_ID, int father_ID);
int IF_STMT(FileField *fileField, int left_brother_ID, int father_ID);
int FOR_STMT(FileField *fileField, int left_brother_ID, int father_ID);
int WHILE_STMT(FileField *fileField, int left_brother_ID, int father_ID);
int FORMULA(FileField *fileField, int left_brother_ID, int father_ID);
int BOOL_FORMULA(FileField *fileField, int left_brother_ID, int father_ID);
int FORMULA_FOLLOW(FileField *fileField, int left_brother_ID, int father_ID);
int BOOL_FORMULA_FOLLOW(FileField *fileField, int left_brother_ID, int father_ID);
int FUNC_CALL(FileField *fileField, int left_brother_ID, int father_ID);



void report_syntax_error(char *func_name, char *detail, int line_number){
    printf("Syntax error accured in function '%s()', at line '%d'.\nDetail: %s\n", func_name, line_number, detail);
    return;
}
void report_memery_error(char *func_name, int line_number){
    printf("Memery error accured in function '%s()', at line '%d'.\n", func_name, line_number);
    return;
}
void report_internal_error(char *func_name, int line_number){
    printf("Internal error accured in function '%s()', at line '%d'.\n", func_name, line_number);
    return;
}
int initialize_IdTable(){
    int i=0;
    int j=0;
    g_IdTable.n_id_num = 0;
    g_IdTable.pIdList = (IdentId_P)malloc( ( MAX_SYN_NODE_NUM + 1 ) * sizeof(IdentId) );
    if( NULL == g_IdTable.pIdList ){
        report_memery_error("initialize_IdTable", __LINE__);
        return 0;
    }
    for( i = 0; i < 51; i++ ){
        for( j = 0; j < 61; j++ ){
            g_IdTable.two_level_index[i][j] = INVALID_ID;
        }
    }
    return 1;
}
int initialize_SynTree(){
    g_SynTree.n_node_num = 0;
    g_SynTree.pSynNodeList = (SynNode_P)malloc( ( MAX_SYN_NODE_NUM + 1 ) * sizeof(SynNode) );
    if( NULL == g_SynTree.pSynNodeList ){
        report_memery_error("initialize_SynTree", __LINE__);
        return 0;
    }
    return 1;
}
int release_IdTable(){
    MY_HELP_FREE( g_IdTable.pIdList )
    g_IdTable.n_id_num = 0;
    return 1;
}
int release_SynTree(){
    MY_HELP_FREE( g_SynTree.pSynNodeList );
    g_SynTree.n_node_num = 0;
    return 1;
}

int syntax_analyzer(FileField *fileField){
    int ret = 0;
    char * func_name="syntax_analyzer";

    /** [ 1 ] initialize a node for whole program **/
    g_SynTree.n_node_num = 1;
    g_SynTree.pSynNodeList[0].n_father_id = INVALID_ID;
    g_SynTree.pSynNodeList[0].n_identifier_id = INVALID_ID;
    g_SynTree.pSynNodeList[0].n_left_brother_id = INVALID_ID;
    g_SynTree.pSynNodeList[0].n_mode = SYN_NODE_HEAD;
    g_SynTree.pSynNodeList[0].n_right_brother_id = INVALID_ID;
    g_SynTree.pSynNodeList[0].n_son_id = INVALID_ID;
    /** [ 2 ] deal with DEFINITION **/
    ret = DEFINITION( fileField, INVALID_ID, 0 );
    /** [ 3 ] deal with 'main' **/
    if( 0 == ret ){
        printf("Syntax_analyzer exit with syntax error.\n");
        return 0;
    } else{
        /* some definition finished, the node 'DEFINITION' is the left brother of 'main' */
        g_SynTree.n_node_num++;
        CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
        g_SynTree.pSynNodeList[g_SynTree.n_node_num-1].n_father_id = 0;/* the index of 'main' is g_SynTree.n_node_num-1 */
        g_SynTree.pSynNodeList[g_SynTree.n_node_num-1].n_identifier_id = INVALID_ID;
        g_SynTree.pSynNodeList[g_SynTree.n_node_num-1].n_left_brother_id = 1;/* the node 'DEFINITION' */
        g_SynTree.pSynNodeList[g_SynTree.n_node_num-1].n_mode = SYN_NODE_MAINFUNID;
        g_SynTree.pSynNodeList[g_SynTree.n_node_num-1].n_right_brother_id = INVALID_ID;
        g_SynTree.pSynNodeList[g_SynTree.n_node_num-1].n_son_id = INVALID_ID;
        g_SynTree.pSynNodeList[1].n_right_brother_id = g_SynTree.n_node_num-1;/* fix the right brother for node 'DEFINITION' */
    }
    /** [ 4 ] deal with '(' and ')' **/
    /* [ 4.1 ] jump the spaces after 'main' */
    JUMP_SPACES( fileField )
    /* [ 4.2 ] check '(' */
    if( '(' != fileField->current_ch ){
        report_syntax_error( "syntax_analyzer", "missing '('.", fileField->n_current_line );
        printf("Syntax_analyzer exit with syntax error.\n");
        return 0;
    }
    /* [ 4.3 ] jump the spaces after '(' */
    GET_NEW_CHAR_JUMP_SPACE( fileField )
    /* [ 4.4 ] check ')' */
    if( ')' != fileField->current_ch ){
        report_syntax_error( "syntax_analyzer", "missing ')'.", fileField->n_current_line );
        printf("Syntax_analyzer exit with syntax error.\n");
        return 0;
    }
    /* [ 4.5 ] jump the spaces after ')' */
    GET_NEW_CHAR_JUMP_SPACE( fileField )
    /* [ 4.6 ] check '{' */
    if( '{' != fileField->current_ch ){
        report_syntax_error( "syntax_analyzer", "missing '{'.", fileField->n_current_line );
        printf("Syntax_analyzer exit with syntax error.\n");
        return 0;
    }
    /** [ 5 ] deal with 'BODY' **/
    ret = BODY( fileField, g_SynTree.n_node_num-1, 0 );
    if( 0 == ret ){
        printf("Syntax_analyzer exit with syntax error.\n");
        return 0;
    }
    /* [ 6 ] jump the spaces after 'BODY' */
    JUMP_SPACES( fileField )
    /* [ 7 ] check '}' */
    if( '}' != fileField->current_ch ){
        report_syntax_error( "syntax_analyzer", "missing '}'.", fileField->n_current_line );
        printf("Syntax_analyzer exit with syntax error.\n");
        return 0;
    }
    /* [ 8 ] jump the spaces after '}' */
    GET_NEW_CHAR_JUMP_SPACE( fileField )
    if( EOF != fileField->current_ch ){
        report_syntax_error( "syntax_analyzer", "Unexpected character.", fileField->n_current_line );
        printf("Syntax_analyzer exit with syntax error.\n");
        return 0;
    }
    return 1;
}


int DEFINITION(FileField *fileField, int left_brother_ID, int father_ID){
    int ret = 0;
    int id_length = 0;
    char *func_name="DEFINITION";
    unsigned int tempIndex = 0;

    /* [ 1 ] make a node for 'DEFINITION' */
    tempIndex = g_SynTree.n_node_num;
    g_SynTree.pSynNodeList[ tempIndex ].n_father_id = father_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_identifier_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_left_brother_id = left_brother_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_mode = SYN_NODE_DEFINITION;
    g_SynTree.pSynNodeList[ tempIndex ].n_right_brother_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_son_id = INVALID_ID;
    /* [ 2 ] fix for father and left brother */
    FIX_FATHER_LBROTHER( father_ID, left_brother_ID, tempIndex )
    g_SynTree.n_node_num++;
    CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )


    /* [ 3 ] deal with VAR_DEF */
    ret = VAR_DEF( fileField, INVALID_ID, tempIndex );
    if( 0 == ret ){
        return 0;
    }
    if( 1000 == ret ){
        report_syntax_error( func_name, "Invalid identifier .", fileField->n_current_line );
        return 0;
    } else if( 100 == ret ){
        return 1;
    } else if( 200 == ret ){
        /* [ 4 ] deal with FUNC_DEF */
        ret = FUNC_DEF( fileField, INVALID_ID, tempIndex );
        if( 0 == ret ){
            return 0;
        }
    } else if( 300 == ret ){
        report_syntax_error( "syntax_analyzer", "Unexpected character.", fileField->n_current_line );
        return 0;
    }
    /* [ 5 ] deal with DEFINITION recursively */
    ret = DEFINITION( fileField, g_SynTree.pSynNodeList[ tempIndex ].n_son_id, tempIndex );
    if( 0 == ret ){
        return 0;
    }
    return 1;
}
/** if it returns 1000, it's unkown character, maybe '}' **/
/** if it returns 100, an identifier name 'main' is stored in FileField.name_buf **/
/** if it returns 200, an identifier name ( not 'main' ) is stored in FileField.name_buf **/
/** if it returns 300, it's 'if' 'while' 'for' **/
int VAR_DEF(FileField *fileField, int left_brother_ID, int father_ID){
    int ret = 0;
    char *func_name="VAR_DEF";
    unsigned int tempIndex = 0;
    unsigned int ident_index = 0;
    int id_length = 0;
    /* [ 1 ] jump spaces in the head */
    GET_NEW_CHAR_JUMP_SPACE( fileField )
    /* [ 2 ] get the first token */
    GET_IDENTIFY( fileField, fileField->name_buf, id_length )
    if( 0 == id_length ){
        return 1000;
    }
    CHECK_KEY_WORD( fileField->name_buf, ret )
    if( KEY_WORD_MAIN == ret ){
        /* no definition */
        return 100;
    } else if( KEY_WORD_NO == ret ){
        /* it's an identifier. maybe statment_list or syntax error. */
        return 200;
    }else if( KEY_WORD_INT == ret ){
        /* [ 3 ] deal with 'VAR_DEF' */
        /* [ 3.1 ] make a node for 'VAR_DEF' */
        tempIndex = g_SynTree.n_node_num;
        g_SynTree.pSynNodeList[ tempIndex ].n_father_id = father_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_identifier_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_left_brother_id = left_brother_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_mode = SYN_NODE_VAR_DEF;
        g_SynTree.pSynNodeList[ tempIndex ].n_right_brother_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_son_id = INVALID_ID;
        /* [ 3.2 ] fix for father and left brother */
        FIX_FATHER_LBROTHER( father_ID, left_brother_ID, tempIndex )
        g_SynTree.n_node_num++;
        CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
        /* [ 3.3 ] get the identifier after 'int' */
        GET_IDENTIFY( fileField, fileField->name_buf, id_length )
        if( 0 == id_length ){
            report_syntax_error( func_name, "Invalid identifier .", fileField->n_current_line );
            return 0;
        }
        CHECK_KEY_WORD( fileField->name_buf, ret )
        if( KEY_WORD_NO != ret ){
            /* Invalid identifier */
            report_syntax_error( func_name, "Invalid identifier: key-word.", fileField->n_current_line );
            return 0;
        }
        /* [ 3.4 ] use a IdentId to store the identifier and make a syntax node */
        ret = add_to_IdTable(fileField, fileField->name_buf, id_length, SYN_NODE_VARID, &ident_index);
        if( 0 == ret ){
            return 0;
        }
        g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_father_id = tempIndex;
        g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_identifier_id = ident_index;
        g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_left_brother_id = INVALID_ID;
        g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_mode = SYN_NODE_VARID;
        g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_right_brother_id = INVALID_ID;
        g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_son_id = INVALID_ID;
        /* [ 3.5 ] fix for father and left brother */
        FIX_FATHER_LBROTHER( tempIndex, INVALID_ID, g_SynTree.n_node_num )
        g_SynTree.n_node_num++;
        CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
        /* [ 3.6 ] deal with ';' */
        JUMP_SPACES( fileField )
        if( ';' != fileField->current_ch ){
            report_syntax_error( func_name, "Missing ';' .", fileField->n_current_line );
            return 0;
        }
        return 1;
    } else{
        /* it's 'if' 'while' 'for' */
        return 300;
    }
}
int FUNC_DEF(FileField *fileField, int left_brother_ID, int father_ID){
    int ret = 0;
    char *func_name="FUNC_DEF";
    unsigned int tempIndex = 0;
    unsigned int ident_index = 0;
    int id_length = 0;
    /* [ 1 ] deal with FUNC_DEF */
    /* [ 1.1 ] make a node for FUNC_DEF */
    g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_father_id = father_ID;
    g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_identifier_id = INVALID_ID;
    g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_left_brother_id = left_brother_ID;
    g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_mode = SYN_NODE_FUNC_DEF;
    g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_right_brother_id = INVALID_ID;
    g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_son_id = INVALID_ID;
    /* [ 1.2 ] fix for father and left brother */
    FIX_FATHER_LBROTHER( father_ID, left_brother_ID, g_SynTree.n_node_num )
    g_SynTree.n_node_num++;
    CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
    /* [ 1.3 ] use a IdentId to store the identifier and make a syntax node */
    ret = add_to_IdTable(fileField, fileField->name_buf, (int)strlen( fileField->name_buf ), SYN_NODE_FUNID, &ident_index);
    if( 0 == ret ){
        return 0;
    }
    g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_father_id = g_SynTree.n_node_num - 1;
    g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_identifier_id = ident_index;
    g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_left_brother_id = INVALID_ID;
    g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_mode = SYN_NODE_FUNID;
    g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_right_brother_id = INVALID_ID;
    g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_son_id = INVALID_ID;
    /* [ 1.4 ] fix for father and left brother */
    FIX_FATHER_LBROTHER( g_SynTree.n_node_num - 1, INVALID_ID, g_SynTree.n_node_num )
    g_SynTree.n_node_num++;
    CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
    /* [ 1.5 ] deal with '(' */
    JUMP_SPACES( fileField )
    if( '(' != fileField->current_ch ){
        report_syntax_error( func_name, "Missing '(' .", fileField->n_current_line );
        return 0;
    }
    /* [ 1.6 ] deal with ')' */
    GET_NEW_CHAR_JUMP_SPACE( fileField )
    if( ')' != fileField->current_ch ){
        report_syntax_error( func_name, "Missing ')' .", fileField->n_current_line );
        return 0;
    }
    /* [ 1.7 ] deal with '{' */
    GET_NEW_CHAR_JUMP_SPACE( fileField )
    if( '{' != fileField->current_ch ){
        report_syntax_error( func_name, "Missing '{' .", fileField->n_current_line );
        return 0;
    }
    /* [ 1.8 ] deal with 'BODY' */
    ret = BODY( fileField, g_SynTree.n_node_num - 1, g_SynTree.n_node_num - 2 );
    if( 0 == ret ){
        return 0;
    }
    /* [ 1.9 ] deal with '}' */
    JUMP_SPACES( fileField )
    if( '}' != fileField->current_ch ){
        report_syntax_error( func_name, "Missing '}' .", fileField->n_current_line );
        return 0;
    }
    return 1;
}
int BODY(FileField *fileField, int left_brother_ID, int father_ID){
    int ret = 0;
    char *func_name="BODY";
    unsigned int tempIndex = 0;
    int id_length = 0;

    /* [ 1 ] make a node for 'BODY' */
    tempIndex = g_SynTree.n_node_num;
    g_SynTree.pSynNodeList[ tempIndex ].n_father_id = father_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_identifier_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_left_brother_id = left_brother_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_mode = SYN_NODE_BODY;
    g_SynTree.pSynNodeList[ tempIndex ].n_right_brother_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_son_id = INVALID_ID;
    /* [ 2 ] fix for father and left brother */
    FIX_FATHER_LBROTHER( father_ID, left_brother_ID, tempIndex )
    g_SynTree.n_node_num++;
    CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
    /* [ 3 ] deal with VAR_DEFINITION */
    ret = VAR_DEFINITION( fileField, INVALID_ID, tempIndex );
    if( 0 == ret ){
        return 0;
    }
    if( 400 != ret ){
        /* [ 4 ] deal with STATEMENT_LIST */
        ret = STATEMENT_LIST( fileField, g_SynTree.pSynNodeList[ tempIndex ].n_son_id, tempIndex );
        if( 0 == ret ){
            return 0;
        }
    }

    return 1;
}
/** if it returns 200, an identifier name is stored in FileField.name_buf **/
/** if it returns 300, it's 'if' 'while' 'for' **/
/** if it returns 400, an empty statment_list is following **/
int VAR_DEFINITION(FileField *fileField, int left_brother_ID, int father_ID){
    int ret = 0;
    char *func_name="VAR_DEFINITION";
    unsigned int tempIndex = 0;
    /* [ 1 ] make a node for 'VAR_DEFINITION' */
    tempIndex = g_SynTree.n_node_num;
    g_SynTree.pSynNodeList[ tempIndex ].n_father_id = father_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_identifier_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_left_brother_id = left_brother_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_mode = SYN_NODE_VAR_DEFINITION;
    g_SynTree.pSynNodeList[ tempIndex ].n_right_brother_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_son_id = INVALID_ID;
    /* [ 2 ] fix for father and left brother */
    FIX_FATHER_LBROTHER( father_ID, left_brother_ID, tempIndex )
    g_SynTree.n_node_num++;
    CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
    /* [ 3 ] deal with VAR_DEF */
    ret = VAR_DEF( fileField, INVALID_ID, tempIndex );
    if( 0 == ret ){
        return 0;
    }
    if( 1000 == ret ){
        if( '}' != fileField->current_ch ){
            report_syntax_error( func_name, "Invalid identifier .", fileField->n_current_line );
            return 0;
        } else{
            /* Empty statement_list */
            return 400;
        }
    } else if( 100 == ret ){
        report_syntax_error( "syntax_analyzer", "Unexpected key-word 'main'.", fileField->n_current_line );
        return 0;/* 'main' can't be here */
    } else if( 200 == ret ){
        /* [ 4 ] 'STATEMENT_LIST' is following */
        return 200;
    } else if( 300 == ret ){
        /* [ 5 ] 'STATEMENT_LIST' is following */
        return 300;
    }
    ret = VAR_DEFINITION( fileField, g_SynTree.pSynNodeList[ tempIndex ].n_son_id, tempIndex );
    return ret;
}
int STATEMENT_LIST(FileField *fileField, int left_brother_ID, int father_ID){
    int ret = 0;
    char *func_name="STATEMENT_LIST";
    unsigned int tempIndex = 0;
    unsigned int id_length = 0;
    /* [ 1 ] make a node for 'STATEMENT_LIST' */
    tempIndex = g_SynTree.n_node_num;
    g_SynTree.pSynNodeList[ tempIndex ].n_father_id = father_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_identifier_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_left_brother_id = left_brother_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_mode = SYN_NODE_STATEMENT_LIST;
    g_SynTree.pSynNodeList[ tempIndex ].n_right_brother_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_son_id = INVALID_ID;
    /* [ 2 ] fix for father and left brother */
    FIX_FATHER_LBROTHER( father_ID, left_brother_ID, tempIndex )
    g_SynTree.n_node_num++;
    CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
    /* [ 3 ] check the last byte */
    if( '}' == fileField->current_ch ){
        /* the statement list is empty */
        return 1;
    }
    /* [ 4 ] check the key-word which has already been read */
    CHECK_KEY_WORD( fileField->name_buf, ret )
    if( KEY_WORD_NO == ret ){
        JUMP_SPACES( fileField )
        if( '=' == fileField->current_ch ){
            /* [ 4.1 ] it's an ASSIGN_STMT */
            ret = ASSIGN_STMT( fileField, INVALID_ID, tempIndex );
            if( 0 == ret ){
                return 0;
            }
            JUMP_SPACES( fileField )
            if( ';' != fileField->current_ch ){
                /* check ';' */
                report_syntax_error( func_name, "Missing ';' .", fileField->n_current_line );
                return 0;
            }
        } else if( '(' == fileField->current_ch ){
            /* [ 4.2 ] it's an FUNC_CALL */
            ret = FUNC_CALL( fileField, INVALID_ID, tempIndex );
            if( 0 == ret ){
                return 0;
            }
        } else{
            report_syntax_error( func_name, "Unknown statement .", fileField->n_current_line );
            return 0;
        }
    } else if( KEY_WORD_IF == ret ){
        /* [ 4.2 ] deal with IF_STMT */
        ret = IF_STMT( fileField, INVALID_ID, tempIndex );
        if( 0 == ret ){
            return 0;
        }
    } else if( KEY_WORD_WHILE == ret ){
        /* [ 4.3 ] deal with WHILE_STMT */
        ret = WHILE_STMT( fileField, INVALID_ID, tempIndex );
        if( 0 == ret ){
            return 0;
        }
    } else if( KEY_WORD_FOR == ret ){
        /* [ 4.4 ] deal with FOR_STMT */
        ret = FOR_STMT( fileField, INVALID_ID, tempIndex );
        if( 0 == ret ){
            return 0;
        }
    } else {
        report_syntax_error( func_name, "Invalid identifier .", fileField->n_current_line );
        return 0;
    }
    /* [ 5 ] jump spaces */
    GET_NEW_CHAR_JUMP_SPACE( fileField )
    /* [ 6 ] get the next token */
    GET_IDENTIFY( fileField, fileField->name_buf, id_length )
    /* [ 7 ] call STATEMENT_LIST() recursively */
    ret = STATEMENT_LIST( fileField, g_SynTree.pSynNodeList[ tempIndex ].n_son_id, tempIndex );
    if( 0 == ret ){
        return 0;
    }
    
    return 1;
}
int ASSIGN_STMT(FileField *fileField, int left_brother_ID, int father_ID){
    int ret = 0;
    char *func_name="ASSIGN_STMT";
    unsigned int tempIndex = 0;
    unsigned int ident_index = 0;
    IdentId_P p_cur_id = NULL;
    /* [ 1 ] make a node for 'ASSIGN_STMT' */
    tempIndex = g_SynTree.n_node_num;
    g_SynTree.pSynNodeList[ tempIndex ].n_father_id = father_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_identifier_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_left_brother_id = left_brother_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_mode = SYN_NODE_ASSIGN_STMT;
    g_SynTree.pSynNodeList[ tempIndex ].n_right_brother_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_son_id = INVALID_ID;
    /* [ 2 ] fix for father and left brother */
    FIX_FATHER_LBROTHER( father_ID, left_brother_ID, tempIndex )
    g_SynTree.n_node_num++;
    CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
    /* [ 3 ] find the identifier in IdTable */
    ret = find_in_IdTable(fileField, fileField->name_buf, (int)strlen(fileField->name_buf), &ident_index);
    if( 0 == ret ){
        return 0;
    }
    p_cur_id = &g_IdTable.pIdList[ ident_index ];
    if( p_cur_id->n_mode != SYN_NODE_VARID ){
        report_syntax_error( func_name, "Identifier can't be assigned, it's a function name.", fileField->n_current_line );
        return 0;
    }
    /* [ 4 ] make a node for the identifier */
    tempIndex = g_SynTree.n_node_num;
    g_SynTree.pSynNodeList[ tempIndex ].n_father_id = tempIndex - 1;
    g_SynTree.pSynNodeList[ tempIndex ].n_identifier_id = ident_index;
    g_SynTree.pSynNodeList[ tempIndex ].n_left_brother_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_mode = SYN_NODE_VARID;
    g_SynTree.pSynNodeList[ tempIndex ].n_right_brother_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_son_id = INVALID_ID;
    /* [ 5 ] fix for father and left brother */
    FIX_FATHER_LBROTHER( tempIndex - 1, INVALID_ID, tempIndex )
    g_SynTree.n_node_num++;
    CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
    /* [ 6 ] check the '=' */
    JUMP_SPACES( fileField )
    if( '=' != fileField->current_ch ){
        report_syntax_error( func_name, "Missing '='.", fileField->n_current_line );
        return 0;
    }
    /* [ 7 ] deal with FORMULA */
    ret = FORMULA( fileField, tempIndex, tempIndex - 1 );
    if( 0 == ret ){
        return 0;
    }

    return 1;
}

int IF_STMT(FileField *fileField, int left_brother_ID, int father_ID){
    int ret = 0;
    char *func_name="IF_STMT";
    unsigned int tempIndex = 0;
    unsigned int id_length = 0;
    /* [ 1 ] make a node for 'IF_STMT' */
    tempIndex = g_SynTree.n_node_num;
    g_SynTree.pSynNodeList[ tempIndex ].n_father_id = father_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_identifier_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_left_brother_id = left_brother_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_mode = SYN_NODE_IF_STMT;
    g_SynTree.pSynNodeList[ tempIndex ].n_right_brother_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_son_id = INVALID_ID;
    /* [ 2 ] fix for father and left brother */
    FIX_FATHER_LBROTHER( father_ID, left_brother_ID, tempIndex )
    g_SynTree.n_node_num++;
    CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
    /* [ 3 ] check '('  */
    JUMP_SPACES( fileField )
    if( '(' != fileField->current_ch ){
        report_syntax_error( func_name, "Missing '('.", fileField->n_current_line );
        return 0;
    }
    /* [ 4 ] deal with BOOL_FORMULA */
    /* [ 4.1 ] jump spaces in the head for two bytes operator e.g. '>=' */
    GET_NEW_CHAR_JUMP_SPACE( fileField )
    ret = BOOL_FORMULA( fileField, INVALID_ID, tempIndex );
    if( 0 == ret ){
        return 0;
    }
    /* [ 5 ] check ')'  */
    JUMP_SPACES( fileField )
    if( ')' != fileField->current_ch ){
        report_syntax_error( func_name, "Missing ')'.", fileField->n_current_line );
        return 0;
    }
    /* [ 6 ] jump spaces */
    GET_NEW_CHAR_JUMP_SPACE( fileField )
    /* [ 7 ] check '{' */
    if( '{' != fileField->current_ch ){
        report_syntax_error( func_name, "Missing '{'.", fileField->n_current_line );
        return 0;
    }
    /* [ 8 ] jump spaces */
    GET_NEW_CHAR_JUMP_SPACE( fileField )
    /* [ 9 ] get the next token */
    GET_IDENTIFY( fileField, fileField->name_buf, id_length )
    /* [ 10 ] call STATEMENT_LIST() */
    ret = STATEMENT_LIST( fileField, g_SynTree.pSynNodeList[ tempIndex ].n_son_id, tempIndex );
    if( 0 == ret ){
        return 0;
    }
    /* [ 11 ] deal with '}' */
    JUMP_SPACES( fileField )
    if( '}' != fileField->current_ch ){
        report_syntax_error( func_name, "Missing '}' .", fileField->n_current_line );
        return 0;
    }

    return 1;
}
int FOR_STMT(FileField *fileField, int left_brother_ID, int father_ID){
    int ret = 0;
    char *func_name="FOR_STMT";
    unsigned int for_stmt_index = 0;
    unsigned int tempIndex = 0;
    unsigned int id_length = 0;
    /* [ 1 ] make a node for 'FOR_STMT' */
    tempIndex = g_SynTree.n_node_num;
    for_stmt_index = tempIndex;
    g_SynTree.pSynNodeList[ tempIndex ].n_father_id = father_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_identifier_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_left_brother_id = left_brother_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_mode = SYN_NODE_FOR_STMT;
    g_SynTree.pSynNodeList[ tempIndex ].n_right_brother_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_son_id = INVALID_ID;
    /* [ 2 ] fix for father and left brother */
    FIX_FATHER_LBROTHER( father_ID, left_brother_ID, tempIndex )
    g_SynTree.n_node_num++;
    CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
    /* [ 3 ] check '('  */
    JUMP_SPACES( fileField )
    if( '(' != fileField->current_ch ){
        report_syntax_error( func_name, "Missing '('.", fileField->n_current_line );
        return 0;
    }
    /* [ 4 ] jump spaces */
    GET_NEW_CHAR_JUMP_SPACE( fileField )
    if( ';' == fileField->current_ch ){
        /* [ 5 ] first statement is empty, make an empty node */
        tempIndex++;
        g_SynTree.pSynNodeList[ tempIndex ].n_father_id = for_stmt_index;
        g_SynTree.pSynNodeList[ tempIndex ].n_identifier_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_left_brother_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_mode = SYN_NODE_EMPTY;
        g_SynTree.pSynNodeList[ tempIndex ].n_right_brother_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_son_id = INVALID_ID;
        /* [ 5.1 ] fix for father and left brother */
        FIX_FATHER_LBROTHER( for_stmt_index, INVALID_ID, tempIndex )
        g_SynTree.n_node_num++;
        CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
    } else{
        /* [ 6 ] deal with ASSIGN_STMT */
        /* [ 6.1 ] get the next token */
        GET_IDENTIFY( fileField, fileField->name_buf, id_length )
        ret = ASSIGN_STMT( fileField, INVALID_ID, for_stmt_index );
        if( 0 == ret ){
            return 0;
        }
        JUMP_SPACES( fileField )
        if( ';' != fileField->current_ch ){
            /* check ';' */
            report_syntax_error( func_name, "Missing ';' .", fileField->n_current_line );
            return 0;
        }
    }
    /* [ 7 ] deal with BOOL_FORMULA */
    /* [ 7.1 ] jump spaces in the head for two bytes operator e.g. '>=' */
    GET_NEW_CHAR_JUMP_SPACE( fileField )
    ret = BOOL_FORMULA( fileField, g_SynTree.pSynNodeList[ for_stmt_index ].n_son_id, for_stmt_index );
    if( 0 == ret ){
        return 0;
    }
    JUMP_SPACES( fileField )
    if( ';' != fileField->current_ch ){
        /* check ';' */
        report_syntax_error( func_name, "Missing ';' .", fileField->n_current_line );
        return 0;
    }
    /* [ 7.1 ] store the index of BOOL_FORMULA */
    tempIndex = g_SynTree.pSynNodeList[ g_SynTree.pSynNodeList[ for_stmt_index ].n_son_id ].n_right_brother_id;
    /* [ 8 ] jump spaces */
    GET_NEW_CHAR_JUMP_SPACE( fileField )
    if( ')' == fileField->current_ch ){
        /* [ 9 ] last statement is empty, make an empty node */
        g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_father_id = for_stmt_index;
        g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_identifier_id = INVALID_ID;
        g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_left_brother_id = tempIndex;
        g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_mode = SYN_NODE_EMPTY;
        g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_right_brother_id = INVALID_ID;
        g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_son_id = INVALID_ID;
        /* [ 9.1 ] fix for father and left brother */
        FIX_FATHER_LBROTHER( for_stmt_index, tempIndex, g_SynTree.n_node_num )
        g_SynTree.n_node_num++;
        CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
    } else{
        /* [ 10 ] deal with ASSIGN_STMT */
        /* [ 10.1 ] get the next token */
        GET_IDENTIFY( fileField, fileField->name_buf, id_length )
        ret = ASSIGN_STMT( fileField, tempIndex, for_stmt_index );
        if( 0 == ret ){
            return 0;
        }
        JUMP_SPACES( fileField )
        if( ')' != fileField->current_ch ){
            /* check ')' */
            report_syntax_error( func_name, "Missing ')' .", fileField->n_current_line );
            return 0;
        }
    }
    /* [ 10.1 ] store the index of third child of FOR_STMT */
    tempIndex = g_SynTree.pSynNodeList[ tempIndex ].n_right_brother_id;
    /* [ 11 ] jump spaces */
    GET_NEW_CHAR_JUMP_SPACE( fileField )
    /* [ 12 ] check '{' */
    if( '{' != fileField->current_ch ){
        report_syntax_error( func_name, "Missing '{' .", fileField->n_current_line );
        return 0;
    }
    /* [ 13 ] jump spaces */
    GET_NEW_CHAR_JUMP_SPACE( fileField )
    /* [ 14 ] get the next token */
    GET_IDENTIFY( fileField, fileField->name_buf, id_length )
    /* [ 15 ] call STATEMENT_LIST() */
    ret = STATEMENT_LIST( fileField, tempIndex, for_stmt_index );
    if( 0 == ret ){
        return 0;
    }
    /* [ 16 ] deal with '}' */
    JUMP_SPACES( fileField )
    if( '}' != fileField->current_ch ){
        report_syntax_error( func_name, "Missing '}' .", fileField->n_current_line );
        return 0;
    }

    return 1;
}
int WHILE_STMT(FileField *fileField, int left_brother_ID, int father_ID){
    int ret = 0;
    char *func_name="WHILE_STMT";
    unsigned int tempIndex = 0;
    unsigned int id_length = 0;
    /* [ 1 ] make a node for 'WHILE_STMT' */
    tempIndex = g_SynTree.n_node_num;
    g_SynTree.pSynNodeList[ tempIndex ].n_father_id = father_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_identifier_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_left_brother_id = left_brother_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_mode = SYN_NODE_WHILE_STMT;
    g_SynTree.pSynNodeList[ tempIndex ].n_right_brother_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_son_id = INVALID_ID;
    /* [ 2 ] fix for father and left brother */
    FIX_FATHER_LBROTHER( father_ID, left_brother_ID, tempIndex )
    g_SynTree.n_node_num++;
    CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
    /* [ 3 ] check '('  */
    JUMP_SPACES( fileField )
    if( '(' != fileField->current_ch ){
        report_syntax_error( func_name, "Missing '('.", fileField->n_current_line );
        return 0;
    }
    /* [ 4 ] jump spaces */
    /* [ 5.1 ] jump spaces in the head for two bytes operator e.g. '>=' */
    GET_NEW_CHAR_JUMP_SPACE( fileField )
    /* [ 5 ] deal with BOOL_FORMULA */
    ret = BOOL_FORMULA( fileField, INVALID_ID, tempIndex );
    if( 0 == ret ){
        return 0;
    }
    /* [ 6 ] check ')' */
    JUMP_SPACES( fileField )
    if( ')' != fileField->current_ch ){
        report_syntax_error( func_name, "Missing ')'.", fileField->n_current_line );
        return 0;
    }
    /* [ 7 ] jump spaces */
    GET_NEW_CHAR_JUMP_SPACE( fileField )
    /* [ 8 ] check '{' */
    if( '{' != fileField->current_ch ){
        report_syntax_error( func_name, "Missing '{'.", fileField->n_current_line );
        return 0;
    }
    /* [ 9 ] jump spaces */
    GET_NEW_CHAR_JUMP_SPACE( fileField )
    /* [ 10 ] get the next token */
    GET_IDENTIFY( fileField, fileField->name_buf, id_length )
    /* [ 11 ] call STATEMENT_LIST() */
    ret = STATEMENT_LIST( fileField, g_SynTree.pSynNodeList[ tempIndex ].n_son_id, tempIndex );
    if( 0 == ret ){
        return 0;
    }
    /* [ 12 ] deal with '}' */
    JUMP_SPACES( fileField )
    if( '}' != fileField->current_ch ){
        report_syntax_error( func_name, "Missing '}' .", fileField->n_current_line );
        return 0;
    }


    return 1;
}
int FORMULA(FileField *fileField, int left_brother_ID, int father_ID){
    int ret = 0;
    char *func_name="FORMULA";
    unsigned int tempIndex = 0;
    unsigned int FORMULAIndex = 0;
    unsigned int id_length = 0;
    unsigned int ident_index = 0;
    int int_value = 0;
    IdentId_P p_cur_id = NULL;
    /* [ 1 ] make a node for 'FORMULA' */
    tempIndex = g_SynTree.n_node_num;
    FORMULAIndex = tempIndex;
    g_SynTree.pSynNodeList[ tempIndex ].n_father_id = father_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_identifier_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_left_brother_id = left_brother_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_mode = SYN_NODE_FORMULA;
    g_SynTree.pSynNodeList[ tempIndex ].n_right_brother_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_son_id = INVALID_ID;
    /* [ 2 ] fix for father and left brother */
    FIX_FATHER_LBROTHER( father_ID, left_brother_ID, tempIndex )
    g_SynTree.n_node_num++;
    CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
    /* [ 3 ] jump spaces in the head */
    GET_NEW_CHAR_JUMP_SPACE( fileField )
    /* [ 4 ] check the first byte */
    if( '(' == fileField->current_ch ){
        /* [ 5 ] make a node for '(' */
        tempIndex = g_SynTree.n_node_num;
        g_SynTree.pSynNodeList[ tempIndex ].n_father_id = FORMULAIndex;
        g_SynTree.pSynNodeList[ tempIndex ].n_identifier_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_left_brother_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_mode = SYN_NODE_L_parenthesis;
        g_SynTree.pSynNodeList[ tempIndex ].n_right_brother_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_son_id = INVALID_ID;
        /* [ 5.1 ] fix for father and left brother */
        FIX_FATHER_LBROTHER( FORMULAIndex, INVALID_ID, tempIndex )
        g_SynTree.n_node_num++;
        CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
        /* [ 5.2 ] deal with FORMULA recursively */
        ret = FORMULA( fileField, tempIndex, FORMULAIndex );
        if( 0 == ret ){
            return 0;
        }
        /* [ 5.3 ] check ')' */
        JUMP_SPACES( fileField )
        if( ')' != fileField->current_ch ){
            report_syntax_error( func_name, "Missing ')' .", fileField->n_current_line );
            return 0;
        }
        /* [ 5.4 ] make a node for ')' */
        tempIndex = g_SynTree.pSynNodeList[ tempIndex ].n_right_brother_id;
        g_SynTree.n_node_num;
        g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_father_id = FORMULAIndex;
        g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_identifier_id = INVALID_ID;
        g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_left_brother_id = tempIndex;
        g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_mode = SYN_NODE_R_parenthesis;
        g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_right_brother_id = INVALID_ID;
        g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_son_id = INVALID_ID;
        /* [ 5.5 ] fix for father and left brother */
        FIX_FATHER_LBROTHER( FORMULAIndex, tempIndex , g_SynTree.n_node_num )
        g_SynTree.n_node_num++;
        CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
        /* [ 5.6 ] jump spaces in the end */
        GET_NEW_CHAR_JUMP_SPACE( fileField )
        /* [ 5.7 ] reflash the tempIndex */
        tempIndex = g_SynTree.n_node_num - 1;
    } else if( isalpha( fileField->current_ch ) ){
        /* [ 6 ] deal with identifier */
        GET_IDENTIFY( fileField, fileField->name_buf, id_length )
        if( 0 == id_length ){
            report_syntax_error( func_name, "Invalid identifier .", fileField->n_current_line );
            return 0;
        }
        CHECK_KEY_WORD( fileField->name_buf, ret )
        if( KEY_WORD_NO != ret ){
            report_syntax_error( func_name, "Invalid identifier :key-word.", fileField->n_current_line );
            return 0;
        }
        /* [ 6.1 ] find the identifier in IdTable */
        ret = find_in_IdTable(fileField, fileField->name_buf, (int)strlen(fileField->name_buf), &ident_index);
        if( 0 == ret ){
            return 0;
        }
        p_cur_id = &g_IdTable.pIdList[ ident_index ];
        if( p_cur_id->n_mode != SYN_NODE_VARID ){
            report_syntax_error( func_name, "Identifier can't be caculated, it's a function name.", fileField->n_current_line );
            return 0;
        }
        /* [ 6.2 ] make a node for the identifier */
        tempIndex = g_SynTree.n_node_num;
        g_SynTree.pSynNodeList[ tempIndex ].n_father_id = FORMULAIndex;
        g_SynTree.pSynNodeList[ tempIndex ].n_identifier_id = ident_index;
        g_SynTree.pSynNodeList[ tempIndex ].n_left_brother_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_mode = SYN_NODE_VARID;
        g_SynTree.pSynNodeList[ tempIndex ].n_right_brother_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_son_id = INVALID_ID;
        /* [ 6.3 ] fix for father and left brother */
        FIX_FATHER_LBROTHER( FORMULAIndex, INVALID_ID, tempIndex )
        g_SynTree.n_node_num++;
        CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
    } else{
        /* [ 7 ] deal with numbers */
        ret = get_number( fileField, &int_value );
        if( 0 == ret ){
            return 0;
        }
        /* [ 7.1 ] make a node for the integer */
        tempIndex = g_SynTree.n_node_num;
        g_SynTree.pSynNodeList[ tempIndex ].n_father_id = FORMULAIndex;
        g_SynTree.pSynNodeList[ tempIndex ].n_identifier_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_left_brother_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_mode = SYN_NODE_NUMBER;
        g_SynTree.pSynNodeList[ tempIndex ].n_right_brother_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_son_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_int_value = int_value;
        /* [ 7.2 ] fix for father and left brother */
        FIX_FATHER_LBROTHER( FORMULAIndex, INVALID_ID, tempIndex )
        g_SynTree.n_node_num++;
        CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
    }
    /* [ 8 ] deal with FORMULA_FOLLOW */
    ret = FORMULA_FOLLOW( fileField, tempIndex,  FORMULAIndex );
    if( 0 == ret ){
        return 0;
    }

    return 1;
};
int BOOL_FORMULA(FileField *fileField, int left_brother_ID, int father_ID){
    int ret = 0;
    char *func_name="BOOL_FORMULA";
    unsigned int tempIndex = 0;
    unsigned int BOOL_FORMULAIndex = 0;
    unsigned int id_length = 0;
    unsigned int ident_index = 0;
    int int_value = 0;
    IdentId_P p_cur_id = NULL;
    /* [ 1 ] make a node for 'BOOL_FORMULA' */
    tempIndex = g_SynTree.n_node_num;
    BOOL_FORMULAIndex = tempIndex;
    g_SynTree.pSynNodeList[ tempIndex ].n_father_id = father_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_identifier_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_left_brother_id = left_brother_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_mode = SYN_NODE_BOOL_FORMULA;
    g_SynTree.pSynNodeList[ tempIndex ].n_right_brother_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_son_id = INVALID_ID;
    /* [ 2 ] fix for father and left brother */
    FIX_FATHER_LBROTHER( father_ID, left_brother_ID, tempIndex )
    g_SynTree.n_node_num++;
    CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
    /* [ 3 ] jump spaces in the head */
    JUMP_SPACES( fileField )
    /* [ 4 ] check the first byte */
    if( '(' == fileField->current_ch ){
        /* [ 5 ] make a node for '(' */
        tempIndex = g_SynTree.n_node_num;
        g_SynTree.pSynNodeList[ tempIndex ].n_father_id = BOOL_FORMULAIndex;
        g_SynTree.pSynNodeList[ tempIndex ].n_identifier_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_left_brother_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_mode = SYN_NODE_L_parenthesis;
        g_SynTree.pSynNodeList[ tempIndex ].n_right_brother_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_son_id = INVALID_ID;
        /* [ 5.1 ] fix for father and left brother */
        FIX_FATHER_LBROTHER( BOOL_FORMULAIndex, INVALID_ID, tempIndex )
        g_SynTree.n_node_num++;
        CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
        /* [ 5.2 ] deal with BOOL_FORMULA recursively */
        /* jump spaces in the head for two bytes operator e.g. '>=' */
        GET_NEW_CHAR_JUMP_SPACE( fileField )
        ret = BOOL_FORMULA( fileField, tempIndex, BOOL_FORMULAIndex );
        if( 0 == ret ){
            return 0;
        }
        /* [ 5.3 ] check ')' */
        JUMP_SPACES( fileField )
        if( ')' != fileField->current_ch ){
            report_syntax_error( func_name, "Missing ')' .", fileField->n_current_line );
            return 0;
        }
        /* [ 5.4 ] make a node for ')' */
        tempIndex = g_SynTree.pSynNodeList[ tempIndex ].n_right_brother_id;
        g_SynTree.n_node_num;
        g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_father_id = BOOL_FORMULAIndex;
        g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_identifier_id = INVALID_ID;
        g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_left_brother_id = tempIndex;
        g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_mode = SYN_NODE_R_parenthesis;
        g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_right_brother_id = INVALID_ID;
        g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_son_id = INVALID_ID;
        /* [ 5.5 ] fix for father and left brother */
        FIX_FATHER_LBROTHER( BOOL_FORMULAIndex, tempIndex , g_SynTree.n_node_num )
        tempIndex = g_SynTree.n_node_num;/* Fix Bug */
        g_SynTree.n_node_num++;
        CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
        /* [ 5.6 ] jump spaces in the end */
        GET_NEW_CHAR_JUMP_SPACE( fileField )
    } else if( isalpha( fileField->current_ch ) ){
        /* [ 6 ] deal with identifier */
        GET_IDENTIFY( fileField, fileField->name_buf, id_length )
        if( 0 == id_length ){
            report_syntax_error( func_name, "Invalid identifier .", fileField->n_current_line );
            return 0;
        }
        CHECK_KEY_WORD( fileField->name_buf, ret )
        if( KEY_WORD_NO != ret ){
            report_syntax_error( func_name, "Invalid identifier :key-word.", fileField->n_current_line );
            return 0;
        }
        /* [ 6.1 ] find the identifier in IdTable */
        ret = find_in_IdTable(fileField, fileField->name_buf, (int)strlen(fileField->name_buf), &ident_index);
        if( 0 == ret ){
            return 0;
        }
        p_cur_id = &g_IdTable.pIdList[ ident_index ];
        if( p_cur_id->n_mode != SYN_NODE_VARID ){
            report_syntax_error( func_name, "Identifier can't be caculated, it's a function name.", fileField->n_current_line );
            return 0;
        }
        /* [ 6.2 ] make a node for the identifier */
        tempIndex = g_SynTree.n_node_num;
        g_SynTree.pSynNodeList[ tempIndex ].n_father_id = BOOL_FORMULAIndex;
        g_SynTree.pSynNodeList[ tempIndex ].n_identifier_id = ident_index;
        g_SynTree.pSynNodeList[ tempIndex ].n_left_brother_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_mode = SYN_NODE_VARID;
        g_SynTree.pSynNodeList[ tempIndex ].n_right_brother_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_son_id = INVALID_ID;
        /* [ 6.3 ] fix for father and left brother */
        FIX_FATHER_LBROTHER( BOOL_FORMULAIndex, INVALID_ID, tempIndex )
        g_SynTree.n_node_num++;
        CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
    } else{
        /* [ 7 ] deal with numbers */
        ret = get_number( fileField, &int_value );
        if( 0 == ret ){
            return 0;
        }
        /* [ 7.1 ] make a node for the integer */
        tempIndex = g_SynTree.n_node_num;
        g_SynTree.pSynNodeList[ tempIndex ].n_father_id = BOOL_FORMULAIndex;
        g_SynTree.pSynNodeList[ tempIndex ].n_identifier_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_left_brother_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_mode = SYN_NODE_NUMBER;
        g_SynTree.pSynNodeList[ tempIndex ].n_right_brother_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_son_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_int_value = int_value;
        /* [ 7.2 ] fix for father and left brother */
        FIX_FATHER_LBROTHER( BOOL_FORMULAIndex, INVALID_ID, tempIndex )
        g_SynTree.n_node_num++;
        CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
    }
    /* [ 8 ] deal with BOOL_FORMULA_FOLLOW */
    ret = BOOL_FORMULA_FOLLOW( fileField, tempIndex,  BOOL_FORMULAIndex );
    if( 0 == ret ){
        return 0;
    }

    return 1;
}
int FORMULA_FOLLOW(FileField *fileField, int left_brother_ID, int father_ID){
    int ret = 0;
    char *func_name="FORMULA_FOLLOW";
    unsigned int tempIndex = 0;
    /* [ 1 ] make a node for 'FORMULA_FOLLOW' */
    tempIndex = g_SynTree.n_node_num;
    g_SynTree.pSynNodeList[ tempIndex ].n_father_id = father_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_identifier_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_left_brother_id = left_brother_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_mode = SYN_NODE_FORMULA_FOLLOW;
    g_SynTree.pSynNodeList[ tempIndex ].n_right_brother_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_son_id = INVALID_ID;
    /* [ 2 ] fix for father and left brother */
    FIX_FATHER_LBROTHER( father_ID, left_brother_ID, tempIndex )
    g_SynTree.n_node_num++;
    CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
    /* [ 3 ] check the first byte */
    JUMP_SPACES( fileField )
    if( '+' == fileField->current_ch ){
        /* [ 4 ] make a node for '+' */
        tempIndex = g_SynTree.n_node_num;
        g_SynTree.pSynNodeList[ tempIndex ].n_father_id = tempIndex - 1;
        g_SynTree.pSynNodeList[ tempIndex ].n_identifier_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_left_brother_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_mode = SYN_NODE_ADD;
        g_SynTree.pSynNodeList[ tempIndex ].n_right_brother_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_son_id = INVALID_ID;
        /* [ 4.1 ] fix for father and left brother */
        FIX_FATHER_LBROTHER( tempIndex - 1, INVALID_ID, tempIndex )
        g_SynTree.n_node_num++;
        CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
    } else if( '-' ==  fileField->current_ch ){
        /* [ 5 ] make a node for '-' */
        tempIndex = g_SynTree.n_node_num;
        g_SynTree.pSynNodeList[ tempIndex ].n_father_id = tempIndex - 1;
        g_SynTree.pSynNodeList[ tempIndex ].n_identifier_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_left_brother_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_mode = SYN_NODE_SUB;
        g_SynTree.pSynNodeList[ tempIndex ].n_right_brother_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_son_id = INVALID_ID;
        /* [ 5.1 ] fix for father and left brother */
        FIX_FATHER_LBROTHER( tempIndex - 1, INVALID_ID, tempIndex )
        g_SynTree.n_node_num++;
        CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
    } else if( '*' == fileField->current_ch ){
        /* [ 6 ] make a node for '*' */
        tempIndex = g_SynTree.n_node_num;
        g_SynTree.pSynNodeList[ tempIndex ].n_father_id = tempIndex - 1;
        g_SynTree.pSynNodeList[ tempIndex ].n_identifier_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_left_brother_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_mode = SYN_NODE_MUT;
        g_SynTree.pSynNodeList[ tempIndex ].n_right_brother_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_son_id = INVALID_ID;
        /* [ 6.1 ] fix for father and left brother */
        FIX_FATHER_LBROTHER( tempIndex - 1, INVALID_ID, tempIndex )
        g_SynTree.n_node_num++;
        CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
    } else if( '/' == fileField->current_ch ){
        /* [ 7 ] make a node for '/' */
        tempIndex = g_SynTree.n_node_num;
        g_SynTree.pSynNodeList[ tempIndex ].n_father_id = tempIndex - 1;
        g_SynTree.pSynNodeList[ tempIndex ].n_identifier_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_left_brother_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_mode = SYN_NODE_DIV;
        g_SynTree.pSynNodeList[ tempIndex ].n_right_brother_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_son_id = INVALID_ID;
        /* [ 7.1 ] fix for father and left brother */
        FIX_FATHER_LBROTHER( tempIndex - 1, INVALID_ID, tempIndex )
        g_SynTree.n_node_num++;
        CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
    } else{
        /* empty follow */
        return 1;
    }
    /* [ 8 ] deal with FORMULA */
    ret = FORMULA( fileField, tempIndex, tempIndex - 1 );
    if( 0 == ret ){
        return 0;
    }

    return 1;
}
int BOOL_FORMULA_FOLLOW(FileField *fileField, int left_brother_ID, int father_ID){
    int ret = 0;
    char *func_name="BOOL_FORMULA_FOLLOW";
    unsigned int tempIndex = 0;
    short n_mode = 0;
    /* [ 1 ] make a node for 'BOOL_FORMULA_FOLLOW' */
    tempIndex = g_SynTree.n_node_num;
    g_SynTree.pSynNodeList[ tempIndex ].n_father_id = father_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_identifier_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_left_brother_id = left_brother_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_mode = SYN_NODE_BOOL_FORMULA_FOLLOW;
    g_SynTree.pSynNodeList[ tempIndex ].n_right_brother_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_son_id = INVALID_ID;
    /* [ 2 ] fix for father and left brother */
    FIX_FATHER_LBROTHER( father_ID, left_brother_ID, tempIndex )
    g_SynTree.n_node_num++;
    CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
    /* [ 3 ] check the operator, maybe two bytes */
    JUMP_SPACES( fileField )
    if( '|' == fileField->current_ch ){
        /* [ 4 ] deal with the operator '||' */
        fileField->current_ch = fgetc( fileField->fp );
        CHECK_NEW_LINE( fileField )
        if( '|' != fileField->current_ch ){
            report_syntax_error( func_name, "Invalid operator.", fileField->n_current_line );
            return 0;
        }
        /* [ 4.1 ] mode is '||' */
        n_mode = SYN_NODE_OR;
        /* [ 4.2 ] jump spaces in the end */
        GET_NEW_CHAR_JUMP_SPACE( fileField )
    } else if( '&' == fileField->current_ch){
        /* [ 5 ] deal with the operator '&&' */
        fileField->current_ch = fgetc( fileField->fp );
        CHECK_NEW_LINE( fileField )
        if( '&' != fileField->current_ch ){
            report_syntax_error( func_name, "Invalid operator.", fileField->n_current_line );
            return 0;
        }
        /* [ 5.1 ] mode is '||' */
        n_mode = SYN_NODE_AND;
        /* [ 5.2 ] jump spaces in the end */
        GET_NEW_CHAR_JUMP_SPACE( fileField )
    } else if( '<' == fileField->current_ch){
        /* [ 6 ] deal with the operator '<' or '<=' */
        fileField->current_ch = fgetc( fileField->fp );
        CHECK_NEW_LINE( fileField )
        if( '=' != fileField->current_ch ){
            /* [ 6.1 ] mode is '<' */
            n_mode = SYN_NODE_LESS;
        } else{
            /* [ 6.2 ] mode is '<=' */
            n_mode = SYN_NODE_NOT_MORE;
            /* [ 6.3 ] jump spaces in the end */
            GET_NEW_CHAR_JUMP_SPACE( fileField )
        }
    } else if( '>' == fileField->current_ch){
        /* [ 7 ] deal with the operator '>' or '>=' */
        fileField->current_ch = fgetc( fileField->fp );
        CHECK_NEW_LINE( fileField )
        if( '=' != fileField->current_ch ){
            /* [ 7.1 ] mode is '>' */
            n_mode = SYN_NODE_MORE;
        } else{
            /* [ 7.2 ] mode is '>=' */
            n_mode = SYN_NODE_NOT_LESS;
            /* [ 7.3 ] jump spaces in the end */
            GET_NEW_CHAR_JUMP_SPACE( fileField )
        }
    } else if( '=' == fileField->current_ch){
        /* [ 8 ] deal with the operator '==' */
        fileField->current_ch = fgetc( fileField->fp );
        CHECK_NEW_LINE( fileField )
        if( '=' != fileField->current_ch ){
            report_syntax_error( func_name, "Invalid operator.", fileField->n_current_line );
            return 0;
        }
        /* [ 8.1 ] mode is '==' */
        n_mode = SYN_NODE_EQ;
        /* [ 8.2 ] jump spaces in the end */
        GET_NEW_CHAR_JUMP_SPACE( fileField )
    } else if( '!' == fileField->current_ch){
        /* [ 9 ] deal with the operator '!=' */
        fileField->current_ch = fgetc( fileField->fp );
        CHECK_NEW_LINE( fileField )
        if( '=' != fileField->current_ch ){
            report_syntax_error( func_name, "Invalid operator.", fileField->n_current_line );
            return 0;
        }
        /* [ 9.1 ] mode is '!=' */
        n_mode = SYN_NODE_NOT_EQ;
        /* [ 9.2 ] jump spaces in the end */
        GET_NEW_CHAR_JUMP_SPACE( fileField )
    } else if( '+' == fileField->current_ch){
        /* [ 10 ] deal with the operator '+' */
        n_mode = SYN_NODE_ADD;
        /* [ 10.1 ] jump spaces in the end */
        GET_NEW_CHAR_JUMP_SPACE( fileField )
    } else if( '-' == fileField->current_ch){
        /* [ 11 ] deal with the operator '-' */
        n_mode = SYN_NODE_SUB;
        /* [ 11.1 ] jump spaces in the end */
        GET_NEW_CHAR_JUMP_SPACE( fileField )
    } else if( '*' == fileField->current_ch){
        /* [ 12 ] deal with the operator '*' */
        n_mode = SYN_NODE_MUT;
        /* [ 12.1 ] jump spaces in the end */
        GET_NEW_CHAR_JUMP_SPACE( fileField )
    } else if( '/' == fileField->current_ch){
        /* [ 13 ] deal with the operator '/' */
        n_mode = SYN_NODE_DIV;
        /* [ 13.1 ] jump spaces in the end */
        GET_NEW_CHAR_JUMP_SPACE( fileField )
    } else{
        /* empty follow */
        return 1;
    }
    /* [ 14 ] make a node for the operator*/
    tempIndex = g_SynTree.n_node_num;
    g_SynTree.pSynNodeList[ tempIndex ].n_father_id = tempIndex - 1;
    g_SynTree.pSynNodeList[ tempIndex ].n_identifier_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_left_brother_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_mode = n_mode;
    g_SynTree.pSynNodeList[ tempIndex ].n_right_brother_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_son_id = INVALID_ID;
    /* [ 15 ] fix for father and left brother */
    FIX_FATHER_LBROTHER( tempIndex - 1, INVALID_ID, tempIndex )
    g_SynTree.n_node_num++;
    CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
    /* [ 16 ] deal with BOOL_FORMULA */
    ret = BOOL_FORMULA( fileField, tempIndex, tempIndex - 1 );
    if( 0 == ret ){
        return 0;
    }

    return 1;
}
int FUNC_CALL(FileField *fileField, int left_brother_ID, int father_ID){
    int ret = 0;
    char *func_name="FUNC_CALL";
    unsigned int tempIndex = 0;
    unsigned int ident_index = 0;
    IdentId_P p_cur_id = NULL;
    /* [ 1 ] make a node for 'FUNC_CALL' */
    tempIndex = g_SynTree.n_node_num;
    g_SynTree.pSynNodeList[ tempIndex ].n_father_id = father_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_identifier_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_left_brother_id = left_brother_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_mode = SYN_NODE_FUNC_CALL;
    g_SynTree.pSynNodeList[ tempIndex ].n_right_brother_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_son_id = INVALID_ID;
    /* [ 2 ] fix for father and left brother */
    FIX_FATHER_LBROTHER( father_ID, left_brother_ID, tempIndex )
    g_SynTree.n_node_num++;
    CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
    /* [ 3 ] find the identifier in IdTable */
    ret = find_in_IdTable(fileField, fileField->name_buf, (int)strlen(fileField->name_buf), &ident_index);
    if( 0 == ret ){
        return 0;
    }
    p_cur_id = &g_IdTable.pIdList[ ident_index ];
    if( p_cur_id->n_mode != SYN_NODE_FUNID ){
        report_syntax_error( func_name, "Function can't be called, it's an identifier name.", fileField->n_current_line );
        return 0;
    }
    /* [ 4 ] make a node for the func_id */
    tempIndex = g_SynTree.n_node_num;
    g_SynTree.pSynNodeList[ tempIndex ].n_father_id = tempIndex - 1;
    g_SynTree.pSynNodeList[ tempIndex ].n_identifier_id = ident_index;
    g_SynTree.pSynNodeList[ tempIndex ].n_left_brother_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_mode = SYN_NODE_FUNID;
    g_SynTree.pSynNodeList[ tempIndex ].n_right_brother_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_son_id = INVALID_ID;
    /* [ 5 ] fix for father and left brother */
    FIX_FATHER_LBROTHER( tempIndex - 1, INVALID_ID, tempIndex )
    g_SynTree.n_node_num++;
    CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
    /* [ 6 ] check the '(' */
    JUMP_SPACES( fileField )
    if( '(' != fileField->current_ch ){
        report_syntax_error( func_name, "Missing '('.", fileField->n_current_line );
        return 0;
    }
    /* [ 7 ] check the ')' */
    GET_NEW_CHAR_JUMP_SPACE( fileField )
    if( ')' != fileField->current_ch ){
        report_syntax_error( func_name, "Missing ')'.", fileField->n_current_line );
        return 0;
    }
    /* [ 8 ] check the ';' */
    GET_NEW_CHAR_JUMP_SPACE( fileField )
    if( ';' != fileField->current_ch ){
        report_syntax_error( func_name, "Missing ';'.", fileField->n_current_line );
        return 0;
    }

    return 1;
}
int add_to_IdTable(FileField * fileField, char *id_name, int length, short mode, unsigned int * p_ident_index){
    char first_index = 0;
    char second_index = 0;
    IdentId_P cur_IdentId_list = NULL;
    unsigned int index = 0;
    unsigned int temp = 0;
    char *func_name = "add_to_IdTable";

    if( length <= 0 ){
        report_internal_error(func_name, __LINE__);
        return 0;
    }
    if( id_name[0] >= 'A' && id_name[0] <= 'Z' ){
        first_index = id_name[0] - 'A';
    } else if( id_name[0] >= 'a' && id_name[0] <= 'z' ){
        first_index = id_name[0] - 'a' + 26;
    } else{
        first_index = 51;
    }
    if( length > 1 ){
        if( id_name[1] >= 'A' && id_name[1] <= 'Z' ){
            second_index = id_name[1] - 'A';
        } else if( id_name[1] >= 'a' && id_name[1] <= 'z' ){
            second_index = id_name[1] - 'a' + 26;
        } else if( id_name[1] >= '0' && id_name[1] <= '9' ){
            second_index = id_name[1] - '0' + 52;
        } else{
            second_index = 61;
        }
    }
    temp = g_IdTable.two_level_index[ first_index ][ second_index ];

    while( temp != INVALID_ID ){
        /* a list is found */
        cur_IdentId_list = &g_IdTable.pIdList[temp];
        if( strcmp( cur_IdentId_list->str_name, id_name ) == 0 ){
            /* already exist */
            report_syntax_error( func_name, "Re-definition error.", fileField->n_current_line );
            return 0;
        }
        temp = cur_IdentId_list->n_next_identifier_id;
    }
    if( g_IdTable.n_id_num + 1 > MAX_SYN_NODE_NUM ){
        report_syntax_error( func_name, "Too many identifiers.", fileField->n_current_line );
        return 0;
    }
    index = g_IdTable.n_id_num;
    g_IdTable.n_id_num++;
    if( NULL != cur_IdentId_list ){
        cur_IdentId_list->n_next_identifier_id = index;
    } else{
        /* create a new list for this id */
        g_IdTable.two_level_index[ first_index ][ second_index ] = index;
    }
    g_IdTable.pIdList[index].n_mode = mode;
    g_IdTable.pIdList[index].n_next_identifier_id = INVALID_ID;
    strcpy_s( g_IdTable.pIdList[index].str_name, MAX_ID_LENGTH+1, id_name );
    *p_ident_index = index;

    return 1;
}

int find_in_IdTable(FileField * fileField, char *id_name, int length, unsigned int * p_ident_index){
    char first_index = 0;
    char second_index = 0;
    IdentId_P cur_IdentId_list = NULL;
    unsigned int index = 0;
    unsigned int temp = 0;
    char *func_name = "find_in_IdTable";

    if( length <= 0 ){
        report_syntax_error( func_name, "Identifier not specified.", fileField->n_current_line );
        return 0;
    }
    if( id_name[0] >= 'A' && id_name[0] <= 'Z' ){
        first_index = id_name[0] - 'A';
    } else if( id_name[0] >= 'a' && id_name[0] <= 'z' ){
        first_index = id_name[0] - 'a' + 26;
    } else{
        first_index = 51;
    }
    if( length > 1 ){
        if( id_name[1] >= 'A' && id_name[1] <= 'Z' ){
            second_index = id_name[1] - 'A';
        } else if( id_name[1] >= 'a' && id_name[1] <= 'z' ){
            second_index = id_name[1] - 'a' + 26;
        } else if( id_name[1] >= '0' && id_name[1] <= '9' ){
            second_index = id_name[1] - '0' + 52;
        } else{
            second_index = 61;
        }
    }
    temp = g_IdTable.two_level_index[ first_index ][ second_index ];

    while( temp != INVALID_ID ){
        /* a list is found */
        cur_IdentId_list = &g_IdTable.pIdList[temp];
        if( strcmp( cur_IdentId_list->str_name, id_name ) == 0 ){
            *p_ident_index = temp;
            return 1;
        }
        temp = cur_IdentId_list->n_next_identifier_id;
    }
    report_syntax_error( func_name, "Identifier not specified.", fileField->n_current_line );
    return 0;
}

int get_number( FileField * fileField, int * pOutValue){
    char *func_name = "get_number";
    int tempValue1 = 0;
    int tempValue2 = 0;
    int b_sign = 0;/* 0 ==> no sign ,  1 ==> '+' , -1 ==> '-'  */
    /* [ 1 ] check the sign */
    if( '-' == fileField->current_ch ){
        b_sign = -1;
        fileField->current_ch = fgetc( fileField->fp );
        CHECK_NEW_LINE( fileField )
    } else if( '+' == fileField->current_ch ){
        b_sign = 1;
        fileField->current_ch = fgetc( fileField->fp );
        CHECK_NEW_LINE( fileField )
    }
    /* [ 2 ] check the first number */
    if( fileField->current_ch < '0' || fileField->current_ch > '9' ){
        report_syntax_error( func_name, "Invalid character.", fileField->n_current_line );
        return 0;
    }
    while( fileField->current_ch >= '0' && fileField->current_ch <= '9' ){
        tempValue1 = tempValue2;
        tempValue2 = tempValue2 * 10 + fileField->current_ch - '0';
        if( tempValue1 > tempValue2 ){
            /* [ 3 ] deal with overflow */
            report_syntax_error( func_name, "Integer overflow.", fileField->n_current_line );
            return 0;
        }
        fileField->current_ch = fgetc( fileField->fp );
        CHECK_NEW_LINE( fileField )        
    }
    if( -1 == b_sign ){
        tempValue2 = ~tempValue2 + 1;
    }
    if( tempValue2 > SHORT_MAX || tempValue2 < SHORT_MIN ){
        /* [ 4 ] deal with overflow. Note: using 16bit-int for EXE file */
        report_syntax_error( func_name, "Integer overflow.", fileField->n_current_line );
        return 0;
    }
    *pOutValue = (int)tempValue2;


    return 1;
}
static void print_syntax_node( FILE* fp, SynNode_P p_node ){
    char buffer[128];
    buffer[0] = '\0';
    switch( p_node->n_mode ){
    case SYN_NODE_HEAD:
        strcpy_s( buffer, 128, "head" );
        break;
    case SYN_NODE_VARID:
        strcpy_s( buffer, 128, "VARID" );
        break;
    case SYN_NODE_FUNID:
        strcpy_s( buffer, 128, "FUNID" );
        break;
    case SYN_NODE_MAINFUNID:
        strcpy_s( buffer, 128, "main" );
        break;
    case SYN_NODE_BODY:
        strcpy_s( buffer, 128, "BODY" );
        break;
    case SYN_NODE_DEFINITION:
        strcpy_s( buffer, 128, "DEFINITION" );
        break;
    case SYN_NODE_VAR_DEF:
        strcpy_s( buffer, 128, "VAR_DEF" );
        break;
    case SYN_NODE_FUNC_DEF:
        strcpy_s( buffer, 128, "FUNC_DEF" );
        break;
    case SYN_NODE_VAR_DEFINITION:
        strcpy_s( buffer, 128, "VAR_DEFINITION" );
        break;
    case SYN_NODE_STATEMENT_LIST:
        strcpy_s( buffer, 128, "STATEMENT_LIST" );
        break;
    case SYN_NODE_ASSIGN_STMT:
        strcpy_s( buffer, 128, "ASSIGN_STMT" );
        break;
    case SYN_NODE_IF_STMT:
        strcpy_s( buffer, 128, "IF_STMT" );
        break;
    case SYN_NODE_FOR_STMT:
        strcpy_s( buffer, 128, "FOR_STMT" );
        break;
    case SYN_NODE_WHILE_STMT:
        strcpy_s( buffer, 128, "WHILE_STMT" );
        break;
    case SYN_NODE_FORMULA:
        strcpy_s( buffer, 128, "FORMULA" );
        break;
    case SYN_NODE_BOOL_FORMULA:
        strcpy_s( buffer, 128, "BOOL_FORMULA" );
        break;
    case SYN_NODE_FORMULA_FOLLOW:
        strcpy_s( buffer, 128, "FORMULA_FOLLOW" );
        break;
    case SYN_NODE_NUMBER:
        strcpy_s( buffer, 128, "NUMBER" );
        break;
    case SYN_NODE_L_parenthesis:
        strcpy_s( buffer, 128, "(" );
        break;
    case SYN_NODE_R_parenthesis:
        strcpy_s( buffer, 128, ")" );
        break;
    case SYN_NODE_ADD:
        strcpy_s( buffer, 128, "+" );
        break;
    case SYN_NODE_SUB:
        strcpy_s( buffer, 128, "-" );
        break;
    case SYN_NODE_MUT:
        strcpy_s( buffer, 128, "*" );
        break;
    case SYN_NODE_DIV:
        strcpy_s( buffer, 128, "/" );
        break;
    case SYN_NODE_AND:
        strcpy_s( buffer, 128, "&&" );
        break;
    case SYN_NODE_OR:
        strcpy_s( buffer, 128, "||" );
        break;
    case SYN_NODE_LESS:
        strcpy_s( buffer, 128, "<" );
        break;
    case SYN_NODE_MORE:
        strcpy_s( buffer, 128, ">" );
        break;
    case SYN_NODE_EQ:
        strcpy_s( buffer, 128, "==" );
        break;
    case SYN_NODE_NOT_LESS:
        strcpy_s( buffer, 128, ">=" );
        break;
    case SYN_NODE_NOT_MORE:
        strcpy_s( buffer, 128, "<=" );
        break;
    case SYN_NODE_NOT_EQ:
        strcpy_s( buffer, 128, "!=" );
        break;
    case SYN_NODE_BOOL_FORMULA_FOLLOW:
        strcpy_s( buffer, 128, "BOOL_FORMULA_FOLLOW" );
        break;
    case SYN_NODE_EMPTY:
        strcpy_s( buffer, 128, "EMPTY" );
        break;
    case SYN_NODE_FUNC_CALL:
        strcpy_s( buffer, 128, "FUNC_CALL" );
        break;
    }

    fprintf( fp,"n_mode = '%s';", buffer);
    if( SYN_NODE_VARID == p_node->n_mode || SYN_NODE_FUNID == p_node->n_mode ){
        fprintf( fp, "id name = '%s';", g_IdTable.pIdList[ p_node->n_identifier_id ].str_name );
    }
    fprintf( fp,"father_id = '%d';", (int)p_node->n_father_id);
    fprintf( fp,"left_brother_id = '%d';", (int)p_node->n_left_brother_id);
    fprintf( fp,"right_brother_id = '%d';", (int)p_node->n_right_brother_id);
    fprintf( fp,"son_id = '%d';", (int)p_node->n_son_id);
    if( SYN_NODE_NUMBER == p_node->n_mode ){
        fprintf( fp, "value = '%d';", p_node->n_int_value );
    }
}
void debug_syntax( FILE* fp ){
    unsigned int i = 0;
    for( i = 0; i < g_SynTree.n_node_num; i++ ){
        fprintf( fp,"id = '%6d';", i);
        print_syntax_node( fp, &g_SynTree.pSynNodeList[ i ] );
        fprintf(fp,"\n*******************************************************************************\n");
    }
}


语义分析器

/** scmpsem.c
====================================================================
This is the base source file for Semantic Analyze


====================================================================
 */

#include "scmpsem.h"
int sem_deal_with_header();
int sem_deal_with_data();
int sem_deal_with_code();
int sem_deal_with_DEFINITION(SynNode_P pSynNode);
int sem_deal_with_BODY(SynNode_P pSynNode);
int sem_deal_with_FUNC_DEF(SynNode_P pSynNode);
int sem_deal_with_STATEMENT_LIST(SynNode_P pSynNode);
int sem_deal_with_ASSIGN_STMT(SynNode_P pSynNode);
int sem_deal_with_IF_STMT(SynNode_P pSynNode);
int sem_deal_with_FOR_STMT(SynNode_P pSynNode);
int sem_deal_with_WHILE_STMT(SynNode_P pSynNode);
int sem_deal_with_FUNC_CALL(SynNode_P pSynNode);
int sem_deal_with_FORMULA(SynNode_P pSynNode);
int sem_deal_with_BOOL_FORMULA(SynNode_P pSynNode);

static int push( SEM_STACK_NODE *in_node );
static int pop( SEM_STACK_NODE *out_node );
#define MY_PUSH( p_in_node )\
    {\
        if( 0 == push( p_in_node ) ){\
           printf("POP error at line '%d' \n", __LINE__ );\
           return 0;\
        }\
    }
#define MY_POP( p_out_node )\
    {\
        if( 0 == pop( p_out_node ) ){\
           printf("POP error at line '%d' \n", __LINE__ );\
           return 0;\
        }\
    }
static int check_caculate( SEM_STACK_NODE *cur_node );
static int caculate_AX_BX_by_op( SEM_STACK_NODE *op_node );

int initialize_SemEnv(){
    g_SemEnv.n_SignCurrentId = 0;
    g_SemEnv.pAsmFile = NULL;
    fopen_s( &g_SemEnv.pAsmFile, ASM_FILE_NAME , "w" );
    if( NULL == g_SemEnv.pAsmFile ){
        printf("Can't open source file '%s'. exit.\n", ASM_FILE_NAME );
        return 0;
    }
    g_SemEnv.s_sem_stack.n_num = 0;
    g_SemEnv.s_sem_stack.sem_node_list = ( SEM_STACK_NODE * )malloc( sizeof(SEM_STACK_NODE) * MAX_STACK_NUM );
    if( NULL == g_SemEnv.s_sem_stack.sem_node_list ){
        printf("Memery not enough while initializing semantic stack.\n" );
        return 0;
    }
    return 1;
}
int finalize_SemEnv(){
    g_SemEnv.n_SignCurrentId = 0;
    MY_HELP_CLOSE( g_SemEnv.pAsmFile );
    g_SemEnv.s_sem_stack.n_num = 0;
    MY_HELP_FREE( g_SemEnv.s_sem_stack.sem_node_list );
    return 1;
}


int semantic_analyzer(){
    int ret = 0;
    char * func_name="semantic_analyzer";

    ret = initialize_SemEnv();
    if( 0 == ret ){
        printf("semantic_analyzer exit with initialize error.\n");
        finalize_SemEnv();
        return 0;
    }
    /* [ 1 ] deal with header */
    sem_deal_with_header();
    /* [ 2 ] deal with data */
    ret = sem_deal_with_data();
    if( 0 == ret ){
        printf("semantic_analyzer exit with internal error.\n");
        finalize_SemEnv();
        return 0;
    }
    /* [ 3 ] deal with code */
    ret =  sem_deal_with_code();
    if( 0 == ret ){
        printf("semantic_analyzer exit with internal error.\n");
        finalize_SemEnv();
        return 0;
    }
    /* [ 4 ] deal with Ending */
    fprintf( g_SemEnv.pAsmFile, ASM_END_MAIN );

    finalize_SemEnv();
    return 1;
}
int sem_deal_with_header(){
    fprintf( g_SemEnv.pAsmFile, ASM_HEADER );

    return 1;
}
int sem_deal_with_data(){
    unsigned int index = 0;
    char * p_VarName = NULL;

    /* [ 1 ] data header */
    fprintf( g_SemEnv.pAsmFile, ASM_DATA_HEADER );
    /* [ 2 ] Variable definition */
    for( index = 0; index < g_IdTable.n_id_num; index++ ){
        if( SYN_NODE_VARID == g_IdTable.pIdList[ index ].n_mode ){
            p_VarName = g_IdTable.pIdList[ index ].str_name;
            fprintf( g_SemEnv.pAsmFile, ASM_VAR_DEF, p_VarName, p_VarName, p_VarName );
        }
    }

    return 1;
}
int sem_deal_with_code(){
    int ret = 0;
    SynNode_P pCurSynNode = NULL;

    /* [ 1 ] code header */
    fprintf( g_SemEnv.pAsmFile, ASM_CODE_HEADER );
    /* [ 2 ] deal with DEFINITION */
    /* [ 2.1 ] Get the first node of DEFINITION */
    pCurSynNode = &g_SynTree.pSynNodeList[1];
    ret = sem_deal_with_DEFINITION( pCurSynNode );
    if( 0 == ret ){
        return 0;
    }
    /* [ 3 ] deal with main */
    /* [ 3.1 ] Get the node of 'main' */
    fprintf( g_SemEnv.pAsmFile, "Main  PROC\nMOV AX, DGROUP\nMOV DS, AX\n" );
    CHECK_SYN_NODE_ID( pCurSynNode->n_right_brother_id )
    pCurSynNode = &g_SynTree.pSynNodeList[ pCurSynNode->n_right_brother_id ];
    /* [ 3.2 ] Get the node of 'BODY' */
    CHECK_SYN_NODE_ID( pCurSynNode->n_right_brother_id )
    pCurSynNode = &g_SynTree.pSynNodeList[ pCurSynNode->n_right_brother_id ];
    ret = sem_deal_with_BODY( pCurSynNode );
    if( 0 == ret ){
        return 0;
    }
#ifdef DEBUG_SEM
    debug_sem();
#endif
    /* [ 3.3 ] Tail of 'main' */
    fprintf( g_SemEnv.pAsmFile, "MOV  AX, 4C00H\nINT  21H\nMain  ENDP\n" );
    return 1;
}
int sem_deal_with_DEFINITION( SynNode_P pSynNode ){
    SynNode_P pCurSynNode = NULL;
    int ret = 0;

    /* [ 1 ] Get the first node of DEFINITION */
    pCurSynNode = pSynNode;
    while( pCurSynNode != NULL && pCurSynNode->n_son_id != INVALID_ID ){
        /* [ 1.1 ] check the son */
        pCurSynNode = &g_SynTree.pSynNodeList[ pCurSynNode->n_son_id ];
        if( SYN_NODE_FUNC_DEF == pCurSynNode->n_mode ){
            /* [ 1.1.1 ] it's FUNC definition, deal with it */
            ret = sem_deal_with_FUNC_DEF( pCurSynNode );
            if( 0 == ret ){
                return 0;
            }

        }
            /* [ 1.1.2 ] deal with right brother of it */
        if( pCurSynNode->n_right_brother_id != INVALID_ID ){
            pCurSynNode = &g_SynTree.pSynNodeList[ pCurSynNode->n_right_brother_id ];
        } else{
            pCurSynNode = NULL;
        }
    }
    return 1;
}
int sem_deal_with_FUNC_DEF(SynNode_P pSynNode){
    SynNode_P pCurSynNode = NULL;
    IdentId_P pId = NULL;
    int ret = 0;
    /* [ 1 ] Function Header */
    /* [ 1.1 ] Get the function id */
    CHECK_SYN_NODE_ID( pSynNode->n_son_id )
    pCurSynNode = &g_SynTree.pSynNodeList[ pSynNode->n_son_id ];
    CHECK_SYN_NODE_ID( pCurSynNode->n_identifier_id )
    pId = &g_IdTable.pIdList[ pCurSynNode->n_identifier_id ];
    fprintf( g_SemEnv.pAsmFile, "%s  PROC\n", pId->str_name );
    /* [ 1.2 ] Save the current Registers */
    fprintf( g_SemEnv.pAsmFile, "PUSH  BP\n", pId->str_name );
    fprintf( g_SemEnv.pAsmFile, "MOV  BP, SP\n", pId->str_name );
    fprintf( g_SemEnv.pAsmFile, "PUSH  DS\n", pId->str_name );
    /* [ 2 ] deal with 'BODY' */
    CHECK_SYN_NODE_ID( pCurSynNode->n_right_brother_id )
    pCurSynNode = &g_SynTree.pSynNodeList[ pCurSynNode->n_right_brother_id ];
    ret = sem_deal_with_BODY( pCurSynNode );
    if( 0 == ret ){
        return 0;
    }
    /* [ 3 ] Function Tail */
    /* [ 3.1 ] Backup the current Registers */
    fprintf( g_SemEnv.pAsmFile, "POP  DS\n", pId->str_name );
    fprintf( g_SemEnv.pAsmFile, "MOV  SP, BP\n", pId->str_name );
    fprintf( g_SemEnv.pAsmFile, "POP  BP\n", pId->str_name );
    fprintf( g_SemEnv.pAsmFile, "RET\n%s  ENDP\n", pId->str_name );
    return 1;
}
int sem_deal_with_BODY(SynNode_P pSynNode){
    SynNode_P pCurSynNode = NULL;
    int ret = 0;
    
    /* [ 1 ] get node of 'VAR_DEFINITION' */
    CHECK_SYN_NODE_ID( pSynNode->n_son_id )
    pCurSynNode = &g_SynTree.pSynNodeList[ pSynNode->n_son_id ];
    /* [ 2 ] deal with  'STATEMENT_LIST' */
    if( INVALID_ID != pCurSynNode->n_right_brother_id ){
        pCurSynNode = &g_SynTree.pSynNodeList[ pCurSynNode->n_right_brother_id ];
        ret = sem_deal_with_STATEMENT_LIST( pCurSynNode );
        if( 0 == ret ){
            return 0;
        }
    }
    return 1;
}
int sem_deal_with_STATEMENT_LIST(SynNode_P pSynNode){
    SynNode_P pCurSynNode = NULL;
    int ret = 0;

    if( INVALID_ID == pSynNode->n_son_id ){
        /* empty statement list */
        return 1;
    }
    /* [ 1 ] deal with first statement */
    pCurSynNode = &g_SynTree.pSynNodeList[ pSynNode->n_son_id ];
    switch( pCurSynNode->n_mode ){
        case SYN_NODE_ASSIGN_STMT:
            ret = sem_deal_with_ASSIGN_STMT( pCurSynNode );
            break;
        case SYN_NODE_IF_STMT:
            ret = sem_deal_with_IF_STMT( pCurSynNode );
            break;
        case SYN_NODE_FOR_STMT:
            ret = sem_deal_with_FOR_STMT( pCurSynNode );
            break;
        case SYN_NODE_WHILE_STMT:
            ret = sem_deal_with_WHILE_STMT( pCurSynNode );
            break;
        case SYN_NODE_FUNC_CALL:
            ret = sem_deal_with_FUNC_CALL( pCurSynNode );
            break;
    }
    if( 0 == ret ){
        return 0;
    }
    /* [ 2 ] deal with following statement */
    CHECK_SYN_NODE_ID( pCurSynNode->n_right_brother_id )
    pCurSynNode = &g_SynTree.pSynNodeList[ pCurSynNode->n_right_brother_id ];
    ret = sem_deal_with_STATEMENT_LIST( pCurSynNode );
    return ret;
}
int sem_deal_with_ASSIGN_STMT(SynNode_P pSynNode){
    SynNode_P pCurSynNode = NULL;
    int ret = 0;
    IdentId_P pId = NULL;
    /* [ 1 ] get the var id */
    CHECK_SYN_NODE_ID( pSynNode->n_son_id )
    pCurSynNode = &g_SynTree.pSynNodeList[ pSynNode->n_son_id ];
    CHECK_SYN_NODE_ID( pCurSynNode->n_identifier_id )
    pId = &g_IdTable.pIdList[ pCurSynNode->n_identifier_id ];

    /* [ 2 ] deal with FORMULA */
    CHECK_SYN_NODE_ID( pCurSynNode->n_right_brother_id )
    pCurSynNode = &g_SynTree.pSynNodeList[ pCurSynNode->n_right_brother_id ];
    ret = sem_deal_with_FORMULA( pCurSynNode );
    if( 0 == ret ){
        return ret;
    }
    /* [ 3 ] deal with assign */
    fprintf( g_SemEnv.pAsmFile, "MOV  %s, AX\n", pId->str_name );

    return 1;
}
int sem_deal_with_IF_STMT(SynNode_P pSynNode){
    SynNode_P pCurSynNode = NULL;
    int ret = 0;
    char str_cur_sign[20];
    /* [ 1 ] deal with BOOL_FORMULA */
    CHECK_SYN_NODE_ID( pSynNode->n_son_id )
    pCurSynNode = &g_SynTree.pSynNodeList[ pSynNode->n_son_id ];
    ret = sem_deal_with_BOOL_FORMULA( pCurSynNode );
    if( 0 == ret ){
        return 0;
    }
    /* [ 2 ] make a sign name. if AX is 0, jump to it. */
    sprintf_s( str_cur_sign, sizeof(str_cur_sign), "SIGN_%d", g_SemEnv.n_SignCurrentId );
    g_SemEnv.n_SignCurrentId++;
    fprintf( g_SemEnv.pAsmFile, "CMP  AX,0\nJE %s\n",  str_cur_sign );
    /* [ 3 ] deal with STATEMENT_LIST */
    CHECK_SYN_NODE_ID( pCurSynNode->n_right_brother_id )
    pCurSynNode = &g_SynTree.pSynNodeList[ pCurSynNode->n_right_brother_id ];
    ret = sem_deal_with_STATEMENT_LIST( pCurSynNode );
    if( 0 == ret ){
        return 0;
    }
    /* [ 4 ] make the sign at the end */
    fprintf( g_SemEnv.pAsmFile, "%s:\n",  str_cur_sign );
    return 1;
}
int sem_deal_with_FOR_STMT(SynNode_P pSynNode){
    SynNode_P pCurSynNode = NULL;
    SynNode_P pSecondAssign = NULL;
    int ret = 0;
    char str_first_sign[20];
    char str_second_sign[20];
    /* [ 1 ] deal with ASSIGN_STMT */
    CHECK_SYN_NODE_ID( pSynNode->n_son_id )
    pCurSynNode = &g_SynTree.pSynNodeList[ pSynNode->n_son_id ];
    if( SYN_NODE_ASSIGN_STMT == pCurSynNode->n_mode ){
        ret = sem_deal_with_ASSIGN_STMT( pCurSynNode );
        if( 0 == ret ){
            return 0;
        }
    }
    /* [ 2 ] make a sign before BOOL_FORMULA */
    sprintf_s( str_first_sign, sizeof(str_first_sign), "SIGN_%d", g_SemEnv.n_SignCurrentId );
    g_SemEnv.n_SignCurrentId++;
    fprintf( g_SemEnv.pAsmFile, "%s:\n",  str_first_sign );
    /* [ 3 ] deal with BOOL_FORMULA */
    CHECK_SYN_NODE_ID( pCurSynNode->n_right_brother_id )
    pCurSynNode = &g_SynTree.pSynNodeList[ pCurSynNode->n_right_brother_id ];
    ret = sem_deal_with_BOOL_FORMULA( pCurSynNode );
    if( 0 == ret ){
        return 0;
    }
    /* [ 4 ] make a sign at the end, if AX=0,jump to it */
    sprintf_s( str_second_sign, sizeof(str_first_sign), "SIGN_%d", g_SemEnv.n_SignCurrentId );
    g_SemEnv.n_SignCurrentId++;
    fprintf( g_SemEnv.pAsmFile, "CMP  AX,0\nJE %s\n",  str_second_sign );
    /* [ 5 ] store the second Assign Statement node */
    CHECK_SYN_NODE_ID( pCurSynNode->n_right_brother_id )
    pCurSynNode = &g_SynTree.pSynNodeList[ pCurSynNode->n_right_brother_id ];
    pSecondAssign = pCurSynNode;
    /* [ 6 ] deal with STATEMENT_LIST */
    CHECK_SYN_NODE_ID( pCurSynNode->n_right_brother_id )
    pCurSynNode = &g_SynTree.pSynNodeList[ pCurSynNode->n_right_brother_id ];
    ret = sem_deal_with_STATEMENT_LIST( pCurSynNode );
    if( 0 == ret ){
        return 0;
    }
    /* [ 7 ] deal with the second Assign Statement */
    if( SYN_NODE_ASSIGN_STMT == pSecondAssign->n_mode ){
        ret = sem_deal_with_ASSIGN_STMT( pSecondAssign );
        if( 0 == ret ){
            return 0;
        }
    }
    /* [ 8 ] jump to first sign */
    fprintf( g_SemEnv.pAsmFile, "JMP %s\n",  str_first_sign );
    /* [ 9 ] store to second sign */
    fprintf( g_SemEnv.pAsmFile, "%s:\n",  str_second_sign );

    return 1;
}
int sem_deal_with_WHILE_STMT(SynNode_P pSynNode){
    SynNode_P pCurSynNode = NULL;
    int ret = 0;
    char str_first_sign[20];
    char str_second_sign[20];
    /* [ 1 ] make a sign before BOOL_FORMULA */
    sprintf_s( str_first_sign, sizeof(str_first_sign), "SIGN_%d", g_SemEnv.n_SignCurrentId );
    g_SemEnv.n_SignCurrentId++;
    fprintf( g_SemEnv.pAsmFile, "%s:\n",  str_first_sign );
    /* [ 2 ] deal with BOOL_FORMULA */
    CHECK_SYN_NODE_ID( pSynNode->n_son_id )
    pCurSynNode = &g_SynTree.pSynNodeList[ pSynNode->n_son_id ];
    ret = sem_deal_with_BOOL_FORMULA( pCurSynNode );
    if( 0 == ret ){
        return 0;
    }
    /* [ 3 ] make a sign at the end, if AX=0,jump to it */
    sprintf_s( str_second_sign, sizeof(str_first_sign), "SIGN_%d", g_SemEnv.n_SignCurrentId );
    g_SemEnv.n_SignCurrentId++;
    fprintf( g_SemEnv.pAsmFile, "CMP  AX,0\nJE %s\n",  str_second_sign );
    /* [ 4 ] deal with STATEMENT_LIST */
    CHECK_SYN_NODE_ID( pCurSynNode->n_right_brother_id )
    pCurSynNode = &g_SynTree.pSynNodeList[ pCurSynNode->n_right_brother_id ];
    ret = sem_deal_with_STATEMENT_LIST( pCurSynNode );
    if( 0 == ret ){
        return 0;
    }
    /* [ 5 ] jump to first sign */
    fprintf( g_SemEnv.pAsmFile, "JMP %s\n",  str_first_sign );
    /* [ 6 ] store to second sign */
    fprintf( g_SemEnv.pAsmFile, "%s:\n",  str_second_sign );

    return 1;
}
int sem_deal_with_FUNC_CALL(SynNode_P pSynNode){
    SynNode_P pCurSynNode = NULL;
    IdentId_P pId = NULL;

    CHECK_SYN_NODE_ID( pSynNode->n_son_id )
    pCurSynNode = &g_SynTree.pSynNodeList[ pSynNode->n_son_id ];
    CHECK_SYN_NODE_ID( pCurSynNode->n_identifier_id )
    pId = &g_IdTable.pIdList[ pCurSynNode->n_identifier_id ];
    fprintf( g_SemEnv.pAsmFile, "CALL  %s\n", pId->str_name );

    return 1;
}
int sem_deal_with_FORMULA(SynNode_P pSynNode){
    char * func_name="sem_deal_with_FORMULA";
    SynNode_P pCurSynNode = NULL;
    IdentId_P pId = NULL;
    int ret = 0;
    unsigned int n_CurrentNodeId = 0;
    SEM_STACK_NODE sem_node;
    SEM_STACK_NODE op_node;
    n_CurrentNodeId = pSynNode->n_son_id;
    while( 1 ){
        /* [ 1 ] check the first Node of the Formula */
        CHECK_SYN_NODE_ID( n_CurrentNodeId )
        pCurSynNode = &g_SynTree.pSynNodeList[ n_CurrentNodeId ];
        /* [ 1.1 ] deal with '(' FORMULA ')' */
        if( SYN_NODE_L_parenthesis == pCurSynNode->n_mode ){
            /* [ 1.1.1 ] push '(' into Stack */
            sem_node.n_mode = 7;
            sem_node.n_value = SYN_NODE_L_parenthesis;
            MY_PUSH( &sem_node );
            /* [ 1.1.2 ] deal with FORMULA recursively */
            CHECK_SYN_NODE_ID( pCurSynNode->n_right_brother_id )
            pCurSynNode = &g_SynTree.pSynNodeList[ pCurSynNode->n_right_brother_id ];
            ret = sem_deal_with_FORMULA( pCurSynNode );
            if( 0 == ret ){
                return 0;
            }
            /* [ 1.1.3 ] deal with ')' */
            CHECK_SYN_NODE_ID( pCurSynNode->n_right_brother_id )
            pCurSynNode = &g_SynTree.pSynNodeList[ pCurSynNode->n_right_brother_id ];
            if( SYN_NODE_R_parenthesis != pCurSynNode->n_mode ){
                report_internal_error( func_name, __LINE__ );
                printf("Missing ')' in FORMULA .\n" );
                return 0;
            }
            /* [ 1.1.4 ] caculate current formula between '(' and ')' */
            op_node.n_mode = 0;
            op_node.n_value = SYN_NODE_R_parenthesis;
            ret = check_caculate( &op_node );
            if( 0 == ret ){
                return 0;
            }
        } else if( SYN_NODE_VARID == pCurSynNode->n_mode ){
        /* [ 1.2 ] deal with identifier */
            /* [ 1.2.1 ] make a sem node for the identifier */
            sem_node.n_mode = 0xffff;
            MY_PUSH( &sem_node );
            /* [ 1.2.2 ] make ASM code for the identifier */
            CHECK_SYN_NODE_ID( pCurSynNode->n_identifier_id )
            pId = &g_IdTable.pIdList[ pCurSynNode->n_identifier_id ];
            fprintf( g_SemEnv.pAsmFile, "MOV AX, %s\n", pId->str_name );
            fprintf( g_SemEnv.pAsmFile, "PUSH AX\n" );
        } else {
        /* [ 1.3 ] deal with number */
            /* [ 1.3.1 ] make a sem node for the number */
            sem_node.n_mode = 0xffff;
            MY_PUSH( &sem_node );
            /* [ 1.3.2 ] make ASM code for the number */
            fprintf( g_SemEnv.pAsmFile, "MOV AX, %d\n", pCurSynNode->n_int_value );
            fprintf( g_SemEnv.pAsmFile, "PUSH AX\n" );
        }
        /* [ 2 ]  deal with FORMULA_FOLLOW */
        CHECK_SYN_NODE_ID( pCurSynNode->n_right_brother_id )
        pCurSynNode = &g_SynTree.pSynNodeList[ pCurSynNode->n_right_brother_id ];
        if( INVALID_ID == pCurSynNode->n_son_id ){
            /*=================================================================
            Empty FORMULA_FOLLOW.Clear the stack and finish the caculating 
            =================================================================*/
            while( 1 ){
                MY_POP( &sem_node );
                if( 0 == g_SemEnv.s_sem_stack.n_num ){
                    /* This node is the only node in the stack , finished. */
                    fprintf( g_SemEnv.pAsmFile, "POP AX\n" );
                    return 1;
                }
                MY_POP( &op_node );
                if( 7 == op_node.n_mode ){/* Reach the Beginning of a FOMULA */
                    MY_PUSH( &op_node );
                    MY_PUSH( &sem_node );
                    return 1;
                } else{
                    MY_POP( &sem_node );
                    ret = caculate_AX_BX_by_op( &op_node );
                }
                /* Push the result */
                MY_PUSH( &sem_node );
                if( 0 == ret ){
                    return 0;
                }
                if( 0 == g_SemEnv.s_sem_stack.n_num ){
                    /* This node is the only node in the stack , finished. */
                    fprintf( g_SemEnv.pAsmFile, "POP AX\n" );
                    return 1;
                }
            }
        } else{
            /* [ 2.1 ] deal with operator */
            pCurSynNode = &g_SynTree.pSynNodeList[ pCurSynNode->n_son_id ];
            switch( pCurSynNode->n_mode ){
                case SYN_NODE_ADD:
                case SYN_NODE_SUB:
                    op_node.n_mode = 5;
                    break;
                case SYN_NODE_MUT:
                case SYN_NODE_DIV:
                    op_node.n_mode = 6;
                    break;
                case SYN_NODE_AND:
                    op_node.n_mode = 2;
                    break;
                case SYN_NODE_OR:
                    op_node.n_mode = 1;
                    break;
                case SYN_NODE_LESS:
                case SYN_NODE_MORE:
                case SYN_NODE_NOT_LESS:
                case SYN_NODE_NOT_MORE:
                    op_node.n_mode = 4;
                    break;
                case SYN_NODE_EQ:
                case SYN_NODE_NOT_EQ:
                    op_node.n_mode = 3;
                    break;
                default:
                    printf("Internal error! invalid operator mode '%d' at line '%d'\n", pCurSynNode->n_mode, __LINE__ );
                    return 0;
            }
            op_node.n_value = pCurSynNode->n_mode;
            ret = check_caculate( &op_node );
            if( 0 == ret ){
                return 0;
            }
            /* [ 2.2 ] deal with FORMULA using the while-looping */
            CHECK_SYN_NODE_ID( pCurSynNode->n_right_brother_id )
            pCurSynNode = &g_SynTree.pSynNodeList[ pCurSynNode->n_right_brother_id ];
            n_CurrentNodeId = pCurSynNode->n_son_id;
        }
    }

    return 1;
}
int sem_deal_with_BOOL_FORMULA(SynNode_P pSynNode){
    if( sem_deal_with_FORMULA( pSynNode ) == 0 ){
        return 0;
    }
    return 1;
}
static int push( SEM_STACK_NODE *in_node ){
    unsigned int num = 0;
    num = g_SemEnv.s_sem_stack.n_num;
    if( num >= MAX_STACK_NUM ){
        printf("Internal Error ! semantic stack overflow!\n");
        return 0;
    }
    memcpy( &g_SemEnv.s_sem_stack.sem_node_list[ num ], in_node, sizeof( SEM_STACK_NODE ) );
    g_SemEnv.s_sem_stack.n_num++;
    return 1;
}
static int pop( SEM_STACK_NODE *out_node ){
    unsigned int index = 0;
    index = g_SemEnv.s_sem_stack.n_num;
    index--;
    if( index >= MAX_STACK_NUM ){
        printf("Internal Error ! semantic stack empty!\n");
        return 0;
    }
    memcpy( out_node, &g_SemEnv.s_sem_stack.sem_node_list[ index ], sizeof( SEM_STACK_NODE ) );
    g_SemEnv.s_sem_stack.n_num--;
    return 1;
}
static int check_caculate( SEM_STACK_NODE *cur_node ){
    unsigned int num = 0;
    unsigned short cur_mode = cur_node->n_mode;
    unsigned short last_mode = 0;
    SEM_STACK_NODE sem_node;
    SEM_STACK_NODE op_node;
    num = g_SemEnv.s_sem_stack.n_num;
    if( 0 == cur_mode ){
        /* [ 1 ] deal with ')' */
        /* [ 1.1 ] pop the first node on top of the stack */
        MY_POP( &sem_node );
        if( 0xffff != sem_node.n_mode ){
            printf("Internal Error ! Missing number between '(' and ')' in FORMULA .\n" );
            return 0;
        }
        /* [ 1.2 ] pop the next node on top of the stack */
        MY_POP( &op_node );
        if( 7 == op_node.n_mode ){/* '(' */
            /* push the result of FORMULA between '(' and ')' */
            MY_PUSH( &sem_node );
        } else{/* operator */
            /* [ 1.2 ] pop the second number on top of the stack */
            MY_POP( &sem_node );
            /* [ 1.3 ] caculate current formula between '(' and ')' */
            if( 0 == caculate_AX_BX_by_op( &op_node ) ){
                return 0;
            }
            /* [ 1.4 ] pop the '(' */
            MY_POP( &op_node );
            /* [ 1.5 ] push the result of FORMULA between '(' and ')' */
            MY_PUSH( &sem_node );
        }
    } else{
        /* [ 2 ] deal with other operators */
        if( num >= 2 && num <= MAX_STACK_NUM ){
            last_mode = g_SemEnv.s_sem_stack.sem_node_list[ num-2 ].n_mode;
        }
        if( cur_mode <= last_mode && last_mode != 7 ){/* '(' can't caculate without ')' */
            MY_POP( &sem_node );
            MY_POP( &op_node );
            MY_POP( &sem_node );
            if( 0 == caculate_AX_BX_by_op( &op_node ) ){
                return 0;
            }
            MY_PUSH( &sem_node );
        } else{
            /* do nothing */
        }
        MY_PUSH( cur_node );
    }
    return 1;
}
static int caculate_AX_BX_by_op( SEM_STACK_NODE *op_node ){
    char * func_name = "caculate_AX_BX_by_op";
    char str_first_sign[20];
    char str_second_sign[20];
    /* [ 1 ] pop BX */
    fprintf( g_SemEnv.pAsmFile, "POP  BX\n" );
    /* [ 2 ] pop AX */
    fprintf( g_SemEnv.pAsmFile, "POP  AX\n" );
    /* [ 3 ] caculate */
    switch( op_node->n_mode ){
        case 1: /* || */
            fprintf( g_SemEnv.pAsmFile, "OR AX, BX\n" );
            break;
        case 2: /* && */
            fprintf( g_SemEnv.pAsmFile, "AND AX, BX\n" );
            break;
        case 3:
            if( SYN_NODE_EQ == op_node->n_value ){ /* == */
                fprintf( g_SemEnv.pAsmFile, ";Deal with '=='\n" );
                sprintf_s( str_first_sign, sizeof(str_first_sign), "SIGN_%d", g_SemEnv.n_SignCurrentId );
                g_SemEnv.n_SignCurrentId++;
                sprintf_s( str_second_sign, sizeof(str_second_sign), "SIGN_%d", g_SemEnv.n_SignCurrentId );
                g_SemEnv.n_SignCurrentId++;
                fprintf( g_SemEnv.pAsmFile, "CMP AX, BX\n" );
                fprintf( g_SemEnv.pAsmFile, "JNE %s\n",  str_first_sign );
                fprintf( g_SemEnv.pAsmFile, "MOV AX, 1\n" );
                fprintf( g_SemEnv.pAsmFile, "JMP %s\n", str_second_sign );
                fprintf( g_SemEnv.pAsmFile, "%s:\n",  str_first_sign );
                fprintf( g_SemEnv.pAsmFile, "MOV AX, 0\n" );
                fprintf( g_SemEnv.pAsmFile, "%s:\n",  str_second_sign );
            } else{ /* != */
                fprintf( g_SemEnv.pAsmFile, "XOR AX, BX\n" );
            }
            break;
        case 4:
            if( SYN_NODE_MORE == op_node->n_value ){ /* > */
                fprintf( g_SemEnv.pAsmFile, "SUB BX, AX\n" );
                fprintf( g_SemEnv.pAsmFile, "AND BX, 8000H\n" );
                fprintf( g_SemEnv.pAsmFile, "MOV AX, BX\n" );
            } else if( SYN_NODE_LESS == op_node->n_value ){ /* < */
                fprintf( g_SemEnv.pAsmFile, "SUB AX, BX\n" );
                fprintf( g_SemEnv.pAsmFile, "AND AX, 8000H\n" );
            } else if( SYN_NODE_NOT_LESS == op_node->n_value ){ /* >= */
                fprintf( g_SemEnv.pAsmFile, "SUB AX, BX\n" );
                fprintf( g_SemEnv.pAsmFile, "AND AX, 8000H\n" );
                fprintf( g_SemEnv.pAsmFile, "XOR AX, 8000H\n" );
            } else{ /* <= */
                fprintf( g_SemEnv.pAsmFile, "SUB BX, AX\n" );
                fprintf( g_SemEnv.pAsmFile, "AND BX, 8000H\n" );
                fprintf( g_SemEnv.pAsmFile, "XOR BX, 8000H\n" );
                fprintf( g_SemEnv.pAsmFile, "MOV AX, BX\n" );
            }
            break;
        case 5:
            if( SYN_NODE_ADD == op_node->n_value ){ /* + */
                fprintf( g_SemEnv.pAsmFile, "ADD AX, BX\n" );
            } else{ /* - */
                fprintf( g_SemEnv.pAsmFile, "SUB AX, BX\n" );
            }
            break;
        case 6:
            if( SYN_NODE_MUT == op_node->n_value ){ /* * */
                fprintf( g_SemEnv.pAsmFile, "MUL BX\n" );
            } else{ /* / */
                fprintf( g_SemEnv.pAsmFile, "MOV DX, 0\n" );
                fprintf( g_SemEnv.pAsmFile, "DIV BX\n" );
            }
            break;
        default:
            report_internal_error( func_name, __LINE__ );
            printf("Invalid operator mode '%d'\n", op_node->n_mode );
            return 0;
    }
    /* [ 4 ] push AX */
    fprintf( g_SemEnv.pAsmFile, "PUSH  AX\n" );

    return 1;
}
void debug_sem( ){
    unsigned int i = 0;
    IdentId_P pId = NULL;
    for( i = 0; i < g_IdTable.n_id_num; i++ ){
        pId = &g_IdTable.pIdList[ i ];
        if( SYN_NODE_VARID == pId->n_mode ){
            fprintf( g_SemEnv.pAsmFile, "LEA  AX, Name_%s\nMOV  DX, AX\nMOV  AH, 9\nINT  21H\n", pId->str_name );
            fprintf( g_SemEnv.pAsmFile, "MOV  AX, %s\nPRINTVAL  AX\n", pId->str_name );
            fprintf( g_SemEnv.pAsmFile, ASM_CHANGE_LINE );
        }
    }
}


主函数

/** SimpleCompiler.c
====================================================================
This is the base source file for Main Function


====================================================================
 */

#include "scmppre.h"
#include "scmpstx.h"
#include "scmpsem.h"
int main(int arg_num, char ** args){
    int ret = 0;
    FILE *srcFP = NULL;
    FILE *outFP = NULL;
    char *inputFile = "test.c";
    char *outputFile = "test.c.tmp";
    FileField srcFileField;
#ifdef DEBUG_SYNTAX
    char *debugFile = "test.c.stx";
    FILE * debugfp = NULL;
#endif
    /* Global initializing */
    ret = initialize_IdTable();
    ret &= initialize_SynTree();
    if( 0 == ret ){
        printf("Program exit with initializing error.\n");
        return 0;
    }
    fopen_s( &srcFP, inputFile , "r" );
    if( NULL == srcFP ){
        printf("Can't open source file '%s'. Program exit.\n", inputFile );
        return 0;
    }
    fopen_s( &outFP, outputFile, "w" );
    if( NULL == outFP ){
        printf("Can't open temp file '%s'. Program exit.\n", outputFile );
        return 0;
    }
    /** pre-compiler **/
    ret = pre_compiler(srcFP, outFP);
    if( 0 == ret ){
        printf("Program exit with pre-compiler error.\n");
        goto ERROR_END;
    }
    MY_HELP_CLOSE( outFP );
    MY_HELP_CLOSE( srcFP );
    /** Syntax analyzing **/
    /* using the temp file as the source */
    fopen_s( &srcFP, outputFile, "r" );
    if( NULL == srcFP ){
        printf("Can't open temp file '%s'. Program exit.\n", outputFile );
        goto ERROR_END;
    }
    srcFileField.fp = srcFP;
    srcFileField.n_current_line = 1;
    ret = syntax_analyzer( &srcFileField );
    if( 0 == ret ){
        printf("Program exit with syntax_analyzer error.\n");
        goto ERROR_END;
    }
#ifdef DEBUG_SYNTAX
    fopen_s(&debugfp, debugFile, "w");
    if( NULL != debugfp ){
        debug_syntax( debugfp );
        fclose( debugfp );
    }
#endif
    /** semantic_analyzer **/
    ret = semantic_analyzer();
    if( 0 == ret ){
        printf("Program exit with semantic_analyzer error.\n");
        goto ERROR_END;
    }

    MY_HELP_CLOSE( outFP );
    MY_HELP_CLOSE( srcFP );
    release_IdTable();
    release_SynTree();
    return 1;
ERROR_END:
    MY_HELP_CLOSE( outFP );
    MY_HELP_CLOSE( srcFP );
    release_IdTable();
    release_SynTree();
    return 0;
}


语法分析头文件

 

/** scmppre.h
====================================================================
This is the base head file for pre-compiler


====================================================================
 */
#ifndef SCMPPRE_H_INCLUDE
#define SCMPPRE_H_INCLUDE

#ifndef STD_COMMON_H_INCLUDE
#define STD_COMMON_H_INCLUDE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#endif


#define MAX_SRC_LINE      1024           /* the max byte number of one line in the source file */

int pre_compiler(FILE * fpInput, FILE * fpOutput);



#endif


语法分析头文件:

/** scmpstx.h
====================================================================
This is the base head file for Syntax Analyze


====================================================================
 */
#ifndef SCMPSTX_H_INCLUDE
#define SCMPSTX_H_INCLUDE


#ifndef STD_COMMON_H_INCLUDE
#define STD_COMMON_H_INCLUDE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#endif

#define MAX_SYN_NODE_NUM  32768          /* the max syntax node number */
#define MAX_ID_LENGTH     32             /* the max length of indentifier */
/* The identifier id */
typedef struct tag_identifier_id{
    short n_mode;                        /* the mode : SYN_NODE_TAIL / SYN_NODE_VARID / SYN_NODE_FUNID */
    short dummy;                         /* not used */
    int n_next_identifier_id;            /* the next identifier in current second-level list */
    char str_name[ MAX_ID_LENGTH+1 ];
}IdentId;
typedef IdentId * IdentId_P;
/* The identifier table */
typedef struct tag_id_table{
    unsigned int n_id_num;               /*============================================================
                                         The number of identifiers in the table.
                                         It's also the first free place for store a new identifier.
                                         Using n_id_num,  pIdList acts as a stack, and n_id_num is
                                         it's stack top.
                                         If n_id_num >= MAX_SYN_NODE_NUM, the stack is full.
                                         ============================================================*/
    IdentId_P pIdList;                   /*============================================================
                                         the head pointer of the identifier list.
                                         malloc MAX_SYN_NODE_NUM IdentId.
                                         ============================================================*/
    unsigned int two_level_index[52][62];        /*============================================================
                                         First index: using the first byte of the name
                                             'A' to 'Z' = 0 to 25
                                             'a' to 'z' = 26 to 51
                                         Second index: using the second byte of the name
                                             'A' to 'Z' = 0 to 25
                                             'a' to 'z' = 26 to 51
                                             '0' to '9' = 52 to 61
                                         Default value: two_level_index[i][j] = -1;
                                         if two_level_index[i][j] is not -1, it shows this second-level
                                         list in the pIdList is started at pIdList[two_level_index[i][j]]
                                         ============================================================*/            
}IdTable;
IdTable g_IdTable;                       /* the identifier table */
/* The node for syntax tree */
typedef struct tag_SyntaxNode{
    short n_mode;                        /* the mode of SyntaxNode */
    unsigned int n_identifier_id;        /*============================================================
                                         The index in the Id Table for this identifier.
                                         If it's not identifier, n_identifier_id = INVALID_ID;
                                         ============================================================*/
    unsigned int n_left_brother_id;      /*============================================================
                                         The index of the left brother in the syntax tree.
                                         If it's the first son of its father, n_left_brother_id = INVALID_ID;
                                         ============================================================*/
    unsigned int n_right_brother_id;     /*============================================================
                                         The index of the right brother in the syntax tree.
                                         If it's the last son of its father, n_right_brother_id = INVALID_ID;
                                         ============================================================*/
    unsigned int n_father_id;            /*============================================================
                                         The index of the father in the syntax tree.
                                         If it's the root, n_father_id = INVALID_ID;
                                         ============================================================*/
    unsigned int n_son_id;               /*============================================================
                                         The index of the son in the syntax tree.
                                         If it has no son, n_son_id = INVALID_ID;
                                         ============================================================*/
    int n_int_value;                       /* the value of integer */
}SynNode;
typedef SynNode * SynNode_P;
typedef struct tat_SyntaxTree{
    unsigned int n_node_num;             /*============================================================
                                         The number of SynNode in the SyntaxTree.
                                         It's also the first free place for store a new SynNode.
                                         Using n_node_num,  pSynNodeList acts as a stack, and n_node_num is
                                         it's stack top.
                                         If n_node_num >= MAX_SYN_NODE_NUM, the stack is full.
                                         ============================================================*/
    SynNode_P pSynNodeList;              /*============================================================
                                         the head pointer of the syntax tree node list.
                                         malloc MAX_SYN_NODE_NUM SynNode.
                                         ============================================================*/
}SynTree;
SynTree g_SynTree;                       /* the syntax tree */
/* Syntax Node mode definitions */
#define SYN_NODE_TAIL                 0          /* the tail node */
#define SYN_NODE_HEAD                 1          /* the head node */
#define SYN_NODE_VARID                2          /* the identifier of variabale */
#define SYN_NODE_FUNID                3          /* the identifier of function */
#define SYN_NODE_MAINFUNID            4          /* the identifier of main function */
#define SYN_NODE_BODY                 11         /* the BODY of a function */
#define SYN_NODE_DEFINITION           12         /* DEFINITION */
#define SYN_NODE_VAR_DEF              13         /* VAR_DEF */
#define SYN_NODE_FUNC_DEF             14         /* FUNC_DEF */
#define SYN_NODE_VAR_DEFINITION       15         /* VAR_DEFINITION */
#define SYN_NODE_STATEMENT_LIST       16         /* STATEMENT_LIST */
#define SYN_NODE_ASSIGN_STMT          17         /* ASSIGN_STMT */
#define SYN_NODE_IF_STMT              18         /* IF_STMT */
#define SYN_NODE_FOR_STMT             19         /* FOR_STMT */
#define SYN_NODE_WHILE_STMT           20         /* WHILE_STMT */
#define SYN_NODE_FORMULA              21         /* FORMULA */
#define SYN_NODE_BOOL_FORMULA         22         /* BOOL_FORMULA */
#define SYN_NODE_FORMULA_FOLLOW       23         /* FORMULA_FOLLOW */
#define SYN_NODE_NUMBER               24         /* numbers */
#define SYN_NODE_L_parenthesis        25         /* '(' */
#define SYN_NODE_R_parenthesis        26         /* ')' */
#define SYN_NODE_ADD                  27         /* '+' */
#define SYN_NODE_SUB                  28         /* '-' */
#define SYN_NODE_MUT                  29         /* '*' */
#define SYN_NODE_DIV                  30         /* '/' */
#define SYN_NODE_AND                  31         /* '&&' */
#define SYN_NODE_OR                   32         /* '||' */
#define SYN_NODE_LESS                 33         /* '<' */
#define SYN_NODE_MORE                 34         /* '>' */
#define SYN_NODE_EQ                   35         /* '==' */
#define SYN_NODE_NOT_LESS             36         /* '>=' */
#define SYN_NODE_NOT_MORE             37         /* '<=' */
#define SYN_NODE_NOT_EQ               38         /* '!=' */
#define SYN_NODE_BOOL_FORMULA_FOLLOW  39         /* BOOL_FORMULA_FOLLOW */
#define SYN_NODE_FUNC_CALL            40         /* FUNC_CALL */
#define SYN_NODE_EMPTY               100         /* An empty node */

#define SHORT_MAX                    32767       /* MAX VALUE OF SHORT */
#define SHORT_MIN                    -32768      /* MIN VALUE OF SHORT */

#define INVALID_ID            (unsigned int)0xFFFFFFFF         /* the invalid index */

typedef struct tag_fileField{
    FILE * fp;                                   /* the pointer to the source file */
    int n_current_line;                          /* the current line number */
    char current_ch;                             /* the current char */
    char name_buf[MAX_ID_LENGTH+1];              /* the buffer for an identifier name */
}FileField;

#define KEY_WORD_NO                   0          /* Not a key word */
#define KEY_WORD_MAIN                 1          /* 'main' */
#define KEY_WORD_INT                  2          /* 'int' */
#define KEY_WORD_IF                   3          /* 'if' */
#define KEY_WORD_WHILE                4          /* 'while' */
#define KEY_WORD_FOR                  5          /* 'for' */

#define CHECK_KEY_WORD( buffer, type ) \
    { \
        if( 0 == strcmp( buffer, "main" ) ){\
            type = KEY_WORD_MAIN;\
        } else if( 0 == strcmp( buffer, "int" ) ){\
            type = KEY_WORD_INT;\
        } else if( 0 == strcmp( buffer, "if" ) ){\
            type = KEY_WORD_IF;\
        } else if( 0 == strcmp( buffer, "while") ){\
            type = KEY_WORD_WHILE;\
        } else if( 0 == strcmp( buffer, "for") ){\
            type = KEY_WORD_FOR;\
        } else{\
            type = KEY_WORD_NO;\
        }\
    }
#define MY_HELP_FREE( pValue )  \
    if( NULL != pValue ){\
        free(pValue);\
        pValue = NULL;\
    }
#define MY_HELP_CLOSE( pFILE )  \
    if( NULL != pFILE ){\
        fclose(pFILE);\
        pFILE = NULL;\
    }
#define CHECK_NEW_LINE( fileField ) \
    if( '\n' == fileField->current_ch ){\
        fileField->n_current_line++;\
    }
#define JUMP_SPACES( fileField ) \
    {\
        while( isspace( fileField->current_ch ) ){\
            fileField->current_ch = fgetc( fileField->fp );\
            CHECK_NEW_LINE( fileField )\
        }\
    }
#define GET_IDENTIFY( fileField, buffer, length )\
    {\
        length = 0;\
        JUMP_SPACES( fileField );\
        if( !isalpha(fileField->current_ch) ){/* the fisrt char must be alphabet */\
            buffer[0] = '\0';\
            length = 0;\
        } else{\
            buffer[0] = fileField->current_ch;\
            length = 1;\
            while( 1 ){\
                fileField->current_ch = fgetc( fileField->fp );\
                CHECK_NEW_LINE( fileField )\
                if( isalnum( fileField->current_ch ) ){\
                    buffer[length] = fileField->current_ch;\
                    length++;\
                    if( length > MAX_ID_LENGTH ){/* too logn identifier */\
                        buffer[0] = '\0';\
                        length = 0;\
                        break;\
                    }\
                } else{\
                    buffer[length] = '\0';\
                    break;\
                }\
            }\
        }\
    }
#define GET_NEW_CHAR_JUMP_SPACE( fileField ) \
    {\
        fileField->current_ch = fgetc( fileField->fp );\
        CHECK_NEW_LINE( fileField )\
        JUMP_SPACES( fileField )\
    }
#define CHECK_NODE_NUM( function, fileField, num ) \
    {\
        if( num > MAX_SYN_NODE_NUM ){\
            report_syntax_error( function, "Too many syntax nodes.", fileField->n_current_line );\
            return 0;\
        }\
    }
#define FIX_FATHER_LBROTHER( father_ID, left_brother_ID, current_ID ) \
    {\
        if( father_ID != INVALID_ID ){\
            if( INVALID_ID == g_SynTree.pSynNodeList[father_ID].n_son_id ){\
                g_SynTree.pSynNodeList[father_ID].n_son_id = current_ID;\
            }\
        }\
        if( left_brother_ID != INVALID_ID ){\
            if( INVALID_ID == g_SynTree.pSynNodeList[left_brother_ID].n_right_brother_id ){\
                g_SynTree.pSynNodeList[left_brother_ID].n_right_brother_id = current_ID;\
            }\
        }\
    }
int syntax_analyzer(FileField *fileField);
int initialize_IdTable();
int initialize_SynTree();
int release_IdTable();
int release_SynTree();
void report_syntax_error(char *func_name, char *detail, int line_number);
void report_memery_error(char *func_name, int line_number);
void report_internal_error(char *func_name, int line_number);
int add_to_IdTable(FileField * fileField, char *id_name, int length, short mode, unsigned int * p_ident_index);
int find_in_IdTable(FileField * fileField, char *id_name, int length, unsigned int * p_ident_index);
int get_number( FileField * fileField, int * pOutValue);
void debug_syntax( FILE* fp );

#endif


语义分析头文件:

 
 

/** scmpsem.h
====================================================================
This is the base head file for Semantic Analyze


====================================================================
 */
#ifndef SCMPSEM_H_INCLUDE
#define SCMPSEM_H_INCLUDE

#include "scmpstx.h"

#ifndef LINUX
/* For Windows only */
/* define the header of the MASM source file */
#define ASM_HEADER ".MODEL SMALL\n.STACK 4096h\nINCLUDE PrintVal.mac\n"
#define ASM_DATA_HEADER ".DATA\nASM_CHAGNE_LINE  DB  0DH,0AH,'$'\n"
/* the definition of varibale e.g. sprintf(buffer, MASM_VAR_DEF, "VAR1", "VAR1", "VAR1") */
#define ASM_VAR_DEF "%s  DW  0\nName_%s  DB '%s',20H,20H,'$'\n"
#define ASM_CODE_HEADER ".CODE\nCALL Main\n"
#define ASM_END_MAIN "END Main\n"
#define ASM_FILE_NAME "MyResult.asm"
#define ASM_CHANGE_LINE "LEA  AX, ASM_CHAGNE_LINE\nMOV  DX, AX\nMOV  AH, 9\nINT  21H\n"

#else
/* For Linux only */
#endif

#define MAX_STACK_NUM 32768               /* the max node number of sem_stack */
typedef struct tag_SEM_STACK_NODE{
    unsigned short n_mode;                /*====================================
                                          Type of the node
                                          0 ==> )
                                          1 ==> ||
                                          2 ==> &&
                                          3 ==> ==   !=
                                          4 ==> >   >=   <   <=
                                          5 ==> +  -
                                          6 ==> *  /
                                          7 ==> (
                                          0xffff ==> number
                                          =====================================*/
    short n_value;                        /*=====================================
                                          The value of the node,using definition
                                          in the scmpstx.h.
                                          e.g.
                                          SYN_NODE_NUMBER   24   numbers
                                          SYN_NODE_EQ       35   '=='
                                          =====================================*/
}SEM_STACK_NODE;
typedef struct tag_SEM_STACK{
    unsigned int n_num;
    SEM_STACK_NODE * sem_node_list;
}SEM_STACK;
typedef struct tag_SemEnv{
    unsigned int n_SignCurrentId;         /* the id of current sign */
    FILE * pAsmFile;                      /* the pointer to the output ASM file */
    SEM_STACK s_sem_stack;                /* the stack for semantic analyze */
}SemEnv;
SemEnv g_SemEnv;/* the semantic analyser environment */

int initialize_SemEnv();
int finalize_SemEnv();
int semantic_analyzer();
void debug_sem( );


#define CHECK_SYN_NODE_ID(id)  \
    if( INVALID_ID == (id) ){\
          printf("Internal Error ! Invalid syntax node id at line '%d'.\n", __LINE__);\
          return 0;\
    }
         

#endif


 


'; fputs(str_line_buffer, fpOutput); index = 0; } else{ /* a single '/', just store it and its following byte */ str_line_buffer[index] = '/'; index++; CHECK_INDEX( index ) if( EOF == current_char ){ /* end of file */ str_line_buffer[index] = '
预处理器:
/** scmppre.c
====================================================================
This is the base source file for pre-compiler


====================================================================
 */

#include "scmppre.h"


static int report_pre_error(char *msg, int code){
    printf("Error : %s\nCode : %d\n", msg, code);
    return 0;
}

#define CHECK_INDEX( index )    \
    if( index >= MAX_SRC_LINE ){\
        report_pre_error("Too long line.", index);\
        return 0;\
    }
/*=======================================================
The main function of pre-compiler.
return     1 : success
           0 : fail
========================================================*/
int pre_compiler(FILE * fpInput, FILE * fpOutput){
    char str_line_buffer[MAX_SRC_LINE + 1];
    int index = 0;
    char current_char;
    current_char = fgetc(fpInput);
    while( current_char != EOF ){
        /*========================================================
        search the '//' . if exists, jump the rest of the line.
        ========================================================*/
        if( '/' == current_char ){
            current_char = fgetc(fpInput);
            if( '/' == current_char ){
                while( current_char != EOF ){
                    current_char =  fgetc(fpInput);
                    if( '\n' == current_char ){
                        /* end of a line */
                        str_line_buffer[index] = '\n';
                        index++;
                        CHECK_INDEX( index )
                        break;/* stop loop */
                    }
                }
                /* output a line */
                str_line_buffer[index] = '\0';
                fputs(str_line_buffer, fpOutput);
                index = 0;
            } else{
                /* a single '/', just store it and its following byte */
                str_line_buffer[index] = '/';
                index++;
                CHECK_INDEX( index )
                if( EOF == current_char ){ /* end of file */
                    str_line_buffer[index] = '\0';
                    fputs(str_line_buffer, fpOutput);
                    index = 0;
                    return 1;
                } else if( '\n' == current_char ){
                    str_line_buffer[index] = current_char;
                    index++;
                    CHECK_INDEX( index )
                    str_line_buffer[index] = '\0';
                    fputs(str_line_buffer, fpOutput);
                    index = 0;
                } else{
                    str_line_buffer[index] = current_char;
                    index++;
                    CHECK_INDEX( index )
                }
            }
        } else if( '\n' == current_char ){
            str_line_buffer[index] = current_char;
            index++;
            CHECK_INDEX( index )
            str_line_buffer[index] = '\0';
            fputs(str_line_buffer, fpOutput);
            index = 0;
        } else{
            str_line_buffer[index] = current_char;
            index++;
            CHECK_INDEX( index )
        }
        current_char = fgetc(fpInput);
    }

    str_line_buffer[index] = '\0';
    fputs(str_line_buffer, fpOutput);
    index = 0;

    return 1;
}


语法分析器

 

/** scmpstx.c
====================================================================
This is the base source file for Syntax Analyze


====================================================================
 */
#include "scmpstx.h"

int DEFINITION(FileField *fileField, int left_brother_ID, int father_ID);
int VAR_DEF(FileField *fileField, int left_brother_ID, int father_ID);
int FUNC_DEF(FileField *fileField, int left_brother_ID, int father_ID);
int IDENTIFY(FileField *fileField, int left_brother_ID, int father_ID);
int BODY(FileField *fileField, int left_brother_ID, int father_ID);
int VAR_DEFINITION(FileField *fileField, int left_brother_ID, int father_ID);
int STATEMENT_LIST(FileField *fileField, int left_brother_ID, int father_ID);
int ASSIGN_STMT(FileField *fileField, int left_brother_ID, int father_ID);
int IF_STMT(FileField *fileField, int left_brother_ID, int father_ID);
int FOR_STMT(FileField *fileField, int left_brother_ID, int father_ID);
int WHILE_STMT(FileField *fileField, int left_brother_ID, int father_ID);
int FORMULA(FileField *fileField, int left_brother_ID, int father_ID);
int BOOL_FORMULA(FileField *fileField, int left_brother_ID, int father_ID);
int FORMULA_FOLLOW(FileField *fileField, int left_brother_ID, int father_ID);
int BOOL_FORMULA_FOLLOW(FileField *fileField, int left_brother_ID, int father_ID);
int FUNC_CALL(FileField *fileField, int left_brother_ID, int father_ID);



void report_syntax_error(char *func_name, char *detail, int line_number){
    printf("Syntax error accured in function '%s()', at line '%d'.\nDetail: %s\n", func_name, line_number, detail);
    return;
}
void report_memery_error(char *func_name, int line_number){
    printf("Memery error accured in function '%s()', at line '%d'.\n", func_name, line_number);
    return;
}
void report_internal_error(char *func_name, int line_number){
    printf("Internal error accured in function '%s()', at line '%d'.\n", func_name, line_number);
    return;
}
int initialize_IdTable(){
    int i=0;
    int j=0;
    g_IdTable.n_id_num = 0;
    g_IdTable.pIdList = (IdentId_P)malloc( ( MAX_SYN_NODE_NUM + 1 ) * sizeof(IdentId) );
    if( NULL == g_IdTable.pIdList ){
        report_memery_error("initialize_IdTable", __LINE__);
        return 0;
    }
    for( i = 0; i < 51; i++ ){
        for( j = 0; j < 61; j++ ){
            g_IdTable.two_level_index[i][j] = INVALID_ID;
        }
    }
    return 1;
}
int initialize_SynTree(){
    g_SynTree.n_node_num = 0;
    g_SynTree.pSynNodeList = (SynNode_P)malloc( ( MAX_SYN_NODE_NUM + 1 ) * sizeof(SynNode) );
    if( NULL == g_SynTree.pSynNodeList ){
        report_memery_error("initialize_SynTree", __LINE__);
        return 0;
    }
    return 1;
}
int release_IdTable(){
    MY_HELP_FREE( g_IdTable.pIdList )
    g_IdTable.n_id_num = 0;
    return 1;
}
int release_SynTree(){
    MY_HELP_FREE( g_SynTree.pSynNodeList );
    g_SynTree.n_node_num = 0;
    return 1;
}

int syntax_analyzer(FileField *fileField){
    int ret = 0;
    char * func_name="syntax_analyzer";

    /** [ 1 ] initialize a node for whole program **/
    g_SynTree.n_node_num = 1;
    g_SynTree.pSynNodeList[0].n_father_id = INVALID_ID;
    g_SynTree.pSynNodeList[0].n_identifier_id = INVALID_ID;
    g_SynTree.pSynNodeList[0].n_left_brother_id = INVALID_ID;
    g_SynTree.pSynNodeList[0].n_mode = SYN_NODE_HEAD;
    g_SynTree.pSynNodeList[0].n_right_brother_id = INVALID_ID;
    g_SynTree.pSynNodeList[0].n_son_id = INVALID_ID;
    /** [ 2 ] deal with DEFINITION **/
    ret = DEFINITION( fileField, INVALID_ID, 0 );
    /** [ 3 ] deal with 'main' **/
    if( 0 == ret ){
        printf("Syntax_analyzer exit with syntax error.\n");
        return 0;
    } else{
        /* some definition finished, the node 'DEFINITION' is the left brother of 'main' */
        g_SynTree.n_node_num++;
        CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
        g_SynTree.pSynNodeList[g_SynTree.n_node_num-1].n_father_id = 0;/* the index of 'main' is g_SynTree.n_node_num-1 */
        g_SynTree.pSynNodeList[g_SynTree.n_node_num-1].n_identifier_id = INVALID_ID;
        g_SynTree.pSynNodeList[g_SynTree.n_node_num-1].n_left_brother_id = 1;/* the node 'DEFINITION' */
        g_SynTree.pSynNodeList[g_SynTree.n_node_num-1].n_mode = SYN_NODE_MAINFUNID;
        g_SynTree.pSynNodeList[g_SynTree.n_node_num-1].n_right_brother_id = INVALID_ID;
        g_SynTree.pSynNodeList[g_SynTree.n_node_num-1].n_son_id = INVALID_ID;
        g_SynTree.pSynNodeList[1].n_right_brother_id = g_SynTree.n_node_num-1;/* fix the right brother for node 'DEFINITION' */
    }
    /** [ 4 ] deal with '(' and ')' **/
    /* [ 4.1 ] jump the spaces after 'main' */
    JUMP_SPACES( fileField )
    /* [ 4.2 ] check '(' */
    if( '(' != fileField->current_ch ){
        report_syntax_error( "syntax_analyzer", "missing '('.", fileField->n_current_line );
        printf("Syntax_analyzer exit with syntax error.\n");
        return 0;
    }
    /* [ 4.3 ] jump the spaces after '(' */
    GET_NEW_CHAR_JUMP_SPACE( fileField )
    /* [ 4.4 ] check ')' */
    if( ')' != fileField->current_ch ){
        report_syntax_error( "syntax_analyzer", "missing ')'.", fileField->n_current_line );
        printf("Syntax_analyzer exit with syntax error.\n");
        return 0;
    }
    /* [ 4.5 ] jump the spaces after ')' */
    GET_NEW_CHAR_JUMP_SPACE( fileField )
    /* [ 4.6 ] check '{' */
    if( '{' != fileField->current_ch ){
        report_syntax_error( "syntax_analyzer", "missing '{'.", fileField->n_current_line );
        printf("Syntax_analyzer exit with syntax error.\n");
        return 0;
    }
    /** [ 5 ] deal with 'BODY' **/
    ret = BODY( fileField, g_SynTree.n_node_num-1, 0 );
    if( 0 == ret ){
        printf("Syntax_analyzer exit with syntax error.\n");
        return 0;
    }
    /* [ 6 ] jump the spaces after 'BODY' */
    JUMP_SPACES( fileField )
    /* [ 7 ] check '}' */
    if( '}' != fileField->current_ch ){
        report_syntax_error( "syntax_analyzer", "missing '}'.", fileField->n_current_line );
        printf("Syntax_analyzer exit with syntax error.\n");
        return 0;
    }
    /* [ 8 ] jump the spaces after '}' */
    GET_NEW_CHAR_JUMP_SPACE( fileField )
    if( EOF != fileField->current_ch ){
        report_syntax_error( "syntax_analyzer", "Unexpected character.", fileField->n_current_line );
        printf("Syntax_analyzer exit with syntax error.\n");
        return 0;
    }
    return 1;
}


int DEFINITION(FileField *fileField, int left_brother_ID, int father_ID){
    int ret = 0;
    int id_length = 0;
    char *func_name="DEFINITION";
    unsigned int tempIndex = 0;

    /* [ 1 ] make a node for 'DEFINITION' */
    tempIndex = g_SynTree.n_node_num;
    g_SynTree.pSynNodeList[ tempIndex ].n_father_id = father_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_identifier_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_left_brother_id = left_brother_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_mode = SYN_NODE_DEFINITION;
    g_SynTree.pSynNodeList[ tempIndex ].n_right_brother_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_son_id = INVALID_ID;
    /* [ 2 ] fix for father and left brother */
    FIX_FATHER_LBROTHER( father_ID, left_brother_ID, tempIndex )
    g_SynTree.n_node_num++;
    CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )


    /* [ 3 ] deal with VAR_DEF */
    ret = VAR_DEF( fileField, INVALID_ID, tempIndex );
    if( 0 == ret ){
        return 0;
    }
    if( 1000 == ret ){
        report_syntax_error( func_name, "Invalid identifier .", fileField->n_current_line );
        return 0;
    } else if( 100 == ret ){
        return 1;
    } else if( 200 == ret ){
        /* [ 4 ] deal with FUNC_DEF */
        ret = FUNC_DEF( fileField, INVALID_ID, tempIndex );
        if( 0 == ret ){
            return 0;
        }
    } else if( 300 == ret ){
        report_syntax_error( "syntax_analyzer", "Unexpected character.", fileField->n_current_line );
        return 0;
    }
    /* [ 5 ] deal with DEFINITION recursively */
    ret = DEFINITION( fileField, g_SynTree.pSynNodeList[ tempIndex ].n_son_id, tempIndex );
    if( 0 == ret ){
        return 0;
    }
    return 1;
}
/** if it returns 1000, it's unkown character, maybe '}' **/
/** if it returns 100, an identifier name 'main' is stored in FileField.name_buf **/
/** if it returns 200, an identifier name ( not 'main' ) is stored in FileField.name_buf **/
/** if it returns 300, it's 'if' 'while' 'for' **/
int VAR_DEF(FileField *fileField, int left_brother_ID, int father_ID){
    int ret = 0;
    char *func_name="VAR_DEF";
    unsigned int tempIndex = 0;
    unsigned int ident_index = 0;
    int id_length = 0;
    /* [ 1 ] jump spaces in the head */
    GET_NEW_CHAR_JUMP_SPACE( fileField )
    /* [ 2 ] get the first token */
    GET_IDENTIFY( fileField, fileField->name_buf, id_length )
    if( 0 == id_length ){
        return 1000;
    }
    CHECK_KEY_WORD( fileField->name_buf, ret )
    if( KEY_WORD_MAIN == ret ){
        /* no definition */
        return 100;
    } else if( KEY_WORD_NO == ret ){
        /* it's an identifier. maybe statment_list or syntax error. */
        return 200;
    }else if( KEY_WORD_INT == ret ){
        /* [ 3 ] deal with 'VAR_DEF' */
        /* [ 3.1 ] make a node for 'VAR_DEF' */
        tempIndex = g_SynTree.n_node_num;
        g_SynTree.pSynNodeList[ tempIndex ].n_father_id = father_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_identifier_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_left_brother_id = left_brother_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_mode = SYN_NODE_VAR_DEF;
        g_SynTree.pSynNodeList[ tempIndex ].n_right_brother_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_son_id = INVALID_ID;
        /* [ 3.2 ] fix for father and left brother */
        FIX_FATHER_LBROTHER( father_ID, left_brother_ID, tempIndex )
        g_SynTree.n_node_num++;
        CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
        /* [ 3.3 ] get the identifier after 'int' */
        GET_IDENTIFY( fileField, fileField->name_buf, id_length )
        if( 0 == id_length ){
            report_syntax_error( func_name, "Invalid identifier .", fileField->n_current_line );
            return 0;
        }
        CHECK_KEY_WORD( fileField->name_buf, ret )
        if( KEY_WORD_NO != ret ){
            /* Invalid identifier */
            report_syntax_error( func_name, "Invalid identifier: key-word.", fileField->n_current_line );
            return 0;
        }
        /* [ 3.4 ] use a IdentId to store the identifier and make a syntax node */
        ret = add_to_IdTable(fileField, fileField->name_buf, id_length, SYN_NODE_VARID, &ident_index);
        if( 0 == ret ){
            return 0;
        }
        g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_father_id = tempIndex;
        g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_identifier_id = ident_index;
        g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_left_brother_id = INVALID_ID;
        g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_mode = SYN_NODE_VARID;
        g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_right_brother_id = INVALID_ID;
        g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_son_id = INVALID_ID;
        /* [ 3.5 ] fix for father and left brother */
        FIX_FATHER_LBROTHER( tempIndex, INVALID_ID, g_SynTree.n_node_num )
        g_SynTree.n_node_num++;
        CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
        /* [ 3.6 ] deal with ';' */
        JUMP_SPACES( fileField )
        if( ';' != fileField->current_ch ){
            report_syntax_error( func_name, "Missing ';' .", fileField->n_current_line );
            return 0;
        }
        return 1;
    } else{
        /* it's 'if' 'while' 'for' */
        return 300;
    }
}
int FUNC_DEF(FileField *fileField, int left_brother_ID, int father_ID){
    int ret = 0;
    char *func_name="FUNC_DEF";
    unsigned int tempIndex = 0;
    unsigned int ident_index = 0;
    int id_length = 0;
    /* [ 1 ] deal with FUNC_DEF */
    /* [ 1.1 ] make a node for FUNC_DEF */
    g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_father_id = father_ID;
    g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_identifier_id = INVALID_ID;
    g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_left_brother_id = left_brother_ID;
    g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_mode = SYN_NODE_FUNC_DEF;
    g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_right_brother_id = INVALID_ID;
    g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_son_id = INVALID_ID;
    /* [ 1.2 ] fix for father and left brother */
    FIX_FATHER_LBROTHER( father_ID, left_brother_ID, g_SynTree.n_node_num )
    g_SynTree.n_node_num++;
    CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
    /* [ 1.3 ] use a IdentId to store the identifier and make a syntax node */
    ret = add_to_IdTable(fileField, fileField->name_buf, (int)strlen( fileField->name_buf ), SYN_NODE_FUNID, &ident_index);
    if( 0 == ret ){
        return 0;
    }
    g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_father_id = g_SynTree.n_node_num - 1;
    g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_identifier_id = ident_index;
    g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_left_brother_id = INVALID_ID;
    g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_mode = SYN_NODE_FUNID;
    g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_right_brother_id = INVALID_ID;
    g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_son_id = INVALID_ID;
    /* [ 1.4 ] fix for father and left brother */
    FIX_FATHER_LBROTHER( g_SynTree.n_node_num - 1, INVALID_ID, g_SynTree.n_node_num )
    g_SynTree.n_node_num++;
    CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
    /* [ 1.5 ] deal with '(' */
    JUMP_SPACES( fileField )
    if( '(' != fileField->current_ch ){
        report_syntax_error( func_name, "Missing '(' .", fileField->n_current_line );
        return 0;
    }
    /* [ 1.6 ] deal with ')' */
    GET_NEW_CHAR_JUMP_SPACE( fileField )
    if( ')' != fileField->current_ch ){
        report_syntax_error( func_name, "Missing ')' .", fileField->n_current_line );
        return 0;
    }
    /* [ 1.7 ] deal with '{' */
    GET_NEW_CHAR_JUMP_SPACE( fileField )
    if( '{' != fileField->current_ch ){
        report_syntax_error( func_name, "Missing '{' .", fileField->n_current_line );
        return 0;
    }
    /* [ 1.8 ] deal with 'BODY' */
    ret = BODY( fileField, g_SynTree.n_node_num - 1, g_SynTree.n_node_num - 2 );
    if( 0 == ret ){
        return 0;
    }
    /* [ 1.9 ] deal with '}' */
    JUMP_SPACES( fileField )
    if( '}' != fileField->current_ch ){
        report_syntax_error( func_name, "Missing '}' .", fileField->n_current_line );
        return 0;
    }
    return 1;
}
int BODY(FileField *fileField, int left_brother_ID, int father_ID){
    int ret = 0;
    char *func_name="BODY";
    unsigned int tempIndex = 0;
    int id_length = 0;

    /* [ 1 ] make a node for 'BODY' */
    tempIndex = g_SynTree.n_node_num;
    g_SynTree.pSynNodeList[ tempIndex ].n_father_id = father_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_identifier_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_left_brother_id = left_brother_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_mode = SYN_NODE_BODY;
    g_SynTree.pSynNodeList[ tempIndex ].n_right_brother_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_son_id = INVALID_ID;
    /* [ 2 ] fix for father and left brother */
    FIX_FATHER_LBROTHER( father_ID, left_brother_ID, tempIndex )
    g_SynTree.n_node_num++;
    CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
    /* [ 3 ] deal with VAR_DEFINITION */
    ret = VAR_DEFINITION( fileField, INVALID_ID, tempIndex );
    if( 0 == ret ){
        return 0;
    }
    if( 400 != ret ){
        /* [ 4 ] deal with STATEMENT_LIST */
        ret = STATEMENT_LIST( fileField, g_SynTree.pSynNodeList[ tempIndex ].n_son_id, tempIndex );
        if( 0 == ret ){
            return 0;
        }
    }

    return 1;
}
/** if it returns 200, an identifier name is stored in FileField.name_buf **/
/** if it returns 300, it's 'if' 'while' 'for' **/
/** if it returns 400, an empty statment_list is following **/
int VAR_DEFINITION(FileField *fileField, int left_brother_ID, int father_ID){
    int ret = 0;
    char *func_name="VAR_DEFINITION";
    unsigned int tempIndex = 0;
    /* [ 1 ] make a node for 'VAR_DEFINITION' */
    tempIndex = g_SynTree.n_node_num;
    g_SynTree.pSynNodeList[ tempIndex ].n_father_id = father_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_identifier_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_left_brother_id = left_brother_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_mode = SYN_NODE_VAR_DEFINITION;
    g_SynTree.pSynNodeList[ tempIndex ].n_right_brother_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_son_id = INVALID_ID;
    /* [ 2 ] fix for father and left brother */
    FIX_FATHER_LBROTHER( father_ID, left_brother_ID, tempIndex )
    g_SynTree.n_node_num++;
    CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
    /* [ 3 ] deal with VAR_DEF */
    ret = VAR_DEF( fileField, INVALID_ID, tempIndex );
    if( 0 == ret ){
        return 0;
    }
    if( 1000 == ret ){
        if( '}' != fileField->current_ch ){
            report_syntax_error( func_name, "Invalid identifier .", fileField->n_current_line );
            return 0;
        } else{
            /* Empty statement_list */
            return 400;
        }
    } else if( 100 == ret ){
        report_syntax_error( "syntax_analyzer", "Unexpected key-word 'main'.", fileField->n_current_line );
        return 0;/* 'main' can't be here */
    } else if( 200 == ret ){
        /* [ 4 ] 'STATEMENT_LIST' is following */
        return 200;
    } else if( 300 == ret ){
        /* [ 5 ] 'STATEMENT_LIST' is following */
        return 300;
    }
    ret = VAR_DEFINITION( fileField, g_SynTree.pSynNodeList[ tempIndex ].n_son_id, tempIndex );
    return ret;
}
int STATEMENT_LIST(FileField *fileField, int left_brother_ID, int father_ID){
    int ret = 0;
    char *func_name="STATEMENT_LIST";
    unsigned int tempIndex = 0;
    unsigned int id_length = 0;
    /* [ 1 ] make a node for 'STATEMENT_LIST' */
    tempIndex = g_SynTree.n_node_num;
    g_SynTree.pSynNodeList[ tempIndex ].n_father_id = father_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_identifier_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_left_brother_id = left_brother_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_mode = SYN_NODE_STATEMENT_LIST;
    g_SynTree.pSynNodeList[ tempIndex ].n_right_brother_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_son_id = INVALID_ID;
    /* [ 2 ] fix for father and left brother */
    FIX_FATHER_LBROTHER( father_ID, left_brother_ID, tempIndex )
    g_SynTree.n_node_num++;
    CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
    /* [ 3 ] check the last byte */
    if( '}' == fileField->current_ch ){
        /* the statement list is empty */
        return 1;
    }
    /* [ 4 ] check the key-word which has already been read */
    CHECK_KEY_WORD( fileField->name_buf, ret )
    if( KEY_WORD_NO == ret ){
        JUMP_SPACES( fileField )
        if( '=' == fileField->current_ch ){
            /* [ 4.1 ] it's an ASSIGN_STMT */
            ret = ASSIGN_STMT( fileField, INVALID_ID, tempIndex );
            if( 0 == ret ){
                return 0;
            }
            JUMP_SPACES( fileField )
            if( ';' != fileField->current_ch ){
                /* check ';' */
                report_syntax_error( func_name, "Missing ';' .", fileField->n_current_line );
                return 0;
            }
        } else if( '(' == fileField->current_ch ){
            /* [ 4.2 ] it's an FUNC_CALL */
            ret = FUNC_CALL( fileField, INVALID_ID, tempIndex );
            if( 0 == ret ){
                return 0;
            }
        } else{
            report_syntax_error( func_name, "Unknown statement .", fileField->n_current_line );
            return 0;
        }
    } else if( KEY_WORD_IF == ret ){
        /* [ 4.2 ] deal with IF_STMT */
        ret = IF_STMT( fileField, INVALID_ID, tempIndex );
        if( 0 == ret ){
            return 0;
        }
    } else if( KEY_WORD_WHILE == ret ){
        /* [ 4.3 ] deal with WHILE_STMT */
        ret = WHILE_STMT( fileField, INVALID_ID, tempIndex );
        if( 0 == ret ){
            return 0;
        }
    } else if( KEY_WORD_FOR == ret ){
        /* [ 4.4 ] deal with FOR_STMT */
        ret = FOR_STMT( fileField, INVALID_ID, tempIndex );
        if( 0 == ret ){
            return 0;
        }
    } else {
        report_syntax_error( func_name, "Invalid identifier .", fileField->n_current_line );
        return 0;
    }
    /* [ 5 ] jump spaces */
    GET_NEW_CHAR_JUMP_SPACE( fileField )
    /* [ 6 ] get the next token */
    GET_IDENTIFY( fileField, fileField->name_buf, id_length )
    /* [ 7 ] call STATEMENT_LIST() recursively */
    ret = STATEMENT_LIST( fileField, g_SynTree.pSynNodeList[ tempIndex ].n_son_id, tempIndex );
    if( 0 == ret ){
        return 0;
    }
    
    return 1;
}
int ASSIGN_STMT(FileField *fileField, int left_brother_ID, int father_ID){
    int ret = 0;
    char *func_name="ASSIGN_STMT";
    unsigned int tempIndex = 0;
    unsigned int ident_index = 0;
    IdentId_P p_cur_id = NULL;
    /* [ 1 ] make a node for 'ASSIGN_STMT' */
    tempIndex = g_SynTree.n_node_num;
    g_SynTree.pSynNodeList[ tempIndex ].n_father_id = father_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_identifier_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_left_brother_id = left_brother_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_mode = SYN_NODE_ASSIGN_STMT;
    g_SynTree.pSynNodeList[ tempIndex ].n_right_brother_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_son_id = INVALID_ID;
    /* [ 2 ] fix for father and left brother */
    FIX_FATHER_LBROTHER( father_ID, left_brother_ID, tempIndex )
    g_SynTree.n_node_num++;
    CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
    /* [ 3 ] find the identifier in IdTable */
    ret = find_in_IdTable(fileField, fileField->name_buf, (int)strlen(fileField->name_buf), &ident_index);
    if( 0 == ret ){
        return 0;
    }
    p_cur_id = &g_IdTable.pIdList[ ident_index ];
    if( p_cur_id->n_mode != SYN_NODE_VARID ){
        report_syntax_error( func_name, "Identifier can't be assigned, it's a function name.", fileField->n_current_line );
        return 0;
    }
    /* [ 4 ] make a node for the identifier */
    tempIndex = g_SynTree.n_node_num;
    g_SynTree.pSynNodeList[ tempIndex ].n_father_id = tempIndex - 1;
    g_SynTree.pSynNodeList[ tempIndex ].n_identifier_id = ident_index;
    g_SynTree.pSynNodeList[ tempIndex ].n_left_brother_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_mode = SYN_NODE_VARID;
    g_SynTree.pSynNodeList[ tempIndex ].n_right_brother_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_son_id = INVALID_ID;
    /* [ 5 ] fix for father and left brother */
    FIX_FATHER_LBROTHER( tempIndex - 1, INVALID_ID, tempIndex )
    g_SynTree.n_node_num++;
    CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
    /* [ 6 ] check the '=' */
    JUMP_SPACES( fileField )
    if( '=' != fileField->current_ch ){
        report_syntax_error( func_name, "Missing '='.", fileField->n_current_line );
        return 0;
    }
    /* [ 7 ] deal with FORMULA */
    ret = FORMULA( fileField, tempIndex, tempIndex - 1 );
    if( 0 == ret ){
        return 0;
    }

    return 1;
}

int IF_STMT(FileField *fileField, int left_brother_ID, int father_ID){
    int ret = 0;
    char *func_name="IF_STMT";
    unsigned int tempIndex = 0;
    unsigned int id_length = 0;
    /* [ 1 ] make a node for 'IF_STMT' */
    tempIndex = g_SynTree.n_node_num;
    g_SynTree.pSynNodeList[ tempIndex ].n_father_id = father_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_identifier_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_left_brother_id = left_brother_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_mode = SYN_NODE_IF_STMT;
    g_SynTree.pSynNodeList[ tempIndex ].n_right_brother_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_son_id = INVALID_ID;
    /* [ 2 ] fix for father and left brother */
    FIX_FATHER_LBROTHER( father_ID, left_brother_ID, tempIndex )
    g_SynTree.n_node_num++;
    CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
    /* [ 3 ] check '('  */
    JUMP_SPACES( fileField )
    if( '(' != fileField->current_ch ){
        report_syntax_error( func_name, "Missing '('.", fileField->n_current_line );
        return 0;
    }
    /* [ 4 ] deal with BOOL_FORMULA */
    /* [ 4.1 ] jump spaces in the head for two bytes operator e.g. '>=' */
    GET_NEW_CHAR_JUMP_SPACE( fileField )
    ret = BOOL_FORMULA( fileField, INVALID_ID, tempIndex );
    if( 0 == ret ){
        return 0;
    }
    /* [ 5 ] check ')'  */
    JUMP_SPACES( fileField )
    if( ')' != fileField->current_ch ){
        report_syntax_error( func_name, "Missing ')'.", fileField->n_current_line );
        return 0;
    }
    /* [ 6 ] jump spaces */
    GET_NEW_CHAR_JUMP_SPACE( fileField )
    /* [ 7 ] check '{' */
    if( '{' != fileField->current_ch ){
        report_syntax_error( func_name, "Missing '{'.", fileField->n_current_line );
        return 0;
    }
    /* [ 8 ] jump spaces */
    GET_NEW_CHAR_JUMP_SPACE( fileField )
    /* [ 9 ] get the next token */
    GET_IDENTIFY( fileField, fileField->name_buf, id_length )
    /* [ 10 ] call STATEMENT_LIST() */
    ret = STATEMENT_LIST( fileField, g_SynTree.pSynNodeList[ tempIndex ].n_son_id, tempIndex );
    if( 0 == ret ){
        return 0;
    }
    /* [ 11 ] deal with '}' */
    JUMP_SPACES( fileField )
    if( '}' != fileField->current_ch ){
        report_syntax_error( func_name, "Missing '}' .", fileField->n_current_line );
        return 0;
    }

    return 1;
}
int FOR_STMT(FileField *fileField, int left_brother_ID, int father_ID){
    int ret = 0;
    char *func_name="FOR_STMT";
    unsigned int for_stmt_index = 0;
    unsigned int tempIndex = 0;
    unsigned int id_length = 0;
    /* [ 1 ] make a node for 'FOR_STMT' */
    tempIndex = g_SynTree.n_node_num;
    for_stmt_index = tempIndex;
    g_SynTree.pSynNodeList[ tempIndex ].n_father_id = father_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_identifier_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_left_brother_id = left_brother_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_mode = SYN_NODE_FOR_STMT;
    g_SynTree.pSynNodeList[ tempIndex ].n_right_brother_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_son_id = INVALID_ID;
    /* [ 2 ] fix for father and left brother */
    FIX_FATHER_LBROTHER( father_ID, left_brother_ID, tempIndex )
    g_SynTree.n_node_num++;
    CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
    /* [ 3 ] check '('  */
    JUMP_SPACES( fileField )
    if( '(' != fileField->current_ch ){
        report_syntax_error( func_name, "Missing '('.", fileField->n_current_line );
        return 0;
    }
    /* [ 4 ] jump spaces */
    GET_NEW_CHAR_JUMP_SPACE( fileField )
    if( ';' == fileField->current_ch ){
        /* [ 5 ] first statement is empty, make an empty node */
        tempIndex++;
        g_SynTree.pSynNodeList[ tempIndex ].n_father_id = for_stmt_index;
        g_SynTree.pSynNodeList[ tempIndex ].n_identifier_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_left_brother_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_mode = SYN_NODE_EMPTY;
        g_SynTree.pSynNodeList[ tempIndex ].n_right_brother_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_son_id = INVALID_ID;
        /* [ 5.1 ] fix for father and left brother */
        FIX_FATHER_LBROTHER( for_stmt_index, INVALID_ID, tempIndex )
        g_SynTree.n_node_num++;
        CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
    } else{
        /* [ 6 ] deal with ASSIGN_STMT */
        /* [ 6.1 ] get the next token */
        GET_IDENTIFY( fileField, fileField->name_buf, id_length )
        ret = ASSIGN_STMT( fileField, INVALID_ID, for_stmt_index );
        if( 0 == ret ){
            return 0;
        }
        JUMP_SPACES( fileField )
        if( ';' != fileField->current_ch ){
            /* check ';' */
            report_syntax_error( func_name, "Missing ';' .", fileField->n_current_line );
            return 0;
        }
    }
    /* [ 7 ] deal with BOOL_FORMULA */
    /* [ 7.1 ] jump spaces in the head for two bytes operator e.g. '>=' */
    GET_NEW_CHAR_JUMP_SPACE( fileField )
    ret = BOOL_FORMULA( fileField, g_SynTree.pSynNodeList[ for_stmt_index ].n_son_id, for_stmt_index );
    if( 0 == ret ){
        return 0;
    }
    JUMP_SPACES( fileField )
    if( ';' != fileField->current_ch ){
        /* check ';' */
        report_syntax_error( func_name, "Missing ';' .", fileField->n_current_line );
        return 0;
    }
    /* [ 7.1 ] store the index of BOOL_FORMULA */
    tempIndex = g_SynTree.pSynNodeList[ g_SynTree.pSynNodeList[ for_stmt_index ].n_son_id ].n_right_brother_id;
    /* [ 8 ] jump spaces */
    GET_NEW_CHAR_JUMP_SPACE( fileField )
    if( ')' == fileField->current_ch ){
        /* [ 9 ] last statement is empty, make an empty node */
        g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_father_id = for_stmt_index;
        g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_identifier_id = INVALID_ID;
        g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_left_brother_id = tempIndex;
        g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_mode = SYN_NODE_EMPTY;
        g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_right_brother_id = INVALID_ID;
        g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_son_id = INVALID_ID;
        /* [ 9.1 ] fix for father and left brother */
        FIX_FATHER_LBROTHER( for_stmt_index, tempIndex, g_SynTree.n_node_num )
        g_SynTree.n_node_num++;
        CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
    } else{
        /* [ 10 ] deal with ASSIGN_STMT */
        /* [ 10.1 ] get the next token */
        GET_IDENTIFY( fileField, fileField->name_buf, id_length )
        ret = ASSIGN_STMT( fileField, tempIndex, for_stmt_index );
        if( 0 == ret ){
            return 0;
        }
        JUMP_SPACES( fileField )
        if( ')' != fileField->current_ch ){
            /* check ')' */
            report_syntax_error( func_name, "Missing ')' .", fileField->n_current_line );
            return 0;
        }
    }
    /* [ 10.1 ] store the index of third child of FOR_STMT */
    tempIndex = g_SynTree.pSynNodeList[ tempIndex ].n_right_brother_id;
    /* [ 11 ] jump spaces */
    GET_NEW_CHAR_JUMP_SPACE( fileField )
    /* [ 12 ] check '{' */
    if( '{' != fileField->current_ch ){
        report_syntax_error( func_name, "Missing '{' .", fileField->n_current_line );
        return 0;
    }
    /* [ 13 ] jump spaces */
    GET_NEW_CHAR_JUMP_SPACE( fileField )
    /* [ 14 ] get the next token */
    GET_IDENTIFY( fileField, fileField->name_buf, id_length )
    /* [ 15 ] call STATEMENT_LIST() */
    ret = STATEMENT_LIST( fileField, tempIndex, for_stmt_index );
    if( 0 == ret ){
        return 0;
    }
    /* [ 16 ] deal with '}' */
    JUMP_SPACES( fileField )
    if( '}' != fileField->current_ch ){
        report_syntax_error( func_name, "Missing '}' .", fileField->n_current_line );
        return 0;
    }

    return 1;
}
int WHILE_STMT(FileField *fileField, int left_brother_ID, int father_ID){
    int ret = 0;
    char *func_name="WHILE_STMT";
    unsigned int tempIndex = 0;
    unsigned int id_length = 0;
    /* [ 1 ] make a node for 'WHILE_STMT' */
    tempIndex = g_SynTree.n_node_num;
    g_SynTree.pSynNodeList[ tempIndex ].n_father_id = father_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_identifier_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_left_brother_id = left_brother_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_mode = SYN_NODE_WHILE_STMT;
    g_SynTree.pSynNodeList[ tempIndex ].n_right_brother_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_son_id = INVALID_ID;
    /* [ 2 ] fix for father and left brother */
    FIX_FATHER_LBROTHER( father_ID, left_brother_ID, tempIndex )
    g_SynTree.n_node_num++;
    CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
    /* [ 3 ] check '('  */
    JUMP_SPACES( fileField )
    if( '(' != fileField->current_ch ){
        report_syntax_error( func_name, "Missing '('.", fileField->n_current_line );
        return 0;
    }
    /* [ 4 ] jump spaces */
    /* [ 5.1 ] jump spaces in the head for two bytes operator e.g. '>=' */
    GET_NEW_CHAR_JUMP_SPACE( fileField )
    /* [ 5 ] deal with BOOL_FORMULA */
    ret = BOOL_FORMULA( fileField, INVALID_ID, tempIndex );
    if( 0 == ret ){
        return 0;
    }
    /* [ 6 ] check ')' */
    JUMP_SPACES( fileField )
    if( ')' != fileField->current_ch ){
        report_syntax_error( func_name, "Missing ')'.", fileField->n_current_line );
        return 0;
    }
    /* [ 7 ] jump spaces */
    GET_NEW_CHAR_JUMP_SPACE( fileField )
    /* [ 8 ] check '{' */
    if( '{' != fileField->current_ch ){
        report_syntax_error( func_name, "Missing '{'.", fileField->n_current_line );
        return 0;
    }
    /* [ 9 ] jump spaces */
    GET_NEW_CHAR_JUMP_SPACE( fileField )
    /* [ 10 ] get the next token */
    GET_IDENTIFY( fileField, fileField->name_buf, id_length )
    /* [ 11 ] call STATEMENT_LIST() */
    ret = STATEMENT_LIST( fileField, g_SynTree.pSynNodeList[ tempIndex ].n_son_id, tempIndex );
    if( 0 == ret ){
        return 0;
    }
    /* [ 12 ] deal with '}' */
    JUMP_SPACES( fileField )
    if( '}' != fileField->current_ch ){
        report_syntax_error( func_name, "Missing '}' .", fileField->n_current_line );
        return 0;
    }


    return 1;
}
int FORMULA(FileField *fileField, int left_brother_ID, int father_ID){
    int ret = 0;
    char *func_name="FORMULA";
    unsigned int tempIndex = 0;
    unsigned int FORMULAIndex = 0;
    unsigned int id_length = 0;
    unsigned int ident_index = 0;
    int int_value = 0;
    IdentId_P p_cur_id = NULL;
    /* [ 1 ] make a node for 'FORMULA' */
    tempIndex = g_SynTree.n_node_num;
    FORMULAIndex = tempIndex;
    g_SynTree.pSynNodeList[ tempIndex ].n_father_id = father_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_identifier_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_left_brother_id = left_brother_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_mode = SYN_NODE_FORMULA;
    g_SynTree.pSynNodeList[ tempIndex ].n_right_brother_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_son_id = INVALID_ID;
    /* [ 2 ] fix for father and left brother */
    FIX_FATHER_LBROTHER( father_ID, left_brother_ID, tempIndex )
    g_SynTree.n_node_num++;
    CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
    /* [ 3 ] jump spaces in the head */
    GET_NEW_CHAR_JUMP_SPACE( fileField )
    /* [ 4 ] check the first byte */
    if( '(' == fileField->current_ch ){
        /* [ 5 ] make a node for '(' */
        tempIndex = g_SynTree.n_node_num;
        g_SynTree.pSynNodeList[ tempIndex ].n_father_id = FORMULAIndex;
        g_SynTree.pSynNodeList[ tempIndex ].n_identifier_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_left_brother_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_mode = SYN_NODE_L_parenthesis;
        g_SynTree.pSynNodeList[ tempIndex ].n_right_brother_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_son_id = INVALID_ID;
        /* [ 5.1 ] fix for father and left brother */
        FIX_FATHER_LBROTHER( FORMULAIndex, INVALID_ID, tempIndex )
        g_SynTree.n_node_num++;
        CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
        /* [ 5.2 ] deal with FORMULA recursively */
        ret = FORMULA( fileField, tempIndex, FORMULAIndex );
        if( 0 == ret ){
            return 0;
        }
        /* [ 5.3 ] check ')' */
        JUMP_SPACES( fileField )
        if( ')' != fileField->current_ch ){
            report_syntax_error( func_name, "Missing ')' .", fileField->n_current_line );
            return 0;
        }
        /* [ 5.4 ] make a node for ')' */
        tempIndex = g_SynTree.pSynNodeList[ tempIndex ].n_right_brother_id;
        g_SynTree.n_node_num;
        g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_father_id = FORMULAIndex;
        g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_identifier_id = INVALID_ID;
        g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_left_brother_id = tempIndex;
        g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_mode = SYN_NODE_R_parenthesis;
        g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_right_brother_id = INVALID_ID;
        g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_son_id = INVALID_ID;
        /* [ 5.5 ] fix for father and left brother */
        FIX_FATHER_LBROTHER( FORMULAIndex, tempIndex , g_SynTree.n_node_num )
        g_SynTree.n_node_num++;
        CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
        /* [ 5.6 ] jump spaces in the end */
        GET_NEW_CHAR_JUMP_SPACE( fileField )
        /* [ 5.7 ] reflash the tempIndex */
        tempIndex = g_SynTree.n_node_num - 1;
    } else if( isalpha( fileField->current_ch ) ){
        /* [ 6 ] deal with identifier */
        GET_IDENTIFY( fileField, fileField->name_buf, id_length )
        if( 0 == id_length ){
            report_syntax_error( func_name, "Invalid identifier .", fileField->n_current_line );
            return 0;
        }
        CHECK_KEY_WORD( fileField->name_buf, ret )
        if( KEY_WORD_NO != ret ){
            report_syntax_error( func_name, "Invalid identifier :key-word.", fileField->n_current_line );
            return 0;
        }
        /* [ 6.1 ] find the identifier in IdTable */
        ret = find_in_IdTable(fileField, fileField->name_buf, (int)strlen(fileField->name_buf), &ident_index);
        if( 0 == ret ){
            return 0;
        }
        p_cur_id = &g_IdTable.pIdList[ ident_index ];
        if( p_cur_id->n_mode != SYN_NODE_VARID ){
            report_syntax_error( func_name, "Identifier can't be caculated, it's a function name.", fileField->n_current_line );
            return 0;
        }
        /* [ 6.2 ] make a node for the identifier */
        tempIndex = g_SynTree.n_node_num;
        g_SynTree.pSynNodeList[ tempIndex ].n_father_id = FORMULAIndex;
        g_SynTree.pSynNodeList[ tempIndex ].n_identifier_id = ident_index;
        g_SynTree.pSynNodeList[ tempIndex ].n_left_brother_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_mode = SYN_NODE_VARID;
        g_SynTree.pSynNodeList[ tempIndex ].n_right_brother_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_son_id = INVALID_ID;
        /* [ 6.3 ] fix for father and left brother */
        FIX_FATHER_LBROTHER( FORMULAIndex, INVALID_ID, tempIndex )
        g_SynTree.n_node_num++;
        CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
    } else{
        /* [ 7 ] deal with numbers */
        ret = get_number( fileField, &int_value );
        if( 0 == ret ){
            return 0;
        }
        /* [ 7.1 ] make a node for the integer */
        tempIndex = g_SynTree.n_node_num;
        g_SynTree.pSynNodeList[ tempIndex ].n_father_id = FORMULAIndex;
        g_SynTree.pSynNodeList[ tempIndex ].n_identifier_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_left_brother_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_mode = SYN_NODE_NUMBER;
        g_SynTree.pSynNodeList[ tempIndex ].n_right_brother_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_son_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_int_value = int_value;
        /* [ 7.2 ] fix for father and left brother */
        FIX_FATHER_LBROTHER( FORMULAIndex, INVALID_ID, tempIndex )
        g_SynTree.n_node_num++;
        CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
    }
    /* [ 8 ] deal with FORMULA_FOLLOW */
    ret = FORMULA_FOLLOW( fileField, tempIndex,  FORMULAIndex );
    if( 0 == ret ){
        return 0;
    }

    return 1;
};
int BOOL_FORMULA(FileField *fileField, int left_brother_ID, int father_ID){
    int ret = 0;
    char *func_name="BOOL_FORMULA";
    unsigned int tempIndex = 0;
    unsigned int BOOL_FORMULAIndex = 0;
    unsigned int id_length = 0;
    unsigned int ident_index = 0;
    int int_value = 0;
    IdentId_P p_cur_id = NULL;
    /* [ 1 ] make a node for 'BOOL_FORMULA' */
    tempIndex = g_SynTree.n_node_num;
    BOOL_FORMULAIndex = tempIndex;
    g_SynTree.pSynNodeList[ tempIndex ].n_father_id = father_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_identifier_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_left_brother_id = left_brother_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_mode = SYN_NODE_BOOL_FORMULA;
    g_SynTree.pSynNodeList[ tempIndex ].n_right_brother_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_son_id = INVALID_ID;
    /* [ 2 ] fix for father and left brother */
    FIX_FATHER_LBROTHER( father_ID, left_brother_ID, tempIndex )
    g_SynTree.n_node_num++;
    CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
    /* [ 3 ] jump spaces in the head */
    JUMP_SPACES( fileField )
    /* [ 4 ] check the first byte */
    if( '(' == fileField->current_ch ){
        /* [ 5 ] make a node for '(' */
        tempIndex = g_SynTree.n_node_num;
        g_SynTree.pSynNodeList[ tempIndex ].n_father_id = BOOL_FORMULAIndex;
        g_SynTree.pSynNodeList[ tempIndex ].n_identifier_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_left_brother_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_mode = SYN_NODE_L_parenthesis;
        g_SynTree.pSynNodeList[ tempIndex ].n_right_brother_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_son_id = INVALID_ID;
        /* [ 5.1 ] fix for father and left brother */
        FIX_FATHER_LBROTHER( BOOL_FORMULAIndex, INVALID_ID, tempIndex )
        g_SynTree.n_node_num++;
        CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
        /* [ 5.2 ] deal with BOOL_FORMULA recursively */
        /* jump spaces in the head for two bytes operator e.g. '>=' */
        GET_NEW_CHAR_JUMP_SPACE( fileField )
        ret = BOOL_FORMULA( fileField, tempIndex, BOOL_FORMULAIndex );
        if( 0 == ret ){
            return 0;
        }
        /* [ 5.3 ] check ')' */
        JUMP_SPACES( fileField )
        if( ')' != fileField->current_ch ){
            report_syntax_error( func_name, "Missing ')' .", fileField->n_current_line );
            return 0;
        }
        /* [ 5.4 ] make a node for ')' */
        tempIndex = g_SynTree.pSynNodeList[ tempIndex ].n_right_brother_id;
        g_SynTree.n_node_num;
        g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_father_id = BOOL_FORMULAIndex;
        g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_identifier_id = INVALID_ID;
        g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_left_brother_id = tempIndex;
        g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_mode = SYN_NODE_R_parenthesis;
        g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_right_brother_id = INVALID_ID;
        g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_son_id = INVALID_ID;
        /* [ 5.5 ] fix for father and left brother */
        FIX_FATHER_LBROTHER( BOOL_FORMULAIndex, tempIndex , g_SynTree.n_node_num )
        tempIndex = g_SynTree.n_node_num;/* Fix Bug */
        g_SynTree.n_node_num++;
        CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
        /* [ 5.6 ] jump spaces in the end */
        GET_NEW_CHAR_JUMP_SPACE( fileField )
    } else if( isalpha( fileField->current_ch ) ){
        /* [ 6 ] deal with identifier */
        GET_IDENTIFY( fileField, fileField->name_buf, id_length )
        if( 0 == id_length ){
            report_syntax_error( func_name, "Invalid identifier .", fileField->n_current_line );
            return 0;
        }
        CHECK_KEY_WORD( fileField->name_buf, ret )
        if( KEY_WORD_NO != ret ){
            report_syntax_error( func_name, "Invalid identifier :key-word.", fileField->n_current_line );
            return 0;
        }
        /* [ 6.1 ] find the identifier in IdTable */
        ret = find_in_IdTable(fileField, fileField->name_buf, (int)strlen(fileField->name_buf), &ident_index);
        if( 0 == ret ){
            return 0;
        }
        p_cur_id = &g_IdTable.pIdList[ ident_index ];
        if( p_cur_id->n_mode != SYN_NODE_VARID ){
            report_syntax_error( func_name, "Identifier can't be caculated, it's a function name.", fileField->n_current_line );
            return 0;
        }
        /* [ 6.2 ] make a node for the identifier */
        tempIndex = g_SynTree.n_node_num;
        g_SynTree.pSynNodeList[ tempIndex ].n_father_id = BOOL_FORMULAIndex;
        g_SynTree.pSynNodeList[ tempIndex ].n_identifier_id = ident_index;
        g_SynTree.pSynNodeList[ tempIndex ].n_left_brother_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_mode = SYN_NODE_VARID;
        g_SynTree.pSynNodeList[ tempIndex ].n_right_brother_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_son_id = INVALID_ID;
        /* [ 6.3 ] fix for father and left brother */
        FIX_FATHER_LBROTHER( BOOL_FORMULAIndex, INVALID_ID, tempIndex )
        g_SynTree.n_node_num++;
        CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
    } else{
        /* [ 7 ] deal with numbers */
        ret = get_number( fileField, &int_value );
        if( 0 == ret ){
            return 0;
        }
        /* [ 7.1 ] make a node for the integer */
        tempIndex = g_SynTree.n_node_num;
        g_SynTree.pSynNodeList[ tempIndex ].n_father_id = BOOL_FORMULAIndex;
        g_SynTree.pSynNodeList[ tempIndex ].n_identifier_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_left_brother_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_mode = SYN_NODE_NUMBER;
        g_SynTree.pSynNodeList[ tempIndex ].n_right_brother_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_son_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_int_value = int_value;
        /* [ 7.2 ] fix for father and left brother */
        FIX_FATHER_LBROTHER( BOOL_FORMULAIndex, INVALID_ID, tempIndex )
        g_SynTree.n_node_num++;
        CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
    }
    /* [ 8 ] deal with BOOL_FORMULA_FOLLOW */
    ret = BOOL_FORMULA_FOLLOW( fileField, tempIndex,  BOOL_FORMULAIndex );
    if( 0 == ret ){
        return 0;
    }

    return 1;
}
int FORMULA_FOLLOW(FileField *fileField, int left_brother_ID, int father_ID){
    int ret = 0;
    char *func_name="FORMULA_FOLLOW";
    unsigned int tempIndex = 0;
    /* [ 1 ] make a node for 'FORMULA_FOLLOW' */
    tempIndex = g_SynTree.n_node_num;
    g_SynTree.pSynNodeList[ tempIndex ].n_father_id = father_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_identifier_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_left_brother_id = left_brother_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_mode = SYN_NODE_FORMULA_FOLLOW;
    g_SynTree.pSynNodeList[ tempIndex ].n_right_brother_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_son_id = INVALID_ID;
    /* [ 2 ] fix for father and left brother */
    FIX_FATHER_LBROTHER( father_ID, left_brother_ID, tempIndex )
    g_SynTree.n_node_num++;
    CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
    /* [ 3 ] check the first byte */
    JUMP_SPACES( fileField )
    if( '+' == fileField->current_ch ){
        /* [ 4 ] make a node for '+' */
        tempIndex = g_SynTree.n_node_num;
        g_SynTree.pSynNodeList[ tempIndex ].n_father_id = tempIndex - 1;
        g_SynTree.pSynNodeList[ tempIndex ].n_identifier_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_left_brother_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_mode = SYN_NODE_ADD;
        g_SynTree.pSynNodeList[ tempIndex ].n_right_brother_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_son_id = INVALID_ID;
        /* [ 4.1 ] fix for father and left brother */
        FIX_FATHER_LBROTHER( tempIndex - 1, INVALID_ID, tempIndex )
        g_SynTree.n_node_num++;
        CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
    } else if( '-' ==  fileField->current_ch ){
        /* [ 5 ] make a node for '-' */
        tempIndex = g_SynTree.n_node_num;
        g_SynTree.pSynNodeList[ tempIndex ].n_father_id = tempIndex - 1;
        g_SynTree.pSynNodeList[ tempIndex ].n_identifier_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_left_brother_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_mode = SYN_NODE_SUB;
        g_SynTree.pSynNodeList[ tempIndex ].n_right_brother_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_son_id = INVALID_ID;
        /* [ 5.1 ] fix for father and left brother */
        FIX_FATHER_LBROTHER( tempIndex - 1, INVALID_ID, tempIndex )
        g_SynTree.n_node_num++;
        CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
    } else if( '*' == fileField->current_ch ){
        /* [ 6 ] make a node for '*' */
        tempIndex = g_SynTree.n_node_num;
        g_SynTree.pSynNodeList[ tempIndex ].n_father_id = tempIndex - 1;
        g_SynTree.pSynNodeList[ tempIndex ].n_identifier_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_left_brother_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_mode = SYN_NODE_MUT;
        g_SynTree.pSynNodeList[ tempIndex ].n_right_brother_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_son_id = INVALID_ID;
        /* [ 6.1 ] fix for father and left brother */
        FIX_FATHER_LBROTHER( tempIndex - 1, INVALID_ID, tempIndex )
        g_SynTree.n_node_num++;
        CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
    } else if( '/' == fileField->current_ch ){
        /* [ 7 ] make a node for '/' */
        tempIndex = g_SynTree.n_node_num;
        g_SynTree.pSynNodeList[ tempIndex ].n_father_id = tempIndex - 1;
        g_SynTree.pSynNodeList[ tempIndex ].n_identifier_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_left_brother_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_mode = SYN_NODE_DIV;
        g_SynTree.pSynNodeList[ tempIndex ].n_right_brother_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_son_id = INVALID_ID;
        /* [ 7.1 ] fix for father and left brother */
        FIX_FATHER_LBROTHER( tempIndex - 1, INVALID_ID, tempIndex )
        g_SynTree.n_node_num++;
        CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
    } else{
        /* empty follow */
        return 1;
    }
    /* [ 8 ] deal with FORMULA */
    ret = FORMULA( fileField, tempIndex, tempIndex - 1 );
    if( 0 == ret ){
        return 0;
    }

    return 1;
}
int BOOL_FORMULA_FOLLOW(FileField *fileField, int left_brother_ID, int father_ID){
    int ret = 0;
    char *func_name="BOOL_FORMULA_FOLLOW";
    unsigned int tempIndex = 0;
    short n_mode = 0;
    /* [ 1 ] make a node for 'BOOL_FORMULA_FOLLOW' */
    tempIndex = g_SynTree.n_node_num;
    g_SynTree.pSynNodeList[ tempIndex ].n_father_id = father_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_identifier_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_left_brother_id = left_brother_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_mode = SYN_NODE_BOOL_FORMULA_FOLLOW;
    g_SynTree.pSynNodeList[ tempIndex ].n_right_brother_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_son_id = INVALID_ID;
    /* [ 2 ] fix for father and left brother */
    FIX_FATHER_LBROTHER( father_ID, left_brother_ID, tempIndex )
    g_SynTree.n_node_num++;
    CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
    /* [ 3 ] check the operator, maybe two bytes */
    JUMP_SPACES( fileField )
    if( '|' == fileField->current_ch ){
        /* [ 4 ] deal with the operator '||' */
        fileField->current_ch = fgetc( fileField->fp );
        CHECK_NEW_LINE( fileField )
        if( '|' != fileField->current_ch ){
            report_syntax_error( func_name, "Invalid operator.", fileField->n_current_line );
            return 0;
        }
        /* [ 4.1 ] mode is '||' */
        n_mode = SYN_NODE_OR;
        /* [ 4.2 ] jump spaces in the end */
        GET_NEW_CHAR_JUMP_SPACE( fileField )
    } else if( '&' == fileField->current_ch){
        /* [ 5 ] deal with the operator '&&' */
        fileField->current_ch = fgetc( fileField->fp );
        CHECK_NEW_LINE( fileField )
        if( '&' != fileField->current_ch ){
            report_syntax_error( func_name, "Invalid operator.", fileField->n_current_line );
            return 0;
        }
        /* [ 5.1 ] mode is '||' */
        n_mode = SYN_NODE_AND;
        /* [ 5.2 ] jump spaces in the end */
        GET_NEW_CHAR_JUMP_SPACE( fileField )
    } else if( '<' == fileField->current_ch){
        /* [ 6 ] deal with the operator '<' or '<=' */
        fileField->current_ch = fgetc( fileField->fp );
        CHECK_NEW_LINE( fileField )
        if( '=' != fileField->current_ch ){
            /* [ 6.1 ] mode is '<' */
            n_mode = SYN_NODE_LESS;
        } else{
            /* [ 6.2 ] mode is '<=' */
            n_mode = SYN_NODE_NOT_MORE;
            /* [ 6.3 ] jump spaces in the end */
            GET_NEW_CHAR_JUMP_SPACE( fileField )
        }
    } else if( '>' == fileField->current_ch){
        /* [ 7 ] deal with the operator '>' or '>=' */
        fileField->current_ch = fgetc( fileField->fp );
        CHECK_NEW_LINE( fileField )
        if( '=' != fileField->current_ch ){
            /* [ 7.1 ] mode is '>' */
            n_mode = SYN_NODE_MORE;
        } else{
            /* [ 7.2 ] mode is '>=' */
            n_mode = SYN_NODE_NOT_LESS;
            /* [ 7.3 ] jump spaces in the end */
            GET_NEW_CHAR_JUMP_SPACE( fileField )
        }
    } else if( '=' == fileField->current_ch){
        /* [ 8 ] deal with the operator '==' */
        fileField->current_ch = fgetc( fileField->fp );
        CHECK_NEW_LINE( fileField )
        if( '=' != fileField->current_ch ){
            report_syntax_error( func_name, "Invalid operator.", fileField->n_current_line );
            return 0;
        }
        /* [ 8.1 ] mode is '==' */
        n_mode = SYN_NODE_EQ;
        /* [ 8.2 ] jump spaces in the end */
        GET_NEW_CHAR_JUMP_SPACE( fileField )
    } else if( '!' == fileField->current_ch){
        /* [ 9 ] deal with the operator '!=' */
        fileField->current_ch = fgetc( fileField->fp );
        CHECK_NEW_LINE( fileField )
        if( '=' != fileField->current_ch ){
            report_syntax_error( func_name, "Invalid operator.", fileField->n_current_line );
            return 0;
        }
        /* [ 9.1 ] mode is '!=' */
        n_mode = SYN_NODE_NOT_EQ;
        /* [ 9.2 ] jump spaces in the end */
        GET_NEW_CHAR_JUMP_SPACE( fileField )
    } else if( '+' == fileField->current_ch){
        /* [ 10 ] deal with the operator '+' */
        n_mode = SYN_NODE_ADD;
        /* [ 10.1 ] jump spaces in the end */
        GET_NEW_CHAR_JUMP_SPACE( fileField )
    } else if( '-' == fileField->current_ch){
        /* [ 11 ] deal with the operator '-' */
        n_mode = SYN_NODE_SUB;
        /* [ 11.1 ] jump spaces in the end */
        GET_NEW_CHAR_JUMP_SPACE( fileField )
    } else if( '*' == fileField->current_ch){
        /* [ 12 ] deal with the operator '*' */
        n_mode = SYN_NODE_MUT;
        /* [ 12.1 ] jump spaces in the end */
        GET_NEW_CHAR_JUMP_SPACE( fileField )
    } else if( '/' == fileField->current_ch){
        /* [ 13 ] deal with the operator '/' */
        n_mode = SYN_NODE_DIV;
        /* [ 13.1 ] jump spaces in the end */
        GET_NEW_CHAR_JUMP_SPACE( fileField )
    } else{
        /* empty follow */
        return 1;
    }
    /* [ 14 ] make a node for the operator*/
    tempIndex = g_SynTree.n_node_num;
    g_SynTree.pSynNodeList[ tempIndex ].n_father_id = tempIndex - 1;
    g_SynTree.pSynNodeList[ tempIndex ].n_identifier_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_left_brother_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_mode = n_mode;
    g_SynTree.pSynNodeList[ tempIndex ].n_right_brother_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_son_id = INVALID_ID;
    /* [ 15 ] fix for father and left brother */
    FIX_FATHER_LBROTHER( tempIndex - 1, INVALID_ID, tempIndex )
    g_SynTree.n_node_num++;
    CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
    /* [ 16 ] deal with BOOL_FORMULA */
    ret = BOOL_FORMULA( fileField, tempIndex, tempIndex - 1 );
    if( 0 == ret ){
        return 0;
    }

    return 1;
}
int FUNC_CALL(FileField *fileField, int left_brother_ID, int father_ID){
    int ret = 0;
    char *func_name="FUNC_CALL";
    unsigned int tempIndex = 0;
    unsigned int ident_index = 0;
    IdentId_P p_cur_id = NULL;
    /* [ 1 ] make a node for 'FUNC_CALL' */
    tempIndex = g_SynTree.n_node_num;
    g_SynTree.pSynNodeList[ tempIndex ].n_father_id = father_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_identifier_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_left_brother_id = left_brother_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_mode = SYN_NODE_FUNC_CALL;
    g_SynTree.pSynNodeList[ tempIndex ].n_right_brother_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_son_id = INVALID_ID;
    /* [ 2 ] fix for father and left brother */
    FIX_FATHER_LBROTHER( father_ID, left_brother_ID, tempIndex )
    g_SynTree.n_node_num++;
    CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
    /* [ 3 ] find the identifier in IdTable */
    ret = find_in_IdTable(fileField, fileField->name_buf, (int)strlen(fileField->name_buf), &ident_index);
    if( 0 == ret ){
        return 0;
    }
    p_cur_id = &g_IdTable.pIdList[ ident_index ];
    if( p_cur_id->n_mode != SYN_NODE_FUNID ){
        report_syntax_error( func_name, "Function can't be called, it's an identifier name.", fileField->n_current_line );
        return 0;
    }
    /* [ 4 ] make a node for the func_id */
    tempIndex = g_SynTree.n_node_num;
    g_SynTree.pSynNodeList[ tempIndex ].n_father_id = tempIndex - 1;
    g_SynTree.pSynNodeList[ tempIndex ].n_identifier_id = ident_index;
    g_SynTree.pSynNodeList[ tempIndex ].n_left_brother_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_mode = SYN_NODE_FUNID;
    g_SynTree.pSynNodeList[ tempIndex ].n_right_brother_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_son_id = INVALID_ID;
    /* [ 5 ] fix for father and left brother */
    FIX_FATHER_LBROTHER( tempIndex - 1, INVALID_ID, tempIndex )
    g_SynTree.n_node_num++;
    CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
    /* [ 6 ] check the '(' */
    JUMP_SPACES( fileField )
    if( '(' != fileField->current_ch ){
        report_syntax_error( func_name, "Missing '('.", fileField->n_current_line );
        return 0;
    }
    /* [ 7 ] check the ')' */
    GET_NEW_CHAR_JUMP_SPACE( fileField )
    if( ')' != fileField->current_ch ){
        report_syntax_error( func_name, "Missing ')'.", fileField->n_current_line );
        return 0;
    }
    /* [ 8 ] check the ';' */
    GET_NEW_CHAR_JUMP_SPACE( fileField )
    if( ';' != fileField->current_ch ){
        report_syntax_error( func_name, "Missing ';'.", fileField->n_current_line );
        return 0;
    }

    return 1;
}
int add_to_IdTable(FileField * fileField, char *id_name, int length, short mode, unsigned int * p_ident_index){
    char first_index = 0;
    char second_index = 0;
    IdentId_P cur_IdentId_list = NULL;
    unsigned int index = 0;
    unsigned int temp = 0;
    char *func_name = "add_to_IdTable";

    if( length <= 0 ){
        report_internal_error(func_name, __LINE__);
        return 0;
    }
    if( id_name[0] >= 'A' && id_name[0] <= 'Z' ){
        first_index = id_name[0] - 'A';
    } else if( id_name[0] >= 'a' && id_name[0] <= 'z' ){
        first_index = id_name[0] - 'a' + 26;
    } else{
        first_index = 51;
    }
    if( length > 1 ){
        if( id_name[1] >= 'A' && id_name[1] <= 'Z' ){
            second_index = id_name[1] - 'A';
        } else if( id_name[1] >= 'a' && id_name[1] <= 'z' ){
            second_index = id_name[1] - 'a' + 26;
        } else if( id_name[1] >= '0' && id_name[1] <= '9' ){
            second_index = id_name[1] - '0' + 52;
        } else{
            second_index = 61;
        }
    }
    temp = g_IdTable.two_level_index[ first_index ][ second_index ];

    while( temp != INVALID_ID ){
        /* a list is found */
        cur_IdentId_list = &g_IdTable.pIdList[temp];
        if( strcmp( cur_IdentId_list->str_name, id_name ) == 0 ){
            /* already exist */
            report_syntax_error( func_name, "Re-definition error.", fileField->n_current_line );
            return 0;
        }
        temp = cur_IdentId_list->n_next_identifier_id;
    }
    if( g_IdTable.n_id_num + 1 > MAX_SYN_NODE_NUM ){
        report_syntax_error( func_name, "Too many identifiers.", fileField->n_current_line );
        return 0;
    }
    index = g_IdTable.n_id_num;
    g_IdTable.n_id_num++;
    if( NULL != cur_IdentId_list ){
        cur_IdentId_list->n_next_identifier_id = index;
    } else{
        /* create a new list for this id */
        g_IdTable.two_level_index[ first_index ][ second_index ] = index;
    }
    g_IdTable.pIdList[index].n_mode = mode;
    g_IdTable.pIdList[index].n_next_identifier_id = INVALID_ID;
    strcpy_s( g_IdTable.pIdList[index].str_name, MAX_ID_LENGTH+1, id_name );
    *p_ident_index = index;

    return 1;
}

int find_in_IdTable(FileField * fileField, char *id_name, int length, unsigned int * p_ident_index){
    char first_index = 0;
    char second_index = 0;
    IdentId_P cur_IdentId_list = NULL;
    unsigned int index = 0;
    unsigned int temp = 0;
    char *func_name = "find_in_IdTable";

    if( length <= 0 ){
        report_syntax_error( func_name, "Identifier not specified.", fileField->n_current_line );
        return 0;
    }
    if( id_name[0] >= 'A' && id_name[0] <= 'Z' ){
        first_index = id_name[0] - 'A';
    } else if( id_name[0] >= 'a' && id_name[0] <= 'z' ){
        first_index = id_name[0] - 'a' + 26;
    } else{
        first_index = 51;
    }
    if( length > 1 ){
        if( id_name[1] >= 'A' && id_name[1] <= 'Z' ){
            second_index = id_name[1] - 'A';
        } else if( id_name[1] >= 'a' && id_name[1] <= 'z' ){
            second_index = id_name[1] - 'a' + 26;
        } else if( id_name[1] >= '0' && id_name[1] <= '9' ){
            second_index = id_name[1] - '0' + 52;
        } else{
            second_index = 61;
        }
    }
    temp = g_IdTable.two_level_index[ first_index ][ second_index ];

    while( temp != INVALID_ID ){
        /* a list is found */
        cur_IdentId_list = &g_IdTable.pIdList[temp];
        if( strcmp( cur_IdentId_list->str_name, id_name ) == 0 ){
            *p_ident_index = temp;
            return 1;
        }
        temp = cur_IdentId_list->n_next_identifier_id;
    }
    report_syntax_error( func_name, "Identifier not specified.", fileField->n_current_line );
    return 0;
}

int get_number( FileField * fileField, int * pOutValue){
    char *func_name = "get_number";
    int tempValue1 = 0;
    int tempValue2 = 0;
    int b_sign = 0;/* 0 ==> no sign ,  1 ==> '+' , -1 ==> '-'  */
    /* [ 1 ] check the sign */
    if( '-' == fileField->current_ch ){
        b_sign = -1;
        fileField->current_ch = fgetc( fileField->fp );
        CHECK_NEW_LINE( fileField )
    } else if( '+' == fileField->current_ch ){
        b_sign = 1;
        fileField->current_ch = fgetc( fileField->fp );
        CHECK_NEW_LINE( fileField )
    }
    /* [ 2 ] check the first number */
    if( fileField->current_ch < '0' || fileField->current_ch > '9' ){
        report_syntax_error( func_name, "Invalid character.", fileField->n_current_line );
        return 0;
    }
    while( fileField->current_ch >= '0' && fileField->current_ch <= '9' ){
        tempValue1 = tempValue2;
        tempValue2 = tempValue2 * 10 + fileField->current_ch - '0';
        if( tempValue1 > tempValue2 ){
            /* [ 3 ] deal with overflow */
            report_syntax_error( func_name, "Integer overflow.", fileField->n_current_line );
            return 0;
        }
        fileField->current_ch = fgetc( fileField->fp );
        CHECK_NEW_LINE( fileField )        
    }
    if( -1 == b_sign ){
        tempValue2 = ~tempValue2 + 1;
    }
    if( tempValue2 > SHORT_MAX || tempValue2 < SHORT_MIN ){
        /* [ 4 ] deal with overflow. Note: using 16bit-int for EXE file */
        report_syntax_error( func_name, "Integer overflow.", fileField->n_current_line );
        return 0;
    }
    *pOutValue = (int)tempValue2;


    return 1;
}
static void print_syntax_node( FILE* fp, SynNode_P p_node ){
    char buffer[128];
    buffer[0] = '\0';
    switch( p_node->n_mode ){
    case SYN_NODE_HEAD:
        strcpy_s( buffer, 128, "head" );
        break;
    case SYN_NODE_VARID:
        strcpy_s( buffer, 128, "VARID" );
        break;
    case SYN_NODE_FUNID:
        strcpy_s( buffer, 128, "FUNID" );
        break;
    case SYN_NODE_MAINFUNID:
        strcpy_s( buffer, 128, "main" );
        break;
    case SYN_NODE_BODY:
        strcpy_s( buffer, 128, "BODY" );
        break;
    case SYN_NODE_DEFINITION:
        strcpy_s( buffer, 128, "DEFINITION" );
        break;
    case SYN_NODE_VAR_DEF:
        strcpy_s( buffer, 128, "VAR_DEF" );
        break;
    case SYN_NODE_FUNC_DEF:
        strcpy_s( buffer, 128, "FUNC_DEF" );
        break;
    case SYN_NODE_VAR_DEFINITION:
        strcpy_s( buffer, 128, "VAR_DEFINITION" );
        break;
    case SYN_NODE_STATEMENT_LIST:
        strcpy_s( buffer, 128, "STATEMENT_LIST" );
        break;
    case SYN_NODE_ASSIGN_STMT:
        strcpy_s( buffer, 128, "ASSIGN_STMT" );
        break;
    case SYN_NODE_IF_STMT:
        strcpy_s( buffer, 128, "IF_STMT" );
        break;
    case SYN_NODE_FOR_STMT:
        strcpy_s( buffer, 128, "FOR_STMT" );
        break;
    case SYN_NODE_WHILE_STMT:
        strcpy_s( buffer, 128, "WHILE_STMT" );
        break;
    case SYN_NODE_FORMULA:
        strcpy_s( buffer, 128, "FORMULA" );
        break;
    case SYN_NODE_BOOL_FORMULA:
        strcpy_s( buffer, 128, "BOOL_FORMULA" );
        break;
    case SYN_NODE_FORMULA_FOLLOW:
        strcpy_s( buffer, 128, "FORMULA_FOLLOW" );
        break;
    case SYN_NODE_NUMBER:
        strcpy_s( buffer, 128, "NUMBER" );
        break;
    case SYN_NODE_L_parenthesis:
        strcpy_s( buffer, 128, "(" );
        break;
    case SYN_NODE_R_parenthesis:
        strcpy_s( buffer, 128, ")" );
        break;
    case SYN_NODE_ADD:
        strcpy_s( buffer, 128, "+" );
        break;
    case SYN_NODE_SUB:
        strcpy_s( buffer, 128, "-" );
        break;
    case SYN_NODE_MUT:
        strcpy_s( buffer, 128, "*" );
        break;
    case SYN_NODE_DIV:
        strcpy_s( buffer, 128, "/" );
        break;
    case SYN_NODE_AND:
        strcpy_s( buffer, 128, "&&" );
        break;
    case SYN_NODE_OR:
        strcpy_s( buffer, 128, "||" );
        break;
    case SYN_NODE_LESS:
        strcpy_s( buffer, 128, "<" );
        break;
    case SYN_NODE_MORE:
        strcpy_s( buffer, 128, ">" );
        break;
    case SYN_NODE_EQ:
        strcpy_s( buffer, 128, "==" );
        break;
    case SYN_NODE_NOT_LESS:
        strcpy_s( buffer, 128, ">=" );
        break;
    case SYN_NODE_NOT_MORE:
        strcpy_s( buffer, 128, "<=" );
        break;
    case SYN_NODE_NOT_EQ:
        strcpy_s( buffer, 128, "!=" );
        break;
    case SYN_NODE_BOOL_FORMULA_FOLLOW:
        strcpy_s( buffer, 128, "BOOL_FORMULA_FOLLOW" );
        break;
    case SYN_NODE_EMPTY:
        strcpy_s( buffer, 128, "EMPTY" );
        break;
    case SYN_NODE_FUNC_CALL:
        strcpy_s( buffer, 128, "FUNC_CALL" );
        break;
    }

    fprintf( fp,"n_mode = '%s';", buffer);
    if( SYN_NODE_VARID == p_node->n_mode || SYN_NODE_FUNID == p_node->n_mode ){
        fprintf( fp, "id name = '%s';", g_IdTable.pIdList[ p_node->n_identifier_id ].str_name );
    }
    fprintf( fp,"father_id = '%d';", (int)p_node->n_father_id);
    fprintf( fp,"left_brother_id = '%d';", (int)p_node->n_left_brother_id);
    fprintf( fp,"right_brother_id = '%d';", (int)p_node->n_right_brother_id);
    fprintf( fp,"son_id = '%d';", (int)p_node->n_son_id);
    if( SYN_NODE_NUMBER == p_node->n_mode ){
        fprintf( fp, "value = '%d';", p_node->n_int_value );
    }
}
void debug_syntax( FILE* fp ){
    unsigned int i = 0;
    for( i = 0; i < g_SynTree.n_node_num; i++ ){
        fprintf( fp,"id = '%6d';", i);
        print_syntax_node( fp, &g_SynTree.pSynNodeList[ i ] );
        fprintf(fp,"\n*******************************************************************************\n");
    }
}


语义分析器

/** scmpsem.c
====================================================================
This is the base source file for Semantic Analyze


====================================================================
 */

#include "scmpsem.h"
int sem_deal_with_header();
int sem_deal_with_data();
int sem_deal_with_code();
int sem_deal_with_DEFINITION(SynNode_P pSynNode);
int sem_deal_with_BODY(SynNode_P pSynNode);
int sem_deal_with_FUNC_DEF(SynNode_P pSynNode);
int sem_deal_with_STATEMENT_LIST(SynNode_P pSynNode);
int sem_deal_with_ASSIGN_STMT(SynNode_P pSynNode);
int sem_deal_with_IF_STMT(SynNode_P pSynNode);
int sem_deal_with_FOR_STMT(SynNode_P pSynNode);
int sem_deal_with_WHILE_STMT(SynNode_P pSynNode);
int sem_deal_with_FUNC_CALL(SynNode_P pSynNode);
int sem_deal_with_FORMULA(SynNode_P pSynNode);
int sem_deal_with_BOOL_FORMULA(SynNode_P pSynNode);

static int push( SEM_STACK_NODE *in_node );
static int pop( SEM_STACK_NODE *out_node );
#define MY_PUSH( p_in_node )\
    {\
        if( 0 == push( p_in_node ) ){\
           printf("POP error at line '%d' \n", __LINE__ );\
           return 0;\
        }\
    }
#define MY_POP( p_out_node )\
    {\
        if( 0 == pop( p_out_node ) ){\
           printf("POP error at line '%d' \n", __LINE__ );\
           return 0;\
        }\
    }
static int check_caculate( SEM_STACK_NODE *cur_node );
static int caculate_AX_BX_by_op( SEM_STACK_NODE *op_node );

int initialize_SemEnv(){
    g_SemEnv.n_SignCurrentId = 0;
    g_SemEnv.pAsmFile = NULL;
    fopen_s( &g_SemEnv.pAsmFile, ASM_FILE_NAME , "w" );
    if( NULL == g_SemEnv.pAsmFile ){
        printf("Can't open source file '%s'. exit.\n", ASM_FILE_NAME );
        return 0;
    }
    g_SemEnv.s_sem_stack.n_num = 0;
    g_SemEnv.s_sem_stack.sem_node_list = ( SEM_STACK_NODE * )malloc( sizeof(SEM_STACK_NODE) * MAX_STACK_NUM );
    if( NULL == g_SemEnv.s_sem_stack.sem_node_list ){
        printf("Memery not enough while initializing semantic stack.\n" );
        return 0;
    }
    return 1;
}
int finalize_SemEnv(){
    g_SemEnv.n_SignCurrentId = 0;
    MY_HELP_CLOSE( g_SemEnv.pAsmFile );
    g_SemEnv.s_sem_stack.n_num = 0;
    MY_HELP_FREE( g_SemEnv.s_sem_stack.sem_node_list );
    return 1;
}


int semantic_analyzer(){
    int ret = 0;
    char * func_name="semantic_analyzer";

    ret = initialize_SemEnv();
    if( 0 == ret ){
        printf("semantic_analyzer exit with initialize error.\n");
        finalize_SemEnv();
        return 0;
    }
    /* [ 1 ] deal with header */
    sem_deal_with_header();
    /* [ 2 ] deal with data */
    ret = sem_deal_with_data();
    if( 0 == ret ){
        printf("semantic_analyzer exit with internal error.\n");
        finalize_SemEnv();
        return 0;
    }
    /* [ 3 ] deal with code */
    ret =  sem_deal_with_code();
    if( 0 == ret ){
        printf("semantic_analyzer exit with internal error.\n");
        finalize_SemEnv();
        return 0;
    }
    /* [ 4 ] deal with Ending */
    fprintf( g_SemEnv.pAsmFile, ASM_END_MAIN );

    finalize_SemEnv();
    return 1;
}
int sem_deal_with_header(){
    fprintf( g_SemEnv.pAsmFile, ASM_HEADER );

    return 1;
}
int sem_deal_with_data(){
    unsigned int index = 0;
    char * p_VarName = NULL;

    /* [ 1 ] data header */
    fprintf( g_SemEnv.pAsmFile, ASM_DATA_HEADER );
    /* [ 2 ] Variable definition */
    for( index = 0; index < g_IdTable.n_id_num; index++ ){
        if( SYN_NODE_VARID == g_IdTable.pIdList[ index ].n_mode ){
            p_VarName = g_IdTable.pIdList[ index ].str_name;
            fprintf( g_SemEnv.pAsmFile, ASM_VAR_DEF, p_VarName, p_VarName, p_VarName );
        }
    }

    return 1;
}
int sem_deal_with_code(){
    int ret = 0;
    SynNode_P pCurSynNode = NULL;

    /* [ 1 ] code header */
    fprintf( g_SemEnv.pAsmFile, ASM_CODE_HEADER );
    /* [ 2 ] deal with DEFINITION */
    /* [ 2.1 ] Get the first node of DEFINITION */
    pCurSynNode = &g_SynTree.pSynNodeList[1];
    ret = sem_deal_with_DEFINITION( pCurSynNode );
    if( 0 == ret ){
        return 0;
    }
    /* [ 3 ] deal with main */
    /* [ 3.1 ] Get the node of 'main' */
    fprintf( g_SemEnv.pAsmFile, "Main  PROC\nMOV AX, DGROUP\nMOV DS, AX\n" );
    CHECK_SYN_NODE_ID( pCurSynNode->n_right_brother_id )
    pCurSynNode = &g_SynTree.pSynNodeList[ pCurSynNode->n_right_brother_id ];
    /* [ 3.2 ] Get the node of 'BODY' */
    CHECK_SYN_NODE_ID( pCurSynNode->n_right_brother_id )
    pCurSynNode = &g_SynTree.pSynNodeList[ pCurSynNode->n_right_brother_id ];
    ret = sem_deal_with_BODY( pCurSynNode );
    if( 0 == ret ){
        return 0;
    }
#ifdef DEBUG_SEM
    debug_sem();
#endif
    /* [ 3.3 ] Tail of 'main' */
    fprintf( g_SemEnv.pAsmFile, "MOV  AX, 4C00H\nINT  21H\nMain  ENDP\n" );
    return 1;
}
int sem_deal_with_DEFINITION( SynNode_P pSynNode ){
    SynNode_P pCurSynNode = NULL;
    int ret = 0;

    /* [ 1 ] Get the first node of DEFINITION */
    pCurSynNode = pSynNode;
    while( pCurSynNode != NULL && pCurSynNode->n_son_id != INVALID_ID ){
        /* [ 1.1 ] check the son */
        pCurSynNode = &g_SynTree.pSynNodeList[ pCurSynNode->n_son_id ];
        if( SYN_NODE_FUNC_DEF == pCurSynNode->n_mode ){
            /* [ 1.1.1 ] it's FUNC definition, deal with it */
            ret = sem_deal_with_FUNC_DEF( pCurSynNode );
            if( 0 == ret ){
                return 0;
            }

        }
            /* [ 1.1.2 ] deal with right brother of it */
        if( pCurSynNode->n_right_brother_id != INVALID_ID ){
            pCurSynNode = &g_SynTree.pSynNodeList[ pCurSynNode->n_right_brother_id ];
        } else{
            pCurSynNode = NULL;
        }
    }
    return 1;
}
int sem_deal_with_FUNC_DEF(SynNode_P pSynNode){
    SynNode_P pCurSynNode = NULL;
    IdentId_P pId = NULL;
    int ret = 0;
    /* [ 1 ] Function Header */
    /* [ 1.1 ] Get the function id */
    CHECK_SYN_NODE_ID( pSynNode->n_son_id )
    pCurSynNode = &g_SynTree.pSynNodeList[ pSynNode->n_son_id ];
    CHECK_SYN_NODE_ID( pCurSynNode->n_identifier_id )
    pId = &g_IdTable.pIdList[ pCurSynNode->n_identifier_id ];
    fprintf( g_SemEnv.pAsmFile, "%s  PROC\n", pId->str_name );
    /* [ 1.2 ] Save the current Registers */
    fprintf( g_SemEnv.pAsmFile, "PUSH  BP\n", pId->str_name );
    fprintf( g_SemEnv.pAsmFile, "MOV  BP, SP\n", pId->str_name );
    fprintf( g_SemEnv.pAsmFile, "PUSH  DS\n", pId->str_name );
    /* [ 2 ] deal with 'BODY' */
    CHECK_SYN_NODE_ID( pCurSynNode->n_right_brother_id )
    pCurSynNode = &g_SynTree.pSynNodeList[ pCurSynNode->n_right_brother_id ];
    ret = sem_deal_with_BODY( pCurSynNode );
    if( 0 == ret ){
        return 0;
    }
    /* [ 3 ] Function Tail */
    /* [ 3.1 ] Backup the current Registers */
    fprintf( g_SemEnv.pAsmFile, "POP  DS\n", pId->str_name );
    fprintf( g_SemEnv.pAsmFile, "MOV  SP, BP\n", pId->str_name );
    fprintf( g_SemEnv.pAsmFile, "POP  BP\n", pId->str_name );
    fprintf( g_SemEnv.pAsmFile, "RET\n%s  ENDP\n", pId->str_name );
    return 1;
}
int sem_deal_with_BODY(SynNode_P pSynNode){
    SynNode_P pCurSynNode = NULL;
    int ret = 0;
    
    /* [ 1 ] get node of 'VAR_DEFINITION' */
    CHECK_SYN_NODE_ID( pSynNode->n_son_id )
    pCurSynNode = &g_SynTree.pSynNodeList[ pSynNode->n_son_id ];
    /* [ 2 ] deal with  'STATEMENT_LIST' */
    if( INVALID_ID != pCurSynNode->n_right_brother_id ){
        pCurSynNode = &g_SynTree.pSynNodeList[ pCurSynNode->n_right_brother_id ];
        ret = sem_deal_with_STATEMENT_LIST( pCurSynNode );
        if( 0 == ret ){
            return 0;
        }
    }
    return 1;
}
int sem_deal_with_STATEMENT_LIST(SynNode_P pSynNode){
    SynNode_P pCurSynNode = NULL;
    int ret = 0;

    if( INVALID_ID == pSynNode->n_son_id ){
        /* empty statement list */
        return 1;
    }
    /* [ 1 ] deal with first statement */
    pCurSynNode = &g_SynTree.pSynNodeList[ pSynNode->n_son_id ];
    switch( pCurSynNode->n_mode ){
        case SYN_NODE_ASSIGN_STMT:
            ret = sem_deal_with_ASSIGN_STMT( pCurSynNode );
            break;
        case SYN_NODE_IF_STMT:
            ret = sem_deal_with_IF_STMT( pCurSynNode );
            break;
        case SYN_NODE_FOR_STMT:
            ret = sem_deal_with_FOR_STMT( pCurSynNode );
            break;
        case SYN_NODE_WHILE_STMT:
            ret = sem_deal_with_WHILE_STMT( pCurSynNode );
            break;
        case SYN_NODE_FUNC_CALL:
            ret = sem_deal_with_FUNC_CALL( pCurSynNode );
            break;
    }
    if( 0 == ret ){
        return 0;
    }
    /* [ 2 ] deal with following statement */
    CHECK_SYN_NODE_ID( pCurSynNode->n_right_brother_id )
    pCurSynNode = &g_SynTree.pSynNodeList[ pCurSynNode->n_right_brother_id ];
    ret = sem_deal_with_STATEMENT_LIST( pCurSynNode );
    return ret;
}
int sem_deal_with_ASSIGN_STMT(SynNode_P pSynNode){
    SynNode_P pCurSynNode = NULL;
    int ret = 0;
    IdentId_P pId = NULL;
    /* [ 1 ] get the var id */
    CHECK_SYN_NODE_ID( pSynNode->n_son_id )
    pCurSynNode = &g_SynTree.pSynNodeList[ pSynNode->n_son_id ];
    CHECK_SYN_NODE_ID( pCurSynNode->n_identifier_id )
    pId = &g_IdTable.pIdList[ pCurSynNode->n_identifier_id ];

    /* [ 2 ] deal with FORMULA */
    CHECK_SYN_NODE_ID( pCurSynNode->n_right_brother_id )
    pCurSynNode = &g_SynTree.pSynNodeList[ pCurSynNode->n_right_brother_id ];
    ret = sem_deal_with_FORMULA( pCurSynNode );
    if( 0 == ret ){
        return ret;
    }
    /* [ 3 ] deal with assign */
    fprintf( g_SemEnv.pAsmFile, "MOV  %s, AX\n", pId->str_name );

    return 1;
}
int sem_deal_with_IF_STMT(SynNode_P pSynNode){
    SynNode_P pCurSynNode = NULL;
    int ret = 0;
    char str_cur_sign[20];
    /* [ 1 ] deal with BOOL_FORMULA */
    CHECK_SYN_NODE_ID( pSynNode->n_son_id )
    pCurSynNode = &g_SynTree.pSynNodeList[ pSynNode->n_son_id ];
    ret = sem_deal_with_BOOL_FORMULA( pCurSynNode );
    if( 0 == ret ){
        return 0;
    }
    /* [ 2 ] make a sign name. if AX is 0, jump to it. */
    sprintf_s( str_cur_sign, sizeof(str_cur_sign), "SIGN_%d", g_SemEnv.n_SignCurrentId );
    g_SemEnv.n_SignCurrentId++;
    fprintf( g_SemEnv.pAsmFile, "CMP  AX,0\nJE %s\n",  str_cur_sign );
    /* [ 3 ] deal with STATEMENT_LIST */
    CHECK_SYN_NODE_ID( pCurSynNode->n_right_brother_id )
    pCurSynNode = &g_SynTree.pSynNodeList[ pCurSynNode->n_right_brother_id ];
    ret = sem_deal_with_STATEMENT_LIST( pCurSynNode );
    if( 0 == ret ){
        return 0;
    }
    /* [ 4 ] make the sign at the end */
    fprintf( g_SemEnv.pAsmFile, "%s:\n",  str_cur_sign );
    return 1;
}
int sem_deal_with_FOR_STMT(SynNode_P pSynNode){
    SynNode_P pCurSynNode = NULL;
    SynNode_P pSecondAssign = NULL;
    int ret = 0;
    char str_first_sign[20];
    char str_second_sign[20];
    /* [ 1 ] deal with ASSIGN_STMT */
    CHECK_SYN_NODE_ID( pSynNode->n_son_id )
    pCurSynNode = &g_SynTree.pSynNodeList[ pSynNode->n_son_id ];
    if( SYN_NODE_ASSIGN_STMT == pCurSynNode->n_mode ){
        ret = sem_deal_with_ASSIGN_STMT( pCurSynNode );
        if( 0 == ret ){
            return 0;
        }
    }
    /* [ 2 ] make a sign before BOOL_FORMULA */
    sprintf_s( str_first_sign, sizeof(str_first_sign), "SIGN_%d", g_SemEnv.n_SignCurrentId );
    g_SemEnv.n_SignCurrentId++;
    fprintf( g_SemEnv.pAsmFile, "%s:\n",  str_first_sign );
    /* [ 3 ] deal with BOOL_FORMULA */
    CHECK_SYN_NODE_ID( pCurSynNode->n_right_brother_id )
    pCurSynNode = &g_SynTree.pSynNodeList[ pCurSynNode->n_right_brother_id ];
    ret = sem_deal_with_BOOL_FORMULA( pCurSynNode );
    if( 0 == ret ){
        return 0;
    }
    /* [ 4 ] make a sign at the end, if AX=0,jump to it */
    sprintf_s( str_second_sign, sizeof(str_first_sign), "SIGN_%d", g_SemEnv.n_SignCurrentId );
    g_SemEnv.n_SignCurrentId++;
    fprintf( g_SemEnv.pAsmFile, "CMP  AX,0\nJE %s\n",  str_second_sign );
    /* [ 5 ] store the second Assign Statement node */
    CHECK_SYN_NODE_ID( pCurSynNode->n_right_brother_id )
    pCurSynNode = &g_SynTree.pSynNodeList[ pCurSynNode->n_right_brother_id ];
    pSecondAssign = pCurSynNode;
    /* [ 6 ] deal with STATEMENT_LIST */
    CHECK_SYN_NODE_ID( pCurSynNode->n_right_brother_id )
    pCurSynNode = &g_SynTree.pSynNodeList[ pCurSynNode->n_right_brother_id ];
    ret = sem_deal_with_STATEMENT_LIST( pCurSynNode );
    if( 0 == ret ){
        return 0;
    }
    /* [ 7 ] deal with the second Assign Statement */
    if( SYN_NODE_ASSIGN_STMT == pSecondAssign->n_mode ){
        ret = sem_deal_with_ASSIGN_STMT( pSecondAssign );
        if( 0 == ret ){
            return 0;
        }
    }
    /* [ 8 ] jump to first sign */
    fprintf( g_SemEnv.pAsmFile, "JMP %s\n",  str_first_sign );
    /* [ 9 ] store to second sign */
    fprintf( g_SemEnv.pAsmFile, "%s:\n",  str_second_sign );

    return 1;
}
int sem_deal_with_WHILE_STMT(SynNode_P pSynNode){
    SynNode_P pCurSynNode = NULL;
    int ret = 0;
    char str_first_sign[20];
    char str_second_sign[20];
    /* [ 1 ] make a sign before BOOL_FORMULA */
    sprintf_s( str_first_sign, sizeof(str_first_sign), "SIGN_%d", g_SemEnv.n_SignCurrentId );
    g_SemEnv.n_SignCurrentId++;
    fprintf( g_SemEnv.pAsmFile, "%s:\n",  str_first_sign );
    /* [ 2 ] deal with BOOL_FORMULA */
    CHECK_SYN_NODE_ID( pSynNode->n_son_id )
    pCurSynNode = &g_SynTree.pSynNodeList[ pSynNode->n_son_id ];
    ret = sem_deal_with_BOOL_FORMULA( pCurSynNode );
    if( 0 == ret ){
        return 0;
    }
    /* [ 3 ] make a sign at the end, if AX=0,jump to it */
    sprintf_s( str_second_sign, sizeof(str_first_sign), "SIGN_%d", g_SemEnv.n_SignCurrentId );
    g_SemEnv.n_SignCurrentId++;
    fprintf( g_SemEnv.pAsmFile, "CMP  AX,0\nJE %s\n",  str_second_sign );
    /* [ 4 ] deal with STATEMENT_LIST */
    CHECK_SYN_NODE_ID( pCurSynNode->n_right_brother_id )
    pCurSynNode = &g_SynTree.pSynNodeList[ pCurSynNode->n_right_brother_id ];
    ret = sem_deal_with_STATEMENT_LIST( pCurSynNode );
    if( 0 == ret ){
        return 0;
    }
    /* [ 5 ] jump to first sign */
    fprintf( g_SemEnv.pAsmFile, "JMP %s\n",  str_first_sign );
    /* [ 6 ] store to second sign */
    fprintf( g_SemEnv.pAsmFile, "%s:\n",  str_second_sign );

    return 1;
}
int sem_deal_with_FUNC_CALL(SynNode_P pSynNode){
    SynNode_P pCurSynNode = NULL;
    IdentId_P pId = NULL;

    CHECK_SYN_NODE_ID( pSynNode->n_son_id )
    pCurSynNode = &g_SynTree.pSynNodeList[ pSynNode->n_son_id ];
    CHECK_SYN_NODE_ID( pCurSynNode->n_identifier_id )
    pId = &g_IdTable.pIdList[ pCurSynNode->n_identifier_id ];
    fprintf( g_SemEnv.pAsmFile, "CALL  %s\n", pId->str_name );

    return 1;
}
int sem_deal_with_FORMULA(SynNode_P pSynNode){
    char * func_name="sem_deal_with_FORMULA";
    SynNode_P pCurSynNode = NULL;
    IdentId_P pId = NULL;
    int ret = 0;
    unsigned int n_CurrentNodeId = 0;
    SEM_STACK_NODE sem_node;
    SEM_STACK_NODE op_node;
    n_CurrentNodeId = pSynNode->n_son_id;
    while( 1 ){
        /* [ 1 ] check the first Node of the Formula */
        CHECK_SYN_NODE_ID( n_CurrentNodeId )
        pCurSynNode = &g_SynTree.pSynNodeList[ n_CurrentNodeId ];
        /* [ 1.1 ] deal with '(' FORMULA ')' */
        if( SYN_NODE_L_parenthesis == pCurSynNode->n_mode ){
            /* [ 1.1.1 ] push '(' into Stack */
            sem_node.n_mode = 7;
            sem_node.n_value = SYN_NODE_L_parenthesis;
            MY_PUSH( &sem_node );
            /* [ 1.1.2 ] deal with FORMULA recursively */
            CHECK_SYN_NODE_ID( pCurSynNode->n_right_brother_id )
            pCurSynNode = &g_SynTree.pSynNodeList[ pCurSynNode->n_right_brother_id ];
            ret = sem_deal_with_FORMULA( pCurSynNode );
            if( 0 == ret ){
                return 0;
            }
            /* [ 1.1.3 ] deal with ')' */
            CHECK_SYN_NODE_ID( pCurSynNode->n_right_brother_id )
            pCurSynNode = &g_SynTree.pSynNodeList[ pCurSynNode->n_right_brother_id ];
            if( SYN_NODE_R_parenthesis != pCurSynNode->n_mode ){
                report_internal_error( func_name, __LINE__ );
                printf("Missing ')' in FORMULA .\n" );
                return 0;
            }
            /* [ 1.1.4 ] caculate current formula between '(' and ')' */
            op_node.n_mode = 0;
            op_node.n_value = SYN_NODE_R_parenthesis;
            ret = check_caculate( &op_node );
            if( 0 == ret ){
                return 0;
            }
        } else if( SYN_NODE_VARID == pCurSynNode->n_mode ){
        /* [ 1.2 ] deal with identifier */
            /* [ 1.2.1 ] make a sem node for the identifier */
            sem_node.n_mode = 0xffff;
            MY_PUSH( &sem_node );
            /* [ 1.2.2 ] make ASM code for the identifier */
            CHECK_SYN_NODE_ID( pCurSynNode->n_identifier_id )
            pId = &g_IdTable.pIdList[ pCurSynNode->n_identifier_id ];
            fprintf( g_SemEnv.pAsmFile, "MOV AX, %s\n", pId->str_name );
            fprintf( g_SemEnv.pAsmFile, "PUSH AX\n" );
        } else {
        /* [ 1.3 ] deal with number */
            /* [ 1.3.1 ] make a sem node for the number */
            sem_node.n_mode = 0xffff;
            MY_PUSH( &sem_node );
            /* [ 1.3.2 ] make ASM code for the number */
            fprintf( g_SemEnv.pAsmFile, "MOV AX, %d\n", pCurSynNode->n_int_value );
            fprintf( g_SemEnv.pAsmFile, "PUSH AX\n" );
        }
        /* [ 2 ]  deal with FORMULA_FOLLOW */
        CHECK_SYN_NODE_ID( pCurSynNode->n_right_brother_id )
        pCurSynNode = &g_SynTree.pSynNodeList[ pCurSynNode->n_right_brother_id ];
        if( INVALID_ID == pCurSynNode->n_son_id ){
            /*=================================================================
            Empty FORMULA_FOLLOW.Clear the stack and finish the caculating 
            =================================================================*/
            while( 1 ){
                MY_POP( &sem_node );
                if( 0 == g_SemEnv.s_sem_stack.n_num ){
                    /* This node is the only node in the stack , finished. */
                    fprintf( g_SemEnv.pAsmFile, "POP AX\n" );
                    return 1;
                }
                MY_POP( &op_node );
                if( 7 == op_node.n_mode ){/* Reach the Beginning of a FOMULA */
                    MY_PUSH( &op_node );
                    MY_PUSH( &sem_node );
                    return 1;
                } else{
                    MY_POP( &sem_node );
                    ret = caculate_AX_BX_by_op( &op_node );
                }
                /* Push the result */
                MY_PUSH( &sem_node );
                if( 0 == ret ){
                    return 0;
                }
                if( 0 == g_SemEnv.s_sem_stack.n_num ){
                    /* This node is the only node in the stack , finished. */
                    fprintf( g_SemEnv.pAsmFile, "POP AX\n" );
                    return 1;
                }
            }
        } else{
            /* [ 2.1 ] deal with operator */
            pCurSynNode = &g_SynTree.pSynNodeList[ pCurSynNode->n_son_id ];
            switch( pCurSynNode->n_mode ){
                case SYN_NODE_ADD:
                case SYN_NODE_SUB:
                    op_node.n_mode = 5;
                    break;
                case SYN_NODE_MUT:
                case SYN_NODE_DIV:
                    op_node.n_mode = 6;
                    break;
                case SYN_NODE_AND:
                    op_node.n_mode = 2;
                    break;
                case SYN_NODE_OR:
                    op_node.n_mode = 1;
                    break;
                case SYN_NODE_LESS:
                case SYN_NODE_MORE:
                case SYN_NODE_NOT_LESS:
                case SYN_NODE_NOT_MORE:
                    op_node.n_mode = 4;
                    break;
                case SYN_NODE_EQ:
                case SYN_NODE_NOT_EQ:
                    op_node.n_mode = 3;
                    break;
                default:
                    printf("Internal error! invalid operator mode '%d' at line '%d'\n", pCurSynNode->n_mode, __LINE__ );
                    return 0;
            }
            op_node.n_value = pCurSynNode->n_mode;
            ret = check_caculate( &op_node );
            if( 0 == ret ){
                return 0;
            }
            /* [ 2.2 ] deal with FORMULA using the while-looping */
            CHECK_SYN_NODE_ID( pCurSynNode->n_right_brother_id )
            pCurSynNode = &g_SynTree.pSynNodeList[ pCurSynNode->n_right_brother_id ];
            n_CurrentNodeId = pCurSynNode->n_son_id;
        }
    }

    return 1;
}
int sem_deal_with_BOOL_FORMULA(SynNode_P pSynNode){
    if( sem_deal_with_FORMULA( pSynNode ) == 0 ){
        return 0;
    }
    return 1;
}
static int push( SEM_STACK_NODE *in_node ){
    unsigned int num = 0;
    num = g_SemEnv.s_sem_stack.n_num;
    if( num >= MAX_STACK_NUM ){
        printf("Internal Error ! semantic stack overflow!\n");
        return 0;
    }
    memcpy( &g_SemEnv.s_sem_stack.sem_node_list[ num ], in_node, sizeof( SEM_STACK_NODE ) );
    g_SemEnv.s_sem_stack.n_num++;
    return 1;
}
static int pop( SEM_STACK_NODE *out_node ){
    unsigned int index = 0;
    index = g_SemEnv.s_sem_stack.n_num;
    index--;
    if( index >= MAX_STACK_NUM ){
        printf("Internal Error ! semantic stack empty!\n");
        return 0;
    }
    memcpy( out_node, &g_SemEnv.s_sem_stack.sem_node_list[ index ], sizeof( SEM_STACK_NODE ) );
    g_SemEnv.s_sem_stack.n_num--;
    return 1;
}
static int check_caculate( SEM_STACK_NODE *cur_node ){
    unsigned int num = 0;
    unsigned short cur_mode = cur_node->n_mode;
    unsigned short last_mode = 0;
    SEM_STACK_NODE sem_node;
    SEM_STACK_NODE op_node;
    num = g_SemEnv.s_sem_stack.n_num;
    if( 0 == cur_mode ){
        /* [ 1 ] deal with ')' */
        /* [ 1.1 ] pop the first node on top of the stack */
        MY_POP( &sem_node );
        if( 0xffff != sem_node.n_mode ){
            printf("Internal Error ! Missing number between '(' and ')' in FORMULA .\n" );
            return 0;
        }
        /* [ 1.2 ] pop the next node on top of the stack */
        MY_POP( &op_node );
        if( 7 == op_node.n_mode ){/* '(' */
            /* push the result of FORMULA between '(' and ')' */
            MY_PUSH( &sem_node );
        } else{/* operator */
            /* [ 1.2 ] pop the second number on top of the stack */
            MY_POP( &sem_node );
            /* [ 1.3 ] caculate current formula between '(' and ')' */
            if( 0 == caculate_AX_BX_by_op( &op_node ) ){
                return 0;
            }
            /* [ 1.4 ] pop the '(' */
            MY_POP( &op_node );
            /* [ 1.5 ] push the result of FORMULA between '(' and ')' */
            MY_PUSH( &sem_node );
        }
    } else{
        /* [ 2 ] deal with other operators */
        if( num >= 2 && num <= MAX_STACK_NUM ){
            last_mode = g_SemEnv.s_sem_stack.sem_node_list[ num-2 ].n_mode;
        }
        if( cur_mode <= last_mode && last_mode != 7 ){/* '(' can't caculate without ')' */
            MY_POP( &sem_node );
            MY_POP( &op_node );
            MY_POP( &sem_node );
            if( 0 == caculate_AX_BX_by_op( &op_node ) ){
                return 0;
            }
            MY_PUSH( &sem_node );
        } else{
            /* do nothing */
        }
        MY_PUSH( cur_node );
    }
    return 1;
}
static int caculate_AX_BX_by_op( SEM_STACK_NODE *op_node ){
    char * func_name = "caculate_AX_BX_by_op";
    char str_first_sign[20];
    char str_second_sign[20];
    /* [ 1 ] pop BX */
    fprintf( g_SemEnv.pAsmFile, "POP  BX\n" );
    /* [ 2 ] pop AX */
    fprintf( g_SemEnv.pAsmFile, "POP  AX\n" );
    /* [ 3 ] caculate */
    switch( op_node->n_mode ){
        case 1: /* || */
            fprintf( g_SemEnv.pAsmFile, "OR AX, BX\n" );
            break;
        case 2: /* && */
            fprintf( g_SemEnv.pAsmFile, "AND AX, BX\n" );
            break;
        case 3:
            if( SYN_NODE_EQ == op_node->n_value ){ /* == */
                fprintf( g_SemEnv.pAsmFile, ";Deal with '=='\n" );
                sprintf_s( str_first_sign, sizeof(str_first_sign), "SIGN_%d", g_SemEnv.n_SignCurrentId );
                g_SemEnv.n_SignCurrentId++;
                sprintf_s( str_second_sign, sizeof(str_second_sign), "SIGN_%d", g_SemEnv.n_SignCurrentId );
                g_SemEnv.n_SignCurrentId++;
                fprintf( g_SemEnv.pAsmFile, "CMP AX, BX\n" );
                fprintf( g_SemEnv.pAsmFile, "JNE %s\n",  str_first_sign );
                fprintf( g_SemEnv.pAsmFile, "MOV AX, 1\n" );
                fprintf( g_SemEnv.pAsmFile, "JMP %s\n", str_second_sign );
                fprintf( g_SemEnv.pAsmFile, "%s:\n",  str_first_sign );
                fprintf( g_SemEnv.pAsmFile, "MOV AX, 0\n" );
                fprintf( g_SemEnv.pAsmFile, "%s:\n",  str_second_sign );
            } else{ /* != */
                fprintf( g_SemEnv.pAsmFile, "XOR AX, BX\n" );
            }
            break;
        case 4:
            if( SYN_NODE_MORE == op_node->n_value ){ /* > */
                fprintf( g_SemEnv.pAsmFile, "SUB BX, AX\n" );
                fprintf( g_SemEnv.pAsmFile, "AND BX, 8000H\n" );
                fprintf( g_SemEnv.pAsmFile, "MOV AX, BX\n" );
            } else if( SYN_NODE_LESS == op_node->n_value ){ /* < */
                fprintf( g_SemEnv.pAsmFile, "SUB AX, BX\n" );
                fprintf( g_SemEnv.pAsmFile, "AND AX, 8000H\n" );
            } else if( SYN_NODE_NOT_LESS == op_node->n_value ){ /* >= */
                fprintf( g_SemEnv.pAsmFile, "SUB AX, BX\n" );
                fprintf( g_SemEnv.pAsmFile, "AND AX, 8000H\n" );
                fprintf( g_SemEnv.pAsmFile, "XOR AX, 8000H\n" );
            } else{ /* <= */
                fprintf( g_SemEnv.pAsmFile, "SUB BX, AX\n" );
                fprintf( g_SemEnv.pAsmFile, "AND BX, 8000H\n" );
                fprintf( g_SemEnv.pAsmFile, "XOR BX, 8000H\n" );
                fprintf( g_SemEnv.pAsmFile, "MOV AX, BX\n" );
            }
            break;
        case 5:
            if( SYN_NODE_ADD == op_node->n_value ){ /* + */
                fprintf( g_SemEnv.pAsmFile, "ADD AX, BX\n" );
            } else{ /* - */
                fprintf( g_SemEnv.pAsmFile, "SUB AX, BX\n" );
            }
            break;
        case 6:
            if( SYN_NODE_MUT == op_node->n_value ){ /* * */
                fprintf( g_SemEnv.pAsmFile, "MUL BX\n" );
            } else{ /* / */
                fprintf( g_SemEnv.pAsmFile, "MOV DX, 0\n" );
                fprintf( g_SemEnv.pAsmFile, "DIV BX\n" );
            }
            break;
        default:
            report_internal_error( func_name, __LINE__ );
            printf("Invalid operator mode '%d'\n", op_node->n_mode );
            return 0;
    }
    /* [ 4 ] push AX */
    fprintf( g_SemEnv.pAsmFile, "PUSH  AX\n" );

    return 1;
}
void debug_sem( ){
    unsigned int i = 0;
    IdentId_P pId = NULL;
    for( i = 0; i < g_IdTable.n_id_num; i++ ){
        pId = &g_IdTable.pIdList[ i ];
        if( SYN_NODE_VARID == pId->n_mode ){
            fprintf( g_SemEnv.pAsmFile, "LEA  AX, Name_%s\nMOV  DX, AX\nMOV  AH, 9\nINT  21H\n", pId->str_name );
            fprintf( g_SemEnv.pAsmFile, "MOV  AX, %s\nPRINTVAL  AX\n", pId->str_name );
            fprintf( g_SemEnv.pAsmFile, ASM_CHANGE_LINE );
        }
    }
}


主函数

/** SimpleCompiler.c
====================================================================
This is the base source file for Main Function


====================================================================
 */

#include "scmppre.h"
#include "scmpstx.h"
#include "scmpsem.h"
int main(int arg_num, char ** args){
    int ret = 0;
    FILE *srcFP = NULL;
    FILE *outFP = NULL;
    char *inputFile = "test.c";
    char *outputFile = "test.c.tmp";
    FileField srcFileField;
#ifdef DEBUG_SYNTAX
    char *debugFile = "test.c.stx";
    FILE * debugfp = NULL;
#endif
    /* Global initializing */
    ret = initialize_IdTable();
    ret &= initialize_SynTree();
    if( 0 == ret ){
        printf("Program exit with initializing error.\n");
        return 0;
    }
    fopen_s( &srcFP, inputFile , "r" );
    if( NULL == srcFP ){
        printf("Can't open source file '%s'. Program exit.\n", inputFile );
        return 0;
    }
    fopen_s( &outFP, outputFile, "w" );
    if( NULL == outFP ){
        printf("Can't open temp file '%s'. Program exit.\n", outputFile );
        return 0;
    }
    /** pre-compiler **/
    ret = pre_compiler(srcFP, outFP);
    if( 0 == ret ){
        printf("Program exit with pre-compiler error.\n");
        goto ERROR_END;
    }
    MY_HELP_CLOSE( outFP );
    MY_HELP_CLOSE( srcFP );
    /** Syntax analyzing **/
    /* using the temp file as the source */
    fopen_s( &srcFP, outputFile, "r" );
    if( NULL == srcFP ){
        printf("Can't open temp file '%s'. Program exit.\n", outputFile );
        goto ERROR_END;
    }
    srcFileField.fp = srcFP;
    srcFileField.n_current_line = 1;
    ret = syntax_analyzer( &srcFileField );
    if( 0 == ret ){
        printf("Program exit with syntax_analyzer error.\n");
        goto ERROR_END;
    }
#ifdef DEBUG_SYNTAX
    fopen_s(&debugfp, debugFile, "w");
    if( NULL != debugfp ){
        debug_syntax( debugfp );
        fclose( debugfp );
    }
#endif
    /** semantic_analyzer **/
    ret = semantic_analyzer();
    if( 0 == ret ){
        printf("Program exit with semantic_analyzer error.\n");
        goto ERROR_END;
    }

    MY_HELP_CLOSE( outFP );
    MY_HELP_CLOSE( srcFP );
    release_IdTable();
    release_SynTree();
    return 1;
ERROR_END:
    MY_HELP_CLOSE( outFP );
    MY_HELP_CLOSE( srcFP );
    release_IdTable();
    release_SynTree();
    return 0;
}


语法分析头文件

 

/** scmppre.h
====================================================================
This is the base head file for pre-compiler


====================================================================
 */
#ifndef SCMPPRE_H_INCLUDE
#define SCMPPRE_H_INCLUDE

#ifndef STD_COMMON_H_INCLUDE
#define STD_COMMON_H_INCLUDE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#endif


#define MAX_SRC_LINE      1024           /* the max byte number of one line in the source file */

int pre_compiler(FILE * fpInput, FILE * fpOutput);



#endif


语法分析头文件:

/** scmpstx.h
====================================================================
This is the base head file for Syntax Analyze


====================================================================
 */
#ifndef SCMPSTX_H_INCLUDE
#define SCMPSTX_H_INCLUDE


#ifndef STD_COMMON_H_INCLUDE
#define STD_COMMON_H_INCLUDE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#endif

#define MAX_SYN_NODE_NUM  32768          /* the max syntax node number */
#define MAX_ID_LENGTH     32             /* the max length of indentifier */
/* The identifier id */
typedef struct tag_identifier_id{
    short n_mode;                        /* the mode : SYN_NODE_TAIL / SYN_NODE_VARID / SYN_NODE_FUNID */
    short dummy;                         /* not used */
    int n_next_identifier_id;            /* the next identifier in current second-level list */
    char str_name[ MAX_ID_LENGTH+1 ];
}IdentId;
typedef IdentId * IdentId_P;
/* The identifier table */
typedef struct tag_id_table{
    unsigned int n_id_num;               /*============================================================
                                         The number of identifiers in the table.
                                         It's also the first free place for store a new identifier.
                                         Using n_id_num,  pIdList acts as a stack, and n_id_num is
                                         it's stack top.
                                         If n_id_num >= MAX_SYN_NODE_NUM, the stack is full.
                                         ============================================================*/
    IdentId_P pIdList;                   /*============================================================
                                         the head pointer of the identifier list.
                                         malloc MAX_SYN_NODE_NUM IdentId.
                                         ============================================================*/
    unsigned int two_level_index[52][62];        /*============================================================
                                         First index: using the first byte of the name
                                             'A' to 'Z' = 0 to 25
                                             'a' to 'z' = 26 to 51
                                         Second index: using the second byte of the name
                                             'A' to 'Z' = 0 to 25
                                             'a' to 'z' = 26 to 51
                                             '0' to '9' = 52 to 61
                                         Default value: two_level_index[i][j] = -1;
                                         if two_level_index[i][j] is not -1, it shows this second-level
                                         list in the pIdList is started at pIdList[two_level_index[i][j]]
                                         ============================================================*/            
}IdTable;
IdTable g_IdTable;                       /* the identifier table */
/* The node for syntax tree */
typedef struct tag_SyntaxNode{
    short n_mode;                        /* the mode of SyntaxNode */
    unsigned int n_identifier_id;        /*============================================================
                                         The index in the Id Table for this identifier.
                                         If it's not identifier, n_identifier_id = INVALID_ID;
                                         ============================================================*/
    unsigned int n_left_brother_id;      /*============================================================
                                         The index of the left brother in the syntax tree.
                                         If it's the first son of its father, n_left_brother_id = INVALID_ID;
                                         ============================================================*/
    unsigned int n_right_brother_id;     /*============================================================
                                         The index of the right brother in the syntax tree.
                                         If it's the last son of its father, n_right_brother_id = INVALID_ID;
                                         ============================================================*/
    unsigned int n_father_id;            /*============================================================
                                         The index of the father in the syntax tree.
                                         If it's the root, n_father_id = INVALID_ID;
                                         ============================================================*/
    unsigned int n_son_id;               /*============================================================
                                         The index of the son in the syntax tree.
                                         If it has no son, n_son_id = INVALID_ID;
                                         ============================================================*/
    int n_int_value;                       /* the value of integer */
}SynNode;
typedef SynNode * SynNode_P;
typedef struct tat_SyntaxTree{
    unsigned int n_node_num;             /*============================================================
                                         The number of SynNode in the SyntaxTree.
                                         It's also the first free place for store a new SynNode.
                                         Using n_node_num,  pSynNodeList acts as a stack, and n_node_num is
                                         it's stack top.
                                         If n_node_num >= MAX_SYN_NODE_NUM, the stack is full.
                                         ============================================================*/
    SynNode_P pSynNodeList;              /*============================================================
                                         the head pointer of the syntax tree node list.
                                         malloc MAX_SYN_NODE_NUM SynNode.
                                         ============================================================*/
}SynTree;
SynTree g_SynTree;                       /* the syntax tree */
/* Syntax Node mode definitions */
#define SYN_NODE_TAIL                 0          /* the tail node */
#define SYN_NODE_HEAD                 1          /* the head node */
#define SYN_NODE_VARID                2          /* the identifier of variabale */
#define SYN_NODE_FUNID                3          /* the identifier of function */
#define SYN_NODE_MAINFUNID            4          /* the identifier of main function */
#define SYN_NODE_BODY                 11         /* the BODY of a function */
#define SYN_NODE_DEFINITION           12         /* DEFINITION */
#define SYN_NODE_VAR_DEF              13         /* VAR_DEF */
#define SYN_NODE_FUNC_DEF             14         /* FUNC_DEF */
#define SYN_NODE_VAR_DEFINITION       15         /* VAR_DEFINITION */
#define SYN_NODE_STATEMENT_LIST       16         /* STATEMENT_LIST */
#define SYN_NODE_ASSIGN_STMT          17         /* ASSIGN_STMT */
#define SYN_NODE_IF_STMT              18         /* IF_STMT */
#define SYN_NODE_FOR_STMT             19         /* FOR_STMT */
#define SYN_NODE_WHILE_STMT           20         /* WHILE_STMT */
#define SYN_NODE_FORMULA              21         /* FORMULA */
#define SYN_NODE_BOOL_FORMULA         22         /* BOOL_FORMULA */
#define SYN_NODE_FORMULA_FOLLOW       23         /* FORMULA_FOLLOW */
#define SYN_NODE_NUMBER               24         /* numbers */
#define SYN_NODE_L_parenthesis        25         /* '(' */
#define SYN_NODE_R_parenthesis        26         /* ')' */
#define SYN_NODE_ADD                  27         /* '+' */
#define SYN_NODE_SUB                  28         /* '-' */
#define SYN_NODE_MUT                  29         /* '*' */
#define SYN_NODE_DIV                  30         /* '/' */
#define SYN_NODE_AND                  31         /* '&&' */
#define SYN_NODE_OR                   32         /* '||' */
#define SYN_NODE_LESS                 33         /* '<' */
#define SYN_NODE_MORE                 34         /* '>' */
#define SYN_NODE_EQ                   35         /* '==' */
#define SYN_NODE_NOT_LESS             36         /* '>=' */
#define SYN_NODE_NOT_MORE             37         /* '<=' */
#define SYN_NODE_NOT_EQ               38         /* '!=' */
#define SYN_NODE_BOOL_FORMULA_FOLLOW  39         /* BOOL_FORMULA_FOLLOW */
#define SYN_NODE_FUNC_CALL            40         /* FUNC_CALL */
#define SYN_NODE_EMPTY               100         /* An empty node */

#define SHORT_MAX                    32767       /* MAX VALUE OF SHORT */
#define SHORT_MIN                    -32768      /* MIN VALUE OF SHORT */

#define INVALID_ID            (unsigned int)0xFFFFFFFF         /* the invalid index */

typedef struct tag_fileField{
    FILE * fp;                                   /* the pointer to the source file */
    int n_current_line;                          /* the current line number */
    char current_ch;                             /* the current char */
    char name_buf[MAX_ID_LENGTH+1];              /* the buffer for an identifier name */
}FileField;

#define KEY_WORD_NO                   0          /* Not a key word */
#define KEY_WORD_MAIN                 1          /* 'main' */
#define KEY_WORD_INT                  2          /* 'int' */
#define KEY_WORD_IF                   3          /* 'if' */
#define KEY_WORD_WHILE                4          /* 'while' */
#define KEY_WORD_FOR                  5          /* 'for' */

#define CHECK_KEY_WORD( buffer, type ) \
    { \
        if( 0 == strcmp( buffer, "main" ) ){\
            type = KEY_WORD_MAIN;\
        } else if( 0 == strcmp( buffer, "int" ) ){\
            type = KEY_WORD_INT;\
        } else if( 0 == strcmp( buffer, "if" ) ){\
            type = KEY_WORD_IF;\
        } else if( 0 == strcmp( buffer, "while") ){\
            type = KEY_WORD_WHILE;\
        } else if( 0 == strcmp( buffer, "for") ){\
            type = KEY_WORD_FOR;\
        } else{\
            type = KEY_WORD_NO;\
        }\
    }
#define MY_HELP_FREE( pValue )  \
    if( NULL != pValue ){\
        free(pValue);\
        pValue = NULL;\
    }
#define MY_HELP_CLOSE( pFILE )  \
    if( NULL != pFILE ){\
        fclose(pFILE);\
        pFILE = NULL;\
    }
#define CHECK_NEW_LINE( fileField ) \
    if( '\n' == fileField->current_ch ){\
        fileField->n_current_line++;\
    }
#define JUMP_SPACES( fileField ) \
    {\
        while( isspace( fileField->current_ch ) ){\
            fileField->current_ch = fgetc( fileField->fp );\
            CHECK_NEW_LINE( fileField )\
        }\
    }
#define GET_IDENTIFY( fileField, buffer, length )\
    {\
        length = 0;\
        JUMP_SPACES( fileField );\
        if( !isalpha(fileField->current_ch) ){/* the fisrt char must be alphabet */\
            buffer[0] = '\0';\
            length = 0;\
        } else{\
            buffer[0] = fileField->current_ch;\
            length = 1;\
            while( 1 ){\
                fileField->current_ch = fgetc( fileField->fp );\
                CHECK_NEW_LINE( fileField )\
                if( isalnum( fileField->current_ch ) ){\
                    buffer[length] = fileField->current_ch;\
                    length++;\
                    if( length > MAX_ID_LENGTH ){/* too logn identifier */\
                        buffer[0] = '\0';\
                        length = 0;\
                        break;\
                    }\
                } else{\
                    buffer[length] = '\0';\
                    break;\
                }\
            }\
        }\
    }
#define GET_NEW_CHAR_JUMP_SPACE( fileField ) \
    {\
        fileField->current_ch = fgetc( fileField->fp );\
        CHECK_NEW_LINE( fileField )\
        JUMP_SPACES( fileField )\
    }
#define CHECK_NODE_NUM( function, fileField, num ) \
    {\
        if( num > MAX_SYN_NODE_NUM ){\
            report_syntax_error( function, "Too many syntax nodes.", fileField->n_current_line );\
            return 0;\
        }\
    }
#define FIX_FATHER_LBROTHER( father_ID, left_brother_ID, current_ID ) \
    {\
        if( father_ID != INVALID_ID ){\
            if( INVALID_ID == g_SynTree.pSynNodeList[father_ID].n_son_id ){\
                g_SynTree.pSynNodeList[father_ID].n_son_id = current_ID;\
            }\
        }\
        if( left_brother_ID != INVALID_ID ){\
            if( INVALID_ID == g_SynTree.pSynNodeList[left_brother_ID].n_right_brother_id ){\
                g_SynTree.pSynNodeList[left_brother_ID].n_right_brother_id = current_ID;\
            }\
        }\
    }
int syntax_analyzer(FileField *fileField);
int initialize_IdTable();
int initialize_SynTree();
int release_IdTable();
int release_SynTree();
void report_syntax_error(char *func_name, char *detail, int line_number);
void report_memery_error(char *func_name, int line_number);
void report_internal_error(char *func_name, int line_number);
int add_to_IdTable(FileField * fileField, char *id_name, int length, short mode, unsigned int * p_ident_index);
int find_in_IdTable(FileField * fileField, char *id_name, int length, unsigned int * p_ident_index);
int get_number( FileField * fileField, int * pOutValue);
void debug_syntax( FILE* fp );

#endif


语义分析头文件:

 
 

/** scmpsem.h
====================================================================
This is the base head file for Semantic Analyze


====================================================================
 */
#ifndef SCMPSEM_H_INCLUDE
#define SCMPSEM_H_INCLUDE

#include "scmpstx.h"

#ifndef LINUX
/* For Windows only */
/* define the header of the MASM source file */
#define ASM_HEADER ".MODEL SMALL\n.STACK 4096h\nINCLUDE PrintVal.mac\n"
#define ASM_DATA_HEADER ".DATA\nASM_CHAGNE_LINE  DB  0DH,0AH,'$'\n"
/* the definition of varibale e.g. sprintf(buffer, MASM_VAR_DEF, "VAR1", "VAR1", "VAR1") */
#define ASM_VAR_DEF "%s  DW  0\nName_%s  DB '%s',20H,20H,'$'\n"
#define ASM_CODE_HEADER ".CODE\nCALL Main\n"
#define ASM_END_MAIN "END Main\n"
#define ASM_FILE_NAME "MyResult.asm"
#define ASM_CHANGE_LINE "LEA  AX, ASM_CHAGNE_LINE\nMOV  DX, AX\nMOV  AH, 9\nINT  21H\n"

#else
/* For Linux only */
#endif

#define MAX_STACK_NUM 32768               /* the max node number of sem_stack */
typedef struct tag_SEM_STACK_NODE{
    unsigned short n_mode;                /*====================================
                                          Type of the node
                                          0 ==> )
                                          1 ==> ||
                                          2 ==> &&
                                          3 ==> ==   !=
                                          4 ==> >   >=   <   <=
                                          5 ==> +  -
                                          6 ==> *  /
                                          7 ==> (
                                          0xffff ==> number
                                          =====================================*/
    short n_value;                        /*=====================================
                                          The value of the node,using definition
                                          in the scmpstx.h.
                                          e.g.
                                          SYN_NODE_NUMBER   24   numbers
                                          SYN_NODE_EQ       35   '=='
                                          =====================================*/
}SEM_STACK_NODE;
typedef struct tag_SEM_STACK{
    unsigned int n_num;
    SEM_STACK_NODE * sem_node_list;
}SEM_STACK;
typedef struct tag_SemEnv{
    unsigned int n_SignCurrentId;         /* the id of current sign */
    FILE * pAsmFile;                      /* the pointer to the output ASM file */
    SEM_STACK s_sem_stack;                /* the stack for semantic analyze */
}SemEnv;
SemEnv g_SemEnv;/* the semantic analyser environment */

int initialize_SemEnv();
int finalize_SemEnv();
int semantic_analyzer();
void debug_sem( );


#define CHECK_SYN_NODE_ID(id)  \
    if( INVALID_ID == (id) ){\
          printf("Internal Error ! Invalid syntax node id at line '%d'.\n", __LINE__);\
          return 0;\
    }
         

#endif


 


'; fputs(str_line_buffer, fpOutput); index = 0; return 1; } else if( '\n' == current_char ){ str_line_buffer[index] = current_char; index++; CHECK_INDEX( index ) str_line_buffer[index] = '
预处理器:
/** scmppre.c
====================================================================
This is the base source file for pre-compiler


====================================================================
 */

#include "scmppre.h"


static int report_pre_error(char *msg, int code){
    printf("Error : %s\nCode : %d\n", msg, code);
    return 0;
}

#define CHECK_INDEX( index )    \
    if( index >= MAX_SRC_LINE ){\
        report_pre_error("Too long line.", index);\
        return 0;\
    }
/*=======================================================
The main function of pre-compiler.
return     1 : success
           0 : fail
========================================================*/
int pre_compiler(FILE * fpInput, FILE * fpOutput){
    char str_line_buffer[MAX_SRC_LINE + 1];
    int index = 0;
    char current_char;
    current_char = fgetc(fpInput);
    while( current_char != EOF ){
        /*========================================================
        search the '//' . if exists, jump the rest of the line.
        ========================================================*/
        if( '/' == current_char ){
            current_char = fgetc(fpInput);
            if( '/' == current_char ){
                while( current_char != EOF ){
                    current_char =  fgetc(fpInput);
                    if( '\n' == current_char ){
                        /* end of a line */
                        str_line_buffer[index] = '\n';
                        index++;
                        CHECK_INDEX( index )
                        break;/* stop loop */
                    }
                }
                /* output a line */
                str_line_buffer[index] = '\0';
                fputs(str_line_buffer, fpOutput);
                index = 0;
            } else{
                /* a single '/', just store it and its following byte */
                str_line_buffer[index] = '/';
                index++;
                CHECK_INDEX( index )
                if( EOF == current_char ){ /* end of file */
                    str_line_buffer[index] = '\0';
                    fputs(str_line_buffer, fpOutput);
                    index = 0;
                    return 1;
                } else if( '\n' == current_char ){
                    str_line_buffer[index] = current_char;
                    index++;
                    CHECK_INDEX( index )
                    str_line_buffer[index] = '\0';
                    fputs(str_line_buffer, fpOutput);
                    index = 0;
                } else{
                    str_line_buffer[index] = current_char;
                    index++;
                    CHECK_INDEX( index )
                }
            }
        } else if( '\n' == current_char ){
            str_line_buffer[index] = current_char;
            index++;
            CHECK_INDEX( index )
            str_line_buffer[index] = '\0';
            fputs(str_line_buffer, fpOutput);
            index = 0;
        } else{
            str_line_buffer[index] = current_char;
            index++;
            CHECK_INDEX( index )
        }
        current_char = fgetc(fpInput);
    }

    str_line_buffer[index] = '\0';
    fputs(str_line_buffer, fpOutput);
    index = 0;

    return 1;
}


语法分析器

 

/** scmpstx.c
====================================================================
This is the base source file for Syntax Analyze


====================================================================
 */
#include "scmpstx.h"

int DEFINITION(FileField *fileField, int left_brother_ID, int father_ID);
int VAR_DEF(FileField *fileField, int left_brother_ID, int father_ID);
int FUNC_DEF(FileField *fileField, int left_brother_ID, int father_ID);
int IDENTIFY(FileField *fileField, int left_brother_ID, int father_ID);
int BODY(FileField *fileField, int left_brother_ID, int father_ID);
int VAR_DEFINITION(FileField *fileField, int left_brother_ID, int father_ID);
int STATEMENT_LIST(FileField *fileField, int left_brother_ID, int father_ID);
int ASSIGN_STMT(FileField *fileField, int left_brother_ID, int father_ID);
int IF_STMT(FileField *fileField, int left_brother_ID, int father_ID);
int FOR_STMT(FileField *fileField, int left_brother_ID, int father_ID);
int WHILE_STMT(FileField *fileField, int left_brother_ID, int father_ID);
int FORMULA(FileField *fileField, int left_brother_ID, int father_ID);
int BOOL_FORMULA(FileField *fileField, int left_brother_ID, int father_ID);
int FORMULA_FOLLOW(FileField *fileField, int left_brother_ID, int father_ID);
int BOOL_FORMULA_FOLLOW(FileField *fileField, int left_brother_ID, int father_ID);
int FUNC_CALL(FileField *fileField, int left_brother_ID, int father_ID);



void report_syntax_error(char *func_name, char *detail, int line_number){
    printf("Syntax error accured in function '%s()', at line '%d'.\nDetail: %s\n", func_name, line_number, detail);
    return;
}
void report_memery_error(char *func_name, int line_number){
    printf("Memery error accured in function '%s()', at line '%d'.\n", func_name, line_number);
    return;
}
void report_internal_error(char *func_name, int line_number){
    printf("Internal error accured in function '%s()', at line '%d'.\n", func_name, line_number);
    return;
}
int initialize_IdTable(){
    int i=0;
    int j=0;
    g_IdTable.n_id_num = 0;
    g_IdTable.pIdList = (IdentId_P)malloc( ( MAX_SYN_NODE_NUM + 1 ) * sizeof(IdentId) );
    if( NULL == g_IdTable.pIdList ){
        report_memery_error("initialize_IdTable", __LINE__);
        return 0;
    }
    for( i = 0; i < 51; i++ ){
        for( j = 0; j < 61; j++ ){
            g_IdTable.two_level_index[i][j] = INVALID_ID;
        }
    }
    return 1;
}
int initialize_SynTree(){
    g_SynTree.n_node_num = 0;
    g_SynTree.pSynNodeList = (SynNode_P)malloc( ( MAX_SYN_NODE_NUM + 1 ) * sizeof(SynNode) );
    if( NULL == g_SynTree.pSynNodeList ){
        report_memery_error("initialize_SynTree", __LINE__);
        return 0;
    }
    return 1;
}
int release_IdTable(){
    MY_HELP_FREE( g_IdTable.pIdList )
    g_IdTable.n_id_num = 0;
    return 1;
}
int release_SynTree(){
    MY_HELP_FREE( g_SynTree.pSynNodeList );
    g_SynTree.n_node_num = 0;
    return 1;
}

int syntax_analyzer(FileField *fileField){
    int ret = 0;
    char * func_name="syntax_analyzer";

    /** [ 1 ] initialize a node for whole program **/
    g_SynTree.n_node_num = 1;
    g_SynTree.pSynNodeList[0].n_father_id = INVALID_ID;
    g_SynTree.pSynNodeList[0].n_identifier_id = INVALID_ID;
    g_SynTree.pSynNodeList[0].n_left_brother_id = INVALID_ID;
    g_SynTree.pSynNodeList[0].n_mode = SYN_NODE_HEAD;
    g_SynTree.pSynNodeList[0].n_right_brother_id = INVALID_ID;
    g_SynTree.pSynNodeList[0].n_son_id = INVALID_ID;
    /** [ 2 ] deal with DEFINITION **/
    ret = DEFINITION( fileField, INVALID_ID, 0 );
    /** [ 3 ] deal with 'main' **/
    if( 0 == ret ){
        printf("Syntax_analyzer exit with syntax error.\n");
        return 0;
    } else{
        /* some definition finished, the node 'DEFINITION' is the left brother of 'main' */
        g_SynTree.n_node_num++;
        CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
        g_SynTree.pSynNodeList[g_SynTree.n_node_num-1].n_father_id = 0;/* the index of 'main' is g_SynTree.n_node_num-1 */
        g_SynTree.pSynNodeList[g_SynTree.n_node_num-1].n_identifier_id = INVALID_ID;
        g_SynTree.pSynNodeList[g_SynTree.n_node_num-1].n_left_brother_id = 1;/* the node 'DEFINITION' */
        g_SynTree.pSynNodeList[g_SynTree.n_node_num-1].n_mode = SYN_NODE_MAINFUNID;
        g_SynTree.pSynNodeList[g_SynTree.n_node_num-1].n_right_brother_id = INVALID_ID;
        g_SynTree.pSynNodeList[g_SynTree.n_node_num-1].n_son_id = INVALID_ID;
        g_SynTree.pSynNodeList[1].n_right_brother_id = g_SynTree.n_node_num-1;/* fix the right brother for node 'DEFINITION' */
    }
    /** [ 4 ] deal with '(' and ')' **/
    /* [ 4.1 ] jump the spaces after 'main' */
    JUMP_SPACES( fileField )
    /* [ 4.2 ] check '(' */
    if( '(' != fileField->current_ch ){
        report_syntax_error( "syntax_analyzer", "missing '('.", fileField->n_current_line );
        printf("Syntax_analyzer exit with syntax error.\n");
        return 0;
    }
    /* [ 4.3 ] jump the spaces after '(' */
    GET_NEW_CHAR_JUMP_SPACE( fileField )
    /* [ 4.4 ] check ')' */
    if( ')' != fileField->current_ch ){
        report_syntax_error( "syntax_analyzer", "missing ')'.", fileField->n_current_line );
        printf("Syntax_analyzer exit with syntax error.\n");
        return 0;
    }
    /* [ 4.5 ] jump the spaces after ')' */
    GET_NEW_CHAR_JUMP_SPACE( fileField )
    /* [ 4.6 ] check '{' */
    if( '{' != fileField->current_ch ){
        report_syntax_error( "syntax_analyzer", "missing '{'.", fileField->n_current_line );
        printf("Syntax_analyzer exit with syntax error.\n");
        return 0;
    }
    /** [ 5 ] deal with 'BODY' **/
    ret = BODY( fileField, g_SynTree.n_node_num-1, 0 );
    if( 0 == ret ){
        printf("Syntax_analyzer exit with syntax error.\n");
        return 0;
    }
    /* [ 6 ] jump the spaces after 'BODY' */
    JUMP_SPACES( fileField )
    /* [ 7 ] check '}' */
    if( '}' != fileField->current_ch ){
        report_syntax_error( "syntax_analyzer", "missing '}'.", fileField->n_current_line );
        printf("Syntax_analyzer exit with syntax error.\n");
        return 0;
    }
    /* [ 8 ] jump the spaces after '}' */
    GET_NEW_CHAR_JUMP_SPACE( fileField )
    if( EOF != fileField->current_ch ){
        report_syntax_error( "syntax_analyzer", "Unexpected character.", fileField->n_current_line );
        printf("Syntax_analyzer exit with syntax error.\n");
        return 0;
    }
    return 1;
}


int DEFINITION(FileField *fileField, int left_brother_ID, int father_ID){
    int ret = 0;
    int id_length = 0;
    char *func_name="DEFINITION";
    unsigned int tempIndex = 0;

    /* [ 1 ] make a node for 'DEFINITION' */
    tempIndex = g_SynTree.n_node_num;
    g_SynTree.pSynNodeList[ tempIndex ].n_father_id = father_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_identifier_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_left_brother_id = left_brother_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_mode = SYN_NODE_DEFINITION;
    g_SynTree.pSynNodeList[ tempIndex ].n_right_brother_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_son_id = INVALID_ID;
    /* [ 2 ] fix for father and left brother */
    FIX_FATHER_LBROTHER( father_ID, left_brother_ID, tempIndex )
    g_SynTree.n_node_num++;
    CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )


    /* [ 3 ] deal with VAR_DEF */
    ret = VAR_DEF( fileField, INVALID_ID, tempIndex );
    if( 0 == ret ){
        return 0;
    }
    if( 1000 == ret ){
        report_syntax_error( func_name, "Invalid identifier .", fileField->n_current_line );
        return 0;
    } else if( 100 == ret ){
        return 1;
    } else if( 200 == ret ){
        /* [ 4 ] deal with FUNC_DEF */
        ret = FUNC_DEF( fileField, INVALID_ID, tempIndex );
        if( 0 == ret ){
            return 0;
        }
    } else if( 300 == ret ){
        report_syntax_error( "syntax_analyzer", "Unexpected character.", fileField->n_current_line );
        return 0;
    }
    /* [ 5 ] deal with DEFINITION recursively */
    ret = DEFINITION( fileField, g_SynTree.pSynNodeList[ tempIndex ].n_son_id, tempIndex );
    if( 0 == ret ){
        return 0;
    }
    return 1;
}
/** if it returns 1000, it's unkown character, maybe '}' **/
/** if it returns 100, an identifier name 'main' is stored in FileField.name_buf **/
/** if it returns 200, an identifier name ( not 'main' ) is stored in FileField.name_buf **/
/** if it returns 300, it's 'if' 'while' 'for' **/
int VAR_DEF(FileField *fileField, int left_brother_ID, int father_ID){
    int ret = 0;
    char *func_name="VAR_DEF";
    unsigned int tempIndex = 0;
    unsigned int ident_index = 0;
    int id_length = 0;
    /* [ 1 ] jump spaces in the head */
    GET_NEW_CHAR_JUMP_SPACE( fileField )
    /* [ 2 ] get the first token */
    GET_IDENTIFY( fileField, fileField->name_buf, id_length )
    if( 0 == id_length ){
        return 1000;
    }
    CHECK_KEY_WORD( fileField->name_buf, ret )
    if( KEY_WORD_MAIN == ret ){
        /* no definition */
        return 100;
    } else if( KEY_WORD_NO == ret ){
        /* it's an identifier. maybe statment_list or syntax error. */
        return 200;
    }else if( KEY_WORD_INT == ret ){
        /* [ 3 ] deal with 'VAR_DEF' */
        /* [ 3.1 ] make a node for 'VAR_DEF' */
        tempIndex = g_SynTree.n_node_num;
        g_SynTree.pSynNodeList[ tempIndex ].n_father_id = father_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_identifier_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_left_brother_id = left_brother_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_mode = SYN_NODE_VAR_DEF;
        g_SynTree.pSynNodeList[ tempIndex ].n_right_brother_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_son_id = INVALID_ID;
        /* [ 3.2 ] fix for father and left brother */
        FIX_FATHER_LBROTHER( father_ID, left_brother_ID, tempIndex )
        g_SynTree.n_node_num++;
        CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
        /* [ 3.3 ] get the identifier after 'int' */
        GET_IDENTIFY( fileField, fileField->name_buf, id_length )
        if( 0 == id_length ){
            report_syntax_error( func_name, "Invalid identifier .", fileField->n_current_line );
            return 0;
        }
        CHECK_KEY_WORD( fileField->name_buf, ret )
        if( KEY_WORD_NO != ret ){
            /* Invalid identifier */
            report_syntax_error( func_name, "Invalid identifier: key-word.", fileField->n_current_line );
            return 0;
        }
        /* [ 3.4 ] use a IdentId to store the identifier and make a syntax node */
        ret = add_to_IdTable(fileField, fileField->name_buf, id_length, SYN_NODE_VARID, &ident_index);
        if( 0 == ret ){
            return 0;
        }
        g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_father_id = tempIndex;
        g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_identifier_id = ident_index;
        g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_left_brother_id = INVALID_ID;
        g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_mode = SYN_NODE_VARID;
        g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_right_brother_id = INVALID_ID;
        g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_son_id = INVALID_ID;
        /* [ 3.5 ] fix for father and left brother */
        FIX_FATHER_LBROTHER( tempIndex, INVALID_ID, g_SynTree.n_node_num )
        g_SynTree.n_node_num++;
        CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
        /* [ 3.6 ] deal with ';' */
        JUMP_SPACES( fileField )
        if( ';' != fileField->current_ch ){
            report_syntax_error( func_name, "Missing ';' .", fileField->n_current_line );
            return 0;
        }
        return 1;
    } else{
        /* it's 'if' 'while' 'for' */
        return 300;
    }
}
int FUNC_DEF(FileField *fileField, int left_brother_ID, int father_ID){
    int ret = 0;
    char *func_name="FUNC_DEF";
    unsigned int tempIndex = 0;
    unsigned int ident_index = 0;
    int id_length = 0;
    /* [ 1 ] deal with FUNC_DEF */
    /* [ 1.1 ] make a node for FUNC_DEF */
    g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_father_id = father_ID;
    g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_identifier_id = INVALID_ID;
    g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_left_brother_id = left_brother_ID;
    g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_mode = SYN_NODE_FUNC_DEF;
    g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_right_brother_id = INVALID_ID;
    g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_son_id = INVALID_ID;
    /* [ 1.2 ] fix for father and left brother */
    FIX_FATHER_LBROTHER( father_ID, left_brother_ID, g_SynTree.n_node_num )
    g_SynTree.n_node_num++;
    CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
    /* [ 1.3 ] use a IdentId to store the identifier and make a syntax node */
    ret = add_to_IdTable(fileField, fileField->name_buf, (int)strlen( fileField->name_buf ), SYN_NODE_FUNID, &ident_index);
    if( 0 == ret ){
        return 0;
    }
    g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_father_id = g_SynTree.n_node_num - 1;
    g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_identifier_id = ident_index;
    g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_left_brother_id = INVALID_ID;
    g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_mode = SYN_NODE_FUNID;
    g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_right_brother_id = INVALID_ID;
    g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_son_id = INVALID_ID;
    /* [ 1.4 ] fix for father and left brother */
    FIX_FATHER_LBROTHER( g_SynTree.n_node_num - 1, INVALID_ID, g_SynTree.n_node_num )
    g_SynTree.n_node_num++;
    CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
    /* [ 1.5 ] deal with '(' */
    JUMP_SPACES( fileField )
    if( '(' != fileField->current_ch ){
        report_syntax_error( func_name, "Missing '(' .", fileField->n_current_line );
        return 0;
    }
    /* [ 1.6 ] deal with ')' */
    GET_NEW_CHAR_JUMP_SPACE( fileField )
    if( ')' != fileField->current_ch ){
        report_syntax_error( func_name, "Missing ')' .", fileField->n_current_line );
        return 0;
    }
    /* [ 1.7 ] deal with '{' */
    GET_NEW_CHAR_JUMP_SPACE( fileField )
    if( '{' != fileField->current_ch ){
        report_syntax_error( func_name, "Missing '{' .", fileField->n_current_line );
        return 0;
    }
    /* [ 1.8 ] deal with 'BODY' */
    ret = BODY( fileField, g_SynTree.n_node_num - 1, g_SynTree.n_node_num - 2 );
    if( 0 == ret ){
        return 0;
    }
    /* [ 1.9 ] deal with '}' */
    JUMP_SPACES( fileField )
    if( '}' != fileField->current_ch ){
        report_syntax_error( func_name, "Missing '}' .", fileField->n_current_line );
        return 0;
    }
    return 1;
}
int BODY(FileField *fileField, int left_brother_ID, int father_ID){
    int ret = 0;
    char *func_name="BODY";
    unsigned int tempIndex = 0;
    int id_length = 0;

    /* [ 1 ] make a node for 'BODY' */
    tempIndex = g_SynTree.n_node_num;
    g_SynTree.pSynNodeList[ tempIndex ].n_father_id = father_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_identifier_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_left_brother_id = left_brother_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_mode = SYN_NODE_BODY;
    g_SynTree.pSynNodeList[ tempIndex ].n_right_brother_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_son_id = INVALID_ID;
    /* [ 2 ] fix for father and left brother */
    FIX_FATHER_LBROTHER( father_ID, left_brother_ID, tempIndex )
    g_SynTree.n_node_num++;
    CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
    /* [ 3 ] deal with VAR_DEFINITION */
    ret = VAR_DEFINITION( fileField, INVALID_ID, tempIndex );
    if( 0 == ret ){
        return 0;
    }
    if( 400 != ret ){
        /* [ 4 ] deal with STATEMENT_LIST */
        ret = STATEMENT_LIST( fileField, g_SynTree.pSynNodeList[ tempIndex ].n_son_id, tempIndex );
        if( 0 == ret ){
            return 0;
        }
    }

    return 1;
}
/** if it returns 200, an identifier name is stored in FileField.name_buf **/
/** if it returns 300, it's 'if' 'while' 'for' **/
/** if it returns 400, an empty statment_list is following **/
int VAR_DEFINITION(FileField *fileField, int left_brother_ID, int father_ID){
    int ret = 0;
    char *func_name="VAR_DEFINITION";
    unsigned int tempIndex = 0;
    /* [ 1 ] make a node for 'VAR_DEFINITION' */
    tempIndex = g_SynTree.n_node_num;
    g_SynTree.pSynNodeList[ tempIndex ].n_father_id = father_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_identifier_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_left_brother_id = left_brother_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_mode = SYN_NODE_VAR_DEFINITION;
    g_SynTree.pSynNodeList[ tempIndex ].n_right_brother_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_son_id = INVALID_ID;
    /* [ 2 ] fix for father and left brother */
    FIX_FATHER_LBROTHER( father_ID, left_brother_ID, tempIndex )
    g_SynTree.n_node_num++;
    CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
    /* [ 3 ] deal with VAR_DEF */
    ret = VAR_DEF( fileField, INVALID_ID, tempIndex );
    if( 0 == ret ){
        return 0;
    }
    if( 1000 == ret ){
        if( '}' != fileField->current_ch ){
            report_syntax_error( func_name, "Invalid identifier .", fileField->n_current_line );
            return 0;
        } else{
            /* Empty statement_list */
            return 400;
        }
    } else if( 100 == ret ){
        report_syntax_error( "syntax_analyzer", "Unexpected key-word 'main'.", fileField->n_current_line );
        return 0;/* 'main' can't be here */
    } else if( 200 == ret ){
        /* [ 4 ] 'STATEMENT_LIST' is following */
        return 200;
    } else if( 300 == ret ){
        /* [ 5 ] 'STATEMENT_LIST' is following */
        return 300;
    }
    ret = VAR_DEFINITION( fileField, g_SynTree.pSynNodeList[ tempIndex ].n_son_id, tempIndex );
    return ret;
}
int STATEMENT_LIST(FileField *fileField, int left_brother_ID, int father_ID){
    int ret = 0;
    char *func_name="STATEMENT_LIST";
    unsigned int tempIndex = 0;
    unsigned int id_length = 0;
    /* [ 1 ] make a node for 'STATEMENT_LIST' */
    tempIndex = g_SynTree.n_node_num;
    g_SynTree.pSynNodeList[ tempIndex ].n_father_id = father_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_identifier_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_left_brother_id = left_brother_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_mode = SYN_NODE_STATEMENT_LIST;
    g_SynTree.pSynNodeList[ tempIndex ].n_right_brother_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_son_id = INVALID_ID;
    /* [ 2 ] fix for father and left brother */
    FIX_FATHER_LBROTHER( father_ID, left_brother_ID, tempIndex )
    g_SynTree.n_node_num++;
    CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
    /* [ 3 ] check the last byte */
    if( '}' == fileField->current_ch ){
        /* the statement list is empty */
        return 1;
    }
    /* [ 4 ] check the key-word which has already been read */
    CHECK_KEY_WORD( fileField->name_buf, ret )
    if( KEY_WORD_NO == ret ){
        JUMP_SPACES( fileField )
        if( '=' == fileField->current_ch ){
            /* [ 4.1 ] it's an ASSIGN_STMT */
            ret = ASSIGN_STMT( fileField, INVALID_ID, tempIndex );
            if( 0 == ret ){
                return 0;
            }
            JUMP_SPACES( fileField )
            if( ';' != fileField->current_ch ){
                /* check ';' */
                report_syntax_error( func_name, "Missing ';' .", fileField->n_current_line );
                return 0;
            }
        } else if( '(' == fileField->current_ch ){
            /* [ 4.2 ] it's an FUNC_CALL */
            ret = FUNC_CALL( fileField, INVALID_ID, tempIndex );
            if( 0 == ret ){
                return 0;
            }
        } else{
            report_syntax_error( func_name, "Unknown statement .", fileField->n_current_line );
            return 0;
        }
    } else if( KEY_WORD_IF == ret ){
        /* [ 4.2 ] deal with IF_STMT */
        ret = IF_STMT( fileField, INVALID_ID, tempIndex );
        if( 0 == ret ){
            return 0;
        }
    } else if( KEY_WORD_WHILE == ret ){
        /* [ 4.3 ] deal with WHILE_STMT */
        ret = WHILE_STMT( fileField, INVALID_ID, tempIndex );
        if( 0 == ret ){
            return 0;
        }
    } else if( KEY_WORD_FOR == ret ){
        /* [ 4.4 ] deal with FOR_STMT */
        ret = FOR_STMT( fileField, INVALID_ID, tempIndex );
        if( 0 == ret ){
            return 0;
        }
    } else {
        report_syntax_error( func_name, "Invalid identifier .", fileField->n_current_line );
        return 0;
    }
    /* [ 5 ] jump spaces */
    GET_NEW_CHAR_JUMP_SPACE( fileField )
    /* [ 6 ] get the next token */
    GET_IDENTIFY( fileField, fileField->name_buf, id_length )
    /* [ 7 ] call STATEMENT_LIST() recursively */
    ret = STATEMENT_LIST( fileField, g_SynTree.pSynNodeList[ tempIndex ].n_son_id, tempIndex );
    if( 0 == ret ){
        return 0;
    }
    
    return 1;
}
int ASSIGN_STMT(FileField *fileField, int left_brother_ID, int father_ID){
    int ret = 0;
    char *func_name="ASSIGN_STMT";
    unsigned int tempIndex = 0;
    unsigned int ident_index = 0;
    IdentId_P p_cur_id = NULL;
    /* [ 1 ] make a node for 'ASSIGN_STMT' */
    tempIndex = g_SynTree.n_node_num;
    g_SynTree.pSynNodeList[ tempIndex ].n_father_id = father_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_identifier_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_left_brother_id = left_brother_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_mode = SYN_NODE_ASSIGN_STMT;
    g_SynTree.pSynNodeList[ tempIndex ].n_right_brother_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_son_id = INVALID_ID;
    /* [ 2 ] fix for father and left brother */
    FIX_FATHER_LBROTHER( father_ID, left_brother_ID, tempIndex )
    g_SynTree.n_node_num++;
    CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
    /* [ 3 ] find the identifier in IdTable */
    ret = find_in_IdTable(fileField, fileField->name_buf, (int)strlen(fileField->name_buf), &ident_index);
    if( 0 == ret ){
        return 0;
    }
    p_cur_id = &g_IdTable.pIdList[ ident_index ];
    if( p_cur_id->n_mode != SYN_NODE_VARID ){
        report_syntax_error( func_name, "Identifier can't be assigned, it's a function name.", fileField->n_current_line );
        return 0;
    }
    /* [ 4 ] make a node for the identifier */
    tempIndex = g_SynTree.n_node_num;
    g_SynTree.pSynNodeList[ tempIndex ].n_father_id = tempIndex - 1;
    g_SynTree.pSynNodeList[ tempIndex ].n_identifier_id = ident_index;
    g_SynTree.pSynNodeList[ tempIndex ].n_left_brother_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_mode = SYN_NODE_VARID;
    g_SynTree.pSynNodeList[ tempIndex ].n_right_brother_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_son_id = INVALID_ID;
    /* [ 5 ] fix for father and left brother */
    FIX_FATHER_LBROTHER( tempIndex - 1, INVALID_ID, tempIndex )
    g_SynTree.n_node_num++;
    CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
    /* [ 6 ] check the '=' */
    JUMP_SPACES( fileField )
    if( '=' != fileField->current_ch ){
        report_syntax_error( func_name, "Missing '='.", fileField->n_current_line );
        return 0;
    }
    /* [ 7 ] deal with FORMULA */
    ret = FORMULA( fileField, tempIndex, tempIndex - 1 );
    if( 0 == ret ){
        return 0;
    }

    return 1;
}

int IF_STMT(FileField *fileField, int left_brother_ID, int father_ID){
    int ret = 0;
    char *func_name="IF_STMT";
    unsigned int tempIndex = 0;
    unsigned int id_length = 0;
    /* [ 1 ] make a node for 'IF_STMT' */
    tempIndex = g_SynTree.n_node_num;
    g_SynTree.pSynNodeList[ tempIndex ].n_father_id = father_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_identifier_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_left_brother_id = left_brother_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_mode = SYN_NODE_IF_STMT;
    g_SynTree.pSynNodeList[ tempIndex ].n_right_brother_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_son_id = INVALID_ID;
    /* [ 2 ] fix for father and left brother */
    FIX_FATHER_LBROTHER( father_ID, left_brother_ID, tempIndex )
    g_SynTree.n_node_num++;
    CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
    /* [ 3 ] check '('  */
    JUMP_SPACES( fileField )
    if( '(' != fileField->current_ch ){
        report_syntax_error( func_name, "Missing '('.", fileField->n_current_line );
        return 0;
    }
    /* [ 4 ] deal with BOOL_FORMULA */
    /* [ 4.1 ] jump spaces in the head for two bytes operator e.g. '>=' */
    GET_NEW_CHAR_JUMP_SPACE( fileField )
    ret = BOOL_FORMULA( fileField, INVALID_ID, tempIndex );
    if( 0 == ret ){
        return 0;
    }
    /* [ 5 ] check ')'  */
    JUMP_SPACES( fileField )
    if( ')' != fileField->current_ch ){
        report_syntax_error( func_name, "Missing ')'.", fileField->n_current_line );
        return 0;
    }
    /* [ 6 ] jump spaces */
    GET_NEW_CHAR_JUMP_SPACE( fileField )
    /* [ 7 ] check '{' */
    if( '{' != fileField->current_ch ){
        report_syntax_error( func_name, "Missing '{'.", fileField->n_current_line );
        return 0;
    }
    /* [ 8 ] jump spaces */
    GET_NEW_CHAR_JUMP_SPACE( fileField )
    /* [ 9 ] get the next token */
    GET_IDENTIFY( fileField, fileField->name_buf, id_length )
    /* [ 10 ] call STATEMENT_LIST() */
    ret = STATEMENT_LIST( fileField, g_SynTree.pSynNodeList[ tempIndex ].n_son_id, tempIndex );
    if( 0 == ret ){
        return 0;
    }
    /* [ 11 ] deal with '}' */
    JUMP_SPACES( fileField )
    if( '}' != fileField->current_ch ){
        report_syntax_error( func_name, "Missing '}' .", fileField->n_current_line );
        return 0;
    }

    return 1;
}
int FOR_STMT(FileField *fileField, int left_brother_ID, int father_ID){
    int ret = 0;
    char *func_name="FOR_STMT";
    unsigned int for_stmt_index = 0;
    unsigned int tempIndex = 0;
    unsigned int id_length = 0;
    /* [ 1 ] make a node for 'FOR_STMT' */
    tempIndex = g_SynTree.n_node_num;
    for_stmt_index = tempIndex;
    g_SynTree.pSynNodeList[ tempIndex ].n_father_id = father_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_identifier_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_left_brother_id = left_brother_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_mode = SYN_NODE_FOR_STMT;
    g_SynTree.pSynNodeList[ tempIndex ].n_right_brother_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_son_id = INVALID_ID;
    /* [ 2 ] fix for father and left brother */
    FIX_FATHER_LBROTHER( father_ID, left_brother_ID, tempIndex )
    g_SynTree.n_node_num++;
    CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
    /* [ 3 ] check '('  */
    JUMP_SPACES( fileField )
    if( '(' != fileField->current_ch ){
        report_syntax_error( func_name, "Missing '('.", fileField->n_current_line );
        return 0;
    }
    /* [ 4 ] jump spaces */
    GET_NEW_CHAR_JUMP_SPACE( fileField )
    if( ';' == fileField->current_ch ){
        /* [ 5 ] first statement is empty, make an empty node */
        tempIndex++;
        g_SynTree.pSynNodeList[ tempIndex ].n_father_id = for_stmt_index;
        g_SynTree.pSynNodeList[ tempIndex ].n_identifier_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_left_brother_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_mode = SYN_NODE_EMPTY;
        g_SynTree.pSynNodeList[ tempIndex ].n_right_brother_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_son_id = INVALID_ID;
        /* [ 5.1 ] fix for father and left brother */
        FIX_FATHER_LBROTHER( for_stmt_index, INVALID_ID, tempIndex )
        g_SynTree.n_node_num++;
        CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
    } else{
        /* [ 6 ] deal with ASSIGN_STMT */
        /* [ 6.1 ] get the next token */
        GET_IDENTIFY( fileField, fileField->name_buf, id_length )
        ret = ASSIGN_STMT( fileField, INVALID_ID, for_stmt_index );
        if( 0 == ret ){
            return 0;
        }
        JUMP_SPACES( fileField )
        if( ';' != fileField->current_ch ){
            /* check ';' */
            report_syntax_error( func_name, "Missing ';' .", fileField->n_current_line );
            return 0;
        }
    }
    /* [ 7 ] deal with BOOL_FORMULA */
    /* [ 7.1 ] jump spaces in the head for two bytes operator e.g. '>=' */
    GET_NEW_CHAR_JUMP_SPACE( fileField )
    ret = BOOL_FORMULA( fileField, g_SynTree.pSynNodeList[ for_stmt_index ].n_son_id, for_stmt_index );
    if( 0 == ret ){
        return 0;
    }
    JUMP_SPACES( fileField )
    if( ';' != fileField->current_ch ){
        /* check ';' */
        report_syntax_error( func_name, "Missing ';' .", fileField->n_current_line );
        return 0;
    }
    /* [ 7.1 ] store the index of BOOL_FORMULA */
    tempIndex = g_SynTree.pSynNodeList[ g_SynTree.pSynNodeList[ for_stmt_index ].n_son_id ].n_right_brother_id;
    /* [ 8 ] jump spaces */
    GET_NEW_CHAR_JUMP_SPACE( fileField )
    if( ')' == fileField->current_ch ){
        /* [ 9 ] last statement is empty, make an empty node */
        g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_father_id = for_stmt_index;
        g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_identifier_id = INVALID_ID;
        g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_left_brother_id = tempIndex;
        g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_mode = SYN_NODE_EMPTY;
        g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_right_brother_id = INVALID_ID;
        g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_son_id = INVALID_ID;
        /* [ 9.1 ] fix for father and left brother */
        FIX_FATHER_LBROTHER( for_stmt_index, tempIndex, g_SynTree.n_node_num )
        g_SynTree.n_node_num++;
        CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
    } else{
        /* [ 10 ] deal with ASSIGN_STMT */
        /* [ 10.1 ] get the next token */
        GET_IDENTIFY( fileField, fileField->name_buf, id_length )
        ret = ASSIGN_STMT( fileField, tempIndex, for_stmt_index );
        if( 0 == ret ){
            return 0;
        }
        JUMP_SPACES( fileField )
        if( ')' != fileField->current_ch ){
            /* check ')' */
            report_syntax_error( func_name, "Missing ')' .", fileField->n_current_line );
            return 0;
        }
    }
    /* [ 10.1 ] store the index of third child of FOR_STMT */
    tempIndex = g_SynTree.pSynNodeList[ tempIndex ].n_right_brother_id;
    /* [ 11 ] jump spaces */
    GET_NEW_CHAR_JUMP_SPACE( fileField )
    /* [ 12 ] check '{' */
    if( '{' != fileField->current_ch ){
        report_syntax_error( func_name, "Missing '{' .", fileField->n_current_line );
        return 0;
    }
    /* [ 13 ] jump spaces */
    GET_NEW_CHAR_JUMP_SPACE( fileField )
    /* [ 14 ] get the next token */
    GET_IDENTIFY( fileField, fileField->name_buf, id_length )
    /* [ 15 ] call STATEMENT_LIST() */
    ret = STATEMENT_LIST( fileField, tempIndex, for_stmt_index );
    if( 0 == ret ){
        return 0;
    }
    /* [ 16 ] deal with '}' */
    JUMP_SPACES( fileField )
    if( '}' != fileField->current_ch ){
        report_syntax_error( func_name, "Missing '}' .", fileField->n_current_line );
        return 0;
    }

    return 1;
}
int WHILE_STMT(FileField *fileField, int left_brother_ID, int father_ID){
    int ret = 0;
    char *func_name="WHILE_STMT";
    unsigned int tempIndex = 0;
    unsigned int id_length = 0;
    /* [ 1 ] make a node for 'WHILE_STMT' */
    tempIndex = g_SynTree.n_node_num;
    g_SynTree.pSynNodeList[ tempIndex ].n_father_id = father_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_identifier_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_left_brother_id = left_brother_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_mode = SYN_NODE_WHILE_STMT;
    g_SynTree.pSynNodeList[ tempIndex ].n_right_brother_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_son_id = INVALID_ID;
    /* [ 2 ] fix for father and left brother */
    FIX_FATHER_LBROTHER( father_ID, left_brother_ID, tempIndex )
    g_SynTree.n_node_num++;
    CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
    /* [ 3 ] check '('  */
    JUMP_SPACES( fileField )
    if( '(' != fileField->current_ch ){
        report_syntax_error( func_name, "Missing '('.", fileField->n_current_line );
        return 0;
    }
    /* [ 4 ] jump spaces */
    /* [ 5.1 ] jump spaces in the head for two bytes operator e.g. '>=' */
    GET_NEW_CHAR_JUMP_SPACE( fileField )
    /* [ 5 ] deal with BOOL_FORMULA */
    ret = BOOL_FORMULA( fileField, INVALID_ID, tempIndex );
    if( 0 == ret ){
        return 0;
    }
    /* [ 6 ] check ')' */
    JUMP_SPACES( fileField )
    if( ')' != fileField->current_ch ){
        report_syntax_error( func_name, "Missing ')'.", fileField->n_current_line );
        return 0;
    }
    /* [ 7 ] jump spaces */
    GET_NEW_CHAR_JUMP_SPACE( fileField )
    /* [ 8 ] check '{' */
    if( '{' != fileField->current_ch ){
        report_syntax_error( func_name, "Missing '{'.", fileField->n_current_line );
        return 0;
    }
    /* [ 9 ] jump spaces */
    GET_NEW_CHAR_JUMP_SPACE( fileField )
    /* [ 10 ] get the next token */
    GET_IDENTIFY( fileField, fileField->name_buf, id_length )
    /* [ 11 ] call STATEMENT_LIST() */
    ret = STATEMENT_LIST( fileField, g_SynTree.pSynNodeList[ tempIndex ].n_son_id, tempIndex );
    if( 0 == ret ){
        return 0;
    }
    /* [ 12 ] deal with '}' */
    JUMP_SPACES( fileField )
    if( '}' != fileField->current_ch ){
        report_syntax_error( func_name, "Missing '}' .", fileField->n_current_line );
        return 0;
    }


    return 1;
}
int FORMULA(FileField *fileField, int left_brother_ID, int father_ID){
    int ret = 0;
    char *func_name="FORMULA";
    unsigned int tempIndex = 0;
    unsigned int FORMULAIndex = 0;
    unsigned int id_length = 0;
    unsigned int ident_index = 0;
    int int_value = 0;
    IdentId_P p_cur_id = NULL;
    /* [ 1 ] make a node for 'FORMULA' */
    tempIndex = g_SynTree.n_node_num;
    FORMULAIndex = tempIndex;
    g_SynTree.pSynNodeList[ tempIndex ].n_father_id = father_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_identifier_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_left_brother_id = left_brother_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_mode = SYN_NODE_FORMULA;
    g_SynTree.pSynNodeList[ tempIndex ].n_right_brother_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_son_id = INVALID_ID;
    /* [ 2 ] fix for father and left brother */
    FIX_FATHER_LBROTHER( father_ID, left_brother_ID, tempIndex )
    g_SynTree.n_node_num++;
    CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
    /* [ 3 ] jump spaces in the head */
    GET_NEW_CHAR_JUMP_SPACE( fileField )
    /* [ 4 ] check the first byte */
    if( '(' == fileField->current_ch ){
        /* [ 5 ] make a node for '(' */
        tempIndex = g_SynTree.n_node_num;
        g_SynTree.pSynNodeList[ tempIndex ].n_father_id = FORMULAIndex;
        g_SynTree.pSynNodeList[ tempIndex ].n_identifier_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_left_brother_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_mode = SYN_NODE_L_parenthesis;
        g_SynTree.pSynNodeList[ tempIndex ].n_right_brother_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_son_id = INVALID_ID;
        /* [ 5.1 ] fix for father and left brother */
        FIX_FATHER_LBROTHER( FORMULAIndex, INVALID_ID, tempIndex )
        g_SynTree.n_node_num++;
        CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
        /* [ 5.2 ] deal with FORMULA recursively */
        ret = FORMULA( fileField, tempIndex, FORMULAIndex );
        if( 0 == ret ){
            return 0;
        }
        /* [ 5.3 ] check ')' */
        JUMP_SPACES( fileField )
        if( ')' != fileField->current_ch ){
            report_syntax_error( func_name, "Missing ')' .", fileField->n_current_line );
            return 0;
        }
        /* [ 5.4 ] make a node for ')' */
        tempIndex = g_SynTree.pSynNodeList[ tempIndex ].n_right_brother_id;
        g_SynTree.n_node_num;
        g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_father_id = FORMULAIndex;
        g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_identifier_id = INVALID_ID;
        g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_left_brother_id = tempIndex;
        g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_mode = SYN_NODE_R_parenthesis;
        g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_right_brother_id = INVALID_ID;
        g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_son_id = INVALID_ID;
        /* [ 5.5 ] fix for father and left brother */
        FIX_FATHER_LBROTHER( FORMULAIndex, tempIndex , g_SynTree.n_node_num )
        g_SynTree.n_node_num++;
        CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
        /* [ 5.6 ] jump spaces in the end */
        GET_NEW_CHAR_JUMP_SPACE( fileField )
        /* [ 5.7 ] reflash the tempIndex */
        tempIndex = g_SynTree.n_node_num - 1;
    } else if( isalpha( fileField->current_ch ) ){
        /* [ 6 ] deal with identifier */
        GET_IDENTIFY( fileField, fileField->name_buf, id_length )
        if( 0 == id_length ){
            report_syntax_error( func_name, "Invalid identifier .", fileField->n_current_line );
            return 0;
        }
        CHECK_KEY_WORD( fileField->name_buf, ret )
        if( KEY_WORD_NO != ret ){
            report_syntax_error( func_name, "Invalid identifier :key-word.", fileField->n_current_line );
            return 0;
        }
        /* [ 6.1 ] find the identifier in IdTable */
        ret = find_in_IdTable(fileField, fileField->name_buf, (int)strlen(fileField->name_buf), &ident_index);
        if( 0 == ret ){
            return 0;
        }
        p_cur_id = &g_IdTable.pIdList[ ident_index ];
        if( p_cur_id->n_mode != SYN_NODE_VARID ){
            report_syntax_error( func_name, "Identifier can't be caculated, it's a function name.", fileField->n_current_line );
            return 0;
        }
        /* [ 6.2 ] make a node for the identifier */
        tempIndex = g_SynTree.n_node_num;
        g_SynTree.pSynNodeList[ tempIndex ].n_father_id = FORMULAIndex;
        g_SynTree.pSynNodeList[ tempIndex ].n_identifier_id = ident_index;
        g_SynTree.pSynNodeList[ tempIndex ].n_left_brother_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_mode = SYN_NODE_VARID;
        g_SynTree.pSynNodeList[ tempIndex ].n_right_brother_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_son_id = INVALID_ID;
        /* [ 6.3 ] fix for father and left brother */
        FIX_FATHER_LBROTHER( FORMULAIndex, INVALID_ID, tempIndex )
        g_SynTree.n_node_num++;
        CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
    } else{
        /* [ 7 ] deal with numbers */
        ret = get_number( fileField, &int_value );
        if( 0 == ret ){
            return 0;
        }
        /* [ 7.1 ] make a node for the integer */
        tempIndex = g_SynTree.n_node_num;
        g_SynTree.pSynNodeList[ tempIndex ].n_father_id = FORMULAIndex;
        g_SynTree.pSynNodeList[ tempIndex ].n_identifier_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_left_brother_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_mode = SYN_NODE_NUMBER;
        g_SynTree.pSynNodeList[ tempIndex ].n_right_brother_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_son_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_int_value = int_value;
        /* [ 7.2 ] fix for father and left brother */
        FIX_FATHER_LBROTHER( FORMULAIndex, INVALID_ID, tempIndex )
        g_SynTree.n_node_num++;
        CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
    }
    /* [ 8 ] deal with FORMULA_FOLLOW */
    ret = FORMULA_FOLLOW( fileField, tempIndex,  FORMULAIndex );
    if( 0 == ret ){
        return 0;
    }

    return 1;
};
int BOOL_FORMULA(FileField *fileField, int left_brother_ID, int father_ID){
    int ret = 0;
    char *func_name="BOOL_FORMULA";
    unsigned int tempIndex = 0;
    unsigned int BOOL_FORMULAIndex = 0;
    unsigned int id_length = 0;
    unsigned int ident_index = 0;
    int int_value = 0;
    IdentId_P p_cur_id = NULL;
    /* [ 1 ] make a node for 'BOOL_FORMULA' */
    tempIndex = g_SynTree.n_node_num;
    BOOL_FORMULAIndex = tempIndex;
    g_SynTree.pSynNodeList[ tempIndex ].n_father_id = father_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_identifier_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_left_brother_id = left_brother_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_mode = SYN_NODE_BOOL_FORMULA;
    g_SynTree.pSynNodeList[ tempIndex ].n_right_brother_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_son_id = INVALID_ID;
    /* [ 2 ] fix for father and left brother */
    FIX_FATHER_LBROTHER( father_ID, left_brother_ID, tempIndex )
    g_SynTree.n_node_num++;
    CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
    /* [ 3 ] jump spaces in the head */
    JUMP_SPACES( fileField )
    /* [ 4 ] check the first byte */
    if( '(' == fileField->current_ch ){
        /* [ 5 ] make a node for '(' */
        tempIndex = g_SynTree.n_node_num;
        g_SynTree.pSynNodeList[ tempIndex ].n_father_id = BOOL_FORMULAIndex;
        g_SynTree.pSynNodeList[ tempIndex ].n_identifier_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_left_brother_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_mode = SYN_NODE_L_parenthesis;
        g_SynTree.pSynNodeList[ tempIndex ].n_right_brother_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_son_id = INVALID_ID;
        /* [ 5.1 ] fix for father and left brother */
        FIX_FATHER_LBROTHER( BOOL_FORMULAIndex, INVALID_ID, tempIndex )
        g_SynTree.n_node_num++;
        CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
        /* [ 5.2 ] deal with BOOL_FORMULA recursively */
        /* jump spaces in the head for two bytes operator e.g. '>=' */
        GET_NEW_CHAR_JUMP_SPACE( fileField )
        ret = BOOL_FORMULA( fileField, tempIndex, BOOL_FORMULAIndex );
        if( 0 == ret ){
            return 0;
        }
        /* [ 5.3 ] check ')' */
        JUMP_SPACES( fileField )
        if( ')' != fileField->current_ch ){
            report_syntax_error( func_name, "Missing ')' .", fileField->n_current_line );
            return 0;
        }
        /* [ 5.4 ] make a node for ')' */
        tempIndex = g_SynTree.pSynNodeList[ tempIndex ].n_right_brother_id;
        g_SynTree.n_node_num;
        g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_father_id = BOOL_FORMULAIndex;
        g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_identifier_id = INVALID_ID;
        g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_left_brother_id = tempIndex;
        g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_mode = SYN_NODE_R_parenthesis;
        g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_right_brother_id = INVALID_ID;
        g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_son_id = INVALID_ID;
        /* [ 5.5 ] fix for father and left brother */
        FIX_FATHER_LBROTHER( BOOL_FORMULAIndex, tempIndex , g_SynTree.n_node_num )
        tempIndex = g_SynTree.n_node_num;/* Fix Bug */
        g_SynTree.n_node_num++;
        CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
        /* [ 5.6 ] jump spaces in the end */
        GET_NEW_CHAR_JUMP_SPACE( fileField )
    } else if( isalpha( fileField->current_ch ) ){
        /* [ 6 ] deal with identifier */
        GET_IDENTIFY( fileField, fileField->name_buf, id_length )
        if( 0 == id_length ){
            report_syntax_error( func_name, "Invalid identifier .", fileField->n_current_line );
            return 0;
        }
        CHECK_KEY_WORD( fileField->name_buf, ret )
        if( KEY_WORD_NO != ret ){
            report_syntax_error( func_name, "Invalid identifier :key-word.", fileField->n_current_line );
            return 0;
        }
        /* [ 6.1 ] find the identifier in IdTable */
        ret = find_in_IdTable(fileField, fileField->name_buf, (int)strlen(fileField->name_buf), &ident_index);
        if( 0 == ret ){
            return 0;
        }
        p_cur_id = &g_IdTable.pIdList[ ident_index ];
        if( p_cur_id->n_mode != SYN_NODE_VARID ){
            report_syntax_error( func_name, "Identifier can't be caculated, it's a function name.", fileField->n_current_line );
            return 0;
        }
        /* [ 6.2 ] make a node for the identifier */
        tempIndex = g_SynTree.n_node_num;
        g_SynTree.pSynNodeList[ tempIndex ].n_father_id = BOOL_FORMULAIndex;
        g_SynTree.pSynNodeList[ tempIndex ].n_identifier_id = ident_index;
        g_SynTree.pSynNodeList[ tempIndex ].n_left_brother_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_mode = SYN_NODE_VARID;
        g_SynTree.pSynNodeList[ tempIndex ].n_right_brother_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_son_id = INVALID_ID;
        /* [ 6.3 ] fix for father and left brother */
        FIX_FATHER_LBROTHER( BOOL_FORMULAIndex, INVALID_ID, tempIndex )
        g_SynTree.n_node_num++;
        CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
    } else{
        /* [ 7 ] deal with numbers */
        ret = get_number( fileField, &int_value );
        if( 0 == ret ){
            return 0;
        }
        /* [ 7.1 ] make a node for the integer */
        tempIndex = g_SynTree.n_node_num;
        g_SynTree.pSynNodeList[ tempIndex ].n_father_id = BOOL_FORMULAIndex;
        g_SynTree.pSynNodeList[ tempIndex ].n_identifier_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_left_brother_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_mode = SYN_NODE_NUMBER;
        g_SynTree.pSynNodeList[ tempIndex ].n_right_brother_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_son_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_int_value = int_value;
        /* [ 7.2 ] fix for father and left brother */
        FIX_FATHER_LBROTHER( BOOL_FORMULAIndex, INVALID_ID, tempIndex )
        g_SynTree.n_node_num++;
        CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
    }
    /* [ 8 ] deal with BOOL_FORMULA_FOLLOW */
    ret = BOOL_FORMULA_FOLLOW( fileField, tempIndex,  BOOL_FORMULAIndex );
    if( 0 == ret ){
        return 0;
    }

    return 1;
}
int FORMULA_FOLLOW(FileField *fileField, int left_brother_ID, int father_ID){
    int ret = 0;
    char *func_name="FORMULA_FOLLOW";
    unsigned int tempIndex = 0;
    /* [ 1 ] make a node for 'FORMULA_FOLLOW' */
    tempIndex = g_SynTree.n_node_num;
    g_SynTree.pSynNodeList[ tempIndex ].n_father_id = father_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_identifier_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_left_brother_id = left_brother_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_mode = SYN_NODE_FORMULA_FOLLOW;
    g_SynTree.pSynNodeList[ tempIndex ].n_right_brother_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_son_id = INVALID_ID;
    /* [ 2 ] fix for father and left brother */
    FIX_FATHER_LBROTHER( father_ID, left_brother_ID, tempIndex )
    g_SynTree.n_node_num++;
    CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
    /* [ 3 ] check the first byte */
    JUMP_SPACES( fileField )
    if( '+' == fileField->current_ch ){
        /* [ 4 ] make a node for '+' */
        tempIndex = g_SynTree.n_node_num;
        g_SynTree.pSynNodeList[ tempIndex ].n_father_id = tempIndex - 1;
        g_SynTree.pSynNodeList[ tempIndex ].n_identifier_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_left_brother_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_mode = SYN_NODE_ADD;
        g_SynTree.pSynNodeList[ tempIndex ].n_right_brother_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_son_id = INVALID_ID;
        /* [ 4.1 ] fix for father and left brother */
        FIX_FATHER_LBROTHER( tempIndex - 1, INVALID_ID, tempIndex )
        g_SynTree.n_node_num++;
        CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
    } else if( '-' ==  fileField->current_ch ){
        /* [ 5 ] make a node for '-' */
        tempIndex = g_SynTree.n_node_num;
        g_SynTree.pSynNodeList[ tempIndex ].n_father_id = tempIndex - 1;
        g_SynTree.pSynNodeList[ tempIndex ].n_identifier_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_left_brother_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_mode = SYN_NODE_SUB;
        g_SynTree.pSynNodeList[ tempIndex ].n_right_brother_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_son_id = INVALID_ID;
        /* [ 5.1 ] fix for father and left brother */
        FIX_FATHER_LBROTHER( tempIndex - 1, INVALID_ID, tempIndex )
        g_SynTree.n_node_num++;
        CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
    } else if( '*' == fileField->current_ch ){
        /* [ 6 ] make a node for '*' */
        tempIndex = g_SynTree.n_node_num;
        g_SynTree.pSynNodeList[ tempIndex ].n_father_id = tempIndex - 1;
        g_SynTree.pSynNodeList[ tempIndex ].n_identifier_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_left_brother_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_mode = SYN_NODE_MUT;
        g_SynTree.pSynNodeList[ tempIndex ].n_right_brother_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_son_id = INVALID_ID;
        /* [ 6.1 ] fix for father and left brother */
        FIX_FATHER_LBROTHER( tempIndex - 1, INVALID_ID, tempIndex )
        g_SynTree.n_node_num++;
        CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
    } else if( '/' == fileField->current_ch ){
        /* [ 7 ] make a node for '/' */
        tempIndex = g_SynTree.n_node_num;
        g_SynTree.pSynNodeList[ tempIndex ].n_father_id = tempIndex - 1;
        g_SynTree.pSynNodeList[ tempIndex ].n_identifier_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_left_brother_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_mode = SYN_NODE_DIV;
        g_SynTree.pSynNodeList[ tempIndex ].n_right_brother_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_son_id = INVALID_ID;
        /* [ 7.1 ] fix for father and left brother */
        FIX_FATHER_LBROTHER( tempIndex - 1, INVALID_ID, tempIndex )
        g_SynTree.n_node_num++;
        CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
    } else{
        /* empty follow */
        return 1;
    }
    /* [ 8 ] deal with FORMULA */
    ret = FORMULA( fileField, tempIndex, tempIndex - 1 );
    if( 0 == ret ){
        return 0;
    }

    return 1;
}
int BOOL_FORMULA_FOLLOW(FileField *fileField, int left_brother_ID, int father_ID){
    int ret = 0;
    char *func_name="BOOL_FORMULA_FOLLOW";
    unsigned int tempIndex = 0;
    short n_mode = 0;
    /* [ 1 ] make a node for 'BOOL_FORMULA_FOLLOW' */
    tempIndex = g_SynTree.n_node_num;
    g_SynTree.pSynNodeList[ tempIndex ].n_father_id = father_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_identifier_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_left_brother_id = left_brother_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_mode = SYN_NODE_BOOL_FORMULA_FOLLOW;
    g_SynTree.pSynNodeList[ tempIndex ].n_right_brother_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_son_id = INVALID_ID;
    /* [ 2 ] fix for father and left brother */
    FIX_FATHER_LBROTHER( father_ID, left_brother_ID, tempIndex )
    g_SynTree.n_node_num++;
    CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
    /* [ 3 ] check the operator, maybe two bytes */
    JUMP_SPACES( fileField )
    if( '|' == fileField->current_ch ){
        /* [ 4 ] deal with the operator '||' */
        fileField->current_ch = fgetc( fileField->fp );
        CHECK_NEW_LINE( fileField )
        if( '|' != fileField->current_ch ){
            report_syntax_error( func_name, "Invalid operator.", fileField->n_current_line );
            return 0;
        }
        /* [ 4.1 ] mode is '||' */
        n_mode = SYN_NODE_OR;
        /* [ 4.2 ] jump spaces in the end */
        GET_NEW_CHAR_JUMP_SPACE( fileField )
    } else if( '&' == fileField->current_ch){
        /* [ 5 ] deal with the operator '&&' */
        fileField->current_ch = fgetc( fileField->fp );
        CHECK_NEW_LINE( fileField )
        if( '&' != fileField->current_ch ){
            report_syntax_error( func_name, "Invalid operator.", fileField->n_current_line );
            return 0;
        }
        /* [ 5.1 ] mode is '||' */
        n_mode = SYN_NODE_AND;
        /* [ 5.2 ] jump spaces in the end */
        GET_NEW_CHAR_JUMP_SPACE( fileField )
    } else if( '<' == fileField->current_ch){
        /* [ 6 ] deal with the operator '<' or '<=' */
        fileField->current_ch = fgetc( fileField->fp );
        CHECK_NEW_LINE( fileField )
        if( '=' != fileField->current_ch ){
            /* [ 6.1 ] mode is '<' */
            n_mode = SYN_NODE_LESS;
        } else{
            /* [ 6.2 ] mode is '<=' */
            n_mode = SYN_NODE_NOT_MORE;
            /* [ 6.3 ] jump spaces in the end */
            GET_NEW_CHAR_JUMP_SPACE( fileField )
        }
    } else if( '>' == fileField->current_ch){
        /* [ 7 ] deal with the operator '>' or '>=' */
        fileField->current_ch = fgetc( fileField->fp );
        CHECK_NEW_LINE( fileField )
        if( '=' != fileField->current_ch ){
            /* [ 7.1 ] mode is '>' */
            n_mode = SYN_NODE_MORE;
        } else{
            /* [ 7.2 ] mode is '>=' */
            n_mode = SYN_NODE_NOT_LESS;
            /* [ 7.3 ] jump spaces in the end */
            GET_NEW_CHAR_JUMP_SPACE( fileField )
        }
    } else if( '=' == fileField->current_ch){
        /* [ 8 ] deal with the operator '==' */
        fileField->current_ch = fgetc( fileField->fp );
        CHECK_NEW_LINE( fileField )
        if( '=' != fileField->current_ch ){
            report_syntax_error( func_name, "Invalid operator.", fileField->n_current_line );
            return 0;
        }
        /* [ 8.1 ] mode is '==' */
        n_mode = SYN_NODE_EQ;
        /* [ 8.2 ] jump spaces in the end */
        GET_NEW_CHAR_JUMP_SPACE( fileField )
    } else if( '!' == fileField->current_ch){
        /* [ 9 ] deal with the operator '!=' */
        fileField->current_ch = fgetc( fileField->fp );
        CHECK_NEW_LINE( fileField )
        if( '=' != fileField->current_ch ){
            report_syntax_error( func_name, "Invalid operator.", fileField->n_current_line );
            return 0;
        }
        /* [ 9.1 ] mode is '!=' */
        n_mode = SYN_NODE_NOT_EQ;
        /* [ 9.2 ] jump spaces in the end */
        GET_NEW_CHAR_JUMP_SPACE( fileField )
    } else if( '+' == fileField->current_ch){
        /* [ 10 ] deal with the operator '+' */
        n_mode = SYN_NODE_ADD;
        /* [ 10.1 ] jump spaces in the end */
        GET_NEW_CHAR_JUMP_SPACE( fileField )
    } else if( '-' == fileField->current_ch){
        /* [ 11 ] deal with the operator '-' */
        n_mode = SYN_NODE_SUB;
        /* [ 11.1 ] jump spaces in the end */
        GET_NEW_CHAR_JUMP_SPACE( fileField )
    } else if( '*' == fileField->current_ch){
        /* [ 12 ] deal with the operator '*' */
        n_mode = SYN_NODE_MUT;
        /* [ 12.1 ] jump spaces in the end */
        GET_NEW_CHAR_JUMP_SPACE( fileField )
    } else if( '/' == fileField->current_ch){
        /* [ 13 ] deal with the operator '/' */
        n_mode = SYN_NODE_DIV;
        /* [ 13.1 ] jump spaces in the end */
        GET_NEW_CHAR_JUMP_SPACE( fileField )
    } else{
        /* empty follow */
        return 1;
    }
    /* [ 14 ] make a node for the operator*/
    tempIndex = g_SynTree.n_node_num;
    g_SynTree.pSynNodeList[ tempIndex ].n_father_id = tempIndex - 1;
    g_SynTree.pSynNodeList[ tempIndex ].n_identifier_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_left_brother_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_mode = n_mode;
    g_SynTree.pSynNodeList[ tempIndex ].n_right_brother_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_son_id = INVALID_ID;
    /* [ 15 ] fix for father and left brother */
    FIX_FATHER_LBROTHER( tempIndex - 1, INVALID_ID, tempIndex )
    g_SynTree.n_node_num++;
    CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
    /* [ 16 ] deal with BOOL_FORMULA */
    ret = BOOL_FORMULA( fileField, tempIndex, tempIndex - 1 );
    if( 0 == ret ){
        return 0;
    }

    return 1;
}
int FUNC_CALL(FileField *fileField, int left_brother_ID, int father_ID){
    int ret = 0;
    char *func_name="FUNC_CALL";
    unsigned int tempIndex = 0;
    unsigned int ident_index = 0;
    IdentId_P p_cur_id = NULL;
    /* [ 1 ] make a node for 'FUNC_CALL' */
    tempIndex = g_SynTree.n_node_num;
    g_SynTree.pSynNodeList[ tempIndex ].n_father_id = father_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_identifier_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_left_brother_id = left_brother_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_mode = SYN_NODE_FUNC_CALL;
    g_SynTree.pSynNodeList[ tempIndex ].n_right_brother_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_son_id = INVALID_ID;
    /* [ 2 ] fix for father and left brother */
    FIX_FATHER_LBROTHER( father_ID, left_brother_ID, tempIndex )
    g_SynTree.n_node_num++;
    CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
    /* [ 3 ] find the identifier in IdTable */
    ret = find_in_IdTable(fileField, fileField->name_buf, (int)strlen(fileField->name_buf), &ident_index);
    if( 0 == ret ){
        return 0;
    }
    p_cur_id = &g_IdTable.pIdList[ ident_index ];
    if( p_cur_id->n_mode != SYN_NODE_FUNID ){
        report_syntax_error( func_name, "Function can't be called, it's an identifier name.", fileField->n_current_line );
        return 0;
    }
    /* [ 4 ] make a node for the func_id */
    tempIndex = g_SynTree.n_node_num;
    g_SynTree.pSynNodeList[ tempIndex ].n_father_id = tempIndex - 1;
    g_SynTree.pSynNodeList[ tempIndex ].n_identifier_id = ident_index;
    g_SynTree.pSynNodeList[ tempIndex ].n_left_brother_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_mode = SYN_NODE_FUNID;
    g_SynTree.pSynNodeList[ tempIndex ].n_right_brother_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_son_id = INVALID_ID;
    /* [ 5 ] fix for father and left brother */
    FIX_FATHER_LBROTHER( tempIndex - 1, INVALID_ID, tempIndex )
    g_SynTree.n_node_num++;
    CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
    /* [ 6 ] check the '(' */
    JUMP_SPACES( fileField )
    if( '(' != fileField->current_ch ){
        report_syntax_error( func_name, "Missing '('.", fileField->n_current_line );
        return 0;
    }
    /* [ 7 ] check the ')' */
    GET_NEW_CHAR_JUMP_SPACE( fileField )
    if( ')' != fileField->current_ch ){
        report_syntax_error( func_name, "Missing ')'.", fileField->n_current_line );
        return 0;
    }
    /* [ 8 ] check the ';' */
    GET_NEW_CHAR_JUMP_SPACE( fileField )
    if( ';' != fileField->current_ch ){
        report_syntax_error( func_name, "Missing ';'.", fileField->n_current_line );
        return 0;
    }

    return 1;
}
int add_to_IdTable(FileField * fileField, char *id_name, int length, short mode, unsigned int * p_ident_index){
    char first_index = 0;
    char second_index = 0;
    IdentId_P cur_IdentId_list = NULL;
    unsigned int index = 0;
    unsigned int temp = 0;
    char *func_name = "add_to_IdTable";

    if( length <= 0 ){
        report_internal_error(func_name, __LINE__);
        return 0;
    }
    if( id_name[0] >= 'A' && id_name[0] <= 'Z' ){
        first_index = id_name[0] - 'A';
    } else if( id_name[0] >= 'a' && id_name[0] <= 'z' ){
        first_index = id_name[0] - 'a' + 26;
    } else{
        first_index = 51;
    }
    if( length > 1 ){
        if( id_name[1] >= 'A' && id_name[1] <= 'Z' ){
            second_index = id_name[1] - 'A';
        } else if( id_name[1] >= 'a' && id_name[1] <= 'z' ){
            second_index = id_name[1] - 'a' + 26;
        } else if( id_name[1] >= '0' && id_name[1] <= '9' ){
            second_index = id_name[1] - '0' + 52;
        } else{
            second_index = 61;
        }
    }
    temp = g_IdTable.two_level_index[ first_index ][ second_index ];

    while( temp != INVALID_ID ){
        /* a list is found */
        cur_IdentId_list = &g_IdTable.pIdList[temp];
        if( strcmp( cur_IdentId_list->str_name, id_name ) == 0 ){
            /* already exist */
            report_syntax_error( func_name, "Re-definition error.", fileField->n_current_line );
            return 0;
        }
        temp = cur_IdentId_list->n_next_identifier_id;
    }
    if( g_IdTable.n_id_num + 1 > MAX_SYN_NODE_NUM ){
        report_syntax_error( func_name, "Too many identifiers.", fileField->n_current_line );
        return 0;
    }
    index = g_IdTable.n_id_num;
    g_IdTable.n_id_num++;
    if( NULL != cur_IdentId_list ){
        cur_IdentId_list->n_next_identifier_id = index;
    } else{
        /* create a new list for this id */
        g_IdTable.two_level_index[ first_index ][ second_index ] = index;
    }
    g_IdTable.pIdList[index].n_mode = mode;
    g_IdTable.pIdList[index].n_next_identifier_id = INVALID_ID;
    strcpy_s( g_IdTable.pIdList[index].str_name, MAX_ID_LENGTH+1, id_name );
    *p_ident_index = index;

    return 1;
}

int find_in_IdTable(FileField * fileField, char *id_name, int length, unsigned int * p_ident_index){
    char first_index = 0;
    char second_index = 0;
    IdentId_P cur_IdentId_list = NULL;
    unsigned int index = 0;
    unsigned int temp = 0;
    char *func_name = "find_in_IdTable";

    if( length <= 0 ){
        report_syntax_error( func_name, "Identifier not specified.", fileField->n_current_line );
        return 0;
    }
    if( id_name[0] >= 'A' && id_name[0] <= 'Z' ){
        first_index = id_name[0] - 'A';
    } else if( id_name[0] >= 'a' && id_name[0] <= 'z' ){
        first_index = id_name[0] - 'a' + 26;
    } else{
        first_index = 51;
    }
    if( length > 1 ){
        if( id_name[1] >= 'A' && id_name[1] <= 'Z' ){
            second_index = id_name[1] - 'A';
        } else if( id_name[1] >= 'a' && id_name[1] <= 'z' ){
            second_index = id_name[1] - 'a' + 26;
        } else if( id_name[1] >= '0' && id_name[1] <= '9' ){
            second_index = id_name[1] - '0' + 52;
        } else{
            second_index = 61;
        }
    }
    temp = g_IdTable.two_level_index[ first_index ][ second_index ];

    while( temp != INVALID_ID ){
        /* a list is found */
        cur_IdentId_list = &g_IdTable.pIdList[temp];
        if( strcmp( cur_IdentId_list->str_name, id_name ) == 0 ){
            *p_ident_index = temp;
            return 1;
        }
        temp = cur_IdentId_list->n_next_identifier_id;
    }
    report_syntax_error( func_name, "Identifier not specified.", fileField->n_current_line );
    return 0;
}

int get_number( FileField * fileField, int * pOutValue){
    char *func_name = "get_number";
    int tempValue1 = 0;
    int tempValue2 = 0;
    int b_sign = 0;/* 0 ==> no sign ,  1 ==> '+' , -1 ==> '-'  */
    /* [ 1 ] check the sign */
    if( '-' == fileField->current_ch ){
        b_sign = -1;
        fileField->current_ch = fgetc( fileField->fp );
        CHECK_NEW_LINE( fileField )
    } else if( '+' == fileField->current_ch ){
        b_sign = 1;
        fileField->current_ch = fgetc( fileField->fp );
        CHECK_NEW_LINE( fileField )
    }
    /* [ 2 ] check the first number */
    if( fileField->current_ch < '0' || fileField->current_ch > '9' ){
        report_syntax_error( func_name, "Invalid character.", fileField->n_current_line );
        return 0;
    }
    while( fileField->current_ch >= '0' && fileField->current_ch <= '9' ){
        tempValue1 = tempValue2;
        tempValue2 = tempValue2 * 10 + fileField->current_ch - '0';
        if( tempValue1 > tempValue2 ){
            /* [ 3 ] deal with overflow */
            report_syntax_error( func_name, "Integer overflow.", fileField->n_current_line );
            return 0;
        }
        fileField->current_ch = fgetc( fileField->fp );
        CHECK_NEW_LINE( fileField )        
    }
    if( -1 == b_sign ){
        tempValue2 = ~tempValue2 + 1;
    }
    if( tempValue2 > SHORT_MAX || tempValue2 < SHORT_MIN ){
        /* [ 4 ] deal with overflow. Note: using 16bit-int for EXE file */
        report_syntax_error( func_name, "Integer overflow.", fileField->n_current_line );
        return 0;
    }
    *pOutValue = (int)tempValue2;


    return 1;
}
static void print_syntax_node( FILE* fp, SynNode_P p_node ){
    char buffer[128];
    buffer[0] = '\0';
    switch( p_node->n_mode ){
    case SYN_NODE_HEAD:
        strcpy_s( buffer, 128, "head" );
        break;
    case SYN_NODE_VARID:
        strcpy_s( buffer, 128, "VARID" );
        break;
    case SYN_NODE_FUNID:
        strcpy_s( buffer, 128, "FUNID" );
        break;
    case SYN_NODE_MAINFUNID:
        strcpy_s( buffer, 128, "main" );
        break;
    case SYN_NODE_BODY:
        strcpy_s( buffer, 128, "BODY" );
        break;
    case SYN_NODE_DEFINITION:
        strcpy_s( buffer, 128, "DEFINITION" );
        break;
    case SYN_NODE_VAR_DEF:
        strcpy_s( buffer, 128, "VAR_DEF" );
        break;
    case SYN_NODE_FUNC_DEF:
        strcpy_s( buffer, 128, "FUNC_DEF" );
        break;
    case SYN_NODE_VAR_DEFINITION:
        strcpy_s( buffer, 128, "VAR_DEFINITION" );
        break;
    case SYN_NODE_STATEMENT_LIST:
        strcpy_s( buffer, 128, "STATEMENT_LIST" );
        break;
    case SYN_NODE_ASSIGN_STMT:
        strcpy_s( buffer, 128, "ASSIGN_STMT" );
        break;
    case SYN_NODE_IF_STMT:
        strcpy_s( buffer, 128, "IF_STMT" );
        break;
    case SYN_NODE_FOR_STMT:
        strcpy_s( buffer, 128, "FOR_STMT" );
        break;
    case SYN_NODE_WHILE_STMT:
        strcpy_s( buffer, 128, "WHILE_STMT" );
        break;
    case SYN_NODE_FORMULA:
        strcpy_s( buffer, 128, "FORMULA" );
        break;
    case SYN_NODE_BOOL_FORMULA:
        strcpy_s( buffer, 128, "BOOL_FORMULA" );
        break;
    case SYN_NODE_FORMULA_FOLLOW:
        strcpy_s( buffer, 128, "FORMULA_FOLLOW" );
        break;
    case SYN_NODE_NUMBER:
        strcpy_s( buffer, 128, "NUMBER" );
        break;
    case SYN_NODE_L_parenthesis:
        strcpy_s( buffer, 128, "(" );
        break;
    case SYN_NODE_R_parenthesis:
        strcpy_s( buffer, 128, ")" );
        break;
    case SYN_NODE_ADD:
        strcpy_s( buffer, 128, "+" );
        break;
    case SYN_NODE_SUB:
        strcpy_s( buffer, 128, "-" );
        break;
    case SYN_NODE_MUT:
        strcpy_s( buffer, 128, "*" );
        break;
    case SYN_NODE_DIV:
        strcpy_s( buffer, 128, "/" );
        break;
    case SYN_NODE_AND:
        strcpy_s( buffer, 128, "&&" );
        break;
    case SYN_NODE_OR:
        strcpy_s( buffer, 128, "||" );
        break;
    case SYN_NODE_LESS:
        strcpy_s( buffer, 128, "<" );
        break;
    case SYN_NODE_MORE:
        strcpy_s( buffer, 128, ">" );
        break;
    case SYN_NODE_EQ:
        strcpy_s( buffer, 128, "==" );
        break;
    case SYN_NODE_NOT_LESS:
        strcpy_s( buffer, 128, ">=" );
        break;
    case SYN_NODE_NOT_MORE:
        strcpy_s( buffer, 128, "<=" );
        break;
    case SYN_NODE_NOT_EQ:
        strcpy_s( buffer, 128, "!=" );
        break;
    case SYN_NODE_BOOL_FORMULA_FOLLOW:
        strcpy_s( buffer, 128, "BOOL_FORMULA_FOLLOW" );
        break;
    case SYN_NODE_EMPTY:
        strcpy_s( buffer, 128, "EMPTY" );
        break;
    case SYN_NODE_FUNC_CALL:
        strcpy_s( buffer, 128, "FUNC_CALL" );
        break;
    }

    fprintf( fp,"n_mode = '%s';", buffer);
    if( SYN_NODE_VARID == p_node->n_mode || SYN_NODE_FUNID == p_node->n_mode ){
        fprintf( fp, "id name = '%s';", g_IdTable.pIdList[ p_node->n_identifier_id ].str_name );
    }
    fprintf( fp,"father_id = '%d';", (int)p_node->n_father_id);
    fprintf( fp,"left_brother_id = '%d';", (int)p_node->n_left_brother_id);
    fprintf( fp,"right_brother_id = '%d';", (int)p_node->n_right_brother_id);
    fprintf( fp,"son_id = '%d';", (int)p_node->n_son_id);
    if( SYN_NODE_NUMBER == p_node->n_mode ){
        fprintf( fp, "value = '%d';", p_node->n_int_value );
    }
}
void debug_syntax( FILE* fp ){
    unsigned int i = 0;
    for( i = 0; i < g_SynTree.n_node_num; i++ ){
        fprintf( fp,"id = '%6d';", i);
        print_syntax_node( fp, &g_SynTree.pSynNodeList[ i ] );
        fprintf(fp,"\n*******************************************************************************\n");
    }
}


语义分析器

/** scmpsem.c
====================================================================
This is the base source file for Semantic Analyze


====================================================================
 */

#include "scmpsem.h"
int sem_deal_with_header();
int sem_deal_with_data();
int sem_deal_with_code();
int sem_deal_with_DEFINITION(SynNode_P pSynNode);
int sem_deal_with_BODY(SynNode_P pSynNode);
int sem_deal_with_FUNC_DEF(SynNode_P pSynNode);
int sem_deal_with_STATEMENT_LIST(SynNode_P pSynNode);
int sem_deal_with_ASSIGN_STMT(SynNode_P pSynNode);
int sem_deal_with_IF_STMT(SynNode_P pSynNode);
int sem_deal_with_FOR_STMT(SynNode_P pSynNode);
int sem_deal_with_WHILE_STMT(SynNode_P pSynNode);
int sem_deal_with_FUNC_CALL(SynNode_P pSynNode);
int sem_deal_with_FORMULA(SynNode_P pSynNode);
int sem_deal_with_BOOL_FORMULA(SynNode_P pSynNode);

static int push( SEM_STACK_NODE *in_node );
static int pop( SEM_STACK_NODE *out_node );
#define MY_PUSH( p_in_node )\
    {\
        if( 0 == push( p_in_node ) ){\
           printf("POP error at line '%d' \n", __LINE__ );\
           return 0;\
        }\
    }
#define MY_POP( p_out_node )\
    {\
        if( 0 == pop( p_out_node ) ){\
           printf("POP error at line '%d' \n", __LINE__ );\
           return 0;\
        }\
    }
static int check_caculate( SEM_STACK_NODE *cur_node );
static int caculate_AX_BX_by_op( SEM_STACK_NODE *op_node );

int initialize_SemEnv(){
    g_SemEnv.n_SignCurrentId = 0;
    g_SemEnv.pAsmFile = NULL;
    fopen_s( &g_SemEnv.pAsmFile, ASM_FILE_NAME , "w" );
    if( NULL == g_SemEnv.pAsmFile ){
        printf("Can't open source file '%s'. exit.\n", ASM_FILE_NAME );
        return 0;
    }
    g_SemEnv.s_sem_stack.n_num = 0;
    g_SemEnv.s_sem_stack.sem_node_list = ( SEM_STACK_NODE * )malloc( sizeof(SEM_STACK_NODE) * MAX_STACK_NUM );
    if( NULL == g_SemEnv.s_sem_stack.sem_node_list ){
        printf("Memery not enough while initializing semantic stack.\n" );
        return 0;
    }
    return 1;
}
int finalize_SemEnv(){
    g_SemEnv.n_SignCurrentId = 0;
    MY_HELP_CLOSE( g_SemEnv.pAsmFile );
    g_SemEnv.s_sem_stack.n_num = 0;
    MY_HELP_FREE( g_SemEnv.s_sem_stack.sem_node_list );
    return 1;
}


int semantic_analyzer(){
    int ret = 0;
    char * func_name="semantic_analyzer";

    ret = initialize_SemEnv();
    if( 0 == ret ){
        printf("semantic_analyzer exit with initialize error.\n");
        finalize_SemEnv();
        return 0;
    }
    /* [ 1 ] deal with header */
    sem_deal_with_header();
    /* [ 2 ] deal with data */
    ret = sem_deal_with_data();
    if( 0 == ret ){
        printf("semantic_analyzer exit with internal error.\n");
        finalize_SemEnv();
        return 0;
    }
    /* [ 3 ] deal with code */
    ret =  sem_deal_with_code();
    if( 0 == ret ){
        printf("semantic_analyzer exit with internal error.\n");
        finalize_SemEnv();
        return 0;
    }
    /* [ 4 ] deal with Ending */
    fprintf( g_SemEnv.pAsmFile, ASM_END_MAIN );

    finalize_SemEnv();
    return 1;
}
int sem_deal_with_header(){
    fprintf( g_SemEnv.pAsmFile, ASM_HEADER );

    return 1;
}
int sem_deal_with_data(){
    unsigned int index = 0;
    char * p_VarName = NULL;

    /* [ 1 ] data header */
    fprintf( g_SemEnv.pAsmFile, ASM_DATA_HEADER );
    /* [ 2 ] Variable definition */
    for( index = 0; index < g_IdTable.n_id_num; index++ ){
        if( SYN_NODE_VARID == g_IdTable.pIdList[ index ].n_mode ){
            p_VarName = g_IdTable.pIdList[ index ].str_name;
            fprintf( g_SemEnv.pAsmFile, ASM_VAR_DEF, p_VarName, p_VarName, p_VarName );
        }
    }

    return 1;
}
int sem_deal_with_code(){
    int ret = 0;
    SynNode_P pCurSynNode = NULL;

    /* [ 1 ] code header */
    fprintf( g_SemEnv.pAsmFile, ASM_CODE_HEADER );
    /* [ 2 ] deal with DEFINITION */
    /* [ 2.1 ] Get the first node of DEFINITION */
    pCurSynNode = &g_SynTree.pSynNodeList[1];
    ret = sem_deal_with_DEFINITION( pCurSynNode );
    if( 0 == ret ){
        return 0;
    }
    /* [ 3 ] deal with main */
    /* [ 3.1 ] Get the node of 'main' */
    fprintf( g_SemEnv.pAsmFile, "Main  PROC\nMOV AX, DGROUP\nMOV DS, AX\n" );
    CHECK_SYN_NODE_ID( pCurSynNode->n_right_brother_id )
    pCurSynNode = &g_SynTree.pSynNodeList[ pCurSynNode->n_right_brother_id ];
    /* [ 3.2 ] Get the node of 'BODY' */
    CHECK_SYN_NODE_ID( pCurSynNode->n_right_brother_id )
    pCurSynNode = &g_SynTree.pSynNodeList[ pCurSynNode->n_right_brother_id ];
    ret = sem_deal_with_BODY( pCurSynNode );
    if( 0 == ret ){
        return 0;
    }
#ifdef DEBUG_SEM
    debug_sem();
#endif
    /* [ 3.3 ] Tail of 'main' */
    fprintf( g_SemEnv.pAsmFile, "MOV  AX, 4C00H\nINT  21H\nMain  ENDP\n" );
    return 1;
}
int sem_deal_with_DEFINITION( SynNode_P pSynNode ){
    SynNode_P pCurSynNode = NULL;
    int ret = 0;

    /* [ 1 ] Get the first node of DEFINITION */
    pCurSynNode = pSynNode;
    while( pCurSynNode != NULL && pCurSynNode->n_son_id != INVALID_ID ){
        /* [ 1.1 ] check the son */
        pCurSynNode = &g_SynTree.pSynNodeList[ pCurSynNode->n_son_id ];
        if( SYN_NODE_FUNC_DEF == pCurSynNode->n_mode ){
            /* [ 1.1.1 ] it's FUNC definition, deal with it */
            ret = sem_deal_with_FUNC_DEF( pCurSynNode );
            if( 0 == ret ){
                return 0;
            }

        }
            /* [ 1.1.2 ] deal with right brother of it */
        if( pCurSynNode->n_right_brother_id != INVALID_ID ){
            pCurSynNode = &g_SynTree.pSynNodeList[ pCurSynNode->n_right_brother_id ];
        } else{
            pCurSynNode = NULL;
        }
    }
    return 1;
}
int sem_deal_with_FUNC_DEF(SynNode_P pSynNode){
    SynNode_P pCurSynNode = NULL;
    IdentId_P pId = NULL;
    int ret = 0;
    /* [ 1 ] Function Header */
    /* [ 1.1 ] Get the function id */
    CHECK_SYN_NODE_ID( pSynNode->n_son_id )
    pCurSynNode = &g_SynTree.pSynNodeList[ pSynNode->n_son_id ];
    CHECK_SYN_NODE_ID( pCurSynNode->n_identifier_id )
    pId = &g_IdTable.pIdList[ pCurSynNode->n_identifier_id ];
    fprintf( g_SemEnv.pAsmFile, "%s  PROC\n", pId->str_name );
    /* [ 1.2 ] Save the current Registers */
    fprintf( g_SemEnv.pAsmFile, "PUSH  BP\n", pId->str_name );
    fprintf( g_SemEnv.pAsmFile, "MOV  BP, SP\n", pId->str_name );
    fprintf( g_SemEnv.pAsmFile, "PUSH  DS\n", pId->str_name );
    /* [ 2 ] deal with 'BODY' */
    CHECK_SYN_NODE_ID( pCurSynNode->n_right_brother_id )
    pCurSynNode = &g_SynTree.pSynNodeList[ pCurSynNode->n_right_brother_id ];
    ret = sem_deal_with_BODY( pCurSynNode );
    if( 0 == ret ){
        return 0;
    }
    /* [ 3 ] Function Tail */
    /* [ 3.1 ] Backup the current Registers */
    fprintf( g_SemEnv.pAsmFile, "POP  DS\n", pId->str_name );
    fprintf( g_SemEnv.pAsmFile, "MOV  SP, BP\n", pId->str_name );
    fprintf( g_SemEnv.pAsmFile, "POP  BP\n", pId->str_name );
    fprintf( g_SemEnv.pAsmFile, "RET\n%s  ENDP\n", pId->str_name );
    return 1;
}
int sem_deal_with_BODY(SynNode_P pSynNode){
    SynNode_P pCurSynNode = NULL;
    int ret = 0;
    
    /* [ 1 ] get node of 'VAR_DEFINITION' */
    CHECK_SYN_NODE_ID( pSynNode->n_son_id )
    pCurSynNode = &g_SynTree.pSynNodeList[ pSynNode->n_son_id ];
    /* [ 2 ] deal with  'STATEMENT_LIST' */
    if( INVALID_ID != pCurSynNode->n_right_brother_id ){
        pCurSynNode = &g_SynTree.pSynNodeList[ pCurSynNode->n_right_brother_id ];
        ret = sem_deal_with_STATEMENT_LIST( pCurSynNode );
        if( 0 == ret ){
            return 0;
        }
    }
    return 1;
}
int sem_deal_with_STATEMENT_LIST(SynNode_P pSynNode){
    SynNode_P pCurSynNode = NULL;
    int ret = 0;

    if( INVALID_ID == pSynNode->n_son_id ){
        /* empty statement list */
        return 1;
    }
    /* [ 1 ] deal with first statement */
    pCurSynNode = &g_SynTree.pSynNodeList[ pSynNode->n_son_id ];
    switch( pCurSynNode->n_mode ){
        case SYN_NODE_ASSIGN_STMT:
            ret = sem_deal_with_ASSIGN_STMT( pCurSynNode );
            break;
        case SYN_NODE_IF_STMT:
            ret = sem_deal_with_IF_STMT( pCurSynNode );
            break;
        case SYN_NODE_FOR_STMT:
            ret = sem_deal_with_FOR_STMT( pCurSynNode );
            break;
        case SYN_NODE_WHILE_STMT:
            ret = sem_deal_with_WHILE_STMT( pCurSynNode );
            break;
        case SYN_NODE_FUNC_CALL:
            ret = sem_deal_with_FUNC_CALL( pCurSynNode );
            break;
    }
    if( 0 == ret ){
        return 0;
    }
    /* [ 2 ] deal with following statement */
    CHECK_SYN_NODE_ID( pCurSynNode->n_right_brother_id )
    pCurSynNode = &g_SynTree.pSynNodeList[ pCurSynNode->n_right_brother_id ];
    ret = sem_deal_with_STATEMENT_LIST( pCurSynNode );
    return ret;
}
int sem_deal_with_ASSIGN_STMT(SynNode_P pSynNode){
    SynNode_P pCurSynNode = NULL;
    int ret = 0;
    IdentId_P pId = NULL;
    /* [ 1 ] get the var id */
    CHECK_SYN_NODE_ID( pSynNode->n_son_id )
    pCurSynNode = &g_SynTree.pSynNodeList[ pSynNode->n_son_id ];
    CHECK_SYN_NODE_ID( pCurSynNode->n_identifier_id )
    pId = &g_IdTable.pIdList[ pCurSynNode->n_identifier_id ];

    /* [ 2 ] deal with FORMULA */
    CHECK_SYN_NODE_ID( pCurSynNode->n_right_brother_id )
    pCurSynNode = &g_SynTree.pSynNodeList[ pCurSynNode->n_right_brother_id ];
    ret = sem_deal_with_FORMULA( pCurSynNode );
    if( 0 == ret ){
        return ret;
    }
    /* [ 3 ] deal with assign */
    fprintf( g_SemEnv.pAsmFile, "MOV  %s, AX\n", pId->str_name );

    return 1;
}
int sem_deal_with_IF_STMT(SynNode_P pSynNode){
    SynNode_P pCurSynNode = NULL;
    int ret = 0;
    char str_cur_sign[20];
    /* [ 1 ] deal with BOOL_FORMULA */
    CHECK_SYN_NODE_ID( pSynNode->n_son_id )
    pCurSynNode = &g_SynTree.pSynNodeList[ pSynNode->n_son_id ];
    ret = sem_deal_with_BOOL_FORMULA( pCurSynNode );
    if( 0 == ret ){
        return 0;
    }
    /* [ 2 ] make a sign name. if AX is 0, jump to it. */
    sprintf_s( str_cur_sign, sizeof(str_cur_sign), "SIGN_%d", g_SemEnv.n_SignCurrentId );
    g_SemEnv.n_SignCurrentId++;
    fprintf( g_SemEnv.pAsmFile, "CMP  AX,0\nJE %s\n",  str_cur_sign );
    /* [ 3 ] deal with STATEMENT_LIST */
    CHECK_SYN_NODE_ID( pCurSynNode->n_right_brother_id )
    pCurSynNode = &g_SynTree.pSynNodeList[ pCurSynNode->n_right_brother_id ];
    ret = sem_deal_with_STATEMENT_LIST( pCurSynNode );
    if( 0 == ret ){
        return 0;
    }
    /* [ 4 ] make the sign at the end */
    fprintf( g_SemEnv.pAsmFile, "%s:\n",  str_cur_sign );
    return 1;
}
int sem_deal_with_FOR_STMT(SynNode_P pSynNode){
    SynNode_P pCurSynNode = NULL;
    SynNode_P pSecondAssign = NULL;
    int ret = 0;
    char str_first_sign[20];
    char str_second_sign[20];
    /* [ 1 ] deal with ASSIGN_STMT */
    CHECK_SYN_NODE_ID( pSynNode->n_son_id )
    pCurSynNode = &g_SynTree.pSynNodeList[ pSynNode->n_son_id ];
    if( SYN_NODE_ASSIGN_STMT == pCurSynNode->n_mode ){
        ret = sem_deal_with_ASSIGN_STMT( pCurSynNode );
        if( 0 == ret ){
            return 0;
        }
    }
    /* [ 2 ] make a sign before BOOL_FORMULA */
    sprintf_s( str_first_sign, sizeof(str_first_sign), "SIGN_%d", g_SemEnv.n_SignCurrentId );
    g_SemEnv.n_SignCurrentId++;
    fprintf( g_SemEnv.pAsmFile, "%s:\n",  str_first_sign );
    /* [ 3 ] deal with BOOL_FORMULA */
    CHECK_SYN_NODE_ID( pCurSynNode->n_right_brother_id )
    pCurSynNode = &g_SynTree.pSynNodeList[ pCurSynNode->n_right_brother_id ];
    ret = sem_deal_with_BOOL_FORMULA( pCurSynNode );
    if( 0 == ret ){
        return 0;
    }
    /* [ 4 ] make a sign at the end, if AX=0,jump to it */
    sprintf_s( str_second_sign, sizeof(str_first_sign), "SIGN_%d", g_SemEnv.n_SignCurrentId );
    g_SemEnv.n_SignCurrentId++;
    fprintf( g_SemEnv.pAsmFile, "CMP  AX,0\nJE %s\n",  str_second_sign );
    /* [ 5 ] store the second Assign Statement node */
    CHECK_SYN_NODE_ID( pCurSynNode->n_right_brother_id )
    pCurSynNode = &g_SynTree.pSynNodeList[ pCurSynNode->n_right_brother_id ];
    pSecondAssign = pCurSynNode;
    /* [ 6 ] deal with STATEMENT_LIST */
    CHECK_SYN_NODE_ID( pCurSynNode->n_right_brother_id )
    pCurSynNode = &g_SynTree.pSynNodeList[ pCurSynNode->n_right_brother_id ];
    ret = sem_deal_with_STATEMENT_LIST( pCurSynNode );
    if( 0 == ret ){
        return 0;
    }
    /* [ 7 ] deal with the second Assign Statement */
    if( SYN_NODE_ASSIGN_STMT == pSecondAssign->n_mode ){
        ret = sem_deal_with_ASSIGN_STMT( pSecondAssign );
        if( 0 == ret ){
            return 0;
        }
    }
    /* [ 8 ] jump to first sign */
    fprintf( g_SemEnv.pAsmFile, "JMP %s\n",  str_first_sign );
    /* [ 9 ] store to second sign */
    fprintf( g_SemEnv.pAsmFile, "%s:\n",  str_second_sign );

    return 1;
}
int sem_deal_with_WHILE_STMT(SynNode_P pSynNode){
    SynNode_P pCurSynNode = NULL;
    int ret = 0;
    char str_first_sign[20];
    char str_second_sign[20];
    /* [ 1 ] make a sign before BOOL_FORMULA */
    sprintf_s( str_first_sign, sizeof(str_first_sign), "SIGN_%d", g_SemEnv.n_SignCurrentId );
    g_SemEnv.n_SignCurrentId++;
    fprintf( g_SemEnv.pAsmFile, "%s:\n",  str_first_sign );
    /* [ 2 ] deal with BOOL_FORMULA */
    CHECK_SYN_NODE_ID( pSynNode->n_son_id )
    pCurSynNode = &g_SynTree.pSynNodeList[ pSynNode->n_son_id ];
    ret = sem_deal_with_BOOL_FORMULA( pCurSynNode );
    if( 0 == ret ){
        return 0;
    }
    /* [ 3 ] make a sign at the end, if AX=0,jump to it */
    sprintf_s( str_second_sign, sizeof(str_first_sign), "SIGN_%d", g_SemEnv.n_SignCurrentId );
    g_SemEnv.n_SignCurrentId++;
    fprintf( g_SemEnv.pAsmFile, "CMP  AX,0\nJE %s\n",  str_second_sign );
    /* [ 4 ] deal with STATEMENT_LIST */
    CHECK_SYN_NODE_ID( pCurSynNode->n_right_brother_id )
    pCurSynNode = &g_SynTree.pSynNodeList[ pCurSynNode->n_right_brother_id ];
    ret = sem_deal_with_STATEMENT_LIST( pCurSynNode );
    if( 0 == ret ){
        return 0;
    }
    /* [ 5 ] jump to first sign */
    fprintf( g_SemEnv.pAsmFile, "JMP %s\n",  str_first_sign );
    /* [ 6 ] store to second sign */
    fprintf( g_SemEnv.pAsmFile, "%s:\n",  str_second_sign );

    return 1;
}
int sem_deal_with_FUNC_CALL(SynNode_P pSynNode){
    SynNode_P pCurSynNode = NULL;
    IdentId_P pId = NULL;

    CHECK_SYN_NODE_ID( pSynNode->n_son_id )
    pCurSynNode = &g_SynTree.pSynNodeList[ pSynNode->n_son_id ];
    CHECK_SYN_NODE_ID( pCurSynNode->n_identifier_id )
    pId = &g_IdTable.pIdList[ pCurSynNode->n_identifier_id ];
    fprintf( g_SemEnv.pAsmFile, "CALL  %s\n", pId->str_name );

    return 1;
}
int sem_deal_with_FORMULA(SynNode_P pSynNode){
    char * func_name="sem_deal_with_FORMULA";
    SynNode_P pCurSynNode = NULL;
    IdentId_P pId = NULL;
    int ret = 0;
    unsigned int n_CurrentNodeId = 0;
    SEM_STACK_NODE sem_node;
    SEM_STACK_NODE op_node;
    n_CurrentNodeId = pSynNode->n_son_id;
    while( 1 ){
        /* [ 1 ] check the first Node of the Formula */
        CHECK_SYN_NODE_ID( n_CurrentNodeId )
        pCurSynNode = &g_SynTree.pSynNodeList[ n_CurrentNodeId ];
        /* [ 1.1 ] deal with '(' FORMULA ')' */
        if( SYN_NODE_L_parenthesis == pCurSynNode->n_mode ){
            /* [ 1.1.1 ] push '(' into Stack */
            sem_node.n_mode = 7;
            sem_node.n_value = SYN_NODE_L_parenthesis;
            MY_PUSH( &sem_node );
            /* [ 1.1.2 ] deal with FORMULA recursively */
            CHECK_SYN_NODE_ID( pCurSynNode->n_right_brother_id )
            pCurSynNode = &g_SynTree.pSynNodeList[ pCurSynNode->n_right_brother_id ];
            ret = sem_deal_with_FORMULA( pCurSynNode );
            if( 0 == ret ){
                return 0;
            }
            /* [ 1.1.3 ] deal with ')' */
            CHECK_SYN_NODE_ID( pCurSynNode->n_right_brother_id )
            pCurSynNode = &g_SynTree.pSynNodeList[ pCurSynNode->n_right_brother_id ];
            if( SYN_NODE_R_parenthesis != pCurSynNode->n_mode ){
                report_internal_error( func_name, __LINE__ );
                printf("Missing ')' in FORMULA .\n" );
                return 0;
            }
            /* [ 1.1.4 ] caculate current formula between '(' and ')' */
            op_node.n_mode = 0;
            op_node.n_value = SYN_NODE_R_parenthesis;
            ret = check_caculate( &op_node );
            if( 0 == ret ){
                return 0;
            }
        } else if( SYN_NODE_VARID == pCurSynNode->n_mode ){
        /* [ 1.2 ] deal with identifier */
            /* [ 1.2.1 ] make a sem node for the identifier */
            sem_node.n_mode = 0xffff;
            MY_PUSH( &sem_node );
            /* [ 1.2.2 ] make ASM code for the identifier */
            CHECK_SYN_NODE_ID( pCurSynNode->n_identifier_id )
            pId = &g_IdTable.pIdList[ pCurSynNode->n_identifier_id ];
            fprintf( g_SemEnv.pAsmFile, "MOV AX, %s\n", pId->str_name );
            fprintf( g_SemEnv.pAsmFile, "PUSH AX\n" );
        } else {
        /* [ 1.3 ] deal with number */
            /* [ 1.3.1 ] make a sem node for the number */
            sem_node.n_mode = 0xffff;
            MY_PUSH( &sem_node );
            /* [ 1.3.2 ] make ASM code for the number */
            fprintf( g_SemEnv.pAsmFile, "MOV AX, %d\n", pCurSynNode->n_int_value );
            fprintf( g_SemEnv.pAsmFile, "PUSH AX\n" );
        }
        /* [ 2 ]  deal with FORMULA_FOLLOW */
        CHECK_SYN_NODE_ID( pCurSynNode->n_right_brother_id )
        pCurSynNode = &g_SynTree.pSynNodeList[ pCurSynNode->n_right_brother_id ];
        if( INVALID_ID == pCurSynNode->n_son_id ){
            /*=================================================================
            Empty FORMULA_FOLLOW.Clear the stack and finish the caculating 
            =================================================================*/
            while( 1 ){
                MY_POP( &sem_node );
                if( 0 == g_SemEnv.s_sem_stack.n_num ){
                    /* This node is the only node in the stack , finished. */
                    fprintf( g_SemEnv.pAsmFile, "POP AX\n" );
                    return 1;
                }
                MY_POP( &op_node );
                if( 7 == op_node.n_mode ){/* Reach the Beginning of a FOMULA */
                    MY_PUSH( &op_node );
                    MY_PUSH( &sem_node );
                    return 1;
                } else{
                    MY_POP( &sem_node );
                    ret = caculate_AX_BX_by_op( &op_node );
                }
                /* Push the result */
                MY_PUSH( &sem_node );
                if( 0 == ret ){
                    return 0;
                }
                if( 0 == g_SemEnv.s_sem_stack.n_num ){
                    /* This node is the only node in the stack , finished. */
                    fprintf( g_SemEnv.pAsmFile, "POP AX\n" );
                    return 1;
                }
            }
        } else{
            /* [ 2.1 ] deal with operator */
            pCurSynNode = &g_SynTree.pSynNodeList[ pCurSynNode->n_son_id ];
            switch( pCurSynNode->n_mode ){
                case SYN_NODE_ADD:
                case SYN_NODE_SUB:
                    op_node.n_mode = 5;
                    break;
                case SYN_NODE_MUT:
                case SYN_NODE_DIV:
                    op_node.n_mode = 6;
                    break;
                case SYN_NODE_AND:
                    op_node.n_mode = 2;
                    break;
                case SYN_NODE_OR:
                    op_node.n_mode = 1;
                    break;
                case SYN_NODE_LESS:
                case SYN_NODE_MORE:
                case SYN_NODE_NOT_LESS:
                case SYN_NODE_NOT_MORE:
                    op_node.n_mode = 4;
                    break;
                case SYN_NODE_EQ:
                case SYN_NODE_NOT_EQ:
                    op_node.n_mode = 3;
                    break;
                default:
                    printf("Internal error! invalid operator mode '%d' at line '%d'\n", pCurSynNode->n_mode, __LINE__ );
                    return 0;
            }
            op_node.n_value = pCurSynNode->n_mode;
            ret = check_caculate( &op_node );
            if( 0 == ret ){
                return 0;
            }
            /* [ 2.2 ] deal with FORMULA using the while-looping */
            CHECK_SYN_NODE_ID( pCurSynNode->n_right_brother_id )
            pCurSynNode = &g_SynTree.pSynNodeList[ pCurSynNode->n_right_brother_id ];
            n_CurrentNodeId = pCurSynNode->n_son_id;
        }
    }

    return 1;
}
int sem_deal_with_BOOL_FORMULA(SynNode_P pSynNode){
    if( sem_deal_with_FORMULA( pSynNode ) == 0 ){
        return 0;
    }
    return 1;
}
static int push( SEM_STACK_NODE *in_node ){
    unsigned int num = 0;
    num = g_SemEnv.s_sem_stack.n_num;
    if( num >= MAX_STACK_NUM ){
        printf("Internal Error ! semantic stack overflow!\n");
        return 0;
    }
    memcpy( &g_SemEnv.s_sem_stack.sem_node_list[ num ], in_node, sizeof( SEM_STACK_NODE ) );
    g_SemEnv.s_sem_stack.n_num++;
    return 1;
}
static int pop( SEM_STACK_NODE *out_node ){
    unsigned int index = 0;
    index = g_SemEnv.s_sem_stack.n_num;
    index--;
    if( index >= MAX_STACK_NUM ){
        printf("Internal Error ! semantic stack empty!\n");
        return 0;
    }
    memcpy( out_node, &g_SemEnv.s_sem_stack.sem_node_list[ index ], sizeof( SEM_STACK_NODE ) );
    g_SemEnv.s_sem_stack.n_num--;
    return 1;
}
static int check_caculate( SEM_STACK_NODE *cur_node ){
    unsigned int num = 0;
    unsigned short cur_mode = cur_node->n_mode;
    unsigned short last_mode = 0;
    SEM_STACK_NODE sem_node;
    SEM_STACK_NODE op_node;
    num = g_SemEnv.s_sem_stack.n_num;
    if( 0 == cur_mode ){
        /* [ 1 ] deal with ')' */
        /* [ 1.1 ] pop the first node on top of the stack */
        MY_POP( &sem_node );
        if( 0xffff != sem_node.n_mode ){
            printf("Internal Error ! Missing number between '(' and ')' in FORMULA .\n" );
            return 0;
        }
        /* [ 1.2 ] pop the next node on top of the stack */
        MY_POP( &op_node );
        if( 7 == op_node.n_mode ){/* '(' */
            /* push the result of FORMULA between '(' and ')' */
            MY_PUSH( &sem_node );
        } else{/* operator */
            /* [ 1.2 ] pop the second number on top of the stack */
            MY_POP( &sem_node );
            /* [ 1.3 ] caculate current formula between '(' and ')' */
            if( 0 == caculate_AX_BX_by_op( &op_node ) ){
                return 0;
            }
            /* [ 1.4 ] pop the '(' */
            MY_POP( &op_node );
            /* [ 1.5 ] push the result of FORMULA between '(' and ')' */
            MY_PUSH( &sem_node );
        }
    } else{
        /* [ 2 ] deal with other operators */
        if( num >= 2 && num <= MAX_STACK_NUM ){
            last_mode = g_SemEnv.s_sem_stack.sem_node_list[ num-2 ].n_mode;
        }
        if( cur_mode <= last_mode && last_mode != 7 ){/* '(' can't caculate without ')' */
            MY_POP( &sem_node );
            MY_POP( &op_node );
            MY_POP( &sem_node );
            if( 0 == caculate_AX_BX_by_op( &op_node ) ){
                return 0;
            }
            MY_PUSH( &sem_node );
        } else{
            /* do nothing */
        }
        MY_PUSH( cur_node );
    }
    return 1;
}
static int caculate_AX_BX_by_op( SEM_STACK_NODE *op_node ){
    char * func_name = "caculate_AX_BX_by_op";
    char str_first_sign[20];
    char str_second_sign[20];
    /* [ 1 ] pop BX */
    fprintf( g_SemEnv.pAsmFile, "POP  BX\n" );
    /* [ 2 ] pop AX */
    fprintf( g_SemEnv.pAsmFile, "POP  AX\n" );
    /* [ 3 ] caculate */
    switch( op_node->n_mode ){
        case 1: /* || */
            fprintf( g_SemEnv.pAsmFile, "OR AX, BX\n" );
            break;
        case 2: /* && */
            fprintf( g_SemEnv.pAsmFile, "AND AX, BX\n" );
            break;
        case 3:
            if( SYN_NODE_EQ == op_node->n_value ){ /* == */
                fprintf( g_SemEnv.pAsmFile, ";Deal with '=='\n" );
                sprintf_s( str_first_sign, sizeof(str_first_sign), "SIGN_%d", g_SemEnv.n_SignCurrentId );
                g_SemEnv.n_SignCurrentId++;
                sprintf_s( str_second_sign, sizeof(str_second_sign), "SIGN_%d", g_SemEnv.n_SignCurrentId );
                g_SemEnv.n_SignCurrentId++;
                fprintf( g_SemEnv.pAsmFile, "CMP AX, BX\n" );
                fprintf( g_SemEnv.pAsmFile, "JNE %s\n",  str_first_sign );
                fprintf( g_SemEnv.pAsmFile, "MOV AX, 1\n" );
                fprintf( g_SemEnv.pAsmFile, "JMP %s\n", str_second_sign );
                fprintf( g_SemEnv.pAsmFile, "%s:\n",  str_first_sign );
                fprintf( g_SemEnv.pAsmFile, "MOV AX, 0\n" );
                fprintf( g_SemEnv.pAsmFile, "%s:\n",  str_second_sign );
            } else{ /* != */
                fprintf( g_SemEnv.pAsmFile, "XOR AX, BX\n" );
            }
            break;
        case 4:
            if( SYN_NODE_MORE == op_node->n_value ){ /* > */
                fprintf( g_SemEnv.pAsmFile, "SUB BX, AX\n" );
                fprintf( g_SemEnv.pAsmFile, "AND BX, 8000H\n" );
                fprintf( g_SemEnv.pAsmFile, "MOV AX, BX\n" );
            } else if( SYN_NODE_LESS == op_node->n_value ){ /* < */
                fprintf( g_SemEnv.pAsmFile, "SUB AX, BX\n" );
                fprintf( g_SemEnv.pAsmFile, "AND AX, 8000H\n" );
            } else if( SYN_NODE_NOT_LESS == op_node->n_value ){ /* >= */
                fprintf( g_SemEnv.pAsmFile, "SUB AX, BX\n" );
                fprintf( g_SemEnv.pAsmFile, "AND AX, 8000H\n" );
                fprintf( g_SemEnv.pAsmFile, "XOR AX, 8000H\n" );
            } else{ /* <= */
                fprintf( g_SemEnv.pAsmFile, "SUB BX, AX\n" );
                fprintf( g_SemEnv.pAsmFile, "AND BX, 8000H\n" );
                fprintf( g_SemEnv.pAsmFile, "XOR BX, 8000H\n" );
                fprintf( g_SemEnv.pAsmFile, "MOV AX, BX\n" );
            }
            break;
        case 5:
            if( SYN_NODE_ADD == op_node->n_value ){ /* + */
                fprintf( g_SemEnv.pAsmFile, "ADD AX, BX\n" );
            } else{ /* - */
                fprintf( g_SemEnv.pAsmFile, "SUB AX, BX\n" );
            }
            break;
        case 6:
            if( SYN_NODE_MUT == op_node->n_value ){ /* * */
                fprintf( g_SemEnv.pAsmFile, "MUL BX\n" );
            } else{ /* / */
                fprintf( g_SemEnv.pAsmFile, "MOV DX, 0\n" );
                fprintf( g_SemEnv.pAsmFile, "DIV BX\n" );
            }
            break;
        default:
            report_internal_error( func_name, __LINE__ );
            printf("Invalid operator mode '%d'\n", op_node->n_mode );
            return 0;
    }
    /* [ 4 ] push AX */
    fprintf( g_SemEnv.pAsmFile, "PUSH  AX\n" );

    return 1;
}
void debug_sem( ){
    unsigned int i = 0;
    IdentId_P pId = NULL;
    for( i = 0; i < g_IdTable.n_id_num; i++ ){
        pId = &g_IdTable.pIdList[ i ];
        if( SYN_NODE_VARID == pId->n_mode ){
            fprintf( g_SemEnv.pAsmFile, "LEA  AX, Name_%s\nMOV  DX, AX\nMOV  AH, 9\nINT  21H\n", pId->str_name );
            fprintf( g_SemEnv.pAsmFile, "MOV  AX, %s\nPRINTVAL  AX\n", pId->str_name );
            fprintf( g_SemEnv.pAsmFile, ASM_CHANGE_LINE );
        }
    }
}


主函数

/** SimpleCompiler.c
====================================================================
This is the base source file for Main Function


====================================================================
 */

#include "scmppre.h"
#include "scmpstx.h"
#include "scmpsem.h"
int main(int arg_num, char ** args){
    int ret = 0;
    FILE *srcFP = NULL;
    FILE *outFP = NULL;
    char *inputFile = "test.c";
    char *outputFile = "test.c.tmp";
    FileField srcFileField;
#ifdef DEBUG_SYNTAX
    char *debugFile = "test.c.stx";
    FILE * debugfp = NULL;
#endif
    /* Global initializing */
    ret = initialize_IdTable();
    ret &= initialize_SynTree();
    if( 0 == ret ){
        printf("Program exit with initializing error.\n");
        return 0;
    }
    fopen_s( &srcFP, inputFile , "r" );
    if( NULL == srcFP ){
        printf("Can't open source file '%s'. Program exit.\n", inputFile );
        return 0;
    }
    fopen_s( &outFP, outputFile, "w" );
    if( NULL == outFP ){
        printf("Can't open temp file '%s'. Program exit.\n", outputFile );
        return 0;
    }
    /** pre-compiler **/
    ret = pre_compiler(srcFP, outFP);
    if( 0 == ret ){
        printf("Program exit with pre-compiler error.\n");
        goto ERROR_END;
    }
    MY_HELP_CLOSE( outFP );
    MY_HELP_CLOSE( srcFP );
    /** Syntax analyzing **/
    /* using the temp file as the source */
    fopen_s( &srcFP, outputFile, "r" );
    if( NULL == srcFP ){
        printf("Can't open temp file '%s'. Program exit.\n", outputFile );
        goto ERROR_END;
    }
    srcFileField.fp = srcFP;
    srcFileField.n_current_line = 1;
    ret = syntax_analyzer( &srcFileField );
    if( 0 == ret ){
        printf("Program exit with syntax_analyzer error.\n");
        goto ERROR_END;
    }
#ifdef DEBUG_SYNTAX
    fopen_s(&debugfp, debugFile, "w");
    if( NULL != debugfp ){
        debug_syntax( debugfp );
        fclose( debugfp );
    }
#endif
    /** semantic_analyzer **/
    ret = semantic_analyzer();
    if( 0 == ret ){
        printf("Program exit with semantic_analyzer error.\n");
        goto ERROR_END;
    }

    MY_HELP_CLOSE( outFP );
    MY_HELP_CLOSE( srcFP );
    release_IdTable();
    release_SynTree();
    return 1;
ERROR_END:
    MY_HELP_CLOSE( outFP );
    MY_HELP_CLOSE( srcFP );
    release_IdTable();
    release_SynTree();
    return 0;
}


语法分析头文件

 

/** scmppre.h
====================================================================
This is the base head file for pre-compiler


====================================================================
 */
#ifndef SCMPPRE_H_INCLUDE
#define SCMPPRE_H_INCLUDE

#ifndef STD_COMMON_H_INCLUDE
#define STD_COMMON_H_INCLUDE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#endif


#define MAX_SRC_LINE      1024           /* the max byte number of one line in the source file */

int pre_compiler(FILE * fpInput, FILE * fpOutput);



#endif


语法分析头文件:

/** scmpstx.h
====================================================================
This is the base head file for Syntax Analyze


====================================================================
 */
#ifndef SCMPSTX_H_INCLUDE
#define SCMPSTX_H_INCLUDE


#ifndef STD_COMMON_H_INCLUDE
#define STD_COMMON_H_INCLUDE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#endif

#define MAX_SYN_NODE_NUM  32768          /* the max syntax node number */
#define MAX_ID_LENGTH     32             /* the max length of indentifier */
/* The identifier id */
typedef struct tag_identifier_id{
    short n_mode;                        /* the mode : SYN_NODE_TAIL / SYN_NODE_VARID / SYN_NODE_FUNID */
    short dummy;                         /* not used */
    int n_next_identifier_id;            /* the next identifier in current second-level list */
    char str_name[ MAX_ID_LENGTH+1 ];
}IdentId;
typedef IdentId * IdentId_P;
/* The identifier table */
typedef struct tag_id_table{
    unsigned int n_id_num;               /*============================================================
                                         The number of identifiers in the table.
                                         It's also the first free place for store a new identifier.
                                         Using n_id_num,  pIdList acts as a stack, and n_id_num is
                                         it's stack top.
                                         If n_id_num >= MAX_SYN_NODE_NUM, the stack is full.
                                         ============================================================*/
    IdentId_P pIdList;                   /*============================================================
                                         the head pointer of the identifier list.
                                         malloc MAX_SYN_NODE_NUM IdentId.
                                         ============================================================*/
    unsigned int two_level_index[52][62];        /*============================================================
                                         First index: using the first byte of the name
                                             'A' to 'Z' = 0 to 25
                                             'a' to 'z' = 26 to 51
                                         Second index: using the second byte of the name
                                             'A' to 'Z' = 0 to 25
                                             'a' to 'z' = 26 to 51
                                             '0' to '9' = 52 to 61
                                         Default value: two_level_index[i][j] = -1;
                                         if two_level_index[i][j] is not -1, it shows this second-level
                                         list in the pIdList is started at pIdList[two_level_index[i][j]]
                                         ============================================================*/            
}IdTable;
IdTable g_IdTable;                       /* the identifier table */
/* The node for syntax tree */
typedef struct tag_SyntaxNode{
    short n_mode;                        /* the mode of SyntaxNode */
    unsigned int n_identifier_id;        /*============================================================
                                         The index in the Id Table for this identifier.
                                         If it's not identifier, n_identifier_id = INVALID_ID;
                                         ============================================================*/
    unsigned int n_left_brother_id;      /*============================================================
                                         The index of the left brother in the syntax tree.
                                         If it's the first son of its father, n_left_brother_id = INVALID_ID;
                                         ============================================================*/
    unsigned int n_right_brother_id;     /*============================================================
                                         The index of the right brother in the syntax tree.
                                         If it's the last son of its father, n_right_brother_id = INVALID_ID;
                                         ============================================================*/
    unsigned int n_father_id;            /*============================================================
                                         The index of the father in the syntax tree.
                                         If it's the root, n_father_id = INVALID_ID;
                                         ============================================================*/
    unsigned int n_son_id;               /*============================================================
                                         The index of the son in the syntax tree.
                                         If it has no son, n_son_id = INVALID_ID;
                                         ============================================================*/
    int n_int_value;                       /* the value of integer */
}SynNode;
typedef SynNode * SynNode_P;
typedef struct tat_SyntaxTree{
    unsigned int n_node_num;             /*============================================================
                                         The number of SynNode in the SyntaxTree.
                                         It's also the first free place for store a new SynNode.
                                         Using n_node_num,  pSynNodeList acts as a stack, and n_node_num is
                                         it's stack top.
                                         If n_node_num >= MAX_SYN_NODE_NUM, the stack is full.
                                         ============================================================*/
    SynNode_P pSynNodeList;              /*============================================================
                                         the head pointer of the syntax tree node list.
                                         malloc MAX_SYN_NODE_NUM SynNode.
                                         ============================================================*/
}SynTree;
SynTree g_SynTree;                       /* the syntax tree */
/* Syntax Node mode definitions */
#define SYN_NODE_TAIL                 0          /* the tail node */
#define SYN_NODE_HEAD                 1          /* the head node */
#define SYN_NODE_VARID                2          /* the identifier of variabale */
#define SYN_NODE_FUNID                3          /* the identifier of function */
#define SYN_NODE_MAINFUNID            4          /* the identifier of main function */
#define SYN_NODE_BODY                 11         /* the BODY of a function */
#define SYN_NODE_DEFINITION           12         /* DEFINITION */
#define SYN_NODE_VAR_DEF              13         /* VAR_DEF */
#define SYN_NODE_FUNC_DEF             14         /* FUNC_DEF */
#define SYN_NODE_VAR_DEFINITION       15         /* VAR_DEFINITION */
#define SYN_NODE_STATEMENT_LIST       16         /* STATEMENT_LIST */
#define SYN_NODE_ASSIGN_STMT          17         /* ASSIGN_STMT */
#define SYN_NODE_IF_STMT              18         /* IF_STMT */
#define SYN_NODE_FOR_STMT             19         /* FOR_STMT */
#define SYN_NODE_WHILE_STMT           20         /* WHILE_STMT */
#define SYN_NODE_FORMULA              21         /* FORMULA */
#define SYN_NODE_BOOL_FORMULA         22         /* BOOL_FORMULA */
#define SYN_NODE_FORMULA_FOLLOW       23         /* FORMULA_FOLLOW */
#define SYN_NODE_NUMBER               24         /* numbers */
#define SYN_NODE_L_parenthesis        25         /* '(' */
#define SYN_NODE_R_parenthesis        26         /* ')' */
#define SYN_NODE_ADD                  27         /* '+' */
#define SYN_NODE_SUB                  28         /* '-' */
#define SYN_NODE_MUT                  29         /* '*' */
#define SYN_NODE_DIV                  30         /* '/' */
#define SYN_NODE_AND                  31         /* '&&' */
#define SYN_NODE_OR                   32         /* '||' */
#define SYN_NODE_LESS                 33         /* '<' */
#define SYN_NODE_MORE                 34         /* '>' */
#define SYN_NODE_EQ                   35         /* '==' */
#define SYN_NODE_NOT_LESS             36         /* '>=' */
#define SYN_NODE_NOT_MORE             37         /* '<=' */
#define SYN_NODE_NOT_EQ               38         /* '!=' */
#define SYN_NODE_BOOL_FORMULA_FOLLOW  39         /* BOOL_FORMULA_FOLLOW */
#define SYN_NODE_FUNC_CALL            40         /* FUNC_CALL */
#define SYN_NODE_EMPTY               100         /* An empty node */

#define SHORT_MAX                    32767       /* MAX VALUE OF SHORT */
#define SHORT_MIN                    -32768      /* MIN VALUE OF SHORT */

#define INVALID_ID            (unsigned int)0xFFFFFFFF         /* the invalid index */

typedef struct tag_fileField{
    FILE * fp;                                   /* the pointer to the source file */
    int n_current_line;                          /* the current line number */
    char current_ch;                             /* the current char */
    char name_buf[MAX_ID_LENGTH+1];              /* the buffer for an identifier name */
}FileField;

#define KEY_WORD_NO                   0          /* Not a key word */
#define KEY_WORD_MAIN                 1          /* 'main' */
#define KEY_WORD_INT                  2          /* 'int' */
#define KEY_WORD_IF                   3          /* 'if' */
#define KEY_WORD_WHILE                4          /* 'while' */
#define KEY_WORD_FOR                  5          /* 'for' */

#define CHECK_KEY_WORD( buffer, type ) \
    { \
        if( 0 == strcmp( buffer, "main" ) ){\
            type = KEY_WORD_MAIN;\
        } else if( 0 == strcmp( buffer, "int" ) ){\
            type = KEY_WORD_INT;\
        } else if( 0 == strcmp( buffer, "if" ) ){\
            type = KEY_WORD_IF;\
        } else if( 0 == strcmp( buffer, "while") ){\
            type = KEY_WORD_WHILE;\
        } else if( 0 == strcmp( buffer, "for") ){\
            type = KEY_WORD_FOR;\
        } else{\
            type = KEY_WORD_NO;\
        }\
    }
#define MY_HELP_FREE( pValue )  \
    if( NULL != pValue ){\
        free(pValue);\
        pValue = NULL;\
    }
#define MY_HELP_CLOSE( pFILE )  \
    if( NULL != pFILE ){\
        fclose(pFILE);\
        pFILE = NULL;\
    }
#define CHECK_NEW_LINE( fileField ) \
    if( '\n' == fileField->current_ch ){\
        fileField->n_current_line++;\
    }
#define JUMP_SPACES( fileField ) \
    {\
        while( isspace( fileField->current_ch ) ){\
            fileField->current_ch = fgetc( fileField->fp );\
            CHECK_NEW_LINE( fileField )\
        }\
    }
#define GET_IDENTIFY( fileField, buffer, length )\
    {\
        length = 0;\
        JUMP_SPACES( fileField );\
        if( !isalpha(fileField->current_ch) ){/* the fisrt char must be alphabet */\
            buffer[0] = '\0';\
            length = 0;\
        } else{\
            buffer[0] = fileField->current_ch;\
            length = 1;\
            while( 1 ){\
                fileField->current_ch = fgetc( fileField->fp );\
                CHECK_NEW_LINE( fileField )\
                if( isalnum( fileField->current_ch ) ){\
                    buffer[length] = fileField->current_ch;\
                    length++;\
                    if( length > MAX_ID_LENGTH ){/* too logn identifier */\
                        buffer[0] = '\0';\
                        length = 0;\
                        break;\
                    }\
                } else{\
                    buffer[length] = '\0';\
                    break;\
                }\
            }\
        }\
    }
#define GET_NEW_CHAR_JUMP_SPACE( fileField ) \
    {\
        fileField->current_ch = fgetc( fileField->fp );\
        CHECK_NEW_LINE( fileField )\
        JUMP_SPACES( fileField )\
    }
#define CHECK_NODE_NUM( function, fileField, num ) \
    {\
        if( num > MAX_SYN_NODE_NUM ){\
            report_syntax_error( function, "Too many syntax nodes.", fileField->n_current_line );\
            return 0;\
        }\
    }
#define FIX_FATHER_LBROTHER( father_ID, left_brother_ID, current_ID ) \
    {\
        if( father_ID != INVALID_ID ){\
            if( INVALID_ID == g_SynTree.pSynNodeList[father_ID].n_son_id ){\
                g_SynTree.pSynNodeList[father_ID].n_son_id = current_ID;\
            }\
        }\
        if( left_brother_ID != INVALID_ID ){\
            if( INVALID_ID == g_SynTree.pSynNodeList[left_brother_ID].n_right_brother_id ){\
                g_SynTree.pSynNodeList[left_brother_ID].n_right_brother_id = current_ID;\
            }\
        }\
    }
int syntax_analyzer(FileField *fileField);
int initialize_IdTable();
int initialize_SynTree();
int release_IdTable();
int release_SynTree();
void report_syntax_error(char *func_name, char *detail, int line_number);
void report_memery_error(char *func_name, int line_number);
void report_internal_error(char *func_name, int line_number);
int add_to_IdTable(FileField * fileField, char *id_name, int length, short mode, unsigned int * p_ident_index);
int find_in_IdTable(FileField * fileField, char *id_name, int length, unsigned int * p_ident_index);
int get_number( FileField * fileField, int * pOutValue);
void debug_syntax( FILE* fp );

#endif


语义分析头文件:

 
 

/** scmpsem.h
====================================================================
This is the base head file for Semantic Analyze


====================================================================
 */
#ifndef SCMPSEM_H_INCLUDE
#define SCMPSEM_H_INCLUDE

#include "scmpstx.h"

#ifndef LINUX
/* For Windows only */
/* define the header of the MASM source file */
#define ASM_HEADER ".MODEL SMALL\n.STACK 4096h\nINCLUDE PrintVal.mac\n"
#define ASM_DATA_HEADER ".DATA\nASM_CHAGNE_LINE  DB  0DH,0AH,'$'\n"
/* the definition of varibale e.g. sprintf(buffer, MASM_VAR_DEF, "VAR1", "VAR1", "VAR1") */
#define ASM_VAR_DEF "%s  DW  0\nName_%s  DB '%s',20H,20H,'$'\n"
#define ASM_CODE_HEADER ".CODE\nCALL Main\n"
#define ASM_END_MAIN "END Main\n"
#define ASM_FILE_NAME "MyResult.asm"
#define ASM_CHANGE_LINE "LEA  AX, ASM_CHAGNE_LINE\nMOV  DX, AX\nMOV  AH, 9\nINT  21H\n"

#else
/* For Linux only */
#endif

#define MAX_STACK_NUM 32768               /* the max node number of sem_stack */
typedef struct tag_SEM_STACK_NODE{
    unsigned short n_mode;                /*====================================
                                          Type of the node
                                          0 ==> )
                                          1 ==> ||
                                          2 ==> &&
                                          3 ==> ==   !=
                                          4 ==> >   >=   <   <=
                                          5 ==> +  -
                                          6 ==> *  /
                                          7 ==> (
                                          0xffff ==> number
                                          =====================================*/
    short n_value;                        /*=====================================
                                          The value of the node,using definition
                                          in the scmpstx.h.
                                          e.g.
                                          SYN_NODE_NUMBER   24   numbers
                                          SYN_NODE_EQ       35   '=='
                                          =====================================*/
}SEM_STACK_NODE;
typedef struct tag_SEM_STACK{
    unsigned int n_num;
    SEM_STACK_NODE * sem_node_list;
}SEM_STACK;
typedef struct tag_SemEnv{
    unsigned int n_SignCurrentId;         /* the id of current sign */
    FILE * pAsmFile;                      /* the pointer to the output ASM file */
    SEM_STACK s_sem_stack;                /* the stack for semantic analyze */
}SemEnv;
SemEnv g_SemEnv;/* the semantic analyser environment */

int initialize_SemEnv();
int finalize_SemEnv();
int semantic_analyzer();
void debug_sem( );


#define CHECK_SYN_NODE_ID(id)  \
    if( INVALID_ID == (id) ){\
          printf("Internal Error ! Invalid syntax node id at line '%d'.\n", __LINE__);\
          return 0;\
    }
         

#endif


 


'; fputs(str_line_buffer, fpOutput); index = 0; } else{ str_line_buffer[index] = current_char; index++; CHECK_INDEX( index ) } } } else if( '\n' == current_char ){ str_line_buffer[index] = current_char; index++; CHECK_INDEX( index ) str_line_buffer[index] = '
预处理器:
/** scmppre.c
====================================================================
This is the base source file for pre-compiler


====================================================================
 */

#include "scmppre.h"


static int report_pre_error(char *msg, int code){
    printf("Error : %s\nCode : %d\n", msg, code);
    return 0;
}

#define CHECK_INDEX( index )    \
    if( index >= MAX_SRC_LINE ){\
        report_pre_error("Too long line.", index);\
        return 0;\
    }
/*=======================================================
The main function of pre-compiler.
return     1 : success
           0 : fail
========================================================*/
int pre_compiler(FILE * fpInput, FILE * fpOutput){
    char str_line_buffer[MAX_SRC_LINE + 1];
    int index = 0;
    char current_char;
    current_char = fgetc(fpInput);
    while( current_char != EOF ){
        /*========================================================
        search the '//' . if exists, jump the rest of the line.
        ========================================================*/
        if( '/' == current_char ){
            current_char = fgetc(fpInput);
            if( '/' == current_char ){
                while( current_char != EOF ){
                    current_char =  fgetc(fpInput);
                    if( '\n' == current_char ){
                        /* end of a line */
                        str_line_buffer[index] = '\n';
                        index++;
                        CHECK_INDEX( index )
                        break;/* stop loop */
                    }
                }
                /* output a line */
                str_line_buffer[index] = '\0';
                fputs(str_line_buffer, fpOutput);
                index = 0;
            } else{
                /* a single '/', just store it and its following byte */
                str_line_buffer[index] = '/';
                index++;
                CHECK_INDEX( index )
                if( EOF == current_char ){ /* end of file */
                    str_line_buffer[index] = '\0';
                    fputs(str_line_buffer, fpOutput);
                    index = 0;
                    return 1;
                } else if( '\n' == current_char ){
                    str_line_buffer[index] = current_char;
                    index++;
                    CHECK_INDEX( index )
                    str_line_buffer[index] = '\0';
                    fputs(str_line_buffer, fpOutput);
                    index = 0;
                } else{
                    str_line_buffer[index] = current_char;
                    index++;
                    CHECK_INDEX( index )
                }
            }
        } else if( '\n' == current_char ){
            str_line_buffer[index] = current_char;
            index++;
            CHECK_INDEX( index )
            str_line_buffer[index] = '\0';
            fputs(str_line_buffer, fpOutput);
            index = 0;
        } else{
            str_line_buffer[index] = current_char;
            index++;
            CHECK_INDEX( index )
        }
        current_char = fgetc(fpInput);
    }

    str_line_buffer[index] = '\0';
    fputs(str_line_buffer, fpOutput);
    index = 0;

    return 1;
}


语法分析器

 

/** scmpstx.c
====================================================================
This is the base source file for Syntax Analyze


====================================================================
 */
#include "scmpstx.h"

int DEFINITION(FileField *fileField, int left_brother_ID, int father_ID);
int VAR_DEF(FileField *fileField, int left_brother_ID, int father_ID);
int FUNC_DEF(FileField *fileField, int left_brother_ID, int father_ID);
int IDENTIFY(FileField *fileField, int left_brother_ID, int father_ID);
int BODY(FileField *fileField, int left_brother_ID, int father_ID);
int VAR_DEFINITION(FileField *fileField, int left_brother_ID, int father_ID);
int STATEMENT_LIST(FileField *fileField, int left_brother_ID, int father_ID);
int ASSIGN_STMT(FileField *fileField, int left_brother_ID, int father_ID);
int IF_STMT(FileField *fileField, int left_brother_ID, int father_ID);
int FOR_STMT(FileField *fileField, int left_brother_ID, int father_ID);
int WHILE_STMT(FileField *fileField, int left_brother_ID, int father_ID);
int FORMULA(FileField *fileField, int left_brother_ID, int father_ID);
int BOOL_FORMULA(FileField *fileField, int left_brother_ID, int father_ID);
int FORMULA_FOLLOW(FileField *fileField, int left_brother_ID, int father_ID);
int BOOL_FORMULA_FOLLOW(FileField *fileField, int left_brother_ID, int father_ID);
int FUNC_CALL(FileField *fileField, int left_brother_ID, int father_ID);



void report_syntax_error(char *func_name, char *detail, int line_number){
    printf("Syntax error accured in function '%s()', at line '%d'.\nDetail: %s\n", func_name, line_number, detail);
    return;
}
void report_memery_error(char *func_name, int line_number){
    printf("Memery error accured in function '%s()', at line '%d'.\n", func_name, line_number);
    return;
}
void report_internal_error(char *func_name, int line_number){
    printf("Internal error accured in function '%s()', at line '%d'.\n", func_name, line_number);
    return;
}
int initialize_IdTable(){
    int i=0;
    int j=0;
    g_IdTable.n_id_num = 0;
    g_IdTable.pIdList = (IdentId_P)malloc( ( MAX_SYN_NODE_NUM + 1 ) * sizeof(IdentId) );
    if( NULL == g_IdTable.pIdList ){
        report_memery_error("initialize_IdTable", __LINE__);
        return 0;
    }
    for( i = 0; i < 51; i++ ){
        for( j = 0; j < 61; j++ ){
            g_IdTable.two_level_index[i][j] = INVALID_ID;
        }
    }
    return 1;
}
int initialize_SynTree(){
    g_SynTree.n_node_num = 0;
    g_SynTree.pSynNodeList = (SynNode_P)malloc( ( MAX_SYN_NODE_NUM + 1 ) * sizeof(SynNode) );
    if( NULL == g_SynTree.pSynNodeList ){
        report_memery_error("initialize_SynTree", __LINE__);
        return 0;
    }
    return 1;
}
int release_IdTable(){
    MY_HELP_FREE( g_IdTable.pIdList )
    g_IdTable.n_id_num = 0;
    return 1;
}
int release_SynTree(){
    MY_HELP_FREE( g_SynTree.pSynNodeList );
    g_SynTree.n_node_num = 0;
    return 1;
}

int syntax_analyzer(FileField *fileField){
    int ret = 0;
    char * func_name="syntax_analyzer";

    /** [ 1 ] initialize a node for whole program **/
    g_SynTree.n_node_num = 1;
    g_SynTree.pSynNodeList[0].n_father_id = INVALID_ID;
    g_SynTree.pSynNodeList[0].n_identifier_id = INVALID_ID;
    g_SynTree.pSynNodeList[0].n_left_brother_id = INVALID_ID;
    g_SynTree.pSynNodeList[0].n_mode = SYN_NODE_HEAD;
    g_SynTree.pSynNodeList[0].n_right_brother_id = INVALID_ID;
    g_SynTree.pSynNodeList[0].n_son_id = INVALID_ID;
    /** [ 2 ] deal with DEFINITION **/
    ret = DEFINITION( fileField, INVALID_ID, 0 );
    /** [ 3 ] deal with 'main' **/
    if( 0 == ret ){
        printf("Syntax_analyzer exit with syntax error.\n");
        return 0;
    } else{
        /* some definition finished, the node 'DEFINITION' is the left brother of 'main' */
        g_SynTree.n_node_num++;
        CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
        g_SynTree.pSynNodeList[g_SynTree.n_node_num-1].n_father_id = 0;/* the index of 'main' is g_SynTree.n_node_num-1 */
        g_SynTree.pSynNodeList[g_SynTree.n_node_num-1].n_identifier_id = INVALID_ID;
        g_SynTree.pSynNodeList[g_SynTree.n_node_num-1].n_left_brother_id = 1;/* the node 'DEFINITION' */
        g_SynTree.pSynNodeList[g_SynTree.n_node_num-1].n_mode = SYN_NODE_MAINFUNID;
        g_SynTree.pSynNodeList[g_SynTree.n_node_num-1].n_right_brother_id = INVALID_ID;
        g_SynTree.pSynNodeList[g_SynTree.n_node_num-1].n_son_id = INVALID_ID;
        g_SynTree.pSynNodeList[1].n_right_brother_id = g_SynTree.n_node_num-1;/* fix the right brother for node 'DEFINITION' */
    }
    /** [ 4 ] deal with '(' and ')' **/
    /* [ 4.1 ] jump the spaces after 'main' */
    JUMP_SPACES( fileField )
    /* [ 4.2 ] check '(' */
    if( '(' != fileField->current_ch ){
        report_syntax_error( "syntax_analyzer", "missing '('.", fileField->n_current_line );
        printf("Syntax_analyzer exit with syntax error.\n");
        return 0;
    }
    /* [ 4.3 ] jump the spaces after '(' */
    GET_NEW_CHAR_JUMP_SPACE( fileField )
    /* [ 4.4 ] check ')' */
    if( ')' != fileField->current_ch ){
        report_syntax_error( "syntax_analyzer", "missing ')'.", fileField->n_current_line );
        printf("Syntax_analyzer exit with syntax error.\n");
        return 0;
    }
    /* [ 4.5 ] jump the spaces after ')' */
    GET_NEW_CHAR_JUMP_SPACE( fileField )
    /* [ 4.6 ] check '{' */
    if( '{' != fileField->current_ch ){
        report_syntax_error( "syntax_analyzer", "missing '{'.", fileField->n_current_line );
        printf("Syntax_analyzer exit with syntax error.\n");
        return 0;
    }
    /** [ 5 ] deal with 'BODY' **/
    ret = BODY( fileField, g_SynTree.n_node_num-1, 0 );
    if( 0 == ret ){
        printf("Syntax_analyzer exit with syntax error.\n");
        return 0;
    }
    /* [ 6 ] jump the spaces after 'BODY' */
    JUMP_SPACES( fileField )
    /* [ 7 ] check '}' */
    if( '}' != fileField->current_ch ){
        report_syntax_error( "syntax_analyzer", "missing '}'.", fileField->n_current_line );
        printf("Syntax_analyzer exit with syntax error.\n");
        return 0;
    }
    /* [ 8 ] jump the spaces after '}' */
    GET_NEW_CHAR_JUMP_SPACE( fileField )
    if( EOF != fileField->current_ch ){
        report_syntax_error( "syntax_analyzer", "Unexpected character.", fileField->n_current_line );
        printf("Syntax_analyzer exit with syntax error.\n");
        return 0;
    }
    return 1;
}


int DEFINITION(FileField *fileField, int left_brother_ID, int father_ID){
    int ret = 0;
    int id_length = 0;
    char *func_name="DEFINITION";
    unsigned int tempIndex = 0;

    /* [ 1 ] make a node for 'DEFINITION' */
    tempIndex = g_SynTree.n_node_num;
    g_SynTree.pSynNodeList[ tempIndex ].n_father_id = father_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_identifier_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_left_brother_id = left_brother_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_mode = SYN_NODE_DEFINITION;
    g_SynTree.pSynNodeList[ tempIndex ].n_right_brother_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_son_id = INVALID_ID;
    /* [ 2 ] fix for father and left brother */
    FIX_FATHER_LBROTHER( father_ID, left_brother_ID, tempIndex )
    g_SynTree.n_node_num++;
    CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )


    /* [ 3 ] deal with VAR_DEF */
    ret = VAR_DEF( fileField, INVALID_ID, tempIndex );
    if( 0 == ret ){
        return 0;
    }
    if( 1000 == ret ){
        report_syntax_error( func_name, "Invalid identifier .", fileField->n_current_line );
        return 0;
    } else if( 100 == ret ){
        return 1;
    } else if( 200 == ret ){
        /* [ 4 ] deal with FUNC_DEF */
        ret = FUNC_DEF( fileField, INVALID_ID, tempIndex );
        if( 0 == ret ){
            return 0;
        }
    } else if( 300 == ret ){
        report_syntax_error( "syntax_analyzer", "Unexpected character.", fileField->n_current_line );
        return 0;
    }
    /* [ 5 ] deal with DEFINITION recursively */
    ret = DEFINITION( fileField, g_SynTree.pSynNodeList[ tempIndex ].n_son_id, tempIndex );
    if( 0 == ret ){
        return 0;
    }
    return 1;
}
/** if it returns 1000, it's unkown character, maybe '}' **/
/** if it returns 100, an identifier name 'main' is stored in FileField.name_buf **/
/** if it returns 200, an identifier name ( not 'main' ) is stored in FileField.name_buf **/
/** if it returns 300, it's 'if' 'while' 'for' **/
int VAR_DEF(FileField *fileField, int left_brother_ID, int father_ID){
    int ret = 0;
    char *func_name="VAR_DEF";
    unsigned int tempIndex = 0;
    unsigned int ident_index = 0;
    int id_length = 0;
    /* [ 1 ] jump spaces in the head */
    GET_NEW_CHAR_JUMP_SPACE( fileField )
    /* [ 2 ] get the first token */
    GET_IDENTIFY( fileField, fileField->name_buf, id_length )
    if( 0 == id_length ){
        return 1000;
    }
    CHECK_KEY_WORD( fileField->name_buf, ret )
    if( KEY_WORD_MAIN == ret ){
        /* no definition */
        return 100;
    } else if( KEY_WORD_NO == ret ){
        /* it's an identifier. maybe statment_list or syntax error. */
        return 200;
    }else if( KEY_WORD_INT == ret ){
        /* [ 3 ] deal with 'VAR_DEF' */
        /* [ 3.1 ] make a node for 'VAR_DEF' */
        tempIndex = g_SynTree.n_node_num;
        g_SynTree.pSynNodeList[ tempIndex ].n_father_id = father_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_identifier_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_left_brother_id = left_brother_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_mode = SYN_NODE_VAR_DEF;
        g_SynTree.pSynNodeList[ tempIndex ].n_right_brother_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_son_id = INVALID_ID;
        /* [ 3.2 ] fix for father and left brother */
        FIX_FATHER_LBROTHER( father_ID, left_brother_ID, tempIndex )
        g_SynTree.n_node_num++;
        CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
        /* [ 3.3 ] get the identifier after 'int' */
        GET_IDENTIFY( fileField, fileField->name_buf, id_length )
        if( 0 == id_length ){
            report_syntax_error( func_name, "Invalid identifier .", fileField->n_current_line );
            return 0;
        }
        CHECK_KEY_WORD( fileField->name_buf, ret )
        if( KEY_WORD_NO != ret ){
            /* Invalid identifier */
            report_syntax_error( func_name, "Invalid identifier: key-word.", fileField->n_current_line );
            return 0;
        }
        /* [ 3.4 ] use a IdentId to store the identifier and make a syntax node */
        ret = add_to_IdTable(fileField, fileField->name_buf, id_length, SYN_NODE_VARID, &ident_index);
        if( 0 == ret ){
            return 0;
        }
        g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_father_id = tempIndex;
        g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_identifier_id = ident_index;
        g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_left_brother_id = INVALID_ID;
        g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_mode = SYN_NODE_VARID;
        g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_right_brother_id = INVALID_ID;
        g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_son_id = INVALID_ID;
        /* [ 3.5 ] fix for father and left brother */
        FIX_FATHER_LBROTHER( tempIndex, INVALID_ID, g_SynTree.n_node_num )
        g_SynTree.n_node_num++;
        CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
        /* [ 3.6 ] deal with ';' */
        JUMP_SPACES( fileField )
        if( ';' != fileField->current_ch ){
            report_syntax_error( func_name, "Missing ';' .", fileField->n_current_line );
            return 0;
        }
        return 1;
    } else{
        /* it's 'if' 'while' 'for' */
        return 300;
    }
}
int FUNC_DEF(FileField *fileField, int left_brother_ID, int father_ID){
    int ret = 0;
    char *func_name="FUNC_DEF";
    unsigned int tempIndex = 0;
    unsigned int ident_index = 0;
    int id_length = 0;
    /* [ 1 ] deal with FUNC_DEF */
    /* [ 1.1 ] make a node for FUNC_DEF */
    g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_father_id = father_ID;
    g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_identifier_id = INVALID_ID;
    g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_left_brother_id = left_brother_ID;
    g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_mode = SYN_NODE_FUNC_DEF;
    g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_right_brother_id = INVALID_ID;
    g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_son_id = INVALID_ID;
    /* [ 1.2 ] fix for father and left brother */
    FIX_FATHER_LBROTHER( father_ID, left_brother_ID, g_SynTree.n_node_num )
    g_SynTree.n_node_num++;
    CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
    /* [ 1.3 ] use a IdentId to store the identifier and make a syntax node */
    ret = add_to_IdTable(fileField, fileField->name_buf, (int)strlen( fileField->name_buf ), SYN_NODE_FUNID, &ident_index);
    if( 0 == ret ){
        return 0;
    }
    g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_father_id = g_SynTree.n_node_num - 1;
    g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_identifier_id = ident_index;
    g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_left_brother_id = INVALID_ID;
    g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_mode = SYN_NODE_FUNID;
    g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_right_brother_id = INVALID_ID;
    g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_son_id = INVALID_ID;
    /* [ 1.4 ] fix for father and left brother */
    FIX_FATHER_LBROTHER( g_SynTree.n_node_num - 1, INVALID_ID, g_SynTree.n_node_num )
    g_SynTree.n_node_num++;
    CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
    /* [ 1.5 ] deal with '(' */
    JUMP_SPACES( fileField )
    if( '(' != fileField->current_ch ){
        report_syntax_error( func_name, "Missing '(' .", fileField->n_current_line );
        return 0;
    }
    /* [ 1.6 ] deal with ')' */
    GET_NEW_CHAR_JUMP_SPACE( fileField )
    if( ')' != fileField->current_ch ){
        report_syntax_error( func_name, "Missing ')' .", fileField->n_current_line );
        return 0;
    }
    /* [ 1.7 ] deal with '{' */
    GET_NEW_CHAR_JUMP_SPACE( fileField )
    if( '{' != fileField->current_ch ){
        report_syntax_error( func_name, "Missing '{' .", fileField->n_current_line );
        return 0;
    }
    /* [ 1.8 ] deal with 'BODY' */
    ret = BODY( fileField, g_SynTree.n_node_num - 1, g_SynTree.n_node_num - 2 );
    if( 0 == ret ){
        return 0;
    }
    /* [ 1.9 ] deal with '}' */
    JUMP_SPACES( fileField )
    if( '}' != fileField->current_ch ){
        report_syntax_error( func_name, "Missing '}' .", fileField->n_current_line );
        return 0;
    }
    return 1;
}
int BODY(FileField *fileField, int left_brother_ID, int father_ID){
    int ret = 0;
    char *func_name="BODY";
    unsigned int tempIndex = 0;
    int id_length = 0;

    /* [ 1 ] make a node for 'BODY' */
    tempIndex = g_SynTree.n_node_num;
    g_SynTree.pSynNodeList[ tempIndex ].n_father_id = father_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_identifier_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_left_brother_id = left_brother_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_mode = SYN_NODE_BODY;
    g_SynTree.pSynNodeList[ tempIndex ].n_right_brother_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_son_id = INVALID_ID;
    /* [ 2 ] fix for father and left brother */
    FIX_FATHER_LBROTHER( father_ID, left_brother_ID, tempIndex )
    g_SynTree.n_node_num++;
    CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
    /* [ 3 ] deal with VAR_DEFINITION */
    ret = VAR_DEFINITION( fileField, INVALID_ID, tempIndex );
    if( 0 == ret ){
        return 0;
    }
    if( 400 != ret ){
        /* [ 4 ] deal with STATEMENT_LIST */
        ret = STATEMENT_LIST( fileField, g_SynTree.pSynNodeList[ tempIndex ].n_son_id, tempIndex );
        if( 0 == ret ){
            return 0;
        }
    }

    return 1;
}
/** if it returns 200, an identifier name is stored in FileField.name_buf **/
/** if it returns 300, it's 'if' 'while' 'for' **/
/** if it returns 400, an empty statment_list is following **/
int VAR_DEFINITION(FileField *fileField, int left_brother_ID, int father_ID){
    int ret = 0;
    char *func_name="VAR_DEFINITION";
    unsigned int tempIndex = 0;
    /* [ 1 ] make a node for 'VAR_DEFINITION' */
    tempIndex = g_SynTree.n_node_num;
    g_SynTree.pSynNodeList[ tempIndex ].n_father_id = father_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_identifier_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_left_brother_id = left_brother_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_mode = SYN_NODE_VAR_DEFINITION;
    g_SynTree.pSynNodeList[ tempIndex ].n_right_brother_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_son_id = INVALID_ID;
    /* [ 2 ] fix for father and left brother */
    FIX_FATHER_LBROTHER( father_ID, left_brother_ID, tempIndex )
    g_SynTree.n_node_num++;
    CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
    /* [ 3 ] deal with VAR_DEF */
    ret = VAR_DEF( fileField, INVALID_ID, tempIndex );
    if( 0 == ret ){
        return 0;
    }
    if( 1000 == ret ){
        if( '}' != fileField->current_ch ){
            report_syntax_error( func_name, "Invalid identifier .", fileField->n_current_line );
            return 0;
        } else{
            /* Empty statement_list */
            return 400;
        }
    } else if( 100 == ret ){
        report_syntax_error( "syntax_analyzer", "Unexpected key-word 'main'.", fileField->n_current_line );
        return 0;/* 'main' can't be here */
    } else if( 200 == ret ){
        /* [ 4 ] 'STATEMENT_LIST' is following */
        return 200;
    } else if( 300 == ret ){
        /* [ 5 ] 'STATEMENT_LIST' is following */
        return 300;
    }
    ret = VAR_DEFINITION( fileField, g_SynTree.pSynNodeList[ tempIndex ].n_son_id, tempIndex );
    return ret;
}
int STATEMENT_LIST(FileField *fileField, int left_brother_ID, int father_ID){
    int ret = 0;
    char *func_name="STATEMENT_LIST";
    unsigned int tempIndex = 0;
    unsigned int id_length = 0;
    /* [ 1 ] make a node for 'STATEMENT_LIST' */
    tempIndex = g_SynTree.n_node_num;
    g_SynTree.pSynNodeList[ tempIndex ].n_father_id = father_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_identifier_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_left_brother_id = left_brother_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_mode = SYN_NODE_STATEMENT_LIST;
    g_SynTree.pSynNodeList[ tempIndex ].n_right_brother_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_son_id = INVALID_ID;
    /* [ 2 ] fix for father and left brother */
    FIX_FATHER_LBROTHER( father_ID, left_brother_ID, tempIndex )
    g_SynTree.n_node_num++;
    CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
    /* [ 3 ] check the last byte */
    if( '}' == fileField->current_ch ){
        /* the statement list is empty */
        return 1;
    }
    /* [ 4 ] check the key-word which has already been read */
    CHECK_KEY_WORD( fileField->name_buf, ret )
    if( KEY_WORD_NO == ret ){
        JUMP_SPACES( fileField )
        if( '=' == fileField->current_ch ){
            /* [ 4.1 ] it's an ASSIGN_STMT */
            ret = ASSIGN_STMT( fileField, INVALID_ID, tempIndex );
            if( 0 == ret ){
                return 0;
            }
            JUMP_SPACES( fileField )
            if( ';' != fileField->current_ch ){
                /* check ';' */
                report_syntax_error( func_name, "Missing ';' .", fileField->n_current_line );
                return 0;
            }
        } else if( '(' == fileField->current_ch ){
            /* [ 4.2 ] it's an FUNC_CALL */
            ret = FUNC_CALL( fileField, INVALID_ID, tempIndex );
            if( 0 == ret ){
                return 0;
            }
        } else{
            report_syntax_error( func_name, "Unknown statement .", fileField->n_current_line );
            return 0;
        }
    } else if( KEY_WORD_IF == ret ){
        /* [ 4.2 ] deal with IF_STMT */
        ret = IF_STMT( fileField, INVALID_ID, tempIndex );
        if( 0 == ret ){
            return 0;
        }
    } else if( KEY_WORD_WHILE == ret ){
        /* [ 4.3 ] deal with WHILE_STMT */
        ret = WHILE_STMT( fileField, INVALID_ID, tempIndex );
        if( 0 == ret ){
            return 0;
        }
    } else if( KEY_WORD_FOR == ret ){
        /* [ 4.4 ] deal with FOR_STMT */
        ret = FOR_STMT( fileField, INVALID_ID, tempIndex );
        if( 0 == ret ){
            return 0;
        }
    } else {
        report_syntax_error( func_name, "Invalid identifier .", fileField->n_current_line );
        return 0;
    }
    /* [ 5 ] jump spaces */
    GET_NEW_CHAR_JUMP_SPACE( fileField )
    /* [ 6 ] get the next token */
    GET_IDENTIFY( fileField, fileField->name_buf, id_length )
    /* [ 7 ] call STATEMENT_LIST() recursively */
    ret = STATEMENT_LIST( fileField, g_SynTree.pSynNodeList[ tempIndex ].n_son_id, tempIndex );
    if( 0 == ret ){
        return 0;
    }
    
    return 1;
}
int ASSIGN_STMT(FileField *fileField, int left_brother_ID, int father_ID){
    int ret = 0;
    char *func_name="ASSIGN_STMT";
    unsigned int tempIndex = 0;
    unsigned int ident_index = 0;
    IdentId_P p_cur_id = NULL;
    /* [ 1 ] make a node for 'ASSIGN_STMT' */
    tempIndex = g_SynTree.n_node_num;
    g_SynTree.pSynNodeList[ tempIndex ].n_father_id = father_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_identifier_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_left_brother_id = left_brother_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_mode = SYN_NODE_ASSIGN_STMT;
    g_SynTree.pSynNodeList[ tempIndex ].n_right_brother_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_son_id = INVALID_ID;
    /* [ 2 ] fix for father and left brother */
    FIX_FATHER_LBROTHER( father_ID, left_brother_ID, tempIndex )
    g_SynTree.n_node_num++;
    CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
    /* [ 3 ] find the identifier in IdTable */
    ret = find_in_IdTable(fileField, fileField->name_buf, (int)strlen(fileField->name_buf), &ident_index);
    if( 0 == ret ){
        return 0;
    }
    p_cur_id = &g_IdTable.pIdList[ ident_index ];
    if( p_cur_id->n_mode != SYN_NODE_VARID ){
        report_syntax_error( func_name, "Identifier can't be assigned, it's a function name.", fileField->n_current_line );
        return 0;
    }
    /* [ 4 ] make a node for the identifier */
    tempIndex = g_SynTree.n_node_num;
    g_SynTree.pSynNodeList[ tempIndex ].n_father_id = tempIndex - 1;
    g_SynTree.pSynNodeList[ tempIndex ].n_identifier_id = ident_index;
    g_SynTree.pSynNodeList[ tempIndex ].n_left_brother_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_mode = SYN_NODE_VARID;
    g_SynTree.pSynNodeList[ tempIndex ].n_right_brother_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_son_id = INVALID_ID;
    /* [ 5 ] fix for father and left brother */
    FIX_FATHER_LBROTHER( tempIndex - 1, INVALID_ID, tempIndex )
    g_SynTree.n_node_num++;
    CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
    /* [ 6 ] check the '=' */
    JUMP_SPACES( fileField )
    if( '=' != fileField->current_ch ){
        report_syntax_error( func_name, "Missing '='.", fileField->n_current_line );
        return 0;
    }
    /* [ 7 ] deal with FORMULA */
    ret = FORMULA( fileField, tempIndex, tempIndex - 1 );
    if( 0 == ret ){
        return 0;
    }

    return 1;
}

int IF_STMT(FileField *fileField, int left_brother_ID, int father_ID){
    int ret = 0;
    char *func_name="IF_STMT";
    unsigned int tempIndex = 0;
    unsigned int id_length = 0;
    /* [ 1 ] make a node for 'IF_STMT' */
    tempIndex = g_SynTree.n_node_num;
    g_SynTree.pSynNodeList[ tempIndex ].n_father_id = father_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_identifier_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_left_brother_id = left_brother_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_mode = SYN_NODE_IF_STMT;
    g_SynTree.pSynNodeList[ tempIndex ].n_right_brother_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_son_id = INVALID_ID;
    /* [ 2 ] fix for father and left brother */
    FIX_FATHER_LBROTHER( father_ID, left_brother_ID, tempIndex )
    g_SynTree.n_node_num++;
    CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
    /* [ 3 ] check '('  */
    JUMP_SPACES( fileField )
    if( '(' != fileField->current_ch ){
        report_syntax_error( func_name, "Missing '('.", fileField->n_current_line );
        return 0;
    }
    /* [ 4 ] deal with BOOL_FORMULA */
    /* [ 4.1 ] jump spaces in the head for two bytes operator e.g. '>=' */
    GET_NEW_CHAR_JUMP_SPACE( fileField )
    ret = BOOL_FORMULA( fileField, INVALID_ID, tempIndex );
    if( 0 == ret ){
        return 0;
    }
    /* [ 5 ] check ')'  */
    JUMP_SPACES( fileField )
    if( ')' != fileField->current_ch ){
        report_syntax_error( func_name, "Missing ')'.", fileField->n_current_line );
        return 0;
    }
    /* [ 6 ] jump spaces */
    GET_NEW_CHAR_JUMP_SPACE( fileField )
    /* [ 7 ] check '{' */
    if( '{' != fileField->current_ch ){
        report_syntax_error( func_name, "Missing '{'.", fileField->n_current_line );
        return 0;
    }
    /* [ 8 ] jump spaces */
    GET_NEW_CHAR_JUMP_SPACE( fileField )
    /* [ 9 ] get the next token */
    GET_IDENTIFY( fileField, fileField->name_buf, id_length )
    /* [ 10 ] call STATEMENT_LIST() */
    ret = STATEMENT_LIST( fileField, g_SynTree.pSynNodeList[ tempIndex ].n_son_id, tempIndex );
    if( 0 == ret ){
        return 0;
    }
    /* [ 11 ] deal with '}' */
    JUMP_SPACES( fileField )
    if( '}' != fileField->current_ch ){
        report_syntax_error( func_name, "Missing '}' .", fileField->n_current_line );
        return 0;
    }

    return 1;
}
int FOR_STMT(FileField *fileField, int left_brother_ID, int father_ID){
    int ret = 0;
    char *func_name="FOR_STMT";
    unsigned int for_stmt_index = 0;
    unsigned int tempIndex = 0;
    unsigned int id_length = 0;
    /* [ 1 ] make a node for 'FOR_STMT' */
    tempIndex = g_SynTree.n_node_num;
    for_stmt_index = tempIndex;
    g_SynTree.pSynNodeList[ tempIndex ].n_father_id = father_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_identifier_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_left_brother_id = left_brother_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_mode = SYN_NODE_FOR_STMT;
    g_SynTree.pSynNodeList[ tempIndex ].n_right_brother_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_son_id = INVALID_ID;
    /* [ 2 ] fix for father and left brother */
    FIX_FATHER_LBROTHER( father_ID, left_brother_ID, tempIndex )
    g_SynTree.n_node_num++;
    CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
    /* [ 3 ] check '('  */
    JUMP_SPACES( fileField )
    if( '(' != fileField->current_ch ){
        report_syntax_error( func_name, "Missing '('.", fileField->n_current_line );
        return 0;
    }
    /* [ 4 ] jump spaces */
    GET_NEW_CHAR_JUMP_SPACE( fileField )
    if( ';' == fileField->current_ch ){
        /* [ 5 ] first statement is empty, make an empty node */
        tempIndex++;
        g_SynTree.pSynNodeList[ tempIndex ].n_father_id = for_stmt_index;
        g_SynTree.pSynNodeList[ tempIndex ].n_identifier_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_left_brother_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_mode = SYN_NODE_EMPTY;
        g_SynTree.pSynNodeList[ tempIndex ].n_right_brother_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_son_id = INVALID_ID;
        /* [ 5.1 ] fix for father and left brother */
        FIX_FATHER_LBROTHER( for_stmt_index, INVALID_ID, tempIndex )
        g_SynTree.n_node_num++;
        CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
    } else{
        /* [ 6 ] deal with ASSIGN_STMT */
        /* [ 6.1 ] get the next token */
        GET_IDENTIFY( fileField, fileField->name_buf, id_length )
        ret = ASSIGN_STMT( fileField, INVALID_ID, for_stmt_index );
        if( 0 == ret ){
            return 0;
        }
        JUMP_SPACES( fileField )
        if( ';' != fileField->current_ch ){
            /* check ';' */
            report_syntax_error( func_name, "Missing ';' .", fileField->n_current_line );
            return 0;
        }
    }
    /* [ 7 ] deal with BOOL_FORMULA */
    /* [ 7.1 ] jump spaces in the head for two bytes operator e.g. '>=' */
    GET_NEW_CHAR_JUMP_SPACE( fileField )
    ret = BOOL_FORMULA( fileField, g_SynTree.pSynNodeList[ for_stmt_index ].n_son_id, for_stmt_index );
    if( 0 == ret ){
        return 0;
    }
    JUMP_SPACES( fileField )
    if( ';' != fileField->current_ch ){
        /* check ';' */
        report_syntax_error( func_name, "Missing ';' .", fileField->n_current_line );
        return 0;
    }
    /* [ 7.1 ] store the index of BOOL_FORMULA */
    tempIndex = g_SynTree.pSynNodeList[ g_SynTree.pSynNodeList[ for_stmt_index ].n_son_id ].n_right_brother_id;
    /* [ 8 ] jump spaces */
    GET_NEW_CHAR_JUMP_SPACE( fileField )
    if( ')' == fileField->current_ch ){
        /* [ 9 ] last statement is empty, make an empty node */
        g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_father_id = for_stmt_index;
        g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_identifier_id = INVALID_ID;
        g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_left_brother_id = tempIndex;
        g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_mode = SYN_NODE_EMPTY;
        g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_right_brother_id = INVALID_ID;
        g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_son_id = INVALID_ID;
        /* [ 9.1 ] fix for father and left brother */
        FIX_FATHER_LBROTHER( for_stmt_index, tempIndex, g_SynTree.n_node_num )
        g_SynTree.n_node_num++;
        CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
    } else{
        /* [ 10 ] deal with ASSIGN_STMT */
        /* [ 10.1 ] get the next token */
        GET_IDENTIFY( fileField, fileField->name_buf, id_length )
        ret = ASSIGN_STMT( fileField, tempIndex, for_stmt_index );
        if( 0 == ret ){
            return 0;
        }
        JUMP_SPACES( fileField )
        if( ')' != fileField->current_ch ){
            /* check ')' */
            report_syntax_error( func_name, "Missing ')' .", fileField->n_current_line );
            return 0;
        }
    }
    /* [ 10.1 ] store the index of third child of FOR_STMT */
    tempIndex = g_SynTree.pSynNodeList[ tempIndex ].n_right_brother_id;
    /* [ 11 ] jump spaces */
    GET_NEW_CHAR_JUMP_SPACE( fileField )
    /* [ 12 ] check '{' */
    if( '{' != fileField->current_ch ){
        report_syntax_error( func_name, "Missing '{' .", fileField->n_current_line );
        return 0;
    }
    /* [ 13 ] jump spaces */
    GET_NEW_CHAR_JUMP_SPACE( fileField )
    /* [ 14 ] get the next token */
    GET_IDENTIFY( fileField, fileField->name_buf, id_length )
    /* [ 15 ] call STATEMENT_LIST() */
    ret = STATEMENT_LIST( fileField, tempIndex, for_stmt_index );
    if( 0 == ret ){
        return 0;
    }
    /* [ 16 ] deal with '}' */
    JUMP_SPACES( fileField )
    if( '}' != fileField->current_ch ){
        report_syntax_error( func_name, "Missing '}' .", fileField->n_current_line );
        return 0;
    }

    return 1;
}
int WHILE_STMT(FileField *fileField, int left_brother_ID, int father_ID){
    int ret = 0;
    char *func_name="WHILE_STMT";
    unsigned int tempIndex = 0;
    unsigned int id_length = 0;
    /* [ 1 ] make a node for 'WHILE_STMT' */
    tempIndex = g_SynTree.n_node_num;
    g_SynTree.pSynNodeList[ tempIndex ].n_father_id = father_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_identifier_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_left_brother_id = left_brother_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_mode = SYN_NODE_WHILE_STMT;
    g_SynTree.pSynNodeList[ tempIndex ].n_right_brother_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_son_id = INVALID_ID;
    /* [ 2 ] fix for father and left brother */
    FIX_FATHER_LBROTHER( father_ID, left_brother_ID, tempIndex )
    g_SynTree.n_node_num++;
    CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
    /* [ 3 ] check '('  */
    JUMP_SPACES( fileField )
    if( '(' != fileField->current_ch ){
        report_syntax_error( func_name, "Missing '('.", fileField->n_current_line );
        return 0;
    }
    /* [ 4 ] jump spaces */
    /* [ 5.1 ] jump spaces in the head for two bytes operator e.g. '>=' */
    GET_NEW_CHAR_JUMP_SPACE( fileField )
    /* [ 5 ] deal with BOOL_FORMULA */
    ret = BOOL_FORMULA( fileField, INVALID_ID, tempIndex );
    if( 0 == ret ){
        return 0;
    }
    /* [ 6 ] check ')' */
    JUMP_SPACES( fileField )
    if( ')' != fileField->current_ch ){
        report_syntax_error( func_name, "Missing ')'.", fileField->n_current_line );
        return 0;
    }
    /* [ 7 ] jump spaces */
    GET_NEW_CHAR_JUMP_SPACE( fileField )
    /* [ 8 ] check '{' */
    if( '{' != fileField->current_ch ){
        report_syntax_error( func_name, "Missing '{'.", fileField->n_current_line );
        return 0;
    }
    /* [ 9 ] jump spaces */
    GET_NEW_CHAR_JUMP_SPACE( fileField )
    /* [ 10 ] get the next token */
    GET_IDENTIFY( fileField, fileField->name_buf, id_length )
    /* [ 11 ] call STATEMENT_LIST() */
    ret = STATEMENT_LIST( fileField, g_SynTree.pSynNodeList[ tempIndex ].n_son_id, tempIndex );
    if( 0 == ret ){
        return 0;
    }
    /* [ 12 ] deal with '}' */
    JUMP_SPACES( fileField )
    if( '}' != fileField->current_ch ){
        report_syntax_error( func_name, "Missing '}' .", fileField->n_current_line );
        return 0;
    }


    return 1;
}
int FORMULA(FileField *fileField, int left_brother_ID, int father_ID){
    int ret = 0;
    char *func_name="FORMULA";
    unsigned int tempIndex = 0;
    unsigned int FORMULAIndex = 0;
    unsigned int id_length = 0;
    unsigned int ident_index = 0;
    int int_value = 0;
    IdentId_P p_cur_id = NULL;
    /* [ 1 ] make a node for 'FORMULA' */
    tempIndex = g_SynTree.n_node_num;
    FORMULAIndex = tempIndex;
    g_SynTree.pSynNodeList[ tempIndex ].n_father_id = father_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_identifier_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_left_brother_id = left_brother_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_mode = SYN_NODE_FORMULA;
    g_SynTree.pSynNodeList[ tempIndex ].n_right_brother_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_son_id = INVALID_ID;
    /* [ 2 ] fix for father and left brother */
    FIX_FATHER_LBROTHER( father_ID, left_brother_ID, tempIndex )
    g_SynTree.n_node_num++;
    CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
    /* [ 3 ] jump spaces in the head */
    GET_NEW_CHAR_JUMP_SPACE( fileField )
    /* [ 4 ] check the first byte */
    if( '(' == fileField->current_ch ){
        /* [ 5 ] make a node for '(' */
        tempIndex = g_SynTree.n_node_num;
        g_SynTree.pSynNodeList[ tempIndex ].n_father_id = FORMULAIndex;
        g_SynTree.pSynNodeList[ tempIndex ].n_identifier_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_left_brother_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_mode = SYN_NODE_L_parenthesis;
        g_SynTree.pSynNodeList[ tempIndex ].n_right_brother_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_son_id = INVALID_ID;
        /* [ 5.1 ] fix for father and left brother */
        FIX_FATHER_LBROTHER( FORMULAIndex, INVALID_ID, tempIndex )
        g_SynTree.n_node_num++;
        CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
        /* [ 5.2 ] deal with FORMULA recursively */
        ret = FORMULA( fileField, tempIndex, FORMULAIndex );
        if( 0 == ret ){
            return 0;
        }
        /* [ 5.3 ] check ')' */
        JUMP_SPACES( fileField )
        if( ')' != fileField->current_ch ){
            report_syntax_error( func_name, "Missing ')' .", fileField->n_current_line );
            return 0;
        }
        /* [ 5.4 ] make a node for ')' */
        tempIndex = g_SynTree.pSynNodeList[ tempIndex ].n_right_brother_id;
        g_SynTree.n_node_num;
        g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_father_id = FORMULAIndex;
        g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_identifier_id = INVALID_ID;
        g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_left_brother_id = tempIndex;
        g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_mode = SYN_NODE_R_parenthesis;
        g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_right_brother_id = INVALID_ID;
        g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_son_id = INVALID_ID;
        /* [ 5.5 ] fix for father and left brother */
        FIX_FATHER_LBROTHER( FORMULAIndex, tempIndex , g_SynTree.n_node_num )
        g_SynTree.n_node_num++;
        CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
        /* [ 5.6 ] jump spaces in the end */
        GET_NEW_CHAR_JUMP_SPACE( fileField )
        /* [ 5.7 ] reflash the tempIndex */
        tempIndex = g_SynTree.n_node_num - 1;
    } else if( isalpha( fileField->current_ch ) ){
        /* [ 6 ] deal with identifier */
        GET_IDENTIFY( fileField, fileField->name_buf, id_length )
        if( 0 == id_length ){
            report_syntax_error( func_name, "Invalid identifier .", fileField->n_current_line );
            return 0;
        }
        CHECK_KEY_WORD( fileField->name_buf, ret )
        if( KEY_WORD_NO != ret ){
            report_syntax_error( func_name, "Invalid identifier :key-word.", fileField->n_current_line );
            return 0;
        }
        /* [ 6.1 ] find the identifier in IdTable */
        ret = find_in_IdTable(fileField, fileField->name_buf, (int)strlen(fileField->name_buf), &ident_index);
        if( 0 == ret ){
            return 0;
        }
        p_cur_id = &g_IdTable.pIdList[ ident_index ];
        if( p_cur_id->n_mode != SYN_NODE_VARID ){
            report_syntax_error( func_name, "Identifier can't be caculated, it's a function name.", fileField->n_current_line );
            return 0;
        }
        /* [ 6.2 ] make a node for the identifier */
        tempIndex = g_SynTree.n_node_num;
        g_SynTree.pSynNodeList[ tempIndex ].n_father_id = FORMULAIndex;
        g_SynTree.pSynNodeList[ tempIndex ].n_identifier_id = ident_index;
        g_SynTree.pSynNodeList[ tempIndex ].n_left_brother_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_mode = SYN_NODE_VARID;
        g_SynTree.pSynNodeList[ tempIndex ].n_right_brother_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_son_id = INVALID_ID;
        /* [ 6.3 ] fix for father and left brother */
        FIX_FATHER_LBROTHER( FORMULAIndex, INVALID_ID, tempIndex )
        g_SynTree.n_node_num++;
        CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
    } else{
        /* [ 7 ] deal with numbers */
        ret = get_number( fileField, &int_value );
        if( 0 == ret ){
            return 0;
        }
        /* [ 7.1 ] make a node for the integer */
        tempIndex = g_SynTree.n_node_num;
        g_SynTree.pSynNodeList[ tempIndex ].n_father_id = FORMULAIndex;
        g_SynTree.pSynNodeList[ tempIndex ].n_identifier_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_left_brother_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_mode = SYN_NODE_NUMBER;
        g_SynTree.pSynNodeList[ tempIndex ].n_right_brother_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_son_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_int_value = int_value;
        /* [ 7.2 ] fix for father and left brother */
        FIX_FATHER_LBROTHER( FORMULAIndex, INVALID_ID, tempIndex )
        g_SynTree.n_node_num++;
        CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
    }
    /* [ 8 ] deal with FORMULA_FOLLOW */
    ret = FORMULA_FOLLOW( fileField, tempIndex,  FORMULAIndex );
    if( 0 == ret ){
        return 0;
    }

    return 1;
};
int BOOL_FORMULA(FileField *fileField, int left_brother_ID, int father_ID){
    int ret = 0;
    char *func_name="BOOL_FORMULA";
    unsigned int tempIndex = 0;
    unsigned int BOOL_FORMULAIndex = 0;
    unsigned int id_length = 0;
    unsigned int ident_index = 0;
    int int_value = 0;
    IdentId_P p_cur_id = NULL;
    /* [ 1 ] make a node for 'BOOL_FORMULA' */
    tempIndex = g_SynTree.n_node_num;
    BOOL_FORMULAIndex = tempIndex;
    g_SynTree.pSynNodeList[ tempIndex ].n_father_id = father_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_identifier_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_left_brother_id = left_brother_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_mode = SYN_NODE_BOOL_FORMULA;
    g_SynTree.pSynNodeList[ tempIndex ].n_right_brother_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_son_id = INVALID_ID;
    /* [ 2 ] fix for father and left brother */
    FIX_FATHER_LBROTHER( father_ID, left_brother_ID, tempIndex )
    g_SynTree.n_node_num++;
    CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
    /* [ 3 ] jump spaces in the head */
    JUMP_SPACES( fileField )
    /* [ 4 ] check the first byte */
    if( '(' == fileField->current_ch ){
        /* [ 5 ] make a node for '(' */
        tempIndex = g_SynTree.n_node_num;
        g_SynTree.pSynNodeList[ tempIndex ].n_father_id = BOOL_FORMULAIndex;
        g_SynTree.pSynNodeList[ tempIndex ].n_identifier_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_left_brother_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_mode = SYN_NODE_L_parenthesis;
        g_SynTree.pSynNodeList[ tempIndex ].n_right_brother_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_son_id = INVALID_ID;
        /* [ 5.1 ] fix for father and left brother */
        FIX_FATHER_LBROTHER( BOOL_FORMULAIndex, INVALID_ID, tempIndex )
        g_SynTree.n_node_num++;
        CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
        /* [ 5.2 ] deal with BOOL_FORMULA recursively */
        /* jump spaces in the head for two bytes operator e.g. '>=' */
        GET_NEW_CHAR_JUMP_SPACE( fileField )
        ret = BOOL_FORMULA( fileField, tempIndex, BOOL_FORMULAIndex );
        if( 0 == ret ){
            return 0;
        }
        /* [ 5.3 ] check ')' */
        JUMP_SPACES( fileField )
        if( ')' != fileField->current_ch ){
            report_syntax_error( func_name, "Missing ')' .", fileField->n_current_line );
            return 0;
        }
        /* [ 5.4 ] make a node for ')' */
        tempIndex = g_SynTree.pSynNodeList[ tempIndex ].n_right_brother_id;
        g_SynTree.n_node_num;
        g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_father_id = BOOL_FORMULAIndex;
        g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_identifier_id = INVALID_ID;
        g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_left_brother_id = tempIndex;
        g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_mode = SYN_NODE_R_parenthesis;
        g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_right_brother_id = INVALID_ID;
        g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_son_id = INVALID_ID;
        /* [ 5.5 ] fix for father and left brother */
        FIX_FATHER_LBROTHER( BOOL_FORMULAIndex, tempIndex , g_SynTree.n_node_num )
        tempIndex = g_SynTree.n_node_num;/* Fix Bug */
        g_SynTree.n_node_num++;
        CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
        /* [ 5.6 ] jump spaces in the end */
        GET_NEW_CHAR_JUMP_SPACE( fileField )
    } else if( isalpha( fileField->current_ch ) ){
        /* [ 6 ] deal with identifier */
        GET_IDENTIFY( fileField, fileField->name_buf, id_length )
        if( 0 == id_length ){
            report_syntax_error( func_name, "Invalid identifier .", fileField->n_current_line );
            return 0;
        }
        CHECK_KEY_WORD( fileField->name_buf, ret )
        if( KEY_WORD_NO != ret ){
            report_syntax_error( func_name, "Invalid identifier :key-word.", fileField->n_current_line );
            return 0;
        }
        /* [ 6.1 ] find the identifier in IdTable */
        ret = find_in_IdTable(fileField, fileField->name_buf, (int)strlen(fileField->name_buf), &ident_index);
        if( 0 == ret ){
            return 0;
        }
        p_cur_id = &g_IdTable.pIdList[ ident_index ];
        if( p_cur_id->n_mode != SYN_NODE_VARID ){
            report_syntax_error( func_name, "Identifier can't be caculated, it's a function name.", fileField->n_current_line );
            return 0;
        }
        /* [ 6.2 ] make a node for the identifier */
        tempIndex = g_SynTree.n_node_num;
        g_SynTree.pSynNodeList[ tempIndex ].n_father_id = BOOL_FORMULAIndex;
        g_SynTree.pSynNodeList[ tempIndex ].n_identifier_id = ident_index;
        g_SynTree.pSynNodeList[ tempIndex ].n_left_brother_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_mode = SYN_NODE_VARID;
        g_SynTree.pSynNodeList[ tempIndex ].n_right_brother_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_son_id = INVALID_ID;
        /* [ 6.3 ] fix for father and left brother */
        FIX_FATHER_LBROTHER( BOOL_FORMULAIndex, INVALID_ID, tempIndex )
        g_SynTree.n_node_num++;
        CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
    } else{
        /* [ 7 ] deal with numbers */
        ret = get_number( fileField, &int_value );
        if( 0 == ret ){
            return 0;
        }
        /* [ 7.1 ] make a node for the integer */
        tempIndex = g_SynTree.n_node_num;
        g_SynTree.pSynNodeList[ tempIndex ].n_father_id = BOOL_FORMULAIndex;
        g_SynTree.pSynNodeList[ tempIndex ].n_identifier_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_left_brother_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_mode = SYN_NODE_NUMBER;
        g_SynTree.pSynNodeList[ tempIndex ].n_right_brother_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_son_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_int_value = int_value;
        /* [ 7.2 ] fix for father and left brother */
        FIX_FATHER_LBROTHER( BOOL_FORMULAIndex, INVALID_ID, tempIndex )
        g_SynTree.n_node_num++;
        CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
    }
    /* [ 8 ] deal with BOOL_FORMULA_FOLLOW */
    ret = BOOL_FORMULA_FOLLOW( fileField, tempIndex,  BOOL_FORMULAIndex );
    if( 0 == ret ){
        return 0;
    }

    return 1;
}
int FORMULA_FOLLOW(FileField *fileField, int left_brother_ID, int father_ID){
    int ret = 0;
    char *func_name="FORMULA_FOLLOW";
    unsigned int tempIndex = 0;
    /* [ 1 ] make a node for 'FORMULA_FOLLOW' */
    tempIndex = g_SynTree.n_node_num;
    g_SynTree.pSynNodeList[ tempIndex ].n_father_id = father_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_identifier_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_left_brother_id = left_brother_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_mode = SYN_NODE_FORMULA_FOLLOW;
    g_SynTree.pSynNodeList[ tempIndex ].n_right_brother_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_son_id = INVALID_ID;
    /* [ 2 ] fix for father and left brother */
    FIX_FATHER_LBROTHER( father_ID, left_brother_ID, tempIndex )
    g_SynTree.n_node_num++;
    CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
    /* [ 3 ] check the first byte */
    JUMP_SPACES( fileField )
    if( '+' == fileField->current_ch ){
        /* [ 4 ] make a node for '+' */
        tempIndex = g_SynTree.n_node_num;
        g_SynTree.pSynNodeList[ tempIndex ].n_father_id = tempIndex - 1;
        g_SynTree.pSynNodeList[ tempIndex ].n_identifier_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_left_brother_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_mode = SYN_NODE_ADD;
        g_SynTree.pSynNodeList[ tempIndex ].n_right_brother_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_son_id = INVALID_ID;
        /* [ 4.1 ] fix for father and left brother */
        FIX_FATHER_LBROTHER( tempIndex - 1, INVALID_ID, tempIndex )
        g_SynTree.n_node_num++;
        CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
    } else if( '-' ==  fileField->current_ch ){
        /* [ 5 ] make a node for '-' */
        tempIndex = g_SynTree.n_node_num;
        g_SynTree.pSynNodeList[ tempIndex ].n_father_id = tempIndex - 1;
        g_SynTree.pSynNodeList[ tempIndex ].n_identifier_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_left_brother_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_mode = SYN_NODE_SUB;
        g_SynTree.pSynNodeList[ tempIndex ].n_right_brother_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_son_id = INVALID_ID;
        /* [ 5.1 ] fix for father and left brother */
        FIX_FATHER_LBROTHER( tempIndex - 1, INVALID_ID, tempIndex )
        g_SynTree.n_node_num++;
        CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
    } else if( '*' == fileField->current_ch ){
        /* [ 6 ] make a node for '*' */
        tempIndex = g_SynTree.n_node_num;
        g_SynTree.pSynNodeList[ tempIndex ].n_father_id = tempIndex - 1;
        g_SynTree.pSynNodeList[ tempIndex ].n_identifier_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_left_brother_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_mode = SYN_NODE_MUT;
        g_SynTree.pSynNodeList[ tempIndex ].n_right_brother_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_son_id = INVALID_ID;
        /* [ 6.1 ] fix for father and left brother */
        FIX_FATHER_LBROTHER( tempIndex - 1, INVALID_ID, tempIndex )
        g_SynTree.n_node_num++;
        CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
    } else if( '/' == fileField->current_ch ){
        /* [ 7 ] make a node for '/' */
        tempIndex = g_SynTree.n_node_num;
        g_SynTree.pSynNodeList[ tempIndex ].n_father_id = tempIndex - 1;
        g_SynTree.pSynNodeList[ tempIndex ].n_identifier_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_left_brother_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_mode = SYN_NODE_DIV;
        g_SynTree.pSynNodeList[ tempIndex ].n_right_brother_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_son_id = INVALID_ID;
        /* [ 7.1 ] fix for father and left brother */
        FIX_FATHER_LBROTHER( tempIndex - 1, INVALID_ID, tempIndex )
        g_SynTree.n_node_num++;
        CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
    } else{
        /* empty follow */
        return 1;
    }
    /* [ 8 ] deal with FORMULA */
    ret = FORMULA( fileField, tempIndex, tempIndex - 1 );
    if( 0 == ret ){
        return 0;
    }

    return 1;
}
int BOOL_FORMULA_FOLLOW(FileField *fileField, int left_brother_ID, int father_ID){
    int ret = 0;
    char *func_name="BOOL_FORMULA_FOLLOW";
    unsigned int tempIndex = 0;
    short n_mode = 0;
    /* [ 1 ] make a node for 'BOOL_FORMULA_FOLLOW' */
    tempIndex = g_SynTree.n_node_num;
    g_SynTree.pSynNodeList[ tempIndex ].n_father_id = father_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_identifier_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_left_brother_id = left_brother_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_mode = SYN_NODE_BOOL_FORMULA_FOLLOW;
    g_SynTree.pSynNodeList[ tempIndex ].n_right_brother_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_son_id = INVALID_ID;
    /* [ 2 ] fix for father and left brother */
    FIX_FATHER_LBROTHER( father_ID, left_brother_ID, tempIndex )
    g_SynTree.n_node_num++;
    CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
    /* [ 3 ] check the operator, maybe two bytes */
    JUMP_SPACES( fileField )
    if( '|' == fileField->current_ch ){
        /* [ 4 ] deal with the operator '||' */
        fileField->current_ch = fgetc( fileField->fp );
        CHECK_NEW_LINE( fileField )
        if( '|' != fileField->current_ch ){
            report_syntax_error( func_name, "Invalid operator.", fileField->n_current_line );
            return 0;
        }
        /* [ 4.1 ] mode is '||' */
        n_mode = SYN_NODE_OR;
        /* [ 4.2 ] jump spaces in the end */
        GET_NEW_CHAR_JUMP_SPACE( fileField )
    } else if( '&' == fileField->current_ch){
        /* [ 5 ] deal with the operator '&&' */
        fileField->current_ch = fgetc( fileField->fp );
        CHECK_NEW_LINE( fileField )
        if( '&' != fileField->current_ch ){
            report_syntax_error( func_name, "Invalid operator.", fileField->n_current_line );
            return 0;
        }
        /* [ 5.1 ] mode is '||' */
        n_mode = SYN_NODE_AND;
        /* [ 5.2 ] jump spaces in the end */
        GET_NEW_CHAR_JUMP_SPACE( fileField )
    } else if( '<' == fileField->current_ch){
        /* [ 6 ] deal with the operator '<' or '<=' */
        fileField->current_ch = fgetc( fileField->fp );
        CHECK_NEW_LINE( fileField )
        if( '=' != fileField->current_ch ){
            /* [ 6.1 ] mode is '<' */
            n_mode = SYN_NODE_LESS;
        } else{
            /* [ 6.2 ] mode is '<=' */
            n_mode = SYN_NODE_NOT_MORE;
            /* [ 6.3 ] jump spaces in the end */
            GET_NEW_CHAR_JUMP_SPACE( fileField )
        }
    } else if( '>' == fileField->current_ch){
        /* [ 7 ] deal with the operator '>' or '>=' */
        fileField->current_ch = fgetc( fileField->fp );
        CHECK_NEW_LINE( fileField )
        if( '=' != fileField->current_ch ){
            /* [ 7.1 ] mode is '>' */
            n_mode = SYN_NODE_MORE;
        } else{
            /* [ 7.2 ] mode is '>=' */
            n_mode = SYN_NODE_NOT_LESS;
            /* [ 7.3 ] jump spaces in the end */
            GET_NEW_CHAR_JUMP_SPACE( fileField )
        }
    } else if( '=' == fileField->current_ch){
        /* [ 8 ] deal with the operator '==' */
        fileField->current_ch = fgetc( fileField->fp );
        CHECK_NEW_LINE( fileField )
        if( '=' != fileField->current_ch ){
            report_syntax_error( func_name, "Invalid operator.", fileField->n_current_line );
            return 0;
        }
        /* [ 8.1 ] mode is '==' */
        n_mode = SYN_NODE_EQ;
        /* [ 8.2 ] jump spaces in the end */
        GET_NEW_CHAR_JUMP_SPACE( fileField )
    } else if( '!' == fileField->current_ch){
        /* [ 9 ] deal with the operator '!=' */
        fileField->current_ch = fgetc( fileField->fp );
        CHECK_NEW_LINE( fileField )
        if( '=' != fileField->current_ch ){
            report_syntax_error( func_name, "Invalid operator.", fileField->n_current_line );
            return 0;
        }
        /* [ 9.1 ] mode is '!=' */
        n_mode = SYN_NODE_NOT_EQ;
        /* [ 9.2 ] jump spaces in the end */
        GET_NEW_CHAR_JUMP_SPACE( fileField )
    } else if( '+' == fileField->current_ch){
        /* [ 10 ] deal with the operator '+' */
        n_mode = SYN_NODE_ADD;
        /* [ 10.1 ] jump spaces in the end */
        GET_NEW_CHAR_JUMP_SPACE( fileField )
    } else if( '-' == fileField->current_ch){
        /* [ 11 ] deal with the operator '-' */
        n_mode = SYN_NODE_SUB;
        /* [ 11.1 ] jump spaces in the end */
        GET_NEW_CHAR_JUMP_SPACE( fileField )
    } else if( '*' == fileField->current_ch){
        /* [ 12 ] deal with the operator '*' */
        n_mode = SYN_NODE_MUT;
        /* [ 12.1 ] jump spaces in the end */
        GET_NEW_CHAR_JUMP_SPACE( fileField )
    } else if( '/' == fileField->current_ch){
        /* [ 13 ] deal with the operator '/' */
        n_mode = SYN_NODE_DIV;
        /* [ 13.1 ] jump spaces in the end */
        GET_NEW_CHAR_JUMP_SPACE( fileField )
    } else{
        /* empty follow */
        return 1;
    }
    /* [ 14 ] make a node for the operator*/
    tempIndex = g_SynTree.n_node_num;
    g_SynTree.pSynNodeList[ tempIndex ].n_father_id = tempIndex - 1;
    g_SynTree.pSynNodeList[ tempIndex ].n_identifier_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_left_brother_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_mode = n_mode;
    g_SynTree.pSynNodeList[ tempIndex ].n_right_brother_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_son_id = INVALID_ID;
    /* [ 15 ] fix for father and left brother */
    FIX_FATHER_LBROTHER( tempIndex - 1, INVALID_ID, tempIndex )
    g_SynTree.n_node_num++;
    CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
    /* [ 16 ] deal with BOOL_FORMULA */
    ret = BOOL_FORMULA( fileField, tempIndex, tempIndex - 1 );
    if( 0 == ret ){
        return 0;
    }

    return 1;
}
int FUNC_CALL(FileField *fileField, int left_brother_ID, int father_ID){
    int ret = 0;
    char *func_name="FUNC_CALL";
    unsigned int tempIndex = 0;
    unsigned int ident_index = 0;
    IdentId_P p_cur_id = NULL;
    /* [ 1 ] make a node for 'FUNC_CALL' */
    tempIndex = g_SynTree.n_node_num;
    g_SynTree.pSynNodeList[ tempIndex ].n_father_id = father_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_identifier_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_left_brother_id = left_brother_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_mode = SYN_NODE_FUNC_CALL;
    g_SynTree.pSynNodeList[ tempIndex ].n_right_brother_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_son_id = INVALID_ID;
    /* [ 2 ] fix for father and left brother */
    FIX_FATHER_LBROTHER( father_ID, left_brother_ID, tempIndex )
    g_SynTree.n_node_num++;
    CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
    /* [ 3 ] find the identifier in IdTable */
    ret = find_in_IdTable(fileField, fileField->name_buf, (int)strlen(fileField->name_buf), &ident_index);
    if( 0 == ret ){
        return 0;
    }
    p_cur_id = &g_IdTable.pIdList[ ident_index ];
    if( p_cur_id->n_mode != SYN_NODE_FUNID ){
        report_syntax_error( func_name, "Function can't be called, it's an identifier name.", fileField->n_current_line );
        return 0;
    }
    /* [ 4 ] make a node for the func_id */
    tempIndex = g_SynTree.n_node_num;
    g_SynTree.pSynNodeList[ tempIndex ].n_father_id = tempIndex - 1;
    g_SynTree.pSynNodeList[ tempIndex ].n_identifier_id = ident_index;
    g_SynTree.pSynNodeList[ tempIndex ].n_left_brother_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_mode = SYN_NODE_FUNID;
    g_SynTree.pSynNodeList[ tempIndex ].n_right_brother_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_son_id = INVALID_ID;
    /* [ 5 ] fix for father and left brother */
    FIX_FATHER_LBROTHER( tempIndex - 1, INVALID_ID, tempIndex )
    g_SynTree.n_node_num++;
    CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
    /* [ 6 ] check the '(' */
    JUMP_SPACES( fileField )
    if( '(' != fileField->current_ch ){
        report_syntax_error( func_name, "Missing '('.", fileField->n_current_line );
        return 0;
    }
    /* [ 7 ] check the ')' */
    GET_NEW_CHAR_JUMP_SPACE( fileField )
    if( ')' != fileField->current_ch ){
        report_syntax_error( func_name, "Missing ')'.", fileField->n_current_line );
        return 0;
    }
    /* [ 8 ] check the ';' */
    GET_NEW_CHAR_JUMP_SPACE( fileField )
    if( ';' != fileField->current_ch ){
        report_syntax_error( func_name, "Missing ';'.", fileField->n_current_line );
        return 0;
    }

    return 1;
}
int add_to_IdTable(FileField * fileField, char *id_name, int length, short mode, unsigned int * p_ident_index){
    char first_index = 0;
    char second_index = 0;
    IdentId_P cur_IdentId_list = NULL;
    unsigned int index = 0;
    unsigned int temp = 0;
    char *func_name = "add_to_IdTable";

    if( length <= 0 ){
        report_internal_error(func_name, __LINE__);
        return 0;
    }
    if( id_name[0] >= 'A' && id_name[0] <= 'Z' ){
        first_index = id_name[0] - 'A';
    } else if( id_name[0] >= 'a' && id_name[0] <= 'z' ){
        first_index = id_name[0] - 'a' + 26;
    } else{
        first_index = 51;
    }
    if( length > 1 ){
        if( id_name[1] >= 'A' && id_name[1] <= 'Z' ){
            second_index = id_name[1] - 'A';
        } else if( id_name[1] >= 'a' && id_name[1] <= 'z' ){
            second_index = id_name[1] - 'a' + 26;
        } else if( id_name[1] >= '0' && id_name[1] <= '9' ){
            second_index = id_name[1] - '0' + 52;
        } else{
            second_index = 61;
        }
    }
    temp = g_IdTable.two_level_index[ first_index ][ second_index ];

    while( temp != INVALID_ID ){
        /* a list is found */
        cur_IdentId_list = &g_IdTable.pIdList[temp];
        if( strcmp( cur_IdentId_list->str_name, id_name ) == 0 ){
            /* already exist */
            report_syntax_error( func_name, "Re-definition error.", fileField->n_current_line );
            return 0;
        }
        temp = cur_IdentId_list->n_next_identifier_id;
    }
    if( g_IdTable.n_id_num + 1 > MAX_SYN_NODE_NUM ){
        report_syntax_error( func_name, "Too many identifiers.", fileField->n_current_line );
        return 0;
    }
    index = g_IdTable.n_id_num;
    g_IdTable.n_id_num++;
    if( NULL != cur_IdentId_list ){
        cur_IdentId_list->n_next_identifier_id = index;
    } else{
        /* create a new list for this id */
        g_IdTable.two_level_index[ first_index ][ second_index ] = index;
    }
    g_IdTable.pIdList[index].n_mode = mode;
    g_IdTable.pIdList[index].n_next_identifier_id = INVALID_ID;
    strcpy_s( g_IdTable.pIdList[index].str_name, MAX_ID_LENGTH+1, id_name );
    *p_ident_index = index;

    return 1;
}

int find_in_IdTable(FileField * fileField, char *id_name, int length, unsigned int * p_ident_index){
    char first_index = 0;
    char second_index = 0;
    IdentId_P cur_IdentId_list = NULL;
    unsigned int index = 0;
    unsigned int temp = 0;
    char *func_name = "find_in_IdTable";

    if( length <= 0 ){
        report_syntax_error( func_name, "Identifier not specified.", fileField->n_current_line );
        return 0;
    }
    if( id_name[0] >= 'A' && id_name[0] <= 'Z' ){
        first_index = id_name[0] - 'A';
    } else if( id_name[0] >= 'a' && id_name[0] <= 'z' ){
        first_index = id_name[0] - 'a' + 26;
    } else{
        first_index = 51;
    }
    if( length > 1 ){
        if( id_name[1] >= 'A' && id_name[1] <= 'Z' ){
            second_index = id_name[1] - 'A';
        } else if( id_name[1] >= 'a' && id_name[1] <= 'z' ){
            second_index = id_name[1] - 'a' + 26;
        } else if( id_name[1] >= '0' && id_name[1] <= '9' ){
            second_index = id_name[1] - '0' + 52;
        } else{
            second_index = 61;
        }
    }
    temp = g_IdTable.two_level_index[ first_index ][ second_index ];

    while( temp != INVALID_ID ){
        /* a list is found */
        cur_IdentId_list = &g_IdTable.pIdList[temp];
        if( strcmp( cur_IdentId_list->str_name, id_name ) == 0 ){
            *p_ident_index = temp;
            return 1;
        }
        temp = cur_IdentId_list->n_next_identifier_id;
    }
    report_syntax_error( func_name, "Identifier not specified.", fileField->n_current_line );
    return 0;
}

int get_number( FileField * fileField, int * pOutValue){
    char *func_name = "get_number";
    int tempValue1 = 0;
    int tempValue2 = 0;
    int b_sign = 0;/* 0 ==> no sign ,  1 ==> '+' , -1 ==> '-'  */
    /* [ 1 ] check the sign */
    if( '-' == fileField->current_ch ){
        b_sign = -1;
        fileField->current_ch = fgetc( fileField->fp );
        CHECK_NEW_LINE( fileField )
    } else if( '+' == fileField->current_ch ){
        b_sign = 1;
        fileField->current_ch = fgetc( fileField->fp );
        CHECK_NEW_LINE( fileField )
    }
    /* [ 2 ] check the first number */
    if( fileField->current_ch < '0' || fileField->current_ch > '9' ){
        report_syntax_error( func_name, "Invalid character.", fileField->n_current_line );
        return 0;
    }
    while( fileField->current_ch >= '0' && fileField->current_ch <= '9' ){
        tempValue1 = tempValue2;
        tempValue2 = tempValue2 * 10 + fileField->current_ch - '0';
        if( tempValue1 > tempValue2 ){
            /* [ 3 ] deal with overflow */
            report_syntax_error( func_name, "Integer overflow.", fileField->n_current_line );
            return 0;
        }
        fileField->current_ch = fgetc( fileField->fp );
        CHECK_NEW_LINE( fileField )        
    }
    if( -1 == b_sign ){
        tempValue2 = ~tempValue2 + 1;
    }
    if( tempValue2 > SHORT_MAX || tempValue2 < SHORT_MIN ){
        /* [ 4 ] deal with overflow. Note: using 16bit-int for EXE file */
        report_syntax_error( func_name, "Integer overflow.", fileField->n_current_line );
        return 0;
    }
    *pOutValue = (int)tempValue2;


    return 1;
}
static void print_syntax_node( FILE* fp, SynNode_P p_node ){
    char buffer[128];
    buffer[0] = '\0';
    switch( p_node->n_mode ){
    case SYN_NODE_HEAD:
        strcpy_s( buffer, 128, "head" );
        break;
    case SYN_NODE_VARID:
        strcpy_s( buffer, 128, "VARID" );
        break;
    case SYN_NODE_FUNID:
        strcpy_s( buffer, 128, "FUNID" );
        break;
    case SYN_NODE_MAINFUNID:
        strcpy_s( buffer, 128, "main" );
        break;
    case SYN_NODE_BODY:
        strcpy_s( buffer, 128, "BODY" );
        break;
    case SYN_NODE_DEFINITION:
        strcpy_s( buffer, 128, "DEFINITION" );
        break;
    case SYN_NODE_VAR_DEF:
        strcpy_s( buffer, 128, "VAR_DEF" );
        break;
    case SYN_NODE_FUNC_DEF:
        strcpy_s( buffer, 128, "FUNC_DEF" );
        break;
    case SYN_NODE_VAR_DEFINITION:
        strcpy_s( buffer, 128, "VAR_DEFINITION" );
        break;
    case SYN_NODE_STATEMENT_LIST:
        strcpy_s( buffer, 128, "STATEMENT_LIST" );
        break;
    case SYN_NODE_ASSIGN_STMT:
        strcpy_s( buffer, 128, "ASSIGN_STMT" );
        break;
    case SYN_NODE_IF_STMT:
        strcpy_s( buffer, 128, "IF_STMT" );
        break;
    case SYN_NODE_FOR_STMT:
        strcpy_s( buffer, 128, "FOR_STMT" );
        break;
    case SYN_NODE_WHILE_STMT:
        strcpy_s( buffer, 128, "WHILE_STMT" );
        break;
    case SYN_NODE_FORMULA:
        strcpy_s( buffer, 128, "FORMULA" );
        break;
    case SYN_NODE_BOOL_FORMULA:
        strcpy_s( buffer, 128, "BOOL_FORMULA" );
        break;
    case SYN_NODE_FORMULA_FOLLOW:
        strcpy_s( buffer, 128, "FORMULA_FOLLOW" );
        break;
    case SYN_NODE_NUMBER:
        strcpy_s( buffer, 128, "NUMBER" );
        break;
    case SYN_NODE_L_parenthesis:
        strcpy_s( buffer, 128, "(" );
        break;
    case SYN_NODE_R_parenthesis:
        strcpy_s( buffer, 128, ")" );
        break;
    case SYN_NODE_ADD:
        strcpy_s( buffer, 128, "+" );
        break;
    case SYN_NODE_SUB:
        strcpy_s( buffer, 128, "-" );
        break;
    case SYN_NODE_MUT:
        strcpy_s( buffer, 128, "*" );
        break;
    case SYN_NODE_DIV:
        strcpy_s( buffer, 128, "/" );
        break;
    case SYN_NODE_AND:
        strcpy_s( buffer, 128, "&&" );
        break;
    case SYN_NODE_OR:
        strcpy_s( buffer, 128, "||" );
        break;
    case SYN_NODE_LESS:
        strcpy_s( buffer, 128, "<" );
        break;
    case SYN_NODE_MORE:
        strcpy_s( buffer, 128, ">" );
        break;
    case SYN_NODE_EQ:
        strcpy_s( buffer, 128, "==" );
        break;
    case SYN_NODE_NOT_LESS:
        strcpy_s( buffer, 128, ">=" );
        break;
    case SYN_NODE_NOT_MORE:
        strcpy_s( buffer, 128, "<=" );
        break;
    case SYN_NODE_NOT_EQ:
        strcpy_s( buffer, 128, "!=" );
        break;
    case SYN_NODE_BOOL_FORMULA_FOLLOW:
        strcpy_s( buffer, 128, "BOOL_FORMULA_FOLLOW" );
        break;
    case SYN_NODE_EMPTY:
        strcpy_s( buffer, 128, "EMPTY" );
        break;
    case SYN_NODE_FUNC_CALL:
        strcpy_s( buffer, 128, "FUNC_CALL" );
        break;
    }

    fprintf( fp,"n_mode = '%s';", buffer);
    if( SYN_NODE_VARID == p_node->n_mode || SYN_NODE_FUNID == p_node->n_mode ){
        fprintf( fp, "id name = '%s';", g_IdTable.pIdList[ p_node->n_identifier_id ].str_name );
    }
    fprintf( fp,"father_id = '%d';", (int)p_node->n_father_id);
    fprintf( fp,"left_brother_id = '%d';", (int)p_node->n_left_brother_id);
    fprintf( fp,"right_brother_id = '%d';", (int)p_node->n_right_brother_id);
    fprintf( fp,"son_id = '%d';", (int)p_node->n_son_id);
    if( SYN_NODE_NUMBER == p_node->n_mode ){
        fprintf( fp, "value = '%d';", p_node->n_int_value );
    }
}
void debug_syntax( FILE* fp ){
    unsigned int i = 0;
    for( i = 0; i < g_SynTree.n_node_num; i++ ){
        fprintf( fp,"id = '%6d';", i);
        print_syntax_node( fp, &g_SynTree.pSynNodeList[ i ] );
        fprintf(fp,"\n*******************************************************************************\n");
    }
}


语义分析器

/** scmpsem.c
====================================================================
This is the base source file for Semantic Analyze


====================================================================
 */

#include "scmpsem.h"
int sem_deal_with_header();
int sem_deal_with_data();
int sem_deal_with_code();
int sem_deal_with_DEFINITION(SynNode_P pSynNode);
int sem_deal_with_BODY(SynNode_P pSynNode);
int sem_deal_with_FUNC_DEF(SynNode_P pSynNode);
int sem_deal_with_STATEMENT_LIST(SynNode_P pSynNode);
int sem_deal_with_ASSIGN_STMT(SynNode_P pSynNode);
int sem_deal_with_IF_STMT(SynNode_P pSynNode);
int sem_deal_with_FOR_STMT(SynNode_P pSynNode);
int sem_deal_with_WHILE_STMT(SynNode_P pSynNode);
int sem_deal_with_FUNC_CALL(SynNode_P pSynNode);
int sem_deal_with_FORMULA(SynNode_P pSynNode);
int sem_deal_with_BOOL_FORMULA(SynNode_P pSynNode);

static int push( SEM_STACK_NODE *in_node );
static int pop( SEM_STACK_NODE *out_node );
#define MY_PUSH( p_in_node )\
    {\
        if( 0 == push( p_in_node ) ){\
           printf("POP error at line '%d' \n", __LINE__ );\
           return 0;\
        }\
    }
#define MY_POP( p_out_node )\
    {\
        if( 0 == pop( p_out_node ) ){\
           printf("POP error at line '%d' \n", __LINE__ );\
           return 0;\
        }\
    }
static int check_caculate( SEM_STACK_NODE *cur_node );
static int caculate_AX_BX_by_op( SEM_STACK_NODE *op_node );

int initialize_SemEnv(){
    g_SemEnv.n_SignCurrentId = 0;
    g_SemEnv.pAsmFile = NULL;
    fopen_s( &g_SemEnv.pAsmFile, ASM_FILE_NAME , "w" );
    if( NULL == g_SemEnv.pAsmFile ){
        printf("Can't open source file '%s'. exit.\n", ASM_FILE_NAME );
        return 0;
    }
    g_SemEnv.s_sem_stack.n_num = 0;
    g_SemEnv.s_sem_stack.sem_node_list = ( SEM_STACK_NODE * )malloc( sizeof(SEM_STACK_NODE) * MAX_STACK_NUM );
    if( NULL == g_SemEnv.s_sem_stack.sem_node_list ){
        printf("Memery not enough while initializing semantic stack.\n" );
        return 0;
    }
    return 1;
}
int finalize_SemEnv(){
    g_SemEnv.n_SignCurrentId = 0;
    MY_HELP_CLOSE( g_SemEnv.pAsmFile );
    g_SemEnv.s_sem_stack.n_num = 0;
    MY_HELP_FREE( g_SemEnv.s_sem_stack.sem_node_list );
    return 1;
}


int semantic_analyzer(){
    int ret = 0;
    char * func_name="semantic_analyzer";

    ret = initialize_SemEnv();
    if( 0 == ret ){
        printf("semantic_analyzer exit with initialize error.\n");
        finalize_SemEnv();
        return 0;
    }
    /* [ 1 ] deal with header */
    sem_deal_with_header();
    /* [ 2 ] deal with data */
    ret = sem_deal_with_data();
    if( 0 == ret ){
        printf("semantic_analyzer exit with internal error.\n");
        finalize_SemEnv();
        return 0;
    }
    /* [ 3 ] deal with code */
    ret =  sem_deal_with_code();
    if( 0 == ret ){
        printf("semantic_analyzer exit with internal error.\n");
        finalize_SemEnv();
        return 0;
    }
    /* [ 4 ] deal with Ending */
    fprintf( g_SemEnv.pAsmFile, ASM_END_MAIN );

    finalize_SemEnv();
    return 1;
}
int sem_deal_with_header(){
    fprintf( g_SemEnv.pAsmFile, ASM_HEADER );

    return 1;
}
int sem_deal_with_data(){
    unsigned int index = 0;
    char * p_VarName = NULL;

    /* [ 1 ] data header */
    fprintf( g_SemEnv.pAsmFile, ASM_DATA_HEADER );
    /* [ 2 ] Variable definition */
    for( index = 0; index < g_IdTable.n_id_num; index++ ){
        if( SYN_NODE_VARID == g_IdTable.pIdList[ index ].n_mode ){
            p_VarName = g_IdTable.pIdList[ index ].str_name;
            fprintf( g_SemEnv.pAsmFile, ASM_VAR_DEF, p_VarName, p_VarName, p_VarName );
        }
    }

    return 1;
}
int sem_deal_with_code(){
    int ret = 0;
    SynNode_P pCurSynNode = NULL;

    /* [ 1 ] code header */
    fprintf( g_SemEnv.pAsmFile, ASM_CODE_HEADER );
    /* [ 2 ] deal with DEFINITION */
    /* [ 2.1 ] Get the first node of DEFINITION */
    pCurSynNode = &g_SynTree.pSynNodeList[1];
    ret = sem_deal_with_DEFINITION( pCurSynNode );
    if( 0 == ret ){
        return 0;
    }
    /* [ 3 ] deal with main */
    /* [ 3.1 ] Get the node of 'main' */
    fprintf( g_SemEnv.pAsmFile, "Main  PROC\nMOV AX, DGROUP\nMOV DS, AX\n" );
    CHECK_SYN_NODE_ID( pCurSynNode->n_right_brother_id )
    pCurSynNode = &g_SynTree.pSynNodeList[ pCurSynNode->n_right_brother_id ];
    /* [ 3.2 ] Get the node of 'BODY' */
    CHECK_SYN_NODE_ID( pCurSynNode->n_right_brother_id )
    pCurSynNode = &g_SynTree.pSynNodeList[ pCurSynNode->n_right_brother_id ];
    ret = sem_deal_with_BODY( pCurSynNode );
    if( 0 == ret ){
        return 0;
    }
#ifdef DEBUG_SEM
    debug_sem();
#endif
    /* [ 3.3 ] Tail of 'main' */
    fprintf( g_SemEnv.pAsmFile, "MOV  AX, 4C00H\nINT  21H\nMain  ENDP\n" );
    return 1;
}
int sem_deal_with_DEFINITION( SynNode_P pSynNode ){
    SynNode_P pCurSynNode = NULL;
    int ret = 0;

    /* [ 1 ] Get the first node of DEFINITION */
    pCurSynNode = pSynNode;
    while( pCurSynNode != NULL && pCurSynNode->n_son_id != INVALID_ID ){
        /* [ 1.1 ] check the son */
        pCurSynNode = &g_SynTree.pSynNodeList[ pCurSynNode->n_son_id ];
        if( SYN_NODE_FUNC_DEF == pCurSynNode->n_mode ){
            /* [ 1.1.1 ] it's FUNC definition, deal with it */
            ret = sem_deal_with_FUNC_DEF( pCurSynNode );
            if( 0 == ret ){
                return 0;
            }

        }
            /* [ 1.1.2 ] deal with right brother of it */
        if( pCurSynNode->n_right_brother_id != INVALID_ID ){
            pCurSynNode = &g_SynTree.pSynNodeList[ pCurSynNode->n_right_brother_id ];
        } else{
            pCurSynNode = NULL;
        }
    }
    return 1;
}
int sem_deal_with_FUNC_DEF(SynNode_P pSynNode){
    SynNode_P pCurSynNode = NULL;
    IdentId_P pId = NULL;
    int ret = 0;
    /* [ 1 ] Function Header */
    /* [ 1.1 ] Get the function id */
    CHECK_SYN_NODE_ID( pSynNode->n_son_id )
    pCurSynNode = &g_SynTree.pSynNodeList[ pSynNode->n_son_id ];
    CHECK_SYN_NODE_ID( pCurSynNode->n_identifier_id )
    pId = &g_IdTable.pIdList[ pCurSynNode->n_identifier_id ];
    fprintf( g_SemEnv.pAsmFile, "%s  PROC\n", pId->str_name );
    /* [ 1.2 ] Save the current Registers */
    fprintf( g_SemEnv.pAsmFile, "PUSH  BP\n", pId->str_name );
    fprintf( g_SemEnv.pAsmFile, "MOV  BP, SP\n", pId->str_name );
    fprintf( g_SemEnv.pAsmFile, "PUSH  DS\n", pId->str_name );
    /* [ 2 ] deal with 'BODY' */
    CHECK_SYN_NODE_ID( pCurSynNode->n_right_brother_id )
    pCurSynNode = &g_SynTree.pSynNodeList[ pCurSynNode->n_right_brother_id ];
    ret = sem_deal_with_BODY( pCurSynNode );
    if( 0 == ret ){
        return 0;
    }
    /* [ 3 ] Function Tail */
    /* [ 3.1 ] Backup the current Registers */
    fprintf( g_SemEnv.pAsmFile, "POP  DS\n", pId->str_name );
    fprintf( g_SemEnv.pAsmFile, "MOV  SP, BP\n", pId->str_name );
    fprintf( g_SemEnv.pAsmFile, "POP  BP\n", pId->str_name );
    fprintf( g_SemEnv.pAsmFile, "RET\n%s  ENDP\n", pId->str_name );
    return 1;
}
int sem_deal_with_BODY(SynNode_P pSynNode){
    SynNode_P pCurSynNode = NULL;
    int ret = 0;
    
    /* [ 1 ] get node of 'VAR_DEFINITION' */
    CHECK_SYN_NODE_ID( pSynNode->n_son_id )
    pCurSynNode = &g_SynTree.pSynNodeList[ pSynNode->n_son_id ];
    /* [ 2 ] deal with  'STATEMENT_LIST' */
    if( INVALID_ID != pCurSynNode->n_right_brother_id ){
        pCurSynNode = &g_SynTree.pSynNodeList[ pCurSynNode->n_right_brother_id ];
        ret = sem_deal_with_STATEMENT_LIST( pCurSynNode );
        if( 0 == ret ){
            return 0;
        }
    }
    return 1;
}
int sem_deal_with_STATEMENT_LIST(SynNode_P pSynNode){
    SynNode_P pCurSynNode = NULL;
    int ret = 0;

    if( INVALID_ID == pSynNode->n_son_id ){
        /* empty statement list */
        return 1;
    }
    /* [ 1 ] deal with first statement */
    pCurSynNode = &g_SynTree.pSynNodeList[ pSynNode->n_son_id ];
    switch( pCurSynNode->n_mode ){
        case SYN_NODE_ASSIGN_STMT:
            ret = sem_deal_with_ASSIGN_STMT( pCurSynNode );
            break;
        case SYN_NODE_IF_STMT:
            ret = sem_deal_with_IF_STMT( pCurSynNode );
            break;
        case SYN_NODE_FOR_STMT:
            ret = sem_deal_with_FOR_STMT( pCurSynNode );
            break;
        case SYN_NODE_WHILE_STMT:
            ret = sem_deal_with_WHILE_STMT( pCurSynNode );
            break;
        case SYN_NODE_FUNC_CALL:
            ret = sem_deal_with_FUNC_CALL( pCurSynNode );
            break;
    }
    if( 0 == ret ){
        return 0;
    }
    /* [ 2 ] deal with following statement */
    CHECK_SYN_NODE_ID( pCurSynNode->n_right_brother_id )
    pCurSynNode = &g_SynTree.pSynNodeList[ pCurSynNode->n_right_brother_id ];
    ret = sem_deal_with_STATEMENT_LIST( pCurSynNode );
    return ret;
}
int sem_deal_with_ASSIGN_STMT(SynNode_P pSynNode){
    SynNode_P pCurSynNode = NULL;
    int ret = 0;
    IdentId_P pId = NULL;
    /* [ 1 ] get the var id */
    CHECK_SYN_NODE_ID( pSynNode->n_son_id )
    pCurSynNode = &g_SynTree.pSynNodeList[ pSynNode->n_son_id ];
    CHECK_SYN_NODE_ID( pCurSynNode->n_identifier_id )
    pId = &g_IdTable.pIdList[ pCurSynNode->n_identifier_id ];

    /* [ 2 ] deal with FORMULA */
    CHECK_SYN_NODE_ID( pCurSynNode->n_right_brother_id )
    pCurSynNode = &g_SynTree.pSynNodeList[ pCurSynNode->n_right_brother_id ];
    ret = sem_deal_with_FORMULA( pCurSynNode );
    if( 0 == ret ){
        return ret;
    }
    /* [ 3 ] deal with assign */
    fprintf( g_SemEnv.pAsmFile, "MOV  %s, AX\n", pId->str_name );

    return 1;
}
int sem_deal_with_IF_STMT(SynNode_P pSynNode){
    SynNode_P pCurSynNode = NULL;
    int ret = 0;
    char str_cur_sign[20];
    /* [ 1 ] deal with BOOL_FORMULA */
    CHECK_SYN_NODE_ID( pSynNode->n_son_id )
    pCurSynNode = &g_SynTree.pSynNodeList[ pSynNode->n_son_id ];
    ret = sem_deal_with_BOOL_FORMULA( pCurSynNode );
    if( 0 == ret ){
        return 0;
    }
    /* [ 2 ] make a sign name. if AX is 0, jump to it. */
    sprintf_s( str_cur_sign, sizeof(str_cur_sign), "SIGN_%d", g_SemEnv.n_SignCurrentId );
    g_SemEnv.n_SignCurrentId++;
    fprintf( g_SemEnv.pAsmFile, "CMP  AX,0\nJE %s\n",  str_cur_sign );
    /* [ 3 ] deal with STATEMENT_LIST */
    CHECK_SYN_NODE_ID( pCurSynNode->n_right_brother_id )
    pCurSynNode = &g_SynTree.pSynNodeList[ pCurSynNode->n_right_brother_id ];
    ret = sem_deal_with_STATEMENT_LIST( pCurSynNode );
    if( 0 == ret ){
        return 0;
    }
    /* [ 4 ] make the sign at the end */
    fprintf( g_SemEnv.pAsmFile, "%s:\n",  str_cur_sign );
    return 1;
}
int sem_deal_with_FOR_STMT(SynNode_P pSynNode){
    SynNode_P pCurSynNode = NULL;
    SynNode_P pSecondAssign = NULL;
    int ret = 0;
    char str_first_sign[20];
    char str_second_sign[20];
    /* [ 1 ] deal with ASSIGN_STMT */
    CHECK_SYN_NODE_ID( pSynNode->n_son_id )
    pCurSynNode = &g_SynTree.pSynNodeList[ pSynNode->n_son_id ];
    if( SYN_NODE_ASSIGN_STMT == pCurSynNode->n_mode ){
        ret = sem_deal_with_ASSIGN_STMT( pCurSynNode );
        if( 0 == ret ){
            return 0;
        }
    }
    /* [ 2 ] make a sign before BOOL_FORMULA */
    sprintf_s( str_first_sign, sizeof(str_first_sign), "SIGN_%d", g_SemEnv.n_SignCurrentId );
    g_SemEnv.n_SignCurrentId++;
    fprintf( g_SemEnv.pAsmFile, "%s:\n",  str_first_sign );
    /* [ 3 ] deal with BOOL_FORMULA */
    CHECK_SYN_NODE_ID( pCurSynNode->n_right_brother_id )
    pCurSynNode = &g_SynTree.pSynNodeList[ pCurSynNode->n_right_brother_id ];
    ret = sem_deal_with_BOOL_FORMULA( pCurSynNode );
    if( 0 == ret ){
        return 0;
    }
    /* [ 4 ] make a sign at the end, if AX=0,jump to it */
    sprintf_s( str_second_sign, sizeof(str_first_sign), "SIGN_%d", g_SemEnv.n_SignCurrentId );
    g_SemEnv.n_SignCurrentId++;
    fprintf( g_SemEnv.pAsmFile, "CMP  AX,0\nJE %s\n",  str_second_sign );
    /* [ 5 ] store the second Assign Statement node */
    CHECK_SYN_NODE_ID( pCurSynNode->n_right_brother_id )
    pCurSynNode = &g_SynTree.pSynNodeList[ pCurSynNode->n_right_brother_id ];
    pSecondAssign = pCurSynNode;
    /* [ 6 ] deal with STATEMENT_LIST */
    CHECK_SYN_NODE_ID( pCurSynNode->n_right_brother_id )
    pCurSynNode = &g_SynTree.pSynNodeList[ pCurSynNode->n_right_brother_id ];
    ret = sem_deal_with_STATEMENT_LIST( pCurSynNode );
    if( 0 == ret ){
        return 0;
    }
    /* [ 7 ] deal with the second Assign Statement */
    if( SYN_NODE_ASSIGN_STMT == pSecondAssign->n_mode ){
        ret = sem_deal_with_ASSIGN_STMT( pSecondAssign );
        if( 0 == ret ){
            return 0;
        }
    }
    /* [ 8 ] jump to first sign */
    fprintf( g_SemEnv.pAsmFile, "JMP %s\n",  str_first_sign );
    /* [ 9 ] store to second sign */
    fprintf( g_SemEnv.pAsmFile, "%s:\n",  str_second_sign );

    return 1;
}
int sem_deal_with_WHILE_STMT(SynNode_P pSynNode){
    SynNode_P pCurSynNode = NULL;
    int ret = 0;
    char str_first_sign[20];
    char str_second_sign[20];
    /* [ 1 ] make a sign before BOOL_FORMULA */
    sprintf_s( str_first_sign, sizeof(str_first_sign), "SIGN_%d", g_SemEnv.n_SignCurrentId );
    g_SemEnv.n_SignCurrentId++;
    fprintf( g_SemEnv.pAsmFile, "%s:\n",  str_first_sign );
    /* [ 2 ] deal with BOOL_FORMULA */
    CHECK_SYN_NODE_ID( pSynNode->n_son_id )
    pCurSynNode = &g_SynTree.pSynNodeList[ pSynNode->n_son_id ];
    ret = sem_deal_with_BOOL_FORMULA( pCurSynNode );
    if( 0 == ret ){
        return 0;
    }
    /* [ 3 ] make a sign at the end, if AX=0,jump to it */
    sprintf_s( str_second_sign, sizeof(str_first_sign), "SIGN_%d", g_SemEnv.n_SignCurrentId );
    g_SemEnv.n_SignCurrentId++;
    fprintf( g_SemEnv.pAsmFile, "CMP  AX,0\nJE %s\n",  str_second_sign );
    /* [ 4 ] deal with STATEMENT_LIST */
    CHECK_SYN_NODE_ID( pCurSynNode->n_right_brother_id )
    pCurSynNode = &g_SynTree.pSynNodeList[ pCurSynNode->n_right_brother_id ];
    ret = sem_deal_with_STATEMENT_LIST( pCurSynNode );
    if( 0 == ret ){
        return 0;
    }
    /* [ 5 ] jump to first sign */
    fprintf( g_SemEnv.pAsmFile, "JMP %s\n",  str_first_sign );
    /* [ 6 ] store to second sign */
    fprintf( g_SemEnv.pAsmFile, "%s:\n",  str_second_sign );

    return 1;
}
int sem_deal_with_FUNC_CALL(SynNode_P pSynNode){
    SynNode_P pCurSynNode = NULL;
    IdentId_P pId = NULL;

    CHECK_SYN_NODE_ID( pSynNode->n_son_id )
    pCurSynNode = &g_SynTree.pSynNodeList[ pSynNode->n_son_id ];
    CHECK_SYN_NODE_ID( pCurSynNode->n_identifier_id )
    pId = &g_IdTable.pIdList[ pCurSynNode->n_identifier_id ];
    fprintf( g_SemEnv.pAsmFile, "CALL  %s\n", pId->str_name );

    return 1;
}
int sem_deal_with_FORMULA(SynNode_P pSynNode){
    char * func_name="sem_deal_with_FORMULA";
    SynNode_P pCurSynNode = NULL;
    IdentId_P pId = NULL;
    int ret = 0;
    unsigned int n_CurrentNodeId = 0;
    SEM_STACK_NODE sem_node;
    SEM_STACK_NODE op_node;
    n_CurrentNodeId = pSynNode->n_son_id;
    while( 1 ){
        /* [ 1 ] check the first Node of the Formula */
        CHECK_SYN_NODE_ID( n_CurrentNodeId )
        pCurSynNode = &g_SynTree.pSynNodeList[ n_CurrentNodeId ];
        /* [ 1.1 ] deal with '(' FORMULA ')' */
        if( SYN_NODE_L_parenthesis == pCurSynNode->n_mode ){
            /* [ 1.1.1 ] push '(' into Stack */
            sem_node.n_mode = 7;
            sem_node.n_value = SYN_NODE_L_parenthesis;
            MY_PUSH( &sem_node );
            /* [ 1.1.2 ] deal with FORMULA recursively */
            CHECK_SYN_NODE_ID( pCurSynNode->n_right_brother_id )
            pCurSynNode = &g_SynTree.pSynNodeList[ pCurSynNode->n_right_brother_id ];
            ret = sem_deal_with_FORMULA( pCurSynNode );
            if( 0 == ret ){
                return 0;
            }
            /* [ 1.1.3 ] deal with ')' */
            CHECK_SYN_NODE_ID( pCurSynNode->n_right_brother_id )
            pCurSynNode = &g_SynTree.pSynNodeList[ pCurSynNode->n_right_brother_id ];
            if( SYN_NODE_R_parenthesis != pCurSynNode->n_mode ){
                report_internal_error( func_name, __LINE__ );
                printf("Missing ')' in FORMULA .\n" );
                return 0;
            }
            /* [ 1.1.4 ] caculate current formula between '(' and ')' */
            op_node.n_mode = 0;
            op_node.n_value = SYN_NODE_R_parenthesis;
            ret = check_caculate( &op_node );
            if( 0 == ret ){
                return 0;
            }
        } else if( SYN_NODE_VARID == pCurSynNode->n_mode ){
        /* [ 1.2 ] deal with identifier */
            /* [ 1.2.1 ] make a sem node for the identifier */
            sem_node.n_mode = 0xffff;
            MY_PUSH( &sem_node );
            /* [ 1.2.2 ] make ASM code for the identifier */
            CHECK_SYN_NODE_ID( pCurSynNode->n_identifier_id )
            pId = &g_IdTable.pIdList[ pCurSynNode->n_identifier_id ];
            fprintf( g_SemEnv.pAsmFile, "MOV AX, %s\n", pId->str_name );
            fprintf( g_SemEnv.pAsmFile, "PUSH AX\n" );
        } else {
        /* [ 1.3 ] deal with number */
            /* [ 1.3.1 ] make a sem node for the number */
            sem_node.n_mode = 0xffff;
            MY_PUSH( &sem_node );
            /* [ 1.3.2 ] make ASM code for the number */
            fprintf( g_SemEnv.pAsmFile, "MOV AX, %d\n", pCurSynNode->n_int_value );
            fprintf( g_SemEnv.pAsmFile, "PUSH AX\n" );
        }
        /* [ 2 ]  deal with FORMULA_FOLLOW */
        CHECK_SYN_NODE_ID( pCurSynNode->n_right_brother_id )
        pCurSynNode = &g_SynTree.pSynNodeList[ pCurSynNode->n_right_brother_id ];
        if( INVALID_ID == pCurSynNode->n_son_id ){
            /*=================================================================
            Empty FORMULA_FOLLOW.Clear the stack and finish the caculating 
            =================================================================*/
            while( 1 ){
                MY_POP( &sem_node );
                if( 0 == g_SemEnv.s_sem_stack.n_num ){
                    /* This node is the only node in the stack , finished. */
                    fprintf( g_SemEnv.pAsmFile, "POP AX\n" );
                    return 1;
                }
                MY_POP( &op_node );
                if( 7 == op_node.n_mode ){/* Reach the Beginning of a FOMULA */
                    MY_PUSH( &op_node );
                    MY_PUSH( &sem_node );
                    return 1;
                } else{
                    MY_POP( &sem_node );
                    ret = caculate_AX_BX_by_op( &op_node );
                }
                /* Push the result */
                MY_PUSH( &sem_node );
                if( 0 == ret ){
                    return 0;
                }
                if( 0 == g_SemEnv.s_sem_stack.n_num ){
                    /* This node is the only node in the stack , finished. */
                    fprintf( g_SemEnv.pAsmFile, "POP AX\n" );
                    return 1;
                }
            }
        } else{
            /* [ 2.1 ] deal with operator */
            pCurSynNode = &g_SynTree.pSynNodeList[ pCurSynNode->n_son_id ];
            switch( pCurSynNode->n_mode ){
                case SYN_NODE_ADD:
                case SYN_NODE_SUB:
                    op_node.n_mode = 5;
                    break;
                case SYN_NODE_MUT:
                case SYN_NODE_DIV:
                    op_node.n_mode = 6;
                    break;
                case SYN_NODE_AND:
                    op_node.n_mode = 2;
                    break;
                case SYN_NODE_OR:
                    op_node.n_mode = 1;
                    break;
                case SYN_NODE_LESS:
                case SYN_NODE_MORE:
                case SYN_NODE_NOT_LESS:
                case SYN_NODE_NOT_MORE:
                    op_node.n_mode = 4;
                    break;
                case SYN_NODE_EQ:
                case SYN_NODE_NOT_EQ:
                    op_node.n_mode = 3;
                    break;
                default:
                    printf("Internal error! invalid operator mode '%d' at line '%d'\n", pCurSynNode->n_mode, __LINE__ );
                    return 0;
            }
            op_node.n_value = pCurSynNode->n_mode;
            ret = check_caculate( &op_node );
            if( 0 == ret ){
                return 0;
            }
            /* [ 2.2 ] deal with FORMULA using the while-looping */
            CHECK_SYN_NODE_ID( pCurSynNode->n_right_brother_id )
            pCurSynNode = &g_SynTree.pSynNodeList[ pCurSynNode->n_right_brother_id ];
            n_CurrentNodeId = pCurSynNode->n_son_id;
        }
    }

    return 1;
}
int sem_deal_with_BOOL_FORMULA(SynNode_P pSynNode){
    if( sem_deal_with_FORMULA( pSynNode ) == 0 ){
        return 0;
    }
    return 1;
}
static int push( SEM_STACK_NODE *in_node ){
    unsigned int num = 0;
    num = g_SemEnv.s_sem_stack.n_num;
    if( num >= MAX_STACK_NUM ){
        printf("Internal Error ! semantic stack overflow!\n");
        return 0;
    }
    memcpy( &g_SemEnv.s_sem_stack.sem_node_list[ num ], in_node, sizeof( SEM_STACK_NODE ) );
    g_SemEnv.s_sem_stack.n_num++;
    return 1;
}
static int pop( SEM_STACK_NODE *out_node ){
    unsigned int index = 0;
    index = g_SemEnv.s_sem_stack.n_num;
    index--;
    if( index >= MAX_STACK_NUM ){
        printf("Internal Error ! semantic stack empty!\n");
        return 0;
    }
    memcpy( out_node, &g_SemEnv.s_sem_stack.sem_node_list[ index ], sizeof( SEM_STACK_NODE ) );
    g_SemEnv.s_sem_stack.n_num--;
    return 1;
}
static int check_caculate( SEM_STACK_NODE *cur_node ){
    unsigned int num = 0;
    unsigned short cur_mode = cur_node->n_mode;
    unsigned short last_mode = 0;
    SEM_STACK_NODE sem_node;
    SEM_STACK_NODE op_node;
    num = g_SemEnv.s_sem_stack.n_num;
    if( 0 == cur_mode ){
        /* [ 1 ] deal with ')' */
        /* [ 1.1 ] pop the first node on top of the stack */
        MY_POP( &sem_node );
        if( 0xffff != sem_node.n_mode ){
            printf("Internal Error ! Missing number between '(' and ')' in FORMULA .\n" );
            return 0;
        }
        /* [ 1.2 ] pop the next node on top of the stack */
        MY_POP( &op_node );
        if( 7 == op_node.n_mode ){/* '(' */
            /* push the result of FORMULA between '(' and ')' */
            MY_PUSH( &sem_node );
        } else{/* operator */
            /* [ 1.2 ] pop the second number on top of the stack */
            MY_POP( &sem_node );
            /* [ 1.3 ] caculate current formula between '(' and ')' */
            if( 0 == caculate_AX_BX_by_op( &op_node ) ){
                return 0;
            }
            /* [ 1.4 ] pop the '(' */
            MY_POP( &op_node );
            /* [ 1.5 ] push the result of FORMULA between '(' and ')' */
            MY_PUSH( &sem_node );
        }
    } else{
        /* [ 2 ] deal with other operators */
        if( num >= 2 && num <= MAX_STACK_NUM ){
            last_mode = g_SemEnv.s_sem_stack.sem_node_list[ num-2 ].n_mode;
        }
        if( cur_mode <= last_mode && last_mode != 7 ){/* '(' can't caculate without ')' */
            MY_POP( &sem_node );
            MY_POP( &op_node );
            MY_POP( &sem_node );
            if( 0 == caculate_AX_BX_by_op( &op_node ) ){
                return 0;
            }
            MY_PUSH( &sem_node );
        } else{
            /* do nothing */
        }
        MY_PUSH( cur_node );
    }
    return 1;
}
static int caculate_AX_BX_by_op( SEM_STACK_NODE *op_node ){
    char * func_name = "caculate_AX_BX_by_op";
    char str_first_sign[20];
    char str_second_sign[20];
    /* [ 1 ] pop BX */
    fprintf( g_SemEnv.pAsmFile, "POP  BX\n" );
    /* [ 2 ] pop AX */
    fprintf( g_SemEnv.pAsmFile, "POP  AX\n" );
    /* [ 3 ] caculate */
    switch( op_node->n_mode ){
        case 1: /* || */
            fprintf( g_SemEnv.pAsmFile, "OR AX, BX\n" );
            break;
        case 2: /* && */
            fprintf( g_SemEnv.pAsmFile, "AND AX, BX\n" );
            break;
        case 3:
            if( SYN_NODE_EQ == op_node->n_value ){ /* == */
                fprintf( g_SemEnv.pAsmFile, ";Deal with '=='\n" );
                sprintf_s( str_first_sign, sizeof(str_first_sign), "SIGN_%d", g_SemEnv.n_SignCurrentId );
                g_SemEnv.n_SignCurrentId++;
                sprintf_s( str_second_sign, sizeof(str_second_sign), "SIGN_%d", g_SemEnv.n_SignCurrentId );
                g_SemEnv.n_SignCurrentId++;
                fprintf( g_SemEnv.pAsmFile, "CMP AX, BX\n" );
                fprintf( g_SemEnv.pAsmFile, "JNE %s\n",  str_first_sign );
                fprintf( g_SemEnv.pAsmFile, "MOV AX, 1\n" );
                fprintf( g_SemEnv.pAsmFile, "JMP %s\n", str_second_sign );
                fprintf( g_SemEnv.pAsmFile, "%s:\n",  str_first_sign );
                fprintf( g_SemEnv.pAsmFile, "MOV AX, 0\n" );
                fprintf( g_SemEnv.pAsmFile, "%s:\n",  str_second_sign );
            } else{ /* != */
                fprintf( g_SemEnv.pAsmFile, "XOR AX, BX\n" );
            }
            break;
        case 4:
            if( SYN_NODE_MORE == op_node->n_value ){ /* > */
                fprintf( g_SemEnv.pAsmFile, "SUB BX, AX\n" );
                fprintf( g_SemEnv.pAsmFile, "AND BX, 8000H\n" );
                fprintf( g_SemEnv.pAsmFile, "MOV AX, BX\n" );
            } else if( SYN_NODE_LESS == op_node->n_value ){ /* < */
                fprintf( g_SemEnv.pAsmFile, "SUB AX, BX\n" );
                fprintf( g_SemEnv.pAsmFile, "AND AX, 8000H\n" );
            } else if( SYN_NODE_NOT_LESS == op_node->n_value ){ /* >= */
                fprintf( g_SemEnv.pAsmFile, "SUB AX, BX\n" );
                fprintf( g_SemEnv.pAsmFile, "AND AX, 8000H\n" );
                fprintf( g_SemEnv.pAsmFile, "XOR AX, 8000H\n" );
            } else{ /* <= */
                fprintf( g_SemEnv.pAsmFile, "SUB BX, AX\n" );
                fprintf( g_SemEnv.pAsmFile, "AND BX, 8000H\n" );
                fprintf( g_SemEnv.pAsmFile, "XOR BX, 8000H\n" );
                fprintf( g_SemEnv.pAsmFile, "MOV AX, BX\n" );
            }
            break;
        case 5:
            if( SYN_NODE_ADD == op_node->n_value ){ /* + */
                fprintf( g_SemEnv.pAsmFile, "ADD AX, BX\n" );
            } else{ /* - */
                fprintf( g_SemEnv.pAsmFile, "SUB AX, BX\n" );
            }
            break;
        case 6:
            if( SYN_NODE_MUT == op_node->n_value ){ /* * */
                fprintf( g_SemEnv.pAsmFile, "MUL BX\n" );
            } else{ /* / */
                fprintf( g_SemEnv.pAsmFile, "MOV DX, 0\n" );
                fprintf( g_SemEnv.pAsmFile, "DIV BX\n" );
            }
            break;
        default:
            report_internal_error( func_name, __LINE__ );
            printf("Invalid operator mode '%d'\n", op_node->n_mode );
            return 0;
    }
    /* [ 4 ] push AX */
    fprintf( g_SemEnv.pAsmFile, "PUSH  AX\n" );

    return 1;
}
void debug_sem( ){
    unsigned int i = 0;
    IdentId_P pId = NULL;
    for( i = 0; i < g_IdTable.n_id_num; i++ ){
        pId = &g_IdTable.pIdList[ i ];
        if( SYN_NODE_VARID == pId->n_mode ){
            fprintf( g_SemEnv.pAsmFile, "LEA  AX, Name_%s\nMOV  DX, AX\nMOV  AH, 9\nINT  21H\n", pId->str_name );
            fprintf( g_SemEnv.pAsmFile, "MOV  AX, %s\nPRINTVAL  AX\n", pId->str_name );
            fprintf( g_SemEnv.pAsmFile, ASM_CHANGE_LINE );
        }
    }
}


主函数

/** SimpleCompiler.c
====================================================================
This is the base source file for Main Function


====================================================================
 */

#include "scmppre.h"
#include "scmpstx.h"
#include "scmpsem.h"
int main(int arg_num, char ** args){
    int ret = 0;
    FILE *srcFP = NULL;
    FILE *outFP = NULL;
    char *inputFile = "test.c";
    char *outputFile = "test.c.tmp";
    FileField srcFileField;
#ifdef DEBUG_SYNTAX
    char *debugFile = "test.c.stx";
    FILE * debugfp = NULL;
#endif
    /* Global initializing */
    ret = initialize_IdTable();
    ret &= initialize_SynTree();
    if( 0 == ret ){
        printf("Program exit with initializing error.\n");
        return 0;
    }
    fopen_s( &srcFP, inputFile , "r" );
    if( NULL == srcFP ){
        printf("Can't open source file '%s'. Program exit.\n", inputFile );
        return 0;
    }
    fopen_s( &outFP, outputFile, "w" );
    if( NULL == outFP ){
        printf("Can't open temp file '%s'. Program exit.\n", outputFile );
        return 0;
    }
    /** pre-compiler **/
    ret = pre_compiler(srcFP, outFP);
    if( 0 == ret ){
        printf("Program exit with pre-compiler error.\n");
        goto ERROR_END;
    }
    MY_HELP_CLOSE( outFP );
    MY_HELP_CLOSE( srcFP );
    /** Syntax analyzing **/
    /* using the temp file as the source */
    fopen_s( &srcFP, outputFile, "r" );
    if( NULL == srcFP ){
        printf("Can't open temp file '%s'. Program exit.\n", outputFile );
        goto ERROR_END;
    }
    srcFileField.fp = srcFP;
    srcFileField.n_current_line = 1;
    ret = syntax_analyzer( &srcFileField );
    if( 0 == ret ){
        printf("Program exit with syntax_analyzer error.\n");
        goto ERROR_END;
    }
#ifdef DEBUG_SYNTAX
    fopen_s(&debugfp, debugFile, "w");
    if( NULL != debugfp ){
        debug_syntax( debugfp );
        fclose( debugfp );
    }
#endif
    /** semantic_analyzer **/
    ret = semantic_analyzer();
    if( 0 == ret ){
        printf("Program exit with semantic_analyzer error.\n");
        goto ERROR_END;
    }

    MY_HELP_CLOSE( outFP );
    MY_HELP_CLOSE( srcFP );
    release_IdTable();
    release_SynTree();
    return 1;
ERROR_END:
    MY_HELP_CLOSE( outFP );
    MY_HELP_CLOSE( srcFP );
    release_IdTable();
    release_SynTree();
    return 0;
}


语法分析头文件

 

/** scmppre.h
====================================================================
This is the base head file for pre-compiler


====================================================================
 */
#ifndef SCMPPRE_H_INCLUDE
#define SCMPPRE_H_INCLUDE

#ifndef STD_COMMON_H_INCLUDE
#define STD_COMMON_H_INCLUDE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#endif


#define MAX_SRC_LINE      1024           /* the max byte number of one line in the source file */

int pre_compiler(FILE * fpInput, FILE * fpOutput);



#endif


语法分析头文件:

/** scmpstx.h
====================================================================
This is the base head file for Syntax Analyze


====================================================================
 */
#ifndef SCMPSTX_H_INCLUDE
#define SCMPSTX_H_INCLUDE


#ifndef STD_COMMON_H_INCLUDE
#define STD_COMMON_H_INCLUDE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#endif

#define MAX_SYN_NODE_NUM  32768          /* the max syntax node number */
#define MAX_ID_LENGTH     32             /* the max length of indentifier */
/* The identifier id */
typedef struct tag_identifier_id{
    short n_mode;                        /* the mode : SYN_NODE_TAIL / SYN_NODE_VARID / SYN_NODE_FUNID */
    short dummy;                         /* not used */
    int n_next_identifier_id;            /* the next identifier in current second-level list */
    char str_name[ MAX_ID_LENGTH+1 ];
}IdentId;
typedef IdentId * IdentId_P;
/* The identifier table */
typedef struct tag_id_table{
    unsigned int n_id_num;               /*============================================================
                                         The number of identifiers in the table.
                                         It's also the first free place for store a new identifier.
                                         Using n_id_num,  pIdList acts as a stack, and n_id_num is
                                         it's stack top.
                                         If n_id_num >= MAX_SYN_NODE_NUM, the stack is full.
                                         ============================================================*/
    IdentId_P pIdList;                   /*============================================================
                                         the head pointer of the identifier list.
                                         malloc MAX_SYN_NODE_NUM IdentId.
                                         ============================================================*/
    unsigned int two_level_index[52][62];        /*============================================================
                                         First index: using the first byte of the name
                                             'A' to 'Z' = 0 to 25
                                             'a' to 'z' = 26 to 51
                                         Second index: using the second byte of the name
                                             'A' to 'Z' = 0 to 25
                                             'a' to 'z' = 26 to 51
                                             '0' to '9' = 52 to 61
                                         Default value: two_level_index[i][j] = -1;
                                         if two_level_index[i][j] is not -1, it shows this second-level
                                         list in the pIdList is started at pIdList[two_level_index[i][j]]
                                         ============================================================*/            
}IdTable;
IdTable g_IdTable;                       /* the identifier table */
/* The node for syntax tree */
typedef struct tag_SyntaxNode{
    short n_mode;                        /* the mode of SyntaxNode */
    unsigned int n_identifier_id;        /*============================================================
                                         The index in the Id Table for this identifier.
                                         If it's not identifier, n_identifier_id = INVALID_ID;
                                         ============================================================*/
    unsigned int n_left_brother_id;      /*============================================================
                                         The index of the left brother in the syntax tree.
                                         If it's the first son of its father, n_left_brother_id = INVALID_ID;
                                         ============================================================*/
    unsigned int n_right_brother_id;     /*============================================================
                                         The index of the right brother in the syntax tree.
                                         If it's the last son of its father, n_right_brother_id = INVALID_ID;
                                         ============================================================*/
    unsigned int n_father_id;            /*============================================================
                                         The index of the father in the syntax tree.
                                         If it's the root, n_father_id = INVALID_ID;
                                         ============================================================*/
    unsigned int n_son_id;               /*============================================================
                                         The index of the son in the syntax tree.
                                         If it has no son, n_son_id = INVALID_ID;
                                         ============================================================*/
    int n_int_value;                       /* the value of integer */
}SynNode;
typedef SynNode * SynNode_P;
typedef struct tat_SyntaxTree{
    unsigned int n_node_num;             /*============================================================
                                         The number of SynNode in the SyntaxTree.
                                         It's also the first free place for store a new SynNode.
                                         Using n_node_num,  pSynNodeList acts as a stack, and n_node_num is
                                         it's stack top.
                                         If n_node_num >= MAX_SYN_NODE_NUM, the stack is full.
                                         ============================================================*/
    SynNode_P pSynNodeList;              /*============================================================
                                         the head pointer of the syntax tree node list.
                                         malloc MAX_SYN_NODE_NUM SynNode.
                                         ============================================================*/
}SynTree;
SynTree g_SynTree;                       /* the syntax tree */
/* Syntax Node mode definitions */
#define SYN_NODE_TAIL                 0          /* the tail node */
#define SYN_NODE_HEAD                 1          /* the head node */
#define SYN_NODE_VARID                2          /* the identifier of variabale */
#define SYN_NODE_FUNID                3          /* the identifier of function */
#define SYN_NODE_MAINFUNID            4          /* the identifier of main function */
#define SYN_NODE_BODY                 11         /* the BODY of a function */
#define SYN_NODE_DEFINITION           12         /* DEFINITION */
#define SYN_NODE_VAR_DEF              13         /* VAR_DEF */
#define SYN_NODE_FUNC_DEF             14         /* FUNC_DEF */
#define SYN_NODE_VAR_DEFINITION       15         /* VAR_DEFINITION */
#define SYN_NODE_STATEMENT_LIST       16         /* STATEMENT_LIST */
#define SYN_NODE_ASSIGN_STMT          17         /* ASSIGN_STMT */
#define SYN_NODE_IF_STMT              18         /* IF_STMT */
#define SYN_NODE_FOR_STMT             19         /* FOR_STMT */
#define SYN_NODE_WHILE_STMT           20         /* WHILE_STMT */
#define SYN_NODE_FORMULA              21         /* FORMULA */
#define SYN_NODE_BOOL_FORMULA         22         /* BOOL_FORMULA */
#define SYN_NODE_FORMULA_FOLLOW       23         /* FORMULA_FOLLOW */
#define SYN_NODE_NUMBER               24         /* numbers */
#define SYN_NODE_L_parenthesis        25         /* '(' */
#define SYN_NODE_R_parenthesis        26         /* ')' */
#define SYN_NODE_ADD                  27         /* '+' */
#define SYN_NODE_SUB                  28         /* '-' */
#define SYN_NODE_MUT                  29         /* '*' */
#define SYN_NODE_DIV                  30         /* '/' */
#define SYN_NODE_AND                  31         /* '&&' */
#define SYN_NODE_OR                   32         /* '||' */
#define SYN_NODE_LESS                 33         /* '<' */
#define SYN_NODE_MORE                 34         /* '>' */
#define SYN_NODE_EQ                   35         /* '==' */
#define SYN_NODE_NOT_LESS             36         /* '>=' */
#define SYN_NODE_NOT_MORE             37         /* '<=' */
#define SYN_NODE_NOT_EQ               38         /* '!=' */
#define SYN_NODE_BOOL_FORMULA_FOLLOW  39         /* BOOL_FORMULA_FOLLOW */
#define SYN_NODE_FUNC_CALL            40         /* FUNC_CALL */
#define SYN_NODE_EMPTY               100         /* An empty node */

#define SHORT_MAX                    32767       /* MAX VALUE OF SHORT */
#define SHORT_MIN                    -32768      /* MIN VALUE OF SHORT */

#define INVALID_ID            (unsigned int)0xFFFFFFFF         /* the invalid index */

typedef struct tag_fileField{
    FILE * fp;                                   /* the pointer to the source file */
    int n_current_line;                          /* the current line number */
    char current_ch;                             /* the current char */
    char name_buf[MAX_ID_LENGTH+1];              /* the buffer for an identifier name */
}FileField;

#define KEY_WORD_NO                   0          /* Not a key word */
#define KEY_WORD_MAIN                 1          /* 'main' */
#define KEY_WORD_INT                  2          /* 'int' */
#define KEY_WORD_IF                   3          /* 'if' */
#define KEY_WORD_WHILE                4          /* 'while' */
#define KEY_WORD_FOR                  5          /* 'for' */

#define CHECK_KEY_WORD( buffer, type ) \
    { \
        if( 0 == strcmp( buffer, "main" ) ){\
            type = KEY_WORD_MAIN;\
        } else if( 0 == strcmp( buffer, "int" ) ){\
            type = KEY_WORD_INT;\
        } else if( 0 == strcmp( buffer, "if" ) ){\
            type = KEY_WORD_IF;\
        } else if( 0 == strcmp( buffer, "while") ){\
            type = KEY_WORD_WHILE;\
        } else if( 0 == strcmp( buffer, "for") ){\
            type = KEY_WORD_FOR;\
        } else{\
            type = KEY_WORD_NO;\
        }\
    }
#define MY_HELP_FREE( pValue )  \
    if( NULL != pValue ){\
        free(pValue);\
        pValue = NULL;\
    }
#define MY_HELP_CLOSE( pFILE )  \
    if( NULL != pFILE ){\
        fclose(pFILE);\
        pFILE = NULL;\
    }
#define CHECK_NEW_LINE( fileField ) \
    if( '\n' == fileField->current_ch ){\
        fileField->n_current_line++;\
    }
#define JUMP_SPACES( fileField ) \
    {\
        while( isspace( fileField->current_ch ) ){\
            fileField->current_ch = fgetc( fileField->fp );\
            CHECK_NEW_LINE( fileField )\
        }\
    }
#define GET_IDENTIFY( fileField, buffer, length )\
    {\
        length = 0;\
        JUMP_SPACES( fileField );\
        if( !isalpha(fileField->current_ch) ){/* the fisrt char must be alphabet */\
            buffer[0] = '\0';\
            length = 0;\
        } else{\
            buffer[0] = fileField->current_ch;\
            length = 1;\
            while( 1 ){\
                fileField->current_ch = fgetc( fileField->fp );\
                CHECK_NEW_LINE( fileField )\
                if( isalnum( fileField->current_ch ) ){\
                    buffer[length] = fileField->current_ch;\
                    length++;\
                    if( length > MAX_ID_LENGTH ){/* too logn identifier */\
                        buffer[0] = '\0';\
                        length = 0;\
                        break;\
                    }\
                } else{\
                    buffer[length] = '\0';\
                    break;\
                }\
            }\
        }\
    }
#define GET_NEW_CHAR_JUMP_SPACE( fileField ) \
    {\
        fileField->current_ch = fgetc( fileField->fp );\
        CHECK_NEW_LINE( fileField )\
        JUMP_SPACES( fileField )\
    }
#define CHECK_NODE_NUM( function, fileField, num ) \
    {\
        if( num > MAX_SYN_NODE_NUM ){\
            report_syntax_error( function, "Too many syntax nodes.", fileField->n_current_line );\
            return 0;\
        }\
    }
#define FIX_FATHER_LBROTHER( father_ID, left_brother_ID, current_ID ) \
    {\
        if( father_ID != INVALID_ID ){\
            if( INVALID_ID == g_SynTree.pSynNodeList[father_ID].n_son_id ){\
                g_SynTree.pSynNodeList[father_ID].n_son_id = current_ID;\
            }\
        }\
        if( left_brother_ID != INVALID_ID ){\
            if( INVALID_ID == g_SynTree.pSynNodeList[left_brother_ID].n_right_brother_id ){\
                g_SynTree.pSynNodeList[left_brother_ID].n_right_brother_id = current_ID;\
            }\
        }\
    }
int syntax_analyzer(FileField *fileField);
int initialize_IdTable();
int initialize_SynTree();
int release_IdTable();
int release_SynTree();
void report_syntax_error(char *func_name, char *detail, int line_number);
void report_memery_error(char *func_name, int line_number);
void report_internal_error(char *func_name, int line_number);
int add_to_IdTable(FileField * fileField, char *id_name, int length, short mode, unsigned int * p_ident_index);
int find_in_IdTable(FileField * fileField, char *id_name, int length, unsigned int * p_ident_index);
int get_number( FileField * fileField, int * pOutValue);
void debug_syntax( FILE* fp );

#endif


语义分析头文件:

 
 

/** scmpsem.h
====================================================================
This is the base head file for Semantic Analyze


====================================================================
 */
#ifndef SCMPSEM_H_INCLUDE
#define SCMPSEM_H_INCLUDE

#include "scmpstx.h"

#ifndef LINUX
/* For Windows only */
/* define the header of the MASM source file */
#define ASM_HEADER ".MODEL SMALL\n.STACK 4096h\nINCLUDE PrintVal.mac\n"
#define ASM_DATA_HEADER ".DATA\nASM_CHAGNE_LINE  DB  0DH,0AH,'$'\n"
/* the definition of varibale e.g. sprintf(buffer, MASM_VAR_DEF, "VAR1", "VAR1", "VAR1") */
#define ASM_VAR_DEF "%s  DW  0\nName_%s  DB '%s',20H,20H,'$'\n"
#define ASM_CODE_HEADER ".CODE\nCALL Main\n"
#define ASM_END_MAIN "END Main\n"
#define ASM_FILE_NAME "MyResult.asm"
#define ASM_CHANGE_LINE "LEA  AX, ASM_CHAGNE_LINE\nMOV  DX, AX\nMOV  AH, 9\nINT  21H\n"

#else
/* For Linux only */
#endif

#define MAX_STACK_NUM 32768               /* the max node number of sem_stack */
typedef struct tag_SEM_STACK_NODE{
    unsigned short n_mode;                /*====================================
                                          Type of the node
                                          0 ==> )
                                          1 ==> ||
                                          2 ==> &&
                                          3 ==> ==   !=
                                          4 ==> >   >=   <   <=
                                          5 ==> +  -
                                          6 ==> *  /
                                          7 ==> (
                                          0xffff ==> number
                                          =====================================*/
    short n_value;                        /*=====================================
                                          The value of the node,using definition
                                          in the scmpstx.h.
                                          e.g.
                                          SYN_NODE_NUMBER   24   numbers
                                          SYN_NODE_EQ       35   '=='
                                          =====================================*/
}SEM_STACK_NODE;
typedef struct tag_SEM_STACK{
    unsigned int n_num;
    SEM_STACK_NODE * sem_node_list;
}SEM_STACK;
typedef struct tag_SemEnv{
    unsigned int n_SignCurrentId;         /* the id of current sign */
    FILE * pAsmFile;                      /* the pointer to the output ASM file */
    SEM_STACK s_sem_stack;                /* the stack for semantic analyze */
}SemEnv;
SemEnv g_SemEnv;/* the semantic analyser environment */

int initialize_SemEnv();
int finalize_SemEnv();
int semantic_analyzer();
void debug_sem( );


#define CHECK_SYN_NODE_ID(id)  \
    if( INVALID_ID == (id) ){\
          printf("Internal Error ! Invalid syntax node id at line '%d'.\n", __LINE__);\
          return 0;\
    }
         

#endif


 


'; fputs(str_line_buffer, fpOutput); index = 0; } else{ str_line_buffer[index] = current_char; index++; CHECK_INDEX( index ) } current_char = fgetc(fpInput); } str_line_buffer[index] = '
预处理器:
/** scmppre.c
====================================================================
This is the base source file for pre-compiler


====================================================================
 */

#include "scmppre.h"


static int report_pre_error(char *msg, int code){
    printf("Error : %s\nCode : %d\n", msg, code);
    return 0;
}

#define CHECK_INDEX( index )    \
    if( index >= MAX_SRC_LINE ){\
        report_pre_error("Too long line.", index);\
        return 0;\
    }
/*=======================================================
The main function of pre-compiler.
return     1 : success
           0 : fail
========================================================*/
int pre_compiler(FILE * fpInput, FILE * fpOutput){
    char str_line_buffer[MAX_SRC_LINE + 1];
    int index = 0;
    char current_char;
    current_char = fgetc(fpInput);
    while( current_char != EOF ){
        /*========================================================
        search the '//' . if exists, jump the rest of the line.
        ========================================================*/
        if( '/' == current_char ){
            current_char = fgetc(fpInput);
            if( '/' == current_char ){
                while( current_char != EOF ){
                    current_char =  fgetc(fpInput);
                    if( '\n' == current_char ){
                        /* end of a line */
                        str_line_buffer[index] = '\n';
                        index++;
                        CHECK_INDEX( index )
                        break;/* stop loop */
                    }
                }
                /* output a line */
                str_line_buffer[index] = '\0';
                fputs(str_line_buffer, fpOutput);
                index = 0;
            } else{
                /* a single '/', just store it and its following byte */
                str_line_buffer[index] = '/';
                index++;
                CHECK_INDEX( index )
                if( EOF == current_char ){ /* end of file */
                    str_line_buffer[index] = '\0';
                    fputs(str_line_buffer, fpOutput);
                    index = 0;
                    return 1;
                } else if( '\n' == current_char ){
                    str_line_buffer[index] = current_char;
                    index++;
                    CHECK_INDEX( index )
                    str_line_buffer[index] = '\0';
                    fputs(str_line_buffer, fpOutput);
                    index = 0;
                } else{
                    str_line_buffer[index] = current_char;
                    index++;
                    CHECK_INDEX( index )
                }
            }
        } else if( '\n' == current_char ){
            str_line_buffer[index] = current_char;
            index++;
            CHECK_INDEX( index )
            str_line_buffer[index] = '\0';
            fputs(str_line_buffer, fpOutput);
            index = 0;
        } else{
            str_line_buffer[index] = current_char;
            index++;
            CHECK_INDEX( index )
        }
        current_char = fgetc(fpInput);
    }

    str_line_buffer[index] = '\0';
    fputs(str_line_buffer, fpOutput);
    index = 0;

    return 1;
}


语法分析器

 

/** scmpstx.c
====================================================================
This is the base source file for Syntax Analyze


====================================================================
 */
#include "scmpstx.h"

int DEFINITION(FileField *fileField, int left_brother_ID, int father_ID);
int VAR_DEF(FileField *fileField, int left_brother_ID, int father_ID);
int FUNC_DEF(FileField *fileField, int left_brother_ID, int father_ID);
int IDENTIFY(FileField *fileField, int left_brother_ID, int father_ID);
int BODY(FileField *fileField, int left_brother_ID, int father_ID);
int VAR_DEFINITION(FileField *fileField, int left_brother_ID, int father_ID);
int STATEMENT_LIST(FileField *fileField, int left_brother_ID, int father_ID);
int ASSIGN_STMT(FileField *fileField, int left_brother_ID, int father_ID);
int IF_STMT(FileField *fileField, int left_brother_ID, int father_ID);
int FOR_STMT(FileField *fileField, int left_brother_ID, int father_ID);
int WHILE_STMT(FileField *fileField, int left_brother_ID, int father_ID);
int FORMULA(FileField *fileField, int left_brother_ID, int father_ID);
int BOOL_FORMULA(FileField *fileField, int left_brother_ID, int father_ID);
int FORMULA_FOLLOW(FileField *fileField, int left_brother_ID, int father_ID);
int BOOL_FORMULA_FOLLOW(FileField *fileField, int left_brother_ID, int father_ID);
int FUNC_CALL(FileField *fileField, int left_brother_ID, int father_ID);



void report_syntax_error(char *func_name, char *detail, int line_number){
    printf("Syntax error accured in function '%s()', at line '%d'.\nDetail: %s\n", func_name, line_number, detail);
    return;
}
void report_memery_error(char *func_name, int line_number){
    printf("Memery error accured in function '%s()', at line '%d'.\n", func_name, line_number);
    return;
}
void report_internal_error(char *func_name, int line_number){
    printf("Internal error accured in function '%s()', at line '%d'.\n", func_name, line_number);
    return;
}
int initialize_IdTable(){
    int i=0;
    int j=0;
    g_IdTable.n_id_num = 0;
    g_IdTable.pIdList = (IdentId_P)malloc( ( MAX_SYN_NODE_NUM + 1 ) * sizeof(IdentId) );
    if( NULL == g_IdTable.pIdList ){
        report_memery_error("initialize_IdTable", __LINE__);
        return 0;
    }
    for( i = 0; i < 51; i++ ){
        for( j = 0; j < 61; j++ ){
            g_IdTable.two_level_index[i][j] = INVALID_ID;
        }
    }
    return 1;
}
int initialize_SynTree(){
    g_SynTree.n_node_num = 0;
    g_SynTree.pSynNodeList = (SynNode_P)malloc( ( MAX_SYN_NODE_NUM + 1 ) * sizeof(SynNode) );
    if( NULL == g_SynTree.pSynNodeList ){
        report_memery_error("initialize_SynTree", __LINE__);
        return 0;
    }
    return 1;
}
int release_IdTable(){
    MY_HELP_FREE( g_IdTable.pIdList )
    g_IdTable.n_id_num = 0;
    return 1;
}
int release_SynTree(){
    MY_HELP_FREE( g_SynTree.pSynNodeList );
    g_SynTree.n_node_num = 0;
    return 1;
}

int syntax_analyzer(FileField *fileField){
    int ret = 0;
    char * func_name="syntax_analyzer";

    /** [ 1 ] initialize a node for whole program **/
    g_SynTree.n_node_num = 1;
    g_SynTree.pSynNodeList[0].n_father_id = INVALID_ID;
    g_SynTree.pSynNodeList[0].n_identifier_id = INVALID_ID;
    g_SynTree.pSynNodeList[0].n_left_brother_id = INVALID_ID;
    g_SynTree.pSynNodeList[0].n_mode = SYN_NODE_HEAD;
    g_SynTree.pSynNodeList[0].n_right_brother_id = INVALID_ID;
    g_SynTree.pSynNodeList[0].n_son_id = INVALID_ID;
    /** [ 2 ] deal with DEFINITION **/
    ret = DEFINITION( fileField, INVALID_ID, 0 );
    /** [ 3 ] deal with 'main' **/
    if( 0 == ret ){
        printf("Syntax_analyzer exit with syntax error.\n");
        return 0;
    } else{
        /* some definition finished, the node 'DEFINITION' is the left brother of 'main' */
        g_SynTree.n_node_num++;
        CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
        g_SynTree.pSynNodeList[g_SynTree.n_node_num-1].n_father_id = 0;/* the index of 'main' is g_SynTree.n_node_num-1 */
        g_SynTree.pSynNodeList[g_SynTree.n_node_num-1].n_identifier_id = INVALID_ID;
        g_SynTree.pSynNodeList[g_SynTree.n_node_num-1].n_left_brother_id = 1;/* the node 'DEFINITION' */
        g_SynTree.pSynNodeList[g_SynTree.n_node_num-1].n_mode = SYN_NODE_MAINFUNID;
        g_SynTree.pSynNodeList[g_SynTree.n_node_num-1].n_right_brother_id = INVALID_ID;
        g_SynTree.pSynNodeList[g_SynTree.n_node_num-1].n_son_id = INVALID_ID;
        g_SynTree.pSynNodeList[1].n_right_brother_id = g_SynTree.n_node_num-1;/* fix the right brother for node 'DEFINITION' */
    }
    /** [ 4 ] deal with '(' and ')' **/
    /* [ 4.1 ] jump the spaces after 'main' */
    JUMP_SPACES( fileField )
    /* [ 4.2 ] check '(' */
    if( '(' != fileField->current_ch ){
        report_syntax_error( "syntax_analyzer", "missing '('.", fileField->n_current_line );
        printf("Syntax_analyzer exit with syntax error.\n");
        return 0;
    }
    /* [ 4.3 ] jump the spaces after '(' */
    GET_NEW_CHAR_JUMP_SPACE( fileField )
    /* [ 4.4 ] check ')' */
    if( ')' != fileField->current_ch ){
        report_syntax_error( "syntax_analyzer", "missing ')'.", fileField->n_current_line );
        printf("Syntax_analyzer exit with syntax error.\n");
        return 0;
    }
    /* [ 4.5 ] jump the spaces after ')' */
    GET_NEW_CHAR_JUMP_SPACE( fileField )
    /* [ 4.6 ] check '{' */
    if( '{' != fileField->current_ch ){
        report_syntax_error( "syntax_analyzer", "missing '{'.", fileField->n_current_line );
        printf("Syntax_analyzer exit with syntax error.\n");
        return 0;
    }
    /** [ 5 ] deal with 'BODY' **/
    ret = BODY( fileField, g_SynTree.n_node_num-1, 0 );
    if( 0 == ret ){
        printf("Syntax_analyzer exit with syntax error.\n");
        return 0;
    }
    /* [ 6 ] jump the spaces after 'BODY' */
    JUMP_SPACES( fileField )
    /* [ 7 ] check '}' */
    if( '}' != fileField->current_ch ){
        report_syntax_error( "syntax_analyzer", "missing '}'.", fileField->n_current_line );
        printf("Syntax_analyzer exit with syntax error.\n");
        return 0;
    }
    /* [ 8 ] jump the spaces after '}' */
    GET_NEW_CHAR_JUMP_SPACE( fileField )
    if( EOF != fileField->current_ch ){
        report_syntax_error( "syntax_analyzer", "Unexpected character.", fileField->n_current_line );
        printf("Syntax_analyzer exit with syntax error.\n");
        return 0;
    }
    return 1;
}


int DEFINITION(FileField *fileField, int left_brother_ID, int father_ID){
    int ret = 0;
    int id_length = 0;
    char *func_name="DEFINITION";
    unsigned int tempIndex = 0;

    /* [ 1 ] make a node for 'DEFINITION' */
    tempIndex = g_SynTree.n_node_num;
    g_SynTree.pSynNodeList[ tempIndex ].n_father_id = father_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_identifier_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_left_brother_id = left_brother_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_mode = SYN_NODE_DEFINITION;
    g_SynTree.pSynNodeList[ tempIndex ].n_right_brother_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_son_id = INVALID_ID;
    /* [ 2 ] fix for father and left brother */
    FIX_FATHER_LBROTHER( father_ID, left_brother_ID, tempIndex )
    g_SynTree.n_node_num++;
    CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )


    /* [ 3 ] deal with VAR_DEF */
    ret = VAR_DEF( fileField, INVALID_ID, tempIndex );
    if( 0 == ret ){
        return 0;
    }
    if( 1000 == ret ){
        report_syntax_error( func_name, "Invalid identifier .", fileField->n_current_line );
        return 0;
    } else if( 100 == ret ){
        return 1;
    } else if( 200 == ret ){
        /* [ 4 ] deal with FUNC_DEF */
        ret = FUNC_DEF( fileField, INVALID_ID, tempIndex );
        if( 0 == ret ){
            return 0;
        }
    } else if( 300 == ret ){
        report_syntax_error( "syntax_analyzer", "Unexpected character.", fileField->n_current_line );
        return 0;
    }
    /* [ 5 ] deal with DEFINITION recursively */
    ret = DEFINITION( fileField, g_SynTree.pSynNodeList[ tempIndex ].n_son_id, tempIndex );
    if( 0 == ret ){
        return 0;
    }
    return 1;
}
/** if it returns 1000, it's unkown character, maybe '}' **/
/** if it returns 100, an identifier name 'main' is stored in FileField.name_buf **/
/** if it returns 200, an identifier name ( not 'main' ) is stored in FileField.name_buf **/
/** if it returns 300, it's 'if' 'while' 'for' **/
int VAR_DEF(FileField *fileField, int left_brother_ID, int father_ID){
    int ret = 0;
    char *func_name="VAR_DEF";
    unsigned int tempIndex = 0;
    unsigned int ident_index = 0;
    int id_length = 0;
    /* [ 1 ] jump spaces in the head */
    GET_NEW_CHAR_JUMP_SPACE( fileField )
    /* [ 2 ] get the first token */
    GET_IDENTIFY( fileField, fileField->name_buf, id_length )
    if( 0 == id_length ){
        return 1000;
    }
    CHECK_KEY_WORD( fileField->name_buf, ret )
    if( KEY_WORD_MAIN == ret ){
        /* no definition */
        return 100;
    } else if( KEY_WORD_NO == ret ){
        /* it's an identifier. maybe statment_list or syntax error. */
        return 200;
    }else if( KEY_WORD_INT == ret ){
        /* [ 3 ] deal with 'VAR_DEF' */
        /* [ 3.1 ] make a node for 'VAR_DEF' */
        tempIndex = g_SynTree.n_node_num;
        g_SynTree.pSynNodeList[ tempIndex ].n_father_id = father_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_identifier_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_left_brother_id = left_brother_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_mode = SYN_NODE_VAR_DEF;
        g_SynTree.pSynNodeList[ tempIndex ].n_right_brother_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_son_id = INVALID_ID;
        /* [ 3.2 ] fix for father and left brother */
        FIX_FATHER_LBROTHER( father_ID, left_brother_ID, tempIndex )
        g_SynTree.n_node_num++;
        CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
        /* [ 3.3 ] get the identifier after 'int' */
        GET_IDENTIFY( fileField, fileField->name_buf, id_length )
        if( 0 == id_length ){
            report_syntax_error( func_name, "Invalid identifier .", fileField->n_current_line );
            return 0;
        }
        CHECK_KEY_WORD( fileField->name_buf, ret )
        if( KEY_WORD_NO != ret ){
            /* Invalid identifier */
            report_syntax_error( func_name, "Invalid identifier: key-word.", fileField->n_current_line );
            return 0;
        }
        /* [ 3.4 ] use a IdentId to store the identifier and make a syntax node */
        ret = add_to_IdTable(fileField, fileField->name_buf, id_length, SYN_NODE_VARID, &ident_index);
        if( 0 == ret ){
            return 0;
        }
        g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_father_id = tempIndex;
        g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_identifier_id = ident_index;
        g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_left_brother_id = INVALID_ID;
        g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_mode = SYN_NODE_VARID;
        g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_right_brother_id = INVALID_ID;
        g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_son_id = INVALID_ID;
        /* [ 3.5 ] fix for father and left brother */
        FIX_FATHER_LBROTHER( tempIndex, INVALID_ID, g_SynTree.n_node_num )
        g_SynTree.n_node_num++;
        CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
        /* [ 3.6 ] deal with ';' */
        JUMP_SPACES( fileField )
        if( ';' != fileField->current_ch ){
            report_syntax_error( func_name, "Missing ';' .", fileField->n_current_line );
            return 0;
        }
        return 1;
    } else{
        /* it's 'if' 'while' 'for' */
        return 300;
    }
}
int FUNC_DEF(FileField *fileField, int left_brother_ID, int father_ID){
    int ret = 0;
    char *func_name="FUNC_DEF";
    unsigned int tempIndex = 0;
    unsigned int ident_index = 0;
    int id_length = 0;
    /* [ 1 ] deal with FUNC_DEF */
    /* [ 1.1 ] make a node for FUNC_DEF */
    g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_father_id = father_ID;
    g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_identifier_id = INVALID_ID;
    g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_left_brother_id = left_brother_ID;
    g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_mode = SYN_NODE_FUNC_DEF;
    g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_right_brother_id = INVALID_ID;
    g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_son_id = INVALID_ID;
    /* [ 1.2 ] fix for father and left brother */
    FIX_FATHER_LBROTHER( father_ID, left_brother_ID, g_SynTree.n_node_num )
    g_SynTree.n_node_num++;
    CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
    /* [ 1.3 ] use a IdentId to store the identifier and make a syntax node */
    ret = add_to_IdTable(fileField, fileField->name_buf, (int)strlen( fileField->name_buf ), SYN_NODE_FUNID, &ident_index);
    if( 0 == ret ){
        return 0;
    }
    g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_father_id = g_SynTree.n_node_num - 1;
    g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_identifier_id = ident_index;
    g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_left_brother_id = INVALID_ID;
    g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_mode = SYN_NODE_FUNID;
    g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_right_brother_id = INVALID_ID;
    g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_son_id = INVALID_ID;
    /* [ 1.4 ] fix for father and left brother */
    FIX_FATHER_LBROTHER( g_SynTree.n_node_num - 1, INVALID_ID, g_SynTree.n_node_num )
    g_SynTree.n_node_num++;
    CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
    /* [ 1.5 ] deal with '(' */
    JUMP_SPACES( fileField )
    if( '(' != fileField->current_ch ){
        report_syntax_error( func_name, "Missing '(' .", fileField->n_current_line );
        return 0;
    }
    /* [ 1.6 ] deal with ')' */
    GET_NEW_CHAR_JUMP_SPACE( fileField )
    if( ')' != fileField->current_ch ){
        report_syntax_error( func_name, "Missing ')' .", fileField->n_current_line );
        return 0;
    }
    /* [ 1.7 ] deal with '{' */
    GET_NEW_CHAR_JUMP_SPACE( fileField )
    if( '{' != fileField->current_ch ){
        report_syntax_error( func_name, "Missing '{' .", fileField->n_current_line );
        return 0;
    }
    /* [ 1.8 ] deal with 'BODY' */
    ret = BODY( fileField, g_SynTree.n_node_num - 1, g_SynTree.n_node_num - 2 );
    if( 0 == ret ){
        return 0;
    }
    /* [ 1.9 ] deal with '}' */
    JUMP_SPACES( fileField )
    if( '}' != fileField->current_ch ){
        report_syntax_error( func_name, "Missing '}' .", fileField->n_current_line );
        return 0;
    }
    return 1;
}
int BODY(FileField *fileField, int left_brother_ID, int father_ID){
    int ret = 0;
    char *func_name="BODY";
    unsigned int tempIndex = 0;
    int id_length = 0;

    /* [ 1 ] make a node for 'BODY' */
    tempIndex = g_SynTree.n_node_num;
    g_SynTree.pSynNodeList[ tempIndex ].n_father_id = father_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_identifier_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_left_brother_id = left_brother_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_mode = SYN_NODE_BODY;
    g_SynTree.pSynNodeList[ tempIndex ].n_right_brother_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_son_id = INVALID_ID;
    /* [ 2 ] fix for father and left brother */
    FIX_FATHER_LBROTHER( father_ID, left_brother_ID, tempIndex )
    g_SynTree.n_node_num++;
    CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
    /* [ 3 ] deal with VAR_DEFINITION */
    ret = VAR_DEFINITION( fileField, INVALID_ID, tempIndex );
    if( 0 == ret ){
        return 0;
    }
    if( 400 != ret ){
        /* [ 4 ] deal with STATEMENT_LIST */
        ret = STATEMENT_LIST( fileField, g_SynTree.pSynNodeList[ tempIndex ].n_son_id, tempIndex );
        if( 0 == ret ){
            return 0;
        }
    }

    return 1;
}
/** if it returns 200, an identifier name is stored in FileField.name_buf **/
/** if it returns 300, it's 'if' 'while' 'for' **/
/** if it returns 400, an empty statment_list is following **/
int VAR_DEFINITION(FileField *fileField, int left_brother_ID, int father_ID){
    int ret = 0;
    char *func_name="VAR_DEFINITION";
    unsigned int tempIndex = 0;
    /* [ 1 ] make a node for 'VAR_DEFINITION' */
    tempIndex = g_SynTree.n_node_num;
    g_SynTree.pSynNodeList[ tempIndex ].n_father_id = father_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_identifier_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_left_brother_id = left_brother_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_mode = SYN_NODE_VAR_DEFINITION;
    g_SynTree.pSynNodeList[ tempIndex ].n_right_brother_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_son_id = INVALID_ID;
    /* [ 2 ] fix for father and left brother */
    FIX_FATHER_LBROTHER( father_ID, left_brother_ID, tempIndex )
    g_SynTree.n_node_num++;
    CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
    /* [ 3 ] deal with VAR_DEF */
    ret = VAR_DEF( fileField, INVALID_ID, tempIndex );
    if( 0 == ret ){
        return 0;
    }
    if( 1000 == ret ){
        if( '}' != fileField->current_ch ){
            report_syntax_error( func_name, "Invalid identifier .", fileField->n_current_line );
            return 0;
        } else{
            /* Empty statement_list */
            return 400;
        }
    } else if( 100 == ret ){
        report_syntax_error( "syntax_analyzer", "Unexpected key-word 'main'.", fileField->n_current_line );
        return 0;/* 'main' can't be here */
    } else if( 200 == ret ){
        /* [ 4 ] 'STATEMENT_LIST' is following */
        return 200;
    } else if( 300 == ret ){
        /* [ 5 ] 'STATEMENT_LIST' is following */
        return 300;
    }
    ret = VAR_DEFINITION( fileField, g_SynTree.pSynNodeList[ tempIndex ].n_son_id, tempIndex );
    return ret;
}
int STATEMENT_LIST(FileField *fileField, int left_brother_ID, int father_ID){
    int ret = 0;
    char *func_name="STATEMENT_LIST";
    unsigned int tempIndex = 0;
    unsigned int id_length = 0;
    /* [ 1 ] make a node for 'STATEMENT_LIST' */
    tempIndex = g_SynTree.n_node_num;
    g_SynTree.pSynNodeList[ tempIndex ].n_father_id = father_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_identifier_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_left_brother_id = left_brother_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_mode = SYN_NODE_STATEMENT_LIST;
    g_SynTree.pSynNodeList[ tempIndex ].n_right_brother_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_son_id = INVALID_ID;
    /* [ 2 ] fix for father and left brother */
    FIX_FATHER_LBROTHER( father_ID, left_brother_ID, tempIndex )
    g_SynTree.n_node_num++;
    CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
    /* [ 3 ] check the last byte */
    if( '}' == fileField->current_ch ){
        /* the statement list is empty */
        return 1;
    }
    /* [ 4 ] check the key-word which has already been read */
    CHECK_KEY_WORD( fileField->name_buf, ret )
    if( KEY_WORD_NO == ret ){
        JUMP_SPACES( fileField )
        if( '=' == fileField->current_ch ){
            /* [ 4.1 ] it's an ASSIGN_STMT */
            ret = ASSIGN_STMT( fileField, INVALID_ID, tempIndex );
            if( 0 == ret ){
                return 0;
            }
            JUMP_SPACES( fileField )
            if( ';' != fileField->current_ch ){
                /* check ';' */
                report_syntax_error( func_name, "Missing ';' .", fileField->n_current_line );
                return 0;
            }
        } else if( '(' == fileField->current_ch ){
            /* [ 4.2 ] it's an FUNC_CALL */
            ret = FUNC_CALL( fileField, INVALID_ID, tempIndex );
            if( 0 == ret ){
                return 0;
            }
        } else{
            report_syntax_error( func_name, "Unknown statement .", fileField->n_current_line );
            return 0;
        }
    } else if( KEY_WORD_IF == ret ){
        /* [ 4.2 ] deal with IF_STMT */
        ret = IF_STMT( fileField, INVALID_ID, tempIndex );
        if( 0 == ret ){
            return 0;
        }
    } else if( KEY_WORD_WHILE == ret ){
        /* [ 4.3 ] deal with WHILE_STMT */
        ret = WHILE_STMT( fileField, INVALID_ID, tempIndex );
        if( 0 == ret ){
            return 0;
        }
    } else if( KEY_WORD_FOR == ret ){
        /* [ 4.4 ] deal with FOR_STMT */
        ret = FOR_STMT( fileField, INVALID_ID, tempIndex );
        if( 0 == ret ){
            return 0;
        }
    } else {
        report_syntax_error( func_name, "Invalid identifier .", fileField->n_current_line );
        return 0;
    }
    /* [ 5 ] jump spaces */
    GET_NEW_CHAR_JUMP_SPACE( fileField )
    /* [ 6 ] get the next token */
    GET_IDENTIFY( fileField, fileField->name_buf, id_length )
    /* [ 7 ] call STATEMENT_LIST() recursively */
    ret = STATEMENT_LIST( fileField, g_SynTree.pSynNodeList[ tempIndex ].n_son_id, tempIndex );
    if( 0 == ret ){
        return 0;
    }
    
    return 1;
}
int ASSIGN_STMT(FileField *fileField, int left_brother_ID, int father_ID){
    int ret = 0;
    char *func_name="ASSIGN_STMT";
    unsigned int tempIndex = 0;
    unsigned int ident_index = 0;
    IdentId_P p_cur_id = NULL;
    /* [ 1 ] make a node for 'ASSIGN_STMT' */
    tempIndex = g_SynTree.n_node_num;
    g_SynTree.pSynNodeList[ tempIndex ].n_father_id = father_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_identifier_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_left_brother_id = left_brother_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_mode = SYN_NODE_ASSIGN_STMT;
    g_SynTree.pSynNodeList[ tempIndex ].n_right_brother_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_son_id = INVALID_ID;
    /* [ 2 ] fix for father and left brother */
    FIX_FATHER_LBROTHER( father_ID, left_brother_ID, tempIndex )
    g_SynTree.n_node_num++;
    CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
    /* [ 3 ] find the identifier in IdTable */
    ret = find_in_IdTable(fileField, fileField->name_buf, (int)strlen(fileField->name_buf), &ident_index);
    if( 0 == ret ){
        return 0;
    }
    p_cur_id = &g_IdTable.pIdList[ ident_index ];
    if( p_cur_id->n_mode != SYN_NODE_VARID ){
        report_syntax_error( func_name, "Identifier can't be assigned, it's a function name.", fileField->n_current_line );
        return 0;
    }
    /* [ 4 ] make a node for the identifier */
    tempIndex = g_SynTree.n_node_num;
    g_SynTree.pSynNodeList[ tempIndex ].n_father_id = tempIndex - 1;
    g_SynTree.pSynNodeList[ tempIndex ].n_identifier_id = ident_index;
    g_SynTree.pSynNodeList[ tempIndex ].n_left_brother_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_mode = SYN_NODE_VARID;
    g_SynTree.pSynNodeList[ tempIndex ].n_right_brother_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_son_id = INVALID_ID;
    /* [ 5 ] fix for father and left brother */
    FIX_FATHER_LBROTHER( tempIndex - 1, INVALID_ID, tempIndex )
    g_SynTree.n_node_num++;
    CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
    /* [ 6 ] check the '=' */
    JUMP_SPACES( fileField )
    if( '=' != fileField->current_ch ){
        report_syntax_error( func_name, "Missing '='.", fileField->n_current_line );
        return 0;
    }
    /* [ 7 ] deal with FORMULA */
    ret = FORMULA( fileField, tempIndex, tempIndex - 1 );
    if( 0 == ret ){
        return 0;
    }

    return 1;
}

int IF_STMT(FileField *fileField, int left_brother_ID, int father_ID){
    int ret = 0;
    char *func_name="IF_STMT";
    unsigned int tempIndex = 0;
    unsigned int id_length = 0;
    /* [ 1 ] make a node for 'IF_STMT' */
    tempIndex = g_SynTree.n_node_num;
    g_SynTree.pSynNodeList[ tempIndex ].n_father_id = father_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_identifier_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_left_brother_id = left_brother_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_mode = SYN_NODE_IF_STMT;
    g_SynTree.pSynNodeList[ tempIndex ].n_right_brother_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_son_id = INVALID_ID;
    /* [ 2 ] fix for father and left brother */
    FIX_FATHER_LBROTHER( father_ID, left_brother_ID, tempIndex )
    g_SynTree.n_node_num++;
    CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
    /* [ 3 ] check '('  */
    JUMP_SPACES( fileField )
    if( '(' != fileField->current_ch ){
        report_syntax_error( func_name, "Missing '('.", fileField->n_current_line );
        return 0;
    }
    /* [ 4 ] deal with BOOL_FORMULA */
    /* [ 4.1 ] jump spaces in the head for two bytes operator e.g. '>=' */
    GET_NEW_CHAR_JUMP_SPACE( fileField )
    ret = BOOL_FORMULA( fileField, INVALID_ID, tempIndex );
    if( 0 == ret ){
        return 0;
    }
    /* [ 5 ] check ')'  */
    JUMP_SPACES( fileField )
    if( ')' != fileField->current_ch ){
        report_syntax_error( func_name, "Missing ')'.", fileField->n_current_line );
        return 0;
    }
    /* [ 6 ] jump spaces */
    GET_NEW_CHAR_JUMP_SPACE( fileField )
    /* [ 7 ] check '{' */
    if( '{' != fileField->current_ch ){
        report_syntax_error( func_name, "Missing '{'.", fileField->n_current_line );
        return 0;
    }
    /* [ 8 ] jump spaces */
    GET_NEW_CHAR_JUMP_SPACE( fileField )
    /* [ 9 ] get the next token */
    GET_IDENTIFY( fileField, fileField->name_buf, id_length )
    /* [ 10 ] call STATEMENT_LIST() */
    ret = STATEMENT_LIST( fileField, g_SynTree.pSynNodeList[ tempIndex ].n_son_id, tempIndex );
    if( 0 == ret ){
        return 0;
    }
    /* [ 11 ] deal with '}' */
    JUMP_SPACES( fileField )
    if( '}' != fileField->current_ch ){
        report_syntax_error( func_name, "Missing '}' .", fileField->n_current_line );
        return 0;
    }

    return 1;
}
int FOR_STMT(FileField *fileField, int left_brother_ID, int father_ID){
    int ret = 0;
    char *func_name="FOR_STMT";
    unsigned int for_stmt_index = 0;
    unsigned int tempIndex = 0;
    unsigned int id_length = 0;
    /* [ 1 ] make a node for 'FOR_STMT' */
    tempIndex = g_SynTree.n_node_num;
    for_stmt_index = tempIndex;
    g_SynTree.pSynNodeList[ tempIndex ].n_father_id = father_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_identifier_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_left_brother_id = left_brother_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_mode = SYN_NODE_FOR_STMT;
    g_SynTree.pSynNodeList[ tempIndex ].n_right_brother_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_son_id = INVALID_ID;
    /* [ 2 ] fix for father and left brother */
    FIX_FATHER_LBROTHER( father_ID, left_brother_ID, tempIndex )
    g_SynTree.n_node_num++;
    CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
    /* [ 3 ] check '('  */
    JUMP_SPACES( fileField )
    if( '(' != fileField->current_ch ){
        report_syntax_error( func_name, "Missing '('.", fileField->n_current_line );
        return 0;
    }
    /* [ 4 ] jump spaces */
    GET_NEW_CHAR_JUMP_SPACE( fileField )
    if( ';' == fileField->current_ch ){
        /* [ 5 ] first statement is empty, make an empty node */
        tempIndex++;
        g_SynTree.pSynNodeList[ tempIndex ].n_father_id = for_stmt_index;
        g_SynTree.pSynNodeList[ tempIndex ].n_identifier_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_left_brother_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_mode = SYN_NODE_EMPTY;
        g_SynTree.pSynNodeList[ tempIndex ].n_right_brother_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_son_id = INVALID_ID;
        /* [ 5.1 ] fix for father and left brother */
        FIX_FATHER_LBROTHER( for_stmt_index, INVALID_ID, tempIndex )
        g_SynTree.n_node_num++;
        CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
    } else{
        /* [ 6 ] deal with ASSIGN_STMT */
        /* [ 6.1 ] get the next token */
        GET_IDENTIFY( fileField, fileField->name_buf, id_length )
        ret = ASSIGN_STMT( fileField, INVALID_ID, for_stmt_index );
        if( 0 == ret ){
            return 0;
        }
        JUMP_SPACES( fileField )
        if( ';' != fileField->current_ch ){
            /* check ';' */
            report_syntax_error( func_name, "Missing ';' .", fileField->n_current_line );
            return 0;
        }
    }
    /* [ 7 ] deal with BOOL_FORMULA */
    /* [ 7.1 ] jump spaces in the head for two bytes operator e.g. '>=' */
    GET_NEW_CHAR_JUMP_SPACE( fileField )
    ret = BOOL_FORMULA( fileField, g_SynTree.pSynNodeList[ for_stmt_index ].n_son_id, for_stmt_index );
    if( 0 == ret ){
        return 0;
    }
    JUMP_SPACES( fileField )
    if( ';' != fileField->current_ch ){
        /* check ';' */
        report_syntax_error( func_name, "Missing ';' .", fileField->n_current_line );
        return 0;
    }
    /* [ 7.1 ] store the index of BOOL_FORMULA */
    tempIndex = g_SynTree.pSynNodeList[ g_SynTree.pSynNodeList[ for_stmt_index ].n_son_id ].n_right_brother_id;
    /* [ 8 ] jump spaces */
    GET_NEW_CHAR_JUMP_SPACE( fileField )
    if( ')' == fileField->current_ch ){
        /* [ 9 ] last statement is empty, make an empty node */
        g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_father_id = for_stmt_index;
        g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_identifier_id = INVALID_ID;
        g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_left_brother_id = tempIndex;
        g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_mode = SYN_NODE_EMPTY;
        g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_right_brother_id = INVALID_ID;
        g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_son_id = INVALID_ID;
        /* [ 9.1 ] fix for father and left brother */
        FIX_FATHER_LBROTHER( for_stmt_index, tempIndex, g_SynTree.n_node_num )
        g_SynTree.n_node_num++;
        CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
    } else{
        /* [ 10 ] deal with ASSIGN_STMT */
        /* [ 10.1 ] get the next token */
        GET_IDENTIFY( fileField, fileField->name_buf, id_length )
        ret = ASSIGN_STMT( fileField, tempIndex, for_stmt_index );
        if( 0 == ret ){
            return 0;
        }
        JUMP_SPACES( fileField )
        if( ')' != fileField->current_ch ){
            /* check ')' */
            report_syntax_error( func_name, "Missing ')' .", fileField->n_current_line );
            return 0;
        }
    }
    /* [ 10.1 ] store the index of third child of FOR_STMT */
    tempIndex = g_SynTree.pSynNodeList[ tempIndex ].n_right_brother_id;
    /* [ 11 ] jump spaces */
    GET_NEW_CHAR_JUMP_SPACE( fileField )
    /* [ 12 ] check '{' */
    if( '{' != fileField->current_ch ){
        report_syntax_error( func_name, "Missing '{' .", fileField->n_current_line );
        return 0;
    }
    /* [ 13 ] jump spaces */
    GET_NEW_CHAR_JUMP_SPACE( fileField )
    /* [ 14 ] get the next token */
    GET_IDENTIFY( fileField, fileField->name_buf, id_length )
    /* [ 15 ] call STATEMENT_LIST() */
    ret = STATEMENT_LIST( fileField, tempIndex, for_stmt_index );
    if( 0 == ret ){
        return 0;
    }
    /* [ 16 ] deal with '}' */
    JUMP_SPACES( fileField )
    if( '}' != fileField->current_ch ){
        report_syntax_error( func_name, "Missing '}' .", fileField->n_current_line );
        return 0;
    }

    return 1;
}
int WHILE_STMT(FileField *fileField, int left_brother_ID, int father_ID){
    int ret = 0;
    char *func_name="WHILE_STMT";
    unsigned int tempIndex = 0;
    unsigned int id_length = 0;
    /* [ 1 ] make a node for 'WHILE_STMT' */
    tempIndex = g_SynTree.n_node_num;
    g_SynTree.pSynNodeList[ tempIndex ].n_father_id = father_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_identifier_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_left_brother_id = left_brother_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_mode = SYN_NODE_WHILE_STMT;
    g_SynTree.pSynNodeList[ tempIndex ].n_right_brother_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_son_id = INVALID_ID;
    /* [ 2 ] fix for father and left brother */
    FIX_FATHER_LBROTHER( father_ID, left_brother_ID, tempIndex )
    g_SynTree.n_node_num++;
    CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
    /* [ 3 ] check '('  */
    JUMP_SPACES( fileField )
    if( '(' != fileField->current_ch ){
        report_syntax_error( func_name, "Missing '('.", fileField->n_current_line );
        return 0;
    }
    /* [ 4 ] jump spaces */
    /* [ 5.1 ] jump spaces in the head for two bytes operator e.g. '>=' */
    GET_NEW_CHAR_JUMP_SPACE( fileField )
    /* [ 5 ] deal with BOOL_FORMULA */
    ret = BOOL_FORMULA( fileField, INVALID_ID, tempIndex );
    if( 0 == ret ){
        return 0;
    }
    /* [ 6 ] check ')' */
    JUMP_SPACES( fileField )
    if( ')' != fileField->current_ch ){
        report_syntax_error( func_name, "Missing ')'.", fileField->n_current_line );
        return 0;
    }
    /* [ 7 ] jump spaces */
    GET_NEW_CHAR_JUMP_SPACE( fileField )
    /* [ 8 ] check '{' */
    if( '{' != fileField->current_ch ){
        report_syntax_error( func_name, "Missing '{'.", fileField->n_current_line );
        return 0;
    }
    /* [ 9 ] jump spaces */
    GET_NEW_CHAR_JUMP_SPACE( fileField )
    /* [ 10 ] get the next token */
    GET_IDENTIFY( fileField, fileField->name_buf, id_length )
    /* [ 11 ] call STATEMENT_LIST() */
    ret = STATEMENT_LIST( fileField, g_SynTree.pSynNodeList[ tempIndex ].n_son_id, tempIndex );
    if( 0 == ret ){
        return 0;
    }
    /* [ 12 ] deal with '}' */
    JUMP_SPACES( fileField )
    if( '}' != fileField->current_ch ){
        report_syntax_error( func_name, "Missing '}' .", fileField->n_current_line );
        return 0;
    }


    return 1;
}
int FORMULA(FileField *fileField, int left_brother_ID, int father_ID){
    int ret = 0;
    char *func_name="FORMULA";
    unsigned int tempIndex = 0;
    unsigned int FORMULAIndex = 0;
    unsigned int id_length = 0;
    unsigned int ident_index = 0;
    int int_value = 0;
    IdentId_P p_cur_id = NULL;
    /* [ 1 ] make a node for 'FORMULA' */
    tempIndex = g_SynTree.n_node_num;
    FORMULAIndex = tempIndex;
    g_SynTree.pSynNodeList[ tempIndex ].n_father_id = father_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_identifier_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_left_brother_id = left_brother_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_mode = SYN_NODE_FORMULA;
    g_SynTree.pSynNodeList[ tempIndex ].n_right_brother_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_son_id = INVALID_ID;
    /* [ 2 ] fix for father and left brother */
    FIX_FATHER_LBROTHER( father_ID, left_brother_ID, tempIndex )
    g_SynTree.n_node_num++;
    CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
    /* [ 3 ] jump spaces in the head */
    GET_NEW_CHAR_JUMP_SPACE( fileField )
    /* [ 4 ] check the first byte */
    if( '(' == fileField->current_ch ){
        /* [ 5 ] make a node for '(' */
        tempIndex = g_SynTree.n_node_num;
        g_SynTree.pSynNodeList[ tempIndex ].n_father_id = FORMULAIndex;
        g_SynTree.pSynNodeList[ tempIndex ].n_identifier_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_left_brother_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_mode = SYN_NODE_L_parenthesis;
        g_SynTree.pSynNodeList[ tempIndex ].n_right_brother_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_son_id = INVALID_ID;
        /* [ 5.1 ] fix for father and left brother */
        FIX_FATHER_LBROTHER( FORMULAIndex, INVALID_ID, tempIndex )
        g_SynTree.n_node_num++;
        CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
        /* [ 5.2 ] deal with FORMULA recursively */
        ret = FORMULA( fileField, tempIndex, FORMULAIndex );
        if( 0 == ret ){
            return 0;
        }
        /* [ 5.3 ] check ')' */
        JUMP_SPACES( fileField )
        if( ')' != fileField->current_ch ){
            report_syntax_error( func_name, "Missing ')' .", fileField->n_current_line );
            return 0;
        }
        /* [ 5.4 ] make a node for ')' */
        tempIndex = g_SynTree.pSynNodeList[ tempIndex ].n_right_brother_id;
        g_SynTree.n_node_num;
        g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_father_id = FORMULAIndex;
        g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_identifier_id = INVALID_ID;
        g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_left_brother_id = tempIndex;
        g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_mode = SYN_NODE_R_parenthesis;
        g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_right_brother_id = INVALID_ID;
        g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_son_id = INVALID_ID;
        /* [ 5.5 ] fix for father and left brother */
        FIX_FATHER_LBROTHER( FORMULAIndex, tempIndex , g_SynTree.n_node_num )
        g_SynTree.n_node_num++;
        CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
        /* [ 5.6 ] jump spaces in the end */
        GET_NEW_CHAR_JUMP_SPACE( fileField )
        /* [ 5.7 ] reflash the tempIndex */
        tempIndex = g_SynTree.n_node_num - 1;
    } else if( isalpha( fileField->current_ch ) ){
        /* [ 6 ] deal with identifier */
        GET_IDENTIFY( fileField, fileField->name_buf, id_length )
        if( 0 == id_length ){
            report_syntax_error( func_name, "Invalid identifier .", fileField->n_current_line );
            return 0;
        }
        CHECK_KEY_WORD( fileField->name_buf, ret )
        if( KEY_WORD_NO != ret ){
            report_syntax_error( func_name, "Invalid identifier :key-word.", fileField->n_current_line );
            return 0;
        }
        /* [ 6.1 ] find the identifier in IdTable */
        ret = find_in_IdTable(fileField, fileField->name_buf, (int)strlen(fileField->name_buf), &ident_index);
        if( 0 == ret ){
            return 0;
        }
        p_cur_id = &g_IdTable.pIdList[ ident_index ];
        if( p_cur_id->n_mode != SYN_NODE_VARID ){
            report_syntax_error( func_name, "Identifier can't be caculated, it's a function name.", fileField->n_current_line );
            return 0;
        }
        /* [ 6.2 ] make a node for the identifier */
        tempIndex = g_SynTree.n_node_num;
        g_SynTree.pSynNodeList[ tempIndex ].n_father_id = FORMULAIndex;
        g_SynTree.pSynNodeList[ tempIndex ].n_identifier_id = ident_index;
        g_SynTree.pSynNodeList[ tempIndex ].n_left_brother_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_mode = SYN_NODE_VARID;
        g_SynTree.pSynNodeList[ tempIndex ].n_right_brother_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_son_id = INVALID_ID;
        /* [ 6.3 ] fix for father and left brother */
        FIX_FATHER_LBROTHER( FORMULAIndex, INVALID_ID, tempIndex )
        g_SynTree.n_node_num++;
        CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
    } else{
        /* [ 7 ] deal with numbers */
        ret = get_number( fileField, &int_value );
        if( 0 == ret ){
            return 0;
        }
        /* [ 7.1 ] make a node for the integer */
        tempIndex = g_SynTree.n_node_num;
        g_SynTree.pSynNodeList[ tempIndex ].n_father_id = FORMULAIndex;
        g_SynTree.pSynNodeList[ tempIndex ].n_identifier_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_left_brother_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_mode = SYN_NODE_NUMBER;
        g_SynTree.pSynNodeList[ tempIndex ].n_right_brother_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_son_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_int_value = int_value;
        /* [ 7.2 ] fix for father and left brother */
        FIX_FATHER_LBROTHER( FORMULAIndex, INVALID_ID, tempIndex )
        g_SynTree.n_node_num++;
        CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
    }
    /* [ 8 ] deal with FORMULA_FOLLOW */
    ret = FORMULA_FOLLOW( fileField, tempIndex,  FORMULAIndex );
    if( 0 == ret ){
        return 0;
    }

    return 1;
};
int BOOL_FORMULA(FileField *fileField, int left_brother_ID, int father_ID){
    int ret = 0;
    char *func_name="BOOL_FORMULA";
    unsigned int tempIndex = 0;
    unsigned int BOOL_FORMULAIndex = 0;
    unsigned int id_length = 0;
    unsigned int ident_index = 0;
    int int_value = 0;
    IdentId_P p_cur_id = NULL;
    /* [ 1 ] make a node for 'BOOL_FORMULA' */
    tempIndex = g_SynTree.n_node_num;
    BOOL_FORMULAIndex = tempIndex;
    g_SynTree.pSynNodeList[ tempIndex ].n_father_id = father_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_identifier_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_left_brother_id = left_brother_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_mode = SYN_NODE_BOOL_FORMULA;
    g_SynTree.pSynNodeList[ tempIndex ].n_right_brother_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_son_id = INVALID_ID;
    /* [ 2 ] fix for father and left brother */
    FIX_FATHER_LBROTHER( father_ID, left_brother_ID, tempIndex )
    g_SynTree.n_node_num++;
    CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
    /* [ 3 ] jump spaces in the head */
    JUMP_SPACES( fileField )
    /* [ 4 ] check the first byte */
    if( '(' == fileField->current_ch ){
        /* [ 5 ] make a node for '(' */
        tempIndex = g_SynTree.n_node_num;
        g_SynTree.pSynNodeList[ tempIndex ].n_father_id = BOOL_FORMULAIndex;
        g_SynTree.pSynNodeList[ tempIndex ].n_identifier_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_left_brother_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_mode = SYN_NODE_L_parenthesis;
        g_SynTree.pSynNodeList[ tempIndex ].n_right_brother_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_son_id = INVALID_ID;
        /* [ 5.1 ] fix for father and left brother */
        FIX_FATHER_LBROTHER( BOOL_FORMULAIndex, INVALID_ID, tempIndex )
        g_SynTree.n_node_num++;
        CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
        /* [ 5.2 ] deal with BOOL_FORMULA recursively */
        /* jump spaces in the head for two bytes operator e.g. '>=' */
        GET_NEW_CHAR_JUMP_SPACE( fileField )
        ret = BOOL_FORMULA( fileField, tempIndex, BOOL_FORMULAIndex );
        if( 0 == ret ){
            return 0;
        }
        /* [ 5.3 ] check ')' */
        JUMP_SPACES( fileField )
        if( ')' != fileField->current_ch ){
            report_syntax_error( func_name, "Missing ')' .", fileField->n_current_line );
            return 0;
        }
        /* [ 5.4 ] make a node for ')' */
        tempIndex = g_SynTree.pSynNodeList[ tempIndex ].n_right_brother_id;
        g_SynTree.n_node_num;
        g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_father_id = BOOL_FORMULAIndex;
        g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_identifier_id = INVALID_ID;
        g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_left_brother_id = tempIndex;
        g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_mode = SYN_NODE_R_parenthesis;
        g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_right_brother_id = INVALID_ID;
        g_SynTree.pSynNodeList[ g_SynTree.n_node_num ].n_son_id = INVALID_ID;
        /* [ 5.5 ] fix for father and left brother */
        FIX_FATHER_LBROTHER( BOOL_FORMULAIndex, tempIndex , g_SynTree.n_node_num )
        tempIndex = g_SynTree.n_node_num;/* Fix Bug */
        g_SynTree.n_node_num++;
        CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
        /* [ 5.6 ] jump spaces in the end */
        GET_NEW_CHAR_JUMP_SPACE( fileField )
    } else if( isalpha( fileField->current_ch ) ){
        /* [ 6 ] deal with identifier */
        GET_IDENTIFY( fileField, fileField->name_buf, id_length )
        if( 0 == id_length ){
            report_syntax_error( func_name, "Invalid identifier .", fileField->n_current_line );
            return 0;
        }
        CHECK_KEY_WORD( fileField->name_buf, ret )
        if( KEY_WORD_NO != ret ){
            report_syntax_error( func_name, "Invalid identifier :key-word.", fileField->n_current_line );
            return 0;
        }
        /* [ 6.1 ] find the identifier in IdTable */
        ret = find_in_IdTable(fileField, fileField->name_buf, (int)strlen(fileField->name_buf), &ident_index);
        if( 0 == ret ){
            return 0;
        }
        p_cur_id = &g_IdTable.pIdList[ ident_index ];
        if( p_cur_id->n_mode != SYN_NODE_VARID ){
            report_syntax_error( func_name, "Identifier can't be caculated, it's a function name.", fileField->n_current_line );
            return 0;
        }
        /* [ 6.2 ] make a node for the identifier */
        tempIndex = g_SynTree.n_node_num;
        g_SynTree.pSynNodeList[ tempIndex ].n_father_id = BOOL_FORMULAIndex;
        g_SynTree.pSynNodeList[ tempIndex ].n_identifier_id = ident_index;
        g_SynTree.pSynNodeList[ tempIndex ].n_left_brother_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_mode = SYN_NODE_VARID;
        g_SynTree.pSynNodeList[ tempIndex ].n_right_brother_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_son_id = INVALID_ID;
        /* [ 6.3 ] fix for father and left brother */
        FIX_FATHER_LBROTHER( BOOL_FORMULAIndex, INVALID_ID, tempIndex )
        g_SynTree.n_node_num++;
        CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
    } else{
        /* [ 7 ] deal with numbers */
        ret = get_number( fileField, &int_value );
        if( 0 == ret ){
            return 0;
        }
        /* [ 7.1 ] make a node for the integer */
        tempIndex = g_SynTree.n_node_num;
        g_SynTree.pSynNodeList[ tempIndex ].n_father_id = BOOL_FORMULAIndex;
        g_SynTree.pSynNodeList[ tempIndex ].n_identifier_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_left_brother_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_mode = SYN_NODE_NUMBER;
        g_SynTree.pSynNodeList[ tempIndex ].n_right_brother_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_son_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_int_value = int_value;
        /* [ 7.2 ] fix for father and left brother */
        FIX_FATHER_LBROTHER( BOOL_FORMULAIndex, INVALID_ID, tempIndex )
        g_SynTree.n_node_num++;
        CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
    }
    /* [ 8 ] deal with BOOL_FORMULA_FOLLOW */
    ret = BOOL_FORMULA_FOLLOW( fileField, tempIndex,  BOOL_FORMULAIndex );
    if( 0 == ret ){
        return 0;
    }

    return 1;
}
int FORMULA_FOLLOW(FileField *fileField, int left_brother_ID, int father_ID){
    int ret = 0;
    char *func_name="FORMULA_FOLLOW";
    unsigned int tempIndex = 0;
    /* [ 1 ] make a node for 'FORMULA_FOLLOW' */
    tempIndex = g_SynTree.n_node_num;
    g_SynTree.pSynNodeList[ tempIndex ].n_father_id = father_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_identifier_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_left_brother_id = left_brother_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_mode = SYN_NODE_FORMULA_FOLLOW;
    g_SynTree.pSynNodeList[ tempIndex ].n_right_brother_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_son_id = INVALID_ID;
    /* [ 2 ] fix for father and left brother */
    FIX_FATHER_LBROTHER( father_ID, left_brother_ID, tempIndex )
    g_SynTree.n_node_num++;
    CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
    /* [ 3 ] check the first byte */
    JUMP_SPACES( fileField )
    if( '+' == fileField->current_ch ){
        /* [ 4 ] make a node for '+' */
        tempIndex = g_SynTree.n_node_num;
        g_SynTree.pSynNodeList[ tempIndex ].n_father_id = tempIndex - 1;
        g_SynTree.pSynNodeList[ tempIndex ].n_identifier_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_left_brother_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_mode = SYN_NODE_ADD;
        g_SynTree.pSynNodeList[ tempIndex ].n_right_brother_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_son_id = INVALID_ID;
        /* [ 4.1 ] fix for father and left brother */
        FIX_FATHER_LBROTHER( tempIndex - 1, INVALID_ID, tempIndex )
        g_SynTree.n_node_num++;
        CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
    } else if( '-' ==  fileField->current_ch ){
        /* [ 5 ] make a node for '-' */
        tempIndex = g_SynTree.n_node_num;
        g_SynTree.pSynNodeList[ tempIndex ].n_father_id = tempIndex - 1;
        g_SynTree.pSynNodeList[ tempIndex ].n_identifier_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_left_brother_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_mode = SYN_NODE_SUB;
        g_SynTree.pSynNodeList[ tempIndex ].n_right_brother_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_son_id = INVALID_ID;
        /* [ 5.1 ] fix for father and left brother */
        FIX_FATHER_LBROTHER( tempIndex - 1, INVALID_ID, tempIndex )
        g_SynTree.n_node_num++;
        CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
    } else if( '*' == fileField->current_ch ){
        /* [ 6 ] make a node for '*' */
        tempIndex = g_SynTree.n_node_num;
        g_SynTree.pSynNodeList[ tempIndex ].n_father_id = tempIndex - 1;
        g_SynTree.pSynNodeList[ tempIndex ].n_identifier_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_left_brother_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_mode = SYN_NODE_MUT;
        g_SynTree.pSynNodeList[ tempIndex ].n_right_brother_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_son_id = INVALID_ID;
        /* [ 6.1 ] fix for father and left brother */
        FIX_FATHER_LBROTHER( tempIndex - 1, INVALID_ID, tempIndex )
        g_SynTree.n_node_num++;
        CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
    } else if( '/' == fileField->current_ch ){
        /* [ 7 ] make a node for '/' */
        tempIndex = g_SynTree.n_node_num;
        g_SynTree.pSynNodeList[ tempIndex ].n_father_id = tempIndex - 1;
        g_SynTree.pSynNodeList[ tempIndex ].n_identifier_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_left_brother_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_mode = SYN_NODE_DIV;
        g_SynTree.pSynNodeList[ tempIndex ].n_right_brother_id = INVALID_ID;
        g_SynTree.pSynNodeList[ tempIndex ].n_son_id = INVALID_ID;
        /* [ 7.1 ] fix for father and left brother */
        FIX_FATHER_LBROTHER( tempIndex - 1, INVALID_ID, tempIndex )
        g_SynTree.n_node_num++;
        CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
    } else{
        /* empty follow */
        return 1;
    }
    /* [ 8 ] deal with FORMULA */
    ret = FORMULA( fileField, tempIndex, tempIndex - 1 );
    if( 0 == ret ){
        return 0;
    }

    return 1;
}
int BOOL_FORMULA_FOLLOW(FileField *fileField, int left_brother_ID, int father_ID){
    int ret = 0;
    char *func_name="BOOL_FORMULA_FOLLOW";
    unsigned int tempIndex = 0;
    short n_mode = 0;
    /* [ 1 ] make a node for 'BOOL_FORMULA_FOLLOW' */
    tempIndex = g_SynTree.n_node_num;
    g_SynTree.pSynNodeList[ tempIndex ].n_father_id = father_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_identifier_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_left_brother_id = left_brother_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_mode = SYN_NODE_BOOL_FORMULA_FOLLOW;
    g_SynTree.pSynNodeList[ tempIndex ].n_right_brother_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_son_id = INVALID_ID;
    /* [ 2 ] fix for father and left brother */
    FIX_FATHER_LBROTHER( father_ID, left_brother_ID, tempIndex )
    g_SynTree.n_node_num++;
    CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
    /* [ 3 ] check the operator, maybe two bytes */
    JUMP_SPACES( fileField )
    if( '|' == fileField->current_ch ){
        /* [ 4 ] deal with the operator '||' */
        fileField->current_ch = fgetc( fileField->fp );
        CHECK_NEW_LINE( fileField )
        if( '|' != fileField->current_ch ){
            report_syntax_error( func_name, "Invalid operator.", fileField->n_current_line );
            return 0;
        }
        /* [ 4.1 ] mode is '||' */
        n_mode = SYN_NODE_OR;
        /* [ 4.2 ] jump spaces in the end */
        GET_NEW_CHAR_JUMP_SPACE( fileField )
    } else if( '&' == fileField->current_ch){
        /* [ 5 ] deal with the operator '&&' */
        fileField->current_ch = fgetc( fileField->fp );
        CHECK_NEW_LINE( fileField )
        if( '&' != fileField->current_ch ){
            report_syntax_error( func_name, "Invalid operator.", fileField->n_current_line );
            return 0;
        }
        /* [ 5.1 ] mode is '||' */
        n_mode = SYN_NODE_AND;
        /* [ 5.2 ] jump spaces in the end */
        GET_NEW_CHAR_JUMP_SPACE( fileField )
    } else if( '<' == fileField->current_ch){
        /* [ 6 ] deal with the operator '<' or '<=' */
        fileField->current_ch = fgetc( fileField->fp );
        CHECK_NEW_LINE( fileField )
        if( '=' != fileField->current_ch ){
            /* [ 6.1 ] mode is '<' */
            n_mode = SYN_NODE_LESS;
        } else{
            /* [ 6.2 ] mode is '<=' */
            n_mode = SYN_NODE_NOT_MORE;
            /* [ 6.3 ] jump spaces in the end */
            GET_NEW_CHAR_JUMP_SPACE( fileField )
        }
    } else if( '>' == fileField->current_ch){
        /* [ 7 ] deal with the operator '>' or '>=' */
        fileField->current_ch = fgetc( fileField->fp );
        CHECK_NEW_LINE( fileField )
        if( '=' != fileField->current_ch ){
            /* [ 7.1 ] mode is '>' */
            n_mode = SYN_NODE_MORE;
        } else{
            /* [ 7.2 ] mode is '>=' */
            n_mode = SYN_NODE_NOT_LESS;
            /* [ 7.3 ] jump spaces in the end */
            GET_NEW_CHAR_JUMP_SPACE( fileField )
        }
    } else if( '=' == fileField->current_ch){
        /* [ 8 ] deal with the operator '==' */
        fileField->current_ch = fgetc( fileField->fp );
        CHECK_NEW_LINE( fileField )
        if( '=' != fileField->current_ch ){
            report_syntax_error( func_name, "Invalid operator.", fileField->n_current_line );
            return 0;
        }
        /* [ 8.1 ] mode is '==' */
        n_mode = SYN_NODE_EQ;
        /* [ 8.2 ] jump spaces in the end */
        GET_NEW_CHAR_JUMP_SPACE( fileField )
    } else if( '!' == fileField->current_ch){
        /* [ 9 ] deal with the operator '!=' */
        fileField->current_ch = fgetc( fileField->fp );
        CHECK_NEW_LINE( fileField )
        if( '=' != fileField->current_ch ){
            report_syntax_error( func_name, "Invalid operator.", fileField->n_current_line );
            return 0;
        }
        /* [ 9.1 ] mode is '!=' */
        n_mode = SYN_NODE_NOT_EQ;
        /* [ 9.2 ] jump spaces in the end */
        GET_NEW_CHAR_JUMP_SPACE( fileField )
    } else if( '+' == fileField->current_ch){
        /* [ 10 ] deal with the operator '+' */
        n_mode = SYN_NODE_ADD;
        /* [ 10.1 ] jump spaces in the end */
        GET_NEW_CHAR_JUMP_SPACE( fileField )
    } else if( '-' == fileField->current_ch){
        /* [ 11 ] deal with the operator '-' */
        n_mode = SYN_NODE_SUB;
        /* [ 11.1 ] jump spaces in the end */
        GET_NEW_CHAR_JUMP_SPACE( fileField )
    } else if( '*' == fileField->current_ch){
        /* [ 12 ] deal with the operator '*' */
        n_mode = SYN_NODE_MUT;
        /* [ 12.1 ] jump spaces in the end */
        GET_NEW_CHAR_JUMP_SPACE( fileField )
    } else if( '/' == fileField->current_ch){
        /* [ 13 ] deal with the operator '/' */
        n_mode = SYN_NODE_DIV;
        /* [ 13.1 ] jump spaces in the end */
        GET_NEW_CHAR_JUMP_SPACE( fileField )
    } else{
        /* empty follow */
        return 1;
    }
    /* [ 14 ] make a node for the operator*/
    tempIndex = g_SynTree.n_node_num;
    g_SynTree.pSynNodeList[ tempIndex ].n_father_id = tempIndex - 1;
    g_SynTree.pSynNodeList[ tempIndex ].n_identifier_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_left_brother_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_mode = n_mode;
    g_SynTree.pSynNodeList[ tempIndex ].n_right_brother_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_son_id = INVALID_ID;
    /* [ 15 ] fix for father and left brother */
    FIX_FATHER_LBROTHER( tempIndex - 1, INVALID_ID, tempIndex )
    g_SynTree.n_node_num++;
    CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
    /* [ 16 ] deal with BOOL_FORMULA */
    ret = BOOL_FORMULA( fileField, tempIndex, tempIndex - 1 );
    if( 0 == ret ){
        return 0;
    }

    return 1;
}
int FUNC_CALL(FileField *fileField, int left_brother_ID, int father_ID){
    int ret = 0;
    char *func_name="FUNC_CALL";
    unsigned int tempIndex = 0;
    unsigned int ident_index = 0;
    IdentId_P p_cur_id = NULL;
    /* [ 1 ] make a node for 'FUNC_CALL' */
    tempIndex = g_SynTree.n_node_num;
    g_SynTree.pSynNodeList[ tempIndex ].n_father_id = father_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_identifier_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_left_brother_id = left_brother_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_mode = SYN_NODE_FUNC_CALL;
    g_SynTree.pSynNodeList[ tempIndex ].n_right_brother_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_son_id = INVALID_ID;
    /* [ 2 ] fix for father and left brother */
    FIX_FATHER_LBROTHER( father_ID, left_brother_ID, tempIndex )
    g_SynTree.n_node_num++;
    CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
    /* [ 3 ] find the identifier in IdTable */
    ret = find_in_IdTable(fileField, fileField->name_buf, (int)strlen(fileField->name_buf), &ident_index);
    if( 0 == ret ){
        return 0;
    }
    p_cur_id = &g_IdTable.pIdList[ ident_index ];
    if( p_cur_id->n_mode != SYN_NODE_FUNID ){
        report_syntax_error( func_name, "Function can't be called, it's an identifier name.", fileField->n_current_line );
        return 0;
    }
    /* [ 4 ] make a node for the func_id */
    tempIndex = g_SynTree.n_node_num;
    g_SynTree.pSynNodeList[ tempIndex ].n_father_id = tempIndex - 1;
    g_SynTree.pSynNodeList[ tempIndex ].n_identifier_id = ident_index;
    g_SynTree.pSynNodeList[ tempIndex ].n_left_brother_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_mode = SYN_NODE_FUNID;
    g_SynTree.pSynNodeList[ tempIndex ].n_right_brother_id = INVALID_ID;
    g_SynTree.pSynNodeList[ tempIndex ].n_son_id = INVALID_ID;
    /* [ 5 ] fix for father and left brother */
    FIX_FATHER_LBROTHER( tempIndex - 1, INVALID_ID, tempIndex )
    g_SynTree.n_node_num++;
    CHECK_NODE_NUM( func_name, fileField, g_SynTree.n_node_num )
    /* [ 6 ] check the '(' */
    JUMP_SPACES( fileField )
    if( '(' != fileField->current_ch ){
        report_syntax_error( func_name, "Missing '('.", fileField->n_current_line );
        return 0;
    }
    /* [ 7 ] check the ')' */
    GET_NEW_CHAR_JUMP_SPACE( fileField )
    if( ')' != fileField->current_ch ){
        report_syntax_error( func_name, "Missing ')'.", fileField->n_current_line );
        return 0;
    }
    /* [ 8 ] check the ';' */
    GET_NEW_CHAR_JUMP_SPACE( fileField )
    if( ';' != fileField->current_ch ){
        report_syntax_error( func_name, "Missing ';'.", fileField->n_current_line );
        return 0;
    }

    return 1;
}
int add_to_IdTable(FileField * fileField, char *id_name, int length, short mode, unsigned int * p_ident_index){
    char first_index = 0;
    char second_index = 0;
    IdentId_P cur_IdentId_list = NULL;
    unsigned int index = 0;
    unsigned int temp = 0;
    char *func_name = "add_to_IdTable";

    if( length <= 0 ){
        report_internal_error(func_name, __LINE__);
        return 0;
    }
    if( id_name[0] >= 'A' && id_name[0] <= 'Z' ){
        first_index = id_name[0] - 'A';
    } else if( id_name[0] >= 'a' && id_name[0] <= 'z' ){
        first_index = id_name[0] - 'a' + 26;
    } else{
        first_index = 51;
    }
    if( length > 1 ){
        if( id_name[1] >= 'A' && id_name[1] <= 'Z' ){
            second_index = id_name[1] - 'A';
        } else if( id_name[1] >= 'a' && id_name[1] <= 'z' ){
            second_index = id_name[1] - 'a' + 26;
        } else if( id_name[1] >= '0' && id_name[1] <= '9' ){
            second_index = id_name[1] - '0' + 52;
        } else{
            second_index = 61;
        }
    }
    temp = g_IdTable.two_level_index[ first_index ][ second_index ];

    while( temp != INVALID_ID ){
        /* a list is found */
        cur_IdentId_list = &g_IdTable.pIdList[temp];
        if( strcmp( cur_IdentId_list->str_name, id_name ) == 0 ){
            /* already exist */
            report_syntax_error( func_name, "Re-definition error.", fileField->n_current_line );
            return 0;
        }
        temp = cur_IdentId_list->n_next_identifier_id;
    }
    if( g_IdTable.n_id_num + 1 > MAX_SYN_NODE_NUM ){
        report_syntax_error( func_name, "Too many identifiers.", fileField->n_current_line );
        return 0;
    }
    index = g_IdTable.n_id_num;
    g_IdTable.n_id_num++;
    if( NULL != cur_IdentId_list ){
        cur_IdentId_list->n_next_identifier_id = index;
    } else{
        /* create a new list for this id */
        g_IdTable.two_level_index[ first_index ][ second_index ] = index;
    }
    g_IdTable.pIdList[index].n_mode = mode;
    g_IdTable.pIdList[index].n_next_identifier_id = INVALID_ID;
    strcpy_s( g_IdTable.pIdList[index].str_name, MAX_ID_LENGTH+1, id_name );
    *p_ident_index = index;

    return 1;
}

int find_in_IdTable(FileField * fileField, char *id_name, int length, unsigned int * p_ident_index){
    char first_index = 0;
    char second_index = 0;
    IdentId_P cur_IdentId_list = NULL;
    unsigned int index = 0;
    unsigned int temp = 0;
    char *func_name = "find_in_IdTable";

    if( length <= 0 ){
        report_syntax_error( func_name, "Identifier not specified.", fileField->n_current_line );
        return 0;
    }
    if( id_name[0] >= 'A' && id_name[0] <= 'Z' ){
        first_index = id_name[0] - 'A';
    } else if( id_name[0] >= 'a' && id_name[0] <= 'z' ){
        first_index = id_name[0] - 'a' + 26;
    } else{
        first_index = 51;
    }
    if( length > 1 ){
        if( id_name[1] >= 'A' && id_name[1] <= 'Z' ){
            second_index = id_name[1] - 'A';
        } else if( id_name[1] >= 'a' && id_name[1] <= 'z' ){
            second_index = id_name[1] - 'a' + 26;
        } else if( id_name[1] >= '0' && id_name[1] <= '9' ){
            second_index = id_name[1] - '0' + 52;
        } else{
            second_index = 61;
        }
    }
    temp = g_IdTable.two_level_index[ first_index ][ second_index ];

    while( temp != INVALID_ID ){
        /* a list is found */
        cur_IdentId_list = &g_IdTable.pIdList[temp];
        if( strcmp( cur_IdentId_list->str_name, id_name ) == 0 ){
            *p_ident_index = temp;
            return 1;
        }
        temp = cur_IdentId_list->n_next_identifier_id;
    }
    report_syntax_error( func_name, "Identifier not specified.", fileField->n_current_line );
    return 0;
}

int get_number( FileField * fileField, int * pOutValue){
    char *func_name = "get_number";
    int tempValue1 = 0;
    int tempValue2 = 0;
    int b_sign = 0;/* 0 ==> no sign ,  1 ==> '+' , -1 ==> '-'  */
    /* [ 1 ] check the sign */
    if( '-' == fileField->current_ch ){
        b_sign = -1;
        fileField->current_ch = fgetc( fileField->fp );
        CHECK_NEW_LINE( fileField )
    } else if( '+' == fileField->current_ch ){
        b_sign = 1;
        fileField->current_ch = fgetc( fileField->fp );
        CHECK_NEW_LINE( fileField )
    }
    /* [ 2 ] check the first number */
    if( fileField->current_ch < '0' || fileField->current_ch > '9' ){
        report_syntax_error( func_name, "Invalid character.", fileField->n_current_line );
        return 0;
    }
    while( fileField->current_ch >= '0' && fileField->current_ch <= '9' ){
        tempValue1 = tempValue2;
        tempValue2 = tempValue2 * 10 + fileField->current_ch - '0';
        if( tempValue1 > tempValue2 ){
            /* [ 3 ] deal with overflow */
            report_syntax_error( func_name, "Integer overflow.", fileField->n_current_line );
            return 0;
        }
        fileField->current_ch = fgetc( fileField->fp );
        CHECK_NEW_LINE( fileField )        
    }
    if( -1 == b_sign ){
        tempValue2 = ~tempValue2 + 1;
    }
    if( tempValue2 > SHORT_MAX || tempValue2 < SHORT_MIN ){
        /* [ 4 ] deal with overflow. Note: using 16bit-int for EXE file */
        report_syntax_error( func_name, "Integer overflow.", fileField->n_current_line );
        return 0;
    }
    *pOutValue = (int)tempValue2;


    return 1;
}
static void print_syntax_node( FILE* fp, SynNode_P p_node ){
    char buffer[128];
    buffer[0] = '\0';
    switch( p_node->n_mode ){
    case SYN_NODE_HEAD:
        strcpy_s( buffer, 128, "head" );
        break;
    case SYN_NODE_VARID:
        strcpy_s( buffer, 128, "VARID" );
        break;
    case SYN_NODE_FUNID:
        strcpy_s( buffer, 128, "FUNID" );
        break;
    case SYN_NODE_MAINFUNID:
        strcpy_s( buffer, 128, "main" );
        break;
    case SYN_NODE_BODY:
        strcpy_s( buffer, 128, "BODY" );
        break;
    case SYN_NODE_DEFINITION:
        strcpy_s( buffer, 128, "DEFINITION" );
        break;
    case SYN_NODE_VAR_DEF:
        strcpy_s( buffer, 128, "VAR_DEF" );
        break;
    case SYN_NODE_FUNC_DEF:
        strcpy_s( buffer, 128, "FUNC_DEF" );
        break;
    case SYN_NODE_VAR_DEFINITION:
        strcpy_s( buffer, 128, "VAR_DEFINITION" );
        break;
    case SYN_NODE_STATEMENT_LIST:
        strcpy_s( buffer, 128, "STATEMENT_LIST" );
        break;
    case SYN_NODE_ASSIGN_STMT:
        strcpy_s( buffer, 128, "ASSIGN_STMT" );
        break;
    case SYN_NODE_IF_STMT:
        strcpy_s( buffer, 128, "IF_STMT" );
        break;
    case SYN_NODE_FOR_STMT:
        strcpy_s( buffer, 128, "FOR_STMT" );
        break;
    case SYN_NODE_WHILE_STMT:
        strcpy_s( buffer, 128, "WHILE_STMT" );
        break;
    case SYN_NODE_FORMULA:
        strcpy_s( buffer, 128, "FORMULA" );
        break;
    case SYN_NODE_BOOL_FORMULA:
        strcpy_s( buffer, 128, "BOOL_FORMULA" );
        break;
    case SYN_NODE_FORMULA_FOLLOW:
        strcpy_s( buffer, 128, "FORMULA_FOLLOW" );
        break;
    case SYN_NODE_NUMBER:
        strcpy_s( buffer, 128, "NUMBER" );
        break;
    case SYN_NODE_L_parenthesis:
        strcpy_s( buffer, 128, "(" );
        break;
    case SYN_NODE_R_parenthesis:
        strcpy_s( buffer, 128, ")" );
        break;
    case SYN_NODE_ADD:
        strcpy_s( buffer, 128, "+" );
        break;
    case SYN_NODE_SUB:
        strcpy_s( buffer, 128, "-" );
        break;
    case SYN_NODE_MUT:
        strcpy_s( buffer, 128, "*" );
        break;
    case SYN_NODE_DIV:
        strcpy_s( buffer, 128, "/" );
        break;
    case SYN_NODE_AND:
        strcpy_s( buffer, 128, "&&" );
        break;
    case SYN_NODE_OR:
        strcpy_s( buffer, 128, "||" );
        break;
    case SYN_NODE_LESS:
        strcpy_s( buffer, 128, "<" );
        break;
    case SYN_NODE_MORE:
        strcpy_s( buffer, 128, ">" );
        break;
    case SYN_NODE_EQ:
        strcpy_s( buffer, 128, "==" );
        break;
    case SYN_NODE_NOT_LESS:
        strcpy_s( buffer, 128, ">=" );
        break;
    case SYN_NODE_NOT_MORE:
        strcpy_s( buffer, 128, "<=" );
        break;
    case SYN_NODE_NOT_EQ:
        strcpy_s( buffer, 128, "!=" );
        break;
    case SYN_NODE_BOOL_FORMULA_FOLLOW:
        strcpy_s( buffer, 128, "BOOL_FORMULA_FOLLOW" );
        break;
    case SYN_NODE_EMPTY:
        strcpy_s( buffer, 128, "EMPTY" );
        break;
    case SYN_NODE_FUNC_CALL:
        strcpy_s( buffer, 128, "FUNC_CALL" );
        break;
    }

    fprintf( fp,"n_mode = '%s';", buffer);
    if( SYN_NODE_VARID == p_node->n_mode || SYN_NODE_FUNID == p_node->n_mode ){
        fprintf( fp, "id name = '%s';", g_IdTable.pIdList[ p_node->n_identifier_id ].str_name );
    }
    fprintf( fp,"father_id = '%d';", (int)p_node->n_father_id);
    fprintf( fp,"left_brother_id = '%d';", (int)p_node->n_left_brother_id);
    fprintf( fp,"right_brother_id = '%d';", (int)p_node->n_right_brother_id);
    fprintf( fp,"son_id = '%d';", (int)p_node->n_son_id);
    if( SYN_NODE_NUMBER == p_node->n_mode ){
        fprintf( fp, "value = '%d';", p_node->n_int_value );
    }
}
void debug_syntax( FILE* fp ){
    unsigned int i = 0;
    for( i = 0; i < g_SynTree.n_node_num; i++ ){
        fprintf( fp,"id = '%6d';", i);
        print_syntax_node( fp, &g_SynTree.pSynNodeList[ i ] );
        fprintf(fp,"\n*******************************************************************************\n");
    }
}


语义分析器

/** scmpsem.c
====================================================================
This is the base source file for Semantic Analyze


====================================================================
 */

#include "scmpsem.h"
int sem_deal_with_header();
int sem_deal_with_data();
int sem_deal_with_code();
int sem_deal_with_DEFINITION(SynNode_P pSynNode);
int sem_deal_with_BODY(SynNode_P pSynNode);
int sem_deal_with_FUNC_DEF(SynNode_P pSynNode);
int sem_deal_with_STATEMENT_LIST(SynNode_P pSynNode);
int sem_deal_with_ASSIGN_STMT(SynNode_P pSynNode);
int sem_deal_with_IF_STMT(SynNode_P pSynNode);
int sem_deal_with_FOR_STMT(SynNode_P pSynNode);
int sem_deal_with_WHILE_STMT(SynNode_P pSynNode);
int sem_deal_with_FUNC_CALL(SynNode_P pSynNode);
int sem_deal_with_FORMULA(SynNode_P pSynNode);
int sem_deal_with_BOOL_FORMULA(SynNode_P pSynNode);

static int push( SEM_STACK_NODE *in_node );
static int pop( SEM_STACK_NODE *out_node );
#define MY_PUSH( p_in_node )\
    {\
        if( 0 == push( p_in_node ) ){\
           printf("POP error at line '%d' \n", __LINE__ );\
           return 0;\
        }\
    }
#define MY_POP( p_out_node )\
    {\
        if( 0 == pop( p_out_node ) ){\
           printf("POP error at line '%d' \n", __LINE__ );\
           return 0;\
        }\
    }
static int check_caculate( SEM_STACK_NODE *cur_node );
static int caculate_AX_BX_by_op( SEM_STACK_NODE *op_node );

int initialize_SemEnv(){
    g_SemEnv.n_SignCurrentId = 0;
    g_SemEnv.pAsmFile = NULL;
    fopen_s( &g_SemEnv.pAsmFile, ASM_FILE_NAME , "w" );
    if( NULL == g_SemEnv.pAsmFile ){
        printf("Can't open source file '%s'. exit.\n", ASM_FILE_NAME );
        return 0;
    }
    g_SemEnv.s_sem_stack.n_num = 0;
    g_SemEnv.s_sem_stack.sem_node_list = ( SEM_STACK_NODE * )malloc( sizeof(SEM_STACK_NODE) * MAX_STACK_NUM );
    if( NULL == g_SemEnv.s_sem_stack.sem_node_list ){
        printf("Memery not enough while initializing semantic stack.\n" );
        return 0;
    }
    return 1;
}
int finalize_SemEnv(){
    g_SemEnv.n_SignCurrentId = 0;
    MY_HELP_CLOSE( g_SemEnv.pAsmFile );
    g_SemEnv.s_sem_stack.n_num = 0;
    MY_HELP_FREE( g_SemEnv.s_sem_stack.sem_node_list );
    return 1;
}


int semantic_analyzer(){
    int ret = 0;
    char * func_name="semantic_analyzer";

    ret = initialize_SemEnv();
    if( 0 == ret ){
        printf("semantic_analyzer exit with initialize error.\n");
        finalize_SemEnv();
        return 0;
    }
    /* [ 1 ] deal with header */
    sem_deal_with_header();
    /* [ 2 ] deal with data */
    ret = sem_deal_with_data();
    if( 0 == ret ){
        printf("semantic_analyzer exit with internal error.\n");
        finalize_SemEnv();
        return 0;
    }
    /* [ 3 ] deal with code */
    ret =  sem_deal_with_code();
    if( 0 == ret ){
        printf("semantic_analyzer exit with internal error.\n");
        finalize_SemEnv();
        return 0;
    }
    /* [ 4 ] deal with Ending */
    fprintf( g_SemEnv.pAsmFile, ASM_END_MAIN );

    finalize_SemEnv();
    return 1;
}
int sem_deal_with_header(){
    fprintf( g_SemEnv.pAsmFile, ASM_HEADER );

    return 1;
}
int sem_deal_with_data(){
    unsigned int index = 0;
    char * p_VarName = NULL;

    /* [ 1 ] data header */
    fprintf( g_SemEnv.pAsmFile, ASM_DATA_HEADER );
    /* [ 2 ] Variable definition */
    for( index = 0; index < g_IdTable.n_id_num; index++ ){
        if( SYN_NODE_VARID == g_IdTable.pIdList[ index ].n_mode ){
            p_VarName = g_IdTable.pIdList[ index ].str_name;
            fprintf( g_SemEnv.pAsmFile, ASM_VAR_DEF, p_VarName, p_VarName, p_VarName );
        }
    }

    return 1;
}
int sem_deal_with_code(){
    int ret = 0;
    SynNode_P pCurSynNode = NULL;

    /* [ 1 ] code header */
    fprintf( g_SemEnv.pAsmFile, ASM_CODE_HEADER );
    /* [ 2 ] deal with DEFINITION */
    /* [ 2.1 ] Get the first node of DEFINITION */
    pCurSynNode = &g_SynTree.pSynNodeList[1];
    ret = sem_deal_with_DEFINITION( pCurSynNode );
    if( 0 == ret ){
        return 0;
    }
    /* [ 3 ] deal with main */
    /* [ 3.1 ] Get the node of 'main' */
    fprintf( g_SemEnv.pAsmFile, "Main  PROC\nMOV AX, DGROUP\nMOV DS, AX\n" );
    CHECK_SYN_NODE_ID( pCurSynNode->n_right_brother_id )
    pCurSynNode = &g_SynTree.pSynNodeList[ pCurSynNode->n_right_brother_id ];
    /* [ 3.2 ] Get the node of 'BODY' */
    CHECK_SYN_NODE_ID( pCurSynNode->n_right_brother_id )
    pCurSynNode = &g_SynTree.pSynNodeList[ pCurSynNode->n_right_brother_id ];
    ret = sem_deal_with_BODY( pCurSynNode );
    if( 0 == ret ){
        return 0;
    }
#ifdef DEBUG_SEM
    debug_sem();
#endif
    /* [ 3.3 ] Tail of 'main' */
    fprintf( g_SemEnv.pAsmFile, "MOV  AX, 4C00H\nINT  21H\nMain  ENDP\n" );
    return 1;
}
int sem_deal_with_DEFINITION( SynNode_P pSynNode ){
    SynNode_P pCurSynNode = NULL;
    int ret = 0;

    /* [ 1 ] Get the first node of DEFINITION */
    pCurSynNode = pSynNode;
    while( pCurSynNode != NULL && pCurSynNode->n_son_id != INVALID_ID ){
        /* [ 1.1 ] check the son */
        pCurSynNode = &g_SynTree.pSynNodeList[ pCurSynNode->n_son_id ];
        if( SYN_NODE_FUNC_DEF == pCurSynNode->n_mode ){
            /* [ 1.1.1 ] it's FUNC definition, deal with it */
            ret = sem_deal_with_FUNC_DEF( pCurSynNode );
            if( 0 == ret ){
                return 0;
            }

        }
            /* [ 1.1.2 ] deal with right brother of it */
        if( pCurSynNode->n_right_brother_id != INVALID_ID ){
            pCurSynNode = &g_SynTree.pSynNodeList[ pCurSynNode->n_right_brother_id ];
        } else{
            pCurSynNode = NULL;
        }
    }
    return 1;
}
int sem_deal_with_FUNC_DEF(SynNode_P pSynNode){
    SynNode_P pCurSynNode = NULL;
    IdentId_P pId = NULL;
    int ret = 0;
    /* [ 1 ] Function Header */
    /* [ 1.1 ] Get the function id */
    CHECK_SYN_NODE_ID( pSynNode->n_son_id )
    pCurSynNode = &g_SynTree.pSynNodeList[ pSynNode->n_son_id ];
    CHECK_SYN_NODE_ID( pCurSynNode->n_identifier_id )
    pId = &g_IdTable.pIdList[ pCurSynNode->n_identifier_id ];
    fprintf( g_SemEnv.pAsmFile, "%s  PROC\n", pId->str_name );
    /* [ 1.2 ] Save the current Registers */
    fprintf( g_SemEnv.pAsmFile, "PUSH  BP\n", pId->str_name );
    fprintf( g_SemEnv.pAsmFile, "MOV  BP, SP\n", pId->str_name );
    fprintf( g_SemEnv.pAsmFile, "PUSH  DS\n", pId->str_name );
    /* [ 2 ] deal with 'BODY' */
    CHECK_SYN_NODE_ID( pCurSynNode->n_right_brother_id )
    pCurSynNode = &g_SynTree.pSynNodeList[ pCurSynNode->n_right_brother_id ];
    ret = sem_deal_with_BODY( pCurSynNode );
    if( 0 == ret ){
        return 0;
    }
    /* [ 3 ] Function Tail */
    /* [ 3.1 ] Backup the current Registers */
    fprintf( g_SemEnv.pAsmFile, "POP  DS\n", pId->str_name );
    fprintf( g_SemEnv.pAsmFile, "MOV  SP, BP\n", pId->str_name );
    fprintf( g_SemEnv.pAsmFile, "POP  BP\n", pId->str_name );
    fprintf( g_SemEnv.pAsmFile, "RET\n%s  ENDP\n", pId->str_name );
    return 1;
}
int sem_deal_with_BODY(SynNode_P pSynNode){
    SynNode_P pCurSynNode = NULL;
    int ret = 0;
    
    /* [ 1 ] get node of 'VAR_DEFINITION' */
    CHECK_SYN_NODE_ID( pSynNode->n_son_id )
    pCurSynNode = &g_SynTree.pSynNodeList[ pSynNode->n_son_id ];
    /* [ 2 ] deal with  'STATEMENT_LIST' */
    if( INVALID_ID != pCurSynNode->n_right_brother_id ){
        pCurSynNode = &g_SynTree.pSynNodeList[ pCurSynNode->n_right_brother_id ];
        ret = sem_deal_with_STATEMENT_LIST( pCurSynNode );
        if( 0 == ret ){
            return 0;
        }
    }
    return 1;
}
int sem_deal_with_STATEMENT_LIST(SynNode_P pSynNode){
    SynNode_P pCurSynNode = NULL;
    int ret = 0;

    if( INVALID_ID == pSynNode->n_son_id ){
        /* empty statement list */
        return 1;
    }
    /* [ 1 ] deal with first statement */
    pCurSynNode = &g_SynTree.pSynNodeList[ pSynNode->n_son_id ];
    switch( pCurSynNode->n_mode ){
        case SYN_NODE_ASSIGN_STMT:
            ret = sem_deal_with_ASSIGN_STMT( pCurSynNode );
            break;
        case SYN_NODE_IF_STMT:
            ret = sem_deal_with_IF_STMT( pCurSynNode );
            break;
        case SYN_NODE_FOR_STMT:
            ret = sem_deal_with_FOR_STMT( pCurSynNode );
            break;
        case SYN_NODE_WHILE_STMT:
            ret = sem_deal_with_WHILE_STMT( pCurSynNode );
            break;
        case SYN_NODE_FUNC_CALL:
            ret = sem_deal_with_FUNC_CALL( pCurSynNode );
            break;
    }
    if( 0 == ret ){
        return 0;
    }
    /* [ 2 ] deal with following statement */
    CHECK_SYN_NODE_ID( pCurSynNode->n_right_brother_id )
    pCurSynNode = &g_SynTree.pSynNodeList[ pCurSynNode->n_right_brother_id ];
    ret = sem_deal_with_STATEMENT_LIST( pCurSynNode );
    return ret;
}
int sem_deal_with_ASSIGN_STMT(SynNode_P pSynNode){
    SynNode_P pCurSynNode = NULL;
    int ret = 0;
    IdentId_P pId = NULL;
    /* [ 1 ] get the var id */
    CHECK_SYN_NODE_ID( pSynNode->n_son_id )
    pCurSynNode = &g_SynTree.pSynNodeList[ pSynNode->n_son_id ];
    CHECK_SYN_NODE_ID( pCurSynNode->n_identifier_id )
    pId = &g_IdTable.pIdList[ pCurSynNode->n_identifier_id ];

    /* [ 2 ] deal with FORMULA */
    CHECK_SYN_NODE_ID( pCurSynNode->n_right_brother_id )
    pCurSynNode = &g_SynTree.pSynNodeList[ pCurSynNode->n_right_brother_id ];
    ret = sem_deal_with_FORMULA( pCurSynNode );
    if( 0 == ret ){
        return ret;
    }
    /* [ 3 ] deal with assign */
    fprintf( g_SemEnv.pAsmFile, "MOV  %s, AX\n", pId->str_name );

    return 1;
}
int sem_deal_with_IF_STMT(SynNode_P pSynNode){
    SynNode_P pCurSynNode = NULL;
    int ret = 0;
    char str_cur_sign[20];
    /* [ 1 ] deal with BOOL_FORMULA */
    CHECK_SYN_NODE_ID( pSynNode->n_son_id )
    pCurSynNode = &g_SynTree.pSynNodeList[ pSynNode->n_son_id ];
    ret = sem_deal_with_BOOL_FORMULA( pCurSynNode );
    if( 0 == ret ){
        return 0;
    }
    /* [ 2 ] make a sign name. if AX is 0, jump to it. */
    sprintf_s( str_cur_sign, sizeof(str_cur_sign), "SIGN_%d", g_SemEnv.n_SignCurrentId );
    g_SemEnv.n_SignCurrentId++;
    fprintf( g_SemEnv.pAsmFile, "CMP  AX,0\nJE %s\n",  str_cur_sign );
    /* [ 3 ] deal with STATEMENT_LIST */
    CHECK_SYN_NODE_ID( pCurSynNode->n_right_brother_id )
    pCurSynNode = &g_SynTree.pSynNodeList[ pCurSynNode->n_right_brother_id ];
    ret = sem_deal_with_STATEMENT_LIST( pCurSynNode );
    if( 0 == ret ){
        return 0;
    }
    /* [ 4 ] make the sign at the end */
    fprintf( g_SemEnv.pAsmFile, "%s:\n",  str_cur_sign );
    return 1;
}
int sem_deal_with_FOR_STMT(SynNode_P pSynNode){
    SynNode_P pCurSynNode = NULL;
    SynNode_P pSecondAssign = NULL;
    int ret = 0;
    char str_first_sign[20];
    char str_second_sign[20];
    /* [ 1 ] deal with ASSIGN_STMT */
    CHECK_SYN_NODE_ID( pSynNode->n_son_id )
    pCurSynNode = &g_SynTree.pSynNodeList[ pSynNode->n_son_id ];
    if( SYN_NODE_ASSIGN_STMT == pCurSynNode->n_mode ){
        ret = sem_deal_with_ASSIGN_STMT( pCurSynNode );
        if( 0 == ret ){
            return 0;
        }
    }
    /* [ 2 ] make a sign before BOOL_FORMULA */
    sprintf_s( str_first_sign, sizeof(str_first_sign), "SIGN_%d", g_SemEnv.n_SignCurrentId );
    g_SemEnv.n_SignCurrentId++;
    fprintf( g_SemEnv.pAsmFile, "%s:\n",  str_first_sign );
    /* [ 3 ] deal with BOOL_FORMULA */
    CHECK_SYN_NODE_ID( pCurSynNode->n_right_brother_id )
    pCurSynNode = &g_SynTree.pSynNodeList[ pCurSynNode->n_right_brother_id ];
    ret = sem_deal_with_BOOL_FORMULA( pCurSynNode );
    if( 0 == ret ){
        return 0;
    }
    /* [ 4 ] make a sign at the end, if AX=0,jump to it */
    sprintf_s( str_second_sign, sizeof(str_first_sign), "SIGN_%d", g_SemEnv.n_SignCurrentId );
    g_SemEnv.n_SignCurrentId++;
    fprintf( g_SemEnv.pAsmFile, "CMP  AX,0\nJE %s\n",  str_second_sign );
    /* [ 5 ] store the second Assign Statement node */
    CHECK_SYN_NODE_ID( pCurSynNode->n_right_brother_id )
    pCurSynNode = &g_SynTree.pSynNodeList[ pCurSynNode->n_right_brother_id ];
    pSecondAssign = pCurSynNode;
    /* [ 6 ] deal with STATEMENT_LIST */
    CHECK_SYN_NODE_ID( pCurSynNode->n_right_brother_id )
    pCurSynNode = &g_SynTree.pSynNodeList[ pCurSynNode->n_right_brother_id ];
    ret = sem_deal_with_STATEMENT_LIST( pCurSynNode );
    if( 0 == ret ){
        return 0;
    }
    /* [ 7 ] deal with the second Assign Statement */
    if( SYN_NODE_ASSIGN_STMT == pSecondAssign->n_mode ){
        ret = sem_deal_with_ASSIGN_STMT( pSecondAssign );
        if( 0 == ret ){
            return 0;
        }
    }
    /* [ 8 ] jump to first sign */
    fprintf( g_SemEnv.pAsmFile, "JMP %s\n",  str_first_sign );
    /* [ 9 ] store to second sign */
    fprintf( g_SemEnv.pAsmFile, "%s:\n",  str_second_sign );

    return 1;
}
int sem_deal_with_WHILE_STMT(SynNode_P pSynNode){
    SynNode_P pCurSynNode = NULL;
    int ret = 0;
    char str_first_sign[20];
    char str_second_sign[20];
    /* [ 1 ] make a sign before BOOL_FORMULA */
    sprintf_s( str_first_sign, sizeof(str_first_sign), "SIGN_%d", g_SemEnv.n_SignCurrentId );
    g_SemEnv.n_SignCurrentId++;
    fprintf( g_SemEnv.pAsmFile, "%s:\n",  str_first_sign );
    /* [ 2 ] deal with BOOL_FORMULA */
    CHECK_SYN_NODE_ID( pSynNode->n_son_id )
    pCurSynNode = &g_SynTree.pSynNodeList[ pSynNode->n_son_id ];
    ret = sem_deal_with_BOOL_FORMULA( pCurSynNode );
    if( 0 == ret ){
        return 0;
    }
    /* [ 3 ] make a sign at the end, if AX=0,jump to it */
    sprintf_s( str_second_sign, sizeof(str_first_sign), "SIGN_%d", g_SemEnv.n_SignCurrentId );
    g_SemEnv.n_SignCurrentId++;
    fprintf( g_SemEnv.pAsmFile, "CMP  AX,0\nJE %s\n",  str_second_sign );
    /* [ 4 ] deal with STATEMENT_LIST */
    CHECK_SYN_NODE_ID( pCurSynNode->n_right_brother_id )
    pCurSynNode = &g_SynTree.pSynNodeList[ pCurSynNode->n_right_brother_id ];
    ret = sem_deal_with_STATEMENT_LIST( pCurSynNode );
    if( 0 == ret ){
        return 0;
    }
    /* [ 5 ] jump to first sign */
    fprintf( g_SemEnv.pAsmFile, "JMP %s\n",  str_first_sign );
    /* [ 6 ] store to second sign */
    fprintf( g_SemEnv.pAsmFile, "%s:\n",  str_second_sign );

    return 1;
}
int sem_deal_with_FUNC_CALL(SynNode_P pSynNode){
    SynNode_P pCurSynNode = NULL;
    IdentId_P pId = NULL;

    CHECK_SYN_NODE_ID( pSynNode->n_son_id )
    pCurSynNode = &g_SynTree.pSynNodeList[ pSynNode->n_son_id ];
    CHECK_SYN_NODE_ID( pCurSynNode->n_identifier_id )
    pId = &g_IdTable.pIdList[ pCurSynNode->n_identifier_id ];
    fprintf( g_SemEnv.pAsmFile, "CALL  %s\n", pId->str_name );

    return 1;
}
int sem_deal_with_FORMULA(SynNode_P pSynNode){
    char * func_name="sem_deal_with_FORMULA";
    SynNode_P pCurSynNode = NULL;
    IdentId_P pId = NULL;
    int ret = 0;
    unsigned int n_CurrentNodeId = 0;
    SEM_STACK_NODE sem_node;
    SEM_STACK_NODE op_node;
    n_CurrentNodeId = pSynNode->n_son_id;
    while( 1 ){
        /* [ 1 ] check the first Node of the Formula */
        CHECK_SYN_NODE_ID( n_CurrentNodeId )
        pCurSynNode = &g_SynTree.pSynNodeList[ n_CurrentNodeId ];
        /* [ 1.1 ] deal with '(' FORMULA ')' */
        if( SYN_NODE_L_parenthesis == pCurSynNode->n_mode ){
            /* [ 1.1.1 ] push '(' into Stack */
            sem_node.n_mode = 7;
            sem_node.n_value = SYN_NODE_L_parenthesis;
            MY_PUSH( &sem_node );
            /* [ 1.1.2 ] deal with FORMULA recursively */
            CHECK_SYN_NODE_ID( pCurSynNode->n_right_brother_id )
            pCurSynNode = &g_SynTree.pSynNodeList[ pCurSynNode->n_right_brother_id ];
            ret = sem_deal_with_FORMULA( pCurSynNode );
            if( 0 == ret ){
                return 0;
            }
            /* [ 1.1.3 ] deal with ')' */
            CHECK_SYN_NODE_ID( pCurSynNode->n_right_brother_id )
            pCurSynNode = &g_SynTree.pSynNodeList[ pCurSynNode->n_right_brother_id ];
            if( SYN_NODE_R_parenthesis != pCurSynNode->n_mode ){
                report_internal_error( func_name, __LINE__ );
                printf("Missing ')' in FORMULA .\n" );
                return 0;
            }
            /* [ 1.1.4 ] caculate current formula between '(' and ')' */
            op_node.n_mode = 0;
            op_node.n_value = SYN_NODE_R_parenthesis;
            ret = check_caculate( &op_node );
            if( 0 == ret ){
                return 0;
            }
        } else if( SYN_NODE_VARID == pCurSynNode->n_mode ){
        /* [ 1.2 ] deal with identifier */
            /* [ 1.2.1 ] make a sem node for the identifier */
            sem_node.n_mode = 0xffff;
            MY_PUSH( &sem_node );
            /* [ 1.2.2 ] make ASM code for the identifier */
            CHECK_SYN_NODE_ID( pCurSynNode->n_identifier_id )
            pId = &g_IdTable.pIdList[ pCurSynNode->n_identifier_id ];
            fprintf( g_SemEnv.pAsmFile, "MOV AX, %s\n", pId->str_name );
            fprintf( g_SemEnv.pAsmFile, "PUSH AX\n" );
        } else {
        /* [ 1.3 ] deal with number */
            /* [ 1.3.1 ] make a sem node for the number */
            sem_node.n_mode = 0xffff;
            MY_PUSH( &sem_node );
            /* [ 1.3.2 ] make ASM code for the number */
            fprintf( g_SemEnv.pAsmFile, "MOV AX, %d\n", pCurSynNode->n_int_value );
            fprintf( g_SemEnv.pAsmFile, "PUSH AX\n" );
        }
        /* [ 2 ]  deal with FORMULA_FOLLOW */
        CHECK_SYN_NODE_ID( pCurSynNode->n_right_brother_id )
        pCurSynNode = &g_SynTree.pSynNodeList[ pCurSynNode->n_right_brother_id ];
        if( INVALID_ID == pCurSynNode->n_son_id ){
            /*=================================================================
            Empty FORMULA_FOLLOW.Clear the stack and finish the caculating 
            =================================================================*/
            while( 1 ){
                MY_POP( &sem_node );
                if( 0 == g_SemEnv.s_sem_stack.n_num ){
                    /* This node is the only node in the stack , finished. */
                    fprintf( g_SemEnv.pAsmFile, "POP AX\n" );
                    return 1;
                }
                MY_POP( &op_node );
                if( 7 == op_node.n_mode ){/* Reach the Beginning of a FOMULA */
                    MY_PUSH( &op_node );
                    MY_PUSH( &sem_node );
                    return 1;
                } else{
                    MY_POP( &sem_node );
                    ret = caculate_AX_BX_by_op( &op_node );
                }
                /* Push the result */
                MY_PUSH( &sem_node );
                if( 0 == ret ){
                    return 0;
                }
                if( 0 == g_SemEnv.s_sem_stack.n_num ){
                    /* This node is the only node in the stack , finished. */
                    fprintf( g_SemEnv.pAsmFile, "POP AX\n" );
                    return 1;
                }
            }
        } else{
            /* [ 2.1 ] deal with operator */
            pCurSynNode = &g_SynTree.pSynNodeList[ pCurSynNode->n_son_id ];
            switch( pCurSynNode->n_mode ){
                case SYN_NODE_ADD:
                case SYN_NODE_SUB:
                    op_node.n_mode = 5;
                    break;
                case SYN_NODE_MUT:
                case SYN_NODE_DIV:
                    op_node.n_mode = 6;
                    break;
                case SYN_NODE_AND:
                    op_node.n_mode = 2;
                    break;
                case SYN_NODE_OR:
                    op_node.n_mode = 1;
                    break;
                case SYN_NODE_LESS:
                case SYN_NODE_MORE:
                case SYN_NODE_NOT_LESS:
                case SYN_NODE_NOT_MORE:
                    op_node.n_mode = 4;
                    break;
                case SYN_NODE_EQ:
                case SYN_NODE_NOT_EQ:
                    op_node.n_mode = 3;
                    break;
                default:
                    printf("Internal error! invalid operator mode '%d' at line '%d'\n", pCurSynNode->n_mode, __LINE__ );
                    return 0;
            }
            op_node.n_value = pCurSynNode->n_mode;
            ret = check_caculate( &op_node );
            if( 0 == ret ){
                return 0;
            }
            /* [ 2.2 ] deal with FORMULA using the while-looping */
            CHECK_SYN_NODE_ID( pCurSynNode->n_right_brother_id )
            pCurSynNode = &g_SynTree.pSynNodeList[ pCurSynNode->n_right_brother_id ];
            n_CurrentNodeId = pCurSynNode->n_son_id;
        }
    }

    return 1;
}
int sem_deal_with_BOOL_FORMULA(SynNode_P pSynNode){
    if( sem_deal_with_FORMULA( pSynNode ) == 0 ){
        return 0;
    }
    return 1;
}
static int push( SEM_STACK_NODE *in_node ){
    unsigned int num = 0;
    num = g_SemEnv.s_sem_stack.n_num;
    if( num >= MAX_STACK_NUM ){
        printf("Internal Error ! semantic stack overflow!\n");
        return 0;
    }
    memcpy( &g_SemEnv.s_sem_stack.sem_node_list[ num ], in_node, sizeof( SEM_STACK_NODE ) );
    g_SemEnv.s_sem_stack.n_num++;
    return 1;
}
static int pop( SEM_STACK_NODE *out_node ){
    unsigned int index = 0;
    index = g_SemEnv.s_sem_stack.n_num;
    index--;
    if( index >= MAX_STACK_NUM ){
        printf("Internal Error ! semantic stack empty!\n");
        return 0;
    }
    memcpy( out_node, &g_SemEnv.s_sem_stack.sem_node_list[ index ], sizeof( SEM_STACK_NODE ) );
    g_SemEnv.s_sem_stack.n_num--;
    return 1;
}
static int check_caculate( SEM_STACK_NODE *cur_node ){
    unsigned int num = 0;
    unsigned short cur_mode = cur_node->n_mode;
    unsigned short last_mode = 0;
    SEM_STACK_NODE sem_node;
    SEM_STACK_NODE op_node;
    num = g_SemEnv.s_sem_stack.n_num;
    if( 0 == cur_mode ){
        /* [ 1 ] deal with ')' */
        /* [ 1.1 ] pop the first node on top of the stack */
        MY_POP( &sem_node );
        if( 0xffff != sem_node.n_mode ){
            printf("Internal Error ! Missing number between '(' and ')' in FORMULA .\n" );
            return 0;
        }
        /* [ 1.2 ] pop the next node on top of the stack */
        MY_POP( &op_node );
        if( 7 == op_node.n_mode ){/* '(' */
            /* push the result of FORMULA between '(' and ')' */
            MY_PUSH( &sem_node );
        } else{/* operator */
            /* [ 1.2 ] pop the second number on top of the stack */
            MY_POP( &sem_node );
            /* [ 1.3 ] caculate current formula between '(' and ')' */
            if( 0 == caculate_AX_BX_by_op( &op_node ) ){
                return 0;
            }
            /* [ 1.4 ] pop the '(' */
            MY_POP( &op_node );
            /* [ 1.5 ] push the result of FORMULA between '(' and ')' */
            MY_PUSH( &sem_node );
        }
    } else{
        /* [ 2 ] deal with other operators */
        if( num >= 2 && num <= MAX_STACK_NUM ){
            last_mode = g_SemEnv.s_sem_stack.sem_node_list[ num-2 ].n_mode;
        }
        if( cur_mode <= last_mode && last_mode != 7 ){/* '(' can't caculate without ')' */
            MY_POP( &sem_node );
            MY_POP( &op_node );
            MY_POP( &sem_node );
            if( 0 == caculate_AX_BX_by_op( &op_node ) ){
                return 0;
            }
            MY_PUSH( &sem_node );
        } else{
            /* do nothing */
        }
        MY_PUSH( cur_node );
    }
    return 1;
}
static int caculate_AX_BX_by_op( SEM_STACK_NODE *op_node ){
    char * func_name = "caculate_AX_BX_by_op";
    char str_first_sign[20];
    char str_second_sign[20];
    /* [ 1 ] pop BX */
    fprintf( g_SemEnv.pAsmFile, "POP  BX\n" );
    /* [ 2 ] pop AX */
    fprintf( g_SemEnv.pAsmFile, "POP  AX\n" );
    /* [ 3 ] caculate */
    switch( op_node->n_mode ){
        case 1: /* || */
            fprintf( g_SemEnv.pAsmFile, "OR AX, BX\n" );
            break;
        case 2: /* && */
            fprintf( g_SemEnv.pAsmFile, "AND AX, BX\n" );
            break;
        case 3:
            if( SYN_NODE_EQ == op_node->n_value ){ /* == */
                fprintf( g_SemEnv.pAsmFile, ";Deal with '=='\n" );
                sprintf_s( str_first_sign, sizeof(str_first_sign), "SIGN_%d", g_SemEnv.n_SignCurrentId );
                g_SemEnv.n_SignCurrentId++;
                sprintf_s( str_second_sign, sizeof(str_second_sign), "SIGN_%d", g_SemEnv.n_SignCurrentId );
                g_SemEnv.n_SignCurrentId++;
                fprintf( g_SemEnv.pAsmFile, "CMP AX, BX\n" );
                fprintf( g_SemEnv.pAsmFile, "JNE %s\n",  str_first_sign );
                fprintf( g_SemEnv.pAsmFile, "MOV AX, 1\n" );
                fprintf( g_SemEnv.pAsmFile, "JMP %s\n", str_second_sign );
                fprintf( g_SemEnv.pAsmFile, "%s:\n",  str_first_sign );
                fprintf( g_SemEnv.pAsmFile, "MOV AX, 0\n" );
                fprintf( g_SemEnv.pAsmFile, "%s:\n",  str_second_sign );
            } else{ /* != */
                fprintf( g_SemEnv.pAsmFile, "XOR AX, BX\n" );
            }
            break;
        case 4:
            if( SYN_NODE_MORE == op_node->n_value ){ /* > */
                fprintf( g_SemEnv.pAsmFile, "SUB BX, AX\n" );
                fprintf( g_SemEnv.pAsmFile, "AND BX, 8000H\n" );
                fprintf( g_SemEnv.pAsmFile, "MOV AX, BX\n" );
            } else if( SYN_NODE_LESS == op_node->n_value ){ /* < */
                fprintf( g_SemEnv.pAsmFile, "SUB AX, BX\n" );
                fprintf( g_SemEnv.pAsmFile, "AND AX, 8000H\n" );
            } else if( SYN_NODE_NOT_LESS == op_node->n_value ){ /* >= */
                fprintf( g_SemEnv.pAsmFile, "SUB AX, BX\n" );
                fprintf( g_SemEnv.pAsmFile, "AND AX, 8000H\n" );
                fprintf( g_SemEnv.pAsmFile, "XOR AX, 8000H\n" );
            } else{ /* <= */
                fprintf( g_SemEnv.pAsmFile, "SUB BX, AX\n" );
                fprintf( g_SemEnv.pAsmFile, "AND BX, 8000H\n" );
                fprintf( g_SemEnv.pAsmFile, "XOR BX, 8000H\n" );
                fprintf( g_SemEnv.pAsmFile, "MOV AX, BX\n" );
            }
            break;
        case 5:
            if( SYN_NODE_ADD == op_node->n_value ){ /* + */
                fprintf( g_SemEnv.pAsmFile, "ADD AX, BX\n" );
            } else{ /* - */
                fprintf( g_SemEnv.pAsmFile, "SUB AX, BX\n" );
            }
            break;
        case 6:
            if( SYN_NODE_MUT == op_node->n_value ){ /* * */
                fprintf( g_SemEnv.pAsmFile, "MUL BX\n" );
            } else{ /* / */
                fprintf( g_SemEnv.pAsmFile, "MOV DX, 0\n" );
                fprintf( g_SemEnv.pAsmFile, "DIV BX\n" );
            }
            break;
        default:
            report_internal_error( func_name, __LINE__ );
            printf("Invalid operator mode '%d'\n", op_node->n_mode );
            return 0;
    }
    /* [ 4 ] push AX */
    fprintf( g_SemEnv.pAsmFile, "PUSH  AX\n" );

    return 1;
}
void debug_sem( ){
    unsigned int i = 0;
    IdentId_P pId = NULL;
    for( i = 0; i < g_IdTable.n_id_num; i++ ){
        pId = &g_IdTable.pIdList[ i ];
        if( SYN_NODE_VARID == pId->n_mode ){
            fprintf( g_SemEnv.pAsmFile, "LEA  AX, Name_%s\nMOV  DX, AX\nMOV  AH, 9\nINT  21H\n", pId->str_name );
            fprintf( g_SemEnv.pAsmFile, "MOV  AX, %s\nPRINTVAL  AX\n", pId->str_name );
            fprintf( g_SemEnv.pAsmFile, ASM_CHANGE_LINE );
        }
    }
}


主函数

/** SimpleCompiler.c
====================================================================
This is the base source file for Main Function


====================================================================
 */

#include "scmppre.h"
#include "scmpstx.h"
#include "scmpsem.h"
int main(int arg_num, char ** args){
    int ret = 0;
    FILE *srcFP = NULL;
    FILE *outFP = NULL;
    char *inputFile = "test.c";
    char *outputFile = "test.c.tmp";
    FileField srcFileField;
#ifdef DEBUG_SYNTAX
    char *debugFile = "test.c.stx";
    FILE * debugfp = NULL;
#endif
    /* Global initializing */
    ret = initialize_IdTable();
    ret &= initialize_SynTree();
    if( 0 == ret ){
        printf("Program exit with initializing error.\n");
        return 0;
    }
    fopen_s( &srcFP, inputFile , "r" );
    if( NULL == srcFP ){
        printf("Can't open source file '%s'. Program exit.\n", inputFile );
        return 0;
    }
    fopen_s( &outFP, outputFile, "w" );
    if( NULL == outFP ){
        printf("Can't open temp file '%s'. Program exit.\n", outputFile );
        return 0;
    }
    /** pre-compiler **/
    ret = pre_compiler(srcFP, outFP);
    if( 0 == ret ){
        printf("Program exit with pre-compiler error.\n");
        goto ERROR_END;
    }
    MY_HELP_CLOSE( outFP );
    MY_HELP_CLOSE( srcFP );
    /** Syntax analyzing **/
    /* using the temp file as the source */
    fopen_s( &srcFP, outputFile, "r" );
    if( NULL == srcFP ){
        printf("Can't open temp file '%s'. Program exit.\n", outputFile );
        goto ERROR_END;
    }
    srcFileField.fp = srcFP;
    srcFileField.n_current_line = 1;
    ret = syntax_analyzer( &srcFileField );
    if( 0 == ret ){
        printf("Program exit with syntax_analyzer error.\n");
        goto ERROR_END;
    }
#ifdef DEBUG_SYNTAX
    fopen_s(&debugfp, debugFile, "w");
    if( NULL != debugfp ){
        debug_syntax( debugfp );
        fclose( debugfp );
    }
#endif
    /** semantic_analyzer **/
    ret = semantic_analyzer();
    if( 0 == ret ){
        printf("Program exit with semantic_analyzer error.\n");
        goto ERROR_END;
    }

    MY_HELP_CLOSE( outFP );
    MY_HELP_CLOSE( srcFP );
    release_IdTable();
    release_SynTree();
    return 1;
ERROR_END:
    MY_HELP_CLOSE( outFP );
    MY_HELP_CLOSE( srcFP );
    release_IdTable();
    release_SynTree();
    return 0;
}


语法分析头文件

 

/** scmppre.h
====================================================================
This is the base head file for pre-compiler


====================================================================
 */
#ifndef SCMPPRE_H_INCLUDE
#define SCMPPRE_H_INCLUDE

#ifndef STD_COMMON_H_INCLUDE
#define STD_COMMON_H_INCLUDE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#endif


#define MAX_SRC_LINE      1024           /* the max byte number of one line in the source file */

int pre_compiler(FILE * fpInput, FILE * fpOutput);



#endif


语法分析头文件:

/** scmpstx.h
====================================================================
This is the base head file for Syntax Analyze


====================================================================
 */
#ifndef SCMPSTX_H_INCLUDE
#define SCMPSTX_H_INCLUDE


#ifndef STD_COMMON_H_INCLUDE
#define STD_COMMON_H_INCLUDE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#endif

#define MAX_SYN_NODE_NUM  32768          /* the max syntax node number */
#define MAX_ID_LENGTH     32             /* the max length of indentifier */
/* The identifier id */
typedef struct tag_identifier_id{
    short n_mode;                        /* the mode : SYN_NODE_TAIL / SYN_NODE_VARID / SYN_NODE_FUNID */
    short dummy;                         /* not used */
    int n_next_identifier_id;            /* the next identifier in current second-level list */
    char str_name[ MAX_ID_LENGTH+1 ];
}IdentId;
typedef IdentId * IdentId_P;
/* The identifier table */
typedef struct tag_id_table{
    unsigned int n_id_num;               /*============================================================
                                         The number of identifiers in the table.
                                         It's also the first free place for store a new identifier.
                                         Using n_id_num,  pIdList acts as a stack, and n_id_num is
                                         it's stack top.
                                         If n_id_num >= MAX_SYN_NODE_NUM, the stack is full.
                                         ============================================================*/
    IdentId_P pIdList;                   /*============================================================
                                         the head pointer of the identifier list.
                                         malloc MAX_SYN_NODE_NUM IdentId.
                                         ============================================================*/
    unsigned int two_level_index[52][62];        /*============================================================
                                         First index: using the first byte of the name
                                             'A' to 'Z' = 0 to 25
                                             'a' to 'z' = 26 to 51
                                         Second index: using the second byte of the name
                                             'A' to 'Z' = 0 to 25
                                             'a' to 'z' = 26 to 51
                                             '0' to '9' = 52 to 61
                                         Default value: two_level_index[i][j] = -1;
                                         if two_level_index[i][j] is not -1, it shows this second-level
                                         list in the pIdList is started at pIdList[two_level_index[i][j]]
                                         ============================================================*/            
}IdTable;
IdTable g_IdTable;                       /* the identifier table */
/* The node for syntax tree */
typedef struct tag_SyntaxNode{
    short n_mode;                        /* the mode of SyntaxNode */
    unsigned int n_identifier_id;        /*============================================================
                                         The index in the Id Table for this identifier.
                                         If it's not identifier, n_identifier_id = INVALID_ID;
                                         ============================================================*/
    unsigned int n_left_brother_id;      /*============================================================
                                         The index of the left brother in the syntax tree.
                                         If it's the first son of its father, n_left_brother_id = INVALID_ID;
                                         ============================================================*/
    unsigned int n_right_brother_id;     /*============================================================
                                         The index of the right brother in the syntax tree.
                                         If it's the last son of its father, n_right_brother_id = INVALID_ID;
                                         ============================================================*/
    unsigned int n_father_id;            /*============================================================
                                         The index of the father in the syntax tree.
                                         If it's the root, n_father_id = INVALID_ID;
                                         ============================================================*/
    unsigned int n_son_id;               /*============================================================
                                         The index of the son in the syntax tree.
                                         If it has no son, n_son_id = INVALID_ID;
                                         ============================================================*/
    int n_int_value;                       /* the value of integer */
}SynNode;
typedef SynNode * SynNode_P;
typedef struct tat_SyntaxTree{
    unsigned int n_node_num;             /*============================================================
                                         The number of SynNode in the SyntaxTree.
                                         It's also the first free place for store a new SynNode.
                                         Using n_node_num,  pSynNodeList acts as a stack, and n_node_num is
                                         it's stack top.
                                         If n_node_num >= MAX_SYN_NODE_NUM, the stack is full.
                                         ============================================================*/
    SynNode_P pSynNodeList;              /*============================================================
                                         the head pointer of the syntax tree node list.
                                         malloc MAX_SYN_NODE_NUM SynNode.
                                         ============================================================*/
}SynTree;
SynTree g_SynTree;                       /* the syntax tree */
/* Syntax Node mode definitions */
#define SYN_NODE_TAIL                 0          /* the tail node */
#define SYN_NODE_HEAD                 1          /* the head node */
#define SYN_NODE_VARID                2          /* the identifier of variabale */
#define SYN_NODE_FUNID                3          /* the identifier of function */
#define SYN_NODE_MAINFUNID            4          /* the identifier of main function */
#define SYN_NODE_BODY                 11         /* the BODY of a function */
#define SYN_NODE_DEFINITION           12         /* DEFINITION */
#define SYN_NODE_VAR_DEF              13         /* VAR_DEF */
#define SYN_NODE_FUNC_DEF             14         /* FUNC_DEF */
#define SYN_NODE_VAR_DEFINITION       15         /* VAR_DEFINITION */
#define SYN_NODE_STATEMENT_LIST       16         /* STATEMENT_LIST */
#define SYN_NODE_ASSIGN_STMT          17         /* ASSIGN_STMT */
#define SYN_NODE_IF_STMT              18         /* IF_STMT */
#define SYN_NODE_FOR_STMT             19         /* FOR_STMT */
#define SYN_NODE_WHILE_STMT           20         /* WHILE_STMT */
#define SYN_NODE_FORMULA              21         /* FORMULA */
#define SYN_NODE_BOOL_FORMULA         22         /* BOOL_FORMULA */
#define SYN_NODE_FORMULA_FOLLOW       23         /* FORMULA_FOLLOW */
#define SYN_NODE_NUMBER               24         /* numbers */
#define SYN_NODE_L_parenthesis        25         /* '(' */
#define SYN_NODE_R_parenthesis        26         /* ')' */
#define SYN_NODE_ADD                  27         /* '+' */
#define SYN_NODE_SUB                  28         /* '-' */
#define SYN_NODE_MUT                  29         /* '*' */
#define SYN_NODE_DIV                  30         /* '/' */
#define SYN_NODE_AND                  31         /* '&&' */
#define SYN_NODE_OR                   32         /* '||' */
#define SYN_NODE_LESS                 33         /* '<' */
#define SYN_NODE_MORE                 34         /* '>' */
#define SYN_NODE_EQ                   35         /* '==' */
#define SYN_NODE_NOT_LESS             36         /* '>=' */
#define SYN_NODE_NOT_MORE             37         /* '<=' */
#define SYN_NODE_NOT_EQ               38         /* '!=' */
#define SYN_NODE_BOOL_FORMULA_FOLLOW  39         /* BOOL_FORMULA_FOLLOW */
#define SYN_NODE_FUNC_CALL            40         /* FUNC_CALL */
#define SYN_NODE_EMPTY               100         /* An empty node */

#define SHORT_MAX                    32767       /* MAX VALUE OF SHORT */
#define SHORT_MIN                    -32768      /* MIN VALUE OF SHORT */

#define INVALID_ID            (unsigned int)0xFFFFFFFF         /* the invalid index */

typedef struct tag_fileField{
    FILE * fp;                                   /* the pointer to the source file */
    int n_current_line;                          /* the current line number */
    char current_ch;                             /* the current char */
    char name_buf[MAX_ID_LENGTH+1];              /* the buffer for an identifier name */
}FileField;

#define KEY_WORD_NO                   0          /* Not a key word */
#define KEY_WORD_MAIN                 1          /* 'main' */
#define KEY_WORD_INT                  2          /* 'int' */
#define KEY_WORD_IF                   3          /* 'if' */
#define KEY_WORD_WHILE                4          /* 'while' */
#define KEY_WORD_FOR                  5          /* 'for' */

#define CHECK_KEY_WORD( buffer, type ) \
    { \
        if( 0 == strcmp( buffer, "main" ) ){\
            type = KEY_WORD_MAIN;\
        } else if( 0 == strcmp( buffer, "int" ) ){\
            type = KEY_WORD_INT;\
        } else if( 0 == strcmp( buffer, "if" ) ){\
            type = KEY_WORD_IF;\
        } else if( 0 == strcmp( buffer, "while") ){\
            type = KEY_WORD_WHILE;\
        } else if( 0 == strcmp( buffer, "for") ){\
            type = KEY_WORD_FOR;\
        } else{\
            type = KEY_WORD_NO;\
        }\
    }
#define MY_HELP_FREE( pValue )  \
    if( NULL != pValue ){\
        free(pValue);\
        pValue = NULL;\
    }
#define MY_HELP_CLOSE( pFILE )  \
    if( NULL != pFILE ){\
        fclose(pFILE);\
        pFILE = NULL;\
    }
#define CHECK_NEW_LINE( fileField ) \
    if( '\n' == fileField->current_ch ){\
        fileField->n_current_line++;\
    }
#define JUMP_SPACES( fileField ) \
    {\
        while( isspace( fileField->current_ch ) ){\
            fileField->current_ch = fgetc( fileField->fp );\
            CHECK_NEW_LINE( fileField )\
        }\
    }
#define GET_IDENTIFY( fileField, buffer, length )\
    {\
        length = 0;\
        JUMP_SPACES( fileField );\
        if( !isalpha(fileField->current_ch) ){/* the fisrt char must be alphabet */\
            buffer[0] = '\0';\
            length = 0;\
        } else{\
            buffer[0] = fileField->current_ch;\
            length = 1;\
            while( 1 ){\
                fileField->current_ch = fgetc( fileField->fp );\
                CHECK_NEW_LINE( fileField )\
                if( isalnum( fileField->current_ch ) ){\
                    buffer[length] = fileField->current_ch;\
                    length++;\
                    if( length > MAX_ID_LENGTH ){/* too logn identifier */\
                        buffer[0] = '\0';\
                        length = 0;\
                        break;\
                    }\
                } else{\
                    buffer[length] = '\0';\
                    break;\
                }\
            }\
        }\
    }
#define GET_NEW_CHAR_JUMP_SPACE( fileField ) \
    {\
        fileField->current_ch = fgetc( fileField->fp );\
        CHECK_NEW_LINE( fileField )\
        JUMP_SPACES( fileField )\
    }
#define CHECK_NODE_NUM( function, fileField, num ) \
    {\
        if( num > MAX_SYN_NODE_NUM ){\
            report_syntax_error( function, "Too many syntax nodes.", fileField->n_current_line );\
            return 0;\
        }\
    }
#define FIX_FATHER_LBROTHER( father_ID, left_brother_ID, current_ID ) \
    {\
        if( father_ID != INVALID_ID ){\
            if( INVALID_ID == g_SynTree.pSynNodeList[father_ID].n_son_id ){\
                g_SynTree.pSynNodeList[father_ID].n_son_id = current_ID;\
            }\
        }\
        if( left_brother_ID != INVALID_ID ){\
            if( INVALID_ID == g_SynTree.pSynNodeList[left_brother_ID].n_right_brother_id ){\
                g_SynTree.pSynNodeList[left_brother_ID].n_right_brother_id = current_ID;\
            }\
        }\
    }
int syntax_analyzer(FileField *fileField);
int initialize_IdTable();
int initialize_SynTree();
int release_IdTable();
int release_SynTree();
void report_syntax_error(char *func_name, char *detail, int line_number);
void report_memery_error(char *func_name, int line_number);
void report_internal_error(char *func_name, int line_number);
int add_to_IdTable(FileField * fileField, char *id_name, int length, short mode, unsigned int * p_ident_index);
int find_in_IdTable(FileField * fileField, char *id_name, int length, unsigned int * p_ident_index);
int get_number( FileField * fileField, int * pOutValue);
void debug_syntax( FILE* fp );

#endif


语义分析头文件:

 
 

/** scmpsem.h
====================================================================
This is the base head file for Semantic Analyze


====================================================================
 */
#ifndef SCMPSEM_H_INCLUDE
#define SCMPSEM_H_INCLUDE

#include "scmpstx.h"

#ifndef LINUX
/* For Windows only */
/* define the header of the MASM source file */
#define ASM_HEADER ".MODEL SMALL\n.STACK 4096h\nINCLUDE PrintVal.mac\n"
#define ASM_DATA_HEADER ".DATA\nASM_CHAGNE_LINE  DB  0DH,0AH,'$'\n"
/* the definition of varibale e.g. sprintf(buffer, MASM_VAR_DEF, "VAR1", "VAR1", "VAR1") */
#define ASM_VAR_DEF "%s  DW  0\nName_%s  DB '%s',20H,20H,'$'\n"
#define ASM_CODE_HEADER ".CODE\nCALL Main\n"
#define ASM_END_MAIN "END Main\n"
#define ASM_FILE_NAME "MyResult.asm"
#define ASM_CHANGE_LINE "LEA  AX, ASM_CHAGNE_LINE\nMOV  DX, AX\nMOV  AH, 9\nINT  21H\n"

#else
/* For Linux only */
#endif

#define MAX_STACK_NUM 32768               /* the max node number of sem_stack */
typedef struct tag_SEM_STACK_NODE{
    unsigned short n_mode;                /*====================================
                                          Type of the node
                                          0 ==> )
                                          1 ==> ||
                                          2 ==> &&
                                          3 ==> ==   !=
                                          4 ==> >   >=   <   <=
                                          5 ==> +  -
                                          6 ==> *  /
                                          7 ==> (
                                          0xffff ==> number
                                          =====================================*/
    short n_value;                        /*=====================================
                                          The value of the node,using definition
                                          in the scmpstx.h.
                                          e.g.
                                          SYN_NODE_NUMBER   24   numbers
                                          SYN_NODE_EQ       35   '=='
                                          =====================================*/
}SEM_STACK_NODE;
typedef struct tag_SEM_STACK{
    unsigned int n_num;
    SEM_STACK_NODE * sem_node_list;
}SEM_STACK;
typedef struct tag_SemEnv{
    unsigned int n_SignCurrentId;         /* the id of current sign */
    FILE * pAsmFile;                      /* the pointer to the output ASM file */
    SEM_STACK s_sem_stack;                /* the stack for semantic analyze */
}SemEnv;
SemEnv g_SemEnv;/* the semantic analyser environment */

int initialize_SemEnv();
int finalize_SemEnv();
int semantic_analyzer();
void debug_sem( );


#define CHECK_SYN_NODE_ID(id)  \
    if( INVALID_ID == (id) ){\
          printf("Internal Error ! Invalid syntax node id at line '%d'.\n", __LINE__);\
          return 0;\
    }
         

#endif


 


'; fputs(str_line_buffer, fpOutput); index = 0; return 1; }/** scmppre.c =========================



你的当前访问异常,请进行认证后继续阅读剩余内容。

分享到: