summaryrefslogtreecommitdiff
path: root/tnslc
diff options
context:
space:
mode:
authorKyle Gunger <kgunger12@gmail.com>2023-01-03 02:03:54 -0500
committerKyle Gunger <kgunger12@gmail.com>2023-01-03 02:03:54 -0500
commitc94edbe007910755087e71cbb1a6a349d75e9b85 (patch)
treef466d26643f7caeb9a1f9a8fc5365338bc8637e8 /tnslc
parent17c838e4755fefadfb001c19ba2f079eaba340f6 (diff)
Basic addition and subtraction
Diffstat (limited to 'tnslc')
-rw-r--r--tnslc/compile/compile.tnsl181
-rw-r--r--tnslc/compile/value.tnsl134
-rw-r--r--tnslc/dummy.tnsl6
-rw-r--r--tnslc/util.tnsl20
4 files changed, 210 insertions, 131 deletions
diff --git a/tnslc/compile/compile.tnsl b/tnslc/compile/compile.tnsl
index cdb651f..034304c 100644
--- a/tnslc/compile/compile.tnsl
+++ b/tnslc/compile/compile.tnsl
@@ -77,7 +77,7 @@
/; method VTrack
/; next_loc(VType vt) [int]
- /; if (is_struct(vt))
+ /; if (is_struct(vt) && vt.ptr == 0)
;return -1
;/
@@ -110,8 +110,8 @@
# Returns true if the variable is being tracked
/; in_vtrack({}uint8 name) [bool]
- /; loop (int i = 0; i < len (self.on_stack)) [i++]
- /; if (string_equate(~name, ~(self.sym_names{i})))
+ /; loop (int i = 0; i < len (self.sym_names)) [i++]
+ /; if (string_equate(name, self.sym_names{i}))
;return true
;/
;/
@@ -131,7 +131,7 @@
# returns the type of the named variable
/; get_val ({}uint8 name) [Value]
- /; loop (int i = 0; i < len (self.on_stack)) [i++]
+ /; loop (int i = 0; i < len (self.sym_names)) [i++]
/; if (string_equate(name, self.sym_names{i}))
;return (self.sym_vals{i})
;/
@@ -146,7 +146,9 @@
;/
/; loop (int i = 0; i < len (self.sym_vals)) [i++]
- ;self.sym_vals{i}.loc = self.sym_vals{i}.loc + tsz
+ /; if (self.sym_vals{i}.on_stack)
+ ;self.sym_vals{i}.loc = self.sym_vals{i}.loc + tsz
+ ;/
;/
;{}uint8 out = "\tsub $"
@@ -196,31 +198,6 @@
;return -1
;/
-# Given an index in the vtrack, returns a string representation of the
-# register or memory where that variable is
-/; index_to_loc (int index, ~VTrack tab) [{}uint8]
- ;{}uint8 out = ""
- ;int stack_bytes = 0
- ;int reg = 0
- ;int i = 0
-
- /; loop (i < index) [i++]
- /; if (tab`.sym_types{i}._size !> 8 && reg < 7)
- ;reg++
- ;; else
- ;stack_bytes = stack_bytes + tab`.sym_types{i}._size
- ;/
- ;/
-
- /; if (is_struct(tab`.sym_types{index}))
- ;out = "(todo: structs)"
- ;; else
- ;out = reg_by_num(reg)
- ;/
-
- ;return out
-;/
-
# Bool to j
/; cmp_to_jxt ({}uint8 c) [{}uint8]
/; if (string_equate(c, "<"))
@@ -235,17 +212,12 @@
;return "e"
;; else if (string_equate(c, "!=="))
;return "ne"
- ;;
;/
;return "nz"
;/
# Is struct returns true if the type name given is a struct
/; is_struct (VType t) [bool]
- /; if (t.ptr !== 0)
- ;return false
- ;/
-
;VType tmp = NT
/; loop (int i = 0; i < 15) [i++]
;tmp = tnslc.type_table{i}
@@ -254,8 +226,6 @@
;/
;/
-
-
;return true
;/
@@ -428,42 +398,88 @@
;/
# Mostly deals with structs and enums
-/; compile_global (~int cur, ~{}Token data, ~VTrack gsc, ~{}uint8 hsec, csec, dsec)
+/; compile_global (~int cur, ~{}Token data, ~{}uint8 hsec, csec, dsec)
;cur`++
/; if (token_is(cur, data, "struct"))
;def_struct(cur, data, dsec)
;/
;/
-# Evaluate a value and return it to the register pointed at by reg
-/; eval_value (~int cur, ~{}Token data, ~VTrack tab, gsc, ~{}uint8 hsec, csec, dsec) [Value]
+# Evaluate a value
+/; eval_value (~int cur, ~{}Token data, ~VTrack tab, ~{}uint8 hsec, csec, dsec, int val_layer) [Value]
/; if (token_is(cur, data, ";/"))
;return NV
;/
- ;int val_layer = 0
+ ;Value tmp = {false, false, val_layer % 5, 0, NT}
+
+ /; if (val_layer > 5)
+ ;tmp.on_stack = true
+ ;/
/; loop (cur` < len data`)
+ ;tnsl.io.println("looping")
/; if (data`{cur`}.token_type == TOKEN_TYPE.LITERAL)
/; if (data`{cur`}.data`{0} == '"')
# String literal
-
+ ;tmp._type = type_table{5}
+ ;tmp._type.ptr = 1
;; else if (data`{cur`}.data`{0} == '\'')
# Char literal
+ ;int val = unquote_char(data`{cur`}.data`)
+ ;Value lit = {false, true, 0, val, type_table{5}}
+ ;{}uint8 tmp = out.set_value(lit)
+ ;add_strings(csec, ~tmp)
;; else
# int literal
- ;{}uint8 tmp = construct_mov_literal(data`{cur`}.data`, get_reg(8, reg_by_num(val_layer)))
- ;add_strings(csec, ~tmp)
- ;val_layer++
+ ;tnsl.io.print("int literal ")
+ ;tnsl.io.println(data`{cur`}.data`)
+ ;tmp.val = int_from_string(data`{cur`}.data`)
+ ;tmp.literal = true
+ ;tmp._type = tnslc.type_table{4}
;cur`++
+ ;tnsl.io.print("next tok ")
+ ;tnsl.io.println(data`{cur`}.data`)
;/
;; else if (data`{cur`}.token_type == TOKEN_TYPE.DEFWORD)
+
+ /; if (is_call(cur, data))
+ ;; else if (tab`.in_vtrack(data`{cur`}.data`))
+ ;tmp = tab`.get_val(data`{cur`}.data`)
+ ;cur`++
+ /; loop (token_is(cur, data, "."))
+ ;cur`++
+ ;tmp = tmp.get_member_value(data`{cur`}.data`)
+ ;cur`++
+ ;/
+ ;/
+
;; else if (token_is(cur, data, "~"))
;; else if (data`{cur`}.token_type == TOKEN_TYPE.AUGMENT)
+
+ ;int acr = cur`
+ ;cur`++
+ ;Value nxt = eval_value(cur, data, tab, hsec, csec, dsec, val_layer + 1)
+ ;{}uint8 code = ""
+ /; if (token_is(~acr, data, "="))
+ ;code = tmp.set_value(nxt)
+ ;; if (token_is(~acr, data, "+"))
+ ;code = tmp.add_value(nxt)
+ ;; if (token_is(~acr, data, "-"))
+ ;tnsl.io.println("here")
+ ;code = tmp.sub_value(nxt)
+ ;; if (token_is(~acr, data, "*"))
+ ;code = tmp.mul_value(nxt)
+ ;; if (token_is(~acr, data, "/"))
+ ;code = tmp.div_value(nxt)
+ ;/
+ ;add_strings(csec, ~code)
+ ;break
;; else
;break
;/
;/
+ ;return tmp
;/
/; get_function_label(~int cur, ~{}Token data) [{}uint8]
@@ -487,7 +503,7 @@
;/
# Sets up a call and reports back where the return value is stored
-/; eval_call (~int cur, ~{}Token data, ~VTrack tab, gsc, ~{}uint8 hsec, csec, dsec) [{}uint8]
+/; eval_call (~int cur, ~{}Token data, ~VTrack tab, ~{}uint8 hsec, csec, dsec) [{}uint8]
# Store the name of the function we are calling
;{}uint8 to_call = get_function_label(cur, data)
@@ -499,10 +515,10 @@
;cur`++
;; else
/; if (reg < 7)
- ;eval_value(cur, data, tab, gsc, hsec, csec, dsec)
+ ;eval_value(cur, data, tab, hsec, csec, dsec)
;reg++
;; else
- ;eval_value(cur, data, tab, gsc, hsec, csec, dsec)
+ ;eval_value(cur, data, tab, hsec, csec, dsec)
;push_asm(get_reg(8, "bp"))
;/
;/
@@ -515,37 +531,6 @@
;return "ax"
;/
-/; set_struct_value (~{}uint8 csec)
-
-;/
-
-/; copy_struct ({}uint8 from, to, VType t) [{}uint8]
- ;{}uint8 out = ""
- ;{}uint8 init = ""
-;/
-
-/; set_value ({}uint8 from, to, int size, ~{}uint8 csec)
- /; if (is_common_reg(from))
- ;from = get_reg(size, from)
- ;; if (is_common_reg(to))
- ;to = get_reg(size, to)
- ;/
-
- ;{}uint8 tmp = "\tmov"
- /; if (size == 1)
- ;mov.append('b')
- ;; else if (size == 2)
- ;mov.append('d')
- ;; else if (size == 4)
- ;mov.append('w')
- ;; else if (size == 8)
- ;mov.append('q')
- ;/
-
- ;tmp = construct_statement(tmp, {from, to})
- ;add_strings(csec, ~tmp)
-;/
-
/; is_call (~int cur, ~{}Token data) [bool]
;bool look_def = true
/; loop (int i = cur`; i < len data`) [i++]
@@ -563,7 +548,7 @@
;/
# Compile a statement in a function
-/; compile_statement (~int cur, ~{}Token data, ~VTrack tab, gsc, ~{}uint8 hsec, csec, dsec) [bool]
+/; compile_statement (~int cur, ~{}Token data, ~VTrack tab, ~{}uint8 hsec, csec, dsec) [bool]
;cur`++
;bool r = false
/; if (cur` !< len data`)
@@ -582,18 +567,20 @@
;r = true
;; else if (token_is(cur, data, "return"))
;cur`++
- ;eval_value(cur, data, tab, gsc, hsec, csec, dsec, 0)
+ ;Value out = eval_value(cur, data, tab, hsec, csec, dsec, 0)
+ ;{}uint8 mv = out.mov_to_reg(0)
+ ;add_strings(csec, ~mv)
;tail_guard(csec)
;add_strings(csec, ~(tnslc.COMMON_ASM{0}))
;return true
;; else if (is_call(cur, data))
# Function call
- ;eval_call(cur, data, tab, gsc, hsec, csec, dsec)
- ;; else if (name_to_index(data`{cur`}.data`, tab) !< 0)
+ ;eval_call(cur, data, tab, hsec, csec, dsec)
+ ;; else if (tab.in_vtrack(data`{cur`}.data`))
# set value
;int i = name_to_index(data`{cur`}.data`, tab)
;{}uint8 tmp = index_to_loc(i)
- ;eval_value(cur, data, tab, gsc, hsec, csec, dsec)
+ ;eval_value(cur, data, tab, hsec, csec, dsec)
;tmp = mov_asm(get_reg(tab`.sym_types{i}._size, "ax"), tmp)
;add_strings(csec, ~tmp)
;; else
@@ -609,7 +596,7 @@
;cur`++
;; else if (token_is(cur, data, "="))
;{}uint8 set = index_to_loc(len tab`.sym_names - 1, tab)
- ;eval_value(cur, data, tab, gsc, hsec, csec, dsec, loc)
+ ;eval_value(cur, data, tab, hsec, csec, dsec, loc)
/; if (token_is(cur, data, ","))
;cur`++
;/
@@ -629,7 +616,7 @@
-/; compile_block (~int cur, ~{}Token data, ~VTrack gsc, ~{}uint8 hsec, csec, dsec, {}{}uint8 mod_path, Path rel)
+/; compile_block (~int cur, ~{}Token data, ~{}uint8 hsec, csec, dsec, {}{}uint8 mod_path, Path rel)
;VTrack tab = { {}, {} }
;VType out_type = tnslc.type_table{14}
;{}uint8 name = ""
@@ -682,7 +669,7 @@
;; else if (token_is(cur, data, "/;"))
;bool ch = true
/; loop (ch)
- ;compile_block(cur, data, gsc, hsec, csec, dsec, mod_path)
+ ;compile_block(cur, data, hsec, csec, dsec, mod_path)
/; if (cur` !< len data`)
;break
;/
@@ -691,10 +678,10 @@
;; else if (string_equate(data`{cur`}.data`, ":"))
;cur` = cur` + 2
;Path inc = rel.rel_file(unquote_string(data`{cur`}.data`))
- ;compile_include(inc, gsc, hsec, csec, dsec, mod_path)
+ ;compile_include(inc, hsec, csec, dsec, mod_path)
;cur`++
;; else if (string_equate(data`{cur`}.data`, ";"))
- ;ret = compile_statement(cur, data, ~tab, gsc, hsec, csec, dsec)
+ ;ret = compile_statement(cur, data, ~tab, hsec, csec, dsec)
;; else
;tnsl.io.print("Failed to compile token [compile_block]: ")
;data`{cur`}.print()
@@ -706,7 +693,7 @@
;csec`.append('\n')
;/
-/; compile_include (Path file_path, ~VTrack global, ~{}uint8 hsec, csec, dsec, {}{}uint8 mod_path)
+/; compile_include (Path file_path, ~{}uint8 hsec, csec, dsec, {}{}uint8 mod_path)
# Autocomplete in the case of module syntax
;bool d = file_path.extension_is("tnsl")
/; if (!d)
@@ -727,22 +714,22 @@
;tnsl.io.print(len data`)
;tnsl.io.println(" tokens parsed.")
- ;compile_file(file_path, data, global, hsec, csec, dsec, mod_path)
+ ;compile_file(file_path, data, hsec, csec, dsec, mod_path)
;/
-/; compile_file (Path rel, ~{}Token data, ~VTrack global, ~{}uint8 hsec, csec, dsec, {}{}uint8 mod_path)
+/; compile_file (Path rel, ~{}Token data, ~{}uint8 hsec, csec, dsec, {}{}uint8 mod_path)
;int j = len data`
/; loop (int i = 0; i < j) [i++]
/; if (string_equate(data`{i}.data`, "/;"))
- ;compile_block(~i, data, global, hsec, csec, dsec, mod_path, rel)
+ ;compile_block(~i, data, hsec, csec, dsec, mod_path, rel)
;; else if (string_equate(data`{i}.data`, ";"))
- ;compile_global(~i, data, global, hsec, csec, dsec)
+ ;compile_global(~i, data, hsec, csec, dsec)
;; else if (string_equate(data`{i}.data`, ":"))
;i = i + 2
;Path inc = rel.rel_file(unquote_string(data`{i}.data`))
- ;compile_include(inc, global, hsec, csec, dsec, mod_path)
+ ;compile_include(inc, hsec, csec, dsec, mod_path)
;; else
;break
;/
@@ -754,10 +741,8 @@
;{}uint8 hsec = ".global main\n"
;{}uint8 csec = ".text\n"
;{}uint8 dsec = ".data\n"
-
- ;VTrack global_scope = {{}, {}}
- ;tnslc.compile_include(rel, ~global_scope, ~hsec, ~csec, ~dsec, {})
+ ;tnslc.compile_include(rel, ~hsec, ~csec, ~dsec, {})
;tnsl.io.File out = tnsl.io.writeFile(file_out)
diff --git a/tnslc/compile/value.tnsl b/tnslc/compile/value.tnsl
index 747c172..da76ac8 100644
--- a/tnslc/compile/value.tnsl
+++ b/tnslc/compile/value.tnsl
@@ -36,10 +36,23 @@
;return "si"
;; if (r == 5)
;return "di"
+ ;; if (r == -1)
+ ;return "sp"
;/
;return string_from_int(r + 2)
;/
+/; ext_by_size(int s) [uint8]
+ /; if (r == 1)
+ ;return 'b'
+ ;; if (r == 2)
+ ;return 'w'
+ ;; if (r == 4)
+ ;return 'l'
+ ;/
+ ;return 'q'
+;/
+
/; method Value
@@ -53,6 +66,12 @@
/; get_norm_loc [{}uint8]
/; if (self.on_stack)
;return val_from_address(self.loc, "%rsp")
+ ;; if (!(self.on_stack) && self._type.ptr == 0 && is_struct(self._type))
+ ;{}uint8 out = "("
+ ;{}uint8 tmp = get_reg(8, reg_by_num(self.loc))
+ ;add_strings(~out, ~tmp)
+ ;out.append(')')
+ ;return out
;/
/; if (self.literal)
@@ -71,25 +90,21 @@
;/
/; init_val [{}uint8]
- /; if (!self.on_stack)
- ;{}uint8 out = "\tmov $0, "
- ;{}uint8 reg = get_reg(8, reg_by_num(self.loc))
- ;add_strings(~out, ~reg)
- ;return out
- ;; else if (!self.literal)
- ;{}uint8 out = "\tsub $"
- ;{}uint8 tmp = string_from_int(self._type._size)
- ;add_strings(~out, ~tmp)
- ;out.append(',')
- ;out.append(' ')
- ;tmp = "%rsp\n"
- ;add_strings(~out, ~tmp)
- ;return out
+ /; if (self.literal || !self.on_stack)
+ ;return ""
;/
- ;return ""
+
+ ;{}uint8 out = "\tsub $"
+ ;{}uint8 tmp = string_from_int(self._type._size)
+ ;add_strings(~out, ~tmp)
+ ;tmp = ", %rsp\n"
+ ;add_strings(~out, ~tmp)
+ ;return out
;/
/; standard_op(Value other, {}uint8 op) [{}uint8]
+ ;tnsl.io.print("Std op ")
+ ;tnsl.io.println(op)
;int tsz = other._type._size
;other._type._size = self._type._size
;{}uint8 tmp = other.get_norm_loc()
@@ -110,22 +125,28 @@
/; if (self.literal)
;self.val = self.val + v.val
;return ""
- ;; else if (!self.on_stack)
+ ;; else if (!(self.on_stack))
;return self.standard_op(v, "add")
;/
;/
/; sub_value (Value v) [{}uint8]
/; if (self.literal)
- ;self.val = self.val + v.val
+ ;self.val = self.val - v.val
;return ""
- ;; else if (!self.on_stack)
+ ;; else if (!(self.on_stack))
;return self.standard_op(v, "sub")
;/
;/
/; ax_compute(Value v, {}uint8 op, bool save_dx)
;{}uint8 out = "\tpush %rax\n\tpush %rdx\n"
+
+ /; if (v.on_stack)
+ ;v.loc = v.loc + 16
+ ;; if (self.on_stack)
+ ;self.loc = self.loc + 16
+ ;/
;{}uint8 tmp = "\tmov "
;{}uint8 t2 = v.get_norm_loc()
@@ -154,6 +175,12 @@
;tmp.append('\n')
;add_strings(~out, ~tmp)
+ /; if (v.on_stack)
+ ;v.loc = v.loc - 16
+ ;; if (self.on_stack)
+ ;self.loc = self.loc - 16
+ ;/
+
;tmp = "\tpop %rdx\n\tpop %rax"
;add_strings(~out, ~tmp)
;return out
@@ -161,9 +188,9 @@
/; mul_value (Value v) [{}uint8]
/; if (self.literal)
- ;self.val = self.val + v.val
+ ;self.val = self.val * v.val
;return ""
- ;; else if (!self.on_stack)
+ ;; else if (!(self.on_stack))
/; if (self._type.name{0} !== 'u')
;return self.standard_op(v, "imul")
;/
@@ -176,7 +203,7 @@
/; if (self.literal)
;self.val = self.val + v.val
;return ""
- ;; else if (!self.on_stack)
+ ;; else if (!(self.on_stack))
/; if (self._type.name{0} !== 'u')
;return self.ax_compute(v, "idiv", false)
;/
@@ -187,7 +214,7 @@
/; mod_value (Value v) [{}uint8]
/; if (self.literal)
- ;self.val = self.val + v.val
+ ;self.val = self.val / v.val
;return ""
;; else if (!self.on_stack)
/; if (self._type.name{0} !== 'u')
@@ -226,9 +253,9 @@
;return out
;/
- /; arr_value (Value index, Value store)
+ /; get_index (Value index) [Value]
/; if (self._type.ptr == 0)
- ;return
+ ;return NV
;/
;/
@@ -237,21 +264,72 @@
;self.val = v.val
;return ""
;; else if (!(self.on_stack))
- ;return self.standard_op(v, "mov")
+ /; if (!is_struct(self._type))
+ ;return self.standard_op(v, "mov")
+ ;/
+ # This is the case where we are storing an address to
+ # a struct in a register.
+ ;{}charp out = "\tpush %rcx\n\tmov "
+ ;{}charp tmp = self.get_norm_loc()
+ ;add_strings(~out, ~tmp)
+ ;tmp = ", %rcx\n"
+ ;add_strings(~out, ~tmp)
+ ;tmp = self.standard_op(v, "movsb")
+ ;add_strings(~out, ~tmp)
+ ;tmp = "\tpop %rcx"
+ ;add_strings(~out, ~tmp)
+ ;return out
+ ;/
+
+ /; if (self._type._size !> 8)
+ /; if (!v.on_stack)
+ ;return self.standard_op(v, "mov")
+ ;/
+ ;{}charp out = "\tpush %rax\n\tmov "
+ ;{}charp tmp = v.get_norm_loc()
+ ;add_strings(~out, ~tmp)
+ ;tmp = ", %rax\n"
+ ;add_strings(~out, ~tmp)
+ ;tmp = self.standard_op(v, "mov")
+ ;add_strings(~out, ~tmp)
+ ;return out
;/
+
+ ;/
+
+ /; load_label_address ({}uint8 lab) [{}uint8]
+ ;{}uint8 out = "\tlea "
+ ;{}uint8 tmp = "(%rip), "
+ ;add_strings(~out, ~lab)
+ ;add_strings(~out, ~tmp)
+ ;tmp = self.get_norm_loc()
+ ;add_strings(~out, tmp)
+ ;out.append('\n')
+ ;return out
;/
/; get_member_value ({}uint8 name) [Value]
;Value out = self
- ;out.loc = out.loc + self._type.get_offset(name)
+ /; if (self.on_stack)
+ ;out.loc = out.loc + self._type.get_offset(name)
+ ;; else
+ ;out.val = out.val + self._type.get_offset(name)
+ ;/
;out._type = self._type.get_sub_type(name)
+ ;out._type.ptr = -1
;return out
;/
+ /; mov_to_reg (int reg) [{}uint8]
+ /; if (!(self.on_stack))
+ ;return self.update_loc(0)
+ ;/
+ ;/
+
/; update_loc(int loc) [{}uint8]
/; if (self.on_stack)
;self.loc = self.loc + loc
- ;; else if (!self.literal)
+ ;; else if (!(self.literal))
;{}uint8 out = "\tmov "
;int tsz = self._type._size
;self._type._size = 8
@@ -263,7 +341,7 @@
;self.loc = loc
- ;{}uint8 tmp = self.get_norm_loc()
+ ;tmp = self.get_norm_loc()
;add_strings(~out, ~tmp)
;out.append('\n')
diff --git a/tnslc/dummy.tnsl b/tnslc/dummy.tnsl
index eda351a..741a0e0 100644
--- a/tnslc/dummy.tnsl
+++ b/tnslc/dummy.tnsl
@@ -6,13 +6,17 @@
test a, b
}
+/; add (int a, b) [int]
+ ;return a + b - 9 - 30
+;/
+
/; main (uint argc, ~~uint8 argv) [int]
# Fix for main func
;asm "mov %rdi, %r8"
;asm "mov %rsi, %r9"
# ;~void ptr = _alloc(10)
# ;_delete(ptr)
- ;return 1
+ # ;return add(argc, 2)
;/
diff --git a/tnslc/util.tnsl b/tnslc/util.tnsl
index 156cbb4..d4a7b4b 100644
--- a/tnslc/util.tnsl
+++ b/tnslc/util.tnsl
@@ -69,9 +69,10 @@
/; string_from_int(int i) [{}uint8]
;{}uint8 c = ""
+ ;bool n = false
/; if (i < 0)
- ;c = "-"
+ ;n = true
;i = -i
;/
@@ -82,17 +83,28 @@
;c.append(digit_to_char(i))
;/
+ /;if (n)
+ ;c.append('-')
+ ;/
+
;return reverse_string(c)
;/
/; int_from_string ({}uint8 str) [int]
;bool inv = str{0} == '-'
;int out = 0
+ ;int fac = 10
+ ;int i = 0
- /; loop ()
-
+ /; if (inv)
+ ;i++
+ ;/
+
+ /; loop (i < len str) [i++]
+ ;out = out * fac
+ ;out = out + str{i} - '0'
;/
-
+
/; if (inv)
;out = -out
;/