]> git.mdlowis.com Git - proto/aas.git/commitdiff
initial commit. Able to generate assembly and a functioning executable
authorMike Lowis <mike.lowis@gentex.com>
Mon, 30 Oct 2023 17:07:25 +0000 (13:07 -0400)
committerMike Lowis <mike.lowis@gentex.com>
Mon, 30 Oct 2023 17:07:25 +0000 (13:07 -0400)
.gitignore [new file with mode: 0644]
aas.rb [new file with mode: 0755]
example.s [new file with mode: 0644]

diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..d7756c2
--- /dev/null
@@ -0,0 +1,2 @@
+a.out
+*.o
diff --git a/aas.rb b/aas.rb
new file mode 100755 (executable)
index 0000000..9ab41c2
--- /dev/null
+++ b/aas.rb
@@ -0,0 +1,415 @@
+#!/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}"
diff --git a/example.s b/example.s
new file mode 100644 (file)
index 0000000..0b22220
--- /dev/null
+++ b/example.s
@@ -0,0 +1,15 @@
+prog_start :bar
+
+var :foo do
+  int 42
+  float 42.0
+  bool false
+  byte 0x42
+end
+
+func :bar, [], :int do
+#  locals 2
+  int 4
+  int 2
+  addi
+end
\ No newline at end of file