summaryrefslogtreecommitdiff
path: root/tnslc
diff options
context:
space:
mode:
Diffstat (limited to 'tnslc')
-rw-r--r--tnslc/compile/function.tnsl391
-rw-r--r--tnslc/compile/module.tnsl6
-rw-r--r--tnslc/compile/scope.tnsl104
-rw-r--r--tnslc/compile/var.tnsl3
4 files changed, 391 insertions, 113 deletions
diff --git a/tnslc/compile/function.tnsl b/tnslc/compile/function.tnsl
index f945479..6f6388e 100644
--- a/tnslc/compile/function.tnsl
+++ b/tnslc/compile/function.tnsl
@@ -6,7 +6,8 @@ struct Function {
outputs,
~parse.Node _up,
int call_padding,
- bool m
+ bool m,
+ ~Module mod
}
/; method Function
@@ -187,6 +188,15 @@ struct Function {
;/
;/
+
+ /; _call_label [~uint8]
+ Scope tmp
+ tmp.init(self.mod, NULL, self.name)
+ ~uint8 out = tmp.base_label()
+ tmp.end()
+ return out
+ ;/
+
/; _build_func(~Module parent, ~CompBuf cb) [Scope]
Scope out
out.init(parent, cb, self.name)
@@ -478,9 +488,172 @@ struct Function {
;/
;/
- /; _compile_call(~Scope s, ~parse.Node params, ~Function f, ~Var self, bool mth) [Var]
- Var out
- return out
+ /; _compile_call(~Scope s, ~parse.Node params, ~Function f, ~Var _self, bool mth) [Var]
+ # Generate result tmp if required
+ Var result
+ ~Var out
+ /; if (f`.outputs.count > 0)
+ out = f`.outputs.get(0)
+ result = s`.mk_tmp(out)
+ ;; else
+ ~Struct t = self._find_literal_type(s, "void\0")
+ result._init(t)
+ ;/
+
+ # Save caller saved tmp variables
+ Var handle = s`.save_caller_tmp()
+
+ # Check that parameter count matches
+ int param_count = params`.sub.count
+ /; if (mth == true)
+ param_count++
+ ;/
+
+ /; if (param_count !== f`.inputs.count)
+ ~uint8 blab = s`.base_label()
+ _printf("ERROR: Failed to call function \"\0")
+ _printf(f`.name)
+ _printf("\" from scope \"\0")
+ _printf(blab)
+ _printf("\"\n\0")
+ _print_num(" Number of arguments (%d) did not match number of provided parameters \0", f`.inputs.count)
+ _print_num("(%d)\n\0", param_count)
+ _delete(blab)
+ result.loc = 0
+ return result
+ ;/
+
+ # Then generate a vector to store all the tmp variables which will store the
+ # params as intermediaries
+ utils.Vector tmps
+ tmps.init(len result)
+ tmps._grow(param_count)
+
+ # Create all stack based tmps
+ ~Var inp
+ Var last_stack
+ last_stack.loc = 0
+ /; loop (int i = 1; i !> f`.inputs.count) [i++]
+ int pidx = f`.inputs.count - i
+ inp = f`.inputs.get(pidx)
+ /; if (inp`.loc < 0)
+ # Make tmp on stack and compute
+ Var to_set = s`.mk_tmp_stack(inp)
+
+ /; if (to_set.is_ref() == true)
+ # Correct for ref
+ int32 ptrc = 0
+ ptrc = ptrc - 1
+ to_set.ptr_pop()
+ to_set.ptr_push(ptrc)
+ ;/
+
+ ~Var tmp = tmps.get(pidx)
+ tmp` = to_set
+ last_stack = to_set
+ ;/
+ ;/
+
+ # Create all register based tmps
+ Var last_reg
+ last_reg.loc = 0
+ /; loop (int i = 0; i < f`.inputs.count) [i++]
+ inp = f`.inputs.get(i)
+ /; if (inp`.loc > 0)
+ # Make tmp on stack and compute
+ Var to_set = s`.mk_tmp_stack(inp)
+
+ /; if (to_set.is_ref() == true)
+ # Correct for ref
+ int32 ptrc = 0
+ ptrc = ptrc - 1
+ to_set.ptr_pop()
+ to_set.ptr_push(ptrc)
+ ;/
+
+ ~Var tmp = tmps.get(i)
+ tmp` = to_set
+ last_reg = to_set
+ ;/
+ ;/
+
+ # Set 'self' if required
+ int use_self = 0
+ /; if (mth == true)
+ inp = tmps.get(0)
+ inp`.set(s`.cb, _self)
+ use_self++
+ ;/
+
+ # compile all parameters and put them into tmp vars
+ ~parse.Node pnode
+ /; loop (int i = use_self; i < f`.inputs.count) [i++]
+ pnode = params`.sub.get(i)
+ inp = tmps.get(i)
+
+ Var param = self._compile_value(s, pnode)
+ inp`.set(s`.cb, ~param)
+ /; if (s`.is_tmp(~param))
+ s`.free_to(~param, true)
+ ;/
+ param.end()
+ ;/
+
+ # Move all register parameters into registers and free the stack space
+ ~Var ptmp
+ /; loop (int i = 0; i < f`.inputs.count) [i++]
+ inp = f`.inputs.get(i)
+ /; if (inp`.loc > 0)
+ ptmp = tmps.get(i)
+ inp`.set(s`.cb, ptmp)
+ ;/
+ ;/
+ s`.free_after(~last_stack, true)
+
+ # Pad out the stack for return if required
+ ~CompBuf buf = s`.cb
+ /; if (f`.call_padding > 0)
+ ~uint8 pad_num = utils.int_to_str(f`.call_padding)
+ buf`.add_c(" sub rsp, \0")
+ buf`.add_c(pad_num)
+ buf`.add_c("\n\0")
+ _delete(pad_num)
+ ;/
+
+ # Do call
+ ~uint8 call = f`._call_label()
+ buf`.add_c(" call \0")
+ buf`.add_c(call)
+ buf`.add_c("\n\0")
+ _delete(call)
+
+ # Generate result variable and move into the result if required
+ /; if (f`.outputs.count > 0)
+ Var out_pos = out`.copy()
+ out_pos.loc = last_stack.loc
+ out_pos.offset = last_stack.offset
+ /; if (f`.call_padding > 0)
+ int offset = out_pos.offset
+ offset = offset - f`.call_padding
+ out_pos.offset = offset
+ ;/
+ result.set(s`.cb, ~out_pos)
+ out_pos.end()
+ ;/
+
+ # Free all in tmp vector
+ /; loop (int i = 0; i < tmps.count) [i++]
+ inp = tmps.get(i)
+ inp`.end()
+ ;/
+ tmps.end()
+
+ # Restore tmps in regs
+ s`.restore_caller_tmp(~handle)
+ handle.end()
+
+ s`.free_after(~result, true)
+ return result
;/
# Chain compilation functions get pretty long. Read at your own risk
@@ -665,14 +838,7 @@ struct Function {
# Function: the very long one.
/; _compile_chain_r (~Scope s, ~parse.Node n, ~utils.Vector v) [Var]
~parse.Node lhn = n`.sub.get(0)
- Var working
- working.loc = 0
-
- /; if (utils.strcmp(lhn`.data, ".\0") == true)
- working = self._compile_chain_r(s, lhn, v)
- ;; else
- working = self._compile_chain_r_base(s, lhn, v)
- ;/
+ Var working = self._compile_chain_r_base(s, lhn, v)
/; if (v`.count == 0)
/; if (working.loc == 0)
@@ -681,51 +847,79 @@ struct Function {
;/
;/
+ # The way in which chains are parsed puts all dots in the second sub-node
+
# Several points here: if have not found var or func yet need to try
# if we can't and there is a post-op, then we need to stop.
+ bool run = true
+ ~parse.Node rhn
+ /; loop (run == true)
+ rhn = n`.sub.get(1)
- ~parse.Node rhn = n`.sub.get(1)
- # Sanity
- /; if (rhn`._type !== parse.NTYPE_ID)
- _printf("TODO: tnslc does not currently support dot-chains with literals or non-identifiers in the middle\n\0")
- v`.end()
- v`.count = 0
- working.loc = 0
- return working
- ;/
-
- /; if (v`.count !== 0)
- # If we haven't yet found the var add to the vec and search the module
- ~uint8 dat = rhn`.data
- v`.push(~dat)
-
- ~Module mod = s`.mod
- ~Var find = mod`.find(SEARCH_VAR, v)
+ /; if (utils.strcmp(rhn`.data, ".\0") == true)
+ n = rhn
+ rhn = n`.sub.get(0)
+ ;; else
+ run = false
+ ;/
- /; if (find !== NULL)
- working = find`.as_global()
+ # Sanity
+ /; if (rhn`._type !== parse.NTYPE_ID)
+ _printf("TODO: tnslc does not currently support dot-chains with literals or non-identifiers in the middle\n\0")
v`.end()
v`.count = 0
+ working.loc = 0
+ return working
;/
- # Then check for post-op.
- /; if (rhn`.sub.count > 0)
- ~parse.Node post_op = rhn`.sub.get(0)
- /; if (utils.strcmp(post_op`.data, "(\0") == true)
- # Try a call
- /; if (find !== NULL)
- _printf("TODO: TNSL doesn't currently have good support for function calling by value\n\0")
- return working
- ;/
+ /; if (v`.count !== 0)
+ # If we haven't yet found the var add to the vec and search the module
+ ~uint8 dat = rhn`.data
+ v`.push(~dat)
- # Try to find function. Does not matter if we are a module since this is multi-part search
- ~Module mod = s`.mod
+ ~Module mod = s`.mod
+ ~Var find = mod`.find(SEARCH_VAR, v)
+
+ /; if (find !== NULL)
+ working = find`.as_global()
+ v`.end()
+ v`.count = 0
+ ;/
+
+ # Then check for post-op.
+ /; if (rhn`.sub.count > 0)
+ ~parse.Node post_op = rhn`.sub.get(0)
+ /; if (utils.strcmp(post_op`.data, "(\0") == true)
+ # Try a call
+ /; if (find !== NULL)
+ _printf("TODO: TNSL doesn't currently have good support for function calling by value\n\0")
+ return working
+ ;/
- # Already tried to find in module so can just use v for search.
- ~Function to_call = mod`.find(SEARCH_FUNC, v)
+ # Try to find function. Does not matter if we are a module since this is multi-part search
+ ~Module mod = s`.mod
- /; if (to_call == NULL)
- _printf("ERROR: Unable to find function or variable with name \"\0")
+ # Already tried to find in module so can just use v for search.
+ ~Function to_call = mod`.find(SEARCH_FUNC, v)
+
+ /; if (to_call == NULL)
+ _printf("ERROR: Unable to find function or variable with name \"\0")
+ _printf(rhn`.data)
+ _printf("\" in scope \"\0")
+ ~uint8 blab = s`.base_label()
+ _printf(blab)
+ _printf("\"\n\0")
+ _delete(blab)
+ v`.end()
+ v`.count = 0
+ return working
+ ;/
+
+ # Do call
+ working = self._compile_call(s, post_op, to_call, NULL, false)
+ ;; else if (working.loc == 0)
+ # Didn't find a variable but there was a post op
+ _printf("ERROR: Failed to find variable (dot chain ends in \"\0")
_printf(rhn`.data)
_printf("\" in scope \"\0")
~uint8 blab = s`.base_label()
@@ -735,80 +929,67 @@ struct Function {
v`.end()
v`.count = 0
return working
+ ;; else
+ # Do the post op on the found variable
+ self._compile_chain_r_post(s, post_op, ~working)
;/
+ ;/
+ ;; else
+ # We already have a var, not doing anything with the vector any more
- # Do call
- working = self._compile_call(s, post_op, to_call, NULL, false)
- ;; else if (working.loc == 0)
- # Didn't find a variable but there was a post op
- _printf("ERROR: Failed to find variable (dot chain ends in \"\0")
- _printf(rhn`.data)
- _printf("\" in scope \"\0")
- ~uint8 blab = s`.base_label()
- _printf(blab)
- _printf("\"\n\0")
- _delete(blab)
- v`.end()
- v`.count = 0
- return working
- ;; else
- # Do the post op on the found variable
- self._compile_chain_r_post(s, post_op, ~working)
+ # Check method call
+ int post_idx = 0
+ /; if (rhn`.sub.count > 0)
+ ~parse.Node post = rhn`.sub.get(0)
+ /; if (utils.strcmp(post`.data, "(\0") == true)
+ # Try method
+ post_idx++
+ ~Function to_call = working.find_method(rhn`.data)
+
+ /; if (to_call == NULL)
+ working.end()
+ working.loc = 0
+ return working
+ ;/
+
+ # Create space for the variable in a tmp
+ Var result = self._compile_call(s, post, to_call, ~working, true)
+ working.end()
+ working = result
+ ;/
;/
- ;/
- ;; else
- # We already have a var, not doing anything with the vector any more
- # Check method call
- int post_idx = 0
- /; if (rhn`.sub.count > 0)
- ~parse.Node post = rhn`.sub.get(0)
- /; if (utils.strcmp(post`.data, "(\0") == true)
- # Try method
- post_idx++
- ~Function to_call = working.find_method(rhn`.data)
+ /; if (post_idx == 0)
+ # Normal member
+ Var mbr = working.member(s`.cb, rhn`.data)
- /; if (to_call == NULL)
+ /; if (mbr.loc == 0)
+ # If the member didn't exist we end here
+ # The member function already prints some info
working.end()
working.loc = 0
return working
;/
+ _printf("Member:\n\0")
+ mbr._print(0)
- # Create space for the variable in a tmp
- Var result = self._compile_call(s, post, to_call, ~working, true)
working.end()
- working = result
- ;/
- ;/
-
- /; if (post_idx == 0)
- # Normal member
- Var mbr = working.member(s`.cb, rhn`.data)
-
- /; if (mbr.loc == 0)
- # If the member didn't exist we end here
- # The member function already prints some info
- working.end()
- working.loc = 0
- return working
- ;/
-
- working.end()
- working = mbr
+ working = mbr
- /; if (rhn`.sub.count > 0)
- # Do first post-op after the member
- ~parse.Node post = rhn`.sub.get(0)
- self._compile_chain_r_post(s, post, ~working)
+ /; if (rhn`.sub.count > 0)
+ # Do first post-op after the member
+ ~parse.Node post = rhn`.sub.get(0)
+ self._compile_chain_r_post(s, post, ~working)
+ ;/
;/
;/
- ;/
- # Loop over rest of post ops
- ~parse.Node post
- /; loop (int i = 1; i < rhn`.sub.count) [i++]
- post = rhn`.sub.get(i)
- self._compile_chain_r_post(s, post, ~working)
+ # Loop over rest of post ops
+ ~parse.Node post
+ /; loop (int i = 1; i < rhn`.sub.count) [i++]
+ post = rhn`.sub.get(i)
+ self._compile_chain_r_post(s, post, ~working)
+ ;/
;/
return working
diff --git a/tnslc/compile/module.tnsl b/tnslc/compile/module.tnsl
index d3deb2f..9de8041 100644
--- a/tnslc/compile/module.tnsl
+++ b/tnslc/compile/module.tnsl
@@ -73,6 +73,12 @@ struct Module {
var = self.vars.get(i)
var`.parent = ~self
;/
+
+ ~Function func
+ /; loop (int i = 0; i < self.funcs.count) [i++]
+ func = self.funcs.get(i)
+ func`.mod = ~self
+ ;/
;/
/; _create_methods (~uint8 name) [~Module]
diff --git a/tnslc/compile/scope.tnsl b/tnslc/compile/scope.tnsl
index ebfc671..2461abb 100644
--- a/tnslc/compile/scope.tnsl
+++ b/tnslc/compile/scope.tnsl
@@ -369,6 +369,9 @@ struct Scope {
v.loc = v.loc + 6
;/
;; else
+ int loc = 0
+ loc = loc - 1
+ v.loc = loc
tmp = self._next_stack_slot()
int sz = v.actual_size()
v.offset = tmp - sz
@@ -388,6 +391,58 @@ struct Scope {
return v.copy()
;/
+ # Make a temp variable on the stack for use in computations
+ /; mk_tmp_stack (~Var base) [Var]
+ Var v = base`.copy()
+ v.offset = 0
+
+ int loc = 0
+ loc = loc - 1
+ v.loc = loc
+ int tmp = self._next_stack_slot()
+ int sz = v.actual_size()
+ v.offset = tmp - sz
+
+ ~uint8 stk_str = utils.int_to_str(sz)
+ self.cb`.add_c(" sub rsp, \0")
+ self.cb`.add_c(stk_str)
+ self.cb`.add_c(" ; Create stack space for tmp variable\n\0")
+ _delete(stk_str)
+
+ self.tmps.push(~v)
+
+ return v.copy()
+ ;/
+
+ /; _save_caller_tmp (~utils.Vector vec)
+ # TODO
+ ;/
+
+ /; save_caller_tmp [Var]
+ Var tmp
+ utils.Vector tmps
+ tmps.init(len tmp)
+
+ self._save_caller_tmp(~tmps)
+
+ ~Var to_save
+ /; loop (int i = 0; i < tmps.count) [i++]
+ to_save = tmps.get(i)
+ tmp = self.mk_tmp_stack(to_save)
+ tmp.set(self.cb, to_save)
+ /; if (i < tmps.count - 1)
+ tmp.end()
+ ;/
+ ;/
+ tmps.end()
+
+ return tmp
+ ;/
+
+ /; restore_caller_tmp (~Var handle)
+ # TODO
+ ;/
+
# Free n tmp variables (starts from most recently created)
# If you want to generate code to set the stack pointer then
# set code to true
@@ -419,33 +474,68 @@ struct Scope {
# Returns true if the variable is in a temp spot
/; is_tmp (~Var v) [bool]
+ ~Var tmp
+ /; loop (int i = 0; i < self.tmps.count) [i++]
+ tmp = self.tmps.get(i)
+ /; if (tmp`.loc == v`.loc)
+ /; if (tmp`.offset == v`.offset)
+ return true
+ ;/
+ ;/
+ ;/
return false
;/
+ # Free all tmp variables created after and including the one provided
/; free_to (~Var tmp, bool code)
# TODO:DETERMINE HOW MANY TMPS
int tmps = 0
+ tmps = tmps - 1
~Var v
- /; loop (int i - 1; i !> self.tmps.count) [i++]
+ /; loop (int i = 1; i !> self.tmps.count) [i++]
v = self.tmps.get(self.tmps.count - i)
/; if (v`.offset == tmp`.offset)
- tmps = self.tmps.count
- tmps = tmps - i
- tmps = tmps + 1
+ tmps = i
+ i = self.tmps.count + 1
;/
;/
- /; if (tmps !== 0)
- self.free_tmp(tmps, code)
- ;; else
+ /; if (tmps < 0)
~uint8 scope_name = self.base_label()
int off = tmp`.offset
_printf("COMPILER ERROR: Unable to find temp to free to in scope \"\0")
_printf(scope_name)
_printf("\"\n\0")
_print_num(" Was looking for tmp with offset %d but could not find one.\n\0", off)
+ ;; else if (tmps > 0)
+ self.free_tmp(tmps, code)
;/
+ ;/
+ # Free all tmp variables created after the one provided
+ /; free_after (~Var tmp, bool code)
+ # TODO:DETERMINE HOW MANY TMPS
+ int tmps = 0
+ tmps = tmps - 1
+ ~Var v
+ /; loop (int i = 1; i !> self.tmps.count) [i++]
+ v = self.tmps.get(self.tmps.count - i)
+ /; if (v`.offset == tmp`.offset)
+ tmps = i - 1
+ i = self.tmps.count + 1
+ ;/
+ ;/
+
+ /; if (tmps < 0)
+ ~uint8 scope_name = self.base_label()
+ int off = tmp`.offset
+ _printf("COMPILER ERROR: Unable to find temp to free to in scope \"\0")
+ _printf(scope_name)
+ _printf("\"\n\0")
+ _print_num(" Was looking for tmp with offset %d but could not find one.\n\0", off)
+ ;; else if (tmps > 0)
+ self.free_tmp(tmps, code)
+ ;/
;/
#
diff --git a/tnslc/compile/var.tnsl b/tnslc/compile/var.tnsl
index f41d233..477a4fb 100644
--- a/tnslc/compile/var.tnsl
+++ b/tnslc/compile/var.tnsl
@@ -920,7 +920,7 @@ struct Var {
buf`.add_c(" ; putting struct address into register\n\0")
# Initial deref or move
- /; if (self.ptrc.count > 0)
+ /; if (self.ptrc.count > 1)
buf`.add_c(" mov \0")
;; else
buf`.add_c(" lea \0")
@@ -1670,6 +1670,7 @@ struct Var {
/; if (self.is_ref() == true)
self._set_struct_r(buf, 5)
out.loc = 5
+ out.ptr_push(0)
;; else
out.loc = self.loc
out.offset = out.offset + self.offset