KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > modules > languages > parser > LLSyntaxAnalyser


1 /*
2  * The contents of this file are subject to the terms of the Common Development
3  * and Distribution License (the License). You may not use this file except in
4  * compliance with the License.
5  *
6  * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7  * or http://www.netbeans.org/cddl.txt.
8  *
9  * When distributing Covered Code, include this CDDL Header Notice in each file
10  * and include the License file at http://www.netbeans.org/cddl.txt.
11  * If applicable, add the following below the CDDL Header, with the fields
12  * enclosed by brackets [] replaced by your own identifying information:
13  * "Portions Copyrighted [year] [name of copyright owner]"
14  *
15  * The Original Software is NetBeans. The Initial Developer of the Original
16  * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
17  * Microsystems, Inc. All Rights Reserved.
18  */

19
20
21 package org.netbeans.modules.languages.parser;
22
23 import java.util.ArrayList JavaDoc;
24 import java.util.Collections JavaDoc;
25 import java.util.HashSet JavaDoc;
26 import java.util.HashSet JavaDoc;
27 import java.util.Iterator JavaDoc;
28 import java.util.List JavaDoc;
29 import java.util.Map JavaDoc;
30 import java.util.Set JavaDoc;
31 import java.util.Set JavaDoc;
32 import java.util.Stack JavaDoc;
33 import java.util.StringTokenizer JavaDoc;
34 import org.netbeans.api.languages.ASTItem;
35 import org.netbeans.api.languages.ASTItem;
36 import org.netbeans.api.languages.ParseException;
37 import org.netbeans.modules.languages.Feature;
38 import org.netbeans.modules.languages.Language;
39 import org.netbeans.modules.languages.LanguagesManagerImpl;
40 import org.netbeans.modules.languages.parser.TokenInput;
41 import org.netbeans.api.languages.ASTNode;
42 import org.netbeans.api.languages.LanguagesManager;
43 import org.netbeans.api.languages.ASTToken;
44 import org.netbeans.modules.languages.Language;
45 import org.netbeans.modules.languages.LanguagesManagerImpl;
46
47
48 /**
49  *
50  * @author Jan Jancura
51  */

52 public class LLSyntaxAnalyser {
53
54     private Language language;
55     private List JavaDoc<Rule> rules;
56     private Map JavaDoc<String JavaDoc,Map JavaDoc> first;
57     private Set JavaDoc<String JavaDoc> skip;
58     private int traceSteps = -1;
59     private boolean cancel = false;
60     private boolean printFirst = false;
61     
62     
63     private LLSyntaxAnalyser (Language language) {
64         this.rules = language.getRules ();
65         this.skip = new HashSet JavaDoc<String JavaDoc> (language.getSkipTokenTypes ());
66         this.skip.add ("error");
67         this.language = language;
68         initTracing ();
69     }
70     
71     
72     // public methods ..........................................................
73

74     public void cancel () {
75         cancel = true;
76     }
77
78     public List JavaDoc<Rule> getRules () {
79         return rules;
80     }
81     
82     public static LLSyntaxAnalyser create (Language language) {
83         return new LLSyntaxAnalyser (language);
84     }
85     
86     public ASTNode read (TokenInput input, boolean skipErrors) throws ParseException {
87         cancel = false;
88         if (rules.isEmpty () || input.eof ())
89             return readNoGrammar (input, skipErrors);
90         if (first == null) {
91             first = Petra.first2 (rules);
92             boolean hasConflicts = AnalyserAnalyser.printConflicts (first, null);
93             if (hasConflicts)
94                 AnalyserAnalyser.printRules (rules, null);
95             if (printFirst)
96                 AnalyserAnalyser.printF (first, null);
97             AnalyserAnalyser.printUndefinedNTs (rules, null);
98         }
99         return read2 (input, skipErrors);
100     }
101     
102     
103     // helper methods ..........................................................
104

105     private ASTNode read2 (TokenInput input, boolean skipErrors) throws ParseException {
106         Stack JavaDoc<Object JavaDoc> stack = new Stack JavaDoc<Object JavaDoc> ();
107         Node root = null, node = null;
108         Iterator JavaDoc it = Collections.singleton ("S").iterator ();
109         do {
110             int offset = input.getOffset ();
111             List JavaDoc whitespaces = readWhitespaces (node, input, skipErrors);
112             if (node != null)
113                 offset = input.getOffset ();
114             while (!it.hasNext ()) {
115                 if (stack.empty ()) break;
116                 node = (Node) stack.pop ();
117                 it = (Iterator JavaDoc) stack.pop ();
118             }
119             if (!it.hasNext ()) break;
120             Object JavaDoc current = it.next ();
121             if (current instanceof String JavaDoc) {
122                 String JavaDoc nt = (String JavaDoc) current;
123                 int newRule = getRule (nt, input);
124                 if (newRule == -1) {
125                     if (!skipErrors)
126                         throw new ParseException ("No rule for " + input.next (1) + " in " + input, root.createASTNode ());
127                     if (input.eof ()) {
128                         if (node == null)
129                             root = node = new Node ("Root", -1, offset, whitespaces);
130                         createErrorNode (node, input.getOffset ());
131                         //S ystem.out.println(input.getIndex () + ": unexpected eof " + nt);
132
return root.createASTNode ();
133                     }
134                     //S ystem.out.println(input.getIndex () + ": no rule for " + nt + "&" + input.next (0));
135
createErrorNode (node, input.getOffset ()).addItem (readEmbeddings (input.read (), skipErrors));
136                 } else {
137                     Rule rule = (Rule) rules.get (newRule);
138                     Feature parse = language.getFeature ("PARSE", rule.getNT ());
139                     if (parse != null) {
140                         stack.push (it);
141                         stack.push (node);
142                         it = Collections.EMPTY_LIST.iterator ();
143                         ASTNode nast = (ASTNode) parse.getValue (
144                             new Object JavaDoc[] {input, stack}
145                         );
146                         node.addItem (nast);
147                         //S ystem.out.println(input.getIndex () + ": >>Java " + nt + "&" + evaluator.getValue ());
148
} else {
149                         if (node == null || it.hasNext () || !nt.equals (node.nt)) {
150                             if (nt.indexOf ('$') > 0 || nt.indexOf ('#') > 0) {
151                                 stack.push (it);
152                                 stack.push (node);
153                             } else {
154                                 Node nnode = new Node (
155                                     rule.getNT (),
156                                     newRule,
157                                     offset,
158                                     whitespaces
159                                 );
160                                 if (node != null) {
161                                     node.addNode (nnode);
162                                     stack.push (it);
163                                     stack.push (node);
164                                 } else {
165                                     root = nnode;
166                                 }
167                                 node = nnode;
168                             }
169                         }
170                         //S ystem.out.println(input.getIndex () + ": " + rule);
171
it = rule.getRight ().iterator ();
172                     }
173                 }
174             } else {
175                 ASTToken token = (ASTToken) current;
176                 if (input.eof ()) {
177                     if (!skipErrors)
178                         throw new ParseException ("Unexpected end of file in " + input, root.createASTNode ());
179                     createErrorNode (node, input.getOffset ());
180                     //S ystem.out.println(input.getIndex () + ": unexpected eof " + token);
181
return root.createASTNode ();
182                 } else
183                 if (!isCompatible (token, input.next (1))) {
184                     if (!skipErrors)
185                         throw new ParseException ("Unexpected token " + input.next (1) + " in " + input + ". Expecting " + token, root.createASTNode ());
186                     createErrorNode (node, input.getOffset ()).addItem (readEmbeddings (input.read (), skipErrors));
187                     //S ystem.out.println(input.getIndex () + ": unrecognized token " + token + "<>" + input.next (1));
188
} else {
189                     node.addItem (readEmbeddings (input.read (), skipErrors));
190                     //S ystem.out.println(input.getIndex () + ": token readed " + input.next (1));
191
}
192             }
193         } while (true);
194         if (!skipErrors && !input.eof ())
195             throw new ParseException ("Unexpected token " + input.next (1) + " in " + input, root.createASTNode ());
196         while (
197             !input.eof () //&&
198
//input.next (1).getMimeType () == mimeType
199
)
200             createErrorNode (node, input.getOffset ()).addItem (readEmbeddings (input.read (), skipErrors));
201         return root.createASTNode ();
202     }
203     
204     private static boolean isCompatible (ASTToken t1, ASTToken t2) {
205         if (t1.getType () == null) {
206             return t1.getIdentifier ().equals (t2.getIdentifier ());
207         } else {
208             if (t1.getIdentifier () == null)
209                 return t1.getType ().equals (t2.getType ());
210             else
211                 return t1.getType ().equals (t2.getType ()) &&
212                        t1.getIdentifier ().equals (t2.getIdentifier ());
213         }
214     }
215     
216     private List JavaDoc<ASTItem> readWhitespaces (
217         Node node,
218         TokenInput input,
219         boolean skipErrors
220     ) throws ParseException {
221         List JavaDoc<ASTItem> result = null;
222         while (
223             !input.eof () &&
224             skip.contains (input.next (1).getType ())
225         ) {
226             ASTToken token = input.read ();
227             if (node != null)
228                 node.addItem (readEmbeddings (token, skipErrors));
229             else {
230                 if (result == null)
231                     result = new ArrayList JavaDoc<ASTItem> ();
232                 result.add (readEmbeddings (token, skipErrors));
233             }
234         }
235         return result;
236     }
237     
238     private ASTItem readEmbeddings (
239         ASTToken token,
240         boolean skipErrors
241     ) throws ParseException {
242         List JavaDoc<ASTItem> children = token.getChildren ();
243         if (children.isEmpty ())
244             return token;
245         TokenInput in = TokenInput.create (children);
246         Language language = ((LanguagesManagerImpl) LanguagesManager.getDefault ()).
247             getLanguage (children.get (0).getMimeType ());
248         ASTNode root = language.getAnalyser ().read (in, skipErrors);
249         return ASTToken.create (
250             token.getMimeType (),
251             token.getType (),
252             token.getIdentifier (),
253             token.getOffset (),
254             token.getLength (),
255             Collections.<ASTItem>singletonList (root)
256         );
257     }
258     
259     private ASTNode readNoGrammar (
260         TokenInput input,
261         boolean skipErrors
262     ) throws ParseException {
263         Node root = new Node ("S", -1, input.getIndex (), null);
264         while (!input.eof ()) {
265             ASTToken token = input.read ();
266             root.addItem (readEmbeddings (token, skipErrors));
267         }
268         return root.createASTNode ();
269     }
270     
271     private Node createErrorNode (Node parentNode, int offset) {
272         if (parentNode != null) {
273             List JavaDoc l = parentNode.children;
274             if (l != null && l.size () > 0) {
275                 Object JavaDoc possibleErrorNode = l.get (l.size () - 1);
276                 if (possibleErrorNode instanceof Node)
277                     if (((Node) possibleErrorNode).nt.equals ("ERROR"))
278                         return (Node) possibleErrorNode;
279             }
280         }
281         Node errorNode = new Node (
282             "ERROR",
283             -2,
284             offset,
285             null
286         );
287         if (parentNode != null)
288             parentNode.addNode (errorNode);
289         return errorNode;
290     }
291     
292     private int getRule (String JavaDoc nt, TokenInput input) {
293         Map JavaDoc m = (Map JavaDoc) first.get (nt);
294         if (m == null) return -1;
295         int i = 1;
296         while (true) {
297             ASTToken token = input.next (i);
298             if (token == null /*|| !mimeType.equals (token.getMimeType ())*/) {
299                 Set JavaDoc result = (Set JavaDoc) (Set JavaDoc) m.get ("#");
300                 if (result == null || result.size () > 1) return -1;
301                 return ((Integer JavaDoc) result.iterator ().next ()).intValue ();
302             }
303             T t = new T (token);
304             Map JavaDoc r = (Map JavaDoc) m.get (t);
305             if (r == null) {
306                 t.type = null;
307                 r = (Map JavaDoc) m.get (t);
308             }
309             if (r == null) {
310                 t.type = token.getType ();
311                 t.identifier = null;
312                 r = (Map JavaDoc) m.get (t);
313             }
314             if (r == null) {
315                 Set JavaDoc s = (Set JavaDoc) m.get ("#");
316                 if (s == null)
317                     s = (Set JavaDoc) m.get ("&");
318                 if (s == null) {
319                     System.out.println("No way! " + nt + " : " + input.next (1) + " " + input.next (2));
320                     return -1;
321                 }
322                 if (s.size () > 1) {
323                     System.out.println("Too many choices! " + nt + " : " + input.next (1) + " " + input.next (2) + ":" + input);
324                     return -1;
325                 }
326                 return ((Integer JavaDoc) s.iterator ().next ()).intValue ();
327             }
328             m = r;
329         }
330     }
331     
332     private void initTracing () {
333         Feature properties = language.getFeature ("PROPERTIES");
334         if (properties == null) return;
335         try {
336             traceSteps = Integer.parseInt ((String JavaDoc) properties.getValue ("traceSteps"));
337         } catch (NumberFormatException JavaDoc ex) {
338             traceSteps = -2;
339         }
340         if (properties.getBoolean ("printRules", false))
341             AnalyserAnalyser.printRules (rules, null);
342         printFirst = properties.getBoolean ("printFirst", false);
343     }
344     
345     private Feature optimiseProperty;
346     private boolean removeEmpty = false;
347     private boolean removeSimple = false;
348     private boolean removeEmptyN = true;
349     private boolean removeSimpleN = true;
350     private Set JavaDoc<String JavaDoc> empty = new HashSet JavaDoc<String JavaDoc> ();
351     private Set JavaDoc<String JavaDoc> simple = new HashSet JavaDoc<String JavaDoc> ();
352     
353     private boolean removeNT (Node n) {
354         if (optimiseProperty == null) {
355             Feature properties = language.getFeature ("PROPERTIES");
356             optimiseProperty = language.getFeature ("AST");
357             if (optimiseProperty != null) {
358                 String JavaDoc s = (String JavaDoc) optimiseProperty.getValue ("removeEmpty");
359                 if (s != null) {
360                     if (s.startsWith ("!")) {
361                         removeEmptyN = false;
362                         s = s.substring (1);
363                     }
364                     removeEmpty = "true".equals (s);
365                     if (!"false".equals (s)) {
366                         StringTokenizer JavaDoc st = new StringTokenizer JavaDoc (s, ",");
367                         while (st.hasMoreTokens ())
368                             empty.add (st.nextToken ());
369                     }
370                 }
371                 s = (String JavaDoc) optimiseProperty.getValue ("removeSimple");
372                 if (s != null) {
373                     if (s.startsWith ("!")) {
374                         removeSimpleN = false;
375                         s = s.substring (1);
376                     }
377                     removeSimple = "true".equals (s);
378                     if (!"false".equals (s)) {
379                         StringTokenizer JavaDoc st = new StringTokenizer JavaDoc (s, ",");
380                         while (st.hasMoreTokens ())
381                             simple.add (st.nextToken ());
382                     }
383                 }
384             }
385         }
386         if (n.children == null)
387             return removeEmpty || (removeEmptyN == empty.contains (n.nt));
388         else
389             return removeSimple || (removeSimpleN == simple.contains (n.nt));
390     }
391     
392     
393     // innerclasses ............................................................
394

395     
396     public static class Rule {
397         
398         private String JavaDoc nt;
399         private List JavaDoc right;
400         
401         private Rule () {}
402         
403         public static Rule create (
404             String JavaDoc nt,
405             List JavaDoc right
406         ) {
407             Rule r = new Rule ();
408             r.nt = nt;
409             r.right = right;
410             return r;
411         }
412
413         public String JavaDoc getNT () {
414             return nt;
415         }
416         
417         public List JavaDoc getRight () {
418             return right;
419         }
420         
421         private String JavaDoc toString = null;
422         
423         public String JavaDoc toString () {
424             if (toString == null) {
425                 StringBuilder JavaDoc sb = new StringBuilder JavaDoc ();
426                 sb.append ("Rule ").append (nt).append (" = ");
427                 int i = 0, k = right.size ();
428                 if (i < k)
429                     sb.append (right.get (i++));
430                 while (i < k)
431                     sb.append (' ').append (right.get (i++));
432                 toString = sb.toString ();
433             }
434             return toString;
435         }
436     }
437
438     public static class T {
439         String JavaDoc type;
440         String JavaDoc identifier;
441         
442 // T (String type, String identifier) {
443
// this.type = type;
444
// this.identifier = identifier;
445
// }
446

447         T (ASTToken t) {
448             type = t.getType ();
449             identifier = t.getIdentifier ();
450             if (type == null && identifier == null)
451                 System.out.println("null null!!!");
452         }
453         
454         public boolean equals (Object JavaDoc o) {
455             if (!(o instanceof T)) return false;
456             return (((T) o).type == null || ((T) o).type.equals (type)) &&
457                    (((T) o).identifier == null || ((T) o).identifier.equals (identifier));
458         }
459         
460         public int hashCode () {
461             return type == null ? -1 : type.hashCode () *
462                    (identifier == null ? -1 : identifier.hashCode ());
463         }
464         
465         public String JavaDoc toString () {
466             if (type == null)
467                 return "\"" + identifier + "\"";
468             if (identifier == null)
469                 return "<" + type + ">";
470             return "[" + type + "," + identifier + "]";
471         }
472     }
473     
474     private class Node {
475         
476         String JavaDoc nt;
477         int rule;
478         int offset;
479         List JavaDoc<Object JavaDoc> children;
480         
481         Node (
482             String JavaDoc nt,
483             int rule,
484             int offset,
485             List JavaDoc children
486         ) {
487             this.nt = nt;
488             this.rule = rule;
489             this.offset = offset;
490             if (children != null) {
491                 Iterator JavaDoc it = children.iterator ();
492                 while (it.hasNext ()) {
493                     Object JavaDoc o = it.next ();
494                     if (o instanceof ASTItem)
495                         addItem ((ASTItem) o);
496                     else
497                         addNode ((Node) o);
498                 }
499             }
500         }
501         
502         void addNode (Node n) {
503             if (children == null) children = new ArrayList JavaDoc<Object JavaDoc> ();
504 // if (((Node) n).offset != getEndOffset ())
505
// throw new IllegalStateException ();
506
children.add (n);
507         }
508         
509         void addItem (ASTItem item) {
510             if (children == null) children = new ArrayList JavaDoc<Object JavaDoc> ();
511 // if (item.getOffset () != getEndOffset ())
512
// throw new IllegalStateException ();
513
children.add (item);
514         }
515         
516         void replace (ASTNode n1, Node n2) {
517             int i, k = children.size ();
518             for (i = 0; i < k; i++) {
519                 Object JavaDoc o = children.get (i);
520                 if (n2.equals (o)) {
521                     children.set (i, n1);
522                     return;
523                 }
524             }
525             throw new IllegalStateException JavaDoc ();
526         }
527         
528         private int getEndOffset () {
529             if (children == null) return offset;
530             if (children.isEmpty ()) return offset;
531             Object JavaDoc l = children.get (children.size () - 1);
532             if (l instanceof ASTToken)
533                 return ((ASTToken) l).getOffset () + ((ASTToken) l).getLength ();
534             if (l instanceof Node) {
535                 return ((Node) l).getEndOffset ();
536             }
537             return ((ASTNode) l).getEndOffset ();
538         }
539
540         ASTNode createASTNode () {
541             List JavaDoc<ASTItem> l = new ArrayList JavaDoc<ASTItem> ();
542             if (children == null) {
543                 if (removeNT (this)) return null;
544             } else {
545                 if (children.size () == 1 &&
546                     children.get (0) instanceof Node &&
547                     removeNT (this)
548                 ) return ((Node) children.get (0)).createASTNode ();
549                 Iterator JavaDoc it = children.iterator ();
550                 while (it.hasNext ()) {
551                     Object JavaDoc o = it.next ();
552                     if (o instanceof Node) {
553                         ASTNode nn = ((Node) o).createASTNode ();
554                         if (nn != null) l.add (nn);
555                     } else
556                         l.add ((ASTItem) o);
557                 }
558             }
559             return ASTNode.create (
560                 language.getMimeType (),
561                 nt,
562                 l,
563                 offset
564             );
565         }
566     }
567 }
568
569
570
Popular Tags