diff options
| author | Kyle Gunger <kgunger12@gmail.com> | 2023-01-03 02:03:54 -0500 | 
|---|---|---|
| committer | Kyle Gunger <kgunger12@gmail.com> | 2023-01-03 02:03:54 -0500 | 
| commit | c94edbe007910755087e71cbb1a6a349d75e9b85 (patch) | |
| tree | f466d26643f7caeb9a1f9a8fc5365338bc8637e8 /tnslc | |
| parent | 17c838e4755fefadfb001c19ba2f079eaba340f6 (diff) | |
Basic addition and subtraction
Diffstat (limited to 'tnslc')
| -rw-r--r-- | tnslc/compile/compile.tnsl | 181 | ||||
| -rw-r--r-- | tnslc/compile/value.tnsl | 134 | ||||
| -rw-r--r-- | tnslc/dummy.tnsl | 6 | ||||
| -rw-r--r-- | tnslc/util.tnsl | 20 | 
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  	;/ |