1
|
1 package plparser;
|
|
2
|
|
3 import java.io.FileNotFoundException;
|
|
4 import java.io.InputStream;
|
|
5 import java.util.LinkedList;
|
|
6
|
|
7
|
|
8 public class PropertyListParser<Node extends Property> {
|
|
9 PropertyListNodeFactory<Node> lf;
|
|
10 Token<Node> nextToken;
|
|
11 public PropertyListScanner<Node> scanner;
|
|
12 private Dictionary<Node> dict;
|
4
|
13 // scope is necessary if you have to parse nested name scope
|
2
|
14 // private PropertyListScope<Node> scope;
|
4
|
15
|
1
|
16 public PropertyListParser(String string,
|
|
17 PropertyListNodeFactory<Node> lf) {
|
|
18 this.lf = lf;
|
2
|
19 initialize();
|
3
|
20 scanner.set(string);
|
1
|
21 }
|
2
|
22
|
4
|
23 public PropertyListParser(PropertyListNodeFactory<Node> lf) {
|
|
24 this.lf = lf;
|
|
25 initialize();
|
|
26 }
|
|
27
|
1
|
28
|
|
29 public void initReservedWord() {
|
|
30 dict.reserve("=",TokenID.Assign);
|
|
31 dict.reserve(",",TokenID.Comma);
|
|
32 dict.reserve(";",TokenID.Semicolon);
|
|
33 dict.reserve("(",TokenID.Paren);
|
|
34 dict.reserve(")",TokenID.CloseParen);
|
|
35 dict.reserve("{",TokenID.CurParen);
|
|
36 dict.reserve("}",TokenID.CloseCurParen);
|
|
37 dict.reserve("true",TokenID.True);
|
|
38 dict.reserve("false",TokenID.False);
|
|
39 }
|
|
40
|
|
41 public void initialize() {
|
|
42 dict = new Dictionary<Node>();
|
2
|
43 // scope = new PropertyListScope<Node>(null,dict);
|
1
|
44 initReservedWord();
|
|
45 scanner = new PropertyListScanner<Node>(dict);
|
|
46 }
|
|
47
|
|
48 public Node parse() {
|
4
|
49 if (scanner==null) return null; // internal error
|
|
50 if (scanner.cb==null) return null; // nothing to do
|
1
|
51 nextToken();
|
|
52 return term();
|
|
53 }
|
|
54
|
|
55 public Node parse(String exp) {
|
|
56 Node n;
|
|
57 scanner = scanner.pushScanner(exp);
|
|
58 n = parse();
|
|
59 scanner = scanner.popScanner();
|
|
60 nextToken = scanner.nextToken;
|
|
61 return n;
|
|
62
|
|
63 }
|
|
64
|
4
|
65 public Node parseFile(String file) {
|
1
|
66 try {
|
|
67 scanner = scanner.pushScannerFile(file);
|
|
68 } catch (FileNotFoundException e) {
|
|
69 error("Can't open "+file);
|
4
|
70 return null;
|
1
|
71 }
|
4
|
72 return doParse();
|
1
|
73 }
|
|
74
|
4
|
75 public Node parse(InputStream file) {
|
1
|
76 scanner = scanner.pushScannerFile(file,null);
|
4
|
77 return doParse();
|
1
|
78 }
|
|
79
|
4
|
80 public Node parse(InputStream in, String prompt) {
|
1
|
81 scanner = scanner.pushScannerFile(in,prompt);
|
4
|
82 return doParse();
|
1
|
83 }
|
|
84
|
|
85 public Node doParse() {
|
|
86 Node n;
|
|
87 do {
|
|
88 n=parse();
|
|
89 } while(scanner.hasRemaining());
|
|
90 scanner = scanner.popScanner();
|
|
91 nextToken = scanner.nextToken;
|
|
92 return n;
|
|
93 }
|
|
94
|
3
|
95 /**
|
|
96 * expr1 {} Dictionary
|
|
97 * @return list of node (key,value,key,value)
|
|
98 */
|
1
|
99 public LinkedList<Node> expr1() {
|
|
100 LinkedList<Node> list = new LinkedList<Node>();
|
5
|
101 if (nextToken.type==TokenID.CloseCurParen ) return list;
|
1
|
102 expr2(list);
|
|
103 while(nextToken.type == TokenID.Semicolon) {
|
|
104 nextToken();
|
3
|
105 if (nextToken.type==TokenID.CloseCurParen ) return list;
|
1
|
106 expr2(list);
|
|
107 }
|
|
108 return list;
|
|
109 }
|
|
110
|
3
|
111 /**
|
|
112 * expr2
|
|
113 * key = value
|
|
114 */
|
1
|
115 public void expr2(LinkedList<Node>list) {
|
|
116 Node n1 = term();
|
|
117 if (nextToken.type!=TokenID.Assign) {
|
|
118 error("needs assignment");
|
|
119 return;
|
|
120 }
|
3
|
121 nextToken();
|
1
|
122 Node n2 = term();
|
|
123 list.add(n1); list.add(n2);
|
|
124 return;
|
|
125 }
|
|
126
|
3
|
127 /**
|
|
128 * expr3 Array
|
|
129 * @return list of node
|
|
130 */
|
1
|
131 public LinkedList<Node> expr3() {
|
|
132 LinkedList<Node>list = new LinkedList<Node>();
|
5
|
133 if (nextToken.type==TokenID.CloseParen) return list;
|
1
|
134 Node n1 = term();
|
|
135 list.add(n1);
|
|
136 while (nextToken.type==TokenID.Comma) {
|
5
|
137 nextToken();
|
|
138 if (nextToken.type==TokenID.CloseParen) return list;
|
1
|
139 Node n2 = term();
|
|
140 list.add(n2);
|
|
141 }
|
|
142 return list;
|
|
143 }
|
|
144
|
|
145 protected Node makeVariable(Token<Node> t) {
|
|
146 Node n;
|
|
147 if ((n=t.value())==null) {
|
|
148 n = lf.variableNode(t.name(),true);
|
|
149 t.setValue(n);
|
|
150 }
|
|
151 // n.token = t;
|
|
152 return n;
|
|
153 }
|
|
154
|
|
155 protected Node term() {
|
|
156 Node n = null;
|
|
157 switch (nextToken.type) {
|
|
158 case Paren: // Array
|
|
159 nextToken();
|
|
160 LinkedList<Node>list1 = expr3();
|
|
161 if (nextToken.type==TokenID.CloseParen) {
|
|
162 } else { // syntax error;
|
5
|
163 error(") expected but got "+nextToken);
|
1
|
164 return lf.trueNode();
|
|
165 }
|
5
|
166 nextToken();
|
1
|
167 return lf.arrayNode(list1);
|
|
168 case CurParen: // Dictionary
|
|
169 nextToken();
|
|
170 LinkedList<Node> list = expr1();
|
|
171 if (nextToken.type==TokenID.CloseCurParen) {
|
|
172 } else { // syntax error;
|
5
|
173 error("} expected but got "+nextToken);
|
1
|
174 }
|
5
|
175 nextToken();
|
1
|
176 return lf.dictionaryNode(list);
|
|
177 case NUMBER:
|
|
178 n = lf.numberNode(Integer.parseInt(nextToken.name));
|
|
179 break;
|
|
180 case NULL:
|
|
181 break;
|
|
182 default:
|
|
183 if (nextToken.type.isVariable())
|
|
184 n = makeVariable(nextToken);
|
|
185 else {
|
|
186 // error("Internal ununderstandable term '"+nextToken+"' type: "+nextToken.type+".");
|
|
187 n = makeVariable(nextToken); // skip any
|
|
188 }
|
|
189 }
|
|
190 nextToken();
|
|
191 return n;
|
|
192 }
|
|
193
|
|
194
|
|
195 /*
|
|
196 * Syntactical Short cut for scanner.textToken()
|
|
197 *
|
|
198 * It never returns null, to check EOF,
|
|
199 * nextToken.type==TokenID.NULL
|
|
200 */
|
|
201 public Token<Node> nextToken() {
|
|
202 return nextToken = scanner.nextToken();
|
|
203 }
|
|
204
|
|
205
|
|
206 public void error(String err) {
|
|
207 scanner.error(err);
|
|
208 }
|
|
209 }
|