/* * xtc - The eXTensible Compiler * Copyright (C) 2009-2012 New York University * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * version 2 as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, * USA. */ package xtc.lang.cpp; import xtc.lang.cpp.ForkMergeParser.Subparser; /* from c.prologue */ import xtc.Constants; import xtc.Limits; import xtc.lang.cpp.CContext.SymbolTable.STField; import xtc.tree.Attribute; import xtc.tree.GNode; import xtc.tree.Location; import xtc.tree.Node; import xtc.tree.Visitor; import xtc.util.Pair; import xtc.lang.cpp.Syntax.Kind; import xtc.lang.cpp.Syntax.LanguageTag; import xtc.lang.cpp.Syntax.ConditionalTag; import xtc.lang.cpp.Syntax.DirectiveTag; import xtc.lang.cpp.Syntax.Layout; import xtc.lang.cpp.Syntax.Language; import xtc.lang.cpp.Syntax.Text; import xtc.lang.cpp.Syntax.Directive; import xtc.lang.cpp.Syntax.Conditional; import xtc.lang.cpp.Syntax.Error; import xtc.type.AliasT; import xtc.type.ArrayT; import xtc.type.BooleanT; import xtc.type.C; import xtc.type.CastReference; import xtc.type.Constant; import xtc.type.DynamicReference; import xtc.type.EnumT; import xtc.type.EnumeratorT; import xtc.type.ErrorT; import xtc.type.FieldReference; import xtc.type.FunctionT; import xtc.type.InternalT; import xtc.type.LabelT; import xtc.type.NullReference; import xtc.type.NumberT; import xtc.type.PointerT; import xtc.type.Reference; import xtc.type.StaticReference; import xtc.type.StringReference; import xtc.type.StructOrUnionT; import xtc.type.StructT; import xtc.type.Tagged; import xtc.type.Type; import xtc.type.Type.Tag; import xtc.type.UnionT; import xtc.type.VariableT; import xtc.type.VoidT; import xtc.util.SymbolTable; import xtc.util.SymbolTable.Scope; import xtc.util.SingletonIterator; import xtc.util.Utilities; import xtc.lang.cpp.PresenceConditionManager.PresenceCondition; import xtc.lang.cpp.ForkMergeParser.StackFrame; import java.util.ArrayList; import java.util.List; import org.sat4j.core.VecInt; import org.sat4j.minisat.SolverFactory; import org.sat4j.specs.ContradictionException; import org.sat4j.specs.IConstr; import org.sat4j.specs.IProblem; import org.sat4j.specs.ISolver; import org.sat4j.specs.TimeoutException; import org.sat4j.tools.ModelIterator; /** * This class is generated from grammar annotations and provides semantic * action support. */ public class CActions implements SemanticActions { /** The instance of this class */ private static CActions ref; /** Get the instance of this class */ public static CActions getInstance() { if (null == ref) { ref = new CActions(); } return ref; } public Object action(int production, Subparser subparser, Object value) { switch (production) { case 12: { ReenterScope(subparser); } break; case 13: { ExitScope(subparser); } break; case 15: { ReenterScope(subparser); } break; case 16: { ExitScope(subparser); } break; case 19: { bindFunDef(subparser, null, getNodeAt(subparser, 1)); } break; case 20: { saveBaseType(subparser, getNodeAt(subparser, 2)); bindFunDef(subparser, getNodeAt(subparser, 2), getNodeAt(subparser, 1)); } break; case 21: { saveBaseType(subparser, getNodeAt(subparser, 2)); bindFunDef(subparser, getNodeAt(subparser, 2), getNodeAt(subparser, 1)); } break; case 22: { saveBaseType(subparser, getNodeAt(subparser, 2)); bindFunDef(subparser, getNodeAt(subparser, 2), getNodeAt(subparser, 1)); } break; case 23: { saveBaseType(subparser, getNodeAt(subparser, 2)); bindFunDef(subparser, getNodeAt(subparser, 2), getNodeAt(subparser, 1)); } break; case 24: { bindFunDef(subparser, null, getNodeAt(subparser, 1)); } break; case 25: { saveBaseType(subparser, getNodeAt(subparser, 2)); bindFunDef(subparser, getNodeAt(subparser, 2), getNodeAt(subparser, 1)); } break; case 26: { saveBaseType(subparser, getNodeAt(subparser, 2)); bindFunDef(subparser, getNodeAt(subparser, 2), getNodeAt(subparser, 1)); } break; case 27: { saveBaseType(subparser, getNodeAt(subparser, 2)); bindFunDef(subparser, getNodeAt(subparser, 2), getNodeAt(subparser, 1)); } break; case 28: { saveBaseType(subparser, getNodeAt(subparser, 2)); bindFunDef(subparser, getNodeAt(subparser, 2), getNodeAt(subparser, 1)); } break; case 29: { bindFunDef(subparser, null, getNodeAt(subparser, 1)); } break; case 30: { saveBaseType(subparser, getNodeAt(subparser, 2)); bindFunDef(subparser, getNodeAt(subparser, 2), getNodeAt(subparser, 1)); } break; case 31: { saveBaseType(subparser, getNodeAt(subparser, 2)); bindFunDef(subparser, getNodeAt(subparser, 2), getNodeAt(subparser, 1)); } break; case 32: { saveBaseType(subparser, getNodeAt(subparser, 2)); bindFunDef(subparser, getNodeAt(subparser, 2), getNodeAt(subparser, 1)); } break; case 33: { saveBaseType(subparser, getNodeAt(subparser, 2)); bindFunDef(subparser, getNodeAt(subparser, 2), getNodeAt(subparser, 1)); } break; case 34: { ReenterScope(subparser); } break; case 35: { ExitScope(subparser); } break; case 37: { ReenterScope(subparser); } break; case 38: { ExitScope(subparser); } break; case 40: { saveBaseType(subparser, getNodeAt(subparser, 2)); bindFunDef(subparser, getNodeAt(subparser, 2), getNodeAt(subparser, 1)); } break; case 41: { saveBaseType(subparser, getNodeAt(subparser, 2)); bindFunDef(subparser, getNodeAt(subparser, 2), getNodeAt(subparser, 1)); } break; case 42: { saveBaseType(subparser, getNodeAt(subparser, 2)); bindFunDef(subparser, getNodeAt(subparser, 2), getNodeAt(subparser, 1)); } break; case 43: { saveBaseType(subparser, getNodeAt(subparser, 2)); bindFunDef(subparser, getNodeAt(subparser, 2), getNodeAt(subparser, 1)); } break; case 44: { saveBaseType(subparser, getNodeAt(subparser, 2)); bindFunDef(subparser, getNodeAt(subparser, 2), getNodeAt(subparser, 1)); } break; case 45: { saveBaseType(subparser, getNodeAt(subparser, 2)); bindFunDef(subparser, getNodeAt(subparser, 2), getNodeAt(subparser, 1)); } break; case 46: { saveBaseType(subparser, getNodeAt(subparser, 2)); bindFunDef(subparser, getNodeAt(subparser, 2), getNodeAt(subparser, 1)); } break; case 47: { saveBaseType(subparser, getNodeAt(subparser, 2)); bindFunDef(subparser, getNodeAt(subparser, 2), getNodeAt(subparser, 1)); } break; case 48: { saveBaseType(subparser, getNodeAt(subparser, 2)); bindFunDef(subparser, getNodeAt(subparser, 2), getNodeAt(subparser, 1)); } break; case 49: { saveBaseType(subparser, getNodeAt(subparser, 2)); bindFunDef(subparser, getNodeAt(subparser, 2), getNodeAt(subparser, 1)); } break; case 50: { saveBaseType(subparser, getNodeAt(subparser, 2)); bindFunDef(subparser, getNodeAt(subparser, 2), getNodeAt(subparser, 1)); } break; case 51: { saveBaseType(subparser, getNodeAt(subparser, 2)); bindFunDef(subparser, getNodeAt(subparser, 2), getNodeAt(subparser, 1)); } break; case 54: { KillReentrantScope(subparser); } break; case 56: { KillReentrantScope(subparser); } break; case 58: { KillReentrantScope(subparser); } break; case 60: { KillReentrantScope(subparser); } break; case 62: { saveBaseType(subparser, getNodeAt(subparser, 2)); bindIdent(subparser, getNodeAt(subparser, 2), getNodeAt(subparser, 1)); } break; case 64: { saveBaseType(subparser, getNodeAt(subparser, 2)); bindIdent(subparser, getNodeAt(subparser, 2), getNodeAt(subparser, 1)); } break; case 66: { // reuses saved base type bindIdent(subparser, getNodeAt(subparser, 4), getNodeAt(subparser, 1)); } break; case 68: { saveBaseType(subparser, getNodeAt(subparser, 2)); bindIdent(subparser, getNodeAt(subparser, 2), getNodeAt(subparser, 1)); } break; case 70: { saveBaseType(subparser, getNodeAt(subparser, 2)); bindIdent(subparser, getNodeAt(subparser, 2), getNodeAt(subparser, 1)); } break; case 72: { // reuses saved base type bindIdent(subparser, getNodeAt(subparser, 4), getNodeAt(subparser, 1)); } break; case 84: { updateSpecs(subparser, getSpecsAt(subparser, 1), value); } break; case 85: { updateSpecs(subparser, getSpecsAt(subparser, 2), getSpecsAt(subparser, 1), value); } break; case 86: { updateSpecs(subparser, getSpecsAt(subparser, 2), getSpecsAt(subparser, 1), value); } break; case 87: { updateSpecs(subparser, getSpecsAt(subparser, 1), value); } break; case 88: { updateSpecs(subparser, getSpecsAt(subparser, 2), getSpecsAt(subparser, 1), value); } break; case 91: { getSpecsAt(subparser, 1).add(Constants.ATT_CONSTANT); updateSpecs(subparser, getSpecsAt(subparser, 1), value); } break; case 92: { getSpecsAt(subparser, 1).add(Constants.ATT_VOLATILE); updateSpecs(subparser, getSpecsAt(subparser, 1), value); } break; case 93: { getSpecsAt(subparser, 1).add(Constants.ATT_RESTRICT); updateSpecs(subparser, getSpecsAt(subparser, 1), value); } break; case 94: { /* TODO AttributeSpecifier */ updateSpecs(subparser, getSpecsAt(subparser, 1), value); } break; case 95: { getSpecsAt(subparser, 1).add(Constants.ATT_INLINE); updateSpecs(subparser, getSpecsAt(subparser, 1), value); } break; case 108: { updateSpecs(subparser, getSpecsAt(subparser, 2), getSpecsAt(subparser, 1), value); } break; case 109: { updateSpecs(subparser, getSpecsAt(subparser, 2), getSpecsAt(subparser, 1), value); } break; case 110: { updateSpecs(subparser, getSpecsAt(subparser, 2), getSpecsAt(subparser, 1), value); } break; case 111: { updateSpecs(subparser, getSpecsAt(subparser, 2), getSpecsAt(subparser, 1), value); } break; case 112: { /* Arithmetic or void */ updateSpecs(subparser, getSpecsAt(subparser, 1), value); } break; case 113: { updateSpecs(subparser, getSpecsAt(subparser, 2), getSpecsAt(subparser, 1), value); } break; case 114: { updateSpecs(subparser, getSpecsAt(subparser, 2), getSpecsAt(subparser, 1), value); } break; case 115: { updateSpecs(subparser, getSpecsAt(subparser, 2), getSpecsAt(subparser, 1), value); } break; case 141: { updateSpecs(subparser, getSpecsAt(subparser, 2), getSpecsAt(subparser, 1), value); } break; case 142: { updateSpecs(subparser, getSpecsAt(subparser, 2), getSpecsAt(subparser, 1), value); } break; case 143: { updateSpecs(subparser, getSpecsAt(subparser, 2), getSpecsAt(subparser, 1), value); } break; case 144: { updateSpecs(subparser, getSpecsAt(subparser, 2), getSpecsAt(subparser, 1), value); } break; case 145: { updateSpecs(subparser, getSpecsAt(subparser, 1), value); } break; case 146: { updateSpecs(subparser, getSpecsAt(subparser, 2), getSpecsAt(subparser, 1), value); } break; case 147: { updateSpecs(subparser, getSpecsAt(subparser, 2), getSpecsAt(subparser, 1), value); } break; case 148: { updateSpecs(subparser, getSpecsAt(subparser, 2), getSpecsAt(subparser, 1), value); } break; case 149: { getSpecsAt(subparser, 1).type = InternalT.VA_LIST; } break; case 150: { getSpecsAt(subparser, 1).storage = Constants.ATT_STORAGE_TYPEDEF; } break; case 151: { getSpecsAt(subparser, 1).storage = Constants.ATT_STORAGE_EXTERN; } break; case 152: { getSpecsAt(subparser, 1).storage = Constants.ATT_STORAGE_STATIC; } break; case 153: { getSpecsAt(subparser, 1).storage = Constants.ATT_STORAGE_AUTO; } break; case 154: { getSpecsAt(subparser, 1).storage = Constants.ATT_STORAGE_REGISTER; } break; case 155: { getSpecsAt(subparser, 1).type = VoidT.TYPE; } break; case 156: { getSpecsAt(subparser, 1).seenChar = true; } break; case 157: { getSpecsAt(subparser, 1).seenShort = true; } break; case 158: { getSpecsAt(subparser, 1).seenInt = true; } break; case 159: { getSpecsAt(subparser, 1).seenInt = true; } break; case 160: { getSpecsAt(subparser, 1).longCount++; } break; case 161: { getSpecsAt(subparser, 1).seenFloat = true; } break; case 162: { getSpecsAt(subparser, 1).seenDouble = true; } break; case 163: { getSpecsAt(subparser, 1).seenSigned = true; } break; case 164: { getSpecsAt(subparser, 1).seenUnsigned = true; } break; case 165: { getSpecsAt(subparser, 1).seenBool = true; } break; case 166: { getSpecsAt(subparser, 1).seenComplex = true; } break; case 175: { EnterScope(subparser); } break; case 176: { ExitScope(subparser); } break; case 177: { Node tag = null; Node members = getNodeAt(subparser, 3); Node attrs = null; updateSpecs(subparser, makeStructSpec(subparser, tag, members, attrs), value); } break; case 178: { EnterScope(subparser); } break; case 179: { ExitScope(subparser); } break; case 180: { Node tag = getNodeAt(subparser, 6); Node members = getNodeAt(subparser, 3); Node attrs = null; updateSpecs(subparser, makeStructSpec(subparser, tag, members, attrs), value); } break; case 182: { EnterScope(subparser); } break; case 183: { ExitScope(subparser); } break; case 184: { Node tag = null; Node members = getNodeAt(subparser, 3); Node attrs = getNodeAt(subparser, 6); updateSpecs(subparser, makeStructSpec(subparser, tag, members, attrs), value); } break; case 185: { EnterScope(subparser); } break; case 186: { ExitScope(subparser); } break; case 187: { Node tag = getNodeAt(subparser, 6); Node members = getNodeAt(subparser, 3); Node attrs = getNodeAt(subparser, 7); updateSpecs(subparser, makeStructSpec(subparser, tag, members, attrs), value); } break; case 189: { EnterScope(subparser); } break; case 190: { ExitScope(subparser); } break; case 192: { EnterScope(subparser); } break; case 193: { ExitScope(subparser); } break; case 196: { EnterScope(subparser); } break; case 197: { ExitScope(subparser); } break; case 199: { EnterScope(subparser); } break; case 200: { ExitScope(subparser); } break; case 203: { ((Node) value).setProperty(SPECS, new Specifiers()); } break; case 204: { updateSpecs(subparser, getSpecsAt(subparser, 2), getSpecsAt(subparser, 1), value); } break; case 233: { BindEnum(subparser); } break; case 235: { BindEnum(subparser); } break; case 253: { saveBaseType(subparser, getNodeAt(subparser, 2)); bindIdent(subparser, getNodeAt(subparser, 2), getNodeAt(subparser, 1)); } break; case 255: { saveBaseType(subparser, getNodeAt(subparser, 2)); bindIdent(subparser, getNodeAt(subparser, 2), getNodeAt(subparser, 1)); } break; case 257: { saveBaseType(subparser, getNodeAt(subparser, 2)); bindIdent(subparser, getNodeAt(subparser, 2), getNodeAt(subparser, 1)); } break; case 259: { saveBaseType(subparser, getNodeAt(subparser, 2)); bindIdent(subparser, getNodeAt(subparser, 2), getNodeAt(subparser, 1)); } break; case 261: { saveBaseType(subparser, getNodeAt(subparser, 2)); bindIdent(subparser, getNodeAt(subparser, 2), getNodeAt(subparser, 1)); } break; case 263: { saveBaseType(subparser, getNodeAt(subparser, 2)); bindIdent(subparser, getNodeAt(subparser, 2), getNodeAt(subparser, 1)); } break; case 267: { BindVar(subparser); } break; case 324: { /* setDecl(value, new PointerT(getDecl(getNodeAt(subparser, 1)))); */ /* copyName(subparser, value, 1); */ } break; case 325: { /* Specifiers spec = getSpecsAt(subparser, 2); */ /* Type baseType = getDecl(getNodeAt(subparser, 1));; */ /* Type result = spec.annotateBase(new PointerT(baseType).annotate()); */ /* setDecl(value, result); */ /* copyName(subparser, value, 1); */ } break; case 330: { /* copyDeclName(subparser, value, 2); */ } break; case 332: { EnterScope(subparser); } break; case 333: { ExitReentrantScope(subparser); } break; case 336: { /* copyDeclName(subparser, value, 1); */ } break; case 337: { /* copyDeclName(subparser, value, 2); */ } break; case 338: { /* setDecl(value, lastSeenType(subparser)); */ /* setName(value, getStringAt(subparser, 1)); */ } break; case 342: { EnterScope(subparser); } break; case 343: { ExitReentrantScope(subparser); } break; case 354: { /* setDecl(value, new ArrayT(getDecl(getNodeAt(subparser, 1)))); */ /* copyName(subparser, value, 1); */ } break; case 355: { /* setDecl(value, new ArrayT(getDecl())); */ /* copyName(subparser, value, 1); */ } break; case 420: { useIdent(subparser, getNodeAt(subparser, 1)); } break; case 422: { EnterScope(subparser); } break; case 423: { ExitScope(subparser); } break; case 434: { callFunction(subparser, getNodeAt(subparser, 3), null); } break; case 435: { callFunction(subparser, getNodeAt(subparser, 4), getNodeAt(subparser, 2)); } break; } return value; } public void dispatch(int id, Subparser subparser) { // no action productions } /* from c.epilogue */ /** True when statistics should be output. */ private boolean languageStatistics = false; /** Turn on error reporting. */ private static boolean showErrors = false; /** Turn on debugging messages. */ private static boolean debug = false; /** Turn on checkers. */ private static boolean enableCheckers = false; /** Turn on checkers. */ private static List<String> extraConstraints = null; /** Turn on function analysis. */ private static boolean enableFunctionAnalysis = false; /** A symbol table for analysis. */ private CContext.SymbolTable functionTable; /** Turn on kconfig feature model clauses. */ private boolean hasClauses = false; /** The clauses for the kconfig feature model. */ private Clauses featureClauses = null; /** The kconfig feature model solver. */ private ISolver featureSolver; /** The assumptions of the feature model, i.e., non-arch config vars. */ private VecInt modelAssumptions; /** * Turn language statistics collection on. Default is off. * * @param b True is on. */ public void collectStatistics(boolean b) { languageStatistics = b; } /** * Show errors. * * @param b True is on. */ public void showErrors(boolean b) { showErrors = b; } /** * Show debugging messages. * * @param b True is on. */ public void debug(boolean b) { debug = b; } /** * Enable checkers. * * @param b Enable checkers if true. */ public void enableCheckers(boolean b) { this.enableCheckers(b, null); } /** * Enable checkers. * * @param b Enable checkers if true. * @param extraConstraints Extra constraints to SAT solver. */ public void enableCheckers(boolean b, List<String> extraConstraints) { this.enableCheckers = b; if (null == extraConstraints) { // avoid having to check for null extraConstraints = new ArrayList<String>(); } this.extraConstraints = extraConstraints; } /** * Enable function analysis. */ public void enableFunctionAnalysis() { this.enableFunctionAnalysis = true; this.functionTable = new CContext.SymbolTable(); } /** * Add kconfig feature model clauses. * * @param clauses The clauses. */ public void addClauses(Clauses clauses, int[] assumptions) { if (null != assumptions) { this.modelAssumptions = new VecInt(assumptions); } else { this.modelAssumptions = new VecInt(new int[0]); } if (null != clauses) { this.hasClauses = true; this.featureClauses = clauses; this.featureSolver = SolverFactory.newDefault(); this.featureSolver.newVar(clauses.getNumVars()); this.featureSolver.setExpectedNumberOfClauses(clauses.size()); try { for (List<Integer> clause : clauses) { int[] cint = new int[clause.size()]; int i = 0; for (Integer val : clause) { cint[i++] = val; } this.featureSolver.addClause(new VecInt(cint)); } } catch (ContradictionException e) { e.printStackTrace(); System.exit(1); } } else { this.hasClauses = false; this.featureClauses = null; } } /** * Get the checker symbol table. * * @return The checker symbol table. */ public CContext.SymbolTable getFunctionTable() { return this.functionTable; } /** * A helper function to get the value of a node on the stack, which * corresponds to the value of the component of a production. Unlike * bison, this is numbered by the stack, i.e., the closest component * to the action has the lowest number, starting with 1. * * @param subparser The reference to the subparser. * @param number The component number, where 1 is the component to the * left of the action, and increasing in number while going towards * the beginning of the production. * @return The node value of the component. */ private static Node getNodeAt(Subparser subparser, int component) { return (Node) (subparser.stack.get(component).value); } private static String getStringAt(Subparser subparser, int component) { return ((Syntax) getNodeAt(subparser, component)).toLanguage().getTokenText(); } /** * A helper function to set the type property of the given node. The * given value will be first cast to a Node. * * @param value A node object. * @param type The type to set. */ private static void setType(Object value, Type type) { ((Node) value).setProperty(Constants.TYPE, type); } private static void error(String msg) { if (showErrors) { System.err.println("error: " + msg); } /* System.exit(1); */ } // ---------- Parsing-only context /** * Compute and store the base type indicated by the specifications * property of the given node. */ public void saveBaseType(Subparser subparser, Node typespec) { if (typespec.getProperty(SPECS) == null) { if (showErrors) { System.err.println("error: no specs available"); } return; } ((CContext) subparser.scope).lastSeenType = ((Specifiers) typespec.getProperty(SPECS)).getType(); } /** * Return the last seen type. */ public Type lastSeenType(Subparser subparser) { return ((CContext) subparser.scope).lastSeenType; } private static class Binding { public Language ident; public Type type; public Binding(Language ident, Type type) { this.ident = ident; this.type = type; } } private boolean findToken(Object n, CTag tag) { if (n instanceof Language && ((Language) n).tag() == tag) { return true; } else if (n instanceof Syntax) { return ((Syntax) n).getTokenText().equals(tag.getText()); } else if (n instanceof Node) { boolean b = false; for (Object o : ((Node) n)) { b |= findToken(o, tag); if (b) return true; } return false; } else if (n instanceof PresenceCondition) { // ignore return false; } else { System.err.println(n.getClass().getSimpleName()); return false; } } public void bindFunDef(Subparser subparser, Node typespec, Node declarator) { boolean static_function; if (getident(declarator).equals("ERR_PTR")) { System.err.println(typespec); System.err.println(declarator); } if (null == typespec) { // only static with static keyword static_function = false; } else if (typespec.getName().equals("DeclarationSpecifier") || typespec.getName().equals("DeclarationQualifierList")) { // the declaration keyword can only appear in these kinds of // specifiers if (typespec.getProperty(SPECS) != null) { static_function = ((Specifiers) typespec.getProperty(SPECS)).storage == Constants.ATT_STORAGE_STATIC; } else { // traverse subtree looking for static until checkers are finished static_function = findToken(typespec, CTag.STATIC); } } else { // the declaration keyword can only appear in these kinds of // specifiers if (typespec.getProperty(SPECS) != null) { static_function = ((Specifiers) typespec.getProperty(SPECS)).storage == Constants.ATT_STORAGE_STATIC; } else { // traverse subtree looking for static until checkers are finished static_function = findToken(typespec, CTag.STATIC); } } if (static_function) { bindIdent(subparser, typespec, declarator, STField.STATIC_FUNDEF); } else { bindIdent(subparser, typespec, declarator, STField.GLOBAL_FUNDEF); } } public void bindIdent(Subparser subparser, Node typespec, Node declarator) { bindIdent(subparser, typespec, declarator, null); } /** typespec might be null for declarations and definitions without a * type spec; alsoSet is used to set another symbol table bit and * might be null. */ public void bindIdent(Subparser subparser, Node typespec, Node declarator, STField alsoSet) { StackFrame stack = subparser.stack; PresenceConditionManager.PresenceCondition presenceCondition = subparser.getPresenceCondition(); CContext scope = (CContext) subparser.scope; // TODO need to hoist conditionals from typespec and declarator // around entire declaration by combining with each other // TODO causing an infinite loop on 3.12 init/main.c /* if (typespec.getProperty(SPECS) == null) { */ /* System.err.println("error: no specs available"); */ /* } else { */ /* Type baseType = ((Specifiers) typespec.getProperty(SPECS)).getType(); */ /* Binding binding = grokdeclarator(declarator, baseType); */ /* Type type = binding.type; */ /* Language ident = binding.ident; */ /* System.err.println(ident + " = " + type); */ /* } */ // TODO replace old-style typedef checking by using specs above Language ident = getident(declarator); // Check whether the declaration is a typedef. This assumes that // the typedef keyword is the first token of the declaration. boolean typedef = false; if (null != typespec) { Object a = typespec; while (true) { if ( ! (a instanceof Syntax)) { Node n = (Node) a; if (n.hasName(ForkMergeParser.CHOICE_NODE_NAME)) { // When it's a conditional node, the first child is a // presence condition, the second is the first AST child. a = n.get(1); } else { a = n.get(0); } } else if (a instanceof Pair) { a = ((Pair) a).head(); } else { break; } } Language t = (Language) a; if (CTag.TYPEDEF == t.tag()) { // Bind a typedef name. typedef = true; if (languageStatistics) { if (typedef) { Location location = subparser.lookahead.token.syntax.getLocation(); System.err.println(String.format("typedef %s %s", ident, location)); } } } else { // Binding a variable name. typedef = false; } } if (showErrors) { System.err.println("bind: " + ident.getTokenText() + " " + typedef); } if (debug) { System.err.println("def: " + ident.getTokenText() + " " + alsoSet); } STField field = typedef ? STField.TYPEDEF : STField.IDENT; scope.getSymbolTable().setbool(ident.getTokenText(), field, true, presenceCondition); if (null != alsoSet) { scope.getSymbolTable().setbool(ident.getTokenText(), alsoSet, true, presenceCondition); } /* if (typedef) { */ /* scope.getSymbolTable().setbool(ident.getTokenText(), STField.TYPEDEF, true, presenceCondition); */ /* } else { */ /* scope.getSymbolTable().setbool(ident.getTokenText(), STField.IDENT, true, presenceCondition); */ /* } */ /* scope.bind(ident.getTokenText(), typedef, presenceCondition); */ } private static Binding grokdeclarator(Node declarator, Type type) { Language ident = null; while (null != declarator) { if (declarator.getName().equals("SimpleDeclarator")) { ident = ((Syntax) declarator.get(0)).toLanguage(); declarator = null; } else if (declarator.getName().equals("ParenIdentifierDeclarator")) { Node parenIdentDecl = null; switch (declarator.size()) { case 3: parenIdentDecl = (Node) declarator.get(1); break; default: error("unexpected grammar structure for " + declarator.getName()); break; } declarator = parenIdentDecl; } else if (declarator.getName().equals("UnaryIdentifierDeclarator")) { Node typeQual; Node identDecl; switch (declarator.size()) { case 2: typeQual = null; identDecl = (Node) declarator.get(1); break; case 3: typeQual = (Node) declarator.get(1); identDecl = (Node) declarator.get(2); break; default: typeQual = null; identDecl = null; error("unexpected grammar structure for " + declarator.getName()); break; } if (null != typeQual) { Specifiers specs = (Specifiers) typeQual.getProperty(SPECS); type = specs.annotateBase(new PointerT(type).annotate()); } else { type = new PointerT(type); } declarator = identDecl; } else if (declarator.getName().equals("ArrayDeclarator")) { Node parenIdentDecl = (Node) declarator.get(0); Node arrayAbsDecl = (Node) declarator.get(1); type = grokabsdeclarator(arrayAbsDecl, type); declarator = parenIdentDecl; } else if (declarator.getName().equals("PostfixIdentifierDeclarator")) { Node unaryIdentDecl = (Node) declarator.get(0); Node postfixAbsDecl = (Node) declarator.get(1); type = grokabsdeclarator(postfixAbsDecl, type); declarator = unaryIdentDecl; } else if (declarator.getName().equals("FunctionDeclarator")) { Node parenIdentDecl = (Node) declarator.get(0); Node postfixFuncDecl = (Node) declarator.get(1); type = grokabsdeclarator(postfixFuncDecl, type); declarator = parenIdentDecl; } else { if (debug) { System.err.println("TODO support declarator " + declarator.getName()); } declarator = null; } } return new Binding(ident, type); } private static Type grokabsdeclarator(Node absdeclarator, Type type) { if (absdeclarator.getName().equals("ArrayAbstractDeclarator")) { while (null != absdeclarator) { Node arraySize = null; switch (absdeclarator.size()) { case 0: arraySize = null; absdeclarator = null; break; case 1: arraySize = (Node) absdeclarator.get(0); absdeclarator = null; break; case 2: arraySize = (Node) absdeclarator.get(1); absdeclarator = (Node) absdeclarator.get(0); break; default: error("unexpected grammar structure for " + absdeclarator.getName()); } type = new ArrayT(type); } } else if (absdeclarator.getName().equals("PostfixingFunctionDeclarator")) { Node parms = null; switch (absdeclarator.size()) { case 1: parms = (Node) absdeclarator.get(0); break; default: error("unexpected grammar structure for " + absdeclarator.getName()); break; } FunctionT function = getParameterTypes(parms); function.setResult(type); type = function; } else { if (debug) { System.err.println("TODO support absdeclarator " + absdeclarator.getName()); } } return type; } private static FunctionT getParameterTypes(Node parms) { // TODO flesh this out and do type checking boolean varArgs = false; ArrayList<Type> types = new ArrayList<Type>(); if (parms != null && parms.size() > 0) { parms = (Node) parms.get(0); /* System.err.println(parms); */ switch (parms.size()) { case 2: varArgs = true; // fall through case 1: parms = (Node) parms.get(0); break; default: error("unexpected grammar structure for " + parms.getName()); break; } // parms is now a list node containing ParameterDeclaration elements if (parms.getName().equals("ParameterList")) { for (Object o : parms) { GNode n = (GNode) o; if (n.getName().equals("Conditional")) { boolean isCond = true; for (Object o_parm : n) { if (isCond) { // TODO get presence condition } else { GNode parm = (GNode) o_parm; Node typespec = (Node) parm.get(0); // TODO remove once specs are done if (typespec.getProperty(SPECS) == null) continue; Type baseType = ((Specifiers) typespec.getProperty(SPECS)).getType(); if (parm.size() > 1) { Node declarator = (Node) parm.get(1); if (parm.getName().equals("ParameterIdentifierDeclaration")) { Binding binding = grokdeclarator(declarator, baseType); Language ident = binding.ident; Type type = binding.type; String name = binding.ident.getTokenText(); types.add(VariableT.newParam(type, name)); } else if (parm.getName().equals("ParameterAbstractDeclaration")) { Type type = grokabsdeclarator(declarator, baseType); types.add(type); } else { if (showErrors) { System.err.println("unsupported parameter declaration " + parm.getName()); } } } else { types.add(baseType); } } isCond = isCond ? false : true; } } else { if (showErrors) { System.err.println("parameter is no conditional"); } } } } else { if (showErrors) { System.err.println("unexpected parameter list node"); } } } FunctionT function = new FunctionT(null, types, varArgs); function.addAttribute(Constants.ATT_STYLE_NEW); return function; } public void BindVar(Subparser subparser) { StackFrame stack = subparser.stack; PresenceConditionManager.PresenceCondition presenceCondition = subparser.getPresenceCondition(); CContext scope = (CContext) subparser.scope; // Get the identifier in the declarator. Object b = stack.get(1).value; Language<?> ident = getident(b); // Bind variable name. scope.getSymbolTable().setbool(ident.getTokenText(), STField.IDENT, true, presenceCondition); /* scope.bind(ident.getTokenText(), false, presenceCondition); */ } public void BindEnum(Subparser subparser) { StackFrame stack = subparser.stack; PresenceConditionManager.PresenceCondition presenceCondition = subparser.getPresenceCondition(); CContext scope = (CContext) subparser.scope; // Get the identifier in the declarator. The identifier must // occur after an IdentifierOrTypedefName token. Object b = stack.get(1).value; String ident = getident(b).getTokenText(); // Bind variable name. scope.getSymbolTable().setbool(ident, STField.IDENT, true, presenceCondition); /* scope.bind(ident, false, presenceCondition); */ } public void useIdent(Subparser subparser, Node ident) { CContext scope = (CContext) subparser.scope; String name = ident.getTokenText(); if (debug) { System.err.println("use: " + name); } if (enableCheckers) { PresenceCondition identPresenceCond = scope.symbolPresenceCond(name, STField.IDENT); if (null != identPresenceCond && ! identPresenceCond.isFalse()) { PresenceCondition not = identPresenceCond.not(); PresenceCondition andnot = subparser.getPresenceCondition().and(not); /* not.delRef(); */ if (! andnot.isFalse()) { boolean satWithKconfig = true; boolean contradiction = false; int[] model = null; // check andnot against kconfig feature model if (this.hasClauses) { // use double negation to get andnot in cnf form PresenceCondition notandnot = andnot.not(); /* System.err.println(notandnot); */ List allsat = (List) notandnot.getBDD().allsat(); ArrayList<ArrayList<Integer>> bugClauses = new ArrayList<ArrayList<Integer>>(); for (Object o : allsat) { byte[] sat = (byte[]) o; ArrayList<Integer> clause = new ArrayList<Integer>(); for (int i = 0; i < sat.length; i++) { // convert to solver's varnum // look up i in variable manager // if varname exists in clauses, then add to clause int sign = 1; switch (sat[i]) { case 1: // negate again sign = -1; case 0: String varname = notandnot.presenceConditionManager().getVariableManager().getName(i); if (varname.startsWith("(defined ")) { varname = varname.substring(9, varname.length() - 1); /* System.err.println(varname); */ if (this.featureClauses.getVarmap().containsKey(varname)) { int var = this.featureClauses.getVarmap().get(varname); var = sign * var; clause.add(var); } } break; } } if (clause.size() > 0) { /* System.err.println(clause); */ bugClauses.add(clause); } } // add extra constraints for (String extraConstraint : extraConstraints) { this.featureClauses.addClauses(extraConstraint); } // remove them to avoid adding them again the next check extraConstraints.clear(); try { ISolver featureSolver = SolverFactory.newDefault(); featureSolver.newVar(this.featureClauses.getNumVars()); /* featureSolver.setExpectedNumberOfClauses(this.featureClauses.size() + bugClauses.size()); */ for (List<Integer> clause : this.featureClauses) { int[] cint = new int[clause.size()]; int i = 0; for (Integer val : clause) { cint[i++] = val; } featureSolver.addClause(new VecInt(cint)); } for (List<Integer> clause : bugClauses) { int[] cint = new int[clause.size()]; int i = 0; for (Integer val : clause) { cint[i++] = val; } IConstr curConstr = featureSolver.addClause(new VecInt(cint)); } ISolver bugSolver = SolverFactory.newDefault(); bugSolver.newVar(this.featureClauses.getNumVars()); bugSolver.setExpectedNumberOfClauses(bugClauses.size()); for (List<Integer> clause : bugClauses) { int[] cint = new int[clause.size()]; int i = 0; for (Integer val : clause) { cint[i++] = val; } IConstr curConstr = bugSolver.addClause(new VecInt(cint)); } IProblem simpleProblem = new ModelIterator(bugSolver); boolean satWithoutKconfig = simpleProblem.isSatisfiable(); /* IProblem problem = featureSolver; */ IProblem problem = new ModelIterator(featureSolver); if (problem.isSatisfiable(modelAssumptions)) { satWithKconfig = true; if (debug) { System.err.println("computing model"); } model = problem.model(); } else { satWithKconfig = false; if (satWithoutKconfig) { System.err.print("invalid config invalidated by kconfig "); } else { System.err.print("invalid config invalidated by bug clauses alone "); } System.err.println(name + " at " + ident.getLocation()); } } catch (ContradictionException e) { contradiction = true; } catch (TimeoutException e) { e.printStackTrace(); /* System.exit(1); */ } notandnot.delRef(); } if (contradiction) { System.err.print("invalid config invalidated by contradiction " + name + " at " + ident.getLocation()); } else if (satWithKconfig) { PresenceCondition sat = andnot.satOne(); if (null != scope.symbolPresenceCond(name, STField.GLOBAL_FUNDEF) || null != scope.symbolPresenceCond(name, STField.STATIC_FUNDEF)) { System.err.println("found for function def"); } System.err.println("found invalid configuration on " + name + " at " + ident.getLocation()); /* System.err.println("config " + andnot); */ /* System.err.println("identPresenceCond: " + identPresenceCond); */ /* /\* System.err.println("undefined under " + not); *\/ */ /* /\* System.err.println("used under " + subparser.getPresenceCondition()); *\/ */ /* if (this.showExample) { */ if (true) { if (null != model) { System.err.print("model: "); String delim = "["; for (int i = 0; i < model.length; i++) { if (model[i] > 0) { System.err.print(delim + featureClauses.getVarName(model[i])); delim = ","; } } System.err.println("]"); } } sat.delRef(); } } else { if (debug) { System.err.println("valid function call " + name + " at " + ident.getLocation()); /* System.err.println("not: " + not); */ /* System.err.println("subparser.getPresenceCondition() " + subparser.getPresenceCondition()); */ } } not.delRef(); andnot.delRef(); /* PresenceCondition and = subparser.getPresenceCondition().and(identPresenceCond); */ /* if (and.isFalse()) { */ /* System.err.println("found infeasible configuration on " + name + " at " + ident.getLocation() + " defined in " + identPresenceCond); */ /* } */ /* and.delRef(); */ // update configurations the identifier is used in scope.getSymbolTable().setbool(name, STField.USED, true, subparser.getPresenceCondition()); } else { if (debug) { System.err.println("not an identifier in any config " + name + " at " + ident.getLocation()); } } } } public void callFunction(Subparser subparser, Node fun, Node parms) { if (fun.getName().equals("PrimaryIdentifier") && enableFunctionAnalysis) { /* CContext scope = (CContext) subparser.scope; */ /* String name = ((Language<?>) fun.get(0)).getTokenText(); */ /* scope.getSymbolTable().setbool(name, STField.FUNCALL, true, subparser.getPresenceCondition()); */ String name = ((Language<?>) fun.get(0)).getTokenText(); functionTable.setbool(name, STField.FUNCALL, true, subparser.getPresenceCondition()); return; } // TODO do later if (true) { return; } String name = ((Syntax) fun.get(0)).getTokenText(); CContext scope = (CContext) subparser.scope; if (debug) { System.err.println("function call: " + name); } if (enableCheckers) { PresenceCondition funPresenceCond = scope.symbolPresenceCond(name, STField.GLOBAL_FUNDEF).or(scope.symbolPresenceCond(name, STField.STATIC_FUNDEF)); if (null != funPresenceCond && ! funPresenceCond.isFalse()) { PresenceCondition not = funPresenceCond.not(); PresenceCondition andnot = subparser.getPresenceCondition().and(not); not.delRef(); if (! andnot.isFalse()) { PresenceCondition sat = andnot.satOne(); System.err.println("found invalid configuration on function call " + name + " at " + fun.getLocation() + " config " + sat); sat.delRef(); } andnot.delRef(); PresenceCondition and = subparser.getPresenceCondition().and(funPresenceCond); if (and.isFalse()) { System.err.println("found infeasible configuration on function call " + name + " at " + fun.getLocation() + " defined in " + funPresenceCond); } and.delRef(); // update configurations the function is used in scope.getSymbolTable().setbool(name, STField.USED, true, subparser.getPresenceCondition()); } else { if (debug) { System.err.println("checker error: " + name + " not a function in any configuration"); } } funPresenceCond.delRef(); } } public void EnterScope(Subparser subparser) { PresenceConditionManager.PresenceCondition presenceCondition = subparser.getPresenceCondition(); subparser.scope = ((CContext) subparser.scope).enterScope(presenceCondition); } public void ExitScope(Subparser subparser) { PresenceConditionManager.PresenceCondition presenceCondition = subparser.getPresenceCondition(); subparser.scope = ((CContext) subparser.scope).exitScope(presenceCondition); } public void ExitReentrantScope(Subparser subparser) { PresenceConditionManager.PresenceCondition presenceCondition = subparser.getPresenceCondition(); subparser.scope = ((CContext) subparser.scope).exitReentrantScope(presenceCondition); } public void ReenterScope(Subparser subparser) { PresenceConditionManager.PresenceCondition presenceCondition = subparser.getPresenceCondition(); subparser.scope = ((CContext) subparser.scope).reenterScope(presenceCondition); } public void KillReentrantScope(Subparser subparser) { PresenceConditionManager.PresenceCondition presenceCondition = subparser.getPresenceCondition(); subparser.scope = ((CContext) subparser.scope).killReentrantScope(presenceCondition); } /** * Find the identifier or typedef name in a declarator. Assume * the first identifier in the subtree is the var or typedef name. * * @param o The semantic value. * @return The first identifier in the subtree or null if there is * none. */ private static Language getident(Object o) { if (o instanceof Language) { Language token = ((Language) o); if (CTag.IDENTIFIER == token.tag() || CTag.TYPEDEFname == token.tag()) { return token; } else { return null; } } else if (o instanceof Pair) { Pair<?> b = (Pair<?>) o; while (b != Pair.empty()) { Object child = b.head(); if (null != child) { Language ident = getident(child); if (null != ident) { return ident; } } b = b.tail(); } return null; } else if (o instanceof PresenceConditionManager.PresenceCondition) { return null; } else if (o instanceof Error) { return null; } else { Node b = (Node) o; for (int i = 0; i < b.size(); i++) { Object child = b.get(i); if (null != child) { Language ident = getident(child); if (null != ident) { return ident; } } } return null; } } // ---------- Specifiers private static String SPECS = "xtc.lang.cpp.Specifiers"; private static class Specifiers { /** Presence condition. */ public PresenceCondition pc; /** True if there is a type error. */ public boolean error; /** The type-error message. */ public String error_message; /** The flag for whether a tag reference is a declaration. */ public boolean refIsDecl; /** The type, if any. */ public Type type; /** The storage class attribute, if any. */ public Attribute storage; /** The thread-local attribute, if any. */ public Attribute threadlocal; /** The inline attribute, if any. */ public Attribute function; /** Any other attributes. */ public List<Attribute> attributes; // The internal state for tracking type specifiers. public boolean seenSigned; public boolean seenUnsigned; public boolean seenBool; public boolean seenChar; public boolean seenShort; public boolean seenInt; public int longCount; public boolean seenFloat; public boolean seenDouble; public boolean seenComplex; public Specifiers() { } /* public Specifiers(PresenceCondition pc) { */ /* this.pc = pc.addRef(); */ /* } */ public Specifiers(PresenceCondition pc, Specifiers s) { /* this(pc); */ this.error = s.error; this.error_message = s.error_message; this.refIsDecl = s.refIsDecl; this.type = s.type; this.storage = s.storage; this.threadlocal = s.threadlocal; this.function = s.function; this.attributes = s.attributes; this.seenSigned = s.seenSigned; this.seenUnsigned = s.seenUnsigned; this.seenBool = s.seenBool; this.seenChar = s.seenChar; this.seenShort = s.seenShort; this.seenInt = s.seenInt; this.longCount = s.longCount; this.seenFloat = s.seenFloat; this.seenDouble = s.seenDouble; this.seenComplex = s.seenComplex; } /** * Add given specs to this set of specs. Adds in-place and returns * this updated specs object. **/ public Specifiers addSpecs(Specifiers other) { if (other.error) { this.setError(other.error_message); return this; } if (null != other.type) { if (null != this.type) { /* System.err.println("1"); */ this.multipleTypes(); } else { this.type = other.type; } } if (other.seenChar) { if (this.hasType()) { /* System.err.println("2"); */ this.multipleTypes(); } else { this.seenChar = true; } } if (other.seenShort) { if (this.seenBool || this.seenChar || this.seenShort || (0 < this.longCount) || this.seenFloat || this.seenDouble || this.seenComplex || (null != this.type)) { /* System.err.println("3"); */ this.multipleTypes(); } else { this.seenShort = true; } } if (other.seenInt) { if (this.seenBool || this.seenChar || this.seenInt || this.seenFloat || this.seenDouble || this.seenComplex || (null != this.type)) { /* System.err.println("4"); */ this.multipleTypes(); } else { this.seenInt = true; } } for (int i = 0; i < other.longCount; i++) { if (this.seenBool || this.seenChar || this.seenShort || (1 < this.longCount) || this.seenFloat || ((this.seenDouble || this.seenComplex) && (0 < this.longCount)) || (null != this.type)) { /* System.err.println("5"); */ this.multipleTypes(); } else { this.longCount++; } } if (other.seenFloat) { if (this.seenBool || this.seenChar || this.seenShort || this.seenInt || (0 < this.longCount) || this.seenDouble || (null != this.type)) { /* System.err.println("6"); */ this.multipleTypes(); } else { this.seenFloat = true; } } if (other.seenDouble) { if (this.seenBool || this.seenChar || this.seenShort || this.seenInt || (1 < this.longCount) || this.seenFloat || (null != this.type)) { /* System.err.println("7"); */ this.multipleTypes(); } else { this.seenDouble = true; } } if (other.seenSigned) { if (this.seenUnsigned) { this.seenSigned = true; this.setError("both 'signed' and 'unsigned' in declaration specifiers"); } else if (this.seenSigned) { this.setError("duplicate 'signed'"); } else { this.seenSigned = true; } } if (other.seenUnsigned) { if (this.seenSigned) { this.seenUnsigned = true; this.setError("both 'signed' and 'unsigned' in declaration specifiers"); } else if (this.seenUnsigned) { this.setError("duplicate 'unsigned'"); } else { this.seenUnsigned = true; } } if (other.seenBool) { if (this.hasType()) { /* System.err.println("8"); */ this.multipleTypes(); } else { this.seenBool = true; } } if (null != other.storage) { if (null == this.storage) { this.storage = other.storage; } else if (this.storage.equals(other.storage)) { this.setError("duplicate storage class"); } else { this.setError("multiple storage classes in declaration specifiers"); } } return this; } /** * Annotate the specified base type. This method annotates the * specified type with all attributes besides the storage class, * thread-local specifier, and function specifier attributes. * * @param base The base type. * @return The annnotated base type. */ public Type annotateBase(Type base) { return (null != attributes)? base.attribute(attributes) : base; } /** * Get the resulting type. */ public Type getType() { Type type; if (seenBool) { type = BooleanT.TYPE; } else if (seenChar) { if (seenUnsigned) { type = NumberT.U_CHAR; } else if (seenSigned) { type = NumberT.S_CHAR; } else { type = NumberT.CHAR; } } else if (seenShort) { if (seenUnsigned) { type = NumberT.U_SHORT; } else { type = NumberT.SHORT; } } else if (seenFloat) { if (seenComplex) { type = NumberT.FLOAT_COMPLEX; } else { type = NumberT.FLOAT; } } else if (seenDouble) { if (0 < longCount) { if (seenComplex) { type = NumberT.LONG_DOUBLE_COMPLEX; } else { type = NumberT.LONG_DOUBLE; } } else { if (seenComplex) { type = NumberT.DOUBLE_COMPLEX; } else { type = NumberT.DOUBLE; } } } else if (1 == longCount) { if (seenUnsigned) { type = NumberT.U_LONG; } else { type = NumberT.LONG; } } else if (1 < longCount) { if (seenUnsigned) { type = NumberT.U_LONG_LONG; } else { type = NumberT.LONG_LONG; } } else if (seenUnsigned) { type = NumberT.U_INT; } else if (seenSigned) { type = NumberT.S_INT; } else if (seenInt) { type = NumberT.INT; } else { type = C.IMPLICIT; } // Annotate the type. if ((! type.hasError()) && (null != attributes)) { type = type.annotate().attribute(attributes); } return type; } /** Test for previous type. */ protected boolean hasType() { return (seenBool || seenChar || seenShort || seenInt || (0 < longCount) || seenFloat || seenDouble || seenComplex || (null != type)); } /** Report error indicating multiple types. */ protected void multipleTypes() { this.setError("multiple data types in declaration specifiers"); } /** Add the specified attribute. */ protected void add(Attribute att) { if (null == attributes) { attributes = new ArrayList<Attribute>(); attributes.add(att); } else if (! attributes.contains(att)) { attributes.add(att); } } public void setError(String msg) { this.error = true; this.error_message = msg; type = ErrorT.TYPE; if (showErrors) { // showErrors is true System.err.println("error in specifiers: " + msg); } } // Get specs. Gets list of specifiers, checking for type errors. // Also need to hoist conditionals around complete type // specifiers. Is it possible to make a hoisting tree-walker? // Walk tree, when encountering conditional, fork the spec state // and walk both. No need for merge, since there are two // different declarations. } /** * A helper function to get the specifiers of the value of a component * node from the stack. * * @param subparser The reference to the subparser. * @param number The component number. * @return The specifiers for the component. */ private static Specifiers getSpecsAt(Subparser subparser, int component) { Node n = getNodeAt(subparser, component); if (n.hasProperty(SPECS)) { return (Specifiers) n.getProperty(SPECS); } else { Specifiers specs = new Specifiers(); n.setProperty(SPECS, specs); return specs; } } private static void updateSpecs(Subparser subparser, Specifiers new_specs, Object value) { updateSpecs(subparser, null, new_specs, value); } private static void updateSpecs(Subparser subparser, Specifiers specs, Specifiers new_specs, Object value) { if (null == specs) { specs = new_specs; } else { specs = specs.addSpecs(new_specs); } ((CContext) subparser.scope).lastSeenType = specs.getType(); ((Node) value).setProperty(SPECS, specs); } private static Specifiers makeUnionSpec(Subparser subparser, Node tagNode, Node membersNode, Node attrsNode) { Specifiers specs = new Specifiers(); return specs; } private static Specifiers makeStructSpec(Subparser subparser, Node tagNode, Node membersNode, Node attrsNode) { String tag; String name; if (null == tagNode) { // TODO struct tag creation /* tag = table.freshName("tag"); */ tag = "tag(untagged)"; name = tag; } else { // TODO check for conditional here /* tag = ((Syntax) tagNode.get(0)).toLanguage().getTokenText(); */ /* name = SymbolTable.toTagName(tag); */ } // TODO remove this once above code is complete tag = "tag(untagged)"; name = tag; Type type; // TODO struct tag is defined /* if (table.current().isDefinedLocally(name)) { */ /* final Type t = (Type)table.current().lookupLocally(name); */ /* if (! t.isStruct()) { */ /* runtime.error("'" + tag + "' defined as wrong kind of tag", n); */ /* reportPreviousTag(t); */ /* type = ErrorT.TYPE; */ /* return; */ /* } else if (null != t.toTagged().getMembers()) { */ /* runtime.error("redefinition of 'struct " + tag + "'", n); */ /* reportPreviousTag(t); */ /* type = ErrorT.TYPE; */ /* return; */ /* } else if (t.hasAttribute(Constants.ATT_DEFINED)) { */ /* runtime.error("nested redefinition of 'struct " + tag + "'", n); */ /* type = ErrorT.TYPE; */ /* return; */ /* } else { */ /* type = t; */ /* } */ /* } else { */ // TODO checkNotParameter /* checkNotParameter(n, "struct"); */ // Declare the struct so that members can reference it. type = new StructT(tag); /* table.current().define(name, type); */ /* } */ // TODO location /* // Update the location. */ /* type.setLocation(n); */ // TODO struct attributes /* // Update the GCC attributes. */ /* for (Attribute a : toAttributeList(n.getGeneric(0))) { */ /* type.addAttribute(a); */ /* } */ /* for (Attribute a : toAttributeList(n.getGeneric(3))) { */ /* type.addAttribute(a); */ /* } */ // Process the members and update the struct declaration. Use // defined attribute to protect against nested redefinition. type.addAttribute(Constants.ATT_DEFINED); // TODO struct members /* List<VariableT> members = processMembers(n.getGeneric(2), true); */ List<VariableT> members = null; type.toStruct().setMembers(members); type.removeAttribute(Constants.ATT_DEFINED); Specifiers specs = new Specifiers(); specs.type = type; return specs; } /** * Check that the tag declaration is not located within a * parameter list. If the declaration is located within a * parameter list, this method prints the appropriate warning. * * @param node The node. * @param kind The kind of tag. */ private void checkNotParameter(Node node, String kind) { // TODO checkNotParameter implementation /* if (TMP_SCOPE.equals(table.current().getName())) { */ /* final String tag = node.getString(1); */ /* final String msg; */ /* if (null == tag) { */ /* msg = "anonymous " + kind + " declared inside parameter list"; */ /* } else { */ /* msg = "'" + kind + " " + tag + "' declared inside parameter list"; */ /* } */ /* runtime.warning(msg, node); */ /* } */ } // ---------- Declarators /* private static String DECL = "xtc.lang.cpp.Declarator"; */ /* private static String NAME = "xtc.lang.cpp.Name"; */ /* private static void setDecl(Object n, Type type) { */ /* ((Node) n).setProperty(DECL, type); */ /* } */ /* private static Type getDecl(Object n) { */ /* return ((Type) ((Node) n).getProperty(DECL)); */ /* } */ /* private static void setName(Object n, String name) { */ /* ((Node) n).setProperty(NAME, name); */ /* } */ /* private static String getName(Object n) { */ /* return ((String) ((Node) n).getProperty(NAME)); */ /* } */ /* private static void setDecl(Object n, Type type, String name) { */ /* setDecl(n, type); */ /* setName(n, name); */ /* } */ /* private static void copyDecl(Subparser subparser, Object value, int from) { */ /* setDecl(value, (Type) (getNodeAt(subparser, from).getProperty(DECL))); */ /* } */ /* private static void copyName(Subparser subparser, Object value, int from) { */ /* setName(value, (String) (getNodeAt(subparser, from).getProperty(NAME))); */ /* } */ /* private static void copyDeclName(Subparser subparser, Object value, int from){ */ /* copyDecl(subparser, value, from); */ /* copyName(subparser, value, from); */ /* } */ }