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