001 /* Copyright 2000, 2001, Compaq Computer Corporation */ 002 003 package javafe.parser; 004 005 import javafe.ast.*; 006 import javafe.util.StackVector; 007 import javafe.util.Location; 008 import javafe.util.ErrorSet; 009 import javafe.Tool; 010 011 /** 012 * <code>Parse</code> objects parse Java statements, creating AST 013 * structures for the parsed input using the static 014 * <code>make*()</code> methods of the classes in the 015 * <code>javafe.ast</code> package. 016 * 017 * <p> The concrete grammar for statements is as follows: 018 * <pre> 019 * Statement: 020 * ';' 021 * | (Modifier | ModifierPragma)* ClassDeclaration 022 * | (Modifier | ModifierPragma)* Type { Idn [ '=' InitExpr ] },+ ';' 023 * | Idn ':' Stmt 024 * | Expr ';' 025 * | '{' BlockStmt* '}' 026 * // In an assert, BoolExpr must be of type boolean, NonVoidExpr must 027 * // not be of type void 028 * | 'assert' BoolExpr [ ':' NonVoidExpr ] ';' 029 * | 'break' [ Idn ] ';' 030 * | 'continue' [ Idn ] ';' 031 * | 'return' [ Expr ] ';' 032 * | 'throw' Expr ';' 033 * | 'if' '(' Expr ')' Stmt [ 'else' Stmt ] 034 * | 'do' Stmt 'while' '(' Expr ')' ';' 035 * | 'while' '(' Expr ')' Stmt 036 * | 'for' '(' [ VDeclInit | StmtExpr,* ] ';' Expr ';' StmtExpr,* ')' Stmt 037 * | 'switch' '(' Expr ')' 038 * '{' { {'case' Expr ':' | 'default:'}* BlockStmt* }* '}' 039 * | 'synchronized' '(' Expr ')' '{' BlockStmt* '}' 040 * | 'try' '{' BlockStmt* '}' { 'catch' '(' VDecl,* ')' '{' BlockStmt* '}' }* 041 * [ 'finally' '{' BlockStmt* '}' ] 042 * | StmtPragma 043 * </pre> 044 * 045 * <p> Currently, there is no error recovery. Upon detection of a 046 * syntax error, all methods in this class throw a {@link 047 * RuntimeException} with a (weak) error message. 048 * 049 * <p> Although the class as a whole is thread-safe, that is, 050 * different threads can be calling methods of different instances of 051 * <code>ParseStmt</code> at the same time, individual instances are 052 * not. 053 * 054 * @see javafe.ast.ASTNode 055 */ 056 057 public abstract class ParseStmt extends ParseExpr 058 { 059 public ParseStmt() { 060 //@ set seqStmt.elementType = \type(Stmt); 061 //@ set seqStmt.owner = this; 062 063 //@ set seqCatchClause.elementType = \type(CatchClause); 064 //@ set seqCatchClause.owner = this; 065 } 066 067 /** 068 * Internal working storage for many <code>ParseStmt</code> 069 * functions. 070 */ 071 //@ invariant seqStmt.elementType == \type(Stmt); 072 //@ invariant seqStmt.owner == this; 073 protected final /*@ non_null @*/ StackVector seqStmt 074 = new StackVector(); 075 076 //* Internal working storage for parseCatches function. 077 //@ invariant seqCatchClause.elementType == \type(CatchClause); 078 //@ invariant seqCatchClause.owner == this; 079 protected final /*@ non_null @*/ StackVector seqCatchClause 080 = new StackVector(); 081 082 /** 083 * Parse a type declaration stating at the class/interface 084 * keyword. A declaration of this method is needed because class 085 * declarations can be in statements. However, the body (and more 086 * documentation) lives in Parse.java. 087 */ 088 //@ requires l != null && l.m_in != null; 089 //@ requires loc != Location.NULL; 090 //@ modifies l.ttype; 091 //@ ensures \result != null; 092 //@ ensures \old(l.ttype)==TagConstants.CLASS ==> \result instanceof ClassDecl; 093 abstract TypeDecl parseTypeDeclTail(Lex l, boolean specOnly, int loc, 094 int modifiers, 095 ModifierPragmaVec modifierPragmas); 096 097 /** 098 * Method for parsing a <code>Stmt</code>. 099 * 100 * <p> Effects: Parses a single <code>Stmt</code> according to the 101 * grammar at the top of this file, <em>except</em> that it does 102 * not accept variable-declaration statements. If no syntax 103 * errors are encountered, it adds one or more <code>Stmt</code> 104 * to <code>seqStmt</code>, leaving <code>l</code> at the token 105 * just after the trailing <code>}</code> of the statement. More 106 * than one statement is added only in the case of variable 107 * declarations that declare more than one variable. 108 */ 109 //@ requires l != null && l.m_in != null; 110 //@ ensures \result != null; 111 public Stmt parseStatement(Lex l) { 112 if (l.ttype == TagConstants.LBRACE) // As an optimization, handle specially 113 return parseBlock(l, false); 114 else { 115 seqStmt.push(); 116 int loc = l.startingLoc; 117 addStmt(l); 118 Stmt result = (Stmt)seqStmt.elementAt(0); 119 if (seqStmt.size() != 1 || result instanceof VarDeclStmt) { 120 fail(loc, 121 "Variable declarations are not legal in this context."); 122 } 123 if (result instanceof StmtPragma) { 124 fail(loc, 125 "Statement pragmas are not legal in this context."); 126 } 127 128 seqStmt.pop(); 129 return result; 130 } 131 } 132 133 /** 134 * Internal method for parsing a <code>Stmt</code>. 135 * 136 * <p> Effects: Parses a single <code>Stmt</code> according to the 137 * grammar at the top of this file. If no syntax errors are 138 * encountered, it adds one or more <code>Stmt</code> to 139 * <code>seqStmt</code>, leaving <code>l</code> at the token just 140 * after the trailing <code>}</code> of the statement. More than 141 * one statement is added only in the case of variable 142 * declarations that declare more than one variable. 143 */ 144 //@ requires l != null && l.m_in != null; 145 //-@ modifies seqStmt.elementCount, seqStmt.currentStackBottom; 146 /*@ ensures (seqStmt.elementCount - seqStmt.currentStackBottom) > 147 (\old(seqStmt.elementCount) - \old(seqStmt.currentStackBottom)); @*/ 148 protected void addStmt(Lex l) { 149 int ttype = l.ttype; 150 151 // Stmt ::= ';' 152 if (ttype == TagConstants.SEMICOLON) { 153 int loc = l.startingLoc; 154 l.getNextToken(); // Discard ';' 155 seqStmt.addElement( SkipStmt.make(loc) ); 156 return; 157 } 158 159 // Stmt ::= Idn ':' Stmt 160 // | Idn { '[' ']' }* { Idn ['=' InitExpr] },+ 161 // | Expr ';' 162 if (ttype == TagConstants.IDENT) { 163 // FIXME @ assert !l.toString().equals("assert"); 164 Expr e = parseExpression(l); 165 if (e.getTag() == TagConstants.AMBIGUOUSVARIABLEACCESS) { 166 Name n = ((AmbiguousVariableAccess)e).name; 167 168 // Check to see if we have a labeled expr... 169 if (l.ttype == TagConstants.COLON) { 170 l.getNextToken(); // Discard ':' 171 if (n.size() != 1) 172 fail(l.startingLoc, "Can't have qualified name in this context"); 173 Identifier id = n.identifierAt(0); 174 int locId = n.locIdAt(0); 175 seqStmt.addElement( LabelStmt.make(id, parseStatement(l), locId) ); 176 return; 177 } 178 179 // Assume we have a variable declaration 180 // first, look for modifiers on type name 181 TypeModifierPragmaVec tmodifiers = null; 182 tmodifiers = parseTypeModifierPragmas(l); 183 Type basetype = TypeName.make(tmodifiers, n); 184 185 basetype = parseBracketPairs(l, basetype); 186 addVarDeclStmts(l, Modifiers.NONE, null, basetype); 187 expect(l, TagConstants.SEMICOLON); 188 return; 189 } else { 190 expect(l, TagConstants.SEMICOLON); 191 // TODO: make sure e is a statement expr 192 seqStmt.addElement( EvalStmt.make(e) ); 193 return; 194 } 195 } 196 197 // Stmt ::= '{' ... '}' (that is, a Block) 198 if (ttype == TagConstants.LBRACE) { 199 seqStmt.addElement( parseBlock(l, false) ); 200 return; 201 } 202 203 // Stmt ::= <keyword> ... 204 int keywordloc = l.startingLoc; 205 switch (ttype) { 206 case TagConstants.ASSERT: { // 'assert' BoolExpr [ ':' NonVoidExpr ] ';' 207 208 int loc = l.startingLoc; 209 l.getNextToken(); // Discard the keyword 210 Expr predicate = parseExpression(l); 211 Expr label = null; 212 if (l.ttype == TagConstants.COLON) { 213 l.getNextToken(); 214 label = parseExpression(l); 215 } 216 expect(l, TagConstants.SEMICOLON); 217 // Only process if assert *is* a keyword. 218 if (Tool.options != null && !Tool.options.assertIsKeyword) { 219 ErrorSet.error(loc, "Java keyword \"assert\" is only supported if the" + 220 " -source 1.4 option is provided."); 221 } else 222 seqStmt.addElement(AssertStmt.make(predicate, label, keywordloc)); 223 return; 224 } 225 226 case TagConstants.BREAK: // 'break' [ Idn ] ';' 227 case TagConstants.CONTINUE: { // 'continue' [ Idn ] ';' 228 l.getNextToken(); // Discard the keyword 229 Identifier label = null; 230 if (l.ttype == TagConstants.IDENT) { 231 label = l.identifierVal; 232 l.getNextToken(); // Discard IDENT 233 } 234 expect(l, TagConstants.SEMICOLON); 235 seqStmt.addElement(ttype == TagConstants.BREAK ? 236 (Stmt)BreakStmt.make(label, keywordloc) 237 : (Stmt)ContinueStmt.make(label, keywordloc)); 238 return; 239 } 240 241 case TagConstants.RETURN: // 'return' Expr ';' 242 l.getNextToken(); // Discard the keyword 243 if (l.ttype == TagConstants.SEMICOLON) { 244 l.getNextToken(); // Discard ';' 245 seqStmt.addElement( ReturnStmt.make(null, keywordloc) ); 246 } else { 247 Expr expr = parseExpression(l); 248 expect(l, TagConstants.SEMICOLON); 249 seqStmt.addElement(ReturnStmt.make(expr, keywordloc)); 250 } 251 return; 252 253 case TagConstants.THROW: { // 'throw' Expr ';' 254 l.getNextToken(); // Discard the keyword 255 Expr expr = parseExpression(l); 256 expect(l, TagConstants.SEMICOLON); 257 seqStmt.addElement(ThrowStmt.make(expr, keywordloc)); 258 return; 259 } 260 261 case TagConstants.IF: { // 'if' '(' Expr ')' Stmt [ 'else' Stmt ] 262 l.getNextToken(); // Discard the keyword 263 expect(l, TagConstants.LPAREN); 264 Expr test = parseExpression(l); 265 expect(l, TagConstants.RPAREN); 266 Stmt consequence = parseStatement(l); 267 Stmt alternative; 268 if (l.ttype == TagConstants.ELSE) { 269 l.getNextToken(); // Discard 'else' 270 alternative = parseStatement(l); 271 } else 272 // set the location of the implicit Skip to be that of the If 273 alternative = SkipStmt.make(keywordloc); 274 seqStmt.addElement(IfStmt.make(test, consequence, alternative, 275 keywordloc)); 276 return; 277 } 278 279 case TagConstants.DO: { // 'do' Stmt 'while' '(' Expr ')' ';' 280 l.getNextToken(); // Discard the keyword 281 Stmt body = parseStatement(l); 282 expect(l, TagConstants.WHILE); 283 expect(l, TagConstants.LPAREN); 284 Expr test = parseExpression(l); 285 expect(l, TagConstants.RPAREN); 286 expect(l, TagConstants.SEMICOLON); 287 seqStmt.addElement( DoStmt.make(test, body, keywordloc) ); 288 return; 289 } 290 291 case TagConstants.WHILE: { // 'while' '(' Expr ')' Stmt 292 l.getNextToken(); // Discard the keyword 293 int locGuardOpenParen = l.startingLoc; 294 expect(l, TagConstants.LPAREN); 295 Expr test = parseExpression(l); 296 expect(l, TagConstants.RPAREN); 297 Stmt body = parseStatement(l); 298 seqStmt.addElement( WhileStmt.make(test, body, keywordloc, 299 locGuardOpenParen) ); 300 return; 301 } 302 303 case TagConstants.FOR: { 304 l.getNextToken(); // Discard the keyword 305 seqStmt.addElement( parseForStmt(l, keywordloc) ); 306 return; 307 } 308 309 case TagConstants.SWITCH: { 310 l.getNextToken(); // Discard the keyword 311 seqStmt.addElement( parseSwitchStmt(l, keywordloc) ); 312 return; 313 } 314 315 case TagConstants.SYNCHRONIZED: { // 'synchronized' '(' Expr ')' '{' BlockStmt* '}' 316 l.getNextToken(); // Discard the keyword 317 int locOpenParen = l.startingLoc; 318 expect(l, TagConstants.LPAREN); 319 Expr value = parseExpression(l); 320 expect(l, TagConstants.RPAREN); 321 BlockStmt body = parseBlock(l, false); 322 seqStmt.addElement( SynchronizeStmt.make(value, body, keywordloc, 323 locOpenParen)); 324 return; 325 } 326 327 case TagConstants.TRY: { //'try' '{' BlockStmt* '}' Catches ['finally' '{'BlockStmt*'}'] 328 l.getNextToken(); // Discard the keyword 329 int openloc = l.startingLoc; 330 Stmt body = parseBlock(l, false); 331 332 CatchClauseVec catches = parseCatches(l); 333 334 if (l.ttype == TagConstants.FINALLY) { 335 int finloc = l.startingLoc; 336 l.getNextToken(); // Discard 'finally' 337 Stmt fbody = parseBlock(l, false); 338 if (catches != null) { 339 Stmt s = TryCatchStmt.make(body, catches, keywordloc); 340 seqStmt.addElement( TryFinallyStmt.make(s, fbody, keywordloc, 341 finloc) ); 342 } else seqStmt.addElement( TryFinallyStmt.make(body, fbody, 343 keywordloc, finloc) ); 344 return; 345 } else { 346 if (catches == null) 347 fail(l.startingLoc, "Missing handlers in try statement"); 348 seqStmt.addElement( TryCatchStmt.make(body, catches, keywordloc) ); 349 return; 350 } 351 } 352 } 353 354 // Stmt ::= ClassDecl | VarDeclInit (Except those starting with IDENT) 355 { 356 int modifiers = parseModifiers(l); 357 ModifierPragmaVec pmodifiers = this.modifierPragmas; 358 359 // This is rather a hack, because some pragmas that are allowed 360 // are not statement pragmas (because they are indistinguishable 361 // from other pragmas). 362 if (l.ttype == TagConstants.TYPEDECLELEMPRAGMA) { 363 do { 364 TypeDeclElemPragma tdp = (TypeDeclElemPragma)l.auxVal; 365 tdp.decorate(pmodifiers); 366 FieldDecl fd = l.pragmaParser.isPragmaDecl(l); 367 if (modifiers != Modifiers.NONE) { 368 ErrorSet.caution(tdp.getStartLoc(), 369 "Misplaced Java modifiers prior to this point"); 370 } 371 if (fd != null) { 372 LocalVarDecl d 373 = LocalVarDecl.make(fd.modifiers, fd.pmodifiers, 374 fd.id, fd.type, fd.locId, fd.init, fd.locAssignOp); 375 seqStmt.addElement( VarDeclStmt.make(d) ); 376 l.getNextToken(); 377 // There might be more than one variable declared in 378 // the one declaration. We could simply let the 379 // parser handle it by returning here, but then we 380 // lose the pmodifiers information up above. 381 if (l.ttype == TagConstants.TYPEDECLELEMPRAGMA) 382 continue; 383 break; 384 } else { 385 l.getNextToken(); 386 break; 387 } 388 } while(true); 389 return; 390 } else if (l.ttype == TagConstants.CLASS) { 391 ClassDecl cd = (ClassDecl)parseTypeDeclTail(l, false, keywordloc, 392 modifiers, pmodifiers); 393 seqStmt.addElement(ClassDeclStmt.make(cd)); 394 return; 395 } else if (modifiers != Modifiers.NONE || pmodifiers != null || 396 isPrimitiveKeywordTag(ttype)) { 397 addVarDeclStmts(l, modifiers, pmodifiers, parseType(l)); 398 expect(l, TagConstants.SEMICOLON); 399 return; 400 } 401 } 402 403 // Check for StmtPragma 404 if( ttype == TagConstants.STMTPRAGMA ) { 405 StmtPragma pragma = (StmtPragma)l.auxVal; 406 seqStmt.addElement( (Stmt)pragma ); 407 l.getNextToken(); 408 return; 409 } 410 411 // Assume it's a statement expression... 412 Expr e = parseExpression(l); 413 if (! isStatementExpression(e)) 414 fail(l.startingLoc, "Statement expression expected"); 415 seqStmt.addElement( EvalStmt.make(e) ); 416 expect(l, TagConstants.SEMICOLON); 417 return; 418 } 419 420 /** 421 * Method for parsing a <code>ConstructorBody</code>. 422 * 423 * <p> Effects: Parses the following grammar: 424 * <pre> 425 * Block ::= 426 * '{' [ { 'this' | 'super' ] '(' ArgumentList ')' ] { VarDeclInit | Stmt }* '}' 427 * </pre> 428 * 429 * <p> If no syntax errors are encountered, it returns a parse 430 * tree for the parsed input, leaving <code>l</code> at the token 431 * just after the trailing <code>}</code> of the statement. 432 */ 433 //@ requires l != null && l.m_in != null; 434 //@ ensures \result != null; 435 public BlockStmt parseConstructorBody(Lex l) { 436 int openloc = l.startingLoc; 437 expect(l, TagConstants.LBRACE); 438 seqStmt.push(); 439 440 // Handle leading constructor invocation; 441 // make one up if missing and the class being declared in not object 442 443 if (((l.ttype == TagConstants.THIS || l.ttype == TagConstants.SUPER) 444 && l.lookahead(1) == TagConstants.LPAREN)) { 445 boolean superCall = (l.ttype == TagConstants.SUPER); 446 int loc = l.startingLoc; 447 l.getNextToken(); 448 // Next, parse the argument list, which should start with an open 449 // parenthesis. As a check that "parseArgumentList" doesn't accept 450 // any other first token than an open parenthesis, the tag of the next 451 // token is stored in "tagShouldBeLParen", and it is assert that 452 // *if* "parseArgumentList" returns normally, then the tag recorded 453 // is indeed an open parenthesis. 454 int locOpenParen = l.startingLoc; 455 int tagShouldBeLParen = l.ttype; 456 ExprVec args = parseArgumentList(l); 457 expect( l, TagConstants.SEMICOLON ); 458 seqStmt.addElement( ConstructorInvocation.make( superCall, 459 null, Location.NULL, 460 loc, locOpenParen, 461 args ) ); 462 } else { 463 // Look for Primary '.' 'super' '(' ArgumentList ')' ';' 464 boolean foundDotSuper = false; 465 for (int i = 0; ; i++) { 466 switch (l.lookahead(i)) { 467 case TagConstants.EOF: 468 break; 469 case TagConstants.LBRACE: 470 for(int braceDepth = 1; 0 < braceDepth; i++) { 471 if (l.lookahead(i) == TagConstants.RBRACE) braceDepth--; 472 } 473 continue; 474 case TagConstants.SEMICOLON: 475 case TagConstants.RBRACE: 476 break; 477 case TagConstants.FIELD: 478 if (l.lookahead(i+1) == TagConstants.SUPER) { 479 foundDotSuper = true; 480 break; 481 } else continue; 482 default: continue; 483 } 484 break; 485 } 486 if (foundDotSuper) { 487 int loc = l.startingLoc; 488 Expr e = parsePrimaryExpression(l); 489 int locDot = l.startingLoc; 490 expect(l, TagConstants.FIELD); 491 expect(l, TagConstants.SUPER); 492 int locOpenParen = l.startingLoc; 493 ExprVec args = parseArgumentList(l); 494 expect(l, TagConstants.SEMICOLON); 495 seqStmt.addElement(ConstructorInvocation.make(true, e, locDot, 496 loc, locOpenParen, 497 args)); 498 } 499 } 500 501 // No explicit constructor invocation. We do not know if this 502 // class is java.lang.Object, so we cannot add a constructor 503 // invocation here; we will do it in type checking. 504 505 // Handle rest of body 506 { 507 int ttype = l.ttype; 508 while (ttype != TagConstants.RBRACE && ttype != TagConstants.EOF) { 509 addStmt(l); 510 ttype = l.ttype; 511 } 512 if (ttype == TagConstants.EOF) 513 fail(l.startingLoc, "End of input in block"); 514 } 515 StmtVec body = StmtVec.popFromStackVector(seqStmt); 516 int closeloc = l.startingLoc; 517 l.getNextToken(); // Discard '}' 518 return BlockStmt.make(body, openloc, closeloc); 519 } 520 521 /** 522 * Method for parsing a <code>Block</code>. 523 * 524 * <p> Effects: Parses the following grammar: 525 * <pre> 526 * Block ::= 527 * '{' { VarDeclInit | Stmt }* '}' 528 * </pre> 529 * 530 * <p> If no syntax errors are encountered, it returns a parse 531 * tree for the parsed input, leaving <code>l</code> at the token 532 * just after the trailing <code>}</code> of the statement. 533 */ 534 //@ requires l != null && l.m_in != null; 535 //@ ensures \result != null; 536 public BlockStmt parseBlock(Lex l, boolean specOnly) { 537 int openloc = l.startingLoc; 538 expect(l, TagConstants.LBRACE); 539 seqStmt.push(); 540 { 541 int ttype = l.ttype; 542 while (ttype != TagConstants.RBRACE && ttype != TagConstants.EOF) { 543 if (!specOnly) 544 addStmt(l); 545 else { 546 if (ttype==TagConstants.LBRACE) 547 parseBlock(l, true); 548 else 549 l.getNextToken(); 550 } 551 ttype = l.ttype; 552 } 553 if (ttype == TagConstants.EOF) 554 fail(l.startingLoc, "End of input in block"); 555 } 556 StmtVec body = StmtVec.popFromStackVector(seqStmt); 557 int closeloc = l.startingLoc; 558 l.getNextToken(); // Discard '}' 559 return specOnly ? null : BlockStmt.make(body, openloc, closeloc); 560 } 561 562 /** 563 * Internal method for parsing a switch statement. 564 * 565 * <p> Effects: Parses the following grammar: 566 * <pre> 567 * ForStmtRemainder ::= 568 * '(' [VDeclInit | StmtExpr,* ] ';' Expr ';' StmtExpr,* ')' Stmt 569 * </pre> 570 * 571 * <p> Note that it assumes the leading <code>for</code> has 572 * already been parsed; <code>keywordloc</code> is the location 573 * assumed for the <code>for</code> token. 574 * 575 * <p> If no syntax errors are encountered, it returns a parse 576 * tree for the parsed input, leaving <code>l</code> at the token 577 * just after the trailing <code>}</code> of the statement. 578 */ 579 //@ requires l != null && l.m_in != null; 580 //@ requires keywordloc != Location.NULL; 581 //@ ensures \result != null; 582 private ForStmt parseForStmt(Lex l, int keywordloc) { 583 int parenloc = l.startingLoc; 584 expect(l, TagConstants.LPAREN); 585 586 // Parse ForInit ::= [VDeclInit | StmtExpr,* ] ';' 587 StmtVec forInit; 588 int locFirstSemi; 589 { // Parse ForInit part 590 seqStmt.push(); 591 592 Type basetype = null; 593 int modifiers = Modifiers.NONE; 594 ModifierPragmaVec pmodifiers = null; 595 switch (l.ttype) { 596 case TagConstants.SEMICOLON: 597 break; 598 599 default: 600 modifiers = parseModifiers(l); 601 pmodifiers = this.modifierPragmas; 602 603 if (modifiers != Modifiers.NONE || pmodifiers != null || 604 isPrimitiveKeywordTag(l.ttype)) { 605 basetype = parseType(l); 606 break; 607 } 608 609 Expr e = parseExpression(l); 610 if (e.getTag() == TagConstants.AMBIGUOUSVARIABLEACCESS) { 611 // Assume a var declaration 612 // look for type modifier pragmas 613 TypeModifierPragmaVec tmodifiers = null; 614 tmodifiers = parseTypeModifierPragmas(l); 615 basetype = TypeName.make(tmodifiers, ((AmbiguousVariableAccess)e).name); 616 617 break; 618 } else { 619 for(;;) { 620 if (! isStatementExpression(e)) 621 fail(l.startingLoc, "Statement expression expected"); 622 seqStmt.addElement( EvalStmt.make(e) ); 623 if (l.ttype != TagConstants.COMMA) break; 624 l.getNextToken(); // Discard the COMMA 625 e = parseExpression(l); 626 } 627 } 628 } 629 630 if (basetype != null) { 631 basetype = parseBracketPairs(l, basetype); 632 addVarDeclStmts(l, modifiers, pmodifiers, basetype); 633 } 634 635 locFirstSemi = l.startingLoc; 636 expect(l, TagConstants.SEMICOLON); 637 forInit = StmtVec.popFromStackVector(seqStmt); 638 } 639 640 // Parse <pre> Test ::= [ Expr ] ';' </pre> 641 Expr test; 642 if (l.ttype != TagConstants.SEMICOLON) 643 test = parseExpression(l); 644 else test = LiteralExpr.make(TagConstants.BOOLEANLIT, 645 Boolean.TRUE, 646 l.startingLoc ); 647 expect(l, TagConstants.SEMICOLON); 648 649 // Parse <pre> ForUpdate ::= StmtExpr,* ')' </pre> 650 ExprVec forUpdate; 651 { 652 seqExpr.push(); 653 654 if (l.ttype != TagConstants.RPAREN) { 655 for(;;) { 656 Expr e = parseExpression(l); 657 if (! isStatementExpression(e)) 658 fail(l.startingLoc, "Statement expression expected."); 659 seqExpr.addElement(e); 660 if (l.ttype != TagConstants.COMMA) break; 661 l.getNextToken(); // Discard COMMA 662 } 663 } 664 expect(l, TagConstants.RPAREN); 665 forUpdate = ExprVec.popFromStackVector(seqExpr); 666 } 667 668 Stmt body = parseStatement(l); 669 return ForStmt.make(forInit, test, forUpdate, body, keywordloc, 670 locFirstSemi); 671 } 672 673 /** 674 * Internal method for parsing a switch statement. 675 * 676 * <p> Effects: Parses the following grammar: 677 * <pre> 678 * SwitchStmtRemainder ::= 679 * '(' Expr ')' '{' { 'case' Expr ':' | 'default ':' | Stmt }* '}' 680 * </pre> 681 * 682 * <p> Note that it assumes the trailing <code>switch</code> has 683 * already been parsed; <code>keywordLoc</code> is the location 684 * assumed for the <code>switch</code> token. 685 * 686 * <p> If no syntax errors are encountered, it returns a parse 687 * tree for the parsed input, leaving <code>l</code> at the token 688 * just after the trailing <code>}</code> of the statement. 689 */ 690 //@ requires l != null && l.m_in != null; 691 //@ requires keywordloc != Location.NULL; 692 //@ ensures \result != null; 693 private SwitchStmt parseSwitchStmt(Lex l, int keywordloc) { 694 // Read value to be tested 695 expect(l, TagConstants.LPAREN); 696 Expr value = parseExpression(l); 697 expect(l, TagConstants.RPAREN); 698 699 // Read body 700 int openloc = l.startingLoc; 701 expect(l, TagConstants.LBRACE); 702 boolean atStart=true; 703 boolean hasDefault = false; 704 seqStmt.push(); 705 while (l.ttype != TagConstants.RBRACE && l.ttype != TagConstants.EOF) { 706 if (l.ttype == TagConstants.CASE || l.ttype == TagConstants.DEFAULT) { 707 if (l.ttype == TagConstants.DEFAULT) { 708 hasDefault = true; 709 } 710 int loc = l.startingLoc; 711 int ttype = l.ttype; 712 l.getNextToken(); // Discard CASE TagConstants.or DEFAULT 713 Expr e = (ttype == TagConstants.CASE ? parseExpression(l) : null); 714 expect(l, TagConstants.COLON); 715 seqStmt.addElement( SwitchLabel.make(e, loc) ); 716 } 717 else { 718 if (atStart) fail(l.startingLoc,"Switch body must start with a label"); 719 addStmt(l); 720 } 721 atStart = false; 722 } 723 if (l.ttype == TagConstants.EOF) 724 fail(l.startingLoc, "End of input in switch body"); 725 int closeloc = l.startingLoc; 726 l.getNextToken(); // Discard '}' 727 728 if (!hasDefault) { 729 seqStmt.addElement(SwitchLabel.make(null, closeloc)); 730 seqStmt.addElement(BreakStmt.make(null, closeloc)); 731 } 732 StmtVec body = StmtVec.popFromStackVector(seqStmt); 733 return SwitchStmt.make(body, openloc, closeloc, value, keywordloc); 734 } 735 736 /** 737 * Internal routine for parsing zero or more catch clauses. 738 * 739 * <p> Effects: Parses the following grammar: 740 * <pre> Catches ::= { 'catch' '(' [Modifiers] Type Idn ')' Block }* </pre> 741 * 742 * At the start of each iteration (including the first), if the 743 * first token is not <code>catch</code>, it stops trying to 744 * parse, returning the (possibly empty) sequence of catch clauses 745 * parsed already and leaving the token at the first token 746 * following the last catch clause parsed. If the first token is 747 * <code>catch</code>, then it tries to parse a catch clause, 748 * throwing an exception if a syntax error is found. 749 */ 750 //@ requires l != null && l.m_in != null; 751 private CatchClauseVec parseCatches(Lex l) { 752 if (l.ttype != TagConstants.CATCH) return null; 753 seqCatchClause.push(); 754 755 do { 756 int loc = l.startingLoc; 757 l.getNextToken(); // Discard CATCH 758 expect(l, TagConstants.LPAREN); 759 FormalParaDecl arg = parseFormalParaDecl(l); 760 expect(l, TagConstants.RPAREN); 761 seqCatchClause.addElement( CatchClause.make(arg, parseBlock(l,false), 762 loc) ); 763 } while (l.ttype == TagConstants.CATCH); 764 return CatchClauseVec.popFromStackVector(seqCatchClause); 765 } 766 767 /** 768 * Internal routine for parsing variable declarations 769 * <em>after</em> the leading type has been parsed. 770 * 771 * <p>Effects: Parses the following grammar: 772 * <pre> 773 * VarDeclRemainder ::= 774 * { Idn { '[' ']' }* [ '=' VariableInitializer ] },* 775 * </pre> 776 * 777 * <p> Each <code>VarDeclRemainder</code> found is combined with 778 * <code>basetype</code> to create a <code>VarDeclStmt</code> 779 * which is added to the end of <code>seqStmt</code>. 780 * 781 * <p> On entry, it assumes at least one 782 * <code>VarDeclRemainder</code> is available, and throws an 783 * exception if one isn't. At the end of each iteration, it stops 784 * trying to parse if the comma is not present, leaving the token 785 * at the first token following the last 786 * <code>VarDeclRemainder</code> parsed. If a comma is found, 787 * then it tries to parse the next <code>VarDeclRemainder</code>, 788 * throwing an exception if a syntax error is found. 789 */ 790 //@ requires l != null && basetype != null && l.m_in != null; 791 //@ requires basetype.syntax; 792 private void addVarDeclStmts(Lex l, int modifiers, 793 ModifierPragmaVec modifierPragmas, 794 Type basetype) 795 { 796 // make modifierPragmas non-null, so can retroactively extend 797 if( modifierPragmas == null ) 798 modifierPragmas = ModifierPragmaVec.make(); 799 800 for(;;) { 801 // Get identifier and any [] pairs trailing it 802 Identifier id = l.identifierVal; 803 int locId = l.startingLoc; 804 expect(l, TagConstants.IDENT); 805 Type vartype = parseBracketPairs(l, basetype); 806 807 // Get initializer if there is one 808 VarInit init = null; 809 int locAssignOp = Location.NULL; 810 if (l.ttype == TagConstants.ASSIGN) { 811 locAssignOp = l.startingLoc; 812 l.getNextToken(); 813 init = parseVariableInitializer(l, false); 814 } 815 816 LocalVarDecl d 817 = LocalVarDecl.make(modifiers, modifierPragmas, 818 id, vartype, locId, init, locAssignOp); 819 seqStmt.addElement( VarDeclStmt.make(d) ); 820 821 // check if end of declaration 822 823 if(l.ttype == TagConstants.MODIFIERPRAGMA ) { 824 // if modifier pragma, retroactively add to modifierPragmas 825 parseMoreModifierPragmas( l, modifierPragmas ); 826 return; 827 } else if(l.ttype != TagConstants.COMMA ) { 828 // all done - do not swallow following semicolon 829 return; 830 } 831 832 expect( l, TagConstants.COMMA ); 833 /* And go around loop again */ 834 } 835 } 836 837 838 /** 839 * Routine for parsing a single formal parameter declarations. 840 * 841 * <p> Effects: Parses the following grammar: 842 * <pre> FormalParaDecl ::= { [Modifiers] Type Idn ModifierPragma* } </pre> 843 * returning an ASTNode representing the result. Leaves 844 * <code>l</code> pointing to the token just after the 845 * <code>FormalParaDecl</code>. 846 */ 847 //@ requires l != null && l.m_in != null; 848 //@ ensures \result != null; 849 public FormalParaDecl parseFormalParaDecl(Lex l) { 850 int modifiers = parseModifiers(l); 851 ModifierPragmaVec modifierPragmas = this.modifierPragmas; 852 Type paratype = parseType(l); 853 Identifier idn = l.identifierVal; 854 int locId = l.startingLoc; 855 expect(l, TagConstants.IDENT); 856 857 // allow more modifier pragmas 858 modifierPragmas = parseMoreModifierPragmas( l, modifierPragmas ); 859 860 return FormalParaDecl.make(modifiers, modifierPragmas, 861 idn, paratype, locId); 862 } 863 864 /** 865 * @return true iff <code>e</code> is a Java 866 * <code>StatementExpression</code> as defined in the grammar 867 * given in the language spec. 868 */ 869 //@ requires e != null; 870 public static boolean isStatementExpression(Expr e) { 871 switch (e.getTag()) { 872 case TagConstants.ASSIGN: 873 case TagConstants.ASGMUL: case TagConstants.ASGDIV: 874 case TagConstants.ASGREM: 875 case TagConstants.ASGADD: case TagConstants.ASGSUB: 876 case TagConstants.ASGLSHIFT: case TagConstants.ASGRSHIFT: 877 case TagConstants.ASGURSHIFT: 878 case TagConstants.ASGBITAND: 879 case TagConstants.ASGBITOR: case TagConstants.ASGBITXOR: 880 case TagConstants.INC: case TagConstants.DEC: 881 case TagConstants.POSTFIXINC: case TagConstants.POSTFIXDEC: 882 case TagConstants.METHODINVOCATION: 883 case TagConstants.NEWINSTANCEEXPR: 884 return true; 885 default: 886 return true; // TODO return false; 887 } 888 } 889 }