Clover coverage report - QedeqKernelSe Coverage Report
Coverage timestamp: Sa Jan 26 2008 14:11:34 CET
file stats: LOC: 398   Methods: 21
NCLOC: 237   Classes: 1
 
 Source file Conditionals Statements Methods TOTAL
LatexTextParser.java 0% 0% 0% 0%
coverage
 1    /* $Id: LatexTextParser.java,v 1.5 2008/01/26 12:39:09 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.5 $
 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 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 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 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 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 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 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 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 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 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 private final void print(final String line) {
 294  0 output.append(line);
 295    }
 296   
 297    /**
 298    * Print end of line.
 299    */
 300  0 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 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 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 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 protected final long rewindPosition() {
 339  0 return input.rewindPosition();
 340    }
 341   
 342    /**
 343    * Forget last remembered position.
 344    */
 345  0 protected final void clearMark() {
 346  0 input.clearMark();
 347    }
 348   
 349    /**
 350    * Get byte position.
 351    *
 352    * @return Position.
 353    */
 354  0 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 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 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 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 public final int getRewindStackSize() {
 395  0 return input.getRewindStackSize();
 396    }
 397   
 398    }