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