generator.cpp 66.4 KB
Newer Older
victor's avatar
 
victor committed
1
#include "generator.h"
Victor Yacovlev's avatar
Victor Yacovlev committed
2
#include "vm/vm_tableelem.hpp"
3
#include "vm/vm.hpp"
Victor Yacovlev's avatar
Victor Yacovlev committed
4 5
#include "extensionsystem/pluginmanager.h"
#include "interfaces/actorinterface.h"
victor's avatar
 
victor committed
6 7 8


namespace KumirCodeGenerator {
victor's avatar
victor committed
9
    
10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
using namespace Shared;

template <typename T> std::vector<T>& operator<<(std::vector<T> & vec, const T & value)
{
    vec.push_back(value);
    return vec;
}


template <typename T> std::deque<T>& operator<<(std::deque<T> & vec, const T & value)
{
    vec.push_back(value);
    return vec;
}


victor's avatar
 
victor committed
26 27 28 29 30 31 32 33

Generator::Generator(QObject *parent) :
    QObject(parent)
{
    m_ast = 0;
    m_bc = 0;
}

34
void Generator::reset(const AST::Data *ast, Bytecode::Data *bc, DebugLevel debugLevel)
victor's avatar
 
victor committed
35 36 37
{
    m_ast = ast;
    m_bc = bc;
38
    e_debugLevel = debugLevel;
victor's avatar
 
victor committed
39
    l_constants.clear();
victor's avatar
 
victor committed
40 41 42
    l_externs.clear();
}

43 44 45 46 47 48 49 50 51 52 53 54 55 56
static void getVarListSizes(const QVariant & var, int sizes[3], int fromDim)
{
    if (fromDim>2)
        return;
    sizes[0] = sizes[1] = sizes[2] = 1;
    QVariantList elems = var.toList();
    for (int i=0; i<elems.size(); i++) {
        if (elems.at(i).type()==QVariant::List) {
            getVarListSizes(elems[i], sizes, fromDim+1);
        }
    }
    sizes[fromDim] = qMax(sizes[fromDim], elems.size());
}

Victor Yacovlev's avatar
Victor Yacovlev committed
57
static VM::AnyValue makeAnyValue(const QVariant & val, std::list<Bytecode::ValueType> vt)
58 59 60
{
    if (val==QVariant::Invalid)
        return VM::AnyValue();
Victor Yacovlev's avatar
Victor Yacovlev committed
61
    switch (vt.front())
62 63 64 65 66 67 68 69 70 71 72
    {
    case Bytecode::VT_int:
        return VM::AnyValue(val.toInt());
    case Bytecode::VT_real:
        return VM::AnyValue(val.toDouble());
    case Bytecode::VT_bool:
        return VM::AnyValue(bool(val.toBool()));
    case Bytecode::VT_char:
        return VM::AnyValue(Kumir::Char(val.toChar().unicode()));
    case Bytecode::VT_string:
        return VM::AnyValue(val.toString().toStdWString());
Victor Yacovlev's avatar
Victor Yacovlev committed
73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105
    case Bytecode::VT_record:
    {
        QVariantList valueFields = val.toList();
        VM::AnyValue value(Bytecode::VT_record);
        VM::Record & record = value.toRecord();
        size_t offset = 0;
        size_t curSize = 0;
        std::list<Bytecode::ValueType>::const_iterator it = vt.begin();
        it++;
        for (int i=1; i<vt.size(); i++) {
            switch (*it) {
            case Bytecode::VT_int:
                record.push_back(VM::AnyValue(valueFields[i-1].toInt()));
                break;
            case Bytecode::VT_real:
                record.push_back(VM::AnyValue(valueFields[i-1].toDouble()));
                break;
            case Bytecode::VT_bool:
                record.push_back(VM::AnyValue(valueFields[i-1].toBool()));
                break;
            case Bytecode::VT_char:
                record.push_back(VM::AnyValue(valueFields[i-1].toChar().unicode()));
                break;
            case Bytecode::VT_string:
                record.push_back(VM::AnyValue(valueFields[i-1].toString().toStdWString()));
                break;
            default:
                break;
            }
            it++;
        }
        return value;
    }
106 107 108 109 110 111 112 113 114 115 116
    default:
        return VM::AnyValue();
    }
}

static Bytecode::TableElem makeConstant(const ConstValue & val)
{
    Bytecode::TableElem e;
    e.type = Bytecode::EL_CONST;
    e.vtype = val.baseType;
    e.dimension = val.dimension;
Victor Yacovlev's avatar
Victor Yacovlev committed
117
    if (val.dimension==0) {
118 119
        VM::Variable var;
        var.setValue(makeAnyValue(val.value, val.baseType));
Victor Yacovlev's avatar
Victor Yacovlev committed
120
        var.setBaseType(val.baseType.front());
121 122 123 124 125 126 127 128 129
        var.setDimension(val.dimension);
        var.setConstantFlag(true);
        e.initialValue = var;
    }
    else {
        int sizes[3];
        getVarListSizes(val.value, sizes, 0);
        VM::Variable var;
        var.setConstantFlag(true);
Victor Yacovlev's avatar
Victor Yacovlev committed
130
        var.setBaseType(val.baseType.front());
131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204
        var.setDimension(val.dimension);
        int bounds[7] = { 1,  sizes[0], 1, sizes[1], 1, sizes[2], var.dimension()*2 };
        var.setBounds(bounds);
        var.init();
        if (var.dimension()==1) {
            QVariantList listX = val.value.toList();
            for (int x=1; x<=sizes[0]; x++) {
                if (x-1 < listX.size()) {
                    var.setValue(x, makeAnyValue(listX[x-1], val.baseType));
                }
                else {
                    var.setValue(x, VM::AnyValue());
                }
            }
        } // end if (var.dimension()==1)
        else if (var.dimension()==2) {
            QVariantList listY = val.value.toList();
            for (int y=1; y<=sizes[0]; y++) {
                if (y-1 < listY.size()) {
                    QVariantList listX = listY[y-1].toList();
                    for (int x=1; x<=sizes[1]; x++) {
                        if (x-1 < listX.size()) {
                            var.setValue(y, x, makeAnyValue(listX[x-1], val.baseType));
                        }
                        else {
                            var.setValue(y, x, VM::AnyValue());
                        }
                    }
                }
                else {
                    for (int x=1; x<=sizes[1]; x++) {
                        var.setValue(y, x, VM::AnyValue());
                    }
                }
            }
        } // end else if (var.dimension()==2)
        else if (var.dimension()==3) {
            QVariantList listZ = val.value.toList();
            for (int z=1; z<=sizes[0]; z++) {
                if (z-1 < listZ.size()) {
                    QVariantList listY = listZ[z-1].toList();
                    for (int y=1; y<=sizes[1]; y++) {
                        if (y-1 < listY.size()) {
                            QVariantList listX = listY[y-1].toList();
                            for (int x=1; x<=sizes[2]; x++) {
                                if (x-1 < listX.size()) {
                                    var.setValue(z, y, x, makeAnyValue(listX[x-1], val.baseType));
                                }
                                else {
                                    var.setValue(z, y, x, VM::AnyValue());
                                }
                            }
                        }
                        else {
                            for (int x=1; x<=sizes[1]; x++) {
                                var.setValue(z, y, x, VM::AnyValue());
                            }
                        }
                    }
                }
                else {
                    for (int y=1; y<=sizes[1]; y++) {
                        for (int x=1; x<=sizes[2]; x++) {
                            var.setValue(z, y, x, VM::AnyValue());
                        }
                    }
                }
            }
        } // end else if (var.dimension()==2)
        e.initialValue = var;
    }
    return e;
}

victor's avatar
 
victor committed
205 206 207
void Generator::generateConstantTable()
{
    for (int i=l_constants.size()-1; i>=0; i--) {
208 209
        const ConstValue cons = l_constants[i];
        Bytecode::TableElem e = makeConstant(cons);
victor's avatar
 
victor committed
210
        e.id = i;
211
        m_bc->d.push_front(e);
victor's avatar
 
victor committed
212 213 214 215 216 217 218 219 220 221 222
    }
}

void Generator::generateExternTable()
{
    for (int i=l_externs.size()-1; i>=0; i--) {
        QPair<quint8, quint16> ext = l_externs[i];
        Bytecode::TableElem e;
        e.type = Bytecode::EL_EXTERN;
        e.module = ext.first;
        e.algId = e.id = ext.second;
Victor Yacovlev's avatar
Victor Yacovlev committed
223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241
        const AST::Module * mod = m_ast->modules[ext.first];
        const QList<AST::Algorhitm*> table = mod->header.algorhitms + mod->header.operators;
        const AST::Algorhitm * alg = table[ext.second];
        QList<ExtensionSystem::KPlugin*> plugins =
                ExtensionSystem::PluginManager::instance()->loadedPlugins("Actor*");
        QString moduleFileName;
        QString signature;
        for (int m=0; m<plugins.size(); m++) {
            Shared::ActorInterface * actor = qobject_cast<Shared::ActorInterface*>(plugins[m]);
            if (actor && actor->name()==mod->header.name) {
                signature = actor->funcList()[e.id];
                moduleFileName = plugins[m]->pluginSpec().libraryFileName;
                // Make filename relative
                int slashP = moduleFileName.lastIndexOf("/");
                if (slashP!=-1) {
                    moduleFileName = moduleFileName.mid(slashP+1);
                }
            }
        }
242 243
        if (mod->header.type==AST::ModTypeCached)
            moduleFileName = mod->header.name;
Victor Yacovlev's avatar
Victor Yacovlev committed
244 245 246 247
        e.moduleName = mod->header.name.toStdWString();
        e.name = alg->header.name.toStdWString();
        e.signature = signature.toStdWString();
        e.fileName = moduleFileName.toStdWString();
248
        m_bc->d.push_front(e);
victor's avatar
 
victor committed
249
    }
victor's avatar
 
victor committed
250 251
}

252

Victor Yacovlev's avatar
Victor Yacovlev committed
253
QList<Bytecode::ValueType> Generator::valueType(const AST::Type & t)
victor's avatar
 
victor committed
254
{
Victor Yacovlev's avatar
Victor Yacovlev committed
255
    QList<Bytecode::ValueType> result;
256
    if (t.kind==AST::TypeInteger)
Victor Yacovlev's avatar
Victor Yacovlev committed
257
        result << Bytecode::VT_int;
258
    else if (t.kind==AST::TypeReal)
Victor Yacovlev's avatar
Victor Yacovlev committed
259
        result << Bytecode::VT_real;
260
    else if (t.kind==AST::TypeBoolean)
Victor Yacovlev's avatar
Victor Yacovlev committed
261
        result << Bytecode::VT_bool;
262
    else if (t.kind==AST::TypeString)
Victor Yacovlev's avatar
Victor Yacovlev committed
263
        result << Bytecode::VT_string;
264
    else if (t.kind==AST::TypeCharect)
Victor Yacovlev's avatar
Victor Yacovlev committed
265 266
        result << Bytecode::VT_char;
    else if (t.kind==AST::TypeUser) {
Victor Yacovlev's avatar
Victor Yacovlev committed
267
        result << Bytecode::VT_record;
Victor Yacovlev's avatar
Victor Yacovlev committed
268 269 270 271 272
        for (int i=0; i<t.userTypeFields.size(); i++) {
            AST::Field field = t.userTypeFields[i];
            result << valueType(field.second);
        }
    }
victor's avatar
 
victor committed
273
    else
Victor Yacovlev's avatar
Victor Yacovlev committed
274 275
        result << Bytecode::VT_void;
    return result;
victor's avatar
 
victor committed
276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309
}

Bytecode::ValueKind Generator::valueKind(AST::VariableAccessType t)
{
    if (t==AST::AccessArgumentIn)
        return Bytecode::VK_In;
    else if (t==AST::AccessArgumentOut)
        return Bytecode::VK_Out;
    else if (t==AST::AccessArgumentInOut)
        return Bytecode::VK_InOut;
    else
        return Bytecode::VK_Plain;
}

Bytecode::InstructionType Generator::operation(AST::ExpressionOperator op)
{
    if (op==AST::OpSumm)
        return Bytecode::SUM;
    else if (op==AST::OpSubstract)
        return Bytecode::SUB;
    else if (op==AST::OpMultiply)
        return Bytecode::MUL;
    else if (op==AST::OpDivision)
        return Bytecode::DIV;
    else if (op==AST::OpPower)
        return Bytecode::POW;
    else if (op==AST::OpNot)
        return Bytecode::NEG;
    else if (op==AST::OpAnd)
        return Bytecode::AND;
    else if (op==AST::OpOr)
        return Bytecode::OR;
    else if (op==AST::OpEqual)
        return Bytecode::EQ;
victor's avatar
 
victor committed
310 311
    else if (op==AST::OpNotEqual)
        return Bytecode::NEQ;
victor's avatar
 
victor committed
312 313 314 315 316 317 318 319 320 321 322 323 324 325
    else if (op==AST::OpLess)
        return Bytecode::LS;
    else if (op==AST::OpGreater)
        return Bytecode::GT;
    else if (op==AST::OpLessOrEqual)
        return Bytecode::LEQ;
    else if (op==AST::OpGreaterOrEqual)
        return Bytecode::GEQ;
    else
        return Bytecode::NOP;
}

void Generator::addModule(const AST::Module *mod)
{
victor's avatar
 
victor committed
326 327
    if (!mod->header.enabled)
        return;
victor's avatar
 
victor committed
328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346
    int id = m_ast->modules.indexOf(const_cast<AST::Module*>(mod));
    if (mod->header.type==AST::ModTypeExternal) {

    }
    else {
        addKumirModule(id, mod);
    }
}



void Generator::addKumirModule(int id, const AST::Module *mod)
{
    for (int i=0; i<mod->impl.globals.size(); i++) {
        const AST::Variable * var = mod->impl.globals[i];
        Bytecode::TableElem glob;
        glob.type = Bytecode::EL_GLOBAL;
        glob.module = quint8(id);
        glob.id = quint16(i);
347
        glob.name = var->name.toStdWString();
victor's avatar
 
victor committed
348
        glob.dimension = quint8(var->dimension);
Victor Yacovlev's avatar
Victor Yacovlev committed
349
        glob.vtype = valueType(var->baseType).toStdList();
victor's avatar
 
victor committed
350
        glob.refvalue = valueKind(var->accessType);
351
        m_bc->d.push_back(glob);
victor's avatar
 
victor committed
352 353
    }
    Bytecode::TableElem initElem;
victor's avatar
 
victor committed
354 355
    Bytecode::Instruction returnFromInit;
    returnFromInit.type = Bytecode::RET;
victor's avatar
 
victor committed
356 357
    initElem.type = Bytecode::EL_INIT;
    initElem.module = quint8(id);
358
    initElem.moduleName = mod->header.name.toStdWString();
359 360
    initElem.instructions = instructions(id, -1, 0, mod->impl.initializerBody).toVector().toStdVector();
    if (!initElem.instructions.empty())
victor's avatar
 
victor committed
361
        initElem.instructions << returnFromInit;
362 363
    if (!initElem.instructions.empty())
        m_bc->d.push_back(initElem);
victor's avatar
 
victor committed
364 365 366 367
    const AST::Module * mainMod = 0;
    const AST::Algorhitm * mainAlg = 0;
    int mainModId = -1;
    int mainAlgorhitmId = -1;
victor's avatar
 
victor committed
368 369 370 371
    for (int i=0; i<mod->impl.algorhitms.size() ; i++) {
        const AST::Algorhitm * alg = mod->impl.algorhitms[i];
        Bytecode::ElemType ft = Bytecode::EL_FUNCTION;
        if (mod->header.name.isEmpty() && i==0) {
victor's avatar
 
victor committed
372
            ft = Bytecode::EL_MAIN;
373
            if (!alg->header.arguments.isEmpty() || alg->header.returnType.kind!=AST::TypeNone)
victor's avatar
 
victor committed
374
            {
victor's avatar
 
victor committed
375 376 377 378 379
                mainMod = mod;
                mainAlg = alg;
                mainModId = id;
                mainAlgorhitmId = i;
            }
victor's avatar
 
victor committed
380 381 382 383
        }
        if (alg->header.specialType==AST::AlgorhitmTypeTesting) {
            ft = Bytecode::EL_TESTING;
        }
384
        addFunction(i, id, ft, mod, alg);
victor's avatar
 
victor committed
385
    }
victor's avatar
 
victor committed
386 387 388
    if (mainMod && mainAlg) {
        addInputArgumentsMainAlgorhitm(mainModId, mainAlgorhitmId, mainMod, mainAlg);
    }
victor's avatar
 
victor committed
389 390 391 392 393 394 395 396 397 398 399 400
}

void Generator::shiftInstructions(QList<Bytecode::Instruction> &instrs, int offset)
{
    for (int i=0; i<instrs.size(); i++) {
        Bytecode::InstructionType t = instrs.at(i).type;
        if (t==Bytecode::JNZ || t==Bytecode::JZ || t==Bytecode::JUMP) {
            instrs[i].arg += offset;
        }
    }
}

victor's avatar
 
victor committed
401 402 403 404 405 406 407
void Generator::addInputArgumentsMainAlgorhitm(int moduleId, int algorhitmId, const AST::Module *mod, const AST::Algorhitm *alg)
{
    // Generate hidden algorhitm, which will called before main to input arguments
    int algId = mod->impl.algorhitms.size();
    QList<Bytecode::Instruction> instrs;
    Bytecode::Instruction l;
    l.type = Bytecode::LINE;
victor's avatar
 
victor committed
408
    l.arg = alg->impl.headerLexems[0]->lineNo;
victor's avatar
 
victor committed
409 410 411 412 413
    instrs << l;
    QList<quint16> varsToOut;
    int locOffset = 0;

    // Add function return as local
414
    if (alg->header.returnType.kind!=AST::TypeNone) {
victor's avatar
 
victor committed
415 416 417 418 419 420
        const AST::Variable * retval = returnValue(alg);
        Bytecode::TableElem loc;
        loc.type = Bytecode::EL_LOCAL;
        loc.module = moduleId;
        loc.algId = algId;
        loc.id = 0;
421
        loc.name = tr("Function return value").toStdWString();
victor's avatar
 
victor committed
422
        loc.dimension = 0;
Victor Yacovlev's avatar
Victor Yacovlev committed
423
        loc.vtype = valueType(retval->baseType).toStdList();
victor's avatar
 
victor committed
424
        loc.refvalue = Bytecode::VK_Plain;
425 426
        m_bc->d.push_back(loc);
        varsToOut << constantValue(Bytecode::VT_int, 0, 0);
victor's avatar
 
victor committed
427 428 429 430 431 432 433 434 435 436 437
        locOffset = 1;
    }

    // Add arguments as locals
    for (int i=0; i<alg->header.arguments.size(); i++) {
        const AST::Variable * var = alg->header.arguments[i];
        Bytecode::TableElem loc;
        loc.type = Bytecode::EL_LOCAL;
        loc.module = moduleId;
        loc.algId = algId;
        loc.id = locOffset+i;
438
        loc.name = var->name.toStdWString();
victor's avatar
 
victor committed
439
        loc.dimension = var->dimension;
Victor Yacovlev's avatar
Victor Yacovlev committed
440
        loc.vtype = valueType(var->baseType).toStdList();
victor's avatar
 
victor committed
441
        loc.refvalue = Bytecode::VK_Plain;
442
        m_bc->d.push_back(loc);
victor's avatar
 
victor committed
443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469

    }

    for (int i=0; i<alg->header.arguments.size(); i++) {
        AST::Variable * var = alg->header.arguments[i];
        // Initialize argument
        if (var->dimension > 0) {
            for (int j=var->dimension-1; j>=0 ; j--) {
                QList<Bytecode::Instruction> initBounds;
                initBounds << calculate(moduleId, algorhitmId, 0, var->bounds[j].second);
                initBounds << calculate(moduleId, algorhitmId, 0, var->bounds[j].first);
                instrs << initBounds;
            }
            Bytecode::Instruction bounds;
            bounds.type = Bytecode::SETARR;
            bounds.scope = Bytecode::LOCAL;
            bounds.arg = quint16(i+locOffset);
            instrs << bounds;
        }
        Bytecode::Instruction init;
        init.type = Bytecode::INIT;
        init.scope = Bytecode::LOCAL;
        init.arg = quint16(i+locOffset);
        instrs << init;
        if (var->initialValue.isValid() && var->dimension==0) {
            Bytecode::Instruction load;
            load.type = Bytecode::LOAD;
Victor Yacovlev's avatar
Victor Yacovlev committed
470
            load.scope = Bytecode::CONSTT;
Victor Yacovlev's avatar
Victor Yacovlev committed
471
            load.arg = constantValue(valueType(var->baseType), 0, var->initialValue);
victor's avatar
 
victor committed
472 473 474 475 476 477 478 479 480 481 482 483 484 485 486
            instrs << load;
            Bytecode::Instruction store = init;
            store.type = Bytecode::STORE;
            instrs << store;
            Bytecode::Instruction pop;
            pop.type = Bytecode::POP;
            pop.registerr = 0;
            instrs << pop;
        }

        // If IN of INOUT argument -- require input
        // This made by special function call
        if (var->accessType==AST::AccessArgumentIn || var->accessType==AST::AccessArgumentInOut)  {
            Bytecode::Instruction varId;
            varId.type = Bytecode::LOAD;
Victor Yacovlev's avatar
Victor Yacovlev committed
487
            varId.scope = Bytecode::CONSTT;
488
            varId.arg = constantValue(Bytecode::VT_int, 0, i+locOffset);
victor's avatar
 
victor committed
489 490 491 492 493 494 495 496 497

            Bytecode::Instruction call;
            call.type = Bytecode::CALL;
            call.module = 0xFF;
            call.arg = 0xBB01;

            instrs << varId << call;
        }
        if (var->accessType==AST::AccessArgumentOut || var->accessType==AST::AccessArgumentInOut) {
498
            varsToOut << constantValue(Bytecode::VT_int, 0, i+locOffset);
victor's avatar
 
victor committed
499 500 501 502 503
        }
    }

    // Call main (first) algorhitm:
    //  -- 1) Push arguments
504
    for (int i=0; i<alg->header.arguments.size(); i++) {
victor's avatar
 
victor committed
505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520
        AST::VariableAccessType t = alg->header.arguments[i]->accessType;
        if (t==AST::AccessArgumentIn) {
            Bytecode::Instruction load;
            load.type = Bytecode::LOAD;
            load.scope = Bytecode::LOCAL;
            load.arg = quint16(i+locOffset);
            instrs << load;
        }
        else if (t==AST::AccessArgumentOut||t==AST::AccessArgumentInOut) {
            Bytecode::Instruction ref;
            ref.type = Bytecode::REF;
            ref.scope = Bytecode::LOCAL;
            ref.arg = quint16(i+locOffset);
            instrs << ref;
        }
    }
521 522 523 524 525 526 527

    Bytecode::Instruction argsCount;
    argsCount.type = Bytecode::LOAD;
    argsCount.scope = Bytecode::CONSTT;
    argsCount.arg = constantValue(QList<Bytecode::ValueType>()<<Bytecode::VT_int,0,alg->header.arguments.size());
    instrs << argsCount;

victor's avatar
 
victor committed
528 529 530 531 532 533
    //  -- 2) Call main (first) algorhitm
    Bytecode::Instruction callInstr;
    callInstr.type = Bytecode::CALL;
    findFunction(alg, callInstr.module, callInstr.arg);
    instrs << callInstr;
    //  -- 3) Store return value
534
    if (alg->header.returnType.kind!=AST::TypeNone) {
victor's avatar
 
victor committed
535 536 537
        Bytecode::Instruction storeRetVal;
        storeRetVal.type = Bytecode::STORE;
        storeRetVal.scope = Bytecode::LOCAL;
victor's avatar
 
victor committed
538
        storeRetVal.arg = 0;
victor's avatar
 
victor committed
539 540 541 542 543 544 545 546 547 548 549
        Bytecode::Instruction pop;
        pop.type = Bytecode::POP;
        pop.registerr = 0;
        instrs << storeRetVal << pop;
    }

    // Show what in result...

    for (int i=0; i<varsToOut.size(); i++) {
        Bytecode::Instruction arg;
        arg.type = Bytecode::LOAD;
Victor Yacovlev's avatar
Victor Yacovlev committed
550
        arg.scope = Bytecode::CONSTT;
victor's avatar
 
victor committed
551 552 553 554 555 556 557 558 559 560
        arg.arg = varsToOut[i];
        instrs << arg;
        Bytecode::Instruction callShow;
        callShow.type = Bytecode::CALL;
        callShow.module = 0xFF;
        callShow.arg = 0xBB02;
        instrs << callShow;
    }

    Bytecode::TableElem func;
victor's avatar
 
victor committed
561
    func.type = Bytecode::EL_BELOWMAIN;
victor's avatar
 
victor committed
562 563
    func.algId = func.id = algId;
    func.module = moduleId;
564 565 566 567
    func.moduleName = mod->header.name.toStdWString();
    func.name = QString::fromAscii("@below_main").toStdWString();
    func.instructions = instrs.toVector().toStdVector();
    m_bc->d.push_back(func);
victor's avatar
 
victor committed
568 569 570

}

571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602
QString typeSignature(const AST::Type & tp) {
    QString signature;
    if (tp.kind==AST::TypeNone) {
        signature += "void";
    }
    else if (tp.kind==AST::TypeInteger) {
        signature += "int";
    }
    else if (tp.kind==AST::TypeReal) {
        signature += "real";
    }
    else if (tp.kind==AST::TypeBoolean) {
        signature += "bool";
    }
    else if (tp.kind==AST::TypeCharect) {
        signature += "char";
    }
    else if (tp.kind==AST::TypeString) {
        signature += "string";
    }
    else if (tp.kind==AST::TypeUser) {
        signature += "record "+tp.name+" {";
        for (int i=0; i<tp.userTypeFields.size(); i++) {
            signature += typeSignature(tp.userTypeFields.at(i).second);
            if (i<tp.userTypeFields.size()-1)
                signature += ";";
        }
        signature += "}";
    }
    return signature;
}

603
void Generator::addFunction(int id, int moduleId, Bytecode::ElemType type, const AST::Module * mod, const AST::Algorhitm *alg)
victor's avatar
 
victor committed
604
{
victor's avatar
 
victor committed
605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625
    QString headerError =  "";
    QString beginError = "";

    if (alg->impl.headerLexems.size()>0) {
        for (int i=0; i<alg->impl.headerLexems.size();i++) {
            if (alg->impl.headerLexems[i]->error.size()>0) {
                headerError = ErrorMessages::message("KumirAnalizer", QLocale::Russian, alg->impl.headerLexems[i]->error);
                break;
            }
        }
    }

    if (alg->impl.beginLexems.size()>0) {
        for (int i=0; i<alg->impl.beginLexems.size();i++) {
            if (alg->impl.beginLexems[i]->error.size()>0) {
                beginError = ErrorMessages::message("KumirAnalizer", QLocale::Russian, alg->impl.beginLexems[i]->error);
                break;
            }
        }
    }

626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644
    QString signature;

    signature = typeSignature(alg->header.returnType)+":";

    for (int i=0; i<alg->header.arguments.size(); i++) {
        const AST::Variable * var = alg->header.arguments[i];
        if (var->accessType==AST::AccessArgumentIn)
            signature += "in ";
        else if (var->accessType==AST::AccessArgumentOut)
            signature += "out ";
        else if (var->accessType==AST::AccessArgumentInOut)
            signature += "inout ";
        signature += typeSignature(var->baseType);
        for (int j=0; j<var->dimension; j++) {
            signature += "[]";
        }
        if (i<alg->header.arguments.size()-1)
            signature += ",";
    }
victor's avatar
 
victor committed
645

victor's avatar
 
victor committed
646 647 648 649 650 651 652
    for (int i=0; i<alg->impl.locals.size(); i++) {
        const AST::Variable * var = alg->impl.locals[i];
        Bytecode::TableElem loc;
        loc.type = Bytecode::EL_LOCAL;
        loc.module = moduleId;
        loc.algId = id;
        loc.id = i;
653
        loc.name = var->name.toStdWString();
victor's avatar
 
victor committed
654
        loc.dimension = var->dimension;
Victor Yacovlev's avatar
Victor Yacovlev committed
655
        loc.vtype = valueType(var->baseType).toStdList();
victor's avatar
 
victor committed
656
        loc.refvalue = valueKind(var->accessType);
657
        m_bc->d.push_back(loc);
victor's avatar
 
victor committed
658 659 660 661 662
    }
    Bytecode::TableElem func;
    func.type = type;
    func.module = moduleId;
    func.algId = func.id = id;
663
    func.name = alg->header.name.toStdWString();
664
    func.signature = signature.toStdWString();
665
    func.moduleName = mod->header.name.toStdWString();
victor's avatar
 
victor committed
666 667
    QList<Bytecode::Instruction> argHandle;

victor's avatar
 
victor committed
668 669
    Bytecode::Instruction l;
    l.type = Bytecode::LINE;
victor's avatar
 
victor committed
670
    l.arg = alg->impl.headerLexems[0]->lineNo;
Victor Yacovlev's avatar
Victor Yacovlev committed
671 672
    if (e_debugLevel!=GeneratorInterface::NoDebug)
        argHandle << l;
victor's avatar
 
victor committed
673

victor's avatar
 
victor committed
674 675
    if (headerError.length()>0) {
        Bytecode::Instruction err;
Victor Yacovlev's avatar
Victor Yacovlev committed
676 677
        err.type = Bytecode::ERRORR;
        err.scope = Bytecode::CONSTT;
678
        err.arg = constantValue(Bytecode::VT_string, 0, headerError);
victor's avatar
 
victor committed
679 680 681
        argHandle << err;
    }

682 683 684 685 686 687 688 689 690 691 692 693 694
    if (alg->impl.headerRuntimeError.size()>0) {
        Bytecode::Instruction l;
        l.type = Bytecode::LINE;
        l.arg = alg->impl.headerRuntimeErrorLine;
        argHandle << l;
        l.type = Bytecode::ERRORR;
        l.scope = Bytecode::CONSTT;
        l.arg = constantValue(Bytecode::VT_string, 0,
                              ErrorMessages::message("KumirAnalizer", QLocale::Russian, alg->impl.headerRuntimeError)
                              );
        argHandle << l;
    }

695
    if (alg->impl.endLexems.size()>0 && e_debugLevel==GeneratorInterface::LinesAndVariables) {
victor's avatar
 
victor committed
696 697 698 699 700 701

        Bytecode::Instruction clearmarg;
        clearmarg.type = Bytecode::CLEARMARG;
        clearmarg.arg = alg->impl.endLexems[0]->lineNo;
        argHandle << clearmarg;
    }
victor's avatar
 
victor committed
702

victor's avatar
 
victor committed
703 704 705 706 707 708
    Bytecode::Instruction ctlOn, ctlOff;
    ctlOn.type = ctlOff.type = Bytecode::CTL;
    ctlOn.module = ctlOff.module = 0x01; // Set error stack offset lineno
    ctlOn.arg = 0x0001;
    ctlOff.arg = 0x0000;

709 710
    if (e_debugLevel==GeneratorInterface::LinesAndVariables)
        argHandle << ctlOn;
victor's avatar
 
victor committed
711

Victor Yacovlev's avatar
Victor Yacovlev committed
712
    for (int i=alg->header.arguments.size()-1; i>=0; i--) {
victor's avatar
 
victor committed
713 714
        Bytecode::Instruction store;
        const AST::Variable * var = alg->header.arguments[i];
victor's avatar
 
victor committed
715 716 717 718
        if (var->accessType==AST::AccessArgumentIn)
            store.type = Bytecode::STORE;
        else
            store.type = Bytecode::SETREF;
victor's avatar
 
victor committed
719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734
        findVariable(moduleId, id, var, store.scope, store.arg);
        argHandle << store;
        Bytecode::Instruction pop;
        pop.type = Bytecode::POP;
        pop.registerr = 0;
        argHandle << pop;
    }

    for (int i=0; i<alg->header.arguments.size(); i++) {
        const AST::Variable * var = alg->header.arguments[i];
        if (var->dimension>0) {
            for (int i=var->dimension-1; i>=0; i--) {
                argHandle << calculate(moduleId, id, 0, var->bounds[i].second);
                argHandle << calculate(moduleId, id, 0, var->bounds[i].first);
            }
            Bytecode::Instruction bounds;
victor's avatar
 
victor committed
735
            bounds.type = Bytecode::UPDARR;
victor's avatar
 
victor committed
736 737 738 739 740 741 742 743 744 745 746
            findVariable(moduleId, id, var, bounds.scope, bounds.arg);
            argHandle << bounds;
        }
        if (var->accessType==AST::AccessArgumentOut) {
            Bytecode::Instruction init;
            init.type = Bytecode::INIT;
            findVariable(moduleId, id, var, init.scope, init.arg);
            argHandle << init;
        }
    }

victor's avatar
 
victor committed
747 748
    if (alg->impl.beginLexems.size()) {
        l.arg = alg->impl.beginLexems[0]->lineNo;
Victor Yacovlev's avatar
Victor Yacovlev committed
749 750
        if (e_debugLevel!=GeneratorInterface::NoDebug)
            argHandle << l;
victor's avatar
 
victor committed
751
    }
victor's avatar
 
victor committed
752

victor's avatar
 
victor committed
753 754
    if (beginError.length()>0) {
        Bytecode::Instruction err;
Victor Yacovlev's avatar
Victor Yacovlev committed
755 756
        err.type = Bytecode::ERRORR;
        err.scope = Bytecode::CONSTT;
757
        err.arg = constantValue(Bytecode::VT_string, 0, beginError);
victor's avatar
 
victor committed
758 759 760
        argHandle << err;
    }

761 762
    if (e_debugLevel==GeneratorInterface::LinesAndVariables)
        argHandle << ctlOff;
victor's avatar
 
victor committed
763

victor's avatar
 
victor committed
764 765 766 767
    QList<Bytecode::Instruction> pre = instructions(moduleId, id, 0, alg->impl.pre);
    QList<Bytecode::Instruction> body = instructions(moduleId, id, 0, alg->impl.body);
    QList<Bytecode::Instruction> post = instructions(moduleId, id, 0, alg->impl.post);

victor's avatar
 
victor committed
768 769
    shiftInstructions(pre, argHandle.size());

victor's avatar
 
victor committed
770 771
    int offset = argHandle.size() + pre.size();
    shiftInstructions(body, offset);
victor's avatar
 
victor committed
772
    offset += body.size();
victor's avatar
 
victor committed
773 774 775 776 777 778
    shiftInstructions(post, offset);

    QList<Bytecode::Instruction> ret;

    int retIp = argHandle.size() + pre.size() + body.size() + post.size();

victor's avatar
 
victor committed
779 780
    setBreakAddress(body, 0, retIp);

victor's avatar
 
victor committed
781

victor's avatar
 
victor committed
782 783
    Bytecode::Instruction line;
    line.type = Bytecode::LINE;
victor's avatar
 
victor committed
784 785
    if (alg->impl.endLexems.size()>0) {
        line.arg = alg->impl.endLexems[0]->lineNo;
Victor Yacovlev's avatar
Victor Yacovlev committed
786 787
        if (e_debugLevel!=GeneratorInterface::NoDebug)
            ret << line;
victor's avatar
 
victor committed
788
    }
victor's avatar
 
victor committed
789

790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808

    if (alg->impl.endLexems.size()>0) {
        QString endError;
        for (int i=0; i<alg->impl.endLexems.size();i++) {
            if (alg->impl.endLexems[i]->error.size()>0) {
                endError = ErrorMessages::message("KumirAnalizer", QLocale::Russian, alg->impl.endLexems[i]->error);
                break;
            }
        }
        if (endError.length()>0) {
            Bytecode::Instruction err;
            err.type = Bytecode::ERRORR;
            err.scope = Bytecode::CONSTT;
            err.arg = constantValue(Bytecode::VT_string, 0, endError);
            ret << err;
        }
    }


victor's avatar
 
victor committed
809 810 811 812 813 814 815 816
    const AST::Variable * retval = returnValue(alg);
    if (retval) {
        Bytecode::Instruction loadRetval;
        loadRetval.type = Bytecode::LOAD;
        findVariable(moduleId, id, retval, loadRetval.scope, loadRetval.arg);
        ret << loadRetval;

    }
victor's avatar
 
victor committed
817

victor's avatar
 
victor committed
818 819 820
    Bytecode::Instruction retturn;
    retturn.type = Bytecode::RET;
    ret << retturn;
victor's avatar
 
victor committed
821

victor's avatar
 
victor committed
822
    QList<Bytecode::Instruction> instrs = argHandle + pre + body + post + ret;
823 824
    func.instructions = instrs.toVector().toStdVector();
    m_bc->d.push_back(func);
victor's avatar
 
victor committed
825 826 827 828 829 830 831 832 833 834 835
}

QList<Bytecode::Instruction> Generator::instructions(
    int modId, int algId, int level,
    const QList<AST::Statement *> &statements)
{
    QList<Bytecode::Instruction> result;
    for (int i=0; i<statements.size(); i++) {
        const AST::Statement * st = statements[i];
        switch (st->type) {
        case AST::StError:
836
            if (!st->skipErrorEvaluation)
Victor Yacovlev's avatar
Victor Yacovlev committed
837
                ERRORR(modId, algId, level, st, result);
victor's avatar
 
victor committed
838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864
            break;
        case AST::StAssign:
            ASSIGN(modId, algId, level, st, result);
            break;
        case AST::StAssert:
            ASSERT(modId, algId, level, st, result);
            break;
        case AST::StVarInitialize:
            INIT(modId, algId, level, st, result);
            break;
        case AST::StInput:
            CALL_SPECIAL(modId, algId, level, st, result);
            break;
        case AST::StOutput:
            CALL_SPECIAL(modId, algId, level, st, result);
            break;
        case AST::StLoop:
            LOOP(modId, algId, level+1, st, result);
            break;
        case AST::StIfThenElse:
            IFTHENELSE(modId, algId, level, st, result);
            break;
        case AST::StSwitchCaseElse:
            SWITCHCASEELSE(modId, algId, level, st, result);
            break;
        case AST::StBreak:
            BREAK(modId, algId, level, st, result);
victor's avatar
 
victor committed
865 866 867 868 869 870 871
            break;
        case AST::StPause:
            PAUSE_STOP(modId, algId, level, st, result);
            break;
        case AST::StHalt:
            PAUSE_STOP(modId, algId, level, st, result);
            break;
victor's avatar
 
victor committed
872 873 874 875 876 877 878
        default:
            break;
        }
    }
    return result;
}

879
quint16 Generator::constantValue(Bytecode::ValueType type, quint8 dimension, const QVariant &value)
Victor Yacovlev's avatar
Victor Yacovlev committed
880 881 882 883 884 885 886
{
    std::list<Bytecode::ValueType> vt;
    vt.push_back(type);
    return constantValue(vt, dimension, value);
}

quint16 Generator::constantValue(const std::list<Bytecode::ValueType> & type, quint8 dimension, const QVariant &value)
victor's avatar
 
victor committed
887
{
888 889 890 891
    ConstValue c;
    c.baseType = type;
    c.dimension = dimension;
    c.value = value;
victor's avatar
 
victor committed
892 893 894 895 896 897 898 899 900
    if (!l_constants.contains(c)) {
        l_constants << c;
        return l_constants.size()-1;
    }
    else {
        return l_constants.indexOf(c);
    }
}

Victor Yacovlev's avatar
Victor Yacovlev committed
901
void Generator::ERRORR(int , int , int , const AST::Statement * st, QList<Bytecode::Instruction>  & result)
victor's avatar
 
victor committed
902 903 904 905 906 907 908
{
    int lineNo = st->lexems[0]->lineNo;
    Bytecode::Instruction l;
    l.type = Bytecode::LINE;
    l.arg = lineNo;
    const QString error = ErrorMessages::message("KumirAnalizer", QLocale::Russian, st->error);
    Bytecode::Instruction e;
Victor Yacovlev's avatar
Victor Yacovlev committed
909 910
    e.type = Bytecode::ERRORR;
    e.scope = Bytecode::CONSTT;
911 912 913 914
    e.arg = constantValue(Bytecode::VT_string, 0, error);
    if (e_debugLevel!=GeneratorInterface::NoDebug)
        result << l;
    result << e;
victor's avatar
 
victor committed
915 916 917 918 919 920 921 922 923 924 925 926 927 928
}

void Generator::findVariable(int modId, int algId, const AST::Variable * var, Bytecode::VariableScope & scope, quint16 & id) const
{
    const AST::Module * mod = m_ast->modules.at(modId);
    for (quint16 i=0; i<mod->impl.globals.size(); i++) {
        if (mod->impl.globals.at(i)==var) {
            scope = Bytecode::GLOBAL;
            id = i;
            return;
        }
    }
    const AST::Algorhitm * alg = mod->impl.algorhitms[algId];
    for (quint16 i=0; i<alg->impl.locals.size(); i++) {
victor's avatar
 
victor committed
929
        if (alg->impl.locals.at(i)==var) {
victor's avatar
 
victor committed
930 931 932 933 934
            scope = Bytecode::LOCAL;
            id = i;
            return;
        }
    }
935

victor's avatar
 
victor committed
936 937 938 939 940 941
}

void Generator::findFunction(const AST::Algorhitm *alg, quint8 &module, quint16 &id)
{
    for (quint8 i=0; i<m_ast->modules.size(); i++) {
        const AST::Module * mod = m_ast->modules[i];
victor's avatar
 
victor committed
942
        QList<AST::Algorhitm*> table;
943
        if (mod->header.type==AST::ModTypeExternal || mod->header.type==AST::ModTypeCached)
Victor Yacovlev's avatar
Victor Yacovlev committed
944
            table = mod->header.algorhitms + mod->header.operators;
victor's avatar
 
victor committed
945
        else
Victor Yacovlev's avatar
Victor Yacovlev committed
946
            table = mod->impl.algorhitms + mod->header.operators;
victor's avatar
 
victor committed
947 948
        for (quint16 j=0; j<table.size(); j++) {
            if (alg==table[j]) {
victor's avatar
 
victor committed
949 950
                module = i;
                id = j;
951 952
                if (mod->header.type==AST::ModTypeCached ||
                        mod->header.type==AST::ModTypeExternal && (mod->builtInID & 0xF0) == 0) {
victor's avatar
 
victor committed
953 954 955 956
                    QPair<quint8,quint16> ext(module, id);
                    if (!l_externs.contains(ext))
                        l_externs << ext;
                }
Victor Yacovlev's avatar
Victor Yacovlev committed
957 958
                if (mod->builtInID)
                    module = mod->builtInID;
victor's avatar
 
victor committed
959 960 961 962 963 964 965 966 967 968 969 970
                return;
            }
        }
    }
}

void Generator::ASSIGN(int modId, int algId, int level, const AST::Statement *st, QList<Bytecode::Instruction> & result)
{
    int lineNo = st->lexems[0]->lineNo;
    Bytecode::Instruction l;
    l.type = Bytecode::LINE;
    l.arg = lineNo;
971 972
    if (e_debugLevel!=GeneratorInterface::NoDebug)
        result << l;
victor's avatar
 
victor committed
973 974

    const AST::Expression * rvalue = st->expressions[0];
victor's avatar
 
victor committed
975 976 977
    QList<Bytecode::Instruction> rvalueInstructions = calculate(modId, algId, level, rvalue);
    shiftInstructions(rvalueInstructions, result.size());
    result << rvalueInstructions;
victor's avatar
 
victor committed
978

victor's avatar
 
victor committed
979

victor's avatar
 
victor committed
980 981
    if (st->expressions.size()>1) {
        const AST::Expression * lvalue = st->expressions[1];
victor's avatar
 
victor committed
982 983 984 985 986 987 988

        int diff = lvalue->operands.size()-lvalue->variable->dimension;

        if (diff>0) {
            // Load source string
            Bytecode::Instruction load;
            findVariable(modId, algId, lvalue->variable, load.scope, load.arg);
victor's avatar
 
victor committed
989
            load.type = lvalue->variable->dimension>0? Bytecode::LOADARR : Bytecode::LOAD;
victor's avatar
 
victor committed
990 991 992 993 994 995 996 997 998 999 1000 1001 1002
            for (int i=lvalue->variable->dimension-1; i>=0 ;i--) {
                result << calculate(modId, algId, level, lvalue->operands[i]);
            }
            result << load;
        }

        if (diff==1) {
            // Set character

            result << calculate(modId, algId, level,
                                lvalue->operands[lvalue->operands.count()-1]);
            Bytecode::Instruction argsCount;
            argsCount.type = Bytecode::LOAD;
Victor Yacovlev's avatar
Victor Yacovlev committed
1003
            argsCount.scope = Bytecode::CONSTT;
1004
            argsCount.arg = constantValue(Bytecode::VT_int, 0, 3);
victor's avatar
 
victor committed
1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022
            result << argsCount;

            Bytecode::Instruction call;
            call.type = Bytecode::CALL;
            call.module = 0xff;
            call.arg = 0x05;
            result << call;
        }

        if (diff==2) {
            // Set slice

            result << calculate(modId, algId, level,
                                lvalue->operands[lvalue->operands.count()-2]);
            result << calculate(modId, algId, level,
                                lvalue->operands[lvalue->operands.count()-1]);
            Bytecode::Instruction argsCount;
            argsCount.type = Bytecode::LOAD;
Victor Yacovlev's avatar
Victor Yacovlev committed
1023
            argsCount.scope = Bytecode::CONSTT;
1024
            argsCount.arg = constantValue(Bytecode::VT_int, 0, 4);
victor's avatar
 
victor committed
1025 1026 1027 1028 1029 1030 1031 1032 1033
            result << argsCount;

            Bytecode::Instruction call;
            call.type = Bytecode::CALL;
            call.module = 0xff;
            call.arg = 0x07;
            result << call;
        }

victor's avatar
 
victor committed
1034 1035
        Bytecode::Instruction store;
        findVariable(modId, algId, lvalue->variable, store.scope, store.arg);
victor's avatar
 
victor committed
1036
        store.type = lvalue->variable->dimension>0? Bytecode::STOREARR : Bytecode::STORE;
victor's avatar
 
victor committed
1037
        if (lvalue->kind==AST::ExprArrayElement) {
victor's avatar
 
victor committed
1038
            for (int i=lvalue->variable->dimension-1; i>=0 ;i--) {
victor's avatar
 
victor committed
1039 1040 1041
                result << calculate(modId, algId, level, lvalue->operands[i]);
            }
        }
victor's avatar
 
victor committed
1042

victor's avatar
 
victor committed
1043
        result << store;
victor's avatar
 
victor committed
1044 1045 1046 1047
        Bytecode::Instruction pop;
        pop.type = Bytecode::POP;
        pop.registerr = 0;
        result << pop;
victor's avatar
 
victor committed
1048 1049 1050 1051 1052 1053 1054
    }
}

QList<Bytecode::Instruction> Generator::calculate(int modId, int algId, int level, const AST::Expression* st)
{
    QList<Bytecode::Instruction> result;
    if (st->kind==AST::ExprConst) {
Victor Yacovlev's avatar
Victor Yacovlev committed
1055
        int constId = constantValue(valueType(st->baseType), st->dimension, st->constant);
victor's avatar
 
victor committed
1056 1057
        Bytecode::Instruction instr;
        instr.type = Bytecode::LOAD;
Victor Yacovlev's avatar
Victor Yacovlev committed
1058
        instr.scope = Bytecode::CONSTT;
victor's avatar
 
victor committed
1059 1060 1061 1062 1063 1064 1065 1066 1067 1068
        instr.arg = constId;
        result << instr;
    }
    else if (st->kind==AST::ExprVariable) {
        Bytecode::Instruction instr;
        instr.type = Bytecode::LOAD;
        findVariable(modId, algId, st->variable, instr.scope, instr.arg);
        result << instr;
    }
    else if (st->kind==AST::ExprArrayElement) {
victor's avatar
 
victor committed
1069

victor's avatar
 
victor committed
1070 1071
        Bytecode::Instruction instr;
        findVariable(modId, algId, st->variable, instr.scope, instr.arg);
victor's avatar
 
victor committed
1072 1073 1074 1075 1076 1077 1078
        instr.type = Bytecode::LOAD;
        if (st->variable->dimension>0) {
            for (int i=st->variable->dimension-1; i>=0; i--) {
                result << calculate(modId, algId, level, st->operands[i]);
            }
            instr.type = Bytecode::LOADARR;
        }
victor's avatar
 
victor committed
1079
        result << instr;
victor's avatar
 
victor committed
1080 1081 1082
        int diff = st->operands.size() - st->variable->dimension;
        Bytecode::Instruction argsCount;
        argsCount.type = Bytecode::LOAD;
Victor Yacovlev's avatar
Victor Yacovlev committed
1083
        argsCount.scope = Bytecode::CONSTT;
victor's avatar
 
victor committed
1084 1085 1086 1087 1088 1089 1090
        Bytecode::Instruction specialFunction;
        specialFunction.type = Bytecode::CALL;
        specialFunction.module = 0xff;
        if (diff==1) {
            // Get char
            result << calculate(modId, algId, level,
                                st->operands[st->operands.count()-1]);
1091
            argsCount.arg = constantValue(Bytecode::VT_int, 0, 2);
victor's avatar
 
victor committed
1092 1093 1094 1095 1096 1097 1098 1099 1100 1101
            result << argsCount;
            specialFunction.arg = 0x04;
            result << specialFunction;
        }
        else if (diff==2) {
            // Get slice
            result << calculate(modId, algId, level,
                                st->operands[st->operands.count()-2]);
            result << calculate(modId, algId, level,
                                st->operands[st->operands.count()-1]);
1102
            argsCount.arg = constantValue(Bytecode::VT_int, 0, 3);
victor's avatar
 
victor committed
1103 1104 1105 1106
            result << argsCount;
            specialFunction.arg = 0x06;
            result << specialFunction;
        }
victor's avatar
 
victor committed
1107 1108 1109
    }
    else if (st->kind==AST::ExprFunctionCall) {
        const AST::Algorhitm * alg = st->function;
Victor Yacovlev's avatar
Victor Yacovlev committed
1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120

        // Push calculable arguments to stack
        int argsCount = 0;
        for (int i=0; i<st->operands.size(); i++) {
            AST::VariableAccessType t = alg->header.arguments[i]->accessType;
            bool arr = alg->header.arguments[i]->dimension>0;
            if (t==AST::AccessArgumentOut||t==AST::AccessArgumentInOut) {
                Bytecode::Instruction ref;
                ref.type = Bytecode::REF;
                findVariable(modId, algId, st->operands[i]->variable, ref.scope, ref.arg);
                result << ref;
victor's avatar
 
victor committed
1121
            }
Victor Yacovlev's avatar
Victor Yacovlev committed
1122 1123 1124 1125 1126 1127 1128 1129
            else if (t==AST::AccessArgumentIn && !arr)
                result << calculate(modId, algId, level, st->operands[i]);
            else if (t==AST::AccessArgumentIn && arr) {
                // load the whole array into stack
                Bytecode::Instruction load;
                load.type = Bytecode::LOAD;
                findVariable(modId, algId, st->operands[i]->variable, load.scope, load.arg);
                result << load;
victor's avatar
 
victor committed
1130
            }
Victor Yacovlev's avatar
Victor Yacovlev committed
1131
            argsCount ++;
victor's avatar
 
victor committed
1132
        }
Victor Yacovlev's avatar
Victor Yacovlev committed
1133 1134 1135 1136 1137 1138 1139
        Bytecode::Instruction b;
        b.type = Bytecode::LOAD;
        b.scope = Bytecode::CONSTT;
        b.arg = constantValue(Bytecode::VT_int, 0, argsCount);
        result << b;


victor's avatar
 
victor committed
1140
        Bytecode::Instruction instr;
victor's avatar
 
victor committed
1141
        instr.type = Bytecode::CALL;
victor's avatar
 
victor committed
1142 1143 1144 1145
        findFunction(st->function, instr.module, instr.arg);
        result << instr;
    }
    else if (st->kind==AST::ExprSubexpression) {
victor's avatar
 
victor committed
1146
        std::list<int> jmps;
victor's avatar
 
victor committed
1147
        for (int i=0; i<st->operands.size(); i++) {
victor's avatar
 
victor committed
1148 1149 1150
            QList<Bytecode::Instruction> operandInstrs = calculate(modId, algId, level, st->operands[i]);
            shiftInstructions(operandInstrs, result.size());
            result << operandInstrs;
victor's avatar
 
victor committed
1151 1152 1153 1154 1155 1156
            // Do short circuit calculation for AND and OR operations
            if (i==0 && (st->operatorr==AST::OpAnd || st->operatorr==AST::OpOr)) {
                // Simple case: just JZ/JNZ to end
                Bytecode::Instruction gotoEnd;
                gotoEnd.registerr = 0;
                gotoEnd.type = st->operatorr==AST::OpAnd? Bytecode::JZ : Bytecode::JNZ;
victor's avatar
 
victor committed
1157
                jmps.push_back(result.size());
victor's avatar
 
victor committed
1158
                result << gotoEnd;
victor's avatar
 
victor committed
1159
            }
victor's avatar
 
victor committed
1160 1161 1162 1163
            else if (st->operatorr==AST::OpAnd || st->operatorr==AST::OpOr)