--- /dev/null
+#!/bin/env ruby
+
+require "tempfile"
+
+def emit(text)
+ $asm_out.write "\t#{text}\n"
+end
+
+
+module Targets
+ module X86_64
+ class << self
+ def int(value)
+ # TODO: optimize this based on size of operand
+ emit "mov $#{value}, %rax"
+ emit "pushq %rax"
+ end
+
+ #############
+ # ARITHMETIC
+ #############
+ # negi
+ def negi
+ emit "negq (%rsp)"
+ end
+
+ def addi
+ emit "popq %rax"
+ emit "addq %rax, (%rsp)"
+ end
+
+ def subi
+ emit "popq %rax"
+ emit "subq %rax, (%rsp)"
+ end
+
+ def muli
+ emit "popq %rax"
+ emit "popq %rbx"
+ emit "imull %rbx, %rax"
+ emit "pushq %rax"
+ end
+
+ def divi
+ emit "popq %rax"
+ emit "popq %rbx"
+ emit "idivl %rbx, %rax"
+ emit "pushq %rax"
+ end
+
+ def modi
+ emit "popq %rax"
+ emit "popq %rbx"
+ emit "idivl %rbx, %rax"
+ emit "pushq %rdx"
+ end
+
+ def inci
+ emit "incq (%rsp)"
+ end
+
+ def deci
+ emit "decq (%rsp)"
+ end
+
+ # negf
+ # addf
+ # subf
+ # divf
+ # mulf
+ # modf !LIBRARY!
+ # incf
+ # decf
+
+ #############
+ # RELATIONAL
+ #############
+ # eqi
+ def eqi
+ emit "popq %rax"
+ emit "popq %rbx"
+ emit "cmpq %rbx, %rax"
+ emit "sete %al"
+ emit "movzbq %al, %rax"
+ emit "pushq %rax"
+ end
+
+ # nei
+ def nei
+ emit "popq %rax"
+ emit "popq %rbx"
+ emit "cmpq %rbx, %rax"
+ emit "setne %al"
+ emit "movzbq %al, %rax"
+ emit "pushq %rax"
+ end
+
+ # lti
+ def lti
+ emit "popq %rax"
+ emit "popq %rbx"
+ emit "cmpq %rbx, %rax"
+ emit "setl %al"
+ emit "movzbq %al, %rax"
+ emit "pushq %rax"
+ end
+
+ # gti
+ def gti
+ emit "popq %rax"
+ emit "popq %rbx"
+ emit "cmpq %rbx, %rax"
+ emit "setg %al"
+ emit "movzbq %al, %rax"
+ emit "pushq %rax"
+ end
+
+ # ltei
+ def ltei
+ emit "popq %rax"
+ emit "popq %rbx"
+ emit "cmpq %rbx, %rax"
+ emit "setle %al"
+ emit "movzbq %al, %rax"
+ emit "pushq %rax"
+ end
+
+ # gtei
+ def gtei
+ emit "popq %rax"
+ emit "popq %rbx"
+ emit "cmpq %rbx, %rax"
+ emit "setge %al"
+ emit "movzbq %al, %rax"
+ emit "pushq %rax"
+ end
+
+ # eqf
+ # nef
+ # ltf
+ # gtf
+ # ltef
+ # gtef
+
+ ##########
+ # LOGICAL
+ ##########
+ def andi
+ emit "popq %rax"
+ emit "andq %rax, (%rsp)"
+ end
+
+ def ori
+ emit "popq %rax"
+ emit "orq %rax, (%rsp)"
+ end
+
+ def noti
+ emit "notq (%rsp)"
+ end
+
+ ##########
+ # BITWISE
+ ##########
+ # bit_and
+ def bit_and
+ emit "popq %rax"
+ emit "andq %rax, (%rsp)"
+ end
+
+ # bit_or
+ def bit_or
+ emit "popq %rax"
+ emit "orq %rax, (%rsp)"
+ end
+
+ # bit_xor
+ def bit_xor
+ emit "popq %rax"
+ emit "orq %rax, (%rsp)"
+ end
+
+ # bit_not
+ def bit_not
+ emit "notq (%rsp)"
+ end
+
+ # bit_asl
+ def bit_asl
+ emit "popq %rax"
+ emit "popq %rbx"
+ emit "salq %bl, %rax"
+ emit "popq %rax"
+ end
+
+ # bit_asr
+ def bit_asl
+ emit "popq %rax"
+ emit "popq %rbx"
+ emit "sharq %bl, %rax"
+ emit "popq %rax"
+ end
+
+ # bit_lsr
+ def bit_
+ emit "popq %rax"
+ emit "popq %rbx"
+ emit "shrq %bl, %rax"
+ emit "popq %rax"
+ end
+
+ ############
+ # FUNCTIONS
+ ############
+ # call NA
+ def call
+ emit "call #{name}"
+ end
+
+ # call_and_ret
+ def call_and_ret
+ emit "call #{name}"
+ emit "pushq %rax"
+ end
+
+# def ret
+# end
+#
+# def ret_with_val
+# end
+
+ def syscall num_args
+ emit "call syscall#{num_args}"
+ end
+
+ #########
+ # MEMORY
+ #########
+ # get_global int
+ # set_global int
+ # get_local int
+ # set_local int
+ end
+ end
+end
+
+class Variable
+ def initialize(name, &block)
+ $asm_out.write ".data\n"
+ $asm_out.write "#{name}:\n"
+ instance_eval(&block)
+ $asm_out.write "\n"
+ end
+
+ def int(value)
+ emit ".long #{value.to_i}"
+ end
+
+ def float(value)
+ emit ".long #{value.to_i}"
+ emit ".long #{value.to_i}"
+ end
+
+ def bool(value)
+ emit ".byte #{value ? 1 : 0}"
+ end
+
+ def byte(value)
+ emit ".byte 0x#{"%02x" % value.to_i}"
+ end
+
+ private
+
+ def emit(text)
+ $asm_out.write "\t#{text}\n"
+ end
+
+end
+
+class Function
+ def initialize(name, args=[], returns = nil, &block)
+ $asm_out.write ".text\n"
+ $asm_out.write "#{name}:\n"
+ emit "pushq %rbp"
+ emit "movq %rsp, %rbp"
+# emit ";-------------------"
+ instance_eval(&block)
+# emit ";-------------------"
+ emit "popq %rax" if returns
+ emit "popq %rbp"
+ emit "ret"
+ $asm_out.write "\n"
+ end
+
+ def method_missing(m, *args, &block)
+ $target::send(m, *args, &block)
+ end
+
+ ##
+ # Function Scaffolding: Locals and Returns
+ ##
+
+ def locals(count)
+ $asm_out.write "subq $#{count * 8}, %rsp\n"
+ end
+
+
+# ##
+# # Literal Value Loading
+# ##
+#
+# def int(value)
+# puts "\tmovq\t$#{value}, %rax"
+# puts "\tpushq\t%rax"
+# end
+#
+# def float(value)
+## puts "\tmovq\t$#{value}, %rax"
+## puts "\tpushq\t%rax"
+# end
+#
+# def bool(value)
+# puts "\tmovq\t$#{value}, %rax"
+# puts "\tpushq\t%rax"
+# end
+#
+# def byte(value)
+# puts "\tmovq\t$#{value}, %rax"
+# puts "\tpushq\t%rax"
+# end
+
+
+# ##
+# # Local/Global Variable Access
+# ##
+#
+# def local_get(idx)
+# raise "unimplemented"
+# end
+#
+# def local_set(idx)
+# raise "unimplemented"
+# end
+#
+# def global_get(idx)
+# raise "unimplemented"
+# end
+#
+# def global_set(idx)
+# raise "unimplemented"
+# end
+#
+# def ret()
+# puts "\tret"
+# end
+#
+# def ret_val()
+# puts "\tret"
+# end
+
+
+ def var(name, &block)
+ raise "variable declarations not allowed inside function block"
+ end
+
+ def func(name, args=[], &block)
+ raise "nested functions are disallowed"
+ end
+
+ def target(name)
+ raise "target output can only be specified at the top level"
+ end
+end
+
+#def label(name, &block)
+# puts "name:"
+# block.call()
+#end
+
+def prog_start func
+ $asm_out.write ".text\n"
+ $asm_out.write ".global _start\n"
+ $asm_out.write "_start:\n"
+ emit "movl (%rsp), %edi\n"
+ emit "lea 8(%rsp), %rsi\n"
+ emit "call #{func || main}\n"
+ emit "movl %eax, %edi\n"
+ emit "movl $60, %eax\n"
+ emit "syscall\n"
+ $asm_out.write ""
+end
+
+def var(name, &block)
+ Variable.new(name, &block)
+end
+
+def func(name, args=[], returns = nil, &block)
+ Function.new(name, args, returns, &block)
+end
+
+def target(name)
+ $target = Targets.const_get(name.to_s)
+end
+
+# Process all the files
+$target = Targets::X86_64
+$out_name = ARGV[0]
+$asm_out = Tempfile.new("aas")
+ARGV[1..-1].each do |f|
+ puts "loading #{f}"
+ load f
+end
+$asm_out.close
+#puts File.read($asm_out.path)
+system "as -o #{$out_name} #{$asm_out.path}"