pasm
Version:
Piston X86-64 Assembler
180 lines (149 loc) • 4.18 kB
text/coffeescript
# Now we are using the BigInt.js class for browser compatibility.
if exports?
BigInt = require(__dirname+'/../javascript-bignum/biginteger.js').BigInteger
else
BigInt = BigInteger
class Hex
constructor: (number) ->
self = this
@int = @parse(number)
getInt: ->
if @neg()
return @twosComplement(@int)
else
return @int
toString: ->
return @getInt().toString 16
padBits: (bits) ->
pad = ""
padBit = (if @neg() then "1" else "0")
a = 0
while a < bits - @getInt().toString(2).length
pad += padBit
a++
"" + pad + @getInt().toString(2)
padBytes: (bytes) ->
padByte = (if @neg() then "f" else "0")
pad = ""
bits = @padBits(bytes * 8)
h = BigInt("0b" + bits).toString(16)
a = 0
while a < bytes * 2 - h.length
pad += padByte
a++
return pad + h
twosComplement: (int) ->
bin = int.toString(2)
bin = bin.substr(1,bin.length)
oLen = bin.length
pad = ""
nbin = ""
for a in bin
nbin += (if a is "0" then "1" else "0")
nbin = BigInt("0b" + nbin).add(1).toString(2)
if nbin.length < oLen
a = 0
while a < oLen - nbin.length
pad += "0"
a++
nbin = "1" + pad + nbin
return BigInt "0b" + nbin
int8: ->
@padBytes(1).substr 0, 1 * 2
int16: ->
return @littleEndian(@padBytes(2)).substr 0, 2 * 2
int32: ->
return @littleEndian(@padBytes(4)).substr 0, 4 * 2
int64: ->
return @littleEndian(@padBytes(8)).substr 0, 8 * 2
littleEndian: (str) ->
little = ""
i = 0
while i < str.length
little += str.substr(str.length - i - 2, 2)
i += 2
little
parse: (number) ->
int = 0
# If negative, then do two's complement
sign = ''
unless number.search("-") is -1 then sign = '-'
# Binary
if /^(\-|\+)?[01]+b$/.test(number)
bin = /^(\-|\+)?([01]+)b$/.exec(number)
int = BigInt("#{sign}0b" + bin[2])
if /^(\-|\+)?0b[01]+$/.test(number)
bin = /^(\-|\+)?0b([01]+)$/.exec(number)
int = BigInt("#{sign}0b" + bin[2])
# Hex
if /^(\-|\+)?0x[0-9A-Fa-f]+$/.test(number)
hex = /^(\-|\+)?0x([0-9A-Fa-f]+)$/.exec(number)
int = BigInt("#{sign}0x" + hex[2])
if /^(\-|\+)?0[0-9A-Fa-f]+h$/.test(number)
hex = /^(\-|\+)?0([0-9A-Fa-f]+)h$/.exec(number)
int = BigInt("#{sign}0x" + hex[2])
# Decimal
if /^(\-|\+)?0?[0-9]+d?$/.test(number)
dec = /^(\-|\+)?0?([0-9]+)d?$/.exec(number)
int = BigInt(sign+dec[2])
return int
valueOf: ->
return parseInt @int.toString(), 10
toJSValue: ->
return parseInt @int.toString(), 10
add: (num) ->
if typeof num is "number"
@int = @int.add(num)
else
@int = @int.add(num.int)
return this
subtract: (num) ->
@int = @int.subtract(num.int)
return this
multiply: (num) ->
if typeof num == 'number'
@int = @int.multiply(num)
else
@int = @int.multiply(num.int)
return this
divide: (num) ->
if typeof num == 'number'
@int = @int.divide(num)
else
@int = @int.divide(num.int)
return this
shiftLeft: (num) ->
str = @getInt().toString(2)
for a in [0..num]
str = str + '0'
return new Hex('0b'+str)
shiftRight: (num) ->
str = @getInt().toString(2)
digit = if @neg() then 1 else 0
for a in [0..num]
str = digit + str
return new Hex('0b'+str)
size: ->
len = @getInt().toString(16).length
return 1 if len <= 2
return 2 if len <= 4
return 4 if len <= 8
return 8 if len <= 16
getRightSize: (num, endian) ->
if endian? && endian == false then val = @padBytes(num) else val = @littleEndian(@padBytes(num))
if val.length > num * 2
# TODO -- make better warning and error system
console.log "Warning: numeric constant does not fit to target size\n"
val = val.substr(0, num * 2)
return val
neg: ->
if @int.sign() < 0 then return true else return false
sign: ->
if @int.sign() < 0
return '-'
else
return '+'
if exports?
exports.Hex = Hex
else if window?
window.Hex = Hex