Source Code Cross Referenced for CAnalyzer.java in  » Parser » Rats-Parser-Generators » xtc » lang » 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.lang 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


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