/** 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
=========================