/* * Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ import java.io.*; import java.util.*; /* * assignment : key = value; * key : string * value : string | array | dict * nValue : , value * array : ( value nValue ) * nAssignment: , assignment|value * dict : { assignment* } * string : "*" or anything but a ,(){}= * * special characters: ,(){}= */ public class PParser { protected static final int OPEN_PAIR = 1; protected static final int CLOSE_PAIR = 2; protected static final int OPEN_ARRAY = 3; protected static final int CLOSE_ARRAY = 4; protected static final int MORE = 5; protected static final int EQUAL = 6; protected static final int STRING = 7; protected static final int WS = 8; protected Reader reader; protected boolean bufferedToken; protected StringBuffer stringBuffer = new StringBuffer(); protected int lastChar; protected int lastToken; protected int lineNumber; protected int column; public PParser() { } public Map<String,Object> parse(Reader r) throws IOException { this.reader = r; bufferedToken = false; lineNumber = 0; column = 0; if (getToken() != OPEN_PAIR) { error("No initial open"); } return parsePair(); } protected Object parseValue(int lookAhead) throws IOException { int token; if (lookAhead == -1) { token = getToken(); } else { token = lookAhead; } switch (token) { case STRING: return stringBuffer.toString(); case OPEN_ARRAY: return parseArray(); case OPEN_PAIR: return parsePair(); default: error("Expecting value"); } return null; } protected Object parseArray() throws IOException { List<Object> array = new ArrayList<>(); int token; while ((token = getToken()) != CLOSE_ARRAY) { if (token == MORE) { token = getToken(); } if (token != CLOSE_ARRAY) { array.add(parseValue(token)); } } return array; } protected Map<String,Object> parsePair() throws IOException { Map<String,Object> ht = new HashMap<>(11); int token; while ((token = getToken()) != CLOSE_PAIR) { if (token != STRING) { error("Pair expecting string got"); } String key = stringBuffer.toString(); if (getToken() != EQUAL) { error("Expecting = "); } Object value = parseValue(-1); ht.put(key, value); } return ht; } protected void ungetToken() { if (bufferedToken) { error("Can not buffer more than one token"); } bufferedToken = true; } protected int getToken() throws IOException { int token = getToken(false, false); return token; } @SuppressWarnings("fallthrough") protected int getToken(boolean wantsWS, boolean inString) throws IOException { if (bufferedToken) { bufferedToken = false; if (lastToken != WS || wantsWS) { return lastToken; } } while ((lastChar = reader.read()) != -1) { // If a line starts with '#', skip the line. if (column == 0 && lastChar == '#') { while ((lastChar = reader.read()) != -1 && lastChar != '\n') { } if (lastChar == -1) { break; } } column++; switch(lastChar) { case '\n': lineNumber++; column = 0; case ' ': case '\r': case '\t': if (wantsWS) { lastToken = WS; return WS; } break; case ',': lastToken = MORE; return MORE; case '(': lastToken = OPEN_ARRAY; return OPEN_ARRAY; case ')': lastToken = CLOSE_ARRAY; return CLOSE_ARRAY; case '{': lastToken = OPEN_PAIR; return OPEN_PAIR; case '}': lastToken = CLOSE_PAIR; return CLOSE_PAIR; case '=': lastToken = EQUAL; return EQUAL; case '"': lastToken = STRING; if (!inString) { stringBuffer.setLength(0); while (true) { getToken(true, true); if (lastChar == '"') { lastToken = STRING; return STRING; } stringBuffer.append((char)lastChar); } } return STRING; default: lastToken = STRING; if (!inString) { stringBuffer.setLength(0); stringBuffer.append((char)lastChar); while (getToken(true, true) == STRING) { if (lastChar == '"') { error("Unexpected quote"); } stringBuffer.append((char)lastChar); } ungetToken(); } return STRING; } } return -1; } protected void error(String errorString) { throw new RuntimeException(errorString + " at line " + lineNumber + " column " + column); } @SuppressWarnings("unchecked") public static void dump(Object o) { if (o instanceof String) { System.out.print(o); } else if(o instanceof List) { dump(" ("); ((List)o).forEach((l) -> { dump(l); dump(" -- "); }); dump(" )"); } else { Map<String,Object> ht = (Map<String,Object>)o; dump(" {"); ht.keySet().forEach(l -> { dump(l); dump(" = "); dump(ht.get(l)); dump(";"); }); dump(" }"); } } public static void main(String[] args) { if (args.length == 0) { System.out.println("need filename"); } else { try { FileReader fr = new FileReader(args[0]); PParser parser = new PParser(); Map<String,Object> ht = parser.parse(fr); dump(ht); System.out.println(); } catch (IOException ioe) { System.out.println("Couldn't parse: " + ioe); } } } }