001/*-------------------------------------------------------------------------+ 002| | 003| Copyright (c) 2009-2017 CQSE GmbH | 004| | 005+-------------------------------------------------------------------------*/ 006package eu.cqse.check.framework.shallowparser.languages.cobol; 007 008import static eu.cqse.check.framework.scanner.ETokenType.*; 009import static eu.cqse.check.framework.shallowparser.framework.EShallowEntityType.ATTRIBUTE; 010import static eu.cqse.check.framework.shallowparser.framework.EShallowEntityType.META; 011import static eu.cqse.check.framework.shallowparser.framework.EShallowEntityType.METHOD; 012import static eu.cqse.check.framework.shallowparser.framework.EShallowEntityType.MODULE; 013import static eu.cqse.check.framework.shallowparser.framework.EShallowEntityType.STATEMENT; 014import static eu.cqse.check.framework.shallowparser.framework.EShallowEntityType.TYPE; 015import static eu.cqse.check.framework.shallowparser.languages.cobol.ECobolParserState.IN_STATEMENT; 016import static eu.cqse.check.framework.shallowparser.languages.cobol.ECobolParserState.TOP_LEVEL; 017import static eu.cqse.check.framework.shallowparser.languages.cobol.EStatementEndType.SCOPE; 018import static eu.cqse.check.framework.shallowparser.languages.cobol.EStatementEndType.SIMPLE; 019 020import java.util.EnumSet; 021import java.util.List; 022 023import org.conqat.lib.commons.region.Region; 024 025import eu.cqse.check.framework.postprocessor.cobol.SectionParagraphToMethodProcessor; 026import eu.cqse.check.framework.scanner.ETokenType; 027import eu.cqse.check.framework.scanner.IToken; 028import eu.cqse.check.framework.shallowparser.SubTypeNames; 029import eu.cqse.check.framework.shallowparser.framework.EShallowEntityType; 030import eu.cqse.check.framework.shallowparser.framework.RecognizerBase; 031import eu.cqse.check.framework.shallowparser.framework.ShallowEntity; 032import eu.cqse.check.framework.shallowparser.framework.ShallowParserBase; 033 034/** 035 * Shallow parser for the Cobol language. It considers the following language 036 * reference documentation links: 037 * <code>http://publibfp.boulder.ibm.com/epubs/pdf/igy6lr10.pdf</code> 038 * <code>https://open-cobol.sourceforge.io/guides/OpenCOBOL%20Programmers%20Guide.pdf</code> 039 * <code>http://www.cs.vu.nl/grammarware/cobol</code> We try to make it 040 * compatible with the fixed and free form versions that Cobol code may be 041 * written in. 042 */ 043public class CobolShallowParser extends ShallowParserBase<ECobolParserState> { 044 045 /** Identifier and string tokens */ 046 private static final EnumSet<ETokenType> IDENTIFIER_AND_STRING_LITERALS = EnumSet.of(IDENTIFIER, STRING_LITERAL); 047 048 /** Identifier and numeric literal tokens */ 049 private static final EnumSet<ETokenType> IDENTIFIER_AND_NUMERIC_LITERALS = EnumSet.of(IDENTIFIER, INTEGER_LITERAL, 050 FLOATING_POINT_LITERAL); 051 052 /** Identifier and literals tokens */ 053 private static final EnumSet<ETokenType> IDENTIFIER_AND_LITERALS = EnumSet.of(IDENTIFIER, INTEGER_LITERAL, 054 FLOATING_POINT_LITERAL, STRING_LITERAL); 055 056 /** Identifier and literals tokens */ 057 private static final EnumSet<ETokenType> IDENTIFIER_LITERALS_AND_ZERO = EnumSet.of(IDENTIFIER, INTEGER_LITERAL, 058 FLOATING_POINT_LITERAL, STRING_LITERAL, ZERO); 059 060 /** Literal types */ 061 private static final EnumSet<ETokenType> LITERAL_TYPES = EnumSet.of(STRING_LITERAL, INTEGER_LITERAL, 062 FLOATING_POINT_LITERAL); 063 064 /** 065 * Apparently, compiler options such as PGMNAME can also be used as variable 066 * names. 067 */ 068 private static final EnumSet<ETokenType> VALID_VARIABLE_NAMES = EnumSet.of(IDENTIFIER, COMPILER_OPTIONS); 069 070 /** Constant subtype name for section */ 071 public static final String SECTION_SUBTYPE_NAME = "section"; 072 073 /** Constant subtype name for paragraph */ 074 public static final String PARAGRAPH_SUBTYPE_NAME = "paragraph"; 075 076 /** Constructor. */ 077 public CobolShallowParser() { 078 super(ECobolParserState.class, TOP_LEVEL); 079 createTopLevelRules(); 080 } 081 082 /** 083 * Create rules for matching divisions. Though there are 4 divisions, we take 084 * only the ID division as being in top level and everything afterwards are 085 * parsed as belonging to a program (or module), method, class, factory or an 086 * object body so the parsed form looks like modern trendy languages. 087 */ 088 private void createTopLevelRules() { 089 createRuleForDivision(TOP_LEVEL, EnumSet.of(ID, IDENTIFICATION)); 090 091 createRuleForProgramType(PROGRAM_ID, MODULE, PROGRAM, true); 092 // Enterprise COBOL for z/OS adds more entities that can be identified 093 createRuleForProgramType(CLASS_ID, TYPE, CLASS, true); 094 createRuleForProgramType(METHOD_ID, METHOD, ETokenType.METHOD, true); 095 createRuleForProgramType(FUNCTION_ID, METHOD, ETokenType.METHOD, true); 096 createRuleForProgramType(OBJECT, TYPE, OBJECT, false); 097 createRuleForProgramType(FACTORY, TYPE, FACTORY, false); 098 099 createRulesForEnvironmentDivision(); 100 createRulesForDataDivision(); 101 createRulesForProcedureDivision(); 102 createRulesForCompilerDirectiveStatements(); 103 } 104 105 /** 106 * Create rule to identify a program, method, factory, object or class. 107 * Factories and objects do not need to have names like programs, methods and 108 * classes in Enterprise COBOL for z/OS 109 */ 110 private void createRuleForProgramType(ETokenType startType, EShallowEntityType entityType, ETokenType endType, 111 boolean canIncludeEndIdentifier) { 112 RecognizerBase<ECobolParserState> recognizer = inAnyState().sequence(startType, DOT); 113 if (canIncludeEndIdentifier) { 114 recognizer = recognizer.sequence(EnumSet.of(IDENTIFIER, STRING_LITERAL)); 115 if (startType == PROGRAM_ID) { 116 recognizer = recognizer.optional(IS).optional(EnumSet.of(RECURSIVE, COMMON, INITIAL)).skipTo(DOT); 117 } else if (startType == CLASS_ID) { 118 recognizer = recognizer.optional(INHERITS, IDENTIFIER).sequence(DOT); 119 } else { 120 recognizer = recognizer.sequence(DOT); 121 } 122 123 // To have the test{@link 124 // CobolShallowParserTest#testMinimalProgramStructure} not return 125 // an incompletely parsed node program node (since there is no end 126 // node), we use parseUntilOrEof() 127 recognizer = recognizer.createNode(entityType, 2).parseUntilOrEof(TOP_LEVEL); 128 } else { 129 recognizer = recognizer.createNode(entityType, 0).parseUntilOrEof(TOP_LEVEL); 130 } 131 132 recognizer.sequence(END, endType, DOT).endNode(); 133 if (canIncludeEndIdentifier) { 134 recognizer.sequence(END, endType, IDENTIFIER, DOT).endNode(); 135 } 136 } 137 138 /** 139 * Create rule for a division. 140 */ 141 private void createRuleForDivision(ECobolParserState state, Object division) { 142 inState(state).sequence(division, DIVISION).createNode(META, 1, 0).skipTo(DOT).endNode(); 143 } 144 145 /** 146 * Create rules for paragraphs and sections in the environment division. 147 */ 148 private void createRulesForEnvironmentDivision() { 149 createRuleForDivision(TOP_LEVEL, ENVIRONMENT); 150 151 completeRule(inState(TOP_LEVEL).sequence(CONFIGURATION, SECTION).createNode(META, new Region(0, 1)), null, 152 SIMPLE); 153 154 RecognizerBase<ECobolParserState> sourceComputerSubRecognizer = createRecognizer( 155 start -> start.sequence(IDENTIFIER).optional(WITH).optional(DEBUGGING, MODE)); 156 RecognizerBase<ECobolParserState> sourceComputerRecognizer = inState(TOP_LEVEL).sequence(SOURCE_COMPUTER, DOT) 157 .createNode(META, 0).optionalSubRecognizer(sourceComputerSubRecognizer); 158 completeRule(sourceComputerRecognizer, null, SIMPLE); 159 160 createRulesForObjectComputer(); 161 createRulesForSpecialNamesParagraph(); 162 createRulesForRepositoryParagraph(); 163 164 // CONSTRAINTS, CLASS-ATTRIBUTES & ASSEMBLY-ATTRIBUTES paragraphs 165 completeRule(inState(TOP_LEVEL).sequence(EnumSet.of(CONSTRAINTS, ASSEMBLY_ATTRIBUTES, CLASS_ATTRIBUTES)) 166 .createNode(META, 0), null, SIMPLE); 167 168 completeRule( 169 inState(TOP_LEVEL).sequence(CUSTOM_ATTRIBUTE).createNode(META, 0).optional(IS).sequence(IDENTIFIER), 170 null, SIMPLE); 171 172 createRulesForIOSection(); 173 } 174 175 /** 176 * Create rules for REPOSITORY paragraph. Rules here match 'import' statements. 177 */ 178 private void createRulesForRepositoryParagraph() { 179 completeRule(inState(TOP_LEVEL).sequence(REPOSITORY).createNode(META, 0), null, SIMPLE); 180 181 completeRule(inState(TOP_LEVEL).sequence(INTERFACE, IDENTIFIER).createNode(META, 0, 1) 182 .subRecognizer(getRepositoryInterfaceClassSubRecognizer()), null, SIMPLE); 183 completeRule(inState(TOP_LEVEL).sequence(EnumSet.of(PROGRAM, PROPERTY, DELEGATE, ENUM), IDENTIFIER) 184 .createNode(META, 0, 1).optional(AS, LITERAL_TYPES), null, SIMPLE); 185 186 RecognizerBase<ECobolParserState> functionNameRecognizer = createRecognizer( 187 start -> start.sequence(AS, LITERAL_TYPES)); 188 functionNameRecognizer.sequence(INTRINSIC); 189 RecognizerBase<ECobolParserState> functionSubRecognizer = createRecognizer( 190 start -> start.sequence(ALL, INTRINSIC)); 191 functionSubRecognizer.repeatedSubRecognizer(getRepeatedSequenceRecognizer(IDENTIFIER)) 192 .optionalSubRecognizer(functionNameRecognizer); 193 RecognizerBase<ECobolParserState> functionRecognizer = inState(TOP_LEVEL).sequence(FUNCTION).createNode(META, 0) 194 .subRecognizer(functionSubRecognizer); 195 completeRule(functionRecognizer, null, SIMPLE); 196 } 197 198 /** 199 * Create rules for SPECIAL-NAMES paragraph. 200 */ 201 private void createRulesForSpecialNamesParagraph() { 202 completeRule(inState(TOP_LEVEL).sequence(SPECIAL_NAMES).createNode(META, 0), null, SIMPLE); 203 204 createRuleForSwitchClause(); 205 createRuleForAlphabetClause(); 206 createRuleForSymbolicClause(); 207 createRuleForClassClauses(); 208 209 RecognizerBase<ECobolParserState> currencySubrecognizer = createRecognizer( 210 start -> start.optional(WITH).sequence(PICTURE, SYMBOL, STRING_LITERAL)); 211 RecognizerBase<ECobolParserState> currencyRecognizer = inState(TOP_LEVEL).sequence(CURRENCY).optional(SIGN) 212 .optional(IS).sequence(STRING_LITERAL).createNode(META, 0, 3) 213 .optionalSubRecognizer(currencySubrecognizer); 214 completeRule(currencyRecognizer, null, SIMPLE); 215 216 completeRule( 217 inState(TOP_LEVEL).sequence(DECIMAL_POINT).createNode(META, 0, "comma").optional(IS).sequence(COMMA), 218 null, SIMPLE); 219 completeRule(inState(TOP_LEVEL).sequence(XML_SCHEMA, IDENTIFIER).optional(IS).sequence(IDENTIFIER_AND_LITERALS) 220 .createNode(META, 0, 1), null, SIMPLE); 221 completeRule(inState(TOP_LEVEL).sequence(NUMERIC, SIGN).optional(IS).sequence(TRAILING, SEPARATE) 222 .createNode(META, new Region(0, 1)), null, SIMPLE); 223 completeRule(inState(TOP_LEVEL).sequence(CALL_CONVENTION, INTEGER_LITERAL).createNode(META, 0).optional(IS) 224 .sequence(IDENTIFIER), null, SIMPLE); 225 completeRule(inState(TOP_LEVEL).sequence(CONSOLE).createNode(META, 0).optional(IS).sequence(CRT), null, SIMPLE); 226 completeRule(inState(TOP_LEVEL).sequence(CURSOR).createNode(META, 0).optional(IS).sequence(IDENTIFIER), null, 227 SIMPLE); 228 completeRule(inState(TOP_LEVEL).sequence(CRT, STATUS).createNode(META, new Region(0, 1)).optional(IS) 229 .sequence(IDENTIFIER), null, SIMPLE); 230 } 231 232 /** 233 * Creates a rule for the CLASS clause as used in the SPECIAL-NAMES & REPOSITORY 234 * paragraphs. 235 */ 236 private void createRuleForClassClauses() { 237 RecognizerBase<ECobolParserState> classRecognizer = inState(TOP_LEVEL).sequence(CLASS, IDENTIFIER) 238 .createNode(META, 0, 1); 239 classRecognizer.sequence(IS).repeatedSubRecognizer(getLiteralThroughAlsoRecognizer(false)); 240 classRecognizer.sequence(IMPLEMENTS).repeatedSubRecognizer(getRepeatedSequenceRecognizer(IDENTIFIER)); 241 classRecognizer.subRecognizer(getRepositoryInterfaceClassSubRecognizer()); 242 243 completeRule(classRecognizer, null, SIMPLE); 244 } 245 246 /** 247 * Returns a sub recognizer for matching the INTERFACE & CLASS clauses in the 248 * REPOSITORY paragraph. 249 */ 250 private RecognizerBase<ECobolParserState> getRepositoryInterfaceClassSubRecognizer() { 251 RecognizerBase<ECobolParserState> expandsRecognizer = createRecognizer( 252 start -> start.sequence(EXPANDS, IDENTIFIER, USING, IDENTIFIER)); 253 return createRecognizer(start -> start.optional(AS, LITERAL_TYPES).optionalSubRecognizer(expandsRecognizer)); 254 } 255 256 /** 257 * Create rule for SWITCH clause. 258 */ 259 private void createRuleForSwitchClause() { 260 RecognizerBase<ECobolParserState> isIdentifierRecognizer = createRecognizer( 261 start -> start.optional(IS).sequence(IDENTIFIER)); 262 RecognizerBase<ECobolParserState> statusRecognizer = createRecognizer(start -> start 263 .sequence(EnumSet.of(ON, OFF)).optional(STATUS).optionalSubRecognizer(isIdentifierRecognizer)); 264 RecognizerBase<ECobolParserState> switchSubRecognizer = createRecognizer( 265 start -> start.optionalSubRecognizer(isIdentifierRecognizer).optionalSubRecognizer(statusRecognizer) 266 .optionalSubRecognizer(statusRecognizer)); 267 RecognizerBase<ECobolParserState> switchRecognizer = inState(TOP_LEVEL).sequence(EnumSet.of(SWITCH_0, SWITCH_1, 268 SWITCH_2, SWITCH_3, SWITCH_4, SWITCH_5, SWITCH_6, SWITCH_7, SWITCH_8, IDENTIFIER)) 269 .subRecognizer(switchSubRecognizer).createNode(META, "special-name", 0); 270 271 completeRule(switchRecognizer, null, SIMPLE); 272 } 273 274 /** 275 * Create rule for SYMBOLIC clause 276 */ 277 private void createRuleForSymbolicClause() { 278 RecognizerBase<ECobolParserState> symbolicSubRecognizer = createRecognizer(start -> start.optional(COMMA) 279 .repeatedSubRecognizer(getRepeatedSequenceRecognizer(IDENTIFIER)).sequence(EnumSet.of(IS, ARE)) 280 .repeatedSubRecognizer(getRepeatedSequenceRecognizer(INTEGER_LITERAL))); 281 RecognizerBase<ECobolParserState> symbolicRecognizer = inState(TOP_LEVEL).sequence(SYMBOLIC).createNode(META, 0) 282 .optional(CHARACTERS).repeatedSubRecognizer(symbolicSubRecognizer).optional(IN, IDENTIFIER); 283 284 completeRule(symbolicRecognizer, null, SIMPLE); 285 } 286 287 /** 288 * Create rule for the ALPHABET clause. 289 */ 290 private void createRuleForAlphabetClause() { 291 RecognizerBase<ECobolParserState> alphabetRecognizer = inState(TOP_LEVEL).sequence(ALPHABET, IDENTIFIER) 292 .createNode(META, 0, 1).sequence(IS); 293 alphabetRecognizer.sequence(EnumSet.of(STANDARD_1, STANDARD_2, NATIVE, ASCII, EBCDIC)); 294 alphabetRecognizer.repeatedSubRecognizer(getLiteralThroughAlsoRecognizer(true)); 295 296 completeRule(alphabetRecognizer, null, SIMPLE); 297 } 298 299 /** 300 * Returns a sub recognizer for LITERAL...THROUGH...ALSO pattern 301 */ 302 private RecognizerBase<ECobolParserState> getLiteralThroughAlsoRecognizer(boolean includeAlsoRecognizer) { 303 RecognizerBase<ECobolParserState> alsoRecognizer = createRecognizer( 304 start -> start.optional(COMMA).sequence(ALSO, LITERAL_TYPES)); 305 RecognizerBase<ECobolParserState> literalSubRecognizer = createRecognizer(start -> { 306 RecognizerBase<ECobolParserState> prefix = start.sequence(LITERAL_TYPES); 307 prefix.sequence(EnumSet.of(THROUGH, THRU), LITERAL_TYPES); 308 if (includeAlsoRecognizer) { 309 prefix.repeatedSubRecognizer(alsoRecognizer); 310 } 311 }); 312 return createRecognizer(start -> start.optional(COMMA).subRecognizer(literalSubRecognizer)); 313 } 314 315 /** 316 * Create rules for the OBJECT-COMPUTER paragraph. 317 */ 318 private void createRulesForObjectComputer() { 319 RecognizerBase<ECobolParserState> segmentLimitRecognizer = createRecognizer(start -> start 320 .sequence(SEGMENT_LIMIT).optional(IS).sequence(EnumSet.of(INTEGER_LITERAL, FLOATING_POINT_LITERAL))); 321 RecognizerBase<ECobolParserState> programRecognizer = createRecognizer(start -> start.optional(PROGRAM) 322 .optional(COLLATING).sequence(SEQUENCE).optional(IS).sequence(IDENTIFIER)); 323 RecognizerBase<ECobolParserState> memoryRecognizer = createRecognizer(start -> start.sequence(MEMORY) 324 .optional(SIZE).sequence(INTEGER_LITERAL, EnumSet.of(WORDS, CHARACTERS, MODULES))); 325 RecognizerBase<ECobolParserState> objectComputerRecognizer = inState(TOP_LEVEL).sequence(OBJECT_COMPUTER, DOT) 326 .createNode(META, 0).optional(IDENTIFIER).optionalSubRecognizer(memoryRecognizer) 327 .optionalSubRecognizer(programRecognizer).optionalSubRecognizer(segmentLimitRecognizer); 328 329 completeRule(objectComputerRecognizer, null, SIMPLE); 330 } 331 332 /** 333 * Create rules for the IO Section in the environment division. 334 */ 335 private void createRulesForIOSection() { 336 completeRule(inState(TOP_LEVEL).sequence(INPUT_OUTPUT, SECTION).createNode(META, 0), null, SIMPLE); 337 338 completeRule(inState(TOP_LEVEL).sequence(EnumSet.of(FILE_CONTROL, I_O_CONTROL)).createNode(META, 0), null, 339 SIMPLE); 340 341 inState(TOP_LEVEL).sequence(SELECT).optional(OPTIONAL).markStart().sequence(IDENTIFIER) 342 .createNode(STATEMENT, "select", 0).skipTo(DOT).endNode(); 343 344 createRuleForRerunClause(); 345 RecognizerBase<ECobolParserState> sameRecognizer = inState(TOP_LEVEL).sequence(SAME).createNode(META, 0) 346 .optional(EnumSet.of(RECORD, SORT, SORT_MERGE)).optional(AREA).optional(FOR).sequence(IDENTIFIER) 347 .repeatedSubRecognizer(getRepeatedSequenceRecognizer(IDENTIFIER)); 348 completeRule(sameRecognizer, null, SIMPLE); 349 350 RecognizerBase<ECobolParserState> multipleFileSubRecognizer = createRecognizer( 351 start -> start.optional(COMMA).sequence(IDENTIFIER).optional(POSITION, INTEGER_LITERAL)); 352 RecognizerBase<ECobolParserState> multipleFileRecognizer = inState(TOP_LEVEL).sequence(MULTIPLE, FILE) 353 .createNode(META, new Region(0, 1)).optional(TAPE).optional(CONTAINS) 354 .repeatedSubRecognizer(multipleFileSubRecognizer); 355 completeRule(multipleFileRecognizer, null, SIMPLE); 356 357 createRuleForApplyClause(); 358 } 359 360 /** 361 * Create rule for APPLY clause. 362 */ 363 private void createRuleForApplyClause() { 364 RecognizerBase<ECobolParserState> applyRecognizer = inState(TOP_LEVEL, IN_STATEMENT).sequence(APPLY) 365 .createNode(META, 0); 366 applyRecognizer.sequence(REORG_CRITERIA).optional(TO).sequence(IDENTIFIER).optional(ON).sequence(IDENTIFIER); 367 applyRecognizer.sequence(EnumSet.of(CORE_INDEX, RECORD_OVERFLOW, WRITE_ONLY)).optional(ON) 368 .repeatedSubRecognizer(getRepeatedSequenceRecognizer(IDENTIFIER)); 369 completeRule(applyRecognizer, null, SIMPLE); 370 } 371 372 /** 373 * Create rule for RERUN CLAUSE. 374 */ 375 private void createRuleForRerunClause() { 376 RecognizerBase<ECobolParserState> everyIntegerRecognizer = createRecognizer(start -> { 377 RecognizerBase<ECobolParserState> prefix = start.sequence(INTEGER_LITERAL); 378 prefix.sequence(RECORDS).optional(OF).sequence(IDENTIFIER); 379 prefix.sequence(CLOCK_UNITS); 380 }); 381 382 RecognizerBase<ECobolParserState> everyRecognizer = createRecognizer(start -> { 383 RecognizerBase<ECobolParserState> prefix = start.sequence(EVERY); 384 prefix.sequence(IDENTIFIER); 385 prefix.sequence(END).optional(OF).sequence(EnumSet.of(REEL, UNIT)).optional(OF).sequence(IDENTIFIER); 386 prefix.subRecognizer(everyIntegerRecognizer); 387 }); 388 389 completeRule(inState(TOP_LEVEL).sequence(RERUN).createNode(META, 0).optional(ON, IDENTIFIER) 390 .subRecognizer(everyRecognizer), null, SIMPLE); 391 } 392 393 /** 394 * Create rules for paragraphs and sections in the data division. These are 395 * mainly program variables declarations. 396 */ 397 private void createRulesForDataDivision() { 398 createRuleForDivision(TOP_LEVEL, DATA); 399 400 completeRule(inState(TOP_LEVEL).sequence(EnumSet.of(FILE, WORKING_STORAGE, LOCAL_STORAGE, THREAD_LOCAL_STORAGE, 401 OBJECT_STORAGE, LINKAGE, REPORT, SCREEN), SECTION).createNode(META, 0, 1), null, SIMPLE); 402 403 createRuleForFileDescriptionEntry(); 404 createRuleForDataDescriptionEntries(); 405 } 406 407 /** 408 * Returns the USAGE clause recognizer used in DATA description. 409 */ 410 private RecognizerBase<ECobolParserState> getUsageClauseRecognizer() { 411 RecognizerBase<ECobolParserState> objectRecognizer = createRecognizer(start -> { 412 RecognizerBase<ECobolParserState> prefix = start.sequence(REFERENCE); 413 prefix.sequence(IDENTIFIER); 414 prefix.sequence(FACTORY).optional(OF).sequence(EnumSet.of(ACTIVE_CLASS, IDENTIFIER)) 415 .optional(EnumSet.of(ONLY, EVENT)); 416 }); 417 RecognizerBase<ECobolParserState> usageSubRecognizer = createRecognizer(start -> { 418 RecognizerBase<ECobolParserState> prefix = start.optional(IS); 419 prefix.sequence(EnumSet.of(BINARY, CHARACTER, COMPUTATIONAL, COMP, COMPUTATIONAL_1, COMP_1, COMPUTATIONAL_2, 420 COMP_2, COMPUTATIONAL_3, COMP_3, COMPUTATIONAL_4, COMP_4, COMPUTATIONAL_5, COMP_5, COMPUTATIONAL_X, 421 COMP_X, CONDITIONAL_VALUE, DECIMAL, DISPLAY, EVENT_POINTER, FLOAT_SHORT, FLOAT_LONG, INDEX, 422 MONITOR_POINTER, MUTEX_POINTER, NATIONAL, PACKED_DECIMAL, POINTER, PROCEDURE_POINTER, 423 SEMAPHORE_POINTER, STRING, THREAD_POINTER, IDENTIFIER)); 424 prefix.sequence(PROGRAM_POINTER).optional(TO).optional(IDENTIFIER); 425 prefix.sequence(OBJECT).optionalSubRecognizer(objectRecognizer); 426 prefix.sequence(EnumSet.of(BINARY_CHAR, BINARY_SHORT, BINARY_LONG, BINARY_DOUBLE), 427 EnumSet.of(SIGNED, UNSIGNED)); 428 }); 429 return createRecognizer(start -> start.optional(USAGE).optional(IS).subRecognizer(usageSubRecognizer)); 430 } 431 432 /** 433 * Returns the OCCURS clause recognizer for DATA description. 434 */ 435 private RecognizerBase<ECobolParserState> getOccursClauseRecognizer() { 436 RecognizerBase<ECobolParserState> indexedRecognizer = createRecognizer(start -> start.sequence(INDEXED) 437 .optional(BY).sequence(IDENTIFIER).repeatedSubRecognizer(getRepeatedSequenceRecognizer(IDENTIFIER))); 438 RecognizerBase<ECobolParserState> ascendDescendRecognizer = createRecognizer( 439 start -> start.sequence(EnumSet.of(ASCENDING, DESCENDING)).optional(KEY).optional(IS) 440 .sequence(IDENTIFIER).repeatedSubRecognizer(getRepeatedSequenceRecognizer(IDENTIFIER))); 441 442 return createRecognizer(start -> start.sequence(OCCURS).optional(INTEGER_LITERAL, TO) 443 .repeatedSubRecognizer(getRepeatedSequenceRecognizer(EnumSet.of(ANY, INTEGER_LITERAL))).optional(TIMES) 444 .optionalSubRecognizer(getDependingRecognizer()).repeatedSubRecognizer(ascendDescendRecognizer) 445 .repeatedSubRecognizer(indexedRecognizer)); 446 } 447 448 /** 449 * Returns the DEPENDING sub recognizer used in data division and the GO TO verb 450 * in procedure division 451 */ 452 private RecognizerBase<ECobolParserState> getDependingRecognizer() { 453 return createRecognizer(start -> start.sequence(DEPENDING).optional(ON).sequence(IDENTIFIER)); 454 } 455 456 /** 457 * Create rules for record and level description entries. These are majorly data 458 * variables. 459 */ 460 private void createRuleForDataDescriptionEntries() { 461 RecognizerBase<ECobolParserState> renameRecognizer = createRecognizer( 462 start -> start.sequence(RENAMES, IDENTIFIER).optional(EnumSet.of(THROUGH, THRU), IDENTIFIER)); 463 RecognizerBase<ECobolParserState> classModifierRecognizer = createRecognizer( 464 start -> start.sequence(EnumSet.of(IDENTIFIER, PUBLIC, PRIVATE, PROTECTED, INTERNAL))); 465 RecognizerBase<ECobolParserState> blankRecognizer = createRecognizer( 466 start -> start.sequence(BLANK).optional(WHEN).sequence(EnumSet.of(ZERO, ZEROS, ZEROES))); 467 RecognizerBase<ECobolParserState> justRecognizer = createRecognizer( 468 start -> start.sequence(EnumSet.of(JUSTIFIED, JUST), RIGHT)); 469 RecognizerBase<ECobolParserState> syncRecognizer = createRecognizer( 470 start -> start.sequence(EnumSet.of(SYNC, SYNCHRONIZED)).optional(EnumSet.of(LEFT, RIGHT))); 471 RecognizerBase<ECobolParserState> redefinesRecognizer = createRecognizer( 472 start -> start.sequence(REDEFINES, IDENTIFIER)); 473 RecognizerBase<ECobolParserState> dataDescriptionRecognizer = inState(TOP_LEVEL).sequence(INTEGER_LITERAL) 474 .sequence(EnumSet.of(FILLER, IDENTIFIER)).createNode(ATTRIBUTE, 1) 475 .optionalSubRecognizer(redefinesRecognizer).subRecognizer(getIsClauseRecognizer(), 0, 4) 476 .optionalSubRecognizer(getUsageClauseRecognizer()).optionalSubRecognizer(getOccursClauseRecognizer()) 477 .optionalSubRecognizer(getSignRecognizer()).optionalSubRecognizer(syncRecognizer) 478 .optionalSubRecognizer(justRecognizer).optionalSubRecognizer(blankRecognizer) 479 .optionalSubRecognizer(getPropertyClauseRecognizer()).optionalSubRecognizer(classModifierRecognizer) 480 .optional(ANY, LENGTH).optional(PICTURE_CLAUSE).optionalSubRecognizer(renameRecognizer) 481 .optionalSubRecognizer(getValuesIsAreRecognizer()); 482 483 completeRule(dataDescriptionRecognizer, null, SIMPLE); 484 } 485 486 /** 487 * Returns the IS clause recognizer for DATA description. 488 */ 489 private RecognizerBase<ECobolParserState> getIsClauseRecognizer() { 490 return createRecognizer(start -> start.optional(IS) 491 .sequence(EnumSet.of(EXTERNAL, GLOBAL, TYPEDEF, THREAD_LOCAL)).optional(BY, LITERAL_TYPES)); 492 } 493 494 /** 495 * Returns the VALUE clause recognizer 496 * <code>https://supportline.microfocus.com/documentation/books/nx50/lrpubb.htm</code> 497 */ 498 private RecognizerBase<ECobolParserState> getValuesIsAreRecognizer() { 499 RecognizerBase<ECobolParserState> arithmeticRecognizer = createRecognizer(start -> { 500 RecognizerBase<ECobolParserState> prefix = start.sequence(EnumSet.of(PLUS, MINUS, MULT, DIV, AND, OR)); 501 prefix.sequence(EnumSet.of(INTEGER_LITERAL, NEXT)); 502 prefix.sequence(EnumSet.of(START, LENGTH)).optional(OF).sequence(IDENTIFIER); 503 }); 504 505 RecognizerBase<ECobolParserState> whenRecognizer = createRecognizer(start -> start.optional(WHEN).optional(SET) 506 .optional(TO).sequence(FALSE).optional(IS).sequence(LITERAL_TYPES)); 507 508 RecognizerBase<ECobolParserState> literalRecognizer = createRecognizer(start -> { 509 RecognizerBase<ECobolParserState> prefix = start.optional(COMMA); 510 prefix.optional(LITERAL_TYPES).sequence(EnumSet.of(THROUGH, THRU), LITERAL_TYPES) 511 .optionalSubRecognizer(whenRecognizer); 512 prefix.subRecognizer(arithmeticRecognizer); 513 prefix.repeatedSubRecognizer(getRepeatedSequenceRecognizer(LITERAL_TYPES)).sequence(FROM) 514 .skipNested(LPAREN, RPAREN).optional(TO).skipNested(LPAREN, RPAREN); 515 }); 516 517 RecognizerBase<ECobolParserState> isAreRecognizer = createRecognizer(start -> { 518 RecognizerBase<ECobolParserState> prefix = start.optional(EnumSet.of(IS, ARE)); 519 prefix.sequence(NEXT).optionalSubRecognizer(arithmeticRecognizer); 520 prefix.sequence(EnumSet.of(START, LENGTH)).optional(OF).sequence(IDENTIFIER) 521 .optionalSubRecognizer(arithmeticRecognizer); 522 prefix.sequence(LITERAL_TYPES).repeatedSubRecognizer(literalRecognizer); 523 }); 524 525 return createRecognizer(start -> start.sequence(EnumSet.of(VALUE, VALUES)).subRecognizer(isAreRecognizer)); 526 } 527 528 /** 529 * Returns the SIGN clause recognizer 530 */ 531 private RecognizerBase<ECobolParserState> getSignRecognizer() { 532 RecognizerBase<ECobolParserState> separateCharRecognizer = createRecognizer( 533 start -> start.sequence(SEPARATE).optional(CHARACTER)); 534 return createRecognizer(start -> start.sequence(SIGN).optional(IS).sequence(EnumSet.of(LEADING, TRAILING)) 535 .optionalSubRecognizer(separateCharRecognizer)); 536 } 537 538 /** 539 * Create sub recognizer for the PROPERTY clause 540 */ 541 private RecognizerBase<ECobolParserState> getPropertyClauseRecognizer() { 542 RecognizerBase<ECobolParserState> getSetRecognizer = createRecognizer( 543 start -> start.optional(WITH).sequence(NO, EnumSet.of(GET, SET))); 544 return createRecognizer(start -> start.sequence(PROPERTY).optionalSubRecognizer(getSetRecognizer)); 545 } 546 547 /** 548 * Create rule for the file description ENTRY. 549 */ 550 private void createRuleForFileDescriptionEntry() { 551 RecognizerBase<ECobolParserState> lineRecognizer = createRecognizer( 552 start -> start.optional(LINES).optional(AT).sequence(EnumSet.of(TOP, BOTTOM), IDENTIFIER_AND_LITERALS)); 553 RecognizerBase<ECobolParserState> dataRecognizer = createRecognizer( 554 start -> start.sequence(DATA).sequence(EnumSet.of(RECORD, RECORDS)).optional(EnumSet.of(IS, ARE)) 555 .sequence(IDENTIFIER).repeatedSubRecognizer(getRepeatedSequenceRecognizer(IDENTIFIER))); 556 RecognizerBase<ECobolParserState> recordingRecognizer = createRecognizer(start -> start.sequence(RECORDING) 557 .optional(MODE).optional(IS).sequence(EnumSet.of(FIXED, VARIABLE, IDENTIFIER))); 558 RecognizerBase<ECobolParserState> valueOfRecognizer = createRecognizer( 559 start -> start.sequence(VALUE, OF, EnumSet.of(FILE_ID, IDENTIFIER)).optional(IS) 560 .repeatedSubRecognizer(getRepeatedSequenceRecognizer(IDENTIFIER_AND_LITERALS))); 561 RecognizerBase<ECobolParserState> recordRecognizer = createRecognizer( 562 start -> start.sequence(RECORD).subRecognizer(getContainsRecognizer())); 563 RecognizerBase<ECobolParserState> blockRecognizer = createRecognizer( 564 start -> start.sequence(BLOCK).subRecognizer(getContainsRecognizer())); 565 RecognizerBase<ECobolParserState> descriptionRecognizer = inState(TOP_LEVEL) 566 .sequence(EnumSet.of(FD, SD), IDENTIFIER).createNode(META, 0, 1) 567 .subRecognizer(getIsClauseRecognizer(), 0, 3).optionalSubRecognizer(blockRecognizer) 568 .optionalSubRecognizer(recordRecognizer).optionalSubRecognizer(getLabelClauseRecognizer()) 569 .optionalSubRecognizer(valueOfRecognizer).optionalSubRecognizer(recordingRecognizer) 570 .optionalSubRecognizer(dataRecognizer).optionalSubRecognizer(linageClauseRecognizer()) 571 .optionalSubRecognizer(lineRecognizer).optionalSubRecognizer(lineRecognizer) 572 .optionalSubRecognizer(getCodeSetClauseRecognizer()); 573 574 completeRule(descriptionRecognizer, null, SIMPLE); 575 } 576 577 /** 578 * Returns the CODE-SET clause recognizer. 579 */ 580 private RecognizerBase<ECobolParserState> getCodeSetClauseRecognizer() { 581 RecognizerBase<ECobolParserState> codeSetSubRecognizer = createRecognizer( 582 start -> start.sequence(FOR).repeatedSubRecognizer(getRepeatedSequenceRecognizer(IDENTIFIER))); 583 584 return createRecognizer(start -> start.sequence(CODE_SET).optional(IS).sequence(IDENTIFIER) 585 .optionalSubRecognizer(codeSetSubRecognizer)); 586 } 587 588 /** 589 * Returns the LINAGE clause recognizer 590 */ 591 private RecognizerBase<ECobolParserState> linageClauseRecognizer() { 592 RecognizerBase<ECobolParserState> linageSubRecognizer = createRecognizer( 593 start -> start.optional(WITH).sequence(FOOTING).optional(AT).sequence(IDENTIFIER_AND_LITERALS)); 594 return createRecognizer(start -> start.sequence(LINAGE).optional(IS).sequence(IDENTIFIER_AND_LITERALS) 595 .optional(LINES).optionalSubRecognizer(linageSubRecognizer)); 596 } 597 598 /** 599 * Returns the LABEL clause recognizer 600 */ 601 private RecognizerBase<ECobolParserState> getLabelClauseRecognizer() { 602 RecognizerBase<ECobolParserState> labelSubRecognizer = createRecognizer(start -> { 603 start.sequence(EnumSet.of(STANDARD, OMITTED)); 604 start.repeatedSubRecognizer(getRepeatedSequenceRecognizer(IDENTIFIER)); 605 }); 606 return createRecognizer(start -> start.sequence(LABEL, EnumSet.of(RECORD, RECORDS)) 607 .optional(EnumSet.of(IS, ARE)).subRecognizer(labelSubRecognizer)); 608 } 609 610 /** 611 * Returns the CONTAINS clause recognizer used in DATA divisions 612 */ 613 private RecognizerBase<ECobolParserState> getContainsRecognizer() { 614 RecognizerBase<ECobolParserState> fromToRecognizer = createRecognizer(start -> start.optional(FROM) 615 .optional(INTEGER_LITERAL).optional(TO, INTEGER_LITERAL).optional(CHARACTERS)); 616 RecognizerBase<ECobolParserState> containsSubRecognizer = createRecognizer( 617 start -> start.optional(IS).sequence(VARYING).optional(IN).optional(SIZE) 618 .optionalSubRecognizer(fromToRecognizer).optionalSubRecognizer(getDependingRecognizer())); 619 return createRecognizer( 620 start -> start.optional(CONTAINS).optional(INTEGER_LITERAL, TO).sequence(INTEGER_LITERAL) 621 .optional(EnumSet.of(RECORDS, CHARACTERS)).optionalSubRecognizer(containsSubRecognizer)); 622 } 623 624 /** 625 * Create rules for the paragraphs, sections and statements in the procedure 626 * division. These are executable program statements. 627 */ 628 private void createRulesForProcedureDivision() { 629 createRuleForDivision(TOP_LEVEL, PROCEDURE); 630 createSimpleVerbRules(); 631 createConditionRules(); 632 createLoopVerbRules(); 633 createRulesForFileIOVerbs(); 634 createTryCatchFinallyVerbsRules(); 635 createRuleForSortVerb(); 636 createRuleForMergeVerb(); 637 638 // paragraphs and sections 639 inState(TOP_LEVEL, IN_STATEMENT).sequence(IDENTIFIER, DOT).preCondition(new ParagraphRecognizer()) 640 .createNode(STATEMENT, PARAGRAPH_SUBTYPE_NAME, 0).endNode(); 641 inState(TOP_LEVEL, IN_STATEMENT).sequence(IDENTIFIER, SECTION, DOT) 642 .createNode(STATEMENT, SECTION_SUBTYPE_NAME, 0).endNode(); 643 completeRule(inState(TOP_LEVEL, IN_STATEMENT).sequence(EnumSet.of(EXEC, EXECUTE)) 644 .createNode(STATEMENT, SubTypeNames.EXECUTE).skipTo(END_EXEC), null, SIMPLE); 645 } 646 647 /** 648 * Create rule for SORT verb. 649 */ 650 private void createRuleForSortVerb() { 651 RecognizerBase<ECobolParserState> withRecognizer = createRecognizer( 652 start -> start.optional(WITH).sequence(DUPLICATES).optional(IN).optional(ORDER)); 653 RecognizerBase<ECobolParserState> collatingRecognizer = createRecognizer( 654 start -> start.optional(COLLATING).sequence(SEQUENCE).optional(IS) 655 .optional(EnumSet.of(STANDARD_1, STANDARD_2, NATIVE, EBCDIC, STRING_LITERAL, INTEGER_LITERAL))); 656 RecognizerBase<ECobolParserState> onRecognizer = createRecognizer( 657 start -> start.optional(COMMA).optional(ON).sequence(EnumSet.of(ASCENDING, DESCENDING)).optional(KEY) 658 .optional(IS).repeatedSubRecognizer(getRepeatedSequenceRecognizer(IDENTIFIER))); 659 660 RecognizerBase<ECobolParserState> sortRecognizer = inState(TOP_LEVEL, IN_STATEMENT).sequence(SORT, IDENTIFIER) 661 .createNode(STATEMENT, 0).repeatedSubRecognizer(onRecognizer).optionalSubRecognizer(withRecognizer) 662 .optionalSubRecognizer(collatingRecognizer) 663 .optionalSubRecognizer(getIOUsingGivingRecognizer(INPUT, USING)) 664 .optionalSubRecognizer(getIOUsingGivingRecognizer(OUTPUT, GIVING)); 665 completeRule(sortRecognizer, null, SIMPLE); 666 } 667 668 /** 669 * Returns the INPUT-OUTPUT USING-GIVING sub-recognizer for the SORT verb. 670 */ 671 private RecognizerBase<ECobolParserState> getIOUsingGivingRecognizer(ETokenType inputOutputToken, 672 ETokenType usingGiving) { 673 RecognizerBase<ECobolParserState> throughRecognizer = createRecognizer( 674 start -> start.sequence(EnumSet.of(THROUGH, THRU), IDENTIFIER)); 675 RecognizerBase<ECobolParserState> result = createRecognizer(start -> start.sequence(inputOutputToken, PROCEDURE) 676 .optional(IS).sequence(IDENTIFIER).optionalSubRecognizer(throughRecognizer)); 677 result.sequence(usingGiving).repeatedSubRecognizer(getRepeatedSequenceRecognizer(IDENTIFIER)); 678 679 return result; 680 } 681 682 /** 683 * Create rule for MERGE verb. 684 */ 685 private void createRuleForMergeVerb() { 686 RecognizerBase<ECobolParserState> onRecognizer = createRecognizer( 687 start -> start.optional(COMMA).optional(ON).sequence(EnumSet.of(ASCENDING, DESCENDING)).optional(KEY) 688 .optional(IS).repeatedSubRecognizer(getRepeatedSequenceRecognizer(IDENTIFIER_AND_LITERALS))); 689 RecognizerBase<ECobolParserState> collatingRecognizer = createRecognizer( 690 start -> start.optional(COLLATING).sequence(SEQUENCE).optional(IS) 691 .sequence(EnumSet.of(STANDARD_1, STANDARD_2, NATIVE, EBCDIC, STRING_LITERAL, INTEGER_LITERAL))); 692 RecognizerBase<ECobolParserState> usingRecognizer = createRecognizer( 693 start -> start.sequence(USING, IDENTIFIER_AND_STRING_LITERALS) 694 .repeatedSubRecognizer(getRepeatedSequenceRecognizer(IDENTIFIER_AND_STRING_LITERALS))); 695 RecognizerBase<ECobolParserState> outputRecognizer = createRecognizer( 696 start -> start.sequence(OUTPUT, PROCEDURE).optional(IS).sequence(IDENTIFIER_AND_STRING_LITERALS) 697 .optional(EnumSet.of(THROUGH, THRU), IDENTIFIER_AND_STRING_LITERALS)); 698 outputRecognizer.sequence(GIVING) 699 .repeatedSubRecognizer(getRepeatedSequenceRecognizer(IDENTIFIER_AND_STRING_LITERALS)); 700 701 RecognizerBase<ECobolParserState> mergeRecognizer = inState(TOP_LEVEL, IN_STATEMENT).sequence(MERGE, IDENTIFIER) 702 .createNode(STATEMENT, 0).repeatedSubRecognizer(onRecognizer).optionalSubRecognizer(collatingRecognizer) 703 .optionalSubRecognizer(usingRecognizer).optionalSubRecognizer(outputRecognizer); 704 completeRule(mergeRecognizer, null, SIMPLE); 705 } 706 707 /** 708 * Create rules for single statements. As opposed to simple statements, a single 709 * statement has only 2 or maximum of 3 verbs in a sequence. 710 */ 711 private void createSingleVerbRules(EShallowEntityType entityType, Object subType, Object... statement) { 712 completeRule(inState(TOP_LEVEL, IN_STATEMENT).sequence(statement).createNode(entityType, subType), null, 713 SIMPLE); 714 } 715 716 /** 717 * Create rules for compiler directive statements. These may be found in the 718 * normal flow with other executable statements. 719 */ 720 private void createRulesForCompilerDirectiveStatements() { 721 createSingleVerbRules(STATEMENT, 0, EJECT); 722 completeRule(inState(TOP_LEVEL, IN_STATEMENT).sequence(BASIS, IDENTIFIER_AND_LITERALS).createNode(STATEMENT, 0), 723 null, SIMPLE); 724 725 EnumSet<ETokenType> moreCompilerOptionTokens = EnumSet.of(CURRENCY, DATA, DBCS, LIST, OBJECT, SIZE, SOURCE, 726 SPACE, SQL, TEST, CICS, NAME, NOSOURCE, NOLIST, NOMAP, MAP); 727 RecognizerBase<ECobolParserState> compilerOptionsRecognizer = createRecognizer(start -> { 728 RecognizerBase<ECobolParserState> comma = start.optional(COMMA); 729 comma.sequence(COMPILER_OPTIONS); 730 comma.sequence(moreCompilerOptionTokens); 731 }); 732 completeRule(inState(TOP_LEVEL, IN_STATEMENT).sequence(EnumSet.of(CBL, PROCESS)).createNode(STATEMENT, 0) 733 .repeatedSubRecognizer(compilerOptionsRecognizer), null, SIMPLE); 734 completeRule(inState(TOP_LEVEL, IN_STATEMENT).sequence(CONTROL) 735 .subRecognizer(getRepeatedSequenceRecognizer(EnumSet.of(SOURCE, NOSOURCE, LIST, NOLIST, MAP, NOMAP)), 1, 736 Integer.MAX_VALUE) 737 .createNode(STATEMENT, 0), null, SIMPLE); 738 739 createRuleForCopyVerb(); 740 RecognizerBase<ECobolParserState> replaceRecognizer = inState(TOP_LEVEL, IN_STATEMENT).sequence(REPLACE) 741 .createNode(STATEMENT, 0); 742 replaceRecognizer.sequence(OFF); 743 replaceRecognizer.repeatedSubRecognizer(getPseudoTextPartialWordRecognizer()); 744 completeRule(replaceRecognizer, null, SIMPLE); 745 746 createSingleVerbRules(STATEMENT, 0, INSERT, INTEGER_LITERAL); 747 748 createRulesForMoreCompilerDirectives(); 749 } 750 751 /** 752 * Creates rules for more compiler directives 753 */ 754 private void createRulesForMoreCompilerDirectives() { 755 RecognizerBase<ECobolParserState> textRecognizer = getRepeatedSequenceRecognizer(IDENTIFIER_AND_LITERALS); 756 createSingleVerbRules(STATEMENT, 0, TITLE, STRING_LITERAL); 757 createSingleVerbRules(STATEMENT, 0, EnumSet.of(SKIP1, SKIP2, SKIP3)); 758 createSingleVerbRules(STATEMENT, 0, EnumSet.of(READY, RESET), TRACE); 759 760 RecognizerBase<ECobolParserState> dollarDisplayRecognizer = inState(TOP_LEVEL, IN_STATEMENT) 761 .sequence(DOLLAR_DISPLAY).createNode(STATEMENT, 0); 762 dollarDisplayRecognizer.sequence(VCS, EQ, STRING_LITERAL); 763 dollarDisplayRecognizer.repeatedSubRecognizer(textRecognizer); 764 completeRule(dollarDisplayRecognizer, null, SIMPLE); 765 766 completeRule(inState(TOP_LEVEL, IN_STATEMENT).sequence(MINUS, INC).createNode(STATEMENT, 1) 767 .repeatedSubRecognizer(textRecognizer), null, SIMPLE); 768 completeRule(inState(TOP_LEVEL, IN_STATEMENT).sequence(PLUS, PLUS, INCLUDE).createNode(STATEMENT, 2) 769 .repeatedSubRecognizer(textRecognizer), null, SIMPLE); 770 771 createIfRule(DOLLAR_IF, EnumSet.of(DOLLAR_ELSE), DOLLAR_END, STATEMENT); 772 createElseRule(EnumSet.of(DOLLAR_ELSE), DOLLAR_END, STATEMENT); 773 } 774 775 /** 776 * Create rules for COPY verb. 777 */ 778 private void createRuleForCopyVerb() { 779 RecognizerBase<ECobolParserState> ofInRecognizer = createRecognizer( 780 start -> start.sequence(EnumSet.of(OF, IN), IDENTIFIER_AND_LITERALS)); 781 RecognizerBase<ECobolParserState> replacingRecognizer = createRecognizer( 782 start -> start.sequence(REPLACING).repeatedSubRecognizer(getPseudoTextPartialWordRecognizer())); 783 RecognizerBase<ECobolParserState> copyRecognizer = inState(TOP_LEVEL).sequence(COPY, IDENTIFIER_AND_LITERALS) 784 .createNode(STATEMENT, 0).optionalSubRecognizer(ofInRecognizer).optional(SUPPRESS) 785 .optionalSubRecognizer(replacingRecognizer); 786 completeRule(copyRecognizer, null, SIMPLE); 787 } 788 789 /** 790 * Returns recognizer for matching pseudo text and partial word syntax for use 791 * in COPY and REPLACE verbs. 792 */ 793 private RecognizerBase<ECobolParserState> getPseudoTextPartialWordRecognizer() { 794 RecognizerBase<ECobolParserState> replacingOperandRecognizer = createRecognizer(start -> { 795 RecognizerBase<ECobolParserState> prefix = start.optional(COMMA); 796 prefix.sequence(IDENTIFIER_AND_LITERALS); 797 prefix.sequence(EQ, EQ).skipTo(EQ, EQ); 798 }); 799 return createRecognizer(start -> start.optional(COMMA).optional(EnumSet.of(LEADING, TRAILING)) 800 .subRecognizer(replacingOperandRecognizer).sequence(BY).subRecognizer(replacingOperandRecognizer)); 801 } 802 803 /** 804 * Create Rules for File IO verbs 805 */ 806 private void createRulesForFileIOVerbs() { 807 createRuleForOpenVerb(); 808 createRuleForRewriteVerb(); 809 createRuleForDeleteVerb(); 810 createRuleForStartVerb(); 811 createRuleForCloseVerb(); 812 createRuleForWriteVerb(); 813 createRuleForReadVerb(); 814 } 815 816 /** 817 * Create rule for OPEN verb. 818 */ 819 private void createRuleForOpenVerb() { 820 RecognizerBase<ECobolParserState> sharingPhraseSubRecognizer = createRecognizer(start -> { 821 RecognizerBase<ECobolParserState> prefix = start.optional(WITH); 822 prefix.sequence(EnumSet.of(ALL, NO)).optional(OTHER); 823 prefix.sequence(READ, ONLY); 824 }); 825 RecognizerBase<ECobolParserState> sharingPhraseRecognizer = createRecognizer( 826 start -> start.sequence(SHARING).subRecognizer(sharingPhraseSubRecognizer)); 827 828 RecognizerBase<ECobolParserState> openSubRecognizer = createRecognizer(start -> { 829 RecognizerBase<ECobolParserState> prefix = start.optional(COMMA); 830 prefix.sequence(INPUT).optionalSubRecognizer(sharingPhraseRecognizer) 831 .repeatedSubRecognizer(getOpenVerbFileSubrecognizer(true, true)); 832 prefix.sequence(OUTPUT).optionalSubRecognizer(sharingPhraseRecognizer) 833 .repeatedSubRecognizer(getOpenVerbFileSubrecognizer(false, true)); 834 prefix.sequence(EnumSet.of(I_O, EXTEND)).optionalSubRecognizer(sharingPhraseRecognizer) 835 .repeatedSubRecognizer(getOpenVerbFileSubrecognizer(false, false)); 836 }); 837 838 RecognizerBase<ECobolParserState> openRecognizer = inState(TOP_LEVEL, IN_STATEMENT).sequence(OPEN) 839 .createNode(STATEMENT, 0).repeatedSubRecognizer(getRepeatedSequenceRecognizer(IDENTIFIER)) 840 .repeatedSubRecognizer(openSubRecognizer); 841 842 completeRule(openRecognizer, null, SIMPLE); 843 } 844 845 /** 846 * Returns the file sub-recognizer for the OPEN verb. 847 */ 848 private RecognizerBase<ECobolParserState> getOpenVerbFileSubrecognizer(boolean includeReserved, 849 boolean includeNoRewind) { 850 RecognizerBase<ECobolParserState> withRecognizer = createRecognizer(start -> { 851 RecognizerBase<ECobolParserState> prefix = start.optional(WITH); 852 if (includeNoRewind) { 853 prefix.sequence(NO, REWIND); 854 } 855 prefix.sequence(LOCK); 856 }); 857 858 return createRecognizer(start -> { 859 RecognizerBase<ECobolParserState> prefix = start.optional(COMMA); 860 prefix.sequence(IDENTIFIER); 861 if (includeReserved) { 862 prefix.sequence(REVERSED); 863 } 864 prefix.subRecognizer(withRecognizer); 865 }); 866 } 867 868 /** 869 * Create rule for CLOSE verb. 870 */ 871 private void createRuleForCloseVerb() { 872 RecognizerBase<ECobolParserState> withRecognizer = createRecognizer(start -> { 873 RecognizerBase<ECobolParserState> prefix = start.optional(WITH); 874 prefix.sequence(NO, REWIND); 875 prefix.sequence(LOCK); 876 prefix.sequence(DISP); 877 }); 878 879 RecognizerBase<ECobolParserState> reelUnitWithRecognizer = createRecognizer(start -> { 880 RecognizerBase<ECobolParserState> prefix = start.optional(WITH); 881 prefix.sequence(LOCK); 882 prefix.optional(NO).sequence(REWIND); 883 }); 884 885 RecognizerBase<ECobolParserState> reelUnitRecognizer = createRecognizer(start -> { 886 RecognizerBase<ECobolParserState> prefix = start.sequence(EnumSet.of(REEL, UNIT)); 887 prefix.optional(FOR).sequence(REMOVAL); 888 prefix.subRecognizer(reelUnitWithRecognizer); 889 }); 890 891 RecognizerBase<ECobolParserState> fileRecognizer = createRecognizer(start -> start.optional(COMMA) 892 .sequence(IDENTIFIER).optionalSubRecognizer(reelUnitRecognizer).optionalSubRecognizer(withRecognizer)); 893 RecognizerBase<ECobolParserState> closeRecognizer = inState(TOP_LEVEL, IN_STATEMENT).sequence(CLOSE) 894 .createNode(STATEMENT, 0).repeatedSubRecognizer(fileRecognizer); 895 completeRule(closeRecognizer, null, SIMPLE); 896 } 897 898 /** 899 * Create rules for READ verb. 900 */ 901 private void createRuleForReadVerb() { 902 RecognizerBase<ECobolParserState> readRecognizer = inState(TOP_LEVEL, IN_STATEMENT).sequence(READ, IDENTIFIER) 903 .createNode(STATEMENT, 0, 1).skipAny(EnumSet.of(NEXT, PREVIOUS, RECORD)); 904 RecognizerBase<ECobolParserState> intoRecognizer = readRecognizer.sequence(INTO, IDENTIFIER) 905 .skipAny(EnumSet.of(WITH, KEPT, NO, LOCK, WAIT, IGNORE)); 906 RecognizerBase<ECobolParserState> readWithKeyRecognizer = readRecognizer 907 .skipAny(EnumSet.of(WITH, KEPT, NO, LOCK, WAIT, IGNORE)).sequence(KEY).optional(IS) 908 .sequence(IDENTIFIER); 909 RecognizerBase<ECobolParserState> intoWithKeyRecognizer = intoRecognizer.sequence(KEY).optional(IS) 910 .sequence(IDENTIFIER); 911 readRecognizer = readRecognizer.skipAny(EnumSet.of(WITH, KEPT, ETokenType.NO, LOCK, WAIT)); 912 913 completeReadImperativeRule(intoWithKeyRecognizer); 914 completeReadImperativeRule(readWithKeyRecognizer); 915 completeReadImperativeRule(intoRecognizer); 916 completeReadImperativeRule(readRecognizer); 917 completeRule(intoRecognizer, null, SIMPLE); 918 completeRule(readRecognizer, null, SIMPLE); 919 } 920 921 /** 922 * Complete syntax for read rules 923 */ 924 private void completeReadImperativeRule(RecognizerBase<ECobolParserState> recognizer) { 925 RecognizerBase<ECobolParserState> notAtSubRecognizer = createRecognizer( 926 start -> start.optional(NOT).optional(AT).sequence(END).parseOnce(IN_STATEMENT)); 927 completeRuleWithConditionalClause(recognizer, notAtSubRecognizer, END_READ); 928 completeRuleWithConditionalClause(recognizer, getNotInvalidKeyClauseSubRecognizer(), END_READ); 929 completeRule(recognizer, END_READ, SIMPLE); 930 } 931 932 /** 933 * Create rules for WRITE verb. 934 */ 935 private void createRuleForWriteVerb() { 936 RecognizerBase<ECobolParserState> writeRecognizer = inState(TOP_LEVEL, IN_STATEMENT) 937 .sequence(WRITE, EnumSet.of(IDENTIFIER, FLOATING_POINT_LITERAL)).createNode(STATEMENT, 0, 1) 938 .optional(FROM, IDENTIFIER); 939 RecognizerBase<ECobolParserState> withAdvancingRecognizer = writeRecognizer 940 .skipAny(EnumSet.of(BEFORE, AFTER, ADVANCING, POSITIONING)) 941 .sequence(EnumSet.of(IDENTIFIER, INTEGER_LITERAL, PAGE, TAB, FORMFEED)) 942 .optional(EnumSet.of(LINE, LINES)); 943 RecognizerBase<ECobolParserState> notAtRecognizer = createRecognizer(start -> start.optional(NOT).optional(AT) 944 .sequence(EnumSet.of(EOP, END_OF_PAGE)).parseOnce(IN_STATEMENT)); 945 completeRuleWithConditionalClause(withAdvancingRecognizer, notAtRecognizer, END_WRITE); 946 completeRuleWithConditionalClause(writeRecognizer, getNotInvalidKeyClauseSubRecognizer(), END_WRITE); 947 completeRule(withAdvancingRecognizer, null, SIMPLE); 948 } 949 950 /** 951 * Get a sub-recognizer for the (NOT) INVALID KEY clause recognizer. 952 */ 953 private RecognizerBase<ECobolParserState> getNotInvalidKeyClauseSubRecognizer() { 954 return createRecognizer(start -> start.optional(NOT).sequence(INVALID).optional(KEY).parseOnce(IN_STATEMENT)); 955 } 956 957 /** 958 * Completes a recognizer rule that ends with one or more conditional clauses 959 */ 960 private static void completeRuleWithConditionalClause(RecognizerBase<ECobolParserState> recognizer, 961 RecognizerBase<ECobolParserState> subRecognizer, ETokenType endTokenType) { 962 RecognizerBase<ECobolParserState> firstRecognizer = recognizer 963 .preCondition(new BoundedByOppositeClausesRecognizer()).subRecognizer(subRecognizer); 964 RecognizerBase<ECobolParserState> secondRecognizer = firstRecognizer.subRecognizer(subRecognizer); 965 RecognizerBase<ECobolParserState> thirdRecognizer = secondRecognizer.subRecognizer(subRecognizer); 966 thirdRecognizer.preCondition(new ConditionalClauseWithEndScopeRecognizer(endTokenType)) 967 .sequence(EnumSet.of(endTokenType, DOT)).endNode(); 968 thirdRecognizer.endNode(); 969 secondRecognizer.preCondition(new ConditionalClauseWithEndScopeRecognizer(endTokenType)) 970 .sequence(EnumSet.of(endTokenType, DOT)).endNode(); 971 secondRecognizer.endNode(); 972 firstRecognizer.preCondition(new ConditionalClauseWithEndScopeRecognizer(endTokenType)) 973 .sequence(EnumSet.of(endTokenType, DOT)).endNode(); 974 firstRecognizer.endNode(); 975 } 976 977 /** 978 * Completes the rule provided in a recognizer depending on the statement end 979 * type. For SIMPLE verbs, matches endToken. For IMPERATIVE verbs, parses once 980 * IN_STATEMENT while for SCOPE verbs, checks if outside of scope and parses 981 * like IMPERATIVE verb otherwise parses until endToken. 982 */ 983 private static void completeRule(RecognizerBase<ECobolParserState> recognizer, ETokenType endToken, 984 EStatementEndType statementEndType) { 985 switch (statementEndType) { 986 case SIMPLE: 987 if (endToken != null) { 988 recognizer.sequence(endToken).endNode(); 989 } 990 991 // Ensures that statements are properly closed with a DOT (if 992 // present). This fixes the dot-close-all scope bug as well as 993 // causes the code to be correctly displayed in the code perspective 994 // (especially in pretty-print mode). 995 recognizer.notPreCondition(new OutOfScopeRecognizer()).sequenceBefore(DOT).endNode(); 996 recognizer.preCondition(new OutOfScopeRecognizer()).sequence(DOT).endNode(); 997 recognizer.endNode(); 998 break; 999 case IMPERATIVE: 1000 recognizer.parseOnce(IN_STATEMENT).endNode(); 1001 break; 1002 case SCOPE: 1003 default: 1004 // Extra check we are not outside a scope. Fall-through is intended 1005 recognizer.preCondition(new OutOfScopeRecognizer()).parseOnce(IN_STATEMENT).endNode(); 1006 RecognizerBase<ECobolParserState> finalRecognizer = recognizer.notPreCondition(new OutOfScopeRecognizer()) 1007 .parseUntil(IN_STATEMENT); 1008 if (endToken != null) { 1009 finalRecognizer.sequence(endToken).endNode(); 1010 } 1011 1012 // Not 'eating' the dot to fix the DOT-close all scope bug 1013 finalRecognizer.sequenceBefore(DOT).endNode(); 1014 } 1015 } 1016 1017 /** 1018 * Create rules for simple (non-block) verbs. 1019 */ 1020 private void createSimpleVerbRules() { 1021 completeRule(inState(TOP_LEVEL, IN_STATEMENT).sequence(RAISE).optional(IDENTIFIER).createNode(STATEMENT, 0), 1022 null, SIMPLE); 1023 1024 completeRule(inState(TOP_LEVEL, IN_STATEMENT).sequence(RELEASE, IDENTIFIER_AND_LITERALS) 1025 .optional(FROM, IDENTIFIER_AND_LITERALS).createNode(STATEMENT, 0), null, SIMPLE); 1026 1027 completeRule(inState(TOP_LEVEL, IN_STATEMENT) 1028 .sequence(UNLOCK, IDENTIFIER_AND_STRING_LITERALS, EnumSet.of(RECORD, RECORDS)).createNode(STATEMENT, 0), 1029 null, SIMPLE); 1030 1031 createRuleForInspectVerb(); 1032 createRuleForServiceVerb(); 1033 createRuleForInitializeVerb(); 1034 createRuleForComputeVerb(); 1035 createRuleForAcceptVerb(); 1036 createRuleForDisplayVerb(); 1037 createRulesForCallVerb(); 1038 createRuleForExamineVerb(); 1039 createRuleForExhibitVerb(); 1040 createRuleForArithmeticVerbs(ADD, END_ADD, TO); 1041 createRuleForArithmeticVerbs(SUBTRACT, END_SUBTRACT, FROM); 1042 createRuleForArithmeticVerbs(MULTIPLY, END_MULTIPLY, BY); 1043 createRuleForArithmeticVerbs(DIVIDE, END_DIVIDE, EnumSet.of(INTO, BY)); 1044 createRuleForReturnVerb(); 1045 createRuleForOnVerb(); 1046 createSingleVerbRules(STATEMENT, 0, CONTINUE); 1047 createSingleVerbRules(STATEMENT, 0, COMMIT); 1048 createSingleVerbRules(STATEMENT, 0, ROLLBACK); 1049 createMoreRulesForSimpleVerbs(); 1050 } 1051 1052 /** 1053 * Create rule for INSPECT verb. 1054 */ 1055 private void createRuleForInspectVerb() { 1056 RecognizerBase<ECobolParserState> tallyingForRecognizer = createRecognizer(start -> { 1057 RecognizerBase<ECobolParserState> comma = start.optional(COMMA); 1058 comma.subRecognizer(getAllLeadingFirstRecognizer()); 1059 comma.subRecognizer(getCharactersRecognizer()); 1060 }); 1061 RecognizerBase<ECobolParserState> forRecognizer = createRecognizer( 1062 start -> start.sequence(FOR).repeatedSubRecognizer(tallyingForRecognizer)); 1063 RecognizerBase<ECobolParserState> tallyingSubRecognizer = createRecognizer( 1064 start -> start.optional(COMMA).sequence(IDENTIFIER).repeatedSubRecognizer(forRecognizer)); 1065 RecognizerBase<ECobolParserState> tallyingRecognizer = createRecognizer( 1066 start -> start.sequence(TALLYING).repeatedSubRecognizer(tallyingSubRecognizer)); 1067 1068 RecognizerBase<ECobolParserState> replacingSubRecognizer = createRecognizer(start -> { 1069 RecognizerBase<ECobolParserState> comma = start.optional(COMMA); 1070 comma.subRecognizer(getCharactersRecognizer()); 1071 comma.subRecognizer(getAllLeadingFirstRecognizer()); 1072 }); 1073 RecognizerBase<ECobolParserState> replacingRecognizer = createRecognizer( 1074 start -> start.sequence(REPLACING).repeatedSubRecognizer(replacingSubRecognizer)); 1075 1076 RecognizerBase<ECobolParserState> convertingRecognizer = createRecognizer( 1077 start -> start.sequence(CONVERTING, IDENTIFIER_AND_LITERALS, TO, IDENTIFIER_AND_LITERALS) 1078 .optionalSubRecognizer(getBeforeAfterRecognizer())); 1079 1080 RecognizerBase<ECobolParserState> inspectRecognizer = inState(TOP_LEVEL, IN_STATEMENT) 1081 .sequence(INSPECT, IDENTIFIER).createNode(STATEMENT, 0); 1082 inspectRecognizer.subRecognizer(tallyingRecognizer).optionalSubRecognizer(replacingRecognizer); 1083 inspectRecognizer.subRecognizer(replacingRecognizer); 1084 inspectRecognizer.subRecognizer(convertingRecognizer); 1085 1086 completeRule(inspectRecognizer, null, SIMPLE); 1087 } 1088 1089 /** 1090 * Returns the (ALL, LEADING, FIRST) sub recognizer for the INSPECT verb 1091 */ 1092 private RecognizerBase<ECobolParserState> getAllLeadingFirstRecognizer() { 1093 RecognizerBase<ECobolParserState> identifierLiteralRecognizer = createRecognizer( 1094 start -> start.optional(COMMA).sequence(IDENTIFIER_AND_LITERALS).optional(BY, IDENTIFIER_AND_LITERALS) 1095 .repeatedSubRecognizer(getBeforeAfterRecognizer())); 1096 1097 return createRecognizer(start -> start.sequence(EnumSet.of(ALL, LEADING, FIRST)) 1098 .repeatedSubRecognizer(identifierLiteralRecognizer)); 1099 } 1100 1101 /** 1102 * Returns the CHARACTERS sub recognizer for the INSPECT verb 1103 */ 1104 private RecognizerBase<ECobolParserState> getCharactersRecognizer() { 1105 return createRecognizer(start -> start.sequence(CHARACTERS).optional(BY, IDENTIFIER_AND_LITERALS) 1106 .repeatedSubRecognizer(getBeforeAfterRecognizer())); 1107 } 1108 1109 /** 1110 * Returns the (BEFORE, AFTER) sub recognizer for the INSPECT verb 1111 */ 1112 private RecognizerBase<ECobolParserState> getBeforeAfterRecognizer() { 1113 return createRecognizer(start -> start.optional(COMMA).sequence(EnumSet.of(BEFORE, AFTER)).optional(INITIAL) 1114 .sequence(IDENTIFIER_AND_LITERALS)); 1115 } 1116 1117 /** 1118 * Create rule for the ON verb. 1119 */ 1120 private void createRuleForOnVerb() { 1121 RecognizerBase<ECobolParserState> everyRecognizer = createRecognizer( 1122 start -> start.sequence(AND, EVERY, IDENTIFIER_AND_LITERALS)); 1123 RecognizerBase<ECobolParserState> untilRecognizer = createRecognizer( 1124 start -> start.sequence(UNTIL, IDENTIFIER_AND_LITERALS)); 1125 RecognizerBase<ECobolParserState> elseOtherwiseRecognizer = createRecognizer( 1126 start -> start.sequence(EnumSet.of(ELSE, OTHERWISE)).parseOnce(IN_STATEMENT)); 1127 RecognizerBase<ECobolParserState> onRecognizer = inState(TOP_LEVEL, IN_STATEMENT) 1128 .sequence(ON, IDENTIFIER_AND_LITERALS).createNode(STATEMENT, 0).optionalSubRecognizer(everyRecognizer) 1129 .optionalSubRecognizer(untilRecognizer).parseOnce(IN_STATEMENT) 1130 .optionalSubRecognizer(elseOtherwiseRecognizer); 1131 completeRule(onRecognizer, null, SIMPLE); 1132 } 1133 1134 /** 1135 * Create rule for SERVICE verb. 1136 */ 1137 private void createRuleForServiceVerb() { 1138 RecognizerBase<ECobolParserState> serviceRecognizer = inState(TOP_LEVEL, IN_STATEMENT).sequence(SERVICE) 1139 .createNode(STATEMENT, 0); 1140 serviceRecognizer.sequence(RELOAD, IDENTIFIER); 1141 serviceRecognizer.sequence(LABEL); 1142 completeRule(serviceRecognizer, null, SIMPLE); 1143 } 1144 1145 /** 1146 * Create rule for RETURN verb. 1147 */ 1148 private void createRuleForReturnVerb() { 1149 RecognizerBase<ECobolParserState> returnRecognizer = inState(TOP_LEVEL, IN_STATEMENT) 1150 .sequence(RETURN, IDENTIFIER).createNode(STATEMENT, 0).optional(RECORD).optional(INTO, IDENTIFIER); 1151 completeRuleWithConditionalClause(returnRecognizer, createOnAtClauseSubRecognizer(END), END_RETURN); 1152 completeRule(returnRecognizer, END_RETURN, SIMPLE); 1153 } 1154 1155 /** 1156 * Create rule for Arithmetic verbs: ADD, SUBTRACT, MULTIPLY and DIVIDE. 1157 */ 1158 private void createRuleForArithmeticVerbs(ETokenType startVerb, ETokenType endVerb, Object... qualifyVerbs) { 1159 RecognizerBase<ECobolParserState> identifierRoundedRecognizer = createRecognizer( 1160 start -> start.optional(COMMA).sequence(IDENTIFIER_AND_NUMERIC_LITERALS).optional(ROUNDED)); 1161 RecognizerBase<ECobolParserState> givingRecognizer = createRecognizer( 1162 start -> start.sequence(GIVING).repeatedSubRecognizer(identifierRoundedRecognizer)); 1163 RecognizerBase<ECobolParserState> arithmeticRecognizer = inState(TOP_LEVEL, IN_STATEMENT).sequence(startVerb) 1164 .createNode(STATEMENT, 0).optional(EnumSet.of(CORRESPONDING, CORR)) 1165 .repeatedSubRecognizer(getRepeatedSequenceRecognizer(IDENTIFIER_AND_NUMERIC_LITERALS)) 1166 .optional(qualifyVerbs).repeatedSubRecognizer(identifierRoundedRecognizer) 1167 .optionalSubRecognizer(givingRecognizer).optional(REMAINDER, IDENTIFIER); 1168 1169 completeRuleWithConditionalClause(arithmeticRecognizer, createOnAtClauseSubRecognizer(SIZE, ERROR), endVerb); 1170 completeRule(arithmeticRecognizer, endVerb, SIMPLE); 1171 } 1172 1173 /** 1174 * Create rule for EXHIBIT verb. 1175 */ 1176 private void createRuleForExhibitVerb() { 1177 RecognizerBase<ECobolParserState> exhibitRecognizer = inState(TOP_LEVEL, IN_STATEMENT).sequence(EXHIBIT) 1178 .createNode(STATEMENT, 0); 1179 exhibitRecognizer.sequence(NAMED).repeatedSubRecognizer(getRepeatedSequenceRecognizer(IDENTIFIER_AND_LITERALS)); 1180 exhibitRecognizer.sequence(CHANGED).optional(NAMED) 1181 .repeatedSubRecognizer(getRepeatedSequenceRecognizer(IDENTIFIER_AND_LITERALS)); 1182 exhibitRecognizer.repeatedSubRecognizer(getRepeatedSequenceRecognizer(IDENTIFIER_AND_LITERALS)); 1183 completeRule(exhibitRecognizer, null, SIMPLE); 1184 } 1185 1186 /** 1187 * Create rule for EXAMINE verb. 1188 */ 1189 private void createRuleForExamineVerb() { 1190 RecognizerBase<ECobolParserState> tallyingRecognizer = createRecognizer(start -> { 1191 RecognizerBase<ECobolParserState> prefix = start.sequence(TALLYING); 1192 prefix.sequence(UNTIL, FIRST, IDENTIFIER_AND_LITERALS).optional(REPLACING, BY, IDENTIFIER_AND_LITERALS); 1193 prefix.sequence(EnumSet.of(ALL, LEADING), IDENTIFIER_AND_LITERALS).optional(REPLACING, BY, 1194 IDENTIFIER_AND_STRING_LITERALS); 1195 }); 1196 1197 RecognizerBase<ECobolParserState> replacingRecognizer = createRecognizer(start -> { 1198 RecognizerBase<ECobolParserState> prefix = start.sequence(REPLACING); 1199 prefix.sequence(UNTIL, FIRST, IDENTIFIER_AND_LITERALS, BY, IDENTIFIER_AND_LITERALS); 1200 prefix.sequence(EnumSet.of(ALL, LEADING, FIRST), IDENTIFIER_AND_LITERALS, BY, IDENTIFIER_AND_LITERALS); 1201 }); 1202 1203 RecognizerBase<ECobolParserState> examineRecognizer = inState(TOP_LEVEL, IN_STATEMENT) 1204 .sequence(EXAMINE, IDENTIFIER).createNode(STATEMENT, 0); 1205 examineRecognizer.subRecognizer(tallyingRecognizer); 1206 examineRecognizer.subRecognizer(replacingRecognizer); 1207 1208 completeRule(examineRecognizer, null, SIMPLE); 1209 } 1210 1211 /** 1212 * Create rule for REWRITE verb. 1213 */ 1214 private void createRuleForRewriteVerb() { 1215 RecognizerBase<ECobolParserState> rewriteRecognizer = inState(TOP_LEVEL, IN_STATEMENT) 1216 .sequence(REWRITE, IDENTIFIER).createNode(STATEMENT, 0, 1).optional(FROM, IDENTIFIER); 1217 completeRuleWithConditionalClause(rewriteRecognizer, getNotInvalidKeyClauseSubRecognizer(), END_REWRITE); 1218 completeRule(rewriteRecognizer, END_REWRITE, SIMPLE); 1219 } 1220 1221 /** 1222 * Create rule for DELETE verb 1223 */ 1224 private void createRuleForDeleteVerb() { 1225 RecognizerBase<ECobolParserState> baseDeleteRecognizer = inState(TOP_LEVEL, IN_STATEMENT).sequence(DELETE); 1226 1227 completeRule(baseDeleteRecognizer.sequence(FILE).createNode(STATEMENT, new Region(0, 1)) 1228 .repeatedSubRecognizer(getRepeatedSequenceRecognizer(IDENTIFIER)), null, SIMPLE); 1229 1230 RecognizerBase<ECobolParserState> withRecordRecognizer = baseDeleteRecognizer.sequence(IDENTIFIER) 1231 .createNode(STATEMENT, 0, 1).optional(RECORD); 1232 completeRuleWithConditionalClause(withRecordRecognizer, getNotInvalidKeyClauseSubRecognizer(), END_DELETE); 1233 completeRule(withRecordRecognizer, END_DELETE, SIMPLE); 1234 } 1235 1236 /** 1237 * Create rules for INITIALIZE verb 1238 */ 1239 private void createRuleForInitializeVerb() { 1240 EnumSet<ETokenType> categoryNameTokens = EnumSet.of(ALPHABETIC, ALPHANUMERIC, ALPHANUMERIC_EDITED, DATA_POINTER, 1241 DBCS, NATIONAL, NATIONAL_EDITED, NUMERIC, NUMERIC_EDITED, OBJECT_REFERENCE, PROGRAM_POINTER); 1242 EnumSet<ETokenType> categoryNamesWithALLToken = EnumSet.copyOf(categoryNameTokens); 1243 categoryNamesWithALLToken.add(ALL); 1244 RecognizerBase<ECobolParserState> byRecognizer = createRecognizer(start -> start.optional(COMMA) 1245 .optional(categoryNameTokens).optional(DATA).sequence(BY, IDENTIFIER_AND_LITERALS)); 1246 RecognizerBase<ECobolParserState> replacingRecognizer = createRecognizer( 1247 start -> start.optional(THEN).sequence(REPLACING).repeatedSubRecognizer(byRecognizer)); 1248 RecognizerBase<ECobolParserState> toValueRecognizer = createRecognizer( 1249 start -> start.sequence(categoryNamesWithALLToken).optional(TO).sequence(IDENTIFIER)); 1250 RecognizerBase<ECobolParserState> identifierRecognizer = createRecognizer( 1251 start -> start.optional(COMMA).sequence(IDENTIFIER)); 1252 RecognizerBase<ECobolParserState> initializeRecognizer = inState(TOP_LEVEL, IN_STATEMENT).sequence(INITIALIZE) 1253 .createNode(STATEMENT, 0).repeatedSubRecognizer(identifierRecognizer).optional(WITH).optional(FILLER) 1254 .optionalSubRecognizer(toValueRecognizer).optionalSubRecognizer(replacingRecognizer) 1255 .optional(THEN, TO, DEFAULT); 1256 1257 completeRule(initializeRecognizer, null, SIMPLE); 1258 } 1259 1260 /** 1261 * Create rules for COMPUTE verb. 1262 */ 1263 private void createRuleForComputeVerb() { 1264 RecognizerBase<ECobolParserState> identifierRoundedRecognizer = createRecognizer( 1265 start -> start.optional(COMMA).sequence(IDENTIFIER).optional(ROUNDED)); 1266 RecognizerBase<ECobolParserState> computeRecognizer = inState(TOP_LEVEL, IN_STATEMENT).sequence(COMPUTE) 1267 .createNode(STATEMENT, 0).repeatedSubRecognizer(identifierRoundedRecognizer) 1268 .sequence(EnumSet.of(EQ, EQUAL)).subRecognizer(getArithmeticExpressionRecognizer(false)); 1269 completeRuleWithConditionalClause(computeRecognizer, createOnAtClauseSubRecognizer(SIZE, ERROR), END_COMPUTE); 1270 completeRule(computeRecognizer, END_COMPUTE, SIMPLE); 1271 } 1272 1273 /** 1274 * Returns the AT sub-recognizer used by the ACCEPT and DISPLAY verbs 1275 */ 1276 private RecognizerBase<ECobolParserState> getAtRecognizer() { 1277 RecognizerBase<ECobolParserState> columnRecognizer = createRecognizer(start -> start 1278 .sequence(EnumSet.of(COLUMN, COL)).optional(NUMBER).sequence(IDENTIFIER_AND_NUMERIC_LITERALS)); 1279 1280 return createRecognizer(start -> { 1281 RecognizerBase<ECobolParserState> prefix = start.optional(AT); 1282 prefix.sequence(LINE).optional(NUMBER).sequence(IDENTIFIER_AND_NUMERIC_LITERALS) 1283 .optionalSubRecognizer(columnRecognizer); 1284 prefix.sequence(IDENTIFIER_AND_NUMERIC_LITERALS); 1285 }); 1286 } 1287 1288 /** 1289 * Return the MODE sub-recognizer for the ACCEPT and DISPLAY verbs. 1290 */ 1291 private RecognizerBase<ECobolParserState> getModeRecognizer() { 1292 return createRecognizer(start -> start.sequence(MODE).optional(IS).sequence(BLOCK)); 1293 } 1294 1295 /** 1296 * Returns the WITH sub-recognizer for ACCEPT DISPLAY verbs. 1297 */ 1298 private RecognizerBase<ECobolParserState> getWithRecognizer(boolean includeTokensForAcceptVerb) { 1299 RecognizerBase<ECobolParserState> withSubRecognizer = createRecognizer(start -> { 1300 RecognizerBase<ECobolParserState> prefix = start.optional(COMMA); 1301 prefix.sequence(EnumSet.of(BELL, BEEP, BLINK, GRID, HIGHLIGHT, LOWLIGHT, LEFTLINE, OVERLINE, REVERSE_VIDEO, 1302 UNDERLINE)); 1303 1304 if (includeTokensForAcceptVerb) { 1305 prefix.sequence(EnumSet.of(AUTO, AUTO_SKIP, FULL, LENGTH_CHECK, REQUIRED, EMPTY_CHECK, SECURE, NO_ECHO, 1306 LEFT_JUSTIFY, RIGHT_JUSTIFY, SPACE_FILL, TRAILING_SIGN, UPDATE, UPPER, LOWER, ZERO_FILL)); 1307 prefix.sequence(PROMPT).optional(CHARACTER).optional(IS).optional(IDENTIFIER_AND_LITERALS); 1308 prefix.sequence(EnumSet.of(TIMEOUT, TIME_OUT), AFTER, IDENTIFIER_AND_LITERALS); 1309 } 1310 1311 prefix.sequence(ERASE, EnumSet.of(EOL, EOS)); 1312 prefix.sequence( 1313 EnumSet.of(SIZE, FOREGROUND_COLOR, FOREGROUND_COLOUR, BACKGROUND_COLOR, BACKGROUND_COLOUR, CONTROL)) 1314 .optional(IS).sequence(IDENTIFIER_AND_LITERALS); 1315 prefix.sequence(BLANK, EnumSet.of(SCREEN, LINE)); 1316 prefix.sequence(NO, ADVANCING); 1317 }); 1318 1319 return createRecognizer(start -> start.sequence(WITH).repeatedSubRecognizer(withSubRecognizer)); 1320 } 1321 1322 /** 1323 * Create rule for ACCEPT verb. 1324 */ 1325 private void createRuleForAcceptVerb() { 1326 RecognizerBase<ECobolParserState> fromRecognizer = createRecognizer(start -> { 1327 RecognizerBase<ECobolParserState> prefix = start.sequence(FROM); 1328 prefix.sequence(EnumSet.of(IDENTIFIER, DAY_OF_WEEK, TIME, CRT)); 1329 prefix.sequence(EnumSet.of(DATE, DAY)).optional(INTEGER_LITERAL); 1330 prefix.sequence(LINE, NUMBER); 1331 prefix.sequence(USER, NAME); 1332 prefix.sequence(ESCAPE, KEY); 1333 prefix.sequence(EXCEPTION, STATUS); 1334 }); 1335 1336 RecognizerBase<ECobolParserState> acceptRecognizer = inState(TOP_LEVEL, IN_STATEMENT) 1337 .sequence(ACCEPT, IDENTIFIER).createNode(STATEMENT, 0).optionalSubRecognizer(getAtRecognizer()) 1338 .optionalSubRecognizer(fromRecognizer).optionalSubRecognizer(getModeRecognizer()) 1339 .optionalSubRecognizer(getWithRecognizer(true)); 1340 1341 completeRuleWithConditionalClause(acceptRecognizer, 1342 createOnAtClauseSubRecognizer(EnumSet.of(EXCEPTION, ESCAPE)), END_ACCEPT); 1343 completeRule(acceptRecognizer, END_ACCEPT, SIMPLE); 1344 } 1345 1346 /** 1347 * Create rules for DISPLAY verb. 1348 */ 1349 private void createRuleForDisplayVerb() { 1350 RecognizerBase<ECobolParserState> uponRecognizer = createRecognizer( 1351 start -> start.sequence(UPON, EnumSet.of(CRT, CRT_UNDER, IDENTIFIER))); 1352 1353 RecognizerBase<ECobolParserState> displaySubRecognizer = createRecognizer(start -> start.optional(COMMA) 1354 .repeatedSubRecognizer(getRepeatedSequenceRecognizer(IDENTIFIER_AND_LITERALS)) 1355 .optionalSubRecognizer(getAtRecognizer()).optionalSubRecognizer(uponRecognizer) 1356 .optionalSubRecognizer(getModeRecognizer()).optionalSubRecognizer(getWithRecognizer(false))); 1357 RecognizerBase<ECobolParserState> displayRecognizer = inState(TOP_LEVEL, IN_STATEMENT).sequence(DISPLAY) 1358 .createNode(STATEMENT, 0).repeatedSubRecognizer(displaySubRecognizer); 1359 1360 completeRuleWithConditionalClause(displayRecognizer, createOnAtClauseSubRecognizer(EXCEPTION), END_DISPLAY); 1361 completeRule(displayRecognizer, END_DISPLAY, SIMPLE); 1362 } 1363 1364 /** 1365 * Create rule for XML Verb. 1366 */ 1367 private void createRuleForXMLVerb() { 1368 RecognizerBase<ECobolParserState> xmlRecognizer = inState(TOP_LEVEL, IN_STATEMENT) 1369 .sequence(XML, EnumSet.of(GENERATE, PARSE), IDENTIFIER).createNode(STATEMENT, 0, 1); 1370 1371 RecognizerBase<ECobolParserState> countRecognizer = createRecognizer( 1372 start -> start.sequence(COUNT).optional(IN).sequence(IDENTIFIER)); 1373 RecognizerBase<ECobolParserState> generateRecognizer = xmlRecognizer.sequence(FROM, IDENTIFIER) 1374 .optionalSubRecognizer(countRecognizer); 1375 RecognizerBase<ECobolParserState> parseRecognizer = xmlRecognizer.sequence(PROCESSING, PROCEDURE).optional(IS) 1376 .sequence(IDENTIFIER).optional(EnumSet.of(THROUGH, THRU), IDENTIFIER); 1377 1378 completeRuleWithConditionalClause(generateRecognizer, createOnAtClauseSubRecognizer(EXCEPTION), END_XML); 1379 completeRule(generateRecognizer, END_XML, SIMPLE); 1380 completeRuleWithConditionalClause(parseRecognizer, createOnAtClauseSubRecognizer(EXCEPTION), END_XML); 1381 completeRule(parseRecognizer, END_XML, SIMPLE); 1382 } 1383 1384 /** 1385 * Create rule for INVOKE verb. 1386 */ 1387 private void createRuleForInvokeVerb() { 1388 RecognizerBase<ECobolParserState> identifierRecognizer = createRecognizer(start -> { 1389 RecognizerBase<ECobolParserState> prefix = start.sequence(IDENTIFIER); 1390 prefix.sequence(AS, EnumSet.of(OBJECT, IDENTIFIER), IDENTIFIER_AND_LITERALS); 1391 prefix.sequence(IDENTIFIER_AND_LITERALS); 1392 }); 1393 RecognizerBase<ECobolParserState> invokeRecognizer = inState(TOP_LEVEL, IN_STATEMENT).sequence(INVOKE) 1394 .createNode(STATEMENT, 0).subRecognizer(identifierRecognizer) 1395 .optionalSubRecognizer(getUsingSubrecognizer()).optionalSubRecognizer(getGivingReturningRecognizer()); 1396 1397 completeRule(invokeRecognizer, null, SIMPLE); 1398 } 1399 1400 /** 1401 * Create rule for CHAIN verb. 1402 */ 1403 private void createRuleForChainVerb() { 1404 RecognizerBase<ECobolParserState> chainRecognizer = inState(TOP_LEVEL, IN_STATEMENT) 1405 .sequence(CHAIN, IDENTIFIER_AND_LITERALS).createNode(STATEMENT, 0) 1406 .optionalSubRecognizer(getUsingSubrecognizer()); 1407 completeRule(chainRecognizer, END_CHAIN, SIMPLE); 1408 } 1409 1410 /** 1411 * Create rules for CALL verb 1412 */ 1413 private void createRulesForCallVerb() { 1414 RecognizerBase<ECobolParserState> identifierNumeralsRecognizer = createRecognizer(start -> start 1415 .sequence(EnumSet.of(IDENTIFIER, STRING_LITERAL), AS, EnumSet.of(NESTED, IDENTIFIER, STRING_LITERAL))); 1416 identifierNumeralsRecognizer.sequence(IDENTIFIER_AND_LITERALS, IDENTIFIER_AND_LITERALS); 1417 identifierNumeralsRecognizer.sequence(EnumSet.of(NESTED, IDENTIFIER, STRING_LITERAL)); 1418 identifierNumeralsRecognizer.sequence(COMPILER_OPTIONS); 1419 RecognizerBase<ECobolParserState> baseCallRecognizer = inState(TOP_LEVEL, IN_STATEMENT).sequence(CALL) 1420 .createNode(STATEMENT, 0).subRecognizer(identifierNumeralsRecognizer); 1421 baseCallRecognizer = baseCallRecognizer.optionalSubRecognizer(getUsingSubrecognizer()) 1422 .optionalSubRecognizer(getGivingReturningRecognizer()); 1423 completeCallRules(baseCallRecognizer); 1424 } 1425 1426 /** 1427 * Returns the GIVING-RETURNING sub recognizer used by the CALL and INVOKE 1428 * verbs. 1429 */ 1430 private RecognizerBase<ECobolParserState> getGivingReturningRecognizer() { 1431 return createRecognizer(start -> { 1432 RecognizerBase<ECobolParserState> prefix = start.sequence(EnumSet.of(GIVING, RETURNING)); 1433 prefix.sequence(ADDRESS, OF, IDENTIFIER); 1434 prefix.optional(INTO).sequence(IDENTIFIER); 1435 }); 1436 } 1437 1438 /** 1439 * Returns the USING recognizer for the CALL, CHAIN AND INVOKE verbs. 1440 */ 1441 private RecognizerBase<ECobolParserState> getUsingSubrecognizer() { 1442 RecognizerBase<ECobolParserState> repeatedUsingSubRecognizer = createRecognizer(start -> { 1443 RecognizerBase<ECobolParserState> prefix = start.optional(COMMA); 1444 prefix.sequence(EnumSet.of(ADDRESS, LENGTH), OF, IDENTIFIER); 1445 prefix.sequence(INTEGER_LITERAL, SIZE).optional(IS).sequence(INTEGER_LITERAL); 1446 prefix.sequence(EnumSet.of(STRING_LITERAL, OMITTED)); 1447 prefix.subRecognizer(getArithmeticExpressionRecognizer(true)); 1448 }); 1449 RecognizerBase<ECobolParserState> usingRecognizer = createRecognizer( 1450 start -> start.optional(COMMA).optional(BY).optional(EnumSet.of(REFERENCE, CONTENT, VALUE)) 1451 .optional(EnumSet.of(ADDRESS, LENGTH), OF).repeatedSubRecognizer(repeatedUsingSubRecognizer)); 1452 1453 return createRecognizer(start -> start.sequence(USING).repeatedSubRecognizer(usingRecognizer)); 1454 } 1455 1456 /** 1457 * Complete a set of CALL recognizer rules. 1458 */ 1459 private void completeCallRules(RecognizerBase<ECobolParserState> recognizer) { 1460 completeRuleWithConditionalClause(recognizer, createOnAtClauseSubRecognizer(EnumSet.of(EXCEPTION, OVERFLOW)), 1461 END_CALL); 1462 completeRule(recognizer, END_CALL, SIMPLE); 1463 } 1464 1465 /** 1466 * Creates conditional clause sub-recognizer for statements like OVERFLOW, 1467 * EXCEPTION and END, statements which conform to the syntax (NOT) ON|AT 1468 * STATEMENT IMPERATIVE_STATEMENT. 1469 */ 1470 private RecognizerBase<ECobolParserState> createOnAtClauseSubRecognizer(Object... statement) { 1471 return createRecognizer( 1472 start -> start.optional(NOT).optional(EnumSet.of(ON, AT)).sequence(statement).parseOnce(IN_STATEMENT)); 1473 } 1474 1475 /** 1476 * Create rules for simple (non-block) verbs. 1477 */ 1478 private void createMoreRulesForSimpleVerbs() { 1479 completeRule(inState(TOP_LEVEL, IN_STATEMENT).sequence(NEXT, SENTENCE).createNode(STATEMENT, new Region(0, 1)), 1480 null, SIMPLE); 1481 1482 inState(TOP_LEVEL, IN_STATEMENT).sequence(INSPECT, IDENTIFIER, EnumSet.of(TALLYING, REPLACING)) 1483 .createNode(STATEMENT, 0).endNode(); 1484 1485 createRuleForAlterVerb(); 1486 createRuleForMoveVerb(); 1487 createRuleForStopVerb(); 1488 createRuleForSetVerb(); 1489 createRuleForExitVerb(); 1490 createRuleForStringVerb(); 1491 createRuleForUnstringVerb(); 1492 createRuleForGobackVerb(); 1493 createRuleForTransformVerb(); 1494 createRuleForUseVerb(); 1495 createRuleForWaitVerb(); 1496 createRuleForChainVerb(); 1497 createRuleForInvokeVerb(); 1498 createRuleForXMLVerb(); 1499 createRuleForEntryVerb(); 1500 1501 completeRule(inState(TOP_LEVEL, IN_STATEMENT).sequence(ENTER).createNode(STATEMENT, 0) 1502 .sequence(EnumSet.of(IDENTIFIER, STRING_LITERAL)).optional(EnumSet.of(IDENTIFIER, STRING_LITERAL)), 1503 null, SIMPLE); 1504 1505 inState(TOP_LEVEL, IN_STATEMENT).sequence(LIST).createNode(STATEMENT, 0).skipTo(SEMICOLON).endNode(); 1506 1507 completeRule(inState(TOP_LEVEL, IN_STATEMENT).sequence(CANCEL).createNode(STATEMENT, 0) 1508 .repeatedSubRecognizer(getRepeatedSequenceRecognizer(IDENTIFIER_AND_LITERALS)), null, SIMPLE); 1509 } 1510 1511 /** 1512 * Create rule for ENTRY verb. 1513 */ 1514 private void createRuleForEntryVerb() { 1515 RecognizerBase<ECobolParserState> givingReturningRecognizer = createRecognizer( 1516 start -> start.sequence(EnumSet.of(GIVING, RETURNING), IDENTIFIER)); 1517 RecognizerBase<ECobolParserState> repeatedRecognizer = createRecognizer( 1518 start -> start.sequence(REPEATED).optional(INTEGER_LITERAL, TO, INTEGER_LITERAL)); 1519 RecognizerBase<ECobolParserState> referenceValueRecognizer = createRecognizer(start -> { 1520 RecognizerBase<ECobolParserState> prefix = start.optional(COMMA); 1521 prefix.sequence(IDENTIFIER).optional(DELIMITED).optional(BY, SIZE); 1522 prefix.sequence(ANY); 1523 }); 1524 RecognizerBase<ECobolParserState> usingSubRecognizer = createRecognizer(start -> start.optional(BY) 1525 .sequence(EnumSet.of(REFERENCE, VALUE)).repeatedSubRecognizer(referenceValueRecognizer)); 1526 RecognizerBase<ECobolParserState> usingRecognizer = createRecognizer(start -> start.sequence(USING) 1527 .repeatedSubRecognizer(usingSubRecognizer).optionalSubRecognizer(repeatedRecognizer)); 1528 RecognizerBase<ECobolParserState> entryRecognizer = inState(TOP_LEVEL, IN_STATEMENT) 1529 .sequence(ENTRY, STRING_LITERAL).createNode(STATEMENT, 0).optional(IDENTIFIER) 1530 .optionalSubRecognizer(usingRecognizer).optionalSubRecognizer(givingReturningRecognizer); 1531 1532 completeRule(entryRecognizer, null, SIMPLE); 1533 } 1534 1535 /** 1536 * Create rule for START verb. 1537 */ 1538 private void createRuleForStartVerb() { 1539 RecognizerBase<ECobolParserState> contentRecognizer = createRecognizer( 1540 start -> start.optional(BY).sequence(CONTENT)); 1541 RecognizerBase<ECobolParserState> usingRecognizer = createRecognizer( 1542 start -> start.sequence(USING).optionalSubRecognizer(contentRecognizer).sequence(IDENTIFIER)); 1543 RecognizerBase<ECobolParserState> returningRecognizer = createRecognizer( 1544 start -> start.sequence(RETURNING).optional(INTO).sequence(IDENTIFIER)); 1545 RecognizerBase<ECobolParserState> identifiedRecognizer = createRecognizer( 1546 start -> start.sequence(IDENTIFIED).optional(BY).sequence(IDENTIFIER_AND_LITERALS)); 1547 RecognizerBase<ECobolParserState> statusRecognizer = createRecognizer( 1548 start -> start.sequence(STATUS).optional(IS).sequence(IDENTIFIER)); 1549 1550 RecognizerBase<ECobolParserState> withRecognizer = createRecognizer( 1551 start -> start.optional(WITH).sequence(SIZE, IDENTIFIER_AND_LITERALS)); 1552 RecognizerBase<ECobolParserState> keyConditionalRecognizer = createRecognizer( 1553 start -> start.sequence(KEY).skipTo(IDENTIFIER).optionalSubRecognizer(withRecognizer)); 1554 1555 // By syntax, I should break keyConditionalRecognizer as an alternate 1556 // and separate path with the getNotInvalidKeyClauseSubRecognizer() but 1557 // it does not work. 1558 RecognizerBase<ECobolParserState> startRecognizer = inState(TOP_LEVEL, IN_STATEMENT).sequence(START) 1559 .createNode(STATEMENT, 0).repeatedSubRecognizer(getRepeatedSequenceRecognizer(IDENTIFIER_AND_LITERALS)) 1560 .optionalSubRecognizer(usingRecognizer).optionalSubRecognizer(returningRecognizer) 1561 .optionalSubRecognizer(identifiedRecognizer).optionalSubRecognizer(statusRecognizer) 1562 .optionalSubRecognizer(keyConditionalRecognizer); 1563 1564 completeRuleWithConditionalClause(startRecognizer, getNotInvalidKeyClauseSubRecognizer(), END_START); 1565 completeRuleWithConditionalClause(startRecognizer, createOnAtClauseSubRecognizer(EXCEPTION), END_START); 1566 completeRule(startRecognizer, END_START, SIMPLE); 1567 } 1568 1569 /** 1570 * Create rule for WAIT verb. 1571 */ 1572 private void createRuleForWaitVerb() { 1573 RecognizerBase<ECobolParserState> returningRecognizer = createRecognizer( 1574 start -> start.sequence(RETURNING).optional(INTO).sequence(IDENTIFIER)); 1575 RecognizerBase<ECobolParserState> statusRecognizer = createRecognizer( 1576 start -> start.sequence(STATUS).optional(IS).sequence(IDENTIFIER)); 1577 RecognizerBase<ECobolParserState> waitRecognizer = inState(TOP_LEVEL, IN_STATEMENT).sequence(WAIT) 1578 .createNode(STATEMENT, 0).optional(FOR).sequence(IDENTIFIER).optionalSubRecognizer(returningRecognizer) 1579 .optionalSubRecognizer(statusRecognizer); 1580 completeRuleWithConditionalClause(waitRecognizer, createOnAtClauseSubRecognizer(EXCEPTION), END_WAIT); 1581 completeRule(waitRecognizer, END_WAIT, SIMPLE); 1582 } 1583 1584 /** 1585 * Create rule for USE verb. 1586 */ 1587 private void createRuleForUseVerb() { 1588 RecognizerBase<ECobolParserState> procedureRecognizer = createRecognizer(start -> { 1589 RecognizerBase<ECobolParserState> onRecognizer = start.optional(ON); 1590 onRecognizer.sequence(EnumSet.of(INPUT, OUTPUT, I_O, EXTEND)); 1591 onRecognizer.repeatedSubRecognizer(getRepeatedSequenceRecognizer(IDENTIFIER_AND_STRING_LITERALS)); 1592 }); 1593 RecognizerBase<ECobolParserState> givingRecognizer = createRecognizer(start -> start 1594 .sequence(GIVING, IDENTIFIER_AND_STRING_LITERALS).optional(IDENTIFIER_AND_STRING_LITERALS)); 1595 RecognizerBase<ECobolParserState> useRecognizer = inState(TOP_LEVEL, IN_STATEMENT).sequence(USE) 1596 .createNode(STATEMENT, 0).optional(GLOBAL).sequence(AFTER).optional(STANDARD); 1597 useRecognizer.sequence(EnumSet.of(EXCEPTION, ERROR), PROCEDURE).subRecognizer(procedureRecognizer) 1598 .optionalSubRecognizer(givingRecognizer); 1599 useRecognizer.sequence(EnumSet.of(BEGINNING, ENDING), EnumSet.of(FILE, REEL, UNIT), LABEL, PROCEDURE) 1600 .subRecognizer(procedureRecognizer); 1601 completeRule(useRecognizer, null, SIMPLE); 1602 } 1603 1604 /** 1605 * Create rule for TRANSFORM verb. 1606 */ 1607 private void createRuleForTransformVerb() { 1608 RecognizerBase<ECobolParserState> transformRecognizer = inState(TOP_LEVEL, IN_STATEMENT) 1609 .sequence(TRANSFORM, IDENTIFIER).createNode(STATEMENT, 0).optional(CHARACTERS); 1610 transformRecognizer.sequence(FROM, IDENTIFIER_AND_STRING_LITERALS, TO, IDENTIFIER_AND_STRING_LITERALS); 1611 completeRule(transformRecognizer, null, SIMPLE); 1612 } 1613 1614 /** 1615 * Create rule for GOBACK verb 1616 */ 1617 private void createRuleForGobackVerb() { 1618 RecognizerBase<ECobolParserState> givingReturningRecognizer = createRecognizer(start -> { 1619 RecognizerBase<ECobolParserState> prefix = start.sequence(EnumSet.of(GIVING, RETURNING)); 1620 prefix.optional(ADDRESS, OF).sequence(IDENTIFIER); 1621 prefix.sequence(INTEGER_LITERAL); 1622 }); 1623 RecognizerBase<ECobolParserState> goBackRecognizer = inState(TOP_LEVEL, IN_STATEMENT).sequence(GOBACK) 1624 .createNode(STATEMENT, 0); 1625 goBackRecognizer.optionalSubRecognizer(givingReturningRecognizer); 1626 completeRule(goBackRecognizer, null, SIMPLE); 1627 } 1628 1629 /** 1630 * Create rules for the ALTER verb 1631 */ 1632 private void createRuleForAlterVerb() { 1633 RecognizerBase<ECobolParserState> repeatedRecognizer = createRecognizer( 1634 start -> start.optional(COMMA).sequence(IDENTIFIER, TO).optional(PROCEED, TO).sequence(IDENTIFIER)); 1635 RecognizerBase<ECobolParserState> alterRecognizer = inState(TOP_LEVEL, IN_STATEMENT).sequence(ALTER) 1636 .createNode(STATEMENT, 0).repeatedSubRecognizer(repeatedRecognizer); 1637 completeRule(alterRecognizer, null, SIMPLE); 1638 } 1639 1640 /** 1641 * Create rule for the MOVE verb 1642 */ 1643 private void createRuleForMoveVerb() { 1644 RecognizerBase<ECobolParserState> moveRecognizer = inState(TOP_LEVEL, IN_STATEMENT).sequence(MOVE) 1645 .createNode(STATEMENT, 0).skipTo(TO).sequence(VALID_VARIABLE_NAMES).skipNested(LPAREN, RPAREN); 1646 RecognizerBase<ECobolParserState> rightOperandRecognizer = createRecognizer( 1647 start -> start.optional(COMMA).sequence(IDENTIFIER).skipNested(LPAREN, RPAREN)); 1648 moveRecognizer.repeatedSubRecognizer(rightOperandRecognizer); 1649 completeRule(moveRecognizer, null, SIMPLE); 1650 } 1651 1652 /** 1653 * Create rules for STOP verb. 1654 */ 1655 private void createRuleForStopVerb() { 1656 RecognizerBase<ECobolParserState> stopRecognizer = inState(TOP_LEVEL, IN_STATEMENT).sequence(STOP) 1657 .createNode(STATEMENT, 0); 1658 RecognizerBase<ECobolParserState> withLiteralRecognizer = stopRecognizer 1659 .sequence(EnumSet.of(STRING_LITERAL, INTEGER_LITERAL)); 1660 RecognizerBase<ECobolParserState> baseRunRecognizer = stopRecognizer.sequence(RUN); 1661 RecognizerBase<ECobolParserState> runRecognizer = baseRunRecognizer.sequence(EnumSet.of(GIVING, RETURNING)); 1662 runRecognizer.sequence(ADDRESS, OF, IDENTIFIER); 1663 runRecognizer.sequence(INTEGER_LITERAL, SIZE).optional(IS).sequence(INTEGER_LITERAL); 1664 runRecognizer.sequence(EnumSet.of(INTEGER_LITERAL, IDENTIFIER)); 1665 1666 completeRule(runRecognizer, null, SIMPLE); 1667 completeRule(baseRunRecognizer, null, SIMPLE); 1668 completeRule(withLiteralRecognizer, null, SIMPLE); 1669 } 1670 1671 /** 1672 * Create rules for the STRING verb 1673 */ 1674 private void createRuleForStringVerb() { 1675 RecognizerBase<ECobolParserState> leftOperandRecognizer = createRecognizer( 1676 start -> start.optional(COMMA).sequence(IDENTIFIER_AND_LITERALS)); 1677 EnumSet<ETokenType> rightOperandTokens = EnumSet.copyOf(IDENTIFIER_AND_LITERALS); 1678 rightOperandTokens.add(SIZE); 1679 RecognizerBase<ECobolParserState> stringRecognizer = createRecognizer( 1680 start -> start.repeatedSubRecognizer(leftOperandRecognizer).sequence(DELIMITED).optional(BY) 1681 .sequence(rightOperandTokens)); 1682 RecognizerBase<ECobolParserState> baseStringRecognizer = inState(TOP_LEVEL, IN_STATEMENT).sequence(STRING) 1683 .createNode(STATEMENT, 0).repeatedSubRecognizer(stringRecognizer).sequence(INTO, IDENTIFIER) 1684 .optional(WITH).optional(POINTER, IDENTIFIER); 1685 completeRuleWithConditionalClause(baseStringRecognizer, createOnAtClauseSubRecognizer(OVERFLOW), END_STRING); 1686 completeRule(baseStringRecognizer, END_STRING, SIMPLE); 1687 } 1688 1689 /** 1690 * Create rules for the UNSTRING verb 1691 */ 1692 private void createRuleForUnstringVerb() { 1693 RecognizerBase<ECobolParserState> orAllRecognizer = createRecognizer( 1694 start -> start.optional(COMMA).sequence(OR).optional(ALL).sequence(IDENTIFIER_AND_LITERALS)); 1695 RecognizerBase<ECobolParserState> delimitedByRecognizer = createRecognizer(start -> start.sequence(DELIMITED) 1696 .skipAny(EnumSet.of(BY, ALL)).sequence(IDENTIFIER_AND_LITERALS).repeatedSubRecognizer(orAllRecognizer)); 1697 RecognizerBase<ECobolParserState> intoRecognizer = createRecognizer(start -> { 1698 RecognizerBase<ECobolParserState> prefix = start.optional(COMMA); 1699 prefix.sequence(EnumSet.of(DELIMITER, COUNT)).optional(IN).sequence(IDENTIFIER); 1700 prefix.sequence(IDENTIFIER); 1701 }); 1702 RecognizerBase<ECobolParserState> withPointerRecognizer = createRecognizer( 1703 start -> start.optional(WITH).sequence(POINTER, IDENTIFIER)); 1704 RecognizerBase<ECobolParserState> tallyingRecognizer = createRecognizer( 1705 start -> start.sequence(TALLYING).optional(IN).sequence(IDENTIFIER)); 1706 RecognizerBase<ECobolParserState> unstringRecognizer = inState(TOP_LEVEL, IN_STATEMENT) 1707 .sequence(UNSTRING, IDENTIFIER).createNode(STATEMENT, 0, 1); 1708 unstringRecognizer = unstringRecognizer.optionalSubRecognizer(delimitedByRecognizer).sequence(INTO) 1709 .repeatedSubRecognizer(intoRecognizer).optionalSubRecognizer(withPointerRecognizer) 1710 .optionalSubRecognizer(tallyingRecognizer); 1711 1712 completeRuleWithConditionalClause(unstringRecognizer, createOnAtClauseSubRecognizer(OVERFLOW), END_UNSTRING); 1713 completeRule(unstringRecognizer, END_UNSTRING, SIMPLE); 1714 } 1715 1716 /** 1717 * Create rules for SET verb 1718 */ 1719 private void createRuleForSetVerb() { 1720 RecognizerBase<ECobolParserState> baseSetRecognizer = inState(TOP_LEVEL, IN_STATEMENT).sequence(SET) 1721 .createNode(STATEMENT, 0); 1722 RecognizerBase<ECobolParserState> leftAndRightRepetitionRecognizer = createRecognizer(start -> start 1723 .repeatedSubRecognizer(getLeftOperandForSetVerb()).subRecognizer(getRightOperandForSetVerb())); 1724 baseSetRecognizer.repeatedSubRecognizer(leftAndRightRepetitionRecognizer); 1725 completeRule(baseSetRecognizer, null, SIMPLE); 1726 } 1727 1728 /** 1729 * Gets the recognizer for the right operand of a SET verb. 1730 */ 1731 private RecognizerBase<ECobolParserState> getRightOperandForSetVerb() { 1732 return createRecognizer(start -> { 1733 RecognizerBase<ECobolParserState> prefix = start.sequence(EnumSet.of(TO, UP, DOWN)); 1734 prefix.sequence(EnumSet.of(STRING_LITERAL, ON, OFF, TRUE, FALSE, NULL, NULLS)); 1735 prefix.sequence(ADDRESS, OF, IDENTIFIER); 1736 prefix.sequence(BY).optional(LENGTH, OF).sequence(IDENTIFIER_AND_NUMERIC_LITERALS); 1737 prefix.sequence(ENTRY, IDENTIFIER_AND_LITERALS); 1738 prefix.optional(NOT).sequence(EnumSet.of(BROWSING, READING, WRITING), CONVERTING, FROM, 1739 EnumSet.of(BROWSING, WRITING)); 1740 prefix.optional(NOT).sequence(EnumSet.of(BROWSING, READING, WRITING)); 1741 prefix.repeatedSubRecognizer(getArithmeticExpressionRecognizer(true)); 1742 }); 1743 } 1744 1745 /** 1746 * Return a sub recognizer for matching repeated sequence of tokens with or 1747 * without a comma separator. 1748 */ 1749 private RecognizerBase<ECobolParserState> getRepeatedSequenceRecognizer(Object sequence) { 1750 return createRecognizer(start -> start.optional(COMMA).sequence(sequence)); 1751 } 1752 1753 /** 1754 * Gets the recognizer for the left operand of a SET verb. 1755 */ 1756 private RecognizerBase<ECobolParserState> getLeftOperandForSetVerb() { 1757 return createRecognizer(start -> { 1758 start.optional(COMMA).sequence(EnumSet.of(ADDRESS, SIZE, CONTENT)).optional(OF).sequence(IDENTIFIER); 1759 start.subRecognizer(getRepeatedSequenceRecognizer(IDENTIFIER)); 1760 }); 1761 } 1762 1763 /** 1764 * Creates parsing rules for EXIT verb. 1765 */ 1766 private void createRuleForExitVerb() { 1767 RecognizerBase<ECobolParserState> exitProgramRecognizer = createRecognizer(start -> { 1768 RecognizerBase<ECobolParserState> prefix = start.sequence(EnumSet.of(GIVING, RETURNING)); 1769 prefix.optional(ADDRESS, OF).sequence(IDENTIFIER); 1770 prefix.sequence(INTEGER_LITERAL); 1771 }); 1772 RecognizerBase<ECobolParserState> exitRecognizer = inState(TOP_LEVEL, IN_STATEMENT).sequence(EXIT) 1773 .createNode(STATEMENT, 0); 1774 exitRecognizer.sequence(PERFORM).optional(CYCLE); 1775 exitRecognizer.sequence(EnumSet.of(FUNCTION, ETokenType.METHOD, PARAGRAPH, SECTION)); 1776 exitRecognizer.sequence(PROGRAM).optionalSubRecognizer(exitProgramRecognizer); 1777 completeRule(exitRecognizer, null, SIMPLE); 1778 } 1779 1780 /** 1781 * Create rules for condition statements. 1782 */ 1783 private void createConditionRules() { 1784 createIfAndElseRules(); 1785 1786 // Search statement 1787 completeRule(inState(TOP_LEVEL, IN_STATEMENT).sequence(EVALUATE).createNode(STATEMENT, SubTypeNames.EVALUATE), 1788 END_EVALUATE, SCOPE); 1789 1790 // Evaluate statement 1791 completeRule(inState(TOP_LEVEL, IN_STATEMENT).sequence(SEARCH).optional(ALL).sequence(IDENTIFIER) 1792 .skipAny(EnumSet.of(VARYING, IDENTIFIER, AT, END)).createNode(STATEMENT, 0), END_SEARCH, SCOPE); 1793 1794 // Child-when statements for search and evaluate statements 1795 completeRule(inState(IN_STATEMENT).sequence(WHEN).optional(OTHER).createNode(STATEMENT, 0, 1), null, SIMPLE); 1796 } 1797 1798 /** 1799 * Create rules for loop verbs. 1800 */ 1801 private void createLoopVerbRules() { 1802 createPerformRules(); 1803 1804 RecognizerBase<ECobolParserState> gotoRecognizer = inState(TOP_LEVEL, IN_STATEMENT).sequence(GO) 1805 .createNode(STATEMENT, SubTypeNames.GOTO).optional(TO).optional(IDENTIFIER); 1806 RecognizerBase<ECobolParserState> gotoDependingRecognizer = gotoRecognizer 1807 .repeatedSubRecognizer(getRepeatedSequenceRecognizer(IDENTIFIER)) 1808 .subRecognizer(getDependingRecognizer()); 1809 1810 completeRule(gotoDependingRecognizer, null, SIMPLE); 1811 completeRule(gotoRecognizer, null, SIMPLE); 1812 } 1813 1814 /** 1815 * Create rules for the various perform statements 1816 */ 1817 private void createPerformRules() { 1818 RecognizerBase<ECobolParserState> performRecognizer = inState(TOP_LEVEL, IN_STATEMENT).sequence(PERFORM); 1819 RecognizerBase<ECobolParserState> identifierRecognizer = performRecognizer.sequence(IDENTIFIER) 1820 .createNode(STATEMENT, 0, 1); 1821 RecognizerBase<ECobolParserState> throughRecognizer = identifierRecognizer.sequence(EnumSet.of(THRU, THROUGH), 1822 (IDENTIFIER)); 1823 completePerformRule(throughRecognizer, SIMPLE); 1824 completePerformRule(identifierRecognizer, SIMPLE); 1825 completePerformRule(performRecognizer.createNode(STATEMENT, 0), SCOPE); 1826 } 1827 1828 /** 1829 * Complete a rule for the perform verb. 1830 */ 1831 private void completePerformRule(RecognizerBase<ECobolParserState> recognizer, EStatementEndType statementEndType) { 1832 EnumSet<ETokenType> skippedTokens = EnumSet.of(WITH, TEST, BEFORE, AFTER); 1833 RecognizerBase<ECobolParserState> timesRecognizer = recognizer.sequence(EnumSet.of(IDENTIFIER, INTEGER_LITERAL), 1834 TIMES); 1835 RecognizerBase<ECobolParserState> untilRecognizer = recognizer.skipAny(skippedTokens).sequence(UNTIL) 1836 .subRecognizer(getConditionSubRecognizer()); 1837 RecognizerBase<ECobolParserState> varyingUntilRecognizer = recognizer.skipAny(skippedTokens).sequence(VARYING) 1838 .skipTo(UNTIL).subRecognizer(getConditionSubRecognizer()); 1839 RecognizerBase<ECobolParserState> repeatedAfterUntilRecognizer = createRecognizer( 1840 start -> start.sequence(AFTER).skipTo(UNTIL).subRecognizer(getConditionSubRecognizer())); 1841 RecognizerBase<ECobolParserState> varyingUntilAfterRecognizer = varyingUntilRecognizer 1842 .repeatedSubRecognizer(repeatedAfterUntilRecognizer); 1843 1844 completeRule(varyingUntilAfterRecognizer, END_PERFORM, statementEndType); 1845 completeRule(varyingUntilRecognizer, END_PERFORM, statementEndType); 1846 completeRule(untilRecognizer, END_PERFORM, statementEndType); 1847 completeRule(timesRecognizer, END_PERFORM, statementEndType); 1848 if (statementEndType == SIMPLE) { 1849 recognizer.notPreCondition(new OutOfScopeRecognizer()).sequenceBefore(END_PERFORM).endNode(); 1850 } 1851 completeRule(recognizer, END_PERFORM, statementEndType); 1852 } 1853 1854 /** 1855 * Get the recognizer to match arithmetic expressions. A comma is not an 1856 * arithmetic operator but its included because as a Cobol separator, it helps 1857 * to match repeated identifiers or expressions 1858 */ 1859 private RecognizerBase<ECobolParserState> getArithmeticExpressionRecognizer(boolean includeComma) { 1860 EnumSet<ETokenType> operatorTokens = EnumSet.of(PLUS, MINUS, DIV, MULT, B_AND, B_OR, B_NOT, B_XOR); 1861 EnumSet<ETokenType> operandTokens = EnumSet.copyOf(IDENTIFIER_LITERALS_AND_ZERO); 1862 operandTokens.addAll(EnumSet.of(NULL, NULLS, SELF)); 1863 operandTokens.remove(STRING_LITERAL); 1864 if (includeComma) { 1865 operandTokens.add(COMMA); 1866 } 1867 RecognizerBase<ECobolParserState> operatorBeforeExpressionRecognizer = createRecognizer(start -> { 1868 RecognizerBase<ECobolParserState> prefix = start.sequence(operatorTokens); 1869 prefix.sequence(operandTokens); 1870 prefix.skipNested(LPAREN, RPAREN); 1871 }); 1872 1873 RecognizerBase<ECobolParserState> repeatedExpressionRecognizer = createRecognizer(start -> { 1874 start.subRecognizer(operatorBeforeExpressionRecognizer); 1875 start.skipNested(LPAREN, RPAREN); 1876 }); 1877 1878 return createRecognizer(start -> { 1879 start.sequence(operandTokens).repeatedSubRecognizer(repeatedExpressionRecognizer); 1880 start.skipNested(LPAREN, RPAREN).repeatedSubRecognizer(repeatedExpressionRecognizer); 1881 }); 1882 } 1883 1884 /** 1885 * Returns a basic condition sub recognizer. 1886 */ 1887 private RecognizerBase<ECobolParserState> getConditionSubRecognizer() { 1888 EnumSet<ETokenType> leftOperandTokens = EnumSet.copyOf(IDENTIFIER_LITERALS_AND_ZERO); 1889 leftOperandTokens.addAll(EnumSet.of(NULL, NULLS, SELF)); 1890 EnumSet<ETokenType> rightOperandTokens = EnumSet.copyOf(leftOperandTokens); 1891 rightOperandTokens.addAll(EnumSet.of(NUMERIC, ALPHABETIC, ALPHABETIC_UPPER, ALPHABETIC_LOWER, DBCS, KANJI)); 1892 1893 RecognizerBase<ECobolParserState> singleOperandRecognizer = createRecognizer( 1894 start -> start.sequence(leftOperandTokens)); 1895 1896 return createRecognizer(start -> start.optionalSubRecognizer(getArithmeticExpressionRecognizer(false)) 1897 .optionalSubRecognizer(singleOperandRecognizer)); 1898 } 1899 1900 /** 1901 * Create rules for if-related condition statements 1902 */ 1903 private void createIfAndElseRules() { 1904 createIfRule(IF, EnumSet.of(ELSE, OTHERWISE), END_IF, STATEMENT); 1905 createElseRule(EnumSet.of(ELSE, OTHERWISE), END_IF, STATEMENT); 1906 } 1907 1908 /** 1909 * Create rules for the ELSE-statement and $ELSE-meta entities 1910 */ 1911 private void createElseRule(EnumSet<ETokenType> elseOtherwise, ETokenType endToken, EShallowEntityType entityType) { 1912 RecognizerBase<ECobolParserState> elseOtherwiseRecognizer = inState(TOP_LEVEL, IN_STATEMENT) 1913 .sequence(elseOtherwise).createNode(entityType, 0).parseUntil(IN_STATEMENT); 1914 1915 elseOtherwiseRecognizer.sequenceBefore(elseOtherwise).endNode(); 1916 elseOtherwiseRecognizer.sequence(endToken).endNode(); 1917 elseOtherwiseRecognizer.sequenceBefore(DOT).endNode(); 1918 } 1919 1920 /** 1921 * Create the IF-statement and $IF-meta rules. 1922 */ 1923 private void createIfRule(ETokenType ifType, EnumSet<ETokenType> elseOtherwise, ETokenType endIfType, 1924 EShallowEntityType entityType) { 1925 RecognizerBase<ECobolParserState> ifRecognizer = inState(TOP_LEVEL, IN_STATEMENT).sequence(ifType) 1926 .createNode(entityType, 0).parseUntil(IN_STATEMENT); 1927 ifRecognizer.sequenceBefore(elseOtherwise).endNodeWithContinuation(); 1928 1929 // Precondition ensures that we are parsing an if-block without an else. 1930 ifRecognizer.preCondition(new NoElseRecognizer(ifType, endIfType)).sequence(endIfType).endNode(); 1931 ifRecognizer.sequenceBefore(DOT).endNode(); 1932 } 1933 1934 /** 1935 * Create rules for the TRY ... CATCH... FINALLY Verbs. 1936 */ 1937 private void createTryCatchFinallyVerbsRules() { 1938 completeRule(inState(TOP_LEVEL, IN_STATEMENT).sequence(TRY).createNode(STATEMENT, 0), END_TRY, SCOPE); 1939 1940 inState(TOP_LEVEL, IN_STATEMENT).sequence(CATCH, IDENTIFIER).createNode(STATEMENT, 0).parseUntil(IN_STATEMENT) 1941 .sequenceBefore(EnumSet.of(CATCH, FINALLY, END_TRY, DOT)).endNode(); 1942 1943 inState(TOP_LEVEL, IN_STATEMENT).sequence(FINALLY).createNode(STATEMENT, 0).parseUntil(IN_STATEMENT) 1944 .sequenceBefore(EnumSet.of(END_TRY, DOT)).endNode(); 1945 } 1946 1947 /** {@inheritDoc} */ 1948 @Override 1949 public List<ShallowEntity> parseTopLevel(List<IToken> tokens) { 1950 return new SectionParagraphToMethodProcessor(tokens).postProcess(super.parseTopLevel(tokens)); 1951 } 1952}