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 Hashtable 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     }
  78     else {
  79       token = lookAhead;
  80     }
  81     switch (token) {
  82     case STRING:
  83       return stringBuffer.toString();
  84     case OPEN_ARRAY:
  85       return parseArray();
  86     case OPEN_PAIR:
  87       return parsePair();
  88     default:
  89       error("Expecting value");
  90     }
  91     return null;
  92   }
  93 
  94   protected Object parseArray() throws IOException {
  95     Vector       array = new Vector();
  96     int          token;
  97 
  98     while ((token = getToken()) != CLOSE_ARRAY) {
  99       if (token == MORE) {
 100         token = getToken();
 101       }
 102       if (token != CLOSE_ARRAY) {
 103         array.addElement(parseValue(token));
 104       }
 105     }
 106     return array;
 107   }
 108 
 109   protected Hashtable parsePair() throws IOException {
 110     Hashtable           ht = new Hashtable(11);
 111     int                 token;
 112 
 113     while ((token = getToken()) != CLOSE_PAIR) {
 114       if (token != STRING) {
 115         error("Pair expecting string got");
 116       }
 117       String     key = stringBuffer.toString();
 118 
 119       if (getToken() != EQUAL) {
 120         error("Expecting = ");
 121       }
 122 
 123       Object     value = parseValue(-1);
 124 
 125       ht.put(key, value);
 126     }
 127     return ht;
 128   }
 129 
 130   protected void ungetToken() {
 131     if (bufferedToken) {
 132       error("Can not buffer more than one token");
 133     }
 134     bufferedToken = true;
 135   }
 136 
 137   protected int getToken() throws IOException {
 138     int            token = getToken(false, false);
 139 
 140     return token;
 141   }
 142 
 143   protected int getToken(boolean wantsWS, boolean inString)
 144                 throws IOException {
 145     if (bufferedToken) {
 146       bufferedToken = false;
 147       if (lastToken != WS || wantsWS) {
 148         return lastToken;
 149       }
 150     }
 151     while ((lastChar = reader.read()) != -1) {
 152       // If a line starts with '#', skip the line.
 153       if (column == 0 && lastChar == '#') {
 154         while ((lastChar = reader.read()) != -1
 155                && lastChar != '\n') {
 156         }
 157         if (lastChar == -1) {
 158           break;
 159         }
 160       }
 161 
 162       column++;
 163       switch(lastChar) {
 164       case '\n':
 165         lineNumber++;
 166         column = 0;
 167       case ' ':
 168       case '\r':
 169       case '\t':
 170         if (wantsWS) {
 171           lastToken = WS;
 172           return WS;
 173         }
 174         break;
 175       case ',':
 176         lastToken = MORE;
 177         return MORE;
 178       case '(':
 179         lastToken = OPEN_ARRAY;
 180         return OPEN_ARRAY;
 181       case ')':
 182         lastToken = CLOSE_ARRAY;
 183         return CLOSE_ARRAY;
 184       case '{':
 185         lastToken = OPEN_PAIR;
 186         return OPEN_PAIR;
 187       case '}':
 188         lastToken = CLOSE_PAIR;
 189         return CLOSE_PAIR;
 190       case '=':
 191         lastToken = EQUAL;
 192         return EQUAL;
 193       case '"':
 194         lastToken = STRING;
 195         if (!inString) {
 196           stringBuffer.setLength(0);
 197           while (true) {
 198             getToken(true, true);
 199             if (lastChar == '"') {
 200               lastToken = STRING;
 201               return STRING;
 202             }
 203             stringBuffer.append((char)lastChar);
 204           }
 205         }
 206         return STRING;
 207       default:
 208         lastToken = STRING;
 209         if (!inString) {
 210           stringBuffer.setLength(0);
 211           stringBuffer.append((char)lastChar);
 212           while (getToken(true, true) == STRING) {
 213             if (lastChar == '"') {
 214               error("Unexpected quote");
 215             }
 216             stringBuffer.append((char)lastChar);
 217           }
 218           ungetToken();
 219         }
 220         return STRING;
 221       }
 222     }
 223     return -1;
 224   }
 225 
 226   protected void error(String errorString) {
 227     throw new RuntimeException(errorString + " at line " + lineNumber + " column " + column);
 228   }
 229 
 230   public static void dump(Object o) {
 231     if (o instanceof String) {
 232       System.out.print(o);
 233     }
 234     else if(o instanceof Vector) {
 235       Enumeration     e = ((Vector)o).elements();
 236 
 237       dump(" (");
 238       while (e.hasMoreElements()) {
 239         dump(e.nextElement());
 240         dump(" -- ");
 241       }
 242       dump(" )");
 243     }
 244     else {
 245       Hashtable       ht = (Hashtable)o;
 246       Enumeration     e = ht.keys();
 247 
 248       dump(" {");
 249       while (e.hasMoreElements()) {
 250         Object       key = e.nextElement();
 251 
 252         dump(key);
 253         dump(" = ");
 254         dump(ht.get(key));
 255         dump(";");
 256       }
 257       dump(" }");
 258     }
 259   }
 260 
 261   public static void main(String[] args) {
 262     if (args.length == 0) {
 263       System.out.println("need filename");
 264     }
 265     else {
 266       try {
 267         FileReader          fr = new FileReader(args[0]);
 268         PParser             parser = new PParser();
 269         Hashtable           ht = parser.parse(fr);
 270 
 271         dump(ht);
 272         System.out.println();
 273       }
 274       catch (IOException ioe) {
 275         System.out.println("Couldn't parse: " + ioe);
 276       }
 277     }
 278   }
 279 }