CBotInstr* CBotReturn::Compile(CBotToken* &p, CBotCStack* pStack) { CBotToken* pp = p; if (!IsOfType(p, ID_RETURN)) return NULL; // should never happen CBotReturn* inst = new CBotReturn(); // creates the object inst->SetToken( pp ); CBotTypResult type = pStack->GetRetType(); if ( type.GetType() == 0 ) // returned void ? { if ( IsOfType( p, ID_SEP ) ) return inst; pStack->SetError( TX_BADTYPE, pp ); return NULL; } inst->m_Instr = CBotExpression::Compile(p, pStack); if ( pStack->IsOk() ) { CBotTypResult retType = pStack->GetTypResult(2); if (TypeCompatible(retType, type, ID_ASS)) { if ( IsOfType( p, ID_SEP ) ) return inst; pStack->SetError(TX_ENDOF, p->GetStart()); } pStack->SetError(TX_BADTYPE, p->GetStart()); } delete inst; return NULL; // no object, the error is on the stack }
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* CBotTwoOpExpr::Compile(CBotToken* &p, CBotCStack* pStack, int* pOperations) { int typeMask; if ( pOperations == nullptr ) pOperations = ListOp; int* pOp = pOperations; while ( *pOp++ != 0 ); // follows the table CBotCStack* pStk = pStack->TokenStack(); // one end of stack please // search the intructions that may be suitable to the left of the operation CBotInstr* left = (*pOp == 0) ? CBotParExpr::Compile( p, pStk ) : // expression (...) left CBotTwoOpExpr::Compile( p, pStk, pOp ); // expression A * B left if (left == nullptr) return pStack->Return(nullptr, pStk); // if error, transmit // did we expected the operand? int typeOp = p->GetType(); if ( IsInList(typeOp, pOperations, typeMask) ) { CBotTypResult type1, type2; type1 = pStk->GetTypResult(); // what kind of the first operand? if (typeOp == ID_LOGIC) // special case provided for: ? op1: op2; { if ( !type1.Eq(CBotTypBoolean) ) { pStk->SetError( CBotErrBadType1, p); return pStack->Return(nullptr, pStk); } CBotLogicExpr* inst = new CBotLogicExpr(); inst->m_condition = left; p = p->GetNext(); // skip the token of the operation inst->m_op1 = CBotExpression::Compile(p, pStk); CBotToken* pp = p; if ( inst->m_op1 == nullptr || !IsOfType( p, ID_DOTS ) ) { pStk->SetError( CBotErrNoDoubleDots, p->GetStart()); delete inst; return pStack->Return(nullptr, pStk); } type1 = pStk->GetTypResult(); inst->m_op2 = CBotExpression::Compile(p, pStk); if ( inst->m_op2 == nullptr ) { pStk->SetError( CBotErrNoTerminator, p->GetStart() ); delete inst; return pStack->Return(nullptr, pStk); } type2 = pStk->GetTypResult(); if (!TypeCompatible(type1, type2)) { pStk->SetError( CBotErrBadType2, pp ); delete inst; return pStack->Return(nullptr, pStk); } pStk->SetType(type1); // the greatest of 2 types return pStack->Return(inst, pStk); } CBotTwoOpExpr* inst = new CBotTwoOpExpr(); // element for operation inst->SetToken(p); // stores the operation p = p->GetNext(); // skip the token of the operation // looking statements that may be suitable for right if ( nullptr != (inst->m_rightop = CBotTwoOpExpr::Compile( p, pStk, pOp )) ) // expression (...) right { // there is an second operand acceptable type2 = pStk->GetTypResult(); // what kind of results? if ( type1.Eq(99) || type2.Eq(99) ) // operand is void { pStack->SetError(CBotErrBadType2, &inst->m_token); delete inst; return nullptr; } // what kind of result? int TypeRes = std::max( type1.GetType(CBotTypResult::GetTypeMode::NULL_AS_POINTER), type2.GetType(CBotTypResult::GetTypeMode::NULL_AS_POINTER) ); if (typeOp == ID_ADD && type1.Eq(CBotTypString)) { TypeRes = CBotTypString; type2 = type1; // any type convertible chain } else if (typeOp == ID_ADD && type2.Eq(CBotTypString)) { TypeRes = CBotTypString; type1 = type2; // any type convertible chain } else if (!TypeOk(TypeRes, typeMask)) type1.SetType(99);// error of type switch (typeOp) { case ID_LOG_OR: case ID_LOG_AND: case ID_TXT_OR: case ID_TXT_AND: case ID_EQ: case ID_NE: case ID_HI: case ID_LO: case ID_HS: case ID_LS: TypeRes = CBotTypBoolean; } if ( TypeCompatible (type1, type2, typeOp) ) // the results are compatible { // ok so, saves the operand in the object inst->m_leftop = left; // special for evaluation of the operations of the same level from left to right while ( IsInList(p->GetType(), pOperations, typeMask) ) // same operation(s) follows? { typeOp = p->GetType(); CBotTwoOpExpr* i = new CBotTwoOpExpr(); // element for operation i->SetToken(p); // stores the operation i->m_leftop = inst; // left operand type1 = TypeRes; p = p->GetNext(); // advance after i->m_rightop = CBotTwoOpExpr::Compile( p, pStk, pOp ); type2 = pStk->GetTypResult(); if ( !TypeCompatible (type1, type2, typeOp) ) // the results are compatible { pStk->SetError(CBotErrBadType2, &i->m_token); delete i; return pStack->Return(nullptr, pStk); } if ( TypeRes != CBotTypString ) // keep string conversion TypeRes = std::max(type1.GetType(), type2.GetType()); inst = i; } CBotTypResult t(type1); t.SetType(TypeRes); // is a variable on the stack for the type of result pStk->SetVar(CBotVar::Create("", t)); // and returns the requested object return pStack->Return(inst, pStk); } pStk->SetError(CBotErrBadType2, &inst->m_token); } // in case of error, releases the elements delete left; delete inst; // and transmits the error to the stack return pStack->Return(nullptr, pStk); } // if we are not dealing with an operation + or - // goes to that requested, the operand (left) found // instead of the object "addition" return pStack->Return(left, pStk); }