mirror of
https://github.com/samsonjs/compiler.git
synced 2026-04-27 14:57:45 +00:00
Removed duplication thanks to caliper @ http://devver.net
This commit is contained in:
parent
dd297479f6
commit
de366ea542
6 changed files with 75 additions and 105 deletions
|
|
@ -616,7 +616,7 @@ module Assembler
|
||||||
|
|
||||||
def dec(op)
|
def dec(op)
|
||||||
if register?(op)
|
if register?(op)
|
||||||
# dec r16 / dec r32
|
# dec reg32
|
||||||
asm { emit_byte(0x48 + op.regnum) }
|
asm { emit_byte(0x48 + op.regnum) }
|
||||||
else
|
else
|
||||||
raise "unsupported DEC instruction, op=#{op.inspect}"
|
raise "unsupported DEC instruction, op=#{op.inspect}"
|
||||||
|
|
@ -655,6 +655,7 @@ module Assembler
|
||||||
raise "unsupported AND instruction: dest=#{dest.inspect}, src=#{src.inspect}"
|
raise "unsupported AND instruction: dest=#{dest.inspect}, src=#{src.inspect}"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
alias_method :and, :and_
|
||||||
|
|
||||||
|
|
||||||
def xor(dest, src)
|
def xor(dest, src)
|
||||||
|
|
@ -674,6 +675,7 @@ module Assembler
|
||||||
def not_(op)
|
def not_(op)
|
||||||
group3(op, 2, 'NOT')
|
group3(op, 2, 'NOT')
|
||||||
end
|
end
|
||||||
|
alias_method :not, :not_
|
||||||
|
|
||||||
|
|
||||||
def neg(op)
|
def neg(op)
|
||||||
|
|
@ -816,6 +818,7 @@ module Assembler
|
||||||
emit_byte(delta)
|
emit_byte(delta)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
alias_method :loop, :loop_
|
||||||
|
|
||||||
|
|
||||||
# Opcode group #3. 1-byte opcode, 1 operand (r/m8 or r/m32).
|
# Opcode group #3. 1-byte opcode, 1 operand (r/m8 or r/m32).
|
||||||
|
|
|
||||||
|
|
@ -304,10 +304,9 @@ if $0 == __FILE__
|
||||||
puts MachHeader::MemberSizes.inspect
|
puts MachHeader::MemberSizes.inspect
|
||||||
puts "# of MachHeader members: " + MachHeader.size.to_s + ", size in bytes: " + MachHeader.bytesize.to_s
|
puts "# of MachHeader members: " + MachHeader.size.to_s + ", size in bytes: " + MachHeader.bytesize.to_s
|
||||||
mh = MachHeader.new(0xfeedface, 7, 3, "foobar")
|
mh = MachHeader.new(0xfeedface, 7, 3, "foobar")
|
||||||
puts "magic(#{MachHeader.sizeof(:magic)}): " + mh[:magic].inspect
|
%w[magic, cputype, cpusubtype, segname].each do |field|
|
||||||
puts "cputype(#{MachHeader.sizeof(:cputype)}): " + mh[:cputype].inspect
|
puts "#{field}(#{MachHeader.sizeof(field.to_sym)}): " + mh[field.to_sym].inspect
|
||||||
puts "cpusubtype(#{MachHeader.sizeof(:cpusubtype)}): " + mh[:cpusubtype].inspect
|
end
|
||||||
puts "segname(#{MachHeader.sizeof(:segname)}): " + mh[:segname].inspect
|
|
||||||
puts mh.pack_pattern.inspect
|
puts mh.pack_pattern.inspect
|
||||||
binstr = mh.serialize
|
binstr = mh.serialize
|
||||||
puts "values: " + mh.values.inspect
|
puts "values: " + mh.values.inspect
|
||||||
|
|
@ -317,4 +316,4 @@ if $0 == __FILE__
|
||||||
puts "serialized: " + binstr.inspect
|
puts "serialized: " + binstr.inspect
|
||||||
puts "unserialized: " + newbinstr.inspect
|
puts "unserialized: " + newbinstr.inspect
|
||||||
puts "new == old ? " + (newbinstr == binstr).to_s
|
puts "new == old ? " + (newbinstr == binstr).to_s
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -131,56 +131,46 @@ module Assembler
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
# Basis for #data, #const, and #bss methods.
|
||||||
|
def segment_based_on_filetype(segname, options={})
|
||||||
|
unless @current_segment
|
||||||
|
permissions = VM_PROT_READ
|
||||||
|
permisions |= VM_PROT_WRITE if options.delete(:writable)
|
||||||
|
segment(segname_based_on_filetype(segname)) do |seg|
|
||||||
|
seg[:initprot] = seg[:maxprot] = permissions
|
||||||
|
end
|
||||||
|
end
|
||||||
|
yield if block_given?
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
# Define a standard data section under the current segment (if present).
|
# Define a standard data section under the current segment (if present).
|
||||||
# This behaves similarly to the text method.
|
# This behaves similarly to the text method.
|
||||||
#
|
#
|
||||||
def data(data, sectname='__data', segname='__DATA')
|
def data(data, sectname='__data', segname='__DATA')
|
||||||
unless @current_segment
|
segment_based_on_filetype(segname, :writable => true) do
|
||||||
segment(segname_based_on_filetype(segname)) do |seg|
|
section(sectname, segname, data)
|
||||||
seg[:maxprot] = VM_PROT_READ | VM_PROT_WRITE
|
|
||||||
seg[:initprot] = VM_PROT_READ | VM_PROT_WRITE
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
section(sectname, segname, data)
|
|
||||||
|
|
||||||
return self
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
# Define a standard const section under the current segment (if present).
|
# Define a standard const section under the current segment (if present).
|
||||||
# This behaves similarly to the data method.
|
# This behaves similarly to the data method.
|
||||||
#
|
#
|
||||||
def const(data, sectname='__const', segname='__DATA')
|
def const(data, sectname='__const', segname='__DATA')
|
||||||
unless @current_segment
|
segment_based_on_filetype(segname) do
|
||||||
segment(segname_based_on_filetype(segname)) do |seg|
|
section(sectname, segname, data)
|
||||||
seg[:maxprot] = VM_PROT_READ
|
|
||||||
seg[:initprot] = VM_PROT_READ
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
section(sectname, segname, data)
|
|
||||||
|
|
||||||
return self
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
# Define a standard BSS section under the current segment (if present).
|
# Define a standard BSS section under the current segment (if present).
|
||||||
# This behaves similarly to the data method but accepts a VM size instead
|
# This behaves similarly to the data method but accepts a VM size instead
|
||||||
# of a blob, and no data is written to file since this section is for
|
# of a blob, and no data is written to file since this section is for
|
||||||
# uninitialized data.
|
# uninitialized data.
|
||||||
#
|
#
|
||||||
def bss(vmsize, sectname='__bss', segname='__DATA')
|
def bss(vmsize, sectname='__bss', segname='__DATA')
|
||||||
unless @current_segment
|
segment_based_on_filetype(segname, :writable => true) do
|
||||||
segment(segname_based_on_filetype(segname)) do |seg|
|
section(sectname, segname, '', vmsize)
|
||||||
seg[:maxprot] = VM_PROT_READ | VM_PROT_WRITE
|
|
||||||
seg[:initprot] = VM_PROT_READ | VM_PROT_WRITE
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
section(sectname, segname, '', vmsize)
|
|
||||||
|
|
||||||
return self
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -18,37 +18,22 @@ module Assembler
|
||||||
return 0x2800
|
return 0x2800
|
||||||
end
|
end
|
||||||
|
|
||||||
def all_symbols
|
def make_symbols(vars, type, segnum)
|
||||||
symbols = []
|
|
||||||
|
|
||||||
# Functions (section #1, __text)
|
|
||||||
#
|
|
||||||
# All labels are exported. This should be changed and only functions exported!
|
|
||||||
# TODO fixme ...
|
|
||||||
#
|
|
||||||
# Note: Sorting a Ruby hash gives an alist, e.g. [[<key>, <value>], ...]
|
# Note: Sorting a Ruby hash gives an alist, e.g. [[<key>, <value>], ...]
|
||||||
# We can use map on it as if it were a hash so it works nicely.
|
# We can use map on it as if it were a hash so it works nicely.
|
||||||
#
|
vars.sort { |a,b| a[1] <=> b[1] }.
|
||||||
symbols +=
|
map do |name, addr|
|
||||||
@labels.sort { |a,b| a[1] <=> b[1] }.
|
MachOSym.new(name, type, segnum, 0, addr)
|
||||||
map do |name,addr|
|
end
|
||||||
MachOSym.new(name, N_SECT | N_EXT, 1, 0, addr)
|
end
|
||||||
end
|
|
||||||
|
def all_symbols
|
||||||
# Constants (section #2, __const)
|
# TODO FIXME:
|
||||||
symbols += @consts.sort { |a,b| a[1] <=> b[1] }.
|
# - the last var exported ends up after main somewhere... WTF?!
|
||||||
map do |name, addr|
|
# - All labels are exported. This should be changed and only functions exported!
|
||||||
MachOSym.new(name, N_SECT, 2, 0, addr)
|
symbols = make_symbols(@labels, N_SECT | N_EXT, 1) + # Functions (section #1, __text)
|
||||||
end
|
make_symbols(@consts, N_SECT, 2) + # Constants (section #2, __const)
|
||||||
|
make_symbols(@vars, N_SECT, 3) # Variables (section #3, __bss)
|
||||||
# Variables (section #3, __bss)
|
|
||||||
#
|
|
||||||
# TODO FIXME the last var exported ends up after main somewhere... WTF?!
|
|
||||||
symbols += @vars.sort { |a,b| a[1] <=> b[1] }.
|
|
||||||
map do |name, addr|
|
|
||||||
MachOSym.new(name, N_SECT, 3, 0, addr)
|
|
||||||
end
|
|
||||||
|
|
||||||
return symbols
|
return symbols
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
||||||
24
build.rb
24
build.rb
|
|
@ -49,16 +49,21 @@ rescue ParseError => e
|
||||||
exit(1)
|
exit(1)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def run_and_warn_on_failure(command, name)
|
||||||
|
output = `#{command}`
|
||||||
|
if $?.exitstatus != 0
|
||||||
|
puts
|
||||||
|
print output
|
||||||
|
name = command.split.first
|
||||||
|
raise "#{name} failed: #{$?.exitstatus}"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
# assemble using nasm, return resulting filename.
|
# assemble using nasm, return resulting filename.
|
||||||
def assemble(filename, binformat='elf')
|
def assemble(filename, binformat='elf')
|
||||||
f = base(filename)
|
f = base(filename)
|
||||||
outfile = "#{f}.o"
|
outfile = "#{f}.o"
|
||||||
output = `nasm -f #{binformat} -g -o #{outfile} #{filename} 2>&1`
|
run_and_warn_on_failure("nasm -f #{binformat} -g -o #{outfile} #{filename} 2>&1")
|
||||||
if $?.exitstatus != 0
|
|
||||||
puts
|
|
||||||
print output
|
|
||||||
raise "nasm failed: #{$?.exitstatus}"
|
|
||||||
end
|
|
||||||
return outfile
|
return outfile
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -71,12 +76,7 @@ def link(filename, platform='linux')
|
||||||
else
|
else
|
||||||
raise "unsupported platform: #{platform}"
|
raise "unsupported platform: #{platform}"
|
||||||
end
|
end
|
||||||
output = `#{cmd} #{args} -o #{f} #{filename} 2>&1`
|
run_and_warn_on_failure("#{cmd} #{args} -o #{f} #{filename} 2>&1")
|
||||||
if $?.exitstatus != 0
|
|
||||||
puts
|
|
||||||
print output
|
|
||||||
raise "ld failed: #{$?.exitstatus}"
|
|
||||||
end
|
|
||||||
`chmod u+x #{f}`
|
`chmod u+x #{f}`
|
||||||
return f
|
return f
|
||||||
end
|
end
|
||||||
|
|
|
||||||
51
compiler.rb
51
compiler.rb
|
|
@ -190,25 +190,23 @@ class Compiler
|
||||||
# bit expressions #
|
# bit expressions #
|
||||||
###################
|
###################
|
||||||
|
|
||||||
def bitor_expr
|
def bit_expr(op, token)
|
||||||
match('|')
|
match(token)
|
||||||
term
|
if block_given? yield else term end
|
||||||
asm.pop(EBX)
|
asm.pop(EBX)
|
||||||
asm.or_(EAX, EBX)
|
asm.send(op, EAX, EBX)
|
||||||
end
|
end
|
||||||
|
|
||||||
def bitand_expr
|
def bitor_expr
|
||||||
match('&')
|
bit_expr(:or, '|')
|
||||||
signed_factor
|
|
||||||
asm.pop(EBX)
|
|
||||||
asm.and_(EAX, EBX)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def xor_expr
|
def xor_expr
|
||||||
match('^')
|
bit_expr(:xor, '^')
|
||||||
term
|
end
|
||||||
asm.pop(EBX)
|
|
||||||
asm.xor(EAX, EBX)
|
def bitand_expr
|
||||||
|
bit_expr(:and, '&') { signed_factor }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -323,6 +321,9 @@ class Compiler
|
||||||
# true (-1) if the difference was below zero and false (0)
|
# true (-1) if the difference was below zero and false (0)
|
||||||
# otherwise (using JL, jump if less than).
|
# otherwise (using JL, jump if less than).
|
||||||
def cmp_relation(a, b, options={})
|
def cmp_relation(a, b, options={})
|
||||||
|
expression
|
||||||
|
asm.pop(EBX)
|
||||||
|
|
||||||
# Invert the sense of the test?
|
# Invert the sense of the test?
|
||||||
invert = options[:invert]
|
invert = options[:invert]
|
||||||
|
|
||||||
|
|
@ -347,8 +348,6 @@ class Compiler
|
||||||
#
|
#
|
||||||
# if a > b then b - a < 0
|
# if a > b then b - a < 0
|
||||||
def gt_relation
|
def gt_relation
|
||||||
expression
|
|
||||||
asm.pop(EBX)
|
|
||||||
cmp_relation(EAX, EBX) # b - a
|
cmp_relation(EAX, EBX) # b - a
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -357,8 +356,6 @@ class Compiler
|
||||||
#
|
#
|
||||||
# if a < b then a - b < 0
|
# if a < b then a - b < 0
|
||||||
def lt_relation
|
def lt_relation
|
||||||
expression
|
|
||||||
asm.pop(EBX)
|
|
||||||
cmp_relation(EBX, EAX) # a - b
|
cmp_relation(EBX, EAX) # a - b
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -367,8 +364,6 @@ class Compiler
|
||||||
#
|
#
|
||||||
# if a >= b then !(a < b)
|
# if a >= b then !(a < b)
|
||||||
def ge_relation
|
def ge_relation
|
||||||
expression
|
|
||||||
asm.pop(EBX)
|
|
||||||
# Compare them as in less than but invert the result.
|
# Compare them as in less than but invert the result.
|
||||||
cmp_relation(EBX, EAX, :invert => true)
|
cmp_relation(EBX, EAX, :invert => true)
|
||||||
end
|
end
|
||||||
|
|
@ -378,8 +373,6 @@ class Compiler
|
||||||
#
|
#
|
||||||
# if a <= b then !(a > b)
|
# if a <= b then !(a > b)
|
||||||
def le_relation
|
def le_relation
|
||||||
expression
|
|
||||||
asm.pop(EBX)
|
|
||||||
# Compare them as in greater than but invert the result.
|
# Compare them as in greater than but invert the result.
|
||||||
cmp_relation(EAX, EBX, :invert => true)
|
cmp_relation(EAX, EBX, :invert => true)
|
||||||
end
|
end
|
||||||
|
|
@ -474,20 +467,20 @@ class Compiler
|
||||||
asm.emit_label(end_label)
|
asm.emit_label(end_label)
|
||||||
end
|
end
|
||||||
|
|
||||||
def while_stmt
|
def condition_loop(name, jump_instruction)
|
||||||
simple_loop('while') do |end_label|
|
simple_loop(name) do |end_label|
|
||||||
condition
|
condition
|
||||||
skip_any_whitespace
|
skip_any_whitespace
|
||||||
asm.jz(end_label)
|
asm.send(jump_instruction, end_label)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def while_stmt
|
||||||
|
condition_loop('while', :jz) # done when == 0 (falsish)
|
||||||
|
end
|
||||||
|
|
||||||
def until_stmt
|
def until_stmt
|
||||||
simple_loop('until') do |end_label|
|
condition_loop('until', :jnz) # done when != 0 (truthy)
|
||||||
condition
|
|
||||||
skip_any_whitespace
|
|
||||||
asm.jnz(end_label)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def repeat_stmt
|
def repeat_stmt
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue