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