3789983e89
Reviewed-by: darcy, ihse
271 lines
8.0 KiB
Java
271 lines
8.0 KiB
Java
/*
|
|
* 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);
|
|
}
|
|
}
|
|
}
|
|
}
|