Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
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/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
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 .
18 : */
19 :
20 : #include <assert.h>
21 : #include <stdio.h>
22 : #include <string.h>
23 : #include <ctype.h>
24 :
25 : // DVO: always use standard headers:
26 : #include <istream>
27 : #include <sstream>
28 : using namespace std;
29 :
30 : #include "mzstring.h"
31 : #include "hwpeq.h"
32 : #include <sal/types.h>
33 : #include <sal/macros.h>
34 :
35 : /* @Man: hwp¼ö½ÄÀ» LaTeXÀ¸·Î ¹Ù²Ù±â */
36 : #ifdef WIN32
37 : # define ENDL "\r\n"
38 : #else /* !WIN32 */
39 : # define ENDL "\n"
40 : #endif
41 :
42 : #define WS " \t\r\n\v\f"
43 :
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
47 :
48 : #define IS_WS(ch) (strchr(WS, ch))
49 : #define IS_BINARY(ch) (strchr("+-<=>", ch))
50 :
51 : #ifdef WIN32
52 : #define STRICMP stricmp
53 : #else
54 : #define STRICMP strcasecmp
55 : #endif
56 :
57 : // sub and sup scipt script status
58 : enum { SCRIPT_NONE, SCRIPT_SUB, SCRIPT_SUP, SCRIPT_ALL};
59 :
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);
62 :
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?
68 : };
69 :
70 : static const 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 }
381 : };
382 :
383 0 : static const hwpeq *lookup_eqn(char *str)
384 : {
385 : static const int eqCount = SAL_N_ELEMENTS(eq_tbl);
386 0 : int m, k, l = 0, r = eqCount;
387 0 : const hwpeq *result = 0;
388 :
389 0 : while( l < r ) {
390 0 : m = (l + r) / 2;
391 0 : k = strcmp(eq_tbl[m].key, str);
392 0 : if( k == 0 ) {
393 0 : result = eq_tbl + m;;
394 0 : break;
395 : }
396 0 : else if( k < 0 )
397 0 : l = m + 1;
398 : else
399 0 : r = m;
400 : }
401 0 : return result;
402 : }
403 :
404 : /* ùÀÚ¸¸ ´ë¹®ÀÚÀ̰ųª ÀüºÎ ´ë¹®ÀÚ¸é ¼Ò¹®ÀÚ·Î ¹Ù²Û´Ù. */
405 :
406 0 : static char *make_keyword( char *keyword, const char *token)
407 : {
408 : assert(keyword);
409 : char *ptr;
410 0 : bool result = true;
411 0 : int len = strlen(token);
412 :
413 0 : if( 255 < len )
414 0 : strncpy(keyword, token, 255);
415 : else
416 0 : strcpy(keyword, token);
417 :
418 0 : if( (token[0] & 0x80) || islower(token[0]) ||
419 0 : strlen(token) < 2 )
420 0 : return keyword;
421 :
422 0 : int capital = isupper(keyword[1]);
423 0 : for( ptr = keyword + 2; *ptr && result; ptr++ )
424 0 : if( (*ptr & 0x80) ||
425 0 : (!capital && isupper(*ptr)) ||
426 0 : (capital && islower(*ptr)) )
427 0 : result = false;
428 :
429 0 : if( result ) {
430 0 : ptr = keyword;
431 0 : while( *ptr ) {
432 0 : if( isupper(*ptr) )
433 0 : *ptr = sal::static_int_cast<char>(tolower(*ptr));
434 0 : ptr++;
435 : }
436 : }
437 0 : return keyword;
438 : }
439 :
440 : // token reading funtion
441 0 : struct eq_stack {
442 : MzString white;
443 : MzString token;
444 : istream *strm;
445 :
446 0 : eq_stack() { strm = 0; };
447 0 : bool state(istream *s) {
448 0 : if( strm != s) { white = 0; token = 0; }
449 0 : return token.length() != 0;
450 : }
451 : };
452 :
453 : static eq_stack *stk = 0;
454 :
455 0 : void push_token(MzString &white, MzString &token, istream *strm)
456 : {
457 : // one time stack
458 : assert(stk->state(strm) == false);
459 :
460 0 : stk->white = white;
461 0 : stk->token = token;
462 0 : stk->strm = strm;
463 0 : }
464 :
465 : /*
ÀÐÀº ÅäÅ«ÀÇ ±æÀ̸¦ ¹ÝȯÇÑ´Ù. */
466 : /* control char, control sequence, binary sequence,
467 : alphabet string, sigle character */
468 : static int next_token(MzString &white, MzString &token, istream *strm)
469 0 : {
470 : int ch = 0;
471 0 :
472 : if( stk->state(strm) ) {
473 0 : white = stk->white;
474 0 : token = stk->token;
475 0 : stk->token = 0;
476 0 : stk->white = 0;
477 0 : return token.length();
478 0 : }
479 :
480 : token = 0;
481 0 : white = 0;
482 0 : if( !strm->good() || (ch = strm->get()) == EOF )
483 0 : return 0;
484 0 :
485 : // read preceeding ws
486 : if( IS_WS(ch) ) {
487 0 : do white << (char) ch;
488 0 : while( IS_WS(ch = strm->get()) );
489 0 : }
490 :
491 : if( ch == '\\' || ch & 0x80 || isalpha(ch) ) {
492 0 : if( ch == '\\' ) {
493 0 : token << (char) ch;
494 0 : ch = strm->get();
495 0 : }
496 : do {
497 0 : token << (char) ch;
498 0 : ch = strm->get();
499 0 : } while( ch != EOF && (ch & 0x80 || isalpha(ch)) ) ;
500 0 : strm->putback(sal::static_int_cast<char>(ch));
501 0 : /* sub, sub, over, atop Ư¼ö ó¸®
502 : ±× ÀÌÀ¯´Â next_state()¿¡ ¿µÇâÀ» ¹ÌÄ¡±â ¶§¹®ÀÌ´Ù.
503 : */
504 : if( !STRICMP("sub", token) || !STRICMP("from", token) ||
505 0 : !STRICMP("sup", token) || !STRICMP("to", token) ||
506 0 : !STRICMP("over", token) || !STRICMP("atop", token) ||
507 0 : !STRICMP("left", token) || !STRICMP("right", token) )
508 0 : {
509 : char buf[256];
510 : make_keyword(buf, token);
511 0 : token = buf;
512 0 : }
513 : if( !token.compare("sub") || !token.compare("from") )
514 0 : token = "_";
515 0 : if( !token.compare("sup") || !token.compare("to") )
516 0 : token = "^";
517 0 : }
518 : else if( IS_BINARY(ch) ) {
519 0 : do token << (char) ch;
520 0 : while( IS_BINARY(ch = strm->get()) );
521 0 : strm->putback(sal::static_int_cast<char>(ch));
522 0 : }
523 : else if( isdigit(ch) ) {
524 0 : do token << (char) ch;
525 0 : while( isdigit(ch = strm->get()) );
526 0 : strm->putback(sal::static_int_cast<char>(ch));
527 0 : }
528 : else
529 : token << (char) ch;
530 0 :
531 : return token.length();
532 0 : }
533 :
534 : static int read_white_space(MzString& outs, istream *strm)
535 0 : {
536 : int result;
537 :
538 : if( stk->state(strm) ) {
539 0 : outs << stk->white;
540 0 : stk->white = 0;
541 0 : result = stk->token[0];
542 0 : }
543 : else {
544 : int ch;
545 : while( IS_WS(ch = strm->get()) )
546 0 : outs << (char )ch;
547 0 : strm->putback(sal::static_int_cast<char>(ch));
548 0 : result = ch;
549 0 : }
550 : return result;
551 0 : }
552 :
553 : /* Àμö°¡ ÇÊ¿äÇÏÁö ¾ÊÀº °æ¿ì °¢ Ç׸ñ°£ÀÇ ±¸ºÐÀº space¿Í brace
554 : sqrt {ab}c = sqrt{ab} c
555 : (, }´Â grouping
556 : ^, _ ´Â ¾ÕµÚ·Î °áÇÕÇÑ´Ù.
557 :
558 : sqrt µî°ú °°ÀÌ Àμö°¡ ÀÖ´Â Çü½Ä Á¤¸®
559 : sqrt a -> sqrt{a}
560 : sqrt {a} -> sqrt{a}
561 : 1 ÀÌ»óÀÇ Àμö°¡ ÀÖ´Â °æ¿ì Àμöµé°£ÀÇ ¿ª¹éÀº ¾ø¾Ø´Ù.
562 : \frac a b -> frac{a}{b}
563 : overÀÇ Çü½Ä Á¤¸®
564 : a over b -> {a}over{b}
565 : */
566 :
567 : static int eq_word(MzString& outs, istream *strm, int status)
568 0 : {
569 : MzString token, white, state;
570 0 : int result;
571 : char keyword[256];
572 : const hwpeq *eq;
573 :
574 : next_token(white, token, strm);
575 0 : if (token.length() <= 0)
576 0 : return 0;
577 0 : result = token[0];
578 0 :
579 : if( token.compare("{") == 0 ) {
580 0 : state << white << token;
581 0 : eq_sentence(state, strm, "}");
582 0 : }
583 : else if( token.compare("left") == 0 ) {
584 0 : state << white << token;
585 0 : next_token(white, token, strm);
586 0 : state << white << token;
587 0 :
588 : eq_sentence(state, strm, "right");
589 0 :
590 : next_token(white, token, strm);
591 0 : state << white << token;
592 0 : }
593 : else {
594 : /* Á¤»óÀûÀÎ token */
595 : int script_status = SCRIPT_NONE;
596 0 : while( true ) {
597 : state << white << token;
598 0 : make_keyword(keyword, token);
599 0 : if( token[0] == '^' )
600 0 : script_status |= SCRIPT_SUP;
601 0 : else if( token[0] == '_' )
602 0 : script_status |= SCRIPT_SUB;
603 0 : else
604 : script_status = SCRIPT_NONE;
605 0 :
606 : if( 0 != (eq = lookup_eqn(keyword)) ) {
607 0 : int nargs = eq->nargs;
608 0 : int ch;
609 : while( nargs-- ) {
610 0 : ch = read_white_space(state, strm);
611 0 : if( ch != '{' ) state << '{';
612 0 : eq_word(state, strm, script_status);
613 0 : if( ch != '{' ) state << '}';
614 0 : }
615 : }
616 :
617 : if( !next_token(white, token, strm) )
618 0 : break;
619 0 : // end loop and restart with this
620 : if( (token[0] == '^' && status && !(status & SCRIPT_SUP)) ||
621 0 : (token[0] == '_' && status && !(status & SCRIPT_SUB)) ||
622 0 : strcmp("over", token) == 0 || strcmp("atop", token) == 0 ||
623 0 : strchr("{}#&`", token[0]) ||
624 0 : (!strchr("^_", token[0]) && white.length()) ) {
625 0 : push_token(white, token, strm);
626 0 : break;
627 0 : }
628 : }
629 0 : }
630 : outs << state;
631 0 :
632 : return result;
633 0 : }
634 :
635 : static bool eq_sentence(MzString& outs, istream *strm, const char *end)
636 0 : {
637 : MzString state;
638 0 : MzString white, token;
639 0 : bool multiline = false;
640 0 :
641 : read_white_space(outs, strm);
642 0 : while( eq_word(state, strm) ) {
643 0 : if( !next_token(white, token, strm) ||
644 0 : (end && strcmp(token.c_str(), end) == 0) )
645 0 : {
646 : state << white << token;
647 0 : break;
648 0 : }
649 : push_token(white, token, strm);
650 0 : if( !token.compare("atop") || !token.compare("over") )
651 0 : outs << '{' << state << '}';
652 0 : else {
653 : if( !token.compare("#") )
654 0 : multiline = true;
655 0 : outs << state;
656 0 : }
657 : state = 0;
658 0 : read_white_space(outs, strm);
659 0 : }
660 : outs << state;
661 0 : return multiline;
662 0 : }
663 :
664 : static char eq2ltxconv(MzString& sstr, istream *strm, const char *sentinel)
665 0 : {
666 : MzString white, token;
667 0 : char key[256];
668 : int ch, result;
669 : const hwpeq *eq = 0;
670 0 :
671 : while( 0 != (result = next_token(white, token, strm)) ) {
672 0 : if( sentinel && (result == 1) && strchr(sentinel, token[0]) )
673 0 : break;
674 0 : make_keyword(key, token);
675 0 : if( (eq = lookup_eqn(key)) != 0 ) {
676 0 : if( eq->latex )
677 0 : strcpy(key, eq->latex);
678 0 : else {
679 : key[0] = '\\';
680 0 : strcpy(key + 1, eq->key);
681 0 : }
682 : if( (eq->flag & EQ_CASE) && isupper(token[0]) )
683 0 : key[1] = sal::static_int_cast<char>(toupper(key[1]));
684 0 : token = key;
685 0 : }
686 :
687 : if( token[0] == '{' ) { // grouping
688 0 : sstr << white << token;
689 0 : eq2ltxconv(sstr, strm, "}");
690 0 : sstr << '}';
691 0 : }
692 : else if( eq && (eq->flag & EQ_ENV) ) {
693 0 : next_token(white, token, strm);
694 0 : if( token[0] != '{' ) return 0;
695 0 : sstr << "\\begin" << "{" << eq->key << "}" << ENDL ;
696 0 : eq2ltxconv(sstr, strm, "}");
697 0 : if( sstr[sstr.length() - 1] != '\n' )
698 0 : sstr << ENDL ;
699 0 : sstr << "\\end" << "{" << eq->key << "}" << ENDL ;
700 0 : }
701 : else if( eq && (eq->flag & EQ_ATOP) ) {
702 0 : if( sstr.length() == 0 )
703 0 : sstr << '{';
704 0 : else {
705 : int pos = sstr.rfind('}');
706 0 : if( 0 < pos)
707 0 : sstr.replace(pos, ' ');
708 0 : }
709 : sstr << token;
710 0 : while( (ch = strm->get()) != EOF && IS_WS(ch) )
711 0 : sstr << (char)ch;
712 0 : if( ch != '{' )
713 0 : sstr << "{}";
714 0 : else {
715 : eq2ltxconv(sstr, strm, "}");
716 0 : sstr << '}';
717 0 : }
718 0 : }
719 : else
720 : sstr << white << token;
721 0 : }
722 : return token[0];
723 0 : }
724 :
725 : void eq2latex(MzString& outs, char *s)
726 0 : {
727 : assert(s);
728 : if( stk == 0 )
729 0 : stk = new eq_stack;
730 0 :
731 : MzString tstr;
732 0 :
733 : istringstream tstrm(s);
734 0 : bool eqnarray = eq_sentence(tstr, &tstrm);
735 0 : istringstream strm(tstr.c_str());
736 0 :
737 : if( eqnarray )
738 0 : outs << "\\begin{array}{rllll}" << ENDL;
739 0 : eq2ltxconv(outs, &strm, 0);
740 0 : outs << ENDL;
741 0 : if( eqnarray )
742 0 : outs << "\\end{array}" << ENDL;
743 0 : delete stk;
744 0 : stk = 0;
745 0 : }
746 0 :
747 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|