5339bb74f4ab956d1dad7e28584884d63060c1ce
[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         return ok;
394     }
395
396     private boolean parse_constraint(ParseNode pn) {
397         if (!precheck(pn, "constraint")) {
398             return false;
399         }
400
401         boolean ok = true;
402         Constraint constraint = new Constraint();
403
404         /* test crash */
405         boolean crash = pn.getChild("crash") != null;
406         constraint.setCrash(crash);
407
408         /* set up symbol table for constraint */
409         assert sts.empty();
410         sts.push(constraint.getSymbolTable());
411         
412         /* get quantifiers */
413         if (pn.getChild("quantifiers") != null) {
414             ParseNodeVector quantifiers = pn.getChild("quantifiers").getChildren();
415             
416             for (int i = 0; i < quantifiers.size(); i++) {
417                 ParseNode qn = quantifiers.elementAt(i);
418                 assert qn.getLabel().equals("quantifier");
419                 Quantifier quantifier = parse_quantifier(qn);
420                 if (quantifier == null) {
421                     ok = false;
422                 } else {
423                     constraint.addQuantifier(quantifier);
424                 }
425             }
426         }
427                                                       
428         /* get body */
429         LogicStatement logicexpr = parse_body(pn.getChild("body"));
430
431         if (logicexpr == null) {
432             ok = false;
433         } else {
434             constraint.setLogicStatement(logicexpr);
435         }
436         
437         /* pop symbol table stack */
438         SymbolTable st = sts.pop();
439
440         /* make sure the stack we pop is our constraint s.t. */
441         assert st == constraint.getSymbolTable(); 
442         assert sts.empty();
443
444         /* add to vConstraints */
445         vConstraints.addElement(constraint);           
446
447         return ok;
448     }
449
450     private Quantifier parse_quantifier(ParseNode pn) {
451         if (!precheck(pn, "quantifier")) {
452             return null;           
453         }
454
455         if (pn.getChild("forall") != null) { /* forall element in Set */
456             SetQuantifier sq = new SetQuantifier();
457
458             /* get var */
459             VarDescriptor vd = reserveName(pn.getChild("var"));
460             
461             if (vd == null) {
462                 return null;
463             } 
464
465             sq.setVar(vd);
466
467             /* parse the set */
468             SetDescriptor set = parse_set(pn.getChild("set"));
469             assert set != null;
470             sq.setSet(set);
471
472             vd.setType(set.getType());
473
474             /* return to caller */
475             return sq;
476
477         } else if (pn.getChild("relation") != null) { /* for < v1, v2 > in Relation */
478             RelationQuantifier rq = new RelationQuantifier();
479
480             /* get vars */
481             VarDescriptor vd1 = reserveName(pn.getChild("left"));
482             VarDescriptor vd2 = reserveName(pn.getChild("right"));
483             
484             if ((vd1 == null) || (vd2 == null)) {
485                 return null;
486             }
487             
488             rq.setTuple(vd1, vd2);
489             
490             /* get relation */
491             String relationname = pn.getChild("relation").getTerminal();
492             assert relationname != null;
493             RelationDescriptor rd = lookupRelation(relationname);
494
495             if (rd == null) {
496                 return null;
497             }
498             
499             rq.setRelation(rd);
500             vd1.setType(rd.getDomain().getType());
501             vd2.setType(rd.getRange().getType());
502             return rq;
503         } else if (pn.getChild("for") != null) { /* for j = x to y */
504             ForQuantifier fq = new ForQuantifier();
505             
506             /* grab var */
507             VarDescriptor vd = reserveName(pn.getChild("var"));
508
509             if (vd == null) {
510                 return null;
511             }
512
513             vd.setType(ReservedTypeDescriptor.INT);
514             fq.setVar(vd);
515
516             /* grab lower/upper bounds */
517             Expr lower = parse_expr(pn.getChild("lower").getChild("expr"));
518             Expr upper = parse_expr(pn.getChild("upper").getChild("expr"));
519
520             if ((lower == null) || (upper == null)) {
521                 return null;
522             }
523
524             fq.setBounds(lower, upper);
525
526             return fq;
527         } else {
528             throw new IRException("not supported yet");
529         }
530     }
531
532     private LogicStatement parse_body(ParseNode pn) {
533         if (!precheck(pn, "body")) {
534             return null;           
535         }
536         
537         if (pn.getChild("and") != null) {
538             /* body AND body */
539             LogicStatement left, right;
540             left = parse_body(pn.getChild("and").getChild("left").getChild("body"));
541             right = parse_body(pn.getChild("and").getChild("right").getChild("body"));
542             
543             if ((left == null) || (right == null)) {
544                 return null;
545             }
546             
547             // what do we want to call the and/or/not body classes?
548             return new LogicStatement(LogicStatement.AND, left, right);
549         } else if (pn.getChild("or") != null) {
550             /* body OR body */
551             LogicStatement left, right;
552             left = parse_body(pn.getChild("or").getChild("left").getChild("body"));
553             right = parse_body(pn.getChild("or").getChild("right").getChild("body"));
554             
555             if ((left == null) || (right == null)) {
556                 return null;
557             }
558
559             return new LogicStatement(LogicStatement.OR, left, right);
560         } else if (pn.getChild("not") != null) {
561             /* NOT body */
562             LogicStatement left = parse_body(pn.getChild("not").getChild("body"));
563             
564             if (left == null) {
565                 return null;
566             }
567             
568             return new LogicStatement(LogicStatement.NOT, left);
569         } else if (pn.getChild("predicate") != null) {
570             return parse_predicate(pn.getChild("predicate"));
571         } else {
572             throw new IRException();
573         }                        
574     }
575
576     private Predicate parse_predicate(ParseNode pn) {
577         if (!precheck(pn, "predicate")) {
578             return null;
579         }
580
581         if (pn.getChild("inclusion") != null) {
582             ParseNode in = pn.getChild("inclusion");
583             
584             /* Expr */
585             Expr expr = parse_expr(in.getChild("expr"));
586            
587             if (expr == null) { 
588                 return null;
589             }
590
591             /* get set expr */
592             SetExpr setexpr = parse_setexpr(in.getChild("setexpr"));
593
594             if (setexpr == null) {
595                 return null;
596             }
597
598             return new InclusionPredicate(expr, setexpr);
599         } else if (pn.getChild("expr") != null) {
600             Expr expr = parse_expr(pn.getChild("expr"));
601             
602             if (expr == null) {
603                 return null;
604             }
605
606             return new ExprPredicate(expr);
607         } else {
608             throw new IRException();
609         }       
610     }
611
612     private SetDescriptor parse_set(ParseNode pn) {
613         if (!precheck(pn, "set")) {
614             return null;
615         }
616     
617         if (pn.getChild("name") != null) {
618             String setname = pn.getChild("name").getTerminal();
619             assert setname != null;
620                 
621             if (!stSets.contains(setname)) {
622                 /* Semantic Error: unknown set */
623                 er.report(pn, "Unknown set '" + setname + "' referenced in quantifier");
624                 return null;
625             } else {
626                 /* all good, get setdescriptor */
627                 SetDescriptor sd = (SetDescriptor) stSets.get(setname);
628                 assert sd != null;
629                 return sd;
630             }            
631         } else if (pn.getChild("listofliterals") != null) {            
632             TokenSetDescriptor tokenset = new TokenSetDescriptor();
633             ParseNodeVector token_literals = pn.getChild("listofliterals").getChildren();
634             assert token_literals.size() > 0;
635             
636             for (int i = 0; i < token_literals.size(); i++) {
637                 ParseNode literal = token_literals.elementAt(i);
638                 assert literal.getLabel().equals("literal");
639                 LiteralExpr litexpr = parse_literal(literal);
640
641                 if (litexpr == null) {
642                     return null;
643                 }
644                 
645                 if (litexpr instanceof TokenLiteralExpr || litexpr instanceof IntegerLiteralExpr) {
646                     tokenset.addLiteral(litexpr);
647                 } else {
648                     er.report(literal, "Elements of a user-defined set must be of type token or integer");
649                     // return null; /* don't think we need to return null */
650                 }
651             }               
652
653             return tokenset;
654         } else {
655             throw new IRException(pn.getTerminal());
656         }
657     }
658     
659     private boolean parse_space(ParseNode pn) {
660         if (!precheck(pn, "space")) {
661             return false;
662         }
663         
664         boolean ok = true;
665         ParseNodeVector sets = pn.getChildren("setdefinition");
666         ParseNodeVector relations = pn.getChildren("relationdefinition");
667
668         assert pn.getChildren().size() == (sets.size() + relations.size());
669         
670         /* parse sets */
671         for (int i = 0; i < sets.size(); i++) {
672             if (!parse_setdefinition(sets.elementAt(i))) {
673                 ok = false;
674             }
675         }
676
677         /* parse relations */
678         for (int i = 0; i < relations.size(); i++) {
679             if (!parse_relationdefinition(relations.elementAt(i))) {
680                 ok = false;
681             }
682         }
683
684         // ok, all the spaces have been parsed, now we should typecheck and check
685         // for cycles etc.
686
687         // #TBD#: typecheck and check for cycles
688       
689         /* replace missing with actual */
690         Iterator allsets = state.stSets.descriptors();
691         
692         while (allsets.hasNext()) {
693             SetDescriptor sd = (SetDescriptor) allsets.next();
694             Vector subsets = sd.getSubsets();
695
696             for (int i = 0; i < subsets.size(); i++) {
697                 SetDescriptor subset = (SetDescriptor) subsets.elementAt(i);
698                 
699                 if (subset instanceof MissingSetDescriptor) {
700                     SetDescriptor newsubset = lookupSet(subset.getSymbol());
701
702                     if (newsubset == null) {
703                         er.report(null, "Unknown subset '" + subset.getSymbol() + "'");
704                     } else {
705                         subsets.setElementAt(newsubset, i);
706                     }
707                 }
708             }
709         }
710         
711         return ok;
712     }
713
714     private boolean parse_setdefinition(ParseNode pn) {
715         if (!precheck(pn, "setdefinition")) {
716             return false;
717         }
718         
719         boolean ok = true;
720         
721         /* get set name */
722         String setname = pn.getChild("name").getTerminal();
723         assert (setname != null);
724
725         SetDescriptor sd = new SetDescriptor(setname);
726         
727         /* get set type */
728         String settype = pn.getChild("type").getTerminal();
729         TypeDescriptor type = lookupType(settype);
730         if (type == null) {
731             er.report(pn, "Undefined type '" + settype + "'");
732             ok = false; 
733         } else {
734             sd.setType(type);
735         }
736
737         /* is this a partition? */
738         boolean partition = pn.getChild("partition") != null;
739         sd.isPartition(partition); 
740
741         /* if set has subsets, add them to set descriptor */
742         if (pn.getChild("setlist") != null) {
743             ParseNodeVector setlist = pn.getChild("setlist").getChildren();
744             
745             for (int i = 0; i < setlist.size(); i++) {
746                 String subsetname = setlist.elementAt(i).getLabel();
747                 sd.addSubset(lookupSet(subsetname, CREATE_MISSING));
748             }            
749         }
750
751         /* add set to symbol table */
752         if (stSets.contains(setname)) {
753             // Semantic Check: redefinition
754             er.report(pn, "Redefinition of set: " + setname);
755             ok = false;
756         } else {
757             stSets.add(sd);
758         }
759
760         return ok;
761     }
762
763     private boolean parse_relationdefinition(ParseNode pn) {
764         if (!precheck(pn, "relationdefinition")) {
765             return false;
766         }
767
768         boolean ok = true;
769
770         /* get relation name */
771         String relname = pn.getChild("name").getTerminal();
772         assert relname != null;
773
774         RelationDescriptor rd = new RelationDescriptor(relname);
775
776         /* check if static */
777         boolean bStatic = pn.getChild("static") != null;
778         rd.isStatic(bStatic);
779
780         /* get domain */
781         String domainsetname = pn.getChild("domain").getChild("type").getTerminal();
782         assert domainsetname != null;
783
784         /* get range */
785         String rangesetname = pn.getChild("range").getChild("type").getTerminal();
786         assert rangesetname != null;
787
788         /* get domain multiplicity */   
789         String domainmult;
790         if (pn.getChild("domain").getChild("domainmult") != null)
791             domainmult = pn.getChild("domain").getChild("domainmult").getChild("mult").getTerminal();
792         //assert domainmult != null;
793
794         /* get range multiplicity */
795         String rangemult;
796         if (pn.getChild("range").getChild("domainrange") != null)
797             rangemult = pn.getChild("range").getChild("domainrange").getChild("mult").getTerminal();
798         //assert rangemult != null;
799
800         /* NOTE: it is assumed that the sets have been parsed already so that the 
801            set namespace is fully populated. any missing setdescriptors for the set
802            symbol table will be assumed to be errors and reported. */
803
804         SetDescriptor domainset = lookupSet(domainsetname);
805         if (domainset == null) {
806             er.report(pn, "Undefined set '" + domainsetname + "' referenced in relation '" + relname + "'");
807             ok = false;
808         } else {
809             rd.setDomain(domainset);
810         }
811
812         SetDescriptor rangeset = lookupSet(rangesetname);
813         if (rangeset == null) {
814             er.report(pn, "Undefined set '" + rangesetname + "' referenced in relation '" + relname + "'");
815             ok = false;
816         } else {
817             rd.setRange(rangeset);
818         }
819
820         // #TBD#: eventually we'll use the multiplicities but now we don't... oh well
821
822         /* lets add the relation to the global symbol table */
823         if (!stRelations.contains(relname)) {
824             stRelations.add(rd);
825         } else {
826             er.report(pn, "Redefinition of relation '" + relname + "'");
827             ok = false;
828         }
829
830         return ok;
831     }
832
833     private boolean parse_structures(ParseNode pn) {
834         if (!precheck(pn, "structures")) {
835             return false;
836         }
837         
838         boolean ok = true;
839         ParseNodeVector structures = pn.getChildren("structure");
840
841         for (int i = 0; i < structures.size(); i++) {
842             if (!parse_structure(structures.elementAt(i))) {
843                 ok = false;
844             }
845         }
846
847         ParseNodeVector globals = pn.getChildren("global");
848
849         for (int i = 0; i < globals.size(); i++) {
850             if (!parse_global(globals.elementAt(i))) {
851                 ok = false;
852             }
853         }
854
855         // ok, all the structures have been parsed, now we gotta type check       
856
857         Enumeration types = stTypes.getDescriptors();
858         while (types.hasMoreElements()) {
859             TypeDescriptor t = (TypeDescriptor) types.nextElement();
860
861             if (t instanceof ReservedTypeDescriptor) {
862                 // we don't need to check reserved types
863             } else if (t instanceof StructureTypeDescriptor) {
864                 
865                 StructureTypeDescriptor type = (StructureTypeDescriptor) t;
866                 TypeDescriptor subtype = type.getSuperType();
867
868                 // check that the subtype is valid
869                 if (subtype instanceof MissingTypeDescriptor) {
870                     TypeDescriptor newtype = lookupType(subtype.getSymbol());
871                     if (newtype == null) {
872                         // subtype not defined anywheere
873                         // #TBD#: somehow determine how we can get the original parsenode (global function?)
874                         er.report(null, "Undefined subtype '" + subtype.getSymbol() + "'");
875                         ok = false;
876                     } else {
877                         type.setSuperType(newtype);
878                     }
879                 }
880
881                 Iterator fields = type.getFields();
882
883                 while (fields.hasNext()) {
884                     FieldDescriptor field = (FieldDescriptor) fields.next();                        
885                     TypeDescriptor fieldtype = field.getType();
886
887                     assert fieldtype != null;
888
889                     // check that the type is valid
890                     if (fieldtype instanceof MissingTypeDescriptor) {
891                         TypeDescriptor newtype = lookupType(fieldtype.getSymbol());
892                         if (newtype == null) {
893                             // type never defined
894                             // #TBD#: replace new ParseNode with original parsenode
895                             er.report(null, "Undefined type '" + fieldtype.getSymbol() + "'");
896                             ok = false;
897                         } else {
898                             assert newtype != null;
899                             field.setType(newtype);
900                         }
901                     }                        
902                 }
903
904                 Iterator labels = type.getLabels();
905
906                 while (labels.hasNext()) {
907                     LabelDescriptor label = (LabelDescriptor) labels.next();
908                     TypeDescriptor labeltype = label.getType();
909
910                     assert labeltype != null;
911
912                     // check that the type is valid
913                     if (labeltype instanceof MissingTypeDescriptor) {
914                         TypeDescriptor newtype = lookupType(labeltype.getSymbol());
915                         if (newtype == null) {
916                             // type never defined
917                             // #TBD#: replace new ParseNode with original parsenode
918                             er.report(null, "Undefined type '" + labeltype.getSymbol() + "'");
919                             ok = false;
920                         } else {
921                             assert newtype != null;
922                             label.setType(newtype);
923                         }
924                     }
925                 }
926                 
927             } else {
928                 throw new IRException("shouldn't be any other typedescriptor classes");
929             }
930         }
931
932         if (!ok) {
933             return false;
934         }
935
936         types = stTypes.getDescriptors();
937
938         while (types.hasMoreElements()) {
939             TypeDescriptor t = (TypeDescriptor) types.nextElement();
940
941             if (t instanceof ReservedTypeDescriptor) {
942                 // we don't need to check reserved types
943             } else if (t instanceof StructureTypeDescriptor) {
944                 
945                 StructureTypeDescriptor type = (StructureTypeDescriptor)t;
946                 TypeDescriptor subtype = type.getSuperType();
947                 Iterator fields = type.getFields();
948
949                 while (fields.hasNext()) {
950                     FieldDescriptor field = (FieldDescriptor) fields.next();                        
951
952                     if (field instanceof ArrayDescriptor) {
953                         ArrayDescriptor ad = (ArrayDescriptor) field;
954                         Expr indexbound = ad.getIndexBound();
955                         TypeDescriptor indextype = indexbound.typecheck(new SemanticAnalyzer() {
956                                 public IRErrorReporter getErrorReporter() { return er; }
957                                 public SymbolTable getSymbolTable() { return stGlobals; }
958                             });
959
960                         if (indextype == null) {
961                             ok = false;
962                         } else if (indextype != ReservedTypeDescriptor.INT) {
963                             er.report(null, "'" + type.getSymbol() + "." + field.getSymbol() + "' index bounds must be type 'int' not '" + indextype.getSymbol() + "'");
964                             ok = false;
965                         }
966                     }
967                 }
968
969                 Iterator labels = type.getLabels();
970
971                 while (labels.hasNext()) {
972                     LabelDescriptor label = (LabelDescriptor) labels.next();
973                     Expr index = label.getIndex();
974
975                     if (index != null) {
976                         TypeDescriptor indextype = index.typecheck(new SemanticAnalyzer() {
977                                 public IRErrorReporter getErrorReporter() { return er; }
978                                 public SymbolTable getSymbolTable() { return stGlobals; }
979                             });
980                         
981                         if (indextype != ReservedTypeDescriptor.INT) {
982                             er.report(null, "Label '" + type.getSymbol() + "." + label.getSymbol() + "' index must be type 'int' not '" + indextype.getSymbol() + "'");
983                             ok = false;
984                         }
985                     }
986                 }
987                 
988             } else {
989                 throw new IRException("shouldn't be any other typedescriptor classes");
990             }
991
992         }
993
994         // #TBD#: need to make sure that no cycles exist in any of the declarations or subtypes
995         // subtypes, of course, are not real subtypes, they are merely a way to validate a 
996         // cast, i believe
997
998         return ok;
999     }
1000
1001     private boolean parse_global(ParseNode pn) {
1002         if (!precheck(pn, "global")) {
1003             return false;
1004         }
1005
1006         String name = pn.getChild("name").getTerminal();
1007         assert name != null;
1008
1009         String type = pn.getChild("type").getTerminal();
1010         assert type != null;
1011         TypeDescriptor td = lookupType(type);
1012         assert td != null;
1013         assert !(td instanceof ReservedTypeDescriptor);
1014         
1015         if (stGlobals.contains(name)) {
1016             /* redefinition of global */
1017             er.report(pn, "Redefinition of global '" + name + "'");
1018             return false;
1019         }
1020
1021         stGlobals.add(new VarDescriptor(name, name, td,true));
1022         return true;
1023     }
1024
1025     private boolean parse_structure(ParseNode pn) {
1026         if (!precheck(pn, "structure")) {
1027             return false;
1028         }
1029
1030         boolean ok = true;
1031         String typename = pn.getChild("name").getTerminal();
1032         StructureTypeDescriptor type = new StructureTypeDescriptor(typename);
1033         
1034         if (pn.getChild("subtype") != null) {
1035             // has a subtype, lets try to resolve it
1036             String subtype = pn.getChild("subtype").getTerminal();
1037
1038             if (subtype.equals(typename)) {
1039                 // Semantic Error: cyclic inheritance
1040                 er.report(pn, "Cyclic inheritance prohibited");
1041                 ok = false;
1042             }
1043
1044             /* lookup the type to get the type descriptor */
1045             type.setSuperType(lookupType(subtype, CREATE_MISSING));
1046         }
1047
1048         // set the current type so that the recursive parses on the labels
1049         // and fields can add themselves automatically to the current type         
1050         dCurrentType = type;
1051         
1052         // parse the labels and fields
1053         if (!parse_labelsandfields(pn.getChild("lf"))) {
1054             ok = false;
1055         }
1056
1057         if (stTypes.contains(typename)) {
1058             er.report(pn, "Redefinition of type '" + typename + "'");
1059             ok = false;
1060         } else {
1061             stTypes.add(type);
1062         }
1063         
1064         return ok;
1065     }
1066
1067     private boolean parse_labelsandfields(ParseNode pn) {
1068         if (!precheck(pn, "lf")) {
1069             return false;
1070         }
1071
1072         boolean ok = true;
1073      
1074         // check the fields first (need the field names 
1075         // to type check the labels)
1076         if (!parse_fields(pn.getChild("fields"))) {
1077             ok = false;
1078         }
1079
1080         // check the labels now that all the fields are sorted
1081         if (!parse_labels(pn.getChild("labels"))) {
1082             ok = false;
1083         }
1084
1085         return ok;
1086     }
1087
1088     private boolean parse_fields(ParseNode pn) {
1089         if (!precheck(pn, "fields")) {
1090             return false;
1091         }
1092         
1093         boolean ok = true;
1094         
1095         /* NOTE: because the order of the fields is important when defining a data structure,
1096            and because the order is defined by the order of the fields defined in the field
1097            vector, its important that the parser returns the fields in the correct order */
1098         
1099         ParseNodeVector fields = pn.getChildren();
1100
1101         for (int i = 0; i < fields.size(); i++) {
1102             ParseNode field = fields.elementAt(i);            
1103             FieldDescriptor fd;
1104             boolean reserved;
1105             String name = null;
1106
1107             if (field.getChild("reserved") != null) {
1108                 // reserved field
1109                 // #TBD#: it will be necessary for reserved field descriptors to generate
1110                 // a unique symbol for the type descriptor requires it for its hashtable
1111                 fd = new ReservedFieldDescriptor();
1112                 reserved = true;
1113             } else {
1114                 name = field.getChild("name").getTerminal();                
1115                 fd = new FieldDescriptor(name);
1116                 reserved = false;
1117             }
1118
1119             String type = field.getChild("type").getTerminal();
1120             boolean ptr = field.getChild("*") != null;
1121             fd.setPtr(ptr);
1122
1123             fd.setType(lookupType(type, CREATE_MISSING));
1124
1125             if (field.getChild("index") != null) {
1126                 // field is an array, so create an array descriptor to wrap the 
1127                 // field descriptor and then replace the top level field descriptor with
1128                 // this array descriptor
1129                 Expr expr = parse_expr(field.getChild("index").getChild("expr"));
1130                 if (expr == null) {
1131                     // #ATTN#: do we really want to return an exception here?
1132                     throw new IRException("invalid index expression");
1133                 }
1134                 ArrayDescriptor ad = new ArrayDescriptor(fd, expr);               
1135                 fd = ad;
1136             }
1137
1138             // add the current field to the current type
1139             if (reserved == false) {
1140                 // lets double check that we are redefining a field
1141                 if (dCurrentType.getField(name) != null) {
1142                     // Semantic Error: field redefinition 
1143                     er.report(pn, "Redefinition of field '" + name + "'");
1144                     ok = false;
1145                 } else {
1146                     dCurrentType.addField(fd);
1147                 }
1148             } else {
1149                 dCurrentType.addField(fd);
1150             }
1151         }
1152         
1153         return ok;
1154     }
1155
1156     private boolean parse_labels(ParseNode pn) {
1157         if (!precheck(pn, "labels")) {
1158             return false;
1159         }
1160
1161         boolean ok = true;
1162
1163         /* NOTE: parse_labels should be called after the fields have been parsed because any
1164            labels not found in the field set of the current type will be flagged as errors */
1165
1166         ParseNodeVector labels = pn.getChildren();
1167
1168         for (int i = 0; i < labels.size(); i++) {           
1169             ParseNode label = labels.elementAt(i);
1170             String name = label.getChild("name").getTerminal();
1171             LabelDescriptor ld = new LabelDescriptor(name); 
1172
1173             if (label.getChild("index") != null) {
1174                 Expr expr = parse_expr(label.getChild("index").getChild("expr"));
1175                 if (expr == null) {
1176                     /* #ATTN#: do we really want to return an exception here? */
1177                     throw new IRException("Invalid expression");
1178                 }
1179                 ld.setIndex(expr);                
1180             } 
1181             
1182             String type = label.getChild("type").getTerminal();
1183
1184             ld.setType(lookupType(type, CREATE_MISSING));
1185                         
1186             String field = label.getChild("field").getTerminal();           
1187             FieldDescriptor fd = dCurrentType.getField(field);
1188
1189             if (fd == null) {
1190                 /* Semantic Error: Undefined field in label */
1191                 er.report(label, "Undefined field '" + field + "' in label");
1192                 ok = false;
1193             } else {
1194                 ld.setField(fd);
1195             }
1196
1197             /* add label to current type */
1198             if (dCurrentType.getLabel(name) != null) {
1199                 /* semantic error: label redefinition */
1200                 er.report(pn, "Redefinition of label '" + name + "'");
1201                 ok = false;
1202             } else {
1203                 dCurrentType.addLabel(ld);            
1204             }
1205         }
1206
1207         return ok;
1208     }
1209
1210     private Expr parse_expr(ParseNode pn) {
1211         if (!precheck(pn, "expr")) {
1212             return null;
1213         }
1214
1215         if (pn.getChild("var") != null) {
1216             // we've got a variable reference... we'll have to scope check it later
1217             // when we are completely done... there are also some issues of cyclic definitions
1218             return new VarExpr(pn.getChild("var").getTerminal());
1219         } else if (pn.getChild("literal") != null) {
1220             return parse_literal(pn.getChild("literal"));
1221         } else if (pn.getChild("operator") != null) {
1222             return parse_operator(pn.getChild("operator"));
1223         } else if (pn.getChild("relation") != null) {
1224             return parse_relation(pn.getChild("relation"));
1225         } else if (pn.getChild("sizeof") != null) {
1226             return parse_sizeof(pn.getChild("sizeof"));
1227         } else if (pn.getChild("simple_expr") != null) {
1228             return parse_simple_expr(pn.getChild("simple_expr"));        
1229         } else if (pn.getChild("elementof") != null) {
1230             return parse_elementof(pn.getChild("elementof"));        
1231         } else if (pn.getChild("tupleof") != null) {
1232             return parse_tupleof(pn.getChild("tupleof"));        
1233         } else if (pn.getChild("isvalid") != null) {
1234             er.report(pn, "Operation 'isvalid' is currently unsupported.");
1235             return null;
1236         } else {
1237             er.report(pn, "Unknown or invalid expression type '" + pn.getTerminal() + "'");
1238             return null;
1239         }            
1240     }
1241
1242     private Expr parse_elementof(ParseNode pn) {
1243         if (!precheck(pn, "elementof")) {
1244             return null;
1245         }
1246
1247         /* get setname */
1248         String setname = pn.getChild("name").getTerminal();
1249         assert setname != null;
1250         SetDescriptor sd = lookupSet(setname);
1251
1252         if (sd == null) {
1253             er.report(pn, "Undefined set '" + setname + "'");
1254             return null;
1255         }
1256
1257         /* get left side expr */
1258         Expr expr = parse_expr(pn.getChild("expr"));
1259         
1260         if (expr == null) {
1261             return null;
1262         }
1263
1264         return new ElementOfExpr(expr, sd);
1265     }
1266
1267     private Expr parse_tupleof(ParseNode pn) {
1268         if (!precheck(pn, "tupleof")) {
1269             return null;
1270         }
1271         
1272         /* get relation */
1273         String relname = pn.getChild("name").getTerminal();
1274         assert relname != null;
1275         RelationDescriptor rd = lookupRelation(relname);
1276
1277         if (rd == null) {
1278             er.report(pn, "Undefined relation '" + relname + "'");
1279             return null;
1280         }
1281
1282         Expr left = parse_expr(pn.getChild("left").getChild("expr"));
1283         Expr right = parse_expr(pn.getChild("right").getChild("expr"));
1284
1285         if ((left == null) || (right == null)) {
1286             return null;
1287         }
1288
1289         return new TupleOfExpr(left, right, rd);
1290     }
1291
1292     private Expr parse_simple_expr(ParseNode pn) {
1293         if (!precheck(pn, "simple_expr")) {
1294             return null;
1295         }
1296
1297         // only locations so far
1298         return parse_location(pn.getChild("location"));
1299     }
1300
1301     private Expr parse_location(ParseNode pn) {
1302         if (!precheck(pn, "location")) {
1303             return null;
1304         }
1305
1306         if (pn.getChild("var") != null) {
1307             // should be changed into a namespace check */
1308             return new VarExpr(pn.getChild("var").getTerminal());
1309         } else if (pn.getChild("cast") != null) {
1310             return parse_cast(pn.getChild("cast"));
1311         } else if (pn.getChild("dot") != null) {
1312             return parse_dot(pn.getChild("dot"));
1313         } else {
1314             throw new IRException();
1315         }
1316     }
1317
1318     private RelationExpr parse_relation(ParseNode pn) {
1319         if (!precheck(pn, "relation")) {
1320             return null;
1321         }
1322
1323         String relname = pn.getChild("name").getTerminal();
1324         boolean inverse = pn.getChild("inv") != null;
1325         Expr expr = parse_expr(pn.getChild("expr"));        
1326
1327         if (expr == null) {
1328             return null;
1329         }
1330                     
1331         RelationDescriptor relation = lookupRelation(relname);
1332             
1333         if (relation == null) {
1334             /* Semantic Error: relation not definied" */
1335             er.report(pn, "Undefined relation '" + relname + "'");
1336             return null;
1337         }                       
1338
1339         /* add usage so correct sets are created */
1340         relation.addUsage(inverse ? RelationDescriptor.INVIMAGE : RelationDescriptor.IMAGE);
1341             
1342         return new RelationExpr(expr, relation, inverse);
1343     }
1344
1345     private SizeofExpr parse_sizeof(ParseNode pn) {
1346         if (!precheck(pn, "sizeof")) {
1347             return null;
1348         }
1349
1350         /* get setexpr */
1351         SetExpr setexpr = parse_setexpr(pn.getChild("setexpr"));
1352         
1353         if (setexpr == null) {
1354             return null;
1355         }
1356
1357         return new SizeofExpr(setexpr);
1358     }
1359
1360     private CastExpr parse_cast(ParseNode pn) {
1361         if (!precheck(pn, "cast")) {
1362             return null;
1363         }
1364
1365         /* get type */
1366         String typename = pn.getChild("type").getTerminal();
1367         assert typename != null;
1368         TypeDescriptor type = lookupType(typename);
1369
1370         if (type == null) {
1371             /* semantic error: undefined type in cast */
1372             er.report(pn, "Undefined type '" + typename + "' in cast operator");
1373             return null;
1374         } 
1375
1376         /* get expr */
1377         Expr expr = parse_simple_expr(pn.getChild("simple_expr"));
1378         
1379         if (expr == null) {
1380             return null;
1381         } 
1382
1383         return new CastExpr(type, expr);
1384     }
1385
1386     private SetExpr parse_setexpr(ParseNode pn) {
1387         if (!precheck(pn, "setexpr")) {
1388             return null;
1389         }
1390
1391         // #TBD#: setexpr and parse_relation seem to be cousins... is there a reduction/refactor possible?
1392
1393         if (pn.getChild("set") != null) {
1394             String setname = pn.getChild("set").getTerminal();
1395             assert setname != null;
1396             SetDescriptor sd = lookupSet(setname);
1397
1398             if (sd == null) {
1399                 er.report(pn, "Unknown or undefined set '" + setname + "'");             
1400                 return null;
1401             } else {                         
1402                 return new SetExpr(sd);
1403             }
1404         } else if (pn.getChild("dot") != null) {
1405             VarDescriptor vd = parse_quantifiervar(pn.getChild("dot").getChild("quantifiervar"));
1406             RelationDescriptor relation = lookupRelation(pn.getChild("dot").getChild("relation").getTerminal());
1407             relation.addUsage(RelationDescriptor.IMAGE);
1408             return new ImageSetExpr(vd, relation);
1409         } else if (pn.getChild("dotinv") != null) {
1410             VarDescriptor vd = parse_quantifiervar(pn.getChild("dotinv").getChild("quantifiervar"));
1411             RelationDescriptor relation = lookupRelation(pn.getChild("dotinv").getChild("relation").getTerminal());
1412             relation.addUsage(RelationDescriptor.INVIMAGE);
1413             return new ImageSetExpr(ImageSetExpr.INVERSE, vd, relation);
1414         } else {
1415             throw new IRException();
1416         }
1417     }
1418
1419     private VarDescriptor parse_quantifiervar(ParseNode pn) {
1420         if (!precheck(pn, "quantifiervar")) {
1421             return null;
1422         }
1423
1424         /* get var */
1425         String varname = pn.getTerminal();
1426         assert varname != null;
1427         
1428         /* NOTE: quantifier var's are only found in the constraints and
1429            model definitions... therefore we can do a semantic check here 
1430            to make sure that the variables exist in the symbol table */
1431
1432         /* NOTE: its assumed that the symbol table stack is appropriately
1433            set up with the parent quantifier symbol table */
1434         assert !sts.empty();          
1435
1436         /* do semantic check and if valid, add it to symbol table
1437            and add it to the quantifier as well */
1438         if (sts.peek().contains(varname)) {
1439             return new VarDescriptor(varname);
1440         } else {
1441             /* Semantic Error: undefined variable */
1442             er.report(pn, "Undefined variable '" + varname + "'");
1443             return null;
1444         }
1445     }
1446     
1447     private LiteralExpr parse_literal(ParseNode pn) {
1448         if (!precheck(pn, "literal")) {
1449             return null;
1450         }
1451
1452         if (pn.getChild("boolean") != null) {
1453             if (pn.getChild("boolean").getChild("true") != null) {
1454                 return new BooleanLiteralExpr(true);
1455             } else {
1456                 return new BooleanLiteralExpr(false);
1457             } 
1458         } else if (pn.getChild("decimal") != null) {            
1459             String integer = pn.getChild("decimal").getTerminal();
1460
1461             /* Check for integer literal overflow */
1462             BigInteger intLitBI = new BigInteger(integer);
1463             BigInteger intMax = new BigInteger("" + Integer.MAX_VALUE);
1464             BigInteger intMin = new BigInteger("" + Integer.MIN_VALUE);
1465             int value;
1466
1467             if (intLitBI.compareTo(intMin) < 0) {
1468                 value = Integer.MIN_VALUE;
1469                 er.warn(pn, "Integer literal overflow");
1470             } else if (intLitBI.compareTo(intMax) > 0) {
1471                 value = Integer.MAX_VALUE;
1472                 er.warn(pn, "Integer literal overflow");
1473             } else {
1474                 /* no truncation needed */
1475                 value = Integer.parseInt(integer);
1476             }
1477
1478             return new IntegerLiteralExpr(value);
1479         } else if (pn.getChild("token") != null) {
1480             return new TokenLiteralExpr(pn.getChild("token").getTerminal());
1481         } else if (pn.getChild("string") != null) {
1482             throw new IRException("string unsupported");
1483         } else if (pn.getChild("char") != null) {
1484             throw new IRException("char unsupported");
1485         } else {
1486             throw new IRException("unknown literal expression type.");
1487         }
1488     }
1489
1490     private OpExpr parse_operator(ParseNode pn) {
1491         if (!precheck(pn, "operator")) {
1492             return null; 
1493         }
1494
1495         String opname = pn.getChild("op").getTerminal();
1496         Opcode opcode = Opcode.decodeFromString(opname);
1497
1498         if (opcode == null) {
1499             er.report(pn, "Unsupported operation: " + opname);
1500             return null;
1501         }
1502         
1503         Expr left = parse_expr(pn.getChild("left").getChild("expr"));
1504         Expr right = null;
1505         
1506         if (pn.getChild("right") != null) {
1507             right = parse_expr(pn.getChild("right").getChild("expr"));
1508         }
1509
1510         if (left == null) {           
1511             return null;
1512         }
1513
1514         if (right == null && opcode != Opcode.NOT) {
1515             er.report(pn, "Two arguments required.");
1516             return null;
1517         }
1518
1519         return new OpExpr(opcode, left, right);
1520     }
1521
1522     private DotExpr parse_dot(ParseNode pn) {
1523         if (!precheck(pn, "dot")) {
1524             return null;
1525         }
1526
1527         Expr left = parse_simple_expr(pn.getChild("simple_expr"));
1528
1529         if (left == null) {
1530             return null;
1531         }
1532
1533         String field = pn.getChild("field").getTerminal();
1534
1535         Expr index = null;
1536
1537         if (pn.getChild("index") != null) {
1538             index = parse_expr(pn.getChild("index").getChild("expr"));
1539             
1540             if (index == null) {
1541                 return null;
1542             }
1543         }
1544
1545         return new DotExpr(left, field, index);        
1546     }
1547
1548 }
1549