Fixed some analysis problems...
[repair.git] / Repair / RepairCompiler / MCC / IR / SemanticChecker.java
1 package MCC.IR;
2
3 import java.util.*;
4 import java.math.BigInteger;
5 import MCC.State;
6
7 public class SemanticChecker {
8
9     private static final boolean CREATE_MISSING = true;
10
11     public State state;
12
13     Vector vConstraints;
14     Vector vRules;
15
16     SymbolTableStack sts;
17
18     SymbolTable stSets;
19     SymbolTable stRelations;
20     SymbolTable stTypes;
21     SymbolTable stGlobals;
22
23     StructureTypeDescriptor dCurrentType;
24
25     IRErrorReporter er;
26     
27     public SemanticChecker () {
28         dCurrentType = null;
29         stTypes = null;
30         er = null;
31     }
32
33     public boolean check(State state, IRErrorReporter er) {
34
35         this.state = state;
36         State.currentState = state;
37
38         if (er == null) {
39             throw new IRException("IRBuilder.build: Received null ErrorReporter");
40         } else {
41             this.er = er;
42         }
43
44         if (state.ptStructures == null) {
45             throw new IRException("IRBuilder.build: Received null ParseNode");
46         }
47
48         state.vConstraints = new Vector();
49         vConstraints = state.vConstraints;
50
51         state.vRules = new Vector();
52         vRules = state.vRules;
53
54         state.stTypes = new SymbolTable();
55         stTypes = state.stTypes;
56
57         state.stSets = new SymbolTable();
58         stSets = state.stSets;
59
60         state.stRelations = new SymbolTable();
61         stRelations = state.stRelations;
62
63         state.stGlobals = new SymbolTable();
64         stGlobals = state.stGlobals;
65
66         sts = new SymbolTableStack();
67         
68         // add int and bool to the types list
69         stTypes.add(ReservedTypeDescriptor.BIT);
70         stTypes.add(ReservedTypeDescriptor.BYTE);
71         stTypes.add(ReservedTypeDescriptor.SHORT);
72         stTypes.add(ReservedTypeDescriptor.INT);
73
74         stSets.add(new ReservedSetDescriptor("int", ReservedTypeDescriptor.INT));
75         stSets.add(new ReservedSetDescriptor("token", ReservedTypeDescriptor.INT));
76
77         boolean ok = true; 
78
79         er.setFilename(state.infile + ".struct");
80         if (!parse_structures(state.ptStructures)) {
81             ok = false;
82         }
83
84         er.setFilename(state.infile + ".space");
85         if (!parse_space(state.ptSpace)) {
86             ok = false;
87         }
88         
89         er.setFilename(state.infile + ".constraints");
90         if (!parse_constraints(state.ptConstraints)) {
91             ok = false;
92         }
93
94         er.setFilename(state.infile + ".model");
95         if (!parse_rules(state.ptModel)) {
96             ok = false;
97         }
98
99         return ok;
100     }
101
102     /********************** HELPER FUNCTIONS ************************/ 
103
104     /**
105      * special case lookup that returns null if no such type exists 
106      */
107     private TypeDescriptor lookupType(String typename) {
108         return lookupType(typename, false);
109     }
110
111     /**
112      * does a look up in the types symbol table. if the type is
113      * not found than a missing type descriptor is returned
114      */
115     private TypeDescriptor lookupType(String typename, boolean createmissing) {
116         if (stTypes.get(typename) != null) {
117             // the type exists, so plug in the descriptor directly 
118             return (TypeDescriptor) stTypes.get(typename);              
119         } else if (createmissing) {
120             return new MissingTypeDescriptor(typename);
121         } else {
122             return null;
123         }       
124     }
125
126     /**
127      * reserve a name 
128      */
129     private VarDescriptor reserveName(ParseNode pn) {
130         assert pn != null;
131         String varname = pn.getTerminal();
132         assert varname != null;
133                 
134         /* do semantic check and if valid, add it to symbol table
135            and add it to the quantifier as well */
136         if (sts.peek().contains(varname)) {
137             /* Semantic Error: redefinition */
138             er.report(pn, "Redefinition of '" + varname + "'");
139             return null;
140         } else {
141             VarDescriptor vd = new VarDescriptor(varname);
142             sts.peek().add(vd);
143             return vd;
144         }
145     }
146
147     /**
148      * special case lookup that returns null if no such set exists 
149      */
150     private SetDescriptor lookupSet(String setname) {
151         return lookupSet(setname, false);
152     }
153
154     /**
155      * does a look up in the set's symbol table. if the set is
156      * not found than a missing set descriptor is returned
157      */
158     private SetDescriptor lookupSet(String setname, boolean createmissing) {
159         if (stSets.get(setname) != null) {
160             // the set exists, so plug in the descriptor directly 
161             return (SetDescriptor) stSets.get(setname);              
162         } else if (createmissing) {
163             return new MissingSetDescriptor(setname);
164         } else {
165             return null;
166         }       
167     }
168     
169     /**
170      * does a look up in the set's symbol table. if the set is
171      * not found than a missing set descriptor is returned
172      */
173     private RelationDescriptor lookupRelation(String relname) {
174         if (stRelations.get(relname) != null) {
175             // the relation exists, so plug in the descriptor directly 
176             return (RelationDescriptor) stRelations.get(relname);              
177         } else {
178             return null;
179         }       
180     }
181     
182     
183     private static int count = 0;
184     private boolean precheck(ParseNode pn, String label) {              
185         if (pn == null) {
186             er.report(pn, "IE: Expected '" + label + "', got null");
187             assert false;
188             return false;
189         }
190
191         if (! pn.getLabel().equals(label)) {
192             er.report(pn, "IE: Expected '" + label + "', got '" + pn.getLabel() + "'");
193             assert false;
194             return false;
195         }
196
197         if (state.verbose >= 2) {
198             System.err.println("visiting*" + (count++) + ": " + label);
199         }
200
201         return true;
202     }
203
204     /********************* PARSING FUNCTIONS ************************/ 
205
206     private boolean parse_rules(ParseNode pn) {
207         if (!precheck(pn, "rules")) {
208             return false;
209         }
210
211         boolean ok = true;
212         ParseNodeVector rules = pn.getChildren();
213         
214         for (int i = 0; i < rules.size(); i++) {
215             ParseNode rule = rules.elementAt(i);
216             if (!parse_rule(rule)) {
217                 ok = false;
218             }
219         }
220                
221         /* type check */       
222         Iterator ruleiterator = state.vRules.iterator();
223         
224         while (ruleiterator.hasNext()) {
225             Rule rule = (Rule) ruleiterator.next();            
226             Expr guard = rule.getGuardExpr();
227             final SymbolTable rulest = rule.getSymbolTable();
228             SemanticAnalyzer sa = new SemanticAnalyzer() {
229                     public IRErrorReporter getErrorReporter() { return er; }
230                     public SymbolTable getSymbolTable() { return rulest; }
231                 };
232             TypeDescriptor guardtype = guard.typecheck(sa);
233             
234             if (guardtype == null) {
235                 ok = false;
236             } else if (guardtype != ReservedTypeDescriptor.INT) {
237                 er.report(null, "Type of guard must be 'int' not '" + guardtype.getSymbol() + "'");
238                 ok = false;
239             }
240             
241             if (!rule.getInclusion().typecheck(sa)) {
242                 ok = false;
243             }           
244             
245             Iterator quantifiers = rule.quantifiers();
246             
247             while (quantifiers.hasNext()) {
248                 Quantifier q = (Quantifier) quantifiers.next();
249                 
250                 if (q instanceof ForQuantifier && !((ForQuantifier)q).typecheck(sa)) {
251                     ok = false;
252                 }
253             }              
254         }        
255
256         /* do any post checks ?? */
257
258         return ok;
259     }
260
261     private boolean parse_rule(ParseNode pn) {
262         if (!precheck(pn, "rule")) {
263             return false;
264         }
265
266         boolean ok = true;
267         Rule rule = new Rule();
268         
269         /* get rule type */
270         boolean isstatic = pn.getChild("static") != null;
271         boolean isdelay = pn.getChild("delay") != null;
272         rule.setStatic(isstatic);
273         rule.setDelay(isdelay);
274
275         /* set up symbol table for constraint */
276         assert sts.empty();
277         sts.push(stGlobals);
278         sts.push(rule.getSymbolTable());
279
280         /* optional quantifiers */
281         if (pn.getChild("quantifiers") != null) {
282             ParseNodeVector quantifiers = pn.getChild("quantifiers").getChildren();
283             
284             for (int i = 0; i < quantifiers.size(); i++) {
285                 ParseNode qn = quantifiers.elementAt(i);
286                 Quantifier quantifier = parse_quantifier(qn);
287
288                 if (quantifier == null) {
289                     ok = false;
290                 } else {
291                     rule.addQuantifier(quantifier);
292                 }
293             }
294         }
295         
296         /* get guard expr */
297         Expr guard = parse_expr(pn.getChild("expr"));
298
299         if (guard == null) {
300             ok = false;
301         } else {
302             rule.setGuardExpr(guard);
303         }
304
305         /* inclusion constraint */
306         Inclusion inclusion = parse_inclusion(pn.getChild("inclusion"));
307         
308         if (inclusion == null) {
309             ok = false;
310         } else {
311             rule.setInclusion(inclusion);
312         }
313         
314         /* pop symbol table stack */
315         SymbolTable st = sts.pop();
316         sts.pop(); /* pop off globals */
317
318         /* make sure the stack we pop is our rule s.t. */
319         assert st == rule.getSymbolTable(); 
320         assert sts.empty();
321
322         /* add rule to global set */
323         vRules.addElement(rule);
324
325         return ok;
326     }
327
328     private Inclusion parse_inclusion(ParseNode pn) {
329         if (!precheck(pn, "inclusion")) {
330             return null;
331         }
332
333         if (pn.getChild("set") != null) {
334             ParseNode set = pn.getChild("set");
335             Expr expr = parse_expr(set.getChild("expr"));
336             
337             if (expr == null) {
338                 return null;
339             }
340
341             String setname = set.getChild("name").getTerminal();
342             assert setname != null;
343             SetDescriptor sd = lookupSet(setname);
344             
345             if (sd == null) {
346                 er.report(set.getChild("name"), "Undefined set '" + setname + "'");
347                 return null;
348             }
349
350             return new SetInclusion(expr, sd);
351         } else if (pn.getChild("relation") != null) {
352             ParseNode relation = pn.getChild("relation");
353             Expr leftexpr = parse_expr(relation.getChild("left").getChild("expr"));
354             Expr rightexpr = parse_expr(relation.getChild("right").getChild("expr"));
355             
356             if ((leftexpr == null) || (rightexpr == null)) {
357                 return null;
358             }
359
360             String relname = relation.getChild("name").getTerminal();
361             assert relname != null;
362             RelationDescriptor rd = lookupRelation(relname);
363
364             if (rd == null) {
365                 er.report(relation.getChild("name"), "Undefined relation '" + relname + "'");
366                 return null;
367             }
368
369             return new RelationInclusion(leftexpr, rightexpr, rd);
370         } else {
371             throw new IRException();
372         }
373     }
374
375     private boolean parse_constraints(ParseNode pn) {
376         if (!precheck(pn, "constraints")) {
377             return false;
378         }
379
380         boolean ok = true;
381         ParseNodeVector constraints = pn.getChildren();
382
383         for (int i = 0; i < constraints.size(); i++) {
384             ParseNode constraint = constraints.elementAt(i);
385             assert constraint.getLabel().equals("constraint");
386             if (!parse_constraint(constraint)) {
387                 ok = false;
388             }
389         }
390
391         /* do any post checks... (type constraints, etc?) */
392
393         Iterator consiterator = state.vConstraints.iterator();
394
395         while (consiterator.hasNext()) {
396             Constraint cons = (Constraint) consiterator.next();
397
398             final SymbolTable consst = cons.getSymbolTable();
399             SemanticAnalyzer sa = new SemanticAnalyzer() {
400                     public IRErrorReporter getErrorReporter() { return er; }
401                     public SymbolTable getSymbolTable() { return consst; }
402                 };
403
404             TypeDescriptor constype = cons.getLogicStatement().typecheck(sa);
405
406             if (constype == null) {
407                 System.out.println("Failed attempting to type constraint");
408                 ok = false;
409             } else if (constype != ReservedTypeDescriptor.INT) {
410                 er.report(null, "Type of guard must be 'int' not '" + constype.getSymbol() + "'");
411                 ok = false;
412             }
413         }
414
415         return ok;
416     }
417
418     private boolean parse_constraint(ParseNode pn) {
419         if (!precheck(pn, "constraint")) {
420             return false;
421         }
422
423         boolean ok = true;
424         Constraint constraint = new Constraint();
425
426         /* test crash */
427         boolean crash = pn.getChild("crash") != null;
428         constraint.setCrash(crash);
429
430         /* set up symbol table for constraint */
431         assert sts.empty();
432         sts.push(constraint.getSymbolTable());
433         
434         /* get quantifiers */
435         if (pn.getChild("quantifiers") != null) {
436             ParseNodeVector quantifiers = pn.getChild("quantifiers").getChildren();
437             
438             for (int i = 0; i < quantifiers.size(); i++) {
439                 ParseNode qn = quantifiers.elementAt(i);
440                 assert qn.getLabel().equals("quantifier");
441                 Quantifier quantifier = parse_quantifier(qn);
442                 if (quantifier == null) {
443                     System.out.println("Failed parsing quantifier");
444                     ok = false;
445                 } else {
446                     constraint.addQuantifier(quantifier);
447                 }
448             }
449         }
450
451         /* get body */
452         LogicStatement logicexpr = parse_body(pn.getChild("body"));
453
454         if (logicexpr == null) {
455             System.out.println("Failed parsing logical expression");
456             ok = false;
457         } else {
458             constraint.setLogicStatement(logicexpr);
459         }
460         
461         /* pop symbol table stack */
462         SymbolTable st = sts.pop();
463
464         /* make sure the stack we pop is our constraint s.t. */
465         assert st == constraint.getSymbolTable(); 
466         assert sts.empty();
467
468         /* add to vConstraints */
469         vConstraints.addElement(constraint);
470
471         return ok;
472     }
473
474     private Quantifier parse_quantifier(ParseNode pn) {
475         if (!precheck(pn, "quantifier")) {
476             return null;           
477         }
478
479         if (pn.getChild("forall") != null) { /* forall element in Set */
480             SetQuantifier sq = new SetQuantifier();
481
482             /* get var */
483             VarDescriptor vd = reserveName(pn.getChild("var"));
484             
485             if (vd == null) {
486                 return null;
487             } 
488
489             sq.setVar(vd);
490
491             /* parse the set */
492             SetDescriptor set = parse_set(pn.getChild("set"));
493             assert set != null;
494             sq.setSet(set);
495             vd.setSet(set);
496
497             vd.setType(set.getType());
498
499             /* return to caller */
500             return sq;
501
502         } else if (pn.getChild("relation") != null) { /* for < v1, v2 > in Relation */
503             RelationQuantifier rq = new RelationQuantifier();
504
505             /* get vars */
506             VarDescriptor vd1 = reserveName(pn.getChild("left"));
507             VarDescriptor vd2 = reserveName(pn.getChild("right"));
508             
509             if ((vd1 == null) || (vd2 == null)) {
510                 return null;
511             }
512             
513             rq.setTuple(vd1, vd2);
514             
515             /* get relation */
516             String relationname = pn.getChild("relation").getTerminal();
517             assert relationname != null;
518             RelationDescriptor rd = lookupRelation(relationname);
519
520             if (rd == null) {
521                 return null;
522             }
523             
524             rq.setRelation(rd);
525             vd1.setType(rd.getDomain().getType());
526             vd1.setSet(rd.getDomain());
527             vd2.setType(rd.getRange().getType());
528             vd2.setSet(rd.getRange());
529             return rq;
530         } else if (pn.getChild("for") != null) { /* for j = x to y */
531             ForQuantifier fq = new ForQuantifier();
532             
533             /* grab var */
534             VarDescriptor vd = reserveName(pn.getChild("var"));
535             
536             if (vd == null) {
537                 return null;
538             }
539
540             vd.setSet(lookupSet("int", false));
541             vd.setType(ReservedTypeDescriptor.INT);
542             fq.setVar(vd);
543
544             /* grab lower/upper bounds */
545             Expr lower = parse_expr(pn.getChild("lower").getChild("expr"));
546             Expr upper = parse_expr(pn.getChild("upper").getChild("expr"));
547
548
549             if ((lower == null) || (upper == null)) {
550                 return null;
551             }
552             vd.setBounds(lower,upper);
553             fq.setBounds(lower, upper);
554
555             return fq;
556         } else {
557             throw new IRException("not supported yet");
558         }
559     }
560
561     private LogicStatement parse_body(ParseNode pn) {
562         if (!precheck(pn, "body")) {
563             return null;           
564         }
565         
566         if (pn.getChild("and") != null) {
567             /* body AND body */
568             LogicStatement left, right;
569             left = parse_body(pn.getChild("and").getChild("left").getChild("body"));
570             right = parse_body(pn.getChild("and").getChild("right").getChild("body"));
571             
572             if ((left == null) || (right == null)) {
573                 return null;
574             }
575             
576             // what do we want to call the and/or/not body classes?
577             return new LogicStatement(LogicStatement.AND, left, right);
578         } else if (pn.getChild("or") != null) {
579             /* body OR body */
580             LogicStatement left, right;
581             left = parse_body(pn.getChild("or").getChild("left").getChild("body"));
582             right = parse_body(pn.getChild("or").getChild("right").getChild("body"));
583             
584             if ((left == null) || (right == null)) {
585                 return null;
586             }
587
588             return new LogicStatement(LogicStatement.OR, left, right);
589         } else if (pn.getChild("not") != null) {
590             /* NOT body */
591             LogicStatement left = parse_body(pn.getChild("not").getChild("body"));
592             
593             if (left == null) {
594                 return null;
595             }
596             
597             return new LogicStatement(LogicStatement.NOT, left);
598         } else if (pn.getChild("predicate") != null) {
599             return parse_predicate(pn.getChild("predicate"));
600         } else {
601             throw new IRException();
602         }                        
603     }
604
605     private Predicate parse_predicate(ParseNode pn) {
606         if (!precheck(pn, "predicate")) {
607             return null;
608         }
609
610         if (pn.getChild("inclusion") != null) {
611             ParseNode in = pn.getChild("inclusion");
612             
613             /* Expr */
614             Expr expr = parse_expr(in.getChild("expr"));
615            
616             if (expr == null) { 
617                 return null;
618             }
619
620             /* get set expr */
621             SetExpr setexpr = parse_setexpr(in.getChild("setexpr"));
622
623             if (setexpr == null) {
624                 return null;
625             }
626
627             return new InclusionPredicate(expr, setexpr);
628         } else if (pn.getChild("expr") != null) {
629             Expr expr = parse_expr(pn.getChild("expr"));
630             
631             if (expr == null) {
632                 return null;
633             }
634
635             return new ExprPredicate(expr);
636         } else {
637             throw new IRException();
638         }       
639     }
640
641     private SetDescriptor parse_set(ParseNode pn) {
642         if (!precheck(pn, "set")) {
643             return null;
644         }
645     
646         if (pn.getChild("name") != null) {
647             String setname = pn.getChild("name").getTerminal();
648             assert setname != null;
649                 
650             if (!stSets.contains(setname)) {
651                 /* Semantic Error: unknown set */
652                 er.report(pn, "Unknown set '" + setname + "' referenced in quantifier");
653                 return null;
654             } else {
655                 /* all good, get setdescriptor */
656                 SetDescriptor sd = (SetDescriptor) stSets.get(setname);
657                 assert sd != null;
658                 return sd;
659             }            
660         } else if (pn.getChild("listofliterals") != null) {            
661             TokenSetDescriptor tokenset = new TokenSetDescriptor();
662             ParseNodeVector token_literals = pn.getChild("listofliterals").getChildren();
663             assert token_literals.size() > 0;
664             
665             for (int i = 0; i < token_literals.size(); i++) {
666                 ParseNode literal = token_literals.elementAt(i);
667                 assert literal.getLabel().equals("literal");
668                 LiteralExpr litexpr = parse_literal(literal);
669
670                 if (litexpr == null) {
671                     return null;
672                 }
673                 
674                 if (litexpr instanceof TokenLiteralExpr || litexpr instanceof IntegerLiteralExpr) {
675                     tokenset.addLiteral(litexpr);
676                 } else {
677                     er.report(literal, "Elements of a user-defined set must be of type token or integer");
678                     // return null; /* don't think we need to return null */
679                 }
680             }               
681
682             return tokenset;
683         } else {
684             throw new IRException(pn.getTerminal());
685         }
686     }
687     
688     private boolean parse_space(ParseNode pn) {
689         if (!precheck(pn, "space")) {
690             return false;
691         }
692         
693         boolean ok = true;
694         ParseNodeVector sets = pn.getChildren("setdefinition");
695         ParseNodeVector relations = pn.getChildren("relationdefinition");
696
697         assert pn.getChildren().size() == (sets.size() + relations.size());
698         
699         /* parse sets */
700         for (int i = 0; i < sets.size(); i++) {
701             if (!parse_setdefinition(sets.elementAt(i))) {
702                 ok = false;
703             }
704         }
705
706         /* parse relations */
707         for (int i = 0; i < relations.size(); i++) {
708             if (!parse_relationdefinition(relations.elementAt(i))) {
709                 ok = false;
710             }
711         }
712
713         // ok, all the spaces have been parsed, now we should typecheck and check
714         // for cycles etc.
715
716         // #TBD#: typecheck and check for cycles
717       
718         /* replace missing with actual */
719         Iterator allsets = state.stSets.descriptors();
720         
721         while (allsets.hasNext()) {
722             SetDescriptor sd = (SetDescriptor) allsets.next();
723             Vector subsets = sd.getSubsets();
724
725             for (int i = 0; i < subsets.size(); i++) {
726                 SetDescriptor subset = (SetDescriptor) subsets.elementAt(i);
727                 
728                 if (subset instanceof MissingSetDescriptor) {
729                     SetDescriptor newsubset = lookupSet(subset.getSymbol());
730
731                     if (newsubset == null) {
732                         er.report(null, "Unknown subset '" + subset.getSymbol() + "'");
733                     } else {
734                         subsets.setElementAt(newsubset, i);
735                     }
736                 }
737             }
738         }
739         
740         return ok;
741     }
742
743     private boolean parse_setdefinition(ParseNode pn) {
744         if (!precheck(pn, "setdefinition")) {
745             return false;
746         }
747         
748         boolean ok = true;
749         
750         /* get set name */
751         String setname = pn.getChild("name").getTerminal();
752         assert (setname != null);
753
754         SetDescriptor sd = new SetDescriptor(setname);
755         
756         /* get set type */
757         String settype = pn.getChild("type").getTerminal();
758         TypeDescriptor type = lookupType(settype);
759         if (type == null) {
760             er.report(pn, "Undefined type '" + settype + "'");
761             ok = false; 
762         } else {
763             sd.setType(type);
764         }
765
766         /* is this a partition? */
767         boolean partition = pn.getChild("partition") != null;
768         sd.isPartition(partition); 
769
770         /* if set has subsets, add them to set descriptor */
771         if (pn.getChild("setlist") != null) {
772             ParseNodeVector setlist = pn.getChild("setlist").getChildren();
773             
774             for (int i = 0; i < setlist.size(); i++) {
775                 String subsetname = setlist.elementAt(i).getLabel();
776                 sd.addSubset(lookupSet(subsetname, CREATE_MISSING));
777             }            
778         }
779
780         /* add set to symbol table */
781         if (stSets.contains(setname)) {
782             // Semantic Check: redefinition
783             er.report(pn, "Redefinition of set: " + setname);
784             ok = false;
785         } else {
786             stSets.add(sd);
787         }
788
789         return ok;
790     }
791
792     private boolean parse_relationdefinition(ParseNode pn) {
793         if (!precheck(pn, "relationdefinition")) {
794             return false;
795         }
796
797         boolean ok = true;
798
799         /* get relation name */
800         String relname = pn.getChild("name").getTerminal();
801         assert relname != null;
802
803         RelationDescriptor rd = new RelationDescriptor(relname);
804
805         /* check if static */
806         boolean bStatic = pn.getChild("static") != null;
807         rd.isStatic(bStatic);
808
809         /* get domain */
810         String domainsetname = pn.getChild("domain").getChild("type").getTerminal();
811         assert domainsetname != null;
812
813         /* get range */
814         String rangesetname = pn.getChild("range").getChild("type").getTerminal();
815         assert rangesetname != null;
816
817         /* get domain multiplicity */   
818         String domainmult;
819         if (pn.getChild("domain").getChild("domainmult") != null)
820             domainmult = pn.getChild("domain").getChild("domainmult").getChild("mult").getTerminal();
821         //assert domainmult != null;
822
823         /* get range multiplicity */
824         String rangemult;
825         if (pn.getChild("range").getChild("domainrange") != null)
826             rangemult = pn.getChild("range").getChild("domainrange").getChild("mult").getTerminal();
827         //assert rangemult != null;
828
829         /* NOTE: it is assumed that the sets have been parsed already so that the 
830            set namespace is fully populated. any missing setdescriptors for the set
831            symbol table will be assumed to be errors and reported. */
832
833         SetDescriptor domainset = lookupSet(domainsetname);
834         if (domainset == null) {
835             er.report(pn, "Undefined set '" + domainsetname + "' referenced in relation '" + relname + "'");
836             ok = false;
837         } else {
838             rd.setDomain(domainset);
839         }
840
841         SetDescriptor rangeset = lookupSet(rangesetname);
842         if (rangeset == null) {
843             er.report(pn, "Undefined set '" + rangesetname + "' referenced in relation '" + relname + "'");
844             ok = false;
845         } else {
846             rd.setRange(rangeset);
847         }
848
849         // #TBD#: eventually we'll use the multiplicities but now we don't... oh well
850
851         /* lets add the relation to the global symbol table */
852         if (!stRelations.contains(relname)) {
853             stRelations.add(rd);
854         } else {
855             er.report(pn, "Redefinition of relation '" + relname + "'");
856             ok = false;
857         }
858
859         return ok;
860     }
861
862     private boolean parse_structures(ParseNode pn) {
863         if (!precheck(pn, "structures")) {
864             return false;
865         }
866         
867         boolean ok = true;
868         ParseNodeVector structures = pn.getChildren("structure");
869
870         for (int i = 0; i < structures.size(); i++) {
871             if (!parse_structure(structures.elementAt(i))) {
872                 ok = false;
873             }
874         }
875
876         ParseNodeVector globals = pn.getChildren("global");
877
878         for (int i = 0; i < globals.size(); i++) {
879             if (!parse_global(globals.elementAt(i))) {
880                 ok = false;
881             }
882         }
883
884         // ok, all the structures have been parsed, now we gotta type check       
885
886         Enumeration types = stTypes.getDescriptors();
887         while (types.hasMoreElements()) {
888             TypeDescriptor t = (TypeDescriptor) types.nextElement();
889
890             if (t instanceof ReservedTypeDescriptor) {
891                 // we don't need to check reserved types
892             } else if (t instanceof StructureTypeDescriptor) {
893                 
894                 StructureTypeDescriptor type = (StructureTypeDescriptor) t;
895                 TypeDescriptor subtype = type.getSuperType();
896
897                 // check that the subtype is valid
898                 if (subtype instanceof MissingTypeDescriptor) {
899                     TypeDescriptor newtype = lookupType(subtype.getSymbol());
900                     if (newtype == null) {
901                         // subtype not defined anywheere
902                         // #TBD#: somehow determine how we can get the original parsenode (global function?)
903                         er.report(null, "Undefined subtype '" + subtype.getSymbol() + "'");
904                         ok = false;
905                     } else {
906                         type.setSuperType(newtype);
907                     }
908                 }
909
910                 Iterator fields = type.getFields();
911
912                 while (fields.hasNext()) {
913                     FieldDescriptor field = (FieldDescriptor) fields.next();                        
914                     TypeDescriptor fieldtype = field.getType();
915
916                     assert fieldtype != null;
917
918                     // check that the type is valid
919                     if (fieldtype instanceof MissingTypeDescriptor) {
920                         TypeDescriptor newtype = lookupType(fieldtype.getSymbol());
921                         if (newtype == null) {
922                             // type never defined
923                             // #TBD#: replace new ParseNode with original parsenode
924                             
925                             if (!field.getPtr()) { 
926                                 /* Pointer types don't have to be defined */
927                                 er.report(null, "Undefined type '" + fieldtype.getSymbol() + "'");
928                                 ok = false;
929                             }
930                         } else {
931                             assert newtype != null;
932                             field.setType(newtype);
933                         }
934                     }
935                 }
936
937                 Iterator labels = type.getLabels();
938
939                 while (labels.hasNext()) {
940                     LabelDescriptor label = (LabelDescriptor) labels.next();
941                     TypeDescriptor labeltype = label.getType();
942
943                     assert labeltype != null;
944
945                     // check that the type is valid
946                     if (labeltype instanceof MissingTypeDescriptor) {
947                         TypeDescriptor newtype = lookupType(labeltype.getSymbol());
948                         if (newtype == null) {
949                             // type never defined
950                             // #TBD#: replace new ParseNode with original parsenode
951                             er.report(null, "Undefined type '" + labeltype.getSymbol() + "'");
952                             ok = false;
953                         } else {
954                             assert newtype != null;
955                             label.setType(newtype);
956                         }
957                     }
958                 }
959                 
960             } else {
961                 throw new IRException("shouldn't be any other typedescriptor classes");
962             }
963         }
964
965         if (!ok) {
966             return false;
967         }
968
969         types = stTypes.getDescriptors();
970
971         while (types.hasMoreElements()) {
972             TypeDescriptor t = (TypeDescriptor) types.nextElement();
973
974             if (t instanceof ReservedTypeDescriptor) {
975                 // we don't need to check reserved types
976             } else if (t instanceof StructureTypeDescriptor) {
977                 
978                 StructureTypeDescriptor type = (StructureTypeDescriptor)t;
979                 TypeDescriptor subtype = type.getSuperType();
980                 Iterator fields = type.getFields();
981
982                 while (fields.hasNext()) {
983                     FieldDescriptor field = (FieldDescriptor) fields.next();                        
984
985                     if (field instanceof ArrayDescriptor) {
986                         ArrayDescriptor ad = (ArrayDescriptor) field;
987                         Expr indexbound = ad.getIndexBound();
988                         TypeDescriptor indextype = indexbound.typecheck(new SemanticAnalyzer() {
989                                 public IRErrorReporter getErrorReporter() { return er; }
990                                 public SymbolTable getSymbolTable() { return stGlobals; }
991                             });
992
993                         if (indextype == null) {
994                             ok = false;
995                         } else if (indextype != ReservedTypeDescriptor.INT) {
996                             er.report(null, "'" + type.getSymbol() + "." + field.getSymbol() + "' index bounds must be type 'int' not '" + indextype.getSymbol() + "'");
997                             ok = false;
998                         }
999                     }
1000                 }
1001
1002                 Iterator labels = type.getLabels();
1003
1004                 while (labels.hasNext()) {
1005                     LabelDescriptor label = (LabelDescriptor) labels.next();
1006                     Expr index = label.getIndex();
1007
1008                     if (index != null) {
1009                         TypeDescriptor indextype = index.typecheck(new SemanticAnalyzer() {
1010                                 public IRErrorReporter getErrorReporter() { return er; }
1011                                 public SymbolTable getSymbolTable() { return stGlobals; }
1012                             });
1013                         
1014                         if (indextype != ReservedTypeDescriptor.INT) {
1015                             er.report(null, "Label '" + type.getSymbol() + "." + label.getSymbol() + "' index must be type 'int' not '" + indextype.getSymbol() + "'");
1016                             ok = false;
1017                         }
1018                     }
1019                 }
1020             } else {
1021                 throw new IRException("shouldn't be any other typedescriptor classes");
1022             }
1023         }
1024
1025         // #TBD#: need to make sure that no cycles exist in any of the declarations or subtypes
1026         // subtypes, of course, are not real subtypes, they are merely a way to validate a 
1027         // cast, i believe
1028
1029         return ok;
1030     }
1031
1032     private boolean parse_global(ParseNode pn) {
1033         if (!precheck(pn, "global")) {
1034             return false;
1035         }
1036
1037         String name = pn.getChild("name").getTerminal();
1038         assert name != null;
1039
1040         String type = pn.getChild("type").getTerminal();
1041         assert type != null;
1042         TypeDescriptor td = lookupType(type);
1043         assert td != null;
1044         assert !(td instanceof ReservedTypeDescriptor);
1045         
1046         if (stGlobals.contains(name)) {
1047             /* redefinition of global */
1048             er.report(pn, "Redefinition of global '" + name + "'");
1049             return false;
1050         }
1051
1052         stGlobals.add(new VarDescriptor(name, name, td,true));
1053         return true;
1054     }
1055
1056     private boolean parse_structure(ParseNode pn) {
1057         if (!precheck(pn, "structure")) {
1058             return false;
1059         }
1060
1061         boolean ok = true;
1062         String typename = pn.getChild("name").getTerminal();
1063         StructureTypeDescriptor type = new StructureTypeDescriptor(typename);
1064         
1065         if (pn.getChild("subtype") != null) {
1066             // has a subtype, lets try to resolve it
1067             String subtype = pn.getChild("subtype").getTerminal();
1068
1069             if (subtype.equals(typename)) {
1070                 // Semantic Error: cyclic inheritance
1071                 er.report(pn, "Cyclic inheritance prohibited");
1072                 ok = false;
1073             }
1074
1075             /* lookup the type to get the type descriptor */
1076             type.setSuperType(lookupType(subtype, CREATE_MISSING));
1077         } else if (pn.getChild("subclass") != null) {
1078             // has a subtype, lets try to resolve it
1079             String subclass = pn.getChild("subclass").getTerminal();
1080             
1081             if (subclass.equals(typename)) {
1082                 // Semantic Error: cyclic inheritance
1083                 er.report(pn, "Cyclic inheritance prohibited");
1084                 ok = false;
1085             }
1086
1087             /* lookup the type to get the type descriptor */
1088             type.setSuperType(lookupType(subclass, CREATE_MISSING));
1089             type.setSubClass(true);
1090         }
1091
1092         // set the current type so that the recursive parses on the labels
1093         // and fields can add themselves automatically to the current type         
1094         dCurrentType = type;
1095         
1096         // parse the labels and fields
1097         if (!parse_labelsandfields(pn.getChild("lf"))) {
1098             ok = false;
1099         }
1100
1101         if (stTypes.contains(typename)) {
1102             er.report(pn, "Redefinition of type '" + typename + "'");
1103             ok = false;
1104         } else {
1105             stTypes.add(type);
1106         }
1107         
1108         return ok;
1109     }
1110
1111     private boolean parse_labelsandfields(ParseNode pn) {
1112         if (!precheck(pn, "lf")) {
1113             return false;
1114         }
1115
1116         boolean ok = true;
1117      
1118         // check the fields first (need the field names 
1119         // to type check the labels)
1120         if (!parse_fields(pn.getChild("fields"))) {
1121             ok = false;
1122         }
1123
1124         // check the labels now that all the fields are sorted
1125         if (!parse_labels(pn.getChild("labels"))) {
1126             ok = false;
1127         }
1128
1129         return ok;
1130     }
1131
1132     private boolean parse_fields(ParseNode pn) {
1133         if (!precheck(pn, "fields")) {
1134             return false;
1135         }
1136         
1137         boolean ok = true;
1138         
1139         /* NOTE: because the order of the fields is important when defining a data structure,
1140            and because the order is defined by the order of the fields defined in the field
1141            vector, its important that the parser returns the fields in the correct order */
1142         
1143         ParseNodeVector fields = pn.getChildren();
1144
1145         for (int i = 0; i < fields.size(); i++) {
1146             ParseNode field = fields.elementAt(i);            
1147             FieldDescriptor fd;
1148             boolean reserved;
1149             String name = null;
1150
1151             if (field.getChild("reserved") != null) {
1152                 // reserved field
1153                 // #TBD#: it will be necessary for reserved field descriptors to generate
1154                 // a unique symbol for the type descriptor requires it for its hashtable
1155                 fd = new ReservedFieldDescriptor();
1156                 reserved = true;
1157             } else {
1158                 name = field.getChild("name").getTerminal();                
1159                 fd = new FieldDescriptor(name);
1160                 reserved = false;
1161             }
1162
1163             String type = field.getChild("type").getTerminal();
1164             boolean ptr = field.getChild("*") != null;
1165             fd.setPtr(ptr);
1166
1167             fd.setType(lookupType(type, CREATE_MISSING));
1168
1169             if (field.getChild("index") != null) {
1170                 // field is an array, so create an array descriptor to wrap the 
1171                 // field descriptor and then replace the top level field descriptor with
1172                 // this array descriptor
1173                 Expr expr = parse_expr(field.getChild("index").getChild("expr"));
1174                 if (expr == null) {
1175                     // #ATTN#: do we really want to return an exception here?
1176                     throw new IRException("invalid index expression");
1177                 }
1178                 ArrayDescriptor ad = new ArrayDescriptor(fd, expr);               
1179                 fd = ad;
1180             }
1181
1182             // add the current field to the current type
1183             if (reserved == false) {
1184                 // lets double check that we are redefining a field
1185                 if (dCurrentType.getField(name) != null) {
1186                     // Semantic Error: field redefinition 
1187                     er.report(pn, "Redefinition of field '" + name + "'");
1188                     ok = false;
1189                 } else {
1190                     dCurrentType.addField(fd);
1191                 }
1192             } else {
1193                 dCurrentType.addField(fd);
1194             }
1195         }
1196         
1197         return ok;
1198     }
1199
1200     private boolean parse_labels(ParseNode pn) {
1201         if (!precheck(pn, "labels")) {
1202             return false;
1203         }
1204
1205         boolean ok = true;
1206
1207         /* NOTE: parse_labels should be called after the fields have been parsed because any
1208            labels not found in the field set of the current type will be flagged as errors */
1209
1210         ParseNodeVector labels = pn.getChildren();
1211
1212         for (int i = 0; i < labels.size(); i++) {           
1213             ParseNode label = labels.elementAt(i);
1214             String name = label.getChild("name").getTerminal();
1215             LabelDescriptor ld = new LabelDescriptor(name); 
1216
1217             if (label.getChild("index") != null) {
1218                 Expr expr = parse_expr(label.getChild("index").getChild("expr"));
1219                 if (expr == null) {
1220                     /* #ATTN#: do we really want to return an exception here? */
1221                     throw new IRException("Invalid expression");
1222                 }
1223                 ld.setIndex(expr);                
1224             } 
1225             
1226             String type = label.getChild("type").getTerminal();
1227
1228             ld.setType(lookupType(type, CREATE_MISSING));
1229                         
1230             String field = label.getChild("field").getTerminal();           
1231             FieldDescriptor fd = dCurrentType.getField(field);
1232
1233             if (fd == null) {
1234                 /* Semantic Error: Undefined field in label */
1235                 er.report(label, "Undefined field '" + field + "' in label");
1236                 ok = false;
1237             } else {
1238                 ld.setField(fd);
1239             }
1240
1241             /* add label to current type */
1242             if (dCurrentType.getLabel(name) != null) {
1243                 /* semantic error: label redefinition */
1244                 er.report(pn, "Redefinition of label '" + name + "'");
1245                 ok = false;
1246             } else {
1247                 dCurrentType.addLabel(ld);            
1248             }
1249         }
1250
1251         return ok;
1252     }
1253
1254     private Expr parse_expr(ParseNode pn) {
1255         if (!precheck(pn, "expr")) {
1256             return null;
1257         }
1258
1259         if (pn.getChild("var") != null) {
1260             // we've got a variable reference... we'll have to scope check it later
1261             // when we are completely done... there are also some issues of cyclic definitions
1262             return new VarExpr(pn.getChild("var").getTerminal());
1263         } else if (pn.getChild("literal") != null) {
1264             return parse_literal(pn.getChild("literal"));
1265         } else if (pn.getChild("operator") != null) {
1266             return parse_operator(pn.getChild("operator"));
1267         } else if (pn.getChild("relation") != null) {
1268             return parse_relation(pn.getChild("relation"));
1269         } else if (pn.getChild("sizeof") != null) {
1270             return parse_sizeof(pn.getChild("sizeof"));
1271         } else if (pn.getChild("simple_expr") != null) {
1272             return parse_simple_expr(pn.getChild("simple_expr"));        
1273         } else if (pn.getChild("elementof") != null) {
1274             return parse_elementof(pn.getChild("elementof"));        
1275         } else if (pn.getChild("tupleof") != null) {
1276             return parse_tupleof(pn.getChild("tupleof"));        
1277         } else if (pn.getChild("isvalid") != null) {
1278             er.report(pn, "Operation 'isvalid' is currently unsupported.");
1279             return null;
1280         } else {
1281             er.report(pn, "Unknown or invalid expression type '" + pn.getTerminal() + "'");
1282             return null;
1283         }            
1284     }
1285
1286     private Expr parse_elementof(ParseNode pn) {
1287         if (!precheck(pn, "elementof")) {
1288             return null;
1289         }
1290
1291         /* get setname */
1292         String setname = pn.getChild("name").getTerminal();
1293         assert setname != null;
1294         SetDescriptor sd = lookupSet(setname);
1295
1296         if (sd == null) {
1297             er.report(pn, "Undefined set '" + setname + "'");
1298             return null;
1299         }
1300
1301         /* get left side expr */
1302         Expr expr = parse_expr(pn.getChild("expr"));
1303         
1304         if (expr == null) {
1305             return null;
1306         }
1307
1308         return new ElementOfExpr(expr, sd);
1309     }
1310
1311     private Expr parse_tupleof(ParseNode pn) {
1312         if (!precheck(pn, "tupleof")) {
1313             return null;
1314         }
1315         
1316         /* get relation */
1317         String relname = pn.getChild("name").getTerminal();
1318         assert relname != null;
1319         RelationDescriptor rd = lookupRelation(relname);
1320
1321         if (rd == null) {
1322             er.report(pn, "Undefined relation '" + relname + "'");
1323             return null;
1324         }
1325
1326         Expr left = parse_expr(pn.getChild("left").getChild("expr"));
1327         Expr right = parse_expr(pn.getChild("right").getChild("expr"));
1328
1329         if ((left == null) || (right == null)) {
1330             return null;
1331         }
1332
1333         return new TupleOfExpr(left, right, rd);
1334     }
1335
1336     private Expr parse_simple_expr(ParseNode pn) {
1337         if (!precheck(pn, "simple_expr")) {
1338             return null;
1339         }
1340
1341         // only locations so far
1342         return parse_location(pn.getChild("location"));
1343     }
1344
1345     private Expr parse_location(ParseNode pn) {
1346         if (!precheck(pn, "location")) {
1347             return null;
1348         }
1349
1350         if (pn.getChild("var") != null) {
1351             // should be changed into a namespace check */
1352             return new VarExpr(pn.getChild("var").getTerminal());
1353         } else if (pn.getChild("cast") != null) {
1354             return parse_cast(pn.getChild("cast"));
1355         } else if (pn.getChild("dot") != null) {
1356             return parse_dot(pn.getChild("dot"));
1357         } else {
1358             throw new IRException();
1359         }
1360     }
1361
1362     private RelationExpr parse_relation(ParseNode pn) {
1363         if (!precheck(pn, "relation")) {
1364             return null;
1365         }
1366
1367         String relname = pn.getChild("name").getTerminal();
1368         boolean inverse = pn.getChild("inv") != null;
1369         Expr expr = parse_expr(pn.getChild("expr"));        
1370
1371         if (expr == null) {
1372             return null;
1373         }
1374                     
1375         RelationDescriptor relation = lookupRelation(relname);
1376             
1377         if (relation == null) {
1378             /* Semantic Error: relation not definied" */
1379             er.report(pn, "Undefined relation '" + relname + "'");
1380             return null;
1381         }                       
1382
1383         /* add usage so correct sets are created */
1384         relation.addUsage(inverse ? RelationDescriptor.INVIMAGE : RelationDescriptor.IMAGE);
1385             
1386         return new RelationExpr(expr, relation, inverse);
1387     }
1388
1389     private SizeofExpr parse_sizeof(ParseNode pn) {
1390         if (!precheck(pn, "sizeof")) {
1391             return null;
1392         }
1393
1394         /* get setexpr */
1395         SetExpr setexpr = parse_setexpr(pn.getChild("setexpr"));
1396         
1397         if (setexpr == null) {
1398             return null;
1399         }
1400
1401         return new SizeofExpr(setexpr);
1402     }
1403
1404     private CastExpr parse_cast(ParseNode pn) {
1405         if (!precheck(pn, "cast")) {
1406             return null;
1407         }
1408
1409         /* get type */
1410         String typename = pn.getChild("type").getTerminal();
1411         assert typename != null;
1412         TypeDescriptor type = lookupType(typename);
1413
1414         if (type == null) {
1415             /* semantic error: undefined type in cast */
1416             er.report(pn, "Undefined type '" + typename + "' in cast operator");
1417             return null;
1418         } 
1419
1420         /* get expr */
1421         Expr expr = parse_simple_expr(pn.getChild("simple_expr"));
1422         
1423         if (expr == null) {
1424             return null;
1425         } 
1426
1427         return new CastExpr(type, expr);
1428     }
1429
1430     private SetExpr parse_setexpr(ParseNode pn) {
1431         if (!precheck(pn, "setexpr")) {
1432             return null;
1433         }
1434
1435         // #TBD#: setexpr and parse_relation seem to be cousins... is there a reduction/refactor possible?
1436
1437         if (pn.getChild("set") != null) {
1438             String setname = pn.getChild("set").getTerminal();
1439             assert setname != null;
1440             SetDescriptor sd = lookupSet(setname);
1441
1442             if (sd == null) {
1443                 er.report(pn, "Unknown or undefined set '" + setname + "'");             
1444                 return null;
1445             } else {                         
1446                 return new SetExpr(sd);
1447             }
1448         } else if (pn.getChild("dot") != null) {
1449             VarDescriptor vd = parse_quantifiervar(pn.getChild("dot").getChild("quantifiervar"));
1450             RelationDescriptor relation = lookupRelation(pn.getChild("dot").getChild("relation").getTerminal());
1451             relation.addUsage(RelationDescriptor.IMAGE);
1452             return new ImageSetExpr(vd, relation);
1453         } else if (pn.getChild("dotinv") != null) {
1454             VarDescriptor vd = parse_quantifiervar(pn.getChild("dotinv").getChild("quantifiervar"));
1455             RelationDescriptor relation = lookupRelation(pn.getChild("dotinv").getChild("relation").getTerminal());
1456             relation.addUsage(RelationDescriptor.INVIMAGE);
1457             return new ImageSetExpr(ImageSetExpr.INVERSE, vd, relation);
1458         } else {
1459             throw new IRException();
1460         }
1461     }
1462
1463     private VarDescriptor parse_quantifiervar(ParseNode pn) {
1464         if (!precheck(pn, "quantifiervar")) {
1465             return null;
1466         }
1467
1468         /* get var */
1469         String varname = pn.getTerminal();
1470         assert varname != null;
1471         
1472         /* NOTE: quantifier var's are only found in the constraints and
1473            model definitions... therefore we can do a semantic check here 
1474            to make sure that the variables exist in the symbol table */
1475
1476         /* NOTE: its assumed that the symbol table stack is appropriately
1477            set up with the parent quantifier symbol table */
1478         assert !sts.empty();          
1479
1480         /* do semantic check and if valid, add it to symbol table
1481            and add it to the quantifier as well */
1482         if (sts.peek().contains(varname)) {
1483             VarDescriptor vdold=(VarDescriptor)sts.peek().get(varname);
1484             return vdold;
1485             /*     Dan was creating a new VarDescriptor...This seems
1486                    like the wrong thing to do.  We'll just lookup the
1487                    other one.
1488                    --------------------------------------------------
1489                    VarDescriptor vd=new VarDescriptor(varname);
1490                    vd.setSet(vdold.getSet()); return vd;*/
1491         } else {
1492             /* Semantic Error: undefined variable */
1493             er.report(pn, "Undefined variable '" + varname + "'");
1494             return null;
1495         }
1496     }
1497     
1498     private LiteralExpr parse_literal(ParseNode pn) {
1499         if (!precheck(pn, "literal")) {
1500             return null;
1501         }
1502
1503         if (pn.getChild("boolean") != null) {
1504             if (pn.getChild("boolean").getChild("true") != null) {
1505                 return new BooleanLiteralExpr(true);
1506             } else {
1507                 return new BooleanLiteralExpr(false);
1508             } 
1509         } else if (pn.getChild("decimal") != null) {            
1510             String integer = pn.getChild("decimal").getTerminal();
1511
1512             /* Check for integer literal overflow */
1513             BigInteger intLitBI = new BigInteger(integer);
1514             BigInteger intMax = new BigInteger("" + Integer.MAX_VALUE);
1515             BigInteger intMin = new BigInteger("" + Integer.MIN_VALUE);
1516             int value;
1517
1518             if (intLitBI.compareTo(intMin) < 0) {
1519                 value = Integer.MIN_VALUE;
1520                 er.warn(pn, "Integer literal overflow");
1521             } else if (intLitBI.compareTo(intMax) > 0) {
1522                 value = Integer.MAX_VALUE;
1523                 er.warn(pn, "Integer literal overflow");
1524             } else {
1525                 /* no truncation needed */
1526                 value = Integer.parseInt(integer);
1527             }
1528
1529             return new IntegerLiteralExpr(value);
1530         } else if (pn.getChild("token") != null) {
1531             return new TokenLiteralExpr(pn.getChild("token").getTerminal());
1532         } else if (pn.getChild("string") != null) {
1533             throw new IRException("string unsupported");
1534         } else if (pn.getChild("char") != null) {
1535             throw new IRException("char unsupported");
1536         } else {
1537             throw new IRException("unknown literal expression type.");
1538         }
1539     }
1540
1541     private OpExpr parse_operator(ParseNode pn) {
1542         if (!precheck(pn, "operator")) {
1543             return null; 
1544         }
1545
1546         String opname = pn.getChild("op").getTerminal();
1547         Opcode opcode = Opcode.decodeFromString(opname);
1548
1549         if (opcode == null) {
1550             er.report(pn, "Unsupported operation: " + opname);
1551             return null;
1552         }
1553         
1554         Expr left = parse_expr(pn.getChild("left").getChild("expr"));
1555         Expr right = null;
1556         
1557         if (pn.getChild("right") != null) {
1558             right = parse_expr(pn.getChild("right").getChild("expr"));
1559         }
1560
1561         if (left == null) {           
1562             return null;
1563         }
1564
1565         if (right == null && opcode != Opcode.NOT) {
1566             er.report(pn, "Two arguments required.");
1567             return null;
1568         }
1569
1570         return new OpExpr(opcode, left, right);
1571     }
1572
1573     private DotExpr parse_dot(ParseNode pn) {
1574         if (!precheck(pn, "dot")) {
1575             return null;
1576         }
1577
1578         Expr left = parse_simple_expr(pn.getChild("simple_expr"));
1579
1580         if (left == null) {
1581             return null;
1582         }
1583
1584         String field = pn.getChild("field").getTerminal();
1585
1586         Expr index = null;
1587
1588         if (pn.getChild("index") != null) {
1589             index = parse_expr(pn.getChild("index").getChild("expr"));
1590             
1591             if (index == null) {
1592                 return null;
1593             }
1594         }
1595
1596         return new DotExpr(left, field, index);        
1597     }
1598
1599 }
1600