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 "formula.h"
21 : #include "grammar.hxx"
22 :
23 : #include "mzstring.h"
24 : #include "nodes.h"
25 : #include "mapping.h"
26 : #include "hwpeq.h"
27 : #include <iostream>
28 : #include <list>
29 :
30 : extern std::list<Node*> nodelist;
31 :
32 : #ifndef DEBUG
33 :
34 : #include "hcode.h"
35 :
36 : #define rstartEl(x,y) do { if (m_rxDocumentHandler.is()) m_rxDocumentHandler->startElement(x,y); } while(false)
37 : #define rendEl(x) do { if (m_rxDocumentHandler.is()) m_rxDocumentHandler->endElement(x); } while(false)
38 : #define rchars(x) do { if (m_rxDocumentHandler.is()) m_rxDocumentHandler->characters(x); } while(false)
39 : #define runistr(x) do { if (m_rxDocumentHandler.is()) m_rxDocumentHandler->characters(OUString(x)); } while(false)
40 : #define reucstr(x,y) do { if (m_rxDocumentHandler.is()) m_rxDocumentHandler->characters(OUString(x,y, RTL_TEXTENCODING_EUC_KR)); } while(false)
41 : #define padd(x,y,z) pList->addAttribute(x,y,z)
42 : #else
43 : static int indent = 0;
44 : #define inds indent++; for(int i = 0 ; i < indent ; i++) fprintf(stderr," ")
45 : #define inde for(int i = 0 ; i < indent ; i++) fprintf(stderr," "); indent--
46 : #define indo indent--;
47 : #endif
48 :
49 0 : void Formula::makeMathML(Node *res)
50 : {
51 0 : Node *tmp = res;
52 0 : if( !tmp ) return;
53 : #ifdef DEBUG
54 : inds;
55 : fprintf(stderr,"<math:math xmlns:math=\"http://www.w3.org/1998/Math/MathML\">\n");
56 : #else
57 0 : padd("xmlns:math", "CDATA", "http://www.w3.org/1998/Math/MathML");
58 0 : rstartEl("math:math", rList);
59 0 : pList->clear();
60 0 : rstartEl("math:semantics", rList);
61 : #endif
62 0 : if( tmp->child )
63 0 : makeLines( tmp->child );
64 :
65 : #ifdef DEBUG
66 : inds;
67 : fprintf(stderr,"<math:semantics/>\n");
68 : indo;
69 : inde;
70 : fprintf(stderr,"</math:math>\n");
71 : #else
72 0 : rendEl("math:semantics");
73 0 : rendEl("math:math");
74 : #endif
75 : }
76 :
77 0 : void Formula::makeLines(Node *res)
78 : {
79 0 : Node *tmp = res;
80 0 : if( !tmp ) return;
81 :
82 0 : if( tmp->child ){
83 0 : if( tmp->child->id == ID_LINES )
84 0 : makeLines( tmp->child );
85 : else
86 0 : makeLine( tmp->child );
87 : }
88 0 : if( tmp->next )
89 0 : makeLine( tmp->next );
90 : }
91 :
92 0 : void Formula::makeLine(Node *res)
93 : {
94 0 : if( !res ) return;
95 : #ifdef DEBUG
96 : inds; fprintf(stderr,"<math:mrow>\n");
97 : #else
98 0 : rstartEl("math:mrow", rList);
99 : #endif
100 0 : if( res->child )
101 0 : makeExprList( res->child );
102 : #ifdef DEBUG
103 : inde; fprintf(stderr,"</math:mrow>\n");
104 : #else
105 0 : rendEl("math:mrow");
106 : #endif
107 : }
108 :
109 0 : void Formula::makeExprList(Node *res)
110 : {
111 0 : if( !res ) return;
112 0 : Node *tmp = res->child;
113 0 : if( !tmp ) return ;
114 :
115 0 : if( tmp->id == ID_EXPRLIST ){
116 0 : Node *next = tmp->next;
117 0 : makeExprList( tmp ) ;
118 0 : if( next )
119 0 : makeExpr( next );
120 : }
121 : else
122 0 : makeExpr( tmp );
123 : }
124 :
125 0 : void Formula::makeExpr(Node *res)
126 : {
127 0 : if( !res ) return;
128 0 : Node *tmp = res->child;
129 0 : if( !tmp ) return;
130 0 : switch( tmp->id ) {
131 : case ID_PRIMARYEXPR:
132 0 : if( tmp->next ){
133 : #ifdef DEBUG
134 : inds;
135 : fprintf(stderr,"<math:mrow>\n");
136 : #else
137 0 : rstartEl("math:mrow", rList);
138 : #endif
139 : }
140 :
141 0 : makePrimary(tmp);
142 :
143 0 : if( tmp->next ){
144 : #ifdef DEBUG
145 : inde; fprintf(stderr,"</math:mrow>\n");
146 : #else
147 0 : rendEl("math:mrow");
148 : #endif
149 : }
150 0 : break;
151 : case ID_SUBEXPR:
152 : case ID_SUPEXPR:
153 : case ID_SUBSUPEXPR:
154 0 : makeSubSup(tmp);
155 0 : break;
156 : case ID_FRACTIONEXPR:
157 : case ID_OVER:
158 0 : makeFraction(tmp);
159 0 : break;
160 : case ID_DECORATIONEXPR:
161 0 : makeDecoration(tmp);
162 0 : break;
163 : case ID_SQRTEXPR:
164 : case ID_ROOTEXPR:
165 0 : makeRoot(tmp);
166 0 : break;
167 : case ID_ARROWEXPR:
168 0 : break;
169 : case ID_ACCENTEXPR:
170 0 : makeAccent(tmp);
171 0 : break;
172 : case ID_PARENTH:
173 : case ID_ABS:
174 0 : makeParenth(tmp);
175 0 : break;
176 : case ID_FENCE:
177 0 : makeFence(tmp);
178 0 : break;
179 : case ID_BLOCK:
180 0 : makeBlock(tmp);
181 : //fall-through
182 : case ID_BEGIN:
183 : //fall-through
184 : case ID_END:
185 0 : break;
186 : }
187 : }
188 :
189 0 : void Formula::makeIdentifier(Node *res)
190 : {
191 0 : Node *tmp = res;
192 0 : if( !tmp ) return;
193 0 : if( !tmp->value ) return;
194 0 : switch( tmp->id ){
195 : case ID_CHARACTER :
196 : #ifdef DEBUG
197 : inds;
198 : fprintf(stderr,"<math:mi>%s</math:mi>\n",tmp->value);
199 : indo;
200 : #else
201 0 : rstartEl("math:mi", rList);
202 0 : rchars(OUString::createFromAscii(tmp->value));
203 0 : rendEl("math:mi");
204 : #endif
205 0 : break;
206 : case ID_STRING :
207 : {
208 : #ifdef DEBUG
209 : #else
210 0 : rstartEl("math:mi", rList);
211 0 : reucstr(tmp->value, strlen(tmp->value));
212 0 : rendEl("math:mi");
213 : #endif
214 : }
215 0 : break;
216 : case ID_IDENTIFIER :
217 : #ifdef DEBUG
218 : inds;
219 : fprintf(stderr,"<math:mi>%s</math:mi>\n",
220 : getMathMLEntity(tmp->value).c_str());
221 : indo;
222 : #else
223 0 : rstartEl("math:mi", rList);
224 0 : runistr(getMathMLEntity(tmp->value).c_str());
225 0 : rendEl("math:mi");
226 : #endif
227 0 : break;
228 : case ID_NUMBER :
229 : #ifdef DEBUG
230 : inds;
231 : fprintf(stderr,"<math:mn>%s</math:mn>\n",tmp->value);
232 : indo;
233 : #else
234 0 : rstartEl("math:mn", rList);
235 0 : rchars(OUString::createFromAscii(tmp->value));
236 0 : rendEl("math:mn");
237 : #endif
238 0 : break;
239 : case ID_OPERATOR :
240 : case ID_DELIMETER :
241 : {
242 : #ifdef DEBUG
243 : inds; fprintf(stderr,"<math:mo>%s</math:mo>\n",tmp->value); indo;
244 : #else
245 0 : rstartEl("math:mo", rList);
246 0 : runistr(getMathMLEntity(tmp->value).c_str());
247 0 : rendEl("math:mo");
248 : #endif
249 0 : break;
250 : }
251 : }
252 : }
253 0 : void Formula::makePrimary(Node *res)
254 : {
255 0 : Node *tmp = res;
256 0 : if( !tmp ) return ;
257 0 : if( tmp->child ){
258 0 : if( tmp->child->id == ID_PRIMARYEXPR ){
259 0 : makePrimary(tmp->child);
260 : }
261 : else{
262 0 : makeIdentifier(tmp->child);
263 : }
264 : }
265 0 : if( tmp->next ){
266 0 : makeIdentifier(tmp->next);
267 : }
268 : }
269 :
270 0 : void Formula::makeSubSup(Node *res)
271 : {
272 0 : Node *tmp = res;
273 0 : if( !tmp ) return;
274 :
275 : #ifdef DEBUG
276 : inds;
277 : if( res->id == ID_SUBEXPR )
278 : fprintf(stderr,"<math:msub>\n");
279 : else if( res->id == ID_SUPEXPR )
280 : fprintf(stderr,"<math:msup>\n");
281 : else
282 : fprintf(stderr,"<math:msubsup>\n");
283 : #else
284 0 : if( res->id == ID_SUBEXPR )
285 0 : rstartEl("math:msub", rList);
286 0 : else if( res->id == ID_SUPEXPR )
287 0 : rstartEl("math:msup", rList);
288 : else
289 0 : rstartEl("math:msubsup", rList);
290 : #endif
291 :
292 0 : tmp = tmp->child;
293 0 : if( res->id == ID_SUBSUPEXPR ) {
294 0 : makeExpr(tmp);
295 0 : makeBlock(tmp->next);
296 0 : makeBlock(tmp->next->next);
297 : }
298 : else{
299 0 : makeExpr(tmp);
300 0 : makeExpr(tmp->next);
301 : }
302 :
303 : #ifdef DEBUG
304 : inde;
305 : if( res->id == ID_SUBEXPR )
306 : fprintf(stderr,"</math:msub>\n");
307 : else if( res->id == ID_SUPEXPR )
308 : fprintf(stderr,"</math:msup>\n");
309 : else
310 : fprintf(stderr,"</math:msubsup>\n");
311 : #else
312 0 : if( res->id == ID_SUBEXPR )
313 0 : rendEl("math:msub");
314 0 : else if( res->id == ID_SUPEXPR )
315 0 : rendEl("math:msup");
316 : else
317 0 : rendEl("math:msubsup");
318 : #endif
319 : }
320 :
321 0 : void Formula::makeFraction(Node *res)
322 : {
323 0 : Node *tmp = res;
324 0 : if( !tmp ) return;
325 :
326 : #ifdef DEBUG
327 : inds;
328 : fprintf(stderr,"<math:mfrac>\n");
329 : #else
330 0 : rstartEl("math:mfrac", rList);
331 : #endif
332 :
333 0 : tmp = tmp->child;
334 : #ifdef DEBUG
335 : inds;
336 : fprintf(stderr,"<math:mrow>\n");
337 : #else
338 0 : rstartEl("math:mrow", rList);
339 : #endif
340 :
341 0 : if( res->id == ID_FRACTIONEXPR )
342 0 : makeBlock(tmp);
343 : else
344 0 : makeExprList(tmp);
345 :
346 : #ifdef DEBUG
347 : inde;
348 : fprintf(stderr,"</math:mrow>\n");
349 : inds;
350 : fprintf(stderr,"<math:mrow>\n");
351 : #else
352 0 : rendEl("math:mrow");
353 0 : rstartEl("math:mrow", rList);
354 : #endif
355 :
356 0 : if( res->id == ID_FRACTIONEXPR )
357 0 : makeBlock(tmp->next);
358 : else
359 0 : makeExprList(tmp->next);
360 :
361 : #ifdef DEBUG
362 : inde;
363 : fprintf(stderr,"</math:mrow>\n");
364 : inde;
365 : fprintf(stderr,"</math:mfrac>\n");
366 : #else
367 0 : rendEl("math:mrow");
368 0 : rendEl("math:mfrac");
369 : #endif
370 : }
371 :
372 0 : void Formula::makeDecoration(Node *res)
373 : {
374 0 : int isover = 1;
375 0 : Node *tmp = res->child;
376 0 : if( !tmp ) return;
377 0 : if( !strncmp(tmp->value,"under", 5) )
378 0 : isover = 0;
379 : #ifdef DEBUG
380 : inds;
381 : if( isover )
382 : fprintf(stderr,"<math:mover>\n");
383 : else
384 : fprintf(stderr,"<math:munder>\n");
385 : #else
386 : /* accent는 언제 true이고, 언제, false인지 모르겠다. */
387 0 : if( isover ){
388 0 : padd("accent","CDATA","true");
389 0 : rstartEl("math:mover", rList);
390 : }
391 : else{
392 0 : padd("accentunder","CDATA","true");
393 0 : rstartEl("math:munder", rList);
394 : }
395 0 : pList->clear();
396 : #endif
397 :
398 0 : makeBlock(tmp->next);
399 :
400 : #ifdef DEBUG
401 : inds;
402 : fprintf(stderr,"<math:mo>%s</math:mo>\n",
403 : getMathMLEntity(tmp->value).c_str());
404 : indo;
405 : #else
406 0 : rstartEl("math:mo", rList);
407 0 : runistr(getMathMLEntity(tmp->value).c_str());
408 0 : rendEl("math:mo");
409 : #endif
410 :
411 : #ifdef DEBUG
412 : inde;
413 : if( isover )
414 : fprintf(stderr,"</math:mover>\n");
415 : else
416 : fprintf(stderr,"</math:munder>\n");
417 : #else
418 0 : if( isover )
419 0 : rendEl("math:mover");
420 : else
421 0 : rendEl("math:munder");
422 : #endif
423 : }
424 :
425 0 : void Formula::makeRoot(Node *res)
426 : {
427 0 : Node *tmp = res;
428 0 : if( !tmp ) return;
429 : #ifdef DEBUG
430 : inds;
431 : if( tmp->id == ID_SQRTEXPR )
432 : fprintf(stderr,"<math:msqrt>\n");
433 : else
434 : fprintf(stderr,"<math:mroot>\n");
435 : #else
436 0 : if( tmp->id == ID_SQRTEXPR )
437 0 : rstartEl("math:msqrt", rList);
438 : else
439 0 : rstartEl("math:mroot", rList);
440 : #endif
441 :
442 0 : if( tmp->id == ID_SQRTEXPR ){
443 0 : makeBlock(tmp->child);
444 : }
445 : else{
446 0 : makeBracket(tmp->child);
447 0 : makeBlock(tmp->child->next);
448 : }
449 :
450 : #ifdef DEBUG
451 : inde;
452 : if( tmp->id == ID_SQRTEXPR )
453 : fprintf(stderr,"</math:msqrt>\n");
454 : else
455 : fprintf(stderr,"</math:mroot>\n");
456 : #else
457 0 : if( tmp->id == ID_SQRTEXPR )
458 0 : rendEl("math:msqrt");
459 : else
460 0 : rendEl("math:mroot");
461 : #endif
462 : }
463 0 : void Formula::makeAccent(Node *res)
464 : {
465 0 : makeDecoration( res );
466 0 : }
467 0 : void Formula::makeParenth(Node *res)
468 : {
469 0 : Node *tmp = res;
470 0 : if( !tmp ) return;
471 : #ifdef DEBUG
472 : inds;
473 : fprintf(stderr,"<math:mrow>\n");
474 : inds;
475 : if( tmp->id == ID_PARENTH ){
476 : fprintf(stderr,"<math:mo>(</math:mo>\n");
477 : }
478 : else
479 : fprintf(stderr,"<math:mo>|</math:mo>\n");
480 : indo; inds;
481 : fprintf(stderr,"<math:mrow>\n");
482 : #else
483 0 : rstartEl("math:mrow", rList);
484 0 : rstartEl("math:mo", rList);
485 0 : if( tmp->id == ID_PARENTH )
486 0 : rchars("(");
487 : else
488 0 : rchars("|");
489 0 : rendEl("math:mo");
490 0 : rstartEl("math:mrow", rList);
491 : #endif
492 :
493 0 : if( tmp->child )
494 0 : makeExprList(tmp->child);
495 :
496 : #ifdef DEBUG
497 : inde;
498 : fprintf(stderr,"</math:mrow>\n");
499 : inds;
500 : if( tmp->id == ID_PARENTH )
501 : fprintf(stderr,"<math:mo>)</math:mo>\n");
502 : else
503 : fprintf(stderr,"<math:mo>|</math:mo>\n");
504 : indo;
505 : inde;
506 : fprintf(stderr,"</math:mrow>\n");
507 : #else
508 0 : rendEl("math:mrow");
509 0 : rstartEl("math:mo", rList);
510 0 : if( tmp->id == ID_PARENTH )
511 0 : rchars(")");
512 : else
513 0 : rchars("|");
514 0 : rendEl("math:mo");
515 0 : rendEl("math:mrow");
516 : #endif
517 : }
518 :
519 0 : void Formula::makeFence(Node *res)
520 : {
521 0 : Node *tmp = res->child;
522 : #ifdef DEBUG
523 : inds;
524 : fprintf(stderr,"<math:mfenced open=\"%s\" close=\"%s\">\n",
525 : getMathMLEntity(tmp->value).c_str(),
526 : getMathMLEntity(tmp->next->next->value).c_str());
527 : #else
528 0 : padd("open", "CDATA",
529 0 : OUString(getMathMLEntity(tmp->value).c_str()) );
530 0 : padd("close", "CDATA",
531 0 : OUString(getMathMLEntity(tmp->next->next->value).c_str()) );
532 0 : rstartEl("math:mfenced", rList);
533 0 : pList->clear();
534 : #endif
535 :
536 0 : makeExprList(tmp->next);
537 :
538 : #ifdef DEBUG
539 : inde;
540 : fprintf(stderr,"</math:mfenced>\n");
541 : #else
542 0 : rendEl("math:mfenced");
543 : #endif
544 0 : }
545 :
546 0 : void Formula::makeBracket(Node *res)
547 : {
548 0 : makeBlock(res);
549 0 : }
550 :
551 0 : void Formula::makeBlock(Node *res)
552 : {
553 : #ifdef DEBUG
554 : inds;
555 : fprintf(stderr,"<math:mrow>\n");
556 : #else
557 0 : rstartEl("math:mrow", rList);
558 : #endif
559 :
560 0 : if( res->child )
561 0 : makeExprList(res->child);
562 :
563 : #ifdef DEBUG
564 : inde;
565 : fprintf(stderr,"</math:mrow>\n");
566 : #else
567 0 : rendEl("math:mrow");
568 : #endif
569 0 : }
570 :
571 0 : int Formula::parse()
572 : {
573 0 : Node *res = 0L;
574 0 : if( !eq ) return 0;
575 0 : if( isHwpEQ ){
576 0 : MzString a;
577 : // fprintf(stderr,"\n\n[BEFORE]\n[%s]\n",eq);
578 0 : eq2latex(a,eq);
579 :
580 0 : int idx=a.find(sal::static_int_cast<char>(0xff));
581 0 : while(idx){
582 : //printf("idx = [%d]\n",idx);
583 0 : a.replace(idx,0x20);
584 0 : if((idx = a.find(sal::static_int_cast<char>(0xff),idx+1)) < 0)
585 0 : break;
586 : }
587 :
588 0 : char *buf = static_cast<char *>(malloc(a.length()+1));
589 0 : bool bStart = false;
590 : int i, j;
591 0 : for( i = 0, j=0 ; i < a.length() ; i++){ // rtrim and ltrim 32 10 13
592 0 : if( bStart ){
593 0 : buf[j++] = a[i];
594 : }
595 : else{
596 0 : if( a[i] != 32 && a[i] != 10 && a[i] != 13){
597 0 : bStart = true;
598 0 : buf[j++] = a[i];
599 : }
600 : }
601 : }
602 0 : buf[j] = 0;
603 0 : for( i = j-1 ; i >= 0 ; i++ ){
604 0 : if( buf[i] == 32 || buf[i] == 10 || buf[i] == 13 ){
605 0 : buf[i] = 0;
606 : }
607 : else
608 : break;
609 : }
610 : // fprintf(stderr,"\n\n[RESULT]\n[%s]\n",a.c_str());
611 0 : if( buf[0] != '\0' )
612 0 : res = mainParse( a.c_str() );
613 : else
614 0 : res = 0L;
615 0 : free(buf);
616 : }
617 : else{
618 0 : res = mainParse( eq );
619 : }
620 :
621 0 : if( res ){
622 0 : makeMathML( res );
623 : }
624 0 : int count = nodelist.size();
625 0 : for( int i = 0 ; i < count ; i++ ){
626 0 : const Node *tmpNode = nodelist.front();
627 0 : nodelist.pop_front();
628 0 : delete tmpNode;
629 : }
630 :
631 0 : return 0;
632 : }
633 :
634 0 : void Formula::trim()
635 : {
636 0 : int len = strlen(eq);
637 0 : char *buf = static_cast<char *>(malloc(len+1));
638 0 : bool bStart = false;
639 : int i, j;
640 0 : for( i = 0, j=0 ; i < len ; i++){ // rtrim and ltrim 32 10 13
641 0 : if( bStart ){
642 0 : buf[j++] = eq[i];
643 : }
644 : else{
645 0 : if( eq[i] != 32 && eq[i] != 10 && eq[i] != 13){
646 0 : bStart = true;
647 0 : buf[j++] = eq[i];
648 : }
649 : }
650 : }
651 0 : buf[j] = 0;
652 0 : for( i = j-1 ; i >= 0 ; i++ ){
653 0 : if( buf[i] == 32 || buf[i] == 10 || buf[i] == 13 ){
654 0 : buf[i] = 0;
655 : }
656 : else
657 : break;
658 : }
659 0 : if( buf[0] != '\0' )
660 0 : strcpy(eq, buf);
661 : else
662 0 : eq = 0L;
663 0 : free(buf);
664 12 : }
665 :
666 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|