Source Code Cross Referenced for C.java in  » Parser » Rats-Parser-Generators » xtc » type » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Parser » Rats Parser Generators » xtc.type 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


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:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.