update credits
[LibreOffice.git] / hwpfilter / source / hwpeq.cxx
blob89bbcad12ccea6ecb7e6615916386b457bd57d99
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <assert.h>
21 #include <stdio.h>
22 #include <string.h>
23 #include <ctype.h>
25 // DVO: always use standard headers:
26 #include <istream>
27 #include <sstream>
28 using namespace std;
30 #include "mzstring.h"
31 #include "hwpeq.h"
32 #include <sal/types.h>
33 #include <sal/macros.h>
35 /* @Man: hwp¼ö½ÄÀ» LaTeXÀ¸·Î ¹Ù²Ù±â */
36 #ifdef WIN32
37 # define ENDL "\r\n"
38 #else /* !WIN32 */
39 # define ENDL "\n"
40 #endif
42 #define WS " \t\r\n\v\f"
44 #define EQ_CASE 0x01 // case sensitive cmd
45 #define EQ_ENV 0x02 // equiv to latex environment
46 #define EQ_ATOP 0x04 // must revert order
48 #define IS_WS(ch) (strchr(WS, ch))
49 #define IS_BINARY(ch) (strchr("+-<=>", ch))
51 #ifdef WIN32
52 #define STRICMP stricmp
53 #else
54 #define STRICMP strcasecmp
55 #endif
57 // sub and sup scipt script status
58 enum { SCRIPT_NONE, SCRIPT_SUB, SCRIPT_SUP, SCRIPT_ALL};
60 static int eq_word(MzString& outs, istream *strm, int script = SCRIPT_NONE);
61 static bool eq_sentence(MzString& outs, istream *strm, const char *end = 0);
63 struct hwpeq {
64 const char *key; // hwp math keyword
65 const char *latex; // corresponding latex keywork
66 int nargs; // # of argument
67 unsigned char flag; // case sensitive?
70 static hwpeq eq_tbl[] = {
71 { "!=", "\\equiv ", 0, 0 },
72 { "#", "\\\\", 0, 0 },
73 { "+-", "\\pm ", 0, 0 },
74 { "-+", "\\mp ", 0, 0 },
75 { "<=", "\\leq ", 0, 0 },
76 { "==", "\\equiv ", 0, 0 },
77 { ">=", "\\geq ", 0, 0 },
78 { "Pr", NULL, 0, 0 },
79 { "^", "^", 1, 0 },
80 { "_", "_", 1, 0 },
81 { "`", "\\;", 0, 0 },
82 { "acute", NULL, 1, 0 },
83 { "aleph", NULL, 0, 0 },
84 { "alpha", NULL, 0, EQ_CASE },
85 { "amalg", NULL, 0, 0 },
86 { "and", NULL, 0, 0 },
87 { "angle", NULL, 0, 0 },
88 { "angstrom", NULL, 0, 0 },
89 { "approx", NULL, 0, 0 },
90 { "arc", NULL, 0, 0 },
91 { "arccos", NULL, 0, 0 },
92 { "arch", NULL, 0, 0 },
93 { "arcsin", NULL, 0, 0 },
94 { "arctan", NULL, 0, 0 },
95 { "arg", NULL, 0, 0 },
96 { "assert", "\\vdash", 0, 0 },
97 { "ast", NULL, 0, 0 },
98 { "asymp", NULL, 0, 0 },
99 { "atop", NULL, 1, EQ_ATOP },
100 { "backslash", NULL, 0, 0 },
101 { "bar", NULL, 1, 0 },
102 { "because", NULL, 0, 0 },
103 { "beta", NULL, 0, EQ_CASE },
104 { "big", NULL, 0, EQ_CASE },
105 { "bigcap", NULL, 0, 0 },
106 { "bigcirc", NULL, 0, 0 },
107 { "bigcup", NULL, 0, 0 },
108 { "bigg", NULL, 0, EQ_CASE },
109 { "bigodiv", NULL, 0, 0 },
110 { "bigodot", NULL, 0, 0 },
111 { "bigominus", NULL, 0, 0 },
112 { "bigoplus", NULL, 0, 0 },
113 { "bigotimes", NULL, 0, 0 },
114 { "bigsqcap", NULL, 0, 0 },
115 { "bigsqcup", NULL, 0, 0 },
116 { "biguplus", NULL, 0, 0 },
117 { "bigvee", NULL, 0, 0 },
118 { "bigwedge", NULL, 0, 0 },
119 { "binom", NULL, 2, 0 },
120 { "bmatrix", NULL, 0, EQ_ENV },
121 { "bold", NULL, 0, 0 },
122 { "bot", NULL, 0, 0 },
123 { "breve", NULL, 1, 0 },
124 { "buildrel", NULL, 0, 0 }, // LATER
125 { "bullet", NULL, 0, 0 },
126 { "cap", NULL, 0, 0 },
127 { "cases", NULL, 0, EQ_ENV },
128 { "ccol", NULL, 0, 0 }, /* ¼¼·Î·Î °¡¿îµ¥ */
129 { "cdot", NULL, 0, 0 },
130 { "cdots", NULL, 0, 0 },
131 { "check", NULL, 1, 0 },
132 { "chi", NULL, 0, EQ_CASE },
133 { "choose", NULL, 0, EQ_ATOP },
134 { "circ", NULL, 0, 0 },
135 { "col", NULL, 0, 0 }, // LATER
136 { "cong", NULL, 0, 0 },
137 { "coprod", NULL, 0, 0 },
138 { "cos", NULL, 0, 0 },
139 { "cosec", NULL, 0, 0 },
140 { "cosh", NULL, 0, 0 },
141 { "cot", NULL, 0, 0 },
142 { "coth", NULL, 0, 0 },
143 { "cpile", NULL, 0, 0 }, // LATER
144 { "csc", NULL, 0, 0 },
145 { "cup", NULL, 0, 0 },
146 { "dagger", NULL, 0, 0 },
147 { "dashv", NULL, 0, 0 },
148 { "ddagger", NULL, 0, 0 },
149 { "ddot", NULL, 1, 0 },
150 { "ddots", NULL, 0, 0 },
151 { "def", NULL, 0, 0 },
152 { "deg", NULL, 0, 0 },
153 { "del", NULL, 0, 0 },
154 { "delta", NULL, 0, EQ_CASE },
155 { "diamond", NULL, 0, 0 },
156 { "dim", NULL, 0, 0 },
157 { "div", NULL, 0, 0 },
158 { "divide", NULL, 0, 0 },
159 { "dline", NULL, 0, 0 },
160 { "dmatrix", NULL, 0, EQ_ENV },
161 { "dot", NULL, 1, 0 },
162 { "doteq", NULL, 0, 0 },
163 { "dotsaxis", NULL, 0, 0 },
164 { "dotsdiag", NULL, 0, 0 },
165 { "dotslow", "\\ldots", 0, 0 },
166 { "dotsvert", "\\vdots", 0, 0 },
167 { "downarrow", NULL, 0, EQ_CASE },
168 { "dsum", "+", 0, 0 },
169 { "dyad", NULL, 0, 0 }, // LATER
170 { "ell", NULL, 0, 0 },
171 { "emptyset", NULL, 0, 0 },
172 { "epsilon", NULL, 0, EQ_CASE },
173 { "eqalign", NULL, 0, EQ_ENV },
174 { "equiv", NULL, 0, 0 },
175 { "eta", NULL, 0, EQ_CASE },
176 { "exarrow", NULL, 0, 0 },
177 { "exist", "\\exists", 0, 0 },
178 { "exists", NULL, 0, 0 },
179 { "exp", NULL, 0, EQ_CASE },
180 { "for", NULL, 0, 0 },
181 { "forall", NULL, 0, 0 },
182 { "from", "_", 1, 0 },
183 { "gamma", NULL, 0, EQ_CASE },
184 { "gcd", NULL, 0, 0 },
185 { "ge", "\\geq", 0, 0 },
186 { "geq", NULL, 0, 0 },
187 { "ggg", NULL, 0, 0 },
188 { "grad", NULL, 0, 0 },
189 { "grave", NULL, 1, 0 },
190 { "hat", "\\widehat", 1, 0 },
191 { "hbar", NULL, 0, 0 },
192 { "hom", NULL, 0, 0 },
193 { "hookleft", NULL, 0, 0 },
194 { "hookright", NULL, 0, 0 },
195 { "identical", NULL, 0, 0 }, // LATER
196 { "if", NULL, 0, 0 },
197 { "imag", NULL, 0, 0 },
198 { "image", NULL, 0, 0 },
199 { "imath", NULL, 0, 0 },
200 { "in", NULL, 0, 0 },
201 { "inf", "\\infty", 0, 0 },
202 { "infinity", "\\infty", 0, 0 },
203 { "infty", NULL, 0, 0 },
204 { "int", NULL, 0, 0 },
205 { "integral", "\\int", 0, 0 },
206 { "inter", "\\bigcap", 0, 0 },
207 { "iota", NULL, 0, EQ_CASE },
208 { "iso", NULL, 0, 0 }, // ams
209 { "it", NULL, 0, 0 },
210 { "jmath", NULL, 0, 0 },
211 { "kappa", NULL, 0, EQ_CASE },
212 { "ker", NULL, 0, 0 },
213 { "lambda", NULL, 0, EQ_CASE },
214 { "land", NULL, 0, 0 }, // LATER
215 { "langle", NULL, 0, 0 },
216 { "larrow", "\\leftarrow", 0, EQ_CASE },
217 { "lbrace", NULL, 0, 0 },
218 { "lbrack", "[", 0, 0 },
219 { "lceil", NULL, 0, 0 },
220 { "lcol", NULL, 0, 0 }, // LATER
221 { "ldots", NULL, 0, 0 },
222 { "le", NULL, 0, 0 },
223 { "left", NULL, 0, 0 },
224 { "leftarrow", NULL, 0, EQ_CASE },
225 { "leq", NULL, 0, 0 },
226 { "lfloor", NULL, 0, 0 },
227 { "lg", NULL, 0, 0 },
228 { "lim", NULL, 0, EQ_CASE },
229 { "line", "\\vert", 0, 0 },
230 { "liter", "\\ell", 0, 0 },
231 { "lll", NULL, 0, 0 }, // ams
232 { "ln", NULL, 0, 0 },
233 { "log", NULL, 0, 0 },
234 { "lor", "\\vee", 0, 0 },
235 { "lparen", "(", 0, 0 },
236 { "lpile", NULL, 0, 0 }, // LATER
237 { "lrarrow", "\\leftrightarrow", 0, EQ_CASE },
238 { "lrharpoons", "\\leftrightharpoons",0, 0 },
239 { "mapsto", NULL, 0, 0 },
240 { "massert", "\\dashv", 0, 0 },
241 { "matrix", NULL, 0, EQ_ENV },
242 { "max", NULL, 0, 0 },
243 { "mho", NULL, 0, 0 }, // ams
244 { "min", NULL, 0, 0 },
245 { "minusplus", NULL, 0, 0 },
246 { "mit", "", 0, 0 }, // font
247 { "mod", "\\bmod", 0, 0 },
248 { "models", NULL, 0, 0 },
249 { "msangle", NULL, 0, 0 }, // LATER
250 { "mu", NULL, 0, EQ_CASE },
251 { "nabla", NULL, 0, 0 },
252 { "ne", NULL, 0, 0 },
253 { "nearrow", NULL, 0, 0 },
254 { "neg", NULL, 0, 0 },
255 { "neq", NULL, 0, 0 },
256 { "nequiv", NULL, 0, 0 },
257 { "ni", NULL, 0, 0 },
258 { "not", NULL, 0, 0 },
259 { "notin", NULL, 0, 0 },
260 { "nu", NULL, 0, EQ_CASE },
261 { "nwarrow", NULL, 0, 0 },
262 { "odiv", NULL, 0, 0 },
263 { "odot", NULL, 0, 0 },
264 { "oint", NULL, 0, 0 },
265 { "omega", NULL, 0, EQ_CASE },
266 { "omicron", NULL, 0, EQ_CASE },
267 { "ominus", NULL, 0, 0 },
268 { "oplus", NULL, 0, 0 },
269 { "or ", NULL, 0, 0 },
270 { "oslash", NULL, 0, 0 },
271 { "otimes", NULL, 0, 0 },
272 { "over", NULL, 1, EQ_ATOP },
273 { "overline", NULL, 1, 0 },
274 { "owns", "\\ni", 0, 0 },
275 { "parallel", NULL, 0, 0 },
276 { "partial", NULL, 0, 0 },
277 { "phantom", NULL, 0, 0 },
278 { "phi", NULL, 0, EQ_CASE },
279 { "pi", NULL, 0, EQ_CASE },
280 { "pile", NULL, 0, 0 }, // LATER
281 { "plusminus", "\\pm", 0, 0 },
282 { "pmatrix", NULL, 0, EQ_ENV },
283 { "prec", NULL, 0, 0 },
284 { "prep", NULL, 0, 0 },
285 { "prime", NULL, 0, 0 },
286 { "prod", NULL, 0, 0 },
287 { "propto", NULL, 0, 0 },
288 { "psi", NULL, 0, EQ_CASE },
289 { "rangle", NULL, 0, 0 },
290 { "rarrow", "\\rightarrow", 0, EQ_CASE },
291 { "rbrace", "]", 0, 0 },
292 { "rbrace", NULL, 0, 0 },
293 { "rceil", NULL, 0, 0 },
294 { "rcol", NULL, 0, 0 }, // LATER
295 { "real", "\\Re", 0, 0 },
296 { "reimage", NULL, 0, 0 },
297 { "rel", NULL, 0, 0 },
298 { "rfloor", NULL, 0, 0 },
299 { "rho", NULL, 0, EQ_CASE },
300 { "right", NULL, 0, 0 },
301 { "rightarrow", NULL, 0, EQ_CASE },
302 { "rlharpoons", NULL, 0, 0 },
303 { "rm", NULL, 0, 0 },
304 { "root", "\\sqrt", 1, 0 },
305 { "rparen", ")", 0, 0 },
306 { "rpile", NULL, 0, 0 }, // LATER
307 { "rtangle", NULL, 0, 0 },
308 { "sangle", NULL, 0, 0 },
309 { "scale", NULL, 0, 0 },
310 { "searrow", NULL, 0, 0 },
311 { "sec", NULL, 0, 0 },
312 { "sigma", NULL, 0, EQ_CASE },
313 { "sim", NULL, 0, 0 },
314 { "simeq", NULL, 0, 0 },
315 { "sin", NULL, 0, 0 },
316 { "sinh", NULL, 0, 0 },
317 { "slash", NULL, 0, 0 },
318 { "smallint", NULL, 0, 0 },
319 { "smallinter", NULL, 0, 0 },
320 { "smalloint", NULL, 0, 0 },
321 { "smallprod", NULL, 0, 0 },
322 { "smallsum", NULL, 0, 0 },
323 { "smallunion", NULL, 0, 0 },
324 { "smcoprod", NULL, 0, 0 },
325 { "sqcap", NULL, 0, 0 },
326 { "sqcup", NULL, 0, 0 },
327 { "sqrt", NULL, 1, 0 },
328 { "sqsubset", NULL, 0, 0 },
329 { "sqsubseteq", NULL, 0, 0 },
330 { "sqsupset", NULL, 0, 0 },
331 { "sqsupseteq", NULL, 0, 0 },
332 { "star", NULL, 0, 0 },
333 { "sub", "_", 0, 0 },
334 { "subset", NULL, 0, 0 },
335 { "subseteq", NULL, 0, 0 },
336 { "succ", NULL, 0, 0 },
337 { "sum", NULL, 0, 0 },
338 { "sup", "^", 0, 0 },
339 { "superset", NULL, 0, 0 },
340 { "supset", NULL, 0, 0 },
341 { "supseteq", NULL, 0, 0 },
342 { "swarrow", NULL, 0, 0 },
343 { "tan", NULL, 0, 0 },
344 { "tanh", NULL, 0, 0 },
345 { "tau", NULL, 0, EQ_CASE },
346 { "therefore", NULL, 0, 0 },
347 { "theta", NULL, 0, EQ_CASE },
348 { "tilde", "\\widetilde", 1, 0 },
349 { "times", NULL, 0, 0 },
350 { "to", "^", 1, 0 },
351 { "top", NULL, 0, 0 },
352 { "triangle", NULL, 0, 0 },
353 { "triangled", NULL, 0, 0 },
354 { "trianglel", NULL, 0, 0 },
355 { "triangler", NULL, 0, 0 },
356 { "triangleu", NULL, 0, 0 },
357 { "udarrow", "\\updownarrow",0, EQ_CASE },
358 { "under", "\\underline", 1, 0 },
359 { "underline", "\\underline", 1, 0 },
360 { "union", "\\bigcup", 0, 0 },
361 { "uparrow", NULL, 0, EQ_CASE },
362 { "uplus", NULL, 0, 0 },
363 { "upsilon", NULL, 0, EQ_CASE },
364 { "varepsilon", NULL, 0, 0 },
365 { "varphi", NULL, 0, 0 },
366 { "varpi", NULL, 0, 0 },
367 { "varrho", NULL, 0, 0 },
368 { "varsigma", NULL, 0, 0 },
369 { "vartheta", NULL, 0, 0 },
370 { "varupsilon", NULL, 0, 0 },
371 { "vdash", NULL, 0, 0 },
372 { "vdots", NULL, 0, 0 },
373 { "vec", NULL, 1, 0 },
374 { "vee", NULL, 0, 0 },
375 { "vert", NULL, 0, 0 },
376 { "wedge", NULL, 0, 0 },
377 { "wp", NULL, 0, 0 },
378 { "xi", NULL, 0, EQ_CASE },
379 { "xor", NULL, 0, 0 },
380 { "zeta", NULL, 0, EQ_CASE }
383 static hwpeq *lookup_eqn(char *str)
385 static int eqCount = SAL_N_ELEMENTS(eq_tbl);
386 int m, k, l = 0, r = eqCount;
387 hwpeq *result = 0;
389 while( l < r ) {
390 m = (l + r) / 2;
391 k = strcmp(eq_tbl[m].key, str);
392 if( k == 0 ) {
393 result = eq_tbl + m;;
394 break;
396 else if( k < 0 )
397 l = m + 1;
398 else
399 r = m;
401 return result;
404 /* ùÀÚ¸¸ ´ë¹®ÀÚÀ̰ųª ÀüºÎ ´ë¹®ÀÚ¸é ¼Ò¹®ÀÚ·Î ¹Ù²Û´Ù. */
406 static char *make_keyword( char *keyword, const char *token)
408 assert(keyword);
409 char *ptr;
410 int result = true, len = strlen(token);
412 if( 255 < len )
413 strncpy(keyword, token, 255);
414 else
415 strcpy(keyword, token);
417 if( (token[0] & 0x80) || islower(token[0]) ||
418 strlen(token) < 2 )
419 return keyword;
421 int capital = isupper(keyword[1]);
422 for( ptr = keyword + 2; *ptr && result; ptr++ )
423 if( (*ptr & 0x80) ||
424 (!capital && isupper(*ptr)) ||
425 (capital && islower(*ptr)) )
426 result = false;
428 if( result ) {
429 ptr = keyword;
430 while( *ptr ) {
431 if( isupper(*ptr) )
432 *ptr = sal::static_int_cast<char>(tolower(*ptr));
433 ptr++;
436 return keyword;
439 // token reading funtion
440 struct eq_stack {
441 MzString white;
442 MzString token;
443 istream *strm;
445 eq_stack() { strm = 0; };
446 bool state(istream *s) {
447 if( strm != s) { white = 0; token = 0; }
448 return token.length() != 0;
452 static eq_stack *stk = 0;
454 void push_token(MzString &white, MzString &token, istream *strm)
456 // one time stack
457 assert(stk->state(strm) == false);
459 stk->white = white;
460 stk->token = token;
461 stk->strm = strm;
464 /* ÀÐÀº ÅäÅ«ÀÇ ±æÀ̸¦ ¹ÝȯÇÑ´Ù. */
465 /* control char, control sequence, binary sequence,
466 alphabet string, sigle character */
467 static int next_token(MzString &white, MzString &token, istream *strm)
469 register int ch = 0;
471 if( stk->state(strm) ) {
472 white = stk->white;
473 token = stk->token;
474 stk->token = 0;
475 stk->white = 0;
476 return token.length();
479 token = 0;
480 white = 0;
481 if( !strm->good() || (ch = strm->get()) == EOF )
482 return 0;
484 // read preceeding ws
485 if( IS_WS(ch) ) {
486 do white << (char) ch;
487 while( IS_WS(ch = strm->get()) );
490 if( ch == '\\' || ch & 0x80 || isalpha(ch) ) {
491 if( ch == '\\' ) {
492 token << (char) ch;
493 ch = strm->get();
495 do {
496 token << (char) ch;
497 ch = strm->get();
498 } while( ch != EOF && (ch & 0x80 || isalpha(ch)) ) ;
499 strm->putback(sal::static_int_cast<char>(ch));
500 /* sub, sub, over, atop Ư¼ö ó¸®
501 ±× ÀÌÀ¯´Â next_state()¿¡ ¿µÇâÀ» ¹ÌÄ¡±â ¶§¹®ÀÌ´Ù.
503 if( !STRICMP("sub", token) || !STRICMP("from", token) ||
504 !STRICMP("sup", token) || !STRICMP("to", token) ||
505 !STRICMP("over", token) || !STRICMP("atop", token) ||
506 !STRICMP("left", token) || !STRICMP("right", token) )
508 char buf[256];
509 make_keyword(buf, token);
510 token = buf;
512 if( !token.compare("sub") || !token.compare("from") )
513 token = "_";
514 if( !token.compare("sup") || !token.compare("to") )
515 token = "^";
517 else if( IS_BINARY(ch) ) {
518 do token << (char) ch;
519 while( IS_BINARY(ch = strm->get()) );
520 strm->putback(sal::static_int_cast<char>(ch));
522 else if( isdigit(ch) ) {
523 do token << (char) ch;
524 while( isdigit(ch = strm->get()) );
525 strm->putback(sal::static_int_cast<char>(ch));
527 else
528 token << (char) ch;
530 return token.length();
533 static int read_white_space(MzString& outs, istream *strm)
535 int result;
537 if( stk->state(strm) ) {
538 outs << stk->white;
539 stk->white = 0;
540 result = stk->token[0];
542 else {
543 int ch;
544 while( IS_WS(ch = strm->get()) )
545 outs << (char )ch;
546 strm->putback(sal::static_int_cast<char>(ch));
547 result = ch;
549 return result;
552 /* Àμö°¡ ÇÊ¿äÇÏÁö ¾ÊÀº °æ¿ì °¢ Ç׸ñ°£ÀÇ ±¸ºÐÀº space¿Í brace
553 sqrt {ab}c = sqrt{ab} c
554 (, }´Â grouping
555 ^, _ ´Â ¾ÕµÚ·Î °áÇÕÇÑ´Ù.
557 sqrt µî°ú °°ÀÌ Àμö°¡ ÀÖ´Â Çü½Ä Á¤¸®
558 sqrt a -> sqrt{a}
559 sqrt {a} -> sqrt{a}
560 1 ÀÌ»óÀÇ Àμö°¡ ÀÖ´Â °æ¿ì Àμöµé°£ÀÇ ¿ª¹éÀº ¾ø¾Ø´Ù.
561 \frac a b -> frac{a}{b}
562 overÀÇ Çü½Ä Á¤¸®
563 a over b -> {a}over{b}
566 static int eq_word(MzString& outs, istream *strm, int status)
568 MzString token, white, state;
569 int result;
570 char keyword[256];
571 hwpeq *eq;
573 next_token(white, token, strm);
574 if (token.length() <= 0)
575 return 0;
576 result = token[0];
578 if( token.compare("{") == 0 ) {
579 state << white << token;
580 eq_sentence(state, strm, "}");
582 else if( token.compare("left") == 0 ) {
583 state << white << token;
584 next_token(white, token, strm);
585 state << white << token;
587 eq_sentence(state, strm, "right");
589 next_token(white, token, strm);
590 state << white << token;
592 else {
593 /* Á¤»óÀûÀÎ token */
594 int script_status = SCRIPT_NONE;
595 while( 1 ) {
596 state << white << token;
597 make_keyword(keyword, token);
598 if( token[0] == '^' )
599 script_status |= SCRIPT_SUP;
600 else if( token[0] == '_' )
601 script_status |= SCRIPT_SUB;
602 else
603 script_status = SCRIPT_NONE;
605 if( 0 != (eq = lookup_eqn(keyword)) ) {
606 int nargs = eq->nargs;
607 int ch;
608 while( nargs-- ) {
609 ch = read_white_space(state, strm);
610 if( ch != '{' ) state << '{';
611 eq_word(state, strm, script_status);
612 if( ch != '{' ) state << '}';
616 if( !next_token(white, token, strm) )
617 break;
618 // end loop and restart with this
619 if( (token[0] == '^' && status && !(status & SCRIPT_SUP)) ||
620 (token[0] == '_' && status && !(status & SCRIPT_SUB)) ||
621 strcmp("over", token) == 0 || strcmp("atop", token) == 0 ||
622 strchr("{}#&`", token[0]) ||
623 (!strchr("^_", token[0]) && white.length()) ) {
624 push_token(white, token, strm);
625 break;
629 outs << state;
631 return result;
634 static bool eq_sentence(MzString& outs, istream *strm, const char *end)
636 MzString state;
637 MzString white, token;
638 bool multiline = false;
640 read_white_space(outs, strm);
641 while( eq_word(state, strm) ) {
642 if( !next_token(white, token, strm) ||
643 (end && strcmp(token.c_str(), end) == 0) )
645 state << white << token;
646 break;
648 push_token(white, token, strm);
649 if( !token.compare("atop") || !token.compare("over") )
650 outs << '{' << state << '}';
651 else {
652 if( !token.compare("#") )
653 multiline = true;
654 outs << state;
656 state = 0;
657 read_white_space(outs, strm);
659 outs << state;
660 return multiline;
663 static char eq2ltxconv(MzString& sstr, istream *strm, const char *sentinel)
665 MzString white, token;
666 char key[256];
667 int ch, result;
668 hwpeq *eq = 0;
670 while( 0 != (result = next_token(white, token, strm)) ) {
671 if( sentinel && (result == 1) && strchr(sentinel, token[0]) )
672 break;
673 make_keyword(key, token);
674 if( (eq = lookup_eqn(key)) != 0 ) {
675 if( eq->latex )
676 strcpy(key, eq->latex);
677 else {
678 key[0] = '\\';
679 strcpy(key + 1, eq->key);
681 if( (eq->flag & EQ_CASE) && isupper(token[0]) )
682 key[1] = sal::static_int_cast<char>(toupper(key[1]));
683 token = key;
686 if( token[0] == '{' ) { // grouping
687 sstr << white << token;
688 eq2ltxconv(sstr, strm, "}");
689 sstr << '}';
691 else if( eq && (eq->flag & EQ_ENV) ) {
692 next_token(white, token, strm);
693 if( token[0] != '{' ) return 0;
694 sstr << "\\begin" << "{" << eq->key << "}" << ENDL ;
695 eq2ltxconv(sstr, strm, "}");
696 if( sstr[sstr.length() - 1] != '\n' )
697 sstr << ENDL ;
698 sstr << "\\end" << "{" << eq->key << "}" << ENDL ;
700 else if( eq && (eq->flag & EQ_ATOP) ) {
701 if( sstr.length() == 0 )
702 sstr << '{';
703 else {
704 int pos = sstr.rfind('}');
705 if( 0 < pos)
706 sstr.replace(pos, ' ');
708 sstr << token;
709 while( (ch = strm->get()) != EOF && IS_WS(ch) )
710 sstr << (char)ch;
711 if( ch != '{' )
712 sstr << "{}";
713 else {
714 eq2ltxconv(sstr, strm, "}");
715 sstr << '}';
718 else
719 sstr << white << token;
721 return token[0];
724 void eq2latex(MzString& outs, char *s)
726 assert(s);
727 if( stk == 0 )
728 stk = new eq_stack;
730 MzString tstr;
732 istringstream tstrm(s);
733 bool eqnarray = eq_sentence(tstr, &tstrm);
734 istringstream strm(tstr.c_str());
736 if( eqnarray )
737 outs << "\\begin{array}{rllll}" << ENDL;
738 eq2ltxconv(outs, &strm, 0);
739 outs << ENDL;
740 if( eqnarray )
741 outs << "\\end{array}" << ENDL;
742 delete stk;
743 stk = 0;
746 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */