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