0001: /*
0002: * xtc - The eXTensible Compiler
0003: * Copyright (C) 2005-2007 Robert Grimm
0004: *
0005: * This program is free software; you can redistribute it and/or
0006: * modify it under the terms of the GNU General Public License
0007: * version 2 as published by the Free Software Foundation.
0008: *
0009: * This program is distributed in the hope that it will be useful,
0010: * but WITHOUT ANY WARRANTY; without even the implied warranty of
0011: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
0012: * GNU General Public License for more details.
0013: *
0014: * You should have received a copy of the GNU General Public License
0015: * along with this program; if not, write to the Free Software
0016: * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
0017: * USA.
0018: */
0019: package xtc.lang;
0020:
0021: import java.math.BigInteger;
0022:
0023: import java.util.ArrayList;
0024: import java.util.Collections;
0025: import java.util.HashSet;
0026: import java.util.IdentityHashMap;
0027: import java.util.Iterator;
0028: import java.util.List;
0029: import java.util.Map;
0030: import java.util.Set;
0031:
0032: import xtc.Constants;
0033: import xtc.Limits;
0034:
0035: import xtc.tree.Attribute;
0036: import xtc.tree.GNode;
0037: import xtc.tree.Node;
0038: import xtc.tree.Token;
0039: import xtc.tree.Visitor;
0040:
0041: import xtc.type.AliasT;
0042: import xtc.type.ArrayT;
0043: import xtc.type.BooleanT;
0044: import xtc.type.C;
0045: import xtc.type.CastReference;
0046: import xtc.type.Constant;
0047: import xtc.type.DynamicReference;
0048: import xtc.type.EnumT;
0049: import xtc.type.EnumeratorT;
0050: import xtc.type.ErrorT;
0051: import xtc.type.FieldReference;
0052: import xtc.type.FunctionT;
0053: import xtc.type.InternalT;
0054: import xtc.type.LabelT;
0055: import xtc.type.NullReference;
0056: import xtc.type.NumberT;
0057: import xtc.type.PointerT;
0058: import xtc.type.Reference;
0059: import xtc.type.StaticReference;
0060: import xtc.type.StringReference;
0061: import xtc.type.StructOrUnionT;
0062: import xtc.type.StructT;
0063: import xtc.type.Tagged;
0064: import xtc.type.Type;
0065: import xtc.type.Type.Tag;
0066: import xtc.type.UnionT;
0067: import xtc.type.VariableT;
0068: import xtc.type.VoidT;
0069:
0070: import xtc.util.SymbolTable;
0071: import xtc.util.SymbolTable.Scope;
0072: import xtc.util.Runtime;
0073: import xtc.util.SingletonIterator;
0074: import xtc.util.Utilities;
0075:
0076: /**
0077: * A visitor to type check C programs.
0078: *
0079: * @author Robert Grimm
0080: * @version $Revision: 1.197 $
0081: */
0082: public class CAnalyzer extends Visitor {
0083:
0084: /**
0085: * The semantic information contained in a sequence of declaration
0086: * specifiers.
0087: */
0088: public class Specifiers extends Visitor {
0089:
0090: /** The declaration specifiers. */
0091: protected GNode specifiers;
0092:
0093: /** The flag for whether a tag reference is a declaration. */
0094: protected boolean refIsDecl;
0095:
0096: /** The type, if any. */
0097: protected Type type;
0098:
0099: /** The storage class attribute, if any. */
0100: private Attribute storage;
0101:
0102: /** The inline attribute, if any. */
0103: private Attribute function;
0104:
0105: /** Any other attributes. */
0106: private List<Attribute> attributes;
0107:
0108: // The internal state for tracking type specifiers.
0109: private boolean seenSigned;
0110: private boolean seenUnsigned;
0111: private boolean seenBool;
0112: private boolean seenChar;
0113: private boolean seenShort;
0114: private boolean seenInt;
0115: private int longCount;
0116: private boolean seenFloat;
0117: private boolean seenDouble;
0118: private boolean seenComplex;
0119:
0120: /**
0121: * Create a new sequence of specifiers. This constructor analyzes
0122: * the specified AST node and may print error messages as a
0123: * result.
0124: *
0125: * @param specifiers The node holding the declaration specifiers
0126: * (which may be <code>null</code>).
0127: * @param refIsDecl The flag for whether a struct/union reference
0128: * also is a struct/union declaration.
0129: */
0130: public Specifiers(GNode specifiers, boolean refIsDecl) {
0131: // Remember the arguments.
0132: this .specifiers = specifiers;
0133: this .refIsDecl = refIsDecl;
0134:
0135: // Process the individual specifiers.
0136: if (null != specifiers) {
0137: for (Object o : specifiers)
0138: dispatch((Node) o);
0139: }
0140:
0141: // Fill in the resulting type.
0142: if (null != type) {
0143: // Nothing to do.
0144:
0145: } else if (seenBool) {
0146: type = BooleanT.TYPE;
0147: } else if (seenChar) {
0148: if (seenUnsigned) {
0149: type = NumberT.U_CHAR;
0150: } else if (seenSigned) {
0151: type = NumberT.S_CHAR;
0152: } else {
0153: type = NumberT.CHAR;
0154: }
0155: } else if (seenShort) {
0156: if (seenUnsigned) {
0157: type = NumberT.U_SHORT;
0158: } else {
0159: type = NumberT.SHORT;
0160: }
0161: } else if (seenFloat) {
0162: if (seenComplex) {
0163: type = NumberT.FLOAT_COMPLEX;
0164: } else {
0165: type = NumberT.FLOAT;
0166: }
0167: } else if (seenDouble) {
0168: if (0 < longCount) {
0169: if (seenComplex) {
0170: type = NumberT.LONG_DOUBLE_COMPLEX;
0171: } else {
0172: type = NumberT.LONG_DOUBLE;
0173: }
0174: } else {
0175: if (seenComplex) {
0176: type = NumberT.DOUBLE_COMPLEX;
0177: } else {
0178: type = NumberT.DOUBLE;
0179: }
0180: }
0181: } else if (1 == longCount) {
0182: if (seenUnsigned) {
0183: type = NumberT.U_LONG;
0184: } else {
0185: type = NumberT.LONG;
0186: }
0187: } else if (1 < longCount) {
0188: if (seenUnsigned) {
0189: type = NumberT.U_LONG_LONG;
0190: } else {
0191: type = NumberT.LONG_LONG;
0192: }
0193: } else if (seenUnsigned) {
0194: type = NumberT.U_INT;
0195: } else if (seenSigned) {
0196: type = NumberT.S_INT;
0197: } else if (seenInt) {
0198: type = NumberT.INT;
0199: } else {
0200: type = C.IMPLICIT;
0201: }
0202:
0203: // Annotate the type.
0204: if ((!type.hasError()) && (null != attributes)) {
0205: type = type.annotate().attribute(attributes);
0206: }
0207:
0208: // Seal the type.
0209: type.seal();
0210: }
0211:
0212: /**
0213: * Get the base type. The base type has been annotated with all
0214: * attributes besides the storage class and function specifier
0215: * attributes.
0216: *
0217: * @return The base type.
0218: */
0219: public Type getBaseType() {
0220: return type;
0221: }
0222:
0223: /**
0224: * Determine whether the base type is the default type.
0225: *
0226: * @return <code>true</code> if the base type is the default type.
0227: */
0228: public boolean isDefault() {
0229: return type.hasTag(Tag.INTEGER)
0230: && type.resolve().hasAttribute(
0231: Constants.ATT_IMPLICIT);
0232: }
0233:
0234: /**
0235: * Determine whether the specifiers contain the specified
0236: * attribute.
0237: *
0238: * @param att The attribute.
0239: * @return <code>true</code> if the specifiers contain the
0240: * specified attribute.
0241: */
0242: public boolean contains(Attribute att) {
0243: if ((null != attributes) && attributes.contains(att))
0244: return true;
0245: if (att.equals(storage))
0246: return true;
0247: return att.equals(function);
0248: }
0249:
0250: /**
0251: * Determine whether the specifiers include any attributes besides
0252: * a function specifier and storage class.
0253: *
0254: * @return <code>true</code> if the specifiers include any
0255: * attributes besides a function specifier and storage class.
0256: */
0257: public boolean hasBaseAttributes() {
0258: return null != attributes;
0259: }
0260:
0261: /**
0262: * Determine whether the specifiers include a function specifier.
0263: *
0264: * @return <code>true</code> if the specifiers include a function
0265: * specifier.
0266: */
0267: public boolean hasInline() {
0268: return null != function;
0269: }
0270:
0271: /**
0272: * Get the storage class.
0273: *
0274: * @return The storage class or <code>null</code> if the
0275: * specifiers do contain one.
0276: */
0277: public Attribute getStorageClass() {
0278: return storage;
0279: }
0280:
0281: /**
0282: * Annotate the specified base type. This method annotates the
0283: * specified type with all attributes besides the storage class
0284: * and function specifier attributes.
0285: *
0286: * @param base The base type.
0287: * @return The annnotated base type.
0288: */
0289: public Type annotateBase(Type base) {
0290: return (null != attributes) ? base.attribute(attributes)
0291: : base;
0292: }
0293:
0294: /**
0295: * Annotate the specified full type. This method annotates the
0296: * specified type with any storage class and function specifier
0297: * attributes.
0298: *
0299: * @param full The full type.
0300: * @return The annotated full type.
0301: */
0302: public Type annotateFull(Type full) {
0303: // If the full type is the same type as the base type, wrap the
0304: // type with an annotated pseudo-type to prevent changes to the
0305: // base type across several declarations.
0306: if ((null != storage) || (null != function)) {
0307: if (type == full)
0308: full = full.annotate();
0309: if (null != storage)
0310: full = full.attribute(storage);
0311: if (null != function)
0312: full = full.attribute(function);
0313: }
0314: return full;
0315: }
0316:
0317: /** Add the specified attribute. */
0318: protected void add(Attribute att) {
0319: if (null == attributes) {
0320: attributes = new ArrayList<Attribute>();
0321: attributes.add(att);
0322: } else if (!attributes.contains(att)) {
0323: attributes.add(att);
0324: }
0325: }
0326:
0327: /** Test for previous storage class specifier and report error. */
0328: protected boolean testStorageClass() {
0329: if (null == storage) {
0330: return false;
0331: } else {
0332: runtime
0333: .error(
0334: "multiple storage classes in declaration specifiers",
0335: specifiers);
0336: return true;
0337: }
0338: }
0339:
0340: /** Test for previous type. */
0341: protected boolean hasType() {
0342: return (seenBool || seenChar || seenShort || seenInt
0343: || (0 < longCount) || seenFloat || seenDouble
0344: || seenComplex || (null != type));
0345: }
0346:
0347: /** Report error indicating multiple types. */
0348: protected void multipleTypes() {
0349: runtime.error(
0350: "multiple data types in declaration specifiers",
0351: specifiers);
0352: type = ErrorT.TYPE;
0353: }
0354:
0355: /** Process the auto specifier. */
0356: public void visitAutoSpecifier(GNode n) {
0357: if (Constants.ATT_STORAGE_AUTO.equals(storage)) {
0358: runtime.error("duplicate 'auto'", n);
0359: } else if (!testStorageClass()) {
0360: storage = Constants.ATT_STORAGE_AUTO;
0361: }
0362: }
0363:
0364: /** Process the extern specifier. */
0365: public void visitExternSpecifier(GNode n) {
0366: if (Constants.ATT_STORAGE_EXTERN.equals(storage)) {
0367: runtime.error("duplicate 'extern'", n);
0368: } else if (!testStorageClass()) {
0369: storage = Constants.ATT_STORAGE_EXTERN;
0370: }
0371: }
0372:
0373: /** Process the register specifier. */
0374: public void visitRegisterSpecifier(GNode n) {
0375: if (Constants.ATT_STORAGE_REGISTER.equals(storage)) {
0376: runtime.error("duplicate 'register'", n);
0377: } else if (!testStorageClass()) {
0378: storage = Constants.ATT_STORAGE_REGISTER;
0379: }
0380: }
0381:
0382: /** Process the static specifier. */
0383: public void visitStaticSpecifier(GNode n) {
0384: if (Constants.ATT_STORAGE_STATIC.equals(storage)) {
0385: runtime.error("duplicate 'static'", n);
0386: } else if (!testStorageClass()) {
0387: storage = Constants.ATT_STORAGE_STATIC;
0388: }
0389: }
0390:
0391: /** Process the typedef specifier. */
0392: public void visitTypedefSpecifier(GNode n) {
0393: if (Constants.ATT_STORAGE_TYPEDEF.equals(storage)) {
0394: runtime.error("duplicate 'typedef'", n);
0395: } else if (!testStorageClass()) {
0396: storage = Constants.ATT_STORAGE_TYPEDEF;
0397: }
0398: }
0399:
0400: /** Process the typeof specifier. */
0401: public void visitTypeofSpecifier(GNode n) {
0402: if (hasType()) {
0403: multipleTypes();
0404: } else {
0405: type = processExpression(n.getNode(0));
0406:
0407: // Strip any annotations from the type, but do keep the
0408: // qualifiers.
0409: if (type.hasEnum()) {
0410: type = c().qualify(type.toEnum(), type);
0411: } else {
0412: type = c().qualify(type.resolve(), type);
0413: }
0414: }
0415: }
0416:
0417: /** Process the volatile qualifier. */
0418: public void visitVolatileQualifier(GNode n) {
0419: add(Constants.ATT_VOLATILE);
0420: }
0421:
0422: /** Process the constant qualifier. */
0423: public void visitConstantQualifier(GNode n) {
0424: add(Constants.ATT_CONSTANT);
0425: }
0426:
0427: /** Process the restrict qualifier. */
0428: public void visitRestrictQualifier(GNode n) {
0429: add(Constants.ATT_RESTRICT);
0430: }
0431:
0432: /** Process the function specifier. */
0433: public void visitFunctionSpecifier(GNode n) {
0434: if (null == function) {
0435: function = Constants.ATT_INLINE;
0436: }
0437: }
0438:
0439: /** Process the signed type specifier. */
0440: public void visitSigned(GNode n) {
0441: if (seenUnsigned) {
0442: seenSigned = true;
0443: runtime.error(
0444: "both 'signed' and 'unsigned' in declaration "
0445: + "specifiers", specifiers);
0446: } else if (seenSigned) {
0447: runtime.error("duplicate 'signed'", n);
0448: } else {
0449: seenSigned = true;
0450: }
0451: }
0452:
0453: /** Process the unsigned type specifier. */
0454: public void visitUnsigned(GNode n) {
0455: if (seenSigned) {
0456: seenUnsigned = true;
0457: runtime.error(
0458: "both 'signed' and 'unsigned' in declaration "
0459: + "specifiers", specifiers);
0460: } else if (seenUnsigned) {
0461: runtime.error("duplicate 'unsigned'", n);
0462: } else {
0463: seenUnsigned = true;
0464: }
0465: }
0466:
0467: /** Process the boolean type specifier. */
0468: public void visitBool(GNode n) {
0469: if (hasType()) {
0470: multipleTypes();
0471: } else {
0472: seenBool = true;
0473: }
0474: }
0475:
0476: /** Process the char type specifier. */
0477: public void visitChar(GNode n) {
0478: if (hasType()) {
0479: multipleTypes();
0480: } else {
0481: seenChar = true;
0482: }
0483: }
0484:
0485: /** Process the short specifier. */
0486: public void visitShort(GNode n) {
0487: if (seenBool || seenChar || seenShort || (0 < longCount)
0488: || seenFloat || seenDouble || seenComplex
0489: || (null != type)) {
0490: multipleTypes();
0491: } else {
0492: seenShort = true;
0493: }
0494: }
0495:
0496: /** Process the int type specifier. */
0497: public void visitInt(GNode n) {
0498: if (seenBool || seenChar || seenInt || seenFloat
0499: || seenDouble || seenComplex || (null != type)) {
0500: multipleTypes();
0501: } else {
0502: seenInt = true;
0503: }
0504: }
0505:
0506: /** Process the long type specifier. */
0507: public void visitLong(GNode n) {
0508: if (seenBool || seenChar || seenShort || (1 < longCount)
0509: || seenFloat
0510: || ((seenDouble || seenComplex) && (0 < longCount))
0511: || (null != type)) {
0512: multipleTypes();
0513: } else {
0514: longCount++;
0515: }
0516: }
0517:
0518: /** Process the float type specifier. */
0519: public void visitFloat(GNode n) {
0520: if (seenBool || seenChar || seenShort || seenInt
0521: || (0 < longCount) || seenDouble || (null != type)) {
0522: multipleTypes();
0523: } else {
0524: seenFloat = true;
0525: }
0526: }
0527:
0528: /** Process the double type specifier. */
0529: public void visitDouble(GNode n) {
0530: if (seenBool || seenChar || seenShort || seenInt
0531: || (1 < longCount) || seenFloat || (null != type)) {
0532: multipleTypes();
0533: } else {
0534: seenDouble = true;
0535: }
0536: }
0537:
0538: /** Process the complex type specifier. */
0539: public void visitComplex(GNode n) {
0540: if (seenBool || seenChar || seenShort || seenInt
0541: || (1 < longCount) || (null != type)) {
0542: multipleTypes();
0543: } else {
0544: seenComplex = true;
0545: }
0546: }
0547:
0548: /**
0549: * Check that the tag declaration is not located within a
0550: * parameter list. If the declaration is located within a
0551: * parameter list, this method prints the appropriate warning.
0552: *
0553: * @param node The node.
0554: * @param kind The kind of tag.
0555: */
0556: private void checkNotParameter(Node node, String kind) {
0557: if (TMP_SCOPE.equals(table.current().getName())) {
0558: final String tag = node.getString(1);
0559: final String msg;
0560: if (null == tag) {
0561: msg = "anonymous " + kind
0562: + " declared inside parameter list";
0563: } else {
0564: msg = "'" + kind + " " + tag
0565: + "' declared inside parameter list";
0566: }
0567:
0568: runtime.warning(msg, node);
0569: }
0570: }
0571:
0572: /**
0573: * Process the structure declaration list. Note that this
0574: * method assumes that the current symbol table scope is the
0575: * corresponding struct's or union's scope.
0576: */
0577: private List<VariableT> processMembers(GNode declarationList,
0578: boolean isStruct) {
0579: final int size = declarationList.size() - 1;
0580: List<VariableT> members = new ArrayList<VariableT>(size);
0581: HashSet<String> names = new HashSet<String>();
0582: int count = 0;
0583: for (int i = 0; i < size; i++) {
0584: final GNode declaration = declarationList.getGeneric(i);
0585: final GNode specifiers = declaration.getGeneric(1);
0586: final Specifiers spec = newSpecifiers(specifiers, false);
0587:
0588: if (null == declaration.get(2)) {
0589: // We expect an unnamed struct/union member.
0590: final Type type = spec.annotateFull(spec
0591: .getBaseType());
0592:
0593: if (type.hasStructOrUnion()
0594: && type.toTagged().isUnnamed() && !pedantic) {
0595: // Check for incomplete types (C99 6.7.2.1).
0596: if (c().isIncomplete(type)) {
0597: final String kind = type.hasTag(Tag.STRUCT) ? "struct"
0598: : "union";
0599: runtime.error("unnamed " + kind
0600: + " has incomplete type",
0601: declaration);
0602: } else if (c().hasTrailingArray(type)) {
0603: runtime
0604: .error(
0605: "unnamed struct ends with flexible array member",
0606: declaration);
0607: }
0608: members.add(VariableT.newField(type, null));
0609:
0610: } else {
0611: runtime
0612: .warning(
0613: "declaration does not declare anything",
0614: declaration);
0615: }
0616:
0617: } else {
0618: Iterator<Object> iter = declaration.getGeneric(2)
0619: .iterator();
0620: while (iter.hasNext()) {
0621: GNode declarator = GNode.cast(iter.next());
0622: final GNode original = declarator;
0623:
0624: final boolean isBitField = declarator
0625: .hasName("BitField");
0626: GNode widthExpr = null;
0627: int width = -1;
0628: if (isBitField) {
0629: widthExpr = declarator.getGeneric(2);
0630: declarator = declarator.getGeneric(1);
0631: }
0632:
0633: final GNode identifier = getDeclaredId(declarator);
0634: String name = null;
0635: if (null != identifier) {
0636: count++;
0637: name = identifier.getString(0);
0638: }
0639: Type type = getDeclaredType(spec.getBaseType(),
0640: declarator);
0641: type = spec.annotateFull(type);
0642:
0643: if (isBitField) {
0644: final Type resolved = type.resolve();
0645: final NumberT.Kind kind = resolved
0646: .isInteger() ? resolved.toInteger()
0647: .getKind() : null;
0648:
0649: // Make sure the base type is valid. Consistent with
0650: // GCC, we allow any integer type, not just __Bool,
0651: // (signed) int, and unsigned int (unless, of course, we
0652: // are running in pedantic mode).
0653: if ((!resolved.isBoolean())
0654: && ((!resolved.isInteger()) || (resolved
0655: .isInteger()
0656: && pedantic
0657: && (!NumberT.equal(
0658: NumberT.Kind.INT,
0659: kind)) && (!NumberT
0660: .equal(NumberT.Kind.U_INT,
0661: kind))))) {
0662: if (null == identifier) {
0663: runtime
0664: .error(
0665: "bit-field has invalid type",
0666: original);
0667: } else {
0668: runtime.error("bit-field '" + name
0669: + "' has invalid type",
0670: original);
0671: }
0672: }
0673:
0674: // Process the width expression.
0675: final Type widthType = processExpression(widthExpr);
0676:
0677: if (widthType.hasError()) {
0678: // Ignore to avoid cascading error messages
0679: // but patch in width.
0680: width = 0;
0681:
0682: } else if ((!widthType.hasConstant())
0683: || (!c().isIntegral(widthType))) {
0684: if (null == identifier) {
0685: runtime
0686: .error(
0687: "bit-field width not an integer constant",
0688: widthExpr);
0689: } else {
0690: runtime
0691: .error(
0692: "bit-field '"
0693: + name
0694: + "' width not an integer constant",
0695: widthExpr);
0696: }
0697: // Patch in width.
0698: width = 0;
0699:
0700: } else if (c().isIntegral(resolved)) {
0701: final int typeWidth = (int) c()
0702: .getWidth(resolved);
0703:
0704: BigInteger widthValue;
0705: try {
0706: widthValue = widthType
0707: .getConstant()
0708: .bigIntValue();
0709: } catch (IllegalStateException x) {
0710: if (null == identifier) {
0711: runtime
0712: .error(
0713: "can't compute width in bit-field",
0714: widthExpr);
0715: } else {
0716: runtime.error(
0717: "can't compute width in bit-field '"
0718: + name + "'",
0719: widthExpr);
0720: }
0721: widthValue = BigInteger.ZERO;
0722: }
0723:
0724: // Test: widthValue > typeWidth
0725: if (widthValue.compareTo(BigInteger
0726: .valueOf(typeWidth)) > 0) {
0727: if (null == identifier) {
0728: runtime
0729: .error(
0730: "bit-field width exceeds its type",
0731: widthExpr);
0732: } else {
0733: runtime
0734: .error(
0735: "bit-field '"
0736: + name
0737: + "' width exceeds its type",
0738: widthExpr);
0739: }
0740: // Patch in width.
0741: width = typeWidth;
0742:
0743: // Test: widthValue < 0
0744: } else if (widthValue
0745: .compareTo(BigInteger.ZERO) < 0) {
0746: if (null == identifier) {
0747: runtime
0748: .error(
0749: "negative width in bit-field",
0750: widthExpr);
0751: } else {
0752: runtime.error(
0753: "negative width in bit-field '"
0754: + name + "'",
0755: widthExpr);
0756: }
0757: // Patch in width.
0758: width = 0;
0759:
0760: } else {
0761: // Use specified value.
0762: width = widthValue.intValue();
0763: }
0764:
0765: } else {
0766: // Width does not matter b/c the base type is invalid.
0767: width = 0;
0768: }
0769:
0770: } else {
0771: // Enforce constraints on incomplete types (C99 6.7.2.1)
0772: // and on fields not being functions.
0773: final Type resolved = type.resolve();
0774:
0775: if (!checkType(declaration, name, type)) {
0776: // Error has already been reported.
0777:
0778: } else if (resolved.isFunction()) {
0779: runtime.error("field '" + name
0780: + "' declared as a function",
0781: declaration);
0782:
0783: } else if (resolved.isArray()) {
0784: ArrayT array = resolved.toArray();
0785:
0786: if (c().isIncomplete(array.getType())
0787: || c().hasTrailingArray(
0788: array.getType())) {
0789: runtime
0790: .error(
0791: "field '"
0792: + name
0793: + "' has array with incomplete element type",
0794: declaration);
0795:
0796: } else if (array.isVarLength()) {
0797: // GCC allows variable length arrays in structs and
0798: // unions outside external declarations.
0799: if (pedantic) {
0800: runtime
0801: .error(
0802: "field '"
0803: + name
0804: + "' has variable length "
0805: + "array type",
0806: declaration);
0807: } else if (isTopLevel
0808: && (!TMP_SCOPE.equals(table
0809: .current()
0810: .getName()))) {
0811: runtime
0812: .error(
0813: "variable length array type declared "
0814: + "outside of any function",
0815: declaration);
0816: }
0817:
0818: } else if (!array.hasLength()) {
0819: if (!isStruct) {
0820: runtime.error(
0821: "flexible array member '"
0822: + name
0823: + "' in union",
0824: declaration);
0825: } else if ((i < size - 1)
0826: || iter.hasNext()) {
0827: runtime
0828: .error(
0829: "flexible array member '"
0830: + name
0831: + "' not at end of struct",
0832: declaration);
0833: } else if (1 >= count) {
0834: runtime
0835: .error(
0836: "flexible array member '"
0837: + name
0838: + "' in otherwise empty struct",
0839: declaration);
0840: }
0841: }
0842:
0843: } else if (c().isIncomplete(type)) {
0844: if (resolved.isVoid()) {
0845: runtime.error("field '" + name
0846: + "' declared void",
0847: declaration);
0848: } else {
0849: runtime.error("field '" + name
0850: + "' has incomplete type",
0851: declaration);
0852: }
0853: } else if (c().hasTrailingArray(type)) {
0854: // GCC allows struct fileds with flexible array
0855: // members.
0856: if (pedantic) {
0857: runtime
0858: .error(
0859: "field '"
0860: + name
0861: + "' has struct with flexible array member",
0862: declaration);
0863: }
0864: } else if (c().isVariablyModified(type)) {
0865: // GCC allows variably modified types in structs and
0866: // unions outside external declarations.
0867: if (pedantic) {
0868: runtime
0869: .error(
0870: "field '"
0871: + name
0872: + "' has variably modified "
0873: + "type",
0874: declaration);
0875: } else if (isTopLevel
0876: && (!TMP_SCOPE.equals(table
0877: .current().getName()))) {
0878: runtime
0879: .error(
0880: "variably modified type declared "
0881: + "outside of any function",
0882: declaration);
0883: }
0884: }
0885: }
0886:
0887: if (names.contains(name)) {
0888: runtime.error("duplicate member '" + name
0889: + "'", original);
0890: } else {
0891: if (null != name)
0892: names.add(name);
0893: if (-1 == width) {
0894: members.add(VariableT.newField(type,
0895: name));
0896: } else {
0897: members.add(VariableT.newBitfield(type,
0898: name, width));
0899: }
0900: }
0901: }
0902: }
0903: }
0904:
0905: return members;
0906: }
0907:
0908: /** Process the structure type definition. */
0909: public void visitStructureTypeDefinition(GNode n) {
0910: if (hasType()) {
0911: multipleTypes();
0912: } else {
0913: String tag = n.getString(1);
0914: String name;
0915: if (null == tag) {
0916: tag = table.freshName("tag");
0917: name = tag;
0918: } else {
0919: name = SymbolTable.toTagName(tag);
0920: }
0921:
0922: if (table.current().isDefinedLocally(name)) {
0923: final Type t = (Type) table.current()
0924: .lookupLocally(name);
0925:
0926: if (!t.isStruct()) {
0927: runtime.error("'" + tag
0928: + "' defined as wrong kind of tag", n);
0929: reportPreviousTag(t);
0930: type = ErrorT.TYPE;
0931: return;
0932:
0933: } else if (null != t.toTagged().getMembers()) {
0934: runtime.error("redefinition of 'struct " + tag
0935: + "'", n);
0936: reportPreviousTag(t);
0937: type = ErrorT.TYPE;
0938: return;
0939:
0940: } else if (t.hasAttribute(Constants.ATT_DEFINED)) {
0941: runtime.error("nested redefinition of 'struct "
0942: + tag + "'", n);
0943: type = ErrorT.TYPE;
0944: return;
0945:
0946: } else {
0947: type = t;
0948: }
0949: } else {
0950: checkNotParameter(n, "struct");
0951:
0952: // Declare the struct so that members can reference it.
0953: type = new StructT(tag);
0954: table.current().define(name, type);
0955: }
0956:
0957: // Update the location.
0958: type.setLocation(n);
0959:
0960: // Update the GCC attributes.
0961: for (Attribute a : toAttributeList(n.getGeneric(0))) {
0962: type.addAttribute(a);
0963: }
0964: for (Attribute a : toAttributeList(n.getGeneric(3))) {
0965: type.addAttribute(a);
0966: }
0967:
0968: // Process the members and update the struct declaration. Use
0969: // defined attribute to protect against nested redefinition.
0970: type.addAttribute(Constants.ATT_DEFINED);
0971: List<VariableT> members = processMembers(n
0972: .getGeneric(2), true);
0973: type.toStruct().setMembers(members);
0974: type.removeAttribute(Constants.ATT_DEFINED);
0975:
0976: // Seal the struct.
0977: type.seal();
0978: }
0979: }
0980:
0981: /** Process the structure type reference. */
0982: public void visitStructureTypeReference(GNode n) {
0983: if (hasType()) {
0984: multipleTypes();
0985: } else {
0986: final String tag = n.getString(1);
0987: final String name = SymbolTable.toTagName(tag);
0988:
0989: if ((refIsDecl && table.current()
0990: .isDefinedLocally(name))
0991: || ((!refIsDecl) && table.isDefined(name))) {
0992: final Type t = (Type) table.lookup(name);
0993:
0994: if (!t.isStruct()) {
0995: runtime.error("'" + tag
0996: + "' defined as wrong kind of tag", n);
0997: reportPreviousTag(t);
0998: type = ErrorT.TYPE;
0999: } else {
1000: type = t;
1001:
1002: // If the struct has not yet been defined, update the
1003: // location and GCC attributes.
1004: if (refIsDecl
1005: && (null == type.toStruct()
1006: .getMembers())) {
1007: type.setLocation(n);
1008: for (Attribute a : toAttributeList(n
1009: .getGeneric(0))) {
1010: type.addAttribute(a);
1011: }
1012: }
1013: }
1014: } else {
1015: checkNotParameter(n, "struct");
1016:
1017: type = new StructT(tag).locate(n);
1018: for (Attribute a : toAttributeList(n.getGeneric(0))) {
1019: type.addAttribute(a);
1020: }
1021: table.current().define(name, type);
1022: }
1023: }
1024: }
1025:
1026: /** Process the union type definition. */
1027: public void visitUnionTypeDefinition(GNode n) {
1028: if (hasType()) {
1029: multipleTypes();
1030: } else {
1031: String tag = n.getString(1);
1032: String name;
1033: if (null == tag) {
1034: tag = table.freshName("tag");
1035: name = tag;
1036: } else {
1037: name = SymbolTable.toTagName(tag);
1038: }
1039:
1040: if (table.current().isDefinedLocally(name)) {
1041: final Type t = (Type) table.current()
1042: .lookupLocally(name);
1043:
1044: if (!t.isUnion()) {
1045: runtime.error("'" + tag
1046: + "' defined as wrong kind of tag", n);
1047: reportPreviousTag(t);
1048: type = ErrorT.TYPE;
1049: return;
1050:
1051: } else if (null != t.toTagged().getMembers()) {
1052: runtime.error("redefinition of 'union " + tag
1053: + "'", n);
1054: reportPreviousTag(t);
1055: type = ErrorT.TYPE;
1056: return;
1057:
1058: } else if (t.hasAttribute(Constants.ATT_DEFINED)) {
1059: runtime.error("nested redefinition of 'union "
1060: + tag + "'", n);
1061: type = ErrorT.TYPE;
1062: return;
1063:
1064: } else {
1065: type = t;
1066: }
1067: } else {
1068: checkNotParameter(n, "union");
1069:
1070: // Declare the union so that members can reference it.
1071: type = new UnionT(tag);
1072: table.current().define(name, type);
1073: }
1074:
1075: // Update the location.
1076: type.setLocation(n);
1077:
1078: // Update the GCC attributes.
1079: for (Attribute a : toAttributeList(n.getGeneric(0))) {
1080: type.addAttribute(a);
1081: }
1082: for (Attribute a : toAttributeList(n.getGeneric(3))) {
1083: type.addAttribute(a);
1084: }
1085:
1086: // Process the members and update the union declaration. Use
1087: // defined attribute to protected against nested redefinition.
1088: type.addAttribute(Constants.ATT_DEFINED);
1089: List<VariableT> members = processMembers(n
1090: .getGeneric(2), false);
1091: type.toUnion().setMembers(members);
1092: type.removeAttribute(Constants.ATT_DEFINED);
1093:
1094: // Seal the union.
1095: type.seal();
1096: }
1097: }
1098:
1099: /** Process the union type reference. */
1100: public void visitUnionTypeReference(GNode n) {
1101: if (hasType()) {
1102: multipleTypes();
1103: } else {
1104: final String tag = n.getString(1);
1105: final String name = SymbolTable.toTagName(tag);
1106:
1107: if ((refIsDecl && table.current()
1108: .isDefinedLocally(name))
1109: || ((!refIsDecl) && table.isDefined(name))) {
1110: final Type t = (Type) table.lookup(name);
1111:
1112: if (!t.isUnion()) {
1113: runtime.error("'" + tag
1114: + "' defined as wrong kind of tag", n);
1115: reportPreviousTag(t);
1116: type = ErrorT.TYPE;
1117: } else {
1118: type = t;
1119:
1120: // If the union has not yet been defined, update the
1121: // location and GCC attributes.
1122: if (refIsDecl
1123: && (null == type.toUnion().getMembers())) {
1124: type.setLocation(n);
1125: for (Attribute a : toAttributeList(n
1126: .getGeneric(0))) {
1127: type.addAttribute(a);
1128: }
1129: }
1130: }
1131: } else {
1132: checkNotParameter(n, "union");
1133:
1134: type = new UnionT(tag).locate(n);
1135: for (Attribute a : toAttributeList(n.getGeneric(0))) {
1136: type.addAttribute(a);
1137: }
1138: table.current().define(name, type);
1139: }
1140: }
1141: }
1142:
1143: /** Process the enumeration type definition. */
1144: public void visitEnumerationTypeDefinition(GNode n) {
1145: if (hasType()) {
1146: multipleTypes();
1147: } else {
1148: String tag = n.getString(1);
1149: String name;
1150: if (null == tag) {
1151: tag = table.freshName("tag");
1152: name = tag;
1153: } else {
1154: name = SymbolTable.toTagName(tag);
1155: }
1156:
1157: if (table.current().isDefinedLocally(name)) {
1158: final Type t = (Type) table.current()
1159: .lookupLocally(name);
1160:
1161: if (!t.isEnum()) {
1162: runtime.error("'" + tag
1163: + "' defined as wrong kind of tag", n);
1164: reportPreviousTag(t);
1165: type = ErrorT.TYPE;
1166: return;
1167:
1168: } else if (null != t.toTagged().getMembers()) {
1169: runtime.error("redefinition of 'enum " + tag
1170: + "'", n);
1171: reportPreviousTag(t);
1172: type = ErrorT.TYPE;
1173: return;
1174:
1175: } else {
1176: type = t;
1177: }
1178: } else {
1179: checkNotParameter(n, "enum");
1180:
1181: type = new EnumT(tag);
1182: }
1183:
1184: // Process the enumerators.
1185: final GNode enumerators = n.getGeneric(2);
1186: final List<EnumeratorT> types = new ArrayList<EnumeratorT>(
1187: enumerators.size());
1188: BigInteger lastValue = BigInteger.ONE.negate();
1189: for (Object o : enumerators) {
1190: final GNode rator = GNode.cast(o);
1191: final String rname = rator.getString(0);
1192: final Node vnode = rator.getNode(1); // The value node.
1193:
1194: BigInteger value = null;
1195: if (null != vnode) {
1196: // The enumerator has an explicitly specified value.
1197: final Type vtype = processExpression(vnode);
1198:
1199: if (vtype.hasError()) {
1200: // Ignore to avoid cascading error messages.
1201:
1202: } else if ((!vtype.hasConstant())
1203: || (!c().isIntegral(vtype))) {
1204: runtime.error("enumerator value for '"
1205: + rname
1206: + "' is not an integer constant",
1207: vnode);
1208:
1209: } else {
1210: try {
1211: value = vtype.getConstant()
1212: .bigIntValue();
1213: lastValue = value;
1214: } catch (IllegalStateException x) {
1215: runtime.warning(
1216: "can't compute value for '"
1217: + rname + "'", vnode);
1218: value = lastValue.add(BigInteger.ONE);
1219: lastValue = value;
1220: }
1221: }
1222: }
1223:
1224: if (null == value) {
1225: // If the value has not been specified or is erroneous,
1226: // fall back on increment-by-one.
1227: value = lastValue.add(BigInteger.ONE);
1228: lastValue = value;
1229: }
1230:
1231: // Record the enumerator in the symbol table.
1232: final EnumeratorT ratorT = new EnumeratorT(rname,
1233: value);
1234: if (table.current().isDefinedLocally(rname)) {
1235: runtime.error(
1236: "redefinition of '" + rname + "'",
1237: rator);
1238: } else {
1239: table.current().define(rname, ratorT);
1240: }
1241:
1242: // Add the enumerator to the list of enumerators.
1243: types.add(ratorT);
1244: }
1245:
1246: // Determine the minimum and maximum value.
1247: BigInteger min = BigInteger.ZERO;
1248: BigInteger max = BigInteger.ZERO;
1249: for (EnumeratorT r : types) {
1250: final BigInteger value = r.getConstant()
1251: .bigIntValue();
1252:
1253: // Test: value < min
1254: if (value.compareTo(min) < 0)
1255: min = value;
1256:
1257: // Test: value > max
1258: if (value.compareTo(max) > 0)
1259: max = value;
1260: }
1261:
1262: // Find a fitting overall type.
1263: final Type baseT;
1264: if (Limits.fitsInt(min) && Limits.fitsInt(max)) {
1265: baseT = NumberT.INT;
1266: } else if (Limits.fitsUnsignedInt(min)
1267: && Limits.fitsUnsignedInt(max)) {
1268: baseT = NumberT.U_INT;
1269: } else if (Limits.fitsLong(min) && Limits.fitsLong(max)) {
1270: baseT = NumberT.LONG;
1271: } else if (Limits.fitsUnsignedLong(min)
1272: && Limits.fitsUnsignedLong(max)) {
1273: baseT = NumberT.U_LONG;
1274: } else if (Limits.fitsLongLong(min)
1275: && Limits.fitsLongLong(max)) {
1276: baseT = NumberT.LONG_LONG;
1277: } else if (Limits.fitsUnsignedLongLong(min)
1278: && Limits.fitsUnsignedLongLong(max)) {
1279: baseT = NumberT.U_LONG_LONG;
1280: } else {
1281: runtime
1282: .error(
1283: "enumeration values exceed range of largest integer",
1284: n);
1285: baseT = ErrorT.TYPE;
1286: }
1287:
1288: // Done.
1289: ((EnumT) type).setMembers(types);
1290: ((EnumT) type).setType(baseT);
1291: type.setLocation(n);
1292: for (Attribute a : toAttributeList(n.getGeneric(0))) {
1293: type.addAttribute(a);
1294: }
1295: for (Attribute a : toAttributeList(n.getGeneric(3))) {
1296: type.addAttribute(a);
1297: }
1298: type.seal();
1299: table.current().define(name, type);
1300: }
1301: }
1302:
1303: /** Process the enumeration type reference. */
1304: public void visitEnumerationTypeReference(GNode n) {
1305: if (hasType()) {
1306: multipleTypes();
1307: } else {
1308: final String tag = n.getString(1);
1309: final String name = SymbolTable.toTagName(tag);
1310:
1311: if (table.isDefined(name)) {
1312: final Type t = (Type) table.lookup(name);
1313:
1314: if (!t.isEnum()) {
1315: runtime.error("'" + tag
1316: + "' defined as wrong kind of tag", n);
1317: reportPreviousTag(t);
1318: type = ErrorT.TYPE;
1319: } else {
1320: type = t;
1321:
1322: // If the enum has not yet been defined, update the
1323: // location and GCC attributes.
1324: if (null == type.toEnum().getMembers()) {
1325: type.setLocation(n);
1326: for (Attribute a : toAttributeList(n
1327: .getGeneric(0))) {
1328: type.addAttribute(a);
1329: }
1330: }
1331: }
1332: } else {
1333: checkNotParameter(n, "enum");
1334:
1335: type = new EnumT(tag).locate(n);
1336: for (Attribute a : toAttributeList(n.getGeneric(0))) {
1337: type.addAttribute(a);
1338: }
1339: table.current().define(name, type);
1340: }
1341: }
1342: }
1343:
1344: /** Process the void type specifier. */
1345: public void visitVoidTypeSpecifier(GNode n) {
1346: if (hasType()) {
1347: multipleTypes();
1348: } else {
1349: type = VoidT.TYPE;
1350: }
1351: }
1352:
1353: /** Process the variable argument list specifier. */
1354: public void visitVarArgListSpecifier(GNode n) {
1355: if (hasType()) {
1356: multipleTypes();
1357: } else {
1358: type = InternalT.VA_LIST;
1359: }
1360: }
1361:
1362: /** Process the typedef name. */
1363: public void visitTypedefName(GNode n) {
1364: if (hasType()) {
1365: multipleTypes();
1366: } else {
1367: final String name = n.getString(0);
1368: final Type value = (Type) table.current().lookup(name);
1369:
1370: if ((null != value) && value.isAlias()) {
1371: type = value;
1372: } else {
1373: runtime.error("typedef name '" + name
1374: + "' undefined", n);
1375: type = ErrorT.TYPE;
1376: }
1377: }
1378: }
1379:
1380: /** Process the attribute specifier. */
1381: public void visitAttributeSpecifier(GNode n) {
1382: final List<Attribute> atts = toAttributeList(n);
1383:
1384: if (!atts.isEmpty()) {
1385: if (null == attributes) {
1386: attributes = atts;
1387: } else {
1388: attributes.addAll(atts);
1389: }
1390: }
1391: }
1392:
1393: }
1394:
1395: // ========================================================================
1396:
1397: /** The saved state of the initializer. */
1398: static class State {
1399: public Type base;
1400: public Type element;
1401: public boolean top;
1402: public long index;
1403: public long size;
1404:
1405: public State(Type base, Type element, boolean top, long index,
1406: long size) {
1407: this .base = base;
1408: this .element = element;
1409: this .top = top;
1410: this .index = index;
1411: this .size = size;
1412: }
1413: }
1414:
1415: /** The semantic information contained in an initializer. */
1416: public class Initializer {
1417:
1418: /** The debug level. */
1419: private static final int DEBUG = 0;
1420:
1421: /** The overall initializer list. */
1422: private GNode node;
1423:
1424: /** The overall type. */
1425: private Type type;
1426:
1427: /** The flag for whether the type has automatic storage. */
1428: private boolean auto;
1429:
1430: /** The current base type. */
1431: private Type base;
1432:
1433: /** The current element type. */
1434: private Type element;
1435:
1436: /** The flag for whether the initializer is top-level. */
1437: private boolean top;
1438:
1439: /** The current index into aggregate types. */
1440: private long index;
1441:
1442: /** The size of aggregate types. */
1443: private long size;
1444:
1445: /** The count of a top-level array's elements. */
1446: private long count;
1447:
1448: /** The stack of processing states. */
1449: private List<State> states;
1450:
1451: /**
1452: * Create a new initializer. The specified node must represent an
1453: * initializer list.
1454: *
1455: * @param node The node.
1456: * @param type The type.
1457: * @param auto The flag for automatic storage.
1458: */
1459: public Initializer(GNode node, Type type, boolean auto) {
1460: this .node = node;
1461: this .type = type;
1462: this .auto = auto;
1463: this .base = type.resolve();
1464: switch (this .base.tag()) {
1465: case ARRAY:
1466: this .element = base.toArray().getType().resolve();
1467: this .top = true;
1468: this .size = getSize(base);
1469: break;
1470: case STRUCT:
1471: case UNION:
1472: this .element = null;
1473: this .top = false;
1474: this .size = getSize(base);
1475: break;
1476: default:
1477: this .element = base;
1478: this .top = true;
1479: this .size = 1;
1480: }
1481: this .index = -1;
1482: this .count = 0;
1483: states = new ArrayList<State>();
1484: }
1485:
1486: /**
1487: * Create a new nested initializer. The specified node must
1488: * represent an initializer list. Both types must have been
1489: * resolved. The element type may be <code>null</code>.
1490: *
1491: * @param node The node.
1492: * @param base The base type.
1493: * @param element The element type.
1494: * @param auto The flag for automatic storage.
1495: */
1496: Initializer(GNode node, Type base, Type element, boolean auto) {
1497: this .node = node;
1498: this .type = base;
1499: this .auto = auto;
1500: this .base = base;
1501: this .element = element;
1502: this .top = false;
1503: this .size = (base == element) ? 1 : getSize(base);
1504: this .index = -1;
1505: this .count = 0;
1506: states = new ArrayList<State>();
1507: }
1508:
1509: /**
1510: * Process the initializer. This method processes this
1511: * initializer, reporting any errors and returning the processed
1512: * type. The processed type generally is the same as the type
1513: * provided to this class' constructor. However, if this
1514: * intializer's type is a top-level incomplete array, it is
1515: * updated with the actual size.
1516: *
1517: * @return The processed type.
1518: */
1519: public Type process() {
1520: // DEBUG: Open brace.
1521: if (1 <= DEBUG) {
1522: runtime.console().pln('{').incr().flush();
1523: }
1524:
1525: // Iterate over the initializer list entries.
1526: final int num = node.size();
1527: for (int cursor = 0; cursor < num; cursor++) {
1528: // Get the entry and its children.
1529: final GNode entry = node.getGeneric(cursor);
1530: final GNode designation = entry.getGeneric(0);
1531: final GNode initializer = entry.getGeneric(1);
1532:
1533: // Process the designation.
1534: if (!designation(designation)) {
1535: // DEBUG: Close brace.
1536: if (1 <= DEBUG)
1537: runtime.console().decr().indent().pln("};")
1538: .flush();
1539: return getResult();
1540: }
1541:
1542: // Process the intializer.
1543: if (initializer.hasName("InitializerList")) {
1544: // DEBUG: Print the designation.
1545: if (1 <= DEBUG) {
1546: runtime.console().indent().p(toString()).p(
1547: " = ").flush();
1548: }
1549:
1550: switch (element.tag()) {
1551: case BOOLEAN:
1552: case INTEGER:
1553: case FLOAT:
1554: case POINTER: {
1555: runtime.warning(
1556: "braces around scalar initializer",
1557: initializer);
1558: new Initializer(initializer, element, element,
1559: auto).process();
1560: }
1561: break;
1562: case ARRAY: {
1563: new Initializer(initializer, element, element
1564: .toArray().getType().resolve(), auto)
1565: .process();
1566: }
1567: break;
1568: default:
1569: new Initializer(initializer, element, null,
1570: auto).process();
1571: }
1572:
1573: } else {
1574: // Determine the right hand type.
1575: final Type right;
1576: if (runtime.test("optionMarkAST")
1577: && initializer.getBooleanProperty(MARKED)) {
1578: right = (Type) initializer
1579: .getProperty(Constants.TYPE);
1580: } else {
1581: right = processExpression(initializer);
1582: }
1583:
1584: // Top-level initializer may only contain constant.
1585: if ((!auto) && (!right.hasConstant())
1586: && (!c().hasConstRef(right))) {
1587: runtime.error(
1588: "initializer element is not constant",
1589: initializer);
1590: }
1591:
1592: // Try to initialize the left-hand type with the right-hand
1593: // type.
1594: loop: while (true) {
1595: if (isInitializable(element, right)) {
1596: // DEBUG: Print the assignment.
1597: if (1 <= DEBUG) {
1598: runtime.console().indent()
1599: .p(toString()).p(" = ");
1600: if (right.hasConstant()) {
1601: runtime.console().p(
1602: right.getConstant()
1603: .getValue()
1604: .toString());
1605: } else if (c().hasConstRef(right)) {
1606: runtime.console().p(
1607: c().getConstRef(right)
1608: .toString());
1609: } else {
1610: runtime.console().p("<val>");
1611: }
1612: runtime.console().pln(';').flush();
1613: }
1614:
1615: // Process the assignment and string size for any warnings.
1616: processAssignment(true, "initializer",
1617: initializer, element, right);
1618: processStringSize(initializer,
1619: "initializer", true, element, right);
1620: break;
1621: }
1622:
1623: switch (element.tag()) {
1624: case ARRAY: {
1625: // Initialize the array's elements.
1626: push(element);
1627: }
1628: break;
1629:
1630: case STRUCT:
1631: case UNION: {
1632: if (0 == element.toTagged()
1633: .getMemberCount()) {
1634: // Continue with the next subobject.
1635: if (!designation(null)) {
1636: // DEBUG: Close brace.
1637: if (1 <= DEBUG) {
1638: runtime.console().decr()
1639: .indent().pln("};")
1640: .flush();
1641: }
1642: return getResult();
1643: }
1644:
1645: } else {
1646: // Initialize the struct/union members.
1647: push(element);
1648: }
1649: }
1650: break;
1651:
1652: default:
1653: // The assignment fails.
1654: processAssignment(true, "initializer",
1655: initializer, element, right);
1656: break loop;
1657: }
1658: }
1659: }
1660: }
1661:
1662: // Check for empty scalar initializers.
1663: if ((0 == num) && c().isScalar(type)) {
1664: runtime.error("empty scalar initializer", node);
1665: }
1666:
1667: // DEBUG: Close brace.
1668: if (1 <= DEBUG)
1669: runtime.console().decr().indent().pln("};").flush();
1670: return getResult();
1671: }
1672:
1673: /**
1674: * Process the specified designation. This method updates the
1675: * internal state to reflect the designation.
1676: *
1677: * @param designation The designation, which may be
1678: * <code>null</code>.
1679: * @return <code>false</code> if the designation contains an
1680: * error.
1681: */
1682: private boolean designation(GNode designation) {
1683: if (null == designation) {
1684: while (true) {
1685: index++;
1686:
1687: if ((-1 == size) || (index < size)) {
1688: // We have an object to initialize.
1689: if (base.hasStructOrUnion()) {
1690: // Set the element type for struct/union types.
1691: element = base.toTagged().getMember(
1692: (int) index).resolve();
1693:
1694: } else if ((!hasSize(type))
1695: && (0 == states.size()) && top) {
1696: // We are processing an initializer list that is not
1697: // nested and has an incomplete array as its type.
1698: // Therefore, we record the maximum size.
1699: count = Math.max(count, index + 1);
1700: }
1701:
1702: // Done.
1703: return true;
1704:
1705: } else {
1706: // We are done with the base type.
1707: if (0 == states.size()) {
1708: // There are no more objects to initialize. Get the
1709: // first excess element.
1710: final GNode excess = node
1711: .getGeneric((int) index);
1712:
1713: // Report excess elements first.
1714: if (pedantic) {
1715: runtime.error("excess elements in "
1716: + c().toDesignation(base)
1717: + " initializer", excess);
1718: } else {
1719: runtime.warning("excess elements in "
1720: + c().toDesignation(base)
1721: + " initializer", excess);
1722: }
1723:
1724: // Report any extra brace groups.
1725: for (int i = (int) index; i < node.size(); i++) {
1726: final GNode el = node.getGeneric(i);
1727:
1728: if (el.getGeneric(1).hasName(
1729: "InitializerList")) {
1730: runtime
1731: .error(
1732: "extra brace group at end of initializer",
1733: el);
1734: }
1735: }
1736:
1737: // Done.
1738: return false;
1739:
1740: } else {
1741: // Continue with the encapsulating type.
1742: pop();
1743: }
1744: }
1745: }
1746:
1747: } else {
1748: // Clear the saved states. We are starting with the overall
1749: // type.
1750: if (0 != states.size()) {
1751: final State state = states.get(0);
1752: base = state.base;
1753: element = state.element;
1754: top = state.top;
1755: index = state.index;
1756: size = state.size;
1757: states.clear();
1758: }
1759: if (base.isArray())
1760: push(base);
1761:
1762: // Process the designators.
1763: final Iterator<Object> iter;
1764: if (designation.hasName("Designation")) {
1765: iter = designation.iterator();
1766: } else {
1767: iter = new SingletonIterator<Object>(designation);
1768: }
1769:
1770: while (iter.hasNext()) {
1771: final GNode designator = GNode.cast(iter.next());
1772:
1773: if (designator.hasName("ObsoleteFieldDesignation")
1774: || ".".equals(designator.getString(0))) {
1775: // A struct/union field.
1776: if (!base.hasStructOrUnion()) {
1777: runtime
1778: .error(
1779: "field name not in struct or union initializer",
1780: designator);
1781: return false;
1782: }
1783:
1784: // Extract the field name.
1785: String name = designator
1786: .hasName("ObsoleteFieldDesignation") ? designator
1787: .getString(0)
1788: : designator.getGeneric(1).getString(0);
1789:
1790: // Find the field.
1791: if (!lookup(name)) {
1792: runtime.error("unknown field '" + name
1793: + "' in initializer", designator);
1794: return false;
1795: }
1796:
1797: } else {
1798: // An array index. Make sure the base type is an array.
1799: if (!base.isArray()) {
1800: runtime
1801: .error(
1802: "array index in non-array initializer",
1803: designator);
1804: return false;
1805: }
1806:
1807: // Determine the index types.
1808: final Type t1 = processExpression(designator
1809: .getNode(1));
1810: final Type t2 = (3 == designator.size()) ? processExpression(designator
1811: .getNode(2))
1812: : null;
1813:
1814: // Make sure that the indices are constant integers.
1815: if ((!c().isIntegral(t1))
1816: || ((null != t2) && (!c()
1817: .isIntegral(t2)))) {
1818: runtime
1819: .error(
1820: "array index in initializer not of integer type",
1821: designator);
1822: return false;
1823:
1824: } else if ((!t1.hasConstant())
1825: || ((null != t2) && (!t2.hasConstant()))) {
1826: runtime
1827: .error(
1828: "nonconstant array index in initializer",
1829: designator);
1830: return false;
1831:
1832: }
1833:
1834: // Make sure that the indices are neither too small nor
1835: // too large and that the range is not empty.
1836: final BigInteger i1 = t1.getConstant()
1837: .bigIntValue();
1838: final BigInteger i2 = (null == t2) ? null : t2
1839: .getConstant().bigIntValue();
1840:
1841: // Test: i1 < 0, i2 < 0
1842: if ((i1.compareTo(BigInteger.ZERO) < 0)
1843: || ((null != i2) && (i2
1844: .compareTo(BigInteger.ZERO) < 0))) {
1845: runtime
1846: .error(
1847: "negative array index in initializer",
1848: designator);
1849: return false;
1850:
1851: // Test: i1 > ARRAY_MAX, i2 > ARRAY_MAX
1852: } else if ((i1.compareTo(Limits.ARRAY_MAX) > 0)
1853: || ((null != i2) && (i2
1854: .compareTo(Limits.ARRAY_MAX) > 0))) {
1855: runtime
1856: .error(
1857: "array index in initializer is too large",
1858: designator);
1859: return false;
1860:
1861: // Test: i2 < i1
1862: } else if ((null != i2)
1863: && (i2.compareTo(i1) < 0)) {
1864: runtime.error(
1865: "empty index range in initializer",
1866: designator);
1867: return false;
1868:
1869: }
1870:
1871: // Make sure that the array index is within the array
1872: // bounds.
1873: final long max = (null == i2) ? i1.longValue()
1874: : i2.longValue();
1875: if ((-1 < size) && (max >= size)) {
1876: runtime
1877: .error(
1878: "array index in initializer exceeds array bounds",
1879: designator);
1880: return false;
1881: }
1882:
1883: if ((!hasSize(type)) && (0 == states.size())
1884: && top) {
1885: // We are processing an initializer list that is not
1886: // nested and has an incomplete array as its type.
1887: // Therefore, we record the maximum size.
1888: count = Math.max(count, max + 1);
1889: }
1890:
1891: // Update the current index.
1892: index = max;
1893: }
1894:
1895: // Prepare for the next designator.
1896: if (iter.hasNext())
1897: push(element);
1898: }
1899:
1900: // Done.
1901: return true;
1902: }
1903: }
1904:
1905: /**
1906: * Look up the specified field. The current base type must be a
1907: * struct or union type.
1908: *
1909: * @return <code>true</code> if the field was found.
1910: */
1911: private boolean lookup(String name) {
1912: index = -1;
1913:
1914: for (VariableT member : ((StructOrUnionT) base)
1915: .getMembers()) {
1916: if (member.hasName()) {
1917: index++;
1918: if (member.hasName(name)) {
1919: element = member.resolve();
1920: return true;
1921: }
1922:
1923: } else if (!member.hasWidth()) {
1924: index++;
1925: element = member.resolve();
1926: push(element);
1927:
1928: if (lookup(name))
1929: return true;
1930:
1931: pop();
1932: }
1933: }
1934:
1935: return false;
1936: }
1937:
1938: /**
1939: * Make the specified type the current type. The type must have
1940: * been resolved.
1941: *
1942: * @param type The type.
1943: */
1944: private void push(Type type) {
1945: // DEBUG: Print pushed type.
1946: if (2 <= DEBUG) {
1947: runtime.console().indent().p("push ");
1948: type.trace(runtime);
1949: runtime.console().flush();
1950: }
1951:
1952: State state = new State(base, element, top, index, size);
1953: states.add(state);
1954: base = type;
1955: switch (type.tag()) {
1956: case ARRAY:
1957: element = type.toArray().getType().resolve();
1958: break;
1959: case STRUCT:
1960: case UNION:
1961: element = type.toTagged().getMember(0).resolve();
1962: break;
1963: default:
1964: element = type;
1965: }
1966: top = false;
1967: index = 0;
1968: size = getSize(type);
1969: }
1970:
1971: /** Restore the previous type and its processing state. */
1972: private void pop() {
1973: // DEBUG: Pop.
1974: if (2 <= DEBUG)
1975: runtime.console().indent().pln("pop").flush();
1976:
1977: assert 0 != states.size() : "Empty initializer type stack";
1978:
1979: final State state = states.remove(states.size() - 1);
1980: base = state.base;
1981: element = state.element;
1982: top = state.top;
1983: index = state.index;
1984: size = state.size;
1985: }
1986:
1987: /**
1988: * Get the result type. If this initializer list is not nested
1989: * and has an incomplete array as its type, this method patches
1990: * the array's size. Otherwise, it returns the overall type.
1991: *
1992: * @return The result type.
1993: */
1994: private Type getResult() {
1995: if ((!hasSize(type))
1996: && (((0 == states.size()) && top) || ((0 < states
1997: .size()) && states.get(0).top))) {
1998: type = type.copy();
1999: type.resolve().toArray().setLength(count);
2000: }
2001: return type;
2002: }
2003:
2004: /**
2005: * Convert this initializer as a string. This method returns a
2006: * string representing the array/struct/union designation of the
2007: * current initializer state.
2008: *
2009: * @return This initializer as a string.
2010: */
2011: public String toString() {
2012: final StringBuilder buf = new StringBuilder();
2013:
2014: for (State state : states) {
2015: if (state.base != state.element) {
2016: if (state.base.isArray()) {
2017: buf.append('[');
2018: buf.append(state.index);
2019: buf.append(']');
2020:
2021: } else if (state.base.hasStructOrUnion()) {
2022: final VariableT m = state.base.toTagged()
2023: .getMember((int) state.index)
2024: .toVariable();
2025: if (m.hasName()) {
2026: buf.append('.');
2027: buf.append(m.getName());
2028: } else {
2029: buf.append(".<anon>");
2030: }
2031: }
2032: }
2033: }
2034:
2035: if ((base != element) && (-1 != index)) {
2036: if (base.isArray()) {
2037: buf.append('[');
2038: buf.append(index);
2039: buf.append(']');
2040:
2041: } else if (base.hasStructOrUnion()) {
2042: final VariableT m = base.toTagged().getMember(
2043: (int) index).toVariable();
2044: if (m.hasName()) {
2045: buf.append('.');
2046: buf.append(m.getName());
2047: } else {
2048: buf.append(".<anon>");
2049: }
2050: }
2051: }
2052:
2053: // Cover the base case.
2054: if ((base == element) && (0 == states.size()))
2055: buf.append("<obj>");
2056:
2057: return buf.toString();
2058: }
2059:
2060: /**
2061: * Determine whether the specified type has a size. Only arrays
2062: * without a length do not have a size. This method is
2063: * effectively static.
2064: *
2065: * @param type The type.
2066: * @return <code>true</code> if the type has a size.
2067: */
2068: private boolean hasSize(Type type) {
2069: return (!type.hasTag(Tag.ARRAY))
2070: || type.resolve().toArray().hasLength();
2071: }
2072:
2073: /**
2074: * Determine the size of the specified type. For scalars, this
2075: * method returns 1. For unions, this method returns 1 if the
2076: * union has any accessible members and 0 otherwise. For structs,
2077: * this method returns the number of accessible members. For
2078: * arrays, it returns the size if known and -1 otherwise. This
2079: * method is effectively static.
2080: *
2081: * @param type The type.
2082: * @return The type's size.
2083: */
2084: private long getSize(Type type) {
2085: switch (type.tag()) {
2086: case ARRAY:
2087: return type.toArray().getLength();
2088: case STRUCT:
2089: return type.toTagged().getMemberCount();
2090: case UNION:
2091: return 0 < type.toTagged().getMemberCount() ? 1 : 0;
2092: default:
2093: return 1;
2094: }
2095: }
2096:
2097: }
2098:
2099: // ========================================================================
2100:
2101: /** The state for checking incomplete types. */
2102: public static class CompletenessCheck {
2103:
2104: /** The type. */
2105: public Type type;
2106:
2107: /** The identifier. */
2108: public String name;
2109:
2110: /** The node. */
2111: public Node node;
2112:
2113: /**
2114: * Create a new completeness check.
2115: *
2116: * @param type The type.
2117: * @param name The name.
2118: * @param node The node.
2119: */
2120: public CompletenessCheck(Type type, String name, Node node) {
2121: this .type = type;
2122: this .name = name;
2123: this .node = node;
2124: }
2125:
2126: }
2127:
2128: // ========================================================================
2129:
2130: /**
2131: * The name of the node property indicating that a node has already
2132: * been marked with its type during initializer processing.
2133: */
2134: protected static final String MARKED = "marked";
2135:
2136: /** The relative name of the scope for external declarations. */
2137: protected static final String EXTERN_SCOPE = "extern";
2138:
2139: /** The relative name of the temporary scope for parameter declarations. */
2140: protected static final String TMP_SCOPE = "tmp";
2141:
2142: /** The fully qualified name of the scope for external declarations. */
2143: protected static final String EXTERN_PATH = Constants.QUALIFIER
2144: + EXTERN_SCOPE;
2145:
2146: /** The common type operations for C. */
2147: protected final C cops;
2148:
2149: /** The runtime. */
2150: protected final Runtime runtime;
2151:
2152: /** The flag for pedantic mode. */
2153: protected final boolean pedantic;
2154:
2155: /** The symbol table. */
2156: protected SymbolTable table;
2157:
2158: /**
2159: * The flag for whether the current declaration is top-level, that
2160: * is, an external declaration.
2161: */
2162: protected boolean isTopLevel;
2163:
2164: /**
2165: * The flag for whether the immediately nested compound statement
2166: * has a scope.
2167: */
2168: protected boolean hasScope;
2169:
2170: /**
2171: * The list of loop statement flags. For each nested loop
2172: * statement, this list contains exactly one boolean.
2173: */
2174: protected List<Boolean> loops;
2175:
2176: /**
2177: * The list of switch statement flags. For each nested switch
2178: * statement, this list contains exactly one boolean, which is
2179: * <code>true</code> if a default label has been seen.
2180: */
2181: protected List<Boolean> switches;
2182:
2183: /**
2184: * The flag for a statement as expression node. This flag
2185: * is <code>true</code> if the current compound statement
2186: * is nested within a statement as expression node.
2187: */
2188: protected boolean isStmtAsExpr;
2189:
2190: /**
2191: * The list of completeness checks to perform at the end of a
2192: * translation unit.
2193: */
2194: protected List<CompletenessCheck> checks;
2195:
2196: /**
2197: * Create a new C analyzer. The newly created analyzer uses {@link
2198: * C} for common type operations.
2199: *
2200: * @param runtime The runtime.
2201: */
2202: public CAnalyzer(Runtime runtime) {
2203: this (new C(), runtime);
2204: }
2205:
2206: /**
2207: * Create a new C analyzer.
2208: *
2209: * @param cops The common type operations for C.
2210: * @param runtime The runtime.
2211: */
2212: public CAnalyzer(C cops, Runtime runtime) {
2213: this .cops = cops;
2214: this .runtime = runtime;
2215: pedantic = runtime.test("optionPedantic");
2216: loops = new ArrayList<Boolean>();
2217: switches = new ArrayList<Boolean>();
2218: checks = new ArrayList<CompletenessCheck>();
2219: }
2220:
2221: /**
2222: * Analyze the specified translation unit.
2223: *
2224: * @param unit The translation unit.
2225: * @return The corresponding symbol table.
2226: */
2227: public SymbolTable analyze(Node unit) {
2228: return analyze(unit, new SymbolTable());
2229: }
2230:
2231: /**
2232: * Process the specified translation unit.
2233: *
2234: * @param unit The translation unit.
2235: * @param table The symbol table.
2236: * @return The symbol table.
2237: */
2238: public SymbolTable analyze(Node unit, SymbolTable table) {
2239: this .table = table;
2240: isTopLevel = true;
2241: isStmtAsExpr = false;
2242: loops.clear();
2243: switches.clear();
2244: checks.clear();
2245: dispatch(unit);
2246: return table;
2247: }
2248:
2249: /**
2250: * Get this analyzer's common type operations for the C language.
2251: *
2252: * @return The common type operations.
2253: */
2254: public C c() {
2255: return cops;
2256: }
2257:
2258: /** Visit the specified translation unit. */
2259: public void visitTranslationUnit(GNode n) {
2260: for (Object o : n)
2261: dispatch((Node) o);
2262:
2263: // Process any tagged checks.
2264: for (CompletenessCheck check : checks) {
2265: if (c().isIncomplete(check.type)) {
2266: runtime.error("storage size of '" + check.name
2267: + "' isn't known", check.node);
2268: }
2269: }
2270: }
2271:
2272: /** Visit the specified declaration. */
2273: public void visitDeclaration(GNode n) {
2274: final GNode specifiers = n.getGeneric(1);
2275: final Specifiers spec = newSpecifiers(specifiers, null == n
2276: .get(2));
2277: final GNode initDeclList = n.getGeneric(2);
2278:
2279: if (null == initDeclList) {
2280: // ----------------------------------------------------------------------
2281: // Empty declarations
2282: // ----------------------------------------------------------------------
2283:
2284: // Check for useless attributes.
2285: if (spec.contains(Constants.ATT_INLINE)) {
2286: runtime.error("'inline' in empty declaration", n);
2287: }
2288: if (null != spec.getStorageClass()) {
2289: runtime
2290: .warning(
2291: "useless storage class specifier in empty declaration",
2292: n);
2293: }
2294: if (spec.contains(Constants.ATT_VOLATILE)
2295: || spec.contains(Constants.ATT_CONSTANT)
2296: || spec.contains(Constants.ATT_RESTRICT)) {
2297: runtime.warning(
2298: "useless type qualifier in empty declaration",
2299: n);
2300: }
2301:
2302: // Make sure the type is tagged.
2303: if ((!spec.getBaseType().hasError())
2304: && (!spec.getBaseType().hasTagged())) {
2305: runtime.warning("empty declaration", n);
2306: }
2307:
2308: } else {
2309: // Iterate over the initialized declarator list.
2310: for (Object o : initDeclList) {
2311: final GNode initDecl = GNode.cast(o);
2312: final GNode declarator = initDecl.getGeneric(1);
2313: final GNode identifier = getDeclaredId(declarator);
2314: final String name = identifier.getString(0);
2315: Type type = getDeclaredType(spec.getBaseType(),
2316: declarator);
2317: final GNode initializer = initDecl.getGeneric(4);
2318:
2319: if (spec.contains(Constants.ATT_STORAGE_TYPEDEF)) {
2320: // ------------------------------------------------------------------
2321: // Typedef declarations
2322: // ------------------------------------------------------------------
2323:
2324: // Check for invalid attributes.
2325: if (spec.contains(Constants.ATT_INLINE)) {
2326: runtime.error("typedef '" + name
2327: + "' is declared 'inline'",
2328: getSpecifier("FunctionSpecifier",
2329: specifiers));
2330: }
2331:
2332: // Check for initializers.
2333: if (null != initializer) {
2334: runtime.error("typedef '" + name
2335: + "' is initialized", initDecl);
2336: }
2337:
2338: // Check that the type is well-formed.
2339: checkType(initDecl, name, type);
2340:
2341: // Check for previous definitions.
2342: if (table.current().isDefinedLocally(name)) {
2343: Type previous = (Type) table.current()
2344: .lookupLocally(name);
2345:
2346: if (previous.isAlias()) {
2347: runtime.error("redefinition of typedef '"
2348: + name + "'", initDecl);
2349: } else {
2350: runtime
2351: .error(
2352: "'"
2353: + name
2354: + "' redeclared as different kind of symbol",
2355: initDecl);
2356: }
2357: reportPrevious(name, previous);
2358:
2359: } else {
2360: table.current()
2361: .define(
2362: name,
2363: new AliasT(name, type)
2364: .locate(n).seal());
2365: }
2366:
2367: } else {
2368: // ------------------------------------------------------------------
2369: // Object declarations/definitions
2370: // ------------------------------------------------------------------
2371:
2372: // The flags for whether to enter the definition into the
2373: // symbol table at the local, at the global, and the extern
2374: // level, respectively.
2375: boolean define = true;
2376: boolean defineGlobal = false;
2377: boolean defineExtern = false;
2378:
2379: // Annotate the type.
2380: type = spec.annotateFull(type.annotate());
2381: type = type.attribute(toAttributeList(initDecl
2382: .getGeneric(0)));
2383: type = type.attribute(toAttributeList(initDecl
2384: .getGeneric(3)));
2385:
2386: // Check that the type is well-formed.
2387: checkType(initDecl, name, type);
2388:
2389: Type resolved = type.resolve();
2390:
2391: // Check function types for invalid storage class,
2392: // parameters, and initializer.
2393: if (resolved.isFunction()) {
2394: FunctionT function = resolved.toFunction();
2395:
2396: if (function
2397: .hasAttribute(Constants.ATT_STORAGE_AUTO)
2398: || function
2399: .hasAttribute(Constants.ATT_STORAGE_REGISTER)) {
2400: runtime.error(
2401: "invalid storage class for function '"
2402: + name + "'", initDecl);
2403: }
2404:
2405: if (type.hasAttribute(Constants.ATT_STYLE_OLD)
2406: && (!function.getParameters().isEmpty())) {
2407: runtime.warning(
2408: "parameter names (without types) in function "
2409: + "declaration", initDecl);
2410: function.getParameters().clear();
2411: }
2412:
2413: if (null != initializer) {
2414: runtime.error("function '" + name
2415: + "' is initialized like a "
2416: + "variable", initDecl);
2417: }
2418:
2419: } else {
2420: // Check non-function types for inline specifier.
2421: if (type.hasAttribute(Constants.ATT_INLINE)) {
2422: runtime.warning("variable '" + name
2423: + "' declared 'inline'",
2424: getSpecifier("FunctionSpecifier",
2425: specifiers));
2426: type.removeAttribute(Constants.ATT_INLINE);
2427: }
2428: }
2429:
2430: // Check for compatibility with prevous declarations.
2431: if (isTopLevel) {
2432: // An external declaration/definition.
2433:
2434: // Check for invalid storage class specifiers.
2435: if (!resolved.isFunction()) {
2436: if (type
2437: .hasAttribute(Constants.ATT_STORAGE_AUTO)) {
2438: runtime.error(
2439: "file-scope declaration of '"
2440: + name
2441: + "' specifies 'auto'",
2442: getSpecifier("AutoSpecifier",
2443: specifiers));
2444:
2445: } else if (type
2446: .hasAttribute(Constants.ATT_STORAGE_REGISTER)) {
2447: // As a GCC extension, the register specifier may
2448: // appear in global register variable declarations.
2449: // Such a declaration, however, requires a simple
2450: // assembly expression.
2451: if (pedantic || null == initDecl.get(2)) {
2452: runtime
2453: .error(
2454: "file-scope declaration of '"
2455: + name
2456: + "' specifies 'register'",
2457: getSpecifier(
2458: "RegisterSpecifier",
2459: specifiers));
2460: }
2461: }
2462: }
2463:
2464: final Type extern = lookupExtern(name);
2465: final boolean global = table.current()
2466: .isDefinedLocally(name);
2467: if (null != extern || global) {
2468: final Type previous = global ? (Type) table
2469: .current().lookupLocally(name)
2470: : extern;
2471:
2472: // Check for same symbol kind and type compatibility.
2473: Type composite = compose(initDecl, name,
2474: type, previous, false);
2475:
2476: // Check for redefinitions and storage class compatibility.
2477: if (composite.isError()) {
2478: define = (null != extern);
2479:
2480: } else if ((null != initializer)
2481: && previous
2482: .hasAttribute(Constants.ATT_DEFINED)) {
2483: runtime.error("redefinition of '"
2484: + name + "'", initDecl);
2485: reportPrevious(name, previous);
2486: define = (null != extern);
2487:
2488: } else if ((!resolved.isFunction())
2489: && previous
2490: .hasAttribute(Constants.ATT_STORAGE_STATIC)
2491: && (!type
2492: .hasAttribute(Constants.ATT_STORAGE_STATIC))
2493: && (!type
2494: .hasAttribute(Constants.ATT_STORAGE_EXTERN))) {
2495: runtime
2496: .error(
2497: "non-static declaration of '"
2498: + name
2499: + "' follows static declaration",
2500: initDecl);
2501: reportPrevious(name, previous);
2502: define = (null != extern);
2503:
2504: } else if ((!previous
2505: .hasAttribute(Constants.ATT_MACRO))
2506: && (!previous
2507: .hasAttribute(Constants.ATT_STORAGE_STATIC))
2508: && type
2509: .hasAttribute(Constants.ATT_STORAGE_STATIC)) {
2510: runtime
2511: .error(
2512: "static declaration of '"
2513: + name
2514: + "' follows non-static declaration",
2515: initDecl);
2516: reportPrevious(name, previous);
2517: define = (null != extern);
2518:
2519: } else if (previous
2520: .hasAttribute(Constants.ATT_MACRO)
2521: || previous
2522: .hasAttribute(Constants.ATT_DEFINED)) {
2523: // There's nothing to add.
2524: define = (null != extern);
2525:
2526: } else {
2527: // We have a winner.
2528: composite = composite.annotate();
2529:
2530: // C99 6.7.4: inline only needs to appear
2531: // once. Similarly for static.
2532: if (resolved.isFunction()) {
2533: if ((previous
2534: .hasAttribute(Constants.ATT_INLINE) || type
2535: .hasAttribute(Constants.ATT_INLINE))
2536: && (!composite
2537: .hasAttribute(Constants.ATT_INLINE))) {
2538: composite = composite
2539: .attribute(Constants.ATT_INLINE);
2540: }
2541: if ((previous
2542: .hasAttribute(Constants.ATT_STORAGE_STATIC) || type
2543: .hasAttribute(Constants.ATT_STORAGE_STATIC))
2544: && (!composite
2545: .hasAttribute(Constants.ATT_STORAGE_STATIC))) {
2546: composite = composite
2547: .attribute(Constants.ATT_STORAGE_STATIC);
2548: }
2549: }
2550:
2551: // Preserve the lvalue.
2552: if (!composite.hasShape()) {
2553: composite = composite
2554: .shape(previous.getShape());
2555: }
2556:
2557: // Update the location.
2558: composite = composite.locate(n);
2559:
2560: // Continue with the composite type.
2561: type = composite;
2562: resolved = type.resolve();
2563: }
2564:
2565: } else {
2566: // The name has not been declared before.
2567:
2568: // Create an lvalue.
2569: type = type.shape(true, name);
2570:
2571: // Remember the location.
2572: type = type.locate(n);
2573: }
2574:
2575: } else {
2576: // A block-level declaration/definition.
2577:
2578: if (type
2579: .hasAttribute(Constants.ATT_STORAGE_EXTERN)
2580: || resolved.isFunction()) {
2581: // Extern and function declarations at the block-level
2582: // are effectively external declarations.
2583:
2584: // Process the function type's storage class.
2585: if (resolved.isFunction()) {
2586: if (type
2587: .hasAttribute(Constants.ATT_STORAGE_AUTO)
2588: || type
2589: .hasAttribute(Constants.ATT_STORAGE_REGISTER)
2590: || type
2591: .hasAttribute(Constants.ATT_STORAGE_STATIC)) {
2592: // C99 6.7.1-5
2593: runtime.error(
2594: "invalid storage class for function '"
2595: + name + "'",
2596: initDecl);
2597: type
2598: .removeAttribute(type
2599: .getAttribute(Constants.NAME_STORAGE));
2600: }
2601:
2602: // C99 6.2.2
2603: type = type
2604: .attribute(Constants.ATT_STORAGE_EXTERN);
2605: }
2606:
2607: final Type local = (Type) table.current()
2608: .lookupLocally(name);
2609: final Type global = (Type) table.root()
2610: .lookupLocally(name);
2611: final Type extern = lookupExtern(name);
2612:
2613: if (null != local || null != global
2614: || null != extern) {
2615: final Type previous;
2616: if (null != local) {
2617: previous = local;
2618: } else if (null != global) {
2619: previous = global;
2620: } else {
2621: previous = extern;
2622: }
2623:
2624: Type composite = compose(initDecl,
2625: name, type, previous, false);
2626:
2627: if (composite.isError()) {
2628: define = false;
2629:
2630: } else if (null != local
2631: && !previous.resolve()
2632: .isFunction()
2633: && !previous
2634: .hasAttribute(Constants.ATT_STORAGE_EXTERN)) {
2635: runtime
2636: .error(
2637: "extern declaration of '"
2638: + name
2639: + "' follows "
2640: + "declaration with no linkage",
2641: initDecl);
2642: reportPrevious(name, previous);
2643: define = false;
2644:
2645: } else if (previous
2646: .hasAttribute(Constants.ATT_STORAGE_STATIC)
2647: && previous != table.current()
2648: .getParent().lookup(
2649: name)) {
2650: // C99 6.2.2-4: If the previous declaration has
2651: // internal linkage (i.e., is declared as static)
2652: // and is not visible in the surrounding scope, then
2653: // this declaration tries to change to external
2654: // linkage, which is a program error.
2655:
2656: // Aside: It is extremely clever language design
2657: // practice to make a declaration's properties
2658: // dependent on an identifier of the same name in
2659: // the surrounding scope.
2660: runtime
2661: .error(
2662: "variable previously declared 'static' "
2663: + "redeclared 'extern'",
2664: initDecl);
2665: reportPrevious(name, previous);
2666:
2667: } else if (previous
2668: .hasAttribute(Constants.ATT_MACRO)
2669: || previous
2670: .hasAttribute(Constants.ATT_DEFINED)) {
2671: // There's nothing to add.
2672: type = previous;
2673: resolved = type.resolve();
2674: define = (null == local);
2675:
2676: } else {
2677: // We have a winner.
2678: composite = composite.annotate();
2679:
2680: // Preserve inline and static attributes for functions.
2681: if (resolved.isFunction()) {
2682: if ((previous
2683: .hasAttribute(Constants.ATT_INLINE) || type
2684: .hasAttribute(Constants.ATT_INLINE))
2685: && (!composite
2686: .hasAttribute(Constants.ATT_INLINE))) {
2687: composite = composite
2688: .attribute(Constants.ATT_INLINE);
2689: }
2690: if ((previous
2691: .hasAttribute(Constants.ATT_STORAGE_STATIC) || type
2692: .hasAttribute(Constants.ATT_STORAGE_STATIC))
2693: && (!composite
2694: .hasAttribute(Constants.ATT_STORAGE_STATIC))) {
2695: composite = composite
2696: .attribute(Constants.ATT_STORAGE_STATIC);
2697: }
2698: }
2699:
2700: // Update the lvalue.
2701: if (!composite.hasShape()) {
2702: composite = composite
2703: .shape(previous
2704: .getShape());
2705: }
2706:
2707: // Update the locaton.
2708: composite = composite.locate(n);
2709:
2710: // Continue with the composite type.
2711: type = composite;
2712: resolved = type.resolve();
2713: defineGlobal = (null != global);
2714: defineExtern = (null != extern);
2715: }
2716:
2717: } else {
2718: // The name has not been declared before.
2719:
2720: // Create an lvalue.
2721: type = type.shape(true, name);
2722:
2723: // Remember the location.
2724: type = type.locate(n);
2725:
2726: // Enter into extern scope.
2727: defineExtern = true;
2728: }
2729:
2730: } else if (table.current().isDefinedLocally(
2731: name)) {
2732: // Non-extern redeclarations at the block-level are
2733: // always errors. We just play along to determine what
2734: // kind of error.
2735: final Type previous = (Type) table
2736: .current().lookupLocally(name);
2737: final Type composite = compose(initDecl,
2738: name, type, previous, false);
2739:
2740: if (composite.isError()) {
2741: define = false;
2742:
2743: } else if (previous
2744: .hasAttribute(Constants.ATT_STORAGE_EXTERN)) {
2745: runtime
2746: .error(
2747: "declaration of '"
2748: + name
2749: + "' with no "
2750: + "linkage follows extern declaration",
2751: initDecl);
2752: reportPrevious(name, previous);
2753: define = false;
2754:
2755: } else {
2756: runtime.error("redeclaration of '"
2757: + name + "' with no linkage",
2758: initDecl);
2759: reportPrevious(name, previous);
2760: define = false;
2761: }
2762:
2763: } else {
2764: // The name has not been declared before.
2765:
2766: // Add the storage class if missing.
2767: if (!type
2768: .hasAttribute(Constants.NAME_STORAGE)) {
2769: type = type
2770: .attribute(Constants.ATT_STORAGE_AUTO);
2771: }
2772:
2773: // Create an lvalue.
2774: type = type
2775: .shape(
2776: type
2777: .hasAttribute(Constants.ATT_STORAGE_STATIC),
2778: name);
2779:
2780: // Remember the location.
2781: type = type.locate(n);
2782: }
2783: }
2784:
2785: // Check for incomplete types.
2786: boolean incomplete = false;
2787: if ((!type
2788: .hasAttribute(Constants.ATT_STORAGE_EXTERN))
2789: || (null != initializer)) {
2790:
2791: if (resolved.isArray()) {
2792: final Type element = resolved.toArray()
2793: .getType();
2794: if (c().isIncomplete(element)
2795: || (pedantic && c()
2796: .hasTrailingArray(element))) {
2797: runtime
2798: .error(
2799: "array type has incomplete element type",
2800: initDecl);
2801: incomplete = true;
2802: }
2803:
2804: } else if (c().isIncomplete(type)) {
2805: if (null == initializer) {
2806: // Per C99 6.9.2-2, as a special case, top-level
2807: // tagged types without initializers are logically
2808: // moved to the end of the translation unit and
2809: // automatically initialized to zero. We simply redo
2810: // the completeness check at the end of the
2811: // translation unit.
2812: if (isTopLevel
2813: && type.hasTagged()
2814: && (null == type.toTagged()
2815: .getMembers())) {
2816: checks.add(new CompletenessCheck(
2817: type, name, initDecl));
2818:
2819: } else if (resolved.isVoid()) {
2820: runtime.error("variable '" + name
2821: + "' declared void",
2822: initDecl);
2823: } else {
2824: runtime.error("storage size of '"
2825: + name + "' isn't known",
2826: initDecl);
2827: }
2828: } else {
2829: runtime.error("variable '" + name
2830: + "' has initializer but "
2831: + "incomplete type", initDecl);
2832: }
2833: incomplete = true;
2834: }
2835: }
2836:
2837: // Process the initializer.
2838: if ((null != initializer)
2839: && (!resolved.isFunction())) {
2840: if (type
2841: .hasAttribute(Constants.ATT_STORAGE_EXTERN)) {
2842: if (isTopLevel) {
2843: runtime
2844: .warning(
2845: "'"
2846: + name
2847: + "' initialized and declared 'extern'",
2848: initDecl);
2849: type = type
2850: .attribute(Constants.ATT_DEFINED);
2851: } else {
2852: runtime
2853: .error(
2854: "'"
2855: + name
2856: + "' has both 'extern' and initializer",
2857: initDecl);
2858: }
2859: } else {
2860: type = type
2861: .attribute(Constants.ATT_DEFINED);
2862: }
2863:
2864: if (!incomplete) {
2865: // C99 6.2.1-4: An identifiers scope starts with its
2866: // declarator. Consequently, we "pre-define" the
2867: // identifier before processing the initializer.
2868: if (define) {
2869: table.current().define(name, type);
2870: }
2871:
2872: // Do the actual processing.
2873: type = processInitializer(initDecl, name,
2874: type, initializer);
2875: }
2876: }
2877:
2878: // (Re)define the name and type.
2879: if (define) {
2880: table.current().define(name, type);
2881: }
2882: if (defineGlobal) {
2883: table.root().define(name, type);
2884: }
2885: if (defineExtern) {
2886: defineExtern(name, type);
2887: }
2888: }
2889: }
2890: }
2891: }
2892:
2893: /**
2894: * Process the specified initializer. This method checks that the
2895: * specified initializer is consistent with the specified type. It
2896: * also completes the type based on the literal.
2897: *
2898: * @param expr The overall expression node.
2899: * @param name The name of the variable being initialized, which may
2900: * be <code>null</code>.
2901: * @param left The left-hand type.
2902: * @param literal The literal node.
2903: */
2904: protected Type processInitializer(GNode expr, String name,
2905: Type left, GNode literal) {
2906: if (left.hasError())
2907: return left;
2908:
2909: // Fix the description for error reporting.
2910: name = (null == name) ? "initializer" : "initializer for '"
2911: + name + "'";
2912:
2913: // Determine whether the left-hand size has automatic storage.
2914: final boolean auto = (left
2915: .hasAttribute(Constants.ATT_STORAGE_AUTO) || left
2916: .hasAttribute(Constants.ATT_STORAGE_REGISTER));
2917:
2918: // Check the actual initializer.
2919: if (literal.hasName("InitializerList")) {
2920:
2921: // Take care of braced string literals here.
2922: if ((c().isString(left) || c().isWideString(left))
2923: && (0 < literal.size())
2924: && (null == literal.getGeneric(0).get(0))
2925: && (!literal.getGeneric(0).getGeneric(1).hasName(
2926: "InitializerList"))) {
2927: final Type right = (Type) dispatch(literal
2928: .getGeneric(0).getGeneric(1));
2929:
2930: if (right.hasConstant()
2931: && (c().isString(right) || c().isWideString(
2932: right))) {
2933: if (1 < literal.size()) {
2934: if (c().isString(left)) {
2935: runtime
2936: .error(
2937: "excess elements in char array initializer",
2938: literal);
2939: } else {
2940: runtime
2941: .error(
2942: "excess elements in wchar_t array initializer",
2943: literal);
2944: }
2945: return left;
2946: } else {
2947: processAssignment(true, name, literal, left,
2948: right);
2949: return processStringSize(literal, name, false,
2950: left, right);
2951: }
2952: }
2953:
2954: // Unmark the already processed node again b/c it will be
2955: // reprocessed below.
2956: if (runtime.test("optionMarkAST")) {
2957: literal.getGeneric(0).getGeneric(1).setProperty(
2958: MARKED, Boolean.TRUE);
2959: }
2960: }
2961:
2962: // Otherwise, just process the initializer list.
2963: return new Initializer(literal, left, auto).process();
2964:
2965: } else {
2966: final Type right = (Type) dispatch(literal);
2967:
2968: // A non-automatic initializer must be constant.
2969: if ((!auto) && (!right.hasConstant())
2970: && (!c().hasConstRef(right))) {
2971: runtime.error(name + " is not constant", expr);
2972: }
2973:
2974: // Are the two types compatible?
2975: processAssignment(true, name, literal, left, right);
2976: return processStringSize(literal, name, false, left, right);
2977: }
2978: }
2979:
2980: /**
2981: * Process the string sizes for the specified types. If the
2982: * specified types are not compatible string types or the right-hand
2983: * type does no represent a string constant, this method simply
2984: * returns the specified left-hand type. Otherwise, if the
2985: * left-hand type is an incomplete array and the expression is not
2986: * nested, this method updates a copy of the left-hand type and
2987: * returns that copy. If the left-hand type is a complete array and
2988: * the right-hand type is longer, it emits a warning.
2989: *
2990: * @param expr The overall expression node.
2991: * @param desc The description.
2992: * @param nested The flag for nested initializers.
2993: * @param left The left-hand type.
2994: * @param right The right-hand type.
2995: * @return The updated type.
2996: */
2997: protected Type processStringSize(GNode expr, String desc,
2998: boolean nested, Type left, Type right) {
2999: if (((c().isString(left) && c().isString(right)) || (c()
3000: .isWideString(left) && c().isWideString(right)))
3001: && right.hasConstant()) {
3002:
3003: final ArrayT array = left.resolve().toArray();
3004: if ((!array.isVarLength()) && (!array.hasLength())
3005: && (!nested)) {
3006: left = left.copy();
3007: left.resolve().toArray().setLength(
3008: right.resolve().toArray().getLength());
3009:
3010: } else if (array.hasLength()
3011: && (array.getLength() < right.resolve().toArray()
3012: .getLength())) {
3013: runtime.warning("string literal in " + desc
3014: + " is too long", expr);
3015: }
3016: }
3017:
3018: return left;
3019: }
3020:
3021: /** Visit the specified function definition. */
3022: public void visitFunctionDefinition(GNode n) {
3023: final GNode specifiers = n.getGeneric(1);
3024: final GNode declarator = n.getGeneric(2);
3025: final GNode identifier = getDeclaredId(declarator);
3026: final String name = identifier.getString(0);
3027:
3028: final Specifiers spec = newSpecifiers(specifiers, false);
3029: Type type = getDeclaredType(spec.getBaseType(), declarator);
3030: type = spec.annotateFull(type);
3031:
3032: // Make sure the type actually is a function.
3033: if (!type.resolve().isFunction()) {
3034: runtime.error(
3035: "function definition without function declarator",
3036: declarator);
3037: return;
3038: }
3039:
3040: // Check the storage class.
3041: if (type.hasAttribute(Constants.ATT_STORAGE_AUTO)) {
3042: runtime.error("function definition declared 'auto'", n);
3043: } else if (type.hasAttribute(Constants.ATT_STORAGE_REGISTER)) {
3044: runtime.error("function definition declared 'register'", n);
3045: } else if (type.hasAttribute(Constants.ATT_STORAGE_TYPEDEF)) {
3046: runtime.error("function definition declared 'typedef'", n);
3047: }
3048:
3049: // Check the function's result type.
3050: checkType(n, name, type);
3051:
3052: // The flag for a GCC inline extern function, i.e., macro.
3053: final boolean isMacro = (!pedantic
3054: && type.hasAttribute(Constants.ATT_STORAGE_EXTERN) && type
3055: .hasAttribute(Constants.ATT_INLINE));
3056:
3057: // The flag for whether to enter the definition into the symbol table.
3058: boolean define = true;
3059:
3060: // Check previous declarations/definitions.
3061: final Type extern = lookupExtern(name);
3062: final boolean global = table.current().isDefinedLocally(name);
3063: if (null != extern || global) {
3064: final Type previous = global ? (Type) table.current()
3065: .lookupLocally(name) : extern;
3066: final Type composite = compose(n, name, type, previous,
3067: true);
3068:
3069: if (composite.isError()) {
3070: define = (null != extern);
3071:
3072: } else if (previous.hasAttribute(Constants.ATT_DEFINED)
3073: || (isMacro && previous
3074: .hasAttribute(Constants.ATT_MACRO))) {
3075: runtime.error("redefinition of '" + name + "'", n);
3076: reportPrevious(name, previous);
3077: define = (null != extern);
3078:
3079: } else if ((!previous.hasAttribute(Constants.ATT_MACRO))
3080: && (!previous
3081: .hasAttribute(Constants.ATT_STORAGE_STATIC))
3082: && type.hasAttribute(Constants.ATT_STORAGE_STATIC)) {
3083: runtime.error("static declaration of '" + name
3084: + "' follows non-static declaration", n);
3085: reportPrevious(name, previous);
3086: define = (null != extern);
3087:
3088: } else {
3089: // Continue with the composite type.
3090: type = composite;
3091:
3092: // Preserve inline and static attributes.
3093: if ((!previous.hasAttribute(Constants.ATT_MACRO))
3094: && previous.hasAttribute(Constants.ATT_INLINE)
3095: && (!type.hasAttribute(Constants.ATT_INLINE))) {
3096: type = type.annotate().attribute(
3097: Constants.ATT_INLINE);
3098: }
3099:
3100: if (previous.hasAttribute(Constants.ATT_STORAGE_STATIC)
3101: && (!type
3102: .hasAttribute(Constants.ATT_STORAGE_STATIC))) {
3103: type = type.annotate().attribute(
3104: Constants.ATT_STORAGE_STATIC);
3105: }
3106:
3107: }
3108:
3109: type = type.annotate();
3110:
3111: // Mark the type as defined.
3112: if (type.resolve().isSealed()) {
3113: type = isMacro ? type.attribute(Constants.ATT_MACRO)
3114: : type.attribute(Constants.ATT_DEFINED);
3115: } else if (isMacro) {
3116: type.resolve().addAttribute(Constants.ATT_MACRO);
3117: } else {
3118: type.resolve().addAttribute(Constants.ATT_DEFINED);
3119: }
3120:
3121: // Ensure the type is marked as an lvalue.
3122: if (!type.hasShape()) {
3123: type = type.shape(true, name);
3124: }
3125:
3126: // Update the type's location.
3127: type = type.locate(n);
3128:
3129: } else {
3130: // The function has not been declared before. Mark it's type as
3131: // a defined lvalue and remember the location.
3132: if (isMacro) {
3133: type.resolve().addAttribute(Constants.ATT_MACRO);
3134: } else {
3135: type.resolve().addAttribute(Constants.ATT_DEFINED);
3136: }
3137: type = type.annotate().shape(true, name).locate(n);
3138: }
3139:
3140: // Update the symbol table.
3141: if (define) {
3142: // Note that processParameters() below may modify the type's
3143: // parameters.
3144: table.current().define(name, type);
3145: }
3146:
3147: // Check that main's return type is int.
3148: if ("main".equals(name)
3149: && type.resolve().isFunction()
3150: && !NumberT.INT.equals(type.resolve().toFunction()
3151: .getResult())) {
3152: runtime.warning("return type of 'main' is not 'int'", n);
3153: }
3154:
3155: // Enter function scope.
3156: final String scopeName = isMacro ? SymbolTable
3157: .toMacroScopeName(name) : SymbolTable
3158: .toFunctionScopeName(name);
3159: table.enter(scopeName);
3160: table.mark(n);
3161:
3162: // C99 6.4.2.2: Declare the function name.
3163: table.current().define("__func__", toFuncType(name));
3164:
3165: // Process the parameters.
3166: processParameters(n, type.resolve().toFunction());
3167:
3168: // Process the body.
3169: final boolean top = isTopLevel;
3170: isTopLevel = false;
3171: final boolean scope = hasScope;
3172: hasScope = false;
3173:
3174: dispatch(n.getNode(4));
3175:
3176: isTopLevel = top;
3177: hasScope = scope;
3178:
3179: table.exit();
3180:
3181: // Check labels.
3182: if (isTopLevel) {
3183: checkUsedLabels(n);
3184: checkDefinedLabels(n);
3185: }
3186: }
3187:
3188: /**
3189: * Create <code>__func__</code>'s type for the function with the
3190: * specified name.
3191: *
3192: * @param name The function name.
3193: * @return The corresponding type.
3194: */
3195: public static Type toFuncType(String name) {
3196: final Type elem = NumberT.CHAR.annotate().attribute(
3197: Constants.ATT_CONSTANT);
3198: final Type array = new ArrayT(elem, name.length()).annotate()
3199: .attribute(Constants.ATT_STORAGE_STATIC).shape(true,
3200: "__func__").seal();
3201:
3202: return array;
3203: }
3204:
3205: /**
3206: * Process the specified function's parameters. This method checks
3207: * that all parameters are named and have valid and complete types.
3208: * Furthermore, for old-style function definitions, it checks that
3209: * the parameter types are consistent with any previous new-style
3210: * declaration and, for previous old-style declarations, updates the
3211: * function's type with the parameter types. Finally, it adds the
3212: * appropriate definitions to the current symbol table scope.
3213: *
3214: * <p />Note that the specified type is expected to be the result of
3215: * composing the defined type with any previous declarations. For
3216: * old-style definitions, this type contains the parameter types of
3217: * any previous new-style declaration or is old-style as well, if
3218: * any previous declarations are also old-style.
3219: *
3220: * @param node The node representing the function.
3221: * @param function The function's type.
3222: */
3223: protected void processParameters(GNode node, FunctionT function) {
3224: // Extract the parameter list.
3225: GNode parameters = getFunctionDeclarator(node.getGeneric(2))
3226: .getGeneric(1);
3227:
3228: if ((null == parameters)
3229: || parameters.hasName("IdentifierList")) {
3230: // An old-style definition: We first process any identifiers.
3231: final Set<String> names = new HashSet<String>();
3232: if (null != parameters) {
3233: for (Object o : parameters)
3234: names.add((String) o);
3235: }
3236:
3237: // Next, we process any declarations.
3238: final GNode declarations = node.getGeneric(3);
3239: if (null != declarations) {
3240: for (Object o : declarations) {
3241: final GNode declaration = GNode.cast(o);
3242: final GNode specifiers = declaration.getGeneric(1);
3243: final Specifiers spec = newSpecifiers(specifiers,
3244: null == declaration.get(2));
3245:
3246: if (null == declaration.get(2)) {
3247: runtime.warning("empty declaration",
3248: declaration);
3249:
3250: } else {
3251: for (Object o2 : declaration.getGeneric(2)) {
3252: final GNode initDecl = GNode.cast(o2);
3253: final GNode declarator = initDecl
3254: .getGeneric(1);
3255: final GNode identifier = getDeclaredId(declarator);
3256: final String name = identifier.getString(0);
3257: Type type = getDeclaredType(true, spec
3258: .getBaseType(), declarator);
3259:
3260: // Check that the type is well-formed.
3261: checkType(declaration, name, type);
3262:
3263: // Pointerize array and function parameter types.
3264: switch (type.tag()) {
3265: case ARRAY:
3266: type = c().qualify(
3267: new PointerT(type.resolve()
3268: .toArray().getType()),
3269: type);
3270: break;
3271: case FUNCTION:
3272: type = c().qualify(
3273: new PointerT(type.resolve()),
3274: type);
3275: break;
3276: }
3277:
3278: // Annotate the type.
3279: type = spec.annotateFull(
3280: VariableT.newParam(type, name))
3281: .attribute(
3282: toAttributeList(initDecl
3283: .getGeneric(0)))
3284: .attribute(
3285: toAttributeList(initDecl
3286: .getGeneric(3)))
3287: .shape(false, name);
3288:
3289: // Check for storage class specifiers and initializers.
3290: if (type
3291: .hasAttribute(Constants.NAME_STORAGE)
3292: && (!type
3293: .hasAttribute(Constants.ATT_STORAGE_REGISTER))) {
3294: runtime.error(
3295: "storage class specified for parameter '"
3296: + name + "'",
3297: declaration);
3298: } else if (!type
3299: .hasAttribute(Constants.NAME_STORAGE)) {
3300: type = type
3301: .attribute(Constants.ATT_STORAGE_AUTO);
3302: }
3303:
3304: if (null != initDecl.get(4)) {
3305: runtime.error("parameter '" + name
3306: + "' is initialized", initDecl
3307: .getNode(4));
3308: }
3309:
3310: // Check for incomplete types.
3311: if (c().isIncomplete(type)) {
3312: if (type.resolve().isVoid()) {
3313: runtime.error("parameter '" + name
3314: + "' declared void",
3315: declaration);
3316: } else {
3317: runtime.error("parameter '" + name
3318: + "' has incomplete type",
3319: declaration);
3320: }
3321: }
3322:
3323: // Check parameter name and previous definitions.
3324: if (!names.contains(name)) {
3325: runtime
3326: .error(
3327: "declaration for parameter '"
3328: + name
3329: + "' but no such parameter",
3330: declaration);
3331:
3332: } else if (table.current()
3333: .isDefinedLocally(name)) {
3334: runtime.error(
3335: "redefinition of parameter '"
3336: + name + "'",
3337: declaration);
3338: } else {
3339: table.current().define(name, type);
3340: }
3341: }
3342: }
3343: }
3344: }
3345:
3346: // Next, we process any undeclared identifiers.
3347: for (String name : names) {
3348: if (!table.current().isDefinedLocally(name)) {
3349: final Type type = VariableT.newParam(C.IMPLICIT,
3350: name).attribute(Constants.ATT_STORAGE_AUTO)
3351: .shape(false, name);
3352: table.current().define(name, type);
3353:
3354: if (pedantic) {
3355: runtime.warning("type of '" + name
3356: + "' defaults to 'int'", node);
3357: }
3358: }
3359: }
3360:
3361: // Finally, for old-style declarations, we patch the function
3362: // type and, for new-style declarations, we compare the
3363: // parameter types.
3364: if (function.hasAttribute(Constants.ATT_STYLE_OLD)) {
3365: // An old-style declaration (or none).
3366: List<Type> types = function.getParameters();
3367: final int size = types.size();
3368: for (int i = 0; i < size; i++) {
3369: final Type t = types.get(i);
3370:
3371: // Old-style declarations have parameter types even if they
3372: // contain errors, since they always have a name.
3373: if (!t.hasError()) {
3374: final String name = t.toVariable().getName();
3375:
3376: if (table.current().isDefinedLocally(name)) {
3377: types.set(i, (Type) table.current()
3378: .lookupLocally(name));
3379: }
3380: }
3381: }
3382:
3383: } else {
3384: // A new-style declaration.
3385:
3386: // Fix parameters.
3387: if (null == parameters) {
3388: parameters = GNode.create("IdentifierList", false);
3389: }
3390:
3391: if (parameters.size() != function.getParameters()
3392: .size()) {
3393: runtime
3394: .error(
3395: "number of arguments doesn't match prototype",
3396: node);
3397:
3398: } else {
3399: final int size = parameters.size();
3400: for (int i = 0; i < size; i++) {
3401: final Type t1 = (Type) table.current()
3402: .lookupLocally(
3403: (String) parameters.get(i));
3404: final Type t2 = function.getParameters().get(i);
3405:
3406: if (t1.hasError() || t2.hasError()) {
3407: // Ignore.
3408: } else if (c().compose(t2,
3409: c().promoteArgument(t1), pedantic)
3410: .isError()) {
3411: runtime
3412: .error(
3413: "argument '"
3414: + t1.toVariable()
3415: .getName()
3416: + "' doesn't match prototype",
3417: node);
3418: } else if (pedantic
3419: && !c().hasSameQualifiers(t2, t1)) {
3420: // C99 6.7.5.3 15
3421: runtime
3422: .error(
3423: "type qualifiers of argument '"
3424: + t1.toVariable()
3425: .getName()
3426: + "' don't match prototype",
3427: node);
3428: }
3429: }
3430: }
3431: }
3432:
3433: } else {
3434: // A new-style definition.
3435: if (null != node.get(3)) {
3436: runtime.error(
3437: "old-style parameter declarations in prototyped "
3438: + "function definition", node
3439: .getNode(3));
3440: }
3441:
3442: // Note that void parameter lists are checked for
3443: // well-formedness by getParameterTypes(), which is invoked by
3444: // getDeclaredType(), which, in turn, is invoked by
3445: // visitFunctionDefinition().
3446: if (!isVoidParameterTypeList(parameters)) {
3447: parameters = parameters.getGeneric(0);
3448: Iterator<Object> iter1 = parameters.iterator();
3449: Iterator<Type> iter2 = function.getParameters()
3450: .iterator();
3451: while (iter1.hasNext()) {
3452: final GNode decl = GNode.cast(iter1.next());
3453: final Type type = iter2.next();
3454: final String name = type.hasVariable() ? type
3455: .toVariable().getName() : null;
3456:
3457: // Check for incomplete types.
3458: if (c().isIncomplete(type)) {
3459: if (null == name) {
3460: runtime
3461: .error(
3462: "unnamed parameter has incomplete type",
3463: decl);
3464: } else {
3465: runtime.error("parameter '" + name
3466: + "' has incomplete type", decl);
3467: }
3468: }
3469:
3470: // Add to symbol table.
3471: if (null == name) {
3472: if (!type.hasError()) {
3473: runtime.error("parameter name omitted",
3474: decl);
3475: }
3476: } else if (!table.current().isDefinedLocally(name)) {
3477: table.current().define(name, type);
3478: }
3479: }
3480: }
3481: }
3482: }
3483:
3484: /**
3485: * Check that all labels used in the specified top-level function
3486: * are also defined. This method requires that all relevant AST
3487: * nodes have been associated with their symbol table {@link
3488: * Constants#SCOPE scopes}.
3489: *
3490: * @param function The function to check.
3491: */
3492: protected void checkUsedLabels(GNode function) {
3493: checkUsedLabelsVisitor.dispatch(function);
3494: }
3495:
3496: /** The actual implementation of {@link #checkUsedLabels(GNode)}. */
3497: @SuppressWarnings("unused")
3498: private Visitor checkUsedLabelsVisitor = new Visitor() {
3499: private void check(String id, GNode labelRef) {
3500: final String name = SymbolTable.toLabelName(id);
3501:
3502: // Start looking for a definition in the current scope.
3503: Scope scope = table.current();
3504:
3505: // If there is a local declaration or definition, use that
3506: // one.
3507: while (!isFunctionScope(scope.getName())) {
3508: final Type type = (Type) scope.lookupLocally(name);
3509: if (null != type) {
3510: assert type.resolve().isLabel() : "Malformed label type";
3511: if (type.hasAttribute(Constants.ATT_UNINITIALIZED)) {
3512: runtime.error("label '" + id
3513: + "' used but not defined", labelRef);
3514: }
3515: type.addAttribute(Constants.ATT_USED);
3516: return;
3517: }
3518:
3519: scope = scope.getParent();
3520: }
3521:
3522: // Otherwise, check the function's scope.
3523: final Type type = (Type) scope.lookupLocally(name);
3524: if (null == type) {
3525: runtime.error(
3526: "label '" + id + "' used but not defined",
3527: labelRef);
3528: } else {
3529: if (type.hasAttribute(Constants.ATT_UNINITIALIZED)) {
3530: runtime.error("label '" + id
3531: + "' used but not defined", labelRef);
3532: }
3533: type.addAttribute(Constants.ATT_USED);
3534: }
3535: }
3536:
3537: public void visitGotoStatement(GNode n) {
3538: if (null == n.get(0)) {
3539: check(n.getGeneric(1).getString(0), n);
3540: }
3541: }
3542:
3543: public void visitLabelAddressExpression(GNode n) {
3544: check(n.getString(0), n);
3545: }
3546:
3547: public void visit(GNode n) {
3548: table.enter(n);
3549: for (Object o : n) {
3550: if (o instanceof Node)
3551: dispatch((Node) o);
3552: }
3553: table.exit(n);
3554: }
3555: };
3556:
3557: /**
3558: * Check that all labels defined in the specified top-level function
3559: * are also used. This method requires that all relevant AST nodes
3560: * have been associated with their symbol table {@link
3561: * Constants#SCOPE scopes} and that all used labels have been
3562: * annotated as {@link Constants#ATT_USED used}.
3563: *
3564: * @param function The function to check.
3565: */
3566: protected void checkDefinedLabels(GNode function) {
3567: @SuppressWarnings("unused")
3568: final Visitor v = new Visitor() {
3569: final Map<Type, Type> checkedDefined = new IdentityHashMap<Type, Type>();
3570: final Map<Type, Type> checkedUsed = new IdentityHashMap<Type, Type>();
3571:
3572: public void visitNamedLabel(GNode n) {
3573: final String id = n.getString(0);
3574: final String name = SymbolTable.toLabelName(id);
3575: final Type type = (Type) table.current().lookup(name);
3576:
3577: if (null != type) {
3578: if (!checkedUsed.containsKey(type)) {
3579: checkedUsed.put(type, type);
3580:
3581: if (!type.hasAttribute(Constants.ATT_USED)) {
3582: runtime.warning("label '" + id
3583: + "' defined but not used", n);
3584: }
3585: }
3586: }
3587: }
3588:
3589: public void visitLocalLabelDeclaration(GNode n) {
3590: for (Object o : n) {
3591: final String id = Token.cast(o);
3592: final String name = SymbolTable.toLabelName(id);
3593: final Type type = (Type) table.current().lookup(
3594: name);
3595:
3596: if (null != type) {
3597: if (!checkedDefined.containsKey(type)) {
3598: checkedDefined.put(type, type);
3599:
3600: if (type
3601: .hasAttribute(Constants.ATT_UNINITIALIZED)
3602: && !type
3603: .hasAttribute(Constants.ATT_USED)) {
3604: runtime.warning("label '" + id
3605: + "' declared but not defined",
3606: n);
3607: }
3608: }
3609: }
3610: }
3611: }
3612:
3613: public void visit(GNode n) {
3614: table.enter(n);
3615: for (Object o : n) {
3616: if (o instanceof Node)
3617: dispatch((Node) o);
3618: }
3619: table.exit(n);
3620: }
3621: };
3622: v.dispatch(function);
3623: }
3624:
3625: /** Visit the specified labeled statement. */
3626: public Type visitLabeledStatement(GNode n) {
3627: // Process the label.
3628: dispatch(n.getNode(0));
3629:
3630: // Process the statement. If the statement has a type, capture
3631: // that type.
3632: final Object o = dispatch(n.getNode(1));
3633: final Type result = (o instanceof Type) ? (Type) o : VoidT.TYPE;
3634:
3635: mark(n, result);
3636: return result;
3637: }
3638:
3639: /** Visit the specified named label. */
3640: public void visitNamedLabel(GNode n) {
3641: final String id = n.getString(0);
3642: final String name = SymbolTable.toLabelName(id);
3643: final List<Attribute> atts = toAttributeList(n.getGeneric(1));
3644:
3645: // Start looking for a suitable scope with the current scope.
3646: Scope scope = table.current();
3647:
3648: // If there is a local label declaration, define the label in the
3649: // declaration's scope.
3650: while (!isFunctionScope(scope.getName())) {
3651: final Type type = (Type) scope.lookupLocally(name);
3652:
3653: if (null != type) {
3654: assert type.isLabel() : "Malformed label type";
3655: if (type.hasAttribute(Constants.ATT_UNINITIALIZED)) {
3656: scope.define(name, new LabelT(id).locate(n)
3657: .attribute(Constants.ATT_DEFINED)
3658: .attribute(atts));
3659: } else {
3660: runtime.error("duplicate label '" + id + "'", n);
3661: reportPrevious(id, type);
3662: }
3663: return;
3664: }
3665:
3666: scope = scope.getParent();
3667: }
3668:
3669: // Define the label in the function's scope.
3670: final Type type = (Type) scope.lookupLocally(name);
3671:
3672: if (null != type
3673: && !type.hasAttribute(Constants.ATT_UNINITIALIZED)) {
3674: runtime.error("duplicate label '" + id + "'", n);
3675: reportPrevious(id, (Type) scope.lookupLocally(name));
3676: } else {
3677: scope.define(name, new LabelT(id).locate(n).attribute(
3678: Constants.ATT_DEFINED).attribute(atts));
3679: }
3680: }
3681:
3682: /** Visit the specified case label. */
3683: public void visitCaseLabel(GNode n) {
3684: if (0 == switches.size()) {
3685: runtime
3686: .error("case label not within a switch statement",
3687: n);
3688: return;
3689: }
3690:
3691: final Node n1 = n.getNode(0);
3692: final Type t1 = (Type) dispatch(n1);
3693: final Node n2 = (2 == n.size()) ? n.getNode(1) : null;
3694: final Type t2 = (Type) dispatch(n2);
3695:
3696: if (t1.isError() || (null != t2 && t2.isError())) {
3697: return;
3698:
3699: } else if ((!c().isIntegral(t1))
3700: || ((null != t2) && (!c().isIntegral(t2)))) {
3701: runtime.error("case label not of integer type", n);
3702: return;
3703:
3704: } else if ((!t1.hasConstant())
3705: || ((null != t2) && (!t2.hasConstant()))) {
3706: runtime.error("case label not constant", n);
3707: return;
3708: }
3709:
3710: if (null != t2) {
3711: // Test: i2 < i1
3712: try {
3713: if (t2.getConstant().bigIntValue().compareTo(
3714: t2.getConstant().bigIntValue()) < 0) {
3715: runtime.error("empty range in case label", n);
3716: }
3717: } catch (IllegalStateException x) {
3718: runtime.warning("can't compute range in case label", n);
3719: }
3720: }
3721: }
3722:
3723: /** Visit the specified default label. */
3724: public void visitDefaultLabel(GNode n) {
3725: if (0 == switches.size()) {
3726: runtime.error(
3727: "'default' label not within a switch statement", n);
3728: } else if (switches.get(switches.size() - 1)) {
3729: runtime.error("multiple default labels in one switch", n);
3730: } else {
3731: switches.set(switches.size() - 1, Boolean.TRUE);
3732: }
3733: }
3734:
3735: /** Visit the specified local label declaration. */
3736: public void visitLocalLabelDeclaration(GNode n) {
3737: for (Object o : n) {
3738: final String id = Token.cast(o);
3739: final String name = SymbolTable.toLabelName(id);
3740: if (table.current().isDefinedLocally(name)) {
3741: runtime.error("duplicate label declaration '" + id
3742: + "'", n);
3743: reportPrevious(id, (Type) table.current()
3744: .lookupLocally(name));
3745: } else {
3746: table.current().define(
3747: name,
3748: new LabelT(id).locate(n).attribute(
3749: Constants.ATT_UNINITIALIZED));
3750: }
3751: }
3752: }
3753:
3754: /** Visit the specified compound statement. */
3755: public Type visitCompoundStatement(GNode n) {
3756: final boolean scope = hasScope;
3757: hasScope = true;
3758: final boolean stmtexpr = isStmtAsExpr;
3759: isStmtAsExpr = false;
3760:
3761: if (scope || stmtexpr) {
3762: String name = table.freshName("block");
3763: table.enter(name);
3764: table.mark(n);
3765: }
3766:
3767: Type result = VoidT.TYPE;
3768:
3769: final int size = n.size();
3770: for (int i = 0; i < size; i++) {
3771: Object o = dispatch((Node) n.get(i));
3772:
3773: if ((size - 2 == i) && (o instanceof Type)) {
3774: // If the last statement (i.e., the child before the trailing
3775: // annotations) is an expression statement, capture that
3776: // expression's type.
3777: result = (Type) o;
3778: }
3779: }
3780:
3781: if (scope || stmtexpr) {
3782: table.exit();
3783: }
3784: hasScope = scope;
3785: return stmtexpr ? result : VoidT.TYPE;
3786: }
3787:
3788: /** Visit the specified if else statement. */
3789: public void visitIfElseStatement(GNode n) {
3790: final Node n1 = n.getNode(0);
3791: ensureScalar(n1, c().pointerize((Type) dispatch(n1)));
3792: dispatch(n.getNode(1));
3793: dispatch(n.getNode(2));
3794: }
3795:
3796: /** Visit the specified if else statement. */
3797: public void visitIfStatement(GNode n) {
3798: final Node n1 = n.getNode(0);
3799: ensureScalar(n1, c().pointerize((Type) dispatch(n1)));
3800: dispatch(n.getNode(1));
3801: }
3802:
3803: /** Visit the specified while statement. */
3804: public void visitWhileStatement(GNode n) {
3805: final Node n1 = n.getNode(0);
3806: ensureScalar(n1, c().pointerize((Type) dispatch(n1)));
3807:
3808: loops.add(Boolean.TRUE);
3809: dispatch(n.getNode(1));
3810: loops.remove(loops.size() - 1);
3811: }
3812:
3813: /** Visit the specified do statement. */
3814: public void visitDoStatement(GNode n) {
3815: loops.add(Boolean.TRUE);
3816: dispatch(n.getNode(0));
3817: loops.remove(loops.size() - 1);
3818:
3819: final Node n2 = n.getNode(1);
3820: ensureScalar(n2, c().pointerize((Type) dispatch(n2)));
3821: }
3822:
3823: /** Visit the specified for statement. */
3824: public void visitForStatement(GNode n) {
3825: final boolean scope = hasScope;
3826: hasScope = false;
3827: final String name = table.freshName("forloop");
3828: table.enter(name);
3829: table.mark(n);
3830:
3831: dispatch(n.getNode(0));
3832: if (null != n.get(1)) {
3833: Node n2 = n.getNode(1);
3834: ensureScalar(n2, c().pointerize((Type) dispatch(n2)));
3835: }
3836: dispatch(n.getNode(2));
3837:
3838: loops.add(Boolean.TRUE);
3839: dispatch(n.getNode(3));
3840: loops.remove(loops.size() - 1);
3841:
3842: table.exit();
3843: hasScope = scope;
3844: }
3845:
3846: /** Visit the specified switch statement. */
3847: public void visitSwitchStatement(GNode n) {
3848: final Node n1 = n.getNode(0);
3849: ensureInteger(n1, c().pointerize((Type) dispatch(n1)));
3850: switches.add(Boolean.FALSE);
3851: dispatch(n.getNode(1));
3852: switches.remove(switches.size() - 1);
3853: }
3854:
3855: /** Visit the specified break statement. */
3856: public void visitBreakStatement(GNode n) {
3857: if ((0 == switches.size()) && (0 == loops.size())) {
3858: runtime.error("break statement not within loop or switch",
3859: n);
3860: }
3861: }
3862:
3863: /** Visit the specified continue statement. */
3864: public void visitContinueStatement(GNode n) {
3865: if (0 == loops.size()) {
3866: runtime.error("continue statement not within a loop", n);
3867: }
3868: }
3869:
3870: /** Visit the specified return statement. */
3871: public Type visitReturnStatement(GNode n) {
3872: final Type t1 = (Type) dispatch(n.getNode(0));
3873:
3874: // Find the enclosing function scope.
3875: Scope scope = table.current();
3876: while (!isFunctionScope(scope.getName())) {
3877: scope = scope.getParent();
3878: }
3879:
3880: // Determine the function's name, type, and result type.
3881: final String name = SymbolTable.fromNameSpace(scope.getName());
3882: final Type function = (Type) scope.getParent().lookupLocally(
3883: name);
3884: final Type result = function.resolve().toFunction().getResult();
3885:
3886: // Check for consistenty.
3887: if (result.hasTag(Tag.VOID)) {
3888: if ((null != t1) && !t1.hasTag(Tag.VOID)) {
3889: runtime
3890: .warning(
3891: "'return' with a value, in function returning void",
3892: n);
3893: }
3894: } else {
3895: if (null != t1) {
3896: processAssignment(false, "return", n, result, t1);
3897: } else if (pedantic) {
3898: runtime.warning(
3899: "'return' with no value, in function returning "
3900: + "non-void", n);
3901: }
3902: }
3903:
3904: // Done.
3905: mark(n, result);
3906: return result;
3907: }
3908:
3909: /** Visit the specified goto statement. */
3910: public void visitGotoStatement(GNode n) {
3911: // Regular goto labels are check by checkLabels().
3912: if (null == n.get(0))
3913: return;
3914:
3915: // Computed goto statements are checked right here.
3916: final Node n1 = n.getNode(1);
3917: final Type t1 = (Type) dispatch(n1);
3918: if (ensureScalar(n1, t1) && t1.resolve().isFloat()) {
3919: runtime.error("cannot convert to pointer type", n);
3920: }
3921: }
3922:
3923: /** Visit the specified expression statement. */
3924: public Type visitExpressionStatement(GNode n) {
3925: final Type t = (Type) dispatch(n.getNode(0));
3926:
3927: // The resulting type is not an lvalue.
3928: final Type result = c().toRValue(t);
3929:
3930: mark(n, result);
3931: return result;
3932: }
3933:
3934: /** Visit the specified expression list. */
3935: public List visitExpressionList(GNode n) {
3936: // Create a list of expression types and return it.
3937: final List<Type> result = new ArrayList<Type>(n.size());
3938: for (Object o : n)
3939: result.add((Type) dispatch((Node) o));
3940: return result;
3941: }
3942:
3943: /**
3944: * Process the specified expression node. This method simply
3945: * dispatches this visitor on the specified node and returns the
3946: * resulting type. It is typically used from other visitors nested
3947: * in this class.
3948: *
3949: * @param n The expression node.
3950: * @return The corresponding type.
3951: */
3952: public Type processExpression(Node n) {
3953: return (Type) dispatch(n);
3954: }
3955:
3956: /** Visit the specified comma expression. */
3957: public Type visitCommaExpression(GNode n) {
3958: // C99 6.5.17
3959: dispatch(n.getNode(0));
3960: final Type t2 = (Type) dispatch(n.getNode(1));
3961: final Type r2 = c().pointerize(t2); // GCC performs pointer decay; so do we.
3962:
3963: // C99 6.5.17, footnote 95: the result is not an lvalue.
3964: final Type result = c().toRValue(r2);
3965:
3966: mark(n, result);
3967: return result;
3968: }
3969:
3970: /** Visit the specified assignment expression. */
3971: public Type visitAssignmentExpression(GNode n) {
3972: // C99 6.5.16
3973: final Node n1 = n.getNode(0);
3974: final String op = n.getString(1);
3975: final Node n2 = n.getNode(2);
3976:
3977: final Type t1 = (Type) dispatch(n1);
3978: final Type t2 = (Type) dispatch(n2);
3979:
3980: Type result;
3981: if (t1.hasError() || t2.hasError()) {
3982: // Nothing to see here. Move on.
3983: result = ErrorT.TYPE;
3984:
3985: } else if ("=".equals(op)) {
3986: final boolean cond1 = ensureLValue(n1, t1);
3987: result = processAssignment(false, "assignment", n, t1, t2);
3988:
3989: // Patch in error type.
3990: if (!cond1)
3991: result = ErrorT.TYPE;
3992:
3993: } else if ("+=".equals(op) || "-=".equals(op)) {
3994: // Addition and subtraction require either arithmetic operands
3995: // or the left side to be a pointer and the right side to be an
3996: // integer.
3997: final Type r1 = t1.resolve();
3998:
3999: switch (r1.tag()) {
4000: case BOOLEAN:
4001: case INTEGER:
4002: case FLOAT: {
4003: final boolean cond1 = ensureLValue(n1, t1);
4004: final boolean cond2 = ensureArithmetic(n2, t2);
4005: result = cond1 && cond2 ? r1 : ErrorT.TYPE;
4006: }
4007: break;
4008:
4009: case POINTER: {
4010: final boolean cond1 = ensureLValue(n1, t1);
4011: final boolean cond2 = ensureInteger(n2, t2);
4012: result = cond1 && cond2 ? r1 : ErrorT.TYPE;
4013: }
4014: break;
4015:
4016: default:
4017: runtime.error("invalid " + toDescription(n1)
4018: + " where scalar required", n1);
4019: result = ErrorT.TYPE;
4020: }
4021:
4022: } else if ("*=".equals(op) || "/=".equals(op)) {
4023: // Multiplication and division require arithmetic operands.
4024: final boolean cond1 = ensureArithmetic(n1, t1)
4025: && ensureLValue(n1, t1);
4026: final boolean cond2 = ensureArithmetic(n2, t2);
4027: result = cond1 && cond2 ? t1.resolve() : ErrorT.TYPE;
4028:
4029: } else {
4030: // Modulo, shift, bitwise and, bitwise xor, and bitwise or
4031: // require integer operands.
4032: final boolean cond1 = ensureInteger(n1, t1)
4033: && ensureLValue(n1, t1);
4034: final boolean cond2 = ensureInteger(n2, t2);
4035: result = cond1 && cond2 ? t1.resolve() : ErrorT.TYPE;
4036: }
4037:
4038: mark(n, result);
4039: return result;
4040: }
4041:
4042: /** Visit the specified conditional expression. */
4043: public Type visitConditionalExpression(GNode n) {
4044: // C99 6.5.15
4045: final Node n1 = n.getNode(0);
4046: final Node n2 = n.getNode(1);
4047: final Node n3 = n.getNode(2);
4048:
4049: final Type t1 = (Type) dispatch(n1);
4050: Type t2 = (Type) dispatch(n2);
4051: final Type t3 = (Type) dispatch(n3);
4052:
4053: if (null == t2)
4054: t2 = t1; // Allow for GCC's omitted middle operand.
4055:
4056: final Type r2 = c().pointerize(t2);
4057: final Type r3 = c().pointerize(t3);
4058:
4059: Type result;
4060: final boolean cond1 = ensureScalar(n1, c().pointerize(t1));
4061: if (r2.isError() || r3.isError()) {
4062: result = ErrorT.TYPE;
4063:
4064: } else if (c().isArithmetic(t2) && c().isArithmetic(t3)) {
4065: result = cond1 ? c().convert(t2, t3) : ErrorT.TYPE;
4066: result = valueConditional(result, t1, t2, t3);
4067:
4068: } else if ((r2.isStruct() && r3.isStruct() && c().equal(t2, t3))
4069: || (r2.isUnion() && r3.isUnion() && c().equal(t2, t3))) {
4070: result = cond1 ? c().qualify(r2, t2) : ErrorT.TYPE;
4071:
4072: } else if (r2.isVoid() && r3.isVoid()) {
4073: result = cond1 ? (Type) VoidT.TYPE : ErrorT.TYPE;
4074:
4075: } else if (r2.isPointer() && t3.hasConstant()
4076: && t3.getConstant().isNull()) {
4077: result = cond1 ? c().qualify(r2, t2) : ErrorT.TYPE;
4078: result = valueConditional(result, t1, t2, t3);
4079:
4080: } else if (t2.hasConstant() && t2.getConstant().isNull()
4081: && r3.isPointer()) {
4082: result = cond1 ? c().qualify(r3, t3) : ErrorT.TYPE;
4083: result = valueConditional(result, t1, t2, t3);
4084:
4085: } else if (r2.isPointer() && r3.isPointer()) {
4086: final Type pt2 = r2.toPointer().getType(); // PointedTo, PointedToResolved
4087: final Type pt3 = r3.toPointer().getType();
4088:
4089: final Type ptr2 = pt2.resolve();
4090: final Type ptr3 = pt3.resolve();
4091:
4092: if (ptr2.isError() || ptr3.isError()) {
4093: result = ErrorT.TYPE;
4094:
4095: } else if (c().equal(ptr2, ptr3)) {
4096: if (cond1) {
4097: result = new PointerT(c().qualify(
4098: c().qualify(ptr2, pt2), pt3));
4099: result = c().qualify(c().qualify(result, t2), t3);
4100: result = valueConditional(result, t1, t2, t3);
4101: } else {
4102: result = ErrorT.TYPE;
4103: }
4104:
4105: } else if (ptr2.isVoid() || ptr3.isVoid()) {
4106: if (cond1) {
4107: result = new PointerT(c().qualify(
4108: c().qualify(VoidT.TYPE, pt2), pt3));
4109: result = c().qualify(c().qualify(result, t2), t3);
4110: result = valueConditional(result, t1, t2, t3);
4111: } else {
4112: result = ErrorT.TYPE;
4113: }
4114:
4115: } else {
4116: runtime
4117: .error(
4118: "pointer type mismatch in conditional expression",
4119: n);
4120: result = ErrorT.TYPE;
4121: }
4122:
4123: } else if ((c().isIntegral(t2) && r3.isPointer())
4124: || (r2.isPointer() && c().isIntegral(t3))) {
4125: runtime
4126: .error(
4127: "pointer/integer type mismatch in conditional expression",
4128: n);
4129: result = ErrorT.TYPE;
4130:
4131: } else {
4132: runtime.error("type mismatch in conditional expression", n);
4133: result = ErrorT.TYPE;
4134: }
4135:
4136: mark(n, result);
4137: return result;
4138: }
4139:
4140: /**
4141: * Determine a conditional expression's value. If a conditional
4142: * expression's value can be statically determined, this method
4143: * annotates the expression's result with that value.
4144: *
4145: * @param result The result type.
4146: * @param t1 The conditional's type.
4147: * @param t2 The consequence's type.
4148: * @param t3 The alternative's type.
4149: * @return The annotated result type.
4150: */
4151: protected Type valueConditional(Type result, Type t1, Type t2,
4152: Type t3) {
4153: if (result.isError())
4154: return result;
4155:
4156: if (t1.hasConstant()) {
4157: final Type type = t1.getConstant().isTrue() ? t2 : t3;
4158:
4159: if (type.hasConstant()) {
4160: result = result.annotate().constant(
4161: type.getConstant().getValue());
4162: }
4163: }
4164: return result;
4165: }
4166:
4167: /** Visit the specified logical or expression. */
4168: public Type visitLogicalOrExpression(GNode n) {
4169: // C99 6.5.14
4170: final Node n1 = n.getNode(0);
4171: final Node n2 = n.getNode(1);
4172: final Type t1 = (Type) dispatch(n1);
4173: final Type t2 = (Type) dispatch(n2);
4174:
4175: Type result;
4176: final boolean cond1 = ensureScalar(n1, c().pointerize(t1));
4177: final boolean cond2 = ensureScalar(n2, c().pointerize(t2));
4178: if (cond1 && cond2) {
4179: result = NumberT.INT;
4180:
4181: if (t1.hasConstant()) {
4182: if (t1.getConstant().isTrue()) {
4183: result = result.annotate().constant(true);
4184: } else if (t2.hasConstant()) {
4185: result = result.annotate().constant(
4186: t2.getConstant().isTrue());
4187: }
4188: }
4189:
4190: } else {
4191: result = ErrorT.TYPE;
4192: }
4193:
4194: mark(n, result);
4195: return result;
4196: }
4197:
4198: /** Visit the specified logical and expression. */
4199: public Type visitLogicalAndExpression(GNode n) {
4200: // C99 6.5.13
4201: final Node n1 = n.getNode(0);
4202: final Node n2 = n.getNode(1);
4203: final Type t1 = (Type) dispatch(n1);
4204: final Type t2 = (Type) dispatch(n2);
4205:
4206: Type result;
4207: final boolean cond1 = ensureScalar(n1, c().pointerize(t1));
4208: final boolean cond2 = ensureScalar(n2, c().pointerize(t2));
4209: if (cond1 && cond2) {
4210: result = NumberT.INT;
4211:
4212: if (t1.hasConstant()) {
4213: if (!t1.getConstant().isTrue()) {
4214: result = result.annotate().constant(false);
4215: } else if (t2.hasConstant()) {
4216: result = result.annotate().constant(
4217: t2.getConstant().isTrue());
4218: }
4219: }
4220:
4221: } else {
4222: result = ErrorT.TYPE;
4223: }
4224:
4225: mark(n, result);
4226: return result;
4227: }
4228:
4229: /** Visit the specified bitwise or expression. */
4230: public Type visitBitwiseOrExpression(GNode n) {
4231: // C99 6.5.12
4232: final Node n1 = n.getNode(0);
4233: final Node n2 = n.getNode(1);
4234: final Type t1 = (Type) dispatch(n1);
4235: final Type t2 = (Type) dispatch(n2);
4236:
4237: Type result;
4238: final boolean cond1 = ensureInteger(n1, t1);
4239: final boolean cond2 = ensureInteger(n2, t2);
4240: if (cond1 && cond2) {
4241: result = c().convert(t1, t2);
4242:
4243: if (t1.hasConstant() && t2.hasConstant()) {
4244: result = result.annotate();
4245: try {
4246: result = result.constant(c().mask(
4247: t1.getConstant().bigIntValue(), result).or(
4248: c().mask(t2.getConstant().bigIntValue(),
4249: result)));
4250: } catch (IllegalStateException x) {
4251: result = result
4252: .constant(new StaticReference(result));
4253: }
4254: }
4255:
4256: } else {
4257: result = ErrorT.TYPE;
4258: }
4259:
4260: mark(n, result);
4261: return result;
4262: }
4263:
4264: /** Visit the specified bitwise xor expression. */
4265: public Type visitBitwiseXorExpression(GNode n) {
4266: // C99 6.5.11
4267: final Node n1 = n.getNode(0);
4268: final Node n2 = n.getNode(1);
4269: final Type t1 = (Type) dispatch(n1);
4270: final Type t2 = (Type) dispatch(n2);
4271:
4272: Type result;
4273: final boolean cond1 = ensureInteger(n1, t1);
4274: final boolean cond2 = ensureInteger(n2, t2);
4275: if (cond1 && cond2) {
4276: result = c().convert(t1, t2);
4277:
4278: if (t1.hasConstant() && t2.hasConstant()) {
4279: result = result.annotate();
4280: try {
4281: result = result.constant(c().mask(
4282: t1.getConstant().bigIntValue(), result)
4283: .xor(
4284: c().mask(
4285: t2.getConstant()
4286: .bigIntValue(),
4287: result)));
4288: } catch (IllegalStateException x) {
4289: result = result
4290: .constant(new StaticReference(result));
4291: }
4292: }
4293:
4294: } else {
4295: result = ErrorT.TYPE;
4296: }
4297:
4298: mark(n, result);
4299: return result;
4300: }
4301:
4302: /** Visit the specified bitwise and expression. */
4303: public Type visitBitwiseAndExpression(GNode n) {
4304: // C99 6.5.10
4305: final Node n1 = n.getNode(0);
4306: final Node n2 = n.getNode(1);
4307: final Type t1 = (Type) dispatch(n1);
4308: final Type t2 = (Type) dispatch(n2);
4309:
4310: Type result;
4311: final boolean cond1 = ensureInteger(n1, t1);
4312: final boolean cond2 = ensureInteger(n2, t2);
4313: if (cond1 && cond2) {
4314: result = c().convert(t1, t2);
4315:
4316: if (t1.hasConstant() && t2.hasConstant()) {
4317: result = result.annotate();
4318: try {
4319: result = result.constant(c().mask(
4320: t1.getConstant().bigIntValue(), result)
4321: .and(
4322: c().mask(
4323: t2.getConstant()
4324: .bigIntValue(),
4325: result)));
4326: } catch (IllegalStateException x) {
4327: result = result
4328: .constant(new StaticReference(result));
4329: }
4330: }
4331:
4332: } else {
4333: result = ErrorT.TYPE;
4334: }
4335:
4336: mark(n, result);
4337: return result;
4338: }
4339:
4340: /** Visit the specified equality expression. */
4341: public Type visitEqualityExpression(GNode n) {
4342: // C99 6.5.9
4343: final Node n1 = n.getNode(0);
4344: final String op = n.getString(1);
4345: final Node n2 = n.getNode(2);
4346: final Type t1 = (Type) dispatch(n1);
4347: final Type t2 = (Type) dispatch(n2);
4348: final Type r1 = c().pointerize(t1);
4349: final Type r2 = c().pointerize(t2);
4350:
4351: Type result;
4352: if (r1.isError() || r2.isError()) {
4353: // Nothing to see here. Move on.
4354: result = ErrorT.TYPE;
4355:
4356: } else if (c().isArithmetic(t1) && c().isArithmetic(t2)) {
4357: result = NumberT.INT;
4358:
4359: if (t1.hasConstant() && t2.hasConstant()) {
4360: result = result.annotate();
4361: try {
4362: if (c().isIntegral(r1) && c().isIntegral(r2)) {
4363: final BigInteger i1 = t1.getConstant()
4364: .bigIntValue();
4365: final BigInteger i2 = t2.getConstant()
4366: .bigIntValue();
4367:
4368: result = result.constant("==".equals(op) ? i1
4369: .compareTo(i2) == 0
4370: : i1.compareTo(i2) != 0);
4371:
4372: } else {
4373: final double d1 = t1.getConstant()
4374: .doubleValue();
4375: final double d2 = t2.getConstant()
4376: .doubleValue();
4377:
4378: result = result
4379: .constant("==".equals(op) ? d1 == d2
4380: : d1 != d2);
4381: }
4382: } catch (IllegalStateException x) {
4383: result = result
4384: .constant(new StaticReference(result));
4385: }
4386: }
4387:
4388: } else if (r1.isPointer() && t2.hasConstant()
4389: && t2.getConstant().isNull()) {
4390: result = NumberT.INT;
4391:
4392: if (t1.hasConstant()) {
4393: result = result.annotate().constant(
4394: !t1.getConstant().isTrue());
4395: }
4396:
4397: } else if (t1.hasConstant() && t1.getConstant().isNull()
4398: && r2.isPointer()) {
4399: result = NumberT.INT;
4400:
4401: if (t2.hasConstant()) {
4402: result = result.annotate().constant(
4403: !t2.getConstant().isTrue());
4404: }
4405:
4406: } else if (r1.isPointer() && r2.isPointer()) {
4407: final Type ptr1 = r1.toPointer().getType().resolve(); // PointedToResolved
4408: final Type ptr2 = r2.toPointer().getType().resolve();
4409:
4410: if (ptr1.isError() || ptr2.isError()) {
4411: result = ErrorT.TYPE;
4412:
4413: } else if (c().equal(ptr1, ptr2) || ptr1.isVoid()
4414: || ptr2.isVoid()) {
4415: result = NumberT.INT;
4416:
4417: if (t1.hasConstant() && t2.hasConstant()) {
4418: final boolean equal = t1.getConstant().getValue()
4419: .equals(t2.getConstant().getValue());
4420: result = result.annotate().constant(
4421: "==".equals(op) ? equal : !equal);
4422: }
4423:
4424: } else {
4425: runtime
4426: .error(
4427: "comparison of distinct pointer types lacks a cast",
4428: n);
4429: result = ErrorT.TYPE;
4430: }
4431:
4432: } else {
4433: runtime.error("invalid operands to 'binary " + op + "'", n);
4434: result = ErrorT.TYPE;
4435: }
4436:
4437: mark(n, result);
4438: return result;
4439: }
4440:
4441: /** Visit the specified relational expression. */
4442: public Type visitRelationalExpression(GNode n) {
4443: // C99 6.5.8
4444: final Node n1 = n.getNode(0);
4445: final String op = n.getString(1);
4446: final Node n2 = n.getNode(2);
4447: final Type t1 = (Type) dispatch(n1);
4448: final Type t2 = (Type) dispatch(n2);
4449: final Type r1 = c().pointerize(t1);
4450: final Type r2 = c().pointerize(t2);
4451:
4452: Type result;
4453: if (r1.isError() || r2.isError()) {
4454: // Nothing to see here. Move on.
4455: result = ErrorT.TYPE;
4456:
4457: } else if (c().isReal(t1) && c().isReal(t2)) {
4458: result = NumberT.INT;
4459:
4460: if (t1.hasConstant() && t2.hasConstant()) {
4461: result = result.annotate();
4462: try {
4463: if (c().isIntegral(r1) && c().isIntegral(r2)) {
4464: final BigInteger i1 = t1.getConstant()
4465: .bigIntValue();
4466: final BigInteger i2 = t2.getConstant()
4467: .bigIntValue();
4468:
4469: if ("<".equals(op)) {
4470: result = result
4471: .constant(i1.compareTo(i2) < 0);
4472: } else if (">".equals(op)) {
4473: result = result
4474: .constant(i1.compareTo(i2) > 0);
4475: } else if ("<=".equals(op)) {
4476: result = result
4477: .constant(i1.compareTo(i2) <= 0);
4478: } else {
4479: result = result
4480: .constant(i1.compareTo(i2) >= 0);
4481: }
4482:
4483: } else {
4484: final double d1 = t1.getConstant()
4485: .doubleValue();
4486: final double d2 = t2.getConstant()
4487: .doubleValue();
4488:
4489: if ("<".equals(op)) {
4490: result = result.constant(d1 < d2);
4491: } else if (">".equals(op)) {
4492: result = result.constant(d1 > d2);
4493: } else if ("<=".equals(op)) {
4494: result = result.constant(d1 <= d2);
4495: } else {
4496: result = result.constant(d1 >= d2);
4497: }
4498: }
4499: } catch (IllegalStateException x) {
4500: result = result
4501: .constant(new StaticReference(result));
4502: }
4503: }
4504:
4505: } else if (r1.isPointer() && r2.isPointer()) {
4506: final Type ptr1 = r1.toPointer().getType().resolve(); // PointedToResolved
4507: final Type ptr2 = r2.toPointer().getType().resolve();
4508:
4509: if (ptr1.isError() || ptr2.isError()) {
4510: result = ErrorT.TYPE;
4511:
4512: } else if (c().equal(ptr1, ptr2)) {
4513: result = NumberT.INT;
4514:
4515: if (t1.hasConstant() && t2.hasConstant()) {
4516: result = result.annotate().constant(
4517: new StaticReference(result));
4518: }
4519:
4520: } else {
4521: runtime
4522: .error(
4523: "comparison of distinct pointer types lacks a cast",
4524: n);
4525: result = ErrorT.TYPE;
4526: }
4527:
4528: } else {
4529: runtime.error("invalid operands to 'binary " + op + "'", n);
4530: result = ErrorT.TYPE;
4531: }
4532:
4533: mark(n, result);
4534: return result;
4535: }
4536:
4537: /** Visit the specified shift expression. */
4538: public Type visitShiftExpression(GNode n) {
4539: // C99 6.5.7
4540: final Node n1 = n.getNode(0);
4541: final String op = n.getString(1);
4542: final Node n2 = n.getNode(2);
4543:
4544: final Type t1 = (Type) dispatch(n1);
4545: final Type t2 = (Type) dispatch(n2);
4546:
4547: Type result;
4548: final boolean cond1 = ensureInteger(n1, t1);
4549: final boolean cond2 = ensureInteger(n2, t2);
4550: if (cond1 && cond2) {
4551: result = c().promote(t1);
4552:
4553: if (t2.hasConstant()) {
4554: BigInteger distance;
4555: try {
4556: distance = t2.getConstant().bigIntValue();
4557: } catch (IllegalStateException x) {
4558: runtime.warning("can't compute shift count", n2);
4559: distance = BigInteger.ZERO;
4560: }
4561: final BigInteger width = BigInteger.valueOf(c()
4562: .getWidth(result));
4563:
4564: // Test: distance >= width
4565: if (distance.compareTo(width) >= 0) {
4566: if ("<<".equals(op)) {
4567: runtime
4568: .warning(
4569: "left shift count >= width of type",
4570: n2);
4571: } else {
4572: runtime.warning(
4573: "right shift count >= width of type",
4574: n2);
4575: }
4576:
4577: // Test: distance < 0
4578: } else if (distance.compareTo(BigInteger.ZERO) < 0) {
4579: if ("<<".equals(op)) {
4580: runtime.warning("left shift count is negative",
4581: n2);
4582: } else {
4583: runtime.warning(
4584: "right shift count is negative", n2);
4585: }
4586:
4587: } else if (t1.hasConstant()) {
4588: result = result.annotate();
4589: try {
4590: final BigInteger value = t1.getConstant()
4591: .bigIntValue();
4592:
4593: if ("<<".equals(op)) {
4594: result = result.constant(value
4595: .shiftLeft(distance.intValue()));
4596: result = c().qualify(result, t1);
4597: } else {
4598: result = result.constant(value
4599: .shiftRight(distance.intValue()));
4600: result = c().qualify(result, t1);
4601: }
4602: } catch (IllegalStateException x) {
4603: result = result.constant(new StaticReference(
4604: result));
4605: result = c().qualify(result, t1);
4606: }
4607:
4608: } else {
4609: result = c().qualify(result, t1);
4610: }
4611:
4612: } else {
4613: result = c().qualify(result, t1);
4614: }
4615:
4616: } else {
4617: result = ErrorT.TYPE;
4618: }
4619:
4620: mark(n, result);
4621: return result;
4622: }
4623:
4624: /** Visit the specified additive expression. */
4625: public Type visitAdditiveExpression(GNode n) {
4626: // C99 6.5.6
4627: final Node n1 = n.getNode(0);
4628: final String op = n.getString(1);
4629: final Node n2 = n.getNode(2);
4630: final Type t1 = (Type) dispatch(n1);
4631: final Type t2 = (Type) dispatch(n2);
4632: final Type r1 = c().pointerize(t1);
4633: final Type r2 = c().pointerize(t2);
4634:
4635: Type result;
4636: if (r1.isError() || r2.isError()) {
4637: result = ErrorT.TYPE;
4638:
4639: } else if (c().isArithmetic(t1) && c().isArithmetic(t2)) {
4640: result = c().convert(t1, t2);
4641:
4642: if (t1.hasConstant() && t2.hasConstant()) {
4643: result = result.annotate();
4644: if (c().isIntegral(result)) {
4645: // If one of the terms has a reference value, try to
4646: // preserve a meaningful value.
4647: if (t1.getConstant().isReference()
4648: && (!t2.getConstant().isReference())) {
4649:
4650: if ("+".equals(op)) {
4651: // ref + int
4652: result = result.constant(t1.getConstant()
4653: .refValue().add(
4654: t2.getConstant()
4655: .bigIntValue()));
4656: } else {
4657: // ref - int
4658: result = result.constant(t1.getConstant()
4659: .refValue().subtract(
4660: t2.getConstant()
4661: .bigIntValue()));
4662: }
4663:
4664: } else if ((!t1.getConstant().isReference())
4665: && "+".equals(op)
4666: && t2.getConstant().isReference()) {
4667: // int + ref
4668: result = result
4669: .constant(t2.getConstant().refValue()
4670: .add(
4671: t1.getConstant()
4672: .bigIntValue()));
4673:
4674: } else if (t1.getConstant().isReference()
4675: && "-".equals(op)
4676: && t2.getConstant().isReference()) {
4677: // ref - ref
4678: final BigInteger diff = t1.getConstant()
4679: .refValue().difference(
4680: t2.getConstant().refValue());
4681: if (null != diff) {
4682: result = result.constant(diff);
4683: } else {
4684: result = result
4685: .constant(new StaticReference(
4686: result));
4687: }
4688:
4689: } else {
4690: try {
4691: final BigInteger i1 = t1.getConstant()
4692: .bigIntValue();
4693: final BigInteger i2 = t2.getConstant()
4694: .bigIntValue();
4695:
4696: // int + int
4697: result = result
4698: .constant("+".equals(op) ? i1
4699: .add(i2) : i1.subtract(i2));
4700: } catch (IllegalStateException x) {
4701: // ref + ref
4702: result = result
4703: .constant(new StaticReference(
4704: result));
4705: }
4706: }
4707:
4708: } else {
4709: try {
4710: final double d1 = t1.getConstant()
4711: .doubleValue();
4712: final double d2 = t2.getConstant()
4713: .doubleValue();
4714:
4715: result = result.constant("+".equals(op) ? d1
4716: + d2 : d1 - d2);
4717: } catch (IllegalStateException x) {
4718: result = result.constant(new StaticReference(
4719: result));
4720: }
4721: }
4722: }
4723:
4724: } else if ("+".equals(op)) {
4725: if (r1.isPointer() && c().isIntegral(r2)) {
4726: if (ensurePointerArithmetic(n, r1)) {
4727: result = r1;
4728:
4729: if (c().hasConstRef(t1) && t2.hasConstant()) {
4730: result = result.annotate();
4731: try {
4732: result = result.constant(c()
4733: .getConstRef(t1).add(
4734: t2.getConstant()
4735: .bigIntValue()));
4736: } catch (IllegalStateException x) {
4737: result = result
4738: .constant(new StaticReference(
4739: result));
4740: }
4741: }
4742: } else {
4743: result = ErrorT.TYPE;
4744: }
4745:
4746: } else if (c().isIntegral(r1) && r2.isPointer()) {
4747: if (ensurePointerArithmetic(n, r2)) {
4748: result = r2;
4749:
4750: if (t1.hasConstant() && c().hasConstRef(t2)) {
4751: result = result.annotate();
4752: try {
4753: result = result.constant(c()
4754: .getConstRef(t2).add(
4755: t1.getConstant()
4756: .bigIntValue()));
4757: } catch (IllegalStateException x) {
4758: result = result
4759: .constant(new StaticReference(
4760: result));
4761: }
4762: }
4763: } else {
4764: result = ErrorT.TYPE;
4765: }
4766:
4767: } else {
4768: runtime.error("invalid operands to 'binary +'", n);
4769: result = ErrorT.TYPE;
4770: }
4771:
4772: } else if (r1.isPointer() && r2.isPointer()) {
4773: final Type ptr1 = r1.toPointer().getType().resolve();
4774: final Type ptr2 = r2.toPointer().getType().resolve();
4775:
4776: if (ptr1.isError() || ptr2.isError()) {
4777: result = ErrorT.TYPE;
4778:
4779: } else if (c().equal(ptr1, ptr2)) {
4780: result = C.PTR_DIFF;
4781:
4782: if (c().hasConstRef(t1) && c().hasConstRef(t2)) {
4783: BigInteger diff = c().getConstRef(t1).difference(
4784: c().getConstRef(t2));
4785:
4786: result = result.annotate();
4787: if (null == diff) {
4788: result = result.constant(new StaticReference(
4789: result));
4790: } else {
4791: result = result.constant(diff);
4792: }
4793: }
4794:
4795: } else {
4796: runtime.error("invalid operands to 'binary -'", n);
4797: result = ErrorT.TYPE;
4798: }
4799:
4800: } else if (r1.isPointer() && c().isIntegral(r2)) {
4801: if (ensurePointerArithmetic(n, r1)) {
4802: result = r1;
4803: if (c().hasConstRef(t1) && t2.hasConstant()) {
4804: result = result.annotate();
4805: try {
4806: result = result
4807: .constant(c().getConstRef(t1).subtract(
4808: t2.getConstant().bigIntValue()));
4809: } catch (IllegalStateException x) {
4810: result = result.constant(new StaticReference(
4811: result));
4812: }
4813: }
4814: } else {
4815: result = ErrorT.TYPE;
4816: }
4817:
4818: } else {
4819: runtime.error("invalid operands to 'binary -'", n);
4820: result = ErrorT.TYPE;
4821: }
4822:
4823: mark(n, result);
4824: return result;
4825: }
4826:
4827: /** Visit the specified multiplicative expression. */
4828: public Type visitMultiplicativeExpression(GNode n) {
4829: // C99 6.5.5
4830: final Node n1 = n.getNode(0);
4831: final String op = n.getString(1);
4832: final Node n2 = n.getNode(2);
4833: final Type t1 = (Type) dispatch(n1);
4834: final Type t2 = (Type) dispatch(n2);
4835:
4836: Type result;
4837: final boolean cond1 = (("%".equals(op) && ensureInteger(n1, t1)) || ((!"%"
4838: .equals(op)) && ensureArithmetic(n1, t1)));
4839: final boolean cond2 = (("%".equals(op) && ensureInteger(n2, t2)) || ((!"%"
4840: .equals(op)) && ensureArithmetic(n2, t2)));
4841: if (cond1 && cond2) {
4842: result = c().convert(t1, t2);
4843:
4844: if (t2.hasConstant()) {
4845: Constant c2 = t2.getConstant();
4846:
4847: if ((!"*".equals(op)) && (!c2.isTrue())) {
4848: runtime.warning("division by zero", n2);
4849:
4850: } else if (t1.hasConstant()) {
4851: Constant c1 = t1.getConstant();
4852: result = result.annotate();
4853:
4854: try {
4855: if (c().isIntegral(result)) {
4856: BigInteger i1 = c1.bigIntValue();
4857: BigInteger i2 = c2.bigIntValue();
4858:
4859: if ("*".equals(op)) {
4860: result = result.constant(i1
4861: .multiply(i2));
4862: } else if ("/".equals(op)) {
4863: result = result.constant(i1.divide(i2));
4864: } else {
4865: result = result.constant(i1
4866: .remainder(i2));
4867: }
4868:
4869: } else {
4870: double d1 = c1.doubleValue();
4871: double d2 = c2.doubleValue();
4872:
4873: result = result
4874: .constant("*".equals(op) ? d1 * d2
4875: : d1 / d2);
4876: }
4877: } catch (IllegalStateException x) {
4878: result = result.constant(new StaticReference(
4879: result));
4880: }
4881: }
4882: }
4883:
4884: } else {
4885: result = ErrorT.TYPE;
4886: }
4887:
4888: mark(n, result);
4889: return result;
4890: }
4891:
4892: /** Visit the specified cast expression. */
4893: public Type visitCastExpression(GNode n) {
4894: // C99 6.5.4, 6.3.2.3
4895: final Node n1 = n.getNode(0);
4896: final Node n2 = n.getNode(1);
4897: final Type t1 = (Type) dispatch(n1);
4898: final Type t2 = (Type) dispatch(n2);
4899: final Type r1 = t1.resolve();
4900: final Type r2 = c().pointerize(t2);
4901:
4902: // As an exception, GCC allows a struct or union cast to itself,
4903: // ignoring qualifiers.
4904: final boolean gcc = (!pedantic && r1.hasStructOrUnion()
4905: && r2.hasStructOrUnion() && c().equal(r1, r2));
4906: Type result;
4907: final boolean cond2 = r1.isVoid() || gcc
4908: || ensureScalar(n2, r2);
4909: switch (r1.tag()) {
4910: case ERROR: {
4911: result = ErrorT.TYPE;
4912: }
4913: break;
4914:
4915: case VOID: {
4916: // Cast to void.
4917: result = t1;
4918: }
4919: break;
4920:
4921: case POINTER: {
4922: // Cast to a pointer.
4923: if (!cond2) {
4924: result = ErrorT.TYPE;
4925:
4926: } else if (r2.isFloat()) {
4927: runtime.error("cannot convert to pointer type", n);
4928: result = ErrorT.TYPE;
4929:
4930: } else if (c().isIntegral(r2)) {
4931: // Cast from an integer.
4932: result = t1;
4933:
4934: if (t2.hasConstant()) {
4935: Type pt1 = r1.toPointer().getType();
4936:
4937: // Capture the memory location.
4938: Reference ref;
4939: try {
4940: ref = NullReference.NULL.add(t2.getConstant()
4941: .bigIntValue());
4942: } catch (IllegalStateException x) {
4943: ref = new StaticReference(pt1);
4944: }
4945:
4946: result = result.annotate();
4947: if (pt1.hasTag(Tag.VOID) || c().isChar(pt1)
4948: || ref.isStatic()) {
4949: result = result.constant(ref);
4950: } else {
4951: result = result.constant(new CastReference(pt1,
4952: ref));
4953: }
4954: }
4955:
4956: } else {
4957: // Cast from another pointer.
4958: result = r1;
4959:
4960: if (c().hasConstRef(t2)) {
4961: Type pt1 = r1.toPointer().getType();
4962: Type pt2 = r2.toPointer().getType();
4963: result = result.annotate();
4964:
4965: if (pt1.equals(pt2)) {
4966: // The types have the same memory shape.
4967: result = result.constant(c().getConstRef(t2));
4968:
4969: } else {
4970: // The types have different shapes.
4971: result = result.constant(new CastReference(pt1,
4972: c().getConstRef(t2)));
4973: }
4974: }
4975: }
4976: }
4977: break;
4978:
4979: case BOOLEAN:
4980: case INTEGER:
4981: case FLOAT: {
4982: // Cast to a number.
4983: if (!cond2) {
4984: result = ErrorT.TYPE;
4985:
4986: } else if (c().isArithmetic(r2)) {
4987: // Cast from another number.
4988: result = t1;
4989:
4990: if (t2.hasConstant()) {
4991: result = result.annotate();
4992: if (c().isIntegral(r1)) {
4993: if (c().isIntegral(r2)) {
4994: // Cast int to int.
4995: result = result.constant(t2.getConstant()
4996: .getValue());
4997: } else {
4998: // Cast float to int: try to convert the original value
4999: // to a big integer value.
5000: try {
5001: result = result.constant(t2
5002: .getConstant().bigIntValue());
5003: } catch (IllegalStateException x) {
5004: result = result
5005: .constant(new StaticReference(
5006: result));
5007: }
5008: }
5009: } else {
5010: // Cast number to float: try to convert the original value
5011: // to a double value.
5012: try {
5013: result = result.constant(t2.getConstant()
5014: .doubleValue());
5015: } catch (IllegalStateException x) {
5016: result = result
5017: .constant(new StaticReference(
5018: result));
5019: }
5020: }
5021: }
5022:
5023: } else {
5024: // Cast from a pointer.
5025: if (r1.isFloat()) {
5026: runtime
5027: .error("cannot convert from pointer type",
5028: n);
5029: result = ErrorT.TYPE;
5030:
5031: } else {
5032: result = t1;
5033:
5034: if (c().hasConstRef(t2)) {
5035: Reference ref = c().getConstRef(t2);
5036: Type pt2 = r2.toPointer().getType();
5037: result = result.annotate();
5038:
5039: if ((pt2.hasTag(Tag.VOID) || c().isChar(pt2))
5040: && ref.hasLocation()) {
5041: // Preserve the location.
5042: result = result.constant(ref.getLocation());
5043: } else {
5044: // Soldier on with the reference as an arithmetic value
5045: // and hope that the program doesn't do any arithmetic
5046: // on the value beyond what is legal for pointers...
5047: result = result.constant(ref);
5048: }
5049: }
5050: }
5051: }
5052: }
5053: break;
5054:
5055: case ARRAY: {
5056: runtime.error("cast specifies array type", n);
5057: result = ErrorT.TYPE;
5058: }
5059: break;
5060:
5061: case FUNCTION: {
5062: runtime.error("cast specifies function type", n);
5063: result = ErrorT.TYPE;
5064: }
5065: break;
5066:
5067: case STRUCT:
5068: case UNION: {
5069: if (gcc) {
5070: // Handle the GCC exception.
5071: result = t1;
5072: break;
5073: }
5074: // Otherwise, fall through.
5075: }
5076:
5077: default:
5078: runtime.error("conversion to non-scalar type requested", n);
5079: result = ErrorT.TYPE;
5080: }
5081:
5082: mark(n, result);
5083: return result;
5084: }
5085:
5086: /** Visit the specified sizeof expression. */
5087: public Type visitSizeofExpression(GNode n) {
5088: // C99 6.5.3.4
5089: final Node n1 = n.getNode(0);
5090: final Type t1 = (Type) dispatch(n1);
5091: final Type r1 = t1.resolve();
5092:
5093: Type result;
5094: if (r1.isError()) {
5095: // Nothing to see here. Move on.
5096: result = ErrorT.TYPE;
5097:
5098: } else if (c().isIncomplete(t1) && !r1.isVoid()) {
5099: runtime
5100: .error(
5101: "invalid application of 'sizeof' to incomplete type",
5102: n);
5103: result = ErrorT.TYPE;
5104:
5105: } else if (t1.hasVariable() && t1.toVariable().hasWidth()) {
5106: runtime.error("'sizeof' applied to a bit-field", n);
5107: result = ErrorT.TYPE;
5108:
5109: } else if (pedantic && r1.isFunction()) {
5110: runtime.error("'sizeof' applied to funcion", n);
5111: result = ErrorT.TYPE;
5112:
5113: } else {
5114: result = C.SIZEOF;
5115:
5116: if (!c().isVariablyModified(r1)) {
5117: result = result.annotate().constant(
5118: BigInteger.valueOf(c().getSize(r1)));
5119: }
5120: }
5121:
5122: mark(n, result);
5123: return result;
5124: }
5125:
5126: /** Visit the specified alignof expression. */
5127: public Type visitAlignofExpression(GNode n) {
5128: // No formal specification, so we treat it just like sizeof.
5129: // Experiments with GCC bear this out.
5130: final Node n1 = n.getNode(0);
5131: final Type t1 = (Type) dispatch(n1);
5132: final Type r1 = t1.resolve();
5133:
5134: final Type result;
5135: if (t1.hasError()) {
5136: // Nothing to see here. Move on.
5137: result = ErrorT.TYPE;
5138:
5139: } else if (c().isIncomplete(t1) && !r1.isVoid()
5140: && !r1.isArray()) {
5141: runtime
5142: .error(
5143: "invalid application of '__alignof' to incomplete type",
5144: n);
5145: result = ErrorT.TYPE;
5146:
5147: } else if (t1.hasVariable() && t1.toVariable().hasWidth()) {
5148: runtime.error("'__alignof' applied to a bit-field", n);
5149: result = ErrorT.TYPE;
5150:
5151: } else if (pedantic && r1.isFunction()) {
5152: runtime.error("'__alignof' applied to function", n);
5153: result = ErrorT.TYPE;
5154:
5155: } else {
5156: result = C.SIZEOF.annotate().constant(
5157: BigInteger.valueOf(c().getAlignment(t1)));
5158: }
5159:
5160: mark(n, result);
5161: return result;
5162: }
5163:
5164: /** Visit the specified offset of expression. */
5165: public Type visitOffsetofExpression(GNode n) {
5166: final Type base = (Type) dispatch(n.getNode(0));
5167:
5168: processOffset(base, n.getGeneric(1));
5169:
5170: final Reference ref = new StaticReference("<offset>", C.SIZEOF);
5171: final Type result = C.SIZEOF.annotate().constant(ref);
5172:
5173: mark(n, result);
5174: return result;
5175: }
5176:
5177: /**
5178: * Process the specified offset selection.
5179: *
5180: * @param base The base type.
5181: * @param selection The selection.
5182: * @return The selected type or <code>ErrorT.TYPE</code> on errors.
5183: */
5184: protected Type processOffset(Type base, GNode selection) {
5185: if (selection.hasName("PrimaryIdentifier")) {
5186: return processSelection(selection, base, selection
5187: .getString(0), false);
5188:
5189: } else if (selection.hasName("DirectComponentSelection")) {
5190: base = processOffset(base, selection.getGeneric(0));
5191: return processSelection(selection, base, selection
5192: .getString(1), false);
5193:
5194: } else if (selection.hasName("SubscriptExpression")) {
5195: base = processOffset(base, selection.getGeneric(0));
5196: final Type index = (Type) dispatch(selection.getNode(1));
5197: return processSubscript(selection, base, index);
5198:
5199: } else {
5200: runtime.error("second argument to 'offsetof' neither a "
5201: + "selection nor a subscript", selection);
5202: return ErrorT.TYPE;
5203: }
5204: }
5205:
5206: /** Visit the specified type compatibility expression. */
5207: public Type visitTypeCompatibilityExpression(GNode n) {
5208: final Type t1 = (Type) dispatch(n.getNode(0));
5209: final Type t2 = (Type) dispatch(n.getNode(1));
5210:
5211: final Type result = NumberT.INT
5212: .annotate()
5213: .constant(
5214: c().compose(t1, t2, pedantic).isError() ? BigInteger.ZERO
5215: : BigInteger.ONE);
5216:
5217: mark(n, result);
5218: return result;
5219: }
5220:
5221: /** Visit the specified unary minus expression. */
5222: public Type visitUnaryMinusExpression(GNode n) {
5223: // C99 6.5.3.3
5224: final Node n1 = n.getNode(0);
5225: final Type t1 = (Type) dispatch(n1);
5226:
5227: Type result;
5228: if (ensureArithmetic(n1, t1)) {
5229: result = c().promote(t1);
5230:
5231: if (t1.hasConstant()) {
5232: result = result.annotate();
5233: try {
5234: if (c().isIntegral(result)) {
5235: result = result.constant(c()
5236: .mask(
5237: t1.getConstant().bigIntValue()
5238: .negate(), result));
5239: } else {
5240: result = result.constant(-t1.getConstant()
5241: .doubleValue());
5242: }
5243: } catch (IllegalStateException x) {
5244: result = result
5245: .constant(new StaticReference(result));
5246: }
5247: }
5248:
5249: } else {
5250: result = ErrorT.TYPE;
5251: }
5252:
5253: mark(n, result);
5254: return result;
5255: }
5256:
5257: /** Visit the specified unary plus expression. */
5258: public Type visitUnaryPlusExpression(GNode n) {
5259: // C99 6.5.3.3
5260: final Node n1 = n.getNode(0);
5261: final Type t1 = (Type) dispatch(n1);
5262:
5263: Type result;
5264: if (ensureArithmetic(n1, t1)) {
5265: result = c().promote(t1);
5266:
5267: if (t1.hasConstant()) {
5268: result = result.annotate().constant(
5269: t1.getConstant().getValue());
5270: }
5271:
5272: } else {
5273: result = ErrorT.TYPE;
5274: }
5275:
5276: mark(n, result);
5277: return result;
5278: }
5279:
5280: /** Visit the specified logical negation expression. */
5281: public Type visitLogicalNegationExpression(GNode n) {
5282: // C99 6.5.3.3
5283: final Node n1 = n.getNode(0);
5284: final Type t1 = (Type) dispatch(n1);
5285: final Type r1 = c().pointerize(t1);
5286:
5287: Type result;
5288: if (ensureScalar(n1, r1)) {
5289: result = NumberT.INT;
5290:
5291: if (t1.hasConstant()) {
5292: result = result.annotate().constant(
5293: !t1.getConstant().isTrue());
5294: }
5295:
5296: } else {
5297: result = ErrorT.TYPE;
5298: }
5299:
5300: mark(n, result);
5301: return result;
5302: }
5303:
5304: /** Visit the specified bitwise negation expression. */
5305: public Type visitBitwiseNegationExpression(GNode n) {
5306: // C99 6.5.3.3
5307: final Node n1 = n.getNode(0);
5308: final Type t1 = (Type) dispatch(n1);
5309:
5310: Type result;
5311: if (ensureInteger(n1, t1)) {
5312: result = c().promote(t1);
5313:
5314: if (t1.hasConstant()) {
5315: try {
5316: result = result.annotate().constant(
5317: c().mask(
5318: t1.getConstant().bigIntValue()
5319: .not(), result));
5320: } catch (IllegalStateException x) {
5321: result = result
5322: .constant(new StaticReference(result));
5323: }
5324: }
5325:
5326: } else {
5327: result = ErrorT.TYPE;
5328: }
5329:
5330: mark(n, result);
5331: return result;
5332: }
5333:
5334: /** Visit the specified address expression. */
5335: public Type visitAddressExpression(GNode n) {
5336: // C99 6.5.3.2
5337: final GNode n1 = n.getGeneric(0);
5338:
5339: // &(*...) and &(x[y]) expressions get special treatment.
5340: if (n1.hasName("IndirectionExpression")) {
5341: // Determine the base type.
5342: final Type base = (Type) dispatch(n1.getGeneric(0));
5343:
5344: // Process the indirection and address to ensure that the types
5345: // are valid.
5346: Type type = processIndirection(n1, base, false);
5347: type = processAddress(n, type);
5348:
5349: // Return the base, but not as an lvalue.
5350: Type result;
5351: if (type.isError()) {
5352: result = ErrorT.TYPE;
5353: } else {
5354: // Ensure the result is a pointer and an rvalue.
5355: result = c().toRValue(c().pointerize(base));
5356:
5357: // Track any constant value.
5358: final Type resolved = base.resolve();
5359: if (resolved.isArray() || resolved.isFunction()) {
5360: // Account for pointer decay.
5361: if (base.hasShape() && base.getShape().isConstant()) {
5362: result = result.annotate().constant(
5363: base.getShape());
5364: }
5365: } else if (base.hasConstant()) {
5366: result = result.annotate().constant(
5367: base.getConstant().getValue());
5368: }
5369: }
5370:
5371: mark(n, result);
5372: return result;
5373:
5374: } else if (n1.hasName("SubscriptExpression")) {
5375: // Determine the base and index types.
5376: final Type base = (Type) dispatch(n1.getGeneric(0));
5377: final Type index = (Type) dispatch(n1.getGeneric(1));
5378:
5379: // Process the subscript to ensure that the types are valid.
5380: final Type type = processSubscript(n1, base, index);
5381:
5382: // Return the type as if performing a pointer, integer addition.
5383: Type result;
5384: if (type.isError()) {
5385: result = ErrorT.TYPE;
5386: } else {
5387: // Ensure the result is a pointer.
5388: result = c().pointerize(base);
5389:
5390: // Track any constant value.
5391: Reference ref = null;
5392:
5393: if (base.resolve().isArray() && base.hasShape()
5394: && base.getShape().isConstant()) {
5395: // Account for pointer decay.
5396: ref = base.getShape();
5397:
5398: } else if (base.hasConstant()) {
5399: // A pointer's constant value must be a reference.
5400: assert base.getConstant().isReference();
5401:
5402: ref = (Reference) base.getConstant().getValue();
5403: }
5404:
5405: if (null != ref && index.hasConstant()) {
5406: result = result.annotate();
5407: try {
5408: result = result.constant(ref.add(index
5409: .getConstant().bigIntValue()));
5410: } catch (IllegalStateException x) {
5411: result = result.constant(new StaticReference(
5412: result));
5413: }
5414: }
5415: }
5416:
5417: mark(n, result);
5418: return result;
5419: }
5420:
5421: // Back to normal operation.
5422: final Type t1 = (Type) dispatch(n1);
5423: Type result = processAddress(n, t1);
5424:
5425: // Track compile-time constant pointers.
5426: if (t1.hasShape() && t1.getShape().isConstant()) {
5427: result = result.annotate().constant(t1.getShape());
5428: }
5429:
5430: // Done.
5431: mark(n, result);
5432: return result;
5433: }
5434:
5435: /**
5436: * Process the specified address expression. This method assumes
5437: * that the specified node neither is an indirection nor a subscript
5438: * expression.
5439: *
5440: * @param n The node.
5441: * @param type The type.
5442: * @return The resulting type.
5443: */
5444: protected Type processAddress(GNode n, Type type) {
5445: final Type resolved = type.resolve();
5446:
5447: if (resolved.isError()) {
5448: return ErrorT.TYPE;
5449:
5450: } else if (type.hasShape()) {
5451: if (type.hasVariable() && type.toVariable().hasWidth()) {
5452: runtime.error("cannot take address of bit-field '"
5453: + type.toVariable().getName() + "'", n);
5454: return ErrorT.TYPE;
5455:
5456: } else if (type
5457: .hasAttribute(Constants.ATT_STORAGE_REGISTER)) {
5458: runtime
5459: .error("address of register "
5460: + toDescription(n.getNode(0))
5461: + " requested", n);
5462: return ErrorT.TYPE;
5463:
5464: } else {
5465: Type result = new PointerT(c().qualify(resolved, type));
5466: if (type.getShape().isConstant()) {
5467: result = result.annotate()
5468: .constant(type.getShape());
5469: }
5470: return result;
5471: }
5472:
5473: } else {
5474: runtime.error("invalid lvalue in unary '&'", n.getNode(0));
5475: return ErrorT.TYPE;
5476: }
5477: }
5478:
5479: /** Visit the specified label address expression. */
5480: public Type visitLabelAddressExpression(GNode n) {
5481: // The label's name is checked in a second phase after all a
5482: // function's labels have been added to the symbol table. Here,
5483: // we only construt the appropriate type (void *).
5484: final Type result = PointerT.TO_VOID.annotate().constant(
5485: new StaticReference(n.getString(0), VoidT.TYPE));
5486:
5487: mark(n, result);
5488: return result;
5489: }
5490:
5491: /** Visit the specified indirection expression. */
5492: public Type visitIndirectionExpression(GNode n) {
5493: // C99 6.5.3.2
5494: final Node n1 = n.getNode(0);
5495: final Type t1 = (Type) dispatch(n1);
5496:
5497: final Type result = processIndirection(n, t1, true);
5498:
5499: mark(n, result);
5500: return result;
5501: }
5502:
5503: /**
5504: * Process the specified indirection expression.
5505: *
5506: * @param n The node.
5507: * @param type The type.
5508: * @param warn The flag for whether to emit any warnings.
5509: * @return The resulting type.
5510: */
5511: protected Type processIndirection(Node n, Type type, boolean warn) {
5512: final Type resolved = c().pointerize(type);
5513:
5514: if (resolved.isError()) {
5515: return ErrorT.TYPE;
5516:
5517: } else if (resolved.isPointer()) {
5518: final Type pt = resolved.toPointer().getType(); // PointedTo, PTResolved
5519: final Type ptr = pt.resolve();
5520:
5521: Type result;
5522: if (ptr.isError()) {
5523: result = ErrorT.TYPE;
5524:
5525: } else if (c().isIncomplete(pt)) {
5526: runtime.error(
5527: "dereferencing pointer to incomplete type", n);
5528: result = ErrorT.TYPE;
5529:
5530: } else {
5531: final Reference ref;
5532: if (type.hasShape()) {
5533: ref = type.getShape().indirect(type);
5534: } else if (type.hasConstant()) {
5535: // Note that arrays and functions never have a value. So,
5536: // just using the reference value is safe.
5537: ref = type.getConstant().refValue();
5538: } else {
5539: ref = new DynamicReference(ptr);
5540: }
5541: result = c().qualify(ptr, pt).annotate().shape(ref);
5542: }
5543:
5544: if (ptr.isVoid() && warn) {
5545: runtime.warning("dereferencing 'void *' pointer", n);
5546: }
5547:
5548: return result;
5549:
5550: } else {
5551: runtime.error("operand to 'unary *' not a pointer type", n);
5552: return ErrorT.TYPE;
5553: }
5554: }
5555:
5556: /** Visit the specified preincrement expression. */
5557: public Type visitPreincrementExpression(GNode n) {
5558: // C99 6.5.3.1
5559: final Node n1 = n.getNode(0);
5560: final Type t1 = (Type) dispatch(n1);
5561:
5562: Type result;
5563: if (ensureScalar(n1, t1) && ensurePointerArithmetic(n, t1)
5564: && ensureLValue(n1, t1)) {
5565: result = t1.resolve();
5566: } else {
5567: result = ErrorT.TYPE;
5568: }
5569:
5570: mark(n, result);
5571: return result;
5572: }
5573:
5574: /** Visit the specified predecrement expression. */
5575: public Type visitPredecrementExpression(GNode n) {
5576: // C99 6.5.3.1
5577: final Node n1 = n.getNode(0);
5578: final Type t1 = (Type) dispatch(n1);
5579:
5580: Type result;
5581: if (ensureScalar(n1, t1) && ensurePointerArithmetic(n, t1)
5582: && ensureLValue(n1, t1)) {
5583: result = t1.resolve();
5584: } else {
5585: result = ErrorT.TYPE;
5586: }
5587:
5588: mark(n, result);
5589: return result;
5590: }
5591:
5592: /** Visit the specified extension expression. */
5593: public Type visitExtensionExpression(GNode n) {
5594: // Nothing to see here. Move on.
5595: return (Type) dispatch(n.getNode(0));
5596: }
5597:
5598: /** Visit the specified subscript expression. */
5599: public Type visitSubscriptExpression(GNode n) {
5600: // C99 6.5.2.1
5601: final Node n1 = n.getNode(0);
5602: final Node n2 = n.getNode(1);
5603: final Type t1 = (Type) dispatch(n1);
5604: final Type t2 = (Type) dispatch(n2);
5605:
5606: final Type result = processSubscript(n, t1, t2);
5607:
5608: mark(n, result);
5609: return result;
5610: }
5611:
5612: /**
5613: * Process the specified subscript expression.
5614: *
5615: * @param n The node.
5616: * @param base The base type.
5617: * @param index The index type.
5618: * @return The corresponding element type or an error type in case
5619: * of an error.
5620: */
5621: protected Type processSubscript(Node n, Type base, Type index) {
5622: // C99 6.5.2.1
5623: final Type resolved = c().pointerize(base);
5624:
5625: final boolean cond2;
5626: if (index.hasError()) {
5627: cond2 = false;
5628: } else if (c().isIntegral(index)) {
5629: cond2 = true;
5630: } else {
5631: runtime.error("array subscript is not an integer", n);
5632: cond2 = false;
5633: }
5634:
5635: if (base.hasError()) {
5636: return ErrorT.TYPE;
5637:
5638: } else if (resolved.isPointer()) {
5639: final Type pt1 = resolved.toPointer().getType(); // PointedTo, PTResolved
5640: final Type ptr1 = pt1.resolve();
5641:
5642: if (ptr1.isError()) {
5643: return ErrorT.TYPE;
5644:
5645: } else if (ptr1.isFunction()) {
5646: runtime.error(
5647: "subscripted value is pointer to function", n);
5648: return ErrorT.TYPE;
5649:
5650: } else if (c().isIncomplete(pt1)) {
5651: runtime.error(
5652: "dereferencing pointer to incomplete type", n);
5653: return ErrorT.TYPE;
5654:
5655: } else if (cond2) {
5656: Reference ref;
5657: if (base.hasShape() && index.hasConstant()) {
5658: try {
5659: ref = base.getShape().indirect(base).add(
5660: index.getConstant().bigIntValue());
5661: } catch (IllegalStateException x) {
5662: ref = new StaticReference(ptr1);
5663: }
5664: } else {
5665: ref = new DynamicReference(ptr1);
5666: }
5667: return c().qualify(ptr1, pt1).annotate().shape(ref);
5668:
5669: } else {
5670: return ErrorT.TYPE;
5671: }
5672:
5673: } else {
5674: runtime
5675: .error(
5676: "subscripted value is neither array nor pointer",
5677: n);
5678: return ErrorT.TYPE;
5679: }
5680: }
5681:
5682: /** Visit the specified direct component selection. */
5683: public Type visitDirectComponentSelection(GNode n) {
5684: // C99 6.5.2.3
5685: final Node n1 = n.getNode(0);
5686: final String id = n.getString(1);
5687: final Type t1 = (Type) dispatch(n1);
5688:
5689: final Type result = processSelection(n1, t1, id, false);
5690:
5691: mark(n, result);
5692: return result;
5693: }
5694:
5695: /** Visit the specified indirect component selection. */
5696: public Type visitIndirectComponentSelection(GNode n) {
5697: // C99 6.5.2.3
5698: final Node n1 = n.getNode(0);
5699: final String id = n.getString(1);
5700: final Type t1 = (Type) dispatch(n1);
5701:
5702: final Type result = processSelection(n1, t1, id, true);
5703:
5704: mark(n, result);
5705: return result;
5706: }
5707:
5708: /**
5709: * Process a component selection. This method extracts the member
5710: * type for the member with the specified name from the specified
5711: * struct or union type.
5712: *
5713: * @param node The node.
5714: * @param type The type.
5715: * @param name The name of the member.
5716: * @param indirect The flag for whether the component selection is
5717: * indirect.
5718: * @return The corresponding member type or an error type in case of
5719: * a malformed type or field name.
5720: */
5721: protected Type processSelection(Node node, Type type, String name,
5722: boolean indirect) {
5723: if (type.hasError())
5724: return ErrorT.TYPE;
5725:
5726: // First, resolve any indirection.
5727: Type base;
5728: if (indirect) {
5729: final Type resolved = c().pointerize(type);
5730:
5731: if (resolved.isPointer()) {
5732: base = resolved.toPointer().getType();
5733:
5734: if (c().isIncomplete(base)) {
5735: runtime.error(
5736: "dereferencing pointer to incomplete type",
5737: node);
5738: return ErrorT.TYPE;
5739: }
5740:
5741: } else {
5742: runtime.error("invalid type argument of '->'", node);
5743: return ErrorT.TYPE;
5744: }
5745: } else {
5746: base = type;
5747: }
5748:
5749: // Second, extract the member type.
5750: if (base.hasError()) {
5751: return ErrorT.TYPE;
5752:
5753: } else if (base.hasStructOrUnion()) {
5754: final Tagged tag = base.toTagged();
5755: Type result = tag.lookup(name);
5756:
5757: if (result.isError()) {
5758: runtime.error("'"
5759: + (tag.isStruct() ? "struct " : "union ")
5760: + tag.getName() + "' has no member named '"
5761: + name + "'", node);
5762: return ErrorT.TYPE;
5763:
5764: } else {
5765: result = c().qualify(result, base);
5766: if (indirect) {
5767: Reference ref;
5768: if (type.hasShape()) {
5769: ref = type.getShape().indirect(type);
5770: } else if (type.hasConstant()) {
5771: // Note that arrays and functions never have a value. So,
5772: // just using the reference value is safe.
5773: ref = type.getConstant().refValue();
5774: } else {
5775: ref = new DynamicReference(base);
5776: }
5777: result = result.annotate().shape(
5778: new FieldReference(ref, name));
5779:
5780: } else if (type.hasShape()) {
5781: result = result.annotate().shape(
5782: new FieldReference(type.getShape(), name));
5783: }
5784: return result;
5785: }
5786:
5787: } else {
5788: runtime.error("request for member '" + name
5789: + "' in something not a struct or union", node);
5790: return ErrorT.TYPE;
5791: }
5792: }
5793:
5794: /** Visit the specified function call. */
5795: public Type visitFunctionCall(GNode n) {
5796: final Node n1 = n.getNode(0);
5797: final Node n2 = n.getNode(1);
5798:
5799: Type t1;
5800: if (GNode.cast(n1).hasName("PrimaryIdentifier")) {
5801: final String name = GNode.cast(n1).getString(0);
5802:
5803: t1 = (Type) table.lookup(name);
5804: if (null == t1) {
5805:
5806: if (pedantic) {
5807: runtime.error("'" + name + "' undeclared", n1);
5808: t1 = ErrorT.TYPE;
5809:
5810: } else {
5811: // Implicitly declare this identifier as a function. Since
5812: // the lookup failed, the identifier is not declared in the
5813: // current scope nor in the global scope.
5814: t1 = new FunctionT(NumberT.INT,
5815: new ArrayList<Type>(0), false).attribute(
5816: Constants.ATT_STYLE_OLD).attribute(
5817: Constants.ATT_IMPLICIT).annotate()
5818: .attribute(Constants.ATT_STORAGE_EXTERN);
5819:
5820: // Always enter the implicit declaration in the local scope.
5821: table.current().define(name,
5822: t1.shape(true, name).locate(n));
5823:
5824: // Compare to any previous extern declarations.
5825: final Type extern = lookupExtern(name);
5826: if (null == extern) {
5827: // runtime.warning("implicit declaration of function '"+name+"'", n);
5828: defineExtern(name, t1.shape(true, name).locate(
5829: n));
5830:
5831: } else if (!extern
5832: .hasAttribute(Constants.ATT_IMPLICIT)) {
5833: // FIXME: add warning for first implicit declaration.
5834:
5835: // Compose the two types to detect any errors.
5836: compose(n, name, t1, extern, false);
5837: }
5838: }
5839: }
5840: } else {
5841: t1 = (Type) dispatch(n1);
5842: }
5843:
5844: final Type r1 = c().pointerize(t1);
5845: final List args = (List) dispatch(n2);
5846:
5847: Type result;
5848: if (r1.isError()) {
5849: result = ErrorT.TYPE;
5850:
5851: } else if (r1.isPointer()
5852: && r1.toPointer().getType().hasTag(Tag.FUNCTION)) {
5853: final FunctionT function = r1.toPointer().getType()
5854: .resolve().toFunction();
5855: final List parameters = function.getParameters();
5856:
5857: // If the function has a prototype, check the types.
5858: if (!function.hasAttribute(Constants.ATT_STYLE_OLD)) {
5859: final int size1 = parameters.size();
5860: final int size2 = (null == args) ? 0 : args.size();
5861: final int min = Math.min(size1, size2);
5862: final String name = toFunctionName(n1);
5863:
5864: for (int i = 0; i < min; i++) {
5865: String desc = "passing argument " + (i + 1);
5866: if (null != name)
5867: desc = desc + " to '" + name + "'";
5868:
5869: final Type a1 = (Type) parameters.get(i);
5870: final Type a2 = (Type) args.get(i);
5871:
5872: processAssignment(false, desc, n, a1, a2);
5873: }
5874:
5875: if (size1 > size2) {
5876: if (null == name) {
5877: runtime.error("too few arguments to function",
5878: n);
5879: } else {
5880: runtime.error("too few arguments to function '"
5881: + name + "'", n);
5882: }
5883: } else if ((!function.isVarArgs()) && (size1 < size2)) {
5884: if (null == name) {
5885: runtime.error("too many arguments to function",
5886: n);
5887: } else {
5888: runtime.error(
5889: "too many arguments to function '"
5890: + name + "'", n);
5891: }
5892: }
5893: }
5894:
5895: result = function.getResult();
5896:
5897: } else {
5898: runtime.error("called " + toDescription(n1)
5899: + " is not a function", n);
5900: result = ErrorT.TYPE;
5901: }
5902:
5903: mark(n, result);
5904: return result;
5905: }
5906:
5907: /** Visit the specified postincrement expression. */
5908: public Type visitPostincrementExpression(GNode n) {
5909: // C99 6.5.2.4
5910: final Node n1 = n.getNode(0);
5911: final Type t1 = (Type) dispatch(n1);
5912:
5913: Type result;
5914: if (ensureScalar(n1, t1) && ensurePointerArithmetic(n, t1)
5915: && ensureLValue(n1, t1)) {
5916: result = t1.resolve();
5917: } else {
5918: result = ErrorT.TYPE;
5919: }
5920:
5921: mark(n, result);
5922: return result;
5923: }
5924:
5925: /** Visit the specified postdecrement expression. */
5926: public Type visitPostdecrementExpression(GNode n) {
5927: // C99 6.5.2.4
5928: final Node n1 = n.getNode(0);
5929: final Type t1 = (Type) dispatch(n1);
5930:
5931: Type result;
5932: if (ensureScalar(n1, t1) && ensurePointerArithmetic(n, t1)
5933: && ensureLValue(n1, t1)) {
5934: result = t1.resolve();
5935: } else {
5936: result = ErrorT.TYPE;
5937: }
5938:
5939: mark(n, result);
5940: return result;
5941: }
5942:
5943: /** Visit the specified compound literal. */
5944: public Type visitCompoundLiteral(GNode n) {
5945: // C99 6.5.2.5
5946: Type t1 = (Type) dispatch(n.getNode(0));
5947:
5948: // Compound literals are compile-time constant lvalues.
5949: final Reference ref = new StaticReference("<literal>", t1
5950: .resolve());
5951: t1 = t1.annotate().shape(ref).constant(ref);
5952:
5953: if (isTopLevel) {
5954: // Top-level compound literals have static storage.
5955: t1 = t1.attribute(Constants.ATT_STORAGE_STATIC);
5956: } else {
5957: // Block-scope compound literals have automatic storage.
5958: t1 = t1.attribute(Constants.ATT_STORAGE_AUTO);
5959: }
5960:
5961: // Process the initializer.
5962: final Type result;
5963:
5964: if (t1.hasStructOrUnion() && c().isIncomplete(t1)) {
5965: final String kind = t1.hasTag(Tag.STRUCT) ? "struct"
5966: : "union";
5967: if (t1.toTagged().isUnnamed()) {
5968: runtime.error("unnamed " + kind
5969: + " has incomplete type", n);
5970: } else {
5971: runtime.error("'" + kind + " "
5972: + t1.toTagged().getName()
5973: + "' has incomplete type", n);
5974: }
5975: result = ErrorT.TYPE;
5976: } else {
5977: result = processInitializer(n, null, t1, n.getGeneric(1));
5978: }
5979:
5980: mark(n, result);
5981: return result;
5982: }
5983:
5984: /** Visit the specified primary identifier. */
5985: public Type visitPrimaryIdentifier(GNode n) {
5986: Type result = (Type) table.lookup(n.getString(0));
5987: if (null == result) {
5988: runtime.error("'" + n.getString(0) + "' undeclared", n);
5989: result = ErrorT.TYPE;
5990: }
5991:
5992: mark(n, result);
5993: return result;
5994: }
5995:
5996: /** Visit the specified floating constant. */
5997: public Type visitFloatingConstant(GNode n) {
5998: final Type result = c().typeFloat(n.getString(0));
5999:
6000: mark(n, result);
6001: return result;
6002: }
6003:
6004: /** Visit the specified integer constant. */
6005: public Type visitIntegerConstant(GNode n) {
6006: Type result = c().typeInteger(n.getString(0));
6007:
6008: if (!c().fits(result.getConstant().bigIntValue(), result)) {
6009: runtime
6010: .warning("integer constant is too large for its type");
6011:
6012: // Reconstruct value.
6013: result = result.resolve().annotate().constant(
6014: c()
6015: .mask(result.getConstant().bigIntValue(),
6016: result));
6017: }
6018:
6019: mark(n, result);
6020: return result;
6021: }
6022:
6023: /** Visit the specified character constant. */
6024: public Type visitCharacterConstant(GNode n) {
6025: Type result = c().typeCharacter(n.getString(0));
6026:
6027: if (!c().fits(result.getConstant().bigIntValue(), result)) {
6028: runtime.warning(
6029: "character constant too large for its type", n);
6030:
6031: // Reconstruct value.
6032: result = result.resolve().annotate().constant(
6033: c()
6034: .mask(result.getConstant().bigIntValue(),
6035: result));
6036: }
6037:
6038: mark(n, result);
6039: return result;
6040: }
6041:
6042: /** Visit the specified string constant. */
6043: public Type visitStringConstant(GNode n) {
6044: // C99 6.4.5
6045:
6046: // Build up the actual string value.
6047: final StringBuilder buf = new StringBuilder();
6048: boolean wide = false;
6049: for (Object o : n) {
6050: String s = Token.cast(o);
6051:
6052: if (s.startsWith("L")) {
6053: try {
6054: buf.append(Utilities.unescape(s.substring(2, s
6055: .length() - 1)));
6056: } catch (IllegalArgumentException x) {
6057: runtime.error(x.getMessage(), n);
6058: }
6059: wide = true;
6060: } else {
6061: try {
6062: buf.append(Utilities.unescape(s.substring(1, s
6063: .length() - 1)));
6064: } catch (IllegalArgumentException x) {
6065: runtime.error(x.getMessage(), n);
6066: }
6067: }
6068: }
6069: final String value = buf.toString();
6070:
6071: // Construct the type. Note that we ignore the terminating null
6072: // character for the string constant's size because later
6073: // comparisons with fixed-size arrays do not consider it (C99
6074: // 6.7.8).
6075: final Type base = wide ? C.WCHAR : NumberT.CHAR;
6076:
6077: Type result = new ArrayT(base, value.length());
6078: result = result.annotate().shape(
6079: new StringReference(value, result));
6080: result = result.constant(result.getShape());
6081:
6082: // Done.
6083: mark(n, result);
6084: return result;
6085: }
6086:
6087: /** Visit the specified statement as expression. */
6088: public Type visitStatementAsExpression(GNode n) {
6089: isStmtAsExpr = true;
6090:
6091: final Type result = (Type) dispatch(n.getNode(0));
6092:
6093: mark(n, result);
6094: return result;
6095: }
6096:
6097: /** Visit the specified variable argument access. */
6098: public Type visitVariableArgumentAccess(GNode n) {
6099: final Type list = (Type) dispatch(n.getNode(0));
6100:
6101: if (!c().equal(InternalT.VA_LIST, list.resolve())) {
6102: runtime
6103: .error("first argument to 'va_arg' not of type 'va_list'");
6104: }
6105:
6106: final Type result = (Type) dispatch(n.getNode(1));
6107:
6108: mark(n, result);
6109: return result;
6110: }
6111:
6112: /** Visit the specified type name. */
6113: public Type visitTypeName(GNode n) {
6114: final Specifiers spec = newSpecifiers(n.getGeneric(0), false);
6115:
6116: Type result = getDeclaredType(spec.getBaseType(), n
6117: .getGeneric(1));
6118: result = spec.annotateFull(result);
6119:
6120: mark(n, result);
6121: return result;
6122: }
6123:
6124: /** Visit the specified generic node. */
6125: public void visit(GNode n) {
6126: final boolean scope = hasScope;
6127: hasScope = true;
6128: for (Object o : n) {
6129: if (o instanceof Node) {
6130: dispatch((Node) o);
6131: }
6132: }
6133: hasScope = scope;
6134: }
6135:
6136: // ========================================================================
6137:
6138: /**
6139: * Check that the specified type is well-formed. This method checks
6140: * that the specified type is not an array of functions, not a
6141: * function returning an array or a function, and not a pointer to
6142: * either of the first two types.
6143: *
6144: * @param node The declaring node.
6145: * @param name The optional name.
6146: * @param type The type.
6147: * @return <code>true</code> if the type is well-formed.
6148: */
6149: public boolean checkType(GNode node, String name, Type type) {
6150: // Resolve the type.
6151: type = type.resolve();
6152:
6153: // Strip any pointers.
6154: while (type.isPointer()) {
6155: type = type.toPointer().getType().resolve();
6156: }
6157:
6158: // Check arrays.
6159: if (type.isArray()) {
6160: Type element = type;
6161: do {
6162: element = element.toArray().getType().resolve();
6163: } while (element.isArray());
6164: if (element.isFunction()) {
6165: if (null == name) {
6166: runtime.error("declaration of array of functions",
6167: node);
6168: } else {
6169: runtime.error("'" + name
6170: + "' declared as array of functions", node);
6171: }
6172: return false;
6173:
6174: } else {
6175: // Recursively check the element type.
6176: return checkType(node, name, element);
6177: }
6178: }
6179:
6180: // Check functions.
6181: if (type.isFunction()) {
6182: Type result = type.toFunction().getResult().resolve();
6183: if (result.isArray()) {
6184: if (null == name) {
6185: runtime
6186: .error(
6187: "declaration of function returning an array",
6188: node);
6189: } else {
6190: runtime.error("'" + name
6191: + "' declared as function returning "
6192: + "an array", node);
6193: }
6194: return false;
6195:
6196: } else if (result.isFunction()) {
6197: if (null == name) {
6198: runtime
6199: .error(
6200: "declaration of function returning a function",
6201: node);
6202: } else {
6203: runtime.error("'" + name
6204: + "' declared as function returning "
6205: + "a function", node);
6206: }
6207: return false;
6208:
6209: } else {
6210: // Recursively check the result type.
6211: return checkType(node, name, result);
6212: }
6213: }
6214:
6215: return true;
6216: }
6217:
6218: /**
6219: * Compose the specified type with the type of the previous
6220: * declaration. This method composes compatible object and function
6221: * types with each other, while also reporting any errors.
6222: *
6223: * @param decl The current declaration's node.
6224: * @param name The identifier name.
6225: * @param type The current declaration's type.
6226: * @param previous The previous declaration's type.
6227: * @param isFuncDef The flag for whether the composition is for a
6228: * function definition.
6229: * @return The composite type or {@link ErrorT#TYPE} if the two
6230: * types are not compatible.
6231: */
6232: public Type compose(GNode decl, String name, Type type,
6233: Type previous, boolean isFuncDef) {
6234: if (previous.isAlias()
6235: || type.resolve().isFunction() != previous.resolve()
6236: .isFunction()) {
6237: runtime.error("'" + name
6238: + "' redeclared as different kind of symbol", decl);
6239: reportPrevious(name, previous);
6240: return ErrorT.TYPE;
6241: }
6242:
6243: // For an invocation of C.compose(t1, t2), t1's attributes
6244: // dominate. Therefore, we give precedence to types not having
6245: // the extern attribute.
6246: Type composite;
6247: if (previous.hasAttribute(Constants.ATT_STORAGE_EXTERN)
6248: || (!type.hasAttribute(Constants.ATT_STORAGE_EXTERN))
6249: || isFuncDef) {
6250: composite = c().compose(type, previous, pedantic);
6251: } else {
6252: composite = c().compose(previous, type, pedantic);
6253: }
6254:
6255: if (composite.isError()) {
6256: if (previous.hasAttribute(Constants.ATT_BUILTIN)
6257: && previous.resolve().isFunction()) {
6258: runtime.error(
6259: "conflicting types for built-in function '"
6260: + name + "'", decl);
6261: } else {
6262: runtime.error("conflicting types for '" + name + "'",
6263: decl);
6264: reportPrevious(name, previous);
6265: }
6266: return ErrorT.TYPE;
6267:
6268: } else if (!c().hasSameQualifiers(type, previous)) {
6269: runtime.error("conflicting type qualifiers for '" + name
6270: + "'", decl);
6271: reportPrevious(name, previous);
6272: return ErrorT.TYPE;
6273: }
6274:
6275: return composite;
6276: }
6277:
6278: /**
6279: * Get the first declaration specifier with the specified name.
6280: *
6281: * @param name The name.
6282: * @param specifiers The specifiers.
6283: * @return The corresponding declaration specifier or
6284: * <code>null</code> if no such specifier exists.
6285: */
6286: public static GNode getSpecifier(String name, GNode specifiers) {
6287: for (Object o : specifiers) {
6288: final GNode specifier = GNode.cast(o);
6289: if (specifier.hasName(name))
6290: return specifier;
6291: }
6292: return null;
6293: }
6294:
6295: /**
6296: * Create a new sequence of specifiers. This factory method should
6297: * be used instead of allocating an instance of {@link Specifiers}
6298: * directly, so that the processing of declaration specifiers can be
6299: * customized by subclasses.
6300: *
6301: * @param specifiers The node holding the declaration specifiers
6302: * (which may be <code>null</code>).
6303: * @param refIsDecl The flag for whether a struct/union reference
6304: * also is a struct/union declaration.
6305: * @return The sequence of specifiers.
6306: */
6307: public Specifiers newSpecifiers(GNode specifiers, boolean refIsDecl) {
6308: return new Specifiers(specifiers, refIsDecl);
6309: }
6310:
6311: /**
6312: * Convert the specified GCC attribute specifier or GCC attribute
6313: * specifier list to an xtc attribute list. If the specified node
6314: * is <code>null</code>, this method returns an empty list.
6315: * Otherwise, it returns a newly allocated, unsealed list.
6316: *
6317: * @param spec The GCC attribute specifier (list).
6318: * @return The corresponding xtc attributes.
6319: */
6320: public List<Attribute> toAttributeList(GNode spec) {
6321: if (null == spec) {
6322: return Collections.emptyList();
6323: } else {
6324: return toAttributeList(spec, new ArrayList<Attribute>());
6325: }
6326: }
6327:
6328: /** The actual implementation of {@link #toAttributeList(GNode)}. */
6329: private List<Attribute> toAttributeList(GNode spec,
6330: List<Attribute> result) {
6331: if (spec.hasName("AttributeSpecifier")) {
6332: if (null != spec.get(0)) {
6333: for (Object o : spec.getGeneric(0)) {
6334: final GNode entry = GNode.cast(o);
6335: final String name = toAttributeName(entry
6336: .getString(0));
6337: final Object value = toAttributeValue(entry
6338: .getGeneric(1));
6339:
6340: // Check values of known attributes.
6341: boolean seenError = false;
6342:
6343: if ("packed".equals(name)) { // -------------------------------------
6344: if (null != value) {
6345: runtime.error(
6346: "wrong number of arguments specified for 'packed'"
6347: + " attribute", entry);
6348: seenError = true;
6349: }
6350:
6351: } else if ("aligned".equals(name)) { // -----------------------------
6352: if (null == value) {
6353: // Ignore.
6354: } else if (value instanceof List) {
6355: runtime.error(
6356: "wrong number of arguments specified for 'aligned'"
6357: + " attribute", entry);
6358: seenError = true;
6359: } else if (value instanceof Node) {
6360: runtime
6361: .error(
6362: "requested alignment is not a constant",
6363: entry);
6364: seenError = true;
6365: } else if (!(value instanceof BigInteger)) {
6366: runtime
6367: .error(
6368: "requested alignment is not an integer constant",
6369: entry);
6370: seenError = true;
6371: } else {
6372: BigInteger i = (BigInteger) value;
6373:
6374: if (1 != i.signum() || 1 != i.bitCount()) {
6375: runtime
6376: .error(
6377: "requested alignment is not a power of 2",
6378: entry);
6379: seenError = true;
6380: } else if (Limits.INT_MAX.compareTo(i) < 0) {
6381: runtime
6382: .error(
6383: "requested alignment is too large",
6384: entry);
6385: seenError = true;
6386: }
6387: }
6388: }
6389:
6390: // Create attribute.
6391: if (!seenError) {
6392: result.add(new Attribute(Constants.NAME_GCC,
6393: new Attribute(name, value)));
6394: }
6395: }
6396: }
6397: return result;
6398:
6399: } else if (spec.hasName("AttributeSpecifierList")) {
6400: for (Object o : spec)
6401: toAttributeList(GNode.cast(o), result);
6402: return result;
6403:
6404: } else {
6405: throw new AssertionError(
6406: "Not an attribute specifier (list): " + spec);
6407: }
6408: }
6409:
6410: /**
6411: * Convert the specified string to an attribute name.
6412: *
6413: * @param s The string.
6414: * @return The corresponding name.
6415: */
6416: public String toAttributeName(String s) {
6417: if (s.startsWith("__"))
6418: s = s.substring(2);
6419: if (s.endsWith("__"))
6420: s = s.substring(0, s.length() - 2);
6421: return s;
6422: }
6423:
6424: /**
6425: * Convert the specified node to an attribute value. This method
6426: * converts a node representing a GCC attribute's value to the
6427: * actual attribute's value:<ul>
6428: *
6429: * <li>If the node is <code>null</code> or an empty expression list,
6430: * this method returns <code>null</code>.</li>
6431: *
6432: * <li>If the node is an expression list with one element, it
6433: * returns the result of recursively processing that element.</li>
6434: *
6435: * <li>If the node is an expression list with more than one element,
6436: * it recursively processes each element, returning a new Java
6437: * collections framework list.</li>
6438: *
6439: * <li>If the node is a primary identifier, it returns the
6440: * corresponding symbol (without checking that the symbol is
6441: * defined).</li>
6442: *
6443: * <li>If the node is a constant expression, it returns the
6444: * corresponding value.</li>
6445: *
6446: * <li>Otherwise, it returns the AST node.</li>
6447: *
6448: * </ul>
6449: *
6450: * @param node The node.
6451: * @return The corresponding value.
6452: */
6453: public Object toAttributeValue(GNode node) {
6454: if (null == node)
6455: return null;
6456:
6457: if (node.hasName("ExpressionList")) {
6458: if (0 == node.size()) {
6459: return null;
6460:
6461: } else if (1 == node.size()) {
6462: return toAttributeValue(node.getGeneric(0));
6463:
6464: } else {
6465: final List<Object> l = new ArrayList<Object>(node
6466: .size());
6467: for (Object o : node)
6468: l.add(toAttributeValue(GNode.cast(o)));
6469: return l;
6470: }
6471:
6472: } else if (node.hasName("PrimaryIdentifier")) {
6473: return node.getString(0);
6474:
6475: } else {
6476: final Type t = (Type) dispatch(node);
6477:
6478: return t.hasConstant() ? t.getConstant().getValue() : node;
6479: }
6480: }
6481:
6482: /**
6483: * Get the parameter types for the specified parameter declaration.
6484: * As a side effect, this method reports any errors in a parameter's
6485: * declaration specifiers, any void parameters (besides a single
6486: * void specifier), any multiple parameters in old-style
6487: * declarations, and any parameter redefinitions in new-style
6488: * declarations.
6489: *
6490: * @param parameters The parameters, which may be <code>null</code>.
6491: * @return The corresponding function type with the argument types
6492: * and variable flag filled in.
6493: */
6494: public FunctionT getParameterTypes(GNode parameters) {
6495: if (null == parameters) {
6496: // No parameters.
6497: final FunctionT function = new FunctionT(null,
6498: new ArrayList<Type>(0), false);
6499: function.addAttribute(Constants.ATT_STYLE_OLD);
6500: return function;
6501:
6502: } else if (parameters.hasName("ParameterTypeList")) {
6503: // Enter a temporary scope so that variable length arrays can
6504: // reference previously declared parameters.
6505: table.enter(TMP_SCOPE);
6506:
6507: // A new-style parameter type list.
6508: final boolean variable;
6509: final List<Type> types;
6510:
6511: if (isVoidParameterTypeList(parameters)) {
6512: variable = false;
6513: types = new ArrayList<Type>(0);
6514:
6515: // Get the
6516: final GNode param = parameters.getGeneric(0)
6517: .getGeneric(0);
6518: final Specifiers spec = new Specifiers(param
6519: .getGeneric(0), false);
6520: final Type type = spec.annotateFull(spec.getBaseType());
6521:
6522: // Check that the void specifier does not have a storage
6523: // class, qualifier, or function specifier.
6524: if (type.hasAttribute(Constants.NAME_STORAGE)) {
6525: runtime
6526: .error(
6527: "'void' as only parameter may not have storage class",
6528: parameters);
6529: }
6530: if (c().hasQualifiers(type)) {
6531: runtime
6532: .error(
6533: "'void' as only parameter may not be qualified",
6534: parameters);
6535:
6536: }
6537: if (type.hasAttribute(Constants.ATT_INLINE)) {
6538: runtime
6539: .error(
6540: "'void' as only parameter may not be declared 'inline'",
6541: parameters);
6542: }
6543:
6544: } else {
6545: variable = (null != parameters.get(1));
6546: parameters = parameters.getGeneric(0);
6547: types = new ArrayList<Type>(parameters.size());
6548: for (Object o : parameters) {
6549: final GNode param = GNode.cast(o);
6550: final GNode decl = param.getGeneric(1);
6551: final GNode ident = getDeclaredId(decl);
6552: final String name = (null != ident) ? ident
6553: .getString(0) : null;
6554: final Specifiers spec = new Specifiers(param
6555: .getGeneric(0), false);
6556: Type type = getDeclaredType(true, spec
6557: .getBaseType(), decl);
6558:
6559: // Check that the type is well-formed.
6560: checkType(param, name, type);
6561:
6562: // Pointerize array and function parameter types.
6563: switch (type.tag()) {
6564: case ARRAY:
6565: type = c().qualify(
6566: new PointerT(type.resolve().toArray()
6567: .getType()), type);
6568: break;
6569: case FUNCTION:
6570: type = c().qualify(
6571: new PointerT(type.resolve()), type);
6572: break;
6573: }
6574:
6575: // Annotate the type.
6576: if (null == name) {
6577: type = type.annotate().shape(false, "<param>");
6578: } else {
6579: type = VariableT.newParam(type, name).shape(
6580: false, name);
6581: }
6582: type = spec.annotateFull(type).attribute(
6583: toAttributeList(param.getGeneric(2)));
6584:
6585: // Check that any storage class specifier is register.
6586: if (type.hasAttribute(Constants.NAME_STORAGE)
6587: && (!type
6588: .hasAttribute(Constants.ATT_STORAGE_REGISTER))) {
6589: if (null == name) {
6590: runtime
6591: .error(
6592: "storage class specified for parameter",
6593: param);
6594: } else {
6595: runtime.error(
6596: "storage class specified for parameter '"
6597: + name + "'", param);
6598: }
6599: }
6600:
6601: // Check that there is no function specifier.
6602: if (spec.contains(Constants.ATT_INLINE)) {
6603: if (null == name) {
6604: runtime.error(
6605: "parameter declared 'inline'",
6606: param);
6607: } else {
6608: runtime.error("parameter '" + name
6609: + "' declared 'inline'", param);
6610: }
6611: }
6612:
6613: if (null == name) {
6614: types.add(type);
6615: } else if (table.current().isDefinedLocally(name)) {
6616: runtime.error("redefinition of parameter '"
6617: + name + "'", param);
6618: types
6619: .add(VariableT.newParam(ErrorT.TYPE,
6620: name));
6621: } else {
6622: table.current().define(name, type);
6623: types.add(type);
6624: }
6625: }
6626: }
6627:
6628: // Exit the temporary scope and delete it again.
6629: table.exit();
6630: table.delete(TMP_SCOPE);
6631:
6632: // Done.
6633: final FunctionT function = new FunctionT(null, types,
6634: variable);
6635: function.addAttribute(Constants.ATT_STYLE_NEW);
6636: return function;
6637:
6638: } else if (parameters.hasName("IdentifierList")) {
6639: // An old-style identifier list.
6640: Set<String> names = new HashSet<String>();
6641: List<Type> types = new ArrayList<Type>(parameters.size());
6642: for (Object o : parameters) {
6643: final String name = Token.cast(o);
6644:
6645: if (names.contains(name)) {
6646: runtime.error("multiple parameters named '" + name
6647: + "'", parameters);
6648: types.add(VariableT.newParam(ErrorT.TYPE, name));
6649: } else {
6650: names.add(name);
6651: types.add(VariableT.newParam(C.IMPLICIT, name)
6652: .shape(false, name));
6653: }
6654: }
6655:
6656: // Done.
6657: final FunctionT function = new FunctionT(null, types, false);
6658: function.addAttribute(Constants.ATT_STYLE_OLD);
6659: return function;
6660:
6661: } else {
6662: throw new AssertionError(
6663: "Unrecognized parameter representation: "
6664: + parameters);
6665: }
6666: }
6667:
6668: /**
6669: * Get the declared type. The type is not a parameter type.
6670: *
6671: * @param base The base type.
6672: * @param declarator The declarator, which may be abstract or
6673: * <code>null</code>.
6674: * @return The declared type.
6675: */
6676: public Type getDeclaredType(Type base, GNode declarator) {
6677: return getDeclaredType(false, base, declarator);
6678: }
6679:
6680: /**
6681: * Get the declared type. In addition to determining the declared
6682: * type, this method checks that any static storage class specifier
6683: * or type qualifiers only appear in an array declarator if the
6684: * declarator is part of a parameter declaration.
6685: *
6686: * @param isParam The flag for whether the type is a parameter type.
6687: * @param base The base type.
6688: * @param declarator The declarator, which may be abstract or
6689: * <code>null</code>.
6690: * @return The declared type.
6691: */
6692: @SuppressWarnings("unused")
6693: public Type getDeclaredType(final boolean isParam, final Type base,
6694: final GNode declarator) {
6695: return (null == declarator) ? base : (Type) new Visitor() {
6696: private Type result = base;
6697: private List<Attribute> list1 = null;
6698: private List<Attribute> list2 = null;
6699:
6700: private void annotate() {
6701: if ((null != list1) && (0 < list1.size())) {
6702: result = result.annotate().attribute(list1);
6703: list1 = null;
6704: }
6705: if ((null != list2) && (0 < list2.size())) {
6706: result = result.annotate().attribute(list2);
6707: list2 = null;
6708: }
6709: }
6710:
6711: private void processPointer(GNode pointer) {
6712: while (null != pointer) {
6713: final Specifiers spec = newSpecifiers(pointer
6714: .getGeneric(0), false);
6715: if (spec.hasBaseAttributes()) {
6716: result = spec.annotateBase(new PointerT(result)
6717: .annotate());
6718: } else {
6719: result = new PointerT(result);
6720: }
6721: pointer = pointer.getGeneric(1);
6722: }
6723: }
6724:
6725: private Type processArray(Type element, GNode expr,
6726: GNode decl) {
6727: // Process the size expression.
6728: if ((null != expr) && expr.hasName("VariableLength")) {
6729: // [*] denotes an incomplete variable length array. We
6730: // simply return an incomplete array type.
6731: if (!isParam) {
6732: runtime
6733: .error(
6734: "'[*]' in non-parameter array declarator",
6735: decl);
6736: }
6737: return new ArrayT(element, true);
6738:
6739: } else if (null == expr) {
6740: // An incomplete array.
6741: return new ArrayT(element);
6742:
6743: } else {
6744: final Type size = processExpression(expr);
6745:
6746: if (size.hasError()) {
6747: return new ArrayT(element);
6748:
6749: } else if (!c().isIntegral(size)) {
6750: final GNode id = getDeclaredId(decl);
6751: if (null == id) {
6752: runtime
6753: .error(
6754: "size of array has non-integer type",
6755: GNode.cast(expr));
6756: } else {
6757: runtime.error("size of array '"
6758: + id.getString(0)
6759: + "' has non-integer type", GNode
6760: .cast(expr));
6761: }
6762: return new ArrayT(element);
6763:
6764: } else if (size.hasConstant()) {
6765: BigInteger value;
6766: try {
6767: value = size.getConstant().bigIntValue();
6768: } catch (IllegalStateException x) {
6769: final GNode id = getDeclaredId(decl);
6770: if (null == id) {
6771: runtime.warning(
6772: "can't compute size of array",
6773: GNode.cast(expr));
6774: } else {
6775: runtime
6776: .warning(
6777: "can't compute size of array '"
6778: + id
6779: .getString(0)
6780: + "'", GNode
6781: .cast(expr));
6782: }
6783: value = BigInteger.ONE;
6784: }
6785:
6786: // Test: value == 0
6787: if (value.compareTo(BigInteger.ZERO) == 0) {
6788: if (pedantic) {
6789: final GNode id = getDeclaredId(decl);
6790: if (null == id) {
6791: runtime
6792: .error(
6793: "ISO C forbids zero-size array",
6794: GNode.cast(expr));
6795: } else {
6796: runtime.error(
6797: "ISO C forbids zero-size array '"
6798: + id.getString(0)
6799: + "'", GNode
6800: .cast(expr));
6801: }
6802: }
6803: return new ArrayT(element, 0);
6804:
6805: // Test: value < 0
6806: } else if (value.compareTo(BigInteger.ZERO) < 0) {
6807: final GNode id = getDeclaredId(decl);
6808: if (null == id) {
6809: runtime.error(
6810: "size of array is negative",
6811: GNode.cast(expr));
6812: } else {
6813: runtime.error("size of array '"
6814: + id.getString(0)
6815: + "' is negative", GNode
6816: .cast(expr));
6817: }
6818: return new ArrayT(element, 0);
6819:
6820: // Test: value > ARRAY_MAX
6821: } else if (value.compareTo(Limits.ARRAY_MAX) > 0) {
6822: final GNode id = getDeclaredId(decl);
6823: if (null == id) {
6824: runtime.error(
6825: "size of array is too large",
6826: GNode.cast(expr));
6827: } else {
6828: runtime.error("size of array '"
6829: + id.getString(0)
6830: + "' is too large", GNode
6831: .cast(expr));
6832: }
6833: return new ArrayT(element, 0);
6834:
6835: } else {
6836: return new ArrayT(element, value
6837: .longValue());
6838: }
6839:
6840: } else {
6841: return new ArrayT(element, true);
6842: }
6843: }
6844: }
6845:
6846: public Object visitAttributedDeclarator(GNode n) {
6847: if (null != n.get(0))
6848: list1 = toAttributeList(n.getGeneric(0));
6849: if (null != n.get(2))
6850: list2 = toAttributeList(n.getGeneric(2));
6851:
6852: return dispatch(n.getGeneric(1));
6853: }
6854:
6855: public Object visitPointerDeclarator(GNode n) {
6856: processPointer(n.getGeneric(0));
6857: annotate();
6858: return dispatch(n.getGeneric(1));
6859: }
6860:
6861: public Object visitArrayDeclarator(GNode n) {
6862: // Process the array size.
6863: result = processArray(result, n.getGeneric(2), n);
6864:
6865: // Process the array qualifier list.
6866: if (isParam) {
6867: if (n.getGeneric(0).hasName("SimpleDeclarator")) {
6868: final Specifiers spec = newSpecifiers(n
6869: .getGeneric(1), false);
6870: if (spec.hasBaseAttributes()) {
6871: result = spec.annotateBase(result
6872: .annotate());
6873: }
6874: if (spec.hasInline()
6875: || (null != spec.getStorageClass())) {
6876: result = spec.annotateFull(result
6877: .annotate());
6878: }
6879: } else if (0 < n.getGeneric(1).size()) {
6880: runtime.error(
6881: "static or type qualifiers not in outermost "
6882: + "array type derivation", n);
6883: }
6884:
6885: } else if (0 < n.getGeneric(1).size()) {
6886: runtime.error(
6887: "static or type qualifiers in non-parameter "
6888: + "array declarator", n);
6889: }
6890:
6891: // Process any annotations.
6892: annotate();
6893:
6894: // Done.
6895: return dispatch(n.getGeneric(0));
6896: }
6897:
6898: public Object visitFunctionDeclarator(GNode n) {
6899: final FunctionT function = getParameterTypes(n
6900: .getGeneric(1));
6901: function.setResult(result);
6902: result = function;
6903: annotate();
6904: return dispatch(n.getGeneric(0));
6905: }
6906:
6907: public Object visitSimpleDeclarator(GNode n) {
6908: annotate();
6909: return result;
6910: }
6911:
6912: public Object visitAttributedAbstractDeclarator(GNode n) {
6913: if (null != n.get(0))
6914: list1 = toAttributeList(n.getGeneric(0));
6915:
6916: return dispatch(n.getGeneric(1));
6917: }
6918:
6919: public Object visitAbstractDeclarator(GNode n) {
6920: processPointer(n.getGeneric(0));
6921: annotate();
6922: return (null == n.get(1)) ? result : dispatch(n
6923: .getGeneric(1));
6924: }
6925:
6926: public Object visitDirectAbstractDeclarator(GNode n) {
6927: if (3 == n.size()) {
6928: if ("[".equals(n.getString(1))) {
6929: result = processArray(result, n.getGeneric(2),
6930: n);
6931:
6932: } else {
6933: final FunctionT function = getParameterTypes(n
6934: .getGeneric(2));
6935: function.setResult(result);
6936: result = function;
6937: }
6938:
6939: if (null == n.get(0)) {
6940: annotate();
6941: return result;
6942: } else {
6943: annotate();
6944: return dispatch(n.getGeneric(0));
6945: }
6946:
6947: } else if (null == n.get(0)) {
6948: annotate();
6949: return result;
6950:
6951: } else {
6952: annotate();
6953: return dispatch(n.getGeneric(0));
6954: }
6955: }
6956:
6957: }.dispatch(declarator);
6958: }
6959:
6960: /**
6961: * Get the declared identifier from the specified declarator.
6962: *
6963: * @param declarator The declarator, which may be abstract or
6964: * <code>null</code>.
6965: * @return The simple declarator node representing the declared
6966: * identifier or <code>null</code> if the specified declarator is
6967: * abstract or <code>null</code>.
6968: */
6969: public static GNode getDeclaredId(GNode declarator) {
6970: return GNode.cast(getDeclaredIdVisitor.dispatch(declarator));
6971: }
6972:
6973: /** The actual implementation of {@link #getDeclaredId(GNode)}. */
6974: @SuppressWarnings("unused")
6975: private static final Visitor getDeclaredIdVisitor = new Visitor() {
6976: public Object visitAttributedDeclarator(GNode n) {
6977: return dispatch(n.getGeneric(1));
6978: }
6979:
6980: public Object visitPointerDeclarator(GNode n) {
6981: return dispatch(n.getGeneric(1));
6982: }
6983:
6984: public Object visitFunctionDeclarator(GNode n) {
6985: return dispatch(n.getGeneric(0));
6986: }
6987:
6988: public Object visitArrayDeclarator(GNode n) {
6989: return dispatch(n.getGeneric(0));
6990: }
6991:
6992: public Object visitSimpleDeclarator(GNode n) {
6993: return n;
6994: }
6995:
6996: public Object visitAttributedAbstractDeclarator(GNode n) {
6997: return null;
6998: }
6999:
7000: public Object visitAbstractDeclarator(GNode n) {
7001: return null;
7002: }
7003:
7004: public Object visitDirectAbstractDeclarator(GNode n) {
7005: return null;
7006: }
7007: };
7008:
7009: /**
7010: * Get the innermost function declarator from the specified
7011: * declarator. The innermost function declarator's parameters are
7012: * the parameters for a function declaration or definition.
7013: *
7014: * @param declarator The declarator.
7015: * @return The innermost function declarator or <code>null</code> if
7016: * the declarator does not contains a function declarator.
7017: */
7018: public static GNode getFunctionDeclarator(GNode declarator) {
7019: return GNode.cast(getFunctionDeclaratorVisitor
7020: .dispatch(declarator));
7021: }
7022:
7023: /** The actual implementation of {@link #getFunctionDeclarator}. */
7024: @SuppressWarnings("unused")
7025: private static final Visitor getFunctionDeclaratorVisitor = new Visitor() {
7026: public Object visitAttributedDeclarator(GNode n) {
7027: return dispatch(n.getGeneric(1));
7028: }
7029:
7030: public Object visitPointerDeclarator(GNode n) {
7031: return dispatch(n.getGeneric(1));
7032: }
7033:
7034: public Object visitFunctionDeclarator(GNode n) {
7035: Object result = dispatch(n.getGeneric(0));
7036: return (null == result) ? n : result;
7037: }
7038:
7039: public Object visitArrayDeclarator(GNode n) {
7040: return dispatch(n.getGeneric(0));
7041: }
7042:
7043: public Object visitSimpleDeclarator(GNode n) {
7044: return null;
7045: }
7046: };
7047:
7048: /**
7049: * Determine whether the specified parameter type list represents a
7050: * function taking no arguments. This method checks whether the
7051: * parameter type list contains a single parameter without a
7052: * declarator, whose specifiers either contains a void type
7053: * specifier or a typedef name aliasing void. Though the parameter
7054: * type list may still be malformed, e.g., contain a qualifier,
7055: * storage class, or another type specifier.
7056: *
7057: * @param parameters The parameter type list.
7058: * @return <code>true</code> if the corresponding function takes no
7059: * arguments.
7060: */
7061: public boolean isVoidParameterTypeList(GNode parameters) {
7062: assert parameters.hasName("ParameterTypeList");
7063:
7064: if (null != parameters.get(1))
7065: return false;
7066: parameters = parameters.getGeneric(0);
7067: if (1 != parameters.size())
7068: return false;
7069: final GNode parameter = parameters.getGeneric(0);
7070: if (null != parameter.get(1))
7071: return false;
7072: final GNode specifiers = parameter.getGeneric(0);
7073:
7074: for (Object o : specifiers) {
7075: final GNode spec = GNode.cast(o);
7076:
7077: if (spec.hasName("VoidTypeSpecifier")) {
7078: return true;
7079:
7080: } else if (spec.hasName("TypedefName")) {
7081: final Type type = (Type) table.current().lookup(
7082: spec.getString(0));
7083:
7084: if ((null != type) && type.isAlias()
7085: && type.resolve().isVoid()) {
7086: return true;
7087: }
7088: }
7089: }
7090: return false;
7091: }
7092:
7093: /**
7094: * Determine whether the specified left-hand type can be initialized
7095: * from the specified right-hand type.
7096: *
7097: * @param t1 The left-hand type.
7098: * @param t2 The right-hand type.
7099: * @return <code>true</code> if the left-hand type can be
7100: * initialized by the right-hand type.
7101: */
7102: protected boolean isInitializable(Type t1, Type t2) {
7103: if (t1.hasError() || t2.hasError())
7104: return true;
7105:
7106: final Type r1 = t1.resolve();
7107: final Type r2 = c().pointerize(t2);
7108:
7109: switch (r1.tag()) {
7110: case BOOLEAN:
7111: case INTEGER:
7112: case FLOAT: {
7113: if (r1.isBoolean()) {
7114: // Booleans can be assigned from scalar operands.
7115: return c().isScalar(r2);
7116: } else {
7117: // All other arithmetic types can only be assigned from
7118: // arithmetic types. GCC also allows assignments from
7119: // pointers.
7120: return c().isArithmetic(r2)
7121: || (r2.isPointer() && !pedantic);
7122: }
7123: }
7124:
7125: case STRUCT:
7126: case UNION: {
7127: // A struct or union can only be assigned from another struct or
7128: // union of compatible type.
7129: return c().equal(r1, r2);
7130: }
7131:
7132: case ARRAY: {
7133: // An array can only be assigned in an initializer and only if
7134: // the left-hand type is a (wide) C string and the right-hand
7135: // type is a matching C string constant.
7136: return (t2.hasConstant() && ((c().isString(r1) && c()
7137: .isString(t2)) || (c().isWideString(r1) && c()
7138: .isWideString(t2))));
7139: }
7140:
7141: case POINTER: {
7142: if (r2.isPointer()) {
7143: final Type pt1 = r1.toPointer().getType(); // PointedTo, PTResolved
7144: final Type pt2 = r2.toPointer().getType();
7145:
7146: final Type ptr1 = pt1.resolve();
7147: final Type ptr2 = pt2.resolve();
7148:
7149: if (c().hasQualifiers(pt1, pt2)
7150: && (c().equal(ptr1, ptr2) || ptr1.isVoid() || ptr2
7151: .isVoid())) {
7152: return true;
7153: } else {
7154: // GCC extension.
7155: return !pedantic;
7156: }
7157:
7158: } else if (t2.hasConstant() && t2.getConstant().isNull()) {
7159: return true;
7160:
7161: } else if (c().isIntegral(t2)) {
7162: // GCC extension.
7163: return !pedantic;
7164:
7165: } else {
7166: return false;
7167: }
7168: }
7169:
7170: default:
7171: return (r1.isInternal() && r2.isInternal() && r1
7172: .toInternal().getName().equals(
7173: r2.toInternal().getName()));
7174: }
7175: }
7176:
7177: /**
7178: * Process the assignment. This method determines the resulting
7179: * type when assigning a value of the specified right-hand type to
7180: * an object with the specified left-hand type. It does not check
7181: * that the left-hand side represents a modifiable lvalue.
7182: *
7183: * @param init The flag for whether the assignment is in an
7184: * initializer.
7185: * @param op The name of the operation.
7186: * @param n The node.
7187: * @param t1 The left-hand type.
7188: * @param t2 The right-hand type.
7189: * @return The resulting type.
7190: */
7191: protected Type processAssignment(boolean init, String op, Node n,
7192: Type t1, Type t2) {
7193: if (t1.hasError() || t2.hasError())
7194: return ErrorT.TYPE;
7195:
7196: final Type r1 = t1.resolve();
7197: final Type r2 = c().pointerize(t2);
7198: Type result = null;
7199:
7200: if (r2.isVoid()) {
7201: runtime
7202: .error("void value not ignored as it ought to be",
7203: n);
7204: return ErrorT.TYPE;
7205: }
7206:
7207: switch (r1.tag()) {
7208: case BOOLEAN: {
7209: // Booleans can be assigned from scalar operands.
7210: if (c().isScalar(r2)) {
7211: result = r1;
7212: }
7213: }
7214: break;
7215:
7216: case INTEGER: {
7217: // Integers can be assigned from scalar operands, but call for a
7218: // warning then the operand is a pointer.
7219: if (c().isArithmetic(r2)) {
7220: result = r1;
7221: } else if (r2.isPointer()) {
7222: if (pedantic) {
7223: runtime
7224: .error(
7225: op
7226: + " makes integer from pointer without a cast",
7227: n);
7228: result = ErrorT.TYPE;
7229: } else {
7230: // GCC extension.
7231: runtime
7232: .warning(
7233: op
7234: + " makes integer from pointer without a cast",
7235: n);
7236: result = r1;
7237: }
7238: }
7239: }
7240: break;
7241:
7242: case FLOAT: {
7243: // Floats can be assigned from other arithmetic types.
7244: if (c().isArithmetic(r2)) {
7245: result = r1;
7246: }
7247: }
7248: break;
7249:
7250: case STRUCT:
7251: case UNION: {
7252: // A struct or union can only be assigned from another struct or
7253: // union of compatible type.
7254: if (c().equal(r1, r2)) {
7255: result = r1;
7256: }
7257: }
7258: break;
7259:
7260: case ARRAY: {
7261: // An array can only be assigned in an initializer and only if
7262: // the left-hand type is a (wide) C string and the right-hand
7263: // type is a matching C string constant.
7264: if (init) {
7265: if (c().isString(r1) && t2.hasConstant()) {
7266: if (c().isString(t2)) {
7267: result = r1;
7268: } else if (c().isWideString(t2)) {
7269: runtime
7270: .error(
7271: "char-array initialized from wide string",
7272: n);
7273: result = ErrorT.TYPE;
7274: }
7275:
7276: } else if (c().isWideString(r1) && t2.hasConstant()) {
7277: if (c().isString(t2)) {
7278: runtime
7279: .error(
7280: "wchar_t-array initialized from non-wide string",
7281: n);
7282: result = ErrorT.TYPE;
7283: } else if (c().isWideString(t2)) {
7284: result = r1;
7285: }
7286: }
7287: }
7288: }
7289: break;
7290:
7291: case POINTER: {
7292: if (r2.isPointer()) {
7293: final Type pt1 = r1.toPointer().getType(); // PointedTo, PTResolved
7294: final Type pt2 = r2.toPointer().getType();
7295:
7296: final Type ptr1 = pt1.resolve();
7297: final Type ptr2 = pt2.resolve();
7298:
7299: if (c().hasQualifiers(pt1, pt2)
7300: && (c().equal(ptr1, ptr2) || ptr1.isVoid() || ptr2
7301: .isVoid())) {
7302: result = r1;
7303:
7304: } else if (pedantic) {
7305: runtime.error(
7306: "incompatible pointer types in " + op, n);
7307: result = ErrorT.TYPE;
7308:
7309: } else if (ptr1.isNumber()
7310: && ptr2.isNumber()
7311: && NumberT.equalIgnoringSign(ptr1.toNumber()
7312: .getKind(), ptr2.toNumber().getKind())) {
7313: // Note: We don't need to consider booleans here because all
7314: // booleans are unsigned.
7315: if (pedantic) {
7316: runtime.error("pointer targets in " + op
7317: + " differ in signedness", n);
7318: result = ErrorT.TYPE;
7319: } else {
7320: // GCC extension.
7321: runtime.warning("pointer targets in " + op
7322: + " differ in signedness", n);
7323: result = r1;
7324: }
7325:
7326: } else {
7327: if (pedantic) {
7328: runtime.error("incompatible pointer types in "
7329: + op, n);
7330: result = ErrorT.TYPE;
7331: } else {
7332: // GCC extension.
7333: runtime.warning(
7334: "incompatible pointer types in " + op,
7335: n);
7336: result = r1;
7337: }
7338: }
7339:
7340: } else if (t2.hasConstant() && t2.getConstant().isNull()) {
7341: result = r1;
7342:
7343: } else if (c().isIntegral(t2)) {
7344: if (pedantic) {
7345: runtime
7346: .error(
7347: op
7348: + " makes pointer from integer without a cast",
7349: n);
7350: result = ErrorT.TYPE;
7351: } else {
7352: // GCC extension.
7353: runtime
7354: .warning(
7355: op
7356: + " makes pointer from integer without a cast",
7357: n);
7358: result = r1;
7359: }
7360: }
7361: }
7362: break;
7363:
7364: default:
7365: if (r1.isInternal()
7366: && r2.isInternal()
7367: && r1.toInternal().getName().equals(
7368: r2.toInternal().getName())) {
7369: result = r1;
7370: }
7371: }
7372:
7373: // Patch in generic error type and message.
7374: if (null == result) {
7375: runtime.error("incompatible types in " + op, n);
7376: result = ErrorT.TYPE;
7377: }
7378:
7379: // Done.
7380: return result;
7381: }
7382:
7383: /**
7384: * Mark the specified node with the specified type. As a
7385: * side-effect, this method also seals the specified type.
7386: *
7387: * @param node The node.
7388: * @param type The type.
7389: */
7390: public void mark(Node node, Type type) {
7391: if (runtime.test("optionMarkAST")) {
7392: type.seal().mark(node);
7393: }
7394: }
7395:
7396: /**
7397: * Ensure that the specified node with the specified type represents
7398: * a modifiable lvalue.
7399: *
7400: * @param n The node.
7401: * @param t The type.
7402: * @return <code>true</code> if the specified node represents a
7403: * modifiable lvalue.
7404: */
7405: public boolean ensureLValue(Node n, Type t) {
7406: if (t.hasError()) {
7407: return false;
7408: } else if (!t.hasShape()) {
7409: runtime.error("invalid operand where lvalue required", n);
7410: return false;
7411: } else if (c().isIncomplete(t)) {
7412: runtime.error("assignment of incomplete "
7413: + toDescription(n), n);
7414: return false;
7415: } else if (!c().isModifiable(t)) {
7416: runtime.error(
7417: "assignment of read-only " + toDescription(n), n);
7418: return false;
7419: } else {
7420: return true;
7421: }
7422: }
7423:
7424: /**
7425: * Ensure that the specified node with the specified type represents
7426: * a scalar.
7427: *
7428: * @param n The node.
7429: * @param t the type.
7430: * @return <code>true</code> if the specified node represents a
7431: * scalar.
7432: */
7433: public boolean ensureScalar(Node n, Type t) {
7434: if (t.hasError()) {
7435: return false;
7436: } else if (!c().isScalar(t)) {
7437: runtime.error("invalid " + toDescription(n)
7438: + " where scalar required", n);
7439: return false;
7440: } else {
7441: return true;
7442: }
7443: }
7444:
7445: /**
7446: * Ensure that the specified node represents valid pointer
7447: * arithmetic for the specified type. If the specified type is a
7448: * pointer, this method ensures that the pointer points to a
7449: * complete type. For all other types besides the error type, it
7450: * returns <code>true</code>.
7451: *
7452: * @param n The node.
7453: * @param t The type.
7454: * @return <code>true</code> if the specified node represents valid
7455: * pointer arithmetic.
7456: */
7457: public boolean ensurePointerArithmetic(Node n, Type t) {
7458: if (t.hasError()) {
7459: return false;
7460:
7461: } else if (t.resolve().isPointer()) {
7462: final Type pt = t.resolve().toPointer().getType();
7463:
7464: if (!pt.resolve().isVoid() && c().isIncomplete(pt)) {
7465: runtime.error(
7466: "arithmetic on pointer to an incomplete type",
7467: n);
7468: return false;
7469: } else {
7470: return true;
7471: }
7472:
7473: } else {
7474: return true;
7475: }
7476: }
7477:
7478: /**
7479: * Ensure that the specified node with the specified type represents
7480: * an arithmetic type.
7481: *
7482: * @param n The node.
7483: * @param t The type.
7484: * @return <code>true</code> if the specified node represents an
7485: * arithmetic type.
7486: */
7487: public boolean ensureArithmetic(Node n, Type t) {
7488: if (t.hasError()) {
7489: return false;
7490: } else if (!c().isArithmetic(t)) {
7491: runtime.error("invalid " + toDescription(n)
7492: + " where arithmetic value required", n);
7493: return false;
7494: } else {
7495: return true;
7496: }
7497: }
7498:
7499: /**
7500: * Ensure that the specified note with the specified type represents
7501: * an integer.
7502: *
7503: * @param n The node.
7504: * @param t The type.
7505: * @return <code>true</code> if the specified node represents an
7506: * integer.
7507: */
7508: public boolean ensureInteger(Node n, Type t) {
7509: if (t.hasError()) {
7510: return false;
7511: } else if (!c().isIntegral(t)) {
7512: runtime.error("invalid " + toDescription(n)
7513: + " where integer required", n);
7514: return false;
7515: } else {
7516: return true;
7517: }
7518: }
7519:
7520: /**
7521: * Convert the specified node representing an operand to its
7522: * description.
7523: *
7524: * @param n The node.
7525: * @return The corresponding description.
7526: */
7527: public static String toDescription(Node n) {
7528: final GNode node = GNode.cast(n);
7529:
7530: if (node.hasName("PrimaryIdentifier")) {
7531: return "variable '" + node.getString(0) + "'";
7532: } else if (node.hasName("DirectComponentSelection")
7533: || node.hasName("IndirectComponentSelection")) {
7534: return "field '" + node.getString(1) + "'";
7535: } else if (node.hasName("IndirectionExpression")) {
7536: final GNode child = node.getGeneric(0);
7537: if (child.hasName("PrimaryIdentifier")) {
7538: return "object '*" + child.getString(0) + "'";
7539: } else {
7540: return "location";
7541: }
7542: } else if (node.hasName("TypeName")) {
7543: return "type name";
7544: } else {
7545: return "operand";
7546: }
7547: }
7548:
7549: /**
7550: * Convert the specified node representing a function to its
7551: * name.
7552: *
7553: * @param n The node.
7554: * @return The corresponding name or <code>null</code> if the name
7555: * cannot be determined.
7556: */
7557: public static String toFunctionName(Node n) {
7558: final GNode node = GNode.cast(n);
7559:
7560: if (node.hasName("PrimaryIdentifier")) {
7561: return node.getString(0);
7562: } else if (node.hasName("DirectComponentSelection")
7563: || node.hasName("IndirectComponentSelection")) {
7564: return node.getString(1);
7565: } else if (node.hasName("indirectionExpressiion")) {
7566: final GNode child = node.getGeneric(0);
7567: if (child.hasName("PrimaryIdentifier")) {
7568: return child.getString(0);
7569: } else {
7570: return null;
7571: }
7572: } else {
7573: return null;
7574: }
7575: }
7576:
7577: /**
7578: * Determine whether the specified scope name represents a function
7579: * or macro scope.
7580: *
7581: * @param name The name.
7582: * @return <code>true</code> if the specified name represents a
7583: * function or macro scope.
7584: */
7585: public static boolean isFunctionScope(String name) {
7586: return (SymbolTable.isFunctionScopeName(name) || SymbolTable
7587: .isMacroScopeName(name));
7588: }
7589:
7590: /**
7591: * Look up the specified name in the scope for extern declarations.
7592: *
7593: * @param name The name.
7594: * @return The corresponding type or <code>null</code> if no such
7595: * binding exists.
7596: */
7597: public Type lookupExtern(String name) {
7598: final Scope scope = table.getScope(EXTERN_PATH);
7599: return null == scope ? null : (Type) scope.lookupLocally(name);
7600: }
7601:
7602: /**
7603: * Define the specified name in the scope for extern declarations.
7604: *
7605: * @param name The name.
7606: * @param type The type.
7607: */
7608: public void defineExtern(String name, Type type) {
7609: Scope scope = table.getScope(EXTERN_PATH);
7610:
7611: // If the extern scope does not exist, create it.
7612: if (null == scope) {
7613: final Scope current = table.current();
7614: table.setScope(table.root());
7615: table.enter(EXTERN_SCOPE);
7616: scope = table.current();
7617: table.setScope(current);
7618: }
7619:
7620: scope.define(name, type);
7621: }
7622:
7623: /**
7624: * Report a previous declaration or definition. If the specified
7625: * type has a location, this method prints that location as a
7626: * previous declaration or definition.
7627: *
7628: * @param name The name.
7629: * @param type The type.
7630: */
7631: public void reportPrevious(String name, Type type) {
7632: // If the type has a location, print the error message.
7633: if (type.hasLocation()) {
7634: runtime.errConsole().loc(type).p(": error: previous ");
7635: if (type.hasAttribute(Constants.ATT_MACRO)
7636: || type.hasAttribute(Constants.ATT_DEFINED)) {
7637: runtime.errConsole().p("definition");
7638: } else {
7639: runtime.errConsole().p("declaration");
7640: }
7641: runtime.errConsole().p(" of '").p(name).pln("' was here")
7642: .flush();
7643: }
7644: }
7645:
7646: /**
7647: * Report a previous declaration or definition of the specified
7648: * tagged type. If the specified type has a location, this method
7649: * prints that location as a previous declaration or definition.
7650: *
7651: * @param type The type.
7652: */
7653: public void reportPreviousTag(Type type) {
7654: final Tagged tag = type.toTagged();
7655:
7656: if (type.hasLocation()) {
7657: runtime.errConsole().loc(type).p(": error: previous ");
7658: if (null != tag.getMembers()) {
7659: runtime.errConsole().p("definition");
7660: } else {
7661: runtime.errConsole().p("declaration");
7662: }
7663: runtime.errConsole().p(" of '").p(tag.getName()).p(
7664: "' was here").flush();
7665: }
7666: }
7667:
7668: }
|