view src/plparser/PropertyListParser.java @ 7:619472ca4742

Refactoring for multiple implementation of scanner
author one
date Wed, 01 Sep 2010 15:23:37 +0900
parents 563bcb96e4fa
children 0d74081c1309
line wrap: on
line source

package plparser;

import java.io.FileNotFoundException;
import java.io.InputStream;
import java.util.LinkedList;


public class PropertyListParser<Node extends Property> {
	PropertyListNodeFactory<Node> lf;
	Token<Node> nextToken;
	public PLScanner<Node> scanner;
	private Dictionary<Node> dict;
	// scope is necessary if you have to parse nested name scope
//	private PropertyListScope<Node> scope;

	public PropertyListParser(String string,
			PropertyListNodeFactory<Node> lf) {
		this.lf = lf;
		initialize();
		scanner.set(string);
	}
	
	public PropertyListParser(PropertyListNodeFactory<Node> lf) {
		this.lf = lf;
		initialize();
	}
	

	public void initReservedWord() {
		dict.reserve("=",TokenID.Assign);
		dict.reserve(",",TokenID.Comma);
		dict.reserve(";",TokenID.Semicolon);
		dict.reserve("(",TokenID.Paren);
		dict.reserve(")",TokenID.CloseParen);
		dict.reserve("{",TokenID.CurParen);
		dict.reserve("}",TokenID.CloseCurParen);
		dict.reserve("true",TokenID.True);
		dict.reserve("false",TokenID.False);
		dict.reserve("True",TokenID.True);
		dict.reserve("False",TokenID.False);
	}

	public void initialize() {
		dict = new Dictionary<Node>();
	//	scope = new PropertyListScope<Node>(null,dict);
		initReservedWord();
		scanner = new PropertyListScanner<Node>(dict);
	}

	public Node parse() {
		if (scanner==null) return null; // internal error
		nextToken();
		return term();
	}

	public Node parse(String exp) {
		Node n;
		scanner = scanner.pushScanner(exp);
		n = parse();
		scanner = scanner.popScanner();
		nextToken = scanner.nextToken();
		return n;
		
	}

	public Node parseFile(String file) {
		try {
			scanner = scanner.pushScannerFile(file);
		} catch (FileNotFoundException e) {
			error("Can't open "+file);
			return null;
		}
		return doParse();
	}
	
	public Node parse(InputStream file) {
		scanner = scanner.pushScannerFile(file,null);
		return doParse();
	}

	public Node parse(InputStream in, String prompt) {
		scanner = scanner.pushScannerFile(in,prompt);
		return doParse();
	}
	
	public Node doParse() {
		Node n;
		do {
			n=parse();
		} while(scanner.hasRemaining());
		scanner = scanner.popScanner();
		nextToken = scanner.nextToken();
		return n;
	}

	/**
	 * expr1 {} Dictionary
	 * @return list of node (key,value,key,value)
	 */
	public LinkedList<Node> expr1() {
		LinkedList<Node> list = new LinkedList<Node>();
		if (nextToken.type==TokenID.CloseCurParen ) return list;
	    expr2(list);
		while(nextToken.type == TokenID.Semicolon) {
			nextToken();
			if (nextToken.type==TokenID.CloseCurParen ) return list;
			expr2(list);
		}
		return list;
	}

	/**
	 * expr2
	 *    key = value
	 */
	public void expr2(LinkedList<Node>list) {
		Node n1 = term();
		if (nextToken.type!=TokenID.Assign) {
			error("needs assignment");
			return;
		}
		nextToken();
		Node n2 = term();
		list.add(n1); list.add(n2);
		return;
	}

	/**
	 * expr3  Array
	 * @return list of node
	 */
	public LinkedList<Node> expr3() {
		LinkedList<Node>list = new LinkedList<Node>();
		if (nextToken.type==TokenID.CloseParen) return list;
		Node n1 = term();
		list.add(n1); 
		while (nextToken.type==TokenID.Comma) {
			nextToken();
			if (nextToken.type==TokenID.CloseParen) return list;
			Node n2 = term();
			list.add(n2);
		}
		return list;
	}
	
	protected Node makeVariable(Token<Node> t) {
		Node n;
		if ((n=t.value())==null) {
			n =  lf.variableNode(t.name(),true);
			t.setValue(n);
		}
		// n.token = t;
		return n;
	}

	protected Node term() {
		Node n = null;
		switch (nextToken.type) {
		case Paren: // Array
			nextToken();
			LinkedList<Node>list1 = expr3();
			if (nextToken.type==TokenID.CloseParen) {
			} else { // syntax error;
				error(") expected but got "+nextToken);
				return lf.trueNode();
			}
			nextToken();
			return lf.arrayNode(list1);
		case CurParen: // Dictionary
			nextToken();
			LinkedList<Node> list = expr1();
			if (nextToken.type==TokenID.CloseCurParen) {
			} else { // syntax error;
				error("} expected but got "+nextToken);
			}
			nextToken();
			return lf.dictionaryNode(list);
		case NUMBER:
			n = lf.numberNode(Integer.parseInt(nextToken.name));
			break;
		case NULL: 
			break;
		default:
			if (nextToken.type.isVariable()) 
				n = makeVariable(nextToken);
			else {
				// error("Internal ununderstandable term '"+nextToken+"' type: "+nextToken.type+".");
				n = makeVariable(nextToken); // skip any
			}
		}
		nextToken();
		return n;
	}


	/*
	 * Syntactical Short cut for scanner.textToken()
	 * 
	 * It never returns null, to check EOF, 
	 *     nextToken.type==TokenID.NULL
	 */
	public Token<Node> nextToken() {
		return nextToken = scanner.nextToken();
	}
	

	public void error(String err) {
		scanner.error(err);
	}
}