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         } 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         Vector       array = new Vector();
  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.addElement(parseValue(token));
 103             }
 104         }
 105         return array;
 106     }
 107 
 108     protected Hashtable parsePair() throws IOException {
 109         Hashtable           ht = new Hashtable(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     protected int getToken(boolean wantsWS, boolean inString)
 142         throws IOException {
 143         if (bufferedToken) {
 144             bufferedToken = false;
 145             if (lastToken != WS || wantsWS) {
 146                 return lastToken;
 147             }
 148         }
 149         while ((lastChar = reader.read()) != -1) {
 150             // If a line starts with '#', skip the line.
 151             if (column == 0 && lastChar == '#') {
 152                 while ((lastChar = reader.read()) != -1
 153                        && lastChar != '\n') {
 154                 }
 155                 if (lastChar == -1) {
 156                     break;
 157                 }
 158             }
 159 
 160             column++;
 161             switch(lastChar) {
 162             case '\n':
 163                 lineNumber++;
 164                 column = 0;
 165             case ' ':
 166             case '\r':
 167             case '\t':
 168                 if (wantsWS) {
 169                     lastToken = WS;
 170                     return WS;
 171                 }
 172                 break;
 173             case ',':
 174                 lastToken = MORE;
 175                 return MORE;
 176             case '(':
 177                 lastToken = OPEN_ARRAY;
 178                 return OPEN_ARRAY;
 179             case ')':
 180                 lastToken = CLOSE_ARRAY;
 181                 return CLOSE_ARRAY;
 182             case '{':
 183                 lastToken = OPEN_PAIR;
 184                 return OPEN_PAIR;
 185             case '}':
 186                 lastToken = CLOSE_PAIR;
 187                 return CLOSE_PAIR;
 188             case '=':
 189                 lastToken = EQUAL;
 190                 return EQUAL;
 191             case '"':
 192                 lastToken = STRING;
 193                 if (!inString) {
 194                     stringBuffer.setLength(0);
 195                     while (true) {
 196                         getToken(true, true);
 197                         if (lastChar == '"') {
 198                             lastToken = STRING;
 199                             return STRING;
 200                         }
 201                         stringBuffer.append((char)lastChar);
 202                     }
 203                 }
 204                 return STRING;
 205             default:
 206                 lastToken = STRING;
 207                 if (!inString) {
 208                     stringBuffer.setLength(0);
 209                     stringBuffer.append((char)lastChar);
 210                     while (getToken(true, true) == STRING) {
 211                         if (lastChar == '"') {
 212                             error("Unexpected quote");
 213                         }
 214                         stringBuffer.append((char)lastChar);
 215                     }
 216                     ungetToken();
 217                 }
 218                 return STRING;
 219             }
 220         }
 221         return -1;
 222     }
 223 
 224     protected void error(String errorString) {
 225         throw new RuntimeException(errorString + " at line " + lineNumber + " column " + column);
 226     }
 227 
 228     public static void dump(Object o) {
 229         if (o instanceof String) {
 230             System.out.print(o);
 231         } else if(o instanceof Vector) {
 232             Enumeration     e = ((Vector)o).elements();
 233 
 234             dump(" (");
 235             while (e.hasMoreElements()) {
 236                 dump(e.nextElement());
 237                 dump(" -- ");
 238             }
 239             dump(" )");
 240         } else {
 241             Hashtable       ht = (Hashtable)o;
 242             Enumeration     e = ht.keys();
 243 
 244             dump(" {");
 245             while (e.hasMoreElements()) {
 246                 Object       key = e.nextElement();
 247 
 248                 dump(key);
 249                 dump(" = ");
 250                 dump(ht.get(key));
 251                 dump(";");
 252             }
 253             dump(" }");
 254         }
 255     }
 256 
 257     public static void main(String[] args) {
 258         if (args.length == 0) {
 259             System.out.println("need filename");
 260         } else {
 261             try {
 262                 FileReader          fr = new FileReader(args[0]);
 263                 PParser             parser = new PParser();
 264                 Hashtable           ht = parser.parse(fr);
 265 
 266                 dump(ht);
 267                 System.out.println();
 268             }
 269             catch (IOException ioe) {
 270                 System.out.println("Couldn't parse: " + ioe);
 271             }
 272         }
 273     }
 274 }