--
-- Usage: require('thisfile');
--

-- Match operand to be r0..r3 (or R0..R3), and return the number;
function isReg(op)
    local nr = op:match( '%s*[rR]([0-3])' );
    if( nr ) then
        return tonumber(nr) ;
    else
        Error("Operand must be R0..R3");
    end
end

-- Match 2 operands to be r0..r3 (or R0..R3), and return
-- a value between 0x00 and 0x0f corresponding with { R0,R0 } .. {R3,R3}
function isReg2(op1, op2)
    local n1, n2 = isReg(op1), isReg(op2);
    return( n2*4 + n1 );
end

--
-- Match a possible operand for the ADDQ instruction, and return
-- the corresponding instruction-offset.
--
function isQuickOp(op1)
    local opVal = { ['#2']=0, ['#1']=1, ['#-2']=2, ['#-1']=3 };

    local result = opVal[op1];
    if( result == nil ) then
        Error("ADDQ value must be #2, #1, #-1 or #-2");
    end
    return result ;
end

--------------------------------------------------------------------------------
-- Chapter: Evaluate symbol:
--------------------------------------------------------------------------------
require( './lib' );
require( 'symtab' );

--
-- Take a value in range 0..2^32-1 and return a table of byte-values
-- in little-endian order
--

function As_table(val)
    local r = {};

    while( val > 0 ) do
        local b = math.fmod(val,256);
        table.insert(r,b);
        val = math.floor(val / 256);
    end

    return r ;
end

-- 
-- Evaluate a constant expression in any of the formats below
--    Decimal, just digits
--    Hex, prefix 0x or 0X
--    Binary, prefix 0b or '%'
--    String, enclosed in single or double quotes.
--    Symbol, start with underscore or letter, followed by one or more letters/digits/underscores
--
-- Return a table with the bytes that compose the value described object.
-- [==[
function Eval(exp)
    local capture, idx;

    if( exp == '' ) then return nil end;
    -- Decimal, just digits.
    capture = exp:match("^(%d+)") 
    if( capture and not exp:match("%D+") ) then return( As_table(tonumber(capture)) ); end;


    -- Hex, prefix 0x or 0X
    capture = exp:match("^(0[xX]%x+)") 
    if( capture and not exp:match("%X+",3) ) then return( As_table(tonumber(capture)) ); end;

    -- Binary, prefix 0b, 0B, or '%'
    idx,capture = exp:match("^0[bB]()([01]+)") 
    if( not idx ) then idx,capture = exp:match("^%%()([01]+)") end;

    if( not exp:match("[^01]+",idx) ) then
        local result = 0;
        for i = 1,capture:len() do
            result = result * 2;
            if( capture:sub(i,i) == '1' ) then result = result + 1; end;
        end--for
        return( As_table(result) );
    end

    -- String, enclosed in single or double-quotes.
    capture = exp:match("'(.+)'") or exp:match('"(.+)"') ;
    if( capture ) then
        local result = {};
        for i = 1,capture:len() do
            table.insert( result, capture:byte(i) );
        end--for
        return result ;
    end--if


    capture = exp:match("^([_%a]+[_%w]*)");
    if( capture ) then
        local result = symtab_lookup(capture);
        if( not result ) then
            print("Undefined symbol");
            return( nil );
        end
        return( As_table( result ) );
    end

end--Eval()

function Eval_as_word(exp)
    local t = Eval(exp);
    if( #t == 1 ) then table.insert(t,0x00); end--if : append zero as most-significant byte.
    return t ;
end

function Eval_as_byte(exp)
    local t = Eval(exp);
    if( #t > 1 ) then Error("Byte operand expected"); end--if
    return t ;
end

--EOF--
