Warning: this is an htmlized version!
The original is here, and the conversion rules are here. |
-- This file: -- http://angg.twu.net/LUA/Parenthesize1.lua.html -- http://angg.twu.net/LUA/Parenthesize1.lua -- (find-angg "LUA/Parenthesize1.lua") -- Author: Eduardo Ochs <eduardoochs@gmail.com> -- -- (defun e () (interactive) (find-angg "LUA/Parenthesize1.lua")) -- (find-angggrep "grep --color=auto -nH --null -e Parenthesize LUA/*.lua") -- (find-es "maxima" "operators") -- (find-angg "LUA/Arith6.lua" "Parenthesize") -- (find-angg "LUA/Arith6.lua" "defs_0") -- (find-es "maxima" "operators") -- «.Parenthesize» (to "Parenthesize") -- «.Parenthesize-tests» (to "Parenthesize-tests") -- «.tostrp» (to "tostrp") -- «.tostrp-tests» (to "tostrp-tests") -- «.Stack» (to "Stack") -- «.Stack-half-close-tests» (to "Stack-half-close-tests") -- «.Stack-reduce-tests» (to "Stack-reduce-tests") require "Show1" -- (find-angg "LUA/Show1.lua" "string.show") require "Tree1" -- (find-angg "LUA/Tree1.lua") require "GetInfo2" -- (find-angg "LUA/GetInfo2.lua") -- «Parenthesize» (to ".Parenthesize") Parenthesize = Class { type = "Parenthesize", new = function () return Parenthesize {ops={}} end, __tostring = function (pth) return mytostringv(pth.ops) end, __index = { addinfix = function (pth, lbp, rbp, names) for _,name in ipairs(split(names)) do pth.ops[name] = HTable {fixity="infix", name=name, lbp=lbp, rbp=rbp} end return pth end, addprefix = function (pth, bp, names) for _,name in ipairs(split(names)) do pth.ops[name] = HTable {fixity="prefix", name=name, bp=bp} end return pth end, addpostfix = function (pth, bp, names) for _,name in ipairs(split(names)) do pth.ops[name] = HTable {fixity="postfix", name=name, bp=bp} end return pth end, op = function (pth, o) return o[0] end, opp = function (pth, o) return pth.ops[o[0]] end, bp = function (pth, o) return pth:opp(o).bp end, lbp = function (pth, o) return pth:opp(o).lbp end, rbp = function (pth, o) return pth:opp(o).rbp end, fixity = function (pth, o) return pth:atomp(o) or pth:opp(o).fixity end, bps = function (pth, o) return pth:lbp(o)..":"..pth:rbp(o) end, infix = function (pth, o) return pth:fixity(o) == "infix" end, prefix = function (pth, o) return pth:fixity(o) == "prefix" end, postfix = function (pth, o) return pth:fixity(o) == "postfix" end, atomp = function (pth, o) return type(o) ~= "table" and "atom" end, -- fixity0 = function (pth, op) return pth.ops[op] and pth.ops[op].fixity end, infix0 = function (pth, op) return pth:fixity0(op) == "infix" end, prefix0 = function (pth, op) return pth:fixity0(op) == "prefix" end, postfix0 = function (pth, op) return pth:fixity0(op) == "postfix" end, -- paren = function (pth, o, i) local bp = function (o) return pth:bp(o) end local lbp = function (o) return pth:lbp(o) end local rbp = function (o) return pth:rbp(o) end local bps = function (o) return pth:bps(o) end local inf = function (o) return pth:infix(o) end local pre = function (o) return pth:prefix(o) end local post = function (o) return pth:postfix(o) end -- trivial cases: if inf(o) and i==1 and post(o[1]) then return false, "_!+_" end if inf(o) and i==2 and pre(o[2]) then return false, "_*-_" end if pre(o) and pre(o[1]) then return false, "--_" end if post(o) and post(o[1]) then return false, "_!!" end -- cases with parentheses: if inf(o) and i==1 and pre(o[1]) and bp(o[1]) < lbp(o) then return true, "(pre_)inf_" end if inf(o) and i==1 and inf(o[1]) and rbp(o[1]) < lbp(o) then return true, "(_inf_)inf_" end if inf(o) and i==2 and post(o[2]) and rbp(o) > bp(o[2]) then return true, "_inf(_post)" end if inf(o) and i==2 and inf(o[2]) and rbp(o) > lbp(o[2]) then return true, "_inf(_inf_)" end if pre(o) and post(o[1]) and bp(o) > bp(o[1]) then return true, "pre(_post)" end if pre(o) and inf(o[1]) and bp(o) > lbp(o[1]) then return true, "pre(_inf_)" end if post(o) and pre(o[1]) and bp(o[1]) < bp(o) then return true, "(pre_)post" end if post(o) and inf(o[1]) and rbp(o[1]) < bp(o) then return true, "(_inf_)post" end -- cases without parentheses: if inf(o) and i==1 and pre(o[1]) and bp(o[1]) >= lbp(o) then return false, ".pre_.inf_" end if inf(o) and i==1 and inf(o[1]) and rbp(o[1]) >= lbp(o) then return false, "._inf_.inf_" end if inf(o) and i==2 and post(o[2]) and rbp(o) <= bp(o[2]) then return false, "_inf._post." end if inf(o) and i==2 and inf(o[2]) and rbp(o) <= lbp(o[2]) then return false, "_inf._inf_." end if pre(o) and post(o[1]) and bp(o) <= bp(o[1]) then return false, "pre._post." end if pre(o) and inf(o[1]) and bp(o) <= lbp(o[1]) then return false, "pre._inf_." end if post(o) and pre(o[1]) and bp(o[1]) >= bp(o) then return false, ".pre_.post" end if post(o) and inf(o[1]) and rbp(o[1]) >= bp(o) then return false, "._inf_.post" end end, }, } pth = Parenthesize.new() pth:addinfix(10, 11, "+ -") pth:addinfix(30, 31, "* /") pth:addinfix(41, 40, "^") pth:addpostfix(50, "!") pth:addprefix (20, "u-") bin = function (a, op, b) return Tree {[0]=op, a, b} end add = function (a, b) return bin(a, "+", b) end minus = function (a, b) return bin(a, "-", b) end mul = function (a, b) return bin(a, "*", b) end div = function (a, b) return bin(a, "/", b) end pow = function (a, b) return bin(a, "^", b) end fact = function (a) return Tree {[0]="!", a} end uminus = function (a) return Tree {[0]="u-", a} end -- string.op = function (o) return pth.ops[o] end -- «Parenthesize-tests» (to ".Parenthesize-tests") --[==[ * (eepitch-lua51) * (eepitch-kill) * (eepitch-lua51) dofile "Parenthesize1.lua" test1 = function (er, o) print(trees(o, er, pth:paren(o, 1))) end test2 = function (er, o) print(trees(o, er, pth:paren(o, 2))) end test2(true, mul(1, add(2, 3))) test2(false, add(1, mul(2, 3))) test1(true, mul(add(1, 2), 3)) test1(false, add(mul(1, 2), 3)) test1(false, minus(minus(1, 2), minus(3, 4))) test2(true, minus(minus(1, 2), minus(3, 4))) test1(true, pow(pow(1, 2), pow(3, 4))) test2(false, pow(pow(1, 2), pow(3, 4))) test1(false, add(fact(1), fact(2))) test1(false, add(fact(1), fact(2))) test1(true, pow(uminus(1), uminus(2))) test2(false, pow(uminus(1), uminus(2))) --]==] -- «tostrp» (to ".tostrp") tostrp = function (o, addparens) if addparens then return "("..tostrp0(o)..")" end return tostrp0(o) end tostrp0 = function (o) local tsp = function (i, j) return tostrp(o[i], pth:paren(o,j)) end if pth:atomp(o) then return tostring(o) end if pth:prefix(o) then return format( "%s %s", o[0], tsp(1) ) end if pth:postfix(o) then return format("%s %s" , tsp(1), o[0] ) end if pth:infix(o) then return format("%s %s %s", tsp(1,1), o[0], tsp(2,2)) end error "Foo!" end -- «tostrp-tests» (to ".tostrp-tests") --[==[ * (eepitch-lua51) * (eepitch-kill) * (eepitch-lua51) dofile "Parenthesize1.lua" foo = minus(minus(1, 2), minus(3, 4)) foo = pow(pow(1, 2), pow(3, 4)) foo = uminus(1) = foo = tostrp(foo) --]==] -- «Stack» (to ".Stack") Stack = Class { type = "Stack", new = function () return Stack {} end, -- __tostring = function (s) return mapconcat(tostring, s, " ") end, __tostring = function (s) return tostring(trees(unpack(s))) end, __index = { push = function (s, o) table.insert(s, o); return s end, pushs = function (s, ...) for _,o in ipairs({...}) do s:push(o) end; return s end, -- check = function (s) assert(#s>0, s.msg or "Empty stack"); return s end, drop = function (s) s:check(); s[#s]=nil; return s end, dropn = function (s, n) for i=1,n do s:drop() end; return s end, dropuntil = function (s, n) while #s>n do s:drop() end; return s end, clear = function (s) return s:dropn(#s) end, -- pop = function (s) return s[#s], s:dropn(1) end, pop2 = function (s) return s[#s-1], s[#s], s:dropn(2) end, pop3 = function (s) return s[#s-2], s[#s-1], s[#s], s:dropn(3) end, pop4 = function (s) return s[#s-3], s[#s-2], s[#s-1], s[#s], s:dropn(4) end, -- pick = function (s, offset) return s[#s-offset] end, pock = function (s, offset, o) s[#s-offset] = o; return s end, -- pf1 = function (s, fmt) return s:push(format(fmt, s:pop())) end, pf2 = function (s, fmt) return s:push(format(fmt, s:pop2())) end, pf3 = function (s, fmt) return s:push(format(fmt, s:pop3())) end, -- -- 2022sep04 halfpre = function (s) local op = s:pop(); return s:push(pre(op,"?")) end, closepre = function (s) local a,b = s:pop2(); return s:push(pre(a[0],b)) end, halfbin = function (s) local a,op = s:pop2(); return s:push(bin(a,op,"?")) end, closebin = function (s) local a,b = s:pop2(); return s:push(bin(a[1], a[0], b)) end, closepost = function (s) local a,op = s:pop2(); return s:push(post(a,op)) end, -- reduce = function (s) if pth:prefix(s:pick(1)) then return s:closepre() end if pth:infix(s:pick(1)) then return s:closebin() end error("bad reduce") end, half = function (s) if pth:infix0(s:pick(0)) then return s:halfbin() end if pth:prefix0(s:pick(0)) then return s:halfpre() end error("bad half") end, pushh = function (s, op) s:push(op); return s:half() end, }, } pre = function (op, a) return Tree {[0]=op, a} end post = function (a, op) return Tree {[0]=op, a} end bin = function (a, op, b) return Tree {[0]=op, a, b} end -- «Stack-reduce-tests» (to ".Stack-reduce-tests") --[==[ * (eepitch-lua51) * (eepitch-kill) * (eepitch-lua51) dofile "Parenthesize1.lua" -- Ok: s = Stack.new() = s:push (2) = s:pushh("+") = s:push (3) = s:reduce(3) -- Ok: s = Stack.new() = s:pushh("u-") = s:push ("2") = s:reduce() = s:halfpre() = s:push("2") = s:reduce() = s:pick(1) = pth:prefix(s:pick(1)) = s:pick(1) = s:reduce() = s:closepre() run_my_repl_now() = s:reduce() stop_my_repl_now() * (eek "C-x r SPC a") = dg = dg[7] = dg[7]:vars() = dg[7]:names() = dg[7]:is() = dg[7].v = dg[7]:v "s" s = Stack.new() = s:push("3") = s:push("/") = s:halfbin() = s:push("4") = s:closebin() s = Stack.new() = s:push("5") = s:push("!") = s:closepost() = s:reduce() = s:push("!") = s:reduce() = s:push("+") = s:reduce() = s:push("b") = s:reduce() = s:push("/") = pth:infix(s:pick(0)) = s:reduce() run_my_repl_now() = s:reduce() stop_my_repl_now() * (eek "C-x r SPC a") = dg = dg[7] = dg[7]:vars() = dg[7]:vs() = s:halfbin() = s:push("b") = s:closebin() = s:push("+") = s:halfbin("+") = s:push("c") = s:push("!") = s:closepost() = s:closebin() = s:push("u-") = s:push("d") = s:closepre() = s:pick(0) = pth:prefix(s:pick(0)) a,op = s:pop2() = s:push(bin(a,op,"?")) = s:push("b") a,b = s:pop2() = s:push(bin(a[1], a[0], b)) r = math.random rr = function () local a = r(0,3) if a == 0 then return "o" end if a == 1 then return ":"..r(0,9) end if a == 2 then return r(0,9)..":" end if a == 3 then return r(0,9)..":"..r(0,9) end end rrs = function (n) local str = "" for i=1,n do str = str.." "..rr() end return str end rs = function (str) str = str or "+ - * / ^ u- ! o o" local spl = split(str) return spl[r(1,#spl)] end rss = function (n) local str = "" for i=1,n do str = str.." "..rs() end return str end s = Stack.new() = s:push("a") = s:push("/") a,op = s:pop2() = s:push(bin(a,op,"?")) = s:push("b") a,b = s:pop2() = s:push(bin(a[1], a[0], b)) = s:push("/") = rrs(20) = rss(20) o / o * o * o / o ! u- u- o / o / o ! o ^ - s = Stack.new() = s:push("o") = s:push("3:7") = s:pf2("(%s_%s") = s:push("o") = s:push("9:1") = s:pf2("(%s_%s") = s:push(":7") = s:push(":5") = s:push(":6") = s:push(":5") = s:push("o") = s:push("9:6") = s:pf2("(%s_%s") = s:push("o") = s:pf2("%s_%s)") = s:pf2("(%s_%s)") = s:pf2("(%s_%s)") = s:pf2("(%s_%s)") = s:pf2("(%s_%s)") = s:push("2:") = s:pf2("(%s_%s)") = s:pf2("%s_%s)") = s:push("0:") = s:pf2("(%s_%s)") = s:pf2("%s_%s)") = s:pf2("%s_%s)") = s:pf2("%s_%s)") = s:push("1:") = s:push("0:") = s:push("o") = s:pf2("(%s_%s)") = s:pf2("(%s_%s)") = s:pf2("(%s_%s)") = s:pf2("(%s_%s)") = s:pf2("(%s_%s") = s s:push(format("(%s %s", s:pop2())) = s o 3:7 o 9:1 :7 :5 :6 :5 o 9:6 o 2: 0: o 2:4 o 2:5 6:2 5: :9 :7 7: s = Stack.new() s:pushs("a", ">", "b", "<") = s = math.random(100) r = function () return math.random(10) end --]==] -- «Stack-half-close-tests» (to ".Stack-half-close-tests") --[==[ * (eepitch-lua51) * (eepitch-kill) * (eepitch-lua51) dofile "Parenthesize1.lua" s = Stack.new() = s:push("u-") = s:halfpre() = s:push("2") = s:closepre() s = Stack.new() = s:push("3") = s:push("/") = s:halfbin() = s:push("4") = s:closebin() s = Stack.new() = s:push("5") = s:push("!") = s:closepost() --]==] -- Local Variables: -- coding: utf-8-unix -- End: