1if not modules then modules = { } end modules ['x-calcmath'] = {
2 version = 1.001,
3 comment = "companion to x-calcmath.mkiv",
4 author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
5 copyright = "PRAGMA ADE / ConTeXt Development Team",
6 license = "see context related readme files"
7}
8
9
10
11local next, type = next, type
12local format, lower, upper, gsub, sub = string.format, string.lower, string.upper, string.gsub, string.sub
13local concat = table.concat
14local lpegmatch = lpeg.match
15
16local calcmath = { }
17local moduledata = moduledata or { }
18moduledata.calcmath = calcmath
19
20local context = context
21
22local list_1 = {
23 "median", "min", "max", "round", "ln", "log",
24 "sin", "cos", "tan", "sinh", "cosh", "tanh"
25}
26local list_2 = {
27 "int", "sum", "prod"
28}
29local list_3 = {
30 "f", "g"
31}
32local list_4 = {
33 "pi", "inf"
34}
35
36local list_1_1 = { }
37local list_2_1 = { }
38local list_2_2 = { }
39local list_2_3 = { }
40local list_4_1 = { }
41
42local frozen = false
43
44local function freeze()
45 for k=1,#list_1 do
46 local v = list_1[k]
47 list_1_1[v] = "\\".. upper(v) .." "
48 end
49 for k=1,#list_2 do
50 local v = list_2[k]
51 list_2_1[v .. "%((.-),(.-),(.-)%)"] = "\\" .. upper(v) .. "^{%1}_{%2}{%3}"
52 list_2_2[v .. "%((.-),(.-)%)"] = "\\" .. upper(v) .. "^{%1}{%2}"
53 list_2_3[v .. "%((.-)%)"] = "\\" .. upper(v) .. "{%1}"
54 end
55 for k=1,#list_4 do
56 local v = list_4[k]
57 list_4_1[v] = "\\" .. upper(v)
58 end
59 frozen = true
60end
61
62local entities = {
63 ['gt'] = '>',
64 ['lt'] = '<',
65}
66
67local symbols = {
68 ["<="] = "\\LE ",
69 [">="] = "\\GE ",
70 ["=<"] = "\\LE ",
71 ["=>"] = "\\GE ",
72 ["=="] = "\\EQ ",
73 ["<" ] = "\\LT ",
74 [">" ] = "\\GT ",
75 ["="] = "\\EQ ",
76}
77
78local function nsub(str,tag,pre,post)
79 return (gsub(str,tag .. "(%b())", function(body)
80 return pre .. nsub(sub(body,2,-2),tag,pre,post) .. post
81 end))
82end
83
84local function totex(str,mode)
85 if not frozen then freeze() end
86 local n = 0
87
88 str = gsub(str,"%s+",' ')
89
90 str = gsub(str,"&(.-);",entities)
91
92 str = gsub(str,"([%-%+]?[%d%.%+%-]+)E([%-%+]?[%d%.]+)", "{\\SCINOT{%1}{%2}}")
93
94 str = gsub(str,"%^([%-%+]*%d+)", "^{%1}")
95
96 str = nsub(str,"%^", "^{", "}")
97
98 repeat
99 str, n = gsub(str,"([%d%w%.]+)/([%d%w%.]+%^{[%d%w%.]+})", "\\frac{%1}{%2}")
100 until n == 0
101
102
103 for k, v in next, list_2_1 do
104 repeat str, n = gsub(str,k,v) until n == 0
105 end
106
107 for k, v in next, list_2_2 do
108 repeat str, n = gsub(str,k,v) until n == 0
109 end
110
111 for k, v in next, list_2_3 do
112 repeat str, n = gsub(str,k,v) until n == 0
113 end
114
115 for k, v in next, list_1_1 do
116 repeat str, n = gsub(str,k,v) until n == 0
117 end
118
119 str = nsub(str, "mean", "\\OVERLINE{", "}")
120
121 repeat
122 str, n = gsub(str,"(%b())/(%b())", function(a,b)
123 return "\\FRAC{" .. sub(a,2,-2) .. "}{" .. sub(b,2,-2) .. "}"
124 end )
125 until n == 0
126
127 repeat
128 str, n = gsub(str,"(%b())/([%+%-]?[%.%d%w]+)", function(a,b)
129 return "\\FRAC{" .. sub(a,2,-2) .. "}{" .. b .. "}"
130 end )
131 until n == 0
132
133 repeat
134 str, n = gsub(str,"([%.%d%w]+)/(%b())", function(a,b)
135 return "\\FRAC{" .. a .. "}{" .. sub(b,2,-2) .. "}"
136 end )
137 until n == 0
138
139 repeat
140 str, n = gsub(str,"([%.%d%w]+)/([%+%-]?[%.%d%w]+)", "\\FRAC{%1}{%2}")
141 until n == 0
142
143 str = gsub(str,"%*", " ")
144
145 str = gsub(str,"([<>=][<>=]*)", symbols)
146
147 str = nsub(str,"sqrt", "\\SQRT{", "}")
148 str = nsub(str,"exp", "e^{", "}")
149 str = nsub(str,"abs", "\\left|", "\\right|")
150
151 str = nsub(str,"D", "{\\FRAC{\\MBOX{d}}{\\MBOX{d}x}{(", ")}}")
152 str = gsub(str,"D([xy])", "\\FRAC{{\\RM d}%1}{{\\RM d}x}")
153
154 for k,v in next, list_3 do
155 str = nsub(str,"D"..v,"{\\RM "..v.."}^{\\PRIME}(",")")
156 str = nsub(str,v,"{\\RM "..v.."}(",")")
157 end
158
159 for k,v in next, list_4_1 do
160 str = gsub(str,k,v)
161 end
162
163 if mode == 2 then
164 str = gsub(str,"%(", "\\left(")
165 str = gsub(str,"%)", "\\right)")
166 end
167
168 str = gsub(str,"(\\[A-Z]+)", lower)
169
170 return str
171end
172
173calcmath.totex = totex
174
175function calcmath.tex(str,mode)
176 context(totex(str))
177end
178
179function calcmath.xml(id,mode)
180 context(totex(lxml.id(id).dt[1],mode))
181end
182
183
184
185if false then
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200 local S, P, R, C, V, Cc, Ct = lpeg.S, lpeg.P, lpeg.R, lpeg.C, lpeg.V, lpeg.Cc, lpeg.Ct
201
202 local space = S(" \n\r\t")^0
203 local integer = P("-")^-1 * R("09")^1
204 local realpart = P("-")^-1 * R("09")^1 * S(".")^1 * R("09")^1
205 local number = Cc("number") * C(integer) * space
206 local real = Cc("real") * C(realpart) * space
207 local float = Cc("float") * C(realpart) * lpeg.P("E") * lpeg.C(integer) * space
208 local identifier = Cc("identifier") * C(R("az","AZ")) * space
209 local compareop = Cc("compare") * C(P("<") + P("=") + P(">") + P(">=") + P("<=") + P(">") + P("<")) * space
210 local factorop = Cc("factor") * C(S("+-^_,")) * space
211 local termop = Cc("term") * C(S("*/")) * space
212 local constant = Cc("constant") * C(P("pi") + lpeg.P("inf")) * space
213 local functionop = Cc("function") * C(R("az")^1) * space
214 local open = P("(") * space
215 local close = P(")") * space
216
217 local grammar = P {
218 "expression",
219 expression = Ct(V("factor") * ((factorop+compareop) * V("factor"))^0),
220 factor = Ct(V("term") * (termop * V("term"))^0),
221 term = Ct(
222 float + real + number +
223 (open * V("expression") * close) +
224 (functionop * open * (V("expression") * (P(",") * V("expression"))^0) * close) +
225 (functionop * V("term")) +
226 constant + identifier
227 ),
228 }
229
230 local parser = space * grammar * -1
231
232 local function has_factor(t)
233 for i=1,#t do
234 if t[i] == "factor" then
235 return true
236 end
237 end
238 end
239
240
241
242 function totex(t)
243 if t then
244 local one = t[1]
245 if type(one) == "string" then
246 local two, three = t[2], t[3]
247 if one == "number" then
248 context(two)
249 elseif one == "real" then
250 context(two)
251 elseif one == "float" then
252 context("\\scinot{",two,"}{",three,"}")
253 elseif one == "identifier" then
254 context(two)
255 elseif one == "constant" then
256 context("\\"..two)
257 elseif one == "function" then
258 if two == "sqrt" then
259 context("\\sqrt{")
260 totex(three)
261 context("}")
262 elseif two == "exp" then
263 context(" e^{")
264 totex(three)
265 context("}")
266 elseif two == "abs" then
267 context("\\left|")
268 totex(three)
269 context("\\right|")
270 elseif two == "mean" then
271 context("\\overline{")
272 totex(three)
273 context("}")
274 elseif two == "int" or two == "prod" or two == "sum" then
275 local four, five = t[4], t[5]
276 if five then
277 context("\\"..two.."^{")
278 totex(three)
279 context("}_{")
280 totex(four)
281 context("}")
282 totex(five)
283 elseif four then
284 context("\\"..two.."^{")
285 totex(three)
286 context("}")
287 totex(four)
288 elseif three then
289 context("\\"..two.." ")
290 totex(three)
291 else
292 context("\\"..two)
293 end
294 else
295 context("\\"..two.."(")
296 totex(three)
297 context(")")
298 end
299 end
300 else
301 local nt = #t
302 local hasfactor = has_factor(t)
303 if hasfactor then
304 context("\\left(")
305 end
306 totex(one)
307 for i=2,nt,3 do
308 local what, how, rest = t[i], t[i+1], t[i+2]
309 if what == "factor" then
310 if how == '^' or how == "_" then
311 context(how)
312 context("{")
313 totex(rest)
314 context("}")
315 else
316 context(how)
317 totex(rest)
318 end
319 elseif what == "term" then
320 if how == '/' then
321 context("\\frac{")
322 totex(rest)
323 context("}{")
324 totex(t[i+3] or "")
325 context("}")
326 elseif how == '*' then
327 context("\\times")
328 totex(rest)
329 else
330 context(how)
331 totex(three)
332 end
333 elseif what == "compare" then
334 if two == ">=" then
335 context("\\ge")
336 elseif two == "<=" then
337 context("\\le")
338 elseif two == ">" then
339 context(">")
340 elseif two == "<" then
341 context("<")
342 end
343 totex(three)
344 end
345 end
346 if hasfactor then
347 context("\\right)")
348 end
349 end
350 end
351 end
352
353 calcmath = { }
354
355 function calcmath.parse(str)
356 return lpegmatch(parser,str)
357 end
358
359 function calcmath.tex(str)
360 str = totex(lpegmatch(parser,str))
361 return (str == "" and "[error]") or str
362 end
363
364end
365 |