A simple expression parser

First the basic requirements. You have an “arbitrary” delimited string which you need to parse. Whitespace counts. So for example, you might have something like:

X:456 T=900; 123456

and you want to be able to express this in by an expression like:

X:${x-value} T:${t-value}; ${other}

So, giving your parser this pattern where keys are represented like ${this} and then feeding it the first string above you want to generate a key, value map (java.util.Map) where, for this example, x-value = 456, t-value = 900 and other = 123456. Note that this is somewhat backwards from something you might see in a template language like Velocity. It doesn’t have to be very forgiving about bad patterns or pieces of text yet. Got it?

Here’s my sample code:

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
/**
  * A simple expression parser
  * Copyright 2004 J Aaron Farr
  * 
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
  *  You may obtain a copy of the License at
  * 
  *     http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
 */
public class ExpressionParser {
  protected static final String TOKEN_START = "${";
  protected static final String TOKEN_END = "}";
  // m_pattern holds the tokenized pattern string
  public ArrayList m_pattern = new ArrayList();
  // m_keyLocations holds Integers which identify indices in 
  // m_pattern which are ${keys}
  public ArrayList m_keyLocations = new ArrayList();
  public ExpressionParser() {
  }
  /**
   * set and parse the pattern string
   */
  public void setPattern(String pattern) {
    int cursor = 0;
    while (cursor < pattern.length()) {
      int[] indices = getNextTokenLocation(pattern, cursor);
      if (indices[0] != -1) {
        // if first element is a token
        if (indices[0] == 0) {
          m_pattern.add(extractToken(pattern, indices));
          m_keyLocations.add(new Integer(m_pattern.size() - 1));
          cursor = indices[1] + 1;
        }
        // just a regular token 
        else {
          m_pattern.add(pattern.substring(cursor, indices[0]));
          m_pattern.add(extractToken(pattern, indices));
          m_keyLocations.add(new Integer(m_pattern.size() - 1));
          cursor = indices[1] + 1;
        }
      }
      // add any left over characters in the pattern past the last key
      else if (cursor != pattern.length()) {
        m_pattern.add(pattern.substring(cursor + 1));
        cursor = pattern.length();
      }
    }
  }
  /**
   * parse the string of text against the pattern
   * @return a map of key value pairs
   */
  public Map parse(String text) {
    Map map = new HashMap();
    int cursor = 0;
    for (int i = 0; i < m_keyLocations.size(); i++) {
      int keyIndex = ((Integer) m_keyLocations.get(i)).intValue();
      // key at start of pattern
      if (keyIndex == 0) {
        String key = (String) m_pattern.get(0);
        // make sure there's something else in the pattern
        if (m_pattern.size() > 1) {
          String next = (String) m_pattern.get(1);
          int nextIndex = text.indexOf(next);
          String value = text.substring(0, nextIndex);
          map.put(key