Clover Coverage Report
Coverage timestamp: Sa Aug 2 2008 13:56:27 CEST
../../../../../../img/srcFileCovDistChart0.png 88% of files have more coverage
151   398   64   7,19
64   237   0,42   21
21     3,05  
1    
 
  LatexTextParser       Line # 30 151 64 0% 0.0
 
No Tests
 
1    /* $Id: LatexTextParser.java,v 1.1 2008/07/26 07:58:28 m31 Exp $
2    *
3    * This file is part of the project "Hilbert II" - http://www.qedeq.org
4    *
5    * Copyright 2000-2008, Michael Meyling <mime@qedeq.org>.
6    *
7    * "Hilbert II" is free software; you can redistribute
8    * it and/or modify it under the terms of the GNU General Public
9    * License as published by the Free Software Foundation; either
10    * version 2 of the License, or (at your option) any later version.
11    *
12    * This program is distributed in the hope that it will be useful,
13    * but WITHOUT ANY WARRANTY; without even the implied warranty of
14    * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15    * GNU General Public License for more details.
16    */
17   
18    package org.qedeq.kernel.bo.service.latex;
19   
20    import org.qedeq.base.io.TextInput;
21    import org.qedeq.base.trace.Trace;
22    import org.qedeq.kernel.bo.parser.MementoTextInput;
23   
24    /**
25    * Transform LaTeX into QEDEQ format.
26    *
27    * @version $Revision: 1.1 $
28    * @author Michael Meyling
29    */
 
30    public final class LatexTextParser {
31   
32    /** This class. */
33    private static final Class CLASS = LatexTextParser.class;
34   
35    /** These characters get a special treatment in LaTeX. */
36    private static final String SPECIALCHARACTERS = "(),{}\\~%$&";
37   
38    /** This is our input stream .*/
39    private MementoTextInput input;
40   
41    /** Herein goes our output. */
42    private StringBuffer output;
43   
44    /**
45    * Parse LaTeX text into QEDEQ module string.
46    *
47    * @param input Parse this input.
48    * @return QEDEQ module string.
49    */
 
50  0 toggle public static final String transform(final String input) {
51  0 final LatexTextParser parser = new LatexTextParser(input);
52  0 return parser.parse();
53    }
54   
55    /**
56    * Constructor.
57    *
58    * @param input Parse this input.
59    */
 
60  0 toggle private LatexTextParser(final String input) {
61  0 this.input = new MementoTextInput(new TextInput(input));
62  0 this.output = new StringBuffer();
63    }
64   
65    /**
66    * Do parsing.
67    *
68    * @return QEDEQ module string.
69    */
 
70  0 toggle private String parse() {
71  0 while (!eof()) {
72  0 final String token = readToken();
73  0 if ("\\begin".equals(token)) {
74  0 final String curly = readCurlyBraceContents();
75  0 if ("eqnarray".equals(curly)) {
76  0 printMathTillEnd(curly);
77  0 } else if ("eqnarray*".equals(curly)) {
78  0 printMathTillEnd(curly);
79  0 } else if ("equation".equals(curly)) {
80  0 printMathTillEnd(curly);
81  0 } else if ("equation*".equals(curly)) {
82  0 printMathTillEnd(curly);
83    } else {
84  0 print(token + "{" + curly + "}");
85    }
86  0 } else if ("$$".equals(token)) {
87  0 println();
88  0 println("<MATH>");
89  0 printMathTillToken(token);
90  0 println("\\,</MATH>");
91  0 println();
92  0 } else if ("$".equals(token)) {
93  0 print("<MATH>");
94  0 printMathTillToken(token);
95  0 print("\\,</MATH>");
96    } else {
97  0 print(token);
98    }
99    }
100  0 return output.toString();
101    }
102   
 
103  0 toggle private void printMathTillEnd(final String curly) {
104  0 final StringBuffer buffer = new StringBuffer();
105  0 do {
106  0 final String item = readToken();
107  0 if ("\\end".equals(item)) {
108  0 final String curly2 = readCurlyBraceContents();
109  0 if (curly.equals(curly2)) {
110  0 break;
111    }
112  0 buffer.append(item + "{" + curly2 + "}");
113    } else {
114  0 buffer.append(item);
115    }
116    } while (true);
117   
118    /*
119    println("\\begin{" + curly + "}");
120    println(buffer);
121    println("\\end{" + curly + "}");
122    println();
123    */
124  0 printMath(buffer);
125    }
126   
127    /**
128    * Print math content till <code>token</code> occurs.
129    *
130    * @param token Terminator token.
131    */
 
132  0 toggle private void printMathTillToken(final String token) {
133  0 final StringBuffer buffer = new StringBuffer();
134  0 do {
135  0 final String item = readToken();
136  0 if (token.equals(item)) {
137  0 break;
138    } else {
139  0 buffer.append(item);
140    }
141    } while (true);
142  0 printMath(buffer);
143    }
144   
145    /**
146    * Print math content.
147    *
148    * @param buffer This should be printed as mathematical content.
149    */
 
150  0 toggle private void printMath(final StringBuffer buffer) {
151  0 print(buffer.toString());
152    }
153   
154    /**
155    * Read next token from input stream.
156    *
157    * @return Read token.
158    */
 
159  0 toggle protected final String readToken() {
160  0 final String method = "readToken()";
161  0 Trace.begin(CLASS, this, method);
162  0 StringBuffer token = new StringBuffer();
163  0 try {
164  0 do {
165  0 if (eof()) {
166  0 if (token.length() <= 0) {
167  0 token = null;
168    }
169  0 break;
170    }
171  0 final int c = getChar();
172  0 if (Character.isDigit((char) c)) {
173  0 token.append((char) readChar());
174  0 if (Character.isDigit((char) getChar())) {
175  0 continue;
176    }
177  0 break;
178    }
179  0 if (Character.isLetter((char) c)) {
180  0 token.append((char) readChar());
181  0 if (Character.isLetter((char) getChar())) {
182  0 continue;
183    }
184  0 break;
185    }
186  0 if (SPECIALCHARACTERS.indexOf(c) >= 0) {
187  0 switch (c) {
188  0 case '&':
189  0 case '%':
190  0 case '{':
191  0 case '}':
192  0 case '~':
193  0 token.append((char) readChar());
194  0 break;
195  0 case '$':
196  0 token.append((char) readChar());
197  0 if ('$' == getChar()) {
198  0 continue;
199    }
200  0 break;
201  0 case '\\':
202  0 final String t = readBackslashToken();
203  0 token.append(t);
204  0 if ('_' == getChar() || '^' == getChar()) {
205  0 token.append((char) readChar());
206  0 continue;
207    }
208  0 break;
209  0 default:
210  0 readChar();
211  0 token.append((char) c);
212    }
213  0 break;
214    }
215  0 token.append((char) readChar());
216  0 if ('_' == getChar() || '^' == getChar()) {
217  0 token.append((char) readChar());
218  0 continue;
219    }
220  0 break;
221  0 } while (!eof());
222  0 Trace.param(CLASS, this, method, "Read token", token);
223  0 return (token != null ? token.toString() : null);
224    } finally {
225  0 Trace.end(CLASS, this, method);
226    }
227    }
228   
229    /**
230    * Get token that starts with a backlash. The backslash itself is removed from the token.
231    *
232    * @return Token (without backslash).
233    */
 
234  0 toggle private String readBackslashToken() {
235  0 final String method = "readBackslashToken()";
236  0 Trace.begin(CLASS, this, method);
237  0 if (getChar() != '\\') {
238  0 throw new IllegalArgumentException("\\ expected");
239    }
240  0 readChar(); // read \
241  0 if (eof()) {
242  0 Trace.param(CLASS, this, method, "return", null);
243  0 Trace.end(CLASS, this, method);
244  0 return null;
245    }
246  0 if (!Character.isLetter((char) getChar())) {
247  0 Trace.param(CLASS, this, method, "return", (char) getChar());
248  0 Trace.end(CLASS, this, method);
249  0 return "\\" + ((char) readChar());
250    }
251  0 final StringBuffer buffer = new StringBuffer("\\");
252  0 do {
253  0 buffer.append((char) readChar());
254  0 } while (!eof() && Character.isLetter((char) getChar()));
255  0 Trace.param(CLASS, this, method, "return", buffer.toString());
256  0 Trace.end(CLASS, this, method);
257  0 return buffer.toString();
258    }
259   
260    /**
261    * Read contents that is within { .. }.
262    *
263    * @return Contents.
264    */
 
265  0 toggle private String readCurlyBraceContents() {
266  0 final String first = readToken();
267  0 if (!"{".equals(first)) {
268  0 throw new IllegalArgumentException("\"{\" expected, but was: \"" + first + "\"");
269    }
270  0 final StringBuffer buffer = new StringBuffer();
271  0 String next;
272  0 int level = 1;
273  0 while (level > 0) {
274  0 next = readToken();
275  0 if ("{".equals(next)) {
276  0 level++;
277  0 } else if ("}".equals(next)) {
278  0 level--;
279    }
280  0 if (level <= 0) {
281  0 break;
282    }
283  0 buffer.append(next);
284    }
285  0 return buffer.toString();
286    }
287   
288    /**
289    * Print <code>line</code> to output stream.
290    *
291    * @param line Print this.
292    */
 
293  0 toggle private final void print(final String line) {
294  0 output.append(line);
295    }
296   
297    /**
298    * Print end of line.
299    */
 
300  0 toggle private final void println() {
301  0 println("");
302    }
303   
304    /**
305    * Print <code>line</code> and start new line to output stream.
306    *
307    * @param line Print this.
308    */
 
309  0 toggle private final void println(final String line) {
310  0 print(line);
311  0 print("\n");
312    }
313   
314    /**
315    * Read next token from input but don't move reading position.
316    *
317    * @return Token read, is <code>null</code> if end of data reached.
318    */
 
319  0 toggle public final String getToken() {
320  0 markPosition();
321  0 final String result = readToken();
322  0 rewindPosition();
323  0 return result;
324    }
325   
326    /**
327    * Remember current position.
328    */
 
329  0 toggle protected final void markPosition() {
330  0 input.markPosition();
331    }
332   
333    /**
334    * Rewind to previous marked position. Also clears the mark.
335    *
336    * @return Current position before pop.
337    */
 
338  0 toggle protected final long rewindPosition() {
339  0 return input.rewindPosition();
340    }
341   
342    /**
343    * Forget last remembered position.
344    */
 
345  0 toggle protected final void clearMark() {
346  0 input.clearMark();
347    }
348   
349    /**
350    * Get byte position.
351    *
352    * @return Position.
353    */
 
354  0 toggle protected long getPosition() {
355  0 return input.getPosition();
356    }
357   
358    /**
359    * Reads a single character and does not change the reading
360    * position.
361    *
362    * @return character read, if there are no more chars
363    * <code>Character.MAX_VALUE</code> is returned
364    */
 
365  0 toggle protected final int getChar() {
366  0 return input.getChar();
367    }
368   
369    /**
370    * Reads a single character and increments the reading position
371    * by one.
372    *
373    * @return character read, if there are no more chars
374    * <code>Character.MAX_VALUE</code> is returned
375    */
 
376  0 toggle protected final int readChar() {
377  0 return input.readChar();
378    }
379   
380    /**
381    * Are there still any characters to read?
382    *
383    * @return Anything left for reading further?
384    */
 
385  0 toggle public final boolean eof() {
386  0 return input.eof();
387    }
388   
389    /**
390    * Get rewind stack size.
391    *
392    * @return Rewind stack size.
393    */
 
394  0 toggle public final int getRewindStackSize() {
395  0 return input.getRewindStackSize();
396    }
397   
398    }