CBotInstr* CBotFor::Compile(CBotToken* &p, CBotCStack* pStack) { CBotFor* inst = new CBotFor(); // creates the object CBotToken* pp = p; // preserves at the ^ token (starting position) if ( IsOfType( p, TokenTypVar ) && IsOfType( p, ID_DOTS ) ) { inst->m_label = pp->GetString(); // register the name of label } inst->SetToken(p); if (!IsOfType(p, ID_FOR)) return nullptr; // should never happen if ( !IsOfType(p, ID_OPENPAR)) // missing parenthesis ? { pStack->SetError(TX_OPENPAR, p->GetStart()); return nullptr; } CBotCStack* pStk = pStack->TokenStack(pp, true); // un petit bout de pile svp // compiles instructions for initialization inst->m_Init = CBotListExpression::Compile( p, pStk ); if ( pStk->IsOk() ) { if ( !IsOfType(p, ID_SEP)) // lack the semicolon? { pStack->SetError(TX_OPENPAR, p->GetStart()); delete inst; return pStack->Return(nullptr, pStk); // no object, the error is on the stack } inst->m_Test = CBotBoolExpr::Compile( p, pStk ); if ( pStk->IsOk() ) { if ( !IsOfType(p, ID_SEP)) // lack the semicolon? { pStack->SetError(TX_OPENPAR, p->GetStart()); delete inst; return pStack->Return(nullptr, pStk); // no object, the error is on the stack } inst->m_Incr = CBotListExpression::Compile( p, pStk ); if ( pStk->IsOk() ) { if ( IsOfType(p, ID_CLOSEPAR)) // missing parenthesis ? { IncLvl(inst->m_label); inst->m_Block = CBotBlock::CompileBlkOrInst( p, pStk, true ); DecLvl(); if ( pStk->IsOk() ) return pStack->Return(inst, pStk);; } pStack->SetError(TX_CLOSEPAR, p->GetStart()); } } } delete inst; // error, frees up return pStack->Return(nullptr, pStk); // no object, the error is on the stack }
CBotInstr* CBotTry::Compile(CBotToken* &p, CBotCStack* pStack) { CBotTry* inst = new CBotTry(); // creates the object CBotToken* pp = p; // preserves at the ^ token (starting position) inst->SetToken(p); if (!IsOfType(p, ID_TRY)) return nullptr; // should never happen CBotCStack* pStk = pStack->TokenStack(pp); // un petit bout de pile svp inst->m_Block = CBotBlock::CompileBlkOrInst( p, pStk ); CBotCatch** pn = &inst->m_ListCatch; while (pStk->IsOk() && p->GetType() == ID_CATCH) { CBotCatch* i = CBotCatch::Compile(p, pStk); *pn = i; pn = &i->m_next; } if (pStk->IsOk() && IsOfType( p, ID_FINALLY) ) { inst->m_FinalInst = CBotBlock::CompileBlkOrInst( p, pStk ); } if (pStk->IsOk()) { return pStack->Return(inst, pStk); // return an object to the application } delete inst; // error, frees up return pStack->Return(nullptr, pStk); // no object, the error is on the stack }
CBotInstr* CBotListInstr::Compile(CBotToken* &p, CBotCStack* pStack, bool bLocal) { CBotCStack* pStk = pStack->TokenStack(p, bLocal); // variables are local CBotListInstr* inst = new CBotListInstr(); while (true) { if (p == nullptr) break; if (IsOfType(p, ID_SEP)) continue; // empty statement ignored if (p->GetType() == ID_CLBLK) break; if (p->GetType() == TokenTypNone) { pStack->SetError(CBotErrCloseBlock, p->GetStart()); delete inst; return pStack->Return(nullptr, pStk); } CBotInstr* i = CBotBlock::CompileBlkOrInst(p, pStk); // compiles next if (!pStk->IsOk()) { delete inst; return pStack->Return(nullptr, pStk); } if (inst->m_instr == nullptr) inst->m_instr = i; else inst->m_instr->AddNext(i); // added a result } return pStack->Return(inst, pStk); }
CBotInstr* CBotIf::Compile(CBotToken* &p, CBotCStack* pStack) { CBotToken* pp = p; // conserve le ^au token (début instruction) if (!IsOfType(p, ID_IF)) return NULL; // ne doit jamais arriver CBotCStack* pStk = pStack->TokenStack(pp); // un petit bout de pile svp CBotIf* inst = new CBotIf(); // crée l'object inst->SetToken( pp ); if ( NULL != (inst->m_Condition = CBotCondition::Compile( p, pStk )) ) { // la condition existe bel et bien inst->m_Block = CBotBlock::CompileBlkOrInst( p, pStk, TRUE ); if ( pStk->IsOk() ) { // le bloc d'instruction est ok (peut être vide) // regarde si l'instruction suivante est le token "else" if (IsOfType(p, ID_ELSE)) { // si oui, compile le bloc d'instruction qui suit inst->m_BlockElse = CBotBlock::CompileBlkOrInst( p, pStk, TRUE ); if (!pStk->IsOk()) { // il n'y a pas de bloc correct après le else // libère l'objet, et transmet l'erreur qui est sur la pile delete inst; return pStack->Return(NULL, pStk); } } // rend l'object correct à qui le demande. return pStack->Return(inst, pStk); } } // erreur, libère l'objet delete inst; // et transmet l'erreur qui se trouve sur la pile. return pStack->Return(NULL, pStk); }
CBotInstr* CBotIf::Compile(CBotToken* &p, CBotCStack* pStack) { CBotToken* pp = p; // preserves at the ^ token (starting instruction) if (!IsOfType(p, ID_IF)) return nullptr; // should never happen CBotCStack* pStk = pStack->TokenStack(pp); // un petit bout de pile svp CBotIf* inst = new CBotIf(); // create the object inst->SetToken( pp ); if ( nullptr != (inst->m_condition = CBotCondition::Compile(p, pStk )) ) { // the condition does exist inst->m_block = CBotBlock::CompileBlkOrInst(p, pStk, true ); if ( pStk->IsOk() ) { // the statement block is ok (can be empty) // see if the next instruction is the token "else" if (IsOfType(p, ID_ELSE)) { // if so, compiles the following statement block inst->m_blockElse = CBotBlock::CompileBlkOrInst(p, pStk, true ); if (!pStk->IsOk()) { // there is no correct block after the else // frees the object, and transmits the error that is on the stack delete inst; return pStack->Return(nullptr, pStk); } } // return the corrent object to the application return pStack->Return(inst, pStk); } } // error, frees the object delete inst; // and transmits the error that is on the stack. return pStack->Return(nullptr, pStk); }
CBotInstr* CompileParams(CBotToken* &p, CBotCStack* pStack, CBotVar** ppVars) { bool first = true; CBotInstr* ret = nullptr; // to return to the list CBotCStack* pile = pStack; int i = 0; if (IsOfType(p, ID_OPENPAR)) { int start, end; if (!IsOfType(p, ID_CLOSEPAR)) while (true) { start = p->GetStart(); pile = pile->TokenStack(); // keeps the result on the stack if (first) pStack->SetStartError(start); first = false; CBotInstr* param = CBotExpression::Compile(p, pile); end = p->GetStart(); if (!pile->IsOk()) { return pStack->Return(nullptr, pile); } if (ret == nullptr) ret = param; else ret->AddNext(param); // construct the list if (param != nullptr) { if (pile->GetTypResult().Eq(99)) { delete pStack->TokenStack(); pStack->SetError(CBotErrVoid, p->GetStart()); return nullptr; } ppVars[i] = pile->GetVar(); ppVars[i]->GetToken()->SetPos(start, end); i++; if (IsOfType(p, ID_COMMA)) continue; // skips the comma if (IsOfType(p, ID_CLOSEPAR)) break; } pStack->SetError(CBotErrClosePar, p->GetStart()); delete pStack->TokenStack(); return nullptr; } } ppVars[i] = nullptr; return ret; }
CBotInstr* CBotDo::Compile(CBotToken* &p, CBotCStack* pStack) { CBotDo* inst = new CBotDo(); // creates the object CBotToken* pp = p; // preserves at the ^ token (starting position) if ( IsOfType( p, TokenTypVar ) && IsOfType( p, ID_DOTS ) ) { inst->m_label = pp->GetString(); // register the name of label } inst->SetToken(p); if (!IsOfType(p, ID_DO)) return nullptr; // should never happen CBotCStack* pStk = pStack->TokenStack(pp); // un petit bout de pile svp // looking for a statement block after the do IncLvl(inst->m_label); inst->m_Block = CBotBlock::CompileBlkOrInst( p, pStk, true ); DecLvl(); if ( pStk->IsOk() ) { if (IsOfType(p, ID_WHILE)) { if ( nullptr != (inst->m_Condition = CBotCondition::Compile( p, pStk )) ) { // the condition exists if (IsOfType(p, ID_SEP)) { return pStack->Return(inst, pStk); // return an object to the application } pStk->SetError(TX_ENDOF, p->GetStart()); } } pStk->SetError(TX_WHILE, p->GetStart()); } delete inst; // error, frees up return pStack->Return(nullptr, pStk); // no object, the error is on the stack }
CBotInstr* CBotWhile::Compile(CBotToken* &p, CBotCStack* pStack) { CBotWhile* inst = new CBotWhile(); // creates the object CBotToken* pp = p; // preserves at the ^ token (starting position) if ( IsOfType( p, TokenTypVar ) && IsOfType( p, ID_DOTS ) ) { inst->m_label = pp->GetString(); // records the name of the label } inst->SetToken(p); if (!IsOfType(p, ID_WHILE)) return nullptr; // should never happen CBotCStack* pStk = pStack->TokenStack(pp); // un petit bout de pile svp // a bit of battery please (??) if ( nullptr != (inst->m_condition = CBotCondition::Compile(p, pStk )) ) { // the condition exists IncLvl(inst->m_label); inst->m_block = CBotBlock::CompileBlkOrInst(p, pStk, true ); DecLvl(); if ( pStk->IsOk() ) { // the statement block is ok (it may be empty! return pStack->Return(inst, pStk); // return an object to the application // makes the object to which the application } } delete inst; // error, frees the place return pStack->Return(nullptr, pStk); // no object, the error is on the stack }
CBotInstr* CBotInstrCall::Compile(CBotToken* &p, CBotCStack* pStack) { CBotVar* ppVars[1000]; int i = 0; CBotToken* pp = p; p = p->GetNext(); pStack->SetStartError(p->GetStart()); CBotCStack* pile = pStack; if ( IsOfType(p, ID_OPENPAR) ) { int start, end; CBotInstrCall* inst = new CBotInstrCall(); inst->SetToken(pp); // compile la list of parameters if (!IsOfType(p, ID_CLOSEPAR)) while (true) { start = p->GetStart(); pile = pile->TokenStack(); // keeps the results on the stack CBotInstr* param = CBotExpression::Compile(p, pile); end = p->GetStart(); if ( inst->m_Parameters == NULL ) inst->m_Parameters = param; else inst->m_Parameters->AddNext(param); // constructs the list if ( !pile->IsOk() ) { delete inst; return pStack->Return(NULL, pile); } if ( param != NULL ) { if ( pile->GetTypResult().Eq(99) ) { delete pStack->TokenStack(); pStack->SetError(TX_VOID, p->GetStart()); delete inst; return NULL; } ppVars[i] = pile->GetVar(); ppVars[i]->GetToken()->SetPos(start, end); i++; if (IsOfType(p, ID_COMMA)) continue; // skips the comma if (IsOfType(p, ID_CLOSEPAR)) break; } pStack->SetError(TX_CLOSEPAR, p->GetStart()); delete pStack->TokenStack(); delete inst; return NULL; } ppVars[i] = NULL; // the routine is known? // CBotClass* pClass = NULL; inst->m_typRes = pStack->CompileCall(pp, ppVars, inst->m_nFuncIdent); if ( inst->m_typRes.GetType() >= 20 ) { // if (pVar2!=NULL) pp = pVar2->RetToken(); pStack->SetError( inst->m_typRes.GetType(), pp ); delete pStack->TokenStack(); delete inst; return NULL; } delete pStack->TokenStack(); if ( inst->m_typRes.GetType() > 0 ) { CBotVar* pRes = CBotVar::Create("", inst->m_typRes); pStack->SetVar(pRes); // for knowing the type of the result } else pStack->SetVar(NULL); // routine returns void return inst; } p = pp; delete pStack->TokenStack(); return NULL; }
// pre-compile a new function CBotFunction* CBotFunction::Compile1(CBotToken* &p, CBotCStack* pStack, CBotClass* pClass) { CBotFunction* func = new CBotFunction(); func->m_nFuncIdent = CBotVar::NextUniqNum(); CBotCStack* pStk = pStack->TokenStack(p, true); while (true) { if ( IsOfType(p, ID_PUBLIC) ) { // func->m_bPublic = true; // will be done in two passes continue; } if ( IsOfType(p, ID_EXTERN) ) { func->m_bExtern = true; continue; } break; } func->m_retToken = *p; func->m_retTyp = TypeParam(p, pStack); // type of the result if (func->m_retTyp.GetType() >= 0) { CBotToken* pp = p; func->m_token = *p; // un nom de fonction est-il là ? if (IsOfType(p, TokenTypVar)) { if ( IsOfType( p, ID_DBLDOTS ) ) // method for a class { func->m_MasterClass = pp->GetString(); CBotClass* pClass = CBotClass::Find(pp); if ( pClass == NULL ) { pStk->SetError(TX_NOCLASS, pp); goto bad; } pp = p; func->m_token = *p; if (!IsOfType(p, TokenTypVar)) goto bad; } func->m_Param = CBotDefParam::Compile( p, pStk ); if (pStk->IsOk()) { // looks if the function exists elsewhere if (( pClass != NULL || !pStack->CheckCall(pp, func->m_Param)) && ( pClass == NULL || !pClass->CheckCall(pp, func->m_Param)) ) { if (IsOfType(p, ID_OPBLK)) { int level = 1; // and skips the following instruction block do { int type = p->GetType(); p = p->GetNext(); if (type == ID_OPBLK) level++; if (type == ID_CLBLK) level--; } while (level > 0 && p != NULL); return pStack->ReturnFunc(func, pStk); } pStk->SetError(TX_OPENBLK, p); } } pStk->SetError(TX_REDEF, pp); } bad: pStk->SetError(TX_NOFONC, p); } pStk->SetError(TX_NOTYP, p); delete func; return pStack->ReturnFunc(NULL, pStk); }
CBotInstr* CBotNew::Compile(CBotToken* &p, CBotCStack* pStack) { CBotToken* pp = p; if (!IsOfType(p, ID_NEW)) return nullptr; // verifies that the token is a class name if (p->GetType() != TokenTypVar) { pStack->SetError(CBotErrBadNew, p); return nullptr; } CBotClass* pClass = CBotClass::Find(p); if (pClass == nullptr) { pStack->SetError(CBotErrBadNew, p); return nullptr; } CBotNew* inst = new CBotNew(); inst->SetToken(pp); inst->m_vartoken = *p; p = p->GetNext(); // creates the object on the stack // with a pointer to the object CBotVar* pVar = CBotVar::Create("", pClass); // do the call of the creator CBotCStack* pStk = pStack->TokenStack(); { // check if there are parameters CBotVar* ppVars[1000]; inst->m_parameters = CompileParams(p, pStk, ppVars); if (!pStk->IsOk()) goto error; // constructor exist? CBotTypResult r = pClass->CompileMethode(pClass->GetName(), pVar, ppVars, pStk, inst->m_nMethodeIdent); delete pStk->TokenStack(); // release extra stack int typ = r.GetType(); // if there is no constructor, and no parameters either, it's ok if (typ == CBotErrUndefCall && inst->m_parameters == nullptr) typ = 0; pVar->SetInit(CBotVar::InitType::DEF); // mark the instance as init if (typ>20) { pStk->SetError(static_cast<CBotError>(typ), inst->m_vartoken.GetEnd()); goto error; } // if the constructor does not exist, but there are parameters if (typ<0 && inst->m_parameters != nullptr) { pStk->SetError(CBotErrNoConstruct, &inst->m_vartoken); goto error; } // makes pointer to the object on the stack pStk->SetVar(pVar); pp = p; // chained method ? if (nullptr != (inst->m_exprRetVar = CBotExprRetVar::Compile(p, pStk, true))) { inst->m_exprRetVar->SetToken(pp); delete pStk->TokenStack(); } if (pStack->IsOk()) return pStack->Return(inst, pStk); } error: delete inst; return pStack->Return(nullptr, pStk); }
CBotInstr* CBotListArray::Compile(CBotToken* &p, CBotCStack* pStack, CBotTypResult type) { CBotCStack* pStk = pStack->TokenStack(p); CBotToken* pp = p; if (IsOfType( p, ID_NULL ) || (IsOfType(p, ID_OPBLK) && IsOfType(p, ID_CLBLK))) { CBotInstr* inst = new CBotExprLitNull(); inst->SetToken(pp); return pStack->Return(inst, pStk); // ok with empty element } p = pp; CBotListArray* inst = new CBotListArray(); if (IsOfType( p, ID_OPBLK )) { // each element takes the one after the other if (type.Eq( CBotTypArrayPointer )) { pStk->SetStartError(p->GetStart()); if (nullptr == ( inst->m_expr = CBotListArray::Compile( p, pStk, type.GetTypElem() ) )) { if (pStk->IsOk()) { inst->m_expr = CBotTwoOpExpr::Compile(p, pStk); if (inst->m_expr == nullptr || !pStk->GetTypResult().Compare(type)) // compatible type ? { pStk->SetError(CBotErrBadType1, p->GetStart()); goto error; } } } while (IsOfType( p, ID_COMMA )) // other elements? { pStk->SetStartError(p->GetStart()); CBotInstr* i = nullptr; if (nullptr == ( i = CBotListArray::Compile(p, pStk, type.GetTypElem() ) )) { if (pStk->IsOk()) { i = CBotTwoOpExpr::Compile(p, pStk); if (i == nullptr || !pStk->GetTypResult().Compare(type)) // compatible type ? { pStk->SetError(CBotErrBadType1, p->GetStart()); goto error; } } } inst->m_expr->AddNext3b(i); if ( p->GetType() == ID_COMMA ) continue; if ( p->GetType() == ID_CLBLK ) break; pStk->SetError(CBotErrClosePar, p); goto error; } } else { pStk->SetStartError(p->GetStart()); if (nullptr == ( inst->m_expr = CBotTwoOpExpr::Compile( p, pStk ))) { goto error; } CBotTypResult valType = pStk->GetTypResult(CBotVar::GetTypeMode::CLASS_AS_INTRINSIC); if (!TypeCompatible(valType, type, ID_ASS) ) { pStk->SetError(CBotErrBadType1, p->GetStart()); goto error; } while (IsOfType( p, ID_COMMA )) // other elements? { pStk->SetStartError(p->GetStart()); CBotInstr* i = CBotTwoOpExpr::Compile(p, pStk) ; if (nullptr == i) { goto error; } CBotTypResult valType = pStk->GetTypResult(CBotVar::GetTypeMode::CLASS_AS_INTRINSIC); if (!TypeCompatible(valType, type, ID_ASS) ) { pStk->SetError(CBotErrBadType1, p->GetStart()); goto error; } inst->m_expr->AddNext3b(i); if (p->GetType() == ID_COMMA) continue; if (p->GetType() == ID_CLBLK) break; pStk->SetError(CBotErrClosePar, p); goto error; } } if (!IsOfType(p, ID_CLBLK) ) { pStk->SetError(CBotErrClosePar, p->GetStart()); goto error; } return pStack->Return(inst, pStk); } error: delete inst; return pStack->Return(nullptr, pStk); }
CBotInstr* CBotParExpr::Compile(CBotToken* &p, CBotCStack* pStack) { CBotCStack* pStk = pStack->TokenStack(); pStk->SetStartError(p->GetStart()); // is it an expression in parentheses? if (IsOfType(p, ID_OPENPAR)) { CBotInstr* inst = CBotExpression::Compile(p, pStk); if (nullptr != inst) { if (IsOfType(p, ID_CLOSEPAR)) { return pStack->Return(inst, pStk); } pStk->SetError(CBotErrClosePar, p->GetStart()); } delete inst; return pStack->Return(nullptr, pStk); } // is this a unary operation? CBotInstr* inst = CBotExprUnaire::Compile(p, pStk); if (inst != nullptr || !pStk->IsOk()) return pStack->Return(inst, pStk); // is it a variable name? if (p->GetType() == TokenTypVar) { // this may be a method call without the "this." before inst = CBotExprVar::CompileMethode(p, pStk); if (inst != nullptr) return pStack->Return(inst, pStk); // is it a procedure call? inst = CBotInstrCall::Compile(p, pStk); if (inst != nullptr || !pStk->IsOk()) return pStack->Return(inst, pStk); CBotToken* pvar = p; // no, it an "ordinaty" variable inst = CBotExprVar::Compile(p, pStk); CBotToken* pp = p; // post incremented or decremented? if (IsOfType(p, ID_INC, ID_DEC)) { if (pStk->GetType() >= CBotTypBoolean) { pStk->SetError(CBotErrBadType1, pp); delete inst; return pStack->Return(nullptr, pStk); } // recompile the variable for read-only delete inst; p = pvar; inst = CBotExprVar::Compile(p, pStk, CBotVar::ProtectionLevel::ReadOnly); p = p->GetNext(); CBotPostIncExpr* i = new CBotPostIncExpr(); i->SetToken(pp); i->m_instr = inst; // associated statement return pStack->Return(i, pStk); } return pStack->Return(inst, pStk); } // pre increpemted or pre decremented? CBotToken* pp = p; if (IsOfType(p, ID_INC, ID_DEC)) { CBotPreIncExpr* i = new CBotPreIncExpr(); i->SetToken(pp); if (p->GetType() == TokenTypVar) { if (nullptr != (i->m_instr = CBotExprVar::Compile(p, pStk, CBotVar::ProtectionLevel::ReadOnly))) { if (pStk->GetType() >= CBotTypBoolean) { pStk->SetError(CBotErrBadType1, pp); delete inst; return pStack->Return(nullptr, pStk); } return pStack->Return(i, pStk); } delete i; return pStack->Return(nullptr, pStk); } } // is it a number or DefineNum? if (p->GetType() == TokenTypNum || p->GetType() == TokenTypDef ) { CBotInstr* inst = CBotExprLitNum::Compile(p, pStk); return pStack->Return(inst, pStk); } // is this a chaine? if (p->GetType() == TokenTypString) { CBotInstr* inst = CBotExprLitString::Compile(p, pStk); return pStack->Return(inst, pStk); } // is a "true" or "false" if (p->GetType() == ID_TRUE || p->GetType() == ID_FALSE ) { CBotInstr* inst = CBotExprLitBool::Compile(p, pStk); return pStack->Return(inst, pStk); } // is an object to be created with new if (p->GetType() == ID_NEW) { CBotInstr* inst = CBotNew::Compile(p, pStk); return pStack->Return(inst, pStk); } // is a null pointer if (IsOfType(p, ID_NULL)) { CBotInstr* inst = new CBotExprLitNull(); inst->SetToken(pp); CBotVar* var = CBotVar::Create("", CBotTypNullPointer); pStk->SetVar(var); return pStack->Return(inst, pStk); } // is a number nan if (IsOfType(p, ID_NAN)) { CBotInstr* inst = new CBotExprLitNan(); inst->SetToken(pp); CBotVar* var = CBotVar::Create("", CBotTypInt); var->SetInit(CBotVar::InitType::IS_NAN); pStk->SetVar(var); return pStack->Return(inst, pStk); } return pStack->Return(nullptr, pStk); }
CBotLeftExpr* CBotLeftExpr::Compile(CBotToken* &p, CBotCStack* pStack) { CBotCStack* pStk = pStack->TokenStack(); pStk->SetStartError(p->GetStart()); // is it a variable name? if (p->GetType() == TokenTypVar) { CBotLeftExpr* inst = new CBotLeftExpr(); // creates the object inst->SetToken(p); CBotVar* var; if (nullptr != (var = pStk->FindVar(p))) // seek if known variable { inst->m_nIdent = var->GetUniqNum(); if (inst->m_nIdent > 0 && inst->m_nIdent < 9000) { if (CBotFieldExpr::CheckProtectionError(pStk, nullptr, var, CBotVar::ProtectionLevel::ReadOnly)) { pStk->SetError(CBotErrPrivate, p); goto err; } // this is an element of the current class // adds the equivalent of this. before CBotToken pthis("this"); inst->SetToken(&pthis); inst->m_nIdent = -2; // indent for this CBotFieldExpr* i = new CBotFieldExpr(); // new element i->SetToken(p); // keeps the name of the token inst->AddNext3(i); // add after var = pStk->FindVar(pthis); var = var->GetItem(p->GetString()); i->SetUniqNum(var->GetUniqNum()); } p = p->GetNext(); // next token while (true) { if (var->GetType() == CBotTypArrayPointer) { if (IsOfType( p, ID_OPBRK )) { CBotIndexExpr* i = new CBotIndexExpr(); i->m_expr = CBotExpression::Compile(p, pStk); inst->AddNext3(i); // add to the chain var = (static_cast<CBotVarArray*>(var))->GetItem(0,true); // gets the component [0] if (i->m_expr == nullptr) { pStk->SetError(CBotErrBadIndex, p->GetStart()); goto err; } if (!pStk->IsOk() || !IsOfType( p, ID_CLBRK )) { pStk->SetError(CBotErrCloseIndex, p->GetStart()); goto err; } continue; } } if (var->GetType(CBotVar::GetTypeMode::CLASS_AS_POINTER) == CBotTypPointer) // for classes { if (IsOfType(p, ID_DOT)) { CBotToken* pp = p; CBotFieldExpr* i = new CBotFieldExpr(); // new element i->SetToken(pp); // keeps the name of the token inst->AddNext3(i); // adds after if (p->GetType() == TokenTypVar) // must be a name { CBotVar* preVar = var; var = var->GetItem(p->GetString()); // get item correspondent if (var != nullptr) { if (CBotFieldExpr::CheckProtectionError(pStk, preVar, var, CBotVar::ProtectionLevel::ReadOnly)) { pStk->SetError(CBotErrPrivate, pp); goto err; } i->SetUniqNum(var->GetUniqNum()); p = p->GetNext(); // skips the name continue; } pStk->SetError(CBotErrUndefItem, p); } pStk->SetError(CBotErrUndefClass, p->GetStart()); goto err; } } break; } if (pStk->IsOk()) return static_cast<CBotLeftExpr*> (pStack->Return(inst, pStk)); } pStk->SetError(CBotErrUndefVar, p); err: delete inst; return static_cast<CBotLeftExpr*> ( pStack->Return(nullptr, pStk)); } return static_cast<CBotLeftExpr*> ( pStack->Return(nullptr, pStk)); }
CBotInstr* CBotExprRetVar::Compile(CBotToken*& p, CBotCStack* pStack, bool bMethodsOnly) { if (p->GetType() == ID_DOT) { CBotVar* var = pStack->GetVar(); if (var == nullptr) return nullptr; CBotCStack* pStk = pStack->TokenStack(); CBotInstr* inst = new CBotExprRetVar(); while (true) { pStk->SetStartError(p->GetStart()); if (var->GetType() == CBotTypArrayPointer) { if (bMethodsOnly) goto err; if (IsOfType( p, ID_OPBRK )) { CBotIndexExpr* i = new CBotIndexExpr(); i->m_expr = CBotExpression::Compile(p, pStk); inst->AddNext3(i); var = var->GetItem(0,true); if (i->m_expr == nullptr || pStk->GetType() != CBotTypInt) { pStk->SetError(CBotErrBadIndex, p->GetStart()); goto err; } if (!pStk->IsOk() || !IsOfType( p, ID_CLBRK )) { pStk->SetError(CBotErrCloseIndex, p->GetStart()); goto err; } continue; } } if (var->GetType(CBotVar::GetTypeMode::CLASS_AS_POINTER) == CBotTypPointer) { if (IsOfType(p, ID_DOT)) { CBotToken* pp = p; if (p->GetType() == TokenTypVar) { if (p->GetNext()->GetType() == ID_OPENPAR) { CBotInstr* i = CBotInstrMethode::Compile(p, pStk, var, bMethodsOnly); if (!pStk->IsOk()) goto err; inst->AddNext3(i); return pStack->Return(inst, pStk); } else if (bMethodsOnly) { p = p->GetPrev(); goto err; } else { CBotFieldExpr* i = new CBotFieldExpr(); i->SetToken(pp); inst->AddNext3(i); CBotVar* preVar = var; var = var->GetItem(p->GetString()); if (var != nullptr) { i->SetUniqNum(var->GetUniqNum()); if (CBotFieldExpr::CheckProtectionError(pStk, preVar, var)) { pStk->SetError(CBotErrPrivate, pp); goto err; } } } if (var != nullptr) { p = p->GetNext(); continue; } pStk->SetError(CBotErrUndefItem, p); goto err; } pStk->SetError(CBotErrUndefClass, p); goto err; } } break; } pStk->SetCopyVar(var); if (pStk->IsOk()) return pStack->Return(inst, pStk); pStk->SetError(CBotErrUndefVar, p); err: delete inst; return pStack->Return(nullptr, pStk); } return nullptr; }
// compiles a new function // bLocal allows of the declaration of parameters on the same level // as the elements belonging to the class for methods CBotFunction* CBotFunction::Compile(CBotToken* &p, CBotCStack* pStack, CBotFunction* finput, bool bLocal) { CBotToken* pp; CBotFunction* func = finput; if ( func == NULL ) func = new CBotFunction(); CBotCStack* pStk = pStack->TokenStack(p, bLocal); // func->m_nFuncIdent = CBotVar::NextUniqNum(); while (true) { if ( IsOfType(p, ID_PUBLIC) ) { func->m_bPublic = true; continue; } pp = p; if ( IsOfType(p, ID_EXTERN) ) { func->m_extern = pp; // for the position of the word "extern" func->m_bExtern = true; // func->m_bPublic = true; // therefore also public! continue; } break; } func->m_retToken = *p; // CBotClass* pClass; func->m_retTyp = TypeParam(p, pStk); // type of the result if (func->m_retTyp.GetType() >= 0) { CBotToken* pp = p; func->m_token = *p; if ( IsOfType(p, ID_NOT) ) { CBotToken d("~" + p->GetString()); func->m_token = d; } // un nom de fonction est-il là ? if (IsOfType(p, TokenTypVar)) { if ( IsOfType( p, ID_DBLDOTS ) ) // method for a class { func->m_MasterClass = pp->GetString(); CBotClass* pClass = CBotClass::Find(pp); if ( pClass == NULL ) goto bad; // pp = p; func->m_token = *p; if (!IsOfType(p, TokenTypVar)) goto bad; } func->m_openpar = p; func->m_Param = CBotDefParam::Compile( p, pStk ); func->m_closepar = p->GetPrev(); if (pStk->IsOk()) { pStk->SetRetType(func->m_retTyp); // for knowledge what type returns if (!func->m_MasterClass.IsEmpty()) { // return "this" known CBotVar* pThis = CBotVar::Create("this", CBotTypResult( CBotTypClass, func->m_MasterClass )); pThis->SetInit(2); // pThis->SetUniqNum(func->m_nThisIdent = -2); //CBotVar::NextUniqNum() will not pThis->SetUniqNum(-2); pStk->AddVar(pThis); // initialize variables acording to This // only saves the pointer to the first, // the rest is chained CBotVar* pv = pThis->GetItemList(); // int num = 1; while (pv != NULL) { CBotVar* pcopy = CBotVar::Create(pv); // pcopy->SetInit(2); pcopy->Copy(pv); pcopy->SetPrivate(pv->GetPrivate()); // pcopy->SetUniqNum(pv->GetUniqNum()); //num++); pStk->AddVar(pcopy); pv = pv->GetNext(); } } // and compiles the following instruction block func->m_openblk = p; func->m_Block = CBotBlock::Compile(p, pStk, false); func->m_closeblk = p->GetPrev(); if ( pStk->IsOk() ) { if ( func->m_bPublic ) // public function, return known for all { CBotFunction::AddPublic(func); } return pStack->ReturnFunc(func, pStk); } } } bad: pStk->SetError(TX_NOFONC, p); } pStk->SetError(TX_NOTYP, p); if ( finput == NULL ) delete func; return pStack->ReturnFunc(NULL, pStk); }
CBotInstr* CBotSwitch::Compile(CBotToken* &p, CBotCStack* pStack) { CBotSwitch* inst = new CBotSwitch(); // creates the object CBotToken* pp = p; // preserves at the ^ token (starting position) inst->SetToken(p); if (!IsOfType(p, ID_SWITCH)) return nullptr; // should never happen CBotCStack* pStk = pStack->TokenStack(pp); // un petit bout de pile svp if ( IsOfType(p, ID_OPENPAR ) ) { if ( nullptr != (inst->m_Value = CBotExpression::Compile( p, pStk )) ) { if ( pStk->GetType() < CBotTypLong ) { if ( IsOfType(p, ID_CLOSEPAR ) ) { if ( IsOfType(p, ID_OPBLK ) ) { IncLvl(); while( !IsOfType( p, ID_CLBLK ) ) { if ( p->GetType() == ID_CASE || p->GetType() == ID_DEFAULT) { CBotCStack* pStk2 = pStk->TokenStack(p); // un petit bout de pile svp CBotInstr* i = CBotCase::Compile( p, pStk2 ); if (i == nullptr) { delete inst; return pStack->Return(nullptr, pStk2); } delete pStk2; if ( inst->m_Block == nullptr ) inst->m_Block = i; else inst->m_Block->AddNext(i); continue; } if ( inst->m_Block == nullptr ) { pStk->SetError(TX_NOCASE, p->GetStart()); delete inst; return pStack->Return(nullptr, pStk); } CBotInstr* i = CBotBlock::CompileBlkOrInst( p, pStk, true ); if ( !pStk->IsOk() ) { delete inst; return pStack->Return(nullptr, pStk); } inst->m_Block->AddNext(i); if ( p == nullptr ) { pStk->SetError(TX_CLOSEBLK, -1); delete inst; return pStack->Return(nullptr, pStk); } } DecLvl(); if ( inst->m_Block == nullptr ) { pStk->SetError(TX_NOCASE, p->GetStart()); delete inst; return pStack->Return(nullptr, pStk); } // the statement block is ok return pStack->Return(inst, pStk); // return an object to the application } pStk->SetError( TX_OPENBLK, p->GetStart() ); } pStk->SetError( TX_CLOSEPAR, p->GetStart() ); } pStk->SetError( TX_BADTYPE, p->GetStart() ); } } pStk->SetError( TX_OPENPAR, p->GetStart()); delete inst; // error, frees up return pStack->Return(nullptr, pStk); // no object, the error is on the stack }
CBotInstr* CBotDefArray::Compile(CBotToken* &p, CBotCStack* pStack, CBotTypResult type) { CBotCStack* pStk = pStack->TokenStack(p); CBotDefArray* inst = new CBotDefArray(); CBotToken* vartoken = p; inst->SetToken(vartoken); // determinse the expression is valid for the item on the left side if (nullptr != (inst->m_var = CBotLeftExprVar::Compile( p, pStk ))) { if (pStk->CheckVarLocal(vartoken)) // redefinition of the variable? { pStk->SetError(CBotErrRedefVar, vartoken); goto error; } CBotInstr* i; while (IsOfType(p, ID_OPBRK)) { pStk->SetStartError(p->GetStart()); if (p->GetType() != ID_CLBRK) { i = CBotExpression::Compile(p, pStk); // expression for the value if (i == nullptr || pStk->GetType() != CBotTypInt) // must be a number { pStk->SetError(CBotErrBadIndex, p->GetStart()); goto error; } } else i = new CBotEmpty(); // if no special formula inst->AddNext3b(i); // construct a list type = CBotTypResult(CBotTypArrayPointer, type); if (IsOfType(p, ID_CLBRK)) continue; pStk->SetError(CBotErrCloseIndex, p->GetStart()); goto error; } CBotVar* var = CBotVar::Create(*vartoken, type); // create an instance inst->m_typevar = type; var->SetUniqNum( (static_cast<CBotLeftExprVar*>(inst->m_var))->m_nIdent = CBotVar::NextUniqNum()); pStack->AddVar(var); // place it on the stack if (IsOfType(p, ID_ASS)) // with an assignment { pStk->SetStartError(p->GetStart()); if ( IsOfType(p, ID_SEP) ) { pStk->SetError(CBotErrNoExpression, p->GetPrev()); goto error; } if ( nullptr == (inst->m_listass = CBotListArray::Compile(p, pStk, type.GetTypElem())) ) { if (pStk->IsOk()) { inst->m_listass = CBotTwoOpExpr::Compile(p, pStk); if (inst->m_listass == nullptr || !pStk->GetTypResult().Compare(type)) // compatible type ? { pStk->SetError(CBotErrBadType1, p->GetStart()); goto error; } } } if (pStk->IsOk()) while (true) // mark initialized { var = var->GetItem(0, true); if (var == nullptr) break; if (var->GetType() == CBotTypArrayPointer) continue; if (var->GetType() <= CBotTypString) var->SetInit(CBotVar::InitType::DEF); break; } } if (pStk->IsOk()) return pStack->Return(inst, pStk); } error: delete inst; return pStack->Return(nullptr, pStk); }
CBotInstr* CBotClassInst::Compile(CBotToken* &p, CBotCStack* pStack, CBotClass* pClass) { // seeks the corresponding classes if ( pClass == NULL ) { pStack->SetStartError(p->GetStart()); pClass = CBotClass::Find(p); if ( pClass == NULL ) { // not found? is bizare pStack->SetError(TX_NOCLASS, p); return NULL; } p = p->GetNext(); } bool bIntrinsic = pClass->IsIntrinsic(); CBotTypResult type = CBotTypResult( bIntrinsic ? CBotTypIntrinsic : CBotTypPointer, pClass ); CBotClassInst* inst = static_cast<CBotClassInst*>(CompileArray(p, pStack, type)); if ( inst != NULL || !pStack->IsOk() ) return inst; CBotCStack* pStk = pStack->TokenStack(); inst = new CBotClassInst(); /// \TODO Need to be revised and fixed after adding unit tests CBotToken token(pClass->GetName(), CBotString(), p->GetStart(), p->GetEnd()); inst->SetToken(&token); CBotToken* vartoken = p; if ( NULL != (inst->m_var = CBotLeftExprVar::Compile( p, pStk )) ) { (static_cast<CBotLeftExprVar*>(inst->m_var))->m_typevar = type; if (pStk->CheckVarLocal(vartoken)) // redefinition of the variable { pStk->SetStartError(vartoken->GetStart()); pStk->SetError(TX_REDEFVAR, vartoken->GetEnd()); goto error; } if (IsOfType(p, ID_OPBRK)) // with any clues? { delete inst; // is not type CBotInt p = vartoken; // returns to the variable name // compiles declaration an array inst = static_cast<CBotClassInst*>(CBotInstArray::Compile( p, pStk, type )); if (!pStk->IsOk() ) { pStk->SetError(TX_CLBRK, p->GetStart()); goto error; } goto suite; // no assignment, variable already created } CBotVar* var; var = CBotVar::Create(vartoken->GetString(), type); // creates the instance // var->SetClass(pClass); var->SetUniqNum( (static_cast<CBotLeftExprVar*>(inst->m_var))->m_nIdent = CBotVar::NextUniqNum()); // its attribute a unique number pStack->AddVar(var); // placed on the stack // look if there are parameters inst->m_hasParams = (p->GetType() == ID_OPENPAR); CBotVar* ppVars[1000]; inst->m_Parameters = CompileParams(p, pStk, ppVars); if ( !pStk->IsOk() ) goto error; // if there are parameters, is the equivalent to the stament "new" // CPoint A ( 0, 0 ) is equivalent to // CPoint A = new CPoint( 0, 0 ) // if ( NULL != inst->m_Parameters ) if ( inst->m_hasParams ) { // the constructor is there? // CBotString noname; CBotTypResult r = pClass->CompileMethode(pClass->GetName(), var, ppVars, pStk, inst->m_nMethodeIdent); delete pStk->TokenStack(); // releases the supplement stack int typ = r.GetType(); if (typ == TX_UNDEFCALL) { // si le constructeur n'existe pas if (inst->m_Parameters != NULL) // with parameters { pStk->SetError(TX_NOCONST, vartoken); goto error; } typ = 0; } if (typ>20) { pStk->SetError(typ, vartoken->GetEnd()); goto error; } } if (IsOfType(p, ID_ASS)) // with a assignment? { if (inst->m_hasParams) { pStk->SetError(TX_ENDOF, p->GetStart()); goto error; } if ( NULL == ( inst->m_expr = CBotTwoOpExpr::Compile( p, pStk )) ) { goto error; } CBotClass* result = pStk->GetClass(); if ( !pStk->GetTypResult(1).Eq(CBotTypNullPointer) && ( !pStk->GetTypResult(1).Eq(CBotTypPointer) || ( result != NULL && !pClass->IsChildOf(result) ))) // type compatible ? { pStk->SetError(TX_BADTYPE, p->GetStart()); goto error; } // if ( !bIntrinsic ) var->SetPointer(pStk->GetVar()->GetPointer()); if ( !bIntrinsic ) { // does not use the result on the stack, to impose the class CBotVar* pvar = CBotVar::Create("", pClass); var->SetPointer( pvar ); // variable already declared instance pointer delete pvar; // removes the second pointer } var->SetInit(true); // marks the pointer as init } else if (inst->m_hasParams) { // creates the object on the "job" (\TODO "tas") // with a pointer to the object if ( !bIntrinsic ) { CBotVar* pvar = CBotVar::Create("", pClass); var->SetPointer( pvar ); // variable already declared instance pointer delete pvar; // removes the second pointer } var->SetInit(2); // marks the pointer as init } suite: if (IsOfType(p, ID_COMMA)) // several chained definitions { if ( NULL != ( inst->m_next = CBotClassInst::Compile(p, pStk, pClass) )) // compiles the following { return pStack->Return(inst, pStk); } } if (IsOfType(p, ID_SEP)) // complete instruction { return pStack->Return(inst, pStk); } pStk->SetError(TX_ENDOF, p->GetStart()); } error: delete inst; return pStack->Return(NULL, pStk); }