CBotString CBotString::Mid(int nFirst) const { char chain[2000]; int i; for (i = nFirst; i < m_lg && i < 1999 ; ++i) { chain[i] = m_ptr[i]; } chain[i] = 0 ; return CBotString(chain); }
CBotString CBotString::Left(int nCount) const { char chain[2000]; int i; for (i = 0; i < m_lg && i < nCount && i < 1999; ++i) { chain[i] = m_ptr[i]; } chain[i] = 0 ; return CBotString(chain); }
CBotString CBotString::Right(int nCount) const { char chain[2000]; int i = m_lg - nCount; if ( i < 0 ) i = 0; int j; for (j = 0 ; i < m_lg && i < 1999; ++i) { chain[j++] = m_ptr[i]; } chain[j] = 0 ; return CBotString(chain); }
CBotString CBotFunction::GetParams() { if ( m_Param == NULL ) return CBotString("()"); CBotString params = "( "; CBotDefParam* p = m_Param; // list of parameters while (p != NULL) { params += p->GetParamString(); p = p->GetNext(); if ( p != NULL ) params += ", "; } params += " )"; return params; }
bool CBotReturn::Execute(CBotStack* &pj) { CBotStack* pile = pj->AddStack(this); // if ( pile == EOX ) return true; if ( pile->GetState() == 0 ) { if ( m_Instr != NULL && !m_Instr->Execute(pile) ) return false; // evaluate the result // the result is on the stack pile->IncState(); } if ( pile->IfStep() ) return false; pile->SetBreak(3, CBotString()); return pj->Return(pile); }
bool CBotClass::AddItem(CBotString name, CBotTypResult type, int mPrivate) { CBotToken token(name, CBotString()); CBotClass* pClass = type.GetClass(); CBotVar* pVar = CBotVar::Create( name, type ); /// pVar->SetUniqNum(CBotVar::NextUniqNum()); pVar->SetPrivate( mPrivate ); if ( pClass != NULL ) { // pVar->SetClass(pClass); if ( type.Eq(CBotTypClass) ) { // adds a new statement for the object initialization pVar->m_InitExpr = new CBotNew() ; CBotToken nom( pClass->GetName() ); pVar->m_InitExpr->SetToken(&nom); } } return AddItem( pVar ); }
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 CBotVar::RestoreState(FILE* pf, CBotVar* &pVar) { unsigned short w, wi, prv, st; float ww; CBotString name, s; delete pVar; pVar = NULL; CBotVar* pNew = NULL; CBotVar* pPrev = NULL; while ( true ) // retrieves a list { if (!ReadWord(pf, w)) return false; // private or type? if ( w == 0 ) return true; CBotString defnum; if ( w == 200 ) { if (!ReadString(pf, defnum)) return false; // number with identifier if (!ReadWord(pf, w)) return false; // type } prv = 100; st = 0; if ( w >= 100 ) { prv = w; if (!ReadWord(pf, st)) return false; // static if (!ReadWord(pf, w)) return false; // type } if ( w == CBotTypClass ) w = CBotTypIntrinsic; // necessarily intrinsic if (!ReadWord(pf, wi)) return false; // init ? if (!ReadString(pf, name)) return false; // variable name CBotToken token(name, CBotString()); switch (w) { case CBotTypInt: case CBotTypBoolean: pNew = CBotVar::Create(&token, w); // creates a variable if (!ReadWord(pf, w)) return false; pNew->SetValInt(static_cast<short>(w), defnum); break; case CBotTypFloat: pNew = CBotVar::Create(&token, w); // creates a variable if (!ReadFloat(pf, ww)) return false; pNew->SetValFloat(ww); break; case CBotTypString: pNew = CBotVar::Create(&token, w); // creates a variable if (!ReadString(pf, s)) return false; pNew->SetValString(s); break; // returns an intrinsic object or element of an array case CBotTypIntrinsic: case CBotTypArrayBody: { CBotTypResult r; long id; if (!ReadType(pf, r)) return false; // complete type if (!ReadLong(pf, id) ) return false; // if (!ReadString(pf, s)) return false; { CBotVar* p = NULL; if ( id ) p = CBotVarClass::Find(id) ; pNew = new CBotVarClass(&token, r); // directly creates an instance // attention cptuse = 0 if ( !RestoreState(pf, (static_cast<CBotVarClass*>(pNew))->m_pVar)) return false; pNew->SetIdent(id); if ( p != NULL ) { delete pNew; pNew = p; // resume known element } } } break; case CBotTypPointer: case CBotTypNullPointer: if (!ReadString(pf, s)) return false; { pNew = CBotVar::Create(&token, CBotTypResult(w, s));// creates a variable // CBotVarClass* p = NULL; long id; ReadLong(pf, id); // if ( id ) p = CBotVarClass::Find(id); // found the instance (made by RestoreInstance) // returns a copy of the original instance CBotVar* pInstance = NULL; if ( !CBotVar::RestoreState( pf, pInstance ) ) return false; (static_cast<CBotVarPointer*>(pNew))->SetPointer( pInstance ); // and point over // if ( p != NULL ) (static_cast<CBotVarPointer*>(pNew))->SetPointer( p ); // rather this one } break; case CBotTypArrayPointer: { CBotTypResult r; if (!ReadType(pf, r)) return false; pNew = CBotVar::Create(&token, r); // creates a variable // returns a copy of the original instance CBotVar* pInstance = NULL; if ( !CBotVar::RestoreState( pf, pInstance ) ) return false; (static_cast<CBotVarPointer*>(pNew))->SetPointer( pInstance ); // and point over } break; default: ASM_TRAP(); } if ( pPrev != NULL ) pPrev->m_next = pNew; if ( pVar == NULL ) pVar = pNew; pNew->m_binit = wi; // pNew->SetInit(wi); pNew->SetStatic(st); pNew->SetPrivate(prv-100); pPrev = pNew; } return true; }
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); }
CBotString CBotVar::GetValString() { ASM_TRAP(); return CBotString(); }
void CTestCBotDoc::OnTest() { CBotProgram::DefineNum("WingedGrabber", 1); CBotProgram::DefineNum("TrackedGrabber", 2); CBotProgram::DefineNum("WheeledGrabber", 3); CBotProgram::DefineNum("LeggedGrabber", 4); CBotProgram::DefineNum("WingedShooter", 5); CBotProgram::DefineNum("TrackedShooter", 6); CBotProgram::DefineNum("WheeledShooter", 7); CBotProgram::DefineNum("LeggedShooter", 8); CBotProgram::DefineNum("WingedOrgaShooter", 9); CBotProgram::DefineNum("TrackedOrgaShooter", 10); CBotProgram::DefineNum("WheeledOrgaShooter", 11); CBotProgram::DefineNum("LeggedOrgaShooter", 12); CBotProgram::DefineNum("WingedSniffer", 13); CBotProgram::DefineNum("TrackedSniffer", 14); CBotProgram::DefineNum("WheeledSniffer", 14); CBotProgram::DefineNum("LeggedSniffer", 15); CBotProgram::DefineNum("Thumper", 16); CBotProgram::DefineNum("PhazerShooter", 17); CBotProgram::DefineNum("Recycler", 18); CBotProgram::DefineNum("Shielder", 19); CBotProgram::DefineNum("Subber", 20); CBotProgram::DefineNum("Me", 21); CBotProgram::DefineNum("TypeMarkPath", 111); OnFileSave(); // CPerformDlg dlg; // dlg.m_Script = m_DocText; // dlg.DoModal(); // défini la routine RetObject CBotProgram::AddFunction( "Radar", rRetObject, cRetObject ); // ajoute une routine pour cette classe CBotProgram::AddFunction("Space", rSpace, cSpace); // défini la routine Test CBotProgram::AddFunction( "TEST", rTEST, cTEST ); CBotProgram::AddFunction( "F", rF, cF ); CBotProgram::AddFunction( "goto", rMove, cMove ); CBotProgram::AddFunction( "fire", rTurn, cTurn ); CBotProgram::AddFunction( "radar", rRadar, cRadar ); // crée une instance de la classe "Bot" pour ce robot CBotVar* pThisRobot = CBotVar::Create( "", CBotTypResult(CBotTypClass, "object") ); pThisRobot->SetUserPtr( (void*)1 ); pThisRobot->SetIdent( 1234 ); delete m_pProg; // crée un objet programme associé à cette instance m_pProg = new CBotProgram(pThisRobot); // compile le programme CString TextError; int code, start, end; m_pEdit->GetWindowText(m_DocText); if (!m_pProg->Compile(m_DocText, m_Liste, (void*) 44)) { m_pProg->GetError(code, start, end); delete m_pProg; m_pProg = NULL; delete pThisRobot; m_pEdit->SetSel( start, end ); m_pEdit->SetFocus(); // met en évidence la partie avec problème TextError = CBotProgram::GivErrorText( code ); AfxMessageBox( TextError ); m_pEdit->SetFocus(); return; } // exécute pour voir m_pProg->Start(m_Liste[0]); int mode = -1; if ( mode >= 0 ) { // sauve et restore à chaque pas possible while (!m_pProg->Run(NULL, 1)) { const char* FunctionName; int start1, end1; m_pProg->GetRunPos(FunctionName, start1, end1); if ( end1 <= 0 ) m_pProg->GetRunPos(FunctionName, start1, end1); m_pEdit->SetSel(start1, end1); if ( mode == 0 ) continue; FILE* pf; pf = fOpen( "TEST.CBO", "wb" ); CBotClass::SaveStaticState(pf); m_pProg->SaveState(pf); fClose(pf); if ( mode == 2 ) if (!m_pProg->Compile(m_DocText, m_Liste, (void*) 44)) { m_pProg->GetError(code, start, end); delete m_pProg; m_pProg = NULL; delete pThisRobot; m_pEdit->SetSel( start, end ); m_pEdit->SetFocus(); // met en évidence la partie avec problème TextError = CBotProgram::GivErrorText( code ); AfxMessageBox( TextError ); m_pEdit->SetFocus(); return; } pf = fOpen( "TEST.CBO", "rb" ); CBotClass::RestoreStaticState(pf); m_pProg->RestoreState(pf); fClose(pf); int start2, end2; m_pProg->GetRunPos(FunctionName, start2, end2); if ( end2 <= 0 ) m_pProg->GetRunPos(FunctionName, start2, end2); if ( start1 != start2 || end1 != end2 ) m_pProg->GetRunPos(FunctionName, start2, end2); m_pEdit->SetSel(start2, end2); } if (m_pProg->GetError(code, start, end)) { m_pEdit->SetSel(start, end); TextError = CBotProgram::GivErrorText(code); AfxMessageBox(TextError); } return;} while (!m_pProg->Run(NULL, 0)) { const char* FunctionName; int start, end; m_pProg->GetRunPos(FunctionName, start, end); m_pEdit->SetSel(start, end); if ( FunctionName == NULL ) continue; CString info (FunctionName); CString sep (":\n"); int level = 0; const char* Name; while ( TRUE ) { CBotVar* pVar = m_pProg->GivStackVars(Name, level--); if ( Name != FunctionName ) break; if ( pVar == NULL ) continue; // pVar->Maj(NULL, FALSE); while ( pVar != NULL ) { info += sep; info += pVar->GivName() + CBotString(" = ") + pVar->GivValString(); sep = ", "; pVar = pVar->GivNext(); } sep = "\n"; } if ( IDOK != AfxMessageBox(info, MB_OKCANCEL) ) break; if ( test == 1 ) { test = 0; FILE* pf; pf = fOpen( "TEST.CBO", "wb" ); m_pProg->SaveState(pf); fClose(pf); } if ( test == 2 ) { test = 0; FILE* pf; pf = fOpen( "TEST.CBO", "rb" ); m_pProg->RestoreState(pf); fClose(pf); } if ( test == 12 ) { test = 0; FILE* pf; pf = fOpen( "TEST.CBO", "wb" ); m_pProg->SaveState(pf); fClose(pf); pf = fOpen( "TEST.CBO", "rb" ); m_pProg->RestoreState(pf); fClose(pf); test = 13; } } if (m_pProg->GetError(code, start, end)) { m_pEdit->SetSel(start, end); TextError = CBotProgram::GivErrorText(code); AfxMessageBox(TextError); } delete pThisRobot; }
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(); }