%{ /* ------------------------------------------------------------------ Initial code (copied verbatim to the output file) ------------------------------------------------------------------ */ #include // _alloca is used by the parser #include // strcpy #include #include #include "lex.h" // the lexer #include "SyntaxTree.h" #include "SymbolTable.h" #include "BaseDef.h" #include "Message.h" // Some yacc (bison) defines #define YYDEBUG 1 // Generate debug code; needed for YYERROR_VERBOSE #define YYERROR_VERBOSE // Give a more specific parse error message // Forward references void yyerror (char *msg); extern CSyntaxTree * g_pSynTree; extern CSymbolTable * g_pSymbolTable; SFuncType GetFunctionType( int nodeID ); SFuncType GetFunctionType( int nodeID1, int nodeID2 ); SFuncType GetFuncCallType( int nodeID ); int CountArrayElements( int nodeID ); int GetConstantValue( int nodeID ); %} /* ------------------------------------------------------------------ Yacc declarations ------------------------------------------------------------------ */ %union { int symbolID; // entry from symbol table int nodeID; // node in the syntax tree char szIdentifier[4096]; char szConstant[4096]; } %type variable new_variable %type program statement_list statement compound_statement expression_statement selection_statement %type cases case_one default iteration_statement for_expression for_init_statement optional_expression %type jump_statement declaration decl_specifiers declarator_list init_declarator %type array_initializer initializer_list argument_declaration_list argument_declaration function_definition %type constant_expression expression assignment_expression logical_or_expression logical_and_expression %type equality_expression relational_expression additive_expression multiplicative_expression unary_expression %type postfix_expression primary_expression %type function_name %type function_decl_end %token TOKEN_ID %token TOKEN_INTEGERVALUE TOKEN_FLOATVALUE TOKEN_BOOLVALUE TOKEN_STRINGVALUE %token TOKEN_INT TOKEN_FLOAT TOKEN_BOOL TOKEN_STRING TOKEN_VOID %token TOKEN_FOR TOKEN_WHILE TOKEN_IF TOKEN_ELSE TOKEN_SWITCH TOKEN_CASE %token TOKEN_DEFAULT TOKEN_CONTINUE TOKEN_BREAK TOKEN_RETURN %token TOKEN_ENDSTATEMENT TOKEN_LEFTPARENTHESIS TOKEN_RIGHTPARENTHESIS %token TOKEN_LEFTBRACE TOKEN_RIGHTBRACE TOKEN_LEFTBRACKET TOKEN_RIGHTBRACKET %token TOKEN_ERROR /*¹Ø¿¡ ÀÖÀ»¼ö·Ï ¿¬»êÀÚ ¿ì¼±¼øÀ§°¡ ³ôÀ½.*/ %left TOKEN_COMMA TOKEN_COLON %right TOKEN_ASSIGNMENT TOKEN_COMPOUNDADDITION TOKEN_COMPOUNDSUBTRACTION TOKEN_COMPOUNDMULTIPLICATION TOKEN_COMPOUNDDIVISION TOKEN_COMPOUNDREMINDER %left TOKEN_AND TOKEN_OR %left TOKEN_LESSTHAN TOKEN_LESSTHANOREQUAL TOKEN_MORETHAN TOKEN_MORETHANOREQUAL TOKEN_EQUALITY TOKEN_NOTEQUAL %left TOKEN_ADDITION TOKEN_SUBTRACTION %right TOKEN_MULTIPLICATION TOKEN_DIVISION TOKEN_REMINDER %right TOKEN_NOT %left PREFIXINCREMENT PREFIXDECREMENT /*Context-Dependent Precedence(°¡Â¥ ½Éº¼)*/ %left TOKEN_INCREMENT TOKEN_DECREMENT %right TOKEN_LEFTPARENTHESIS %left TOKEN_RIGHTPARENTHESIS %expect 1 /* shift/reduce conflict: dangling ELSE */ /* declaration */ %% /* ------------------------------------------------------------------ Yacc grammar rules ------------------------------------------------------------------ */ program : statement_list { assert( g_pSynTree != NULL ); g_pSynTree->SetRoot( $1 ); } ; statement_list : statement_list statement { $$ = g_pSynTree->Insert( @1.first_line, TYPE_STATEMENT_LIST, $1, $2 ); } | /* empty */ { $$ = g_pSynTree->Insert( @1.first_line, TYPE_EMPTY_STATEMENT ); } ; statement : compound_statement { $$ = $1; } | expression_statement { $$ = $1; } | selection_statement { $$ = $1; } | iteration_statement { $$ = $1; } | jump_statement { $$ = $1; } | error TOKEN_ENDSTATEMENT { $$ = g_pSynTree->Insert( @1.first_line, TYPE_ERROR_STATEMENT ); } | declaration { $$ = $1; } | function_definition { $$ = $1; } ; compound_statement : TOKEN_LEFTBRACKET statement_list TOKEN_RIGHTBRACKET { $$ = $2; } ; expression_statement : TOKEN_ENDSTATEMENT { $$ = g_pSynTree->Insert( @1.first_line, TYPE_EMPTY_STATEMENT ); } | expression TOKEN_ENDSTATEMENT { $$ = g_pSynTree->Insert( @1.first_line, TYPE_EXPRESSION, $1 ); } ; selection_statement : TOKEN_IF TOKEN_LEFTPARENTHESIS expression TOKEN_RIGHTPARENTHESIS statement { $$ = g_pSynTree->Insert( @1.first_line, TYPE_IF_STATEMENT, $3, $5 ); } | TOKEN_IF TOKEN_LEFTPARENTHESIS expression TOKEN_RIGHTPARENTHESIS statement TOKEN_ELSE statement { $$ = g_pSynTree->Insert( @1.first_line, TYPE_IF_ELSE_STATEMENT, $3, $5, $7 ); } | TOKEN_SWITCH TOKEN_LEFTPARENTHESIS expression TOKEN_RIGHTPARENTHESIS TOKEN_LEFTBRACKET cases default TOKEN_RIGHTBRACKET { $$ = g_pSynTree->Insert( @1.first_line, TYPE_SWITCH_STATEMENT, $3, $6, $7 ); } ; cases : case_one cases { $$ = g_pSynTree->Insert( @1.first_line, TYPE_SWITCH_CASES, $1, $2 ); } | case_one { $$ = $1; } ; case_one : TOKEN_CASE constant_expression TOKEN_COLON statement_list { $$ = g_pSynTree->Insert( @1.first_line, TYPE_CASE_ONE, $2, $4 ); } ; default : TOKEN_DEFAULT TOKEN_COLON statement_list { $$ = g_pSynTree->Insert( @1.first_line, TYPE_DEFAULT, $3 ); } | { $$ = 0; } ; iteration_statement : TOKEN_FOR TOKEN_LEFTPARENTHESIS for_expression TOKEN_RIGHTPARENTHESIS statement { $$ = g_pSynTree->Insert( @1.first_line, TYPE_FOR_STATEMENT, $3, $5 ); } | TOKEN_WHILE TOKEN_LEFTPARENTHESIS expression TOKEN_RIGHTPARENTHESIS statement { $$ = g_pSynTree->Insert( @1.first_line, TYPE_WHILE_STATEMENT, $3, $5 ); } ; for_expression : for_init_statement optional_expression TOKEN_ENDSTATEMENT optional_expression { $$ = g_pSynTree->Insert( @1.first_line, TYPE_FOR_EXPRESSION, $1, $2, $4 ); } ; for_init_statement : expression_statement { $$ = $1; } | declaration { $$ = $1; } ; optional_expression : expression { $$ = $1; } | { $$ = 0; } ; jump_statement : TOKEN_BREAK TOKEN_ENDSTATEMENT { $$ = g_pSynTree->Insert( @1.first_line, TYPE_BREAK_STATEMENT ); } | TOKEN_CONTINUE TOKEN_ENDSTATEMENT { $$ = g_pSynTree->Insert( @1.first_line, TYPE_CONTINUE_STATEMENT ); } | TOKEN_RETURN optional_expression TOKEN_ENDSTATEMENT { $$ = g_pSynTree->Insert( @1.first_line, TYPE_RETURN_STATEMENT, $2 ); } ; declaration : decl_specifiers declarator_list TOKEN_ENDSTATEMENT { $$ = g_pSynTree->Insert( @1.first_line, TYPE_DECLARATION, $1, $2 ); g_pSymbolTable->SetCurrentType( T_VOID ); } ; decl_specifiers : TOKEN_VOID { $$ = g_pSynTree->Insert( @1.first_line, TYPE_SPECIFIER_VOID ); } | TOKEN_INT { g_pSymbolTable->SetCurrentType( T_INT ); $$ = g_pSynTree->Insert( @1.first_line, TYPE_SPECIFIER_INT ); } | TOKEN_FLOAT { g_pSymbolTable->SetCurrentType( T_FLOAT ); $$ = g_pSynTree->Insert( @1.first_line, TYPE_SPECIFIER_FLOAT ); } | TOKEN_BOOL { g_pSymbolTable->SetCurrentType( T_BOOL ); $$ = g_pSynTree->Insert( @1.first_line, TYPE_SPECIFIER_BOOL ); } | TOKEN_STRING { g_pSymbolTable->SetCurrentType( T_STRING ); $$ = g_pSynTree->Insert( @1.first_line, TYPE_SPECIFIER_STRING ); } ; variable : TOKEN_ID { $$ = g_pSymbolTable->FindVar( $1 ); if( $$ == 0 ) ErrorMessage2( @1.first_line, "undefined symbol : %s", $1 ); } ; new_variable : TOKEN_ID { $$ = g_pSymbolTable->AddVar( $1 ); if( $$ == 0 ) ErrorMessage2( @1.first_line, "ÀÌ¹Ì Á¤ÀÇ µÇ¾î ÀÖ´Â ½Éº¼ÀÔ´Ï´Ù. : %s", $1 ); } ; declarator_list : init_declarator { $$ = $1; } | declarator_list TOKEN_COMMA init_declarator { $$ = g_pSynTree->Insert( @1.first_line, TYPE_DECLARATOR_LIST, $1, $3 ); } ; init_declarator : new_variable TOKEN_ASSIGNMENT assignment_expression { $$ = g_pSynTree->Insert( @1.first_line, $1, TYPE_INIT_DECLARATION, $3 ); } | new_variable { $$ = g_pSynTree->Insert( @1.first_line, $1, TYPE_NORMAL_DECLARATION ); } | TOKEN_ID TOKEN_LEFTBRACE TOKEN_RIGHTBRACE array_initializer { $$ = g_pSynTree->Insert( @1.first_line, g_pSymbolTable->AddArrVar( $1, CountArrayElements( $4 ) ), TYPE_ARRAY_INITIALIZE, $4 ); } | TOKEN_ID TOKEN_LEFTBRACE constant_expression TOKEN_RIGHTBRACE array_initializer { $$ = g_pSynTree->Insert( @1.first_line, g_pSymbolTable->AddArrVar( $1, GetConstantValue( $3 ) ), TYPE_ARRAY_INITIALIZE2, $3, $5 ); } | TOKEN_ID TOKEN_LEFTBRACE constant_expression TOKEN_RIGHTBRACE { $$ = g_pSynTree->Insert( @1.first_line, g_pSymbolTable->AddArrVar( $1, GetConstantValue( $3 ) ), TYPE_ARRAY_DECLARATION, $3 ); } ; array_initializer : TOKEN_ASSIGNMENT TOKEN_LEFTBRACKET initializer_list TOKEN_RIGHTBRACKET { $$ = $3; } ; initializer_list : assignment_expression { $$ = $1; } | assignment_expression TOKEN_COMMA initializer_list { $$ = g_pSynTree->Insert( @1.first_line, TYPE_INITIALIZER_LIST, $1, $3 ); } ; argument_declaration_list : argument_declaration { $$ = $1; } | argument_declaration TOKEN_COMMA argument_declaration_list { $$ = g_pSynTree->Insert( @1.first_line, TYPE_ARGUMENT_DECLARATION_LIST, $1, $3 ); } | { $$ = 0; } ; argument_declaration : decl_specifiers new_variable { $$ = g_pSynTree->Insert( @1.first_line, $2, TYPE_ARGUMENT_DECLARATION, $1 ); } | decl_specifiers { $$ = $1; } ; function_name : TOKEN_ID { strcpy( $$, $1 ); g_pSymbolTable->BeginLocalNameSpace(); } ; function_decl_end : TOKEN_ENDSTATEMENT { g_pSymbolTable->EndLocalNameSpace( 0 ); } ; function_def_start : TOKEN_LEFTBRACKET { g_pSymbolTable->EndArgument(); } ; function_definition : decl_specifiers function_name TOKEN_LEFTPARENTHESIS argument_declaration_list TOKEN_RIGHTPARENTHESIS function_def_start statement_list TOKEN_RIGHTBRACKET { int symbID = g_pSymbolTable->AddFunc( true, $2, GetFunctionType( $1, $4 ) ); if( symbID == 0 ) ErrorMessage( @1.first_line, "°°Àº ÇÔ¼ö¸¦ Áߺ¹ÇÏ¿© Á¤ÀÇÇß½À´Ï´Ù." ); $$ = g_pSynTree->Insert( @1.first_line, symbID, TYPE_FUNCTION_DEFINITION, $4, $7 ); g_pSymbolTable->SetCurrentType( T_VOID ); g_pSymbolTable->EndLocalNameSpace( symbID ); } | decl_specifiers function_name TOKEN_LEFTPARENTHESIS argument_declaration_list TOKEN_RIGHTPARENTHESIS function_decl_end { $$ = g_pSynTree->Insert( @1.first_line, g_pSymbolTable->AddFunc( false, $2, GetFunctionType( $1, $4 ) ), TYPE_FUNCTION_DECLARATION, $4 ); g_pSymbolTable->SetCurrentType( T_VOID ); } ; constant_expression : TOKEN_INTEGERVALUE { $$ = g_pSynTree->Insert( @1.first_line, g_pSymbolTable->AddConst( $1, T_INT ), TYPE_CONSTANT_EXPRESSION ); } | TOKEN_FLOATVALUE { $$ = g_pSynTree->Insert( @1.first_line, g_pSymbolTable->AddConst( $1, T_FLOAT ), TYPE_CONSTANT_EXPRESSION ); } | TOKEN_BOOLVALUE { $$ = g_pSynTree->Insert( @1.first_line, g_pSymbolTable->AddConst( $1, T_BOOL ), TYPE_CONSTANT_EXPRESSION ); } | TOKEN_STRINGVALUE { $$ = g_pSynTree->Insert( @1.first_line, g_pSymbolTable->AddConst( $1, T_STRING ), TYPE_CONSTANT_EXPRESSION ); } ; expression : assignment_expression { $$ = $1; } | assignment_expression TOKEN_COMMA expression { $$ = g_pSynTree->Insert( @1.first_line, TYPE_EXPRESSION_LIST, $1, $3 ); } ; assignment_expression : logical_or_expression { $$ = $1; } | variable TOKEN_ASSIGNMENT assignment_expression { $$ = g_pSynTree->Insert( @1.first_line, $1, TYPE_ASSIGNMENT_EXPRESSION, $3 ); } | variable TOKEN_COMPOUNDADDITION assignment_expression { $$ = g_pSynTree->Insert( @1.first_line, $1, TYPE_COMPOUND_ADDITION, $3 ); } | variable TOKEN_COMPOUNDSUBTRACTION assignment_expression { $$ = g_pSynTree->Insert( @1.first_line, $1, TYPE_COMPOUND_SUBTRACTION, $3 ); } | variable TOKEN_COMPOUNDMULTIPLICATION assignment_expression { $$ = g_pSynTree->Insert( @1.first_line, $1, TYPE_COMPOUND_MULTIPLICATION, $3 ); } | variable TOKEN_COMPOUNDDIVISION assignment_expression { $$ = g_pSynTree->Insert( @1.first_line, $1, TYPE_COMPOUND_DIVISION, $3 ); } | variable TOKEN_COMPOUNDREMINDER assignment_expression { $$ = g_pSynTree->Insert( @1.first_line, $1, TYPE_COMPOUND_REMINDER, $3 ); } ; logical_or_expression : logical_and_expression { $$ = $1; } | logical_or_expression TOKEN_OR logical_and_expression { $$ = g_pSynTree->Insert( @1.first_line, TYPE_OR_EXPRESSION, $1, $3 ); } ; logical_and_expression : equality_expression { $$ = $1; } | logical_and_expression TOKEN_AND equality_expression { $$ = g_pSynTree->Insert( @1.first_line, TYPE_AND_EXPRESSION, $1, $3 ); } ; equality_expression : relational_expression { $$ = $1; } | equality_expression TOKEN_EQUALITY relational_expression { $$ = g_pSynTree->Insert( @1.first_line, TYPE_EQUALITY_EXPRESSION, $1, $3 ); } | equality_expression TOKEN_NOTEQUAL relational_expression { $$ = g_pSynTree->Insert( @1.first_line, TYPE_NOTEQAUL_EXPRESSION, $1, $3 ); } ; relational_expression : additive_expression { $$ = $1; } | relational_expression TOKEN_LESSTHAN additive_expression { $$ = g_pSynTree->Insert( @1.first_line, TYPE_LESSTHAN_EXPRESSION, $1, $3 ); } | relational_expression TOKEN_MORETHAN additive_expression { $$ = g_pSynTree->Insert( @1.first_line, TYPE_MORETHAN_EXPRESSION, $1, $3 ); } | relational_expression TOKEN_LESSTHANOREQUAL additive_expression { $$ = g_pSynTree->Insert( @1.first_line, TYPE_LESSTHANOREQUAL_EXPRESSION, $1, $3 ); } | relational_expression TOKEN_MORETHANOREQUAL additive_expression { $$ = g_pSynTree->Insert( @1.first_line, TYPE_MORETHANOREQUAL_EXPRESSION, $1, $3 ); } ; additive_expression : multiplicative_expression { $$ = $1; } | additive_expression TOKEN_ADDITION multiplicative_expression { $$ = g_pSynTree->Insert( @1.first_line, TYPE_ADDITION_EXPRESSION, $1, $3 ); } | additive_expression TOKEN_SUBTRACTION multiplicative_expression { $$ = g_pSynTree->Insert( @1.first_line, TYPE_SUBTRACTION_EXPRESSION, $1, $3 ); } ; multiplicative_expression : unary_expression { $$ = $1; } | multiplicative_expression TOKEN_MULTIPLICATION unary_expression { $$ = g_pSynTree->Insert( @1.first_line, TYPE_MULTIPLICATION_EXPRESSION, $1, $3 ); } | multiplicative_expression TOKEN_DIVISION unary_expression { $$ = g_pSynTree->Insert( @1.first_line, TYPE_DIVISION_EXPRESSION, $1, $3 ); } | multiplicative_expression TOKEN_REMINDER unary_expression { $$ = g_pSynTree->Insert( @1.first_line, TYPE_REMINDER_EXPRESSION, $1, $3 ); } ; unary_expression : postfix_expression { $$ = $1; } | TOKEN_INCREMENT variable %prec PREFIXINCREMENT { $$ = g_pSynTree->Insert( @1.first_line, $2, TYPE_PREFIXINCREMENT ); } | TOKEN_DECREMENT variable %prec PREFIXDECREMENT { $$ = g_pSynTree->Insert( @1.first_line, $2, TYPE_PREFIXDECREMENT ); } | TOKEN_NOT unary_expression { $$ = g_pSynTree->Insert( @1.first_line, TYPE_NOT_EXPRESSION, $2 ); } ; postfix_expression : primary_expression { $$ = $1; } | variable TOKEN_LEFTBRACE expression TOKEN_RIGHTBRACE { $$ = g_pSynTree->Insert( @1.first_line, $1, TYPE_ARRAY_INDEXING, $3 ); } | TOKEN_ID TOKEN_LEFTPARENTHESIS expression TOKEN_RIGHTPARENTHESIS { int symbolID = g_pSymbolTable->FindFunc( $1, GetFuncCallType( $3 ) ); if( symbolID == 0 ) ErrorMessage2( "Error(line %d) : ÁöÁ¤ÇÑ ÇÔ¼ö¸¦ ãÀ» ¼ö ¾ø½À´Ï´Ù.\n", @1.first_line ); $$ = g_pSynTree->Insert( @1.first_line, symbolID, TYPE_FUNCTION_CALL, $3 ); } | TOKEN_ID TOKEN_LEFTPARENTHESIS TOKEN_RIGHTPARENTHESIS { int symbolID = g_pSymbolTable->FindFunc( $1, 0 ); if( symbolID == 0 ) ErrorMessage2( "Error(line %d) : ÁöÁ¤ÇÑ ÇÔ¼ö¸¦ ãÀ» ¼ö ¾ø½À´Ï´Ù.\n", @1.first_line ); $$ = g_pSynTree->Insert( @1.first_line, symbolID, TYPE_FUNCTION_CALL ); } | variable TOKEN_INCREMENT { $$ = g_pSynTree->Insert( @1.first_line, $1, TYPE_POSTFIXINCREMENT ); } | variable TOKEN_DECREMENT { $$ = g_pSynTree->Insert( @1.first_line, $1, TYPE_POSTFIXDECREMENT ); } ; primary_expression : constant_expression { $$ = $1; } | TOKEN_LEFTPARENTHESIS expression TOKEN_RIGHTPARENTHESIS { $$ = g_pSynTree->Insert( @1.first_line, TYPE_EXPRESSION, $2 ); } | variable { $$ = g_pSynTree->Insert( @1.first_line, $1, TYPE_VARIABLE ); } ; %% /* ------------------------------------------------------------------ Additional code (again copied verbatim to the output file) ------------------------------------------------------------------ */ eDataType GetType( SNode * pNode ) { switch( pNode->m_eType ) { case TYPE_ARGUMENT_DECLARATION : return GetType( pNode->m_ArrPtrChilds[0] ); case TYPE_SPECIFIER_INT : return T_INT; case TYPE_SPECIFIER_FLOAT : return T_FLOAT; case TYPE_SPECIFIER_BOOL : return T_BOOL; case TYPE_SPECIFIER_STRING : return T_STRING; } return T_VOID; } SFuncType GetFunctionType( eDataType retType, int nodeID ) { SNode * pNode = (SNode*)nodeID; SFuncType FuncType; int i = 0; while( pNode != NULL ) { if( pNode->m_eType == TYPE_ARGUMENT_DECLARATION_LIST ) { FuncType.SetArgType( i++, GetType( pNode->m_ArrPtrChilds[0] ) ); pNode = pNode->m_ArrPtrChilds[1]; } else //TYPE_ARGUMENT_DECLARATION³ª TYPE_SPECIFIER_XXX °è¿­ÀÏ ¶§ { FuncType.SetArgType( i++, GetType( pNode ) ); break; } } assert( i <= 36 ); FuncType.SetReturnType( retType ); return FuncType; } SFuncType GetFunctionType( int nodeID ) { return GetFunctionType( g_pSymbolTable->GetCurrentType(), nodeID ); } SFuncType GetFunctionType( int nodeID1, int nodeID2 ) { SNode * pNode = (SNode*)nodeID1; if( pNode != NULL ) { return GetFunctionType( GetType( pNode ), nodeID2 ); } return 0; } SFuncType GetFuncCallType( int nodeID ) { SNode * pNode = (SNode*)nodeID; SFuncType FuncType; int i = 0; while( pNode != NULL ) { if( pNode->m_eType == TYPE_EXPRESSION_LIST ) { FuncType.SetArgType( i++, pNode->m_ArrPtrChilds[0]->m_eReturnType ); pNode = pNode->m_ArrPtrChilds[1]; } else { FuncType.SetArgType( i++, pNode->m_eReturnType ); break; } } assert( i <= 36 ); FuncType.SetReturnType( T_VOID ); return FuncType; } int CountArrayElements( int nodeID ) { if( nodeID == 0 ) return 0; SNode * pNode = (SNode*)nodeID; //initializer_list int i = 0; while( pNode != NULL ) { if( pNode->m_eType == TYPE_INITIALIZER_LIST ) { i++; pNode = pNode->m_ArrPtrChilds[1]; } else { i++; break; } } return i; } int GetConstantValue( int nodeID ) { //constant expression SNode * pNode = (SNode*)nodeID; if( pNode->m_eType == TYPE_CONSTANT_EXPRESSION ) { if( g_pSymbolTable->GetTypeOfConst( pNode->m_SymbolID ) == T_INT ) { const char * pStr = g_pSymbolTable->GetNameOfConst( pNode->m_SymbolID ); return strtol( pStr, NULL, 0 ); } } return 0; }