Clover coverage report - QedeqKernelSe Coverage Report
Coverage timestamp: Sa Jan 26 2008 14:11:34 CET
file stats: LOC: 274   Methods: 8
NCLOC: 154   Classes: 1
 
 Source file Conditionals Statements Methods TOTAL
LatexMathParser.java 83,3% 78,4% 87,5% 80,4%
coverage coverage
 1    /* $Id: LatexMathParser.java,v 1.6 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.parser;
 19   
 20    import java.util.ArrayList;
 21    import java.util.List;
 22   
 23    import org.qedeq.kernel.trace.Trace;
 24    import org.qedeq.kernel.utility.TextInput;
 25   
 26    /*
 27    * TODO mime 20080118: refactor
 28    *
 29    * Whitespace LaTeX form, could be eaten
 30    * \t
 31    * \r
 32    * \n
 33    * \\
 34    * \\,
 35    * &
 36    * \\\\
 37    * \\par
 38    * \\quad
 39    * \\qquad
 40    *
 41    * Separator only one allowed, before and after only whitespace is possible
 42    * ,
 43    * |
 44    * $$
 45    * Separator should be read as tokens.
 46    *
 47    * Problem: If some atom like is followed by "(" it should be taken as an
 48    * (function) operator. But if we start with readToken we don't see the "("
 49    * character.
 50    *
 51    * Problem: Could whitespace be recognized?
 52    * Translating whitespace tokens into spaces is not easy, one has to know the
 53    * end of the whitespace token.
 54    * Possible solution:
 55    * function read token (LaTeX specific)
 56    * skip real whitespace (" ", "\t", "\r", "\n")
 57    * read char
 58    * case char
 59    * "\\" read characters or numbers (check LaTeX Syntax)
 60    * "{", "}", "(", ")" are also allowed
 61    * resulting string is token
 62    * LaTeX command definition modifies above:
 63    * Die meisten LATEX-Befehle haben eines der beiden folgenden Formate: Entweder sie beginnen
 64    * mit einem Backslash (\) und haben dann einen nur aus Buchstaben bestehenden Namen, der durch
 65    * ein oder mehrere Leerzeichen oder durch ein nachfolgendes Sonderzeichen oder eine Ziffer beendet
 66    * wird; oder sie bestehen aus einem Backslash und genau einem Sonderzeichen oder einer Ziffer.
 67    * Gross- und Kleinbuchstaben haben auch in Befehlsnamen verschiedene Bedeutung. Wenn man nach
 68    * einem Befehlsnamen eine Leerstelle erhalten will, muss man "{}" zur Beendigung des Befehlsnamens
 69    * oder einen eigenen Befehl f\u00fcr die Leerstelle verwenden.
 70    */
 71   
 72    /**
 73    * Parse LaTeX term or formula data into {@link org.qedeq.kernel.parser.Term}s.
 74    *
 75    * @version $Revision: 1.6 $
 76    * @author Michael Meyling
 77    */
 78    public class LatexMathParser extends MathParser {
 79   
 80    /** This class. */
 81    private static final Class CLASS = LatexMathParser.class;
 82   
 83    /** Characters with special LaTeX meaning. */
 84    private static final String SPECIALCHARACTERS = "(),{}\\~%$&";
 85   
 86    /** Counter for token whitespace lines. */
 87    private int tokenWhiteSpaceLines;
 88   
 89    /**
 90    * Constructor.
 91    *
 92    * @param input Parse this input.
 93    * @param operators List of operators.
 94    */
 95  16 public LatexMathParser(final TextInput input, final List operators) {
 96  16 super(new MementoTextInput(input), operators);
 97    }
 98   
 99   
 100    /**
 101    * Constructor.
 102    *
 103    * @param buffer Parse this input.
 104    * @param operators List of operators.
 105    */
 106  0 public LatexMathParser(final StringBuffer buffer, final List operators) {
 107  0 this(new TextInput(buffer), operators);
 108    }
 109   
 110  2905 protected final String readToken() {
 111  2905 final String method = "readToken()";
 112  2905 Trace.begin(CLASS, this, method);
 113  2905 StringBuffer token = new StringBuffer();
 114  2905 tokenWhiteSpaceLines = 0;
 115  2905 try {
 116  2905 do {
 117  3091 tokenWhiteSpaceLines += readPureWhitespace();
 118  3091 if (tokenWhiteSpaceLines > 1) {
 119  11 break;
 120    }
 121  3080 if (eof()) {
 122  54 if (token.length() <= 0) {
 123  54 token = null;
 124    }
 125  54 break;
 126    }
 127  3026 final int c = getChar();
 128  3026 if (Character.isDigit((char) c)) {
 129  16 token.append((char) readChar());
 130  16 if (Character.isDigit((char) getChar())) {
 131  0 continue;
 132    }
 133  16 break;
 134    }
 135  3010 if (SPECIALCHARACTERS.indexOf(c) >= 0) {
 136  927 switch (c) {
 137  0 case '&':
 138  0 case '%':
 139  22 case '~':
 140  134 case '$': // TODO mime 20060504 or break in this case?
 141  156 readChar();
 142  156 continue;
 143  273 case '\\':
 144  273 final String t = readBackslashToken();
 145  273 if (t.equals(" ") || t.equals("quad") || t.equals("qquad")) {
 146  34 continue;
 147    }
 148  239 token.append(t);
 149  239 if ('_' == getChar() || '^' == getChar()) {
 150  0 token.append((char) readChar());
 151  0 continue;
 152    }
 153  239 break;
 154  0 case '{':
 155  0 readChar();
 156  0 token.append("(");
 157  0 break;
 158  0 case '}':
 159  0 readChar();
 160  0 token.append(")");
 161  0 break;
 162  498 default:
 163  498 readChar();
 164  498 token.append((char) c);
 165  498 if ('_' == getChar() || '^' == getChar()) {
 166  0 token.append((char) readChar());
 167  0 continue;
 168    }
 169    }
 170  737 break;
 171    }
 172  2083 token.append((char) readChar());
 173  2083 if ('_' == getChar() || '^' == getChar()) {
 174  16 token.append((char) readChar());
 175  16 continue;
 176    }
 177  2067 break;
 178    /*
 179    String operator = null;
 180    markPosition();
 181    while (!eof() && (Character.isLetterOrDigit((char) getChar()) || '_' == getChar()
 182    || '^' == getChar())) {
 183    token.append((char) readChar());
 184    if (null != getOperator(token.toString())) {
 185    operator = token.toString();
 186    clearMark();
 187    markPosition();
 188    }
 189    }
 190    if (operator != null) {
 191    rewindPosition();
 192    token.setLength(0);
 193    token.append(operator);
 194    } else {
 195    clearMark();
 196    }
 197    */
 198  206 } while (!eof());
 199  2905 Trace.param(CLASS, this, method, "return token", token);
 200  2905 return (token != null ? token.toString() : null);
 201    } finally {
 202  2905 Trace.end(CLASS, this, method);
 203    }
 204    }
 205   
 206  273 private String readBackslashToken() {
 207  273 final String method = "readBackslashToken()";
 208  273 Trace.begin(CLASS, this, method);
 209  273 if (getChar() != '\\') {
 210  0 throw new IllegalArgumentException("\\ expected");
 211    }
 212  273 readChar(); // read \
 213  273 if (eof()) {
 214  0 Trace.param(CLASS, this, method, "return", null);
 215  0 Trace.end(CLASS, this, method);
 216  0 return null;
 217    }
 218  273 if (!Character.isLetter((char) getChar())) {
 219  46 Trace.param(CLASS, this, method, "return", (char) getChar());
 220  46 Trace.end(CLASS, this, method);
 221  46 return "" + ((char) readChar());
 222    }
 223  227 final StringBuffer buffer = new StringBuffer();
 224  227 do {
 225  930 buffer.append((char) readChar());
 226  930 } while (!eof() && Character.isLetter((char) getChar()));
 227  227 Trace.param(CLASS, this, method, "return", buffer.toString());
 228  227 Trace.end(CLASS, this, method);
 229  227 return buffer.toString();
 230    }
 231   
 232  3091 private int readPureWhitespace() {
 233  3091 int lines = 0;
 234  3091 while (getChar() != -1 && Character.isWhitespace((char) getChar())) {
 235  1570 if ('\n' == (char) getChar()) {
 236  282 lines++;
 237    }
 238  1570 readChar();
 239    }
 240  3091 return lines;
 241    }
 242   
 243  567 protected final Operator getOperator(final String token) {
 244  567 Operator result = null;
 245  567 if (token == null) {
 246  0 return result;
 247    }
 248  567 for (int i = 0; i < getOperators().size(); i++) {
 249  17723 if (token.equals(((Operator) getOperators().get(i)).getStartSymbol())) {
 250  175 result = (Operator) getOperators().get(i);
 251  175 break;
 252    }
 253    }
 254  567 return result;
 255    }
 256   
 257  512 protected final List getOperators(final String token) {
 258  512 final List result = new ArrayList();
 259  512 if (token == null) {
 260  0 return result;
 261    }
 262  512 for (int i = 0; i < getOperators().size(); i++) {
 263  19168 if (token.equals(((Operator) getOperators().get(i)).getStartSymbol())) {
 264  127 result.add(getOperators().get(i));
 265    }
 266    }
 267  512 return result;
 268    }
 269   
 270  870 protected boolean eot(final String token) {
 271  870 return token == null || token.trim().length() == 0;
 272    }
 273   
 274    }