1%D \module 2%D [ file=x-asciimath, 3%D version=2014.06.01, % 2006.04.24, % 1999.11.06, 4%D title=\CONTEXT\ Modules, 5%D subtitle=AsciiMath, 6%D author=Hans Hagen, 7%D date=\currentdate, 8%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}] 9%C 10%C This module is part of the \CONTEXT\ macro||package and is 11%C therefore copyrighted by \PRAGMA. See mreadme.pdf for 12%C details. 13 14\registerctxluafile{x-asciimath}{autosuffix} 15 16%D When the Math4All project started, we immediately started using content \MATHML. 17%D Because in school math there is often a reference to calculator input, we also 18%D provided what we called \quote {calcmath}: a predictable expression based way 19%D entering math. At some point \OPENMATH\ was also used but that was later 20%D abandoned because editing is more cumbersome. 21%D 22%D Due to limitations in the web variant (which is independent of rendering for 23%D paper but often determines the coding of document, not seldom for the worse) the 24%D switch was made to presentational \MATHML. But even that proved to be too complex 25%D for rendering on the web, so it got converted to so called \ASCIIMATH\ which 26%D can be rendered using some \JAVASCRIPT\ magic. However, all the formulas (and 27%D we're talking of tens of thousands of them) were very precisely coded by the main 28%D author. Because in intermediate stages of the editing (by additional authors) a 29%D mixture of \MATHML\ and \ASCIIMATH\ was used, we wrote the first version of this 30%D module. As reference we took \url 31%D {http://www1.chapman.edu/~jipsen/mathml/asciimath.html} and. The idea was to 32%D stick to \MATHML\ as reference and if needed use \ASCIIMATH\ as annotation. 33%D 34%D Eventually we ended up with supporting several math encodings in \CONTEXT\ that 35%D could be used mixed: content \MATHML\ (preferred), presentation \MATHML\ (often 36%D messy), \OPENMATH\ (somewhat minimalistic) calcmath (handy for students who are 37%D accustomed to calculators), \ASCIIMATH\ (to make web support easier) and of 38%D course \TEX. 39%D 40%D The first version had some limitations as we didn't want to support all quirks of 41%D \ASCIIMATH\ and also because I was not really in the mood to write a complex parser 42%D when a bit of sane coding can work equally well. Some comments from that version: 43%D 44%D \startnarrower 45%D \startitemize 46%D \item We support only the syntactically clear variants and as long as lpeg does 47%D not support left recursion this is as far as we want to go. 48%D \item The parser is rather insensitive for spaces but yet the advice is to avoid 49%D weird coding like \type {d/dxf(x)} but use \type {d/dx f(x)} instead. After 50%D all we're not in a compact coding cq.\ parser challenge. 51%D \item We also don't support the somewhat confusing \type {sqrt sqrt 2} nor \type 52%D {root3x} (although the second one kind of works). A bit of defensive coding 53%D does not hurt. 54%D \item We can process \type {a/b/c/d} but it's not compatible with the default 55%D behaviour of \ASCIIMATH. Use grouping instead. Yes, we do support the somewhat 56%D nonstandard grouping token mix. 57%D \item You should use explicit \type {text(..)} directives as one can never be sure 58%D what is a reserved word and not. 59%D \stopitemize 60%D 61%D Actually, as the only parsing sensitive elements of \TEX\ are fractions (\type {\over} 62%D and friends, a restricted use of \TEX\ coding is probably as comprehensive and 63%D parsable. The webpage with examples served as starting point so anything beyond 64%D what can be found there isn't supported. 65%D \stopnarrower 66%D 67%D Then in 2014 something bad happened. Following the fashion of minimal encoding 68%D (which of course means messy encoding of complex cases and which can make authors 69%D sloppy too) the web based support workflow of the mentioned project ran into some 70%D limitations and magically one day all carefully coded \MATHML\ was converted into 71%D \ASCIIMATH. As there was no way to recover the original thousands of files and 72%D tens of thousands of formulas we were suddenly stuck with \ASCIIMATH. Because the 73%D conversion had be done automagically, we also saw numerous errors and were forced 74%D to come up with some methods to check formulas. Because \MATHML\ poses some 75%D restrictions it has predictable rendering; \ASCIIMATH\ on the other hand enforces 76%D no structure. Also, because \MATHML\ has to be valid \XML\ it always processes. 77%D Of course, during the decade that the project had run we also had to built in 78%D some catches for abuse but at least we had a relatively stable and configurable 79%D subsystem. So, in order to deal with less predictable cases as well as extensive 80%D checking, a new \ASCIIMATH\ parser was written, one that could also be used to 81%D trace bad coding. 82%D 83%D Because the formal description is incomplete, and because some links to resources 84%D are broken, and because some testing on the web showed that sequences of characters 85%D are interpreted that were not mentioned anywhere (visible), and because we noticed 86%D that the parser was dangerously tolerant, the new code is quite different from the 87%D old code. 88%D 89%D One need to keep in mind that because spaces are optional, the only robust way to 90%D edit \ASCIIMATH\ is to use a \WYSIWYG\ editor and hope that the parser doesn't 91%D change ever. Keys are picked up from spaceless sequences and when not recognized 92%D a (sequence) of characters is considered to be variables. So, \type {xsqrtx} is 93%D valid and renders as \type {$x\sqrt{x}$}, \type {xx} becomes \type {×} (times) 94%D but \type {ac} becomes \type {$a c$} (a times c). We're lucky that \type {AC} is 95%D not turned into Alternating Current, but who knows what happens a few years from 96%D now. So, we do support this spaceless mess, but users are warned: best use a 97%D spacy sequence. The extra amount of spaces (at one byte each) an author has to 98%D include in his|/|her active writing time probably stays below the size of one 99%D holiday picture. Another complication is that numbers (in Dutch) use commas instead 100%D of periods, but vectors use commas as well. We also hav esome different names for 101%D functions which then can conflict with the expectations about collapsed variables. 102%D 103%D It must be noted that simplified encodings (that seem to be the fashion today) 104%D can demand from applications to apply fuzzy logic to make something work out 105%D well. Because we have sequential data that gets rendered, sometimes wrong input 106%D gets obscured simply by the rendering: like the comma's in numbers as well as 107%D for separators (depending on space usage), or plain wrong symbols that somehow 108%D get a representation anyway. This in itself is more a side effect of trying to 109%D use the simplified encoding without applying rules (in the input) or to use it 110%D beyong its intended usage, which then of course can lead to adapted parsers and 111%D catches that themselves trigger further abuse. Imagine that instead of developing 112%D new cars, planes, space ships, mobile phones, computers we would have adapted 113%D horse cars, kites, firework, old fashioned phones and mechanical calculators in a 114%D similar way: patch upon patch of traditional means for sure would not have 115%D worked. So, when you use \ASCIIMATH\ best check immediately how it gets rendered 116%D in the browser as well as on paper. And be prepared to check the more complex 117%D code in the future again. We don't offer any guarantees but of course will try to 118%D keep up. 119%D 120%D In retrospect I sometimes wonder if the energy put into constantly adapting to 121%D the fashion of the day pays off. Probably not. It definitely doesn't pay of. 122%D 123%D More complex crap: 124%D 125%D 1: $x + \stackrel{comment}{\stackrel{\utfchar{"23DE}}{yyyyyyyy}} = y$ \blank 126%D 2: \asciimath{x + stackrel{\utfchar{"23DE}}{yyyyyyyy} = y} \blank 127%D 3: \asciimath{x + stackrel{yyyyyyyy}{\utfchar{"23DE}} = y} \blank 128%D 4: \asciimath{x + stackrel{"comment"}{stackrel{\utfchar{"23DE}}{yyyyyyyy}} = y} \blank 129 130\usemodule[mathml-basics] 131 132\startmodule[asciimath] 133 134\unprotect 135 136\writestatus{asciimath}{beware, this is an experimental (m4all only) module} 137 138%D Hacks: 139 140\permanent\protected\def\asciimathoptext #1{\ifmmode\mathoptext{#1}\else#1\fi} 141\permanent\protected\def\asciimathoptexttraced #1{\ifmmode\mathoptext{\color[darkgreen]{#1}}\else\color[darkgreen]{#1}\fi} 142\permanent\protected\def\asciimathstackrel #1#2{\mathematics{\mathop{\math_relax_limits\mover{#2}{#1}}}} 143\permanent\protected\def\asciimathroot #1#2{\sqrt[#1]{#2}} 144\permanent\protected\def\asciimathsqrt #1{\sqrt{#1}} 145 146%D The core commands: 147 148\installsetuponlycommandhandler {asciimath} {asciimath} 149 150\appendtoks 151 moduledata.asciimath.setup { 152 splitmethod = "\asciimathparameter\c!splitmethod", 153 separator = "\asciimathparameter\c!separator", 154 symbol = "\asciimathparameter\c!symbol", 155 }% 156\to \everysetupasciimath 157 158\newtoks\everyasciimath 159 160% \appendtoks 161% \ignorediscretionaries % yes or no 162% \to \everyasciimath 163 164% \appendtoks 165% \enableautofences 166% \enableautofencemode 167% \to \everyasciimath 168 169\permanent\tolerant\protected\def\asciimath[#1]#:#2% 170 {\mathematics 171 [#1]% 172 {\expand\everyasciimath 173 {\detokenize\expandafter{\normalexpanded{#2}}}}} 174 175\permanent\tolerant\protected\def[#1]#:#2% 176 {\mathematics 177 [#1]% 178 {\expand\everyasciimath 179 {#2}}} 180 181\permanent\protected\def\ctxmoduleasciimath#1% 182 {moduledata.asciimath.#1} 183 184%D Some tracing commands. Using tex commands is 10\% slower that directly piping 185%D from \LUA, but this is non|-|critical code. 186 187\permanent\protected\def\ShowAsciiMathLoad [#1]{moduledata.asciimath.show.load("#1")} 188\permanent\protected\def\ShowAsciiMathIgnore[#1]{moduledata.asciimath.show.ignore("#1")} 189\permanent\protected\def\ShowAsciiMathXML #1#2{moduledata.asciimath.show.filter("#1","#2")} 190\permanent\protected\def\ShowAsciiMathStats {moduledata.asciimath.show.statistics()} 191\permanent\protected\def\ShowAsciiMathMax {moduledata.asciimath.show.max()} 192 193\permanent\protected\def\ShowAsciiMathResult#1% 194 {\begingroup 195 \blank 196 % if we are in vmode, we don't get positions i.e. a smaller tuc file 197 \inleft{\ttbf#1\hfillmoduledata.asciimath.show.count(#1,true)}% 198 \dontleavehmode 199 \begingroup 200 \ttbf 201 moduledata.asciimath.show.files(#1) 202 \endgroup 203 \blank[\v!medium,\v!samepage] 204 \startcolor[darkblue] 205 moduledata.asciimath.show.input(#1,true) 206 \stopcolor 207 \blank[medium,samepage] 208 \doifmode{asciimath:show:dirty} { 209 \dorecurse{moduledata.asciimath.show.nofdirty(#1)} { 210 moduledata.asciimath.show.dirty(\recurselevel,true) 211 \blank[\v!medium,\v!samepage] 212 } 213 } 214 moduledata.asciimath.show.result(#1) 215 \blank 216 \endgroup} 217 218\permanent\protected\def\ShowAsciiMathStart 219 {\begingroup 220 \let\asciimathoptext\asciimathoptexttraced 221 \setuptyping[\v!buffer][\c!before=,\c!after=] 222 \setupmargindata[\v!left][\c!style=]} 223 224\permanent\protected\def\ShowAsciiMathStop 225 {\endgroup} 226 227\permanent\tolerant\protected\def\ShowAsciiMath[#1]#*[#2]% 228 {\ifparameter#1\or 229 \ShowAsciiMathStart 230 \ShowAsciiMathLoad[#1] 231 \ifparameter#2\or 232 \ShowAsciiMathIgnore[#2] 233 \fi 234 \dorecurse{\ShowAsciiMathMax}{\ShowAsciiMathResult\recurselevel} 235 \page 236 \ShowAsciiMathStats 237 \ShowAsciiMathStop 238 \fi} 239 240\permanent\protected\def\xmlShowAsciiMath#1#2% 241 {\ifparameter#1\or 242 \ShowAsciiMathStart 243 \ShowAsciiMathXML{#1}{#2}% 244 \dorecurse{\ShowAsciiMathMax}{\ShowAsciiMathResult\recurselevel} 245 \page 246 \ShowAsciiMathStats 247 \ShowAsciiMathStop 248 \fi} 249 250\permanent\tolerant\protected\def\ShowAsciiMathSave[#1]% 251 {moduledata.asciimath.show.save("#1")} 252 253% extras: 254 255% if not then we need an extra class 256 257% \inherited\setmathspacing \mathclosecode \mathmiddlecode \alldisplaystyles \thickmuskip 258% \inherited\setmathspacing \mathclosecode \mathmiddlecode \allunsplitstyles \pettymuskip 259 260\protect 261 262\startsetups asciimath:layout 263 264 \setupbodyfont 265 % [pagella,10pt] 266 [dejavu,10pt] 267 268 \setuplayout 269 [backspace=35mm, 270 leftmargin=20mm, 271 rightmargindistance=0pt, 272 leftmargindistance=5mm, 273 cutspace=1cm, 274 topspace=1cm, 275 bottomspace=1cm, 276 width=middle, 277 height=middle, 278 header=0cm, 279 footer=1cm] 280 281 \setupheadertexts 282 [] 283 284 \setupfootertexts 285 [\currentdate][\pagenumber] 286 287 \setupalign 288 [flushleft,verytolerant,stretch] 289 290 \dontcomplain 291 292\stopsetups 293 294\stopmodule 295 296\continueifinputfile{x-asciimath.mkxl} 297 298%D This will become an extra. 299 300\starttext 301 302\setups[asciimath:layout] 303 304% \enabletrackers[modules.asciimath.mapping] 305% \enabletrackers[modules.asciimath.detail] 306 307% \starttext 308% \enablemode[asciimath:show:dirty] 309% \ShowAsciiMath[e:/temporary/asciimath/*.xml] 310% % \ShowAsciiMathSave[e:/temporary/asciimath/asciimath.lua] 311% \stoptext 312 313\subject{Some tests} 314 315\enabletrackers[modules.asciimath.mapping] 316 317\showglyphs 318 319\asciimath{x + (a/b)//(d/c) + x} 320 321% $\mathoptext{\meaning|!}$ 322 323\asciimath{a text(|) b} 324 325% a \asciimathoptext{{|}} b 326 327% {\left.{\left\lparent \frac{a}{b} \right\rparent}\middle/{\left\lparent \frac{d}{c} \right\rparent}\right.} 328% \vfrac 329 % {\left.{\left\lparent \frac{a}{b} \right\rparent}} 330 % {{\left\lparent \frac{d}{c} \right\rparent}\right.} 331 332% \protected\def\MyAsciiMath#1{\startformula\asciimath{#1}\stopformula} 333% 334% \startlines 335% \MyAsciiMath{x^2 / 10 // z_12^34 / 20} 336% \MyAsciiMath{{:{:x^2:} / 10:} // {:{:z_12^34 :} / 20:}} 337% \MyAsciiMath{x^2+y_1+z_12^34} 338% \MyAsciiMath{sin^-1(x)} 339% \MyAsciiMath{d/dx f(x)=lim_(h->0) (f(x+h)-f(x))/h} 340% \MyAsciiMath{f(x)=sum_(n=0)^oo(f^((n))(a))/(n!)(x-a)^n} 341% \MyAsciiMath{int_0^1 f(x)dx} 342% \MyAsciiMath{int^1_0 f(x)dx} 343% \MyAsciiMath{a//b} 344% \MyAsciiMath{a//\alpha} 345% \MyAsciiMath{(a/b)/(d/c)} 346% \MyAsciiMath{((a*b))/(d/c)} 347% \MyAsciiMath{[[a,b],[c,d]]((n),(k))} 348% \MyAsciiMath{1/x={(1,text{if } x!=0),(text{undefined},if x=0):}} 349% \MyAsciiMath{{ (1,2), (x,(x + text(x))) }} 350% \MyAsciiMath{{(1,2),(x,(x+text(x))),(x,text(x))}} 351% \MyAsciiMath{{(1,2),(x,(x+text(x))),(x,x text(x))}} 352% \MyAsciiMath{{(1,2/2),(x,(x+x^22+sqrt(xx))),(x,x text(xyz))}} 353% \MyAsciiMath{{(1,2/2),(x,(x+x^22+sqrt(xx))),(x,text(xyz)+1+text(hans))}} 354% \MyAsciiMath{<<a,b>> text{and} {:(x,y),(u,v):}} 355% \MyAsciiMath{(a,b] = {x text(in) RR | a < x <= b}} 356% \MyAsciiMath{a/b / c/d = (a * d) / (b * d) / (b * c) / (b * d) = (a * d) / (b * c)} 357% \MyAsciiMath{ (a/b) // (c/d) = ( (a * d) / (b * d) ) // ( (b * c) / (b * d) ) = (a * d) / (b * c)} 358% \MyAsciiMath{sin(x+1)_3^2/b / c/d} 359% \MyAsciiMath{{:{:sin(x+1)_3^2:}/b:} / {:c/d:}} 360% \MyAsciiMath{cos(a) + sin(x+1)_3^2/b / c/d = (a * d) / (b * d) / (b * c) / (b * d) = (a * d) / (b * c)} 361% \MyAsciiMath{S_(11)} 362% \MyAsciiMath{f(x)} 363% \MyAsciiMath{sin(x)} 364% \MyAsciiMath{sin(x+1)} 365% \MyAsciiMath{sin^-1(x)} 366% \MyAsciiMath{sin(2x)} 367% \MyAsciiMath{a_2^2} 368% \MyAsciiMath{( (S_(11),S_(12),S_(1n)),(vdots,ddots,vdots),(S_(m1),S_(m2),S_(mn)) ]} 369% \MyAsciiMath{frac a b} 370% \MyAsciiMath{sin(x)/2 // cos(x)/pi} 371% \MyAsciiMath{a/13 // c/d} 372% \MyAsciiMath{a/b // c/d} 373% \MyAsciiMath{x} 374% \MyAsciiMath{x^2} 375% \MyAsciiMath{sqrt x} 376% \MyAsciiMath{sqrt (x)} 377% \MyAsciiMath{root 2 x} 378% \MyAsciiMath{x+x} 379% \MyAsciiMath{x/3} 380% \MyAsciiMath{x^2 / 10} 381% \MyAsciiMath{x^2 / 10 // z_12^34 / 20} 382% \MyAsciiMath{a^23} 383% \MyAsciiMath{a^{:b^23:}+3x} 384% \MyAsciiMath{a/b / c/d} 385% \MyAsciiMath{sin(x)/b / c/d} 386% \MyAsciiMath{sin(x)/b // c/d} 387% \MyAsciiMath{a/b / c/d = (a * d) / (b * d) / (b * c) / (b * d) = (a * d) / (b * c) } 388% \MyAsciiMath{{:{:x^2:} / 10:} // {:{:z_12^34 :} / 20:}} 389% \MyAsciiMath{x^2+y_1+z_12^34} 390% \MyAsciiMath{sin^-1(x)} 391% \MyAsciiMath{d/dx f(x)=lim_(h->0) (f(x+h)-f(x))/h} 392% \MyAsciiMath{f(x)=sum_(n=0)^oo(f^((n))(a))/(n!)(x-a)^n} 393% \MyAsciiMath{int_0^1 f(x)dx} 394% \MyAsciiMath{int^1_0 f(x)dx} 395% \MyAsciiMath{2x} 396% \MyAsciiMath{a//b} 397% \MyAsciiMath{a//\alpha} 398% \MyAsciiMath{(a/b)/(d/c)} 399% \MyAsciiMath{((a*b))/(d/c)} 400% \MyAsciiMath{[[a,b],[c,d]]((n),(k))} 401% \MyAsciiMath{1/x={(1,text{if } x!=0),(text{undefined},if x=0):}} 402% \MyAsciiMath{{ (1,2), (x,(x + text(x))) }} 403% \MyAsciiMath{{(1,2),(x,(x+text(x))),(x,text(x))}} 404% \MyAsciiMath{{(1,2),(x,(x+text(x))),(x,x text(x))}} 405% \MyAsciiMath{{(1,2/2),(x,(x+x^22+sqrt(xx))),(x,x text(xyz))}} 406% \MyAsciiMath{{(1,2/2),(x,(x+x^22+sqrt(xx))),(x,text(xyz)+1+text(hans))}} 407% \MyAsciiMath{<<a,b>> text{and} {:(x,y),(u,v):}} 408% \MyAsciiMath{(a,b] = {x text(in) RR | a < x <= b}} 409% \MyAsciiMath{x^-2} 410% \MyAsciiMath{x^2(x-1/16)=0} 411% \MyAsciiMath{y= ((1/4)) ^x} 412% \MyAsciiMath{log (0,002) / (log(1/4))} 413% \MyAsciiMath{x=ax+b \ oeps} 414% \MyAsciiMath{x=\ ^ (1/4) log(x)} 415% \MyAsciiMath{x=\ ^ (1/4) log(0 ,002 )= log(0,002) / (log(1/4))} 416% \MyAsciiMath{x^ (-1 1/2) =1/x^ (1 1/2)=1/ (x^1*x^ (1/2)) =1/ (xsqrt(x))} 417% \MyAsciiMath{x^2(10 -x)>2 x^2} 418% \MyAsciiMath{x^4>x} 419% \stoplines 420 421% \setupasciimath[splitmethod=3,symbol={{,}}] 422% 423% \startlines 424% \asciimath{sqrt 1} 425% \asciimath{sqrt 1.2} 426% \asciimath{sqrt 1.2} 427% \asciimath{1} 428% \asciimath{12} 429% \asciimath{123} 430% \asciimath{1234} 431% \asciimath{12345} 432% \asciimath{123456} 433% \asciimath{1234567} 434% \asciimath{12345678} 435% \asciimath{123456789} 436% \asciimath{1.1} 437% \asciimath{12.12} 438% \asciimath{1234.123} 439% \asciimath{1234.1234} 440% \asciimath{12345.1234} 441% \asciimath{1234.12345} 442% \asciimath{12345.12345} 443% \asciimath{123456.123456} 444% \asciimath{1234567.1234567} 445% \asciimath{12345678.12345678} 446% \asciimath{123456789.123456789} 447% \asciimath{0.1234} 448% \asciimath{1234.0} 449% \asciimath{1234.00} 450% \asciimath{0.123456789} 451% \stoplines 452 453% \definemixedcolumns[asciimath][n=3,balance=yes] 454% 455% \startluacode 456% local asciimath = moduledata.asciimath 457% local variables = { "w", "x", "y", "z", "p", "q", "r" } 458% local constants = { "a", "b", "c" } 459% local functions = { "g", "h", "i" } 460% local iterators = { "i", "j", "k" } 461% local vectors = { "A", "B", "C", "D", "E", "P", "Q", "R" } 462% local reserved = { } 463% local reserved = { 464% -- "vdots","ddots","oint", 465% "grad", "prod", "prop", "sube", "supe", "sum", 466% "vvv", "nnn", "uuu", "sub", "sup", 467% "iff", "int", "del", 468% "sinh", "cosh", "tanh", "sin", "cos", "tan", "csc", "sec", "cot", 469% "atan", "asin", "acos", "arctan", "arcsin", "arccos", 470% "log", "ln", "det", "lim", "mod", "gcd", -- "lcm", 471% "min", "max", 472% "xx", "in", "ox", "vv", "nn", "uu", "oo", "bb", 473% "not", "and", "or", "if", 474% "AA", "EE", "TT", 475% "sqrt", "root", "frac", "stackrel", 476% "hat", "overbar", "underline", "vec", 477% "dx", "dy", "dz", 478% } 479% for c=1,#constants do 480% for r=1,#reserved do 481% context.startmixedcolumns { "asciimath" } 482% for v1=1,#variables do 483% for v2=1,#variables do 484% local str = constants[c] .. variables[v1] .. reserved[r] .. variables[v2] 485% context.type(str) 486% context.quad() 487% commands.asciimath(str) 488% context.par() 489% end 490% end 491% context.stopmixedcolumns() 492% context.blank() 493% end 494% end 495% \stopluacode 496 497\stoptext 498 |