com.legstar.cobol.RecognizerErrorHandler.java Source code

Java tutorial

Introduction

Here is the source code for com.legstar.cobol.RecognizerErrorHandler.java

Source

/*******************************************************************************
 * Copyright (c) 2010 LegSem.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the GNU Lesser Public License v2.1
 * which accompanies this distribution, and is available at
 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
 * 
 * Contributors:
 *     LegSem - initial API and implementation
 ******************************************************************************/
package com.legstar.cobol;

import java.util.ArrayList;
import java.util.List;

import org.antlr.runtime.BaseRecognizer;
import org.antlr.runtime.EarlyExitException;
import org.antlr.runtime.FailedPredicateException;
import org.antlr.runtime.MismatchedTokenException;
import org.antlr.runtime.NoViableAltException;
import org.antlr.runtime.RecognitionException;
import org.antlr.runtime.Token;
import org.antlr.runtime.UnwantedTokenException;
import org.apache.commons.logging.Log;

/**
 * A helper class which does error message formating and also stores
 * all errors reported by recognizers (this is useful for recoverable
 * errors which might be important).
 *
 */
public class RecognizerErrorHandler {

    /** The list of error messages gathered.*/
    private List<String> _errorMessages = new ArrayList<String>();

    /**
     * Format an error message as expected by ANTLR. It is basically the
     * same error message that ANTL BaseRecognizer generates with some
     * additional data.
     * Also used to log debugging information.
     * @param log the logger to use at debug time
     * @param recognizer the lexer or parser who generated the error
     * @param e the exception that occured
     * @param superMessage the error message that the super class generated
     * @param tokenNames list of token names
     * @return a formatted error message
     */
    public static String getErrorMessage(final Log log, final BaseRecognizer recognizer,
            final RecognitionException e, final String superMessage, final String[] tokenNames) {
        if (log.isDebugEnabled()) {
            List<?> stack = BaseRecognizer.getRuleInvocationStack(e,
                    recognizer.getClass().getSuperclass().getName());
            String debugMsg = recognizer.getErrorHeader(e) + " " + e.getClass().getSimpleName() + ": "
                    + superMessage + ":";
            if (e instanceof NoViableAltException) {
                NoViableAltException nvae = (NoViableAltException) e;
                debugMsg += " (decision=" + nvae.decisionNumber + " state=" + nvae.stateNumber + ")"
                        + " decision=<<" + nvae.grammarDecisionDescription + ">>";
            } else if (e instanceof UnwantedTokenException) {
                UnwantedTokenException ute = (UnwantedTokenException) e;
                debugMsg += " (unexpected token=" + toString(ute.getUnexpectedToken(), tokenNames) + ")";

            } else if (e instanceof EarlyExitException) {
                EarlyExitException eea = (EarlyExitException) e;
                debugMsg += " (decision=" + eea.decisionNumber + ")";
            }
            debugMsg += " ruleStack=" + stack.toString();
            log.debug(debugMsg);
        }

        return makeUserMsg(e, superMessage);
    }

    /**
     * Simplify error message text for end users.
     * @param e exception that occurred
     * @param msg as formatted by ANTLR
     * @return a more readable error message
     */
    public static String makeUserMsg(final RecognitionException e, final String msg) {
        if (e instanceof NoViableAltException) {
            return msg.replace("no viable alternative at", "unrecognized");
        } else if (e instanceof UnwantedTokenException) {
            return msg.replace("extraneous input", "unexpected token");
        } else if (e instanceof MismatchedTokenException) {
            if (msg.contains("mismatched input '<EOF>'")) {
                return msg.replace("mismatched input '<EOF>' expecting", "reached end of file looking for");
            } else {
                return msg.replace("mismatched input", "unexpected token");
            }
        } else if (e instanceof EarlyExitException) {
            return msg.replace("required (...)+ loop did not match anything", "required tokens not found");
        } else if (e instanceof FailedPredicateException) {
            if (msg.contains("picture_string failed predicate: {Unbalanced parentheses}")) {
                return "Unbalanced parentheses in picture string";
            }
            if (msg.contains("PICTURE_PART failed predicate: {Contains invalid picture symbols}")) {
                return "Picture string contains invalid symbols";
            }
            if (msg.contains("PICTURE_PART failed predicate: {Syntax error in last picture clause}")) {
                return "Syntax error in last picture clause";
            }
            if (msg.contains("DATA_NAME failed predicate: {Syntax error in last clause}")) {
                return "Syntax error in last COBOL clause";
            }
        }
        return msg;
    }

    /**
     * @param msg the last error message recorded
     */
    public void addMessageToHistory(final String msg) {
        getErrorMessages().add(msg);
    }

    /**
     * Token traces are slightly more readable if numeric type is translated to a readable string.
     * @param token a lexer token
     * @param tokenNames the list of token names
     * @return same as Token.toString but with token type label rather than int
     */
    public static String toString(final Token token, final String[] tokenNames) {
        return token.toString().replace("<" + token.getType() + ">",
                "<" + ((token.getType() > -1) ? tokenNames[token.getType()] : "no type") + ">");
    }

    /**
     * @return the error message history list
     */
    public List<String> getErrorMessages() {
        return _errorMessages;
    }

}