lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


Am 10.07.2013 00:18 schröbte Rena:
As an example, I once had to implement some very hairy decompiled code in
Lua, that looked like several lines of such lovely constructs as:

T = (a << 24) | 0x10000000 | (((d & 0xF) >> 4) << 8) | ((d & 0xF0) >> 8) <<
16) | (s + 0x100000)

Until Lua gets bit operators, maybe you want to have a look at this modified version of one of Roberto's LPeg examples ...

Philipp


local bit32 = require( "bit32" )
local L = require( "lpeg" )

-- unary operations
local function eval1( op, v1 )
  if op == "+" then return v1
  elseif op == "-" then return (bit32.bnot( v1 )+1) % 4294967296
  elseif op == "~" then return bit32.bnot( v1 )
  end
end

-- binary multiplication with 32-bit wrap-around
local max_int = 2^51

local function umul( v1, v2 )
  local vm = v1 * v2
  if vm >= max_int then
    local mask = 4294967295
    vm = 0
    for i = 0, 31 do
      vm = vm + bit32.band( bit32.extract( v1, i )*bit32.lshift( mask, i ),
                            bit32.lshift( v2, i ) )
    end
  end
  return vm % 4294967296
end

-- binary operations
local function eval2( v1, op, v2 )
  if op == "+" then return (v1 + v2) % 4294967296
  elseif op == "-" then return (v1 + bit32.bnot( v2 ) + 1) % 4294967296
  elseif op == "*" then return umul( v1, v2 )
  elseif op == "/" then return (v1 - (v1 % v2)) / v2
  elseif op == "%" then return v1 % v2
  elseif op == "^" then return bit32.bxor( v1, v2 )
  elseif op == "&" then return bit32.band( v1, v2 )
  elseif op == "|" then return bit32.bor( v1, v2 )
  elseif op == ">>" then return bit32.rshift( v1, v2 )
  elseif op == "<<" then return bit32.lshift( v1, v2 )
  end
end

-- lpeg parser/evaluator
local P,S,R,V,C,Cf,Cg,Cc,Carg = L.P,L.S,L.R,L.V,L.C,L.Cf,L.Cg,L.Cc,L.Carg
local Space = S" \n\t"^0
local Number = C( R"19" * R"09"^0 + P"0" ) * Space
local HexNumber = P"0" * S"xX" * C( R( "09", "AF", "af" )^1 ) * Space
local Ident = C( (R( "az", "AZ" ) + P"_") * (R( "az", "AZ", "09" ) + P"_")^0 ) * Space
local BinOp1 = C( P"|" ) * Space
local BinOp2 = C( P"^" ) * Space
local BinOp3 = C( P"&" ) * Space
local BinOp4 = C( P"<<" + P">>" ) * Space
local BinOp5 = C( S"+-" ) * Space
local BinOp6 = C( S"*/%" ) * Space
local Open = "(" * Space
local Close = ")" * Space
local UnOp = C( S"+-~" ) * Space

local G = P{
  "Exp0",
  Exp0 = Cf( V"Exp1" * Cg( BinOp1 * V"Exp1" )^0, eval2 ),
  Exp1 = Cf( V"Exp2" * Cg( BinOp2 * V"Exp2" )^0, eval2 ),
  Exp2 = Cf( V"Exp3" * Cg( BinOp3 * V"Exp3" )^0, eval2 ),
  Exp3 = Cf( V"Exp4" * Cg( BinOp4 * V"Exp4" )^0, eval2 ),
  Exp4 = Cf( V"Exp5" * Cg( BinOp5 * V"Exp5" )^0, eval2 ),
  Exp5 = Cf( V"Atom" * Cg( BinOp6 * V"Atom" )^0, eval2 ),
  Atom = HexNumber * Cc( 16 ) / tonumber +
         Number / tonumber +
         Ident * Carg( 1 ) / function( n, t ) return bit32.bor( t[ n ], 0 ) end +
         UnOp * V"Atom" / eval1 +
         Open * V"Exp0" * Close
}

local function bitops( s, vars )
  return L.match( G, s, 1, vars )
end



--[=[
-- TESTS:
local function test( s, exp, ... )
  local v = nil
  if select( '#', ... ) > 0 then
    v, exp = exp, (...)
  end
  local r = bitops( s, v )
  print( s, "=", r )
  assert( r == exp, "`"..s.."' is "..r..", not "..exp )
end

test( "123", 123 )
test( "0xFF", 255 )
test( "a", { a = 5 }, 5 )
test( "~0", 4294967295 )
test( "-2", 4294967294 )
test( "-0", 0 )
test( "+1", 1 )
test( "1+2*3", 7 )
test( "(1+2)*3", 9 )
test( "-1 + 1", 0 )
test( "2 - 3", 4294967295 )
test( "5 / 2", 2 )
test( "5 % 2", 1 )
test( "0xFFFFFFFF * 0xfffffffe", 2 )
test( "1 | 2", 3 )
test( "5 ^ 7", 2 )
test( "1 & 3", 1 )
test( "1 << 2", 4 )
test( "4 >> 1", 2 )
test( "7 & ~3", 4 )
test( [[(a << 24) | 0x10000000 | (((d & 0xF) >> 4) << 8) |
(((d & 0xF0) >> 8) << 16) | (s + 0x100000)]],
{ a = 34567, d = 19876, s = 12345 }, 386936889 )
--]=]

return bitops