001/*-------------------------------------------------------------------------+ 002| | 003| Copyright 2005-2011 the ConQAT Project | 004| | 005| Licensed under the Apache License, Version 2.0 (the "License"); | 006| you may not use this file except in compliance with the License. | 007| You may obtain a copy of the License at | 008| | 009| http://www.apache.org/licenses/LICENSE-2.0 | 010| | 011| Unless required by applicable law or agreed to in writing, software | 012| distributed under the License is distributed on an "AS IS" BASIS, | 013| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 014| See the License for the specific language governing permissions and | 015| limitations under the License. | 016+-------------------------------------------------------------------------*/ 017package eu.cqse.check.framework.shallowparser.languages.fortran; 018 019import static eu.cqse.check.framework.scanner.ETokenType.ALLOCATE; 020import static eu.cqse.check.framework.scanner.ETokenType.ASYNCHRONOUS; 021import static eu.cqse.check.framework.scanner.ETokenType.BLOCK; 022import static eu.cqse.check.framework.scanner.ETokenType.CALL; 023import static eu.cqse.check.framework.scanner.ETokenType.CASE; 024import static eu.cqse.check.framework.scanner.ETokenType.CLASS; 025import static eu.cqse.check.framework.scanner.ETokenType.CLOSE; 026import static eu.cqse.check.framework.scanner.ETokenType.COLON; 027import static eu.cqse.check.framework.scanner.ETokenType.COMMA; 028import static eu.cqse.check.framework.scanner.ETokenType.COMMON; 029import static eu.cqse.check.framework.scanner.ETokenType.CONCURRENT; 030import static eu.cqse.check.framework.scanner.ETokenType.CONTAINS; 031import static eu.cqse.check.framework.scanner.ETokenType.CONTINUE; 032import static eu.cqse.check.framework.scanner.ETokenType.CRITICAL; 033import static eu.cqse.check.framework.scanner.ETokenType.CYCLE; 034import static eu.cqse.check.framework.scanner.ETokenType.DATA; 035import static eu.cqse.check.framework.scanner.ETokenType.DEALLOCATE; 036import static eu.cqse.check.framework.scanner.ETokenType.DEFAULT; 037import static eu.cqse.check.framework.scanner.ETokenType.DO; 038import static eu.cqse.check.framework.scanner.ETokenType.DOUBLE_COLON; 039import static eu.cqse.check.framework.scanner.ETokenType.ELEMENTAL; 040import static eu.cqse.check.framework.scanner.ETokenType.ELSE; 041import static eu.cqse.check.framework.scanner.ETokenType.ELSEIF; 042import static eu.cqse.check.framework.scanner.ETokenType.ELSEWHERE; 043import static eu.cqse.check.framework.scanner.ETokenType.END; 044import static eu.cqse.check.framework.scanner.ETokenType.ENDFILE; 045import static eu.cqse.check.framework.scanner.ETokenType.ENTRY; 046import static eu.cqse.check.framework.scanner.ETokenType.ENUM; 047import static eu.cqse.check.framework.scanner.ETokenType.ENUMERATOR; 048import static eu.cqse.check.framework.scanner.ETokenType.EOL; 049import static eu.cqse.check.framework.scanner.ETokenType.EQUIVALENCE; 050import static eu.cqse.check.framework.scanner.ETokenType.EXIT; 051import static eu.cqse.check.framework.scanner.ETokenType.EXTERNAL; 052import static eu.cqse.check.framework.scanner.ETokenType.FORALL; 053import static eu.cqse.check.framework.scanner.ETokenType.FUNCTION; 054import static eu.cqse.check.framework.scanner.ETokenType.GOTO; 055import static eu.cqse.check.framework.scanner.ETokenType.IDENTIFIER; 056import static eu.cqse.check.framework.scanner.ETokenType.IF; 057import static eu.cqse.check.framework.scanner.ETokenType.IMPLICIT; 058import static eu.cqse.check.framework.scanner.ETokenType.INQUIRE; 059import static eu.cqse.check.framework.scanner.ETokenType.INTEGER_LITERAL; 060import static eu.cqse.check.framework.scanner.ETokenType.INTERFACE; 061import static eu.cqse.check.framework.scanner.ETokenType.IS; 062import static eu.cqse.check.framework.scanner.ETokenType.LOCK; 063import static eu.cqse.check.framework.scanner.ETokenType.LPAREN; 064import static eu.cqse.check.framework.scanner.ETokenType.MODULE; 065import static eu.cqse.check.framework.scanner.ETokenType.NAMELIST; 066import static eu.cqse.check.framework.scanner.ETokenType.NULLIFY; 067import static eu.cqse.check.framework.scanner.ETokenType.OPEN; 068import static eu.cqse.check.framework.scanner.ETokenType.PARAMETER; 069import static eu.cqse.check.framework.scanner.ETokenType.PAUSE; 070import static eu.cqse.check.framework.scanner.ETokenType.PRINT; 071import static eu.cqse.check.framework.scanner.ETokenType.PRIVATE; 072import static eu.cqse.check.framework.scanner.ETokenType.PROCEDURE; 073import static eu.cqse.check.framework.scanner.ETokenType.PROGRAM; 074import static eu.cqse.check.framework.scanner.ETokenType.PUBLIC; 075import static eu.cqse.check.framework.scanner.ETokenType.PURE; 076import static eu.cqse.check.framework.scanner.ETokenType.RECURSIVE; 077import static eu.cqse.check.framework.scanner.ETokenType.RETURN; 078import static eu.cqse.check.framework.scanner.ETokenType.REWIND; 079import static eu.cqse.check.framework.scanner.ETokenType.REWRITE; 080import static eu.cqse.check.framework.scanner.ETokenType.RPAREN; 081import static eu.cqse.check.framework.scanner.ETokenType.SELECT; 082import static eu.cqse.check.framework.scanner.ETokenType.SEMICOLON; 083import static eu.cqse.check.framework.scanner.ETokenType.SEQUENCE; 084import static eu.cqse.check.framework.scanner.ETokenType.STOP; 085import static eu.cqse.check.framework.scanner.ETokenType.SUBMODULE; 086import static eu.cqse.check.framework.scanner.ETokenType.SUBROUTINE; 087import static eu.cqse.check.framework.scanner.ETokenType.THEN; 088import static eu.cqse.check.framework.scanner.ETokenType.TYPE; 089import static eu.cqse.check.framework.scanner.ETokenType.UNLOCK; 090import static eu.cqse.check.framework.scanner.ETokenType.USE; 091import static eu.cqse.check.framework.scanner.ETokenType.VOLATILE; 092import static eu.cqse.check.framework.scanner.ETokenType.WAIT; 093import static eu.cqse.check.framework.scanner.ETokenType.WHERE; 094import static eu.cqse.check.framework.scanner.ETokenType.WHILE; 095import static eu.cqse.check.framework.scanner.ETokenType.WRITE; 096import static eu.cqse.check.framework.shallowparser.languages.fortran.FortranShallowParser.EFortranParserStates.IN_ENUM; 097import static eu.cqse.check.framework.shallowparser.languages.fortran.FortranShallowParser.EFortranParserStates.IN_METHOD; 098import static eu.cqse.check.framework.shallowparser.languages.fortran.FortranShallowParser.EFortranParserStates.IN_MODULE; 099import static eu.cqse.check.framework.shallowparser.languages.fortran.FortranShallowParser.EFortranParserStates.IN_SELECT; 100import static eu.cqse.check.framework.shallowparser.languages.fortran.FortranShallowParser.EFortranParserStates.IN_TYPE; 101import static eu.cqse.check.framework.shallowparser.languages.fortran.FortranShallowParser.EFortranParserStates.TOP_LEVEL; 102 103import java.util.EnumSet; 104 105import org.conqat.lib.commons.region.Region; 106 107import eu.cqse.check.framework.scanner.ETokenType; 108import eu.cqse.check.framework.shallowparser.SubTypeNames; 109import eu.cqse.check.framework.shallowparser.framework.EShallowEntityType; 110import eu.cqse.check.framework.shallowparser.framework.RecognizerBase; 111import eu.cqse.check.framework.shallowparser.framework.ShallowParserBase; 112import eu.cqse.check.framework.shallowparser.languages.fortran.FortranShallowParser.EFortranParserStates; 113 114/** 115 * A shallow parser for Fortran. 116 * 117 * This parser supports the free form of Fortran 2008. 118 */ 119public class FortranShallowParser extends ShallowParserBase<EFortranParserStates> { 120 121 /** All possible states of a FortranShallowParser. */ 122 public static enum EFortranParserStates { 123 /** Top-level state. */ 124 TOP_LEVEL, 125 126 /** Inside a module. */ 127 IN_MODULE, 128 129 /** Inside a type declaration. */ 130 IN_TYPE, 131 132 /** Inside a enum declaration. */ 133 IN_ENUM, 134 135 /** Inside a method's body. */ 136 IN_METHOD, 137 138 /** Inside a select statement. */ 139 IN_SELECT, 140 } 141 142 /** All tokens that indicate a simple statement. */ 143 private static final EnumSet<ETokenType> STATEMENT_TOKENS = EnumSet.of(ALLOCATE, ASYNCHRONOUS, CALL, CLOSE, COMMON, 144 CONTINUE, CYCLE, DATA, DEALLOCATE, ENDFILE, ENTRY, EQUIVALENCE, EXIT, EXTERNAL, GOTO, IDENTIFIER, 145 INTEGER_LITERAL, INQUIRE, LOCK, NAMELIST, NULLIFY, OPEN, PAUSE, PARAMETER, PRINT, RETURN, REWIND, REWRITE, 146 STOP, UNLOCK, WAIT, WRITE, VOLATILE); 147 148 /** All parser states in which statements can occur. */ 149 private static final EFortranParserStates[] STATEMENT_STATES = { IN_MODULE, IN_METHOD }; 150 151 /** All modifiers that can be used in front of a function declaration. */ 152 private static final EnumSet<ETokenType> FUNCTION_MODIFIERS = EnumSet.of(MODULE, ELEMENTAL, PURE, RECURSIVE); 153 154 /** All modifiers that can be used in front of a procedure declaration. */ 155 private static final EnumSet<ETokenType> PROCEDURE_MODIFIERS = EnumSet.of(MODULE); 156 157 /** All token types that can be used as a type. */ 158 private static final EnumSet<ETokenType> TYPE_TOKENS = EnumSet.of(IDENTIFIER, TYPE, CLASS); 159 160 /** Constructor. */ 161 public FortranShallowParser() { 162 super(EFortranParserStates.class, TOP_LEVEL); 163 createTopLevelRules(); 164 createInModuleRules(); 165 createInTypeRules(); 166 createInEnumRule(); 167 createMethodRules(); 168 createStatementRules(); 169 createAnyStateRules(); 170 } 171 172 /** 173 * Create rules for parsing top-level constructs like modules or program. 174 */ 175 private void createTopLevelRules() { 176 // module 177 inState(TOP_LEVEL).sequence(MODULE, IDENTIFIER).createNode(EShallowEntityType.MODULE, 0, 1).sequence(EOL) 178 .parseUntil(IN_MODULE).sequence(END).optional(MODULE).optional(IDENTIFIER).endNode(); 179 180 // program 181 inState(TOP_LEVEL).sequence(PROGRAM, IDENTIFIER).createNode(EShallowEntityType.METHOD, 0, -1).sequence(EOL) 182 .parseUntil(IN_MODULE).sequence(END).optional(PROGRAM).optional(IDENTIFIER).endNode(); 183 184 // submodule 185 inState(TOP_LEVEL).sequence(SUBMODULE).skipToWithNesting(IDENTIFIER, LPAREN, RPAREN) 186 .createNode(EShallowEntityType.MODULE, 0, -1).sequence(EOL).parseUntil(IN_MODULE).sequence(END) 187 .optional(SUBMODULE).optional(IDENTIFIER).endNode(); 188 } 189 190 /** Create rules for parsing some meta information. */ 191 private void createAnyStateRules() { 192 inAnyState().sequence(IMPLICIT).createNode(EShallowEntityType.META, 0).skipTo(EOL).endNode(); 193 194 inAnyState().sequence(CONTAINS).createNode(EShallowEntityType.META, 0).endNode(); 195 196 inState(IN_MODULE, IN_METHOD).sequence(USE).createNode(EShallowEntityType.META, 0).skipTo(EOL).endNode(); 197 } 198 199 /** Create rules for parsing the body of a module. */ 200 private void createInModuleRules() { 201 // visibility 202 inState(IN_MODULE).sequence(EnumSet.of(PUBLIC, PRIVATE)).createNode(EShallowEntityType.META, 0).skipTo(EOL) 203 .endNode(); 204 205 // interface with name 206 inState(IN_MODULE).sequence(INTERFACE, IDENTIFIER).createNode(EShallowEntityType.TYPE, 0, 1) 207 .parseUntil(IN_MODULE).sequence(END).optional(INTERFACE).sequence(IDENTIFIER).endNode(); 208 209 // interface with no name 210 inState(IN_MODULE).sequence(INTERFACE).createNode(EShallowEntityType.TYPE, 0).parseUntil(IN_MODULE) 211 .sequence(END).optional(INTERFACE).endNode(); 212 213 // type declaration 214 RecognizerBase<EFortranParserStates> typeAlternative = inState(IN_MODULE).sequence(TYPE); 215 typeAlternative.optional(DOUBLE_COLON).sequence(IDENTIFIER, EOL).createNode(EShallowEntityType.TYPE, 0, -2) 216 .parseUntil(IN_TYPE).sequence(END).optional(TYPE).optional(IDENTIFIER).endNode(); 217 typeAlternative.sequence(COMMA).skipBefore(EnumSet.of(DOUBLE_COLON, EOL)) 218 .sequence(DOUBLE_COLON, IDENTIFIER, EOL).createNode(EShallowEntityType.TYPE, 0, -2).parseUntil(IN_TYPE) 219 .sequence(END).optional(TYPE).optional(IDENTIFIER).endNode(); 220 221 // enum declaration 222 inState(IN_MODULE).sequence(ENUM).skipBefore(EnumSet.of(DOUBLE_COLON, EOL)) 223 .sequence(DOUBLE_COLON, IDENTIFIER, EOL).createNode(EShallowEntityType.TYPE, 0, -2).parseUntil(IN_ENUM) 224 .sequence(END).optional(ENUM).optional(IDENTIFIER).endNode(); 225 } 226 227 /** Create rules for parsing type bodies. */ 228 private void createInTypeRules() { 229 // sequence 230 inState(IN_TYPE).sequence(SEQUENCE, EOL).createNode(EShallowEntityType.META, 0).endNode(); 231 232 // attribute 233 inState(IN_TYPE).sequence(TYPE_TOKENS).skipBefore(EnumSet.of(DOUBLE_COLON, EOL)) 234 .sequence(DOUBLE_COLON, IDENTIFIER).createNode(EShallowEntityType.ATTRIBUTE, SubTypeNames.ATTRIBUTE, -1) 235 .skipTo(EOL).endNode(); 236 237 // procedure 238 inState(IN_TYPE).sequence(PROCEDURE, DOUBLE_COLON, IDENTIFIER).skipTo(EOL) 239 .createNode(EShallowEntityType.METHOD, 0, 2).endNode(); 240 } 241 242 /** Create rule for parsing an enum body. */ 243 private void createInEnumRule() { 244 inState(IN_ENUM).sequence(ENUMERATOR).optional(DOUBLE_COLON).sequence(IDENTIFIER) 245 .createNode(EShallowEntityType.ATTRIBUTE, 0, -1).skipTo(EOL).endNode(); 246 } 247 248 /** Create rules for parsing method declarations. */ 249 private void createMethodRules() { 250 // subroutine 251 inState(TOP_LEVEL, IN_MODULE, IN_METHOD).sequence(SUBROUTINE, IDENTIFIER) 252 .createNode(EShallowEntityType.METHOD, 0, 1).skipTo(EOL).parseUntil(IN_METHOD).sequence(END) 253 .optional(SUBROUTINE).optional(IDENTIFIER).endNode(); 254 255 // function 256 inState(TOP_LEVEL, IN_MODULE, IN_METHOD).optional(FUNCTION_MODIFIERS, TYPE_TOKENS) 257 .skipBefore(EnumSet.of(FUNCTION, EOL)).sequence(FUNCTION, IDENTIFIER) 258 .createNode(EShallowEntityType.METHOD, -2, -1).skipTo(EOL).parseUntil(IN_METHOD).sequence(END) 259 .optional(FUNCTION).optional(IDENTIFIER).endNode(); 260 261 // variable declaration 262 inState(IN_MODULE, IN_METHOD).sequence(TYPE_TOKENS).skipBefore(EnumSet.of(DOUBLE_COLON, EOL)) 263 .sequence(DOUBLE_COLON, IDENTIFIER) 264 .createNode(EShallowEntityType.STATEMENT, SubTypeNames.LOCAL_VARIABLE, -1).skipTo(EOL).endNode(); 265 266 // procedure 267 inState(IN_MODULE, IN_TYPE).repeated(PROCEDURE_MODIFIERS).sequence(PROCEDURE, IDENTIFIER) 268 .createNode(EShallowEntityType.METHOD, -2, -1).skipTo(EOL).endNode(); 269 } 270 271 /** 272 * Create rules for parsing statements. All constructs are taken from 273 * http://de.wikibooks.org/wiki/Fortran:_Fortran_95: 274 * _Verzweigungen_und_Schleifen. 275 */ 276 private void createStatementRules() { 277 createArithmeticIfRule(); 278 279 createSingleLineConstructs(IF, WHERE, FORALL); 280 281 createLoopRules(); 282 createSelectRules(); 283 284 createElseIfRule(); 285 createContinuedConstructRules(IF, ELSEIF, ELSE, THEN); 286 createContinuedConstructRules(WHERE, ELSEWHERE, ELSEWHERE, null); 287 288 createConcurrentRules(); 289 290 createSimpleStatementRules(); 291 } 292 293 /** 294 * Create rule for parsing the arithmetic if construct (e.g. 'if 295 * (<arithmetic expression>) 1, 2, 3') 296 */ 297 private void createArithmeticIfRule() { 298 inState(STATEMENT_STATES).sequence(IF).skipNested(LPAREN, RPAREN) 299 .sequence(INTEGER_LITERAL, COMMA, INTEGER_LITERAL, COMMA, INTEGER_LITERAL, EOL) 300 .createNode(EShallowEntityType.STATEMENT, 0).endNode(); 301 } 302 303 /** 304 * Create rules for parsing constructs with a condition in parenthesis and 305 * one statement in the same line for all given token types. A single line 306 * construct is e.g. 'if (<condition>) <statement>' 307 */ 308 private void createSingleLineConstructs(ETokenType... constructTokens) { 309 for (ETokenType constructToken : constructTokens) { 310 inState(STATEMENT_STATES).sequence(constructToken, LPAREN).skipToWithNesting(RPAREN, LPAREN, RPAREN) 311 .sequenceBefore(STATEMENT_TOKENS).createNode(EShallowEntityType.STATEMENT, 0).parseOnce(IN_METHOD) 312 .sequence(EOL).endNode(); 313 } 314 } 315 316 /** Create rules for parsing block and critical sections. */ 317 private void createConcurrentRules() { 318 inState(STATEMENT_STATES).sequence(BLOCK).createNode(EShallowEntityType.STATEMENT, 0).skipTo(EOL) 319 .parseUntil(IN_METHOD).sequence(END).optional(BLOCK).endNode(); 320 321 inState(STATEMENT_STATES).sequence(CRITICAL).createNode(EShallowEntityType.STATEMENT, 0).skipTo(EOL) 322 .parseUntil(IN_METHOD).sequence(END).optional(CRITICAL).endNode(); 323 } 324 325 /** Create rules for parsing a select statement. */ 326 private void createSelectRules() { 327 finishConstructWithOptionalName(inState(STATEMENT_STATES).optional(IDENTIFIER, COLON).markStart() 328 .sequence(SELECT).optional(EnumSet.of(CASE, TYPE)).sequence(LPAREN) 329 .skipToWithNesting(RPAREN, LPAREN, RPAREN).sequence(EOL) 330 .createNode(EShallowEntityType.STATEMENT, SubTypeNames.SELECT).parseUntil(IN_SELECT), SELECT); 331 332 RecognizerBase<EFortranParserStates> labelAlternative = inState(IN_SELECT) 333 .sequence(EnumSet.of(CASE, TYPE, CLASS)).optional(IS).skipNested(LPAREN, RPAREN).optional(IDENTIFIER) 334 .sequence(EOL).createNode(EShallowEntityType.META, 0).parseUntil(IN_METHOD); 335 labelAlternative.sequenceBefore(END).endNode(); 336 labelAlternative.sequenceBefore(EnumSet.of(CASE, TYPE, CLASS)).endNodeWithContinuation(); 337 338 inState(IN_SELECT).sequence(EnumSet.of(CASE, CLASS), DEFAULT).optional(IDENTIFIER).sequence(EOL) 339 .createNode(EShallowEntityType.META, 0).parseUntil(IN_METHOD).sequenceBefore(END).endNode(); 340 } 341 342 /** Create rules for parsing do and forall loops. */ 343 private void createLoopRules() { 344 // do/do concurrent/do while loop 345 finishConstructWithOptionalName( 346 inState(STATEMENT_STATES).optional(IDENTIFIER, COLON).markStart().sequence(DO) 347 .optional(EnumSet.of(CONCURRENT, WHILE)) 348 .createNode(EShallowEntityType.STATEMENT, new Region(0, -1)).skipTo(EOL).parseUntil(IN_METHOD), 349 DO); 350 351 // forall loop 352 finishConstructWithOptionalName(inState(STATEMENT_STATES).optional(IDENTIFIER, COLON).markStart() 353 .sequence(FORALL, LPAREN).skipToWithNesting(RPAREN, LPAREN, RPAREN) 354 .createNode(EShallowEntityType.STATEMENT, 0).sequence(EOL).parseUntil(IN_METHOD), FORALL); 355 } 356 357 /** 358 * Create a special rule for handling 'else if' that consists of two 359 * separate tokens. 360 */ 361 private void createElseIfRule() { 362 RecognizerBase<EFortranParserStates> recognizer = inState(STATEMENT_STATES).sequence(ELSE, IF, LPAREN) 363 .skipToWithNesting(RPAREN, LPAREN, RPAREN).sequence(THEN).optional(IDENTIFIER).sequence(EOL) 364 .createNode(EShallowEntityType.STATEMENT, SubTypeNames.ELSE_IF_NOSPACE).parseUntil(IN_METHOD); 365 finishConstructWithOptionalName(recognizer, IF); 366 recognizer.sequenceBefore(EnumSet.of(ELSE, ELSEIF)).endNodeWithContinuation(); 367 } 368 369 /** 370 * Create rules for parsing constructs than can be continued. The given 371 * begin token is the token that begins the construct for e.g. 'if'. The 372 * continuation token can continue a construct, e.g. 'else if'. The final 373 * token is the last unconditional continuation token, e.g. 'else'. The 374 * complete construct is ended with 'end <beginToken>'. The given 375 * suffix token must be recognized after the parenthesis of the construct 376 * e.g. 'then' in an 'if' construct. The suffix token can be null, if there 377 * is none. The construct can be prefixed by a construct name, e.g. 'name:if 378 * (...)' 379 */ 380 private void createContinuedConstructRules(ETokenType beginToken, ETokenType continuationToken, 381 ETokenType finalToken, ETokenType suffixToken) { 382 createContinuedConstructRuleWithName(beginToken, beginToken, EnumSet.of(continuationToken, finalToken), 383 suffixToken, true); 384 createContinuedConstructRuleWithName(beginToken, continuationToken, EnumSet.of(continuationToken, finalToken), 385 suffixToken, false); 386 createEndContinuedConstructRule(beginToken, finalToken); 387 } 388 389 /** 390 * Create a rule for parsing a statement of a construct that can be 391 * continued. The construct token is the token of the construct type, e.g. 392 * 'if'. The statement token is the beginning token of the construct 393 * statement, e.g. 'if' or 'else if'. The given continuation tokens are 394 * those, that can continue the current construct statement. The given 395 * suffix token must be recognized after the parenthesis of the construct 396 * e.g. 'then' in an 'if' construct. The suffix token can be null, if there 397 * is none. If nameInFront is true, an optional name label can prefix the 398 * construct. If it is false, the construct can be followed by a name. 399 */ 400 private void createContinuedConstructRuleWithName(ETokenType constructToken, ETokenType partToken, 401 EnumSet<ETokenType> continuationTokens, ETokenType suffixToken, boolean nameInFront) { 402 RecognizerBase<EFortranParserStates> recognizer = inState(STATEMENT_STATES); 403 if (nameInFront) { 404 recognizer = recognizer.optional(IDENTIFIER, COLON); 405 } 406 recognizer = recognizer.markStart().sequence(partToken, LPAREN).skipToWithNesting(RPAREN, LPAREN, RPAREN); 407 if (suffixToken != null) { 408 recognizer = recognizer.sequence(suffixToken); 409 } 410 if (!nameInFront) { 411 recognizer = recognizer.optional(IDENTIFIER); 412 } 413 recognizer = recognizer.sequence(EOL).createNode(EShallowEntityType.STATEMENT, 0).parseUntil(IN_METHOD); 414 415 finishConstructWithOptionalName(recognizer, constructToken); 416 recognizer.sequenceBefore(continuationTokens).endNodeWithContinuation(); 417 } 418 419 /** 420 * Create a rule for parsing the end of a continued construct. The construct 421 * token is the token of the construct type, e.g. 'if'. The final token is 422 * the beginning token of the statement, e.g. 'else'. An optional identifier 423 * can follow for named constructs. 424 */ 425 private void createEndContinuedConstructRule(ETokenType constructToken, ETokenType finalToken) { 426 RecognizerBase<EFortranParserStates> finalAlternative = inState(STATEMENT_STATES).sequence(finalToken) 427 .optional(IDENTIFIER).sequence(EOL).createNode(EShallowEntityType.STATEMENT, 0).parseUntil(IN_METHOD); 428 429 finishConstructWithOptionalName(finalAlternative, constructToken); 430 } 431 432 /** 433 * Finishes the given recognizer with 'end' and the optional given token 434 * type. An optional identifier can follow for named constructs. 435 */ 436 private static void finishConstructWithOptionalName(RecognizerBase<EFortranParserStates> recognizer, 437 ETokenType constructType) { 438 recognizer.sequence(END).optional(constructType).optional(IDENTIFIER).sequence(EOL).endNode(); 439 } 440 441 /** Creates rules for parsing simple statements. */ 442 private void createSimpleStatementRules() { 443 inState(STATEMENT_STATES).sequence(STATEMENT_TOKENS) 444 .createNode(EShallowEntityType.STATEMENT, SubTypeNames.SIMPLE_STATEMENT, 0) 445 .skipBefore(EnumSet.of(EOL, SEMICOLON)).optional(SEMICOLON).endNode(); 446 } 447}