Source Code Cross Referenced for Parser.java in  » Scripting » jacl » org » codehaus » janino » 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 » Scripting » jacl » org.codehaus.janino 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * Janino - An embedded Java[TM] compiler
0003:         *
0004:         * Copyright (c) 2006, Arno Unkrig
0005:         * All rights reserved.
0006:         *
0007:         * Redistribution and use in source and binary forms, with or without
0008:         * modification, are permitted provided that the following conditions
0009:         * are met:
0010:         *
0011:         *    1. Redistributions of source code must retain the above copyright
0012:         *       notice, this list of conditions and the following disclaimer.
0013:         *    2. Redistributions in binary form must reproduce the above
0014:         *       copyright notice, this list of conditions and the following
0015:         *       disclaimer in the documentation and/or other materials
0016:         *       provided with the distribution.
0017:         *    3. The name of the author may not be used to endorse or promote
0018:         *       products derived from this software without specific prior
0019:         *       written permission.
0020:         *
0021:         * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
0022:         * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
0023:         * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0024:         * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
0025:         * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
0026:         * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
0027:         * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0028:         * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
0029:         * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
0030:         * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
0031:         * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
0032:         */
0033:
0034:        package org.codehaus.janino;
0035:
0036:        import java.io.*;
0037:        import java.util.*;
0038:
0039:        import org.codehaus.janino.util.enumerator.Enumerator;
0040:
0041:        /**
0042:         * A parser for the Java<sup>TM</sup> programming language.
0043:         */
0044:        public class Parser {
0045:            private final Scanner scanner;
0046:
0047:            public Parser(Scanner scanner) {
0048:                this .scanner = scanner;
0049:            }
0050:
0051:            public Scanner getScanner() {
0052:                return this .scanner;
0053:            }
0054:
0055:            /**
0056:             * <pre>
0057:             *   CompilationUnit := [ PackageDeclaration ]
0058:             *                      { ImportDeclaration }
0059:             *                      { TypeDeclaration }
0060:             * </pre>
0061:             */
0062:            public Java.CompilationUnit parseCompilationUnit()
0063:                    throws ParseException, Scanner.ScanException, IOException {
0064:                Java.CompilationUnit compilationUnit = new Java.CompilationUnit(
0065:                        this .location().getFileName());
0066:
0067:                if (this .peekKeyword("package")) {
0068:                    compilationUnit.setPackageDeclaration(this 
0069:                            .parsePackageDeclaration());
0070:                }
0071:
0072:                while (this .peekKeyword("import")) {
0073:                    compilationUnit.addImportDeclaration(this 
0074:                            .parseImportDeclaration());
0075:                }
0076:
0077:                while (!this .scanner.peek().isEOF()) {
0078:                    if (this .peekOperator(";")) {
0079:                        this .eatToken();
0080:                    } else {
0081:                        compilationUnit.addPackageMemberTypeDeclaration(this 
0082:                                .parsePackageMemberTypeDeclaration());
0083:                    }
0084:                }
0085:
0086:                return compilationUnit;
0087:            }
0088:
0089:            /**
0090:             * <pre>
0091:             *   PackageDeclaration := 'package' QualifiedIdentifier ';'
0092:             * </pre>
0093:             */
0094:            public Java.PackageDeclaration parsePackageDeclaration()
0095:                    throws Parser.ParseException, Scanner.ScanException,
0096:                    IOException {
0097:                this .readKeyword("package");
0098:                Location loc = this .location();
0099:                String packageName = Parser.join(this 
0100:                        .parseQualifiedIdentifier(), ".");
0101:                this .readOperator(";");
0102:                this .verifyStringIsConventionalPackageName(packageName, loc);
0103:                return new Java.PackageDeclaration(loc, packageName);
0104:            }
0105:
0106:            /**
0107:             * <pre>
0108:             *   ImportDeclaration := 'import' ImportDeclarationBody ';'
0109:             * </pre>
0110:             */
0111:            public Java.CompilationUnit.ImportDeclaration parseImportDeclaration()
0112:                    throws ParseException, Scanner.ScanException, IOException {
0113:                this .readKeyword("import");
0114:                Java.CompilationUnit.ImportDeclaration importDeclaration = this 
0115:                        .parseImportDeclarationBody();
0116:                this .readOperator(";");
0117:                return importDeclaration;
0118:            }
0119:
0120:            /**
0121:             * <pre>
0122:             *   ImportDeclarationBody := Identifier { '.' Identifier } [ '.' '*' ]
0123:             * </pre>
0124:             */
0125:            public Java.CompilationUnit.ImportDeclaration parseImportDeclarationBody()
0126:                    throws ParseException, Scanner.ScanException, IOException {
0127:                Location loc = this .location();
0128:                List l = new ArrayList();
0129:                l.add(this .readIdentifier());
0130:                for (;;) {
0131:                    if (!this .peekOperator(".")) {
0132:                        return new Java.CompilationUnit.SingleTypeImportDeclaration(
0133:                                loc, (String[]) l.toArray(new String[l.size()]));
0134:                    }
0135:                    this .readOperator(".");
0136:                    if (this .peekOperator("*")) {
0137:                        this .eatToken();
0138:                        return new Java.CompilationUnit.TypeImportOnDemandDeclaration(
0139:                                loc, (String[]) l.toArray(new String[l.size()]));
0140:                    }
0141:                    l.add(this .readIdentifier());
0142:                }
0143:            }
0144:
0145:            /**
0146:             * QualifiedIdentifier := Identifier { '.' Identifier }
0147:             */
0148:            public String[] parseQualifiedIdentifier() throws ParseException,
0149:                    Scanner.ScanException, IOException {
0150:                if (!this .scanner.peek().isIdentifier())
0151:                    this .throwParseException("Identifier expected");
0152:                List l = new ArrayList();
0153:                l.add(this .readIdentifier());
0154:                while (this .peekOperator(".")
0155:                        && this .scanner.peekNextButOne().isIdentifier()) {
0156:                    this .eatToken();
0157:                    l.add(this .readIdentifier());
0158:                }
0159:                return (String[]) l.toArray(new String[l.size()]);
0160:            }
0161:
0162:            /**
0163:             * <pre>
0164:             *   PackageMemberTypeDeclaration :=
0165:             *             ModifiersOpt 'class' ClassDeclarationRest |
0166:             *             ModifiersOpt 'interface' InterfaceDeclarationRest
0167:             * </pre>
0168:             */
0169:            public Java.PackageMemberTypeDeclaration parsePackageMemberTypeDeclaration()
0170:                    throws ParseException, Scanner.ScanException, IOException {
0171:                String optionalDocComment = this .scanner.doc();
0172:
0173:                short modifiers = this .parseModifiersOpt();
0174:
0175:                Java.PackageMemberTypeDeclaration res;
0176:                if (this .peekKeyword("class")) {
0177:                    if (optionalDocComment == null)
0178:                        this .warning("CDCM", "Class doc comment missing", this 
0179:                                .location());
0180:                    this .eatToken();
0181:                    res = (Java.PackageMemberClassDeclaration) this 
0182:                            .parseClassDeclarationRest(optionalDocComment, // optionalDocComment
0183:                                    modifiers, // modifiers
0184:                                    ClassDeclarationContext.COMPILATION_UNIT // context
0185:                            );
0186:                } else if (this .peekKeyword("interface")) {
0187:                    if (optionalDocComment == null)
0188:                        this .warning("IDCM", "Interface doc comment missing",
0189:                                this .location());
0190:                    this .eatToken();
0191:                    res = (Java.PackageMemberInterfaceDeclaration) this 
0192:                            .parseInterfaceDeclarationRest(
0193:                                    optionalDocComment, // optionalDocComment
0194:                                    modifiers, // modifiers
0195:                                    InterfaceDeclarationContext.COMPILATION_UNIT // context
0196:                            );
0197:                } else {
0198:                    this .throwParseException("Unexpected token \""
0199:                            + this .scanner.peek()
0200:                            + "\" in class or interface declaration");
0201:                    /* NEVER REACHED */return null;
0202:                }
0203:                return res;
0204:            }
0205:
0206:            /**
0207:             * <pre>
0208:             *   ModifiersOpt := { 'public' | 'protected' | 'private' | 'static' |
0209:             *           'abstract' | 'final' | 'native' | 'synchronized' |
0210:             *           'transient' | 'volatile' | 'strictfp'
0211:             * </pre>
0212:             */
0213:            public short parseModifiersOpt() throws ParseException,
0214:                    Scanner.ScanException, IOException {
0215:                short mod = 0;
0216:                while (this .peekKeyword()) {
0217:                    String kw = this .scanner.peek().getKeyword();
0218:                    short x = (short) (kw == "public" ? Mod.PUBLIC
0219:                            : kw == "protected" ? Mod.PROTECTED
0220:                                    : kw == "private" ? Mod.PRIVATE
0221:                                            : kw == "static" ? Mod.STATIC
0222:                                                    : kw == "abstract" ? Mod.ABSTRACT
0223:                                                            : kw == "final" ? Mod.FINAL
0224:                                                                    : kw == "native" ? Mod.NATIVE
0225:                                                                            : kw == "synchronized" ? Mod.SYNCHRONIZED
0226:                                                                                    : kw == "transient" ? Mod.TRANSIENT
0227:                                                                                            : kw == "volatile" ? Mod.VOLATILE
0228:                                                                                                    : kw == "strictfp" ? Mod.STRICTFP
0229:                                                                                                            : -1);
0230:                    if (x == -1)
0231:                        break;
0232:
0233:                    this .eatToken();
0234:                    if ((mod & x) != 0)
0235:                        this .throwParseException("Duplicate modifier \"" + kw
0236:                                + "\"");
0237:                    for (int i = 0; i < Parser.MUTUALS.length; ++i) {
0238:                        short m = Parser.MUTUALS[i];
0239:                        if ((x & m) != 0 && (mod & m) != 0) {
0240:                            this .throwParseException("Only one of \""
0241:                                    + Mod.shortToString(m) + "\" allowed");
0242:                        }
0243:                    }
0244:                    mod |= x;
0245:                }
0246:                return mod;
0247:            }
0248:
0249:            private static final short[] MUTUALS = { Mod.PUBLIC | Mod.PROTECTED
0250:                    | Mod.PRIVATE, };
0251:
0252:            /**
0253:             * <pre>
0254:             *   ClassDeclarationRest :=
0255:             *        Identifier
0256:             *        [ 'extends' ReferenceType ]
0257:             *        [ 'implements' ReferenceTypeList ]
0258:             *        ClassBody
0259:             * </pre>
0260:             */
0261:            public Java.NamedClassDeclaration parseClassDeclarationRest(
0262:                    String optionalDocComment, short modifiers,
0263:                    ClassDeclarationContext context) throws ParseException,
0264:                    Scanner.ScanException, IOException {
0265:                Location location = this .location();
0266:                String className = this .readIdentifier();
0267:                this .verifyIdentifierIsConventionalClassOrInterfaceName(
0268:                        className, location);
0269:
0270:                Java.ReferenceType optionalExtendedType = null;
0271:                if (this .peekKeyword("extends")) {
0272:                    this .eatToken();
0273:                    optionalExtendedType = this .parseReferenceType();
0274:                }
0275:
0276:                Java.ReferenceType[] implementedTypes = new Java.ReferenceType[0];
0277:                if (this .peekKeyword("implements")) {
0278:                    this .eatToken();
0279:                    implementedTypes = this .parseReferenceTypeList();
0280:                }
0281:
0282:                Java.NamedClassDeclaration namedClassDeclaration;
0283:                if (context == ClassDeclarationContext.COMPILATION_UNIT) {
0284:                    namedClassDeclaration = new Java.PackageMemberClassDeclaration(
0285:                            location, // location
0286:                            optionalDocComment, // optionalDocComment
0287:                            modifiers, // modifiers
0288:                            className, // name
0289:                            optionalExtendedType, // optinalExtendedType
0290:                            implementedTypes // implementedTypes
0291:                    );
0292:                } else if (context == ClassDeclarationContext.TYPE_DECLARATION) {
0293:                    namedClassDeclaration = new Java.MemberClassDeclaration(
0294:                            location, // location
0295:                            optionalDocComment, // optionalDocComment
0296:                            modifiers, // modifiers
0297:                            className, // name
0298:                            optionalExtendedType, // optionalExtendedType
0299:                            implementedTypes // implementedTypes
0300:                    );
0301:                } else if (context == ClassDeclarationContext.BLOCK) {
0302:                    namedClassDeclaration = new Java.LocalClassDeclaration(
0303:                            location, // location
0304:                            optionalDocComment, // optionalDocComment
0305:                            modifiers, // modifiers
0306:                            className, // name
0307:                            optionalExtendedType, // optionalExtendedType
0308:                            implementedTypes // implementedTypes
0309:                    );
0310:                } else {
0311:                    throw new RuntimeException(
0312:                            "SNO: Class declaration in unexpected context "
0313:                                    + context);
0314:                }
0315:
0316:                this .parseClassBody(namedClassDeclaration);
0317:                return namedClassDeclaration;
0318:            }
0319:
0320:            private static class ClassDeclarationContext extends Enumerator {
0321:                public static final ClassDeclarationContext BLOCK = new ClassDeclarationContext(
0322:                        "block");
0323:                public static final ClassDeclarationContext TYPE_DECLARATION = new ClassDeclarationContext(
0324:                        "type_declaration");
0325:                public static final ClassDeclarationContext COMPILATION_UNIT = new ClassDeclarationContext(
0326:                        "compilation_unit");
0327:
0328:                private ClassDeclarationContext(String name) {
0329:                    super (name);
0330:                }
0331:            }
0332:
0333:            /**
0334:             * <pre>
0335:             *   ClassBody := '{' { ClassBodyDeclaration } '}'
0336:             * </pre>
0337:             */
0338:            public void parseClassBody(Java.ClassDeclaration classDeclaration)
0339:                    throws ParseException, Scanner.ScanException, IOException {
0340:                if (!this .peekOperator("{"))
0341:                    this 
0342:                            .throwParseException("\"{\" expected at start of class body");
0343:                this .eatToken();
0344:
0345:                for (;;) {
0346:                    if (this .peekOperator("}")) {
0347:                        this .eatToken();
0348:                        return;
0349:                    }
0350:
0351:                    this .parseClassBodyDeclaration(classDeclaration);
0352:                }
0353:            }
0354:
0355:            /**
0356:             * <pre>
0357:             *   ClassBodyDeclaration :=
0358:             *     ';' |
0359:             *     ModifiersOpt (
0360:             *       Block |                                    // Instance (JLS2 8.6) or static initializer (JLS2 8.7)
0361:             *       'void' Identifier MethodDeclarationRest |
0362:             *       'class' ClassDeclarationRest |
0363:             *       'interface' InterfaceDeclarationRest |
0364:             *       ConstructorDeclarator |
0365:             *       Type Identifier (
0366:             *         MethodDeclarationRest |
0367:             *         FieldDeclarationRest ';'
0368:             *       )
0369:             *     )
0370:             *
0371:             * </pre>
0372:             */
0373:            public void parseClassBodyDeclaration(
0374:                    Java.ClassDeclaration classDeclaration)
0375:                    throws ParseException, Scanner.ScanException, IOException {
0376:                if (this .peekOperator(";")) {
0377:                    this .eatToken();
0378:                    return;
0379:                }
0380:
0381:                String optionalDocComment = this .scanner.doc();
0382:                short modifiers = this .parseModifiersOpt();
0383:
0384:                // Initializer?
0385:                if (this .peekOperator("{")) {
0386:                    if ((modifiers & ~Mod.STATIC) != 0)
0387:                        this 
0388:                                .throwParseException("Only modifier \"static\" allowed on initializer");
0389:
0390:                    Java.Initializer initializer = new Java.Initializer(this 
0391:                            .location(), // location
0392:                            (modifiers & Mod.STATIC) != 0, // statiC
0393:                            this .parseBlock() // block
0394:                    );
0395:
0396:                    classDeclaration
0397:                            .addVariableDeclaratorOrInitializer(initializer);
0398:                    return;
0399:                }
0400:
0401:                // "void" method declaration.
0402:                if (this .peekKeyword("void")) {
0403:                    Location location = this .location();
0404:                    this .eatToken();
0405:                    if (optionalDocComment == null)
0406:                        this .warning("MDCM", "Method doc comment missing",
0407:                                location);
0408:                    String name = this .readIdentifier();
0409:                    classDeclaration.addDeclaredMethod(this 
0410:                            .parseMethodDeclarationRest(classDeclaration, // declaringType
0411:                                    optionalDocComment, // optionalDocComment
0412:                                    modifiers, // modifiers
0413:                                    new Java.BasicType(location,
0414:                                            Java.BasicType.VOID), // type
0415:                                    name // name
0416:                            ));
0417:                    return;
0418:                }
0419:
0420:                // Member class.
0421:                if (this .peekKeyword("class")) {
0422:                    if (optionalDocComment == null)
0423:                        this .warning("MCDCM",
0424:                                "Member class doc comment missing", this 
0425:                                        .location());
0426:                    this .eatToken();
0427:                    classDeclaration
0428:                            .addMemberTypeDeclaration((Java.MemberTypeDeclaration) this 
0429:                                    .parseClassDeclarationRest(
0430:                                            optionalDocComment, // optionalDocComment
0431:                                            modifiers, // modifiers
0432:                                            ClassDeclarationContext.TYPE_DECLARATION // context
0433:                                    ));
0434:                    return;
0435:                }
0436:
0437:                // Member interface.
0438:                if (this .peekKeyword("interface")) {
0439:                    if (optionalDocComment == null)
0440:                        this .warning("MIDCM",
0441:                                "Member interface doc comment missing", this 
0442:                                        .location());
0443:                    this .eatToken();
0444:                    classDeclaration
0445:                            .addMemberTypeDeclaration((Java.MemberTypeDeclaration) this 
0446:                                    .parseInterfaceDeclarationRest(
0447:                                            optionalDocComment, // optionalDocComment
0448:                                            (short) (modifiers | Mod.STATIC), // modifiers
0449:                                            InterfaceDeclarationContext.NAMED_TYPE_DECLARATION // context
0450:                                    ));
0451:                    return;
0452:                }
0453:
0454:                // Constructor.
0455:                if (classDeclaration instanceof  Java.NamedClassDeclaration
0456:                        && this .scanner.peek().isIdentifier(
0457:                                ((Java.NamedClassDeclaration) classDeclaration)
0458:                                        .getName())
0459:                        && this .scanner.peekNextButOne().isOperator("(")) {
0460:                    if (optionalDocComment == null)
0461:                        this .warning("CDCM", "Constructor doc comment missing",
0462:                                this .location());
0463:                    classDeclaration.addConstructor(this 
0464:                            .parseConstructorDeclarator(classDeclaration, // declaringClass
0465:                                    optionalDocComment, // optionalDocComment
0466:                                    modifiers // modifiers
0467:                            ));
0468:                    return;
0469:                }
0470:
0471:                // Member method or field.
0472:                Java.Type memberType = this .parseType();
0473:                Location location = this .location();
0474:                String memberName = this .readIdentifier();
0475:
0476:                // Method declarator.
0477:                if (this .peekOperator("(")) {
0478:                    if (optionalDocComment == null)
0479:                        this .warning("MDCM", "Method doc comment missing", this 
0480:                                .location());
0481:                    classDeclaration.addDeclaredMethod(this 
0482:                            .parseMethodDeclarationRest(classDeclaration, // declaringType
0483:                                    optionalDocComment, // optionalDocComment
0484:                                    modifiers, // modifiers
0485:                                    memberType, // type
0486:                                    memberName // name
0487:                            ));
0488:                    return;
0489:                }
0490:
0491:                // Field declarator.
0492:                if (optionalDocComment == null)
0493:                    this .warning("FDCM", "Field doc comment missing", this 
0494:                            .location());
0495:                Java.FieldDeclaration fd = new Java.FieldDeclaration(location, // location
0496:                        optionalDocComment, // optionalDocComment
0497:                        modifiers, // modifiers
0498:                        memberType, // type
0499:                        this .parseFieldDeclarationRest(memberName) // variableDeclarators
0500:                );
0501:                this .readOperator(";");
0502:                classDeclaration.addVariableDeclaratorOrInitializer(fd);
0503:            }
0504:
0505:            /**
0506:             * <pre>
0507:             *   InterfaceDeclarationRest :=
0508:             *     Identifier
0509:             *     [ 'extends' ReferenceTypeList ]
0510:             *     InterfaceBody
0511:             * </pre>
0512:             */
0513:            public Java.InterfaceDeclaration parseInterfaceDeclarationRest(
0514:                    String optionalDocComment, short modifiers,
0515:                    InterfaceDeclarationContext context) throws ParseException,
0516:                    Scanner.ScanException, IOException {
0517:                Location location = this .location();
0518:                String interfaceName = this .readIdentifier();
0519:                this .verifyIdentifierIsConventionalClassOrInterfaceName(
0520:                        interfaceName, location);
0521:
0522:                Java.ReferenceType[] extendedTypes = new Java.ReferenceType[0];
0523:                if (this .peekKeyword("extends")) {
0524:                    this .eatToken();
0525:                    extendedTypes = this .parseReferenceTypeList();
0526:                }
0527:
0528:                Java.InterfaceDeclaration interfaceDeclaration;
0529:                if (context == InterfaceDeclarationContext.COMPILATION_UNIT) {
0530:                    interfaceDeclaration = new Java.PackageMemberInterfaceDeclaration(
0531:                            location, // location
0532:                            optionalDocComment, // optionalDocComment
0533:                            modifiers, // modifiers
0534:                            interfaceName, // name
0535:                            extendedTypes // extendedTypes
0536:                    );
0537:                } else if (context == InterfaceDeclarationContext.NAMED_TYPE_DECLARATION) {
0538:                    interfaceDeclaration = new Java.MemberInterfaceDeclaration(
0539:                            location, // location
0540:                            optionalDocComment, // optionalDocComment
0541:                            modifiers, // modifiers
0542:                            interfaceName, // name
0543:                            extendedTypes // extendedTypes
0544:                    );
0545:                } else {
0546:                    throw new RuntimeException(
0547:                            "SNO: Interface declaration in unexpected context "
0548:                                    + context);
0549:                }
0550:
0551:                this .parseInterfaceBody(interfaceDeclaration);
0552:                return interfaceDeclaration;
0553:            }
0554:
0555:            private static class InterfaceDeclarationContext extends Enumerator {
0556:                public static final InterfaceDeclarationContext NAMED_TYPE_DECLARATION = new InterfaceDeclarationContext(
0557:                        "named_type_declaration");
0558:                public static final InterfaceDeclarationContext COMPILATION_UNIT = new InterfaceDeclarationContext(
0559:                        "compilation_unit");
0560:
0561:                private InterfaceDeclarationContext(String name) {
0562:                    super (name);
0563:                }
0564:            }
0565:
0566:            /**
0567:             * <pre>
0568:             *   InterfaceBody := '{' {
0569:             *     ';' |
0570:             *     ModifiersOpt (
0571:             *       'void' Identifier MethodDeclarationRest |
0572:             *       'class' ClassDeclarationRest |
0573:             *       'interface' InterfaceDeclarationRest |
0574:             *       Type Identifier (
0575:             *         MethodDeclarationRest |
0576:             *         FieldDeclarationRest
0577:             *       )
0578:             *     )
0579:             *   } '}'
0580:             * </pre>
0581:             */
0582:            public void parseInterfaceBody(
0583:                    Java.InterfaceDeclaration interfaceDeclaration)
0584:                    throws ParseException, Scanner.ScanException, IOException {
0585:                this .readOperator("{");
0586:
0587:                for (;;) {
0588:                    if (this .peekOperator("}")) {
0589:                        this .eatToken();
0590:                        break;
0591:                    }
0592:
0593:                    if (this .peekOperator(";")) {
0594:                        this .eatToken();
0595:                        continue;
0596:                    }
0597:
0598:                    String optionalDocComment = this .scanner.doc();
0599:                    short modifiers = this .parseModifiersOpt();
0600:
0601:                    // "void" method declaration.
0602:                    if (this .peekKeyword("void")) {
0603:                        if (optionalDocComment == null)
0604:                            this .warning("MDCM", "Method doc comment missing",
0605:                                    this .location());
0606:                        Location location = this .location();
0607:                        this .eatToken();
0608:                        String name = this .readIdentifier();
0609:                        interfaceDeclaration
0610:                                .addDeclaredMethod(this 
0611:                                        .parseMethodDeclarationRest(
0612:                                                interfaceDeclaration, // declaringType
0613:                                                optionalDocComment, // optionalDocComment
0614:                                                (short) (modifiers
0615:                                                        | Mod.ABSTRACT | Mod.PUBLIC), // modifiers
0616:                                                new Java.BasicType(location,
0617:                                                        Java.BasicType.VOID), // type
0618:                                                name // name
0619:                                        ));
0620:                    } else
0621:
0622:                    // Member class.
0623:                    if (this .peekKeyword("class")) {
0624:                        if (optionalDocComment == null)
0625:                            this .warning("MCDCM",
0626:                                    "Member class doc comment missing", this 
0627:                                            .location());
0628:                        this .eatToken();
0629:                        interfaceDeclaration
0630:                                .addMemberTypeDeclaration((Java.MemberTypeDeclaration) this 
0631:                                        .parseClassDeclarationRest(
0632:                                                optionalDocComment, // optionalDocComment
0633:                                                (short) (modifiers | Mod.STATIC | Mod.PUBLIC), // modifiers
0634:                                                ClassDeclarationContext.TYPE_DECLARATION // context
0635:                                        ));
0636:                    } else
0637:
0638:                    // Member interface.
0639:                    if (this .peekKeyword("interface")) {
0640:                        if (optionalDocComment == null)
0641:                            this .warning("MIDCM",
0642:                                    "Member interface doc comment missing",
0643:                                    this .location());
0644:                        this .eatToken();
0645:                        interfaceDeclaration
0646:                                .addMemberTypeDeclaration((Java.MemberTypeDeclaration) this 
0647:                                        .parseInterfaceDeclarationRest(
0648:                                                optionalDocComment, // optionalDocComment
0649:                                                (short) (modifiers | Mod.STATIC | Mod.PUBLIC), // modifiers
0650:                                                InterfaceDeclarationContext.NAMED_TYPE_DECLARATION // context
0651:                                        ));
0652:                    } else
0653:
0654:                    // Member method or field.
0655:                    {
0656:                        Java.Type memberType = this .parseType();
0657:                        if (!this .scanner.peek().isIdentifier())
0658:                            this 
0659:                                    .throwParseException("Identifier expected in member declaration");
0660:                        Location location = this .location();
0661:                        String memberName = this .readIdentifier();
0662:
0663:                        // Method declarator.
0664:                        if (this .peekOperator("(")) {
0665:                            if (optionalDocComment == null)
0666:                                this .warning("MDCM",
0667:                                        "Method doc comment missing", this 
0668:                                                .location());
0669:                            interfaceDeclaration
0670:                                    .addDeclaredMethod(this 
0671:                                            .parseMethodDeclarationRest(
0672:                                                    interfaceDeclaration, // declaringType
0673:                                                    optionalDocComment, // optionalDocComment
0674:                                                    (short) (modifiers
0675:                                                            | Mod.ABSTRACT | Mod.PUBLIC), // modifiers
0676:                                                    memberType, // type
0677:                                                    memberName // name
0678:                                            ));
0679:                        } else
0680:
0681:                        // Field declarator.
0682:                        {
0683:                            if (optionalDocComment == null)
0684:                                this .warning("FDCM",
0685:                                        "Field doc comment missing", this 
0686:                                                .location());
0687:                            Java.FieldDeclaration fd = new Java.FieldDeclaration(
0688:                                    location, // location
0689:                                    optionalDocComment, // optionalDocComment
0690:                                    (short) ( // modifiers
0691:                                    modifiers | Mod.PUBLIC | Mod.STATIC | Mod.FINAL),
0692:                                    memberType, // type
0693:                                    this .parseFieldDeclarationRest(memberName) // variableDeclarators
0694:                            );
0695:                            interfaceDeclaration.addConstantDeclaration(fd);
0696:                        }
0697:                    }
0698:                }
0699:            }
0700:
0701:            /**
0702:             * <pre>
0703:             *   ConstructorDeclarator :=
0704:             *     Identifier
0705:             *     FormalParameters
0706:             *     [ 'throws' ReferenceTypeList ]
0707:             *     '{'
0708:             *       [ 'this' Arguments ';' | 'super' Arguments ';' | Primary '.' 'super' Arguments ';' ]
0709:             *       BlockStatements
0710:             *     '}'
0711:             * </pre>
0712:             */
0713:            public Java.ConstructorDeclarator parseConstructorDeclarator(
0714:                    Java.ClassDeclaration declaringClass,
0715:                    String optionalDocComment, short modifiers)
0716:                    throws ParseException, Scanner.ScanException, IOException {
0717:                Location location = this .location();
0718:                this .readIdentifier(); // Class name
0719:
0720:                // Parse formal parameters.
0721:                Java.FunctionDeclarator.FormalParameter[] formalParameters = this 
0722:                        .parseFormalParameters(declaringClass // enclosingScope
0723:                        );
0724:
0725:                // Parse "throws" clause.
0726:                Java.ReferenceType[] thrownExceptions;
0727:                if (this .peekKeyword("throws")) {
0728:                    this .eatToken();
0729:                    thrownExceptions = this .parseReferenceTypeList();
0730:                } else {
0731:                    thrownExceptions = new Java.ReferenceType[0];
0732:                }
0733:
0734:                // Parse constructor body.
0735:                location = this .location();
0736:                this .readOperator("{");
0737:
0738:                // Special treatment for the first statement of the constructor body: If this is surely an
0739:                // expression statement, and if it could be a "ConstructorInvocation", then parse the
0740:                // expression and check if it IS a ConstructorInvocation.
0741:                Java.ConstructorInvocation optionalConstructorInvocation = null;
0742:                Java.Block body = new Java.Block(location);
0743:                if (this .peekKeyword(new String[] { "this", "super", "new",
0744:                        "void", "byte", "char", "short", "int", "long",
0745:                        "float", "double", "boolean", })
0746:                        || this .scanner.peek().isLiteral()
0747:                        || this .scanner.peek().isIdentifier()) {
0748:                    Java.Atom a = this .parseExpression();
0749:                    if (a instanceof  Java.ConstructorInvocation) {
0750:                        this .readOperator(";");
0751:                        optionalConstructorInvocation = (Java.ConstructorInvocation) a;
0752:                    } else {
0753:                        Java.Statement s;
0754:                        if (this .scanner.peek().isIdentifier()) {
0755:                            Java.Type variableType = a.toTypeOrPE();
0756:                            s = new Java.LocalVariableDeclarationStatement(a
0757:                                    .getLocation(), // location
0758:                                    (short) 0, // modifiers
0759:                                    variableType, // type
0760:                                    this .parseLocalVariableDeclarators() // variableDeclarators
0761:                            );
0762:                            this .readOperator(";");
0763:                        } else {
0764:                            s = new Java.ExpressionStatement(a.toRvalueOrPE());
0765:                            this .readOperator(";");
0766:                        }
0767:                        body.addStatement(s);
0768:                    }
0769:                }
0770:                body.addStatements(this .parseBlockStatements());
0771:
0772:                this .readOperator("}");
0773:
0774:                return new Java.ConstructorDeclarator(location, // location
0775:                        optionalDocComment, // optionalDocComment
0776:                        modifiers, // modifiers
0777:                        formalParameters, // formalParameters
0778:                        thrownExceptions, // thrownExceptions
0779:                        optionalConstructorInvocation, // optionalConstructorInvocationStatement
0780:                        body // body
0781:                );
0782:            }
0783:
0784:            /**
0785:             * <pre>
0786:             *   MethodDeclarationRest :=
0787:             *     FormalParameters
0788:             *     { '[' ']' }
0789:             *     [ 'throws' ReferenceTypeList ]
0790:             *     ( ';' | MethodBody )
0791:             * </pre>
0792:             */
0793:            public Java.MethodDeclarator parseMethodDeclarationRest(
0794:                    Java.AbstractTypeDeclaration declaringType,
0795:                    String optionalDocComment, short modifiers, Java.Type type,
0796:                    String name) throws ParseException, Scanner.ScanException,
0797:                    IOException {
0798:                Location location = this .location();
0799:
0800:                this .verifyIdentifierIsConventionalMethodName(name, location);
0801:
0802:                Java.FunctionDeclarator.FormalParameter[] formalParameters = this 
0803:                        .parseFormalParameters(declaringType // enclosingScope
0804:                        );
0805:
0806:                for (int i = this .parseBracketsOpt(); i > 0; --i)
0807:                    type = new Java.ArrayType(type);
0808:
0809:                Java.ReferenceType[] thrownExceptions;
0810:                if (this .peekKeyword("throws")) {
0811:                    this .eatToken();
0812:                    thrownExceptions = this .parseReferenceTypeList();
0813:                } else {
0814:                    thrownExceptions = new Java.ReferenceType[0];
0815:                }
0816:
0817:                Java.Block optionalBody;
0818:                if (this .peekOperator(";")) {
0819:                    if ((modifiers & (Mod.ABSTRACT | Mod.NATIVE)) == 0)
0820:                        this 
0821:                                .throwParseException("Non-abstract, non-native method must have a body");
0822:                    this .eatToken();
0823:                    optionalBody = null;
0824:                } else {
0825:                    if ((modifiers & (Mod.ABSTRACT | Mod.NATIVE)) != 0)
0826:                        this 
0827:                                .throwParseException("Abstract or native method must not have a body");
0828:                    optionalBody = this .parseMethodBody();
0829:                }
0830:                return new Java.MethodDeclarator(location, // location
0831:                        optionalDocComment, // optionalDocComment
0832:                        modifiers, // modifiers
0833:                        type, // type
0834:                        name, // name
0835:                        formalParameters, // formalParameters
0836:                        thrownExceptions, // thrownExceptions
0837:                        optionalBody // optionalBody
0838:                );
0839:            }
0840:
0841:            /**
0842:             * <pre>
0843:             *   VariableInitializer :=
0844:             *     ArrayInitializer |
0845:             *     Expression
0846:             * </pre>
0847:             */
0848:            public Java.ArrayInitializerOrRvalue parseVariableInitializer()
0849:                    throws ParseException, Scanner.ScanException, IOException {
0850:                if (this .peekOperator("{")) {
0851:                    return this .parseArrayInitializer();
0852:                } else {
0853:                    return this .parseExpression().toRvalueOrPE();
0854:                }
0855:            }
0856:
0857:            /**
0858:             * <pre>
0859:             *   ArrayInitializer :=
0860:             *     '{' [ VariableInitializer { ',' VariableInitializer } [ ',' ] '}'
0861:             * </pre>
0862:             */
0863:            public Java.ArrayInitializer parseArrayInitializer()
0864:                    throws ParseException, Scanner.ScanException, IOException {
0865:                Location location = this .location();
0866:                this .readOperator("{");
0867:                List l = new ArrayList(); // ArrayInitializerOrRvalue
0868:                while (!this .peekOperator("}")) {
0869:                    l.add(this .parseVariableInitializer());
0870:                    if (this .peekOperator("}"))
0871:                        break;
0872:                    if (!this .peekOperator(","))
0873:                        this .throwParseException("\",\" or \"}\" expected");
0874:                    this .eatToken();
0875:                }
0876:                this .eatToken();
0877:                return new Java.ArrayInitializer(location,
0878:                        (Java.ArrayInitializerOrRvalue[]) l
0879:                                .toArray(new Java.ArrayInitializerOrRvalue[l
0880:                                        .size()]));
0881:            }
0882:
0883:            /**
0884:             * <pre>
0885:             *   FormalParameters := '(' [ FormalParameter { ',' FormalParameter } ] ')'
0886:             * </pre>
0887:             */
0888:            public Java.FunctionDeclarator.FormalParameter[] parseFormalParameters(
0889:                    Java.Scope enclosingScope) throws ParseException,
0890:                    Scanner.ScanException, IOException {
0891:                this .readOperator("(");
0892:                if (this .peekOperator(")")) {
0893:                    this .eatToken();
0894:                    return new Java.FunctionDeclarator.FormalParameter[0];
0895:                }
0896:
0897:                List l = new ArrayList(); // Java.FormalParameter
0898:                for (;;) {
0899:                    l.add(this .parseFormalParameter());
0900:                    if (!this .peekOperator(","))
0901:                        break;
0902:                    this .eatToken();
0903:                }
0904:                this .readOperator(")");
0905:                return (Java.FunctionDeclarator.FormalParameter[]) l
0906:                        .toArray(new Java.FunctionDeclarator.FormalParameter[l
0907:                                .size()]);
0908:            }
0909:
0910:            /**
0911:             * <pre>
0912:             *   FormalParameter := [ 'final' ] Type Identifier BracketsOpt
0913:             * </pre>
0914:             */
0915:            public Java.FunctionDeclarator.FormalParameter parseFormalParameter()
0916:                    throws ParseException, Scanner.ScanException, IOException {
0917:                boolean finaL = this .peekKeyword("final");
0918:                if (finaL)
0919:                    this .eatToken();
0920:
0921:                Java.Type type = this .parseType();
0922:
0923:                Location location = this .location();
0924:                String name = this .readIdentifier();
0925:                this 
0926:                        .verifyIdentifierIsConventionalLocalVariableOrParameterName(
0927:                                name, location);
0928:
0929:                for (int i = this .parseBracketsOpt(); i > 0; --i)
0930:                    type = new Java.ArrayType(type);
0931:                return new Java.FunctionDeclarator.FormalParameter(location,
0932:                        finaL, type, name);
0933:            }
0934:
0935:            /**
0936:             * <pre>
0937:             *   BracketsOpt := { '[' ']' }
0938:             * </pre>
0939:             */
0940:            int parseBracketsOpt() throws Scanner.ScanException, IOException {
0941:                int res = 0;
0942:                while (this .scanner.peek().isOperator("[")
0943:                        && this .scanner.peekNextButOne().isOperator("]")) {
0944:                    this .eatToken();
0945:                    this .eatToken();
0946:                    ++res;
0947:                }
0948:                return res;
0949:            }
0950:
0951:            /**
0952:             * <pre>
0953:             *   MethodBody := Block
0954:             * </pre>
0955:             */
0956:            public Java.Block parseMethodBody() throws ParseException,
0957:                    Scanner.ScanException, IOException {
0958:                return this .parseBlock();
0959:            }
0960:
0961:            /**
0962:             * <pre>
0963:             *   '{' BlockStatements '}'
0964:             * </pre>
0965:             */
0966:            public Java.Block parseBlock() throws ParseException,
0967:                    Scanner.ScanException, IOException {
0968:                Java.Block block = new Java.Block(this .location());
0969:                this .readOperator("{");
0970:                block.addStatements(this .parseBlockStatements());
0971:                this .readOperator("}");
0972:                return block;
0973:            }
0974:
0975:            /**
0976:             * <pre>
0977:             *   BlockStatements := { BlockStatement }
0978:             * </pre>
0979:             */
0980:            public List parseBlockStatements() throws ParseException,
0981:                    Scanner.ScanException, IOException {
0982:                List l = new ArrayList();
0983:                while (!this .peekOperator("}") && !this .peekKeyword("case")
0984:                        && !this .peekKeyword("default"))
0985:                    l.add(this .parseBlockStatement());
0986:                return l;
0987:            }
0988:
0989:            /**
0990:             * <pre>
0991:             *   BlockStatement := { Identifier ':' } (
0992:             *     ( Modifiers Type | ModifiersOpt BasicType ) LocalVariableDeclarators ';' |
0993:             *     'class' ... |
0994:             *     Statement |
0995:             *     'final' Type LocalVariableDeclarators ';' |
0996:             *     Expression ';' |
0997:             *     Expression LocalVariableDeclarators ';'   (1)
0998:             *   )
0999:             * </pre>
1000:             *
1001:             * (1) "Expression" must pose a type, and has optional trailing brackets.
1002:             */
1003:            public Java.BlockStatement parseBlockStatement()
1004:                    throws ParseException, Scanner.ScanException, IOException {
1005:
1006:                // Statement?
1007:                if ((this .scanner.peek().isIdentifier() && this .scanner
1008:                        .peekNextButOne().isOperator(":"))
1009:                        || this .peekKeyword(new String[] { "if", "for",
1010:                                "while", "do", "try", "switch", "synchronized",
1011:                                "return", "throw", "break", "continue" })
1012:                        || this .peekOperator(new String[] { "{", ";" }))
1013:                    return this .parseStatement();
1014:
1015:                // Local class declaration?
1016:                if (this .peekKeyword("class")) {
1017:                    // JAVADOC[TM] ignores doc comments for local classes, but we
1018:                    // don't...
1019:                    String optionalDocComment = this .scanner.doc();
1020:                    if (optionalDocComment == null)
1021:                        this .warning("LCDCM",
1022:                                "Local class doc comment missing", this 
1023:                                        .location());
1024:
1025:                    this .eatToken();
1026:                    final Java.LocalClassDeclaration lcd = (Java.LocalClassDeclaration) this 
1027:                            .parseClassDeclarationRest(optionalDocComment, // optionalDocComment
1028:                                    (short) (Mod.FINAL | Mod.PRIVATE), // modifiers
1029:                                    ClassDeclarationContext.BLOCK // context
1030:                            );
1031:                    return new Java.LocalClassDeclarationStatement(lcd);
1032:                }
1033:
1034:                // 'final' Type LocalVariableDeclarators ';'
1035:                if (this .peekKeyword("final")) {
1036:                    Location location = this .location();
1037:                    this .eatToken();
1038:                    Java.Type variableType = this .parseType();
1039:                    Java.LocalVariableDeclarationStatement lvds = new Java.LocalVariableDeclarationStatement(
1040:                            location, // location
1041:                            Mod.FINAL, // modifiers
1042:                            variableType, // type
1043:                            this .parseLocalVariableDeclarators() // variableDeclarators
1044:                    );
1045:                    this .readOperator(";");
1046:                    return lvds;
1047:                }
1048:
1049:                // It's either a non-final local variable declaration or an expression statement. We can
1050:                // only tell after parsing an expression.
1051:                Java.Atom a = this .parseExpression();
1052:
1053:                // Expression ';'
1054:                if (this .peekOperator(";")) {
1055:                    this .eatToken();
1056:                    return new Java.ExpressionStatement(a.toRvalueOrPE());
1057:                }
1058:
1059:                // Expression LocalVariableDeclarators ';'
1060:                Java.Type variableType = a.toTypeOrPE();
1061:                Java.LocalVariableDeclarationStatement lvds = new Java.LocalVariableDeclarationStatement(
1062:                        a.getLocation(), // location
1063:                        Mod.NONE, // modifiers
1064:                        variableType, // type
1065:                        this .parseLocalVariableDeclarators() // variableDeclarators
1066:                );
1067:                this .readOperator(";");
1068:                return lvds;
1069:            }
1070:
1071:            /**
1072:             * <pre>
1073:             *   LocalVariableDeclarators := VariableDeclarator { ',' VariableDeclarator }
1074:             * </pre>
1075:             */
1076:            public Java.VariableDeclarator[] parseLocalVariableDeclarators()
1077:                    throws ParseException, Scanner.ScanException, IOException {
1078:                List l = new ArrayList();
1079:                for (;;) {
1080:                    Java.VariableDeclarator vd = this .parseVariableDeclarator();
1081:                    this 
1082:                            .verifyIdentifierIsConventionalLocalVariableOrParameterName(
1083:                                    vd.name, vd.getLocation());
1084:                    l.add(vd);
1085:                    if (!this .peekOperator(","))
1086:                        break;
1087:                    this .eatToken();
1088:                }
1089:                return (Java.VariableDeclarator[]) l
1090:                        .toArray(new Java.VariableDeclarator[l.size()]);
1091:            }
1092:
1093:            /**
1094:             * <pre>
1095:             *   FieldDeclarationRest :=
1096:             *     VariableDeclaratorRest
1097:             *     { ',' VariableDeclarator }
1098:             * </pre>
1099:             */
1100:            public Java.VariableDeclarator[] parseFieldDeclarationRest(
1101:                    String name) throws ParseException, Scanner.ScanException,
1102:                    IOException {
1103:                List l = new ArrayList();
1104:
1105:                Java.VariableDeclarator vd = this 
1106:                        .parseVariableDeclaratorRest(name);
1107:                this .verifyIdentifierIsConventionalFieldName(vd.name, vd
1108:                        .getLocation());
1109:                l.add(vd);
1110:
1111:                while (this .peekOperator(",")) {
1112:                    this .eatToken();
1113:
1114:                    vd = this .parseVariableDeclarator();
1115:                    this .verifyIdentifierIsConventionalFieldName(vd.name, vd
1116:                            .getLocation());
1117:                    l.add(vd);
1118:                }
1119:                return (Java.VariableDeclarator[]) l
1120:                        .toArray(new Java.VariableDeclarator[l.size()]);
1121:            }
1122:
1123:            /**
1124:             * <pre>
1125:             *   VariableDeclarator := Identifier VariableDeclaratorRest
1126:             * </pre>
1127:             */
1128:            public Java.VariableDeclarator parseVariableDeclarator()
1129:                    throws ParseException, Scanner.ScanException, IOException {
1130:                return this .parseVariableDeclaratorRest(this .readIdentifier());
1131:            }
1132:
1133:            /**
1134:             * <pre>
1135:             *   VariableDeclaratorRest := { '[' ']' } [ '=' VariableInitializer ]
1136:             * </pre>
1137:             * Used by field declarations and local variable declarations.
1138:             */
1139:            public Java.VariableDeclarator parseVariableDeclaratorRest(
1140:                    String name) throws ParseException, Scanner.ScanException,
1141:                    IOException {
1142:                Location loc = this .location();
1143:                int brackets = this .parseBracketsOpt();
1144:                Java.ArrayInitializerOrRvalue initializer = null;
1145:                if (this .peekOperator("=")) {
1146:                    this .eatToken();
1147:                    initializer = this .parseVariableInitializer();
1148:                }
1149:                return new Java.VariableDeclarator(loc, name, brackets,
1150:                        initializer);
1151:            }
1152:
1153:            /**
1154:             * <pre>
1155:             *   Statement :=
1156:             *     LabeledStatement |
1157:             *     Block |
1158:             *     IfStatement |
1159:             *     ForStatement |
1160:             *     WhileStatement |
1161:             *     DoStatement |
1162:             *     TryStatement |
1163:             *     'switch' ... |
1164:             *     'synchronized' ... |
1165:             *     ReturnStatement |
1166:             *     ThrowStatement |
1167:             *     BreakStatement |
1168:             *     ContinueStatement |
1169:             *     EmptyStatement |
1170:             *     ExpressionStatement
1171:             * </pre>
1172:             */
1173:            public Java.Statement parseStatement() throws ParseException,
1174:                    Scanner.ScanException, IOException {
1175:                if (this .scanner.peek().isIdentifier()
1176:                        && this .scanner.peekNextButOne().isOperator(":")) {
1177:                    return this .parseLabeledStatement();
1178:                }
1179:
1180:                Scanner.Token t = this .scanner.peek();
1181:                Java.Statement stmt = (t.isOperator("{") ? this .parseBlock()
1182:                        : t.isKeyword("if") ? this .parseIfStatement() : t
1183:                                .isKeyword("for") ? this .parseForStatement()
1184:                                : t.isKeyword("while") ? this 
1185:                                        .parseWhileStatement() : t
1186:                                        .isKeyword("do") ? this 
1187:                                        .parseDoStatement() : t
1188:                                        .isKeyword("try") ? this 
1189:                                        .parseTryStatement() : t
1190:                                        .isKeyword("switch") ? this 
1191:                                        .parseSwitchStatement() : t
1192:                                        .isKeyword("synchronized") ? this 
1193:                                        .parseSynchronizedStatement() : t
1194:                                        .isKeyword("return") ? this 
1195:                                        .parseReturnStatement() : t
1196:                                        .isKeyword("throw") ? this 
1197:                                        .parseThrowStatement() : t
1198:                                        .isKeyword("break") ? this 
1199:                                        .parseBreakStatement() : t
1200:                                        .isKeyword("continue") ? this 
1201:                                        .parseContinueStatement() : t
1202:                                        .isOperator(";") ? this 
1203:                                        .parseEmptyStatement() : this 
1204:                                        .parseExpressionStatement());
1205:                if (stmt == null)
1206:                    this .throwParseException("\"" + t.getKeyword() + "\" NYI");
1207:
1208:                return stmt;
1209:            }
1210:
1211:            /**
1212:             * <pre>
1213:             *   LabeledStatement := Identifier ':' Statement
1214:             * </pre>
1215:             */
1216:            public Java.Statement parseLabeledStatement()
1217:                    throws ParseException, Scanner.ScanException, IOException {
1218:                String label = this .readIdentifier();
1219:                this .readOperator(":");
1220:                return new Java.LabeledStatement(this .location(), // location
1221:                        label, // label
1222:                        this .parseStatement() // body
1223:                );
1224:            }
1225:
1226:            /**
1227:             * <pre>
1228:             *   IfStatement := 'if' '(' Expression ')' Statement [ 'else' Statement ]
1229:             * </pre>
1230:             */
1231:            public Java.Statement parseIfStatement() throws ParseException,
1232:                    Scanner.ScanException, IOException {
1233:                Location location = this .location();
1234:                this .readKeyword("if");
1235:                this .readOperator("(");
1236:                final Java.Rvalue condition = this .parseExpression()
1237:                        .toRvalueOrPE();
1238:                this .readOperator(")");
1239:
1240:                Java.Statement thenStatement = this .parseStatement();
1241:
1242:                Java.Statement optionalElseStatement = null;
1243:                if (this .peekKeyword("else")) {
1244:                    this .eatToken();
1245:                    optionalElseStatement = this .parseStatement();
1246:                }
1247:
1248:                return new Java.IfStatement(location, // location
1249:                        condition, // condition
1250:                        thenStatement, // thenStatement
1251:                        optionalElseStatement // optionalElseStatement
1252:                );
1253:            }
1254:
1255:            /**
1256:             * <pre>
1257:             *   ForStatement :=
1258:             *     'for' '('
1259:             *       [ ForInit ] ';'
1260:             *       [ Expression ] ';'
1261:             *       [ ExpressionList ]
1262:             *     ')' Statement
1263:             * </pre>
1264:             */
1265:            public Java.Statement parseForStatement() throws ParseException,
1266:                    Scanner.ScanException, IOException {
1267:                Location location = this .location();
1268:                this .readKeyword("for");
1269:
1270:                this .readOperator("(");
1271:
1272:                Java.BlockStatement optionalInit = null;
1273:                if (!this .peekOperator(";"))
1274:                    optionalInit = this .parseForInit();
1275:
1276:                this .readOperator(";");
1277:
1278:                Java.Rvalue optionalCondition = null;
1279:                if (!this .peekOperator(";"))
1280:                    optionalCondition = this .parseExpression().toRvalueOrPE();
1281:
1282:                this .readOperator(";");
1283:
1284:                Java.Rvalue[] optionalUpdate = null;
1285:                if (!this .peekOperator(")"))
1286:                    optionalUpdate = this .parseExpressionList();
1287:
1288:                this .readOperator(")");
1289:
1290:                // KLUDGE: Insert an implicit Block here.
1291:                //        Java.Block implicitBlock = new Java.Block(location);
1292:                return /*Java.ForStatement forStatement =*/new Java.ForStatement(
1293:                        location, // location
1294:                        optionalInit, // optionalInit
1295:                        optionalCondition, // optionalCondition
1296:                        optionalUpdate, // optionalUpdate
1297:                        this .parseStatement() // body
1298:                );
1299:                //        implicitBlock.addStatement(forStatement);
1300:
1301:                //        return implicitBlock;
1302:            }
1303:
1304:            /**
1305:             * <pre>
1306:             *   ForInit :=
1307:             *     Modifiers Type LocalVariableDeclarators |
1308:             *     ModifiersOpt BasicType LocalVariableDeclarators |
1309:             *     Expression (
1310:             *       LocalVariableDeclarators |       (1)
1311:             *       { ',' Expression }
1312:             *     )
1313:             * </pre>
1314:             *
1315:             * (1) "Expression" must pose a type.
1316:             */
1317:            private Java.BlockStatement parseForInit() throws ParseException,
1318:                    Scanner.ScanException, IOException {
1319:
1320:                // Modifiers Type LocalVariableDeclarators
1321:                // ModifiersOpt BasicType LocalVariableDeclarators
1322:                if (this .peekKeyword(new String[] { "final", "byte", "short",
1323:                        "char", "int", "long", "float", "double", "boolean" })) {
1324:                    short modifiers = this .parseModifiersOpt();
1325:                    Java.Type variableType = this .parseType();
1326:                    return new Java.LocalVariableDeclarationStatement(this 
1327:                            .location(), // location
1328:                            modifiers, // modifiers
1329:                            variableType, // type
1330:                            this .parseLocalVariableDeclarators() // variableDeclarators
1331:                    );
1332:                }
1333:
1334:                Java.Atom a = this .parseExpression();
1335:
1336:                // Expression LocalVariableDeclarators
1337:                if (this .scanner.peek().isIdentifier()) {
1338:                    Java.Type variableType = a.toTypeOrPE();
1339:                    return new Java.LocalVariableDeclarationStatement(a
1340:                            .getLocation(), // location
1341:                            Mod.NONE, // modifiers
1342:                            variableType, // type
1343:                            this .parseLocalVariableDeclarators() // variableDeclarators
1344:                    );
1345:                }
1346:
1347:                // Expression { ',' Expression }
1348:                if (!this .peekOperator(",")) {
1349:                    return new Java.ExpressionStatement(a.toRvalueOrPE());
1350:                }
1351:                this .eatToken();
1352:                List l = new ArrayList();
1353:                l.add(new Java.ExpressionStatement(a.toRvalueOrPE()));
1354:                for (;;) {
1355:                    l.add(new Java.ExpressionStatement(this .parseExpression()
1356:                            .toRvalueOrPE()));
1357:                    if (!this .peekOperator(","))
1358:                        break;
1359:                    this .eatToken();
1360:                }
1361:
1362:                Java.Block b = new Java.Block(a.getLocation());
1363:                b.addStatements(l);
1364:                return b;
1365:            }
1366:
1367:            /**
1368:             * <pre>
1369:             *   WhileStatement := 'while' '(' Expression ')' Statement
1370:             * </pre>
1371:             */
1372:            public Java.Statement parseWhileStatement() throws ParseException,
1373:                    Scanner.ScanException, IOException {
1374:                Location location = this .location();
1375:                this .readKeyword("while");
1376:
1377:                this .readOperator("(");
1378:                Java.Rvalue condition = this .parseExpression().toRvalueOrPE();
1379:                this .readOperator(")");
1380:
1381:                return new Java.WhileStatement(location, // location
1382:                        condition, // condition
1383:                        this .parseStatement() // body
1384:                );
1385:            }
1386:
1387:            /**
1388:             * <pre>
1389:             *   DoStatement := 'do' Statement 'while' '(' Expression ')' ';'
1390:             * </pre>
1391:             */
1392:            public Java.Statement parseDoStatement() throws ParseException,
1393:                    Scanner.ScanException, IOException {
1394:                Location location = this .location();
1395:                this .readKeyword("do");
1396:
1397:                Java.Statement body = this .parseStatement();
1398:
1399:                this .readKeyword("while");
1400:                this .readOperator("(");
1401:                Java.Rvalue condition = this .parseExpression().toRvalueOrPE();
1402:                this .readOperator(")");
1403:                this .readOperator(";");
1404:
1405:                return new Java.DoStatement(location, // location
1406:                        body, // body
1407:                        condition // condition
1408:                );
1409:            }
1410:
1411:            /**
1412:             * <pre>
1413:             *   TryStatement :=
1414:             *     'try' Block Catches [ Finally ] |
1415:             *     'try' Block Finally
1416:             *
1417:             *   Catches := CatchClause { CatchClause }
1418:             *
1419:             *   CatchClause := 'catch' '(' FormalParameter ')' Block
1420:             *
1421:             *   Finally := 'finally' Block
1422:             * </pre>
1423:             */
1424:            public Java.Statement parseTryStatement() throws ParseException,
1425:                    Scanner.ScanException, IOException {
1426:                Location location = this .location();
1427:                this .readKeyword("try");
1428:
1429:                Java.Block body = this .parseBlock();
1430:
1431:                // { CatchClause }
1432:                List ccs = new ArrayList();
1433:                while (this .peekKeyword("catch")) {
1434:                    Location loc = this .location();
1435:                    this .eatToken();
1436:                    this .readOperator("(");
1437:                    Java.FunctionDeclarator.FormalParameter caughtException = this 
1438:                            .parseFormalParameter();
1439:                    this .readOperator(")");
1440:                    ccs.add(new Java.CatchClause(loc, // location
1441:                            caughtException, // caughtException
1442:                            this .parseBlock() // body
1443:                            ));
1444:                }
1445:                Java.Block optionalFinally = null;
1446:                if (this .peekKeyword("finally")) {
1447:                    this .eatToken();
1448:                    optionalFinally = this .parseBlock();
1449:                }
1450:                if (ccs.size() == 0 && optionalFinally == null)
1451:                    this 
1452:                            .throwParseException("\"try\" statement must have at least one \"catch\" clause or a \"finally\" clause");
1453:
1454:                return new Java.TryStatement(location, // location
1455:                        body, // body
1456:                        ccs, // catchClauses
1457:                        optionalFinally // optionalFinally
1458:                );
1459:            }
1460:
1461:            /**
1462:             * <pre>
1463:             *   SwitchStatement :=
1464:             *     'switch' '(' Expression ')' '{' { SwitchLabels BlockStatements } '}'
1465:             *
1466:             *   SwitchLabels := SwitchLabels { SwitchLabels }
1467:             *
1468:             *   SwitchLabel := 'case' Expression ':' | 'default' ':'
1469:             * </pre>
1470:             */
1471:            public Java.Statement parseSwitchStatement() throws ParseException,
1472:                    Scanner.ScanException, IOException {
1473:                Location location = this .location();
1474:                this .readKeyword("switch");
1475:
1476:                this .readOperator("(");
1477:                Java.Rvalue condition = this .parseExpression().toRvalueOrPE();
1478:                this .readOperator(")");
1479:
1480:                this .readOperator("{");
1481:                List sbsgs = new ArrayList();
1482:                while (!this .peekOperator("}")) {
1483:                    Location location2 = this .location();
1484:                    boolean hasDefaultLabel = false;
1485:                    List caseLabels = new ArrayList();
1486:                    do {
1487:                        if (this .peekKeyword("case")) {
1488:                            this .eatToken();
1489:                            caseLabels.add(this .parseExpression()
1490:                                    .toRvalueOrPE());
1491:                        } else if (this .peekKeyword("default")) {
1492:                            this .eatToken();
1493:                            if (hasDefaultLabel)
1494:                                this 
1495:                                        .throwParseException("Duplicate \"default\" label");
1496:                            hasDefaultLabel = true;
1497:                        } else {
1498:                            this 
1499:                                    .throwParseException("\"case\" or \"default\" expected");
1500:                        }
1501:                        this .readOperator(":");
1502:                    } while (this 
1503:                            .peekKeyword(new String[] { "case", "default" }));
1504:
1505:                    Java.SwitchStatement.SwitchBlockStatementGroup sbsg = new Java.SwitchStatement.SwitchBlockStatementGroup(
1506:                            location2, // location
1507:                            caseLabels, // caseLabels
1508:                            hasDefaultLabel, // hasDefaultLabel
1509:                            this .parseBlockStatements() // blockStatements
1510:                    );
1511:                    sbsgs.add(sbsg);
1512:                }
1513:                this .eatToken();
1514:                return new Java.SwitchStatement(location, // location
1515:                        condition, // condition
1516:                        sbsgs // sbsgs
1517:                );
1518:            }
1519:
1520:            /**
1521:             * <pre>
1522:             *   SynchronizedStatement :=
1523:             *     'synchronized' '(' expression ')' Block
1524:             * </pre>
1525:             */
1526:            public Java.Statement parseSynchronizedStatement()
1527:                    throws ParseException, Scanner.ScanException, IOException {
1528:                Location location = this .location();
1529:                this .readKeyword("synchronized");
1530:                this .readOperator("(");
1531:                Java.Rvalue expression = this .parseExpression().toRvalueOrPE();
1532:                this .readOperator(")");
1533:                return new Java.SynchronizedStatement(location, // location
1534:                        expression, // expression
1535:                        this .parseBlock() // body
1536:                );
1537:            }
1538:
1539:            /**
1540:             * <pre>
1541:             *   ReturnStatement := 'return' [ Expression ] ';'
1542:             * </pre>
1543:             */
1544:            public Java.Statement parseReturnStatement() throws ParseException,
1545:                    Scanner.ScanException, IOException {
1546:                Location location = this .location();
1547:                this .readKeyword("return");
1548:                Java.Rvalue returnValue = this .peekOperator(";") ? null : this 
1549:                        .parseExpression().toRvalueOrPE();
1550:                this .readOperator(";");
1551:                return new Java.ReturnStatement(location, returnValue);
1552:            }
1553:
1554:            /**
1555:             * <pre>
1556:             *   ThrowStatement := 'throw' Expression ';'
1557:             * </pre>
1558:             */
1559:            public Java.Statement parseThrowStatement() throws ParseException,
1560:                    Scanner.ScanException, IOException {
1561:                Location location = this .location();
1562:                this .readKeyword("throw");
1563:                final Java.Rvalue expression = this .parseExpression()
1564:                        .toRvalueOrPE();
1565:                this .readOperator(";");
1566:
1567:                return new Java.ThrowStatement(location, expression);
1568:            }
1569:
1570:            /**
1571:             * <pre>
1572:             *   BreakStatement := 'break' [ Identifier ] ';'
1573:             * </pre>
1574:             */
1575:            public Java.Statement parseBreakStatement() throws ParseException,
1576:                    Scanner.ScanException, IOException {
1577:                Location location = this .location();
1578:                this .readKeyword("break");
1579:                String optionalLabel = null;
1580:                if (this .scanner.peek().isIdentifier())
1581:                    optionalLabel = this .readIdentifier();
1582:                this .readOperator(";");
1583:                return new Java.BreakStatement(location, optionalLabel);
1584:            }
1585:
1586:            /**
1587:             * <pre>
1588:             *   ContinueStatement := 'continue' [ Identifier ] ';'
1589:             * </pre>
1590:             */
1591:            public Java.Statement parseContinueStatement()
1592:                    throws ParseException, Scanner.ScanException, IOException {
1593:                Location location = this .location();
1594:                this .readKeyword("continue");
1595:                String optionalLabel = null;
1596:                if (this .scanner.peek().isIdentifier())
1597:                    optionalLabel = this .readIdentifier();
1598:                this .readOperator(";");
1599:                return new Java.ContinueStatement(location, optionalLabel);
1600:            }
1601:
1602:            /**
1603:             * <pre>
1604:             *   EmptyStatement := ';'
1605:             * </pre>
1606:             */
1607:            public Java.Statement parseEmptyStatement() throws ParseException,
1608:                    Scanner.ScanException, IOException {
1609:                Location location = this .location();
1610:                this .readOperator(";");
1611:                return new Java.EmptyStatement(location);
1612:            }
1613:
1614:            /**
1615:             * <pre>
1616:             *   ExpressionList := Expression { ',' Expression }
1617:             * </pre>
1618:             */
1619:            public Java.Rvalue[] parseExpressionList() throws ParseException,
1620:                    Scanner.ScanException, IOException {
1621:                List l = new ArrayList();
1622:                for (;;) {
1623:                    l.add(this .parseExpression().toRvalueOrPE());
1624:                    if (!this .peekOperator(","))
1625:                        break;
1626:                    this .eatToken();
1627:                }
1628:                return (Java.Rvalue[]) l.toArray(new Java.Rvalue[l.size()]);
1629:            }
1630:
1631:            /**
1632:             * <pre>
1633:             *   Type := (
1634:             *     'byte' | 'short' | 'char' | 'int' | 'long' |
1635:             *     'float' | 'double' | 'boolean' |
1636:             *     ReferenceType
1637:             *   ) { '[' ']' }
1638:             * </pre>
1639:             */
1640:            public Java.Type parseType() throws ParseException,
1641:                    Scanner.ScanException, IOException {
1642:                Scanner.Token t = this .scanner.peek();
1643:                int bt = -1;
1644:                if (t.isKeyword("byte")) {
1645:                    bt = Java.BasicType.BYTE;
1646:                } else if (t.isKeyword("short")) {
1647:                    bt = Java.BasicType.SHORT;
1648:                } else if (t.isKeyword("char")) {
1649:                    bt = Java.BasicType.CHAR;
1650:                } else if (t.isKeyword("int")) {
1651:                    bt = Java.BasicType.INT;
1652:                } else if (t.isKeyword("long")) {
1653:                    bt = Java.BasicType.LONG;
1654:                } else if (t.isKeyword("float")) {
1655:                    bt = Java.BasicType.FLOAT;
1656:                } else if (t.isKeyword("double")) {
1657:                    bt = Java.BasicType.DOUBLE;
1658:                } else if (t.isKeyword("boolean")) {
1659:                    bt = Java.BasicType.BOOLEAN;
1660:                }
1661:                Java.Type res;
1662:                if (bt != -1) {
1663:                    res = new Java.BasicType(t.getLocation(), bt);
1664:                    this .eatToken();
1665:                } else {
1666:                    res = this .parseReferenceType();
1667:                }
1668:                for (int i = this .parseBracketsOpt(); i > 0; --i)
1669:                    res = new Java.ArrayType(res);
1670:                return res;
1671:            }
1672:
1673:            /**
1674:             * <pre>
1675:             *   ReferenceType := QualifiedIdentifier
1676:             * </pre>
1677:             */
1678:            public Java.ReferenceType parseReferenceType()
1679:                    throws ParseException, Scanner.ScanException, IOException {
1680:                return new Java.ReferenceType(this .location(), // location
1681:                        this .parseQualifiedIdentifier() // identifiers
1682:                );
1683:            }
1684:
1685:            /**
1686:             * <pre>
1687:             *   ReferenceTypeList := ReferenceType { ',' ReferenceType }
1688:             * </pre>
1689:             */
1690:            public Java.ReferenceType[] parseReferenceTypeList()
1691:                    throws ParseException, Scanner.ScanException, IOException {
1692:                List l = new ArrayList();
1693:                l.add(this .parseReferenceType());
1694:                while (this .peekOperator(",")) {
1695:                    this .eatToken();
1696:                    l.add(this .parseReferenceType());
1697:                }
1698:                return (Java.ReferenceType[]) l
1699:                        .toArray(new Java.ReferenceType[l.size()]);
1700:            }
1701:
1702:            /**
1703:             * <pre>
1704:             *   Expression := AssignmentExpression
1705:             * </pre>
1706:             */
1707:            public Java.Atom parseExpression() throws ParseException,
1708:                    Scanner.ScanException, IOException {
1709:                return this .parseAssignmentExpression();
1710:            }
1711:
1712:            /**
1713:             * <pre>
1714:             *   AssignmentExpression :=
1715:             *     ConditionalExpression [ AssignmentOperator AssignmentExpression ]
1716:             *
1717:             *   AssignmentOperator :=
1718:             *     '=' | '*=' | '/=' | '%=' | '+=' | '-=' | '<<=' |
1719:             *     '>>=' | '>>>=' | '&=' | '^=' | '|='
1720:             * </pre>
1721:             */
1722:            public Java.Atom parseAssignmentExpression() throws ParseException,
1723:                    Scanner.ScanException, IOException {
1724:                Java.Atom a = this .parseConditionalExpression();
1725:                if (this .peekOperator(new String[] { "=", "+=", "-=", "*=",
1726:                        "/=", "&=", "|=", "^=", "%=", "<<=", ">>=", ">>>=" })) {
1727:                    Location location = this .location();
1728:                    String operator = this .readOperator();
1729:                    final Java.Lvalue lhs = a.toLvalueOrPE();
1730:                    final Java.Rvalue rhs = this .parseAssignmentExpression()
1731:                            .toRvalueOrPE();
1732:                    return new Java.Assignment(location, lhs, operator, rhs);
1733:                }
1734:                return a;
1735:            }
1736:
1737:            /**
1738:             * <pre>
1739:             *   ConditionalExpression :=
1740:             *     ConditionalOrExpression [ '?' Expression ':' ConditionalExpression ]
1741:             * </pre>
1742:             */
1743:            public Java.Atom parseConditionalExpression()
1744:                    throws ParseException, Scanner.ScanException, IOException {
1745:                Java.Atom a = this .parseConditionalOrExpression();
1746:                if (!this .peekOperator("?"))
1747:                    return a;
1748:                Location location = this .location();
1749:                this .eatToken();
1750:
1751:                Java.Rvalue lhs = a.toRvalueOrPE();
1752:                Java.Rvalue mhs = this .parseExpression().toRvalueOrPE();
1753:                this .readOperator(":");
1754:                Java.Rvalue rhs = this .parseConditionalExpression()
1755:                        .toRvalueOrPE();
1756:                return new Java.ConditionalExpression(location, lhs, mhs, rhs);
1757:            }
1758:
1759:            /**
1760:             * <pre>
1761:             *   ConditionalOrExpression :=
1762:             *     ConditionalAndExpression { '||' ConditionalAndExpression ]
1763:             * </pre>
1764:             */
1765:            public Java.Atom parseConditionalOrExpression()
1766:                    throws ParseException, Scanner.ScanException, IOException {
1767:                Java.Atom a = this .parseConditionalAndExpression();
1768:                while (this .peekOperator("||")) {
1769:                    Location location = this .location();
1770:                    this .eatToken();
1771:                    a = new Java.BinaryOperation(location, a.toRvalueOrPE(),
1772:                            "||", this .parseConditionalAndExpression()
1773:                                    .toRvalueOrPE());
1774:                }
1775:                return a;
1776:            }
1777:
1778:            /**
1779:             * <pre>
1780:             *   ConditionalAndExpression :=
1781:             *     InclusiveOrExpression { '&&' InclusiveOrExpression }
1782:             * </pre>
1783:             */
1784:            public Java.Atom parseConditionalAndExpression()
1785:                    throws ParseException, Scanner.ScanException, IOException {
1786:                Java.Atom a = this .parseInclusiveOrExpression();
1787:                while (this .peekOperator("&&")) {
1788:                    Location location = this .location();
1789:                    this .eatToken();
1790:                    a = new Java.BinaryOperation(location, a.toRvalueOrPE(),
1791:                            "&&", this .parseInclusiveOrExpression()
1792:                                    .toRvalueOrPE());
1793:                }
1794:                return a;
1795:            }
1796:
1797:            /**
1798:             * <pre>
1799:             *   InclusiveOrExpression :=
1800:             *     ExclusiveOrExpression { '|' ExclusiveOrExpression }
1801:             * </pre>
1802:             */
1803:            public Java.Atom parseInclusiveOrExpression()
1804:                    throws ParseException, Scanner.ScanException, IOException {
1805:                Java.Atom a = this .parseExclusiveOrExpression();
1806:                while (this .peekOperator("|")) {
1807:                    Location location = this .location();
1808:                    this .eatToken();
1809:                    a = new Java.BinaryOperation(location, a.toRvalueOrPE(),
1810:                            "|", this .parseExclusiveOrExpression()
1811:                                    .toRvalueOrPE());
1812:                }
1813:                return a;
1814:            }
1815:
1816:            /**
1817:             * <pre>
1818:             *   ExclusiveOrExpression :=
1819:             *     AndExpression { '^' AndExpression }
1820:             * </pre>
1821:             */
1822:            public Java.Atom parseExclusiveOrExpression()
1823:                    throws ParseException, Scanner.ScanException, IOException {
1824:                Java.Atom a = this .parseAndExpression();
1825:                while (this .peekOperator("^")) {
1826:                    Location location = this .location();
1827:                    this .eatToken();
1828:                    a = new Java.BinaryOperation(location, a.toRvalueOrPE(),
1829:                            "^", this .parseAndExpression().toRvalueOrPE());
1830:                }
1831:                return a;
1832:            }
1833:
1834:            /**
1835:             * <pre>
1836:             *   AndExpression :=
1837:             *     EqualityExpression { '&' EqualityExpression }
1838:             * </pre>
1839:             */
1840:            public Java.Atom parseAndExpression() throws ParseException,
1841:                    Scanner.ScanException, IOException {
1842:                Java.Atom a = this .parseEqualityExpression();
1843:                while (this .peekOperator("&")) {
1844:                    Location location = this .location();
1845:                    this .eatToken();
1846:                    a = new Java.BinaryOperation(location, a.toRvalueOrPE(),
1847:                            "&", this .parseEqualityExpression().toRvalueOrPE());
1848:                }
1849:                return a;
1850:            }
1851:
1852:            /**
1853:             * <pre>
1854:             *   EqualityExpression :=
1855:             *     RelationalExpression { ( '==' | '!=' ) RelationalExpression }
1856:             * </pre>
1857:             */
1858:            public Java.Atom parseEqualityExpression() throws ParseException,
1859:                    Scanner.ScanException, IOException {
1860:                Java.Atom a = this .parseRelationalExpression();
1861:
1862:                while (this .peekOperator(new String[] { "==", "!=" })) {
1863:                    a = new Java.BinaryOperation(this .location(), // location
1864:                            a.toRvalueOrPE(), // lhs
1865:                            this .readOperator(), // op
1866:                            this .parseRelationalExpression().toRvalueOrPE() // rhs
1867:                    );
1868:                }
1869:                return a;
1870:            }
1871:
1872:            /**
1873:             * <pre>
1874:             *   RelationalExpression :=
1875:             *     ShiftExpression {
1876:             *       ( ( '<' | '>' | '<=' | '>=' ) ShiftExpression ) |
1877:             *       ( 'instanceof' ReferenceType )
1878:             *     }
1879:             * </pre>
1880:             */
1881:            public Java.Atom parseRelationalExpression() throws ParseException,
1882:                    Scanner.ScanException, IOException {
1883:                Java.Atom a = this .parseShiftExpression();
1884:
1885:                for (;;) {
1886:                    if (this .peekKeyword("instanceof")) {
1887:                        Location location = this .location();
1888:                        this .eatToken();
1889:                        a = new Java.Instanceof(location, a.toRvalueOrPE(),
1890:                                this .parseType());
1891:                    } else if (this .peekOperator(new String[] { "<", ">", "<=",
1892:                            ">=" })) {
1893:                        a = new Java.BinaryOperation(this .location(), // location
1894:                                a.toRvalueOrPE(), // lhs
1895:                                this .readOperator(), // op
1896:                                this .parseShiftExpression().toRvalueOrPE() // rhs
1897:                        );
1898:                    } else {
1899:                        return a;
1900:                    }
1901:                }
1902:            }
1903:
1904:            /**
1905:             * <pre>
1906:             *   ShiftExpression :=
1907:             *     AdditiveExpression { ( '<<' | '>>' | '>>>' ) AdditiveExpression }
1908:             * </pre>
1909:             */
1910:            public Java.Atom parseShiftExpression() throws ParseException,
1911:                    Scanner.ScanException, IOException {
1912:                Java.Atom a = this .parseAdditiveExpression();
1913:
1914:                while (this .peekOperator(new String[] { "<<", ">>", ">>>" })) {
1915:                    a = new Java.BinaryOperation(this .location(), // location
1916:                            a.toRvalueOrPE(), // lhs
1917:                            this .readOperator(), // op
1918:                            this .parseAdditiveExpression().toRvalueOrPE() // rhs
1919:                    );
1920:                }
1921:                return a;
1922:            }
1923:
1924:            /**
1925:             * <pre>
1926:             *   AdditiveExpression :=
1927:             *     MultiplicativeExpression { ( '+' | '-' ) MultiplicativeExpression }
1928:             * </pre>
1929:             */
1930:            public Java.Atom parseAdditiveExpression() throws ParseException,
1931:                    Scanner.ScanException, IOException {
1932:                Java.Atom a = this .parseMultiplicativeExpression();
1933:
1934:                while (this .peekOperator(new String[] { "+", "-" })) {
1935:                    a = new Java.BinaryOperation(this .location(), // location
1936:                            a.toRvalueOrPE(), // lhs
1937:                            this .readOperator(), // op
1938:                            this .parseMultiplicativeExpression().toRvalueOrPE() // rhs
1939:                    );
1940:                }
1941:                return a;
1942:            }
1943:
1944:            /**
1945:             * <pre>
1946:             *   MultiplicativeExpression :=
1947:             *     UnaryExpression { ( '*' | '/' | '%' ) UnaryExpression }
1948:             * </pre>
1949:             */
1950:            public Java.Atom parseMultiplicativeExpression()
1951:                    throws ParseException, Scanner.ScanException, IOException {
1952:                Java.Atom a = this .parseUnaryExpression();
1953:
1954:                while (this .peekOperator(new String[] { "*", "/", "%" })) {
1955:                    a = new Java.BinaryOperation(this .location(), // location
1956:                            a.toRvalueOrPE(), // lhs
1957:                            this .readOperator(), // op
1958:                            this .parseUnaryExpression().toRvalueOrPE() // rhs
1959:                    );
1960:                }
1961:                return a;
1962:            }
1963:
1964:            /**
1965:             * <pre>
1966:             *   UnaryExpression :=
1967:             *     { PrefixOperator } Primary { Selector } { PostfixOperator }
1968:             *
1969:             *   PrefixOperator := '++' | '--' | '+' | '-' | '~' | '!'
1970:             *
1971:             *   PostfixOperator := '++' | '--'
1972:             * </pre>
1973:             */
1974:            public Java.Atom parseUnaryExpression() throws ParseException,
1975:                    Scanner.ScanException, IOException {
1976:                if (this .peekOperator(new String[] { "++", "--" })) {
1977:                    return new Java.Crement(this .location(), // location
1978:                            this .readOperator(), // operator
1979:                            this .parseUnaryExpression().toLvalueOrPE() // operand
1980:                    );
1981:                }
1982:
1983:                if (this .peekOperator(new String[] { "+", "-", "~", "!" })) {
1984:                    return new Java.UnaryOperation(this .location(), // location
1985:                            this .readOperator(), // operator
1986:                            this .parseUnaryExpression().toRvalueOrPE() // operand
1987:                    );
1988:                }
1989:
1990:                Java.Atom a = this .parsePrimary();
1991:
1992:                while (this .peekOperator(new String[] { ".", "[" })) {
1993:                    a = this .parseSelector(a);
1994:                }
1995:
1996:                while (this .peekOperator(new String[] { "++", "--" })) {
1997:                    a = new Java.Crement(this .location(), // location
1998:                            a.toLvalueOrPE(), // operand
1999:                            this .readOperator() // operator
2000:                    );
2001:                }
2002:
2003:                return a;
2004:            }
2005:
2006:            /**
2007:             * <pre>
2008:             *   Primary :=
2009:             *     CastExpression |                        // CastExpression 15.16
2010:             *     '(' Expression ')' |                    // ParenthesizedExpression 15.8.5
2011:             *     Literal |                               // Literal 15.8.1
2012:             *     Name |                                  // AmbiguousName
2013:             *     Name Arguments |                        // MethodInvocation
2014:             *     Name '[]' { '[]' } |                    // ArrayType 10.1
2015:             *     Name '[]' { '[]' } '.' 'class' |        // ClassLiteral 15.8.2
2016:             *     'this' |                                // This 15.8.3
2017:             *     'this' Arguments |                      // Alternate constructor invocation 8.8.5.1
2018:             *     'super' Arguments |                     // Unqualified superclass constructor invocation 8.8.5.1
2019:             *     'super' '.' Identifier |                // SuperclassFieldAccess 15.11.2
2020:             *     'super' '.' Identifier Arguments |      // SuperclassMethodInvocation 15.12.4.9
2021:             *     NewClassInstance |
2022:             *     NewAnonymousClassInstance |             // ClassInstanceCreationExpression 15.9
2023:             *     NewArray |                              // ArrayCreationExpression 15.10
2024:             *     NewInitializedArray |                   // ArrayInitializer 10.6
2025:             *     BasicType { '[]' } |                    // Type
2026:             *     BasicType { '[]' } '.' 'class' |        // ClassLiteral 15.8.2
2027:             *     'void' '.' 'class'                      // ClassLiteral 15.8.2
2028:             *
2029:             *   CastExpression :=
2030:             *     '(' PrimitiveType { '[]' } ')' UnaryExpression |
2031:             *     '(' Expression ')' UnaryExpression
2032:             * 
2033:             *   NewClassInstance := 'new' ReferenceType Arguments
2034:             * 
2035:             *   NewAnonymousClassInstance := 'new' ReferenceType Arguments [ ClassBody ]
2036:             * 
2037:             *   NewArray := 'new' Type DimExprs { '[]' }
2038:             * 
2039:             *   NewInitializedArray := 'new' ArrayType ArrayInitializer
2040:             * </pre>
2041:             */
2042:            public Java.Atom parsePrimary() throws ParseException,
2043:                    Scanner.ScanException, IOException {
2044:                if (this .peekOperator("(")) {
2045:                    this .eatToken();
2046:                    if (this 
2047:                            .peekKeyword(new String[] { "boolean", "char",
2048:                                    "byte", "short", "int", "long", "float",
2049:                                    "double", })) {
2050:                        // '(' PrimitiveType { '[]' } ')' UnaryExpression
2051:                        Java.Type type = this .parseType();
2052:                        int brackets = this .parseBracketsOpt();
2053:                        this .readOperator(")");
2054:                        for (int i = 0; i < brackets; ++i)
2055:                            type = new Java.ArrayType(type);
2056:                        return new Java.Cast(this .location(), // location
2057:                                type, // targetType
2058:                                this .parseUnaryExpression().toRvalueOrPE() // value
2059:                        );
2060:                    }
2061:                    Java.Atom a = this .parseExpression();
2062:                    this .readOperator(")");
2063:
2064:                    if (this .scanner.peek().isLiteral()
2065:                            || this .scanner.peek().isIdentifier()
2066:                            || this 
2067:                                    .peekOperator(new String[] { "(", "~", "!", })
2068:                            || this .peekKeyword(new String[] { "this", "super",
2069:                                    "new", })) {
2070:                        // '(' Expression ')' UnaryExpression
2071:                        return new Java.Cast(this .location(), // location
2072:                                a.toTypeOrPE(), // targetType
2073:                                this .parseUnaryExpression().toRvalueOrPE() // value
2074:                        );
2075:                    }
2076:
2077:                    // '(' Expression ')'
2078:                    return new Java.ParenthesizedExpression(a.getLocation(), a
2079:                            .toRvalueOrPE());
2080:                }
2081:
2082:                if (this .scanner.peek().isLiteral()) {
2083:                    // Literal
2084:                    return this .parseLiteral();
2085:                }
2086:
2087:                if (this .scanner.peek().isIdentifier()) {
2088:                    Location location = this .location();
2089:                    String[] qi = this .parseQualifiedIdentifier();
2090:                    if (this .peekOperator("(")) {
2091:                        // Name Arguments
2092:                        return new Java.MethodInvocation(this .location(), // location
2093:                                qi.length == 1 ? null : new Java.AmbiguousName( // optionalTarget
2094:                                        location, // location
2095:                                        qi, // identifiers
2096:                                        qi.length - 1 // n
2097:                                        ), qi[qi.length - 1], // methodName
2098:                                this .parseArguments() // arguments
2099:                        );
2100:                    }
2101:                    if (this .peekOperator("[")
2102:                            && this .scanner.peekNextButOne().isOperator("]")) {
2103:                        // Name '[]' { '[]' }
2104:                        // Name '[]' { '[]' } '.' 'class'
2105:                        Java.Type res = new Java.ReferenceType(location, // location
2106:                                qi // identifiers
2107:                        );
2108:                        int brackets = this .parseBracketsOpt();
2109:                        for (int i = 0; i < brackets; ++i)
2110:                            res = new Java.ArrayType(res);
2111:                        if (this .peekOperator(".")
2112:                                && this .scanner.peekNextButOne().isKeyword(
2113:                                        "class")) {
2114:                            this .eatToken();
2115:                            Location location2 = this .location();
2116:                            this .eatToken();
2117:                            return new Java.ClassLiteral(location2, res);
2118:                        } else {
2119:                            return res;
2120:                        }
2121:                    }
2122:                    // Name
2123:                    return new Java.AmbiguousName(this .location(), // location
2124:                            qi // identifiers
2125:                    );
2126:                }
2127:
2128:                if (this .peekKeyword("this")) {
2129:                    Location location = this .location();
2130:                    this .eatToken();
2131:                    if (this .peekOperator("(")) {
2132:
2133:                        // 'this' Arguments
2134:                        // Alternate constructor invocation (JLS 8.8.5.1)
2135:                        return new Java.AlternateConstructorInvocation(
2136:                                location, // location
2137:                                this .parseArguments() // arguments
2138:                        );
2139:                    } else {
2140:
2141:                        // 'this'
2142:                        return new Java.ThisReference(location);
2143:                    }
2144:                }
2145:
2146:                if (this .peekKeyword("super")) {
2147:                    this .eatToken();
2148:                    if (this .peekOperator("(")) {
2149:
2150:                        // 'super' Arguments
2151:                        // Unqualified superclass constructor invocation (JLS 8.8.5.1)
2152:                        return new Java.SuperConstructorInvocation(this 
2153:                                .location(), // location
2154:                                (Java.Rvalue) null, // optionalQualification
2155:                                this .parseArguments() // arguments
2156:                        );
2157:                    }
2158:                    this .readOperator(".");
2159:                    String name = this .readIdentifier();
2160:                    if (this .peekOperator("(")) {
2161:
2162:                        // 'super' '.' Identifier Arguments
2163:                        return new Java.SuperclassMethodInvocation(this 
2164:                                .location(), // location
2165:                                name, // methodName
2166:                                this .parseArguments() // arguments
2167:                        );
2168:                    } else {
2169:
2170:                        // 'super' '.' Identifier
2171:                        this .throwParseException("Superclass field access NYI");
2172:                    }
2173:                }
2174:
2175:                // 'new'
2176:                if (this .peekKeyword("new")) {
2177:                    Location location = this .location();
2178:                    this .eatToken();
2179:                    Java.Type type = this .parseType();
2180:                    if (type instanceof  Java.ArrayType) {
2181:                        // 'new' ArrayType ArrayInitializer
2182:                        return new Java.NewInitializedArray(location,
2183:                                (Java.ArrayType) type, this 
2184:                                        .parseArrayInitializer());
2185:                    }
2186:                    if (type instanceof  Java.ReferenceType
2187:                            && this .peekOperator("(")) {
2188:                        // 'new' ReferenceType Arguments [ ClassBody ]
2189:                        Java.Rvalue[] arguments = this .parseArguments();
2190:                        if (this .peekOperator("{")) {
2191:                            // 'new' ReferenceType Arguments ClassBody
2192:                            final Java.AnonymousClassDeclaration anonymousClassDeclaration = new Java.AnonymousClassDeclaration(
2193:                                    this .location(), // location
2194:                                    type // baseType
2195:                            );
2196:                            this .parseClassBody(anonymousClassDeclaration);
2197:                            return new Java.NewAnonymousClassInstance(location, // location
2198:                                    (Java.Rvalue) null, // optionalQualification
2199:                                    anonymousClassDeclaration, // anonymousClassDeclaration
2200:                                    arguments // arguments
2201:                            );
2202:                        } else {
2203:                            // 'new' ReferenceType Arguments
2204:                            return new Java.NewClassInstance(location, // location
2205:                                    (Java.Rvalue) null, // optionalQualification
2206:                                    type, // type
2207:                                    arguments // arguments
2208:                            );
2209:                        }
2210:                    }
2211:                    // 'new' Type DimExprs { '[]' }
2212:                    return new Java.NewArray(location, // location
2213:                            type, // type
2214:                            this .parseDimExprs(), // dimExprs
2215:                            this .parseBracketsOpt() // dims
2216:                    );
2217:                }
2218:
2219:                // BasicType
2220:                if (this .peekKeyword(new String[] { "boolean", "char", "byte",
2221:                        "short", "int", "long", "float", "double", })) {
2222:                    Java.Type res = this .parseType();
2223:                    int brackets = this .parseBracketsOpt();
2224:                    for (int i = 0; i < brackets; ++i)
2225:                        res = new Java.ArrayType(res);
2226:                    if (this .peekOperator(".")
2227:                            && this .scanner.peekNextButOne().isKeyword("class")) {
2228:                        // BasicType { '[]' } '.' 'class'
2229:                        this .eatToken();
2230:                        Location location = this .location();
2231:                        this .eatToken();
2232:                        return new Java.ClassLiteral(location, res);
2233:                    }
2234:                    // BasicType { '[]' }
2235:                    return res;
2236:                }
2237:
2238:                // 'void'
2239:                if (this .peekKeyword("void")) {
2240:                    this .eatToken();
2241:                    if (this .peekOperator(".")
2242:                            && this .scanner.peekNextButOne().isKeyword("class")) {
2243:                        // 'void' '.' 'class'
2244:                        this .eatToken();
2245:                        Location location = this .location();
2246:                        this .eatToken();
2247:                        return new Java.ClassLiteral(location,
2248:                                new Java.BasicType(location,
2249:                                        Java.BasicType.VOID));
2250:                    }
2251:                    this 
2252:                            .throwParseException("\"void\" encountered in wrong context");
2253:                }
2254:
2255:                this .throwParseException("Unexpected token \""
2256:                        + this .scanner.peek() + "\" in primary");
2257:                /* NEVER REACHED */return null;
2258:            }
2259:
2260:            /**
2261:             * <pre>
2262:             *   Selector :=
2263:             *     '.' Identifier |                       // FieldAccess 15.11.1
2264:             *     '.' Identifier Arguments |             // MethodInvocation
2265:             *     '.' 'this'                             // QualifiedThis 15.8.4
2266:             *     '.' 'super' Arguments                  // Qualified superclass constructor invocation (JLS 8.8.5.1)
2267:             *     '.' 'super' '.' Identifier |           // SuperclassFieldReference (JLS 15.11.2)
2268:             *     '.' 'super' '.' Identifier Arguments | // SuperclassMethodInvocation (JLS 15.12.4.9)
2269:             *     '.' 'new' Identifier Arguments [ ClassBody ] | // QualifiedClassInstanceCreationExpression  15.9
2270:             *     '.' 'class'
2271:             *     '[' Expression ']'                     // ArrayAccessExpression 15.13
2272:             * </pre>
2273:             */
2274:            public Java.Atom parseSelector(Java.Atom atom)
2275:                    throws ParseException, Scanner.ScanException, IOException {
2276:                if (this .peekOperator(".")) {
2277:                    this .eatToken();
2278:                    if (this .scanner.peek().isIdentifier()) {
2279:                        String identifier = this .readIdentifier();
2280:                        if (this .peekOperator("(")) {
2281:                            // '.' Identifier Arguments
2282:                            return new Java.MethodInvocation(this .location(), // location
2283:                                    atom.toRvalueOrPE(), // optionalTarget
2284:                                    identifier, // methodName
2285:                                    this .parseArguments() // arguments
2286:                            );
2287:                        }
2288:                        // '.' Identifier
2289:                        return new Java.FieldAccessExpression(this .location(), // location
2290:                                atom.toRvalueOrPE(), // lhs
2291:                                identifier // fieldName
2292:                        );
2293:                    }
2294:                    if (this .peekKeyword("this")) {
2295:                        // '.' 'this'
2296:                        Location location = this .location();
2297:                        this .eatToken();
2298:                        return new Java.QualifiedThisReference(location, // location
2299:                                atom.toTypeOrPE() // qualification
2300:                        );
2301:                    }
2302:                    if (this .peekKeyword("super")) {
2303:                        Location location = this .location();
2304:                        this .eatToken();
2305:                        if (this .peekOperator("(")) {
2306:
2307:                            // '.' 'super' Arguments
2308:                            // Qualified superclass constructor invocation (JLS 8.8.5.1) (LHS is an Rvalue)
2309:                            return new Java.SuperConstructorInvocation(
2310:                                    location, // location
2311:                                    atom.toRvalueOrPE(), // optionalQualification
2312:                                    this .parseArguments() // arguments
2313:                            );
2314:                        }
2315:                        this .readOperator(".");
2316:                        /*String identifier =*/this .readIdentifier();
2317:
2318:                        if (this .peekOperator("(")) {
2319:
2320:                            // '.' 'super' '.' Identifier Arguments
2321:                            // Qualified superclass method invocation (JLS 15.12) (LHS is a ClassName)
2322:                            // TODO: Qualified superclass method invocation
2323:                            this 
2324:                                    .throwParseException("Qualified superclass method invocation NYI");
2325:                        } else {
2326:
2327:                            // '.' 'super' '.' Identifier
2328:                            // Qualified superclass field access (JLS 15.11.2) (LHS is an Rvalue)
2329:                            // TODO: Qualified superclass field access
2330:                            this 
2331:                                    .throwParseException("Qualified superclass field access NYI");
2332:                        }
2333:                    }
2334:                    if (this .peekKeyword("new")) {
2335:                        // '.' 'new' Identifier Arguments [ ClassBody ]
2336:                        Java.Rvalue lhs = atom.toRvalue();
2337:                        Location location = this .location();
2338:                        this .eatToken();
2339:                        String identifier = this .readIdentifier();
2340:                        Java.Type type = new Java.RvalueMemberType(location, // location
2341:                                lhs, // rValue
2342:                                identifier // identifier
2343:                        );
2344:                        Java.Rvalue[] arguments = this .parseArguments();
2345:                        if (this .peekOperator("{")) {
2346:                            // '.' 'new' Identifier Arguments ClassBody (LHS is an Rvalue)
2347:                            final Java.AnonymousClassDeclaration anonymousClassDeclaration = new Java.AnonymousClassDeclaration(
2348:                                    this .location(), // location
2349:                                    type // baseType
2350:                            );
2351:                            this .parseClassBody(anonymousClassDeclaration);
2352:                            return new Java.NewAnonymousClassInstance(location, // location
2353:                                    lhs, // optionalQualification
2354:                                    anonymousClassDeclaration, // anonymousClassDeclaration
2355:                                    arguments // arguments
2356:                            );
2357:                        } else {
2358:                            // '.' 'new' Identifier Arguments (LHS is an Rvalue)
2359:                            return new Java.NewClassInstance(location, // location
2360:                                    lhs, // optionalQualification
2361:                                    type, // referenceType
2362:                                    arguments // arguments
2363:                            );
2364:                        }
2365:                    }
2366:                    if (this .peekKeyword("class")) {
2367:                        // '.' 'class'
2368:                        Location location = this .location();
2369:                        this .eatToken();
2370:                        return new Java.ClassLiteral(location, atom
2371:                                .toTypeOrPE());
2372:                    }
2373:                    this .throwParseException("Unexpected selector \""
2374:                            + this .scanner.peek() + "\" after \".\"");
2375:                }
2376:                if (this .peekOperator("[")) {
2377:                    // '[' Expression ']'
2378:                    Location location = this .location();
2379:                    this .eatToken();
2380:                    Java.Rvalue index = this .parseExpression().toRvalueOrPE();
2381:                    this .readOperator("]");
2382:                    return new Java.ArrayAccessExpression(location, // location
2383:                            atom.toRvalueOrPE(), // lhs
2384:                            index // index
2385:                    );
2386:                }
2387:                this .throwParseException("Unexpected token \""
2388:                        + this .scanner.peek() + "\" in selector");
2389:                /* NEVER REACHED */return null;
2390:            }
2391:
2392:            /**
2393:             * <pre>
2394:             *   DimExprs := DimExpr { DimExpr }
2395:             * </pre>
2396:             */
2397:            public Java.Rvalue[] parseDimExprs() throws ParseException,
2398:                    Scanner.ScanException, IOException {
2399:                List l = new ArrayList();
2400:                l.add(this .parseDimExpr());
2401:                while (this .peekOperator("[")
2402:                        && !this .scanner.peekNextButOne().isOperator("]"))
2403:                    l.add(this .parseDimExpr());
2404:                return (Java.Rvalue[]) l.toArray(new Java.Rvalue[l.size()]);
2405:            }
2406:
2407:            /**
2408:             * <pre>
2409:             *   DimExpr := '[' Expression ']'
2410:             * </pre>
2411:             */
2412:            public Java.Rvalue parseDimExpr() throws Scanner.ScanException,
2413:                    ParseException, IOException {
2414:                this .readOperator("[");
2415:                Java.Rvalue res = this .parseExpression().toRvalueOrPE();
2416:                this .readOperator("]");
2417:                return res;
2418:            }
2419:
2420:            /**
2421:             * <pre>
2422:             *   Arguments := '(' [ ArgumentList ] ')'
2423:             * </pre>
2424:             */
2425:            public Java.Rvalue[] parseArguments() throws ParseException,
2426:                    Scanner.ScanException, IOException {
2427:                this .readOperator("(");
2428:                if (this .peekOperator(")")) {
2429:                    this .eatToken();
2430:                    return new Java.Rvalue[0];
2431:                }
2432:                Java.Rvalue[] arguments = this .parseArgumentList();
2433:                this .readOperator(")");
2434:                return arguments;
2435:            }
2436:
2437:            /**
2438:             * <pre>
2439:             *   ArgumentList := Expression { ',' Expression }
2440:             * </pre>
2441:             */
2442:            public Java.Rvalue[] parseArgumentList() throws ParseException,
2443:                    Scanner.ScanException, IOException {
2444:                List l = new ArrayList();
2445:                for (;;) {
2446:                    l.add(this .parseExpression().toRvalueOrPE());
2447:                    if (!this .peekOperator(","))
2448:                        break;
2449:                    this .eatToken();
2450:                }
2451:                return (Java.Rvalue[]) l.toArray(new Java.Rvalue[l.size()]);
2452:            }
2453:
2454:            public Java.Atom parseLiteral() throws ParseException,
2455:                    Scanner.ScanException, IOException {
2456:                Scanner.Token t = this .scanner.read();
2457:                if (!t.isLiteral())
2458:                    this .throwParseException("Literal expected");
2459:                return new Java.Literal(t.getLocation(), t.getLiteralValue());
2460:            }
2461:
2462:            // Simplified access to the scanner.
2463:
2464:            public Location location() {
2465:                return this .scanner.location();
2466:            }
2467:
2468:            public void eatToken() throws Scanner.ScanException, IOException {
2469:                this .scanner.read();
2470:            }
2471:
2472:            // Keyword-related.
2473:            public boolean peekKeyword() {
2474:                return this .scanner.peek().isKeyword();
2475:            }
2476:
2477:            public boolean peekKeyword(String keyword) {
2478:                return this .scanner.peek().isKeyword(keyword);
2479:            }
2480:
2481:            public boolean peekKeyword(String[] keywords) {
2482:                return this .scanner.peek().isKeyword(keywords);
2483:            }
2484:
2485:            public void readKeyword(String keyword) throws ParseException,
2486:                    Scanner.ScanException, IOException {
2487:                if (!this .scanner.read().isKeyword(keyword))
2488:                    this .throwParseException("\"" + keyword + "\" expected"); // We want a ParseException, not a ScanException
2489:            }
2490:
2491:            // Operator-related.
2492:            public boolean peekOperator(String operator) {
2493:                return this .scanner.peek().isOperator(operator);
2494:            }
2495:
2496:            public boolean peekOperator(String[] operators) {
2497:                return this .scanner.peek().isOperator(operators);
2498:            }
2499:
2500:            public String readOperator() throws ParseException,
2501:                    Scanner.ScanException, IOException {
2502:                Scanner.Token t = this .scanner.read();
2503:                if (!t.isOperator())
2504:                    this .throwParseException("Operator expected"); // We want a ParseException, not a ScanException
2505:                return t.getOperator();
2506:            }
2507:
2508:            public void readOperator(String operator) throws ParseException,
2509:                    Scanner.ScanException, IOException {
2510:                if (!this .scanner.read().isOperator(operator))
2511:                    this .throwParseException("Operator \"" + operator
2512:                            + "\" expected"); // We want a ParseException, not a ScanException
2513:            }
2514:
2515:            // Identifier-related.
2516:            public boolean peekIdentifier() {
2517:                return this .scanner.peek().isIdentifier();
2518:            }
2519:
2520:            public String readIdentifier() throws ParseException,
2521:                    Scanner.ScanException, IOException {
2522:                Scanner.Token t = this .scanner.read();
2523:                if (!t.isIdentifier())
2524:                    this .throwParseException("Identifier expected"); // We want a ParseException, not a ScanException
2525:                return t.getIdentifier();
2526:            }
2527:
2528:            /**
2529:             * <pre>
2530:             *   ExpressionStatement := Expression ';'
2531:             * </pre>
2532:             */
2533:            public Java.Statement parseExpressionStatement()
2534:                    throws ParseException, Scanner.ScanException, IOException {
2535:                Java.Rvalue rv = this .parseExpression().toRvalueOrPE();
2536:                this .readOperator(";");
2537:
2538:                return new Java.ExpressionStatement(rv);
2539:            }
2540:
2541:            /**
2542:             * Issue a warning if the given string does not comply with the package naming conventions
2543:             * (JLS2 6.8.1).
2544:             */
2545:            private void verifyStringIsConventionalPackageName(String s,
2546:                    Location loc) {
2547:                if (!Character.isLowerCase(s.charAt(0))) {
2548:                    this 
2549:                            .warning(
2550:                                    "UPN",
2551:                                    "Package name \""
2552:                                            + s
2553:                                            + "\" does not begin with a lower-case letter (see JLS2 6.8.1)",
2554:                                    loc);
2555:                    return;
2556:                }
2557:
2558:                for (int i = 0; i < s.length(); ++i) {
2559:                    char c = s.charAt(i);
2560:                    if (!Character.isLowerCase(c) && c != '_' && c != '.') {
2561:                        this .warning("PPN", "Poorly chosen package name \"" + s
2562:                                + "\" contains bad character '" + c + "'", loc);
2563:                        return;
2564:                    }
2565:                }
2566:            }
2567:
2568:            /**
2569:             * Issue a warning if the given identifier does not comply with the class and interface type
2570:             * naming conventions (JLS2 6.8.2).
2571:             */
2572:            private void verifyIdentifierIsConventionalClassOrInterfaceName(
2573:                    String id, Location loc) {
2574:                if (!Character.isUpperCase(id.charAt(0))) {
2575:                    this 
2576:                            .warning(
2577:                                    "UCOIN1",
2578:                                    "Class or interface name \""
2579:                                            + id
2580:                                            + "\" does not begin with an upper-case letter (see JLS2 6.8.2)",
2581:                                    loc);
2582:                    return;
2583:                }
2584:                for (int i = 0; i < id.length(); ++i) {
2585:                    char c = id.charAt(i);
2586:                    if (!Character.isLetter(c) && !Character.isDigit(c)) {
2587:                        this .warning("UCOIN", "Class or interface name \"" + id
2588:                                + "\" contains unconventional character \"" + c
2589:                                + "\" (see JLS2 6.8.2)", loc);
2590:                        return;
2591:                    }
2592:                }
2593:            }
2594:
2595:            /**
2596:             * Issue a warning if the given identifier does not comply with the method naming conventions
2597:             * (JLS2 6.8.3).
2598:             */
2599:            private void verifyIdentifierIsConventionalMethodName(String id,
2600:                    Location loc) {
2601:                if (!Character.isLowerCase(id.charAt(0))) {
2602:                    this 
2603:                            .warning(
2604:                                    "UMN1",
2605:                                    "Method name \""
2606:                                            + id
2607:                                            + "\" does not begin with a lower-case letter (see JLS2 6.8.3)",
2608:                                    loc);
2609:                    return;
2610:                }
2611:                for (int i = 0; i < id.length(); ++i) {
2612:                    char c = id.charAt(i);
2613:                    if (!Character.isLetter(c) && !Character.isDigit(c)) {
2614:                        this .warning("UMN", "Method name \"" + id
2615:                                + "\" contains unconventional character \"" + c
2616:                                + "\" (see JLS2 6.8.3)", loc);
2617:                        return;
2618:                    }
2619:                }
2620:            }
2621:
2622:            /**
2623:             * Issue a warning if the given identifier does not comply with the field naming conventions
2624:             * (JLS2 6.8.4) and constant naming conventions (JLS2 6.8.5).
2625:             */
2626:            private void verifyIdentifierIsConventionalFieldName(String id,
2627:                    Location loc) {
2628:
2629:                // In practice, a field is not always a constant iff it is static-final. So let's
2630:                // always tolerate both field and constant names.
2631:
2632:                if (Character.isUpperCase(id.charAt(0))) {
2633:                    for (int i = 0; i < id.length(); ++i) {
2634:                        char c = id.charAt(i);
2635:                        if (!Character.isUpperCase(c) && !Character.isDigit(c)
2636:                                && c != '_') {
2637:                            this .warning("UCN", "Constant name \"" + id
2638:                                    + "\" contains unconventional character \""
2639:                                    + c + "\" (see JLS2 6.8.5)", loc);
2640:                            return;
2641:                        }
2642:                    }
2643:                } else if (Character.isLowerCase(id.charAt(0))) {
2644:                    for (int i = 0; i < id.length(); ++i) {
2645:                        char c = id.charAt(i);
2646:                        if (!Character.isLetter(c) && !Character.isDigit(c)) {
2647:                            this .warning("UFN", "Field name \"" + id
2648:                                    + "\" contains unconventional character \""
2649:                                    + c + "\" (see JLS2 6.8.4)", loc);
2650:                            return;
2651:                        }
2652:                    }
2653:                } else {
2654:                    this 
2655:                            .warning(
2656:                                    "UFN1",
2657:                                    "\""
2658:                                            + id
2659:                                            + "\" is neither a conventional field name (JLS2 6.8.4) nor a conventional constant name (JLS2 6.8.5)",
2660:                                    loc);
2661:                }
2662:            }
2663:
2664:            /**
2665:             * Issue a warning if the given identifier does not comply with the local variable and
2666:             * parameter naming conventions (JLS2 6.8.6).
2667:             */
2668:            private void verifyIdentifierIsConventionalLocalVariableOrParameterName(
2669:                    String id, Location loc) {
2670:                if (!Character.isLowerCase(id.charAt(0))) {
2671:                    this 
2672:                            .warning(
2673:                                    "ULVN1",
2674:                                    "Local variable name \""
2675:                                            + id
2676:                                            + "\" does not begin with a lower-case letter (see JLS2 6.8.6)",
2677:                                    loc);
2678:                    return;
2679:                }
2680:                for (int i = 0; i < id.length(); ++i) {
2681:                    char c = id.charAt(i);
2682:                    if (!Character.isLetter(c) && !Character.isDigit(c)) {
2683:                        this .warning("ULVN", "Local variable name \"" + id
2684:                                + "\" contains unconventional character \"" + c
2685:                                + "\" (see JLS2 6.8.6)", loc);
2686:                        return;
2687:                    }
2688:                }
2689:            }
2690:
2691:            /**
2692:             * By default, warnings are discarded, but an application my install a
2693:             * {@link WarningHandler}.
2694:             * <p>
2695:             * Notice that there is no <code>Parser.setErrorHandler()</code> method, but parse errors
2696:             * always throw a {@link ParseException}. The reason being is that there is no reasonable
2697:             * way to recover from parse errors and continue parsing, so there is no need to install
2698:             * a custom parse error handler.
2699:             *
2700:             * @param optionalWarningHandler <code>null</code> to indicate that no warnings be issued
2701:             */
2702:            public void setWarningHandler(WarningHandler optionalWarningHandler) {
2703:                this .optionalWarningHandler = optionalWarningHandler;
2704:            }
2705:
2706:            // Used for elaborate warning handling.
2707:            private WarningHandler optionalWarningHandler = null;
2708:
2709:            /**
2710:             * Issues a warning with the given message and location and returns. This is done through
2711:             * a {@link WarningHandler} that was installed through
2712:             * {@link #setWarningHandler(WarningHandler)}.
2713:             * <p>
2714:             * The <code>handle</code> argument qulifies the warning and is typically used by
2715:             * the {@link WarningHandler} to suppress individual warnings.
2716:             */
2717:            private void warning(String handle, String message,
2718:                    Location optionalLocation) {
2719:                if (this .optionalWarningHandler != null)
2720:                    this .optionalWarningHandler.handleWarning(handle, message,
2721:                            optionalLocation);
2722:            }
2723:
2724:            /**
2725:             * An exception that reflects an error during parsing.
2726:             *
2727:             * This exception is associated with a particular {@link Location
2728:             * Location} in the source code.
2729:             */
2730:            public static class ParseException extends Scanner.LocatedException {
2731:                ParseException(String message, Location location) {
2732:                    super (message, location);
2733:                }
2734:            }
2735:
2736:            /**
2737:             * Convenience method for throwing a ParseException.
2738:             */
2739:            protected final void throwParseException(String message)
2740:                    throws ParseException {
2741:                throw new ParseException(message, this .location());
2742:            }
2743:
2744:            private static String join(String[] sa, String separator) {
2745:                if (sa == null)
2746:                    return ("(null)");
2747:                if (sa.length == 0)
2748:                    return ("(zero length array)");
2749:                StringBuffer sb = new StringBuffer(sa[0]);
2750:                for (int i = 1; i < sa.length; ++i) {
2751:                    sb.append(separator).append(sa[i]);
2752:                }
2753:                return sb.toString();
2754:            }
2755:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.