1503 lines
		
	
	
		
			54 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			1503 lines
		
	
	
		
			54 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
#include <stdio.h>
 | 
						|
#include <stdlib.h>
 | 
						|
#include <ctype.h>
 | 
						|
#include <cmath>
 | 
						|
#include <algorithm>
 | 
						|
#include <stdlib.h>
 | 
						|
#include <time.h>
 | 
						|
 | 
						|
#include "memory.h"
 | 
						|
#include "cpu.h"
 | 
						|
#include "assembler.h"
 | 
						|
#include "compiler.h"
 | 
						|
#include "operators.h"
 | 
						|
#include "linker.h"
 | 
						|
 | 
						|
 | 
						|
namespace Operators
 | 
						|
{
 | 
						|
    bool _nextTempVar = true;
 | 
						|
 | 
						|
    std::vector<std::string> _operators;
 | 
						|
 | 
						|
    std::vector<std::string>& getOperators(void) {return _operators;}
 | 
						|
 | 
						|
 | 
						|
    bool initialise(void)
 | 
						|
    {
 | 
						|
        _nextTempVar = true;
 | 
						|
 | 
						|
        // Operators
 | 
						|
        _operators.push_back(" AND ");
 | 
						|
        _operators.push_back(" XOR ");
 | 
						|
        _operators.push_back(" OR " );
 | 
						|
        _operators.push_back("NOT " );
 | 
						|
        _operators.push_back(" MOD ");
 | 
						|
        _operators.push_back(" LSL ");
 | 
						|
        _operators.push_back(" LSR ");
 | 
						|
        _operators.push_back(" ASR ");
 | 
						|
 | 
						|
        return true;
 | 
						|
    }
 | 
						|
 | 
						|
 | 
						|
    void changeToTmpVar(Expression::Numeric& numeric)
 | 
						|
    {
 | 
						|
        numeric._value = uint8_t(Compiler::getTempVarStart());
 | 
						|
        numeric._varType = Expression::TmpVar;
 | 
						|
        numeric._name = Compiler::getTempVarStartStr();
 | 
						|
    }
 | 
						|
 | 
						|
    void createSingleOp(const std::string& opcodeStr, Expression::Numeric& numeric)
 | 
						|
    {
 | 
						|
        switch(numeric._varType)
 | 
						|
        {
 | 
						|
            // Temporary variable address
 | 
						|
            case Expression::TmpVar:
 | 
						|
            {
 | 
						|
                Compiler::emitVcpuAsm(opcodeStr, Expression::byteToHexString(uint8_t(std::lround(numeric._value))), false);
 | 
						|
            }
 | 
						|
            break;
 | 
						|
 | 
						|
            // User variable name
 | 
						|
            case Expression::IntVar16:
 | 
						|
            {
 | 
						|
                Compiler::emitVcpuAsmUserVar(opcodeStr, numeric, false);
 | 
						|
            }
 | 
						|
            break;
 | 
						|
 | 
						|
            default: break;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    void handleSingleOp(const std::string& opcodeStr, Expression::Numeric& numeric)
 | 
						|
    {
 | 
						|
        createSingleOp(opcodeStr, numeric);
 | 
						|
        changeToTmpVar(numeric);
 | 
						|
    }
 | 
						|
 | 
						|
    void selectSingleOp(const std::string& opcodeStr, Expression::Numeric& numeric)
 | 
						|
    {
 | 
						|
        if(numeric._varType == Expression::Number)
 | 
						|
        {
 | 
						|
            int16_t val = int16_t(std::lround(numeric._value));
 | 
						|
            (val >= 0  && val <= 255) ? Compiler::emitVcpuAsm("LDI", std::to_string(val), false) : Compiler::emitVcpuAsm("LDWI", std::to_string(val), false);
 | 
						|
        }
 | 
						|
        else
 | 
						|
        {
 | 
						|
            Operators::createSingleOp(opcodeStr, numeric);
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    bool handleDualOp(const std::string& opcodeStr, Expression::Numeric& lhs, Expression::Numeric& rhs, bool outputHex)
 | 
						|
    {
 | 
						|
        std::string opcode = std::string(opcodeStr);
 | 
						|
 | 
						|
        // Swap left and right to take advantage of LDWI for 16bit numbers
 | 
						|
        if(rhs._varType == Expression::Number  &&  (rhs._value < 0  ||  rhs._value > 255))
 | 
						|
        {
 | 
						|
            std::swap(lhs, rhs);
 | 
						|
            if(opcode == "SUB")
 | 
						|
            {
 | 
						|
                opcode = "ADD";
 | 
						|
                if(lhs._value > 0) lhs._value = -lhs._value;
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        // LHS
 | 
						|
        if(lhs._varType == Expression::Number)
 | 
						|
        {
 | 
						|
            // 8bit positive constants
 | 
						|
            if(lhs._value >=0  &&  lhs._value <= 255)
 | 
						|
            {
 | 
						|
                (outputHex) ? Compiler::emitVcpuAsm("LDI", Expression::byteToHexString(uint8_t(std::lround(lhs._value))), false) : Compiler::emitVcpuAsm("LDI", std::to_string(uint8_t(std::lround(lhs._value))), false);
 | 
						|
            }
 | 
						|
            // 16bit constants
 | 
						|
            else
 | 
						|
            {
 | 
						|
                (outputHex) ? Compiler::emitVcpuAsm("LDWI", Expression::wordToHexString(int16_t(std::lround(lhs._value))), false) : Compiler::emitVcpuAsm("LDWI", std::to_string(int16_t(std::lround(lhs._value))), false);
 | 
						|
            }
 | 
						|
 | 
						|
            _nextTempVar = true;
 | 
						|
        }
 | 
						|
        else
 | 
						|
        {
 | 
						|
            switch(lhs._varType)
 | 
						|
            {
 | 
						|
                // Temporary variable address
 | 
						|
                case Expression::TmpVar:
 | 
						|
                {
 | 
						|
                    Compiler::emitVcpuAsm("LDW", Expression::byteToHexString(uint8_t(std::lround(lhs._value))), false);
 | 
						|
                }
 | 
						|
                break;
 | 
						|
 | 
						|
                // User variable name
 | 
						|
                case Expression::IntVar16:
 | 
						|
                {
 | 
						|
                    if(!Compiler::emitVcpuAsmUserVar("LDW", lhs, true)) return false;
 | 
						|
                    _nextTempVar = false;
 | 
						|
                }
 | 
						|
                break;
 | 
						|
 | 
						|
                default: break;
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        // RHS
 | 
						|
        if(rhs._varType == Expression::Number)
 | 
						|
        {
 | 
						|
            // Skip XOR if operand is 0, (n XOR 0 = n)
 | 
						|
            if(rhs._value  ||  opcode != "XOR") 
 | 
						|
            {
 | 
						|
                (outputHex) ? Compiler::emitVcpuAsm(opcode + "I", Expression::wordToHexString(int8_t(std::lround(rhs._value))), false) : Compiler::emitVcpuAsm(opcode + "I", std::to_string(int8_t(std::lround(rhs._value))), false);
 | 
						|
            }
 | 
						|
        }
 | 
						|
        else
 | 
						|
        {
 | 
						|
            switch(rhs._varType)
 | 
						|
            {
 | 
						|
                // Temporary variable address
 | 
						|
                case Expression::TmpVar:
 | 
						|
                {
 | 
						|
                    Compiler::emitVcpuAsm(opcode + "W", Expression::byteToHexString(uint8_t(std::lround(rhs._value))), false);
 | 
						|
                }
 | 
						|
                break;
 | 
						|
 | 
						|
                // User variable name
 | 
						|
                case Expression::IntVar16:
 | 
						|
                {
 | 
						|
                    if(!Compiler::emitVcpuAsmUserVar(opcode + "W", rhs, _nextTempVar)) return false;
 | 
						|
                    _nextTempVar = false;
 | 
						|
                }
 | 
						|
                break;
 | 
						|
 | 
						|
                default: break;
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        changeToTmpVar(lhs);
 | 
						|
        Compiler::emitVcpuAsm("STW", Expression::byteToHexString(uint8_t(Compiler::getTempVarStart())), false);
 | 
						|
 | 
						|
        return true;
 | 
						|
    }
 | 
						|
 | 
						|
    bool handleLogicalOp(const std::string& opcode, Expression::Numeric& lhs)
 | 
						|
    {
 | 
						|
        // SYS shift function needs this preamble, LSLW doesn't
 | 
						|
        switch(lhs._varType)
 | 
						|
        {
 | 
						|
            // Temporary variable address
 | 
						|
            case Expression::TmpVar:
 | 
						|
            {
 | 
						|
                Compiler::emitVcpuAsm("LDW", Expression::byteToHexString(uint8_t(std::lround(lhs._value))), false);
 | 
						|
            }
 | 
						|
            break;
 | 
						|
 | 
						|
            // User variable name
 | 
						|
            case Expression::IntVar16:
 | 
						|
            {
 | 
						|
                if(!Compiler::emitVcpuAsmUserVar("LDW", lhs, true)) return false;
 | 
						|
            }
 | 
						|
            break;
 | 
						|
 | 
						|
            default: break;
 | 
						|
        }
 | 
						|
 | 
						|
        if(opcode != "LSLW") Compiler::emitVcpuAsm("STW", "mathShift", false);
 | 
						|
 | 
						|
        changeToTmpVar(lhs);
 | 
						|
 | 
						|
        return true;
 | 
						|
    }
 | 
						|
 | 
						|
    void emitCcType(Expression::CCType ccType, std::string& cc)
 | 
						|
    {
 | 
						|
        switch(ccType)
 | 
						|
        {
 | 
						|
            case Expression::BooleanCC:
 | 
						|
            {
 | 
						|
                // Init functions are not needed for ROMv5a and higher as CALLI is able to directly CALL them
 | 
						|
                if(Compiler::getCodeRomType() >= Cpu::ROMv5a)
 | 
						|
                {
 | 
						|
                    Compiler::emitVcpuAsm("CALLI", "convert" + cc + "Op", false);
 | 
						|
                }
 | 
						|
                else
 | 
						|
                // Enable system internal sub intialiser and mark system internal sub to be loaded
 | 
						|
                {
 | 
						|
                    Compiler::emitVcpuAsm("CALL", "convert" + cc + "OpAddr", false);
 | 
						|
                    Compiler::enableSysInitFunc("Init" + cc + "Op");
 | 
						|
                    Linker::setInternalSubToLoad("convert" + cc + "Op");
 | 
						|
                }
 | 
						|
            }
 | 
						|
            break;
 | 
						|
 | 
						|
            case Expression::NormalCC: Compiler::emitVcpuAsm("%Jump" + Expression::strToUpper(cc), "", false); break;
 | 
						|
            case Expression::FastCC: Compiler::emitVcpuAsm("B" + Expression::strToUpper(cc), "", false); break;
 | 
						|
 | 
						|
            default: break;
 | 
						|
        }
 | 
						|
 | 
						|
        Compiler::emitVcpuAsm("STW", Expression::byteToHexString(uint8_t(Compiler::getTempVarStart())), false);
 | 
						|
    }
 | 
						|
    bool handleConditionOp(Expression::Numeric& lhs, Expression::Numeric& rhs, Expression::CCType ccType, bool& invertedLogic, const std::string& opcode="SUB")
 | 
						|
    {
 | 
						|
        // Swap left and right to take advantage of LDWI for 16bit numbers
 | 
						|
        invertedLogic = false;
 | 
						|
        if(rhs._varType == Expression::Number  &&  (rhs._value < 0  ||  rhs._value > 255))
 | 
						|
        {
 | 
						|
            std::swap(lhs, rhs);
 | 
						|
            invertedLogic = true;
 | 
						|
        }
 | 
						|
 | 
						|
        // JumpCC and BCC are inverses of each other
 | 
						|
        lhs._ccType = ccType;
 | 
						|
        if(ccType == Expression::FastCC) invertedLogic = !invertedLogic;
 | 
						|
 | 
						|
        // LHS
 | 
						|
        if(lhs._varType == Expression::Number)
 | 
						|
        {
 | 
						|
            // 8bit positive constants
 | 
						|
            if(lhs._value >=0  &&  lhs._value <= 255)
 | 
						|
            {
 | 
						|
                Compiler::emitVcpuAsm("LDI", std::to_string(uint8_t(std::lround(lhs._value))), false);
 | 
						|
            }
 | 
						|
            // 16bit constants
 | 
						|
            else
 | 
						|
            {
 | 
						|
                Compiler::emitVcpuAsm("LDWI", std::to_string(int16_t(std::lround(lhs._value))), false);
 | 
						|
            }
 | 
						|
 | 
						|
            _nextTempVar = true;
 | 
						|
        }
 | 
						|
        else
 | 
						|
        {
 | 
						|
            switch(lhs._varType)
 | 
						|
            {
 | 
						|
                // Temporary variable address
 | 
						|
                case Expression::TmpVar:
 | 
						|
                {
 | 
						|
                    Compiler::emitVcpuAsm("LDW", Expression::byteToHexString(uint8_t(std::lround(lhs._value))), false);
 | 
						|
                }
 | 
						|
                break;
 | 
						|
 | 
						|
                // User variable name
 | 
						|
                case Expression::IntVar16:
 | 
						|
                {
 | 
						|
                    if(!Compiler::emitVcpuAsmUserVar("LDW", lhs, true)) return false;
 | 
						|
                    _nextTempVar = false;
 | 
						|
                }
 | 
						|
                break;
 | 
						|
 | 
						|
                default: break;
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        // RHS
 | 
						|
        if(rhs._varType == Expression::Number)
 | 
						|
        {
 | 
						|
            // Skip XOR if operand is 0, (n XOR 0 = n)
 | 
						|
            if(rhs._value  ||  opcode != "XOR") Compiler::emitVcpuAsm(opcode + "I", std::to_string(int16_t(std::lround(rhs._value))), false);
 | 
						|
        }
 | 
						|
        else        
 | 
						|
        {
 | 
						|
            switch(rhs._varType)
 | 
						|
            {
 | 
						|
                // Temporary variable address
 | 
						|
                case Expression::TmpVar:
 | 
						|
                {
 | 
						|
                    Compiler::emitVcpuAsm(opcode + "W", Expression::byteToHexString(uint8_t(std::lround(rhs._value))), false);
 | 
						|
                }
 | 
						|
                break;
 | 
						|
 | 
						|
                // User variable name
 | 
						|
                case Expression::IntVar16:
 | 
						|
                {
 | 
						|
                    if(!Compiler::emitVcpuAsmUserVar(opcode + "W", rhs, _nextTempVar)) return false;
 | 
						|
                    _nextTempVar = false;
 | 
						|
                }
 | 
						|
                break;
 | 
						|
 | 
						|
                default: break;
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        changeToTmpVar(lhs);
 | 
						|
 | 
						|
        return true;
 | 
						|
    }
 | 
						|
 | 
						|
    bool handleStringCcOP(Expression::Numeric& lhs, Expression::Numeric& rhs, Expression::OPType opType)
 | 
						|
    {
 | 
						|
        if(lhs._varType != Expression::String  &&  lhs._varType != Expression::Constant  &&  lhs._varType != Expression::StrVar  &&  lhs._varType != Expression::Str2Var  &&
 | 
						|
           lhs._varType != Expression::TmpStrVar) return false;
 | 
						|
        if(rhs._varType != Expression::String  &&  rhs._varType != Expression::Constant  &&  rhs._varType != Expression::StrVar  &&  rhs._varType != Expression::Str2Var  &&
 | 
						|
           rhs._varType != Expression::TmpStrVar) return false;
 | 
						|
 | 
						|
        if(lhs._varType == Expression::String  &&  rhs._varType == Expression::String)
 | 
						|
        {
 | 
						|
            switch(opType)
 | 
						|
            {
 | 
						|
                case Expression::EqOP: lhs._value = (int16_t(lhs._text.compare(rhs._text)) == 0); return true;
 | 
						|
                case Expression::NeOP: lhs._value = (int16_t(lhs._text.compare(rhs._text)) != 0); return true;
 | 
						|
                case Expression::LeOP: lhs._value = (int16_t(lhs._text.compare(rhs._text)) <= 0); return true;
 | 
						|
                case Expression::GeOP: lhs._value = (int16_t(lhs._text.compare(rhs._text)) >= 0); return true;
 | 
						|
                case Expression::LtOP: lhs._value = (int16_t(lhs._text.compare(rhs._text)) <  0); return true;
 | 
						|
                case Expression::GtOP: lhs._value = (int16_t(lhs._text.compare(rhs._text)) >  0); return true;
 | 
						|
 | 
						|
                default: break;
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        // Get addresses of strings to be compared
 | 
						|
        int lhsIndex = int(lhs._index);
 | 
						|
        int rhsIndex = int(rhs._index);
 | 
						|
        std::string lhsName, rhsName;
 | 
						|
        uint16_t lhsAddr, rhsAddr;
 | 
						|
 | 
						|
        // String inputs can be literal, const, var and temp
 | 
						|
        if(lhs._varType == Expression::TmpStrVar)
 | 
						|
        {
 | 
						|
            lhsAddr = Compiler::getStrWorkArea();
 | 
						|
        }
 | 
						|
        else
 | 
						|
        {
 | 
						|
            Compiler::getOrCreateString(lhs, lhsName, lhsAddr, lhsIndex);
 | 
						|
        }
 | 
						|
        if(rhs._varType == Expression::TmpStrVar)
 | 
						|
        {
 | 
						|
            rhsAddr = Compiler::getStrWorkArea();
 | 
						|
        }
 | 
						|
        else
 | 
						|
        {
 | 
						|
            Compiler::getOrCreateString(rhs, rhsName, rhsAddr, rhsIndex);
 | 
						|
        }
 | 
						|
 | 
						|
        // By definition this must be a match
 | 
						|
        if(lhsAddr == rhsAddr)
 | 
						|
        {
 | 
						|
            Compiler::emitVcpuAsm("LDI", "1", false);
 | 
						|
        }
 | 
						|
        // Compare strings
 | 
						|
        else
 | 
						|
        {
 | 
						|
            Compiler::emitStringAddress(lhs, lhsAddr);
 | 
						|
            Compiler::emitVcpuAsm("STW",  "strSrcAddr", false);
 | 
						|
            Compiler::emitStringAddress(rhs, rhsAddr);
 | 
						|
            Compiler::emitVcpuAsm("%StringCmp", "", false);
 | 
						|
 | 
						|
            // 0, 1, 2, (lesser, equal, greater)
 | 
						|
            switch(opType)
 | 
						|
            {
 | 
						|
                case Expression::EqOP:
 | 
						|
                {
 | 
						|
                    // 0, 1, 2 to 0, 1, 0
 | 
						|
                    Compiler::emitVcpuAsm("ANDI", "1", false);
 | 
						|
                }
 | 
						|
                break;
 | 
						|
 | 
						|
                case Expression::NeOP:
 | 
						|
                {
 | 
						|
                    // 0, 1, 2 to 1, 0, 1
 | 
						|
                    Compiler::emitVcpuAsm("ANDI", "1", false);
 | 
						|
                    Compiler::emitVcpuAsm("XORI", "1", false);
 | 
						|
                }
 | 
						|
                break;
 | 
						|
 | 
						|
                case Expression::LeOP:
 | 
						|
                {
 | 
						|
                    // 0, 1 to 1 : 2 to 0
 | 
						|
                    Compiler::emitVcpuAsm("XORI", "2", false);
 | 
						|
                    if(Compiler::getCodeRomType() >= Cpu::ROMv5a)
 | 
						|
                    {
 | 
						|
                        Compiler::emitVcpuAsm("CALLI", "convertNeOpAddr", false);
 | 
						|
                    }
 | 
						|
                    else
 | 
						|
                    {
 | 
						|
                        Compiler::emitVcpuAsm("CALL", "convertNeOpAddr", false);
 | 
						|
                        Compiler::enableSysInitFunc("InitNeOp");
 | 
						|
                        Linker::setInternalSubToLoad("convertNeOp");
 | 
						|
                    }
 | 
						|
                }
 | 
						|
                break;
 | 
						|
 | 
						|
                case Expression::GeOP:
 | 
						|
                {
 | 
						|
                    // 1, 2 to 1 : 0 to 0
 | 
						|
                    if(Compiler::getCodeRomType() >= Cpu::ROMv5a)
 | 
						|
                    {
 | 
						|
                        Compiler::emitVcpuAsm("CALLI", "convertNeOpAddr", false);
 | 
						|
                    }
 | 
						|
                    else
 | 
						|
                    {
 | 
						|
                        Compiler::emitVcpuAsm("CALL", "convertNeOpAddr", false);
 | 
						|
                        Compiler::enableSysInitFunc("InitNeOp");
 | 
						|
                        Linker::setInternalSubToLoad("convertNeOp");
 | 
						|
                    }
 | 
						|
                }
 | 
						|
                break;
 | 
						|
 | 
						|
                case Expression::LtOP:
 | 
						|
                {
 | 
						|
                    // 0 to 1 : 1, 2 to 0
 | 
						|
                    if(Compiler::getCodeRomType() >= Cpu::ROMv5a)
 | 
						|
                    {
 | 
						|
                        Compiler::emitVcpuAsm("CALLI", "convertEqOpAddr", false);
 | 
						|
                    }
 | 
						|
                    else
 | 
						|
                    {
 | 
						|
                        Compiler::emitVcpuAsm("CALL", "convertEqOpAddr", false);
 | 
						|
                        Compiler::enableSysInitFunc("InitEqOp");
 | 
						|
                        Linker::setInternalSubToLoad("convertEqOp");
 | 
						|
                    }
 | 
						|
                }
 | 
						|
                break;
 | 
						|
 | 
						|
                case Expression::GtOP:
 | 
						|
                {
 | 
						|
                    // 0, 1 to 0 : 2 to 1
 | 
						|
                    Compiler::emitVcpuAsm("ANDI",  "2", false);
 | 
						|
                    if(Compiler::getCodeRomType() >= Cpu::ROMv5a)
 | 
						|
                    {
 | 
						|
                        Compiler::emitVcpuAsm("CALLI", "convertNeOpAddr", false);
 | 
						|
                    }
 | 
						|
                    else
 | 
						|
                    {
 | 
						|
                        Compiler::emitVcpuAsm("CALL", "convertNeOpAddr", false);
 | 
						|
                        Compiler::enableSysInitFunc("InitNeOp");
 | 
						|
                        Linker::setInternalSubToLoad("convertNeOp");
 | 
						|
                    }
 | 
						|
                }
 | 
						|
                break;
 | 
						|
 | 
						|
                default: break;
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        changeToTmpVar(lhs);
 | 
						|
        Compiler::emitVcpuAsm("STW", Expression::byteToHexString(uint8_t(Compiler::getTempVarStart())), false);
 | 
						|
 | 
						|
        return true;
 | 
						|
    }
 | 
						|
 | 
						|
    bool handleStringAdd(Expression::Numeric& lhs, Expression::Numeric& rhs)
 | 
						|
    {
 | 
						|
        if(lhs._varType != Expression::String  &&  lhs._varType != Expression::Constant  &&  lhs._varType != Expression::StrVar  &&  lhs._varType != Expression::Str2Var  &&
 | 
						|
           lhs._varType != Expression::TmpStrVar) return false;
 | 
						|
        if(rhs._varType != Expression::String  &&  rhs._varType != Expression::Constant  &&  rhs._varType != Expression::StrVar  &&  rhs._varType != Expression::Str2Var  &&
 | 
						|
           rhs._varType != Expression::TmpStrVar) return false;
 | 
						|
 | 
						|
        // Get addresses of strings to be compared
 | 
						|
        int lhsIndex = int(lhs._index);
 | 
						|
        int rhsIndex = int(rhs._index);
 | 
						|
        std::string lhsName, rhsName;
 | 
						|
        uint16_t lhsAddr, rhsAddr;
 | 
						|
 | 
						|
        // String inputs can be literal, const, var and temp
 | 
						|
        if(lhs._varType == Expression::TmpStrVar)
 | 
						|
        {
 | 
						|
            lhsAddr = Compiler::getStrWorkArea();
 | 
						|
        }
 | 
						|
        else
 | 
						|
        {
 | 
						|
            Compiler::getOrCreateString(lhs, lhsName, lhsAddr, lhsIndex);
 | 
						|
        }
 | 
						|
        if(rhs._varType == Expression::TmpStrVar)
 | 
						|
        {
 | 
						|
            // If both lhs and rhs are temporaries then get next string work area and swap lhs and rhs, (stringConcat requires dst = src0)
 | 
						|
            if(lhs._varType == Expression::TmpStrVar) Compiler::nextStrWorkArea();
 | 
						|
            rhsAddr = Compiler::getStrWorkArea();
 | 
						|
            std::swap(lhs, rhs);
 | 
						|
            std::swap(lhsAddr, rhsAddr);
 | 
						|
        }
 | 
						|
        else
 | 
						|
        {
 | 
						|
            Compiler::getOrCreateString(rhs, rhsName, rhsAddr, rhsIndex);
 | 
						|
        }
 | 
						|
 | 
						|
        Compiler::emitStringAddress(lhs, lhsAddr);
 | 
						|
        Compiler::emitVcpuAsm("STW",  "strSrcAddr", false);
 | 
						|
        Compiler::emitStringAddress(rhs, rhsAddr);
 | 
						|
        Compiler::emitVcpuAsm("STW",  "strSrcAddr2", false);
 | 
						|
        Compiler::emitVcpuAsm("LDWI", Expression::wordToHexString(Compiler::getStrWorkArea()), false);
 | 
						|
        Compiler::emitVcpuAsm("%StringConcat", "", false);
 | 
						|
 | 
						|
        lhs =  Expression::Numeric(0, -1, true, false, false, Expression::TmpStrVar, Expression::BooleanCC, Expression::Int16Both, "", std::string(""));
 | 
						|
 | 
						|
        return true;
 | 
						|
    }
 | 
						|
 | 
						|
    bool handleMathOp(const std::string& opcode, const std::string& operand, Expression::Numeric& lhs, Expression::Numeric& rhs, bool isMod=false)
 | 
						|
    {
 | 
						|
        // LHS
 | 
						|
        if(lhs._varType == Expression::Number)
 | 
						|
        {
 | 
						|
            // 8bit positive constants
 | 
						|
            if(lhs._value >=0  &&  lhs._value <= 255)
 | 
						|
            {
 | 
						|
                Compiler::emitVcpuAsm("LDI", std::to_string(uint8_t(std::lround(lhs._value))), false);
 | 
						|
            }
 | 
						|
            // 16bit constants
 | 
						|
            else
 | 
						|
            {
 | 
						|
                Compiler::emitVcpuAsm("LDWI", std::to_string(int16_t(std::lround(lhs._value))), false);
 | 
						|
            }
 | 
						|
 | 
						|
            _nextTempVar = true;
 | 
						|
        }
 | 
						|
        else
 | 
						|
        {
 | 
						|
            switch(lhs._varType)
 | 
						|
            {
 | 
						|
                // Temporary variable address
 | 
						|
                case Expression::TmpVar:
 | 
						|
                {
 | 
						|
                    Compiler::emitVcpuAsm("LDW", Expression::byteToHexString(uint8_t(std::lround(lhs._value))), false);
 | 
						|
                }
 | 
						|
                break;
 | 
						|
 | 
						|
                // User variable name
 | 
						|
                case Expression::IntVar16:
 | 
						|
                {
 | 
						|
                    if(!Compiler::emitVcpuAsmUserVar("LDW", lhs, true)) return false;
 | 
						|
                    _nextTempVar = false;
 | 
						|
                }
 | 
						|
                break;
 | 
						|
 | 
						|
                default: break;
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        Compiler::emitVcpuAsm("STW", "mathX", false);
 | 
						|
 | 
						|
        // RHS
 | 
						|
        if(rhs._varType == Expression::Number)
 | 
						|
        {
 | 
						|
            if(rhs._value >=0  &&  rhs._value <= 255)
 | 
						|
            {
 | 
						|
                Compiler::emitVcpuAsm("LDI", std::to_string(uint8_t(std::lround(rhs._value))), false);
 | 
						|
            }
 | 
						|
            else
 | 
						|
            {
 | 
						|
                Compiler::emitVcpuAsm("LDWI", std::to_string(int16_t(std::lround(rhs._value))), false);
 | 
						|
            }
 | 
						|
        }
 | 
						|
        else
 | 
						|
        {
 | 
						|
            switch(rhs._varType)
 | 
						|
            {
 | 
						|
                // Temporary variable address
 | 
						|
                case Expression::TmpVar:
 | 
						|
                {
 | 
						|
                    Compiler::emitVcpuAsm("LDW", Expression::byteToHexString(uint8_t(std::lround(rhs._value))), false);
 | 
						|
                }
 | 
						|
                break;
 | 
						|
 | 
						|
                // User variable name
 | 
						|
                case Expression::IntVar16:
 | 
						|
                {
 | 
						|
                    if(!Compiler::emitVcpuAsmUserVar("LDW", rhs, _nextTempVar)) return false;
 | 
						|
                    _nextTempVar = false;
 | 
						|
                }
 | 
						|
                break;
 | 
						|
 | 
						|
                default: break;
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        Compiler::emitVcpuAsm("STW", "mathY", false);
 | 
						|
 | 
						|
        if(Compiler::getCodeRomType() >= Cpu::ROMv5a)
 | 
						|
        {
 | 
						|
            Compiler::emitVcpuAsm(opcode, operand, false);
 | 
						|
        }
 | 
						|
        else
 | 
						|
        {
 | 
						|
            Compiler::emitVcpuAsm("LDWI", operand, false);
 | 
						|
            Compiler::emitVcpuAsm(opcode, "giga_vAC", false);
 | 
						|
        }
 | 
						|
 | 
						|
        changeToTmpVar(lhs);
 | 
						|
        
 | 
						|
        if(isMod) Compiler::emitVcpuAsm("LDW", "mathRem", false);
 | 
						|
        Compiler::emitVcpuAsm("STW", Expression::byteToHexString(uint8_t(Compiler::getTempVarStart())), false);
 | 
						|
 | 
						|
        return true;
 | 
						|
    }
 | 
						|
 | 
						|
    uint32_t handleRevOp(uint32_t input, uint32_t n)
 | 
						|
    {
 | 
						|
        uint32_t output = 0;
 | 
						|
        uint32_t bits = input & uint32_t(pow(2, n) - 1);
 | 
						|
        for(uint32_t i=0; i<=n-1; i++)
 | 
						|
        {
 | 
						|
            output = (output << 1) | (bits & 1);
 | 
						|
            bits = bits >> 1;
 | 
						|
        }
 | 
						|
 | 
						|
        return output;
 | 
						|
    }
 | 
						|
 | 
						|
 | 
						|
    // ********************************************************************************************
 | 
						|
    // Unary Operators
 | 
						|
    // ********************************************************************************************
 | 
						|
    Expression::Numeric POS(Expression::Numeric& numeric, const std::string& moduleName, const std::string& codeLineText, int codeLineStart)
 | 
						|
    {
 | 
						|
        UNREFERENCED_PARAM(moduleName);
 | 
						|
        UNREFERENCED_PARAM(codeLineText);
 | 
						|
        UNREFERENCED_PARAM(codeLineStart);
 | 
						|
 | 
						|
        if(numeric._varType == Expression::Number)
 | 
						|
        {
 | 
						|
            numeric._value = +numeric._value;
 | 
						|
            return numeric;
 | 
						|
        }
 | 
						|
 | 
						|
        Compiler::getNextTempVar();
 | 
						|
        handleSingleOp("LDW", numeric);
 | 
						|
        Compiler::emitVcpuAsm("STW", Expression::byteToHexString(uint8_t(Compiler::getTempVarStart())), false);
 | 
						|
        
 | 
						|
        return numeric;
 | 
						|
    }
 | 
						|
 | 
						|
    Expression::Numeric NEG(Expression::Numeric& numeric, const std::string& moduleName, const std::string& codeLineText, int codeLineStart)
 | 
						|
    {
 | 
						|
        UNREFERENCED_PARAM(moduleName);
 | 
						|
        UNREFERENCED_PARAM(codeLineText);
 | 
						|
        UNREFERENCED_PARAM(codeLineStart);
 | 
						|
 | 
						|
        if(numeric._varType == Expression::Number)
 | 
						|
        {
 | 
						|
            numeric._value = -numeric._value;
 | 
						|
            return numeric;
 | 
						|
        }
 | 
						|
 | 
						|
        Compiler::getNextTempVar();
 | 
						|
        Compiler::emitVcpuAsm("LDI", std::to_string(0), false);
 | 
						|
        handleSingleOp("SUBW", numeric);
 | 
						|
        Compiler::emitVcpuAsm("STW", Expression::byteToHexString(uint8_t(Compiler::getTempVarStart())), false);
 | 
						|
        
 | 
						|
        return numeric;
 | 
						|
    }
 | 
						|
 | 
						|
    Expression::Numeric NOT(Expression::Numeric& numeric, const std::string& moduleName, const std::string& codeLineText, int codeLineStart)
 | 
						|
    {
 | 
						|
        UNREFERENCED_PARAM(moduleName);
 | 
						|
        UNREFERENCED_PARAM(codeLineText);
 | 
						|
        UNREFERENCED_PARAM(codeLineStart);
 | 
						|
 | 
						|
        if(numeric._varType == Expression::Number)
 | 
						|
        {
 | 
						|
            numeric._value = ~int16_t(std::lround(numeric._value));
 | 
						|
            return numeric;
 | 
						|
        }
 | 
						|
 | 
						|
        Compiler::getNextTempVar();
 | 
						|
        Compiler::emitVcpuAsm("LDWI", std::to_string(-1), false);
 | 
						|
        handleSingleOp("XORW", numeric);
 | 
						|
        Compiler::emitVcpuAsm("STW", Expression::byteToHexString(uint8_t(Compiler::getTempVarStart())), false);
 | 
						|
 | 
						|
        return numeric;
 | 
						|
    }
 | 
						|
 | 
						|
 | 
						|
    // ********************************************************************************************
 | 
						|
    // Unary Math Operators
 | 
						|
    // ********************************************************************************************
 | 
						|
    Expression::Numeric CEIL(Expression::Numeric& numeric, const std::string& moduleName, const std::string& codeLineText, int codeLineStart)
 | 
						|
    {
 | 
						|
        UNREFERENCED_PARAM(moduleName);
 | 
						|
        UNREFERENCED_PARAM(codeLineText);
 | 
						|
        UNREFERENCED_PARAM(codeLineStart);
 | 
						|
 | 
						|
        if(numeric._varType == Expression::Number)
 | 
						|
        {
 | 
						|
            numeric._value = ceil(numeric._value);
 | 
						|
        }
 | 
						|
 | 
						|
        return numeric;
 | 
						|
    }
 | 
						|
 | 
						|
    Expression::Numeric FLOOR(Expression::Numeric& numeric, const std::string& moduleName, const std::string& codeLineText, int codeLineStart)
 | 
						|
    {
 | 
						|
        UNREFERENCED_PARAM(moduleName);
 | 
						|
        UNREFERENCED_PARAM(codeLineText);
 | 
						|
        UNREFERENCED_PARAM(codeLineStart);
 | 
						|
 | 
						|
        if(numeric._varType == Expression::Number)
 | 
						|
        {
 | 
						|
            numeric._value = floor(numeric._value);
 | 
						|
        }
 | 
						|
 | 
						|
        return numeric;
 | 
						|
    }
 | 
						|
 | 
						|
    Expression::Numeric POWF(Expression::Numeric& numeric, const std::string& moduleName, const std::string& codeLineText, int codeLineStart)
 | 
						|
    {
 | 
						|
        UNREFERENCED_PARAM(moduleName);
 | 
						|
        UNREFERENCED_PARAM(codeLineText);
 | 
						|
        UNREFERENCED_PARAM(codeLineStart);
 | 
						|
 | 
						|
        if(numeric._varType == Expression::Number  &&  numeric._params.size() > 0  &&  numeric._params[0]._varType == Expression::Number)
 | 
						|
        {
 | 
						|
            numeric._value = pow(numeric._value, numeric._params[0]._value);
 | 
						|
        }
 | 
						|
 | 
						|
        numeric._params.clear();
 | 
						|
        return numeric;
 | 
						|
    }
 | 
						|
 | 
						|
    Expression::Numeric SQRT(Expression::Numeric& numeric, const std::string& moduleName, const std::string& codeLineText, int codeLineStart)
 | 
						|
    {
 | 
						|
        UNREFERENCED_PARAM(moduleName);
 | 
						|
        UNREFERENCED_PARAM(codeLineText);
 | 
						|
        UNREFERENCED_PARAM(codeLineStart);
 | 
						|
 | 
						|
        if(numeric._varType == Expression::Number  &&  numeric._value > 0.0)
 | 
						|
        {
 | 
						|
            numeric._value = sqrt(numeric._value);
 | 
						|
        }
 | 
						|
 | 
						|
        return numeric;
 | 
						|
    }
 | 
						|
 | 
						|
    Expression::Numeric EXP(Expression::Numeric& numeric, const std::string& moduleName, const std::string& codeLineText, int codeLineStart)
 | 
						|
    {
 | 
						|
        UNREFERENCED_PARAM(moduleName);
 | 
						|
        UNREFERENCED_PARAM(codeLineText);
 | 
						|
        UNREFERENCED_PARAM(codeLineStart);
 | 
						|
 | 
						|
        if(numeric._varType == Expression::Number)
 | 
						|
        {
 | 
						|
            numeric._value = exp(numeric._value);
 | 
						|
        }
 | 
						|
 | 
						|
        return numeric;
 | 
						|
    }
 | 
						|
 | 
						|
    Expression::Numeric EXP2(Expression::Numeric& numeric, const std::string& moduleName, const std::string& codeLineText, int codeLineStart)
 | 
						|
    {
 | 
						|
        UNREFERENCED_PARAM(moduleName);
 | 
						|
        UNREFERENCED_PARAM(codeLineText);
 | 
						|
        UNREFERENCED_PARAM(codeLineStart);
 | 
						|
 | 
						|
        if(numeric._varType == Expression::Number)
 | 
						|
        {
 | 
						|
            numeric._value = exp2(numeric._value);
 | 
						|
        }
 | 
						|
 | 
						|
        return numeric;
 | 
						|
    }
 | 
						|
 | 
						|
    Expression::Numeric LOG(Expression::Numeric& numeric, const std::string& moduleName, const std::string& codeLineText, int codeLineStart)
 | 
						|
    {
 | 
						|
        UNREFERENCED_PARAM(moduleName);
 | 
						|
        UNREFERENCED_PARAM(codeLineText);
 | 
						|
        UNREFERENCED_PARAM(codeLineStart);
 | 
						|
 | 
						|
        if(numeric._varType == Expression::Number  &&  numeric._value > 0.0)
 | 
						|
        {
 | 
						|
            numeric._value = log(numeric._value);
 | 
						|
        }
 | 
						|
 | 
						|
        return numeric;
 | 
						|
    }
 | 
						|
 | 
						|
    Expression::Numeric LOG2(Expression::Numeric& numeric, const std::string& moduleName, const std::string& codeLineText, int codeLineStart)
 | 
						|
    {
 | 
						|
        UNREFERENCED_PARAM(moduleName);
 | 
						|
        UNREFERENCED_PARAM(codeLineText);
 | 
						|
        UNREFERENCED_PARAM(codeLineStart);
 | 
						|
 | 
						|
        if(numeric._varType == Expression::Number  &&  numeric._value > 0.0)
 | 
						|
        {
 | 
						|
            numeric._value = log2(numeric._value);
 | 
						|
        }
 | 
						|
 | 
						|
        return numeric;
 | 
						|
    }
 | 
						|
 | 
						|
    Expression::Numeric LOG10(Expression::Numeric& numeric, const std::string& moduleName, const std::string& codeLineText, int codeLineStart)
 | 
						|
    {
 | 
						|
        UNREFERENCED_PARAM(moduleName);
 | 
						|
        UNREFERENCED_PARAM(codeLineText);
 | 
						|
        UNREFERENCED_PARAM(codeLineStart);
 | 
						|
 | 
						|
        if(numeric._varType == Expression::Number  &&  numeric._value > 0.0)
 | 
						|
        {
 | 
						|
            numeric._value = log10(numeric._value);
 | 
						|
        }
 | 
						|
 | 
						|
        return numeric;
 | 
						|
    }
 | 
						|
 | 
						|
    Expression::Numeric SIN(Expression::Numeric& numeric, const std::string& moduleName, const std::string& codeLineText, int codeLineStart)
 | 
						|
    {
 | 
						|
        UNREFERENCED_PARAM(moduleName);
 | 
						|
        UNREFERENCED_PARAM(codeLineText);
 | 
						|
        UNREFERENCED_PARAM(codeLineStart);
 | 
						|
 | 
						|
        if(numeric._varType == Expression::Number)
 | 
						|
        {
 | 
						|
            numeric._value = sin(numeric._value*MATH_PI/180.0);
 | 
						|
        }
 | 
						|
 | 
						|
        return numeric;
 | 
						|
    }
 | 
						|
 | 
						|
    Expression::Numeric COS(Expression::Numeric& numeric, const std::string& moduleName, const std::string& codeLineText, int codeLineStart)
 | 
						|
    {
 | 
						|
        UNREFERENCED_PARAM(moduleName);
 | 
						|
        UNREFERENCED_PARAM(codeLineText);
 | 
						|
        UNREFERENCED_PARAM(codeLineStart);
 | 
						|
 | 
						|
        if(numeric._varType == Expression::Number)
 | 
						|
        {
 | 
						|
            numeric._value = cos(numeric._value*MATH_PI/180.0);
 | 
						|
        }
 | 
						|
 | 
						|
        return numeric;
 | 
						|
    }
 | 
						|
 | 
						|
    Expression::Numeric TAN(Expression::Numeric& numeric, const std::string& moduleName, const std::string& codeLineText, int codeLineStart)
 | 
						|
    {
 | 
						|
        UNREFERENCED_PARAM(moduleName);
 | 
						|
        UNREFERENCED_PARAM(codeLineText);
 | 
						|
        UNREFERENCED_PARAM(codeLineStart);
 | 
						|
 | 
						|
        if(numeric._varType == Expression::Number)
 | 
						|
        {
 | 
						|
            numeric._value = tan(numeric._value*MATH_PI/180.0);
 | 
						|
        }
 | 
						|
 | 
						|
        return numeric;
 | 
						|
    }
 | 
						|
 | 
						|
    Expression::Numeric ASIN(Expression::Numeric& numeric, const std::string& moduleName, const std::string& codeLineText, int codeLineStart)
 | 
						|
    {
 | 
						|
        UNREFERENCED_PARAM(moduleName);
 | 
						|
        UNREFERENCED_PARAM(codeLineText);
 | 
						|
        UNREFERENCED_PARAM(codeLineStart);
 | 
						|
 | 
						|
        if(numeric._varType == Expression::Number)
 | 
						|
        {
 | 
						|
            numeric._value = asin(numeric._value)/MATH_PI*180.0;
 | 
						|
        }
 | 
						|
 | 
						|
        return numeric;
 | 
						|
    }
 | 
						|
 | 
						|
    Expression::Numeric ACOS(Expression::Numeric& numeric, const std::string& moduleName, const std::string& codeLineText, int codeLineStart)
 | 
						|
    {
 | 
						|
        UNREFERENCED_PARAM(moduleName);
 | 
						|
        UNREFERENCED_PARAM(codeLineText);
 | 
						|
        UNREFERENCED_PARAM(codeLineStart);
 | 
						|
 | 
						|
        if(numeric._varType == Expression::Number)
 | 
						|
        {
 | 
						|
            numeric._value = acos(numeric._value)/MATH_PI*180.0;
 | 
						|
        }
 | 
						|
 | 
						|
        return numeric;
 | 
						|
    }
 | 
						|
 | 
						|
    Expression::Numeric ATAN(Expression::Numeric& numeric, const std::string& moduleName, const std::string& codeLineText, int codeLineStart)
 | 
						|
    {
 | 
						|
        UNREFERENCED_PARAM(moduleName);
 | 
						|
        UNREFERENCED_PARAM(codeLineText);
 | 
						|
        UNREFERENCED_PARAM(codeLineStart);
 | 
						|
 | 
						|
        if(numeric._varType == Expression::Number)
 | 
						|
        {
 | 
						|
            numeric._value = atan(numeric._value)/MATH_PI*180.0;
 | 
						|
        }
 | 
						|
 | 
						|
        return numeric;
 | 
						|
    }
 | 
						|
 | 
						|
    Expression::Numeric ATAN2(Expression::Numeric& numeric, const std::string& moduleName, const std::string& codeLineText, int codeLineStart)
 | 
						|
    {
 | 
						|
        UNREFERENCED_PARAM(moduleName);
 | 
						|
        UNREFERENCED_PARAM(codeLineText);
 | 
						|
        UNREFERENCED_PARAM(codeLineStart);
 | 
						|
 | 
						|
        if(numeric._varType == Expression::Number  &&  numeric._params.size() > 0  &&  numeric._params[0]._varType == Expression::Number)
 | 
						|
        {
 | 
						|
            if(numeric._value != 0.0  ||  numeric._params[0]._value != 0.0)
 | 
						|
            {
 | 
						|
                numeric._value = atan2(numeric._value, numeric._params[0]._value)/MATH_PI*180.0;
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        numeric._params.clear();
 | 
						|
        return numeric;
 | 
						|
    }
 | 
						|
 | 
						|
    Expression::Numeric RAND(Expression::Numeric& numeric, const std::string& moduleName, const std::string& codeLineText, int codeLineStart)
 | 
						|
    {
 | 
						|
        UNREFERENCED_PARAM(moduleName);
 | 
						|
        UNREFERENCED_PARAM(codeLineText);
 | 
						|
        UNREFERENCED_PARAM(codeLineStart);
 | 
						|
 | 
						|
        if(numeric._varType == Expression::Number)
 | 
						|
        {
 | 
						|
            long value = std::lround(numeric._value);
 | 
						|
            numeric._value = (value <= 0) ? 0 : double(rand() % value);
 | 
						|
        }
 | 
						|
 | 
						|
        return numeric;
 | 
						|
    }
 | 
						|
 | 
						|
    Expression::Numeric REV16(Expression::Numeric& numeric, const std::string& moduleName, const std::string& codeLineText, int codeLineStart)
 | 
						|
    {
 | 
						|
        UNREFERENCED_PARAM(moduleName);
 | 
						|
        UNREFERENCED_PARAM(codeLineText);
 | 
						|
        UNREFERENCED_PARAM(codeLineStart);
 | 
						|
 | 
						|
        if(numeric._varType == Expression::Number)
 | 
						|
        {
 | 
						|
            numeric._value = double(handleRevOp(uint32_t(std::lround(numeric._value)), 16));
 | 
						|
        }
 | 
						|
 | 
						|
        return numeric;
 | 
						|
    }
 | 
						|
 | 
						|
    Expression::Numeric REV8(Expression::Numeric& numeric, const std::string& moduleName, const std::string& codeLineText, int codeLineStart)
 | 
						|
    {
 | 
						|
        UNREFERENCED_PARAM(moduleName);
 | 
						|
        UNREFERENCED_PARAM(codeLineText);
 | 
						|
        UNREFERENCED_PARAM(codeLineStart);
 | 
						|
 | 
						|
        if(numeric._varType == Expression::Number)
 | 
						|
        {
 | 
						|
            numeric._value = double(handleRevOp(uint32_t(std::lround(numeric._value)), 8));
 | 
						|
        }
 | 
						|
 | 
						|
        return numeric;
 | 
						|
    }
 | 
						|
 | 
						|
    Expression::Numeric REV4(Expression::Numeric& numeric, const std::string& moduleName, const std::string& codeLineText, int codeLineStart)
 | 
						|
    {
 | 
						|
        UNREFERENCED_PARAM(moduleName);
 | 
						|
        UNREFERENCED_PARAM(codeLineText);
 | 
						|
        UNREFERENCED_PARAM(codeLineStart);
 | 
						|
 | 
						|
        if(numeric._varType == Expression::Number)
 | 
						|
        {
 | 
						|
            numeric._value = double(handleRevOp(uint32_t(std::lround(numeric._value)), 4));
 | 
						|
        }
 | 
						|
 | 
						|
        return numeric;
 | 
						|
    }
 | 
						|
 | 
						|
 | 
						|
    // ********************************************************************************************
 | 
						|
    // Binary Operators
 | 
						|
    // ********************************************************************************************
 | 
						|
    Expression::Numeric ADD(Expression::Numeric& left, Expression::Numeric& right, const std::string& moduleName, const std::string& codeLineText, int codeLineStart)
 | 
						|
    {
 | 
						|
        UNREFERENCED_PARAM(moduleName);
 | 
						|
        UNREFERENCED_PARAM(codeLineText);
 | 
						|
        UNREFERENCED_PARAM(codeLineStart);
 | 
						|
 | 
						|
        if(handleStringAdd(left, right)) return left;
 | 
						|
 | 
						|
        if(left._varType == Expression::Number  &&  right._varType == Expression::Number)
 | 
						|
        {
 | 
						|
            left._value += right._value;
 | 
						|
            return left;
 | 
						|
        }
 | 
						|
 | 
						|
        left._isValid = handleDualOp("ADD", left, right, false);
 | 
						|
        return left;
 | 
						|
    }
 | 
						|
 | 
						|
    Expression::Numeric SUB(Expression::Numeric& left, Expression::Numeric& right, const std::string& moduleName, const std::string& codeLineText, int codeLineStart)
 | 
						|
    {
 | 
						|
        UNREFERENCED_PARAM(moduleName);
 | 
						|
        UNREFERENCED_PARAM(codeLineText);
 | 
						|
        UNREFERENCED_PARAM(codeLineStart);
 | 
						|
 | 
						|
        if(left._varType == Expression::Number  &&  right._varType == Expression::Number)
 | 
						|
        {
 | 
						|
            left._value -= right._value;
 | 
						|
            return left;
 | 
						|
        }
 | 
						|
 | 
						|
        left._isValid = handleDualOp("SUB", left, right, false);
 | 
						|
        return left;
 | 
						|
    }
 | 
						|
 | 
						|
    Expression::Numeric AND(Expression::Numeric& left, Expression::Numeric& right, const std::string& moduleName, const std::string& codeLineText, int codeLineStart)
 | 
						|
    {
 | 
						|
        UNREFERENCED_PARAM(moduleName);
 | 
						|
        UNREFERENCED_PARAM(codeLineText);
 | 
						|
        UNREFERENCED_PARAM(codeLineStart);
 | 
						|
 | 
						|
        if(left._varType == Expression::Number  &&  right._varType == Expression::Number)
 | 
						|
        {
 | 
						|
            left._value = int16_t(std::lround(left._value)) & int16_t(std::lround(right._value));
 | 
						|
            return left;
 | 
						|
        }
 | 
						|
 | 
						|
        left._isValid = handleDualOp("AND", left, right, true);
 | 
						|
        return left;
 | 
						|
    }
 | 
						|
 | 
						|
    Expression::Numeric XOR(Expression::Numeric& left, Expression::Numeric& right, const std::string& moduleName, const std::string& codeLineText, int codeLineStart)
 | 
						|
    {
 | 
						|
        UNREFERENCED_PARAM(moduleName);
 | 
						|
        UNREFERENCED_PARAM(codeLineText);
 | 
						|
        UNREFERENCED_PARAM(codeLineStart);
 | 
						|
 | 
						|
        if(left._varType == Expression::Number  &&  right._varType == Expression::Number)
 | 
						|
        {
 | 
						|
            left._value = int16_t(std::lround(left._value)) ^ int16_t(std::lround(right._value));
 | 
						|
            return left;
 | 
						|
        }
 | 
						|
 | 
						|
        left._isValid = handleDualOp("XOR", left, right, true);
 | 
						|
        return left;
 | 
						|
    }
 | 
						|
 | 
						|
    Expression::Numeric OR(Expression::Numeric& left, Expression::Numeric& right, const std::string& moduleName, const std::string& codeLineText, int codeLineStart)
 | 
						|
    {
 | 
						|
        UNREFERENCED_PARAM(moduleName);
 | 
						|
        UNREFERENCED_PARAM(codeLineText);
 | 
						|
        UNREFERENCED_PARAM(codeLineStart);
 | 
						|
 | 
						|
        if(left._varType == Expression::Number  &&  right._varType == Expression::Number)
 | 
						|
        {
 | 
						|
            left._value = int16_t(std::lround(left._value)) | int16_t(std::lround(right._value));
 | 
						|
            return left;
 | 
						|
        }
 | 
						|
 | 
						|
        left._isValid = handleDualOp("OR", left, right, true);
 | 
						|
        return left;
 | 
						|
    }
 | 
						|
 | 
						|
 | 
						|
    // ********************************************************************************************
 | 
						|
    // Logical Operators
 | 
						|
    // ********************************************************************************************
 | 
						|
    Expression::Numeric LSL(Expression::Numeric& left, Expression::Numeric& right, const std::string& moduleName, const std::string& codeLineText, int codeLineStart)
 | 
						|
    {
 | 
						|
        UNREFERENCED_PARAM(moduleName);
 | 
						|
        UNREFERENCED_PARAM(codeLineText);
 | 
						|
        UNREFERENCED_PARAM(codeLineStart);
 | 
						|
 | 
						|
        if(left._varType == Expression::Number  &&  right._varType == Expression::Number)
 | 
						|
        {
 | 
						|
            left._value = (int16_t(std::lround(left._value)) << int16_t(std::lround(right._value))) & 0x0000FFFF;
 | 
						|
            return left;
 | 
						|
        }
 | 
						|
 | 
						|
        Compiler::getNextTempVar();
 | 
						|
 | 
						|
        if((left._varType == Expression::TmpVar  ||  left._varType == Expression::IntVar16)  &&  right._varType == Expression::Number)
 | 
						|
        {
 | 
						|
            if(right._value == 8)
 | 
						|
            {
 | 
						|
                switch(left._varType)
 | 
						|
                {
 | 
						|
                    // Temporary variable address
 | 
						|
                    case Expression::TmpVar:
 | 
						|
                    {
 | 
						|
                        Compiler::emitVcpuAsm("LD", Expression::byteToHexString(uint8_t(std::lround(left._value))), false);
 | 
						|
                    }
 | 
						|
                    break;
 | 
						|
 | 
						|
                    // User variable name
 | 
						|
                    case Expression::IntVar16:
 | 
						|
                    {
 | 
						|
                        int varIndex = Compiler::findVar(left._name);
 | 
						|
                        if(varIndex == -1) fprintf(stderr, "Operator::LSL() : '%s:%d' : couldn't find variable name '%s' : %s\n", moduleName.c_str(), codeLineStart, left._name.c_str(), codeLineText.c_str());
 | 
						|
                        Compiler::emitVcpuAsm("LD", "_" + left._name, false);
 | 
						|
                    }
 | 
						|
 | 
						|
                    default: break;
 | 
						|
                }
 | 
						|
 | 
						|
                changeToTmpVar(left);
 | 
						|
 | 
						|
                Compiler::emitVcpuAsm("ST", "giga_vAC + 1", false);
 | 
						|
                Compiler::emitVcpuAsm("ORI", "0xFF", false);
 | 
						|
                Compiler::emitVcpuAsm("XORI", "0xFF", false);
 | 
						|
            }
 | 
						|
            else
 | 
						|
            {
 | 
						|
                handleLogicalOp("LSLW", left);
 | 
						|
                for(uint8_t s=0; s<uint8_t(std::lround(right._value)); s++)
 | 
						|
                {
 | 
						|
                    Compiler::emitVcpuAsm("LSLW", "", false);
 | 
						|
                }
 | 
						|
            }
 | 
						|
 | 
						|
            Compiler::emitVcpuAsm("STW", Expression::byteToHexString(uint8_t(Compiler::getTempVarStart())), false);
 | 
						|
        }
 | 
						|
 | 
						|
        return left;
 | 
						|
    }
 | 
						|
 | 
						|
    Expression::Numeric LSR(Expression::Numeric& left, Expression::Numeric& right, const std::string& moduleName, const std::string& codeLineText, int codeLineStart)
 | 
						|
    {
 | 
						|
        UNREFERENCED_PARAM(moduleName);
 | 
						|
        UNREFERENCED_PARAM(codeLineText);
 | 
						|
        UNREFERENCED_PARAM(codeLineStart);
 | 
						|
 | 
						|
        if(left._varType == Expression::Number  &&  right._varType == Expression::Number)
 | 
						|
        {
 | 
						|
            left._value = int16_t(std::lround(left._value)) >> int16_t(std::lround(right._value));
 | 
						|
            return left;
 | 
						|
        }
 | 
						|
 | 
						|
        Compiler::getNextTempVar();
 | 
						|
 | 
						|
        if((left._varType == Expression::TmpVar  ||  left._varType == Expression::IntVar16)  &&  right._varType == Expression::Number)
 | 
						|
        {
 | 
						|
            // Optimised high byte read
 | 
						|
            if(right._value == 8)
 | 
						|
            {
 | 
						|
                switch(left._varType)
 | 
						|
                {
 | 
						|
                    // Temporary variable address
 | 
						|
                    case Expression::TmpVar:
 | 
						|
                    {
 | 
						|
                        Compiler::emitVcpuAsm("LD", Expression::byteToHexString(uint8_t(std::lround(left._value))) + " + 1", false);
 | 
						|
                    }
 | 
						|
                    break;
 | 
						|
 | 
						|
                    // User variable name
 | 
						|
                    case Expression::IntVar16:
 | 
						|
                    {
 | 
						|
                        int varIndex = Compiler::findVar(left._name);
 | 
						|
                        if(varIndex == -1) fprintf(stderr, "Operator::LSR() : '%s:%d' : couldn't find variable name '%s' : %s\n", moduleName.c_str(), codeLineStart, left._name.c_str(), codeLineText.c_str());
 | 
						|
                        Compiler::emitVcpuAsm("LD", "_" + left._name + " + 1", false);
 | 
						|
                    }
 | 
						|
                    break;
 | 
						|
 | 
						|
                    default: break;
 | 
						|
                }
 | 
						|
 | 
						|
                changeToTmpVar(left);
 | 
						|
            }
 | 
						|
            else
 | 
						|
            {
 | 
						|
                std::string opcode;
 | 
						|
                switch(int16_t(std::lround(right._value)))
 | 
						|
                {
 | 
						|
                    case 1: opcode = "%ShiftRight1bit"; break;
 | 
						|
                    case 2: opcode = "%ShiftRight2bit"; break;
 | 
						|
                    case 3: opcode = "%ShiftRight3bit"; break;
 | 
						|
                    case 4: opcode = "%ShiftRight4bit"; break;
 | 
						|
                    case 5: opcode = "%ShiftRight5bit"; break;
 | 
						|
                    case 6: opcode = "%ShiftRight6bit"; break;
 | 
						|
                    case 7: opcode = "%ShiftRight7bit"; break;
 | 
						|
 | 
						|
                    default: break;
 | 
						|
                }
 | 
						|
 | 
						|
                handleLogicalOp(opcode, left);
 | 
						|
                Compiler::emitVcpuAsm(opcode, "", false);
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        Compiler::emitVcpuAsm("STW", Expression::byteToHexString(uint8_t(Compiler::getTempVarStart())), false);
 | 
						|
 | 
						|
        return left;
 | 
						|
    }
 | 
						|
 | 
						|
    Expression::Numeric ASR(Expression::Numeric& left, Expression::Numeric& right, const std::string& moduleName, const std::string& codeLineText, int codeLineStart)
 | 
						|
    {
 | 
						|
        UNREFERENCED_PARAM(moduleName);
 | 
						|
        UNREFERENCED_PARAM(codeLineText);
 | 
						|
        UNREFERENCED_PARAM(codeLineStart);
 | 
						|
 | 
						|
        if(left._varType == Expression::Number  &&  right._varType == Expression::Number)
 | 
						|
        {
 | 
						|
            left._value /= (1 << int16_t(std::lround(right._value))) & 0x0000FFFF;
 | 
						|
            return left;
 | 
						|
        }
 | 
						|
 | 
						|
        Compiler::getNextTempVar();
 | 
						|
 | 
						|
        if((left._varType == Expression::TmpVar  ||  left._varType == Expression::IntVar16)  &&  right._varType == Expression::Number)
 | 
						|
        {
 | 
						|
            std::string opcode;
 | 
						|
            switch(int16_t(std::lround(right._value)))
 | 
						|
            {
 | 
						|
                case 1: opcode = "%ShiftRightSgn1bit"; break;
 | 
						|
                case 2: opcode = "%ShiftRightSgn2bit"; break;
 | 
						|
                case 3: opcode = "%ShiftRightSgn3bit"; break;
 | 
						|
                case 4: opcode = "%ShiftRightSgn4bit"; break;
 | 
						|
                case 5: opcode = "%ShiftRightSgn5bit"; break;
 | 
						|
                case 6: opcode = "%ShiftRightSgn6bit"; break;
 | 
						|
                case 7: opcode = "%ShiftRightSgn7bit"; break;
 | 
						|
                case 8: opcode = "%ShiftRightSgn8bit"; break;
 | 
						|
 | 
						|
                default: break;
 | 
						|
            }
 | 
						|
 | 
						|
            handleLogicalOp(opcode, left);
 | 
						|
            Compiler::emitVcpuAsm(opcode, "", false);
 | 
						|
        }
 | 
						|
 | 
						|
        Compiler::emitVcpuAsm("STW", Expression::byteToHexString(uint8_t(Compiler::getTempVarStart())), false);
 | 
						|
 | 
						|
        return left;
 | 
						|
    }
 | 
						|
 | 
						|
 | 
						|
    // ********************************************************************************************
 | 
						|
    // Conditional Operators
 | 
						|
    // ********************************************************************************************
 | 
						|
    Expression::Numeric EQ(Expression::Numeric& left, Expression::Numeric& right, Expression::CCType ccType, const std::string& moduleName, const std::string& codeLineText, int codeLineStart)
 | 
						|
    {
 | 
						|
        UNREFERENCED_PARAM(moduleName);
 | 
						|
        UNREFERENCED_PARAM(codeLineText);
 | 
						|
        UNREFERENCED_PARAM(codeLineStart);
 | 
						|
 | 
						|
        if(handleStringCcOP(left, right, Expression::EqOP)) return left;
 | 
						|
 | 
						|
        if(left._varType == Expression::Number  &&  right._varType == Expression::Number)
 | 
						|
        {
 | 
						|
            left._value = (left._value == right._value);
 | 
						|
            return left;
 | 
						|
        }
 | 
						|
 | 
						|
        bool invertedLogic = false;
 | 
						|
        left._isValid = handleConditionOp(left, right, ccType, invertedLogic, "XOR");
 | 
						|
 | 
						|
        // Convert EQ into one of the condition types of branch instruction
 | 
						|
        std::string cc = (ccType == Expression::FastCC) ? "Ne" : "Eq"; //(!invertedLogic) ? "Eq" : "Ne";
 | 
						|
        emitCcType(ccType, cc);
 | 
						|
 | 
						|
        return left;
 | 
						|
    }
 | 
						|
 | 
						|
    Expression::Numeric NE(Expression::Numeric& left, Expression::Numeric& right, Expression::CCType ccType, const std::string& moduleName, const std::string& codeLineText, int codeLineStart)
 | 
						|
    {
 | 
						|
        UNREFERENCED_PARAM(moduleName);
 | 
						|
        UNREFERENCED_PARAM(codeLineText);
 | 
						|
        UNREFERENCED_PARAM(codeLineStart);
 | 
						|
 | 
						|
        if(handleStringCcOP(left, right, Expression::NeOP)) return left;
 | 
						|
 | 
						|
        if(left._varType == Expression::Number  &&  right._varType == Expression::Number)
 | 
						|
        {
 | 
						|
            left._value = left._value != right._value;
 | 
						|
            return left;
 | 
						|
        }
 | 
						|
 | 
						|
        bool invertedLogic = false;
 | 
						|
        left._isValid = handleConditionOp(left, right, ccType, invertedLogic, "XOR");
 | 
						|
 | 
						|
        // Convert NE into one of the condition types of branch instruction
 | 
						|
        std::string cc = (ccType == Expression::FastCC) ? "Eq" : "Ne"; //(!invertedLogic) ? "Ne" : "Eq";
 | 
						|
        emitCcType(ccType, cc);
 | 
						|
 | 
						|
        return left;
 | 
						|
    }
 | 
						|
 | 
						|
    Expression::Numeric LE(Expression::Numeric& left, Expression::Numeric& right, Expression::CCType ccType, const std::string& moduleName, const std::string& codeLineText, int codeLineStart)
 | 
						|
    {
 | 
						|
        UNREFERENCED_PARAM(moduleName);
 | 
						|
        UNREFERENCED_PARAM(codeLineText);
 | 
						|
        UNREFERENCED_PARAM(codeLineStart);
 | 
						|
 | 
						|
        if(handleStringCcOP(left, right, Expression::LeOP)) return left;
 | 
						|
 | 
						|
        if(left._varType == Expression::Number  &&  right._varType == Expression::Number)
 | 
						|
        {
 | 
						|
            left._value = left._value <= right._value;
 | 
						|
            return left;
 | 
						|
        }
 | 
						|
 | 
						|
        bool invertedLogic = false;
 | 
						|
        left._isValid = handleConditionOp(left, right, ccType, invertedLogic);
 | 
						|
 | 
						|
        // Convert LE into one of the condition types of branch instruction
 | 
						|
        std::string cc = (!invertedLogic) ? "Le" : "Gt";
 | 
						|
        emitCcType(ccType, cc);
 | 
						|
 | 
						|
        return left;
 | 
						|
    }
 | 
						|
 | 
						|
    Expression::Numeric GE(Expression::Numeric& left, Expression::Numeric& right, Expression::CCType ccType, const std::string& moduleName, const std::string& codeLineText, int codeLineStart)
 | 
						|
    {
 | 
						|
        UNREFERENCED_PARAM(moduleName);
 | 
						|
        UNREFERENCED_PARAM(codeLineText);
 | 
						|
        UNREFERENCED_PARAM(codeLineStart);
 | 
						|
 | 
						|
        if(handleStringCcOP(left, right, Expression::GeOP)) return left;
 | 
						|
 | 
						|
        if(left._varType == Expression::Number  &&  right._varType == Expression::Number)
 | 
						|
        {
 | 
						|
            left._value = left._value >= right._value;
 | 
						|
            return left;
 | 
						|
        }
 | 
						|
 | 
						|
        bool invertedLogic = false;
 | 
						|
        left._isValid = handleConditionOp(left, right, ccType, invertedLogic);
 | 
						|
 | 
						|
        // Convert GE into one of the condition types of branch instruction
 | 
						|
        std::string cc = (!invertedLogic) ? "Ge" : "Lt";
 | 
						|
        emitCcType(ccType, cc);
 | 
						|
 | 
						|
        return left;
 | 
						|
    }
 | 
						|
 | 
						|
    Expression::Numeric LT(Expression::Numeric& left, Expression::Numeric& right, Expression::CCType ccType, const std::string& moduleName, const std::string& codeLineText, int codeLineStart)
 | 
						|
    {
 | 
						|
        UNREFERENCED_PARAM(moduleName);
 | 
						|
        UNREFERENCED_PARAM(codeLineText);
 | 
						|
        UNREFERENCED_PARAM(codeLineStart);
 | 
						|
 | 
						|
        if(handleStringCcOP(left, right, Expression::LtOP)) return left;
 | 
						|
 | 
						|
        if(left._varType == Expression::Number  &&  right._varType == Expression::Number)
 | 
						|
        {
 | 
						|
            left._value = (left._value < right._value);
 | 
						|
            return left;
 | 
						|
        }
 | 
						|
 | 
						|
        bool invertedLogic = false;
 | 
						|
        left._isValid = handleConditionOp(left, right, ccType, invertedLogic);
 | 
						|
 | 
						|
        // Convert LT into one of the condition types of branch instruction
 | 
						|
        std::string cc = (!invertedLogic) ? "Lt" : "Ge";
 | 
						|
        emitCcType(ccType, cc);
 | 
						|
 | 
						|
        return left;
 | 
						|
    }
 | 
						|
 | 
						|
    Expression::Numeric GT(Expression::Numeric& left, Expression::Numeric& right, Expression::CCType ccType, const std::string& moduleName, const std::string& codeLineText, int codeLineStart)
 | 
						|
    {
 | 
						|
        UNREFERENCED_PARAM(moduleName);
 | 
						|
        UNREFERENCED_PARAM(codeLineText);
 | 
						|
        UNREFERENCED_PARAM(codeLineStart);
 | 
						|
 | 
						|
        if(handleStringCcOP(left, right, Expression::GtOP)) return left;
 | 
						|
 | 
						|
        if(left._varType == Expression::Number  &&  right._varType == Expression::Number)
 | 
						|
        {
 | 
						|
            left._value = (left._value > right._value);
 | 
						|
            return left;
 | 
						|
        }
 | 
						|
 | 
						|
        bool invertedLogic = false;
 | 
						|
        left._isValid = handleConditionOp(left, right, ccType, invertedLogic);
 | 
						|
 | 
						|
        // Convert GT into one of the condition types of branch instruction
 | 
						|
        std::string cc = (!invertedLogic) ? "Gt" : "Le";
 | 
						|
        emitCcType(ccType, cc);
 | 
						|
 | 
						|
        return left;
 | 
						|
    }
 | 
						|
 | 
						|
 | 
						|
    // ********************************************************************************************
 | 
						|
    // Math Operators
 | 
						|
    // ********************************************************************************************
 | 
						|
    Expression::Numeric POW(Expression::Numeric& left, Expression::Numeric& right, const std::string& moduleName, const std::string& codeLineText, int codeLineStart)
 | 
						|
    {
 | 
						|
        UNREFERENCED_PARAM(moduleName);
 | 
						|
        UNREFERENCED_PARAM(codeLineText);
 | 
						|
        UNREFERENCED_PARAM(codeLineStart);
 | 
						|
 | 
						|
        if(left._varType == Expression::Number  &&  right._varType == Expression::Number)
 | 
						|
        {
 | 
						|
            left._value = pow(double(left._value), double(right._value));
 | 
						|
            return left;
 | 
						|
        }
 | 
						|
 | 
						|
        // Optimise base = 0
 | 
						|
        if(left._varType == Expression::Number  &&  left._value == 0)
 | 
						|
        {
 | 
						|
            return Expression::Numeric(0, -1, true, false, false, Expression::Number, Expression::BooleanCC, Expression::Int16Both, std::string(""), std::string(""));
 | 
						|
        }
 | 
						|
        // Optimise base = 1
 | 
						|
        else if(left._varType == Expression::Number  &&  left._value == 1)
 | 
						|
        {
 | 
						|
            return Expression::Numeric(1, -1, true, false, false, Expression::Number, Expression::BooleanCC, Expression::Int16Both, std::string(""), std::string(""));
 | 
						|
        }
 | 
						|
        // Optimise exponent = 0
 | 
						|
        else if(right._varType == Expression::Number  &&  right._value == 0)
 | 
						|
        {
 | 
						|
            return Expression::Numeric(1, -1, true, false, false, Expression::Number, Expression::BooleanCC, Expression::Int16Both, std::string(""), std::string(""));
 | 
						|
        }
 | 
						|
 | 
						|
        left._isValid = (Compiler::getCodeRomType() >= Cpu::ROMv5a) ? handleMathOp("CALLI", "power16bit", left, right) : handleMathOp("CALL", "power16bit", left, right);
 | 
						|
 | 
						|
        return left;
 | 
						|
    }
 | 
						|
 | 
						|
    Expression::Numeric MUL(Expression::Numeric& left, Expression::Numeric& right, const std::string& moduleName, const std::string& codeLineText, int codeLineStart)
 | 
						|
    {
 | 
						|
        UNREFERENCED_PARAM(moduleName);
 | 
						|
        UNREFERENCED_PARAM(codeLineText);
 | 
						|
        UNREFERENCED_PARAM(codeLineStart);
 | 
						|
 | 
						|
        if(left._varType == Expression::Number  &&  right._varType == Expression::Number)
 | 
						|
        {
 | 
						|
            left._value *= right._value;
 | 
						|
            return left;
 | 
						|
        }
 | 
						|
 | 
						|
        // Optimise multiply with 0
 | 
						|
        if((left._varType == Expression::Number  &&  left._value == 0)  ||  (right._varType == Expression::Number  &&  right._value == 0))
 | 
						|
        {
 | 
						|
            return Expression::Numeric(0, -1, true, false, false, Expression::Number, Expression::BooleanCC, Expression::Int16Both, std::string(""), std::string(""));
 | 
						|
        }
 | 
						|
 | 
						|
        left._isValid = (Compiler::getCodeRomType() >= Cpu::ROMv5a) ? handleMathOp("CALLI", "multiply16bit", left, right) : handleMathOp("CALL", "multiply16bit", left, right);
 | 
						|
 | 
						|
        return left;
 | 
						|
    }
 | 
						|
 | 
						|
    Expression::Numeric DIV(Expression::Numeric& left, Expression::Numeric& right, const std::string& moduleName, const std::string& codeLineText, int codeLineStart)
 | 
						|
    {
 | 
						|
        UNREFERENCED_PARAM(moduleName);
 | 
						|
        UNREFERENCED_PARAM(codeLineText);
 | 
						|
        UNREFERENCED_PARAM(codeLineStart);
 | 
						|
 | 
						|
        if(left._varType == Expression::Number  &&  right._varType == Expression::Number)
 | 
						|
        {
 | 
						|
            left._value = (right._value == 0) ? 0 : left._value / right._value;
 | 
						|
            return left;
 | 
						|
        }
 | 
						|
 | 
						|
        // Optimise divide with 0, term() never lets denominator = 0
 | 
						|
        if((left._varType == Expression::Number  &&  left._value == 0)  ||  (right._varType == Expression::Number  &&  right._value == 0))
 | 
						|
        {
 | 
						|
            return Expression::Numeric(0, -1, true, false, false, Expression::Number, Expression::BooleanCC, Expression::Int16Both, std::string(""), std::string(""));
 | 
						|
        }
 | 
						|
 | 
						|
        left._isValid = (Compiler::getCodeRomType() >= Cpu::ROMv5a) ? handleMathOp("CALLI", "divide16bit", left, right) : handleMathOp("CALL", "divide16bit", left, right);
 | 
						|
 | 
						|
        return left;
 | 
						|
    }
 | 
						|
 | 
						|
    Expression::Numeric MOD(Expression::Numeric& left, Expression::Numeric& right, const std::string& moduleName, const std::string& codeLineText, int codeLineStart)
 | 
						|
    {
 | 
						|
        UNREFERENCED_PARAM(moduleName);
 | 
						|
        UNREFERENCED_PARAM(codeLineText);
 | 
						|
        UNREFERENCED_PARAM(codeLineStart);
 | 
						|
 | 
						|
        if(left._varType == Expression::Number  &&  right._varType == Expression::Number)
 | 
						|
        {
 | 
						|
            left._value = (int16_t(std::lround(right._value)) == 0) ? 0 : int16_t(std::lround(left._value)) % int16_t(std::lround(right._value));
 | 
						|
            return left;
 | 
						|
        }
 | 
						|
 | 
						|
        // Optimise divide with 0, term() never lets denominator = 0
 | 
						|
        if((left._varType == Expression::Number  &&  left._value == 0)  ||  (right._varType == Expression::Number  &&  right._value == 0))
 | 
						|
        {
 | 
						|
            return Expression::Numeric(0, -1, true, false, false, Expression::Number, Expression::BooleanCC, Expression::Int16Both, std::string(""), std::string(""));
 | 
						|
        }
 | 
						|
 | 
						|
        left._isValid = (Compiler::getCodeRomType() >= Cpu::ROMv5a) ? handleMathOp("CALLI", "divide16bit", left, right, true) : handleMathOp("CALL", "divide16bit", left, right, true);
 | 
						|
 | 
						|
        return left;
 | 
						|
    }
 | 
						|
} |