PageRenderTime 30ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 0ms

/ojc-core/encodersl/encoder-coco/src/com/sun/encoder/coco/model/CocoParser.java

https://bitbucket.org/pymma/openesb-components
Java | 1334 lines | 874 code | 144 blank | 316 comment | 298 complexity | a6808b034c34480de3ded1a305a12c28 MD5 | raw file
  1. /*
  2. * BEGIN_HEADER - DO NOT EDIT
  3. *
  4. * The contents of this file are subject to the terms
  5. * of the Common Development and Distribution License
  6. * (the "License"). You may not use this file except
  7. * in compliance with the License.
  8. *
  9. * You can obtain a copy of the license at
  10. * https://open-jbi-components.dev.java.net/public/CDDLv1.0.html.
  11. * See the License for the specific language governing
  12. * permissions and limitations under the License.
  13. *
  14. * When distributing Covered Code, include this CDDL
  15. * HEADER in each file and include the License file at
  16. * https://open-jbi-components.dev.java.net/public/CDDLv1.0.html.
  17. * If applicable add the following below this CDDL HEADER,
  18. * with the fields enclosed by brackets "[]" replaced with
  19. * your own identifying information: Portions Copyright
  20. * [year] [name of copyright owner]
  21. */
  22. /*
  23. * @(#)CocoParser.java
  24. *
  25. * Copyright 2004-2007 Sun Microsystems, Inc. All Rights Reserved.
  26. *
  27. * END_HEADER - DO NOT EDIT
  28. */
  29. package com.sun.encoder.coco.model;
  30. import java.io.IOException;
  31. import java.util.ArrayList;
  32. import java.util.Collections;
  33. import java.util.HashSet;
  34. import java.util.Iterator;
  35. import java.util.Set;
  36. import java.util.List;
  37. import java.util.ListIterator;
  38. import com.sun.encoder.coco.runtime.messages.ErrorManager;
  39. import com.sun.encoder.coco.runtime.messages.Message;
  40. import com.sun.encoder.coco.runtime.messages.MessageCatalog;
  41. /**
  42. * Reads Cobol Copybook files and creates a data model
  43. *
  44. * @author Noel Ang
  45. *
  46. */
  47. public class CocoParser {
  48. /**
  49. * Length of Cobol source lines
  50. */
  51. public static final int SOURCE_LINE_LENGTH = 82;
  52. private static Set cSourceAreas;
  53. private ArrayList mCols;
  54. private ArrayList mRows;
  55. private CocoLexer mLexer;
  56. private CocoDataModel mModel;
  57. private CocoDescriptionEntry mCurrentEntry;
  58. private CocoDescriptionEntry mLastEntry;
  59. private int mCol;
  60. private int mRow;
  61. private boolean mReservedWordCheck = true;
  62. private final ErrorManager mErrorMgr =
  63. ErrorManager.getManager("STC.eWay.converter.COBOLCopybook."
  64. + getClass().getName());
  65. static {
  66. String pkg = CocoParser.class.getPackage().getName();
  67. HashSet areas = new HashSet();
  68. areas.add(CobolSourceSequenceArea.getArea());
  69. areas.add(CobolSourceIndicatorArea.getArea());
  70. areas.add(CobolSourceAreaA.getArea());
  71. areas.add(CobolSourceAreaB.getArea());
  72. cSourceAreas = Collections.unmodifiableSet(areas);
  73. }
  74. /**
  75. * Create a parser.
  76. *
  77. * @param lexer CocoLexer object to use as the parser's input source
  78. */
  79. public CocoParser(CocoLexer lexer) {
  80. mLexer = lexer;
  81. mModel = new CocoDataModel();
  82. mCol = 1;
  83. mRow = 1;
  84. mCols = new ArrayList();
  85. mRows = new ArrayList();
  86. }
  87. /**
  88. * Parse Copybook data and create a data model.
  89. *
  90. * @throws CocoParseException
  91. * @throws java.io.IOException if an I/O error occurs
  92. */
  93. public CocoDataModel parse() throws CocoParseException, IOException {
  94. createModel();
  95. // resolve OCCURS with DEPENDING ON <data-name> etc
  96. mModel.validate();
  97. mModel.resolveOccurs();
  98. // Name mangling/resolution suspended.
  99. // First, this is not a parser concern, so it should be addressed elsewhere.
  100. // Second, COCOCO relaunch support requires the name mangling process to
  101. // modify its behaviour based on whether or not a relaunch is underway.
  102. // Name collision handling will be handled where and when it matters:
  103. // during OTD creation.
  104. //mModel.makeBaseNamesUnique();
  105. return mModel;
  106. }
  107. /**
  108. * Parse Copybook data and populate data model. If the supplied model is
  109. * null, a new model will be allocated instead.
  110. *
  111. * @param model Data model to fill with information
  112. * @throws CocoParseException
  113. * @throws java.io.IOException if an I/O error occurs
  114. */
  115. public CocoDataModel parse(CocoDataModel model)
  116. throws CocoParseException, IOException {
  117. if (model != null) {
  118. mModel = model;
  119. }
  120. return parse();
  121. }
  122. /**
  123. * Disable reserved word checking for item names. By default, reserved word
  124. * checking is enabled. The consequence of disabling it is that the parser
  125. * will not be able to parse item descriptions without names
  126. * (implied 'FILLER' items).
  127. *
  128. * @param disable <code>true</code> to disable reserved word checking.
  129. */
  130. public void disableItemNameReservedWordChecking(boolean disable) {
  131. mReservedWordCheck = !disable;
  132. }
  133. /**
  134. * Create the data model from parsed Cobol Copybook input.
  135. *
  136. * @throws CocoParseException
  137. * @throws java.io.IOException if an I/O error occurs
  138. * @see CocoDataModel
  139. */
  140. protected void createModel() throws CocoParseException, IOException {
  141. processEntries();
  142. }
  143. /**
  144. * Process parsed entries to make the data model.
  145. *
  146. * @see CocoDataModel
  147. * @see CocoDescriptionEntry
  148. */
  149. private void processEntries() throws CocoParseException, IOException {
  150. CocoDescriptionEntry entry = null;
  151. do {
  152. entry = getEntry();
  153. if (entry != null) {
  154. if (entry.getLevel() != -1) {
  155. mLastEntry = entry;
  156. /* special case: don't add 88 entries */
  157. if (entry.getLevel() == 88) {
  158. continue;
  159. }
  160. try {
  161. mModel.addEntry(entry);
  162. } catch (IllegalArgumentException iae) {
  163. logAndThrow("CCCB4201",
  164. new Object[]{iae.getLocalizedMessage()},
  165. ErrorManager.Severity.ERROR,
  166. iae,
  167. null);
  168. }
  169. }
  170. }
  171. } while (entry != null);
  172. }
  173. /**
  174. * Read one item description from the input source, and create a
  175. * CocoDescriptionEntry object for it.
  176. *
  177. * @return a CocoDescriptionEntry object, or null if there is no available
  178. * input. This method also has the side-effect of designating
  179. * the returned object as the "current" object for this parser
  180. * object.
  181. * @throws CocoParseException if the input cannot be parsed successfully
  182. * @throws java.io.IOException if an I/O error occurs
  183. */
  184. private CocoDescriptionEntry getEntry()
  185. throws CocoParseException,
  186. IOException {
  187. CocoDescriptionEntry entry = null;
  188. if (skipSequenceArea()) {
  189. entry = mCurrentEntry = new CocoDescriptionEntry();
  190. if (parseIndicatorArea(entry)) {
  191. // EOL
  192. consumeEOL();
  193. } else {
  194. // indicator already parsed
  195. boolean isEOLReached = parseAreaA(entry);
  196. if (isEOLReached) {
  197. consumeEOL();
  198. }
  199. if (!isEOLReached || entry.isContinuation()) {
  200. // either a blank but continue line or a line that has B area
  201. parseAreaB(entry);
  202. skipLine();
  203. }
  204. }
  205. } else {
  206. // no token following - but check EOL and EOF
  207. // an entry to be skipped
  208. CocoToken token = getNextToken();
  209. ungetToken(token);
  210. if (token != null) {
  211. if (token.isEOL()) {
  212. // return a dummy entry so getEntries() will continue
  213. entry = new CocoDescriptionEntry();
  214. // consume it
  215. consumeEOL();
  216. } else if (token.isEOF()) {
  217. // THE END
  218. entry = null;
  219. }
  220. } else {
  221. // unlikely
  222. }
  223. }
  224. return entry;
  225. }
  226. private void consumeEOL() throws IOException {
  227. CocoToken token = getNextToken();
  228. if (token != null && token.isEOL()) {
  229. // consume EOL
  230. updatePosition(token);
  231. } else {
  232. ungetToken(token);
  233. }
  234. }
  235. /**
  236. * Process the Indicator Area of the current Cobol source line.
  237. *
  238. * @param entry Description entry to initialize/populate with information
  239. * from Indicator Area.
  240. * @return true if EOL is reached, or false otherwise.
  241. * @throws CocoParseException if a parsing error occurs
  242. * @throws java.io.IOException if an I/O error occurs
  243. */
  244. private boolean parseIndicatorArea(CocoDescriptionEntry entry)
  245. throws CocoParseException, IOException {
  246. CocoToken token = getNextToken();
  247. if (!isInIndicatorArea(token)) {
  248. return false;
  249. } else {
  250. if (token.isEOL()) {
  251. ungetToken(token);
  252. return true;
  253. }
  254. /* Ignore entries with no indicators */
  255. if (isSpace(token)) {
  256. skipIndicatorArea();
  257. return false;
  258. }
  259. /* Ignore comments by consuming rest of area */
  260. if (isComment(token)) {
  261. entry.setComment(true);
  262. skipIndicatorArea();
  263. return false;
  264. }
  265. String value = token.getStringValue().toUpperCase();
  266. /* Ignore debugging lines */
  267. if (value.equals(CocoLanguage.DEBUGGING_INDICATOR)) {
  268. entry.setIndicatorValue(value);
  269. return false;
  270. }
  271. /* Process continuation entries */
  272. if (value.equals(CocoLanguage.HYPHEN)) {
  273. /*
  274. * This is not a conclusive indication; primary checking
  275. * is done during parsing of Area A
  276. */
  277. entry.setContinuation(true);
  278. return false;
  279. }
  280. /* Unrecognized indicator */
  281. logAndThrow("CCCB4202", new Object[]{token.getStringValue()},
  282. ErrorManager.Severity.ERROR, null, null);
  283. return false;
  284. }
  285. }
  286. /**
  287. * Process the Area A of the current Cobol source line.
  288. *
  289. * @param entry Description entry to initialize/populate with information
  290. * from Area A
  291. * @return true if EOL is reached, or false otherwise.
  292. * @throws CocoParseException if a parsing error occurs
  293. * @throws java.io.IOException if an I/O error occurs
  294. */
  295. private boolean parseAreaA(CocoDescriptionEntry entry)
  296. throws CocoParseException, IOException {
  297. boolean eodEncountered = false;
  298. if (entry.isComment()) {
  299. skipAreaA();
  300. return eodEncountered;
  301. }
  302. CocoToken token = null;
  303. while (true) {
  304. token = getNextToken();
  305. if (token == null || token.isEOF()) {
  306. ungetToken(token);
  307. break;
  308. }
  309. // scan until the first non blank char - break for level number parsing
  310. if (!CocoLanguage.SPACE.equals(token.getStringValue())) {
  311. ungetToken(token);
  312. break;
  313. } else {
  314. if (token.isEOL()) {
  315. ungetToken(token);
  316. return true;
  317. }
  318. if (!isInAreaA(token) && !isPartiallyInAreaA(token)) {
  319. ungetToken(token);
  320. break;
  321. }
  322. }
  323. }
  324. /* per 89392 a EOL is possible in area A, B, and indicator area
  325. */
  326. if (token == null || token.isEOF()) {
  327. ungetToken(token);
  328. return false;
  329. }
  330. /*
  331. * If Area A is blank, depending on what I find in Area B later,
  332. * it's either a blank line, a continuation line, or a free-standing
  333. * line whose level number is in Area B.
  334. *
  335. * Right now, assume this is a continuation line.
  336. *
  337. * If Area A is NOT blank, but the Indicator Area marked this as a
  338. * continuation line, it's an error.
  339. */
  340. if (!isInAreaA(token) && !isPartiallyInAreaA(token)) {
  341. entry.setContinuation(true);
  342. return false;
  343. } else if (entry.isContinuation()) {
  344. logAndThrow("CCCB4204", null, ErrorManager.Severity.ERROR, null, token);
  345. }
  346. parseLevelNumber(entry);
  347. skipSpacesOrPeriods(true);
  348. token = getNextToken();
  349. if (token != null && !token.isEOL()) {
  350. ungetToken(token);
  351. parseDataName(entry);
  352. }
  353. return false;
  354. }
  355. /**
  356. * Process the Area B of the current Cobol source line.
  357. *
  358. * @param entry Description entry to initialize/populate with information
  359. * from Area B
  360. * @throws CocoParseException if a parsing error occurs
  361. * @throws java.io.IOException if an I/O error occurs
  362. */
  363. private void parseAreaB(CocoDescriptionEntry entry)
  364. throws CocoParseException, IOException {
  365. if (entry.isComment()) {
  366. skipAreaB();
  367. return;
  368. }
  369. /* The entry being processed may be a blank line */
  370. skipOptionalSpaces(false);
  371. CocoToken token = getNextTokenAreaB(true, true);
  372. ungetToken(token);
  373. if (token == null || token.isEOF() || !isInAreaB(token)) {
  374. entry.setContinuation(false);
  375. return;
  376. }
  377. if ( entry.getLevel() == -1
  378. && ( entry.getName() == null || entry.getName().trim().length() == 0 )
  379. && token != null
  380. && token.isEOL() )
  381. return;
  382. /* I never found a level number while scanning Area A */
  383. if (entry.getLevel() == -1) {
  384. entry.setContinuation(false);
  385. parseLevelNumber(entry);
  386. }
  387. /* a level number and data name already been parsed before parseAreaB() */
  388. if (entry.getLevel() > 0
  389. && entry.getName() != null
  390. && entry.getName().length() > 0) {
  391. // already got a data name in A or A across B
  392. } else {
  393. parseDataName(entry);
  394. }
  395. parseRedefinesClause(entry);
  396. boolean gotBlankClause = false;
  397. boolean gotExternalClause = false;
  398. boolean gotGlobalClause = false;
  399. boolean gotJustifiedClause = false;
  400. boolean gotOccursClause = false;
  401. boolean gotPictureClause = false;
  402. boolean gotSignClause = false;
  403. boolean gotSynchronizedClause = false;
  404. boolean gotUsageClause = false;
  405. boolean gotValueClause = false;
  406. boolean gotDateFormatClause = false;
  407. boolean done = false;
  408. int prevCount = 0;
  409. while (!done) {
  410. int passCount = 0;
  411. if (!gotBlankClause) {
  412. gotBlankClause = parseBlankWhenZeroClause(entry);
  413. passCount += (gotBlankClause ? 1 : 0);
  414. }
  415. if (!gotExternalClause) {
  416. gotExternalClause = parseExternalClause(entry);
  417. passCount += (gotExternalClause ? 1 : 0);
  418. }
  419. if (!gotGlobalClause) {
  420. gotGlobalClause = parseGlobalClause(entry);
  421. passCount += (gotGlobalClause ? 1 : 0);
  422. }
  423. if (!gotJustifiedClause) {
  424. gotJustifiedClause = parseJustifiedClause(entry);
  425. passCount += (gotJustifiedClause ? 1 : 0);
  426. }
  427. if (!gotOccursClause) {
  428. gotOccursClause = parseOccursClause(entry); //also indexed by...
  429. passCount += (gotOccursClause ? 1 : 0);
  430. }
  431. if (!gotPictureClause) {
  432. gotPictureClause = parsePictureClause(entry);
  433. passCount += (gotPictureClause ? 1 : 0);
  434. }
  435. if (!gotSignClause) {
  436. gotSignClause = parseSignClause(entry);
  437. passCount += (gotSignClause ? 1 : 0);
  438. }
  439. if (!gotSynchronizedClause) {
  440. gotSynchronizedClause = parseSynchronizedClause(entry);
  441. passCount += (gotSynchronizedClause ? 1 : 0);
  442. }
  443. if (!gotUsageClause) {
  444. gotUsageClause = parseUsageClause(entry);
  445. passCount += (gotUsageClause ? 1 : 0);
  446. }
  447. if (!gotValueClause) {
  448. gotValueClause = parseValueClause(entry);
  449. passCount += (gotValueClause ? 1 : 0);
  450. }
  451. if (!gotDateFormatClause) {
  452. gotDateFormatClause = parseDateFormatClause(entry);
  453. passCount += (gotDateFormatClause ? 1 : 0);
  454. }
  455. skipOptionalSpaces(true);
  456. token = getNextTokenAreaB(false, true);
  457. ungetToken(token);
  458. if (token == null || token.isEOF()) {
  459. logAndThrow("CCCB4203", new Object[]{entry.getName()},
  460. ErrorManager.Severity.ERROR, null, null);
  461. }
  462. String value = token.getStringValue();
  463. done = (value.equals(CocoLanguage.PERIOD)
  464. || value.equals(CocoLanguage.PERIOD_S));
  465. if (!done) {
  466. if (passCount <= prevCount) {
  467. logAndThrow("CCCB4205", new Object[]{value},
  468. ErrorManager.Severity.ERROR, null, token, entry);
  469. }
  470. }
  471. prevCount = passCount;
  472. }
  473. skipLine();
  474. }
  475. /**
  476. * Read parser input for a level number and assign it to a description entry.
  477. *
  478. * @param entry CocoDescriptionEntry to initialize with the level number
  479. * @throws CocoParseException if a parsing error occurs
  480. * @throws java.io.IOException if an I/O error occurs
  481. */
  482. private void parseLevelNumber(CocoDescriptionEntry entry)
  483. throws CocoParseException, IOException {
  484. CobolSourceArea area = getCurrentArea();
  485. CocoToken token = null;
  486. skipOptionalSpaces(true);
  487. if (area instanceof CobolSourceAreaB) {
  488. token = getNextTokenAreaB(false, true);
  489. } else {
  490. token = getNextToken();
  491. }
  492. if (token != null && !token.isEOF()) {
  493. if (token.getType() == CocoTokenTypes.NUM_TOKEN) {
  494. int level = -1;
  495. try {
  496. level = Integer.parseInt(token.getStringValue());
  497. } catch (NumberFormatException nfe) {
  498. logAndThrow("CCCB4108", new Object[]{
  499. entry.getName(),
  500. String.valueOf(token.getStringValue())},
  501. ErrorManager.Severity.ERROR, nfe, token);
  502. }
  503. try {
  504. entry.setLevel(level);
  505. } catch (IllegalArgumentException e) {
  506. logAndThrow("CCCB4108", new Object[]{
  507. entry.getName(),
  508. String.valueOf(token.getStringValue())},
  509. ErrorManager.Severity.ERROR, e, token);
  510. }
  511. } else {
  512. logAndThrow("CCCB4108", new Object[]{
  513. entry.getName(),
  514. String.valueOf(token.getStringValue())},
  515. ErrorManager.Severity.ERROR, null, token);
  516. }
  517. } else {
  518. logAndThrow("CCCB4206", new Object[]{entry.getName()},
  519. ErrorManager.Severity.ERROR, null, null);
  520. }
  521. }
  522. /**
  523. * Attempt to read parser input for a data name, and make it the name of a
  524. * description entry. If no valid name can be obtained, the name of the
  525. * description entry is set to null (to nothing).
  526. *
  527. * @param entry CocoDescriptionEntry to initialize with the name
  528. * @throws CocoParseException if a parsing error occurs
  529. * @throws java.io.IOException if an I/O error occurs
  530. */
  531. private void parseDataName(CocoDescriptionEntry entry)
  532. throws CocoParseException, IOException {
  533. try {
  534. String name = parseCobolWord(mReservedWordCheck);
  535. entry.setName(name);
  536. entry.setOriginalName(name);
  537. skipClauseSeparator();
  538. } catch (ReservedWordEncounteredException rwe) {
  539. // since the data name could be FILLER or empty (blank)
  540. // we should let the parsing continue
  541. if (mReservedWordCheck) {
  542. entry.setReservedWordAfterLevel(rwe);
  543. //throw rwe;
  544. }
  545. // the following code is unlikely be reached
  546. // but put it here in case - fall back to old logic;
  547. String name = formWord("FILLER", false);
  548. if (name != null && !"".equals(name.trim())) {
  549. entry.setName(name);
  550. entry.setOriginalName(name);
  551. } else {
  552. entry.setName("BLANK");
  553. entry.setOriginalName("");
  554. }
  555. } catch (CocoParseException cpe) {
  556. String name = formWord("FILLER", false);
  557. if (name != null && !"".equals(name.trim())) {
  558. entry.setName(name);
  559. entry.setOriginalName(name);
  560. } else {
  561. entry.setName("BLANK");
  562. entry.setOriginalName("");
  563. }
  564. }
  565. }
  566. /**
  567. * Process 'Redefines' clause from the parser input, and initialize a
  568. * description entry with its information. If a Redefines clause is not
  569. * available, the entry is unchanged.
  570. *
  571. * @param entry CocoDescriptionEntry to initialize with the clause information
  572. * @throws CocoParseException if a parsing error occurs
  573. * @throws java.io.IOException if an I/O error occurs
  574. */
  575. private void parseRedefinesClause(CocoDescriptionEntry entry)
  576. throws CocoParseException, IOException {
  577. if (expectWord("REDEFINES")) {
  578. skipOptionalSpaces(true);
  579. // if EOL encountered - should continue to next B area
  580. // we must be in area B - so should call getNextTokenAreaB to jump to the
  581. // next point;
  582. CocoToken token = this.getNextTokenAreaB(false, true);
  583. if (token == null || token.isEOF()) {
  584. // error
  585. logAndThrow("CCCB4203",
  586. new Object[]{entry.getInfo()},
  587. ErrorManager.Severity.ERROR,
  588. null,
  589. null);
  590. }
  591. if (token.isEOL()) {
  592. // go to next line and scan for a word as redefined target
  593. token = this.getNextTokenAreaB(false, true);
  594. if (token == null || token.isEOF()) {
  595. logAndThrow("CCCB4203",
  596. new Object[]{entry.getInfo()},
  597. ErrorManager.Severity.ERROR,
  598. null,
  599. null);
  600. }
  601. }
  602. ungetToken(token);
  603. String name = parseCobolWord(mReservedWordCheck);
  604. CocoDescriptionEntry redefineTarget = mModel.findRedefineTarget(entry, name);
  605. if (redefineTarget == null) {
  606. logAndThrow("CCCB4207", new Object[]{
  607. name,
  608. entry.getName()},
  609. ErrorManager.Severity.ERROR, null, null);
  610. } else if (redefineTarget == entry) {
  611. logAndThrow("CCCB4114", new Object[]{entry.getName()},
  612. ErrorManager.Severity.ERROR, null, null);
  613. } else if (redefineTarget.getLevel() != entry.getLevel()) {
  614. logAndThrow("CCCB4116", new Object[]{
  615. entry.getName(),
  616. redefineTarget.getName(),
  617. String.valueOf(entry.getLevel()),
  618. String.valueOf(redefineTarget.getLevel())},
  619. ErrorManager.Severity.ERROR, null, null);
  620. } else {
  621. try {
  622. entry.setRedefinedTarget(redefineTarget);
  623. } catch (IllegalArgumentException e) {
  624. } catch (IllegalStateException e) {
  625. // TODO - implement
  626. }
  627. }
  628. skipClauseSeparator();
  629. }
  630. }
  631. /**
  632. * Process 'Blank When Zero' clause from the parser input, and initialize a
  633. * description entry with its information. If a Blank clause is not available,
  634. * the entry is also updated with that information.
  635. *
  636. * @param entry CocoDescriptionEntry to initialize with the clause information
  637. * @return true if a 'blank when zero' clause was consumed, false otherwise.
  638. * @throws CocoParseException if a parsing error occurs
  639. * @throws java.io.IOException if an I/O error occurs
  640. */
  641. private boolean parseBlankWhenZeroClause(CocoDescriptionEntry entry)
  642. throws CocoParseException, IOException {
  643. boolean gotClause = true;
  644. if (expectWord("BLANK")) {
  645. expectWord("WHEN");
  646. if (!expectWord("ZERO")) {
  647. if (!expectWord("ZEROS")) {
  648. if (!expectWord("ZEROES")) {
  649. logAndThrow("CCCB4208", null, ErrorManager.Severity.ERROR, null, null);
  650. } else {
  651. entry.setBlankWhenZero(true);
  652. skipClauseSeparator();
  653. }
  654. } else {
  655. entry.setBlankWhenZero(true);
  656. skipClauseSeparator();
  657. }
  658. } else {
  659. entry.setBlankWhenZero(true);
  660. skipClauseSeparator();
  661. }
  662. } else {
  663. entry.setBlankWhenZero(false);
  664. gotClause = false;
  665. }
  666. return gotClause;
  667. }
  668. /**
  669. * Process 'External' clause from the parser input, and initialize a
  670. * description entry with its information. If a External clause is not
  671. * available, the entry is unchanged.
  672. *
  673. * @param entry CocoDescriptionEntry to initialize with the clause information
  674. * @return true if a 'external' clause was consumed, false otherwise.
  675. * @throws CocoParseException if a parsing error occurs
  676. * @throws java.io.IOException if an I/O error occurs
  677. */
  678. private boolean parseExternalClause(CocoDescriptionEntry entry)
  679. throws CocoParseException, IOException {
  680. boolean gotClause = false;
  681. /* EXTERNAL clause not supported (ignored) */
  682. if (expectWord("EXTERNAL")) {
  683. skipClauseSeparator();
  684. gotClause = true;
  685. }
  686. return gotClause;
  687. }
  688. /**
  689. * Process 'Global' clause from the parser input, and initialize a
  690. * description entry with its information. If a Global clause is not
  691. * available, the entry is unchanged.
  692. *
  693. * @param entry CocoDescriptionEntry to initialize with the clause information
  694. * @return true if a 'global' clause was consumed, false otherwise.
  695. * @throws CocoParseException if a parsing error occurs
  696. * @throws java.io.IOException if an I/O error occurs
  697. */
  698. private boolean parseGlobalClause(CocoDescriptionEntry entry)
  699. throws CocoParseException, IOException {
  700. boolean gotClause = false;
  701. /* GLOBAL clause not supported (ignored) */
  702. if (expectWord("GLOBAL")) {
  703. skipClauseSeparator();
  704. gotClause = true;
  705. }
  706. return gotClause;
  707. }
  708. /**
  709. * Process 'Justified' clause from the parser input, and initialize a
  710. * description entry with its information.
  711. *
  712. * @param entry CocoDescriptionEntry to initialize with the clause information
  713. * @return true if a 'justified' clause was consumed, false otherwise.
  714. * @throws CocoParseException if a parsing error occurs
  715. * @throws java.io.IOException if an I/O error occurs
  716. */
  717. private boolean parseJustifiedClause(CocoDescriptionEntry entry)
  718. throws CocoParseException, IOException {
  719. boolean gotClause = false;
  720. if (expectWord("JUSTIFIED") || expectWord("JUST")) {
  721. expectWord("RIGHT");
  722. entry.setJustified(true);
  723. skipClauseSeparator();
  724. gotClause = true;
  725. } else {
  726. entry.setJustified(false);
  727. }
  728. return gotClause;
  729. }
  730. /**
  731. * Process 'Occurs' clause from the parser input, and initialize a
  732. * description entry with its information.
  733. *
  734. * @param entry CocoDescriptionEntry to initialize with the clause information
  735. * @return true if a 'occurs' clause was consumed, false otherwise.
  736. * @throws CocoParseException if a parsing error occurs
  737. * @throws java.io.IOException if an I/O error occurs
  738. */
  739. private boolean parseOccursClause(CocoDescriptionEntry entry)
  740. throws CocoParseException, IOException {
  741. boolean gotClause = false;
  742. if (expectWord("OCCURS")) {
  743. /* OCCURS cannot occur for level 01, 66, 77, or 88 entries */
  744. int level = entry.getLevel();
  745. if (level == 1 || level == 66 || level == 77 || level == 88) {
  746. logAndThrow("CCCB4209", new Object[]{
  747. entry.getName()
  748. }, ErrorManager.Severity.ERROR, null, null);
  749. }
  750. CocoToken token = null;
  751. if (skipOptionalSpaces(true)) {
  752. token = this.getNextToken();
  753. }
  754. int count1 = 0;
  755. int count2 = 0;
  756. /* "OCCURS n"... */
  757. token = getNextTokenAreaB(false, true);
  758. if (token == null || token.isEOF()) {
  759. logAndThrow("CCCB4203",
  760. new Object[]{entry.getInfo()},
  761. ErrorManager.Severity.ERROR,
  762. null,
  763. null);
  764. }
  765. if (token.isEOL()) {
  766. // next token after EOL
  767. token = getNextTokenAreaB(false, true);
  768. if (token == null || token.isEOF()) {
  769. logAndThrow("CCCB4203",
  770. new Object[]{entry.getInfo()},
  771. ErrorManager.Severity.ERROR,
  772. null,
  773. null);
  774. }
  775. }
  776. if (token.getType() == CocoTokenTypes.NUM_TOKEN) {
  777. try {
  778. count1 = Integer.parseInt(token.getStringValue());
  779. count2 = count1;
  780. } catch (NumberFormatException nfe) {
  781. logAndThrow("CCCB4210",
  782. new Object[]{token.getStringValue()},
  783. ErrorManager.Severity.ERROR, nfe, token);
  784. }
  785. }
  786. /* "OCCURS n to m..." */
  787. if (expectWord("TO")) { // OCCURS count1 TO...
  788. if (skipOptionalSpaces(true)) {
  789. token = this.getNextToken();
  790. }
  791. token = getNextTokenAreaB(false, true);
  792. if (token == null || token.isEOF()) {
  793. logAndThrow("CCCB4203",
  794. new Object[]{entry.getInfo()},
  795. ErrorManager.Severity.ERROR,
  796. null,
  797. null);
  798. }
  799. if (token.isEOL()) {
  800. token = getNextTokenAreaB(false, true);
  801. if (token == null || token.isEOF()) {
  802. logAndThrow("CCCB4203", new Object[]{entry.getName()},
  803. ErrorManager.Severity.ERROR, null, token);
  804. }
  805. }
  806. if (token.getType() == CocoTokenTypes.NUM_TOKEN) {
  807. try {
  808. int count = Integer.parseInt(token.getStringValue());
  809. count2 = count;
  810. } catch (NumberFormatException nfe) {
  811. logAndThrow("CCCB4210",
  812. new Object[]{token.getStringValue()},
  813. ErrorManager.Severity.ERROR, nfe, token);
  814. }
  815. }
  816. if (count1 < 0 || count2 <= count1) {
  817. logAndThrow("CCCB4118", new Object[]{
  818. String.valueOf(count1),
  819. String.valueOf(count2)},
  820. ErrorManager.Severity.ERROR, null, token);
  821. }
  822. } else if (count1 < 1) {
  823. logAndThrow("CCCB4117", new Object[]{String.valueOf(count1)},
  824. ErrorManager.Severity.ERROR, null, token);
  825. }
  826. expectWord("TIMES");
  827. /* "OCCURS" ... DEPENDING ON */
  828. if (expectWord("DEPENDING")) {
  829. // When the "DEPENDS ON" phrase is encountered
  830. // completing a "Foo OCCURS x TIMES" statement,
  831. // changes the semantic from "Foo occurs x times"
  832. // to "Foo can occur up to x times". In other words,
  833. // minimum recurrence count is no longer equal to the
  834. // maximum recurrence count; it becomes 0.
  835. count1 = 0;
  836. expectWord("ON");
  837. if (skipOptionalSpaces(true)) {
  838. token = this.getNextToken();
  839. }
  840. token = getNextTokenAreaB(false, true);
  841. if (token == null || token.isEOF()) {
  842. logAndThrow("CCCB4203", new Object[]{entry.getName()},
  843. ErrorManager.Severity.ERROR, null, token);
  844. }
  845. if (token.isEOL()) {
  846. // next token after EOL
  847. token = getNextTokenAreaB(false, true);
  848. if (token == null || token.isEOF()) {
  849. logAndThrow("CCCB4203", new Object[]{entry.getName()},
  850. ErrorManager.Severity.ERROR, null, token);
  851. }
  852. }
  853. ungetToken(token);
  854. String entryName = parseCobolWord(mReservedWordCheck);
  855. if (entryName == null || entryName.trim().length() == 0) {
  856. String item1 = entry.getLevel() + " " + entry.getName();
  857. // expecting a data name after DEPENDING ON
  858. token = getNextTokenAreaB(false, true);
  859. logAndThrow("CCCB4224", new Object[]{
  860. "data name",
  861. "DEPENDING ON",
  862. item1},
  863. ErrorManager.Severity.ERROR, null, token);
  864. }
  865. // the data-name for DEPENDING ON can be qualified
  866. // e.g., F1 OF L1 OF L2 OF R2 etc
  867. List qualifiers = null;
  868. while (expectWord("OF")) {
  869. if (skipOptionalSpaces(true)) {
  870. token = this.getNextToken();
  871. }
  872. token = getNextTokenAreaB(false, true);
  873. if (token == null || token.isEOF()) {
  874. logAndThrow("CCCB4203", new Object[]{entry.getName()},
  875. ErrorManager.Severity.ERROR, null, token);
  876. }
  877. if (token.isEOL()) {
  878. // next token after EOL
  879. token = getNextTokenAreaB(false, true);
  880. if (token == null || token.isEOF()) {
  881. logAndThrow("CCCB4203",
  882. new Object[]{entry.getName()},
  883. ErrorManager.Severity.ERROR, null, token);
  884. }
  885. }
  886. ungetToken(token);
  887. String qualifierName = parseCobolWord(mReservedWordCheck);
  888. if (qualifierName == null || qualifierName.trim().length() == 0) {
  889. token = getNextTokenAreaB(false, true);
  890. logAndThrow("CCCB4224", new Object[]{
  891. "data name",
  892. "OF",
  893. entry.getInfo()},
  894. ErrorManager.Severity.ERROR, null, token);
  895. }
  896. if (qualifiers == null) {
  897. qualifiers = new ArrayList(1);
  898. }
  899. qualifiers.add(qualifierName);
  900. }
  901. entry.setOccursResolveLater(count1, count2, qualifiers, entryName);
  902. mModel.addOccurs(entry);
  903. } else if (count1 == count2) {
  904. entry.setOccurs(count1);
  905. } else {
  906. token = getNextTokenAreaB(false, true);
  907. logAndThrow("CCCB4215", new Object[]{entry.getName()},
  908. ErrorManager.Severity.ERROR, null, token);
  909. }
  910. /* ignore rest of OCCURS clause (ASCENDING KEY, INDEX BY phrases et al) */
  911. if (expectWord("ASCENDING") || expectWord("DESCENDING")) {
  912. expectWord("KEY");
  913. expectWord("IS");
  914. skipOptionalSpaces(true);
  915. token = getNextTokenAreaB(false, true);
  916. if (token == null || token.isEOF()) {
  917. logAndThrow("CCCB4203", new Object[]{entry.getName()},
  918. ErrorManager.Severity.ERROR, null, token);
  919. }
  920. if (token.isEOL()) {
  921. // next token after EOL
  922. token = getNextTokenAreaB(false, true);
  923. if (token == null || token.isEOF()) {
  924. logAndThrow("CCCB4203", new Object[]{entry.getName()},
  925. ErrorManager.Severity.ERROR, null, token);
  926. }
  927. }
  928. ungetToken(token);
  929. String wd = parseCobolWord(mReservedWordCheck);
  930. if (wd == null || wd.trim().length() == 0) {
  931. token = getNextTokenAreaB(false, true);
  932. logAndThrow("CCCB4224", new Object[]{
  933. "data name",
  934. "ASCENDING or DESCENDINNG [KEY] [IS]",
  935. entry.getInfo()},
  936. ErrorManager.Severity.ERROR, null, token);
  937. }
  938. }
  939. if (expectWord("INDEXED")) {
  940. expectWord("BY");
  941. skipOptionalSpaces(true);
  942. token = getNextTokenAreaB(false, true);
  943. if (token == null || token.isEOF()) {
  944. logAndThrow("CCCB4203", new Object[]{entry.getName()},
  945. ErrorManager.Severity.ERROR, null, token);
  946. }
  947. if (token.isEOL()) {
  948. // get next token after EOL
  949. token = getNextTokenAreaB(false, true);
  950. if (token == null || token.isEOF()) {
  951. logAndThrow("CCCB4203", new Object[]{entry.getName()},
  952. ErrorManager.Severity.ERROR, null, token);
  953. }
  954. }
  955. ungetToken(token);
  956. while (true) {
  957. try {
  958. // try to parse 1 or more indexed variables
  959. // Open-ESB issue 2296
  960. String wd = parseCobolWord(mReservedWordCheck);
  961. if (wd == null || wd.trim().length() == 0) {
  962. token = getNextTokenAreaB(false, true);
  963. logAndThrow("CCCB4224", new Object[]{
  964. "data name",
  965. "INDEXED [BY]",
  966. entry.getInfo()},
  967. ErrorManager.Severity.ERROR, null, token);
  968. }
  969. } catch (CocoParseException e) {
  970. break;
  971. }
  972. }
  973. skipUntilNextClause();
  974. } else {
  975. skipClauseSeparator();
  976. }
  977. gotClause = true;
  978. }
  979. return gotClause;
  980. }
  981. /**
  982. * Consume tokens until a word is encountered that is the start of a
  983. * recognized clause. USE THIS METHOD ONLY WHEN CURRENT TOKEN POSITION
  984. * IS IN AREA B, OTHERWISE THE BEHAVIOUR IS UNDEFINED.
  985. *
  986. * @throws CocoParseException if EOD encountered
  987. * @throws IOException if any I/O error occurs
  988. */
  989. private void skipUntilNextClause() throws CocoParseException, IOException {
  990. final List tokenList = new ArrayList();
  991. final StringBuffer wordBuffer = new StringBuffer();
  992. String word;
  993. ListIterator it;
  994. CocoToken tok;
  995. try {
  996. // loop for skipping words
  997. while(true) {
  998. tokenList.clear();
  999. skipOptionalSpaces(true);
  1000. // loop for skipping tokens
  1001. while(true) {
  1002. tok = getNextTokenAreaB(false, true);
  1003. if (null == tok) {
  1004. break;
  1005. }
  1006. if (tok.getType() == CocoTokenTypes.SEPARATOR_TOKEN) {
  1007. ungetToken(tok);
  1008. break;
  1009. }
  1010. wordBuffer.append(tok.getStringValue());
  1011. tokenList.add(0, tok);
  1012. }
  1013. // no word formed
  1014. if (wordBuffer.length() == 0) {
  1015. break;
  1016. // if word is the start of a clause, then stuff the
  1017. // tokens that formed it, back into the token stream; I'm done
  1018. } else {
  1019. word = wordBuffer.toString();
  1020. wordBuffer.delete(0, word.length());
  1021. if (CocoLanguage.isClauseWord(word)) {
  1022. it = tokenList.listIterator();
  1023. while (it.hasNext()) {
  1024. ungetToken((CocoToken) it.next());
  1025. }
  1026. break;
  1027. }
  1028. }
  1029. }
  1030. } finally {
  1031. tokenList.clear();
  1032. wordBuffer.delete(0, wordBuffer.length());
  1033. }
  1034. }
  1035. /**
  1036. * Process 'Picture'/'Pic' clause from the parser input, and initialize a
  1037. * description entry with its information.
  1038. *
  1039. * @param entry CocoDescriptionEntry to initialize with the clause information
  1040. * @return true if a 'picture' clause was consumed, false otherwise.
  1041. * @throws CocoParseException if a parsing error occurs
  1042. * @throws java.io.IOException if an I/O error occurs
  1043. */
  1044. private boolean parsePictureClause(CocoDescriptionEntry entry)
  1045. throws CocoParseException, IOException {
  1046. boolean gotClause = false;
  1047. if (expectWord("PIC") || expectWord("PICTURE")) {
  1048. expectWord("IS");
  1049. skipOptionalSpaces(true);
  1050. // make sure EOL is skipped
  1051. CocoToken token = getNextTokenAreaB(false, true);
  1052. if (token == null || token.isEOF()) {
  1053. logAndThrow("CCCB4203", new Object[]{entry.getName()},
  1054. ErrorManager.Severity.ERROR, null, token);
  1055. }
  1056. if (token.isEOL()) {
  1057. // go to next line and scan for a word as redefined target
  1058. token = this.getNextTokenAreaB(false, true);
  1059. if (token == null || token.isEOF()) {
  1060. // error
  1061. if (token == null || token.isEOF()) {
  1062. logAndThrow("CCCB4203", new Object[]{entry.getName()},
  1063. ErrorManager.Severity.ERROR, null, token);
  1064. }
  1065. }
  1066. }
  1067. ungetToken(token);
  1068. parsePictureLiteral(entry);
  1069. skipClauseSeparator();
  1070. gotClause = true;
  1071. }
  1072. return gotClause;
  1073. }
  1074. /**
  1075. * Process a Picture clause's character string from the parser input, and
  1076. * initialize a description entry with its information.
  1077. *
  1078. * @param entry CocoDescriptionEntry to initialize with the clause information
  1079. * @throws CocoParseException if a parsing error occurs
  1080. * @throws java.io.IOException if an I/O error occurs
  1081. */
  1082. private void parsePictureLiteral(CocoDescriptionEntry entry)
  1083. throws CocoParseException, IOException {
  1084. StringBuffer buffer = new StringBuffer();
  1085. boolean foundPart = false;
  1086. skipOptionalSpaces(true);
  1087. do {
  1088. CocoToken token = getNextTokenAreaB(true, true);
  1089. if (token == null || token.isEOF()) {
  1090. break;
  1091. }
  1092. String value = token.getStringValue();
  1093. CocoTokenTypes type = token.getType();
  1094. foundPart =
  1095. (type == CocoTokenTypes.ALNUM_TOKEN
  1096. || type == CocoTokenTypes.NUM_TOKEN
  1097. || value.equals(CocoLanguage.SLANT)
  1098. || value.equals(CocoLanguage.COMMA)
  1099. || value.equals(CocoLanguage.PERIOD)
  1100. || value.equals(CocoLanguage.PLUS)
  1101. || value.equals(CocoLanguage.HYPHEN)
  1102. || value.equals(CocoLanguage.ASTERISK)
  1103. || value.equals(CocoLanguage.LPARENS)
  1104. || value.equals(CocoLanguage.RPARENS)
  1105. || CocoLanguage.isCurrencySymbol(value));
  1106. /*
  1107. * If I find a period or comma, in order to be part of the literal,
  1108. * it must be followed immediately one of the following:
  1109. * - a separator period
  1110. * - a separator comma (not just a comma)
  1111. * - a separator semicolon (not just a semicolon)
  1112. */
  1113. if (value.equals(CocoLanguage.PERIOD) || value.equals(CocoLanguage.COMMA)) {
  1114. CocoToken nextToken = getNextTokenAreaB(true, true);
  1115. if (nextToken == null) {
  1116. foundPart = false;
  1117. } else {
  1118. String nextValue = nextToken.getStringValue();
  1119. if (nextValue.equals(CocoLanguage.SPACE)
  1120. || nextValue.charAt(0) == '\r'
  1121. || nextValue.equals("EOF")) {
  1122. // added check on "EOF" here, see open-esb issue 2273
  1123. foundPart = false;
  1124. ungetToken(nextToken);
  1125. } else if (nextValue.equals(CocoLanguage.COMMA)
  1126. || nextValue.equals(CocoLanguage.SEMICOLON)
  1127. || nextValue.equals(CocoLanguage.PERIOD)) {
  1128. CocoToken anotherToken = getNextTokenAreaB(true, true);
  1129. ungetToken(nextToken);
  1130. if (anotherToken != null) {
  1131. String anotherValue = anotherToken.getStringValue();
  1132. ungetToken(anotherToken);
  1133. foundPart = anotherValue.equals(CocoLanguage.SPACE);
  1134. }
  1135. } else {
  1136. ungetToken(nextToken);
  1137. }
  1138. }
  1139. }
  1140. if (foundPart) {
  1141. buffer.append(value);
  1142. } else {
  1143. ungetToken(token);
  1144. }
  1145. } while (foundPart);
  1146. String picstr = "";
  1147. try {
  1148. picstr = buffer.toString();
  1149. CocoPicture picture = new CocoPicture(picstr);
  1150. entry.setPicture(picture);
  1151. } catch (IllegalArgumentException iae) {
  1152. logAndThrow("CCCB4218", new Object[]{
  1153. entry.getName(),
  1154. picstr,
  1155. iae.getLocalizedMessage()},
  1156. ErrorManager.Severity.ERROR, iae, null);
  1157. }
  1158. }
  1159. /**
  1160. * Process 'Sign' clause from the parser input, and initialize a description
  1161. * entry with its information.
  1162. *
  1163. * @param entry CocoDescriptionEntry to initialize with the clause information
  1164. * @return true if a 'sign' clause was consumed, false otherwise.
  1165. * @throws CocoParseException if a parsing error occurs
  1166. * @throws java.io.IOException if an I/O error occurs
  1167. */
  1168. private boolean parseSignClause(CocoDescriptionEntry entry)
  1169. throws CocoParseException, IOException {
  1170. boolean gotClause = true;
  1171. if (expectWord("SIGN")) {
  1172. expectWord("IS");
  1173. if (expectWord("LEADING")) {
  1174. entry.setSign(CocoSign.LeadingSign);
  1175. } else if (expectWord("TRAILING")) {
  1176. entry.setSign(CocoSign.TrailingSign);
  1177. } else {
  1178. logAndThrow("CCCB4219", new Object[]{entry.getName()},
  1179. ErrorManager.Severity.ERROR, null, null);
  1180. }
  1181. if (expectWord("SEPARATE")) {
  1182. expectWord("CHARACTER");
  1183. entry.setSeparateSign(true);
  1184. }
  1185. skipClauseSeparator();
  1186. } else if (expectWord("LEADING")) {
  1187. entry.setSign(CocoSign.LeadingSign);
  1188. if (expectWord("SEPARATE")) {
  1189. expectWord("CHARACTER");
  1190. entry.setSeparateSign