void CParser::subroutineDecl(CAstScope *s) { // // subroutineDecl ::= (procedureDecl | functionDecl) subroutineBody ident ";". // procedureDecl ::= "procedure" ident [ formalParam ] ";". // functionDecl ::= "function" ident [ formalParam ] ":" type ";". // formalParam ::= "(" [ varDeclSequence ] ")". // subroutineBody ::= varDeclaration "begin" statSequence "end". // varDeclSequence ::= varDecl { ";" varDecl }. // varDecl ::= ident { "," ident } ":" type. // CToken subroutine_name; CToken subroutine_name_check; CTypeManager *tm = CTypeManager::Get(); // procedureDecl if(_scanner->Peek().GetType() == tProcedure) { CToken t; CAstStatement *statseq = NULL; Consume(tProcedure); Consume(tIdent, &subroutine_name); // Check duplicate procedure declaration. if(dynamic_cast<CAstModule *>(s)) { if(s->GetSymbolTable()->FindSymbol(subroutine_name.GetValue(), sGlobal) != NULL) SetError(subroutine_name, "duplicate procedure/function declaration '" + subroutine_name.GetValue() + "'."); } else { if(s->GetSymbolTable()->FindSymbol(subroutine_name.GetValue(), sLocal) != NULL) SetError(subroutine_name, "duplicate procedure/function declaration '" + subroutine_name.GetValue() + "'."); } CSymProc *symproc = new CSymProc(subroutine_name.GetValue(), tm->GetNull()); CAstProcedure *procedure = new CAstProcedure(subroutine_name, subroutine_name.GetValue(), s, symproc); // formalParam if(_scanner->Peek().GetType() == tLBrak) { Consume(tLBrak); if(_scanner->Peek().GetType() == tIdent) { varDeclParam(procedure, symproc, 0); while(1) { if(_scanner->Peek().GetType() == tSemicolon) { Consume(tSemicolon); varDeclParam(procedure, symproc, symproc->GetNParams()); } else break; } } Consume(tRBrak); } s->GetSymbolTable()->AddSymbol(symproc); Consume(tSemicolon); // subroutineBody from here. // subroutineBody ::= varDeclaration "begin" statSequence "end". // varDeclaration if(_scanner->Peek().GetType() == tVar) { Consume(tVar); varDecl(procedure); Consume(tSemicolon); while(1) { if(_scanner->Peek().GetType() == tIdent) { varDecl(procedure); Consume(tSemicolon); } else break; } } Consume(tBegin); // statSequence statseq = statSequence(procedure); procedure->SetStatementSequence(statseq); Consume(tEnd); Consume(tIdent, &subroutine_name_check); // Check procedure names are equal. if(subroutine_name.GetValue() != subroutine_name_check.GetValue()) { SetError(subroutine_name_check, "procedure/function identifier mismatch ('" + subroutine_name.GetValue() + "' != '" + subroutine_name_check.GetValue() + "')."); } Consume(tSemicolon); } // functionDecl else { CToken tmp; // Parameters are pushed into params. Then they will be added into symproc later. vector<CSymParam *> params; const CType *func_type; CAstStatement *statseq = NULL; Consume(tFunction); Consume(tIdent, &subroutine_name); // Check duplicate function declaration. if(dynamic_cast<CAstModule *>(s)) { if(s->GetSymbolTable()->FindSymbol(subroutine_name.GetValue(), sGlobal) != NULL) SetError(subroutine_name, "duplicate procedure/function declaration '" + subroutine_name.GetValue() + "'."); } else { if(s->GetSymbolTable()->FindSymbol(subroutine_name.GetValue(), sLocal) != NULL) SetError(subroutine_name, "duplicate procedure/function declaration '" + subroutine_name.GetValue() + "'."); } // formalParam if(_scanner->Peek().GetType() == tLBrak) { int idx = 0; CToken t; vector<string> vars; const CType *var_type; Consume(tLBrak); // Get parameters. if(_scanner->Peek().GetType() == tIdent) { Consume(tIdent, &t); vars.push_back(t.GetValue()); while(_scanner->Peek().GetType() == tComma) { Consume(tComma); Consume(tIdent, &t); // Check duplicate parameter declaration. for(int i = 0; i < vars.size(); i++) { if(vars[i] == t.GetValue()) { SetError(t, "duplicate variable declaration '" + t.GetValue() + "'."); break; } } vars.push_back(t.GetValue()); } Consume(tColon); var_type = type(true); for(int i = vars.size() - 1; i >= 0; i--) { CSymParam *param = new CSymParam(i, vars[i], var_type); params.push_back(param); idx++; } // for multiple parameter declaration. while(1) { if(_scanner->Peek().GetType() == tSemicolon) { Consume(tSemicolon); CToken t_loop; vector<string> vars_loop; const CType *var_type_loop; Consume(tIdent, &t_loop); // Check duplicate parameter declaration. for(int i = 0; i < params.size(); i++) { if(params[i]->GetName() == t_loop.GetValue()) { SetError(t_loop, "duplicate variable declaration '" + t_loop.GetValue() + "'."); break; } } vars_loop.push_back(t_loop.GetValue()); while(_scanner->Peek().GetType() == tComma) { Consume(tComma); Consume(tIdent, &t_loop); for(int i = 0; i < params.size(); i++) { if(params[i]->GetName() == t_loop.GetValue()) { SetError(t_loop, "duplicate variable declaration '" + t_loop.GetValue() + "'."); break; } } // Check duplicate parameter declaration. for(int i = 0; i < vars_loop.size(); i++) { if(vars_loop[i] == t_loop.GetValue()) { SetError(t_loop, "duplicate variable declaration '" + t_loop.GetValue() + "'."); break; } } vars_loop.push_back(t_loop.GetValue()); } Consume(tColon); var_type_loop = type(true); int tmp_idx = idx; // Add parameters into vector 'params'. for(int i = vars_loop.size() - 1; i >= 0; i--) { CSymParam *param_loop = new CSymParam(i+tmp_idx, vars_loop[i], var_type_loop); params.push_back(param_loop); vars_loop.pop_back(); idx++; } } else break; } } Consume(tRBrak); } Consume(tColon); func_type = type(false, true); Consume(tSemicolon); CSymProc *symproc = new CSymProc(subroutine_name.GetValue(), func_type); CAstProcedure *function = new CAstProcedure(subroutine_name, subroutine_name.GetValue(), s, symproc); assert(symproc != NULL); // Add parameters into symproc. for(int i = 0; i < params.size(); i++) { CSymParam *param = params[i]; symproc->AddParam(param); function->GetSymbolTable()->AddSymbol(param); } while(!params.empty()) params.pop_back(); s->GetSymbolTable()->AddSymbol(symproc); // subroutineBody from here. // subroutineBody ::= varDeclaration "begin" statSequence "end". // varDeclaration if(_scanner->Peek().GetType() == tVar) { Consume(tVar); varDecl(function); Consume(tSemicolon); while(1) { if(_scanner->Peek().GetType() == tIdent) { varDecl(function); Consume(tSemicolon); } else break; } } Consume(tBegin); // statSequence statseq = statSequence(function); function->SetStatementSequence(statseq); Consume(tEnd); Consume(tIdent, &subroutine_name_check); // Check function names are equal. if(subroutine_name.GetValue() != subroutine_name_check.GetValue()) { SetError(subroutine_name_check, "procedure/function identifier mismatch ('" + subroutine_name.GetValue() + "' != '" + subroutine_name_check.GetValue() + "')."); } Consume(tSemicolon); } }