/plugins/JavaSideKick/tags/javasidekick-2-1-1/src/sidekick/java/parser/Tiger.jj

# · Unknown · 2884 lines · 2644 code · 240 blank · 0 comment · 0 complexity · 366fb909a263b1202f286b8fa80cbe7c MD5 · raw file

Large files are truncated click here to view the full file

  1. /*
  2. Per Sreenivasa Viswanadha (as posted on the javacc user mailing list), the
  3. original java 1.5 grammar is licensed under the BSD license, so this modified
  4. grammar is also.
  5. Copyright (c) 2005, Dale Anson
  6. All rights reserved.
  7. Redistribution and use in source and binary forms, with or without modification,
  8. are permitted provided that the following conditions are met:
  9. * Redistributions of source code must retain the above copyright notice,
  10. this list of conditions and the following disclaimer.
  11. * Redistributions in binary form must reproduce the above copyright notice,
  12. this list of conditions and the following disclaimer in the documentation
  13. and/or other materials provided with the distribution.
  14. * Neither the name of the <ORGANIZATION> nor the names of its contributors
  15. may be used to endorse or promote products derived from this software without
  16. specific prior written permission.
  17. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  18. ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  19. WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  20. DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
  21. ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  22. (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  23. LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
  24. ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  25. (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  26. SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  27. */
  28. options {
  29. JAVA_UNICODE_ESCAPE = true;
  30. ERROR_REPORTING = false;
  31. STATIC = false;
  32. }
  33. PARSER_BEGIN(TigerParser)
  34. package sidekick.java.parser;
  35. import sidekick.java.node.*;
  36. import java.io.*;
  37. import java.util.*;
  38. /**
  39. * Based on grammar to parse Java version 1.5 written by Sreenivasa Viswanadha,
  40. * parses a java file for the JavaSideKick plugin to provide a java code
  41. * browser that works with java 1.5. I've also updated this file so it will
  42. * parse javacc files for JavaSideKick too, that makes it a lot easier to edit
  43. * files such as this.
  44. * <p>
  45. * Example usage to parse a java file:<p>
  46. * <code>
  47. * TigerParser parser = new TigerParser(filename);<br>
  48. * CUNode root = parser.getJavaRootNode();<br>
  49. * </code>
  50. * or to parse a javacc file:<br>
  51. * <code>
  52. * TigerParser parser = new TigerParser(filename);<br>
  53. * CUNode root = parser.getJavaCCRootNode();<br>
  54. * </code>
  55. * Calling either of the above causes the file to be parsed into
  56. * TigerNodes, of which, CUNode is the top-level. The TigerNodes have a parent/
  57. * child relastionship, which naturally forms a tree structure.
  58. * <p>
  59. * To turn this .jj file into a .java file, run <code>javacc Tiger.jj</code>
  60. * from the directory that contains this file. Javacc will produce a number of
  61. * .java files, Be careful -- not all files in the directory are produced by
  62. * javacc, in particular ModifierSet.java and Token.java are required files and
  63. * are NOT produced by javacc. So the sequence is:<br>
  64. * .jj -> javacc -> .java -> javac -> .class
  65. * <p>
  66. */
  67. public class TigerParser
  68. {
  69. // accumulates counts of classes, interfaces, methods and fields.
  70. private Results results = new Results();
  71. private InputStream inputStream = null;
  72. /**
  73. * Constructor for TigerParser. Note that JavaSideKick does not use this
  74. * constructor -- since the options for building the parser have both
  75. * USER_TOKEN_MANAGER and USER_CHAR_STREAM set to false (these are the
  76. * default values so are not explicitly set), javacc will create a
  77. * constructor "public TigerParser(InputStream)". It is that constructor
  78. * that JavaSideKick uses.
  79. * @param fileName name of the file to parse
  80. */
  81. public TigerParser(String filename)
  82. {
  83. this(System.in);
  84. try {
  85. inputStream = new FileInputStream(new File(filename));
  86. ReInit(inputStream);
  87. }
  88. catch(Exception e) {
  89. e.printStackTrace();
  90. }
  91. }
  92. TigerParser(JavaCharStream stream) {
  93. jj_input_stream = stream;
  94. token_source = new TigerParserTokenManager(jj_input_stream);
  95. token = new Token();
  96. jj_ntk = -1;
  97. }
  98. /**
  99. * @return the accumulated counts of classes, interfaces, methods, and fields.
  100. */
  101. public Results getResults() {
  102. return results;
  103. }
  104. public Location getLocation(Token t) {
  105. if (t == null)
  106. return new Location(0, 0);
  107. return new Location(t.beginLine, t.beginColumn);
  108. }
  109. public Location getEndLocation(Token t) {
  110. if (t == null)
  111. return new Location(0, 0);
  112. return new Location(t.endLine, t.endColumn);
  113. }
  114. public Location getLocation(Modifier m) {
  115. if (m == null)
  116. return new Location(0, 0);
  117. if (m.beginLine == -1)
  118. m.beginLine = 0;
  119. return new Location(m.beginLine, m.beginColumn);
  120. }
  121. public void error_skipto(int kind) {
  122. ParseException e = generateParseException(); // generate the exception object.
  123. addException(e);
  124. Token t = null;
  125. int i = 0;
  126. do {
  127. i++;
  128. if (i > 100) {
  129. break;
  130. }
  131. t = getNextToken();
  132. } while (t != null && t.kind != kind);
  133. }
  134. private List exceptions = new ArrayList();
  135. private void addException(ParseException pe) {
  136. ErrorNode en = new ErrorNode(pe);
  137. exceptions.add(en);
  138. }
  139. public List getErrors() {
  140. return exceptions;
  141. }
  142. public void adjustModifier(Modifier m, Token t) {
  143. if (m.beginLine < t.beginLine) {
  144. m.beginLine = t.beginLine;
  145. }
  146. if (m.beginLine == t.beginLine && (t.beginColumn < m.beginColumn || m.beginColumn == -1)) {
  147. m.beginColumn = t.beginColumn;
  148. }
  149. if (m.endLine < t.endLine) {
  150. m.endLine = t.endLine;
  151. }
  152. if (m.endLine == t.endLine && m.endColumn < t.endColumn) {
  153. m.endColumn = t.endColumn;
  154. }
  155. }
  156. public void setTabSize(int size) {
  157. jj_input_stream.setTabSize(size);
  158. }
  159. public int getTabSize() {
  160. return jj_input_stream.getTabSize(0);
  161. }
  162. /*
  163. * Returns true if the next token is not in the FOLLOW list of "expansion".
  164. * It is used to decide when the end of an "expansion" has been reached.
  165. */
  166. private boolean notTailOfExpansionUnit() {
  167. Token t;
  168. t = getToken(1);
  169. if (t.kind == BIT_OR || t.kind == COMMA || t.kind == RPAREN || t.kind == RBRACE || t.kind == RBRACKET) return false;
  170. return true;
  171. }
  172. }
  173. PARSER_END(TigerParser)
  174. /********************************************
  175. * THE JAVA TOKEN SPECIFICATION STARTS HERE *
  176. ********************************************/
  177. /* WHITE SPACE */
  178. SKIP :
  179. {
  180. " "
  181. | "\t"
  182. | "\n"
  183. | "\r"
  184. | "\f"
  185. }
  186. /* COMMENTS */
  187. MORE :
  188. {
  189. /* danson, added backup(2) for special handling of single line comments at
  190. the end of a file, see <IN_SINGLE_LINE_COMMENT> special token below */
  191. "//" { input_stream.backup(2); } : IN_SINGLE_LINE_COMMENT
  192. |
  193. <"/**" ~["/"]> { input_stream.backup(1); } : IN_FORMAL_COMMENT
  194. |
  195. "/*" : IN_MULTI_LINE_COMMENT
  196. }
  197. <IN_SINGLE_LINE_COMMENT>
  198. SPECIAL_TOKEN :
  199. {
  200. /* this is the original, I've replaced with the next line to allow a single
  201. line comment at the end of a java file without a new line following the
  202. comment. The java language specification says that single line comments
  203. must be followed by an end-of-line marker (see section 3.4), so this new rule
  204. relaxes that requirement slightly by allowing the line terminator to be
  205. optional. This only makes sense when the comment is the last line of the
  206. source file, all other single line comments will have a line terminator. This
  207. request was posted as a bug against JBrowse, I don't see any problem with
  208. allowing it, especially since Sun's compiler doesn't complain. */
  209. /* <SINGLE_LINE_COMMENT: "\n" | "\r" | "\r\n" > : DEFAULT */
  210. < SINGLE_LINE_COMMENT: "//"(~["\n","\r"])* ("\n"|"\r"|"\r\n")? > : DEFAULT
  211. }
  212. <IN_FORMAL_COMMENT>
  213. SPECIAL_TOKEN :
  214. {
  215. <FORMAL_COMMENT: "*/" > : DEFAULT
  216. }
  217. <IN_MULTI_LINE_COMMENT>
  218. SPECIAL_TOKEN :
  219. {
  220. <MULTI_LINE_COMMENT: "*/" > : DEFAULT
  221. }
  222. <IN_SINGLE_LINE_COMMENT,IN_FORMAL_COMMENT,IN_MULTI_LINE_COMMENT>
  223. MORE :
  224. {
  225. < ~[] >
  226. }
  227. /* RESERVED WORDS AND LITERALS */
  228. TOKEN :
  229. {
  230. < ABSTRACT: "abstract" >
  231. | < ASSERT: "assert" >
  232. | < BOOLEAN: "boolean" >
  233. | < BREAK: "break" >
  234. | < BYTE: "byte" >
  235. | < CASE: "case" >
  236. | < CATCH: "catch" >
  237. | < CHAR: "char" >
  238. | < CLASS: "class" >
  239. | < CONST: "const" >
  240. | < CONTINUE: "continue" >
  241. | < _DEFAULT: "default" >
  242. | < DO: "do" >
  243. | < DOUBLE: "double" >
  244. | < ELSE: "else" >
  245. | < ENUM: "enum" >
  246. | < EXTENDS: "extends" >
  247. | < FALSE: "false" >
  248. | < FINAL: "final" >
  249. | < FINALLY: "finally" >
  250. | < FLOAT: "float" >
  251. | < FOR: "for" >
  252. | < GOTO: "goto" >
  253. | < IF: "if" >
  254. | < IMPLEMENTS: "implements" >
  255. | < IMPORT: "import" >
  256. | < INSTANCEOF: "instanceof" >
  257. | < INT: "int" >
  258. | < INTERFACE: "interface" >
  259. | < LONG: "long" >
  260. | < NATIVE: "native" >
  261. | < NEW: "new" >
  262. | < NULL: "null" >
  263. | < PACKAGE: "package">
  264. | < PRIVATE: "private" >
  265. | < PROTECTED: "protected" >
  266. | < PUBLIC: "public" >
  267. | < RETURN: "return" >
  268. | < SHORT: "short" >
  269. | < STATIC: "static" >
  270. | < STRICTFP: "strictfp" >
  271. | < SUPER: "super" >
  272. | < SWITCH: "switch" >
  273. | < SYNCHRONIZED: "synchronized" >
  274. | < THIS: "this" >
  275. | < THROW: "throw" >
  276. | < THROWS: "throws" >
  277. | < TRANSIENT: "transient" >
  278. | < TRUE: "true" >
  279. | < TRY: "try" >
  280. | < VOID: "void" >
  281. | < VOLATILE: "volatile" >
  282. | < WHILE: "while" >
  283. }
  284. /* JAVACC RESERVED WORDS: These are the only tokens in JavaCC but not in Java */
  285. /* danson, using these keywords as tokens causes problems when parsing java
  286. code, so I'm replacing these keyworks with semantic lookahead as described in
  287. the javacc faq. */
  288. /*
  289. TOKEN :
  290. {
  291. < _OPTIONS: "options" >
  292. | < _LOOKAHEAD: "LOOKAHEAD" >
  293. | < _IGNORE_CASE: "IGNORE_CASE" >
  294. | < _PARSER_BEGIN: "PARSER_BEGIN" >
  295. | < _PARSER_END: "PARSER_END" >
  296. | < _JAVACODE: "JAVACODE" >
  297. | < _TOKEN: "TOKEN" >
  298. | < _SPECIAL_TOKEN: "SPECIAL_TOKEN" >
  299. | < _MORE: "MORE" >
  300. | < _SKIP: "SKIP" >
  301. | < _TOKEN_MGR_DECLS: "TOKEN_MGR_DECLS" >
  302. | < _EOF: "EOF" >
  303. }
  304. */
  305. /* LITERALS */
  306. TOKEN :
  307. {
  308. < INTEGER_LITERAL:
  309. <DECIMAL_LITERAL> (["l","L"])?
  310. | <HEX_LITERAL> (["l","L"])?
  311. | <OCTAL_LITERAL> (["l","L"])?
  312. >
  313. |
  314. < #DECIMAL_LITERAL: ["1"-"9"] (["0"-"9"])* >
  315. |
  316. < #HEX_LITERAL: "0" ["x","X"] (["0"-"9","a"-"f","A"-"F"])+ >
  317. |
  318. < #OCTAL_LITERAL: "0" (["0"-"7"])* >
  319. |
  320. < FLOATING_POINT_LITERAL:
  321. (["0"-"9"])+ "." (["0"-"9"])* (<EXPONENT>)? (["f","F","d","D"])?
  322. | "." (["0"-"9"])+ (<EXPONENT>)? (["f","F","d","D"])?
  323. | (["0"-"9"])+ <EXPONENT> (["f","F","d","D"])?
  324. | (["0"-"9"])+ (<EXPONENT>)? ["f","F","d","D"]
  325. >
  326. |
  327. < #EXPONENT: ["e","E"] (["+","-"])? (["0"-"9"])+ >
  328. |
  329. < CHARACTER_LITERAL:
  330. "'"
  331. ( (~["'","\\","\n","\r"])
  332. | ("\\"
  333. ( ["n","t","b","r","f","\\","'","\""]
  334. | ["0"-"7"] ( ["0"-"7"] )?
  335. | ["0"-"3"] ["0"-"7"] ["0"-"7"]
  336. )
  337. )
  338. )
  339. "'"
  340. >
  341. |
  342. < STRING_LITERAL:
  343. "\""
  344. ( (~["\"","\\","\n","\r"])
  345. | ("\\"
  346. ( ["n","t","b","r","f","\\","'","\""]
  347. | ["0"-"7"] ( ["0"-"7"] )?
  348. | ["0"-"3"] ["0"-"7"] ["0"-"7"]
  349. )
  350. )
  351. )*
  352. "\""
  353. >
  354. }
  355. /* IDENTIFIERS */
  356. TOKEN :
  357. {
  358. < IDENTIFIER: <LETTER> (<LETTER>|<DIGIT>)* >
  359. |
  360. < #LETTER:
  361. [
  362. "\u0024",
  363. "\u0041"-"\u005a",
  364. "\u005f",
  365. "\u0061"-"\u007a",
  366. "\u00c0"-"\u00d6",
  367. "\u00d8"-"\u00f6",
  368. "\u00f8"-"\u00ff",
  369. "\u0100"-"\u1fff",
  370. "\u3040"-"\u318f",
  371. "\u3300"-"\u337f",
  372. "\u3400"-"\u3d2d",
  373. "\u4e00"-"\u9fff",
  374. "\uf900"-"\ufaff"
  375. ]
  376. >
  377. |
  378. < #DIGIT:
  379. [
  380. "\u0030"-"\u0039",
  381. "\u0660"-"\u0669",
  382. "\u06f0"-"\u06f9",
  383. "\u0966"-"\u096f",
  384. "\u09e6"-"\u09ef",
  385. "\u0a66"-"\u0a6f",
  386. "\u0ae6"-"\u0aef",
  387. "\u0b66"-"\u0b6f",
  388. "\u0be7"-"\u0bef",
  389. "\u0c66"-"\u0c6f",
  390. "\u0ce6"-"\u0cef",
  391. "\u0d66"-"\u0d6f",
  392. "\u0e50"-"\u0e59",
  393. "\u0ed0"-"\u0ed9",
  394. "\u1040"-"\u1049"
  395. ]
  396. >
  397. }
  398. /* SEPARATORS */
  399. TOKEN :
  400. {
  401. < LPAREN: "(" >
  402. | < RPAREN: ")" >
  403. | < LBRACE: "{" >
  404. | < RBRACE: "}" >
  405. | < LBRACKET: "[" >
  406. | < RBRACKET: "]" >
  407. | < SEMICOLON: ";" >
  408. | < COMMA: "," >
  409. | < DOT: "." >
  410. | < AT: "@" >
  411. }
  412. /* OPERATORS */
  413. TOKEN :
  414. {
  415. < ASSIGN: "=" >
  416. | < LT: "<" >
  417. | < BANG: "!" >
  418. | < TILDE: "~" >
  419. | < HOOK: "?" >
  420. | < COLON: ":" >
  421. | < EQ: "==" >
  422. | < LE: "<=" >
  423. | < GE: ">=" >
  424. | < NE: "!=" >
  425. | < SC_OR: "||" >
  426. | < SC_AND: "&&" >
  427. | < INCR: "++" >
  428. | < DECR: "--" >
  429. | < PLUS: "+" >
  430. | < MINUS: "-" >
  431. | < STAR: "*" >
  432. | < SLASH: "/" >
  433. | < BIT_AND: "&" >
  434. | < BIT_OR: "|" >
  435. | < XOR: "^" >
  436. | < REM: "%" >
  437. | < LSHIFT: "<<" >
  438. | < PLUSASSIGN: "+=" >
  439. | < MINUSASSIGN: "-=" >
  440. | < STARASSIGN: "*=" >
  441. | < SLASHASSIGN: "/=" >
  442. | < ANDASSIGN: "&=" >
  443. | < ORASSIGN: "|=" >
  444. | < XORASSIGN: "^=" >
  445. | < REMASSIGN: "%=" >
  446. | < LSHIFTASSIGN: "<<=" >
  447. | < RSIGNEDSHIFTASSIGN: ">>=" >
  448. | < RUNSIGNEDSHIFTASSIGN: ">>>=" >
  449. | < ELLIPSIS: "..." >
  450. }
  451. /* >'s need special attention due to generics syntax. */
  452. TOKEN :
  453. {
  454. < RUNSIGNEDSHIFT: ">>>" >
  455. {
  456. matchedToken.kind = GT;
  457. ((Token.GTToken)matchedToken).realKind = RUNSIGNEDSHIFT;
  458. input_stream.backup(2);
  459. }
  460. | < RSIGNEDSHIFT: ">>" >
  461. {
  462. matchedToken.kind = GT;
  463. ((Token.GTToken)matchedToken).realKind = RSIGNEDSHIFT;
  464. input_stream.backup(1);
  465. }
  466. | < GT: ">" >
  467. }
  468. /************************************************
  469. * THE JAVACC GRAMMAR SPECIFICATION STARTS HERE *
  470. ************************************************/
  471. CUNode getJavaCCRootNode(int tab_size) :
  472. {
  473. setTabSize(tab_size);
  474. CUNode n = new CUNode();
  475. List children = null;
  476. }
  477. {
  478. children = javacc_input()
  479. {
  480. if (children != null ) {
  481. for (Iterator it = children.iterator(); it.hasNext(); ) {
  482. n.addChild((TigerNode)it.next());
  483. }
  484. }
  485. return n;
  486. }
  487. }
  488. List javacc_input() :
  489. {
  490. List children = new ArrayList();
  491. TigerNode options_node = null;
  492. Token parser_node_start_t = null;
  493. Token parser_node_end_t = null;
  494. Token cunode_start_t = null;
  495. Token cunode_end_t = null;
  496. TigerNode production_node = null;
  497. TigerNode cunode = null;
  498. TigerNode parser_node = new TigerNode(){public int getOrdinal(){return TigerNode.PARSER;}};
  499. }
  500. {
  501. options_node=javacc_options()
  502. // special handling for javacc keyword
  503. LOOKAHEAD( {getToken(1).kind == IDENTIFIER && getToken(1).image.equals("PARSER_BEGIN")} )
  504. parser_node_start_t=<IDENTIFIER> "(" identifier() cunode_start_t=")"
  505. cunode=CompilationUnit(getTabSize())
  506. // special handling for javacc keyword
  507. LOOKAHEAD( {getToken(1).kind == IDENTIFIER && getToken(1).image.equals("PARSER_END")} )
  508. cunode_end_t=<IDENTIFIER> "(" identifier() parser_node_end_t=")"
  509. ( production_node=production() { children.add(production_node); } )+
  510. <EOF>
  511. {
  512. if (options_node != null) {
  513. children.add(options_node);
  514. }
  515. if (parser_node_start_t != null && parser_node_end_t != null ) {
  516. parser_node.setName("PARSER");
  517. parser_node.setStartLocation(getLocation(parser_node_start_t));
  518. parser_node.setEndLocation(getEndLocation(parser_node_end_t));
  519. children.add(parser_node);
  520. if (cunode != null) {
  521. cunode.setStartLocation(getLocation(cunode_start_t));
  522. cunode.setEndLocation(getEndLocation(cunode_end_t));
  523. if (cunode.getChildren() != null ) {
  524. for (Iterator it = cunode.getChildren().iterator(); it.hasNext(); ) {
  525. parser_node.addChild((TigerNode)it.next());
  526. }
  527. }
  528. else {
  529. parser_node.addChild(cunode);
  530. }
  531. }
  532. }
  533. return children;
  534. }
  535. }
  536. TigerNode javacc_options() :
  537. {
  538. TigerNode tn = new TigerNode() {public int getOrdinal() { return TigerNode.OPTIONS;}};
  539. Token start_t = null;
  540. Token end_t = null;
  541. }
  542. {
  543. // special handling for javacc keyword
  544. [
  545. LOOKAHEAD( {getToken(1).kind == IDENTIFIER && getToken(1).image.equals("options")} )
  546. (start_t=<IDENTIFIER> "{" ( option_binding() )+ end_t="}" )
  547. ]
  548. //[ start_t=<_OPTIONS> "{" ( option_binding() )+ end_t="}" ]
  549. {
  550. tn.setName("options");
  551. tn.setStartLocation(getLocation(start_t));
  552. tn.setEndLocation(getEndLocation(end_t));
  553. return tn;
  554. }
  555. }
  556. void option_binding() :
  557. {}
  558. {
  559. (
  560. // special handling for javacc keyword
  561. LOOKAHEAD( {getToken(1).kind == IDENTIFIER && getToken(1).image.equals("LOOKAHEAD")} )
  562. identifier()
  563. |
  564. // special handling for javacc keyword
  565. LOOKAHEAD( {getToken(1).kind == IDENTIFIER && getToken(1).image.equals("IGNORE_CASE")} )
  566. identifier()
  567. |
  568. <IDENTIFIER>
  569. |
  570. "static" )
  571. "="
  572. ( IntegerLiteral() | BooleanLiteral() | StringLiteral() )
  573. ";"
  574. }
  575. TigerNode production() :
  576. {
  577. TigerNode tn = null;
  578. }
  579. {
  580. (
  581. LOOKAHEAD(1)
  582. /*
  583. * Since JAVACODE is both a JavaCC reserved word and a Java identifier,
  584. * we need to give preference to "javacode_production" over
  585. * "bnf_production".
  586. */
  587. tn=javacode_production()
  588. |
  589. LOOKAHEAD(1)
  590. /*
  591. * Since SKIP, TOKEN, etc. are both JavaCC reserved words and Java
  592. * identifiers, we need to give preference to "regular_expression_production"
  593. * over "bnf_production".
  594. */
  595. tn=regular_expr_production()
  596. |
  597. LOOKAHEAD(1)
  598. /*
  599. * Since TOKEN_MGR_DECLS is both a JavaCC reserved word and a Java identifier,
  600. * we need to give preference to "token_manager_decls" over
  601. * "bnf_production".
  602. */
  603. tn=token_manager_decls()
  604. |
  605. tn=bnf_production()
  606. )
  607. {
  608. return tn;
  609. }
  610. }
  611. TigerNode javacode_production() :
  612. {
  613. MethodNode mn = new MethodNode();
  614. List params = null;
  615. Token start_t = null;
  616. Type resultType = null;
  617. String identifier = "";
  618. BlockNode bn = null;
  619. }
  620. {
  621. // special handling for javacc keyword
  622. LOOKAHEAD( {getToken(1).kind == IDENTIFIER && getToken(1).image.equals("JAVACODE")} )
  623. start_t=<IDENTIFIER>
  624. resultType=ResultType() identifier=identifier() params=FormalParameters()
  625. [ LOOKAHEAD(2) "throws" Name() ( "," Name() )* ]
  626. [ LOOKAHEAD(2) node_descriptor() ]
  627. bn=Block()
  628. {
  629. if (start_t != null){
  630. mn.setStartLocation(getLocation(start_t));
  631. }
  632. if (resultType != null) {
  633. mn.setReturnType(resultType.toString());
  634. }
  635. mn.setName(identifier);
  636. if (params != null) {
  637. mn.setFormalParams(params);
  638. }
  639. if (bn != null) {
  640. mn.setEndLocation(bn.getEndLocation());
  641. mn.addChild(bn);
  642. }
  643. return mn;
  644. }
  645. }
  646. TigerNode bnf_production() :
  647. {
  648. MethodNode mn = new MethodNode();
  649. List params = null;
  650. Type resultType = null;
  651. String identifier = "";
  652. Token end_t = null;
  653. BlockNode java_block = null;
  654. }
  655. {
  656. resultType=ResultType() identifier=identifier() params=FormalParameters()
  657. [ "throws" Name() ( "," Name() )* ]
  658. [ node_descriptor() ]
  659. ":"
  660. java_block = Block()
  661. "{" expansion_choices() end_t="}"
  662. {
  663. if (resultType != null) {
  664. mn.setStartLocation(resultType.getStartLocation());
  665. mn.setReturnType(resultType.toString());
  666. }
  667. mn.setName(identifier);
  668. if (params != null) {
  669. mn.setFormalParams(params);
  670. }
  671. if (end_t != null ) {
  672. mn.setEndLocation(getEndLocation(end_t));
  673. }
  674. if (java_block != null) {
  675. mn.addChild(java_block);
  676. }
  677. return mn;
  678. }
  679. }
  680. TigerNode regular_expr_production() :
  681. {
  682. Token start_t = null;
  683. Token end_t = null;
  684. Token t = null;
  685. TigerNode tn = new TigerNode();
  686. Token kind = null;
  687. StringBuffer lexical_state_list = new StringBuffer();
  688. }
  689. {
  690. [
  691. LOOKAHEAD(2) start_t="<" "*" ">" {lexical_state_list.append("<*>"); }
  692. |
  693. start_t="<" t=<IDENTIFIER> {lexical_state_list.append("<").append(t.image);} ( "," t=<IDENTIFIER> {lexical_state_list.append(",").append(t.image);} )* ">" {lexical_state_list.append(">");}
  694. ]
  695. kind=regexpr_kind() [ "["
  696. // special handling for javacc keyword
  697. LOOKAHEAD( {getToken(1).kind == IDENTIFIER && getToken(1).image.equals("IGNORE_CASE")} )
  698. <IDENTIFIER>
  699. "]"
  700. ] ":"
  701. "{" regexpr_spec() ( "|" regexpr_spec() )* end_t="}"
  702. {
  703. if (lexical_state_list.length() > 0) {
  704. tn.setName(lexical_state_list.toString());
  705. }
  706. else if (kind != null) {
  707. tn.setName(kind.image);
  708. }
  709. tn.setStartLocation(getLocation(start_t == null ? kind : start_t));
  710. tn.setEndLocation(getEndLocation(end_t));
  711. return tn;
  712. }
  713. }
  714. TigerNode token_manager_decls() :
  715. {
  716. Token start_t = null;
  717. BlockNode bn = null;
  718. }
  719. {
  720. // special handling for javacc keyword
  721. LOOKAHEAD( {getToken(1).kind == IDENTIFIER && getToken(1).image.equals("TOKEN_MGR_DECLS")} )
  722. start_t=<IDENTIFIER> ":" bn=TokenMgrDeclBlock()
  723. {
  724. TigerNode tn = new TigerNode();
  725. tn.setName(start_t.image);
  726. tn.setStartLocation(getLocation(start_t));
  727. if (bn != null) {
  728. tn.setEndLocation(bn.getEndLocation());
  729. tn.addChildren(bn.getChildren());
  730. }
  731. return tn;
  732. }
  733. }
  734. Token regexpr_kind() :
  735. {
  736. Token t = null;
  737. }
  738. {
  739. (
  740. // special handling for javacc keyword
  741. LOOKAHEAD( {getToken(1).kind == IDENTIFIER && getToken(1).image.equals("TOKEN")} )
  742. t=<IDENTIFIER>
  743. |
  744. // special handling for javacc keyword
  745. LOOKAHEAD( {getToken(1).kind == IDENTIFIER && getToken(1).image.equals("SPECIAL_TOKEN")} )
  746. t=<IDENTIFIER>
  747. |
  748. // special handling for javacc keyword
  749. LOOKAHEAD( {getToken(1).kind == IDENTIFIER && getToken(1).image.equals("SKIP")} )
  750. t=<IDENTIFIER>
  751. |
  752. // special handling for javacc keyword
  753. LOOKAHEAD( {getToken(1).kind == IDENTIFIER && getToken(1).image.equals("MORE")} )
  754. t=<IDENTIFIER>
  755. )
  756. {
  757. return t;
  758. }
  759. }
  760. void regexpr_spec() :
  761. {}
  762. {
  763. regular_expression() [ Block() ] [ ":" <IDENTIFIER> ]
  764. }
  765. void expansion_choices() :
  766. {}
  767. {
  768. expansion() ( "|" expansion() )*
  769. }
  770. void expansion() :
  771. {}
  772. {
  773. ( LOOKAHEAD(1)
  774. // special handling for javacc keyword
  775. LOOKAHEAD( {getToken(1).kind == IDENTIFIER && getToken(1).image.equals("LOOKAHEAD")} )
  776. <IDENTIFIER> "(" local_lookahead() ")"
  777. )?
  778. ( LOOKAHEAD(0, { notTailOfExpansionUnit() } )
  779. expansion_unit()
  780. [ node_descriptor() ]
  781. )+
  782. }
  783. void local_lookahead() :
  784. {
  785. boolean commaAtEnd = false, emptyLA = true;
  786. }
  787. {
  788. [
  789. /*
  790. * The lookahead of 1 is to turn off the warning message that lets
  791. * us know that an expansion choice can also start with an integer
  792. * literal because a primary expression can do the same. But we
  793. * know that this is what we want.
  794. */
  795. LOOKAHEAD(1)
  796. IntegerLiteral()
  797. {
  798. emptyLA = false;
  799. }
  800. ]
  801. [ LOOKAHEAD(0, { !emptyLA && (getToken(1).kind != RPAREN) } )
  802. ","
  803. {
  804. commaAtEnd = true;
  805. }
  806. ]
  807. [ LOOKAHEAD(0, { getToken(1).kind != RPAREN && getToken(1).kind != LBRACE } )
  808. expansion_choices()
  809. {
  810. emptyLA = false; commaAtEnd = false;
  811. }
  812. ]
  813. [ LOOKAHEAD(0, { !emptyLA && !commaAtEnd && (getToken(1).kind != RPAREN) } )
  814. ","
  815. {
  816. commaAtEnd = true;
  817. }
  818. ]
  819. [ LOOKAHEAD(0, { emptyLA || commaAtEnd } )
  820. "{" Expression() "}"
  821. ]
  822. }
  823. void expansion_unit() :
  824. {}
  825. {
  826. LOOKAHEAD(1)
  827. /*
  828. * We give this priority over primary expressions which use LOOKAHEAD as the
  829. * name of its identifier.
  830. */
  831. // special handling for javacc keyword
  832. LOOKAHEAD( {getToken(1).kind == IDENTIFIER && getToken(1).image.equals("LOOKAHEAD")} )
  833. <IDENTIFIER> "(" local_lookahead() ")"
  834. |
  835. Block()
  836. |
  837. "[" expansion_choices() "]"
  838. |
  839. "try" "{" expansion_choices() "}"
  840. ( "catch" "(" Name() <IDENTIFIER> ")" Block() )*
  841. [ "finally" Block() ]
  842. |
  843. LOOKAHEAD( identifier() | StringLiteral() | "<" | PrimaryExpression() "=" )
  844. [
  845. LOOKAHEAD(PrimaryExpression() "=")
  846. PrimaryExpression() "="
  847. ]
  848. ( regular_expression() | identifier() Arguments() )
  849. |
  850. "(" expansion_choices() ")" ( "+" | "*" | "?" )?
  851. }
  852. void regular_expression() :
  853. {}
  854. {
  855. StringLiteral()
  856. |
  857. LOOKAHEAD(3)
  858. "<" [ [ "#" ] identifier() ":" ] complex_regular_expression_choices() ">"
  859. |
  860. LOOKAHEAD(2)
  861. "<" identifier() ">"
  862. |
  863. "<"
  864. // special handling for javacc keyword
  865. LOOKAHEAD( {getToken(1).kind == IDENTIFIER && getToken(1).image.equals("EOF")} )
  866. <IDENTIFIER>
  867. ">"
  868. }
  869. void complex_regular_expression_choices() :
  870. {}
  871. {
  872. complex_regular_expression() ( "|" complex_regular_expression() )*
  873. }
  874. void complex_regular_expression() :
  875. {}
  876. {
  877. ( complex_regular_expression_unit() )+
  878. }
  879. void complex_regular_expression_unit() :
  880. {}
  881. {
  882. StringLiteral()
  883. |
  884. "<" identifier() ">"
  885. |
  886. character_list()
  887. |
  888. "(" complex_regular_expression_choices() ")" ( "+" | "*" | "?" )?
  889. }
  890. void character_list() :
  891. {}
  892. {
  893. [ "~" ] "[" [ character_descriptor() ( "," character_descriptor() )* ] "]"
  894. }
  895. void character_descriptor() :
  896. {}
  897. {
  898. StringLiteral() [ "-" StringLiteral() ]
  899. }
  900. String identifier() :
  901. {
  902. Token t = null;
  903. }
  904. {
  905. t=<IDENTIFIER>
  906. {
  907. return t.image;
  908. }
  909. }
  910. /**********************************************
  911. * THE JJTREE PRODUCTIONS START HERE *
  912. **********************************************/
  913. void node_descriptor() :
  914. {}
  915. {
  916. "#" ( <IDENTIFIER> | <VOID> )
  917. [
  918. LOOKAHEAD(1)
  919. "(" [ ">" ] node_descriptor_expression() ")"
  920. ]
  921. }
  922. JAVACODE
  923. void node_descriptor_expression()
  924. {
  925. Token tok;
  926. int nesting = 1;
  927. while (true) {
  928. tok = getToken(1);
  929. if (tok.kind == 0) {
  930. throw new ParseException();
  931. }
  932. if (tok.kind == LPAREN) nesting++;
  933. if (tok.kind == RPAREN) {
  934. nesting--;
  935. if (nesting == 0) break;
  936. }
  937. tok = getNextToken();
  938. }
  939. }
  940. /* javacc productions */
  941. void IntegerLiteral() :
  942. {}
  943. {
  944. <INTEGER_LITERAL>
  945. }
  946. void StringLiteral() :
  947. {}
  948. {
  949. <STRING_LITERAL>
  950. }
  951. /*****************************************
  952. * THE JAVA LANGUAGE GRAMMAR STARTS HERE *
  953. *****************************************/
  954. /*
  955. * Program structuring syntax follows.
  956. */
  957. CUNode getJavaRootNode(int tab_size) :
  958. {
  959. CUNode n = null;
  960. }
  961. {
  962. n = JavaCompilationUnit(tab_size)
  963. {
  964. return n;
  965. }
  966. }
  967. /**
  968. * Main entry point for parsing the PARSER section in javacc files. Use
  969. * JavaCompilationUnit as main entry point for parsing java files.
  970. * @return a CUNode, which is parent or root node of all other nodes.
  971. */
  972. CUNode CompilationUnit(int tab_size):
  973. {
  974. setTabSize(tab_size);
  975. CUNode n = new CUNode();
  976. TigerNode a;
  977. String packageName = "";
  978. ImportNode in = null;
  979. }
  980. {
  981. try {
  982. (
  983. [ packageName=PackageDeclaration() ]
  984. ( in=ImportDeclaration() { n.addImport(in); } )*
  985. // TypeDeclaration, this will be one or more classes or
  986. // interfaces, add these as child nodes of the root node
  987. (
  988. a=TypeDeclaration()
  989. { n.addChild(a); }
  990. )*
  991. )
  992. }
  993. catch(ParseException pe) {
  994. error_skipto(SEMICOLON);
  995. }
  996. {
  997. n.setPackageName(packageName);
  998. return n;
  999. }
  1000. }
  1001. /**
  1002. * Main entry point for parsing java files.
  1003. * @return a CUNode, which is parent or root node of all other nodes.
  1004. */
  1005. CUNode JavaCompilationUnit(int tab_size):
  1006. {
  1007. CUNode n = null;
  1008. Token end_t = null;
  1009. }
  1010. {
  1011. try {
  1012. (
  1013. n = CompilationUnit(tab_size)
  1014. // read the whole file
  1015. end_t=<EOF>
  1016. )
  1017. }
  1018. catch(ParseException pe) {
  1019. error_skipto(SEMICOLON);
  1020. }
  1021. {
  1022. if (end_t != null) {
  1023. n.setEndLocation(getLocation(end_t));
  1024. }
  1025. return n;
  1026. }
  1027. }
  1028. String PackageDeclaration():
  1029. {
  1030. TigerNode name = null;
  1031. }
  1032. {
  1033. try {
  1034. "package" name=Name() ";"
  1035. }
  1036. catch(ParseException pe) {
  1037. error_skipto(SEMICOLON);
  1038. }
  1039. {
  1040. return name == null ? "" : name.getName();
  1041. }
  1042. }
  1043. /**
  1044. * @return just the package name, without the 'import' or 'static' or '.*', e.g.
  1045. * "import java.util.*;" will return "java.util". A fully qualified import will
  1046. * return the full classname, e.g. "import java.util.List;" will return
  1047. * "java.util.List", this is also the case with static imports, e.g.
  1048. * "import static java.lang.Math.PI;" will return "java.lang.Math.PI".
  1049. */
  1050. ImportNode ImportDeclaration():
  1051. {
  1052. TigerNode name = null;
  1053. }
  1054. {
  1055. try {
  1056. "import" [ "static" ] name=Name() [ "." "*" ] ";"
  1057. }
  1058. catch(ParseException pe) {
  1059. error_skipto(SEMICOLON);
  1060. }
  1061. {
  1062. if (name != null) {
  1063. ImportNode in = new ImportNode(name.getName());
  1064. in.setStartLocation(name.getStartLocation());
  1065. in.setEndLocation(name.getEndLocation());
  1066. return in;
  1067. }
  1068. return null;
  1069. }
  1070. }
  1071. /*
  1072. * Modifiers. We match all modifiers in a single rule to reduce the chances of
  1073. * syntax errors for simple modifier mistakes. It will also enable us to give
  1074. * better error messages.
  1075. */
  1076. Modifier Modifiers():
  1077. {
  1078. int modifiers = 0;
  1079. Token t = null;
  1080. Modifier m = new Modifier();
  1081. }
  1082. {
  1083. (
  1084. LOOKAHEAD(2)
  1085. (
  1086. t="public" { modifiers |= ModifierSet.PUBLIC; adjustModifier(m, t);}
  1087. |
  1088. t="static" { modifiers |= ModifierSet.STATIC; adjustModifier(m, t);}
  1089. |
  1090. t="protected" { modifiers |= ModifierSet.PROTECTED; adjustModifier(m, t);}
  1091. |
  1092. t="private" { modifiers |= ModifierSet.PRIVATE; adjustModifier(m, t);}
  1093. |
  1094. t="final" { modifiers |= ModifierSet.FINAL; adjustModifier(m, t);}
  1095. |
  1096. t="abstract" { modifiers |= ModifierSet.ABSTRACT; adjustModifier(m, t);}
  1097. |
  1098. t="synchronized" { modifiers |= ModifierSet.SYNCHRONIZED; adjustModifier(m, t);}
  1099. |
  1100. t="native" { modifiers |= ModifierSet.NATIVE; adjustModifier(m, t);}
  1101. |
  1102. t="transient" { modifiers |= ModifierSet.TRANSIENT; adjustModifier(m, t);}
  1103. |
  1104. t="volatile" { modifiers |= ModifierSet.VOLATILE; adjustModifier(m, t);}
  1105. |
  1106. t="strictfp" { modifiers |= ModifierSet.STRICTFP; adjustModifier(m, t);}
  1107. |
  1108. Annotation()
  1109. )
  1110. )*
  1111. {
  1112. m.modifiers = modifiers;
  1113. return m;
  1114. }
  1115. }
  1116. /*
  1117. * Declaration syntax follows.
  1118. */
  1119. // Handle classes, interfaces, enums, and annotations.
  1120. TigerNode TypeDeclaration():
  1121. {
  1122. Modifier modifier;
  1123. TigerNode tn = null;
  1124. }
  1125. {
  1126. try {
  1127. ";" /// is this the semi-colon that I need to handle at the end of a class??
  1128. |
  1129. modifier = Modifiers()
  1130. (
  1131. tn=ClassOrInterfaceDeclaration(modifier)
  1132. |
  1133. tn=EnumDeclaration(modifier)
  1134. |
  1135. AnnotationTypeDeclaration(modifier) { tn = null; }
  1136. )
  1137. }
  1138. catch(ParseException pe) {
  1139. error_skipto(SEMICOLON);
  1140. }
  1141. {
  1142. return tn;
  1143. }
  1144. }
  1145. /**
  1146. * @return a ClassNode or an InterfaceNode
  1147. */
  1148. TigerNode ClassOrInterfaceDeclaration(Modifier m):
  1149. {
  1150. boolean isInterface = false;
  1151. Token t = null;
  1152. TigerNode kids = null; // only need the children of this node
  1153. String type_params = "";
  1154. List extends_list = null;
  1155. List implements_list = null;
  1156. Token type = null;
  1157. }
  1158. {
  1159. try {
  1160. ( type="class" | type="interface" { isInterface = true; } )
  1161. t=<IDENTIFIER>
  1162. [ type_params = TypeParameters() ]
  1163. [ extends_list=ExtendsList(isInterface) ]
  1164. [ implements_list=ImplementsList(isInterface) ]
  1165. kids=ClassOrInterfaceBody(isInterface)
  1166. /* danson, added this check for trailing semi-colon. Apparently, this has been
  1167. legal since the beginning of Java, some sort of a C hold-over. Sun's latest
  1168. Java 1.5 compiler doesn't mind it, but this parser whined if the class has a
  1169. semi-colon after the last }. The original Java1.5.jj file that this parser
  1170. is based on does NOT whine, so I've done something to change the base behaviour.
  1171. See below, I probably broke this in ClassOrInterfaceBody. */
  1172. [ LOOKAHEAD(2) <SEMICOLON> ]
  1173. }
  1174. catch(ParseException pe) {
  1175. error_skipto(SEMICOLON);
  1176. }
  1177. {
  1178. ClassNode node = isInterface ? new InterfaceNode(t.image, m.modifiers) : new ClassNode(t.image, m.modifiers);
  1179. if (isInterface)
  1180. results.incInterfaceCount();
  1181. else
  1182. results.incClassCount();
  1183. if (m.beginColumn > -1) {
  1184. node.setStartLocation(getLocation(m) );
  1185. }
  1186. else {
  1187. node.setStartLocation(getLocation(type));
  1188. }
  1189. if (kids != null)
  1190. node.setEndLocation(kids.getEndLocation());
  1191. // add the child nodes, don't need the 'kids' node itself, it's just a holder
  1192. // for the nodes I want (although I do want the end location).
  1193. if (kids != null && kids.getChildren() != null)
  1194. node.addChildren(kids.getChildren());
  1195. node.setTypeParams(type_params);
  1196. node.setExtendsList(extends_list);
  1197. node.setImplementsList(implements_list);
  1198. return node;
  1199. }
  1200. }
  1201. /**
  1202. * @return a list of sidekick.java.node.Types representing items in an 'extends'
  1203. * list, e.g. the "Bar" in "public class Foo extends Bar"
  1204. */
  1205. List ExtendsList(boolean isInterface):
  1206. {
  1207. boolean extendsMoreThanOne = false;
  1208. List list = new ArrayList(); // a list of Types
  1209. Type type_s = null;
  1210. Type type_a = null;
  1211. }
  1212. {
  1213. try {
  1214. "extends" type_s=ClassOrInterfaceType() { list.add(type_s); }
  1215. ( "," type_a=ClassOrInterfaceType() { extendsMoreThanOne = true; list.add(type_a); } )*
  1216. }
  1217. catch(ParseException pe) {
  1218. error_skipto(SEMICOLON);
  1219. }
  1220. {
  1221. if (extendsMoreThanOne && !isInterface)
  1222. throw new ParseException("A class cannot extend more than one other class");
  1223. return list;
  1224. }
  1225. }
  1226. /**
  1227. * @return a list of sidekick.java.node.Types representing items in an 'implements'
  1228. * list, e.g. the "Bar" and "Serializable" in "public class Foo implements Bar, Serializable"
  1229. */
  1230. List ImplementsList(boolean isInterface):
  1231. {
  1232. List list = new ArrayList();
  1233. Type type_s = null;
  1234. Type type_a = null;
  1235. }
  1236. {
  1237. try {
  1238. "implements" type_s=ClassOrInterfaceType() { list.add(type_s); }
  1239. ( "," type_a=ClassOrInterfaceType() { list.add(type_a); } )*
  1240. }
  1241. catch(ParseException pe) {
  1242. error_skipto(SEMICOLON);
  1243. }
  1244. {
  1245. if (isInterface)
  1246. throw new ParseException("An interface cannot implement other interfaces");
  1247. return list;
  1248. }
  1249. }
  1250. /**
  1251. * @return an EnumNode
  1252. */
  1253. TigerNode EnumDeclaration(Modifier m):
  1254. {
  1255. Token t = null;
  1256. Token start_t = null;
  1257. Location end_loc = null;
  1258. }
  1259. {
  1260. try {
  1261. start_t="enum" t=<IDENTIFIER>
  1262. [ ImplementsList(false) ]
  1263. end_loc=EnumBody()
  1264. }
  1265. catch(ParseException pe) {
  1266. if (t == null) {
  1267. // handle the case where old code used 'enum' as a variable name
  1268. ParseException e = new ParseException("Parse error at line " + start_t.beginLine + ", column " + start_t.beginColumn + ". Encountered: 'enum' as an identifier, 'enum' is a keyword.");
  1269. addException(e);
  1270. return null;
  1271. }
  1272. else
  1273. error_skipto(SEMICOLON);
  1274. }
  1275. {
  1276. if (t == null) {
  1277. // handle the case where old code used 'enum' as a variable name
  1278. ParseException e = new ParseException("Parse error at line " + start_t.beginLine + ", column " + start_t.beginColumn + ". Encountered: 'enum' as an identifier, 'enum' is a keyword.");
  1279. addException(e);
  1280. return null;
  1281. }
  1282. EnumNode node = new EnumNode(t.image, m.modifiers);
  1283. if (start_t != null) {
  1284. if (m.beginColumn == -1)
  1285. node.setStartLocation(getLocation(start_t));
  1286. else
  1287. node.setStartLocation(getLocation(m));
  1288. }
  1289. if (end_loc != null)
  1290. node.setEndLocation(end_loc);
  1291. return node;
  1292. }
  1293. }
  1294. // returns the end location of the enum body
  1295. Location EnumBody():
  1296. {
  1297. Token t = null;
  1298. }
  1299. {
  1300. try {
  1301. "{"
  1302. EnumConstant() ( "," EnumConstant() )*
  1303. [ ";" ( ClassOrInterfaceBodyDeclaration(false) )* ]
  1304. t="}"
  1305. }
  1306. catch(ParseException pe) {
  1307. error_skipto(SEMICOLON);
  1308. }
  1309. {
  1310. return t == null ? null : getLocation(t);
  1311. }
  1312. }
  1313. /// what is this? Should I be handling it?
  1314. void EnumConstant():
  1315. {}
  1316. {
  1317. try {
  1318. <IDENTIFIER> [ Arguments() ] [ ClassOrInterfaceBody(false) ]
  1319. }
  1320. catch(ParseException pe) {
  1321. error_skipto(SEMICOLON);
  1322. }
  1323. }
  1324. /**
  1325. * @return a string representing a generics type, e.g. the "<String>" in
  1326. * "List<String> list = new List();", the string will contain the angle brackets.
  1327. */
  1328. String TypeParameters():
  1329. {
  1330. String s = "<";
  1331. String a = "";
  1332. }
  1333. {
  1334. try {
  1335. (
  1336. "<"
  1337. a=TypeParameter()
  1338. { s += a; }
  1339. (
  1340. ","
  1341. { s += ","; }
  1342. a=TypeParameter()
  1343. { s += a; }
  1344. )*
  1345. ">"
  1346. )
  1347. }
  1348. catch(ParseException pe) {
  1349. error_skipto(SEMICOLON);
  1350. }
  1351. {
  1352. return s + ">";
  1353. }
  1354. }
  1355. String TypeParameter():
  1356. {
  1357. String s = "";
  1358. Token t = null;
  1359. }
  1360. {
  1361. try {
  1362. (
  1363. t=<IDENTIFIER> [ s=TypeBound() ]
  1364. )
  1365. }
  1366. catch(ParseException pe) {
  1367. error_skipto(SEMICOLON);
  1368. }
  1369. {
  1370. StringBuffer sb = new StringBuffer();
  1371. if (t.image != null)
  1372. sb.append(t.image);
  1373. if (s.length() > 0)
  1374. sb.append(" ").append(s);
  1375. return sb.toString();
  1376. }
  1377. }
  1378. String TypeBound():
  1379. {
  1380. String s = "extends";
  1381. Type type_s = null;
  1382. Type type_a = null;
  1383. }
  1384. {
  1385. try {
  1386. (
  1387. "extends"
  1388. type_a=ClassOrInterfaceType()
  1389. { s += " " + type_a.toString(); }
  1390. (
  1391. "&"
  1392. { s += " & "; }
  1393. type_a=ClassOrInterfaceType()
  1394. { s += type_a.toString(); }
  1395. )*
  1396. )
  1397. }
  1398. catch(ParseException pe) {
  1399. error_skipto(SEMICOLON);
  1400. }
  1401. {
  1402. return s;
  1403. }
  1404. }
  1405. /**
  1406. * @return a node representing the contents of a Class or Interface body. The
  1407. * returned node is simply a holder for the contents, it is the children of this
  1408. * node that is useful as they are the methods and fields of the class or
  1409. * interface.
  1410. */
  1411. TigerNode ClassOrInterfaceBody(boolean isInterface):
  1412. {
  1413. TigerNode parent = new TigerNode("", -1);
  1414. TigerNode child;
  1415. Token start_t = null;
  1416. Token end_t = null;
  1417. }
  1418. {
  1419. try {
  1420. (
  1421. start_t="{"
  1422. (
  1423. child=ClassOrInterfaceBodyDeclaration(isInterface)
  1424. { if (child != null) parent.addChild(child); }
  1425. )*
  1426. end_t="}"
  1427. )
  1428. }
  1429. catch(ParseException pe) {
  1430. error_skipto(SEMICOLON);
  1431. }
  1432. {
  1433. if (start_t != null)
  1434. parent.setStartLocation(getLocation(start_t));
  1435. if (end_t != null)
  1436. parent.setEndLocation(getLocation(end_t));
  1437. return parent.getChildren() != null ? parent : null;
  1438. }
  1439. }
  1440. /**
  1441. * @return one of several different nodes, could be a ClassNode, EnumNode,
  1442. * ConstructorNode, FieldNode, MethodNode, or an InterfaceNode.
  1443. */
  1444. TigerNode ClassOrInterfaceBodyDeclaration(boolean isInterface):
  1445. {
  1446. // see note above (~ line 510), I think my changes here have broken the test for a
  1447. // trailing ; after a class body.
  1448. boolean isNestedInterface = false;
  1449. Modifier m;
  1450. TigerNode a = null;
  1451. TigerNode initializer = null;
  1452. String type_params = null;
  1453. }
  1454. {
  1455. try {
  1456. (
  1457. LOOKAHEAD(2)
  1458. initializer=Initializer()
  1459. {
  1460. if (isInterface)
  1461. throw new ParseException("An interface cannot have initializers");
  1462. if (initializer != null)
  1463. return initializer;
  1464. }
  1465. |
  1466. m = Modifiers() // Just get all the modifiers out of the way. If you want to do
  1467. // more checks, pass the modifiers down to the member
  1468. (
  1469. a=ClassOrInterfaceDeclaration(m)
  1470. |
  1471. a=EnumDeclaration(m)
  1472. |
  1473. LOOKAHEAD( [ TypeParameters() ] <IDENTIFIER> "(" )
  1474. a=ConstructorDeclaration(m)
  1475. |
  1476. LOOKAHEAD( Type() <IDENTIFIER> ( "[" "]" )* ( "," | "=" | ";" ) )
  1477. a=FieldDeclaration(m)
  1478. |
  1479. a=MethodDeclaration(m)
  1480. )
  1481. |
  1482. ";" /// is this the trailing semi-colon??
  1483. )
  1484. }
  1485. catch(ParseException pe) {
  1486. error_skipto(SEMICOLON);
  1487. }
  1488. {
  1489. return a;
  1490. }
  1491. }
  1492. /**
  1493. * @return a FieldNode
  1494. */
  1495. TigerNode FieldDeclaration(Modifier m):
  1496. {
  1497. Type type = null;
  1498. TigerNode name = null;
  1499. TigerNode a;
  1500. Token t = null;
  1501. }
  1502. {
  1503. try {
  1504. (
  1505. // Modifiers are already matched in the caller
  1506. /// might need to change this, I'm collecting multiple declarations into a single
  1507. /// field, which seems to be okay, e.g. I'm putting "int x = 0, y = 6" into a
  1508. /// field with Type "int" and name "x, y". It might be better to create individual
  1509. /// nodes for each, so for this example, this method could return 2 fields, one
  1510. /// for "int x" and one for "int y".
  1511. type=Type() name=VariableDeclarator() ( "," a=VariableDeclarator() { name.setName(name.getName() + ", " + a.getName()); })* t=";"
  1512. )
  1513. }
  1514. catch(ParseException pe) {
  1515. error_skipto(SEMICOLON);
  1516. }
  1517. {
  1518. FieldNode fn = new FieldNode(name.getName(), m.modifiers, type);
  1519. if (fn.isPrimitive())
  1520. results.incPrimitiveFieldCount();
  1521. else
  1522. results.incReferenceFieldCount();
  1523. if (m.beginColumn == -1)
  1524. fn.setStartLocation(type.getStartLocation());
  1525. else
  1526. fn.setStartLocation(getLocation(m)); //type.getStartLocation());
  1527. fn.setEndLocation(getLocation(t));
  1528. return fn;
  1529. }
  1530. }
  1531. TigerNode VariableDeclarator():
  1532. {
  1533. TigerNode s = null;
  1534. }
  1535. {
  1536. try {
  1537. (
  1538. s=VariableDeclaratorId() [ "=" VariableInitializer() ]
  1539. )
  1540. }
  1541. catch(ParseException pe) {
  1542. error_skipto(SEMICOLON);
  1543. }
  1544. {
  1545. return s;
  1546. }
  1547. }
  1548. TigerNode VariableDeclaratorId():
  1549. {
  1550. Token t = null;
  1551. }
  1552. {
  1553. try {
  1554. t=<IDENTIFIER> ( "[" "]" )*
  1555. }
  1556. catch(ParseException pe) {
  1557. error_skipto(SEMICOLON);
  1558. }
  1559. {
  1560. TigerNode tn = new TigerNode(t.image, 0);
  1561. tn.setStartLocation(new Location(t.beginLine, t.beginColumn));
  1562. tn.setEndLocation(new Location(t.beginLine, t.beginColumn + t.image.length()));
  1563. return tn;
  1564. }
  1565. }
  1566. void VariableInitializer():
  1567. {}
  1568. {
  1569. try {
  1570. ArrayInitializer()
  1571. |
  1572. Expression()
  1573. }
  1574. catch(ParseException pe) {
  1575. error_skipto(SEMICOLON);
  1576. }
  1577. }
  1578. void ArrayInitializer():
  1579. {}
  1580. {
  1581. try {
  1582. "{" [ VariableInitializer() ( LOOKAHEAD(2) "," VariableInitializer() )* ] [ "," ] "}"
  1583. }
  1584. catch(ParseException pe) {
  1585. error_skipto(SEMICOLON);
  1586. }
  1587. }
  1588. /**
  1589. * @return a MethodNode
  1590. */
  1591. TigerNode MethodDeclaration(Modifier m):
  1592. {
  1593. String type_params = "";
  1594. Type return_type = null;
  1595. MethodNode m_node = null;
  1596. List name_list = null;
  1597. int line_number = -1;
  1598. BlockNode block = null;
  1599. Location endLoc = null;
  1600. Token t = null;
  1601. }
  1602. {
  1603. try {
  1604. (
  1605. // Modifiers already matched in the caller!
  1606. [ type_params = TypeParameters() ]
  1607. return_type = ResultType()
  1608. m_node = MethodDeclarator() [ "throws" name_list=NameList() ]
  1609. ( block = Block() | t=";" )
  1610. )
  1611. }
  1612. catch(ParseException pe) {
  1613. error_skipto(SEMICOLON);
  1614. }
  1615. {
  1616. if (m_node == null)
  1617. return null;
  1618. MethodNode node = new MethodNode();
  1619. node.setName(m_node.getName());
  1620. if (m.beginColumn == -1)
  1621. node.setStartLocation(new Location(m_node.getStartLocation().line, 0));
  1622. else
  1623. node.setStartLocation(getLocation(m));
  1624. node.setModifiers(m.modifiers);
  1625. node.setFormalParams(m_node.getFormalParams());
  1626. node.setReturnType(return_type.toString());
  1627. node.setTypeParams(type_params);
  1628. node.setThrows(name_list);
  1629. if (block == null && t != null) {
  1630. node.setEndLocation(getLocation(t));
  1631. }
  1632. else {
  1633. node.addChildren(block.getChildren());
  1634. node.setEndLocation(block.getEndLocation());
  1635. }
  1636. results.incMethodCount();
  1637. return node;
  1638. }
  1639. }
  1640. MethodNode MethodDeclarator():
  1641. {
  1642. Token t = null;
  1643. String s = "";
  1644. List f = null;
  1645. }
  1646. {
  1647. try {
  1648. (
  1649. t=<IDENTIFIER> f=FormalParameters() ( "[" "]" )*
  1650. )
  1651. }
  1652. catch(ParseException pe) {
  1653. error_skipto(SEMICOLON);
  1654. }
  1655. {
  1656. if (t == null)
  1657. return null;
  1658. MethodNode node = new MethodNode();
  1659. node.setName(t.image);
  1660. node.setStartLocation(getLocation(t));
  1661. node.setFormalParams(f);
  1662. return node;
  1663. }
  1664. }
  1665. List FormalParameters():
  1666. {
  1667. ArrayList params = new ArrayList();
  1668. Parameter a = null;
  1669. }
  1670. {
  1671. try {
  1672. (
  1673. "("
  1674. [
  1675. a=FormalParameter()
  1676. { params.add(a); }
  1677. (
  1678. ","
  1679. a=FormalParameter()
  1680. { params.add(a); }
  1681. )*
  1682. ]
  1683. ")"
  1684. )
  1685. }
  1686. catch(ParseException pe) {
  1687. error_skipto(SEMICOLON);
  1688. }
  1689. {
  1690. return params;
  1691. }
  1692. }
  1693. Parameter FormalParameter():
  1694. {
  1695. Parameter param = new Parameter();
  1696. TigerNode n;
  1697. Type type_a = null;
  1698. Token t = null;
  1699. }
  1700. {
  1701. try {
  1702. (
  1703. [
  1704. t="final"
  1705. {
  1706. param.setFinal(true);
  1707. param.setStartLocation(getLocation(t));
  1708. }
  1709. ]
  1710. type_a=Type()
  1711. { param.setType(type_a); }
  1712. [
  1713. "..."
  1714. { param.setVarArg(true); }
  1715. ]
  1716. n=VariableDeclaratorId()
  1717. {
  1718. param.setName(n.getName());
  1719. if (t == null)
  1720. param.setStartLocation(n.getStartLocation());
  1721. param.setEndLocation(n.getEndLocation());
  1722. }
  1723. )
  1724. }
  1725. catch(ParseException pe) {
  1726. error_skipto(SEMICOLON);
  1727. }
  1728. {
  1729. return param;
  1730. }
  1731. }
  1732. ConstructorNode ConstructorDeclaration(Modifier m):
  1733. {
  1734. Token t = null;
  1735. List params = null;
  1736. List name_list = null;
  1737. String type_params = null;
  1738. Token end_t = null;
  1739. TigerNode child = null;
  1740. ConstructorNode cn = new ConstructorNode();
  1741. cn.setModifiers(m.modifiers);
  1742. }
  1743. {
  1744. try {
  1745. (
  1746. [ type_params=TypeParameters() ]
  1747. t=<IDENTIFIER> params=FormalParameters() [ "throws" name_list=NameList() ]
  1748. "{"
  1749. [ LOOKAHEAD(ExplicitConstructorInvocation()) ExplicitConstructorInvocation() ]
  1750. ( child=BlockStatement() { if (child != null) cn.addChildren(child.getChildren()); })*
  1751. end_t="}"
  1752. )
  1753. }
  1754. catch(ParseException pe) {
  1755. error_skipto(SEMICOLON);
  1756. }
  1757. {
  1758. cn.setName(t.image);
  1759. if (ModifierSet.toString(m.modifiers).equals("")) {
  1760. // no modifiers, so use constructor name for start location
  1761. cn.setStartLocation(new Location(t.beginLine, 0));
  1762. }
  1763. else {
  1764. cn.setStartLocation(getLocation(m));
  1765. }
  1766. cn.setEndLocation(getLocation(end_t));
  1767. cn.setFormalParams(params);
  1768. cn.setTypeParams(type_params);
  1769. cn.setThrows(name_list);
  1770. return cn;
  1771. }
  1772. }
  1773. void ExplicitConstructorInvocation():
  1774. {}
  1775. {
  1776. try {
  1777. LOOKAHEAD("this" Arguments() ";")
  1778. "this" Arguments() ";"
  1779. |
  1780. [ LOOKAHEAD(2) PrimaryExpression() "." ] "super" Arguments() ";"
  1781. }
  1782. catch(ParseException pe) {
  1783. error_skipto(SEMICOLON);
  1784. }
  1785. }
  1786. /**
  1787. * @return an InitializerNode, this handles static initializer blocks
  1788. */
  1789. TigerNode Initializer():
  1790. {
  1791. Token t = null;
  1792. BlockNode block = null;
  1793. }
  1794. {
  1795. try {
  1796. [ t="static" ] block=Block()
  1797. }
  1798. catch(ParseException pe) {
  1799. error_skipto(SEMICOLON);
  1800. }
  1801. {
  1802. if (t != null && block != null) {
  1803. TigerNode node = new InitializerNode(t.beginLine);
  1804. node.setStartLocation(block.getStartLocation());
  1805. node.setEndLocation(block.getEndLocation());
  1806. node.addChild(block);
  1807. return node;
  1808. }
  1809. return null;
  1810. }
  1811. }
  1812. /*
  1813. * Type, name and expression syntax follows.
  1814. */
  1815. Type Type():
  1816. {
  1817. Type s = null;
  1818. }
  1819. {
  1820. try {
  1821. (
  1822. LOOKAHEAD(2) s=ReferenceType()
  1823. |
  1824. s=PrimitiveType()
  1825. )
  1826. }
  1827. catch(ParseException pe) {
  1828. error_skipto(SEMICOLON);
  1829. }
  1830. {
  1831. return s;
  1832. }
  1833. }
  1834. Type ReferenceType():
  1835. {
  1836. Type s = null;
  1837. }
  1838. {
  1839. try {
  1840. (
  1841. s=PrimitiveType() ( LOOKAHEAD(2) "[" "]" )+
  1842. |
  1843. ( s=ClassOrInterfaceType() ) ( LOOKAHEAD(2) "[" "]" )*
  1844. )
  1845. }
  1846. catch(ParseException pe) {
  1847. error_skipto(SEMICOLON);
  1848. }
  1849. {
  1850. return s;
  1851. }
  1852. }
  1853. Type ClassOrInterfaceType():
  1854. {
  1855. Type s = new Type();
  1856. String type_arg = "";
  1857. Token t = null;
  1858. }
  1859. {
  1860. try {
  1861. (
  1862. t=<IDENTIFIER> [ LOOKAHEAD(2) type_arg=TypeArguments() ]
  1863. {
  1864. s.type = t.image;
  1865. s.typeArgs=type_arg;
  1866. s.setStartLocation(new Location(t.beginLine, t.beginColumn));
  1867. s.setEndLocation(new Location(t.endLine, t.endColumn));
  1868. }
  1869. ( LOOKAHEAD(2) "." t=<IDENTIFIER> [ LOOKAHEAD(2) type_arg=TypeArguments() ]
  1870. {
  1871. s.type += "." + t.image;
  1872. s.typeArgs += type_arg;
  1873. s.setEndLocation(new Location(t.endLine, t.endColumn));
  1874. }