1 /* 2 * Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 import java.io.*; 25 import java.util.*; 26 27 /* 28 * assignment : key = value; 29 * key : string 30 * value : string | array | dict 31 * nValue : , value 32 * array : ( value nValue ) 33 * nAssignment: , assignment|value 34 * dict : { assignment* } 35 * string : "*" or anything but a ,(){}= 36 * 37 * special characters: ,(){}= 38 */ 39 40 public class PParser { 41 protected static final int OPEN_PAIR = 1; 42 protected static final int CLOSE_PAIR = 2; 43 protected static final int OPEN_ARRAY = 3; 44 protected static final int CLOSE_ARRAY = 4; 45 protected static final int MORE = 5; 46 protected static final int EQUAL = 6; 47 protected static final int STRING = 7; 48 protected static final int WS = 8; 49 50 protected Reader reader; 51 protected boolean bufferedToken; 52 protected StringBuffer stringBuffer = new StringBuffer(); 53 protected int lastChar; 54 protected int lastToken; 55 protected int lineNumber; 56 protected int column; 57 58 public PParser() { 59 } 60 61 public Map<String,Object> parse(Reader r) throws IOException { 62 this.reader = r; 63 bufferedToken = false; 64 lineNumber = 0; 65 column = 0; 66 if (getToken() != OPEN_PAIR) { 67 error("No initial open"); 68 } 69 return parsePair(); 70 } 71 72 protected Object parseValue(int lookAhead) throws IOException { 73 int token; 74 75 if (lookAhead == -1) { 76 token = getToken(); 77 } else { 78 token = lookAhead; 79 } 80 switch (token) { 81 case STRING: 82 return stringBuffer.toString(); 83 case OPEN_ARRAY: 84 return parseArray(); 85 case OPEN_PAIR: 86 return parsePair(); 87 default: 88 error("Expecting value"); 89 } 90 return null; 91 } 92 93 protected Object parseArray() throws IOException { 94 List<Object> array = new ArrayList<>(); 95 int token; 96 97 while ((token = getToken()) != CLOSE_ARRAY) { 98 if (token == MORE) { 99 token = getToken(); 100 } 101 if (token != CLOSE_ARRAY) { 102 array.add(parseValue(token)); 103 } 104 } 105 return array; 106 } 107 108 protected Map<String,Object> parsePair() throws IOException { 109 Map<String,Object> ht = new HashMap<>(11); 110 int token; 111 112 while ((token = getToken()) != CLOSE_PAIR) { 113 if (token != STRING) { 114 error("Pair expecting string got"); 115 } 116 String key = stringBuffer.toString(); 117 118 if (getToken() != EQUAL) { 119 error("Expecting = "); 120 } 121 122 Object value = parseValue(-1); 123 ht.put(key, value); 124 } 125 return ht; 126 } 127 128 protected void ungetToken() { 129 if (bufferedToken) { 130 error("Can not buffer more than one token"); 131 } 132 bufferedToken = true; 133 } 134 135 protected int getToken() throws IOException { 136 int token = getToken(false, false); 137 138 return token; 139 } 140 141 @SuppressWarnings("fallthrough") 142 protected int getToken(boolean wantsWS, boolean inString) 143 throws IOException { 144 if (bufferedToken) { 145 bufferedToken = false; 146 if (lastToken != WS || wantsWS) { 147 return lastToken; 148 } 149 } 150 while ((lastChar = reader.read()) != -1) { 151 // If a line starts with '#', skip the line. 152 if (column == 0 && lastChar == '#') { 153 while ((lastChar = reader.read()) != -1 154 && lastChar != '\n') { 155 } 156 if (lastChar == -1) { 157 break; 158 } 159 } 160 161 column++; 162 switch(lastChar) { 163 case '\n': 164 lineNumber++; 165 column = 0; 166 case ' ': 167 case '\r': 168 case '\t': 169 if (wantsWS) { 170 lastToken = WS; 171 return WS; 172 } 173 break; 174 case ',': 175 lastToken = MORE; 176 return MORE; 177 case '(': 178 lastToken = OPEN_ARRAY; 179 return OPEN_ARRAY; 180 case ')': 181 lastToken = CLOSE_ARRAY; 182 return CLOSE_ARRAY; 183 case '{': 184 lastToken = OPEN_PAIR; 185 return OPEN_PAIR; 186 case '}': 187 lastToken = CLOSE_PAIR; 188 return CLOSE_PAIR; 189 case '=': 190 lastToken = EQUAL; 191 return EQUAL; 192 case '"': 193 lastToken = STRING; 194 if (!inString) { 195 stringBuffer.setLength(0); 196 while (true) { 197 getToken(true, true); 198 if (lastChar == '"') { 199 lastToken = STRING; 200 return STRING; 201 } 202 stringBuffer.append((char)lastChar); 203 } 204 } 205 return STRING; 206 default: 207 lastToken = STRING; 208 if (!inString) { 209 stringBuffer.setLength(0); 210 stringBuffer.append((char)lastChar); 211 while (getToken(true, true) == STRING) { 212 if (lastChar == '"') { 213 error("Unexpected quote"); 214 } 215 stringBuffer.append((char)lastChar); 216 } 217 ungetToken(); 218 } 219 return STRING; 220 } 221 } 222 return -1; 223 } 224 225 protected void error(String errorString) { 226 throw new RuntimeException(errorString + " at line " + lineNumber + " column " + column); 227 } 228 229 @SuppressWarnings("unchecked") 230 public static void dump(Object o) { 231 if (o instanceof String) { 232 System.out.print(o); 233 } else if(o instanceof List) { 234 dump(" ("); 235 ((List)o).forEach((l) -> { 236 dump(l); 237 dump(" -- "); 238 }); 239 dump(" )"); 240 } else { 241 Map<String,Object> ht = (Map<String,Object>)o; 242 dump(" {"); 243 ht.keySet().forEach(l -> { 244 dump(l); 245 dump(" = "); 246 dump(ht.get(l)); 247 dump(";"); 248 }); 249 dump(" }"); 250 } 251 } 252 253 public static void main(String[] args) { 254 if (args.length == 0) { 255 System.out.println("need filename"); 256 } else { 257 try { 258 FileReader fr = new FileReader(args[0]); 259 PParser parser = new PParser(); 260 Map<String,Object> ht = parser.parse(fr); 261 262 dump(ht); 263 System.out.println(); 264 } 265 catch (IOException ioe) { 266 System.out.println("Couldn't parse: " + ioe); 267 } 268 } 269 } 270 }