
package org.openspml.browser;

import java.util.*;

/**
 * Very simple expression language lexical analyzer.
 * Developed to parse SPML queries, may have other uses.
 */
public class Lexer {

    char[] _src;
    int _max;
    int _psn;
    StringBuffer _b = new StringBuffer();

    public Lexer(String s) {
        if (s != null) {
            _src = s.toCharArray();
            _max = _src.length; 
        }
    }

    /**
     * Advance to the next non-whitespace character.
     */
    public void skipSpace() {
        while (_psn < _max && Character.isWhitespace(_src[_psn]))
            _psn++;
    }

    /**
     * Parse the next token.  Symbols are normally delimited by whitespace
     * or the operator characters =<>.  Quoted strings are delimited
     * by " or '.  The escape character \ may be used within strings.
     *
     * Assume for now that an unquoted symbol will not contain embedded
     * spaces, and may only contain . $ [
     */
    public String nextToken() {

        String tok = null;
        skipSpace();
        _b.setLength(0);

        if (_psn < _max) {
            char next = _src[_psn];
            if (next == '"' || next == '\'') {
                // quoted string
                char delim = next;
                _psn++;
                boolean escape = false;
                while (_psn < _max) {
                    next = _src[_psn];
                    _psn++;
                    if (escape) {
                        _b.append(next);
                        escape = false;
                    }
                    else if (next == '\\')
                        escape = true;
                    else if (next == delim) {
                        _psn++;
                        break;
                    }
                    else
                        _b.append(next);
                }
            }
            else if (isOperatorChar(next)) {
                // logical operator
                do {
                    _b.append(next);
                    _psn++;
                    next = 0;
                    if (_psn < _max)
                        next = _src[_psn];
                } 
                while (isOperatorChar(next));
            }
            else {
                // unquoted symbol
                do {
                    _b.append(next);
                    _psn++;
                    next = 0;
                    if (_psn < _max)
                        next = _src[_psn];
                } 
                while (isSymbolChar(next));
            }
        }

        if (_b.length() > 0)
            tok = _b.toString();

        return tok;
    }

    public boolean isOperatorChar(char ch) {
        return (ch == '=' || ch == '<' || ch == '>');
    }

    public boolean isSymbolChar(char ch) {
        
        return (ch != 0 &&
                !isOperatorChar(ch) && 
                !Character.isWhitespace(ch) &&
                ch != '"' && 
                ch != '\'');
    }


    public static void println(String msg) {
        System.out.println(msg);
    }

    public static void main(String[] args) {

        if (args.length < 1) {
            println("Lexer: <string>");
        }
        else {
            String s = args[0];
            println("Parsing \"" + s + "\"");

            Lexer p = new Lexer(s);
            String tok;
            do {       
                tok = p.nextToken();
                if (tok != null)
                    println(tok);
            }
            while (tok != null);
        }
    }


}    





