4 import java.math.BigInteger;
7 public class SemanticChecker {
9 private static final boolean CREATE_MISSING = true;
19 SymbolTable stRelations;
21 SymbolTable stGlobals;
23 StructureTypeDescriptor dCurrentType;
27 public SemanticChecker () {
33 public boolean check(State state, IRErrorReporter er) {
36 State.currentState = state;
39 throw new IRException("IRBuilder.build: Received null ErrorReporter");
44 if (state.ptStructures == null) {
45 throw new IRException("IRBuilder.build: Received null ParseNode");
48 state.vConstraints = new Vector();
49 vConstraints = state.vConstraints;
51 state.vRules = new Vector();
52 vRules = state.vRules;
54 state.stTypes = new SymbolTable();
55 stTypes = state.stTypes;
57 state.stSets = new SymbolTable();
58 stSets = state.stSets;
60 state.stRelations = new SymbolTable();
61 stRelations = state.stRelations;
63 state.stGlobals = new SymbolTable();
64 stGlobals = state.stGlobals;
66 sts = new SymbolTableStack();
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);
74 stSets.add(new ReservedSetDescriptor("int", ReservedTypeDescriptor.INT));
75 stSets.add(new ReservedSetDescriptor("token", ReservedTypeDescriptor.INT));
79 er.setFilename(state.infile + ".struct");
80 if (!parse_structures(state.ptStructures)) {
84 er.setFilename(state.infile + ".space");
85 if (!parse_space(state.ptSpace)) {
89 er.setFilename(state.infile + ".constraints");
90 if (!parse_constraints(state.ptConstraints)) {
94 er.setFilename(state.infile + ".model");
95 if (!parse_rules(state.ptModel)) {
102 /********************** HELPER FUNCTIONS ************************/
105 * special case lookup that returns null if no such type exists
107 private TypeDescriptor lookupType(String typename) {
108 return lookupType(typename, false);
112 * does a look up in the types symbol table. if the type is
113 * not found than a missing type descriptor is returned
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);
129 private VarDescriptor reserveName(ParseNode pn) {
131 String varname = pn.getTerminal();
132 assert varname != null;
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 + "'");
141 VarDescriptor vd = new VarDescriptor(varname);
148 * special case lookup that returns null if no such set exists
150 private SetDescriptor lookupSet(String setname) {
151 return lookupSet(setname, false);
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
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);
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
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);
183 private static int count = 0;
184 private boolean precheck(ParseNode pn, String label) {
186 er.report(pn, "IE: Expected '" + label + "', got null");
191 if (! pn.getLabel().equals(label)) {
192 er.report(pn, "IE: Expected '" + label + "', got '" + pn.getLabel() + "'");
197 if (state.verbose >= 2) {
198 System.err.println("visiting*" + (count++) + ": " + label);
204 /********************* PARSING FUNCTIONS ************************/
206 private boolean parse_rules(ParseNode pn) {
207 if (!precheck(pn, "rules")) {
212 ParseNodeVector rules = pn.getChildren();
214 for (int i = 0; i < rules.size(); i++) {
215 ParseNode rule = rules.elementAt(i);
216 if (!parse_rule(rule)) {
222 Iterator ruleiterator = state.vRules.iterator();
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; }
232 TypeDescriptor guardtype = guard.typecheck(sa);
234 if (guardtype == null) {
236 } else if (guardtype != ReservedTypeDescriptor.INT) {
237 er.report(null, "Type of guard must be 'int' not '" + guardtype.getSymbol() + "'");
241 if (!rule.getInclusion().typecheck(sa)) {
245 Iterator quantifiers = rule.quantifiers();
247 while (quantifiers.hasNext()) {
248 Quantifier q = (Quantifier) quantifiers.next();
250 if (q instanceof ForQuantifier && !((ForQuantifier)q).typecheck(sa)) {
256 /* do any post checks ?? */
261 private boolean parse_rule(ParseNode pn) {
262 if (!precheck(pn, "rule")) {
267 Rule rule = new Rule();
270 boolean isstatic = pn.getChild("static") != null;
271 boolean isdelay = pn.getChild("delay") != null;
272 rule.setStatic(isstatic);
273 rule.setDelay(isdelay);
275 /* set up symbol table for constraint */
278 sts.push(rule.getSymbolTable());
280 /* optional quantifiers */
281 if (pn.getChild("quantifiers") != null) {
282 ParseNodeVector quantifiers = pn.getChild("quantifiers").getChildren();
284 for (int i = 0; i < quantifiers.size(); i++) {
285 ParseNode qn = quantifiers.elementAt(i);
286 Quantifier quantifier = parse_quantifier(qn);
288 if (quantifier == null) {
291 rule.addQuantifier(quantifier);
297 Expr guard = parse_expr(pn.getChild("expr"));
302 rule.setGuardExpr(guard);
305 /* inclusion constraint */
306 Inclusion inclusion = parse_inclusion(pn.getChild("inclusion"));
308 if (inclusion == null) {
311 rule.setInclusion(inclusion);
314 /* pop symbol table stack */
315 SymbolTable st = sts.pop();
316 sts.pop(); /* pop off globals */
318 /* make sure the stack we pop is our rule s.t. */
319 assert st == rule.getSymbolTable();
322 /* add rule to global set */
323 vRules.addElement(rule);
328 private Inclusion parse_inclusion(ParseNode pn) {
329 if (!precheck(pn, "inclusion")) {
333 if (pn.getChild("set") != null) {
334 ParseNode set = pn.getChild("set");
335 Expr expr = parse_expr(set.getChild("expr"));
341 String setname = set.getChild("name").getTerminal();
342 assert setname != null;
343 SetDescriptor sd = lookupSet(setname);
346 er.report(set.getChild("name"), "Undefined set '" + setname + "'");
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"));
356 if ((leftexpr == null) || (rightexpr == null)) {
360 String relname = relation.getChild("name").getTerminal();
361 assert relname != null;
362 RelationDescriptor rd = lookupRelation(relname);
365 er.report(relation.getChild("name"), "Undefined relation '" + relname + "'");
369 return new RelationInclusion(leftexpr, rightexpr, rd);
371 throw new IRException();
375 private boolean parse_constraints(ParseNode pn) {
376 if (!precheck(pn, "constraints")) {
381 ParseNodeVector constraints = pn.getChildren();
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)) {
391 /* do any post checks... (type constraints, etc?) */
396 private boolean parse_constraint(ParseNode pn) {
397 if (!precheck(pn, "constraint")) {
402 Constraint constraint = new Constraint();
405 boolean crash = pn.getChild("crash") != null;
406 constraint.setCrash(crash);
408 /* set up symbol table for constraint */
410 sts.push(constraint.getSymbolTable());
412 /* get quantifiers */
413 if (pn.getChild("quantifiers") != null) {
414 ParseNodeVector quantifiers = pn.getChild("quantifiers").getChildren();
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) {
423 constraint.addQuantifier(quantifier);
429 LogicStatement logicexpr = parse_body(pn.getChild("body"));
431 if (logicexpr == null) {
434 constraint.setLogicStatement(logicexpr);
437 /* pop symbol table stack */
438 SymbolTable st = sts.pop();
440 /* make sure the stack we pop is our constraint s.t. */
441 assert st == constraint.getSymbolTable();
444 /* add to vConstraints */
445 vConstraints.addElement(constraint);
450 private Quantifier parse_quantifier(ParseNode pn) {
451 if (!precheck(pn, "quantifier")) {
455 if (pn.getChild("forall") != null) { /* forall element in Set */
456 SetQuantifier sq = new SetQuantifier();
459 VarDescriptor vd = reserveName(pn.getChild("var"));
468 SetDescriptor set = parse_set(pn.getChild("set"));
472 vd.setType(set.getType());
474 /* return to caller */
477 } else if (pn.getChild("relatiion") != null) { /* for < v1, v2 > in Relation */
478 RelationQuantifier rq = new RelationQuantifier();
481 VarDescriptor vd1 = reserveName(pn.getChild("left"));
482 VarDescriptor vd2 = reserveName(pn.getChild("right"));
484 if ((vd1 == null) || (vd2 == null)) {
488 rq.setTuple(vd1, vd2);
491 String relationname = pn.getChild("relation").getTerminal();
492 assert relationname != null;
493 RelationDescriptor rd = lookupRelation(relationname);
500 vd1.setType(rd.getDomain().getType());
501 vd2.setType(rd.getRange().getType());
503 } else if (pn.getChild("for") != null) { /* for j = x to y */
504 ForQuantifier fq = new ForQuantifier();
507 VarDescriptor vd = reserveName(pn.getChild("var"));
513 vd.setType(ReservedTypeDescriptor.INT);
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"));
520 if ((lower == null) || (upper == null)) {
524 fq.setBounds(lower, upper);
528 throw new IRException("not supported yet");
533 private LogicStatement parse_body(ParseNode pn) {
534 if (!precheck(pn, "body")) {
538 if (pn.getChild("and") != null) {
540 LogicStatement left, right;
541 left = parse_body(pn.getChild("and").getChild("left").getChild("body"));
542 right = parse_body(pn.getChild("and").getChild("right").getChild("body"));
544 if ((left == null) || (right == null)) {
548 // what do we want to call the and/or/not body classes?
549 return new LogicStatement(LogicStatement.AND, left, right);
550 } else if (pn.getChild("or") != null) {
552 LogicStatement left, right;
553 left = parse_body(pn.getChild("or").getChild("left").getChild("body"));
554 right = parse_body(pn.getChild("or").getChild("right").getChild("body"));
556 if ((left == null) || (right == null)) {
560 return new LogicStatement(LogicStatement.OR, left, right);
561 } else if (pn.getChild("not") != null) {
563 LogicStatement left = parse_body(pn.getChild("not").getChild("left").getChild("body"));
569 return new LogicStatement(LogicStatement.NOT, left);
570 } else if (pn.getChild("predicate") != null) {
571 return parse_predicate(pn.getChild("predicate"));
573 throw new IRException();
577 private Predicate parse_predicate(ParseNode pn) {
578 if (!precheck(pn, "predicate")) {
582 if (pn.getChild("inclusion") != null) {
583 ParseNode in = pn.getChild("inclusion");
585 /* get quantiifer var */
586 VarDescriptor vd = parse_quantifiervar(in.getChild("quantifiervar"));
593 SetExpr setexpr = parse_setexpr(in.getChild("setexpr"));
595 if (setexpr == null) {
599 return new InclusionPredicate(vd, setexpr);
600 } else if (pn.getChild("sizeof") != null) {
601 ParseNode sizeof = pn.getChild("sizeof");
604 SetExpr setexpr = parse_setexpr(sizeof.getChild("setexpr"));
606 if (setexpr == null) {
610 /* get comparison operator */
611 String compareop = sizeof.getChild("compare").getTerminal();
612 Opcode opcode = Opcode.decodeFromString(compareop);
614 if (opcode == null) {
615 er.report(pn, "Unsupported operation '" + compareop + "'");
617 } else if (opcode != Opcode.EQ &&
618 opcode != Opcode.GE &&
619 opcode != Opcode.LE) {
620 er.report(pn, "Invalid operation '" + compareop + "': Must be one of '=', '>=', '<='");
625 String decimal = sizeof.getChild("decimal").getTerminal();
626 IntegerLiteralExpr cardinality = new IntegerLiteralExpr(Integer.parseInt(decimal));
628 return new SizeofPredicate(setexpr, opcode, cardinality);
629 } else if (pn.getChild("comparison") != null) {
630 ParseNode cn = pn.getChild("comparison");
632 /* get quantifier variable */
633 String varname = cn.getChild("quantifier").getTerminal();
634 String relation = cn.getChild("relation").getTerminal();
636 if (!sts.peek().contains(varname)) {
637 er.report(pn, "Undefined quantifier '" + varname + "'");
641 VarDescriptor vd = (VarDescriptor) sts.peek().get(varname);
643 if (!stRelations.contains(relation)) {
644 er.report(pn, "Undefined relation '" + varname + "'");
648 RelationDescriptor rd = (RelationDescriptor) stRelations.get(relation);
651 Expr expr = parse_expr(cn.getChild("expr"));
657 /* get comparison operator */
658 String compareop = cn.getChild("compare").getTerminal();
659 Opcode opcode = Opcode.decodeFromString(compareop);
661 if (opcode == null) {
662 er.report(pn, "Unsupported operation '" + compareop + "'");
664 } else if (opcode != Opcode.EQ &&
665 opcode != Opcode.GE &&
666 opcode != Opcode.LE) {
667 er.report(pn, "Invalid operation '" + compareop + "': Must be one of '=', '>=', '<='");
671 return new ComparisonPredicate(vd, rd, opcode, expr);
673 throw new IRException();
677 private SetDescriptor parse_set(ParseNode pn) {
678 if (!precheck(pn, "set")) {
682 if (pn.getChild("name") != null) {
683 String setname = pn.getChild("name").getTerminal();
684 assert setname != null;
686 if (!stSets.contains(setname)) {
687 /* Semantic Error: unknown set */
688 er.report(pn, "Unknown set '" + setname + "' referenced in quantifier");
691 /* all good, get setdescriptor */
692 SetDescriptor sd = (SetDescriptor) stSets.get(setname);
696 } else if (pn.getChild("listofliterals") != null) {
697 TokenSetDescriptor tokenset = new TokenSetDescriptor();
698 ParseNodeVector token_literals = pn.getChild("listofliterals").getChildren();
699 assert token_literals.size() > 0;
701 for (int i = 0; i < token_literals.size(); i++) {
702 ParseNode literal = token_literals.elementAt(i);
703 assert literal.getLabel().equals("literal");
704 LiteralExpr litexpr = parse_literal(literal);
706 if (litexpr == null) {
710 if (litexpr instanceof TokenLiteralExpr || litexpr instanceof IntegerLiteralExpr) {
711 tokenset.addLiteral(litexpr);
713 er.report(literal, "Elements of a user-defined set must be of type token or integer");
714 // return null; /* don't think we need to return null */
720 throw new IRException(pn.getTerminal());
724 private boolean parse_space(ParseNode pn) {
725 if (!precheck(pn, "space")) {
730 ParseNodeVector sets = pn.getChildren("setdefinition");
731 ParseNodeVector relations = pn.getChildren("relationdefinition");
733 assert pn.getChildren().size() == (sets.size() + relations.size());
736 for (int i = 0; i < sets.size(); i++) {
737 if (!parse_setdefinition(sets.elementAt(i))) {
742 /* parse relations */
743 for (int i = 0; i < relations.size(); i++) {
744 if (!parse_relationdefinition(relations.elementAt(i))) {
749 // ok, all the spaces have been parsed, now we should typecheck and check
752 // #TBD#: typecheck and check for cycles
754 /* replace missing with actual */
755 Iterator allsets = state.stSets.descriptors();
757 while (allsets.hasNext()) {
758 SetDescriptor sd = (SetDescriptor) allsets.next();
759 Vector subsets = sd.getSubsets();
761 for (int i = 0; i < subsets.size(); i++) {
762 SetDescriptor subset = (SetDescriptor) subsets.elementAt(i);
764 if (subset instanceof MissingSetDescriptor) {
765 SetDescriptor newsubset = lookupSet(subset.getSymbol());
767 if (newsubset == null) {
768 er.report(null, "Unknown subset '" + subset.getSymbol() + "'");
770 subsets.setElementAt(newsubset, i);
779 private boolean parse_setdefinition(ParseNode pn) {
780 if (!precheck(pn, "setdefinition")) {
787 String setname = pn.getChild("name").getTerminal();
788 assert (setname != null);
790 SetDescriptor sd = new SetDescriptor(setname);
793 String settype = pn.getChild("type").getTerminal();
794 TypeDescriptor type = lookupType(settype);
796 er.report(pn, "Undefined type '" + settype + "'");
802 /* is this a partition? */
803 boolean partition = pn.getChild("partition") != null;
804 sd.isPartition(partition);
806 /* if set has subsets, add them to set descriptor */
807 if (pn.getChild("setlist") != null) {
808 ParseNodeVector setlist = pn.getChild("setlist").getChildren();
810 for (int i = 0; i < setlist.size(); i++) {
811 String subsetname = setlist.elementAt(i).getLabel();
812 sd.addSubset(lookupSet(subsetname, CREATE_MISSING));
816 /* add set to symbol table */
817 if (stSets.contains(setname)) {
818 // Semantic Check: redefinition
819 er.report(pn, "Redefinition of set: " + setname);
828 private boolean parse_relationdefinition(ParseNode pn) {
829 if (!precheck(pn, "relationdefinition")) {
835 /* get relation name */
836 String relname = pn.getChild("name").getTerminal();
837 assert relname != null;
839 RelationDescriptor rd = new RelationDescriptor(relname);
841 /* check if static */
842 boolean bStatic = pn.getChild("static") != null;
843 rd.isStatic(bStatic);
846 String domainsetname = pn.getChild("domain").getChild("type").getTerminal();
847 assert domainsetname != null;
850 String rangesetname = pn.getChild("range").getChild("type").getTerminal();
851 assert rangesetname != null;
853 /* get domain multiplicity */
854 String domainmult = pn.getChild("domain").getChild("mult").getTerminal();
855 assert domainmult != null;
857 /* get range multiplicity */
858 String rangemult = pn.getChild("range").getChild("mult").getTerminal();
859 assert rangemult != null;
861 /* NOTE: it is assumed that the sets have been parsed already so that the
862 set namespace is fully populated. any missing setdescriptors for the set
863 symbol table will be assumed to be errors and reported. */
865 SetDescriptor domainset = lookupSet(domainsetname);
866 if (domainset == null) {
867 er.report(pn, "Undefined set '" + domainsetname + "' referenced in relation '" + relname + "'");
870 rd.setDomain(domainset);
873 SetDescriptor rangeset = lookupSet(rangesetname);
874 if (rangeset == null) {
875 er.report(pn, "Undefined set '" + rangesetname + "' referenced in relation '" + relname + "'");
878 rd.setRange(rangeset);
881 // #TBD#: eventually we'll use the multiplicities but now we don't... oh well
883 /* lets add the relation to the global symbol table */
884 if (!stRelations.contains(relname)) {
887 er.report(pn, "Redefinition of relation '" + relname + "'");
894 private boolean parse_structures(ParseNode pn) {
895 if (!precheck(pn, "structures")) {
900 ParseNodeVector structures = pn.getChildren("structure");
902 for (int i = 0; i < structures.size(); i++) {
903 if (!parse_structure(structures.elementAt(i))) {
908 ParseNodeVector globals = pn.getChildren("global");
910 for (int i = 0; i < globals.size(); i++) {
911 if (!parse_global(globals.elementAt(i))) {
916 // ok, all the structures have been parsed, now we gotta type check
918 Enumeration types = stTypes.getDescriptors();
919 while (types.hasMoreElements()) {
920 TypeDescriptor t = (TypeDescriptor) types.nextElement();
922 if (t instanceof ReservedTypeDescriptor) {
923 // we don't need to check reserved types
924 } else if (t instanceof StructureTypeDescriptor) {
926 StructureTypeDescriptor type = (StructureTypeDescriptor) t;
927 TypeDescriptor subtype = type.getSubType();
929 // check that the subtype is valid
930 if (subtype instanceof MissingTypeDescriptor) {
931 TypeDescriptor newtype = lookupType(subtype.getSymbol());
932 if (newtype == null) {
933 // subtype not defined anywheere
934 // #TBD#: somehow determine how we can get the original parsenode (global function?)
935 er.report(null, "Undefined subtype '" + subtype.getSymbol() + "'");
938 type.setSubType(newtype);
942 Iterator fields = type.getFields();
944 while (fields.hasNext()) {
945 FieldDescriptor field = (FieldDescriptor) fields.next();
946 TypeDescriptor fieldtype = field.getType();
948 assert fieldtype != null;
950 // check that the type is valid
951 if (fieldtype instanceof MissingTypeDescriptor) {
952 TypeDescriptor newtype = lookupType(fieldtype.getSymbol());
953 if (newtype == null) {
954 // type never defined
955 // #TBD#: replace new ParseNode with original parsenode
956 er.report(null, "Undefined type '" + fieldtype.getSymbol() + "'");
959 assert newtype != null;
960 field.setType(newtype);
965 Iterator labels = type.getLabels();
967 while (labels.hasNext()) {
968 LabelDescriptor label = (LabelDescriptor) labels.next();
969 TypeDescriptor labeltype = label.getType();
971 assert labeltype != null;
973 // check that the type is valid
974 if (labeltype instanceof MissingTypeDescriptor) {
975 TypeDescriptor newtype = lookupType(labeltype.getSymbol());
976 if (newtype == null) {
977 // type never defined
978 // #TBD#: replace new ParseNode with original parsenode
979 er.report(null, "Undefined type '" + labeltype.getSymbol() + "'");
982 assert newtype != null;
983 label.setType(newtype);
989 throw new IRException("shouldn't be any other typedescriptor classes");
997 types = stTypes.getDescriptors();
999 while (types.hasMoreElements()) {
1000 TypeDescriptor t = (TypeDescriptor) types.nextElement();
1002 if (t instanceof ReservedTypeDescriptor) {
1003 // we don't need to check reserved types
1004 } else if (t instanceof StructureTypeDescriptor) {
1006 StructureTypeDescriptor type = (StructureTypeDescriptor)t;
1007 TypeDescriptor subtype = type.getSubType();
1008 Iterator fields = type.getFields();
1010 while (fields.hasNext()) {
1011 FieldDescriptor field = (FieldDescriptor) fields.next();
1013 if (field instanceof ArrayDescriptor) {
1014 ArrayDescriptor ad = (ArrayDescriptor) field;
1015 Expr indexbound = ad.getIndexBound();
1016 TypeDescriptor indextype = indexbound.typecheck(new SemanticAnalyzer() {
1017 public IRErrorReporter getErrorReporter() { return er; }
1018 public SymbolTable getSymbolTable() { return stGlobals; }
1021 if (indextype == null) {
1023 } else if (indextype != ReservedTypeDescriptor.INT) {
1024 er.report(null, "'" + type.getSymbol() + "." + field.getSymbol() + "' index bounds must be type 'int' not '" + indextype.getSymbol() + "'");
1030 Iterator labels = type.getLabels();
1032 while (labels.hasNext()) {
1033 LabelDescriptor label = (LabelDescriptor) labels.next();
1034 Expr index = label.getIndex();
1036 if (index != null) {
1037 TypeDescriptor indextype = index.typecheck(new SemanticAnalyzer() {
1038 public IRErrorReporter getErrorReporter() { return er; }
1039 public SymbolTable getSymbolTable() { return stGlobals; }
1042 if (indextype != ReservedTypeDescriptor.INT) {
1043 er.report(null, "Label '" + type.getSymbol() + "." + label.getSymbol() + "' index must be type 'int' not '" + indextype.getSymbol() + "'");
1050 throw new IRException("shouldn't be any other typedescriptor classes");
1055 // #TBD#: need to make sure that no cycles exist in any of the declarations or subtypes
1056 // subtypes, of course, are not real subtypes, they are merely a way to validate a
1062 private boolean parse_global(ParseNode pn) {
1063 if (!precheck(pn, "global")) {
1067 String name = pn.getChild("name").getTerminal();
1068 assert name != null;
1070 String type = pn.getChild("type").getTerminal();
1071 assert type != null;
1072 TypeDescriptor td = lookupType(type);
1074 assert !(td instanceof ReservedTypeDescriptor);
1076 if (stGlobals.contains(name)) {
1077 /* redefinition of global */
1078 er.report(pn, "Redefinition of global '" + name + "'");
1082 stGlobals.add(new VarDescriptor(name, name, td));
1086 private boolean parse_structure(ParseNode pn) {
1087 if (!precheck(pn, "structure")) {
1092 String typename = pn.getChild("name").getTerminal();
1093 StructureTypeDescriptor type = new StructureTypeDescriptor(typename);
1095 if (pn.getChild("subtype") != null) {
1096 // has a subtype, lets try to resolve it
1097 String subtype = pn.getChild("subtype").getTerminal();
1099 if (subtype.equals(typename)) {
1100 // Semantic Error: cyclic inheritance
1101 er.report(pn, "Cyclic inheritance prohibited");
1105 /* lookup the type to get the type descriptor */
1106 type.setSubType(lookupType(subtype, CREATE_MISSING));
1109 // set the current type so that the recursive parses on the labels
1110 // and fields can add themselves automatically to the current type
1111 dCurrentType = type;
1113 // parse the labels and fields
1114 if (!parse_labelsandfields(pn.getChild("lf"))) {
1118 if (stTypes.contains(typename)) {
1119 er.report(pn, "Redefinition of type '" + typename + "'");
1128 private boolean parse_labelsandfields(ParseNode pn) {
1129 if (!precheck(pn, "lf")) {
1135 // check the fields first (need the field names
1136 // to type check the labels)
1137 if (!parse_fields(pn.getChild("fields"))) {
1141 // check the labels now that all the fields are sorted
1142 if (!parse_labels(pn.getChild("labels"))) {
1149 private boolean parse_fields(ParseNode pn) {
1150 if (!precheck(pn, "fields")) {
1156 /* NOTE: because the order of the fields is important when defining a data structure,
1157 and because the order is defined by the order of the fields defined in the field
1158 vector, its important that the parser returns the fields in the correct order */
1160 ParseNodeVector fields = pn.getChildren();
1162 for (int i = 0; i < fields.size(); i++) {
1163 ParseNode field = fields.elementAt(i);
1168 if (field.getChild("reserved") != null) {
1170 // #TBD#: it will be necessary for reserved field descriptors to generate
1171 // a unique symbol for the type descriptor requires it for its hashtable
1172 fd = new ReservedFieldDescriptor();
1175 name = field.getChild("name").getTerminal();
1176 fd = new FieldDescriptor(name);
1180 String type = field.getChild("type").getTerminal();
1181 boolean ptr = field.getChild("*") != null;
1184 fd.setType(lookupType(type, CREATE_MISSING));
1186 if (field.getChild("index") != null) {
1187 // field is an array, so create an array descriptor to wrap the
1188 // field descriptor and then replace the top level field descriptor with
1189 // this array descriptor
1190 Expr expr = parse_expr(field.getChild("index").getChild("expr"));
1192 // #ATTN#: do we really want to return an exception here?
1193 throw new IRException("invalid index expression");
1195 ArrayDescriptor ad = new ArrayDescriptor(fd, expr);
1199 // add the current field to the current type
1200 if (reserved == false) {
1201 // lets double check that we are redefining a field
1202 if (dCurrentType.getField(name) != null) {
1203 // Semantic Error: field redefinition
1204 er.report(pn, "Redefinition of field '" + name + "'");
1207 dCurrentType.addField(fd);
1210 dCurrentType.addField(fd);
1217 private boolean parse_labels(ParseNode pn) {
1218 if (!precheck(pn, "labels")) {
1224 /* NOTE: parse_labels should be called after the fields have been parsed because any
1225 labels not found in the field set of the current type will be flagged as errors */
1227 ParseNodeVector labels = pn.getChildren();
1229 for (int i = 0; i < labels.size(); i++) {
1230 ParseNode label = labels.elementAt(i);
1231 String name = label.getChild("name").getTerminal();
1232 LabelDescriptor ld = new LabelDescriptor(name);
1234 if (label.getChild("index") != null) {
1235 Expr expr = parse_expr(label.getChild("index").getChild("expr"));
1237 /* #ATTN#: do we really want to return an exception here? */
1238 throw new IRException("Invalid expression");
1243 String type = label.getChild("type").getTerminal();
1245 ld.setType(lookupType(type, CREATE_MISSING));
1247 String field = label.getChild("field").getTerminal();
1248 FieldDescriptor fd = dCurrentType.getField(field);
1251 /* Semantic Error: Undefined field in label */
1252 er.report(label, "Undefined field '" + field + "' in label");
1258 /* add label to current type */
1259 if (dCurrentType.getLabel(name) != null) {
1260 /* semantic error: label redefinition */
1261 er.report(pn, "Redefinition of label '" + name + "'");
1264 dCurrentType.addLabel(ld);
1271 private Expr parse_expr(ParseNode pn) {
1272 if (!precheck(pn, "expr")) {
1276 if (pn.getChild("var") != null) {
1277 // we've got a variable reference... we'll have to scope check it later
1278 // when we are completely done... there are also some issues of cyclic definitions
1279 return new VarExpr(pn.getChild("var").getTerminal());
1280 } else if (pn.getChild("literal") != null) {
1281 return parse_literal(pn.getChild("literal"));
1282 } else if (pn.getChild("operator") != null) {
1283 return parse_operator(pn.getChild("operator"));
1284 } else if (pn.getChild("relation") != null) {
1285 return parse_relation(pn.getChild("relation"));
1286 } else if (pn.getChild("sizeof") != null) {
1287 return parse_sizeof(pn.getChild("sizeof"));
1288 } else if (pn.getChild("simple_expr") != null) {
1289 return parse_simple_expr(pn.getChild("simple_expr"));
1290 } else if (pn.getChild("elementof") != null) {
1291 return parse_elementof(pn.getChild("elementof"));
1292 } else if (pn.getChild("tupleof") != null) {
1293 return parse_tupleof(pn.getChild("tupleof"));
1294 } else if (pn.getChild("isvalid") != null) {
1295 er.report(pn, "Operation 'isvalid' is currently unsupported.");
1298 er.report(pn, "Unknown or invalid expression type '" + pn.getTerminal() + "'");
1303 private Expr parse_elementof(ParseNode pn) {
1304 if (!precheck(pn, "elementof")) {
1309 String setname = pn.getChild("name").getTerminal();
1310 assert setname != null;
1311 SetDescriptor sd = lookupSet(setname);
1314 er.report(pn, "Undefined set '" + setname + "'");
1318 /* get left side expr */
1319 Expr expr = parse_expr(pn.getChild("expr"));
1325 return new ElementOfExpr(expr, sd);
1328 private Expr parse_tupleof(ParseNode pn) {
1329 if (!precheck(pn, "tupleof")) {
1334 String relname = pn.getChild("name").getTerminal();
1335 assert relname != null;
1336 RelationDescriptor rd = lookupRelation(relname);
1339 er.report(pn, "Undefined relation '" + relname + "'");
1343 Expr left = parse_expr(pn.getChild("left").getChild("expr"));
1344 Expr right = parse_expr(pn.getChild("right").getChild("expr"));
1346 if ((left == null) || (right == null)) {
1350 return new TupleOfExpr(left, right, rd);
1353 private Expr parse_simple_expr(ParseNode pn) {
1354 if (!precheck(pn, "simple_expr")) {
1358 // only locations so far
1359 return parse_location(pn.getChild("location"));
1362 private Expr parse_location(ParseNode pn) {
1363 if (!precheck(pn, "location")) {
1367 if (pn.getChild("var") != null) {
1368 // should be changed into a namespace check */
1369 return new VarExpr(pn.getChild("var").getTerminal());
1370 } else if (pn.getChild("cast") != null) {
1371 return parse_cast(pn.getChild("cast"));
1372 } else if (pn.getChild("dot") != null) {
1373 return parse_dot(pn.getChild("dot"));
1375 throw new IRException();
1379 private RelationExpr parse_relation(ParseNode pn) {
1380 if (!precheck(pn, "relation")) {
1384 String relname = pn.getChild("name").getTerminal();
1385 boolean inverse = pn.getChild("inv") == null;
1386 Expr expr = parse_expr(pn.getChild("expr"));
1392 RelationDescriptor relation = lookupRelation(relname);
1394 if (relation == null) {
1395 /* Semantic Error: relation not definied" */
1396 er.report(pn, "Undefined relation '" + relname + "'");
1400 return new RelationExpr(expr, relation, inverse);
1403 private SizeofExpr parse_sizeof(ParseNode pn) {
1404 if (!precheck(pn, "sizeof")) {
1409 SetExpr setexpr = parse_setexpr(pn.getChild("setexpr"));
1411 if (setexpr == null) {
1415 return new SizeofExpr(setexpr);
1418 private CastExpr parse_cast(ParseNode pn) {
1419 if (!precheck(pn, "cast")) {
1424 String typename = pn.getChild("type").getTerminal();
1425 assert typename != null;
1426 TypeDescriptor type = lookupType(typename);
1429 /* semantic error: undefined type in cast */
1430 er.report(pn, "Undefined type '" + typename + "' in cast operator");
1435 Expr expr = parse_simple_expr(pn.getChild("simple_expr"));
1441 return new CastExpr(type, expr);
1444 private SetExpr parse_setexpr(ParseNode pn) {
1445 if (!precheck(pn, "setexpr")) {
1449 // #TBD#: setexpr and parse_relation seem to be cousins... is there a reduction/refactor possible?
1451 if (pn.getChild("set") != null) {
1452 String setname = pn.getChild("set").getTerminal();
1453 assert setname != null;
1454 SetDescriptor sd = lookupSet(setname);
1457 er.report(pn, "Unknown or undefined set '" + setname + "'");
1460 return new SetExpr(sd);
1462 } else if (pn.getChild("dot") != null) {
1463 VarDescriptor vd = parse_quantifiervar(pn.getChild("dot").getChild("quantifiervar"));
1464 RelationDescriptor relation = lookupRelation(pn.getChild("dot").getChild("relation").getTerminal());
1465 return new ImageSetExpr(vd, relation);
1466 } else if (pn.getChild("dotinv") != null) {
1467 VarDescriptor vd = parse_quantifiervar(pn.getChild("dotinv").getChild("quantifiervar"));
1468 RelationDescriptor relation = lookupRelation(pn.getChild("dotinv").getChild("relation").getTerminal());
1469 return new ImageSetExpr(ImageSetExpr.INVERSE, vd, relation);
1471 throw new IRException();
1475 private VarDescriptor parse_quantifiervar(ParseNode pn) {
1476 if (!precheck(pn, "quantifiervar")) {
1481 String varname = pn.getTerminal();
1482 assert varname != null;
1484 /* NOTE: quantifier var's are only found in the constraints and
1485 model definitions... therefore we can do a semantic check here
1486 to make sure that the variables exist in the symbol table */
1488 /* NOTE: its assumed that the symbol table stack is appropriately
1489 set up with the parent quantifier symbol table */
1490 assert !sts.empty();
1492 /* do semantic check and if valid, add it to symbol table
1493 and add it to the quantifier as well */
1494 if (sts.peek().contains(varname)) {
1495 return new VarDescriptor(varname);
1497 /* Semantic Error: undefined variable */
1498 er.report(pn, "Undefined variable '" + varname + "'");
1503 private LiteralExpr parse_literal(ParseNode pn) {
1504 if (!precheck(pn, "literal")) {
1508 if (pn.getChild("boolean") != null) {
1509 if (pn.getChild("boolean").getChild("true") != null) {
1510 return new BooleanLiteralExpr(true);
1512 return new BooleanLiteralExpr(false);
1514 } else if (pn.getChild("decimal") != null) {
1515 String integer = pn.getChild("decimal").getTerminal();
1517 /* Check for integer literal overflow */
1518 BigInteger intLitBI = new BigInteger(integer);
1519 BigInteger intMax = new BigInteger("" + Integer.MAX_VALUE);
1520 BigInteger intMin = new BigInteger("" + Integer.MIN_VALUE);
1523 if (intLitBI.compareTo(intMin) < 0) {
1524 value = Integer.MIN_VALUE;
1525 er.warn(pn, "Integer literal overflow");
1526 } else if (intLitBI.compareTo(intMax) > 0) {
1527 value = Integer.MAX_VALUE;
1528 er.warn(pn, "Integer literal overflow");
1530 /* no truncation needed */
1531 value = Integer.parseInt(integer);
1534 return new IntegerLiteralExpr(value);
1535 } else if (pn.getChild("token") != null) {
1536 return new TokenLiteralExpr(pn.getChild("token").getTerminal());
1537 } else if (pn.getChild("string") != null) {
1538 throw new IRException("string unsupported");
1539 } else if (pn.getChild("char") != null) {
1540 throw new IRException("char unsupported");
1542 throw new IRException("unknown literal expression type.");
1546 private OpExpr parse_operator(ParseNode pn) {
1547 if (!precheck(pn, "operator")) {
1551 String opname = pn.getChild("op").getTerminal();
1552 Opcode opcode = Opcode.decodeFromString(opname);
1554 if (opcode == null) {
1555 er.report(pn, "Unsupported operation: " + opname);
1559 Expr left = parse_expr(pn.getChild("left").getChild("expr"));
1562 if (pn.getChild("right") != null) {
1563 right = parse_expr(pn.getChild("right").getChild("expr"));
1570 if (right == null && opcode != Opcode.NOT) {
1571 er.report(pn, "Two arguments required.");
1575 return new OpExpr(opcode, left, right);
1578 private DotExpr parse_dot(ParseNode pn) {
1579 if (!precheck(pn, "dot")) {
1583 Expr left = parse_simple_expr(pn.getChild("simple_expr"));
1589 String field = pn.getChild("field").getTerminal();
1593 if (pn.getChild("index") != null) {
1594 index = parse_expr(pn.getChild("index").getChild("expr"));
1596 if (index == null) {
1601 return new DotExpr(left, field, index);