/**
 * SQLLex
 *
 * <p>A basic lexer for SQL like grammar</p>
 *
 *	@author: 	Alan Yates <alany@alanyates.com>
 *	@version	$Id: SQLLex.java,v 1.1.1.1 2002/06/23 06:18:01 alany Exp $
 */

import java.io.*;
import java.util.*;

public class SQLLex {
	private Stack stack;
	private long line = 1;
	private PushbackReader input;
	private boolean ignoreComments;

	public SQLLex(Reader input) {
		this.stack = new Stack();
		this.input = new PushbackReader(input);
	}
	public SQLLex(InputStream input) {
		this(new InputStreamReader(input));
	}
	public SQLLex(String filename) throws FileNotFoundException {
		this(new FileReader(filename));
	}

	/** close source */
	public void close() throws IOException {
		this.input.close();
	}

	/** set ignore comments flag */
	public void setIgnoreComments(boolean ignoreComments) {
		this.ignoreComments = ignoreComments;
	}

	/** pop next lexeme */
	public Lexeme pop() {
		if(this.stack.isEmpty()) return this.nextLexeme();
		return (Lexeme) this.stack.pop();
	}

	/** push lexeme */
	public void push(Lexeme lexeme) {
		this.stack.push(lexeme);
	}

	private int popChar() {
		int c = -1;
		try {
			c = this.input.read();
		} catch (IOException ignored) {
		}
		if(c == '\n') this.line++;
		return c;
	}

	private void pushChar(int c) {
		try {
			if(c == '\n') this.line--;
			this.input.unread(c);
		} catch (IOException ignored) {
		}
	}

	private Lexeme nextLexeme() {
		int c = -1;
		while((c = this.popChar()) != -1) {
			if(!Character.isWhitespace((char)c)) break;
		}
		
		switch(c) {
			case -1:
				/* EOF */
				return null;
			case '(':
				return new Lexeme(this.line, Lexeme.LPARA, "(");
			case ')':
				return new Lexeme(this.line, Lexeme.RPARA, ")");
			case ',':
				return new Lexeme(this.line, Lexeme.COMMA, ",");
			case ';':
				return new Lexeme(this.line, Lexeme.SEMI, ";");
			default:
				return this.atom((char)c);
		}
	}

	private Lexeme atom(char firstChar) {
		int c = -1;
		StringBuffer sb = new StringBuffer();
		if(firstChar == '\'') {
			while((c = this.popChar()) != -1) {
				if(c == firstChar) {
					c = this.popChar();
					if(c == -1) {
						break;
					} else if(c != firstChar) {
						this.pushChar(c);
						break;
					}
				}
				sb.append((char)c);
			}
			return new Lexeme(this.line, Lexeme.QATOM, sb.toString());
		} else {
			sb.append(firstChar);
			while((c = this.popChar()) != -1) {
				if(Character.isWhitespace((char)c)) {
					this.pushChar((char)c);
					break;
				}
				if(c == '(' || c == ')' || c == ',' || c == ';') {
					this.pushChar((char)c);
					break;
				}
				sb.append((char)c);
			}
		}
		if(sb.toString().startsWith("--")) {
			while((c = this.popChar()) != -1) {
				if(c == '\n') {
					this.pushChar((char)c);
					break;
				}
				sb.append((char)c);
			}
			if(this.ignoreComments) return this.nextLexeme();
			return new Lexeme(this.line, Lexeme.COMMENT, sb.toString());
		}
		return new Lexeme(this.line, Lexeme.ATOM, sb.toString());
	}

	public static void main(String args[]) throws Throwable {
		SQLLex lex = new SQLLex(args[0]);
		Lexeme lexeme = null;
		while((lexeme = lex.pop()) != null) {
			System.out.println(lexeme.toString());
		}
		lex.close();
	}
}
