Rev 16251 | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
10 | reyssat | 1 | /* Copyright (C) 1998-2003 XIAO, Gang of Universite de Nice - Sophia Antipolis |
2 | * |
||
3 | * This program is free software; you can redistribute it and/or modify |
||
4 | * it under the terms of the GNU General Public License as published by |
||
5 | * the Free Software Foundation; either version 2 of the License, or |
||
6 | * (at your option) any later version. |
||
7 | * |
||
8 | * This program is distributed in the hope that it will be useful, |
||
9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
||
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||
11 | * GNU General Public License for more details. |
||
12 | * |
||
13 | * You should have received a copy of the GNU General Public License |
||
14 | * along with this program; if not, write to the Free Software |
||
15 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
||
16 | */ |
||
5502 | bpr | 17 | /* subroutines for texmath */ |
8185 | bpr | 18 | #include "wims.h" |
10 | reyssat | 19 | |
8185 | bpr | 20 | /* Careful! increasing this number risks stack overflow. */ |
10 | reyssat | 21 | #define MAX_FACTORS 256 |
22 | |||
23 | enum { |
||
24 | type_integer, type_numeric, type_var, |
||
25 | type_poly, type_transcend |
||
26 | }; |
||
27 | |||
28 | typedef struct afactor{ |
||
29 | char *beg, *end; |
||
30 | int type, side; |
||
31 | } afactor; |
||
32 | |||
33 | char texmathbuf[MAX_LINELEN+1]; |
||
34 | char *find_term_end(char *p); |
||
35 | void t_onestring(char *p); |
||
36 | void t_oneterm(char *p, int num); |
||
37 | void t_onefactor(struct afactor *p, int num); |
||
5516 | bpr | 38 | /* never used or defined ?? */ |
10 | reyssat | 39 | void n_onestring(char *p); |
40 | void n_oneterm(char *p, int num); |
||
41 | void n_onefactor(struct afactor *p, int num); |
||
5516 | bpr | 42 | /* */ |
10 | reyssat | 43 | void texmath(char *p); |
44 | |||
5502 | bpr | 45 | /* print to texmathbuf */ |
10 | reyssat | 46 | void tprint(char *s,...) |
47 | { |
||
48 | va_list vp; |
||
49 | char buf[MAX_LINELEN+1]; |
||
50 | |||
51 | va_start(vp,s); vsnprintf(buf,sizeof(buf),s,vp); va_end(vp); |
||
7673 | bpr | 52 | if(strlen(buf)+strlen(texmathbuf)>=MAX_LINELEN) |
10 | reyssat | 53 | user_error("cmd_output_too_long"); |
54 | strcat(texmathbuf,buf); |
||
55 | } |
||
5458 | bpr | 56 | /* transforms sum(n,n=1..infinity) , product(n/(n+1),n=1..infinity). */ |
10 | reyssat | 57 | void _tex_sums(char *p, char *name, int type) |
58 | { |
||
59 | char *p1,*p2,*p3; |
||
60 | p1=find_item_end(p); if(*p1) *(p1++)=0; |
||
61 | p2=find_item_end(p1); p3=strparstr(p1,"="); |
||
11125 | georgesk | 62 | if(p3<p2) p2=p3; |
63 | if(*p2) *(p2++)=0; |
||
10 | reyssat | 64 | p3=find_item_end(p2); |
65 | if(*p3) *(p3++)=0; |
||
66 | tprint("\\%s ",name); |
||
67 | if(type) { |
||
5502 | bpr | 68 | if(*p2) { |
69 | tprint("_{"); t_onestring(p2); tprint("}"); |
||
70 | } |
||
10 | reyssat | 71 | } |
72 | else if(*p1) { |
||
5502 | bpr | 73 | tprint("_{%s",p1); |
74 | if(*p2) { tprint("="); t_onestring(p2); } |
||
75 | tprint("}"); |
||
10 | reyssat | 76 | } |
77 | if(*p3) { |
||
5502 | bpr | 78 | tprint("^{"); t_onestring(p3); tprint("}"); |
10 | reyssat | 79 | } |
80 | strip_trailing_spaces(p); if(find_term_end(p)<p+strlen(p)) { |
||
5502 | bpr | 81 | tprint("\\left("); t_onestring(p); tprint("\\right)"); |
10 | reyssat | 82 | } |
83 | else t_onestring(p); |
||
84 | if(type && *p1) { |
||
16251 | reyssat | 85 | strip_trailing_spaces(p1); tprint("\\,\\textrm{d}"); // case of the integrale |
5502 | bpr | 86 | if(find_term_end(p1)<p1+strlen(p1)) { |
87 | tprint("\\left("); t_onestring(p1); tprint("\\right)"); |
||
88 | } |
||
89 | else t_onestring(p1); |
||
10 | reyssat | 90 | } |
91 | } |
||
92 | |||
5502 | bpr | 93 | /* integration, sum and product */ |
10 | reyssat | 94 | void tex_int(char *p) { _tex_sums(p,"int",1); } |
95 | void tex_sum(char *p) { _tex_sums(p,"sum",0); } |
||
96 | void tex_prod(char *p) { _tex_sums(p,"prod",0);} |
||
97 | |||
8185 | bpr | 98 | struct tmathfn tmathfn[]={ |
5502 | bpr | 99 | {"Arg", 1, "\\rm{Arg}", "\\right)"}, |
100 | {"Int", 2, "","", tex_int}, |
||
101 | {"Prod", 2, "","", tex_prod}, |
||
102 | {"Sum", 2, "","", tex_sum}, |
||
103 | {"abs", 0, "\\left|", "\\right|"}, |
||
104 | {"acos", 1, "\\rm{arccos}", "\\right)"}, |
||
105 | {"acosh", 1, "\\rm{Argch}", "\\right)"}, |
||
106 | {"arg", 1, "\\rm{Arg}", "\\right)"}, |
||
107 | {"asin", 1, "\\rm{arcsin}", "\\right)"}, |
||
108 | {"asinh", 1, "\\rm{Argsh}", "\\right)"}, |
||
109 | {"atan", 1, "\\rm{arctg}", "\\right)"}, |
||
110 | {"atanh", 1, "\\rm{Argth}", "\\right)"}, |
||
111 | {"ch", 1, "\\rm{ch}", "\\right)"}, |
||
112 | {"conj", 0, "\\overline{", "}"}, |
||
113 | {"conjugate",0, "\\overline{", "}"}, |
||
114 | {"cos", 1, "\\cos", "\\right)"}, |
||
115 | {"cosh", 1, "\\rm{ch}", "\\right)"}, |
||
116 | {"cot", 1, "\\rm{ctg}", "\\right)"}, |
||
117 | {"cotan", 1, "\\rm{ctg}", "\\right)"}, |
||
118 | {"cotanh", 1, "\\rm{cth}", "\\right)"}, |
||
119 | {"csc", 1, "\\rm{csc}", "\\right)"}, |
||
120 | {"ctg", 1, "\\rm{ctg}", "\\right)"}, |
||
121 | {"cth", 1, "\\rm{cth}", "\\right)"}, |
||
122 | {"det", 1, "\\rm{det}", "\\right)"}, |
||
123 | {"erf", 1, "\\rm{erf}", "\\right)"}, |
||
124 | {"exp", 1, "\\exp", "\\right)"}, |
||
125 | {"int", 2, "","", tex_int}, |
||
126 | {"integrate",2, "","", tex_int}, |
||
127 | {"lg", 1, "\\rm{lg}", "\\right)"}, |
||
128 | {"ln", 1, "\\ln", "\\right)"}, |
||
129 | {"log", 1, "\\log", "\\right)"}, |
||
130 | {"prod", 2, "","", tex_prod}, |
||
131 | {"product", 2, "","", tex_prod}, |
||
132 | {"sec", 1, "\\rm{sec}", "\\right)"}, |
||
133 | {"sgn", 1, "\\rm{sgn}", "\\right)"}, |
||
134 | {"sh", 1, "\\rm{sh}", "\\right)"}, |
||
135 | {"sign", 1, "\\rm{sign}", "\\right)"}, |
||
136 | {"sin", 1, "\\sin", "\\right)"}, |
||
137 | {"sinh", 1, "\\rm{sh}", "\\right)"}, |
||
138 | {"sqrt", 0, "\\sqrt{", "}"}, |
||
139 | {"sum", 2, "","", tex_sum}, |
||
140 | {"tan", 1, "\\tan", "\\right)"}, |
||
141 | {"tanh", 1, "\\rm{th}", "\\right)"}, |
||
142 | {"tg", 1, "\\rm{tg}", "\\right)"}, |
||
143 | {"th", 1, "\\rm{th}", "\\right)"} |
||
10 | reyssat | 144 | }; |
145 | |||
8185 | bpr | 146 | int tmathfn_no=(sizeof(tmathfn)/sizeof(tmathfn[0])); |
10 | reyssat | 147 | |
8185 | bpr | 148 | struct tmathvar tmathvar[]={ |
5502 | bpr | 149 | {"CC", "\\mathbb{C}"}, |
150 | {"Delta", "\\Delta"}, |
||
151 | {"Gamma", "\\Gamma"}, |
||
152 | {"Inf", "\\infty"}, |
||
153 | {"Lambda", "\\Lambda"}, |
||
154 | {"NN", "\\mathbb{N}"}, |
||
155 | {"Omega", "\\Omega"}, |
||
156 | {"PI", "\\pi"}, |
||
157 | {"Phi", "\\Phi"}, |
||
158 | {"Pi", "\\Pi"}, |
||
159 | {"Psi", "\\Psi"}, |
||
160 | {"QQ", "\\mathbb{Q}"}, |
||
161 | {"RR", "\\mathbb{R}"}, |
||
162 | {"Sigma", "\\Sigma"}, |
||
163 | {"Theta", "\\Theta"}, |
||
164 | {"Upsilon", "\\Upsilon"}, |
||
165 | {"Xi", "\\Xi"}, |
||
166 | {"ZZ", "\\mathbb{Z}"}, |
||
167 | {"aleph", "\\aleph"}, |
||
168 | {"alpha", "\\alpha"}, |
||
169 | {"beta", "\\beta"}, |
||
170 | {"chi", "\\chi"}, |
||
171 | {"delta", "\\delta"}, |
||
172 | {"epsilon","\\epsilon"}, |
||
173 | {"eta", "\\eta"}, |
||
174 | {"gamma", "\\gamma"}, |
||
175 | {"inf", "\\infty"}, |
||
176 | {"infinity","\\infty"}, |
||
177 | {"infty", "\\infty"}, |
||
178 | {"iota", "\\iota"}, |
||
179 | {"kappa", "\\kappa"}, |
||
180 | {"lambda", "\\lambda"}, |
||
181 | {"mu", "\\mu"}, |
||
182 | {"neq", "\\neq"}, |
||
183 | {"nu", "\\nu"}, |
||
184 | {"omega", "\\omega"}, |
||
185 | {"phi", "\\phi"}, |
||
186 | {"pi", "\\pi"}, |
||
187 | {"psi", "\\psi"}, |
||
188 | {"rho", "\\rho"}, |
||
189 | {"sigma", "\\sigma"}, |
||
190 | {"tau", "\\tau"}, |
||
191 | {"theta", "\\theta"}, |
||
192 | {"xi", "\\xi"}, |
||
193 | {"zeta", "\\zeta"} |
||
10 | reyssat | 194 | }; |
195 | |||
8185 | bpr | 196 | int tmathvar_no=(sizeof(tmathvar)/sizeof(tmathvar[0])); |
10 | reyssat | 197 | |
198 | |||
5502 | bpr | 199 | /* find the end of an additive term. */ |
10 | reyssat | 200 | char *find_term_end(char *p) |
201 | { |
||
202 | char *pp; |
||
7673 | bpr | 203 | pp=p; |
10 | reyssat | 204 | if(*pp==',' || *pp==';' || *pp=='=' || *pp=='<') pp++; |
205 | while(*pp=='+' || *pp=='-' || *pp=='=' || *pp=='>') pp++; |
||
206 | for(;*pp;pp++) { |
||
5502 | bpr | 207 | switch(*pp) { |
208 | case '(': pp=find_matching(pp+1,')'); goto loopend; |
||
209 | case '[': pp=find_matching(pp+1,']'); goto loopend; |
||
210 | /* case '{': pp=find_matching(pp+1,'}'); goto loopend;*/ |
||
7673 | bpr | 211 | |
5502 | bpr | 212 | case 0: |
213 | case '<': |
||
214 | case '>': |
||
215 | case ',': |
||
216 | case ';': |
||
217 | case '=': |
||
218 | case ')': |
||
219 | case ']': |
||
220 | case '}': |
||
221 | case '-': |
||
222 | case '+': return pp; |
||
223 | |||
224 | case '*': |
||
225 | case '/': |
||
226 | case '^': { |
||
227 | while(*(pp+1)=='+' || *(pp+1)=='-') pp++; |
||
228 | goto loopend; |
||
229 | } |
||
230 | } |
||
231 | if(isalnum(*pp) || *pp=='.') { |
||
232 | pp=find_mathvar_end(pp); pp--; continue; |
||
233 | } |
||
234 | continue; |
||
235 | loopend: |
||
236 | if(pp==NULL) module_error("unmatched_parentheses"); |
||
10 | reyssat | 237 | } |
238 | return pp; |
||
239 | } |
||
240 | |||
5502 | bpr | 241 | /* find the end of an multiplicative factor. */ |
10 | reyssat | 242 | char *find_factor_end(char *p) |
243 | { |
||
244 | char *pp; |
||
245 | pp=p; if(*pp==',' || *pp==';' || *pp=='=') pp++; |
||
246 | while(*pp=='+' || *pp=='-' || *pp=='*' || *pp=='/') pp++; |
||
247 | for(;*pp;pp++) { |
||
5502 | bpr | 248 | switch(*pp) { |
249 | case '(': pp=find_matching(pp+1,')'); goto loopend; |
||
250 | case '[': pp=find_matching(pp+1,']'); goto loopend; |
||
251 | /* case '{': pp=find_matching(pp+1,'}'); goto loopend;*/ |
||
7673 | bpr | 252 | |
5502 | bpr | 253 | case 0: |
254 | case '<': |
||
255 | case '>': |
||
256 | case ',': |
||
257 | case ';': |
||
258 | case '=': |
||
259 | case ')': |
||
260 | case ']': |
||
261 | case '}': |
||
262 | case '+': |
||
263 | case '-': |
||
264 | case '*': |
||
265 | case '/': return pp; |
||
7673 | bpr | 266 | |
5502 | bpr | 267 | case '^': { |
268 | while(*(pp+1)=='+' || *(pp+1)=='-') pp++; |
||
269 | goto loopend; |
||
270 | } |
||
271 | } |
||
272 | if(isalnum(*pp) || *pp=='.') { |
||
273 | pp=find_mathvar_end(pp); pp--; continue; |
||
274 | } |
||
275 | continue; |
||
276 | loopend: |
||
277 | if(pp==NULL) module_error("unmatched_parentheses"); |
||
10 | reyssat | 278 | } |
279 | return pp; |
||
280 | } |
||
281 | |||
5502 | bpr | 282 | /* returns the number of terms */ |
10 | reyssat | 283 | int term_cnt(char *p) |
284 | { |
||
285 | char *pe, *pp; |
||
286 | int i; |
||
7673 | bpr | 287 | |
10 | reyssat | 288 | pe=p+strlen(p); |
289 | for(i=0,pp=p;pp<pe;pp=find_term_end(pp),i++); |
||
290 | return i; |
||
291 | } |
||
292 | |||
5460 | bpr | 293 | /* Print a number: transform 4E+05 in 4 \times 10^{5} and 4E-05 in 4 \times 10^{-5} |
5822 | bpr | 294 | suppress multiple + or 0 ; see rawmath.c |
5460 | bpr | 295 | */ |
10 | reyssat | 296 | void putnumber(char *p) |
5822 | bpr | 297 | { |
298 | char *sgn = "", *pp = strpbrk(p,"Ee"); |
||
299 | if (pp == NULL) { tprint("%s",p); return; } |
||
300 | *pp++ = 0; |
||
301 | if (*pp == '-') { sgn = "-"; pp++; } |
||
302 | while (*pp == '0' || *pp == '+') pp++; |
||
303 | tprint("%s \\times 10^{%s%s}", p, sgn, pp); |
||
304 | } |
||
7673 | bpr | 305 | |
5502 | bpr | 306 | /* Print a variable name ; transform abc475 in abc_475 */ |
10 | reyssat | 307 | void putvar(char *p) |
308 | { |
||
309 | char vbuf[1024]; |
||
310 | char *pp, *p2; |
||
311 | int i; |
||
7673 | bpr | 312 | |
10 | reyssat | 313 | vbuf[0]=0; |
314 | if(*(p+1)==0) {tprint("%c",*p); return;} |
||
315 | for(pp=p;isalpha(*pp);pp++); |
||
316 | if(myisdigit(*pp)) { |
||
5502 | bpr | 317 | for(p2=pp+1;myisdigit(*p2);p2++); |
318 | if(*p2==0) {/* subscript */ |
||
319 | mystrncpy(vbuf,pp,sizeof(vbuf));*pp=0; |
||
10 | reyssat | 320 | } |
5502 | bpr | 321 | } |
10 | reyssat | 322 | i=search_list(tmathvar, tmathvar_no, sizeof(tmathvar[0]), p); |
323 | if(i>=0) tprint("%s ",tmathvar[i].tex); |
||
324 | else tprint("%s ",p); |
||
325 | if(vbuf[0]) { |
||
5502 | bpr | 326 | if(vbuf[1]==0) tprint("_%c ",vbuf[0]); |
327 | else tprint("_{%s} ",vbuf); |
||
10 | reyssat | 328 | } |
329 | } |
||
5514 | bpr | 330 | |
5512 | bpr | 331 | /* sort according to type */ |
10 | reyssat | 332 | int fsort(const void *p1, const void *p2) |
333 | { |
||
12237 | bpr | 334 | struct afactor *t1, *t2; |
335 | int i1,i2; |
||
7673 | bpr | 336 | |
12237 | bpr | 337 | t1=*(struct afactor **) p1; t2=*(struct afactor **) p2; |
338 | i1=t1->type; i2=t2->type; |
||
339 | if(i1>type_var) i1=type_var; |
||
340 | if(i2>type_var) i2=type_var; |
||
341 | return i1-i2; |
||
10 | reyssat | 342 | } |
343 | |||
344 | void t_oneterm(char *p, int num) |
||
345 | { |
||
12237 | bpr | 346 | int sign, fcnt, s, i, dentype, rel; |
347 | char *pp, *pe, *pt; |
||
348 | struct afactor factors[MAX_FACTORS]; |
||
349 | struct afactor *numerator[MAX_FACTORS], |
||
350 | *denominator[MAX_FACTORS], |
||
351 | *neutral[MAX_FACTORS]; |
||
352 | int numcnt,dencnt,neucnt; |
||
5502 | bpr | 353 | /* interpret some arrows */ |
12237 | bpr | 354 | rel=0; |
355 | switch(*p) { |
||
356 | case '<': { |
||
357 | rel++; p++; if(*p!='=') {tprint(" < "); break;} // < |
||
358 | do p++; while(*p=='='); |
||
359 | if(*p!='>') {tprint("\\le ");break;} // <= , <=== |
||
360 | else {tprint("\\iff ");p++; break;} // <==> |
||
361 | } |
||
362 | case '>': { |
||
363 | rel++; p++; if(*p!='=') {tprint(" > "); rel=1; break;} // > |
||
364 | while(*p=='=') p++; |
||
11132 | bpr | 365 | tprint("\\ge "); // >= |
5502 | bpr | 366 | break; |
12237 | bpr | 367 | } |
368 | case '-': { |
||
369 | for(pp=p;*pp=='-';pp++); |
||
370 | if(*pp!='>') break; |
||
371 | rel++; tprint("\\to "); p=++pp; //-> |
||
372 | break; |
||
373 | } |
||
374 | case '=': { |
||
5502 | bpr | 375 | rel++; for(pp=p;*pp=='=';pp++); |
376 | if(*pp!='>') break; |
||
377 | tprint("\\Rightarrow "); p=++pp; // => |
||
378 | break; |
||
10 | reyssat | 379 | } |
12237 | bpr | 380 | } |
381 | if(*p==',' || *p==';' || *p=='=') {tprint("%c",*p); p++; num=0;} |
||
10 | reyssat | 382 | sign=1; while(*p=='+' || *p=='-') { |
5502 | bpr | 383 | if(*p=='-') sign*=-1; |
384 | p++; |
||
12237 | bpr | 385 | } |
386 | for(fcnt=0, pp=p; fcnt<MAX_FACTORS && *pp; fcnt++, pp=pe) { |
||
387 | s=1; |
||
388 | while(*pp=='*' || *pp=='/') { |
||
389 | if(*pp=='/') s=-1; |
||
390 | pp++; |
||
10 | reyssat | 391 | } |
12237 | bpr | 392 | factors[fcnt].side=s; |
393 | while(*pp=='+' || *pp=='-') { |
||
394 | if(*pp=='-') sign*=-1; |
||
395 | pp++; |
||
396 | } |
||
397 | pe=find_factor_end(pp); if(pe<=pp) break; |
||
398 | factors[fcnt].beg=pp; factors[fcnt].end=pe; |
||
399 | if(pe-pp==1 && *pp=='1') fcnt--; |
||
400 | if(*pp=='(') { |
||
401 | char *pt, *pe2, buf[MAX_LINELEN+1]; |
||
402 | int ss; |
||
403 | pp++; pt=find_matching(pp,')'); |
||
404 | if(pt>=pe-1) { |
||
405 | memmove(buf,pp,pt-pp); buf[pt-pp]=0; |
||
406 | i=term_cnt(buf); |
||
407 | if(i==1) { /* remove parentheses */ |
||
408 | for(;pp<pt && fcnt<MAX_FACTORS;pp=pe2,fcnt++) { |
||
409 | ss=s; |
||
410 | while(*pp=='*' || *pp=='/') { |
||
411 | if(*pp=='/') ss=-s; |
||
412 | pp++; |
||
413 | } |
||
414 | factors[fcnt].side=ss; |
||
415 | while(*pp=='+' || *pp=='-') { |
||
416 | if(*pp=='-') sign*=-1; |
||
417 | pp++; |
||
418 | } |
||
419 | pe2=find_factor_end(pp); |
||
420 | if(pe2<=pp) goto bailout; |
||
421 | factors[fcnt].beg=pp; factors[fcnt].end=pe2; |
||
422 | if(pe2-pp==1 && *pp=='1') fcnt--; |
||
5502 | bpr | 423 | } |
12237 | bpr | 424 | fcnt--; |
5502 | bpr | 425 | } |
426 | } |
||
10 | reyssat | 427 | } |
12237 | bpr | 428 | } |
429 | bailout: |
||
7673 | bpr | 430 | /* decide if the factor is of type numeric, integer, poly, transcend or variable |
5512 | bpr | 431 | * (see priorities) |
432 | */ |
||
12237 | bpr | 433 | for(i=0;i<fcnt;i++) { |
434 | pp=factors[i].beg; pe=factors[i].end; |
||
435 | if(myisdigit(*pp) || *pp=='.') { |
||
436 | for(pt=pp;pt<pe && myisdigit(*pt);pt++); |
||
437 | if(pt<pe) factors[i].type=type_numeric; // digits with a point |
||
438 | else factors[i].type=type_integer; // digits without point |
||
439 | continue; |
||
10 | reyssat | 440 | } |
12237 | bpr | 441 | if(*pp=='(') { |
442 | factors[i].type=type_poly; continue; //there exists a parenthesis |
||
10 | reyssat | 443 | } |
12237 | bpr | 444 | pt=strchr(pp,'('); |
445 | if(pt!=NULL && pt<pe) factors[i].type=type_transcend; //?? |
||
446 | else factors[i].type=type_var; // variable in other cases |
||
447 | } |
||
448 | dentype=-1; |
||
449 | for(i=0;i<fcnt;i++) if(factors[i].side<0 && factors[i].type>dentype) |
||
450 | dentype=factors[i].type; // denominator type will be compared to the type of the factors |
||
451 | dencnt=numcnt=neucnt=0; |
||
452 | for(i=0;i<fcnt;i++) { |
||
453 | if(factors[i].type>dentype) neutral[neucnt++]=factors+i; |
||
454 | else { |
||
455 | if(factors[i].side>0) numerator[numcnt++]=factors+i; |
||
456 | else denominator[dencnt++]=factors+i; |
||
457 | } |
||
458 | } |
||
459 | if(dencnt>0) qsort(denominator,dencnt,sizeof(denominator[0]),fsort); |
||
460 | if(numcnt>0) qsort(numerator,numcnt,sizeof(numerator[0]),fsort); |
||
461 | if(neucnt>0) qsort(neutral,neucnt,sizeof(neutral[0]),fsort); |
||
462 | if(sign>0 && num>0 && rel==0) tprint(" +"); |
||
463 | if(sign<0) tprint(" -"); |
||
464 | if(fcnt<1) tprint("1 "); // no factors why 1 - don't remove the 1 if [1,2;3,4], the 1 is useful? |
||
465 | if(dencnt>0) { |
||
17693 | bpr | 466 | tprint(" {\\frac{"); |
12237 | bpr | 467 | if(numcnt==0) tprint(" 1"); // no numerator ? will write {1 over denominator} |
468 | else {/* numerator */ |
||
469 | if(numcnt==1 && *numerator[0]->beg=='(' && |
||
470 | find_matching(numerator[0]->beg+1,')')==(numerator[0]->end)-1) { |
||
471 | *(numerator[0]->end-1)=0; |
||
472 | t_onestring(numerator[0]->beg+1); |
||
473 | *(numerator[0]->end-1)=')'; |
||
5512 | bpr | 474 | } |
12237 | bpr | 475 | else for(i=0; i<numcnt; i++) {t_onefactor(numerator[i],i); |
476 | if(i<numcnt-1) tprint(" ");} /* add space between factors */ |
||
10 | reyssat | 477 | } |
17693 | bpr | 478 | tprint(" }{ "); /* Now denominator */ |
12237 | bpr | 479 | if(dencnt==1 && *denominator[0]->beg=='(' && |
480 | find_matching(denominator[0]->beg+1,')')==(denominator[0]->end)-1) { |
||
481 | *(denominator[0]->end-1)=0; |
||
482 | t_onestring(denominator[0]->beg+1); |
||
483 | *(denominator[0]->end-1)=')'; |
||
484 | } |
||
485 | else for(i=0;i<dencnt;i++) {t_onefactor(denominator[i],i); |
||
486 | if(i<dencnt-1) tprint(" ");} /* add space between factors */ |
||
17693 | bpr | 487 | tprint("}} "); |
12237 | bpr | 488 | } |
489 | for(i=0;i<neucnt;i++) {t_onefactor(neutral[i],i+dencnt); |
||
490 | if(i<neucnt-1) tprint(" ");} /* add space between factors */ |
||
10 | reyssat | 491 | } |
492 | |||
8155 | bpr | 493 | /* put exponential */ |
10 | reyssat | 494 | void t_exponential(char *pp) |
495 | { |
||
12237 | bpr | 496 | char *pe, *pt; |
497 | int t=0; |
||
7673 | bpr | 498 | |
12237 | bpr | 499 | while(*pp && strchr("!'\"",*pp)!=NULL) { |
500 | tprint("%c",*pp); pp++; |
||
501 | } |
||
502 | if(*pp=='^') pp++; else return; |
||
503 | if(*pp=='(') { |
||
504 | pe=find_matching(pp+1,')'); |
||
505 | if(*(pe+1)==0) { |
||
506 | pp++;*pe=0; |
||
507 | for(pt=pp;*pt && (isalnum(*pt) || *pt=='.');pt++); |
||
508 | if(*pt==0) t=1; |
||
10 | reyssat | 509 | } |
12237 | bpr | 510 | } |
511 | if(strlen(pp)==1 && t==0) tprint("^%s ",pp); |
||
512 | else { |
||
513 | tprint(" ^{"); if(t) tprint("("); |
||
514 | t_onestring(pp); |
||
515 | if(t) tprint(")"); |
||
516 | tprint("} "); |
||
517 | } |
||
10 | reyssat | 518 | } |
519 | |||
520 | void t_onefactor(struct afactor *fb, int num) |
||
521 | { |
||
12237 | bpr | 522 | char *p, *pe, lp, *rp, rp2, rpbuf[128]; |
523 | char fbuf[MAX_LINELEN+1], pbuf[MAX_LINELEN+1]; |
||
524 | int i; |
||
10 | reyssat | 525 | |
12237 | bpr | 526 | memmove(pbuf,fb->beg,fb->end-fb->beg); |
527 | pbuf[fb->end-fb->beg]=0; |
||
528 | if(num>0 && (myisdigit(pbuf[0]) || pbuf[0]=='.')) |
||
529 | tprint("\\times "); |
||
530 | rp2=')'; p=pbuf; |
||
531 | if(strchr("({[",*p)!=NULL) { |
||
532 | lp=*p; switch(lp) { |
||
533 | case '(': rp2=')'; break; |
||
534 | case '[': { /* verify for matrices */ |
||
535 | char *pt; |
||
536 | pe=find_matching(p+1,']'); |
||
537 | for(pt=p+1;pt<pe;pt++) { |
||
538 | switch(*pt) { |
||
539 | case '(': pt=find_matching(pt+1,')'); break; |
||
540 | case '[': pt=find_matching(pt+1,']'); break; |
||
541 | case '{': pt=find_matching(pt+1,'}'); break; |
||
542 | case '|': pt=find_matching(pt+1,'|'); break; |
||
7673 | bpr | 543 | |
12237 | bpr | 544 | case ',': |
545 | case ';': goto out; |
||
546 | } |
||
547 | } |
||
548 | out: if(*pt==';' || *pt==',') { /* is matrix of the form [ 1,2;5,6] */ |
||
549 | char mbuf[MAX_LINELEN+1]; |
||
550 | char *pp, *pt; |
||
5502 | bpr | 551 | |
12237 | bpr | 552 | p++; if(*pe) *pe++=0; |
553 | tprint(" \\begin{pmatrix}"); |
||
554 | for(pp=p,i=0;*pp;pp=pt,i++) { |
||
555 | pt=find_term_end(pp); |
||
556 | memmove(mbuf,pp,pt-pp); mbuf[pt-pp]=0; |
||
557 | t_oneterm(mbuf,i); |
||
558 | if(*pt==',') { |
||
559 | tprint(" &"); pt++; i=-1; |
||
5502 | bpr | 560 | } |
12237 | bpr | 561 | if(*pt==';') { |
562 | tprint("\\cr "); pt++; i=-1; |
||
563 | } |
||
5502 | bpr | 564 | } |
12237 | bpr | 565 | tprint(" \\end{pmatrix}"); goto expon; |
566 | } |
||
567 | rp2=']'; break; |
||
10 | reyssat | 568 | } |
12237 | bpr | 569 | case '{': { /* protected */ |
570 | pe=find_matching(p+1,'}'); |
||
571 | *pe=0;tprint(" %s} ",p); |
||
572 | goto expon; |
||
5502 | bpr | 573 | } |
12237 | bpr | 574 | } |
575 | tprint(" \\left%c",lp); |
||
576 | snprintf(rpbuf,sizeof(rpbuf),"\\right%c ",rp2); rp=rpbuf; |
||
577 | paren: p++;pe=find_matching(p,rp2); *pe=0; |
||
578 | t_onestring(p); tprint(rp); pe++; goto expon; |
||
579 | } |
||
580 | pe=find_mathvar_end(p); while(*pe && strchr("'\"!",*pe)!=NULL) pe++; |
||
581 | memmove(fbuf,p,pe-p); fbuf[pe-p]=0; |
||
582 | if(myisdigit(*p) || *p=='.') putnumber(fbuf); |
||
583 | if(isalpha(*p)) { |
||
10 | reyssat | 584 | pe=find_mathvar_end(p); while(*pe && strchr("'\"!",*pe)!=NULL) pe++; |
5502 | bpr | 585 | if(*pe=='(') { |
12237 | bpr | 586 | p=pe; |
5502 | bpr | 587 | /* search in list of math functions*/ |
12237 | bpr | 588 | i=search_list(tmathfn, tmathfn_no, sizeof(tmathfn[0]), fbuf); |
589 | if(i>=0) { |
||
590 | switch(tmathfn[i].expind) { |
||
591 | case 0: { |
||
592 | tprint(" %s",tmathfn[i].left); |
||
593 | rp=tmathfn[i].right; break; |
||
5502 | bpr | 594 | } |
12237 | bpr | 595 | case 1: { |
596 | tprint(" %s",tmathfn[i].left); |
||
597 | pe=find_matching(pe+1,')')+1; |
||
598 | if(*pe && strchr("^'\"!",*pe)!=NULL) { |
||
599 | t_exponential(pe); *pe=0; |
||
600 | } |
||
601 | tprint(" \\left("); rp=tmathfn[i].right; |
||
602 | break; |
||
603 | } |
||
604 | case 2: { /* routine */ |
||
605 | p++;pe=find_matching(p,rp2); *pe=0; |
||
606 | tmathfn[i].routine(p); |
||
607 | pe++; goto expon; |
||
608 | } |
||
609 | default: rp=""; break; |
||
5502 | bpr | 610 | } |
12237 | bpr | 611 | } |
612 | else { |
||
613 | putvar(fbuf); |
||
614 | rp="\\right) "; tprint(" \\left("); |
||
615 | } |
||
616 | rp2=')'; goto paren; |
||
10 | reyssat | 617 | } |
5502 | bpr | 618 | else { |
12237 | bpr | 619 | putvar(fbuf); |
620 | if(*pe=='_') { |
||
621 | char *ptt, buff[256]; |
||
622 | tprint("_"); pe++; |
||
623 | if(*pe=='(') { |
||
624 | ptt=find_matching(pe+1,')'); if(ptt) ptt++; |
||
625 | } |
||
626 | else { |
||
627 | if(*pe=='{') { |
||
628 | ptt=find_matching(pe+1,'}'); if(ptt) ptt++; |
||
5502 | bpr | 629 | } |
12237 | bpr | 630 | else ptt=find_mathvar_end(pe); |
5502 | bpr | 631 | } |
12237 | bpr | 632 | if(ptt==NULL || ptt-pe>128) goto expon; |
633 | memmove(buff,pe,ptt-pe); buff[ptt-pe]=0; pe=ptt; |
||
634 | strip_enclosing_par(buff); |
||
635 | tprint("{%s}",buff); |
||
636 | } |
||
5502 | bpr | 637 | } |
12237 | bpr | 638 | } |
5502 | bpr | 639 | /* exponential */ |
12237 | bpr | 640 | expon: if(*pe && strchr("^'\"!",*pe)!=NULL) t_exponential(pe); |
10 | reyssat | 641 | } |
642 | |||
643 | void t_onestring(char *p) |
||
644 | { |
||
12237 | bpr | 645 | char termbuf[MAX_LINELEN+1]; |
646 | char *pp, *pe; |
||
647 | int i; |
||
10 | reyssat | 648 | |
12237 | bpr | 649 | for(pp=p,i=0;*pp;pp=pe,i++) { |
650 | pe=find_term_end(pp); |
||
651 | memmove(termbuf,pp,pe-pp); termbuf[pe-pp]=0; |
||
652 | t_oneterm(termbuf,i); |
||
653 | } |
||
10 | reyssat | 654 | } |
5459 | bpr | 655 | /* replace \pmatrix{ } by latex syntax \begin{pmatrix} .. \end{pmatrix} */ |
656 | |||
657 | void _replace_matrix ( char *p , char *s_mat1, char *s_mat2 ) |
||
12237 | bpr | 658 | { |
659 | char pbuf[MAX_LINELEN]; |
||
660 | while ( (p = strstr(p,s_mat1)) ){ |
||
661 | char *p2 = find_matching(p+strlen(s_mat1),'}'); |
||
5459 | bpr | 662 | long len = p2-p-strlen(s_mat1); |
663 | if (!p2) { module_error("unmatched_parentheses"); return; } |
||
664 | memcpy(pbuf, p+strlen(s_mat1), len); pbuf[len]= 0; |
||
665 | p2 ++ ; |
||
666 | string_modify(p, p, p2, "\\begin{%s}%s\\end{%s}",s_mat2,pbuf,s_mat2); |
||
667 | } |
||
668 | } |
||
669 | |||
5502 | bpr | 670 | /* translate raw math expression into TeX source */ |
10 | reyssat | 671 | void texmath(char *p) |
672 | { |
||
12237 | bpr | 673 | char *pp; |
674 | _replace_matrix (p,"\\matrix{","matrix"); |
||
675 | _replace_matrix (p,"\\pmatrix{","pmatrix"); |
||
676 | if(strpbrk(p,"{}\\")!=NULL) return; |
||
677 | for(pp=strstr(p,"!="); pp; pp=strstr(pp+1,"!=")) { |
||
678 | if(pp>p && !isspace(*(pp-1))) continue; |
||
679 | string_modify(p,pp,pp+2,"*neq*"); |
||
680 | } |
||
5502 | bpr | 681 | /* remove spaces */ |
12237 | bpr | 682 | for(pp=p; *pp; pp++) { |
683 | if(isspace(*pp)) {ovlstrcpy(pp,pp+1); pp--;} |
||
684 | } |
||
8155 | bpr | 685 | /* replace ** by ^ see __replace_badchar(p,"**", "^");*/ |
12237 | bpr | 686 | for(pp=strstr(p,"**"); pp!=NULL; pp=strstr(pp,"**")) { |
687 | *pp='^'; ovlstrcpy(pp+1,pp+2); |
||
688 | } |
||
689 | if(check_parentheses(p,1)!=0) module_error("unmatched_parentheses"); |
||
690 | texmathbuf[0]=0; t_onestring(p); |
||
691 | singlespace(texmathbuf);strip_trailing_spaces(texmathbuf); |
||
692 | mystrncpy(p,texmathbuf,MAX_LINELEN); |
||
10 | reyssat | 693 | } |