156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson/* 256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * Copyright (C) 2010 Google Inc. 356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * 456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * Licensed under the Apache License, Version 2.0 (the "License"); 556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * you may not use this file except in compliance with the License. 656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * You may obtain a copy of the License at 756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * 856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * http://www.apache.org/licenses/LICENSE-2.0 956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * 1056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * Unless required by applicable law or agreed to in writing, software 1156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * distributed under the License is distributed on an "AS IS" BASIS, 1256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * See the License for the specific language governing permissions and 1456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * limitations under the License. 1556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson */ 1656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 1756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonpackage com.google.streamhtmlparser.impl; 1856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 1956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.common.base.Preconditions; 2056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.streamhtmlparser.ExternalState; 2156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.streamhtmlparser.Parser; 2256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.streamhtmlparser.ParseException; 2356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.streamhtmlparser.util.HtmlUtils; 2456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 2556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport java.util.Map; 2656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 2756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson/** 2856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * An implementation of the {@code Parser} interface that is common to both 2956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * {@code HtmlParser} and {@code JavascriptParser}. 3056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * 3156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * <p>Provides methods for parsing input and ensuring that all in-state, 3256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * entering-a-state and exiting-a-state callbacks are invoked as appropriate. 3356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * 3456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * <p>This class started as abstract but it was found better for testing to 3556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * make it instantiatable so that the parsing logic can be tested with dummy 3656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * state transitions. 3756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson */ 3856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonpublic class GenericParser implements Parser { 3956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 4056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson protected final ParserStateTable parserStateTable; 4156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson protected final Map<InternalState, ExternalState> intToExtStateTable; 4256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson protected final InternalState initialState; 4356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson protected InternalState currentState; 4456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson protected int lineNumber; 4556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson protected int columnNumber; 4656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 4756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson protected GenericParser(ParserStateTable parserStateTable, 4856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson Map<InternalState, ExternalState> intToExtStateTable, 4956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson InternalState initialState) { 5056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson this.parserStateTable = parserStateTable; 5156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson this.intToExtStateTable = intToExtStateTable; 5256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson this.initialState = initialState; 5356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson this.currentState = initialState; 5456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson this.lineNumber = 1; 5556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson this.columnNumber = 1; 5656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 5756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 5856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson /** 5956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * Constructs a generic parser that is an exact copy of the 6056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * one given. Note that here too, data structures that do not 6156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * change are shallow-copied (parser state table and state mappings). 6256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * 6356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * @param aGenericParser the {@code GenericParser} to copy 6456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson */ 6556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson protected GenericParser(GenericParser aGenericParser) { 6656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson parserStateTable = aGenericParser.parserStateTable; 6756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson intToExtStateTable = aGenericParser.intToExtStateTable; 6856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson initialState = aGenericParser.initialState; 6956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson currentState = aGenericParser.currentState; 7056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson lineNumber = aGenericParser.lineNumber; 7156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson columnNumber = aGenericParser.columnNumber; 7256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 7356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 7456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson /** 7556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * Tell the parser to process the provided {@code String}. This is just a 7656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * convenience method that wraps over {@link Parser#parse(char)}. 7756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * @param input the {@code String} to parse 7856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * @throws ParseException if an unrecoverable error occurred during parsing 7956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson */ 8056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson @Override 8156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson public void parse(String input) throws ParseException { 8256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson for (int i = 0; i < input.length(); i++) 8356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson parse(input.charAt(i)); 8456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 8556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 8656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson /** 8756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * Main loop for parsing of input. 8856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * 8956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * <p>Absent any callbacks defined, this function simply determines the 9056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * next state to switch to based on the <code>ParserStateTable</code> which is 9156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * derived from a state-machine configuration file in the original C++ parser. 9256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * 9356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * <p>However some states have specific callbacks defined which when 9456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * receiving specific characters may decide to overwrite the next state to 9556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * go to. Hence the next state is a function both of the main state table 9656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * in {@code ParserStateTable} as well as specific run-time information 9756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * from the callback functions. 9856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * 9956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * <p>Also note that the callbacks are called in a proper sequence, 10056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * first the exit-state one then the enter-state one and finally the 10156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * in-state one. Changing the order may result in a functional change. 10256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * 10356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * @param input the input character to parse (process) 10456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * @throws ParseException if an unrecoverable error occurred during parsing 10556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson */ 10656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson @Override 10756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson public void parse(char input) throws ParseException { 10856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson InternalState nextState = 10956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson parserStateTable.getNextState(currentState, input); 11056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 11156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson if (nextState == InternalState.INTERNAL_ERROR_STATE) { 11256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson String errorMsg = 11356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson String.format("Unexpected character '%s' in int_state '%s' " + 11456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson "(ext_state '%s')", 11556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson HtmlUtils.encodeCharForAscii(input), 11656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson currentState.getName(), getState().getName()); 11756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson currentState = InternalState.INTERNAL_ERROR_STATE; 11856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson throw new ParseException(this, errorMsg); 11956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 12056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 12156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson if (currentState != nextState) { 12256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson nextState = handleExitState(currentState, nextState, input); 12356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 12456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson if (currentState != nextState) { 12556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson nextState = handleEnterState(nextState, nextState, input); 12656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 12756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson nextState = handleInState(nextState, input); 12856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson currentState = nextState; 12956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson record(input); 13056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 13156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson columnNumber++; 13256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson if (input == '\n') { 13356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson lineNumber++; 13456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson columnNumber = 1; 13556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 13656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 13756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 13856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson /** 13956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * Return the current state of the parser. 14056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson */ 14156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson @Override 14256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson public ExternalState getState() { 14356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson if (!intToExtStateTable.containsKey(currentState)) { 14456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson throw new NullPointerException("Did not find external state mapping " + 14556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson "For internal state: " + currentState); 14656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 14756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson return intToExtStateTable.get(currentState); 14856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 14956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 15056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson /** 15156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * Reset the parser back to its initial default state. 15256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson */ 15356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson @Override 15456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson public void reset() { 15556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson currentState = initialState; 15656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson lineNumber = 1; 15756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson columnNumber = 1; 15856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 15956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 16056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson /** 16156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * Sets the current line number which is returned during error messages. 16256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson */ 16356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson @Override 16456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson public void setLineNumber(int lineNumber) { 16556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson this.lineNumber = lineNumber; 16656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 16756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 16856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson /** 16956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * Returns the current line number. 17056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson */ 17156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson @Override 17256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson public int getLineNumber() { 17356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson return lineNumber; 17456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 17556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 17656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson /** 17756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * Sets the current column number which is returned during error messages. 17856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson */ 17956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson @Override 18056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson public void setColumnNumber(int columnNumber) { 18156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson this.columnNumber = columnNumber; 18256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 18356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 18456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson /** 18556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * Returns the current column number. 18656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson */ 18756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson @Override 18856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson public int getColumnNumber() { 18956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson return columnNumber; 19056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 19156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 19256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson InternalState getCurrentInternalState() { 19356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson return currentState; 19456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 19556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 19656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson protected void setNextState(InternalState nextState) throws ParseException { 19756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson Preconditions.checkNotNull(nextState); // Developer error if it triggers. 19856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 19956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson /* We are not actually parsing hence providing 20056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * a null char to the event handlers. 20156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson */ 20256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson // TODO: Complicated logic to follow in C++ but clean it up. 20356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson final char nullChar = '\0'; 20456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 20556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson if (currentState != nextState) { 20656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson nextState = handleExitState(currentState, nextState, nullChar); 20756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 20856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson if (currentState != nextState) { 20956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson handleEnterState(nextState, nextState, nullChar); 21056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 21156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson currentState = nextState; 21256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 21356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 21456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson /** 21556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * Invoked when the parser enters a new state. 21656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * 21756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * @param currentState the current state of the parser 21856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * @param expectedNextState the next state according to the 21956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * state table definition 22056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * @param input the last character parsed 22156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * @return the state to change to, could be the same as the 22256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * {@code expectedNextState} provided 22356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * @throws ParseException if an unrecoverable error occurred during parsing 22456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson */ 22556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson protected InternalState handleEnterState(InternalState currentState, 22656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson InternalState expectedNextState, 22756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson char input) throws ParseException { 22856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson return expectedNextState; 22956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 23056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 23156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson /** 23256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * Invoked when the parser exits a state. 23356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * 23456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * @param currentState the current state of the parser 23556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * @param expectedNextState the next state according to the 23656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * state table definition 23756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * @param input the last character parsed 23856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * @return the state to change to, could be the same as the 23956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * {@code expectedNextState} provided 24056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * @throws ParseException if an unrecoverable error occurred during parsing 24156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson */ 24256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson protected InternalState handleExitState(InternalState currentState, 24356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson InternalState expectedNextState, 24456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson char input) throws ParseException { 24556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson return expectedNextState; 24656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 24756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 24856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson /** 24956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * Invoked for each character read when no state change occured. 25056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * 25156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * @param currentState the current state of the parser 25256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * @param input the last character parsed 25356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * @return the state to change to, could be the same as the 25456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * {@code expectedNextState} provided 25556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * @throws ParseException if an unrecoverable error occurred during parsing 25656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson */ 25756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson protected InternalState handleInState(InternalState currentState, 25856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson char input) throws ParseException { 25956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson return currentState; 26056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 26156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 26256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson /** 26356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * Perform some processing on the given character. Derived classes 26456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * may override this method in order to perform additional logic 26556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * on every processed character beyond the logic defined in 26656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * state transitions. 26756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * 26856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * @param input the input character to operate on 26956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson */ 27056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson protected void record(char input) { } 27156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson} 272