0001: /*
0002: * xtc - The eXTensible Compiler
0003: * Copyright (C) 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.type;
0020:
0021: import java.math.BigInteger;
0022:
0023: import java.util.ArrayList;
0024: import java.util.Iterator;
0025: import java.util.List;
0026:
0027: import xtc.Constants;
0028: import xtc.Limits;
0029:
0030: import xtc.tree.Attribute;
0031:
0032: import xtc.util.Utilities;
0033:
0034: /**
0035: * Common type operations for the C language.
0036: *
0037: * @author Robert Grimm
0038: * @version $Revision: 1.30 $
0039: */
0040: public class C {
0041:
0042: /** Create a new instance. */
0043: public C() { /* Nothing to do. */
0044: }
0045:
0046: /**
0047: * The canonical implicit int type. In K&R C, a missing type
0048: * specifier is treated as an int. We preserve knowledge about this
0049: * lack of type specifier through this type, which has a {@link
0050: * Constants#ATT_IMPLICIT} attribute.
0051: */
0052: public static final IntegerT IMPLICIT = new IntegerT(
0053: NumberT.Kind.INT);
0054:
0055: static {
0056: IMPLICIT.addAttribute(Constants.ATT_IMPLICIT);
0057: IMPLICIT.seal();
0058: }
0059:
0060: /** The integer kind of the sizeof type. */
0061: protected static final NumberT.Kind KIND_SIZEOF = IntegerT
0062: .fromRank(Limits.SIZEOF_RANK, false);
0063:
0064: /** The canonical sizeof type. */
0065: public static final IntegerT SIZEOF = new IntegerT(KIND_SIZEOF);
0066:
0067: static {
0068: SIZEOF.seal();
0069: }
0070:
0071: /** The integer kind of the pointer difference type. */
0072: protected static final NumberT.Kind KIND_PTR_DIFF = IntegerT
0073: .fromRank(Limits.PTRDIFF_RANK, true);
0074:
0075: /** The canonical pointer difference type. */
0076: public static final IntegerT PTR_DIFF = new IntegerT(KIND_PTR_DIFF);
0077:
0078: static {
0079: PTR_DIFF.seal();
0080: }
0081:
0082: /** The number kind of the wchar_t type. */
0083: protected static final NumberT.Kind KIND_WCHAR = IntegerT.fromRank(
0084: Limits.WCHAR_RANK, Limits.IS_WCHAR_SIGNED);
0085:
0086: /** The canonical wide char type. */
0087: public static final IntegerT WCHAR = new IntegerT(KIND_WCHAR);
0088:
0089: static {
0090: WCHAR.seal();
0091: }
0092:
0093: // =========================================================================
0094:
0095: /**
0096: * Determine whether the specified type is a char.
0097: *
0098: * @param type The type.
0099: * @return <code>true</code> if the type is a char.
0100: */
0101: public boolean isChar(Type type) {
0102: if (type.hasEnum())
0103: return false;
0104:
0105: type = type.resolve();
0106:
0107: if (type.isInteger()) {
0108: switch (type.toInteger().getKind()) {
0109: case CHAR:
0110: case S_CHAR:
0111: case U_CHAR:
0112: return true;
0113: default:
0114: return false;
0115: }
0116: } else {
0117: return false;
0118: }
0119: }
0120:
0121: /**
0122: * Determine whether the specified type is a wide char.
0123: *
0124: * @param type The type.
0125: * @return <code>true</code> if the type is a wide char.
0126: */
0127: public boolean isWideChar(Type type) {
0128: if (type.hasEnum())
0129: return false;
0130:
0131: type = type.resolve();
0132:
0133: if (type.isInteger()) {
0134: return NumberT
0135: .equal(KIND_WCHAR, type.toInteger().getKind());
0136: } else {
0137: return false;
0138: }
0139: }
0140:
0141: /**
0142: * Determine whether the specified type is a string.
0143: *
0144: * @param type The type.
0145: * @return <code>true</code> if the type is a string.
0146: */
0147: public boolean isString(Type type) {
0148: type = type.resolve();
0149:
0150: return type.isArray() && isChar(type.toArray().getType());
0151: }
0152:
0153: /**
0154: * Determine whether the specified type is a wide string.
0155: *
0156: * @param type The type.
0157: * @return <code>true</code> if the type is a wide string.
0158: */
0159: public boolean isWideString(Type type) {
0160: type = type.resolve();
0161:
0162: return type.isArray() && isWideChar(type.toArray().getType());
0163: }
0164:
0165: // =========================================================================
0166:
0167: /**
0168: * Determine whether the specified type is integral.
0169: *
0170: * @param type The type.
0171: * @return <code>true</code> if the specified type is integral.
0172: */
0173: public boolean isIntegral(Type type) {
0174: switch (type.tag()) {
0175: case BOOLEAN:
0176: case INTEGER:
0177: return true;
0178: default:
0179: return false;
0180: }
0181: }
0182:
0183: /**
0184: * Determine whether the specified type is real.
0185: *
0186: * @param type The type.
0187: * @return <code>true</code> if the specified type is real.
0188: */
0189: public boolean isReal(Type type) {
0190: switch (type.tag()) {
0191: case BOOLEAN:
0192: case INTEGER:
0193: return true;
0194: case FLOAT:
0195: switch (type.resolve().toFloat().getKind()) {
0196: case FLOAT_COMPLEX:
0197: case DOUBLE_COMPLEX:
0198: case LONG_DOUBLE_COMPLEX:
0199: return false;
0200: default:
0201: return true;
0202: }
0203: default:
0204: return false;
0205: }
0206: }
0207:
0208: /**
0209: * Determine whether the specified type is arithmetic.
0210: *
0211: * @param type The type.
0212: * @return <code>true</code> if the specified type is arithmetic.
0213: */
0214: public boolean isArithmetic(Type type) {
0215: switch (type.tag()) {
0216: case BOOLEAN:
0217: case INTEGER:
0218: case FLOAT:
0219: return true;
0220: default:
0221: return false;
0222: }
0223: }
0224:
0225: /**
0226: * Determine whether the specified type is scalar.
0227: *
0228: * @param type The type.
0229: * @return <code>true</code> if the specified type is scalar.
0230: */
0231: public boolean isScalar(Type type) {
0232: switch (type.tag()) {
0233: case BOOLEAN:
0234: case INTEGER:
0235: case FLOAT:
0236: case POINTER:
0237: return true;
0238: default:
0239: return false;
0240: }
0241: }
0242:
0243: /**
0244: * Determine whether the specified type is incomplete.
0245: *
0246: * <p />Per C99 6.2.5, a type is incomplete if it does not contain
0247: * sufficient information for determining its size. However, per
0248: * C99 6.7.2.1, a struct type with more than one named member may
0249: * have an incomplete type as its last member, while still being
0250: * considered complete.
0251: *
0252: * @param type The type.
0253: * @return <code>true</code> if the type is incomplete.
0254: */
0255: public boolean isIncomplete(Type type) {
0256: // Handle alias and enum types first since they are wrapped and do
0257: // not have a tag.
0258: while (type.isWrapped()) {
0259: switch (type.wtag()) {
0260: case ALIAS:
0261: return null == type.toAlias().getType();
0262: case ENUM:
0263: return null == type.toEnum().getMembers();
0264: default:
0265: type = type.toWrapped().getType();
0266: }
0267: }
0268:
0269: // The type has been resolved.
0270: switch (type.tag()) {
0271: case VOID:
0272: // Void always is incomplete.
0273: return true;
0274: case ARRAY: {
0275: // An array is incomplete if (1) it is not variable and has no
0276: // lenght, (2) it has an incomplete member type, or (3) it has a
0277: // trailing array.
0278: ArrayT a = type.toArray();
0279: return (((!a.isVarLength()) && (!a.hasLength()))
0280: || isIncomplete(a.getType()) || hasTrailingArray(a
0281: .getType()));
0282: }
0283: case STRUCT: {
0284: // A struct is incomplete if (1) it has no members, (2) any
0285: // member but the last member is incomplete, (3) the last member
0286: // is not an array but is incomplete, or (4) the last member is
0287: // an array with an incomplete element type.
0288: List<VariableT> members = type.toStruct().getMembers();
0289: if (null == members)
0290: return true;
0291: for (Iterator<VariableT> iter = members.iterator(); iter
0292: .hasNext();) {
0293: VariableT member = iter.next();
0294:
0295: if (iter.hasNext() || (Type.Tag.ARRAY != member.tag())) {
0296: // In general, members may not be incomplete. We allow
0297: // struct members with trailing incomplete arrays because
0298: // GCC allows them.
0299: if (isIncomplete(member))
0300: return true;
0301: } else {
0302: // The last member is an array. We allow struct element
0303: // types with trailing incomplete arrays because GCC allows
0304: // them.
0305: ArrayT array = member.resolve().toArray();
0306: if (isIncomplete(array.getType()))
0307: return true;
0308: }
0309: }
0310: return false;
0311: }
0312: case UNION: {
0313: // A union is incomplete if (1) it has no members or (2) any
0314: // member is incomplete.
0315: List<VariableT> members = type.toUnion().getMembers();
0316: if (null == members)
0317: return true;
0318: for (Type t : members) {
0319: if (isIncomplete(t))
0320: return true;
0321: }
0322: return false;
0323: }
0324: default:
0325: return false;
0326: }
0327: }
0328:
0329: /**
0330: * Determine whether the specified type has a trailing array. This
0331: * method checks whether the specified type is either a struct type
0332: * with an incomplete array as its last member or a union containing
0333: * such a member.
0334: *
0335: * @param type The type.
0336: * @return <code>true</code> if the type has a trailing array.
0337: */
0338: public boolean hasTrailingArray(Type type) {
0339: switch (type.tag()) {
0340: case STRUCT: {
0341: // A struct has a trailing array if its last member is a fixed
0342: // length array without a concrete length.
0343: List<VariableT> members = type.resolve().toStruct()
0344: .getMembers();
0345: if (null != members) {
0346: int size = members.size();
0347: Type last = 0 < size ? members.get(size - 1) : null;
0348:
0349: if ((null != last) && (Type.Tag.ARRAY == last.tag())) {
0350: ArrayT a = last.resolve().toArray();
0351: return (!a.isVarLength()) && (!a.hasLength());
0352: }
0353: }
0354: return false;
0355: }
0356: case UNION: {
0357: // A union has a trailing array if any member has a trailing
0358: // array.
0359: List<VariableT> members = type.resolve().toUnion()
0360: .getMembers();
0361: if (null != members) {
0362: for (Type t : members) {
0363: if (hasTrailingArray(t))
0364: return true;
0365: }
0366: }
0367: return false;
0368: }
0369: default:
0370: return false;
0371: }
0372: }
0373:
0374: /**
0375: * Determine whether the specified type is variably modified.
0376: * Consistent with C99 6.7.5-3, this method checks whether the type
0377: * contains a variable length array type.
0378: *
0379: * @param type The type.
0380: * @return <code>true</code> if the type is variably modified.
0381: */
0382: public boolean isVariablyModified(Type type) {
0383: switch (type.tag()) {
0384: case POINTER:
0385: return isVariablyModified(type.resolve().toPointer()
0386: .getType());
0387: case ARRAY:
0388: ArrayT a = type.resolve().toArray();
0389: return a.isVarLength() || isVariablyModified(a.getType());
0390: default:
0391: return false;
0392: }
0393: }
0394:
0395: /**
0396: * Determine whether the specified type is qualified as constant.
0397: * Consistent with C99 6.3.2.1, this method checks whether the type
0398: * has a {@link Constants#ATT_CONSTANT} attribute and, if it is an
0399: * array, struct, or union, whether any member or element of the
0400: * type has that attribute.
0401: *
0402: * @param type The type.
0403: * @return <code>true</code> if the specified type is constant
0404: * qualified.
0405: */
0406: public boolean isConstant(Type type) {
0407: if (type.hasAttribute(Constants.ATT_CONSTANT))
0408: return true;
0409:
0410: switch (type.tag()) {
0411: case ARRAY:
0412: type = type.resolve().toArray().getType();
0413: return (null == type) ? false : isConstant(type);
0414: case STRUCT:
0415: case UNION:
0416: for (Type member : type.toTagged().getMembers()) {
0417: if (isConstant(member))
0418: return true;
0419: }
0420: return false;
0421: default:
0422: return false;
0423: }
0424: }
0425:
0426: /**
0427: * Determine whether the specified type represents a modifiable
0428: * lvalue. Consistent with C99 6.3.2.1, this method checks that the
0429: * type represents an lvalue, is not incomplete, and is not
0430: * qualified as constant. For struct and union types, this method
0431: * also checks that no member is qualified as constant.
0432: *
0433: * @param type The type.
0434: * @return <code>true</code> if the type represents a modifiable
0435: * lvalue.
0436: */
0437: public boolean isModifiable(Type type) {
0438: if (!type.hasShape())
0439: return false;
0440: if (isIncomplete(type))
0441: return false;
0442: if (Type.Tag.ARRAY == type.tag())
0443: return false;
0444: return !isConstant(type);
0445: }
0446:
0447: // =========================================================================
0448:
0449: /**
0450: * Determine whether this type has a constant reference. This
0451: * method takes the pointer decay of arrays and functions into
0452: * account and returns <code>true</code> either if the specified
0453: * type has a constant reference or if this type is an array or
0454: * function and has a constant reference.
0455: *
0456: * @param type The type.
0457: * @return <code>true</code> if the type has a constant reference.
0458: */
0459: public boolean hasConstRef(Type type) {
0460: if (type.hasConstant() && type.getConstant().isReference())
0461: return true;
0462:
0463: switch (type.tag()) {
0464: case ARRAY:
0465: case FUNCTION:
0466: return type.hasShape() && type.getShape().isConstant();
0467: default:
0468: return false;
0469: }
0470: }
0471:
0472: /**
0473: * Get the specified type's constant reference.
0474: *
0475: * @param type The type.
0476: * @return The constant reference.
0477: * @throws IllegalArgumentException Signals that the type does not
0478: * have a constant reference.
0479: */
0480: public Reference getConstRef(Type type) {
0481: if (type.hasConstant()) {
0482: Constant constant = type.getConstant();
0483: if (!constant.isReference()) {
0484: throw new IllegalArgumentException(
0485: "Constant not a reference " + type);
0486: }
0487: return constant.refValue();
0488: }
0489:
0490: switch (type.tag()) {
0491: case ARRAY:
0492: case FUNCTION:
0493: if (type.hasShape()) {
0494: Reference ref = type.getShape();
0495: if (!ref.isConstant()) {
0496: throw new IllegalArgumentException(
0497: "Shaped not constant " + type);
0498: }
0499: return ref;
0500: }
0501: // Fall through.
0502: default:
0503: throw new IllegalArgumentException(
0504: "Type without constant reference " + type);
0505: }
0506: }
0507:
0508: // =========================================================================
0509:
0510: /**
0511: * Determine whether the specified type has any qualifiers.
0512: *
0513: * @param type The type.
0514: * @return <code>true</code> if the type has any qualifiers.
0515: */
0516: public boolean hasQualifiers(Type type) {
0517: return (type.hasAttribute(Constants.ATT_CONSTANT)
0518: || type.hasAttribute(Constants.ATT_RESTRICT) || type
0519: .hasAttribute(Constants.ATT_VOLATILE));
0520: }
0521:
0522: /**
0523: * Determine whether the specified type has at least the qualifiers
0524: * of the specified template.
0525: *
0526: * @param type The type.
0527: * @param template The template.
0528: * @return <code>true</code> if the type has at least the template's
0529: * qualifiers.
0530: */
0531: public boolean hasQualifiers(Type type, Type template) {
0532: if (template.hasAttribute(Constants.ATT_CONSTANT)
0533: && (!type.hasAttribute(Constants.ATT_CONSTANT))) {
0534: return false;
0535: }
0536:
0537: if (template.hasAttribute(Constants.ATT_RESTRICT)
0538: && (!type.hasAttribute(Constants.ATT_RESTRICT))) {
0539: return false;
0540: }
0541:
0542: if (template.hasAttribute(Constants.ATT_VOLATILE)
0543: && (!type.hasAttribute(Constants.ATT_VOLATILE))) {
0544: return false;
0545: }
0546:
0547: return true;
0548: }
0549:
0550: /**
0551: * Determine whether the specified type has the same qualifiers as
0552: * the specified template.
0553: *
0554: * @param type The type.
0555: * @param template The template.
0556: * @return <code>true</code> if the type has the same qualifiers
0557: * as the template.
0558: */
0559: public boolean hasSameQualifiers(Type type, Type template) {
0560: return ((type.hasAttribute(Constants.ATT_CONSTANT) == template
0561: .hasAttribute(Constants.ATT_CONSTANT))
0562: && (type.hasAttribute(Constants.ATT_RESTRICT) == template
0563: .hasAttribute(Constants.ATT_RESTRICT)) && (type
0564: .hasAttribute(Constants.ATT_VOLATILE) == template
0565: .hasAttribute(Constants.ATT_VOLATILE)));
0566: }
0567:
0568: /**
0569: * Qualify the specified type with the qualifiers of the specified
0570: * template. If the template has any qualifiers, this method first
0571: * {@link Type#annotate() annotates} the specified type first.
0572: *
0573: * @param type The type.
0574: * @param template The template.
0575: * @return The qualified type.
0576: */
0577: public Type qualify(Type type, Type template) {
0578: if (!hasQualifiers(template))
0579: return type;
0580:
0581: type = type.annotate();
0582: if (template.hasAttribute(Constants.ATT_CONSTANT)) {
0583: type = type.attribute(Constants.ATT_CONSTANT);
0584: }
0585: if (template.hasAttribute(Constants.ATT_RESTRICT)) {
0586: type = type.attribute(Constants.ATT_RESTRICT);
0587: }
0588: if (template.hasAttribute(Constants.ATT_VOLATILE)) {
0589: type = type.attribute(Constants.ATT_VOLATILE);
0590: }
0591: return type;
0592: }
0593:
0594: // =========================================================================
0595:
0596: /**
0597: * Reattribute the specified type with the specified template's GCC
0598: * attributes.
0599: *
0600: * @param type The type.
0601: * @param template The template.
0602: * @return The reattributed type.
0603: */
0604: public Type reattribute(Type type, Type template) {
0605: boolean annotated = false;
0606:
0607: do {
0608: // If the template has any attributes, check them out.
0609: if (template.hasAttributes()) {
0610: for (Attribute att : template.attributes()) {
0611: if (Constants.NAME_GCC.equals(att.getName())
0612: && (!type.hasAttribute(att))) {
0613: if (!annotated) {
0614: type = type.annotate();
0615: annotated = true;
0616: }
0617: type.addAttribute(att);
0618: }
0619: }
0620: }
0621:
0622: // If the template is a wrapped type, continue with the wrapped type.
0623: template = template.isWrapped() ? template.toWrapped()
0624: .getType() : null;
0625: } while (null != template);
0626:
0627: return type;
0628: }
0629:
0630: // =========================================================================
0631:
0632: /**
0633: * Convert the specified type to an rvalue. If the specified type
0634: * has a shape, this method returns the resolved type, annotated
0635: * with any qualifiers and constant value. Otherwise, it returns
0636: * the specified type.
0637: *
0638: * @param type The type.
0639: * @return The type as an rvalue.
0640: */
0641: public Type toRValue(Type type) {
0642: if (!type.hasShape())
0643: return type;
0644:
0645: Type result = type.hasEnum() ? type.toEnum() : type.resolve();
0646: if (hasQualifiers(type) || type.hasConstant()) {
0647: result = qualify(result.annotate(), type);
0648: if (type.hasConstant()) {
0649: result = result.constant(type.getConstant().getValue());
0650: }
0651: }
0652: return result;
0653: }
0654:
0655: // =========================================================================
0656:
0657: /**
0658: * Get the specified type's alignment in bytes.
0659: *
0660: * @param type The type.
0661: * @return The type's alignment.
0662: * @throws IllegalArgumentException Signals that the type does not
0663: * have a static alignment.
0664: */
0665: public long getAlignment(Type type) {
0666: return getAlignment(type, false);
0667: }
0668:
0669: /**
0670: * Get the specified type's alignment in bytes.
0671: *
0672: * @param type The type.
0673: * @param natural The flag for determining the natural alignment.
0674: * @return The type's alignment.
0675: * @throws IllegalArgumentException
0676: * Signals that the type does not have a static alignment.
0677: */
0678: public long getAlignment(Type type, boolean natural) {
0679: long alignment = getAligned(type);
0680: if (-1 != alignment)
0681: return alignment;
0682:
0683: switch (type.tag()) {
0684: case VOID:
0685: return Limits.VOID_ALIGN;
0686:
0687: case BOOLEAN:
0688: return 1;
0689:
0690: case INTEGER:
0691: case FLOAT:
0692: switch (type.resolve().toNumber().getKind()) {
0693: case CHAR:
0694: case S_CHAR:
0695: case U_CHAR:
0696: return 1;
0697: case SHORT:
0698: case U_SHORT:
0699: return natural ? Limits.SHORT_ALIGN : Limits.SHORT_SIZE;
0700: case INT:
0701: case S_INT:
0702: case U_INT:
0703: return natural ? Limits.INT_ALIGN : Limits.INT_SIZE;
0704: case LONG:
0705: case U_LONG:
0706: return natural ? Limits.LONG_ALIGN : Limits.LONG_SIZE;
0707: case LONG_LONG:
0708: case U_LONG_LONG:
0709: return natural ? Limits.LONG_LONG_ALIGN
0710: : Limits.LONG_LONG_SIZE;
0711: case FLOAT:
0712: return natural ? Limits.FLOAT_ALIGN : Limits.FLOAT_SIZE;
0713: case DOUBLE:
0714: return natural ? Limits.DOUBLE_ALIGN
0715: : Limits.DOUBLE_SIZE;
0716: case LONG_DOUBLE:
0717: return natural ? Limits.LONG_DOUBLE_ALIGN
0718: : Limits.LONG_DOUBLE_SIZE;
0719: case FLOAT_COMPLEX:
0720: return natural ? Limits.FLOAT_ALIGN : Limits.FLOAT_SIZE;
0721: case DOUBLE_COMPLEX:
0722: return natural ? Limits.DOUBLE_ALIGN
0723: : Limits.DOUBLE_SIZE;
0724: case LONG_DOUBLE_COMPLEX:
0725: return natural ? Limits.LONG_DOUBLE_ALIGN
0726: : Limits.LONG_DOUBLE_SIZE;
0727: default:
0728: throw new AssertionError("Invalid number kind "
0729: + type.toNumber().getKind());
0730: }
0731:
0732: case POINTER:
0733: return natural ? Limits.POINTER_ALIGN : Limits.POINTER_SIZE;
0734:
0735: case ARRAY:
0736: return getAlignment(type.resolve().toArray().getType(),
0737: natural);
0738:
0739: case STRUCT:
0740: case UNION: {
0741: alignment = 1;
0742: for (Type t : type.toTagged().getMembers()) {
0743: alignment = Math.max(alignment, getAlignment(t, true));
0744: }
0745: return alignment;
0746: }
0747:
0748: case FUNCTION:
0749: return Limits.FUNCTION_ALIGN;
0750:
0751: default:
0752: throw new IllegalArgumentException(
0753: "Type without alignment " + type);
0754: }
0755: }
0756:
0757: // =========================================================================
0758:
0759: /**
0760: * Get the specified type's size in bytes.
0761: *
0762: * @param type The type.
0763: * @return The type's size.
0764: * @throws IllegalArgumentException Signals that the type does not
0765: * have a static size.
0766: */
0767: public long getSize(Type type) {
0768: switch (type.tag()) {
0769: case VOID:
0770: return Limits.VOID_SIZE;
0771:
0772: case BOOLEAN:
0773: return 1;
0774:
0775: case INTEGER:
0776: case FLOAT:
0777: switch (type.resolve().toNumber().getKind()) {
0778: case CHAR:
0779: case S_CHAR:
0780: case U_CHAR:
0781: return 1;
0782: case SHORT:
0783: case U_SHORT:
0784: return Limits.SHORT_SIZE;
0785: case INT:
0786: case S_INT:
0787: case U_INT:
0788: return Limits.INT_SIZE;
0789: case LONG:
0790: case U_LONG:
0791: return Limits.LONG_SIZE;
0792: case LONG_LONG:
0793: case U_LONG_LONG:
0794: return Limits.LONG_LONG_SIZE;
0795: case FLOAT:
0796: return Limits.FLOAT_SIZE;
0797: case DOUBLE:
0798: return Limits.DOUBLE_SIZE;
0799: case LONG_DOUBLE:
0800: return Limits.LONG_DOUBLE_SIZE;
0801: case FLOAT_COMPLEX:
0802: return 2 * Limits.FLOAT_SIZE;
0803: case DOUBLE_COMPLEX:
0804: return 2 * Limits.DOUBLE_SIZE;
0805: case LONG_DOUBLE_COMPLEX:
0806: return 2 * Limits.LONG_DOUBLE_SIZE;
0807: default:
0808: throw new AssertionError("Invalid number kind "
0809: + type.toNumber().getKind());
0810: }
0811:
0812: case POINTER:
0813: return Limits.POINTER_SIZE;
0814:
0815: case ARRAY: {
0816: ArrayT array = type.resolve().toArray();
0817: if (array.hasLength()) {
0818: return getSize(array.getType()) * array.getLength();
0819: } else {
0820: throw new IllegalArgumentException("Array without size");
0821: }
0822: }
0823:
0824: case STRUCT:
0825: return getSize(type.resolve().toStruct());
0826:
0827: case UNION: {
0828: long size = 0;
0829: for (Type t : type.toTagged().getMembers()) {
0830: size = Math.max(size, getSize(t));
0831: }
0832: return size;
0833: }
0834:
0835: case FUNCTION:
0836: return Limits.FUNCTION_SIZE;
0837:
0838: default:
0839: throw new IllegalArgumentException("Type without size "
0840: + type);
0841: }
0842: }
0843:
0844: /**
0845: * Get the specified struct's size in bytes.
0846: *
0847: * @param type The struct.
0848: * @return The struct's size.
0849: * @throws IllegalArgumentException Signals that the struct does not
0850: * have a static size.
0851: */
0852: protected long getSize(StructT type) {
0853: final List<VariableT> members = type.getMembers();
0854: final int memberCount = members.size();
0855: final boolean hasTrailing = hasTrailingArray(type);
0856: final long alignment = getAligned(type);
0857: final boolean isPacked = (-1 != alignment) ? false
0858: : isPacked(type);
0859:
0860: long size = 0;
0861: for (int i = 0; i < memberCount; i++) {
0862: final VariableT var = members.get(i);
0863:
0864: if (!hasTrailing || i < memberCount - 1) {
0865: if (!isPacked) {
0866: final long a = (-1 == alignment) ? getAlignment(
0867: var, true) : alignment;
0868: final long mod = size % a;
0869: if (0 != mod)
0870: size += (a - mod);
0871: }
0872: size += getSize(var);
0873: }
0874: }
0875:
0876: return size;
0877: }
0878:
0879: /** The canonical GCC packed attribute. */
0880: private static final Attribute PACKED = new Attribute(
0881: Constants.NAME_GCC, new Attribute("packed", null));
0882:
0883: /**
0884: * Determine whether the specified type has a GCC packed attribute.
0885: *
0886: * @param type The type.
0887: * @return <code>true</code> if the type has a packed attribute.
0888: */
0889: protected boolean isPacked(Type type) {
0890: return type.hasAttribute(PACKED);
0891: }
0892:
0893: /**
0894: * Get the specified type's alignment. If the specified type has a
0895: * GCC aligned attribute, this method returns the corresponding
0896: * alignment. Otherwise, it returns -1.
0897: *
0898: * @param type The type.
0899: * @return The alignment or -1 if the type does not have an aligned
0900: * attribute.
0901: */
0902: protected long getAligned(Type type) {
0903: long alignment = -1;
0904:
0905: do {
0906: for (Attribute att : type.attributes()) {
0907: if (Constants.NAME_GCC.equals(att.getName())) {
0908: att = (Attribute) att.getValue();
0909: if ("aligned".equals(att.getName())) {
0910: if (null == att.getValue()) {
0911: alignment = Math.max(
0912: Limits.LONG_LONG_ALIGN,
0913: Limits.LONG_DOUBLE_ALIGN);
0914: } else {
0915: alignment = ((BigInteger) att.getValue())
0916: .longValue();
0917: }
0918: }
0919: }
0920: }
0921:
0922: if (type.isWrapped()) {
0923: type = type.toWrapped().getType();
0924: } else {
0925: break;
0926: }
0927: } while (true);
0928:
0929: return alignment;
0930: }
0931:
0932: // =========================================================================
0933:
0934: /**
0935: * Get the specified number's size in bits.
0936: *
0937: * @param number The number.
0938: * @return The size in bits.
0939: */
0940: public long getWidth(Type number) {
0941: switch (number.tag()) {
0942: case BOOLEAN:
0943: case INTEGER:
0944: case FLOAT:
0945: return getSize(number) * Limits.CHAR_BITS;
0946: default:
0947: throw new AssertionError("Not a C number " + number);
0948: }
0949: }
0950:
0951: /**
0952: * Determine whether the specified number fits the specified integer
0953: * type.
0954: *
0955: * @param number The number.
0956: * @param type The integer type.
0957: * @return <code>true</code> if the number fits the type.
0958: */
0959: public boolean fits(BigInteger number, Type type) {
0960: switch (type.tag()) {
0961: case BOOLEAN:
0962: return Limits.fitsUnsignedChar(number);
0963: case INTEGER:
0964: switch (type.resolve().toInteger().getKind()) {
0965: case CHAR:
0966: return Limits.IS_CHAR_SIGNED ? Limits.fitsChar(number)
0967: : Limits.fitsUnsignedChar(number);
0968: case S_CHAR:
0969: return Limits.fitsChar(number);
0970: case U_CHAR:
0971: return Limits.fitsUnsignedChar(number);
0972: case SHORT:
0973: return Limits.fitsShort(number);
0974: case U_SHORT:
0975: return Limits.fitsUnsignedShort(number);
0976: case INT:
0977: case S_INT:
0978: return Limits.fitsInt(number);
0979: case U_INT:
0980: return Limits.fitsUnsignedInt(number);
0981: case LONG:
0982: return Limits.fitsLong(number);
0983: case U_LONG:
0984: return Limits.fitsUnsignedLong(number);
0985: case LONG_LONG:
0986: return Limits.fitsLongLong(number);
0987: case U_LONG_LONG:
0988: return Limits.fitsUnsignedLongLong(number);
0989: }
0990: default:
0991: throw new AssertionError("Not a C integer " + type);
0992: }
0993: }
0994:
0995: /**
0996: * Mask the specified number as a value of this integer type.
0997: *
0998: * @param number The number.
0999: * @param type The type.
1000: * @return The number masked as a value of this type.
1001: */
1002: public BigInteger mask(BigInteger number, Type type) {
1003: switch (type.tag()) {
1004: case BOOLEAN:
1005: return (0 != number.signum()) ? BigInteger.ONE
1006: : BigInteger.ZERO;
1007: case INTEGER:
1008: switch (type.resolve().toInteger().getKind()) {
1009: case CHAR:
1010: return Limits.IS_CHAR_SIGNED ? Limits
1011: .maskAsSignedChar(number) : Limits
1012: .maskAsUnsignedChar(number);
1013: case S_CHAR:
1014: return Limits.maskAsSignedChar(number);
1015: case U_CHAR:
1016: return Limits.maskAsUnsignedChar(number);
1017: case SHORT:
1018: return Limits.maskAsShort(number);
1019: case U_SHORT:
1020: return Limits.maskAsUnsignedShort(number);
1021: case INT:
1022: case S_INT:
1023: return Limits.maskAsInt(number);
1024: case U_INT:
1025: return Limits.maskAsUnsignedInt(number);
1026: case LONG:
1027: return Limits.maskAsLong(number);
1028: case U_LONG:
1029: return Limits.maskAsUnsignedLong(number);
1030: case LONG_LONG:
1031: return Limits.maskAsLongLong(number);
1032: case U_LONG_LONG:
1033: return Limits.maskAsUnsignedLongLong(number);
1034: }
1035: default:
1036: throw new AssertionError("Not a C integer " + type);
1037: }
1038: }
1039:
1040: // =========================================================================
1041:
1042: /**
1043: * Get the specified type's designation.
1044: *
1045: * @param type The type.
1046: * @return The designation.
1047: */
1048: public String toDesignation(Type type) {
1049: switch (type.tag()) {
1050: case BOOLEAN:
1051: case INTEGER:
1052: case FLOAT:
1053: case POINTER:
1054: return "scalar";
1055: case ARRAY:
1056: return "array";
1057: case STRUCT:
1058: return "struct";
1059: case UNION:
1060: return "union";
1061: case FUNCTION:
1062: return "function";
1063: case INTERNAL:
1064: return type.resolve().toInternal().getName();
1065: default:
1066: throw new AssertionError("Not a C type " + type);
1067: }
1068: }
1069:
1070: // =========================================================================
1071:
1072: /**
1073: * Integer promote the specified type. This method resolves the
1074: * type and, if the type is integral, then performs C's integer
1075: * promotion (C99 6.3.1.1). Additionally, it normalizes implicit
1076: * and signed int types to int types.
1077: *
1078: * @param type The type.
1079: * @return The integer promoted type.
1080: */
1081: public Type promote(Type type) {
1082: // Flag for whether the type represents a bit-field and int is not
1083: // signed.
1084: boolean flip = ((!Limits.IS_INT_SIGNED) && type.hasVariable() && type
1085: .toVariable().hasWidth());
1086:
1087: type = type.resolve();
1088:
1089: switch (type.tag()) {
1090: case BOOLEAN:
1091: return NumberT.INT;
1092: case INTEGER:
1093: switch (type.toInteger().getKind()) {
1094: case CHAR:
1095: case S_CHAR:
1096: case U_CHAR:
1097: case SHORT:
1098: // Shorts and types of lesser rank always fit into an int.
1099: return NumberT.INT;
1100: case U_SHORT:
1101: if (Limits.SHORT_SIZE < Limits.INT_SIZE) {
1102: // Unsigned shorts fit into regular ints if their size is
1103: // smaller.
1104: return NumberT.INT;
1105: } else {
1106: return NumberT.U_INT;
1107: }
1108: case INT:
1109: return flip ? NumberT.U_INT : NumberT.INT;
1110: case S_INT:
1111: return NumberT.INT; // Normalize to INT.
1112: case U_INT:
1113: case LONG:
1114: case U_LONG:
1115: case LONG_LONG:
1116: case U_LONG_LONG:
1117: // Nothing to promote.
1118: return type;
1119: default:
1120: throw new AssertionError("Not a C integer " + type);
1121: }
1122: default:
1123: return type;
1124: }
1125: }
1126:
1127: /**
1128: * Argument promote this type. This method resolves the type and,
1129: * if the type is an integral type or a float, then performs C's
1130: * default argument promotions (C99 6.5.2.2).
1131: *
1132: * @param type The type.
1133: * @return The argument promoted type.
1134: */
1135: public Type promoteArgument(Type type) {
1136: Type resolved = type.resolve();
1137:
1138: if (resolved.isFloat()) {
1139: if (NumberT.Kind.FLOAT == resolved.toFloat().getKind()) {
1140: return NumberT.DOUBLE;
1141: } else {
1142: return resolved;
1143: }
1144: } else {
1145: return promote(type);
1146: }
1147: }
1148:
1149: /**
1150: * Pointerize the specified type. This method resolves the type
1151: * and, if the type is an array or function, then performs C's
1152: * pointer decay (C99 6.3.2.1).
1153: *
1154: * @param type The type.
1155: * @return The pointerized type.
1156: */
1157: public Type pointerize(Type type) {
1158: type = type.resolve();
1159:
1160: switch (type.tag()) {
1161: case ARRAY:
1162: return new PointerT(type.toArray().getType());
1163: case FUNCTION:
1164: return new PointerT(type);
1165: default:
1166: return type;
1167: }
1168: }
1169:
1170: // =========================================================================
1171:
1172: /**
1173: * Perform the usual arithmetic conversions. Per C99 6.3.1.8, this
1174: * method performs the usual arithmetic conversions for the
1175: * specified two types and returns the type of the corresponding
1176: * result.
1177: *
1178: * @param t1 The first type.
1179: * @param t2 The second type.
1180: * @return The converted type.
1181: * @throws IllegalArgumentException Signals that either type is
1182: * not arithmetic.
1183: */
1184: public Type convert(Type t1, Type t2) {
1185: // We can't combine non-arithmetic types.
1186: if ((!isArithmetic(t1)) || t1.hasError()) {
1187: throw new IllegalArgumentException(
1188: "Not an arithmetic type " + t1);
1189: } else if ((!isArithmetic(t2)) || t2.hasError()) {
1190: throw new IllegalArgumentException(
1191: "Not an arithmetic type " + t2);
1192: }
1193:
1194: // Promote the types. Note that promotion turns enums,
1195: // enumerators, and bit-fields into integers.
1196: t1 = promote(t1);
1197: t2 = promote(t2);
1198:
1199: // Now, we are left with integers and floats.
1200: NumberT.Kind k1 = ((NumberT) t1).getKind();
1201: NumberT.Kind k2 = ((NumberT) t2).getKind();
1202:
1203: // First, we convert any complex types.
1204: if ((!isReal(t1)) || (!isReal(t2))) {
1205: if ((NumberT.Kind.LONG_DOUBLE_COMPLEX == k1)
1206: || (NumberT.Kind.LONG_DOUBLE_COMPLEX == k2)) {
1207: return NumberT.LONG_DOUBLE_COMPLEX;
1208:
1209: } else if ((NumberT.Kind.DOUBLE_COMPLEX == k1)
1210: || (NumberT.Kind.DOUBLE_COMPLEX == k2)) {
1211: return NumberT.DOUBLE_COMPLEX;
1212:
1213: }
1214: if ((NumberT.Kind.FLOAT_COMPLEX == k1)
1215: || (NumberT.Kind.FLOAT_COMPLEX == k2)) {
1216: return NumberT.FLOAT_COMPLEX;
1217: }
1218: }
1219:
1220: // Next, we convert any real types.
1221: if ((NumberT.Kind.LONG_DOUBLE == k1)
1222: || (NumberT.Kind.LONG_DOUBLE == k2)) {
1223: return NumberT.LONG_DOUBLE;
1224:
1225: } else if ((NumberT.Kind.DOUBLE == k1)
1226: || (NumberT.Kind.DOUBLE == k2)) {
1227: return NumberT.DOUBLE;
1228:
1229: } else if ((NumberT.Kind.FLOAT == k1)
1230: || (NumberT.Kind.FLOAT == k2)) {
1231: return NumberT.FLOAT;
1232: }
1233:
1234: // Otherwise, the integer promotions are performed... Well, they
1235: // have already been performed above and we are guaranteed to have
1236: // integers here.
1237: IntegerT i1 = t1.toInteger();
1238: IntegerT i2 = t2.toInteger();
1239:
1240: // If both operands have the same type, ...
1241: if (k1 == k2)
1242: return i1;
1243:
1244: // Otherwise,...
1245: if (i1.isSigned() == i2.isSigned()) {
1246: return (k1.ordinal() < k2.ordinal()) ? i2 : i1;
1247: }
1248:
1249: // Otherwise,...
1250: if (!i1.isSigned()) {
1251: if (k1.ordinal() > k2.ordinal()) {
1252: return i1;
1253: }
1254: } else {
1255: if (k2.ordinal() > k1.ordinal()) {
1256: return i2;
1257: }
1258: }
1259:
1260: // Otherwise,...
1261: if (i1.isSigned()) {
1262: if (getSize(i1) > getSize(i2)) {
1263: return i1;
1264: }
1265: } else {
1266: if (getSize(i2) > getSize(i1)) {
1267: return i2;
1268: }
1269: }
1270:
1271: // Otherwise,...
1272: if (i1.isSigned()) {
1273: if (NumberT.Kind.INT == k1) {
1274: return NumberT.U_INT;
1275: } else if (NumberT.Kind.LONG == k1) {
1276: return NumberT.U_LONG;
1277: } else {
1278: return NumberT.U_LONG_LONG;
1279: }
1280: } else {
1281: if (NumberT.Kind.INT == k2) {
1282: return NumberT.U_INT;
1283: } else if (NumberT.Kind.LONG == k2) {
1284: return NumberT.U_LONG;
1285: } else {
1286: return NumberT.U_LONG_LONG;
1287: }
1288: }
1289: }
1290:
1291: // =========================================================================
1292:
1293: /**
1294: * Compose the specified types. This method determines whether the
1295: * two types are compatible while also constructing a composite type
1296: * as specified in C99 6.2.7. If the types are compatible, the
1297: * resulting type is wrapped exactly as the first type. If the
1298: * types are not compatible, the resulting type is {@link
1299: * ErrorT#TYPE}.
1300: *
1301: * <p />Note that if both types are derived types, this method
1302: * ensures that any referenced types have the same qualifiers.
1303: * However, it does not ensure that the two types have the same
1304: * qualifiers. As a result, two types <code>t1</code> and
1305: * <code>t2</code> are compatible if:
1306: * <pre>
1307: * C.hasSameQualfiers(t1, t2) && (! C.compose(t1, t2).isError())
1308: * </pre>
1309: *
1310: * <p />Further note that the composed type does not preserve any
1311: * annotations or wraped types and thus needs to be annotated with
1312: * the two type's qualifiers etc.
1313: *
1314: * @see #equal(Type,Type)
1315: *
1316: * @param t1 The first type.
1317: * @param t2 The second type.
1318: * @param pedantic The flag for pedantic composition.
1319: * @return The composed type.
1320: */
1321: public Type compose(Type t1, Type t2, boolean pedantic) {
1322: return compose(t1, t2, pedantic, true);
1323: }
1324:
1325: /**
1326: * Compose the specified types.
1327: *
1328: * @param t1 The first type.
1329: * @param t2 The second type.
1330: * @param pedantic The flag for pedantic composition.
1331: * @param recursive The flag for recursive invocations.
1332: * @return The composed type.
1333: */
1334: protected Type compose(Type t1, Type t2, boolean pedantic,
1335: boolean recursive) {
1336: if (recursive) {
1337: // Preserve any wrapped types.
1338: if (t1.isEnum()) {
1339: return t1.equals(t2) ? t1 : ErrorT.TYPE;
1340:
1341: } else if (t1.isWrapped()) {
1342: Type w1 = t1.toWrapped().getType();
1343: Type c = compose(w1, t2, pedantic, true);
1344:
1345: if (c.isError()) {
1346: return ErrorT.TYPE;
1347:
1348: } else if (w1 == c) {
1349: return t1;
1350:
1351: } else {
1352: switch (t1.wtag()) {
1353: case ALIAS:
1354: return new AliasT(t1, t1.toAlias().getName(), c);
1355: case ANNOTATED:
1356: return new AnnotatedT(t1, c);
1357: case ENUMERATOR: {
1358: EnumeratorT e = t1.toEnumerator();
1359: return new EnumeratorT(t1, c, e.getName(), e
1360: .getValue());
1361: }
1362: case VARIABLE: {
1363: VariableT v = t1.toVariable();
1364: return v.hasWidth() ? new VariableT(t1, c, v
1365: .getName(), v.getWidth())
1366: : new VariableT(t1, c, v.getKind(), v
1367: .getName());
1368: }
1369: default:
1370: throw new AssertionError("Invalid type " + t1);
1371: }
1372: }
1373: }
1374:
1375: } else {
1376: // Unwrap t1 while still checking enums.
1377: while (t1.isWrapped()) {
1378: if (t1.isEnum()) {
1379: return t1.equals(t2) ? t1 : ErrorT.TYPE;
1380: } else {
1381: t1 = t1.toWrapped().getType();
1382: }
1383: }
1384: }
1385:
1386: // t1 has already been resolved; resolve t2 as well.
1387: t2 = t2.resolve();
1388:
1389: // Make sure both types have the same tag.
1390: if (t1 == t2)
1391: return t1;
1392: if (t1.tag() != t2.tag())
1393: return ErrorT.TYPE;
1394:
1395: // Now, do the type-specific composition.
1396: switch (t1.tag()) {
1397: case ERROR:
1398: return ErrorT.TYPE;
1399:
1400: case VOID:
1401: case BOOLEAN:
1402: return t1;
1403:
1404: case FLOAT:
1405: case INTEGER:
1406: return NumberT.equal(t1.toNumber().getKind(), t2.toNumber()
1407: .getKind()) ? t1 : ErrorT.TYPE;
1408:
1409: case INTERNAL:
1410: return t1.toInternal().getName().equals(
1411: t2.toInternal().getName()) ? t1 : ErrorT.TYPE;
1412:
1413: case LABEL:
1414: return t1.toLabel().getName()
1415: .equals(t2.toLabel().getName()) ? t1 : ErrorT.TYPE;
1416:
1417: case STRUCT:
1418: case UNION:
1419: return t1 == t2 ? t1 : ErrorT.TYPE;
1420:
1421: case POINTER: {
1422: // C99 6.7.2, 6.7.5.1
1423: Type pt1 = t1.toPointer().getType();
1424: Type pt2 = t2.toPointer().getType();
1425: if (!hasSameQualifiers(pt1, pt2))
1426: return ErrorT.TYPE;
1427: Type ptc = compose(pt1, pt2, pedantic, true);
1428: if (ptc.isError())
1429: return ErrorT.TYPE;
1430: return pt1 == ptc ? t1 : new PointerT(t1, ptc);
1431: }
1432:
1433: case ARRAY:
1434: return composeArrays(t1.toArray(), t2.toArray());
1435:
1436: case FUNCTION:
1437: return composeFunctions(t1.toFunction(), t2.toFunction(),
1438: pedantic);
1439:
1440: default:
1441: throw new AssertionError("Not a C type " + t1);
1442: }
1443: }
1444:
1445: /**
1446: * Compose the specified array types (C99 6.2.7).
1447: *
1448: * @param a1 The first array.
1449: * @param a2 The second array.
1450: * @return The composed type.
1451: */
1452: protected Type composeArrays(ArrayT a1, ArrayT a2) {
1453: if (!hasSameQualifiers(a1.getType(), a2.getType()))
1454: return ErrorT.TYPE;
1455: Type el = compose(a1.getType(), a2.getType(), true);
1456: if (el.isError())
1457: return ErrorT.TYPE;
1458:
1459: if (a1.isVarLength()) {
1460: if (el == a1.getType()) {
1461: return a1;
1462: } else {
1463: return new ArrayT(a1, el, a1.isVarLength(), a1
1464: .getLength());
1465: }
1466: } else if (a2.isVarLength()) {
1467: if (el == a2.getType()) {
1468: return a2;
1469: } else {
1470: return new ArrayT(a2, el, a2.isVarLength(), a2
1471: .getLength());
1472: }
1473: }
1474:
1475: if (a1.hasLength() && a2.hasLength()) {
1476: if (a1.getLength() == a2.getLength()) {
1477: if (el == a1.getType()) {
1478: return a1;
1479: } else {
1480: return new ArrayT(a1, el, a1.isVarLength(), a1
1481: .getLength());
1482: }
1483: } else {
1484: return ErrorT.TYPE;
1485: }
1486: }
1487:
1488: if (a1.hasLength()) {
1489: if (el == a1.getType()) {
1490: return a1;
1491: } else {
1492: return new ArrayT(a1, el, a1.isVarLength(), a1
1493: .getLength());
1494: }
1495: }
1496:
1497: if (a2.hasLength()) {
1498: if (el == a1.getType()) {
1499: return a2;
1500: } else {
1501: return new ArrayT(a2, el, a2.isVarLength(), a2
1502: .getLength());
1503: }
1504: }
1505:
1506: return el == a1.getType() ? a1 : new ArrayT(a1, el, a1
1507: .isVarLength(), a1.getLength());
1508: }
1509:
1510: /**
1511: * Compose the specified function types (C99 6.2.7). Note that this
1512: * method ignores any exceptions, which are not part of the C
1513: * language anyway.
1514: *
1515: * @param f1 The first function.
1516: * @param f2 The second function.
1517: * @param pedantic The flag for pedantic composition.
1518: * @return The composed type.
1519: */
1520: protected Type composeFunctions(FunctionT f1, FunctionT f2,
1521: boolean pedantic) {
1522: // Compare the names.
1523: if (null == f1.getName()) {
1524: if (null != f2.getName())
1525: return ErrorT.TYPE;
1526: } else {
1527: if (!f1.getName().equals(f2.getName()))
1528: return ErrorT.TYPE;
1529: }
1530:
1531: // The flag for whether the component types differ from this type.
1532: boolean differs = false;
1533:
1534: // Compare the results.
1535: if (!hasSameQualifiers(f1.getResult(), f2.getResult()))
1536: return ErrorT.TYPE;
1537: final Type res = compose(f1.getResult(), f2.getResult(), true);
1538: if (res.isError())
1539: return ErrorT.TYPE;
1540: if (f1.getResult() != res)
1541: differs = true;
1542:
1543: // Process functions with old-style declarations, since we ignore
1544: // their parameters.
1545: if (f1.hasAttribute(Constants.ATT_STYLE_OLD)) {
1546: if (f2.hasAttribute(Constants.ATT_STYLE_OLD)) {
1547: // Both types are functions without a parameter type list.
1548: // However, if type information from the function definition
1549: // is available, we preserve (but not check) it.
1550: if (f1.hasAttribute(Constants.ATT_DEFINED)
1551: || (!f2.hasAttribute(Constants.ATT_DEFINED))) {
1552: return differs ? new FunctionT(f1, res, f1
1553: .getParameters(), f1.isVarArgs()) : f1;
1554: } else {
1555: return new FunctionT(f2, res, f2.getParameters(),
1556: f2.isVarArgs());
1557: }
1558:
1559: } else {
1560: // The other type is a function type with a parameter type
1561: // list. It is compatible with this function type as long as
1562: // it is not variable and this function type is declared.
1563: if (f2.isVarArgs()
1564: && (!f1.hasAttribute(Constants.ATT_DEFINED))) {
1565: return ErrorT.TYPE;
1566: } else {
1567: return new FunctionT(f2, res, f2.getParameters(),
1568: f2.isVarArgs());
1569: }
1570: }
1571:
1572: } else if (f2.hasAttribute(Constants.ATT_STYLE_OLD)) {
1573: // This type is a function type with a parameter type list. It
1574: // is compatible with the other function type as long as it is
1575: // not variable and the other function type is declared.
1576: if (f1.isVarArgs()
1577: && (!f2.hasAttribute(Constants.ATT_DEFINED))) {
1578: return ErrorT.TYPE;
1579: } else {
1580: return differs ? new FunctionT(f1, res, f1
1581: .getParameters(), f1.isVarArgs()) : f1;
1582: }
1583: }
1584:
1585: // Neither type is a function type with an old-style declaration.
1586: // Continue by checking the parameters.
1587: if (f1.getParameters().size() != f2.getParameters().size()) {
1588: return ErrorT.TYPE;
1589: }
1590: if (f1.isVarArgs() != f2.isVarArgs())
1591: return ErrorT.TYPE;
1592:
1593: final int size = f1.getParameters().size();
1594: List<Type> par = differs ? new ArrayList<Type>(f1
1595: .getParameters()) : null;
1596: for (int i = 0; i < size; i++) {
1597: final Type p1 = f1.getParameters().get(i);
1598: final Type p2 = f2.getParameters().get(i);
1599: if (pedantic && !hasSameQualifiers(p1, p2))
1600: return ErrorT.TYPE;
1601: final Type p3 = compose(p1, p2, true);
1602: if (p3.isError())
1603: return ErrorT.TYPE;
1604:
1605: if (p1 != p3) {
1606: if (null == par)
1607: par = new ArrayList<Type>(f1.getParameters());
1608: differs = true;
1609: par.set(i, p3);
1610: }
1611: }
1612:
1613: // Ignore the exceptions and we are done.
1614: if (!differs)
1615: return f1;
1616:
1617: if (null == par)
1618: par = new ArrayList<Type>(f1.getParameters());
1619:
1620: final FunctionT result = new FunctionT(f1, res, par, f1
1621: .isVarArgs());
1622: return result;
1623: }
1624:
1625: /**
1626: * Determine whether the specified types are equal to each other.
1627: * Calling this method on types <code>t1</code> and <code>t2</code>
1628: * is equivalent to:
1629: * <pre>
1630: * C.hasSameQualifiers(t1, t2) && (! C.compose(t1, t2).isError())
1631: * </pre>
1632: *
1633: * @param t1 The first type.
1634: * @param t2 The second type.
1635: * @return <code>true</code> if the types are equal.
1636: */
1637: public boolean equal(Type t1, Type t2) {
1638: return hasSameQualifiers(t1, t2)
1639: && (!compose(t1, t2, true).isError());
1640: }
1641:
1642: // =========================================================================
1643:
1644: /** The factor for chars. */
1645: protected final BigInteger FACTOR_CHAR = BigInteger.valueOf(2).pow(
1646: Limits.CHAR_BITS);
1647:
1648: /** The factor for wide chars. */
1649: protected final BigInteger FACTOR_WIDE = BigInteger.valueOf(2).pow(
1650: Limits.CHAR_BITS * Limits.WCHAR_SIZE);
1651:
1652: /**
1653: * Type the specified C character literal. This method determines
1654: * the type for the specified character literal, which may be a wide
1655: * character literal, and returns that type. The type is annotated
1656: * with the literal's constant value, even if the value does not fit
1657: * the type.
1658: *
1659: * @param literal The literal.
1660: * @return The corresponding constant valued type.
1661: */
1662: public Type typeCharacter(String literal) {
1663: // The flag for a wide character literal.
1664: boolean isWide = false;
1665:
1666: // Strip wide marker and ticks.
1667: if (literal.startsWith("L")) {
1668: literal = literal.substring(2, literal.length() - 1);
1669: isWide = true;
1670: } else {
1671: literal = literal.substring(1, literal.length() - 1);
1672: }
1673:
1674: // Unescape.
1675: literal = Utilities.unescape(literal);
1676:
1677: // Determine the value.
1678: BigInteger value = BigInteger.ZERO;
1679: BigInteger factor = isWide ? FACTOR_WIDE : FACTOR_CHAR;
1680:
1681: final int length = literal.length();
1682: for (int i = 0; i < length; i++) {
1683: value = value.multiply(factor).add(
1684: BigInteger.valueOf(literal.charAt(i)));
1685: }
1686:
1687: // Determine the type, which according to C99 6.4.4.4 is an int
1688: // for chars.
1689: return isWide ? WCHAR.annotate().constant(value) : NumberT.CHAR
1690: .annotate().constant(value);
1691: }
1692:
1693: /**
1694: * Type the specified integer literal. This method returns the type
1695: * for the specified C integer literal wrapped in the literal's
1696: * constant value. If the specified literal does not fit any type,
1697: * this method returns the largest appropriate type.
1698: *
1699: * @param literal The literal.
1700: * @return The corresponding type and constant value.
1701: */
1702: public Type typeInteger(String literal) {
1703: // Extract the suffix.
1704: boolean isUnsigned = false;
1705: boolean isLong = false;
1706: boolean isLongLong = false;
1707: int idx = literal.length();
1708:
1709: for (; idx > 0; idx--) {
1710: char c = literal.charAt(idx - 1);
1711:
1712: if (('u' == c) || ('U' == c)) {
1713: isUnsigned = true;
1714:
1715: } else if (('l' == c) || ('L' == c)) {
1716: if (isLong) {
1717: isLong = false;
1718: isLongLong = true;
1719: } else {
1720: isLong = true;
1721: }
1722:
1723: } else {
1724: break;
1725: }
1726: }
1727: literal = literal.substring(0, idx);
1728:
1729: // Extract the radix.
1730: int radix = 10;
1731:
1732: if (literal.startsWith("0x") || literal.startsWith("0X")) {
1733: radix = 16;
1734: literal = literal.substring(2);
1735:
1736: } else if (literal.startsWith("0")) {
1737: radix = 8;
1738: }
1739:
1740: // Extract the value.
1741: final BigInteger value = new BigInteger(literal, radix);
1742:
1743: // Find a fitting type (C99 6.4.4.1)
1744: IntegerT type = null;
1745:
1746: if (isUnsigned) {
1747: if (isLongLong) {
1748: if (Limits.fitsUnsignedLongLong(value)) {
1749: type = NumberT.U_LONG_LONG;
1750: }
1751:
1752: } else if (isLong) {
1753: if (Limits.fitsUnsignedLong(value)) {
1754: type = NumberT.U_LONG;
1755: } else if (Limits.fitsUnsignedLongLong(value)) {
1756: type = NumberT.U_LONG_LONG;
1757: }
1758:
1759: } else {
1760: if (Limits.fitsUnsignedInt(value)) {
1761: type = NumberT.U_INT;
1762: } else if (Limits.fitsUnsignedLong(value)) {
1763: type = NumberT.U_LONG;
1764: } else if (Limits.fitsUnsignedLongLong(value)) {
1765: type = NumberT.U_LONG_LONG;
1766: }
1767: }
1768:
1769: // Patch in the biggest type.
1770: if (null == type)
1771: type = NumberT.U_LONG_LONG;
1772:
1773: } else if (10 == radix) {
1774: if (isLongLong) {
1775: if (Limits.fitsLongLong(value)) {
1776: type = NumberT.LONG_LONG;
1777: }
1778:
1779: } else if (isLong) {
1780: if (Limits.fitsLong(value)) {
1781: type = NumberT.LONG;
1782: } else if (Limits.fitsLongLong(value)) {
1783: type = NumberT.LONG_LONG;
1784: }
1785:
1786: } else {
1787: if (Limits.fitsInt(value)) {
1788: type = NumberT.INT;
1789: } else if (Limits.fitsLong(value)) {
1790: type = NumberT.LONG;
1791: } else if (Limits.fitsLongLong(value)) {
1792: type = NumberT.LONG_LONG;
1793: }
1794: }
1795:
1796: // Patch in the biggest type.
1797: if (null == type)
1798: type = NumberT.LONG_LONG;
1799:
1800: } else {
1801: if (isLongLong) {
1802: if (Limits.fitsLongLong(value)) {
1803: type = NumberT.LONG_LONG;
1804: } else if (Limits.fitsUnsignedLongLong(value)) {
1805: type = NumberT.U_LONG_LONG;
1806: }
1807:
1808: } else if (isLong) {
1809: if (Limits.fitsLong(value)) {
1810: type = NumberT.LONG;
1811: } else if (Limits.fitsUnsignedLong(value)) {
1812: type = NumberT.U_LONG;
1813: } else if (Limits.fitsLongLong(value)) {
1814: type = NumberT.LONG_LONG;
1815: } else if (Limits.fitsUnsignedLongLong(value)) {
1816: type = NumberT.U_LONG_LONG;
1817: }
1818:
1819: } else {
1820: if (Limits.fitsInt(value)) {
1821: type = NumberT.INT;
1822: } else if (Limits.fitsUnsignedInt(value)) {
1823: type = NumberT.U_INT;
1824: } else if (Limits.fitsLong(value)) {
1825: type = NumberT.LONG;
1826: } else if (Limits.fitsUnsignedLong(value)) {
1827: type = NumberT.U_LONG;
1828: } else if (Limits.fitsLongLong(value)) {
1829: type = NumberT.LONG_LONG;
1830: } else if (Limits.fitsUnsignedLongLong(value)) {
1831: type = NumberT.U_LONG_LONG;
1832: }
1833: }
1834:
1835: // Patch in the biggest type.
1836: if (null == type)
1837: type = NumberT.U_LONG_LONG;
1838: }
1839:
1840: // Done.
1841: return type.annotate().constant(value);
1842: }
1843:
1844: /**
1845: * Type the specified floating point literal. This method returns
1846: * the type for the specified C floating point literal wrapped in
1847: * the literal's constant value.
1848: *
1849: * @param literal The literal.
1850: * @return The corresponding type.
1851: */
1852: public Type typeFloat(String literal) {
1853: char suffix = literal.charAt(literal.length() - 1);
1854: boolean chop = false;
1855: FloatT type;
1856:
1857: switch (suffix) {
1858: case 'f':
1859: case 'F':
1860: chop = true;
1861: type = NumberT.FLOAT;
1862: break;
1863: case 'l':
1864: case 'L':
1865: chop = true;
1866: type = NumberT.LONG_DOUBLE;
1867: break;
1868: case 'd':
1869: case 'D':
1870: chop = true;
1871: // Fall through.
1872: default:
1873: type = NumberT.DOUBLE;
1874: }
1875:
1876: if (chop)
1877: literal = literal.substring(0, literal.length() - 1);
1878: return type.annotate().constant(Double.valueOf(literal));
1879: }
1880:
1881: }
|