introduce constant class and add block to compile signature(wip, work in progress)
This commit is contained in:
parent
dd05b30230
commit
d7f31e7f39
@ -30,7 +30,15 @@ module Arm
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
def integer_less_or_equal left , right
|
||||
cmp(:left => left , :right => right )
|
||||
end
|
||||
|
||||
def integer_plus left , right
|
||||
add(:left => left , :right => right )
|
||||
end
|
||||
|
||||
def word_load value , reg
|
||||
raise "not a register :#{reg}:" unless reg.class == Symbol
|
||||
mov( :left => reg , :right => value )
|
||||
|
@ -39,11 +39,11 @@ module Arm
|
||||
|
||||
# Add a string to the string table. Strings are global and constant. So only one copy of each
|
||||
# string exists
|
||||
# Internally StringLiterals are created and stored and during assembly written after the blocks
|
||||
# Internally StringConstants are created and stored and during assembly written after the blocks
|
||||
def add_string str
|
||||
code = @string_table[str]
|
||||
return code if code
|
||||
data = Vm::StringLiteral.new(str)
|
||||
data = Vm::StringConstant.new(str)
|
||||
@string_table[str] = data
|
||||
end
|
||||
|
||||
|
@ -22,7 +22,7 @@ module Arm
|
||||
|
||||
#(stays in subclases, while build is overriden to provide different arguments)
|
||||
def do_build(arg)
|
||||
if arg.is_a?(Vm::StringLiteral)
|
||||
if arg.is_a?(Vm::StringConstant)
|
||||
# do pc relative addressing with the difference to the instuction
|
||||
# 8 is for the funny pipeline adjustment (ie oc pointing to fetch and not execute)
|
||||
arg = Arm::NumLiteral.new( arg.position - self.position - 8 )
|
||||
@ -31,7 +31,7 @@ module Arm
|
||||
if( arg.is_a? Fixnum ) #HACK to not have to change the code just now
|
||||
arg = Arm::NumLiteral.new( arg )
|
||||
end
|
||||
if( arg.is_a? Vm::Signed ) #HACK to not have to change the code just now
|
||||
if( arg.is_a? Vm::Integer ) #HACK to not have to change the code just now
|
||||
arg = Arm::NumLiteral.new( arg.value )
|
||||
end
|
||||
if (arg.is_a?(Arm::NumLiteral))
|
||||
|
@ -50,7 +50,7 @@ module Arm
|
||||
raise "reference offset too large/small (max 4095) #{arg} #{inspect}"
|
||||
end
|
||||
end
|
||||
elsif (arg.is_a?(Vm::StringLiteral)) #use pc relative
|
||||
elsif (arg.is_a?(Vm::StringConstant)) #use pc relative
|
||||
@rn = :pc
|
||||
@operand = arg.position - self.position - 8 #stringtable is after code
|
||||
@add_offset = 1
|
||||
|
@ -13,8 +13,8 @@ module Ast
|
||||
def to_s
|
||||
value.to_s
|
||||
end
|
||||
def compile context
|
||||
Vm::Signed.new value
|
||||
def compile context , into
|
||||
Vm::Integer.new value
|
||||
end
|
||||
def attributes
|
||||
[:value]
|
||||
@ -26,10 +26,10 @@ module Ast
|
||||
def initialize name
|
||||
@name = name
|
||||
end
|
||||
def compile context
|
||||
variable = Vm::Variable.new(@name)
|
||||
context.locals[@name] = variable
|
||||
variable
|
||||
# compiling a variable resolves it.
|
||||
# if it wasn't defined, nli is returned
|
||||
def compile context , into
|
||||
context.locals[name]
|
||||
end
|
||||
def inspect
|
||||
self.class.name + '.new("' + name + '")'
|
||||
@ -51,8 +51,8 @@ module Ast
|
||||
self.class.name + '.new("' + string + '")'
|
||||
end
|
||||
|
||||
def compile context
|
||||
value = Vm::StringLiteral.new(string)
|
||||
def compile context , into
|
||||
value = Vm::StringConstant.new(string)
|
||||
context.program.add_object value
|
||||
value
|
||||
end
|
||||
|
@ -12,7 +12,7 @@ module Ast
|
||||
def eval
|
||||
raise "abstract #{self}"
|
||||
end
|
||||
def compile context
|
||||
def compile context , into
|
||||
raise "abstract #{self}"
|
||||
end
|
||||
def attributes
|
||||
|
@ -16,27 +16,31 @@ module Ast
|
||||
def to_s
|
||||
"def #{name}( " + params.join(",") + ") \n" + block.join("\n") + "end\n"
|
||||
end
|
||||
def compile context
|
||||
raise self.to_s
|
||||
def compile context , into
|
||||
raise "function does not compile into anything #{self}" if into
|
||||
parent_locals = context.locals
|
||||
context.locals = {}
|
||||
args = []
|
||||
params.each do |param|
|
||||
args << param.compile(context) # making the argument a local
|
||||
params.each_with_index do |param , index|
|
||||
arg = param.name
|
||||
arg_value = Vm::Integer.new(index)
|
||||
context.locals[arg] = arg_value
|
||||
args << arg_value
|
||||
end
|
||||
# args = params.collect{|p| Vm::Value.type p.name }
|
||||
function = Vm::Function.new(name ,args )
|
||||
function = Vm::Function.new(name , args )
|
||||
context.program.add_function function
|
||||
into = function.entry
|
||||
block.each do |b|
|
||||
compiled = b.compile context
|
||||
compiled = b.compile(context , into)
|
||||
if compiled.is_a? Vm::Block
|
||||
into = compiled
|
||||
he.breaks.loose
|
||||
else
|
||||
function.body.add_code compiled
|
||||
end
|
||||
puts compiled.inspect
|
||||
end
|
||||
context.locals = parent_locals if parent_locals
|
||||
context.locals = parent_locals
|
||||
function
|
||||
end
|
||||
|
||||
|
@ -7,13 +7,14 @@ module Ast
|
||||
def initialize name, args
|
||||
@name , @args = name , args
|
||||
end
|
||||
def compile context
|
||||
fun = Vm::FunctionCall.new( name , args.collect{ |a| a.compile(context) } )
|
||||
fun.assign_function context
|
||||
fun.load_args
|
||||
fun.do_call
|
||||
def compile context , into
|
||||
params = args.collect{ |a| a.compile(context, into) }
|
||||
fun = Vm::FunctionCall.new( name , params )
|
||||
fun.load_args into
|
||||
fun.do_call into
|
||||
fun
|
||||
end
|
||||
|
||||
def inspect
|
||||
self.class.name + ".new(" + name.inspect + ", ["+
|
||||
args.collect{|m| m.inspect }.join( ",") +"] )"
|
||||
@ -41,35 +42,24 @@ module Ast
|
||||
def to_s
|
||||
"#{left} #{operator} #{right}"
|
||||
end
|
||||
def compile context
|
||||
parent_locals = context.locals
|
||||
context.locals = {}
|
||||
args = []
|
||||
|
||||
#assignemnt
|
||||
value = @assigned.compile(context)
|
||||
variable = Vm::Variable.new @assignee , :r0 , value
|
||||
context.locals[@assignee] = variable
|
||||
variable
|
||||
|
||||
|
||||
params.each do |param|
|
||||
args << param.compile(context) # making the argument a local
|
||||
def compile context , into
|
||||
r_val = right.compile(context , into)
|
||||
|
||||
if operator == "=" # assignemnt
|
||||
raise "Can only assign variables, not #{left}" unless left.is_a?(NameExpression)
|
||||
context.locals[left.name] = r_val
|
||||
return r_val
|
||||
end
|
||||
# args = params.collect{|p| Vm::Value.type p.name }
|
||||
function = Vm::Function.new(name ,args )
|
||||
context.program.add_function function
|
||||
block.each do |b|
|
||||
compiled = b.compile context
|
||||
if compiled.is_a? Vm::Block
|
||||
he.breaks.loose
|
||||
else
|
||||
function.body.add_code compiled
|
||||
end
|
||||
puts compiled.inspect
|
||||
l_val = left.compile(context , into)
|
||||
|
||||
case operator
|
||||
when ">"
|
||||
code = l_val.less_or_equal r_val
|
||||
when "+"
|
||||
code = l_val.plus r_val
|
||||
else
|
||||
raise "unimplemented operator #{operator} #{self}"
|
||||
end
|
||||
context.locals = parent_locals if parent_locals
|
||||
function
|
||||
end
|
||||
end
|
||||
end
|
@ -13,6 +13,14 @@ module Ast
|
||||
def attributes
|
||||
[:condition, :body]
|
||||
end
|
||||
def compile context , into
|
||||
cond_val = condition.compile(context , into)
|
||||
#set up branches for bodies
|
||||
body.each do |part|
|
||||
part.compile(context , into )
|
||||
end
|
||||
return cond_val
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
@ -8,7 +8,7 @@ module Parser
|
||||
rule(:bit_and) { str('&') >> space?}
|
||||
rule(:bit_or) { str('|') >> space?}
|
||||
rule(:greater_equal) { str('>=') >> space?}
|
||||
rule(:smaller_equal) { str('<=') >> space?}
|
||||
rule(:less_or_equal) { str('<=') >> space?}
|
||||
rule(:larger) { str('>') >> space?}
|
||||
rule(:smaller) { str('<') >> space?}
|
||||
rule(:identity) { str('===') >> space?}
|
||||
@ -31,7 +31,7 @@ module Parser
|
||||
[bit_and, 90, :left],
|
||||
[bit_or, 90, :right],
|
||||
[greater_equal, 80, :left],
|
||||
[smaller_equal, 80, :left],
|
||||
[less_or_equal, 80, :left],
|
||||
[larger, 80, :left],
|
||||
[smaller, 80, :left],
|
||||
[identity, 70, :right],
|
||||
|
@ -22,7 +22,7 @@ require 'parslet/pattern'
|
||||
#
|
||||
# class Example < Parslet::Transform
|
||||
# rule(:string => simple(:x)) { # (1)
|
||||
# StringLiteral.new(x)
|
||||
# StringConstant.new(x)
|
||||
# }
|
||||
# end
|
||||
#
|
||||
|
51
lib/vm/constants.rb
Normal file
51
lib/vm/constants.rb
Normal file
@ -0,0 +1,51 @@
|
||||
module Vm
|
||||
|
||||
# constants are the stuff that you embedd in the program as numbers or strings.
|
||||
# Another way to think about them is as Operands, they have no seperate "identity"
|
||||
# and usually end up embedded in the instructions. ie your basic foo + 4 will encode
|
||||
# the 4 in the instruction opcode. The 4 is not accessible anywhere else.
|
||||
# When it should be usable in other forms, the constant must become a Value first
|
||||
class Constant < Value
|
||||
|
||||
end
|
||||
|
||||
|
||||
class IntegerConstant < Constant
|
||||
def init int
|
||||
@integer = int
|
||||
end
|
||||
attr_reader :integer
|
||||
end
|
||||
|
||||
# The name really says it all.
|
||||
# The only interesting thing is storage.
|
||||
# Currently string are stored "inline" , ie in the code segment.
|
||||
# Mainly because that works an i aint no elf expert.
|
||||
|
||||
class StringConstant < Constant
|
||||
attr_reader :string
|
||||
# currently aligned to 4 (ie padded with 0) and off course 0 at the end
|
||||
def initialize str
|
||||
length = str.length
|
||||
# rounding up to the next 4 (always adding one for zero pad)
|
||||
pad = ((length / 4 ) + 1 ) * 4 - length
|
||||
raise "#{pad} #{self}" unless pad >= 1
|
||||
@string = str + "\x00" * pad
|
||||
end
|
||||
|
||||
def load reg_num
|
||||
Machine.instance.string_load self , reg_num
|
||||
end
|
||||
|
||||
# the strings length plus padding
|
||||
def length
|
||||
string.length
|
||||
end
|
||||
|
||||
# just writing the string
|
||||
def assemble(io)
|
||||
io << string
|
||||
end
|
||||
end
|
||||
|
||||
end
|
@ -2,31 +2,23 @@ module Vm
|
||||
|
||||
# name and args , return
|
||||
|
||||
class FunctionCall < Block
|
||||
class FunctionCall < Value
|
||||
|
||||
def initialize(name , args)
|
||||
super(name)
|
||||
@name = name
|
||||
@args = args
|
||||
@function = nil
|
||||
end
|
||||
attr_reader :function , :args
|
||||
attr_reader :function , :args , :name
|
||||
|
||||
def assign_function context
|
||||
@function = context.program.get_function @name
|
||||
if @function
|
||||
raise "error #{self} , #{@function.args.length} != #{args.length}" if @function.arity != args.length
|
||||
else
|
||||
@function = context.program.get_or_create_function @name
|
||||
end
|
||||
end
|
||||
def load_args
|
||||
def load_args into
|
||||
args.each_with_index do |arg , index|
|
||||
add_code arg.load("r#{index}".to_sym)
|
||||
into.add_code arg.load("r#{index}".to_sym)
|
||||
end
|
||||
end
|
||||
|
||||
def do_call
|
||||
add_code Machine.instance.function_call self
|
||||
def do_call into
|
||||
into.add_code Machine.instance.function_call self
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -14,7 +14,7 @@ module Vm
|
||||
# A Machines main responsibility in the framework is to instantiate Instruction
|
||||
|
||||
# Value functions are mapped to machines by concatenating the values class name + the methd name
|
||||
# Example: SignedValue.plus( value ) -> Machine.signed_plus (value )
|
||||
# Example: IntegerValue.plus( value ) -> Machine.signed_plus (value )
|
||||
|
||||
# Also, shortcuts are created to easily instantiate Instruction objects. The "standard" set of instructions
|
||||
# (arm-influenced) provides for normal operations on a register machine,
|
||||
|
@ -21,27 +21,23 @@ module Vm
|
||||
# just a base class for data. not sure how this will be usefull (may just have read too much llvm)
|
||||
class Value < Code
|
||||
|
||||
def initialize value
|
||||
@value = value
|
||||
end
|
||||
attr_reader :value
|
||||
|
||||
#naming convention to infer types in kernel functions. Kernel types are basic types, ie see below
|
||||
#
|
||||
def self.type name
|
||||
parts = name.split("_")
|
||||
t = "Basic"
|
||||
if parts[1]
|
||||
t = parts[1]
|
||||
end
|
||||
t
|
||||
|
||||
def type
|
||||
self.class
|
||||
end
|
||||
end
|
||||
|
||||
# This is what it is when we don't know what it is.
|
||||
# Must be promoted to A Word-Value to to anything
|
||||
# remembering that our oo machine is typed, no overloading or stuff
|
||||
class Word < Value
|
||||
def load reg
|
||||
Machine.instance.word_load self , reg
|
||||
|
||||
attr_accessor :register
|
||||
|
||||
def initialize reg
|
||||
register = reg
|
||||
end
|
||||
|
||||
def length
|
||||
4
|
||||
end
|
||||
@ -54,59 +50,15 @@ module Vm
|
||||
end
|
||||
end
|
||||
|
||||
class Signed < Word
|
||||
def plus signed
|
||||
Machine.instance.signed_plus self , signed
|
||||
end
|
||||
end
|
||||
class Integer < Word
|
||||
|
||||
class Variable < Value
|
||||
attr_reader :name , :register
|
||||
def initialize name , register = nil , val = nil
|
||||
super(val)
|
||||
@register = register
|
||||
@name = name
|
||||
end
|
||||
def length
|
||||
@value.length
|
||||
end
|
||||
def assemble io
|
||||
@value.load @register
|
||||
end
|
||||
end
|
||||
|
||||
# The name really says it all.
|
||||
# The only interesting thing is storage.
|
||||
# Currently string are stored "inline" , ie in the code segment.
|
||||
# Mainly because that works an i aint no elf expert.
|
||||
|
||||
class StringLiteral < Value
|
||||
|
||||
# currently aligned to 4 (ie padded with 0) and off course 0 at the end
|
||||
def initialize(str)
|
||||
super(str)
|
||||
length = str.length
|
||||
# rounding up to the next 4 (always adding one for zero pad)
|
||||
pad = ((length / 4 ) + 1 ) * 4 - length
|
||||
raise "#{pad} #{self}" unless pad >= 1
|
||||
@value = str + "\x00" * pad
|
||||
end
|
||||
def string
|
||||
@value
|
||||
def less_or_equal right
|
||||
Machine.instance.integer_less_or_equal self , right
|
||||
end
|
||||
|
||||
def load reg_num
|
||||
Machine.instance.string_load self , reg_num
|
||||
end
|
||||
|
||||
# the strings length plus padding
|
||||
def length
|
||||
string.length
|
||||
end
|
||||
|
||||
# just writing the string
|
||||
def assemble(io)
|
||||
io << string
|
||||
def plus right
|
||||
Machine.instance.integer_plus self , right
|
||||
end
|
||||
end
|
||||
end
|
||||
require_relative "constants"
|
Loading…
Reference in New Issue
Block a user