1 /* 2 * Copyright (c) 1999, 2000, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 /* 26 * COMPONENT_NAME: idl.parser 27 * 28 * ORIGINS: 27 29 * 30 * Licensed Materials - Property of IBM 31 * 5639-D57 (C) COPYRIGHT International Business Machines Corp. 1997, 1999 32 * RMI-IIOP v1.0 33 * 34 */ 35 36 package com.sun.tools.corba.se.idl; 37 38 // NOTES: 39 // -D57110<daz> Allow ID pragma directive to be applied to modules and update 40 // feature in accordance to CORBA 2.3. 41 // -D59165<daz> Enable escaped identifiers when processing pragmas. 42 // -f60858.1<daz> Support -corba option, level = 2.2: Accept identifiers that 43 // collide with keywords, in letter but not case, and issue a warning. 44 // -d62023 <daz> support -noWarn option; suppress inappropriate warnings when 45 // parsing IBM-specific pragmas (#meta <interface_name> abstract). 46 47 import java.io.File; 48 import java.io.FileNotFoundException; 49 import java.io.IOException; 50 import java.math.BigInteger; 51 import java.util.Enumeration; 52 import java.util.Hashtable; 53 import java.util.Stack; 54 import java.util.Vector; 55 56 import com.sun.tools.corba.se.idl.RepositoryID; 57 58 import com.sun.tools.corba.se.idl.constExpr.*; 59 60 /** 61 * This class should be extended if new pragmas are desired. If the 62 * preprocessor encounters a pragma name which it doesn't recognize 63 * (anything other than ID, prefix, or version), it calls the method 64 * otherPragmas. This is the only method which need be overridden. 65 * The Preprocessor base class has a number of utility-like methods 66 * which can be used by the overridden otherPragmas method. 67 **/ 68 public class Preprocessor 69 { 70 /** 71 * Public zero-argument constructor. 72 **/ 73 Preprocessor () 74 { 75 } // ctor 76 77 /** 78 * 79 **/ 80 void init (Parser p) 81 { 82 parser = p; 83 symbols = p.symbols; 84 macros = p.macros; 85 } // init 86 87 /** 88 * 89 **/ 90 protected Object clone () 91 { 92 return new Preprocessor (); 93 } // clone 94 95 /** 96 * 97 **/ 98 Token process (Token t) throws IOException, ParseException 99 { 100 token = t; 101 scanner = parser.scanner; 102 // <f46082.40> Deactivate escaped identifier processing in Scanner while 103 // preprocessing. 104 //scanner.underscoreOK = true; 105 scanner.escapedOK = false; 106 try 107 { 108 switch (token.type) 109 { 110 case Token.Include: 111 include (); 112 break; 113 case Token.If: 114 ifClause (); 115 break; 116 case Token.Ifdef: 117 ifdef (false); 118 break; 119 case Token.Ifndef: 120 ifdef (true); 121 break; 122 case Token.Else: 123 if (alreadyProcessedABranch.empty ()) 124 throw ParseException.elseNoIf (scanner); 125 else if (((Boolean)alreadyProcessedABranch.peek ()).booleanValue ()) 126 skipToEndif (); 127 else 128 { 129 alreadyProcessedABranch.pop (); 130 alreadyProcessedABranch.push (new Boolean (true)); 131 token = scanner.getToken (); 132 } 133 break; 134 case Token.Elif: 135 elif (); 136 break; 137 case Token.Endif: 138 if (alreadyProcessedABranch.empty ()) 139 throw ParseException.endNoIf (scanner); 140 else 141 { 142 alreadyProcessedABranch.pop (); 143 token = scanner.getToken (); 144 break; 145 } 146 case Token.Define: 147 define (); 148 break; 149 case Token.Undef: 150 undefine (); 151 break; 152 case Token.Pragma: 153 pragma (); 154 break; 155 case Token.Unknown: 156 if (!parser.noWarn) 157 ParseException.warning (scanner, Util.getMessage ("Preprocessor.unknown", token.name)); 158 case Token.Error: 159 case Token.Line: 160 case Token.Null: 161 // ignore 162 default: 163 scanner.skipLineComment (); 164 token = scanner.getToken (); 165 } 166 } 167 catch (IOException e) 168 { 169 // <f46082.40> Underscore may now precede any identifier, so underscoreOK 170 // is vestigal. The Preprocessor must reset escapedOK so that Scanner 171 // will process escaped identifiers according to specification. 172 //scanner.underscoreOK = false; 173 scanner.escapedOK = true; 174 throw e; 175 } 176 catch (ParseException e) 177 { 178 // <f46082.40> See above. 179 //scanner.underscoreOK = false; 180 scanner.escapedOK = true; 181 throw e; 182 } 183 // <f46082.40> See above. 184 //scanner.underscoreOK = false; 185 scanner.escapedOK = true; 186 return token; 187 } // process 188 189 /** 190 * 191 **/ 192 private void include () throws IOException, ParseException 193 { 194 match (Token.Include); 195 IncludeEntry include = parser.stFactory.includeEntry (parser.currentModule); 196 include.sourceFile (scanner.fileEntry ()); 197 scanner.fileEntry ().addInclude (include); 198 if (token.type == Token.StringLiteral) 199 include2 (include); 200 else if (token.type == Token.LessThan) 201 include3 (include); 202 else 203 { 204 int[] expected = {Token.StringLiteral, Token.LessThan}; 205 throw ParseException.syntaxError (scanner, expected, token.type); 206 } 207 if (parser.currentModule instanceof ModuleEntry) 208 ((ModuleEntry)parser.currentModule).addContained (include); 209 else if (parser.currentModule instanceof InterfaceEntry) 210 ((InterfaceEntry)parser.currentModule).addContained (include); 211 } // include 212 213 /** 214 * 215 **/ 216 private void include2 (IncludeEntry include) throws IOException, ParseException 217 { 218 include.name ('"' + token.name + '"'); 219 include4 (include, token.name); 220 match (Token.StringLiteral); 221 } // include2 222 223 /** 224 * 225 **/ 226 private void include3 (IncludeEntry include) throws IOException, ParseException 227 { 228 if (token.type != Token.LessThan) 229 // match will throw an exception 230 match (Token.LessThan); 231 else 232 { 233 try 234 { 235 String includeFile = getUntil ('>'); 236 token = scanner.getToken (); 237 include.name ('<' + includeFile + '>'); 238 include4 (include, includeFile); 239 match (Token.GreaterThan); 240 } 241 catch (IOException e) 242 { 243 throw ParseException.syntaxError (scanner, ">", "EOF"); 244 } 245 } 246 } // include3 247 248 /** 249 * 250 **/ 251 private void include4 (IncludeEntry include, String filename) throws IOException, ParseException 252 { 253 try 254 { 255 // If the #include is at the global scope, it is treated as 256 // an import statement. If it is within some other scope, it 257 // is treated as a normal #include. 258 boolean includeIsImport = parser.currentModule == parser.topLevelModule; 259 //daz 260 include.absFilename (Util.getAbsolutePath (filename, parser.paths)); 261 scanner.scanIncludedFile (include, getFilename (filename), includeIsImport); 262 } 263 catch (IOException e) 264 { 265 ParseException.generic (scanner, e.toString ()); 266 } 267 } // include4 268 269 /** 270 * 271 **/ 272 private void define () throws IOException, ParseException 273 { 274 match (Token.Define); 275 if (token.equals (Token.Identifier)) 276 { 277 String symbol = scanner.getStringToEOL (); 278 symbols.put (token.name, symbol.trim ()); 279 match (Token.Identifier); 280 } 281 else if (token.equals (Token.MacroIdentifier)) 282 { 283 symbols.put (token.name, '(' + scanner.getStringToEOL () . trim ()); 284 macros.addElement (token.name); 285 match (Token.MacroIdentifier); 286 } 287 else 288 throw ParseException.syntaxError (scanner, Token.Identifier, token.type); 289 } // define 290 291 /** 292 * 293 **/ 294 private void undefine () throws IOException, ParseException 295 { 296 match (Token.Undef); 297 if (token.equals (Token.Identifier)) 298 { 299 symbols.remove (token.name); 300 macros.removeElement (token.name); 301 match (Token.Identifier); 302 } 303 else 304 throw ParseException.syntaxError (scanner, Token.Identifier, token.type); 305 } // undefine 306 307 /** 308 * 309 **/ 310 private void ifClause () throws IOException, ParseException 311 { 312 match (Token.If); 313 constExpr (); 314 } // ifClause 315 316 /** 317 * 318 **/ 319 private void constExpr () throws IOException, ParseException 320 { 321 SymtabEntry dummyEntry = new SymtabEntry (parser.currentModule); 322 dummyEntry.container (parser.currentModule); 323 parser.parsingConditionalExpr = true; 324 Expression boolExpr = booleanConstExpr (dummyEntry); 325 parser.parsingConditionalExpr = false; 326 boolean expr; 327 if (boolExpr.value () instanceof Boolean) 328 expr = ((Boolean)boolExpr.value ()).booleanValue (); 329 else 330 expr = ((Number)boolExpr.value ()).longValue () != 0; 331 alreadyProcessedABranch.push (new Boolean (expr)); 332 if (!expr) 333 skipToEndiforElse (); 334 } // constExpr 335 336 /** 337 * 338 **/ 339 Expression booleanConstExpr (SymtabEntry entry) throws IOException, ParseException 340 { 341 Expression expr = orExpr (null, entry); 342 try 343 { 344 expr.evaluate (); 345 } 346 catch (EvaluationException e) 347 { 348 ParseException.evaluationError (scanner, e.toString ()); 349 } 350 return expr; 351 } // booleanConstExpr 352 353 /** 354 * 355 **/ 356 private Expression orExpr (Expression e, SymtabEntry entry) throws IOException, ParseException 357 { 358 if (e == null) 359 e = andExpr (null, entry); 360 else 361 { 362 BinaryExpr b = (BinaryExpr)e; 363 b.right (andExpr (null, entry)); 364 e.rep (e.rep () + b.right ().rep ()); 365 } 366 if (token.equals (Token.DoubleBar)) 367 { 368 match (token.type); 369 BooleanOr or = parser.exprFactory.booleanOr (e, null); 370 or.rep (e.rep () + " || "); 371 return orExpr (or, entry); 372 } 373 else 374 return e; 375 } // orExpr 376 377 /** 378 * 379 **/ 380 private Expression andExpr (Expression e, SymtabEntry entry) throws IOException, ParseException 381 { 382 if (e == null) 383 e = notExpr (entry); 384 else 385 { 386 BinaryExpr b = (BinaryExpr)e; 387 b.right (notExpr (entry)); 388 e.rep (e.rep () + b.right ().rep ()); 389 } 390 if (token.equals (Token.DoubleAmpersand)) 391 { 392 match (token.type); 393 BooleanAnd and = parser.exprFactory.booleanAnd (e, null); 394 and.rep (e.rep () + " && "); 395 return andExpr (and, entry); 396 } 397 else 398 return e; 399 } // andExpr 400 401 /** 402 * 403 **/ 404 private Expression notExpr (/*boolean alreadySawExclamation, */SymtabEntry entry) throws IOException, ParseException 405 { 406 Expression e; 407 if (token.equals (Token.Exclamation)) 408 { 409 match (Token.Exclamation); 410 e = parser.exprFactory.booleanNot (definedExpr (entry)); 411 e.rep ("!" + ((BooleanNot)e).operand ().rep ()); 412 } 413 else 414 e = definedExpr (entry); 415 return e; 416 } // notExpr 417 418 /** 419 * 420 **/ 421 private Expression definedExpr (SymtabEntry entry) throws IOException, ParseException 422 { 423 if (token.equals (Token.Identifier) && token.name.equals ("defined")) 424 match (Token.Identifier); 425 return equalityExpr (null, entry); 426 } // definedExpr 427 428 /** 429 * 430 **/ 431 private Expression equalityExpr (Expression e, SymtabEntry entry) throws IOException, ParseException 432 { 433 if (e == null) 434 { 435 parser.token = token; // Since parser to parse, give it this token 436 e = parser.constExp (entry); 437 token = parser.token; // Since parser last parsed, get its token 438 } 439 else 440 { 441 BinaryExpr b = (BinaryExpr)e; 442 parser.token = token; // Since parser to parse, give it this token 443 Expression constExpr = parser.constExp (entry); 444 token = parser.token; // Since parser last parsed, get its token 445 b.right (constExpr); 446 e.rep (e.rep () + b.right ().rep ()); 447 } 448 if (token.equals (Token.DoubleEqual)) 449 { 450 match (token.type); 451 Equal eq = parser.exprFactory.equal (e, null); 452 eq.rep (e.rep () + " == "); 453 return equalityExpr (eq, entry); 454 } 455 else if (token.equals (Token.NotEqual)) 456 { 457 match (token.type); 458 NotEqual n = parser.exprFactory.notEqual (e, null); 459 n.rep (e.rep () + " != "); 460 return equalityExpr (n, entry); 461 } 462 else if (token.equals (Token.GreaterThan)) 463 { 464 match (token.type); 465 GreaterThan g = parser.exprFactory.greaterThan (e, null); 466 g.rep (e.rep () + " > "); 467 return equalityExpr (g, entry); 468 } 469 else if (token.equals (Token.GreaterEqual)) 470 { 471 match (token.type); 472 GreaterEqual g = parser.exprFactory.greaterEqual (e, null); 473 g.rep (e.rep () + " >= "); 474 return equalityExpr (g, entry); 475 } 476 else if (token.equals (Token.LessThan)) 477 { 478 match (token.type); 479 LessThan l = parser.exprFactory.lessThan (e, null); 480 l.rep (e.rep () + " < "); 481 return equalityExpr (l, entry); 482 } 483 else if (token.equals (Token.LessEqual)) 484 { 485 match (token.type); 486 LessEqual l = parser.exprFactory.lessEqual (e, null); 487 l.rep (e.rep () + " <= "); 488 return equalityExpr (l, entry); 489 } 490 else 491 return e; 492 } // equalityExpr 493 494 /** 495 * 496 **/ 497 Expression primaryExpr (SymtabEntry entry) throws IOException, ParseException 498 { 499 Expression primary = null; 500 switch (token.type) 501 { 502 case Token.Identifier: 503 // If an identifier gets this far, it means that no 504 // preprocessor variable was defined with that name. 505 // Generate a FALSE boolean expr. 506 //daz primary = parser.exprFactory.terminal ("0", new Long (0)); 507 primary = parser.exprFactory.terminal ("0", BigInteger.valueOf (0)); 508 token = scanner.getToken (); 509 break; 510 case Token.BooleanLiteral: 511 case Token.CharacterLiteral: 512 case Token.IntegerLiteral: 513 case Token.FloatingPointLiteral: 514 case Token.StringLiteral: 515 //daz primary = parser.literal (); 516 primary = parser.literal (entry); 517 token = parser.token; 518 break; 519 case Token.LeftParen: 520 match (Token.LeftParen); 521 primary = booleanConstExpr (entry); 522 match (Token.RightParen); 523 primary.rep ('(' + primary.rep () + ')'); 524 break; 525 default: 526 int[] expected = {Token.Literal, Token.LeftParen}; 527 throw ParseException.syntaxError (scanner, expected, token.type); 528 } 529 return primary; 530 } // primaryExpr 531 532 /** 533 * 534 **/ 535 private void ifDefine (boolean inParens, boolean not) throws IOException, ParseException 536 { 537 if (token.equals (Token.Identifier)) 538 if ((not && symbols.containsKey (token.name)) || (!not && !symbols.containsKey (token.name))) 539 { 540 alreadyProcessedABranch.push (new Boolean (false)); 541 skipToEndiforElse (); 542 } 543 else 544 { 545 alreadyProcessedABranch.push (new Boolean (true)); 546 match (Token.Identifier); 547 if (inParens) 548 match (Token.RightParen); 549 } 550 else 551 throw ParseException.syntaxError (scanner, Token.Identifier, token.type); 552 } // ifDefine 553 554 /** 555 * 556 **/ 557 private void ifdef (boolean not) throws IOException, ParseException 558 { 559 if (not) 560 match (Token.Ifndef); 561 else 562 match (Token.Ifdef); 563 if (token.equals (Token.Identifier)) 564 if ((not && symbols.containsKey (token.name)) || (!not && !symbols.containsKey (token.name))) 565 { 566 alreadyProcessedABranch.push (new Boolean (false)); 567 skipToEndiforElse (); 568 } 569 else 570 { 571 alreadyProcessedABranch.push (new Boolean (true)); 572 match (Token.Identifier); 573 } 574 else 575 throw ParseException.syntaxError (scanner, Token.Identifier, token.type); 576 } // ifdef 577 578 /** 579 * 580 **/ 581 private void elif () throws IOException, ParseException 582 { 583 if (alreadyProcessedABranch.empty ()) 584 throw ParseException.elseNoIf (scanner); 585 else if (((Boolean)alreadyProcessedABranch.peek ()).booleanValue ()) 586 skipToEndif (); 587 else 588 { 589 match (Token.Elif); 590 constExpr (); 591 } 592 } // elif 593 594 /** 595 * 596 **/ 597 private void skipToEndiforElse () throws IOException, ParseException 598 { 599 while (!token.equals (Token.Endif) && !token.equals (Token.Else) && !token.equals (Token.Elif)) 600 { 601 if (token.equals (Token.Ifdef) || token.equals (Token.Ifndef)) 602 { 603 alreadyProcessedABranch.push (new Boolean (true)); 604 skipToEndif (); 605 } 606 else 607 token = scanner.skipUntil ('#'); 608 } 609 process (token); 610 } // skipToEndiforElse 611 612 /** 613 * 614 **/ 615 private void skipToEndif () throws IOException, ParseException 616 { 617 while (!token.equals (Token.Endif)) 618 { 619 token = scanner.skipUntil ('#'); 620 if (token.equals (Token.Ifdef) || token.equals (Token.Ifndef)) 621 { 622 alreadyProcessedABranch.push (new Boolean (true)); 623 skipToEndif (); 624 } 625 } 626 alreadyProcessedABranch.pop (); 627 match (Token.Endif); 628 } // skipToEndif 629 630 /////////////// 631 // For Pragma 632 633 /** 634 * 635 **/ 636 private void pragma () throws IOException, ParseException 637 { 638 match (Token.Pragma); 639 String pragmaType = token.name; 640 641 // <d59165> Enable escaped identifiers while processing pragma internals. 642 // Don't enable until scanning pragma name! 643 scanner.escapedOK = true; 644 match (Token.Identifier); 645 646 // Add pragma entry to container 647 PragmaEntry pragmaEntry = parser.stFactory.pragmaEntry (parser.currentModule); 648 pragmaEntry.name (pragmaType); 649 pragmaEntry.sourceFile (scanner.fileEntry ()); 650 pragmaEntry.data (scanner.currentLine ()); 651 if (parser.currentModule instanceof ModuleEntry) 652 ((ModuleEntry)parser.currentModule).addContained (pragmaEntry); 653 else if (parser.currentModule instanceof InterfaceEntry) 654 ((InterfaceEntry)parser.currentModule).addContained (pragmaEntry); 655 656 // If the token was an identifier, then pragmaType WILL be non-null. 657 if (pragmaType.equals ("ID")) 658 idPragma (); 659 else if (pragmaType.equals ("prefix")) 660 prefixPragma (); 661 else if (pragmaType.equals ("version")) 662 versionPragma (); 663 664 // we are adding extensions to the Sun's idlj compiler to 665 // handle correct code generation for local Objects, where 666 // the OMG is taking a long time to formalize stuff. Good 667 // example of this is poa.idl. Two proprietory pragmas 668 // sun_local and sun_localservant are defined. sun_local 669 // generates only Holder and Helper classes, where read 670 // and write methods throw marshal exceptions. sun_localservant 671 // is to generate Helper, Holder, and only Skel with _invoke 672 // throwing an exception, since it does not make sense for 673 // local objects. 674 675 else if (pragmaType.equals ("sun_local")) 676 localPragma(); 677 else if (pragmaType.equals ("sun_localservant")) 678 localServantPragma(); 679 else 680 { 681 otherPragmas (pragmaType, tokenToString ()); 682 token = scanner.getToken (); 683 } 684 685 scanner.escapedOK = false; // <d59165> Disable escaped identifiers. 686 } // pragma 687 688 // <d57110> Pragma ID can be appiled to modules and it is an error to 689 // name a type in more than one ID pragma directive. 690 691 private Vector PragmaIDs = new Vector (); 692 693 private void localPragma () throws IOException, ParseException 694 { 695 // Before I can use a parser method, I must make sure it has the current token. 696 parser.token = token; 697 // this makes sense only for interfaces, if specified for modules, 698 // parser should throw an error 699 SymtabEntry anErrorOccurred = new SymtabEntry (); 700 SymtabEntry entry = parser.scopedName (parser.currentModule, anErrorOccurred); 701 // Was the indicated type found in the symbol table? 702 if (entry == anErrorOccurred) 703 { 704 System.out.println("Error occured "); 705 // Don't have to generate an error, scopedName already has. 706 scanner.skipLineComment (); 707 token = scanner.getToken (); 708 } 709 else 710 { 711 // by this time we have already parsed the ModuleName and the 712 // pragma type, therefore setInterfaceType 713 if (entry instanceof InterfaceEntry) { 714 InterfaceEntry ent = (InterfaceEntry) entry; 715 ent.setInterfaceType (InterfaceEntry.LOCAL_SIGNATURE_ONLY); 716 } 717 token = parser.token; 718 String string = token.name; 719 match (Token.StringLiteral); 720 // for non-interfaces it doesn't make sense, so just ignore it 721 } 722 } // localPragma 723 724 private void localServantPragma () throws IOException, ParseException 725 { 726 // Before I can use a parser method, I must make sure it has the current token. 727 parser.token = token; 728 // this makes sense only for interfaces, if specified for modules, 729 // parser should throw an error 730 SymtabEntry anErrorOccurred = new SymtabEntry (); 731 SymtabEntry entry = parser.scopedName (parser.currentModule, anErrorOccurred); 732 733 // Was the indicated type found in the symbol table? 734 if (entry == anErrorOccurred) 735 { 736 // Don't have to generate an error, scopedName already has. 737 scanner.skipLineComment (); 738 token = scanner.getToken (); 739 System.out.println("Error occured "); 740 } 741 else 742 { 743 // by this time we have already parsed the ModuleName and the 744 // pragma type, therefore setInterfaceType 745 if (entry instanceof InterfaceEntry) { 746 InterfaceEntry ent = (InterfaceEntry) entry; 747 ent.setInterfaceType (InterfaceEntry.LOCALSERVANT); 748 } 749 token = parser.token; 750 String string = token.name; 751 match (Token.StringLiteral); 752 // for non-interfaces it doesn't make sense, so just ignore it 753 } 754 } // localServantPragma 755 756 757 /** 758 * 759 **/ 760 private void idPragma () throws IOException, ParseException 761 { 762 // Before I can use a parser method, I must make sure it has the current token. 763 parser.token = token; 764 765 // <d57110> This flag will relax the restriction that the scopedNamed 766 // in this ID pragma directive cannot resolve to a module. 767 parser.isModuleLegalType (true); 768 SymtabEntry anErrorOccurred = new SymtabEntry (); 769 SymtabEntry entry = parser.scopedName (parser.currentModule, anErrorOccurred); 770 parser.isModuleLegalType (false); // <57110> 771 772 // Was the indicated type found in the symbol table? 773 if (entry == anErrorOccurred) 774 { 775 // Don't have to generate an error, scopedName already has. 776 scanner.skipLineComment (); 777 token = scanner.getToken (); 778 } 779 // <d57110> 780 //else if (PragmaIDs.contains (entry)) 781 //{ 782 // ParseException.badRepIDAlreadyAssigned (scanner, entry.name ()); 783 // scanner.skipLineComment (); 784 // token = scanner.getToken (); 785 //} 786 else 787 { 788 token = parser.token; 789 String string = token.name; 790 // Do not match token until after raise exceptions, otherwise 791 // incorrect messages will be emitted! 792 if (PragmaIDs.contains (entry)) // <d57110> 793 { 794 ParseException.badRepIDAlreadyAssigned (scanner, entry.name ()); 795 } 796 else if (!RepositoryID.hasValidForm (string)) // <d57110> 797 { 798 ParseException.badRepIDForm (scanner, string); 799 } 800 else 801 { 802 entry.repositoryID (new RepositoryID (string)); 803 PragmaIDs.addElement (entry); // <d57110> 804 } 805 match (Token.StringLiteral); 806 } 807 } // idPragma 808 809 /** 810 * 811 **/ 812 private void prefixPragma () throws IOException, ParseException 813 { 814 String string = token.name; 815 match (Token.StringLiteral); 816 ((IDLID)parser.repIDStack.peek ()).prefix (string); 817 ((IDLID)parser.repIDStack.peek ()).name (""); 818 } // prefixPragma 819 820 /** 821 * 822 **/ 823 private void versionPragma () throws IOException, ParseException 824 { 825 // Before I can use a parser method, I must make sure it has the current token. 826 parser.token = token; 827 // This flag will relax the restriction that the scopedNamed 828 // in this Version pragma directive cannot resolve to a module. 829 parser.isModuleLegalType (true); 830 SymtabEntry anErrorOccurred = new SymtabEntry (); 831 SymtabEntry entry = parser.scopedName (parser.currentModule, anErrorOccurred); 832 // reset the flag to original value 833 parser.isModuleLegalType (false); 834 if (entry == anErrorOccurred) 835 { 836 // Don't have to generate an error, scopedName already has. 837 scanner.skipLineComment (); 838 token = scanner.getToken (); 839 } 840 else 841 { 842 token = parser.token; 843 String string = token.name; 844 match (Token.FloatingPointLiteral); 845 if (entry.repositoryID () instanceof IDLID) 846 ((IDLID)entry.repositoryID ()).version (string); 847 } 848 } // versionPragma 849 850 private Vector pragmaHandlers = new Vector (); 851 852 /** 853 * 854 **/ 855 void registerPragma (PragmaHandler handler) 856 { 857 pragmaHandlers.addElement (handler); 858 } // registerPragma 859 860 /** 861 * 862 **/ 863 private void otherPragmas (String pragmaType, String currentToken) throws IOException 864 { 865 for (int i = pragmaHandlers.size () - 1; i >= 0; --i) 866 { 867 PragmaHandler handler = (PragmaHandler)pragmaHandlers.elementAt (i); 868 if (handler.process (pragmaType, currentToken)) 869 break; 870 } 871 } // otherPragmas 872 873 /* 874 * These protected methods are used by extenders, by the code 875 * which implements otherPragma. 876 */ 877 878 /** 879 * Get the current token. 880 **/ 881 String currentToken () 882 { 883 return tokenToString (); 884 } // currentToken 885 886 /** 887 * This method, given an entry name, returns the entry with that name. 888 * It can take fully or partially qualified names and returns the 889 * appropriate entry defined within the current scope. If no entry 890 * exists, null is returned. 891 **/ 892 SymtabEntry getEntryForName (String string) 893 { 894 boolean partialScope = false; 895 boolean globalScope = false; 896 897 // Change all ::'s to /'s 898 if (string.startsWith ("::")) 899 { 900 globalScope = true; 901 string = string.substring (2); 902 } 903 int index = string.indexOf ("::"); 904 while (index >= 0) 905 { 906 partialScope = true; 907 string = string.substring (0, index) + '/' + string.substring (index + 2); 908 index = string.indexOf ("::"); 909 } 910 911 // Get the entry for that string 912 SymtabEntry entry = null; 913 if (globalScope) 914 entry = parser.recursiveQualifiedEntry (string); 915 else if (partialScope) 916 entry = parser.recursivePQEntry (string, parser.currentModule); 917 else 918 entry = parser.unqualifiedEntryWMod (string, parser.currentModule); 919 return entry; 920 } // getEntryForName 921 922 /** 923 * This method returns a string of all of the characters from the 924 * input file from the current position up to, but not including, 925 * the end-of-line character(s). 926 **/ 927 String getStringToEOL () throws IOException 928 { 929 return scanner.getStringToEOL (); 930 } // getStringToEOL 931 932 /** 933 * This method returns a string of all of the characters from the 934 * input file from the current position up to, but not including, 935 * the given character. It encapsulates parenthesis and quoted strings, 936 * meaning it does not stop if the given character is found within 937 * parentheses or quotes. For instance, given the input of 938 * `start(inside)end', getUntil ('n') will return "start(inside)e" 939 **/ 940 String getUntil (char c) throws IOException 941 { 942 return scanner.getUntil (c); 943 } // getUntil 944 945 private boolean lastWasMacroID = false; 946 947 /** 948 * 949 **/ 950 private String tokenToString () 951 { 952 if (token.equals (Token.MacroIdentifier)) 953 { 954 lastWasMacroID = true; 955 return token.name; 956 } 957 else if (token.equals (Token.Identifier)) 958 return token.name; 959 else 960 return token.toString (); 961 } // tokenToString 962 963 /** 964 * This method returns the next token String from the input file. 965 **/ 966 String nextToken () throws IOException 967 { 968 if (lastWasMacroID) 969 { 970 lastWasMacroID = false; 971 return "("; 972 } 973 else 974 { 975 token = scanner.getToken (); 976 return tokenToString (); 977 } 978 } // nextToken 979 980 /** 981 * This method assumes that the current token marks the beginning 982 * of a scoped name. It then parses the subsequent identifier and 983 * double colon tokens, builds the scoped name, and finds the symbol 984 * table entry with that name. 985 **/ 986 SymtabEntry scopedName () throws IOException 987 { 988 boolean globalScope = false; 989 boolean partialScope = false; 990 String name = null; 991 SymtabEntry entry = null; 992 try 993 { 994 if (token.equals (Token.DoubleColon)) 995 globalScope = true; 996 else 997 { 998 if (token.equals (Token.Object)) 999 { 1000 name = "Object"; 1001 match (Token.Object); 1002 } 1003 else if (token.type == Token.ValueBase) 1004 { 1005 name = "ValueBase"; 1006 match (Token.ValueBase); 1007 } 1008 else 1009 { 1010 name = token.name; 1011 match (Token.Identifier); 1012 } 1013 } 1014 while (token.equals (Token.DoubleColon)) 1015 { 1016 match (Token.DoubleColon); 1017 partialScope = true; 1018 if (name != null) 1019 name = name + '/' + token.name; 1020 else 1021 name = token.name; 1022 match (Token.Identifier); 1023 } 1024 if (globalScope) 1025 entry = parser.recursiveQualifiedEntry (name); 1026 else if (partialScope) 1027 entry = parser.recursivePQEntry (name, parser.currentModule); 1028 else 1029 entry = parser.unqualifiedEntryWMod (name, parser.currentModule); 1030 } 1031 catch (ParseException e) 1032 { 1033 entry = null; 1034 } 1035 return entry; 1036 } // scopedName 1037 1038 /** 1039 * Skip to the end of the line. 1040 **/ 1041 void skipToEOL () throws IOException 1042 { 1043 scanner.skipLineComment (); 1044 } // skipToEOL 1045 1046 /** 1047 * This method skips the data in the input file until the specified 1048 * character is encountered, then it returns the next token. 1049 **/ 1050 String skipUntil (char c) throws IOException 1051 { 1052 if (!(lastWasMacroID && c == '(')) 1053 token = scanner.skipUntil (c); 1054 return tokenToString (); 1055 } // skipUntil 1056 1057 /** 1058 * This method displays a Parser Exception complete with line number 1059 * and position information with the given message string. 1060 **/ 1061 void parseException (String message) 1062 { 1063 // <d62023> Suppress warnings 1064 if (!parser.noWarn) 1065 ParseException.warning (scanner, message); 1066 } // parseException 1067 1068 // For Pragma 1069 /////////////// 1070 // For macro expansion 1071 1072 /** 1073 * 1074 **/ 1075 String expandMacro (String macroDef, Token t) throws IOException, ParseException 1076 { 1077 token = t; 1078 // Get the parameter values from the macro 'call' 1079 Vector parmValues = getParmValues (); 1080 1081 // Get the parameter names from the macro definition 1082 // NOTE: a newline character is appended here so that when 1083 // getStringToEOL is called, it stops scanning at the end 1084 // of this string. 1085 scanner.scanString (macroDef + '\n'); 1086 Vector parmNames = new Vector (); 1087 macro (parmNames); 1088 1089 if (parmValues.size () < parmNames.size ()) 1090 throw ParseException.syntaxError (scanner, Token.Comma, Token.RightParen); 1091 else if (parmValues.size () > parmNames.size ()) 1092 throw ParseException.syntaxError (scanner, Token.RightParen, Token.Comma); 1093 1094 macroDef = scanner.getStringToEOL (); 1095 for (int i = 0; i < parmNames.size (); ++i) 1096 macroDef = replaceAll (macroDef, (String)parmNames.elementAt (i), (String)parmValues.elementAt (i)); 1097 return removeDoublePound (macroDef); 1098 } // expandMacro 1099 1100 // This method is only used by the macro expansion methods. 1101 /** 1102 * 1103 **/ 1104 private void miniMatch (int type) throws ParseException 1105 { 1106 // A normal production would now execute: 1107 // match (type); 1108 // But match reads the next token. I don't want to do that now. 1109 // Just make sure the current token is a 'type'. 1110 if (!token.equals (type)) 1111 throw ParseException.syntaxError (scanner, type, token.type); 1112 } // miniMatch 1113 1114 /** 1115 * 1116 **/ 1117 private Vector getParmValues () throws IOException, ParseException 1118 { 1119 Vector values = new Vector (); 1120 if (token.equals (Token.Identifier)) 1121 { 1122 match (Token.Identifier); 1123 miniMatch (Token.LeftParen); 1124 } 1125 else if (!token.equals (Token.MacroIdentifier)) 1126 throw ParseException.syntaxError (scanner, Token.Identifier, token.type); 1127 1128 if (!token.equals (Token.RightParen)) 1129 { 1130 values.addElement (scanner.getUntil (',', ')').trim ()); 1131 token = scanner.getToken (); 1132 macroParmValues (values); 1133 } 1134 return values; 1135 } // getParmValues 1136 1137 /** 1138 * 1139 **/ 1140 private void macroParmValues (Vector values) throws IOException, ParseException 1141 { 1142 while (!token.equals (Token.RightParen)) 1143 { 1144 miniMatch (Token.Comma); 1145 values.addElement (scanner.getUntil (',', ')').trim ()); 1146 token = scanner.getToken (); 1147 } 1148 } // macroParmValues 1149 1150 /** 1151 * 1152 **/ 1153 private void macro (Vector parmNames) throws IOException, ParseException 1154 { 1155 match (token.type); 1156 match (Token.LeftParen); 1157 macroParms (parmNames); 1158 miniMatch (Token.RightParen); 1159 } // macro 1160 1161 /** 1162 * 1163 **/ 1164 private void macroParms (Vector parmNames) throws IOException, ParseException 1165 { 1166 if (!token.equals (Token.RightParen)) 1167 { 1168 parmNames.addElement (token.name); 1169 match (Token.Identifier); 1170 macroParms2 (parmNames); 1171 } 1172 } // macroParms 1173 1174 /** 1175 * 1176 **/ 1177 private void macroParms2 (Vector parmNames) throws IOException, ParseException 1178 { 1179 while (!token.equals (Token.RightParen)) 1180 { 1181 match (Token.Comma); 1182 parmNames.addElement (token.name); 1183 match (Token.Identifier); 1184 } 1185 } // macroParms2 1186 1187 /** 1188 * 1189 **/ 1190 private String replaceAll (String string, String from, String to) 1191 { 1192 int index = 0; 1193 while (index != -1) 1194 { 1195 index = string.indexOf (from, index); 1196 if (index != -1) 1197 { 1198 if (!embedded (string, index, index + from.length ())) 1199 if (index > 0 && string.charAt(index) == '#') 1200 string = string.substring (0, index) + '"' + to + '"' + string.substring (index + from.length ()); 1201 else 1202 string = string.substring (0, index) + to + string.substring (index + from.length ()); 1203 index += to.length (); 1204 } 1205 } 1206 return string; 1207 } // replaceAll 1208 1209 /** 1210 * 1211 **/ 1212 private boolean embedded (String string, int index, int endIndex) 1213 { 1214 // Don't replace if found substring is not an independent id. 1215 // For example, don't replace "thither".indexOf ("it", 0) 1216 boolean ret = false; 1217 char preCh = index == 0 ? ' ' : string.charAt (index - 1); 1218 char postCh = endIndex >= string.length () - 1 ? ' ' : string.charAt (endIndex); 1219 if ((preCh >= 'a' && preCh <= 'z') || (preCh >= 'A' && preCh <= 'Z')) 1220 ret = true; 1221 else if ((postCh >= 'a' && postCh <= 'z') || (postCh >= 'A' && postCh <= 'Z') || (postCh >= '0' && postCh <= '9') || postCh == '_') 1222 ret = true; 1223 else 1224 ret = inQuotes (string, index); 1225 return ret; 1226 } // embedded 1227 1228 /** 1229 * 1230 **/ 1231 private boolean inQuotes (String string, int index) 1232 { 1233 int quoteCount = 0; 1234 for (int i = 0; i < index; ++i) 1235 if (string.charAt (i) == '"') ++quoteCount; 1236 // If there are an odd number of quotes before this region, 1237 // then this region is within quotes 1238 return quoteCount % 2 != 0; 1239 } // inQuotes 1240 1241 /** 1242 * Remove any occurrences of ##. 1243 **/ 1244 private String removeDoublePound (String string) 1245 { 1246 int index = 0; 1247 while (index != -1) 1248 { 1249 index = string.indexOf ("##", index); 1250 if (index != -1) 1251 { 1252 int startSkip = index - 1; 1253 int stopSkip = index + 2; 1254 if (startSkip < 0) 1255 startSkip = 0; 1256 if (stopSkip >= string.length ()) 1257 stopSkip = string.length () - 1; 1258 while (startSkip > 0 && 1259 (string.charAt (startSkip) == ' ' || 1260 string.charAt (startSkip) == '\t')) 1261 --startSkip; 1262 while (stopSkip < string.length () - 1 && 1263 (string.charAt (stopSkip) == ' ' || 1264 string.charAt (stopSkip) == '\t')) 1265 ++stopSkip; 1266 string = string.substring (0, startSkip + 1) + string.substring (stopSkip); 1267 } 1268 } 1269 return string; 1270 } // removeDoublePound 1271 1272 // For macro expansion 1273 /////////////// 1274 1275 /** 1276 * 1277 **/ 1278 private String getFilename (String name) throws FileNotFoundException 1279 { 1280 String fullName = null; 1281 File file = new File (name); 1282 if (file.canRead ()) 1283 fullName = name; 1284 else 1285 { 1286 Enumeration pathList = parser.paths.elements (); 1287 while (!file.canRead () && pathList.hasMoreElements ()) 1288 { 1289 fullName = (String)pathList.nextElement () + File.separatorChar + name; 1290 file = new File (fullName); 1291 } 1292 if (!file.canRead ()) 1293 throw new FileNotFoundException (name); 1294 } 1295 return fullName; 1296 } // getFilename 1297 1298 /** 1299 * 1300 **/ 1301 private void match (int type) throws IOException, ParseException 1302 { 1303 if (!token.equals (type)) 1304 throw ParseException.syntaxError (scanner, type, token.type); 1305 token = scanner.getToken (); 1306 1307 // <d62023> Added for convenience, but commented-out because there is 1308 // no reason to issue warnings for tokens scanned during preprocessing. 1309 // See issueTokenWarnings(). 1310 //issueTokenWarnings (); 1311 1312 //System.out.println ("Preprocessor.match token = " + token.type); 1313 //if (token.equals (Token.Identifier) || token.equals (Token.MacroIdentifier)) 1314 // System.out.println ("Preprocessor.match token name = " + token.name); 1315 1316 // If the token is a defined thingy, scan the defined string 1317 // instead of the input stream for a while. 1318 if (token.equals (Token.Identifier) || token.equals (Token.MacroIdentifier)) 1319 { 1320 String string = (String)symbols.get (token.name); 1321 if (string != null && !string.equals ("")) 1322 // If this is a macro, parse the macro 1323 if (macros.contains (token.name)) 1324 { 1325 scanner.scanString (expandMacro (string, token)); 1326 token = scanner.getToken (); 1327 } 1328 // else this is just a normal define 1329 else 1330 { 1331 scanner.scanString (string); 1332 token = scanner.getToken (); 1333 } 1334 } 1335 } // match 1336 1337 // <d62023> 1338 /** 1339 * Issue warnings about tokens scanned during preprocessing. 1340 **/ 1341 private void issueTokenWarnings () 1342 { 1343 if (parser.noWarn) 1344 return; 1345 1346 // There are no keywords defined for preprocessing (only directives), so: 1347 // 1348 // 1.) Do not issue warnings for identifiers known to be keywords in 1349 // another level of IDL. 1350 // 2.) Do not issue warnings for identifiers that collide with keywords 1351 // in letter, but not case. 1352 // 3.) Do not issue warnings for deprecated keywords. 1353 // 1354 // Should we warn when a macro identifier replaces a keyword? Hmmm. 1355 1356 // Deprecated directives? None to date. 1357 //if (token.isDirective () && token.isDeprecated ()) 1358 // ParseException.warning (scanner, Util.getMesage ("Deprecated.directive", token.name)); 1359 } // issueTokenWarnings 1360 1361 /** 1362 * This method is called when the parser encounters a left curly brace. 1363 * An extender of PragmaHandler may find scope information useful. 1364 * For example, the prefix pragma takes effect as soon as it is 1365 * encountered and stays in effect until the current scope is closed. 1366 * If a similar pragma extension is desired, then the openScope and 1367 * closeScope methods are available for overriding. 1368 * @param entry the symbol table entry whose scope has just been opened. 1369 * Be aware that, since the scope has just been entered, this entry is 1370 * incomplete at this point. 1371 **/ 1372 void openScope (SymtabEntry entry) 1373 { 1374 for (int i = pragmaHandlers.size () - 1; i >= 0; --i) 1375 { 1376 PragmaHandler handler = (PragmaHandler)pragmaHandlers.elementAt (i); 1377 handler.openScope (entry); 1378 } 1379 } // openScope 1380 1381 /** 1382 * This method is called when the parser encounters a right curly brace. 1383 * An extender of PragmaHandler may find scope information useful. 1384 * For example, the prefix pragma takes effect as soon as it is 1385 * encountered and stays in effect until the current scope is closed. 1386 * If a similar pragma extension is desired, then the openScope and 1387 * closeScope methods are available for overriding. 1388 * @param entry the symbol table entry whose scope has just been closed. 1389 **/ 1390 void closeScope (SymtabEntry entry) 1391 { 1392 for (int i = pragmaHandlers.size () - 1; i >= 0; --i) 1393 { 1394 PragmaHandler handler = (PragmaHandler)pragmaHandlers.elementAt (i); 1395 handler.closeScope (entry); 1396 } 1397 } // closeScope 1398 1399 private Parser parser; 1400 private Scanner scanner; 1401 private Hashtable symbols; 1402 private Vector macros; 1403 1404 // The logic associated with this stack is scattered above. 1405 // A concise map of the logic is: 1406 // case #if false, #ifdef false, #ifndef true 1407 // push (false); 1408 // skipToEndifOrElse (); 1409 // case #if true, #ifdef true, #ifndef false 1410 // push (true); 1411 // case #elif <conditional> 1412 // if (top == true) 1413 // skipToEndif (); 1414 // else if (conditional == true) 1415 // pop (); 1416 // push (true); 1417 // else if (conditional == false) 1418 // skipToEndifOrElse (); 1419 // case #else 1420 // if (top == true) 1421 // skipToEndif (); 1422 // else 1423 // pop (); 1424 // push (true); 1425 // case #endif 1426 // pop (); 1427 private Stack alreadyProcessedABranch = new Stack (); 1428 Token token; 1429 1430 private static String indent = ""; 1431 }