commit 9828682d540b975b38136ea29d9e2d4821f3442b from: Onana Onana Xavier Manuel date: Sat Sep 26 11:25:23 2026 UTC Parser for memory blocks without nesting for now commit - 2be87f778a56964007d4c5ccf7171fa000149f79 commit + 9828682d540b975b38136ea29d9e2d4821f3442b blob - 771e0898b66bd3ce7b85cd60ab72614d746765e4 blob + cf4055f93e6f1181a01b395d5b0428d13ee87d33 --- tools/6c +++ tools/6c @@ -3,7 +3,7 @@ ----------------------------------------------------------------------- -- TOKEN MATCHING ----------------------------------------------------------------------- -local mnemonics = { "mov", "cli", "hlt", "ret", "sti" } +local mnemonics = { "mov", "cli", "hlt", "ret", "sti", "int" } -- This is kinda a double definition but fix later :^) local arithmetics = { "+", "-", "*", "/", "^", "~", "|", "&" } @@ -208,6 +208,9 @@ local function intval(intstr) for i = 1, len do local s = intstr:sub(len - i + 1, len - i + 1) + if s:match("[0-9]") == false then + return nil + end s = s * (10 ^ (i - 1)) res = res + s end @@ -255,7 +258,179 @@ function bitval(b) return result end + + ----------------------------------------------------------------------- +-- EXPRESSION SOLVING +----------------------------------------------------------------------- + +local function subarray(array, start, last) + if last == nil then + last = #array + end + + local sub = { } + + for i, v in ipairs(array) do + if i >= start and i <= last then + table.insert(sub, array[i]) + end + end + + return sub +end + +local function finddepth(array, spos) + local epos = nil + local depth = 1 + + for j = spos, #array do + if array[j] == "(" then depth = depth + 1 end + if array[j] == ")" then depth = depth - 1 end + + if depth == 0 then + epos = j + break + end + end + + if depth ~= 0 then + perror("invalid nesting") + end + + if epos == nil then perror("Mismatched paranthesis") end + + return epos +end + +-- Use this once the syntax validation is completed +local function evaluate_expression(array) + local i = 1 + local eval = { } + while i <= #array do + if array[i] == "(" then + local spos = i + local epos = finddepth(array, spos + 1) + + local sub = { } + for k = spos + 1, epos - 1 do + table.insert(sub, array[k]) + end + + local result = evaluate_expression(sub) + + for _, val in ipairs(result) do + table.insert(eval, val) + end + + i = epos + 1 + elseif array[i] == "*" then + local left = table.remove(eval) + local right = array[i + 1] + local epos = i + 2 + + if right == "(" then + local sub = subarray(array, i + 1) + right = evaluate_expression(sub)[1] + epos = finddepth(array, i + 2) + 1 + end + + if type(left) == "string" and type(right) == "string" then + if tonumber(left) ~= nil and tonumber(right) ~= nil then + table.insert(eval, tostring(tonumber(left) * tonumber(right))) + + elseif tonumber(left) == nil and tonumber(right) ~= nil then + table.insert(eval, { left, tonumber(right) }) + + elseif tonumber(left) ~= nil and tonumber(right) == nil then + table.insert(eval, { right, tonumber(left) }) + + end + elseif type(left) == "table" and type(right) == "string" then + if tonumber(right) ~= nil then + table.insert(eval, { left[1], left[2] * tonumber(right) }) + end + end + + i = epos + else + table.insert(eval, array[i]) + i = i + 1 + end + end + + local k = 1 + local total = 0 + local final = {} + + while k < #eval do + local cur = eval[k] + local opr = eval[k + 1] + local nxt = eval[k + 2] + + local n1 = tonumber(cur) + local n2 = tonumber(nxt) + + if n1 ~= nil then + total = n1 + total + k = k + 1 + elseif cur == "+" or cur == "-" then + if tonumber(opr) ~= nil then + if cur == "+" then + total = tonumber(opr) + total + elseif cur == "-" then + total = total - tonumber(opr) + end + + k = k + 2 + else + if type(opr) == "string" then + table.insert(final, {opr, 1}) + else + table.insert(final, opr) + end + k = k + 2 + end + + elseif type(cur) == "string" and n2 ~= nil then + table.insert(final, { cur, 1 }) + total = total + n2 + k = k + 3 + + elseif type(cur) == "table" and n2 ~= nil then + table.insert(final, cur) + if opr == "-" then + total = total - n2 + else + total = total + n2 + end + k = k + 3 + + elseif type(cur) == "table" and type(nxt) == "string" then + k = k + 3 + + elseif type(cur) == "string" and type(nxt) == "string" then + table.insert(final, { cur, 1 }) + table.insert(final, { nxt, 1 }) + k = k + 3 + + elseif type(cur) == "string" and type(nxt) == "table" then + table.insert(final, { cur, 1 }) + table.insert(final, nxt) + k = k + 3 + + else + k = k + 3 + end + end + + if total ~= 0 then + table.insert(final, tostring(total)) + end + + return final +end +----------------------------------------------------------------------- -- Checking arguments and setting read and write file ----------------------------------------------------------------------- @@ -357,7 +532,7 @@ end -- Tokenizing ----------------------------------------------------------------------- -local nline = 0 +local nline = 1 while true do local line = src:read("*l") if line == nil then blob - c40eacaa915eea26d8db27517a070e966ab2c204 blob + 037ae3288d68a6b0a53ce2301d8fade58d65088c --- tools/6l +++ tools/6l @@ -3,7 +3,7 @@ ----------------------------------------------------------------------- -- TOKEN MATCHING ----------------------------------------------------------------------- -local mnemonics = { "mov", "cli", "hlt", "ret", "sti" } +local mnemonics = { "mov", "cli", "hlt", "ret", "sti", "int" } -- This is kinda a double definition but fix later :^) local arithmetics = { "+", "-", "*", "/", "^", "~", "|", "&" } @@ -208,6 +208,9 @@ local function intval(intstr) for i = 1, len do local s = intstr:sub(len - i + 1, len - i + 1) + if s:match("[0-9]") == false then + return nil + end s = s * (10 ^ (i - 1)) res = res + s end @@ -255,7 +258,179 @@ function bitval(b) return result end + + ----------------------------------------------------------------------- +-- EXPRESSION SOLVING +----------------------------------------------------------------------- + +local function subarray(array, start, last) + if last == nil then + last = #array + end + + local sub = { } + + for i, v in ipairs(array) do + if i >= start and i <= last then + table.insert(sub, array[i]) + end + end + + return sub +end + +local function finddepth(array, spos) + local epos = nil + local depth = 1 + + for j = spos, #array do + if array[j] == "(" then depth = depth + 1 end + if array[j] == ")" then depth = depth - 1 end + + if depth == 0 then + epos = j + break + end + end + + if depth ~= 0 then + perror("invalid nesting") + end + + if epos == nil then perror("Mismatched paranthesis") end + + return epos +end + +-- Use this once the syntax validation is completed +local function evaluate_expression(array) + local i = 1 + local eval = { } + while i <= #array do + if array[i] == "(" then + local spos = i + local epos = finddepth(array, spos + 1) + + local sub = { } + for k = spos + 1, epos - 1 do + table.insert(sub, array[k]) + end + + local result = evaluate_expression(sub) + + for _, val in ipairs(result) do + table.insert(eval, val) + end + + i = epos + 1 + elseif array[i] == "*" then + local left = table.remove(eval) + local right = array[i + 1] + local epos = i + 2 + + if right == "(" then + local sub = subarray(array, i + 1) + right = evaluate_expression(sub)[1] + epos = finddepth(array, i + 2) + 1 + end + + if type(left) == "string" and type(right) == "string" then + if tonumber(left) ~= nil and tonumber(right) ~= nil then + table.insert(eval, tostring(tonumber(left) * tonumber(right))) + + elseif tonumber(left) == nil and tonumber(right) ~= nil then + table.insert(eval, { left, tonumber(right) }) + + elseif tonumber(left) ~= nil and tonumber(right) == nil then + table.insert(eval, { right, tonumber(left) }) + + end + elseif type(left) == "table" and type(right) == "string" then + if tonumber(right) ~= nil then + table.insert(eval, { left[1], left[2] * tonumber(right) }) + end + end + + i = epos + else + table.insert(eval, array[i]) + i = i + 1 + end + end + + local k = 1 + local total = 0 + local final = {} + + while k < #eval do + local cur = eval[k] + local opr = eval[k + 1] + local nxt = eval[k + 2] + + local n1 = tonumber(cur) + local n2 = tonumber(nxt) + + if n1 ~= nil then + total = n1 + total + k = k + 1 + elseif cur == "+" or cur == "-" then + if tonumber(opr) ~= nil then + if cur == "+" then + total = tonumber(opr) + total + elseif cur == "-" then + total = total - tonumber(opr) + end + + k = k + 2 + else + if type(opr) == "string" then + table.insert(final, {opr, 1}) + else + table.insert(final, opr) + end + k = k + 2 + end + + elseif type(cur) == "string" and n2 ~= nil then + table.insert(final, { cur, 1 }) + total = total + n2 + k = k + 3 + + elseif type(cur) == "table" and n2 ~= nil then + table.insert(final, cur) + if opr == "-" then + total = total - n2 + else + total = total + n2 + end + k = k + 3 + + elseif type(cur) == "table" and type(nxt) == "string" then + k = k + 3 + + elseif type(cur) == "string" and type(nxt) == "string" then + table.insert(final, { cur, 1 }) + table.insert(final, { nxt, 1 }) + k = k + 3 + + elseif type(cur) == "string" and type(nxt) == "table" then + table.insert(final, { cur, 1 }) + table.insert(final, nxt) + k = k + 3 + + else + k = k + 3 + end + end + + if total ~= 0 then + table.insert(final, tostring(total)) + end + + return final +end +----------------------------------------------------------------------- -- Checking arguments ----------------------------------------------------------------------- progname = "6l" @@ -375,7 +550,8 @@ local function operlyze(op, ret) -- You cannot multiply the base reg (not allowed according to manual) -- You can only multiply index reg by a factor of 2 up to max value 8 (1, 2, 4, 8) elseif op.type == tk_type["["] then - local brackets = { opened = 0, closed = 0 } + local expr = { } + local depth = 0 while true do local pre = op @@ -395,25 +571,54 @@ local function operlyze(op, ret) " line " .. op.line) end - if #ret.memblock.regs == 0 and typematch(pre, { "+", "-" }) == false then + if #ret.memblock.regs == 0 and typematch(pre, { "+", "-" , "[", "(" }) == false then perror("Base register `" .. gettokenkey(op) .. "` can only be applied + or - on it line " .. op.line) - elseif #ret.memblock.regs == 1 and typematch(pre, { "+", "-", "*" }) == false then + elseif #ret.memblock.regs == 1 and typematch(pre, { "+", "-", "*", "(", "[" }) == false then perror("Index register `" .. gettokenkey(op) .. "` can only be applied +, - or * on it line " .. op.line) end table.insert(ret.memblock.regs, gettokenkey(op)) + table.insert(expr, gettokenkey(op)) elseif typematch(op, { "hexadecimal", "integer" }) then if typematch(pre, { "[", arithmetics }) == false then perror("missing arithmetic/paranthesis prefix for whole number " .. op.raw .. " line " .. op.line) end + + if op.type == tk_type["hexadecimal"] then + table.insert(expr, tostring(hexval(op.raw))) + elseif op.type == tk_type["integer"] then + table.insert(expr, tostring(intval(op.raw))) + end + -- Other arithmetic symbols elseif isarithmetic(op) == true then - if typematch(pre, { regs8, "hexadecimal", "integer" }) == false then + if typematch(pre, { regs8, "hexadecimal", "integer", ")" }) == false then perror("illegal token before " .. gettokenkey(op) .. " at line " .. op.line) end + + if #ret.memblock.regs == 1 and typematch(pre, { regs8 }) == true and typematch(op, { "+", "-" } ) == false then + perror("Base register `" .. gettokenkey(pre) .. + "` can only be applied + or - on it line " .. op.line) + end + table.insert(expr, gettokenkey(op)) + + elseif op.type == tk_type["("] then + if typematch(pre, { regs8, arithmetics, "(", "[" , "hexadecimal", "integer" }) == false then + perror("illegal token befor `(` at line " .. op.line) + end + + table.insert(expr, "(") + depth = depth + 1 + elseif op.type == tk_type[")"] then + if typematch(pre, { regs8, "hexadecimal", ")", "integer" }) == false then + perror("illegal token before `)` at line " .. op.line) + end + + table.insert(expr, ")") + depth = depth - 1 else perror("illegal token " .. gettokenkey(op) .. " at line " .. op.line) end @@ -423,12 +628,34 @@ local function operlyze(op, ret) end end + if depth ~= 0 then + perror("Mismatching paranthesis at line " .. op.line) + end + if op.type ~= tk_type["]"] then perror("Missing closing `]` at line " .. op.line) end + local e = evaluate_expression(expr) + --[[ + for _,v in ipairs(e) do + if type(v) == "string" then + io.write(v, " ") + else + io.write("{") + io.write(v[1], ", ") + io.write(v[2], "") + io.write("} ") + end + end + io.write("\n") + io.write("\n") + ]]-- + + ret.memblock.expression = e table.insert(ret.details, ASM_MEM8) ret.opcount = 1 + elseif op.type == tk_type["\n"] then ret.opcount = 0 else @@ -447,6 +674,7 @@ local function asmlyze(first) regs = { }, dispsize = 0, blevel = 0, + expression = nil } } @@ -516,6 +744,7 @@ local function instvaluate(inst) return ret elseif opcount == 1 then -- amslyze caps it at 2 + return ret else if inst.details[1] == ASM_R8 and inst.details[2] == ASM_R8 then local dstmap = regmap[gettokenkey(inst.operands[1])] @@ -534,6 +763,8 @@ local function instvaluate(inst) -- 10 memory 32 bit displacement -- 11 register to register elseif inst.details[1] == ASM_MEM8 and inst.details[2] == ASM_R8 then + local mod = "00" + return ret end end @@ -661,6 +892,25 @@ while true do elseif hdr.type == tk_type["cli"] then writeu8(dst, hexval("0hFA")) + + elseif hdr.type == tk_type["int"] then + local opcount = #inst.details + + if opcount ~= 1 then + perror("int takes 1 operand at line " .. hdr.line) + end + + if inst.details[1] ~= ASM_IMM8 then + perror("int requires an immediate 8 byte value") + end + + writeu8(dst, hexval("0hCD")) + + if inst.operands[1].type == tk_type["hexadecimal"] then + writeu8(dst, hexval(inst.operands[1].raw)) + elseif inst.operands[1].type == tk_type["integer"] then + writeu8(dst, intval(inst.operands[1].raw)) + end end end end blob - 6d39970a0aa2f1314e3971c97ecf869d5bff94ec blob + 5ab188ebc6559ddc93627d47140bf87ce8a562de --- tools/boot.sc +++ tools/boot.sc @@ -1,4 +1,8 @@ asm { _start: + mov ah, 0h0e + mov al, 0h61 + int 0h10 + mov [ al + 0h100 ], bl hlt } blob - 73c6a396f089b292270ae57e9209b940ccaa8b91 blob + 4f1f15f1abbc7a87e724565092403922576b4833 --- tools/compiler.lua +++ tools/compiler.lua @@ -100,7 +100,7 @@ end -- Tokenizing ----------------------------------------------------------------------- -local nline = 0 +local nline = 1 while true do local line = src:read("*l") if line == nil then blob - 88127113ea6e94d8819871d58c5f49c92ed74cda blob + aff9c78043627789dc3802f77df40ac91a3b049b --- tools/linker.lua +++ tools/linker.lua @@ -118,7 +118,8 @@ local function operlyze(op, ret) -- You cannot multiply the base reg (not allowed according to manual) -- You can only multiply index reg by a factor of 2 up to max value 8 (1, 2, 4, 8) elseif op.type == tk_type["["] then - local brackets = { opened = 0, closed = 0 } + local expr = { } + local depth = 0 while true do local pre = op @@ -138,25 +139,54 @@ local function operlyze(op, ret) " line " .. op.line) end - if #ret.memblock.regs == 0 and typematch(pre, { "+", "-" }) == false then + if #ret.memblock.regs == 0 and typematch(pre, { "+", "-" , "[", "(" }) == false then perror("Base register `" .. gettokenkey(op) .. "` can only be applied + or - on it line " .. op.line) - elseif #ret.memblock.regs == 1 and typematch(pre, { "+", "-", "*" }) == false then + elseif #ret.memblock.regs == 1 and typematch(pre, { "+", "-", "*", "(", "[" }) == false then perror("Index register `" .. gettokenkey(op) .. "` can only be applied +, - or * on it line " .. op.line) end table.insert(ret.memblock.regs, gettokenkey(op)) + table.insert(expr, gettokenkey(op)) elseif typematch(op, { "hexadecimal", "integer" }) then if typematch(pre, { "[", arithmetics }) == false then perror("missing arithmetic/paranthesis prefix for whole number " .. op.raw .. " line " .. op.line) end + + if op.type == tk_type["hexadecimal"] then + table.insert(expr, tostring(hexval(op.raw))) + elseif op.type == tk_type["integer"] then + table.insert(expr, tostring(intval(op.raw))) + end + -- Other arithmetic symbols elseif isarithmetic(op) == true then - if typematch(pre, { regs8, "hexadecimal", "integer" }) == false then + if typematch(pre, { regs8, "hexadecimal", "integer", ")" }) == false then perror("illegal token before " .. gettokenkey(op) .. " at line " .. op.line) end + + if #ret.memblock.regs == 1 and typematch(pre, { regs8 }) == true and typematch(op, { "+", "-" } ) == false then + perror("Base register `" .. gettokenkey(pre) .. + "` can only be applied + or - on it line " .. op.line) + end + table.insert(expr, gettokenkey(op)) + + elseif op.type == tk_type["("] then + if typematch(pre, { regs8, arithmetics, "(", "[" , "hexadecimal", "integer" }) == false then + perror("illegal token befor `(` at line " .. op.line) + end + + table.insert(expr, "(") + depth = depth + 1 + elseif op.type == tk_type[")"] then + if typematch(pre, { regs8, "hexadecimal", ")", "integer" }) == false then + perror("illegal token before `)` at line " .. op.line) + end + + table.insert(expr, ")") + depth = depth - 1 else perror("illegal token " .. gettokenkey(op) .. " at line " .. op.line) end @@ -166,12 +196,34 @@ local function operlyze(op, ret) end end + if depth ~= 0 then + perror("Mismatching paranthesis at line " .. op.line) + end + if op.type ~= tk_type["]"] then perror("Missing closing `]` at line " .. op.line) end + local e = evaluate_expression(expr) + --[[ + for _,v in ipairs(e) do + if type(v) == "string" then + io.write(v, " ") + else + io.write("{") + io.write(v[1], ", ") + io.write(v[2], "") + io.write("} ") + end + end + io.write("\n") + io.write("\n") + ]]-- + + ret.memblock.expression = e table.insert(ret.details, ASM_MEM8) ret.opcount = 1 + elseif op.type == tk_type["\n"] then ret.opcount = 0 else @@ -190,6 +242,7 @@ local function asmlyze(first) regs = { }, dispsize = 0, blevel = 0, + expression = nil } } @@ -259,6 +312,7 @@ local function instvaluate(inst) return ret elseif opcount == 1 then -- amslyze caps it at 2 + return ret else if inst.details[1] == ASM_R8 and inst.details[2] == ASM_R8 then local dstmap = regmap[gettokenkey(inst.operands[1])] @@ -277,6 +331,8 @@ local function instvaluate(inst) -- 10 memory 32 bit displacement -- 11 register to register elseif inst.details[1] == ASM_MEM8 and inst.details[2] == ASM_R8 then + local mod = "00" + return ret end end @@ -404,6 +460,25 @@ while true do elseif hdr.type == tk_type["cli"] then writeu8(dst, hexval("0hFA")) + + elseif hdr.type == tk_type["int"] then + local opcount = #inst.details + + if opcount ~= 1 then + perror("int takes 1 operand at line " .. hdr.line) + end + + if inst.details[1] ~= ASM_IMM8 then + perror("int requires an immediate 8 byte value") + end + + writeu8(dst, hexval("0hCD")) + + if inst.operands[1].type == tk_type["hexadecimal"] then + writeu8(dst, hexval(inst.operands[1].raw)) + elseif inst.operands[1].type == tk_type["integer"] then + writeu8(dst, intval(inst.operands[1].raw)) + end end end end blob - ae98f98922a5a8d6611cabb8da4d82c4cefa68c7 blob + fb968cda91cacb539c610a579f1f4f914ebc3164 --- tools/util.lua +++ tools/util.lua @@ -1,7 +1,7 @@ ----------------------------------------------------------------------- -- TOKEN MATCHING ----------------------------------------------------------------------- -local mnemonics = { "mov", "cli", "hlt", "ret", "sti" } +local mnemonics = { "mov", "cli", "hlt", "ret", "sti", "int" } -- This is kinda a double definition but fix later :^) local arithmetics = { "+", "-", "*", "/", "^", "~", "|", "&" } @@ -206,6 +206,9 @@ local function intval(intstr) for i = 1, len do local s = intstr:sub(len - i + 1, len - i + 1) + if s:match("[0-9]") == false then + return nil + end s = s * (10 ^ (i - 1)) res = res + s end @@ -253,3 +256,175 @@ function bitval(b) return result end + + +----------------------------------------------------------------------- +-- EXPRESSION SOLVING +----------------------------------------------------------------------- + +local function subarray(array, start, last) + if last == nil then + last = #array + end + + local sub = { } + + for i, v in ipairs(array) do + if i >= start and i <= last then + table.insert(sub, array[i]) + end + end + + return sub +end + +local function finddepth(array, spos) + local epos = nil + local depth = 1 + + for j = spos, #array do + if array[j] == "(" then depth = depth + 1 end + if array[j] == ")" then depth = depth - 1 end + + if depth == 0 then + epos = j + break + end + end + + if depth ~= 0 then + perror("invalid nesting") + end + + if epos == nil then perror("Mismatched paranthesis") end + + return epos +end + +-- Use this once the syntax validation is completed +local function evaluate_expression(array) + local i = 1 + local eval = { } + while i <= #array do + if array[i] == "(" then + local spos = i + local epos = finddepth(array, spos + 1) + + local sub = { } + for k = spos + 1, epos - 1 do + table.insert(sub, array[k]) + end + + local result = evaluate_expression(sub) + + for _, val in ipairs(result) do + table.insert(eval, val) + end + + i = epos + 1 + elseif array[i] == "*" then + local left = table.remove(eval) + local right = array[i + 1] + local epos = i + 2 + + if right == "(" then + local sub = subarray(array, i + 1) + right = evaluate_expression(sub)[1] + epos = finddepth(array, i + 2) + 1 + end + + if type(left) == "string" and type(right) == "string" then + if tonumber(left) ~= nil and tonumber(right) ~= nil then + table.insert(eval, tostring(tonumber(left) * tonumber(right))) + + elseif tonumber(left) == nil and tonumber(right) ~= nil then + table.insert(eval, { left, tonumber(right) }) + + elseif tonumber(left) ~= nil and tonumber(right) == nil then + table.insert(eval, { right, tonumber(left) }) + + end + elseif type(left) == "table" and type(right) == "string" then + if tonumber(right) ~= nil then + table.insert(eval, { left[1], left[2] * tonumber(right) }) + end + end + + i = epos + else + table.insert(eval, array[i]) + i = i + 1 + end + end + + local k = 1 + local total = 0 + local final = {} + + while k < #eval do + local cur = eval[k] + local opr = eval[k + 1] + local nxt = eval[k + 2] + + local n1 = tonumber(cur) + local n2 = tonumber(nxt) + + if n1 ~= nil then + total = n1 + total + k = k + 1 + elseif cur == "+" or cur == "-" then + if tonumber(opr) ~= nil then + if cur == "+" then + total = tonumber(opr) + total + elseif cur == "-" then + total = total - tonumber(opr) + end + + k = k + 2 + else + if type(opr) == "string" then + table.insert(final, {opr, 1}) + else + table.insert(final, opr) + end + k = k + 2 + end + + elseif type(cur) == "string" and n2 ~= nil then + table.insert(final, { cur, 1 }) + total = total + n2 + k = k + 3 + + elseif type(cur) == "table" and n2 ~= nil then + table.insert(final, cur) + if opr == "-" then + total = total - n2 + else + total = total + n2 + end + k = k + 3 + + elseif type(cur) == "table" and type(nxt) == "string" then + k = k + 3 + + elseif type(cur) == "string" and type(nxt) == "string" then + table.insert(final, { cur, 1 }) + table.insert(final, { nxt, 1 }) + k = k + 3 + + elseif type(cur) == "string" and type(nxt) == "table" then + table.insert(final, { cur, 1 }) + table.insert(final, nxt) + k = k + 3 + + else + k = k + 3 + end + end + + if total ~= 0 then + table.insert(final, tostring(total)) + end + + return final +end