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?) */
393 Iterator consiterator = state.vConstraints.iterator();
395 while (consiterator.hasNext()) {
396 Constraint cons = (Constraint) consiterator.next();
398 final SymbolTable consst = cons.getSymbolTable();
399 SemanticAnalyzer sa = new SemanticAnalyzer() {
400 public IRErrorReporter getErrorReporter() { return er; }
401 public SymbolTable getSymbolTable() { return consst; }
404 TypeDescriptor constype = cons.getLogicStatement().typecheck(sa);
406 if (constype == null) {
408 } else if (constype != ReservedTypeDescriptor.INT) {
409 er.report(null, "Type of guard must be 'int' not '" + constype.getSymbol() + "'");
417 private boolean parse_constraint(ParseNode pn) {
418 if (!precheck(pn, "constraint")) {
423 Constraint constraint = new Constraint();
426 boolean crash = pn.getChild("crash") != null;
427 constraint.setCrash(crash);
429 /* set up symbol table for constraint */
431 sts.push(constraint.getSymbolTable());
433 /* get quantifiers */
434 if (pn.getChild("quantifiers") != null) {
435 ParseNodeVector quantifiers = pn.getChild("quantifiers").getChildren();
437 for (int i = 0; i < quantifiers.size(); i++) {
438 ParseNode qn = quantifiers.elementAt(i);
439 assert qn.getLabel().equals("quantifier");
440 Quantifier quantifier = parse_quantifier(qn);
441 if (quantifier == null) {
444 constraint.addQuantifier(quantifier);
450 LogicStatement logicexpr = parse_body(pn.getChild("body"));
452 if (logicexpr == null) {
455 constraint.setLogicStatement(logicexpr);
458 /* pop symbol table stack */
459 SymbolTable st = sts.pop();
461 /* make sure the stack we pop is our constraint s.t. */
462 assert st == constraint.getSymbolTable();
465 /* add to vConstraints */
466 vConstraints.addElement(constraint);
471 private Quantifier parse_quantifier(ParseNode pn) {
472 if (!precheck(pn, "quantifier")) {
476 if (pn.getChild("forall") != null) { /* forall element in Set */
477 SetQuantifier sq = new SetQuantifier();
480 VarDescriptor vd = reserveName(pn.getChild("var"));
489 SetDescriptor set = parse_set(pn.getChild("set"));
494 vd.setType(set.getType());
496 /* return to caller */
499 } else if (pn.getChild("relation") != null) { /* for < v1, v2 > in Relation */
500 RelationQuantifier rq = new RelationQuantifier();
503 VarDescriptor vd1 = reserveName(pn.getChild("left"));
504 VarDescriptor vd2 = reserveName(pn.getChild("right"));
506 if ((vd1 == null) || (vd2 == null)) {
510 rq.setTuple(vd1, vd2);
513 String relationname = pn.getChild("relation").getTerminal();
514 assert relationname != null;
515 RelationDescriptor rd = lookupRelation(relationname);
522 vd1.setType(rd.getDomain().getType());
523 vd1.setSet(rd.getDomain());
524 vd2.setType(rd.getRange().getType());
525 vd2.setSet(rd.getRange());
527 } else if (pn.getChild("for") != null) { /* for j = x to y */
528 ForQuantifier fq = new ForQuantifier();
531 VarDescriptor vd = reserveName(pn.getChild("var"));
537 vd.setSet(lookupSet("int", false));
538 vd.setType(ReservedTypeDescriptor.INT);
541 /* grab lower/upper bounds */
542 Expr lower = parse_expr(pn.getChild("lower").getChild("expr"));
543 Expr upper = parse_expr(pn.getChild("upper").getChild("expr"));
545 if ((lower == null) || (upper == null)) {
549 fq.setBounds(lower, upper);
553 throw new IRException("not supported yet");
557 private LogicStatement parse_body(ParseNode pn) {
558 if (!precheck(pn, "body")) {
562 if (pn.getChild("and") != null) {
564 LogicStatement left, right;
565 left = parse_body(pn.getChild("and").getChild("left").getChild("body"));
566 right = parse_body(pn.getChild("and").getChild("right").getChild("body"));
568 if ((left == null) || (right == null)) {
572 // what do we want to call the and/or/not body classes?
573 return new LogicStatement(LogicStatement.AND, left, right);
574 } else if (pn.getChild("or") != null) {
576 LogicStatement left, right;
577 left = parse_body(pn.getChild("or").getChild("left").getChild("body"));
578 right = parse_body(pn.getChild("or").getChild("right").getChild("body"));
580 if ((left == null) || (right == null)) {
584 return new LogicStatement(LogicStatement.OR, left, right);
585 } else if (pn.getChild("not") != null) {
587 LogicStatement left = parse_body(pn.getChild("not").getChild("body"));
593 return new LogicStatement(LogicStatement.NOT, left);
594 } else if (pn.getChild("predicate") != null) {
595 return parse_predicate(pn.getChild("predicate"));
597 throw new IRException();
601 private Predicate parse_predicate(ParseNode pn) {
602 if (!precheck(pn, "predicate")) {
606 if (pn.getChild("inclusion") != null) {
607 ParseNode in = pn.getChild("inclusion");
610 Expr expr = parse_expr(in.getChild("expr"));
617 SetExpr setexpr = parse_setexpr(in.getChild("setexpr"));
619 if (setexpr == null) {
623 return new InclusionPredicate(expr, setexpr);
624 } else if (pn.getChild("expr") != null) {
625 Expr expr = parse_expr(pn.getChild("expr"));
631 return new ExprPredicate(expr);
633 throw new IRException();
637 private SetDescriptor parse_set(ParseNode pn) {
638 if (!precheck(pn, "set")) {
642 if (pn.getChild("name") != null) {
643 String setname = pn.getChild("name").getTerminal();
644 assert setname != null;
646 if (!stSets.contains(setname)) {
647 /* Semantic Error: unknown set */
648 er.report(pn, "Unknown set '" + setname + "' referenced in quantifier");
651 /* all good, get setdescriptor */
652 SetDescriptor sd = (SetDescriptor) stSets.get(setname);
656 } else if (pn.getChild("listofliterals") != null) {
657 TokenSetDescriptor tokenset = new TokenSetDescriptor();
658 ParseNodeVector token_literals = pn.getChild("listofliterals").getChildren();
659 assert token_literals.size() > 0;
661 for (int i = 0; i < token_literals.size(); i++) {
662 ParseNode literal = token_literals.elementAt(i);
663 assert literal.getLabel().equals("literal");
664 LiteralExpr litexpr = parse_literal(literal);
666 if (litexpr == null) {
670 if (litexpr instanceof TokenLiteralExpr || litexpr instanceof IntegerLiteralExpr) {
671 tokenset.addLiteral(litexpr);
673 er.report(literal, "Elements of a user-defined set must be of type token or integer");
674 // return null; /* don't think we need to return null */
680 throw new IRException(pn.getTerminal());
684 private boolean parse_space(ParseNode pn) {
685 if (!precheck(pn, "space")) {
690 ParseNodeVector sets = pn.getChildren("setdefinition");
691 ParseNodeVector relations = pn.getChildren("relationdefinition");
693 assert pn.getChildren().size() == (sets.size() + relations.size());
696 for (int i = 0; i < sets.size(); i++) {
697 if (!parse_setdefinition(sets.elementAt(i))) {
702 /* parse relations */
703 for (int i = 0; i < relations.size(); i++) {
704 if (!parse_relationdefinition(relations.elementAt(i))) {
709 // ok, all the spaces have been parsed, now we should typecheck and check
712 // #TBD#: typecheck and check for cycles
714 /* replace missing with actual */
715 Iterator allsets = state.stSets.descriptors();
717 while (allsets.hasNext()) {
718 SetDescriptor sd = (SetDescriptor) allsets.next();
719 Vector subsets = sd.getSubsets();
721 for (int i = 0; i < subsets.size(); i++) {
722 SetDescriptor subset = (SetDescriptor) subsets.elementAt(i);
724 if (subset instanceof MissingSetDescriptor) {
725 SetDescriptor newsubset = lookupSet(subset.getSymbol());
727 if (newsubset == null) {
728 er.report(null, "Unknown subset '" + subset.getSymbol() + "'");
730 subsets.setElementAt(newsubset, i);
739 private boolean parse_setdefinition(ParseNode pn) {
740 if (!precheck(pn, "setdefinition")) {
747 String setname = pn.getChild("name").getTerminal();
748 assert (setname != null);
750 SetDescriptor sd = new SetDescriptor(setname);
753 String settype = pn.getChild("type").getTerminal();
754 TypeDescriptor type = lookupType(settype);
756 er.report(pn, "Undefined type '" + settype + "'");
762 /* is this a partition? */
763 boolean partition = pn.getChild("partition") != null;
764 sd.isPartition(partition);
766 /* if set has subsets, add them to set descriptor */
767 if (pn.getChild("setlist") != null) {
768 ParseNodeVector setlist = pn.getChild("setlist").getChildren();
770 for (int i = 0; i < setlist.size(); i++) {
771 String subsetname = setlist.elementAt(i).getLabel();
772 sd.addSubset(lookupSet(subsetname, CREATE_MISSING));
776 /* add set to symbol table */
777 if (stSets.contains(setname)) {
778 // Semantic Check: redefinition
779 er.report(pn, "Redefinition of set: " + setname);
788 private boolean parse_relationdefinition(ParseNode pn) {
789 if (!precheck(pn, "relationdefinition")) {
795 /* get relation name */
796 String relname = pn.getChild("name").getTerminal();
797 assert relname != null;
799 RelationDescriptor rd = new RelationDescriptor(relname);
801 /* check if static */
802 boolean bStatic = pn.getChild("static") != null;
803 rd.isStatic(bStatic);
806 String domainsetname = pn.getChild("domain").getChild("type").getTerminal();
807 assert domainsetname != null;
810 String rangesetname = pn.getChild("range").getChild("type").getTerminal();
811 assert rangesetname != null;
813 /* get domain multiplicity */
815 if (pn.getChild("domain").getChild("domainmult") != null)
816 domainmult = pn.getChild("domain").getChild("domainmult").getChild("mult").getTerminal();
817 //assert domainmult != null;
819 /* get range multiplicity */
821 if (pn.getChild("range").getChild("domainrange") != null)
822 rangemult = pn.getChild("range").getChild("domainrange").getChild("mult").getTerminal();
823 //assert rangemult != null;
825 /* NOTE: it is assumed that the sets have been parsed already so that the
826 set namespace is fully populated. any missing setdescriptors for the set
827 symbol table will be assumed to be errors and reported. */
829 SetDescriptor domainset = lookupSet(domainsetname);
830 if (domainset == null) {
831 er.report(pn, "Undefined set '" + domainsetname + "' referenced in relation '" + relname + "'");
834 rd.setDomain(domainset);
837 SetDescriptor rangeset = lookupSet(rangesetname);
838 if (rangeset == null) {
839 er.report(pn, "Undefined set '" + rangesetname + "' referenced in relation '" + relname + "'");
842 rd.setRange(rangeset);
845 // #TBD#: eventually we'll use the multiplicities but now we don't... oh well
847 /* lets add the relation to the global symbol table */
848 if (!stRelations.contains(relname)) {
851 er.report(pn, "Redefinition of relation '" + relname + "'");
858 private boolean parse_structures(ParseNode pn) {
859 if (!precheck(pn, "structures")) {
864 ParseNodeVector structures = pn.getChildren("structure");
866 for (int i = 0; i < structures.size(); i++) {
867 if (!parse_structure(structures.elementAt(i))) {
872 ParseNodeVector globals = pn.getChildren("global");
874 for (int i = 0; i < globals.size(); i++) {
875 if (!parse_global(globals.elementAt(i))) {
880 // ok, all the structures have been parsed, now we gotta type check
882 Enumeration types = stTypes.getDescriptors();
883 while (types.hasMoreElements()) {
884 TypeDescriptor t = (TypeDescriptor) types.nextElement();
886 if (t instanceof ReservedTypeDescriptor) {
887 // we don't need to check reserved types
888 } else if (t instanceof StructureTypeDescriptor) {
890 StructureTypeDescriptor type = (StructureTypeDescriptor) t;
891 TypeDescriptor subtype = type.getSuperType();
893 // check that the subtype is valid
894 if (subtype instanceof MissingTypeDescriptor) {
895 TypeDescriptor newtype = lookupType(subtype.getSymbol());
896 if (newtype == null) {
897 // subtype not defined anywheere
898 // #TBD#: somehow determine how we can get the original parsenode (global function?)
899 er.report(null, "Undefined subtype '" + subtype.getSymbol() + "'");
902 type.setSuperType(newtype);
906 Iterator fields = type.getFields();
908 while (fields.hasNext()) {
909 FieldDescriptor field = (FieldDescriptor) fields.next();
910 TypeDescriptor fieldtype = field.getType();
912 assert fieldtype != null;
914 // check that the type is valid
915 if (fieldtype instanceof MissingTypeDescriptor) {
916 TypeDescriptor newtype = lookupType(fieldtype.getSymbol());
917 if (newtype == null) {
918 // type never defined
919 // #TBD#: replace new ParseNode with original parsenode
920 er.report(null, "Undefined type '" + fieldtype.getSymbol() + "'");
923 assert newtype != null;
924 field.setType(newtype);
929 Iterator labels = type.getLabels();
931 while (labels.hasNext()) {
932 LabelDescriptor label = (LabelDescriptor) labels.next();
933 TypeDescriptor labeltype = label.getType();
935 assert labeltype != null;
937 // check that the type is valid
938 if (labeltype instanceof MissingTypeDescriptor) {
939 TypeDescriptor newtype = lookupType(labeltype.getSymbol());
940 if (newtype == null) {
941 // type never defined
942 // #TBD#: replace new ParseNode with original parsenode
943 er.report(null, "Undefined type '" + labeltype.getSymbol() + "'");
946 assert newtype != null;
947 label.setType(newtype);
953 throw new IRException("shouldn't be any other typedescriptor classes");
961 types = stTypes.getDescriptors();
963 while (types.hasMoreElements()) {
964 TypeDescriptor t = (TypeDescriptor) types.nextElement();
966 if (t instanceof ReservedTypeDescriptor) {
967 // we don't need to check reserved types
968 } else if (t instanceof StructureTypeDescriptor) {
970 StructureTypeDescriptor type = (StructureTypeDescriptor)t;
971 TypeDescriptor subtype = type.getSuperType();
972 Iterator fields = type.getFields();
974 while (fields.hasNext()) {
975 FieldDescriptor field = (FieldDescriptor) fields.next();
977 if (field instanceof ArrayDescriptor) {
978 ArrayDescriptor ad = (ArrayDescriptor) field;
979 Expr indexbound = ad.getIndexBound();
980 TypeDescriptor indextype = indexbound.typecheck(new SemanticAnalyzer() {
981 public IRErrorReporter getErrorReporter() { return er; }
982 public SymbolTable getSymbolTable() { return stGlobals; }
985 if (indextype == null) {
987 } else if (indextype != ReservedTypeDescriptor.INT) {
988 er.report(null, "'" + type.getSymbol() + "." + field.getSymbol() + "' index bounds must be type 'int' not '" + indextype.getSymbol() + "'");
994 Iterator labels = type.getLabels();
996 while (labels.hasNext()) {
997 LabelDescriptor label = (LabelDescriptor) labels.next();
998 Expr index = label.getIndex();
1000 if (index != null) {
1001 TypeDescriptor indextype = index.typecheck(new SemanticAnalyzer() {
1002 public IRErrorReporter getErrorReporter() { return er; }
1003 public SymbolTable getSymbolTable() { return stGlobals; }
1006 if (indextype != ReservedTypeDescriptor.INT) {
1007 er.report(null, "Label '" + type.getSymbol() + "." + label.getSymbol() + "' index must be type 'int' not '" + indextype.getSymbol() + "'");
1013 throw new IRException("shouldn't be any other typedescriptor classes");
1017 // #TBD#: need to make sure that no cycles exist in any of the declarations or subtypes
1018 // subtypes, of course, are not real subtypes, they are merely a way to validate a
1024 private boolean parse_global(ParseNode pn) {
1025 if (!precheck(pn, "global")) {
1029 String name = pn.getChild("name").getTerminal();
1030 assert name != null;
1032 String type = pn.getChild("type").getTerminal();
1033 assert type != null;
1034 TypeDescriptor td = lookupType(type);
1036 assert !(td instanceof ReservedTypeDescriptor);
1038 if (stGlobals.contains(name)) {
1039 /* redefinition of global */
1040 er.report(pn, "Redefinition of global '" + name + "'");
1044 stGlobals.add(new VarDescriptor(name, name, td,true));
1048 private boolean parse_structure(ParseNode pn) {
1049 if (!precheck(pn, "structure")) {
1054 String typename = pn.getChild("name").getTerminal();
1055 StructureTypeDescriptor type = new StructureTypeDescriptor(typename);
1057 if (pn.getChild("subtype") != null) {
1058 // has a subtype, lets try to resolve it
1059 String subtype = pn.getChild("subtype").getTerminal();
1061 if (subtype.equals(typename)) {
1062 // Semantic Error: cyclic inheritance
1063 er.report(pn, "Cyclic inheritance prohibited");
1067 /* lookup the type to get the type descriptor */
1068 type.setSuperType(lookupType(subtype, CREATE_MISSING));
1071 // set the current type so that the recursive parses on the labels
1072 // and fields can add themselves automatically to the current type
1073 dCurrentType = type;
1075 // parse the labels and fields
1076 if (!parse_labelsandfields(pn.getChild("lf"))) {
1080 if (stTypes.contains(typename)) {
1081 er.report(pn, "Redefinition of type '" + typename + "'");
1090 private boolean parse_labelsandfields(ParseNode pn) {
1091 if (!precheck(pn, "lf")) {
1097 // check the fields first (need the field names
1098 // to type check the labels)
1099 if (!parse_fields(pn.getChild("fields"))) {
1103 // check the labels now that all the fields are sorted
1104 if (!parse_labels(pn.getChild("labels"))) {
1111 private boolean parse_fields(ParseNode pn) {
1112 if (!precheck(pn, "fields")) {
1118 /* NOTE: because the order of the fields is important when defining a data structure,
1119 and because the order is defined by the order of the fields defined in the field
1120 vector, its important that the parser returns the fields in the correct order */
1122 ParseNodeVector fields = pn.getChildren();
1124 for (int i = 0; i < fields.size(); i++) {
1125 ParseNode field = fields.elementAt(i);
1130 if (field.getChild("reserved") != null) {
1132 // #TBD#: it will be necessary for reserved field descriptors to generate
1133 // a unique symbol for the type descriptor requires it for its hashtable
1134 fd = new ReservedFieldDescriptor();
1137 name = field.getChild("name").getTerminal();
1138 fd = new FieldDescriptor(name);
1142 String type = field.getChild("type").getTerminal();
1143 boolean ptr = field.getChild("*") != null;
1146 fd.setType(lookupType(type, CREATE_MISSING));
1148 if (field.getChild("index") != null) {
1149 // field is an array, so create an array descriptor to wrap the
1150 // field descriptor and then replace the top level field descriptor with
1151 // this array descriptor
1152 Expr expr = parse_expr(field.getChild("index").getChild("expr"));
1154 // #ATTN#: do we really want to return an exception here?
1155 throw new IRException("invalid index expression");
1157 ArrayDescriptor ad = new ArrayDescriptor(fd, expr);
1161 // add the current field to the current type
1162 if (reserved == false) {
1163 // lets double check that we are redefining a field
1164 if (dCurrentType.getField(name) != null) {
1165 // Semantic Error: field redefinition
1166 er.report(pn, "Redefinition of field '" + name + "'");
1169 dCurrentType.addField(fd);
1172 dCurrentType.addField(fd);
1179 private boolean parse_labels(ParseNode pn) {
1180 if (!precheck(pn, "labels")) {
1186 /* NOTE: parse_labels should be called after the fields have been parsed because any
1187 labels not found in the field set of the current type will be flagged as errors */
1189 ParseNodeVector labels = pn.getChildren();
1191 for (int i = 0; i < labels.size(); i++) {
1192 ParseNode label = labels.elementAt(i);
1193 String name = label.getChild("name").getTerminal();
1194 LabelDescriptor ld = new LabelDescriptor(name);
1196 if (label.getChild("index") != null) {
1197 Expr expr = parse_expr(label.getChild("index").getChild("expr"));
1199 /* #ATTN#: do we really want to return an exception here? */
1200 throw new IRException("Invalid expression");
1205 String type = label.getChild("type").getTerminal();
1207 ld.setType(lookupType(type, CREATE_MISSING));
1209 String field = label.getChild("field").getTerminal();
1210 FieldDescriptor fd = dCurrentType.getField(field);
1213 /* Semantic Error: Undefined field in label */
1214 er.report(label, "Undefined field '" + field + "' in label");
1220 /* add label to current type */
1221 if (dCurrentType.getLabel(name) != null) {
1222 /* semantic error: label redefinition */
1223 er.report(pn, "Redefinition of label '" + name + "'");
1226 dCurrentType.addLabel(ld);
1233 private Expr parse_expr(ParseNode pn) {
1234 if (!precheck(pn, "expr")) {
1238 if (pn.getChild("var") != null) {
1239 // we've got a variable reference... we'll have to scope check it later
1240 // when we are completely done... there are also some issues of cyclic definitions
1241 return new VarExpr(pn.getChild("var").getTerminal());
1242 } else if (pn.getChild("literal") != null) {
1243 return parse_literal(pn.getChild("literal"));
1244 } else if (pn.getChild("operator") != null) {
1245 return parse_operator(pn.getChild("operator"));
1246 } else if (pn.getChild("relation") != null) {
1247 return parse_relation(pn.getChild("relation"));
1248 } else if (pn.getChild("sizeof") != null) {
1249 return parse_sizeof(pn.getChild("sizeof"));
1250 } else if (pn.getChild("simple_expr") != null) {
1251 return parse_simple_expr(pn.getChild("simple_expr"));
1252 } else if (pn.getChild("elementof") != null) {
1253 return parse_elementof(pn.getChild("elementof"));
1254 } else if (pn.getChild("tupleof") != null) {
1255 return parse_tupleof(pn.getChild("tupleof"));
1256 } else if (pn.getChild("isvalid") != null) {
1257 er.report(pn, "Operation 'isvalid' is currently unsupported.");
1260 er.report(pn, "Unknown or invalid expression type '" + pn.getTerminal() + "'");
1265 private Expr parse_elementof(ParseNode pn) {
1266 if (!precheck(pn, "elementof")) {
1271 String setname = pn.getChild("name").getTerminal();
1272 assert setname != null;
1273 SetDescriptor sd = lookupSet(setname);
1276 er.report(pn, "Undefined set '" + setname + "'");
1280 /* get left side expr */
1281 Expr expr = parse_expr(pn.getChild("expr"));
1287 return new ElementOfExpr(expr, sd);
1290 private Expr parse_tupleof(ParseNode pn) {
1291 if (!precheck(pn, "tupleof")) {
1296 String relname = pn.getChild("name").getTerminal();
1297 assert relname != null;
1298 RelationDescriptor rd = lookupRelation(relname);
1301 er.report(pn, "Undefined relation '" + relname + "'");
1305 Expr left = parse_expr(pn.getChild("left").getChild("expr"));
1306 Expr right = parse_expr(pn.getChild("right").getChild("expr"));
1308 if ((left == null) || (right == null)) {
1312 return new TupleOfExpr(left, right, rd);
1315 private Expr parse_simple_expr(ParseNode pn) {
1316 if (!precheck(pn, "simple_expr")) {
1320 // only locations so far
1321 return parse_location(pn.getChild("location"));
1324 private Expr parse_location(ParseNode pn) {
1325 if (!precheck(pn, "location")) {
1329 if (pn.getChild("var") != null) {
1330 // should be changed into a namespace check */
1331 return new VarExpr(pn.getChild("var").getTerminal());
1332 } else if (pn.getChild("cast") != null) {
1333 return parse_cast(pn.getChild("cast"));
1334 } else if (pn.getChild("dot") != null) {
1335 return parse_dot(pn.getChild("dot"));
1337 throw new IRException();
1341 private RelationExpr parse_relation(ParseNode pn) {
1342 if (!precheck(pn, "relation")) {
1346 String relname = pn.getChild("name").getTerminal();
1347 boolean inverse = pn.getChild("inv") != null;
1348 Expr expr = parse_expr(pn.getChild("expr"));
1354 RelationDescriptor relation = lookupRelation(relname);
1356 if (relation == null) {
1357 /* Semantic Error: relation not definied" */
1358 er.report(pn, "Undefined relation '" + relname + "'");
1362 /* add usage so correct sets are created */
1363 relation.addUsage(inverse ? RelationDescriptor.INVIMAGE : RelationDescriptor.IMAGE);
1365 return new RelationExpr(expr, relation, inverse);
1368 private SizeofExpr parse_sizeof(ParseNode pn) {
1369 if (!precheck(pn, "sizeof")) {
1374 SetExpr setexpr = parse_setexpr(pn.getChild("setexpr"));
1376 if (setexpr == null) {
1380 return new SizeofExpr(setexpr);
1383 private CastExpr parse_cast(ParseNode pn) {
1384 if (!precheck(pn, "cast")) {
1389 String typename = pn.getChild("type").getTerminal();
1390 assert typename != null;
1391 TypeDescriptor type = lookupType(typename);
1394 /* semantic error: undefined type in cast */
1395 er.report(pn, "Undefined type '" + typename + "' in cast operator");
1400 Expr expr = parse_simple_expr(pn.getChild("simple_expr"));
1406 return new CastExpr(type, expr);
1409 private SetExpr parse_setexpr(ParseNode pn) {
1410 if (!precheck(pn, "setexpr")) {
1414 // #TBD#: setexpr and parse_relation seem to be cousins... is there a reduction/refactor possible?
1416 if (pn.getChild("set") != null) {
1417 String setname = pn.getChild("set").getTerminal();
1418 assert setname != null;
1419 SetDescriptor sd = lookupSet(setname);
1422 er.report(pn, "Unknown or undefined set '" + setname + "'");
1425 return new SetExpr(sd);
1427 } else if (pn.getChild("dot") != null) {
1428 VarDescriptor vd = parse_quantifiervar(pn.getChild("dot").getChild("quantifiervar"));
1429 RelationDescriptor relation = lookupRelation(pn.getChild("dot").getChild("relation").getTerminal());
1430 relation.addUsage(RelationDescriptor.IMAGE);
1431 return new ImageSetExpr(vd, relation);
1432 } else if (pn.getChild("dotinv") != null) {
1433 VarDescriptor vd = parse_quantifiervar(pn.getChild("dotinv").getChild("quantifiervar"));
1434 RelationDescriptor relation = lookupRelation(pn.getChild("dotinv").getChild("relation").getTerminal());
1435 relation.addUsage(RelationDescriptor.INVIMAGE);
1436 return new ImageSetExpr(ImageSetExpr.INVERSE, vd, relation);
1438 throw new IRException();
1442 private VarDescriptor parse_quantifiervar(ParseNode pn) {
1443 if (!precheck(pn, "quantifiervar")) {
1448 String varname = pn.getTerminal();
1449 assert varname != null;
1451 /* NOTE: quantifier var's are only found in the constraints and
1452 model definitions... therefore we can do a semantic check here
1453 to make sure that the variables exist in the symbol table */
1455 /* NOTE: its assumed that the symbol table stack is appropriately
1456 set up with the parent quantifier symbol table */
1457 assert !sts.empty();
1459 /* do semantic check and if valid, add it to symbol table
1460 and add it to the quantifier as well */
1461 if (sts.peek().contains(varname)) {
1462 VarDescriptor vdold=(VarDescriptor)sts.peek().get(varname);
1464 /* Dan was creating a new VarDescriptor...This seems
1465 like the wrong thing to do. We'll just lookup the
1467 --------------------------------------------------
1468 VarDescriptor vd=new VarDescriptor(varname);
1469 vd.setSet(vdold.getSet()); return vd;*/
1471 /* Semantic Error: undefined variable */
1472 er.report(pn, "Undefined variable '" + varname + "'");
1477 private LiteralExpr parse_literal(ParseNode pn) {
1478 if (!precheck(pn, "literal")) {
1482 if (pn.getChild("boolean") != null) {
1483 if (pn.getChild("boolean").getChild("true") != null) {
1484 return new BooleanLiteralExpr(true);
1486 return new BooleanLiteralExpr(false);
1488 } else if (pn.getChild("decimal") != null) {
1489 String integer = pn.getChild("decimal").getTerminal();
1491 /* Check for integer literal overflow */
1492 BigInteger intLitBI = new BigInteger(integer);
1493 BigInteger intMax = new BigInteger("" + Integer.MAX_VALUE);
1494 BigInteger intMin = new BigInteger("" + Integer.MIN_VALUE);
1497 if (intLitBI.compareTo(intMin) < 0) {
1498 value = Integer.MIN_VALUE;
1499 er.warn(pn, "Integer literal overflow");
1500 } else if (intLitBI.compareTo(intMax) > 0) {
1501 value = Integer.MAX_VALUE;
1502 er.warn(pn, "Integer literal overflow");
1504 /* no truncation needed */
1505 value = Integer.parseInt(integer);
1508 return new IntegerLiteralExpr(value);
1509 } else if (pn.getChild("token") != null) {
1510 return new TokenLiteralExpr(pn.getChild("token").getTerminal());
1511 } else if (pn.getChild("string") != null) {
1512 throw new IRException("string unsupported");
1513 } else if (pn.getChild("char") != null) {
1514 throw new IRException("char unsupported");
1516 throw new IRException("unknown literal expression type.");
1520 private OpExpr parse_operator(ParseNode pn) {
1521 if (!precheck(pn, "operator")) {
1525 String opname = pn.getChild("op").getTerminal();
1526 Opcode opcode = Opcode.decodeFromString(opname);
1528 if (opcode == null) {
1529 er.report(pn, "Unsupported operation: " + opname);
1533 Expr left = parse_expr(pn.getChild("left").getChild("expr"));
1536 if (pn.getChild("right") != null) {
1537 right = parse_expr(pn.getChild("right").getChild("expr"));
1544 if (right == null && opcode != Opcode.NOT) {
1545 er.report(pn, "Two arguments required.");
1549 return new OpExpr(opcode, left, right);
1552 private DotExpr parse_dot(ParseNode pn) {
1553 if (!precheck(pn, "dot")) {
1557 Expr left = parse_simple_expr(pn.getChild("simple_expr"));
1563 String field = pn.getChild("field").getTerminal();
1567 if (pn.getChild("index") != null) {
1568 index = parse_expr(pn.getChild("index").getChild("expr"));
1570 if (index == null) {
1575 return new DotExpr(left, field, index);