diff options
Diffstat (limited to 'Master/texmf-dist/tex/context/base/x-calcmath.lua')
-rw-r--r-- | Master/texmf-dist/tex/context/base/x-calcmath.lua | 289 |
1 files changed, 159 insertions, 130 deletions
diff --git a/Master/texmf-dist/tex/context/base/x-calcmath.lua b/Master/texmf-dist/tex/context/base/x-calcmath.lua index fcb6b7470a6..e4d5da139f9 100644 --- a/Master/texmf-dist/tex/context/base/x-calcmath.lua +++ b/Master/texmf-dist/tex/context/base/x-calcmath.lua @@ -6,7 +6,8 @@ if not modules then modules = { } end modules ['x-calcmath'] = { license = "see context related readme files" } -local format, lower, upper, gsub = string.format, string.lower, string.upper, string.gsub +local format, lower, upper, gsub, sub = string.format, string.lower, string.upper, string.gsub, string.sub +local lpegmatch = lpeg.match tex = tex or { } @@ -71,8 +72,8 @@ local symbols = { } local function nsub(str,tag,pre,post) - return (str:gsub(tag .. "(%b())", function(body) - return pre .. nsub(body:sub(2,-2),tag,pre,post) .. post + return (gsub(str,tag .. "(%b())", function(body) + return pre .. nsub(sub(body,2,-2),tag,pre,post) .. post end)) end @@ -80,87 +81,87 @@ function calcmath.totex(str,mode) if not frozen then freeze() end local n = 0 -- crap - str = str:gsub("%s+" , ' ') + str = gsub(str,"%s+",' ') -- xml - str = str:gsub("&(.-);", entities) + str = gsub(str,"&(.-);",entities) -- ...E... - str = str:gsub("([%-%+]?[%d%.%+%-]+)E([%-%+]?[%d%.]+)", "{\\SCINOT{%1}{%2}}") + str = gsub(str,"([%-%+]?[%d%.%+%-]+)E([%-%+]?[%d%.]+)", "{\\SCINOT{%1}{%2}}") -- ^-.. - str = str:gsub( "%^([%-%+]*%d+)", "^{%1}") + str = gsub(str,"%^([%-%+]*%d+)", "^{%1}") -- ^(...) - str = nsub(str, "%^", "^{", "}") + str = nsub(str,"%^", "^{", "}") -- 1/x^2 repeat - str, n = str:gsub("([%d%w%.]+)/([%d%w%.]+%^{[%d%w%.]+})", "\\frac{%1}{%2}") + str, n = gsub(str,"([%d%w%.]+)/([%d%w%.]+%^{[%d%w%.]+})", "\\frac{%1}{%2}") until n == 0 -- todo: autoparenthesis -- int(a,b,c) for k, v in next, list_2_1 do - repeat str, n = str:gsub(k,v) until n == 0 + repeat str, n = gsub(str,k,v) until n == 0 end -- int(a,b) for k, v in next, list_2_2 do - repeat str, n = str:gsub(k, v) until n == 0 + repeat str, n = gsub(str,k,v) until n == 0 end -- int(a) for k, v in next, list_2_3 do - repeat str, n = str:gsub(k, v) until n == 0 + repeat str, n = gsub(str,k,v) until n == 0 end -- sin(x) => {\\sin(x)} for k, v in next, list_1_1 do - repeat str, n = str:gsub(k, v) until n == 0 + repeat str, n = gsub(str,k,v) until n == 0 end -- mean str = nsub(str, "mean", "\\OVERLINE{", "}") -- (1+x)/(1+x) => \\FRAC{1+x}{1+x} repeat - str, n = str:gsub("(%b())/(%b())", function(a,b) - return "\\FRAC{" .. a:sub(2,-2) .. "}{" .. b:sub(2,-2) .. "}" + str, n = gsub(str,"(%b())/(%b())", function(a,b) + return "\\FRAC{" .. sub(a,2,-2) .. "}{" .. sub(b,2,-2) .. "}" end ) until n == 0 -- (1+x)/x => \\FRAC{1+x}{x} repeat - str, n = str:gsub("(%b())/([%+%-]?[%.%d%w]+)", function(a,b) - return "\\FRAC{" .. a:sub(2,-2) .. "}{" .. b .. "}" + str, n = gsub(str,"(%b())/([%+%-]?[%.%d%w]+)", function(a,b) + return "\\FRAC{" .. sub(a,2,-2) .. "}{" .. b .. "}" end ) until n == 0 -- 1/(1+x) => \\FRAC{1}{1+x} repeat - str, n = str:gsub("([%.%d%w]+)/(%b())", function(a,b) - return "\\FRAC{" .. a .. "}{" .. b:sub(2,-2) .. "}" + str, n = gsub(str,"([%.%d%w]+)/(%b())", function(a,b) + return "\\FRAC{" .. a .. "}{" .. sub(b,2,-2) .. "}" end ) until n == 0 -- 1/x => \\FRAC{1}{x} repeat - str, n = str:gsub("([%.%d%w]+)/([%+%-]?[%.%d%w]+)", "\\FRAC{%1}{%2}") + str, n = gsub(str,"([%.%d%w]+)/([%+%-]?[%.%d%w]+)", "\\FRAC{%1}{%2}") until n == 0 -- times - str = str:gsub("%*", " ") + str = gsub(str,"%*", " ") -- symbols -- we can use a table substitution here - str = str:gsub("([<>=][<>=]*)", symbols) + str = gsub(str,"([<>=][<>=]*)", symbols) -- functions - str = nsub(str, "sqrt", "\\SQRT{", "}") - str = nsub(str, "exp", "e^{", "}") - str = nsub(str, "abs", "\\left|", "\\right|") + str = nsub(str,"sqrt", "\\SQRT{", "}") + str = nsub(str,"exp", "e^{", "}") + str = nsub(str,"abs", "\\left|", "\\right|") -- d/D - str = nsub(str, "D", "{\\FRAC{\\MBOX{d}}{\\MBOX{d}x}{(", ")}}") - str = str:gsub("D([xy])", "\\FRAC{{\\RM d}%1}{{\\RM d}x}") + str = nsub(str,"D", "{\\FRAC{\\MBOX{d}}{\\MBOX{d}x}{(", ")}}") + str = gsub(str,"D([xy])", "\\FRAC{{\\RM d}%1}{{\\RM d}x}") -- f/g for k,v in next, list_3 do -- todo : prepare k,v - str = nsub(str, "D"..v,"{\\RM "..v.."}^{\\PRIME}(",")") - str = nsub(str, v,"{\\RM "..v.."}(",")") + str = nsub(str,"D"..v,"{\\RM "..v.."}^{\\PRIME}(",")") + str = nsub(str,v,"{\\RM "..v.."}(",")") end -- more symbols for k,v in next, list_4_1 do - str = str:gsub(k, v) + str = gsub(str,k,v) end -- parenthesis (optional) if mode == 2 then - str = str:gsub("%(", "\\left\(") - str = str:gsub("%)", "\\right\)") + str = gsub(str,"%(", "\\left\(") + str = gsub(str,"%)", "\\right\)") end -- csnames - str = str:gsub("(\\[A-Z]+)", lower) + str = gsub(str,"(\\[A-Z]+)", lower) -- trace --~ print(str) -- report @@ -191,19 +192,20 @@ if false then -- Df Dg {\rm f}^{\prime} -- f() g() {\rm f}() + -- valid utf8 local S, P, R, C, V, Cc, Ct = lpeg.S, lpeg.P, lpeg.R, lpeg.C, lpeg.V, lpeg.Cc, lpeg.Ct local space = S(" \n\r\t")^0 - local number_x = P("-")^-1 * R("09")^1 - local real_x = P("-")^-1 * R("09")^1 * S(".")^1 * R("09")^1 - local number = Cc("number") * C(number_x) * space - local real = Cc("real") * C(real_x) * space - local float = Cc("float") * C(real_x) * lpeg.P("E") * lpeg.C(number_x) * space - local identifier = Cc("identifier") * C(R("az","AZ")^1) * space - local compareop = P("<") + P("=") + P(">") + P(">=") + P("<=") + P(">") + P("<") - local factorop = Cc("factor") * C(S("+-^,") + compareop ) * space + local integer = P("-")^-1 * R("09")^1 + local realpart = P("-")^-1 * R("09")^1 * S(".")^1 * R("09")^1 + local number = Cc("number") * C(integer) * space + local real = Cc("real") * C(realpart) * space + local float = Cc("float") * C(realpart) * lpeg.P("E") * lpeg.C(integer) * space + local identifier = Cc("identifier") * C(R("az","AZ")) * space + local compareop = Cc("compare") * C(P("<") + P("=") + P(">") + P(">=") + P("<=") + P(">") + P("<")) * space + local factorop = Cc("factor") * C(S("+-^_,")) * space local termop = Cc("term") * C(S("*/")) * space local constant = Cc("constant") * C(P("pi") + lpeg.P("inf")) * space local functionop = Cc("function") * C(R("az")^1) * space @@ -212,123 +214,150 @@ if false then local grammar = P { "expression", - expression = Ct(V("factor" ) * (factorop * V("factor" ))^0), - factor = Ct(V("term" ) * (termop * V("term" ))^0), + expression = Ct(V("factor") * ((factorop+compareop) * V("factor"))^0), + factor = Ct(V("term") * (termop * V("term"))^0), term = Ct( float + real + number + (open * V("expression") * close) + - (functionop * open * V("expression") * close) + + (functionop * open * (V("expression") * (P(",") * V("expression"))^0) * close) + + (functionop * V("term")) + constant + identifier ), } + local parser = space * grammar * -1 + local texprint = function(...) texio.write(table.concat{ ... }) end + + local function has_factor(t) + for i=1,#t do + if t[i] == "factor" then + return true + end + end + end + function totex(t) if t then - local one, two, three = t[1], t[2], t[3] - if one == "number" then - return two - elseif one == "real" then - return two - elseif one == "float" then - return format("\\scinot{%s}{%s}", two, three) - elseif one == "identifier" then - return format(" %s ", two) - elseif one == "constant" then - return format("\\%s ", two) - elseif one == "function" then - if two == "sqrt" then - return format("\\sqrt{%s}", totex(three)) - elseif two == "exp" then - return format(" e^{%s}", totex(three)) - elseif two == "abs" then - return format("\\left|%s\\right|", totex(three)) - elseif two == "mean" then - return format("\\overline{%s}", totex(three)) - elseif two == "int" or two == "prod" or two == "sum" then --brrr, we need to parse better for ,, - local tt = three - if #tt == 1 then - return format("\\%s{%s}", two ,totex(tt[1])) - elseif #tt == 4 then - return format("\\%s^{%s}{%s}", two ,totex(tt[1]), totex(tt[4])) - elseif #tt == 7 then - return format("\\%s^{%s}_{%s}{%s}", two ,totex(tt[1]), totex(tt[4]), totex(tt[7])) - end - elseif #two == 1 then - return format("%s(%s)", two, totex(three)) - else - return format("\\%s(%s)", two, totex(three)) - end - elseif one == "factor" then - if two == '^' then - return format("^{%s}%s",totex(three), (#t>3 and totex({unpack(t,4,#t)})) or "") - else - if two == ">=" then - two = "\\ge " - elseif two == "<=" then - two = "\\le " - elseif two == ">" then - two = "> " - elseif two == "<" then - two = "< " - end - return format("%s%s%s", two, totex(three), (#t>3 and totex({unpack(t,4,#t)})) or "") - end - elseif one == "term" then - if two == '/' then - if #t > 4 then - return format("\\frac{%s}{%s}", totex(three), totex({unpack(t,4,#t)})) + local one = t[1] + if type(one) == "string" then + local two, three = t[2], t[3] + if one == "number" then + texprint(two) + elseif one == "real" then + texprint(two) + elseif one == "float" then + texprint("\\scinot{",two,"}{",three,"}") + elseif one == "identifier" then + texprint(two) + elseif one == "constant" then + texprint("\\"..two) + elseif one == "function" then + if two == "sqrt" then + texprint("\\sqrt{") + totex(three) + texprint("}") + elseif two == "exp" then + texprint(" e^{") + totex(three) + texprint("}") + elseif two == "abs" then + texprint("\\left|") + totex(three) + texprint("\\right|") + elseif two == "mean" then + texprint("\\overline{") + totex(three) + texprint("}") + elseif two == "int" or two == "prod" or two == "sum" then + local four, five = t[4], t[5] + if five then + texprint("\\"..two.."^{") + totex(three) + texprint("}_{") + totex(four) + texprint("}") + totex(five) + elseif four then + texprint("\\"..two.."^{") + totex(three) + texprint("}") + totex(four) + elseif three then + texprint("\\"..two.." ") -- " " not needed + totex(three) + else + texprint("\\"..two) + end else - return format("\\frac{%s}{%s}", totex(three), totex(t[4])) + texprint("\\"..two.."(") + totex(three) + texprint(")") end - elseif two == '*' then - local times = "\\times " - return format("%s%s%s", times, totex(three), (#t>3 and totex({unpack(t,4,#t)})) or "") - else - return format("%s%s%s", two, totex(three), (#t>3 and totex({unpack(t,4,#t)})) or "") end - elseif two == "factor" then - if three == '^' then - return format("%s^{%s}", totex(one), totex(t[4])) - else - if two == ">=" then - two = "\\ge " - elseif two == "<=" then - two = "\\le " - elseif two == ">" then - two = "> " - elseif two == "<" then - two = "< " + else + local nt = #t + local hasfactor = has_factor(t) + if hasfactor then + texprint("\\left(") + end + totex(one) + for i=2,nt,3 do + local what, how, rest = t[i], t[i+1], t[i+2] + if what == "factor" then + if how == '^' or how == "_" then + texprint(how) + texprint("{") + totex(rest) + texprint("}") + else + texprint(how) + totex(rest) + end + elseif what == "term" then + if how == '/' then + texprint("\\frac{") + totex(rest) + texprint("}{") + totex(t[i+3] or "") + texprint("}") + elseif how == '*' then + texprint("\\times") + totex(rest) + else + texprint(how) + totex(three) + end + elseif what == "compare" then + if two == ">=" then + texprint("\\ge") + elseif two == "<=" then + texprint("\\le") + elseif two == ">" then + texprint(">") + elseif two == "<" then + texprint("<") + end + totex(three) end - return format("%s%s", totex(one), (#t>1 and totex({unpack(t,2,#t)})) or "") end - elseif two == "term" then - if three == '/' then - return format("\\frac{%s}{%s}", totex(one), (#t>3 and totex({unpack(t,4,#t)})) or "") - else - return format("%s%s", totex(one), (#t>1 and totex({unpack(t,2,#t)})) or "") + if hasfactor then + texprint("\\right)") end - else - return totex(one) end end - return "" end calcmath = { } function calcmath.parse(str) - return parser:match(str) + return lpegmatch(parser,str) end function calcmath.tex(str) - str = totex(parser:match(str)) - print(str) + str = totex(lpegmatch(parser,str)) return (str == "" and "[error]") or str end end - ---~ compareop = Cc("compare") * C(P("<") + P("=") + P(">") + P(">=") + P("<=") + P(">")/">" + P("<")/"<") * space ---~ comparison = Ct(V("expression") * (compareop * V("expression"))^0), |