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* CBotCase::Compile(CBotToken* &p, CBotCStack* pStack) { CBotCase* inst = new CBotCase(); // creates the object CBotToken* pp = p; // preserves at the ^ token (starting position) inst->SetToken(p); if (!IsOfType(p, ID_CASE, ID_DEFAULT)) return nullptr; // should never happen if ( pp->GetType() == ID_CASE ) { pp = p; inst->m_Value = CBotExprNum::Compile(p, pStack); if ( inst->m_Value == nullptr ) { pStack->SetError( TX_BADNUM, pp ); delete inst; return nullptr; } } if ( !IsOfType( p, ID_DOTS )) { pStack->SetError( TX_MISDOTS, p->GetStart() ); delete inst; return nullptr; } return inst; }
void CBotStack::GetRunPos(const char* &FunctionName, int &start, int &end) { CBotProgram* prog = m_prog; // Current program CBotInstr* funct = NULL; // function found CBotInstr* instr = NULL; // the highest intruction CBotStack* p = this; while (p->m_next != NULL) { if ( p->m_instr != NULL ) instr = p->m_instr; if ( p->m_bFunc == 1 ) funct = p->m_instr; if ( p->m_next->m_prog != prog ) break ; if (p->m_next2 && p->m_next2->m_state != 0) p = p->m_next2 ; else p = p->m_next; } if ( p->m_instr != NULL ) instr = p->m_instr; if ( p->m_bFunc == 1 ) funct = p->m_instr; if ( funct == NULL ) return; CBotToken* t = funct->GetToken(); FunctionName = t->GetString(); // if ( p->m_instr != NULL ) instr = p->m_instr; t = instr->GetToken(); start = t->GetStart(); end = t->GetEnd(); }
// compiles a list of parameters CBotDefParam* CBotDefParam::Compile(CBotToken* &p, CBotCStack* pStack) { // mainly not pStack->TokenStack here // declared variables must remain visible thereafter pStack->SetStartError(p->GetStart()); if (IsOfType(p, ID_OPENPAR)) { CBotDefParam* list = NULL; while (!IsOfType(p, ID_CLOSEPAR)) { CBotDefParam* param = new CBotDefParam(); if (list == NULL) list = param; else list->AddNext(param); // added to the list // CBotClass* pClass = NULL;//= CBotClass::Find(p); param->m_typename = p->GetString(); CBotTypResult type = param->m_type = TypeParam(p, pStack); // if ( type == CBotTypPointer ) type = CBotTypClass; // we must create a new object if (param->m_type.GetType() > 0) { CBotToken* pp = p; param->m_token = *p; if (pStack->IsOk() && IsOfType(p, TokenTypVar) ) { // variable already declared? if (pStack->CheckVarLocal(pp)) { pStack->SetError(TX_REDEFVAR, pp); break; } if ( type.Eq(CBotTypArrayPointer) ) type.SetType(CBotTypArrayBody); CBotVar* var = CBotVar::Create(pp->GetString(), type); // creates the variable // if ( pClass ) var->SetClass(pClass); var->SetInit(2); // mark initialized param->m_nIdent = CBotVar::NextUniqNum(); var->SetUniqNum(param->m_nIdent); pStack->AddVar(var); // place on the stack if (IsOfType(p, ID_COMMA) || p->GetType() == ID_CLOSEPAR) continue; } pStack->SetError(TX_CLOSEPAR, p->GetStart()); } pStack->SetError(TX_NOTYP, p); delete list; return NULL; } return list; } pStack->SetError(TX_OPENPAR, p->GetStart()); return NULL; }
bool CBotCStack::NextToken(CBotToken* &p) { CBotToken* pp = p; p = p->GetNext(); if (p!=NULL) return true; SetError(TX_ENDOF, pp->GetEnd()); return false; }
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 }
CBotVar* CBotStack::GetStackVars(const char* &FunctionName, int level) { CBotProgram* prog = m_prog; // current program FunctionName = NULL; // back the stack in the current module CBotStack* p = this; while (p->m_next != NULL) { if ( p->m_next->m_prog != prog ) break ; if (p->m_next2 && p->m_next2->m_state != 0) p = p->m_next2 ; else p = p->m_next; } // descends upon the elements of block while ( p != NULL && !p->m_bBlock ) p = p->m_prev; while ( p != NULL && level++ < 0 ) { p = p->m_prev; while ( p != NULL && !p->m_bBlock ) p = p->m_prev; } if ( p == NULL ) return NULL; // search the name of the current function CBotStack* pp = p; while ( pp != NULL ) { if ( pp->m_bFunc == 1 ) break; pp = pp->m_prev; } if ( pp == NULL || pp->m_instr == NULL ) return NULL; CBotToken* t = pp->m_instr->GetToken(); FunctionName = t->GetString(); return p->m_listVar; }
void CScript::ColorizeScript(Ui::CEdit* edit) { CBotToken* bt; CBotString bs; const char* token; int error, type, cursor1, cursor2; Gfx::FontHighlight color; edit->ClearFormat(); bt = CBotToken::CompileTokens(edit->GetText(), error); while ( bt != 0 ) { bs = bt->GetString(); token = bs; type = bt->GetType(); cursor1 = bt->GetStart(); cursor2 = bt->GetEnd(); color = Gfx::FONT_HIGHLIGHT_NONE; if ( type >= TokenKeyWord && type < TokenKeyWord+100 ) { color = Gfx::FONT_HIGHLIGHT_TOKEN; } if ( type >= TokenKeyDeclare && type < TokenKeyDeclare+100 ) { color = Gfx::FONT_HIGHLIGHT_TYPE; } if ( type >= TokenKeyVal && type < TokenKeyVal+100 ) { color = Gfx::FONT_HIGHLIGHT_CONST; } if ( type == TokenTypVar ) { if ( IsType(token) ) { color = Gfx::FONT_HIGHLIGHT_TYPE; } else if ( IsFunction(token) ) { color = Gfx::FONT_HIGHLIGHT_TOKEN; } } if ( type == TokenTypDef ) { color =Gfx::FONT_HIGHLIGHT_CONST; } if ( cursor1 < cursor2 && color != Gfx::FONT_HIGHLIGHT_NONE ) { edit->SetFormat(cursor1, cursor2, color); } bt = bt->GetNext(); } CBotToken::Delete(bt); }
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* CBotBreak::Compile(CBotToken* &p, CBotCStack* pStack) { CBotToken* pp = p; // preserves at the ^ token (starting position) int type = p->GetType(); if (!IsOfType(p, ID_BREAK, ID_CONTINUE)) return nullptr; // should never happen if ( !ChkLvl(CBotString(), type ) ) { pStack->SetError(TX_BREAK, pp); return nullptr; // no object, the error is on the stack } CBotBreak* inst = new CBotBreak(); // creates the object inst->SetToken(pp); // keeps the operation pp = p; if ( IsOfType( p, TokenTypVar ) ) { inst->m_label = pp->GetString(); // register the name of label if ( !ChkLvl(inst->m_label, type ) ) { delete inst; pStack->SetError(TX_NOLABEL, pp); return nullptr; // no object, the error is on the stack } } if (IsOfType(p, ID_SEP)) { return inst; // return what it wants } delete inst; pStack->SetError(TX_ENDOF, p->GetStart()); return nullptr; // no object, the error is on the stack }
bool CBotProgram::Compile(const std::string& program, std::vector<std::string>& externFunctions, void* pUser) { // Cleanup the previously compiled program Stop(); for (CBotClass* c : m_classes) c->Purge(); // purge the old definitions of classes // but without destroying the object m_classes.clear(); for (CBotFunction* f : m_functions) delete f; m_functions.clear(); externFunctions.clear(); m_error = CBotNoErr; // Step 1. Process the code into tokens auto tokens = CBotToken::CompileTokens(program); if (tokens == nullptr) return false; auto pStack = std::unique_ptr<CBotCStack>(new CBotCStack(nullptr)); CBotToken* p = tokens.get()->GetNext(); // skips the first token (separator) pStack->SetProgram(this); // defined used routines m_externalCalls->SetUserPtr(pUser); // Step 2. Find all function and class definitions while ( pStack->IsOk() && p != nullptr && p->GetType() != 0) { if ( IsOfType(p, ID_SEP) ) continue; // semicolons lurking if ( p->GetType() == ID_CLASS || ( p->GetType() == ID_PUBLIC && p->GetNext()->GetType() == ID_CLASS )) { m_classes.push_back(CBotClass::Compile1(p, pStack.get())); } else { m_functions.push_back(CBotFunction::Compile1(p, pStack.get(), nullptr)); } } // Define fields and pre-compile methods for each class in this program if (pStack->IsOk()) CBotClass::DefineClasses(m_classes, pStack.get()); if ( !pStack->IsOk() ) { m_error = pStack->GetError(m_errorStart, m_errorEnd); for (CBotFunction* f : m_functions) delete f; m_functions.clear(); return false; } // Step 3. Real compilation std::list<CBotFunction*>::iterator next = m_functions.begin(); p = tokens.get()->GetNext(); // returns to the beginning while ( pStack->IsOk() && p != nullptr && p->GetType() != 0 ) { if ( IsOfType(p, ID_SEP) ) continue; // semicolons lurking if ( p->GetType() == ID_CLASS || ( p->GetType() == ID_PUBLIC && p->GetNext()->GetType() == ID_CLASS )) { CBotClass::Compile(p, pStack.get()); // completes the definition of the class } else { CBotFunction::Compile(p, pStack.get(), *next); if ((*next)->IsExtern()) externFunctions.push_back((*next)->GetName()/* + next->GetParams()*/); if ((*next)->IsPublic()) CBotFunction::AddPublic(*next); (*next)->m_pProg = this; // keeps pointers to the module ++next; } } if ( !pStack->IsOk() ) { m_error = pStack->GetError(m_errorStart, m_errorEnd); for (CBotFunction* f : m_functions) delete f; m_functions.clear(); } return !m_functions.empty(); }
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); }
// 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); }
// 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); }
bool CBotClass::CompileDefItem(CBotToken* &p, CBotCStack* pStack, bool bSecond) { bool bStatic = false; int mProtect = PR_PUBLIC; bool bSynchro = false; while (IsOfType(p, ID_SEP)) ; CBotTypResult type( -1 ); if ( IsOfType(p, ID_SYNCHO) ) bSynchro = true; CBotToken* pBase = p; if ( IsOfType(p, ID_STATIC) ) bStatic = true; if ( IsOfType(p, ID_PUBLIC) ) mProtect = PR_PUBLIC; if ( IsOfType(p, ID_PRIVATE) ) mProtect = PR_PRIVATE; if ( IsOfType(p, ID_PROTECTED) ) mProtect = PR_PROTECT; if ( IsOfType(p, ID_STATIC) ) bStatic = true; // CBotClass* pClass = NULL; type = TypeParam(p, pStack); // type of the result if ( type.Eq(-1) ) { pStack->SetError(TX_NOTYP, p); return false; } while (pStack->IsOk()) { CBotToken* pp = p; IsOfType(p, ID_NOT); // skips ~ eventual (destructor) if (IsOfType(p, TokenTypVar)) { CBotInstr* limites = NULL; while ( IsOfType( p, ID_OPBRK ) ) // a table? { CBotInstr* i = NULL; if ( p->GetType() != ID_CLBRK ) i = CBotExpression::Compile( p, pStack ); // expression for the value else i = new CBotEmpty(); // special if not a formula type = CBotTypResult(CBotTypArrayPointer, type); if (!pStack->IsOk() || !IsOfType( p, ID_CLBRK ) ) { pStack->SetError(TX_CLBRK, p->GetStart()); return false; } /* CBotVar* pv = pStack->GetVar(); if ( pv->GetType()>= CBotTypBoolean ) { pStack->SetError(TX_BADTYPE, p->GetStart()); return false; }*/ if (limites == NULL) limites = i; else limites->AddNext3(i); } if ( p->GetType() == ID_OPENPAR ) { if ( !bSecond ) { p = pBase; CBotFunction* f = CBotFunction::Compile1(p, pStack, this); if ( f == NULL ) return false; if (m_pMethod == NULL) m_pMethod = f; else m_pMethod->AddNext(f); } else { // return a method precompiled in pass 1 CBotFunction* pf = m_pMethod; CBotFunction* prev = NULL; while ( pf != NULL ) { if (pf->GetName() == pp->GetString()) break; prev = pf; pf = pf->Next(); } bool bConstructor = (pp->GetString() == GetName()); CBotCStack* pile = pStack->TokenStack(NULL, true); // make "this" known CBotToken TokenThis(CBotString("this"), CBotString()); CBotVar* pThis = CBotVar::Create(&TokenThis, CBotTypResult( CBotTypClass, this ) ); pThis->SetUniqNum(-2); pile->AddVar(pThis); if ( m_pParent ) { // makes "super" known CBotToken TokenSuper(CBotString("super"), CBotString()); CBotVar* pThis = CBotVar::Create(&TokenSuper, CBotTypResult( CBotTypClass, m_pParent ) ); pThis->SetUniqNum(-3); pile->AddVar(pThis); } // int num = 1; CBotClass* my = this; while (my != NULL) { // places a copy of variables of a class (this) on a stack CBotVar* pv = my->m_pVar; while (pv != NULL) { CBotVar* pcopy = CBotVar::Create(pv); pcopy->SetInit(!bConstructor || pv->IsStatic()); pcopy->SetUniqNum(pv->GetUniqNum()); pile->AddVar(pcopy); pv = pv->GetNext(); } my = my->m_pParent; } // compiles a method p = pBase; CBotFunction* f = CBotFunction::Compile(p, pile, NULL/*, false*/); if ( f != NULL ) { f->m_pProg = pStack->GetBotCall(); f->m_bSynchro = bSynchro; // replaces the element in the chain f->m_next = pf->m_next; pf->m_next = NULL; delete pf; if (prev == NULL) m_pMethod = f; else prev->m_next = f; } pStack->Return(NULL, pile); } return pStack->IsOk(); } // definition of an element if (type.Eq(0)) { pStack->SetError(TX_ENDOF, p); return false; } CBotInstr* i = NULL; if ( IsOfType(p, ID_ASS ) ) { if ( type.Eq(CBotTypArrayPointer) ) { i = CBotListArray::Compile(p, pStack, type.GetTypElem()); } else { // it has an assignmet to calculate i = CBotTwoOpExpr::Compile(p, pStack); } if ( !pStack->IsOk() ) return false; } if ( !bSecond ) { CBotVar* pv = CBotVar::Create(pp->GetString(), type); pv -> SetStatic( bStatic ); pv -> SetPrivate( mProtect ); AddItem( pv ); pv->m_InitExpr = i; pv->m_LimExpr = limites; if ( pv->IsStatic() && pv->m_InitExpr != NULL ) { CBotStack* pile = CBotStack::FirstStack(); // independent stack while(pile->IsOk() && !pv->m_InitExpr->Execute(pile)); // evaluates the expression without timer pv->SetVal( pile->GetVar() ) ; pile->Delete(); } } else delete i; if ( IsOfType(p, ID_COMMA) ) continue; if ( IsOfType(p, ID_SEP) ) break; } pStack->SetError(TX_ENDOF, p); } return pStack->IsOk(); }
bool CScript::CheckToken() { CBotToken* bt; CBotToken* allBt; CBotString bs; const char* token; int error, cursor1, cursor2, i; char used[100]; if ( !m_object->GetCheckToken() ) return true; m_error = 0; m_title[0] = 0; m_mainFunction[0] = 0; m_token[0] = 0; m_bCompile = false; for ( i=0 ; i<m_main->GetObligatoryToken() ; i++ ) { used[i] = 0; // token not used } allBt = CBotToken::CompileTokens(m_script, error); bt = allBt; while ( bt != 0 ) { bs = bt->GetString(); token = bs; cursor1 = bt->GetStart(); cursor2 = bt->GetEnd(); i = m_main->IsObligatoryToken(token); if ( i != -1 ) { used[i] = 1; // token used } if ( !m_main->IsProhibitedToken(token) ) { m_error = ERR_PROHIBITEDTOKEN; m_cursor1 = cursor1; m_cursor2 = cursor2; strcpy(m_title, "<prohibited>"); m_mainFunction[0] = 0; CBotToken::Delete(allBt); return false; } bt = bt->GetNext(); } // At least once every obligatory instruction? for ( i=0 ; i<m_main->GetObligatoryToken() ; i++ ) { if ( used[i] == 0 ) // token not used? { strcpy(m_token, m_main->GetObligatoryToken(i)); m_error = ERR_OBLIGATORYTOKEN; strcpy(m_title, "<obligatory>"); m_mainFunction[0] = 0; CBotToken::Delete(allBt); return false; } } CBotToken::Delete(allBt); return true; }