PageRenderTime 31ms CodeModel.GetById 12ms RepoModel.GetById 0ms app.codeStats 0ms

/code/Parser.java

http://silkin.googlecode.com/
Java | 1484 lines | 1190 code | 71 blank | 223 comment | 336 complexity | a14be171636dfe0a638ad31664634ce2 MD5 | raw file
  1. import java.io.*;
  2. import java.util.*;
  3. /** This Parser is an adaptation of the Mock-a-Java parser built for Nobo
  4. Komogata's Compiler class (CIS 341) in Spring 2000 at Penn. It is NOT an elegant
  5. or professional-quality parser -- just a utility to allow Domain Theories written in
  6. Horn Clauses to be read into Kinship programs and converted to the proper Java objects
  7. for reasoning there. The Context-Free Grammar defining a Domain Theory is documented
  8. in {@link DomainTheoryGrammar}.
  9. //
  10. When constructed with a {@link Tokenizer}, a Parser will construct a Kinship domain theory
  11. from the tokens found in the <code>Tokenizer's</code> input file.
  12. @author Gary Morris, Northern Virginia Community College garymorris2245@verizon.net
  13. */
  14. public class Parser {
  15. public static String errorFound = "";
  16. public static ArrayList<Object> cachedStdMacros;
  17. TokenScanned current;
  18. Linus lineMan, macroLineMan;
  19. Tokenizer scanner, macroScanner;
  20. String filePath;
  21. DomainTheory dTheory;
  22. /** Construct a Parser from a DomainTheory file.
  23. @param tok a <code>Tokenizer</code> which parses tokens from an input file on demand.
  24. */
  25. public Parser(Tokenizer tok) {
  26. scanner = tok;
  27. lineMan = scanner.lineServer;
  28. this.filePath = tok.filePath;
  29. }
  30. /** Construct a Parserfrom a DomainTheory file and a Standard_Macros file.
  31. @param dtTokens a <code>Tokenizer</code> which parses tokens from a DomainTheory file on demand.
  32. @param macroTokens a <code>Tokenizer</code> which parses tokens from a Macro file on demand.
  33. */
  34. public Parser(Tokenizer dtTokens, Tokenizer macroTokens) {
  35. scanner = dtTokens;
  36. lineMan = scanner.lineServer;
  37. this.filePath = dtTokens.filePath;
  38. macroScanner = macroTokens;
  39. macroLineMan = macroScanner.lineServer;
  40. }
  41. /** Return the category of the predicate <code>symbol</code>.
  42. @param symbol a String which has been identified as a predicate symbol in a Horn Clause.
  43. @return either {@link PrimitiveCategory} (a built-in predicate the Kinship system understands)
  44. or {@link CulturalCategory} (a kinship term in the language of the target culture).
  45. */
  46. public static PredCategory determinePrimitive(String symbol, DomainTheory dt) {
  47. // Identify the 19 Primitive Predicates as special
  48. // Also consider userDefinedProperties and Math predicates as primitive predicates
  49. if ((symbol.equals("father")) || (symbol.equals("mother")) || (symbol.equals("son"))
  50. || (symbol.equals("daughter")) || (symbol.equals("husband")) || (symbol.equals("wife"))
  51. || (symbol.equals("male")) || (symbol.equals("female")) || (symbol.equals("elder"))
  52. || (symbol.equals("younger")) || (symbol.equals("dead")) || (symbol.equals("divorced"))
  53. || (symbol.equals("not")) || (symbol.equals("equal")) || (symbol.equals("parent"))
  54. || (symbol.equals("child")) || (symbol.equals("spouse"))
  55. || (symbol.equals("allowCreation")) || (symbol.equals("gender"))
  56. || (dt != null && dt.userDefinedProperties != null
  57. && dt.userDefinedProperties.containsKey(symbol))) {
  58. return new PrimitiveCategory();
  59. } // Treat the Math predicates as a special kind of Primitive
  60. else if ((symbol.equals("lessThan")) || (symbol.equals("greaterThan"))
  61. || (symbol.equals("lessOrEql")) || (symbol.equals("greaterOrEql"))
  62. || (symbol.equals("contains"))) {
  63. return new MathCategory();
  64. } else {
  65. return new CulturalCategory();
  66. }
  67. } // end of method determinePrimitive
  68. /** Assemble information about a parsing error encountered, then throw a {@link KSParsingErrorException}.
  69. @param msgOut a String describing the exact error found.
  70. @throws a <code>KSParsingErrorException</code>.
  71. */
  72. public void error(String msgOut) throws KSParsingErrorException {
  73. msgOut += "\nCurrent = " + current.token + ": " + current.lexeme;
  74. msgOut += "\nOn Line # " + current.lineNum + " Character Position: " + current.charPos
  75. + " of " + filePath;
  76. if (Parser.errorFound.length() < 10) {
  77. msgOut += "\n" + lineMan.lineImage;
  78. }
  79. throw new KSParsingErrorException(msgOut);
  80. } // end of error method
  81. /** Begin the parse of a Domain Theory.
  82. //
  83. DomainTheory -> LanguageName, HeaderOpts, StandardMacros, Theory.
  84. @throws <code>KSParsingErrorException</code>
  85. */
  86. public DomainTheory parseDomainTheory() throws KSParsingErrorException, KSConstraintInconsistency {
  87. String languageName = parseLanguageName();
  88. try {
  89. dTheory = new DomainTheory(languageName);
  90. } catch (ExceptionInInitializerError e) {
  91. System.out.println("Cause is " + e.getCause());
  92. }
  93. dTheory.filePath = filePath;
  94. parseHeaderOpts();
  95. if (dTheory.addressTerms) {
  96. int start = languageName.length() - 5;
  97. if (!languageName.substring(start).equals("(Adr)")) {
  98. throw new KSParsingErrorException("Language Name '" + languageName
  99. + "' violates convention for Terms of Address.\n"
  100. + "Should be <langName>(Adr)");
  101. }
  102. } // end of validity check on languageName
  103. parseStandardMacros();
  104. if (current.token.equals("$")) {
  105. return dTheory; // There were no definitions
  106. }
  107. parseTheory();
  108. dTheory.validateSynonymsAndUmbrellas();
  109. return dTheory;
  110. } // end of method parseDomainTheory
  111. /* LanguageName -> leftParen, "languageName", comma, string, rightParen.
  112. First: [leftParen] Follow: [leftParen, symbol]
  113. */
  114. private String parseLanguageName() throws KSParsingErrorException {
  115. String name;
  116. current = scanner.lookAhead();
  117. if (current.token.equals("leftParen")) {
  118. scanner.readToken(); // consume the leftParen
  119. current = scanner.readToken(); // read next, which must be the string "languageName"
  120. if (!current.lexeme.equals("languageName")) {
  121. error("parseLanguageName seeking the string 'languageName'. ");
  122. }
  123. current = scanner.readToken(); // read next, which must be a comma
  124. if (!current.token.equals("comma")) {
  125. error("parseLanguageName seeking a comma. ");
  126. }
  127. current = scanner.readToken(); // read next, which must be a string
  128. if (!current.token.equals("string")) {
  129. error("parseLanguageName seeking a string. ");
  130. }
  131. name = current.lexeme;
  132. int where = name.indexOf("(Adr)"); // where = end of langName without '(Adr)'
  133. if (where == -1) {
  134. where = name.length();
  135. }
  136. if (name.substring(0, where).indexOf("(") > 0 || name.substring(0, where).indexOf(")") > 0) {
  137. error("The language name '" + name + "' contains a parenthesis -- Prohibited Character.\n"
  138. + "Replace with angle-bracket or square-bracket.");
  139. }
  140. current = scanner.readToken(); // read next, which must be a rightParen.
  141. if (!current.token.equals("rightParen")) {
  142. error("parseLanguageName seeking a rightParen. ");
  143. }
  144. return name;
  145. } // end of if = leftParen
  146. else {
  147. error("First non-comment line of file MUST contain '(languageName, name)'.");
  148. }
  149. return "ERROR";
  150. } // end of method parseLanguageName()
  151. /* HeaderOpts -> leftParen, HdrOpts2, HeaderOpts.
  152. | \empty.
  153. First: [leftParen] Follow: [symbol]
  154. */
  155. private void parseHeaderOpts() throws KSParsingErrorException {
  156. current = scanner.lookAhead();
  157. if (current.token.equals("leftParen")) {
  158. scanner.readToken(); // consume the leftParen
  159. parseHdrOpts2();
  160. parseHeaderOpts();
  161. return;
  162. } // end of if = leftParen
  163. if (current.token.equals("symbol")) {
  164. return;
  165. }
  166. if (current.token.equals("$")) {
  167. return;
  168. }
  169. error("parseHeaderOpts seeking leftParen or symbol.");
  170. return;
  171. } // end of method parseHeaderOpts
  172. /*
  173. HdrOpts2 -> "author", comma, string, rightParen.
  174. | "date", comma, string, rightParen.
  175. | "partial", comma, Boolean, rightParen.
  176. | "address", comma, Boolean, rightParen.
  177. | "polygamyOK", comma, Boolean, rightParen.
  178. | "citation", comma, string, rightParen.
  179. | "non_term", comma, FlagOrKinTerm, OtherFlagOrKinTerm, rightParen.
  180. | "recursiveLevels", comma, integer, rightParen.
  181. | "userDefinedProperties", UDProps, rightParen.
  182. | "synonyms", comma, TermPairs, rightParen.
  183. | "umbrellas", comma, TermListPairs, rightParen.
  184. | "overlaps", comma, TermListPairs, rightParen.
  185. First: ["author", "date", "partial", "polygamyOK", "citation", "non_term",
  186. "recursiveLevels", "userDefinedProperties", "umbrellas", "synonyms", "overlaps"]
  187. Follow: [leftParen, symbol]
  188. */
  189. private void parseHdrOpts2() throws KSParsingErrorException {
  190. current = scanner.lookAhead();
  191. if (current.lexeme.equals("author")) {
  192. scanner.readToken(); // consume the string 'author'
  193. current = scanner.readToken(); // read next, which must be a comma
  194. if (!current.token.equals("comma")) {
  195. error("parseHdrOpts2 seeking a comma.");
  196. }
  197. current = scanner.readToken(); // read next, which must be a string
  198. if (!current.token.equals("string")) {
  199. error("parseHdrOpts2 seeking a string.");
  200. } else {
  201. dTheory.author = current.lexeme;
  202. }
  203. current = scanner.readToken(); // read next, which must be a rightParen
  204. if (!current.token.equals("rightParen")) {
  205. error("parseHdrOpts2 seeking a rightParen.");
  206. }
  207. return;
  208. } // end of if = author
  209. if (current.lexeme.equals("date")) {
  210. scanner.readToken(); // consume the string 'date'
  211. current = scanner.readToken(); // read next, which must be a comma
  212. if (!current.token.equals("comma")) {
  213. error("parseHdrOpts2 seeking a comma.");
  214. }
  215. current = scanner.readToken(); // read next, which must be a string
  216. if (!current.token.equals("string")) {
  217. error("parseHdrOpts2 seeking a string.");
  218. } else {
  219. Date cDate = null;
  220. try {
  221. cDate = UDate.parse(current.lexeme);
  222. }catch(KSDateParseException dpe) {
  223. error("While parsing createion date: " + dpe);
  224. }
  225. dTheory.createDate = UDate.formatAsXSD(cDate);
  226. }
  227. current = scanner.readToken(); // read next, which must be a rightParen
  228. if (!current.token.equals("rightParen")) {
  229. error("parseHdrOpts2 seeking a rightParen.");
  230. }
  231. return;
  232. } // end of if = date
  233. if (current.lexeme.equals("partial")) {
  234. scanner.readToken(); // consume the string 'partial'
  235. current = scanner.readToken(); // read next, which must be a comma
  236. if (!current.token.equals("comma")) {
  237. error("parseHdrOpts2 seeking a comma.");
  238. }
  239. dTheory.partial = parseBoolean();
  240. current = scanner.readToken(); // read next, which must be a rightParen
  241. if (!current.token.equals("rightParen")) {
  242. error("parseHdrOpts2 seeking a rightParen.");
  243. }
  244. return;
  245. } // end of if = partial
  246. if (current.lexeme.equals("address")) {
  247. scanner.readToken(); // consume the string 'address'
  248. current = scanner.readToken(); // read next, which must be a comma
  249. if (!current.token.equals("comma")) {
  250. error("parseHdrOpts2 seeking a comma.");
  251. }
  252. dTheory.addressTerms = parseBoolean();
  253. current = scanner.readToken(); // read next, which must be a rightParen
  254. if (!current.token.equals("rightParen")) {
  255. error("parseHdrOpts2 seeking a rightParen.");
  256. }
  257. return;
  258. } // end of if = partial
  259. if (current.lexeme.equals("polygamyOK")) {
  260. scanner.readToken(); // consume the string 'polygamyOK'
  261. current = scanner.readToken(); // read next, which must be a comma
  262. if (!current.token.equals("comma")) {
  263. error("parseHdrOpts2 seeking a comma.");
  264. }
  265. dTheory.polygamyOK = parseBoolean();
  266. current = scanner.readToken(); // read next, which must be a rightParen
  267. if (!current.token.equals("rightParen")) {
  268. error("parseHdrOpts2 seeking a rightParen.");
  269. }
  270. return;
  271. } // end of if = polygamyOK
  272. if (current.lexeme.equals("citation")) {
  273. scanner.readToken(); // consume the string 'citation'
  274. current = scanner.readToken(); // read next, which must be a comma
  275. if (!current.token.equals("comma")) {
  276. error("parseHdrOpts2 seeking a comma.");
  277. }
  278. current = scanner.readToken(); // read next, which must be a string
  279. if (!current.token.equals("string")) {
  280. error("parseHdrOpts2 seeking a string.");
  281. } else {
  282. dTheory.citation = current.lexeme;
  283. }
  284. current = scanner.readToken(); // read next, which must be a rightParen
  285. if (!current.token.equals("rightParen")) {
  286. error("parseHdrOpts2 seeking a rightParen.");
  287. }
  288. return;
  289. } // end of if = citation
  290. if (current.lexeme.equals("non_term")) {
  291. scanner.readToken(); // consume the string 'non_term'
  292. current = scanner.readToken(); // read next, which must be a comma
  293. if (!current.token.equals("comma")) {
  294. error("parseHdrOpts2 seeking a comma.");
  295. }
  296. parseFlagOrKinTerm();
  297. parseOtherFlagOrKinTerm();
  298. current = scanner.readToken(); // read next, which must be a rightParen
  299. if (!current.token.equals("rightParen")) {
  300. error("parseHdrOpts2 seeking a rightParen.");
  301. }
  302. return;
  303. } // end of if = non_term
  304. if (current.lexeme.equals("recursiveLevels")) {
  305. scanner.readToken(); // consume the string 'recursiveLevels'
  306. current = scanner.readToken(); // read next, which must be a comma
  307. if (!current.token.equals("comma")) {
  308. error("parseHdrOpts2 seeking a comma.");
  309. }
  310. current = scanner.readToken(); // read next, which must be an integer
  311. if (!current.token.equals("integer")) {
  312. error("parseHdrOpts2 seeking an integer.");
  313. }
  314. dTheory.levelsOfRecursion = current.intVal;
  315. current = scanner.readToken(); // read next, which must be a rightParen
  316. if (!current.token.equals("rightParen")) {
  317. error("parseHdrOpts2 seeking a rightParen.");
  318. }
  319. return;
  320. } // end of if = recursiveLevels
  321. if (current.lexeme.equals("userDefinedProperties")) {
  322. scanner.readToken(); // consume the string 'userDefinedProperties'
  323. dTheory.userDefinedProperties = new TreeMap();
  324. parseUDProps();
  325. current = scanner.readToken(); // read next, which must be a rightParen
  326. if (!current.token.equals("rightParen")) {
  327. error("parseHdrOpts2 seeking a rightParen.");
  328. }
  329. return;
  330. } // end of if = userDefinedProperties
  331. if (current.lexeme.equals("synonyms")) {
  332. scanner.readToken(); // consume the string 'synonyms'
  333. if (dTheory.synonyms != null) {
  334. error("Duplicate synonym declarations.");
  335. }
  336. dTheory.synonyms = new TreeMap();
  337. current = scanner.readToken(); // read next, which must be a comma
  338. if (!current.token.equals("comma")) {
  339. error("parseHdrOpts2 seeking a comma.");
  340. }
  341. parseTermPairs(dTheory.synonyms, false);
  342. current = scanner.readToken(); // read next, which must be a rightParen
  343. if (!current.token.equals("rightParen")) {
  344. error("parseHdrOpts2 seeking a rightParen.");
  345. }
  346. return;
  347. } // end of if = synonyms
  348. if (current.lexeme.equals("umbrellas")) {
  349. scanner.readToken(); // consume the string 'umbrellas'
  350. if (dTheory.umbrellas != null) {
  351. error("Duplicate umbrella declarations.");
  352. }
  353. dTheory.umbrellas = new TreeMap();
  354. current = scanner.readToken(); // read next, which must be a comma
  355. if (!current.token.equals("comma")) {
  356. error("parseHdrOpts2 seeking a comma.");
  357. }
  358. parseTermListPairs(dTheory.umbrellas, false);
  359. current = scanner.readToken(); // read next, which must be a rightParen
  360. if (!current.token.equals("rightParen")) {
  361. error("parseHdrOpts2 seeking a rightParen.");
  362. }
  363. return;
  364. } // end of if = userDefinedProperties
  365. if (current.lexeme.equals("overlaps")) {
  366. scanner.readToken(); // consume the string 'overlaps'
  367. if (dTheory.overlaps != null) {
  368. error("Duplicate overlapping term declarations.");
  369. }
  370. dTheory.overlaps = new TreeMap();
  371. current = scanner.readToken(); // read next, which must be a comma
  372. if (!current.token.equals("comma")) {
  373. error("parseHdrOpts2 seeking a comma.");
  374. }
  375. parseTermListPairs(dTheory.overlaps, true);
  376. current = scanner.readToken(); // read next, which must be a rightParen
  377. if (!current.token.equals("rightParen")) {
  378. error("parseHdrOpts2 seeking a rightParen.");
  379. }
  380. return;
  381. } // end of if = synonyms
  382. error("parseHdrOpts2 seeking 'author' 'date' 'polygamyOK' 'citation' 'non_term' 'recursiveLevels' "
  383. + "'userDefinedProperties' 'synonyms' 'umbrellas' 'overlaps' or 'partial'.");
  384. } // end of method parseHdrOpts
  385. /* Boolean -> "true".
  386. | "false".
  387. First: ["true", "false"] Follow: [comma, rightParen]
  388. */
  389. private boolean parseBoolean() throws KSParsingErrorException {
  390. current = scanner.readToken(); // consume next, which must be a symbol = "true" or "false"
  391. if (!current.token.equals("symbol")) {
  392. error("parseBoolean seeking symbol ('true' or 'false').");
  393. }
  394. if (current.lexeme.equals("true")) {
  395. return true;
  396. }
  397. if (current.lexeme.equals("false")) {
  398. return false;
  399. }
  400. error("parseBoolean seeking symbol ('true' or 'false').");
  401. return false;
  402. } // end of method parseBoolean
  403. /*U_D_Props -> comma, leftParen, starName, comma, "type", comma, Type, comma, "single_value", comma, Boolean, UDP_Opts, rightParen, U_D_Props.
  404. | \empty.
  405. First: [comma] Follow: [rightParen]
  406. */
  407. private void parseUDProps() throws KSParsingErrorException {
  408. current = scanner.lookAhead();
  409. if (current.token.equals("comma")) {
  410. scanner.readToken(); // consume the comma
  411. current = scanner.readToken(); // read next, which must be a leftParen
  412. if (!current.token.equals("leftParen")) {
  413. error("parseUDProps seeking a leftParen.");
  414. }
  415. current = scanner.readToken(); // read next, which must be a starName
  416. if (!current.token.equals("starName")) {
  417. error("parseUDProps seeking a starName.");
  418. }
  419. String starNam = current.lexeme; // this will be the particular *-name user has chosen
  420. current = scanner.readToken(); // read next, which must be a comma
  421. if (!current.token.equals("comma")) {
  422. error("parseUDProps seeking a comma.");
  423. }
  424. UserDefinedProperty newProp = new UserDefinedProperty(starNam);
  425. dTheory.userDefinedProperties.put(starNam, newProp);
  426. current = scanner.readToken(); // read next, which must be the word "type"
  427. if ((!current.token.equals("symbol")) || (current.lexeme == null) || (!current.lexeme.equals("type"))) {
  428. error("parseUDProps seeking keyword 'type'.");
  429. }
  430. current = scanner.readToken(); // read next, which must be a comma
  431. if (!current.token.equals("comma")) {
  432. error("parseUDProps seeking a comma.");
  433. }
  434. parseType(newProp);
  435. current = scanner.readToken(); // read next, which must be a comma
  436. if (!current.token.equals("comma")) {
  437. error("parseUDProps seeking a comma.");
  438. }
  439. current = scanner.readToken(); // read next, which must be the word "single_value"
  440. if ((!current.token.equals("symbol")) || (current.lexeme == null) || (!current.lexeme.equals("single_value"))) {
  441. error("parseUDProps seeking keyword 'single_value'.");
  442. }
  443. current = scanner.readToken(); // read next, which must be a comma
  444. if (!current.token.equals("comma")) {
  445. error("parseUDProps seeking a comma.");
  446. }
  447. newProp.singleValue = parseBoolean();
  448. parseUDP_Opts(newProp);
  449. current = scanner.readToken(); // read next, which must be a rightParen
  450. if (!current.token.equals("rightParen")) {
  451. error("parseUDProps seeking a rightParen.");
  452. }
  453. // VALIDITY CHECKS
  454. if ((!newProp.singleValue) && (newProp.typ.equals("boolean"))) {
  455. error("UserDefinedProperty '" + starNam + "' is boolean with multiple values. Not allowed.");
  456. }
  457. if ((newProp.minVal != null) && (newProp.maxVal != null)
  458. && (newProp.maxVal.intValue() < newProp.minVal.intValue())) {
  459. error("UserDefinedProperty '" + starNam + "' has max value less than its min value. Does not compute!");
  460. }
  461. if ((newProp.defaultValue != null) && (newProp.minVal != null)
  462. && (((Number) newProp.minVal).intValue() > ((Number) newProp.defaultValue).intValue())) {
  463. error("UserDefinedProperty '" + starNam + "' has default value less than its min value. Does not compute!");
  464. }
  465. if ((newProp.defaultValue != null) && (newProp.maxVal != null)
  466. && (((Number) newProp.maxVal).intValue() < ((Number) newProp.defaultValue).intValue())) {
  467. error("UserDefinedProperty '" + starNam + "' has default value greater than its max value. Does not compute!");
  468. }
  469. if ((newProp.validEntries != null) && (newProp.validEntries.size() > 0) && (newProp.maxVal != null)) {
  470. for (int i = 0; i < newProp.validEntries.size(); i++) {
  471. if (((Number) newProp.maxVal).intValue() < ((Number) newProp.validEntries.get(i)).intValue()) {
  472. error("UserDefinedProperty '" + starNam + "' has a 'permissible value' greater than its max value. Does not compute!");
  473. }
  474. }
  475. }
  476. if ((newProp.validEntries != null) && (newProp.validEntries.size() > 0) && (newProp.minVal != null)) {
  477. for (int i = 0; i < newProp.validEntries.size(); i++) {
  478. if (((Number) newProp.minVal).intValue() > ((Number) newProp.validEntries.get(i)).intValue()) {
  479. error("UserDefinedProperty '" + starNam + "' has a 'permissible value' less than its minimum value. Does not compute!");
  480. }
  481. }
  482. }
  483. parseUDProps();
  484. return;
  485. } // end of if = comma
  486. if (current.token.equals("rightParen")) {
  487. return; // we hit the end
  488. }
  489. error("parseUDProps seeking comma or rightParen.");
  490. return;
  491. } // end of method parseUDProps
  492. /* Type -> "integer".
  493. | "float".
  494. | "string".
  495. | "boolean".
  496. | "individual".
  497. | "Individual".
  498. | "person".
  499. | "Person".
  500. First: [<all-the-above>] Follow: [comma]
  501. */
  502. private void parseType(UserDefinedProperty prop) throws KSParsingErrorException {
  503. current = scanner.readToken(); // consume next, which must be a valid type
  504. if ((!(current.token.equals("symbol") || current.token.equals("var"))) || (current.lexeme == null)) {
  505. error("parseType seeking a valid data type.");
  506. }
  507. if ((current.lexeme.equalsIgnoreCase("integer"))) {
  508. prop.typ = "integer";
  509. } else if (current.lexeme.equals("float")) {
  510. prop.typ = "float";
  511. } else if (current.lexeme.equals("string")) {
  512. prop.typ = "string";
  513. } else if (current.lexeme.equals("boolean")) {
  514. prop.typ = "boolean";
  515. } else if ((current.lexeme.equalsIgnoreCase("individual")) || (current.lexeme.equalsIgnoreCase("person"))) {
  516. prop.typ = "individual";
  517. } else {
  518. error("parseType seeking a valid data type.");
  519. }
  520. return;
  521. } // end of method parseType
  522. /* UDP_Opts -> comma, RestrictOrDefault, UDP_Opts.
  523. | \empty.
  524. First: [comma] Follow: [rightParen]
  525. */
  526. private void parseUDP_Opts(UserDefinedProperty prop) throws KSParsingErrorException {
  527. current = scanner.lookAhead();
  528. if (current.token.equals("comma")) { // non-empty
  529. scanner.readToken(); // consume the comma
  530. parseRestrictOrDefault(prop);
  531. parseUDP_Opts(prop);
  532. } else if (current.token.equals("rightParen")) {
  533. return; // empty
  534. } else {
  535. error("parseUDP_Opts seeking a comma or rightParen.");
  536. }
  537. } // end of method parseUDP_Opts
  538. /* RestrictOrDefault -> "restricted_to", comma, leftParen, Ints_Floats_Strings, rightParen.
  539. | "default", comma, Int_Float_String.
  540. | "max", comma, Int_Float.
  541. | "min", comma, Int_Float.
  542. First: ["restricted_to", "default", "max", "min"] Follow: [comma, rightParen]
  543. */
  544. private void parseRestrictOrDefault(UserDefinedProperty udp) throws KSParsingErrorException {
  545. current = scanner.readToken(); // read next, which must be a keyword
  546. if ((!current.token.equals("symbol")) || (current.lexeme == null)) {
  547. error("parseRestrictOrDefault seeking keywords: 'default', 'max', min', or 'restricted_to'.");
  548. }
  549. if (current.lexeme.equals("restricted_to")) { // restricted values declaration
  550. if ((udp.typ.equals("boolean")) || (udp.typ.equals("individual"))) {
  551. error("UserDefinedProperty '" + udp.starName + "' is " + udp.typ + " but has restricted values. Not allowed.");
  552. }
  553. current = scanner.readToken(); // read next, which must be a comma
  554. if (!current.token.equals("comma")) {
  555. error("parseRestrictOrDefault seeking a comma.");
  556. }
  557. current = scanner.readToken(); // read next, which must be a leftParen
  558. if (!current.token.equals("leftParen")) {
  559. error("parseRestrictOrDefault seeking a leftParen.");
  560. }
  561. udp.validEntries = parseInts_Floats_Strings(udp);
  562. current = scanner.readToken(); // read next, which must be a rightParen
  563. if (!current.token.equals("rightParen")) {
  564. error("parseRestrictOrDefault seeking a rightParen.");
  565. }
  566. } else if (current.lexeme.equals("default")) { // default value declaration
  567. current = scanner.readToken(); // read next, which must be a comma
  568. if (udp.typ.equals("individual")) {
  569. error("UserDefinedProperty '" + udp.starName + "' is " + udp.typ + ". Default value not allowed.");
  570. }
  571. if (!current.token.equals("comma")) {
  572. error("parseRestrictOrDefault seeking a comma.");
  573. }
  574. udp.defaultValue = parseInt_Float_String();
  575. } else if (current.lexeme.equals("max")) {
  576. current = scanner.readToken(); // read next, which must be a comma
  577. if ((udp.typ.equals("string")) || (udp.typ.equals("boolean")) || (udp.typ.equals("individual"))) {
  578. error("UserDefinedProperty '" + udp.starName + "' is " + udp.typ + ". Max value not allowed.");
  579. }
  580. if (!current.token.equals("comma")) {
  581. error("parseRestrictOrDefault seeking a comma.");
  582. }
  583. udp.maxVal = parseInt_Float();
  584. if (!current.token.equals(udp.typ)) {
  585. error("UserDefinedProperty '" + udp.starName + "' has type = " + udp.typ + ", but Max Value is a " + current.token);
  586. }
  587. } else if (current.lexeme.equals("min")) {
  588. current = scanner.readToken(); // read next, which must be a comma
  589. if ((udp.typ.equals("string")) || (udp.typ.equals("boolean")) || (udp.typ.equals("individual"))) {
  590. error("UserDefinedProperty '" + udp.starName + "' is " + udp.typ + ". Min value not allowed.");
  591. }
  592. if (!current.token.equals("comma")) {
  593. error("parseRestrictOrDefault seeking a comma.");
  594. }
  595. udp.minVal = parseInt_Float();
  596. if (!current.token.equals(udp.typ)) {
  597. error("UserDefinedProperty '" + udp.starName + "' has type = " + udp.typ + ", but Max Value is a " + current.token);
  598. }
  599. } else {
  600. error("parseRestrictOrDefault seeking keywords: 'default', 'max', min', or 'restricted_to'.");
  601. }
  602. } // end of method parseRestrictOrDefault
  603. /* Int_Float -> integer.
  604. | float.
  605. First: [integer, float] Follow: [comma, rightParen]
  606. */
  607. private Number parseInt_Float() throws KSParsingErrorException {
  608. current = scanner.readToken(); // read next, must be int or float.
  609. if (current.token.equals("integer")) {
  610. return new Integer(current.intVal);
  611. }
  612. if (current.token.equals("float")) {
  613. return new Float(current.floatVal);
  614. }
  615. error("parseInt_Float seeking an integer or a float.");
  616. return null;
  617. } // end of method parseInt_Float
  618. /* Int_Float_String -> integer.
  619. | float.
  620. | string.
  621. First: [integer, float, string] Follow: [comma, rightParen]
  622. */
  623. private Object parseInt_Float_String() throws KSParsingErrorException {
  624. current = scanner.readToken(); // read next, must be int, float, string
  625. if (current.token.equals("integer")) {
  626. return new Integer(current.intVal);
  627. }
  628. if (current.token.equals("float")) {
  629. return new Float(current.floatVal);
  630. }
  631. // Accept symbols as strings -- folks will forget the quotes.
  632. if ((current.token.equals("string")) || (current.token.equals("symbol"))) {
  633. return current.lexeme;
  634. }
  635. error("parseInt_Float_String seeking an integer, float, or string.");
  636. return null;
  637. } // end of method parseInt_Float_String
  638. /* Ints_Floats_Strings -> Ints.
  639. | Floats.
  640. | Strings.
  641. First: [integer, float, string] Follow: [rightParen]
  642. */
  643. private ArrayList<Object> parseInts_Floats_Strings(UserDefinedProperty udp) throws KSParsingErrorException {
  644. current = scanner.lookAhead();
  645. if (!udp.typ.equals(current.token)) {
  646. error("UserDefinedProperty '" + udp.starName + "' has type = " + udp.typ + ", but 'legal values' has a " + current.token);
  647. }
  648. if (current.token.equals("integer")) {
  649. return parseInts();
  650. }
  651. if (current.token.equals("float")) {
  652. return parseFloats();
  653. }
  654. if (current.token.equals("string")) {
  655. return parseStrings();
  656. }
  657. error("parseInts_Floats_Strings seeking an integer, float, or string.");
  658. return null;
  659. } // end of method parseInts_Floats_Strings
  660. /* Ints -> integer, MoreInts.
  661. First: [integer] Follow: [rightParen]
  662. */
  663. private ArrayList<Object> parseInts() throws KSParsingErrorException {
  664. ArrayList<Object> list = new ArrayList<Object>();
  665. current = scanner.readToken(); // read next, which must be an integer
  666. if (!current.token.equals("integer")) {
  667. error("parseInts seeking an integer.");
  668. }
  669. list.add(new Integer(current.intVal));
  670. parseMoreInts(list);
  671. return list;
  672. } // end of method parseInts
  673. /* MoreInts -> comma, integer, MoreInts.
  674. | \empty
  675. First: [comma] Follow: [rightParen]
  676. */
  677. private void parseMoreInts(ArrayList<Object> list) throws KSParsingErrorException {
  678. current = scanner.lookAhead();
  679. if (current.token.equals("comma")) {
  680. scanner.readToken(); // consume the comma
  681. current = scanner.readToken(); // read next, which must be an integer
  682. if (!current.token.equals("integer")) {
  683. error("parseMoreInts seeking an integer.");
  684. }
  685. list.add(new Integer(current.intVal));
  686. parseMoreInts(list);
  687. return;
  688. } else if (current.token.equals("rightParen")) {
  689. return;
  690. } else {
  691. error("parseMoreInts seeking a comma or a rightParen.");
  692. }
  693. } // end of method parseMoreInts
  694. /* Floats -> float, MoreFloats.
  695. First: [float] Follow: [rightParen]
  696. */
  697. private ArrayList<Object> parseFloats() throws KSParsingErrorException {
  698. ArrayList<Object> list = new ArrayList<Object>();
  699. current = scanner.readToken(); // read next, which must be a float
  700. if (!current.token.equals("float")) {
  701. error("parseFloats seeking a float.");
  702. }
  703. list.add(new Float(current.floatVal));
  704. parseMoreFloats(list);
  705. return list;
  706. } // end of method parseFloats
  707. /* MoreFloats -> comma, float, MoreFloats.
  708. | \empty.
  709. First: [comma] Follow: [rightParen]
  710. */
  711. private void parseMoreFloats(ArrayList<Object> list) throws KSParsingErrorException {
  712. current = scanner.lookAhead();
  713. if (current.token.equals("comma")) {
  714. scanner.readToken(); // consume the comma
  715. current = scanner.readToken(); // read next, which must be a float
  716. if (!current.token.equals("float")) {
  717. error("parseMoreFloats seeking a float.");
  718. }
  719. list.add(new Float(current.floatVal));
  720. parseMoreFloats(list);
  721. return;
  722. } else if (current.token.equals("rightParen")) {
  723. return;
  724. } else {
  725. error("parseMoreFloats seeking a comma or a rightParen.");
  726. }
  727. } // end of method parseMoreFloats
  728. /* Strings -> string, MoreStrings.
  729. First: [string] Follow: [rightParen]
  730. */
  731. private ArrayList<Object> parseStrings() throws KSParsingErrorException {
  732. ArrayList<Object> list = new ArrayList<Object>();
  733. current = scanner.readToken(); // read next, which must be a string
  734. if (!current.token.equals("string")) {
  735. error("parseStrings seeking a string.");
  736. }
  737. list.add(current.lexeme);
  738. parseMoreStrings(list);
  739. return list;
  740. } // end of method parseStrings
  741. /* MoreStrings -> comma, string, MoreStrings.
  742. | \empty.
  743. First: [comma] Follow: [rightParen]
  744. */
  745. private void parseMoreStrings(ArrayList<Object> list) throws KSParsingErrorException {
  746. current = scanner.lookAhead();
  747. if (current.token.equals("comma")) {
  748. scanner.readToken(); // consume the comma
  749. current = scanner.readToken(); // read next, which must be a string
  750. if (!current.token.equals("string")) {
  751. error("parseMoreStrings seeking a string.");
  752. }
  753. list.add(current.lexeme);
  754. parseMoreStrings(list);
  755. return;
  756. } else if (current.token.equals("rightParen")) {
  757. return;
  758. } else {
  759. error("parseMoreStrings seeking a comma or a rightParen.");
  760. }
  761. } // end of method parseMoreStrings
  762. public DomainTheory parseMacrosOnly() throws KSParsingErrorException {
  763. dTheory = new DomainTheory();
  764. current = scanner.lookAhead();
  765. KinTermDef ktd = parseKinTermDef();
  766. parseSignatureString(ktd);
  767. parseExpansion(ktd);
  768. for (int i = 0; i < ktd.expandedDefs.size(); i++) { // number the expanded defintions
  769. ((ClauseBody) ktd.expandedDefs.get(i)).seqNmbr = i;
  770. }
  771. parseOtherDefs();
  772. return dTheory;
  773. }
  774. // StandardMacros -> KinTermDef, SignatureString, Expansion, OtherDefs.
  775. // | \empty.
  776. private void parseStandardMacros() throws KSParsingErrorException {
  777. if (macroScanner == null) {
  778. return; // No Macros were provided
  779. }
  780. if (cachedStdMacros != null) { // no need to parse again
  781. for (int i = 0; i < cachedStdMacros.size(); i++) {
  782. KinTermDef macro = new KinTermDef((KinTermDef) cachedStdMacros.get(i));
  783. macro.domTh = dTheory;
  784. dTheory.theory.put(macro.kinTerm, macro);
  785. dTheory.nonTerms.add(macro.kinTerm);
  786. }
  787. return;
  788. }
  789. Tokenizer holdScan = scanner; // temporarily store the main Tokenizer & Linus
  790. Linus holdThatLine = lineMan; // I couldn't resist!
  791. TokenScanned priorCurrent = current;
  792. scanner = macroScanner; // Substitute the Macro Tokenizer & Linus
  793. lineMan = macroLineMan;
  794. current = scanner.lookAhead();
  795. KinTermDef ktd = parseKinTermDef();
  796. parseSignatureString(ktd);
  797. parseExpansion(ktd);
  798. for (int i = 0; i < ktd.expandedDefs.size(); i++) // number the expanded defintions
  799. {
  800. ((ClauseBody) ktd.expandedDefs.get(i)).seqNmbr = i;
  801. }
  802. parseOtherDefs();
  803. // All KTDs in the Macro file have been parsed & added; now put them in nonTerms List.
  804. Iterator ktdIter = dTheory.theory.values().iterator();
  805. cachedStdMacros = new ArrayList<Object>();
  806. while (ktdIter.hasNext()) {
  807. KinTermDef tempKTD = (KinTermDef) ktdIter.next();
  808. dTheory.nonTerms.add(tempKTD.kinTerm);
  809. cachedStdMacros.add(tempKTD);
  810. }
  811. scanner = holdScan; // Put back original Tokenizer & Linus
  812. lineMan = holdThatLine;
  813. current = priorCurrent;
  814. return;
  815. } // end of method parseStandardMacros
  816. public void parseStandardMacros(DomainTheory dt) throws KSParsingErrorException {
  817. // NOTE: This version of parseStandardMacros is meant to be called with a DomainTheory
  818. // that needs just the Std Macros added to it's theory.
  819. if (cachedStdMacros != null) { // no need to parse again
  820. for (int i = 0; i < cachedStdMacros.size(); i++) {
  821. KinTermDef macro = new KinTermDef((KinTermDef) cachedStdMacros.get(i));
  822. macro.domTh = dt;
  823. dt.theory.put(macro.kinTerm, macro);
  824. dt.nonTerms.add(macro.kinTerm);
  825. }
  826. return;
  827. }
  828. dTheory = dt;
  829. current = scanner.lookAhead();
  830. KinTermDef ktd = parseKinTermDef();
  831. parseSignatureString(ktd);
  832. parseExpansion(ktd);
  833. for (int i = 0; i < ktd.expandedDefs.size(); i++) // number the expanded defintions
  834. {
  835. ((ClauseBody) ktd.expandedDefs.get(i)).seqNmbr = i;
  836. }
  837. parseOtherDefs();
  838. // All KTDs in the Macro file have been parsed & added; now put them in nonTerms List.
  839. Iterator ktdIter = dTheory.theory.values().iterator();
  840. cachedStdMacros = new ArrayList<Object>();
  841. while (ktdIter.hasNext()) {
  842. KinTermDef tempKTD = (KinTermDef) ktdIter.next();
  843. dTheory.nonTerms.add(tempKTD.kinTerm);
  844. cachedStdMacros.add(tempKTD);
  845. }
  846. return;
  847. } // end of method parseStandardMacros
  848. // TermPairs -> TermPair, OtherTermPairs.
  849. // First: [leftParen] Follow: [rightParen]
  850. private void parseTermPairs(TreeMap tMap, boolean dblPost) throws KSParsingErrorException {
  851. parseTermPair(tMap, dblPost);
  852. parseOtherTermPairs(tMap, dblPost);
  853. } // end of method parseTermPairs
  854. // TermPair -> leftParen, symbol, comma, symbol, rightParen.
  855. // First: [leftParen] Follow: [comma, rightParen]
  856. private void parseTermPair(TreeMap tMap, boolean dblPost) throws KSParsingErrorException {
  857. current = scanner.readToken(); // consume next, which must be a leftParen
  858. if (!current.token.equals("leftParen")) {
  859. error("parseTermPair seeking a leftParen");
  860. }
  861. current = scanner.readToken(); // consume next, which must be a symbol
  862. if (!current.token.equals("symbol")) {
  863. error("parseTermPair seeking a symbol");
  864. }
  865. String term1 = current.lexeme;
  866. current = scanner.readToken(); // consume next, which must be a comma
  867. if (!current.token.equals("comma")) {
  868. error("parseTermPair seeking a comma");
  869. }
  870. current = scanner.readToken(); // consume next, which must be a symbol
  871. if (!current.token.equals("symbol")) {
  872. error("parseTermPair seeking a symbol");
  873. }
  874. String term2 = current.lexeme;
  875. current = scanner.readToken(); // consume next, which must be a rightParen
  876. if (!current.token.equals("rightParen")) {
  877. error("parseTermPair seeking a rightParen");
  878. }
  879. // all elements of the term pair are now validated. Post.
  880. if (dblPost) { // Overlaps are double-posted in a different structure
  881. if (tMap.get(term1) == null) {
  882. tMap.put(term1, new ArrayList<Object>());
  883. }
  884. ArrayList<Object> oLapList = (ArrayList<Object>) tMap.get(term1);
  885. oLapList.add(term2);
  886. if (tMap.get(term2) == null) {
  887. tMap.put(term2, new ArrayList<Object>());
  888. }
  889. oLapList = (ArrayList<Object>) tMap.get(term2);
  890. oLapList.add(term1);
  891. } else {
  892. tMap.put(term2, term1);
  893. }
  894. } // end of method parseTermPairs
  895. // OtherTermPairs -> comma, TermPair, OtherTermPairs.
  896. // | \empty.
  897. // First: [comma] Follow: [rightParen]
  898. private void parseOtherTermPairs(TreeMap tMap, boolean dblPost) throws KSParsingErrorException {
  899. current = scanner.lookAhead();
  900. if ((!current.token.equals("comma"))
  901. && (!current.token.equals("rightParen"))) {
  902. error("parseOtherTermPairs seeking a comma or rightParen");
  903. }
  904. if (current.token.equals("rightParen")) {
  905. return;
  906. }
  907. scanner.readToken(); // consume the comma
  908. parseTermPair(tMap, dblPost);
  909. parseOtherTermPairs(tMap, dblPost);
  910. } // end of method parseOtherTermPairs
  911. // TermListPairs -> TermListPair, OtherTermListPairs.
  912. // First: [leftParen] Follow: [rightParen]
  913. private void parseTermListPairs(TreeMap tMap, boolean dblPost) throws KSParsingErrorException {
  914. parseTermListPair(tMap, dblPost);
  915. parseOtherTermListPairs(tMap, dblPost);
  916. } // end of method parseTermListPairs
  917. // OtherTermListPairs -> comma, TermListPair, OtherTermListPairs.
  918. // | \empty.
  919. // First: [comma] Follow: [rightParen]
  920. private void parseOtherTermListPairs(TreeMap tMap, boolean dblPost) throws KSParsingErrorException {
  921. current = scanner.lookAhead();
  922. if ((!current.token.equals("comma"))
  923. && (!current.token.equals("rightParen"))) {
  924. error("parseOtherTermListPairs seeking a comma or rightParen");
  925. }
  926. if (current.token.equals("rightParen")) {
  927. return;
  928. }
  929. scanner.readToken(); // consume the comma
  930. parseTermListPair(tMap, dblPost);
  931. parseOtherTermListPairs(tMap, dblPost);
  932. } // end of method parseOtherTermListPairs
  933. // TermListPair -> leftParen, symbol, comma, TermList, rightParen.
  934. // First: [leftParen] Follow: [rightParen]
  935. private void parseTermListPair(TreeMap tMap, boolean dblPost) throws KSParsingErrorException {
  936. current = scanner.readToken(); // consume next, which must be a leftParen
  937. if (!current.token.equals("leftParen")) {
  938. error("parseTermListPair seeking a leftParen");
  939. }
  940. current = scanner.readToken(); // consume next, which must be a symbol
  941. if (!current.token.equals("symbol")) {
  942. error("parseTermListPair seeking a symbol");
  943. }
  944. String baseTerm = current.lexeme;
  945. current = scanner.readToken(); // consume next, which must be a comma
  946. if (!current.token.equals("comma")) {
  947. error("parseTermListPair seeking a comma");
  948. }
  949. ArrayList<Object> termList = parseTermList();
  950. current = scanner.readToken(); // consume next, which must be a rightParen
  951. if (!current.token.equals("rightParen")) {
  952. error("parseTermListPair seeking a rightParen");
  953. }
  954. // all elements are validated. Post to tMap.
  955. if (dblPost) { // overlaps require double-posting; umbrellas do not
  956. if (tMap.get(baseTerm) == null) {
  957. tMap.put(baseTerm, new ArrayList<Object>());
  958. }
  959. ArrayList<Object> baseList = (ArrayList<Object>) tMap.get(baseTerm);
  960. for (int i = 0; i < termList.size(); i++) {
  961. String oLapTerm = (String) termList.get(i);
  962. if (tMap.get(oLapTerm) == null) {
  963. tMap.put(oLapTerm, new ArrayList<Object>());
  964. }
  965. ArrayList<Object> oLapTermList = (ArrayList<Object>) tMap.get(oLapTerm);
  966. if (!baseList.contains(oLapTerm)) {
  967. baseList.add(oLapTerm);
  968. }
  969. if (!oLapTermList.contains(baseTerm)) {
  970. oLapTermList.add(baseTerm);
  971. }
  972. } // end of loop thru all overlapping terms of baseTerm
  973. } else {
  974. tMap.put(baseTerm, termList);
  975. }
  976. } // end of method parseTermListPair
  977. // TermList -> leftParen, symbol, MoreTerms, rightParen.
  978. // First: [leftParen] Follow: [rightParen]
  979. private ArrayList<Object> parseTermList() throws KSParsingErrorException {
  980. current = scanner.readToken(); // consume next, which must be a leftParen
  981. if (!current.token.equals("leftParen")) {
  982. error("parseTermList seeking a leftParen");
  983. }
  984. current = scanner.readToken(); // consume next, which must be a symbol
  985. if (!current.token.equals("symbol")) {
  986. error("parseTermList seeking a symbol");
  987. }
  988. ArrayList<Object> termList = new ArrayList<Object>();
  989. termList.add(current.lexeme);
  990. current = scanner.lookAhead();
  991. if ((!current.token.equals("comma")) && (!current.token.equals("rightParen"))) {
  992. error("parseTermList seeking a comma or rightParen");
  993. }
  994. if (current.token.equals("comma")) {
  995. termList.addAll(parseMoreTerms());
  996. }
  997. current = scanner.readToken(); // consume next, which must be a rightParen
  998. if (!current.token.equals("rightParen")) {
  999. error("parseTermList seeking a rightParen");
  1000. }
  1001. return termList;
  1002. } // end of method parseTermList
  1003. // MoreTerms -> comma, symbol, MoreTerms.
  1004. // | \empty.
  1005. // First: [comma] Follow: [rightParen]
  1006. private ArrayList<Object> parseMoreTerms() throws KSParsingErrorException {
  1007. current = scanner.readToken(); // consume next, which must be a comma
  1008. if (!current.token.equals("comma")) {
  1009. error("parseMoreTerms seeking a comma");
  1010. }
  1011. current = scanner.readToken(); // consume next, which must be a symbol
  1012. if (!current.token.equals("symbol")) {
  1013. error("parseMoreTerms seeking a symbol");
  1014. }
  1015. ArrayList<Object> termList = new ArrayList<Object>();
  1016. termList.add(current.lexeme);
  1017. current = scanner.lookAhead();
  1018. if ((!current.token.equals("comma")) && (!current.token.equals("rightParen"))) {
  1019. error("parseMoreTerms seeking a comma or rightParen");
  1020. }
  1021. if (current.token.equals("comma")) {
  1022. termList.addAll(parseMoreTerms());
  1023. }
  1024. return termList;
  1025. } // end of method parseMoreTerms
  1026. // Theory -> KinTermDef, SignatureString, (optional) string,
  1027. // Expansion, OtherDefs.
  1028. private void parseTheory() throws KSParsingErrorException {
  1029. KinTermDef ktd = parseKinTermDef();
  1030. parseSignatureString(ktd);
  1031. current = scanner.lookAhead();
  1032. if (current.token.equals("string")) {
  1033. scanner.readToken(); // consume the string
  1034. ktd.comments = current.lexeme;
  1035. }
  1036. parseExpansion(ktd);
  1037. for (int i = 0; i < ktd.expandedDefs.size(); i++) // number the expanded defintions
  1038. {
  1039. ((ClauseBody) ktd.expandedDefs.get(i)).seqNmbr = i;
  1040. }
  1041. parseOtherDefs();
  1042. return;
  1043. } // end of method parseTheory
  1044. /* OtherDefs -> KinTermDef, SignatureString, (optional) string,
  1045. Expansion, OtherDefs.
  1046. | \empty.
  1047. First: [symbol] Follow: [$]
  1048. */
  1049. private void parseOtherDefs() throws KSParsingErrorException {
  1050. current = scanner.lookAhead();
  1051. if (current.token.equals("symbol")) {
  1052. KinTermDef ktd = parseKinTermDef();
  1053. parseSignatureString(ktd);
  1054. current = scanner.lookAhead();
  1055. if (current.token.equals("string")) {
  1056. scanner.readToken(); // consume the string
  1057. ktd.comments = current.lexeme;
  1058. }
  1059. parseExpansion(ktd);
  1060. int siz = ktd.expandedDefs.size();
  1061. for (int i = 0; i < siz; i++) // number the expanded defintions
  1062. {
  1063. ((ClauseBody) ktd.expandedDefs.get(i)).seqNmbr = i;
  1064. }
  1065. parseOtherDefs();
  1066. return;
  1067. } // end of if = symbol
  1068. if (current.token.equals("$")) {
  1069. return;
  1070. }
  1071. error("parseOtherDefs seeking symbol or end-of-file.");
  1072. return;
  1073. } // end of method parseOtherDefs
  1074. // KinTermDef -> ClauseHead, imply, ClauseBody, OtherBodies.
  1075. // First: [symbol] Follow: [percent, leftCurly, $]
  1076. private KinTermDef parseKinTermDef() throws KSParsingErrorException {
  1077. Literal lit = parseClauseHead();
  1078. KinTermDef ktd = new KinTermDef(lit);
  1079. dTheory.addTerm(ktd);
  1080. ktd.domTh = dTheory;
  1081. current = scanner.readToken(); // consume next, which must be an 'imply'
  1082. if (!current.token.equals("imply")) {
  1083. error("parseKinTermDef seeking 'imply'.");
  1084. }
  1085. parseClauseBody(ktd);
  1086. parseOtherBodies(ktd);
  1087. int siz = ktd.definitions.size();
  1088. for (int i = 0; i < siz; i++) { // number the original definitions
  1089. ((ClauseBody) ktd.definitions.get(i)).seqNmbr = i;
  1090. ((ClauseBody) ktd.definitions.get(i)).ktd = ktd;
  1091. } // end of loop thru ClauseBodies
  1092. return ktd;
  1093. } // end of method parseKinTermDef
  1094. // ClauseHead -> symbol, leftParen, Args, rightParen.
  1095. // First: [symbol] Follow: [imply]
  1096. private Literal parseClauseHead() throws KSParsingErrorException {
  1097. Predicate pred;
  1098. Literal lit;
  1099. ArrayList<Object> args = new ArrayList<Object>();
  1100. current = scanner.readToken(); // consume next, which must be a symbol.
  1101. if (!current.token.equals("symbol")) {
  1102. error("parseClauseHead seeking 'symbol'.");
  1103. }
  1104. pred = new Predicate(current.lexeme);
  1105. pred.category = determinePrimitive(current.lexeme, dTheory);
  1106. current = scanner.readToken(); // consume next, which must be a leftParen
  1107. if (!current.token.equals("leftParen")) {
  1108. error("parseClauseHead seeking 'leftParen'.");
  1109. }
  1110. lit = new Literal(pred);
  1111. parseArgs(lit);
  1112. current = scanner.readToken(); // consume next, which must be a rightParen
  1113. if (!current.token.equals("rightParen")) {
  1114. error("parseClauseHead seeking 'rightParen'.");
  1115. }
  1116. return lit;
  1117. } // end of method parseClauseHead
  1118. /* Args -> var, OtherArgs.
  1119. | symbol, OtherArgs.
  1120. | string, OtherArgs.
  1121. | integer, OtherArgs.
  1122. | float, OtherArgs.
  1123. First: [var, symbol, string] Follow: [rightParen]
  1124. */
  1125. private void parseArgs(Literal lit) throws KSParsingErrorException {
  1126. current = scanner.lookAhead();
  1127. if (current.token.equals("var")) {
  1128. scanner.readToken(); // consume the var
  1129. lit.args.add(new Variable(current.lexeme));
  1130. parseOtherArgs(lit);
  1131. return;
  1132. } // end of if = var
  1133. if (current.token.equals("symbol")) {
  1134. scanner.readToken(); // consume the symbol
  1135. Constant konstant = new Constant(current.lexeme);
  1136. lit.args.add(konstant);
  1137. if ((current.lexeme.equals("true")) || (current.lexeme.equals("false"))) {
  1138. konstant.valueType = "boolean";
  1139. konstant.addVal(new Boolean(current.lexeme));
  1140. } else {
  1141. konstant.valueType = "symbol";
  1142. konstant.addVal(current.lexeme);
  1143. }
  1144. parseOtherArgs(lit);
  1145. return;
  1146. } // end of if = symbol
  1147. if (current.token.equals("string")) {
  1148. scanner.readToken(); // consume the string
  1149. ArgString astring = new ArgString(current.lexeme);
  1150. lit.args.add(astring);
  1151. astring.valueType = "string";
  1152. parseOtherArgs(lit);
  1153. return;
  1154. } // end of if = string
  1155. if (current.token.equals("integer")) {
  1156. scanner.readToken(); // consume the integer
  1157. Integer newint = Integer.valueOf(current.lexeme);
  1158. Constant konstant = new Constant(current.lexeme);
  1159. lit.args.add(konstant);
  1160. konstant.addVal(newint);
  1161. konstant.valueType = "integer";
  1162. parseOtherArgs(lit);
  1163. return;
  1164. } // end of if = integer
  1165. if (current.token.equals("float")) {
  1166. scanner.readToken(); // consume the float
  1167. Float newfloat = Float.valueOf(current.lexeme);
  1168. Constant konstant = new Constant(current.lexeme);
  1169. lit.args.add(konstant);
  1170. konstant.addVal(newfloat);
  1171. konstant.valueType = "float";
  1172. parseOtherArgs(lit);
  1173. return;
  1174. } // end of if = float
  1175. error("parseArgs seeking var, symbol, integer, float, or string.");
  1176. return;
  1177. } // end of method parseArgs
  1178. /* OtherArgs -> \empty.
  1179. | comma, Args.
  1180. First: [comma] Follow: [rightParen]
  1181. */
  1182. private void parseOtherArgs(Literal lit) throws KSParsingErrorException {
  1183. current = scanner.lookAhead();
  1184. if (current.token.equals("comma")) {
  1185. scanner.readToken(); // consume the comma
  1186. parseArgs(lit);
  1187. return;
  1188. } // end of if = comma
  1189. if (current.token.equals("rightParen")) {
  1190. return;
  1191. }
  1192. error("parseOtherArgs seeking comma or rightParen (end of arg list).");
  1193. return;
  1194. } // end of method parseOtherArgs
  1195. /* ClauseBody -> LitOrFlag, OtherLitsOrFlags, period.
  1196. First: [symbol, flag] Follow: [bar, symbol, percent, $]
  1197. */
  1198. private void parseClauseBody(KinTermDef def) throws KSParsingErrorException {
  1199. ClauseBody claws = new ClauseBody();
  1200. parseLitOrFlag(claws);
  1201. parseOtherLitsOrFlags(claws);
  1202. current = scanner.readToken(); // consume next, which must be a period
  1203. if (!current.token.equals("period")) {
  1204. error("parseClauseBody seeking 'period'.");
  1205. }
  1206. errorFound = "None";
  1207. if (claws.invalid()) {
  1208. error(errorFound);
  1209. }
  1210. def.addClause(claws);
  1211. return;
  1212. } // end of method parseClauseBody
  1213. /* OtherLitsOrFlags -> \empty.
  1214. | comma, LitOrFlag, OtherLitsOrFlags.
  1215. First: [comma] Follow: [period]
  1216. */
  1217. private void parseOtherLitsOrFlags(ClauseBody claws) throws KSParsingErrorException {
  1218. current = scanner.lookAhead();
  1219. if (current.token.equals("comma")) {
  1220. scanner.readToken(); // consume the comma
  1221. parseLitOrFlag(claws);
  1222. parseOtherLitsOrFlags(claws);
  1223. return;
  1224. } // end of if = comma
  1225. if (current.token.equals("period")) {
  1226. return;
  1227. }
  1228. error("parseOtherLiterals seeking period or comma.");
  1229. return;
  1230. } // end of method parseOtherLitsOrFlags
  1231. /* OtherBodies -> bar, ClauseBody, OtherBodies.
  1232. | \empty.
  1233. First: [bar] Follow: [symbol, starName, percent, leftCurly, $]
  1234. */
  1235. private void parseOtherBodies(KinTermDef def) throws KSParsingErrorException {
  1236. current = scanner.lookAhead();
  1237. if (current.token.equals("bar")) {
  1238. scanner.readToken(); // consume the bar
  1239. parseClauseBody(def);
  1240. parseOtherBodies(def);
  1241. return;
  1242. } // end of if = bar
  1243. if (current.token.equals("symbol") || current.token.equals("$") || current.token.equals("leftCurly")
  1244. || current.token.equals("percent") || current.token.equals("starName")) {
  1245. return;
  1246. }
  1247. error("parseOtherBodies seeking bar, symbol, percent, starName, leftCurly, or $ (end of file).");
  1248. return;
  1249. } // end of method parseOtherBodies
  1250. /* FlagOrKinTerm -> flag.
  1251. | symbol.
  1252. First: [flag, symbol]
  1253. Follow: [comma, leftParen, symbol]
  1254. */
  1255. private void parseFlagOrKinTerm() throws KSParsingErrorException {
  1256. current = scanner.readToken();
  1257. if (current.token.equals("flag")) {
  1258. dTheory.nonTermFlags.add(current.lexeme.substring(1, (current.lexeme.length() - 1)));
  1259. } else if (current.token.equals("symbol")) {
  1260. dTheory.nonTerms.add(current.lexeme);
  1261. } else {
  1262. error("parseFlagOrKinTerm seeking a flag or symbol (kinTerm).");
  1263. }
  1264. return;
  1265. } // end of method parseFlagOrKinTerm
  1266. /* OtherFlagOrKinTerm -> comma, OtherFlagOrKinTerm2.
  1267. | \empty.
  1268. First: [comma]
  1269. Follow: [rightParen]
  1270. */
  1271. private void parseOtherFlagOrKinTerm() throws KSParsingErrorException {
  1272. current = scanner.lookAhead();
  1273. if (current.token.equals("comma")) {
  1274. scanner.readToken(); // consume the comma
  1275. parseOtherFlagOrKinTerm2();
  1276. return;
  1277. } // end of found-a-comma
  1278. else if (current.token.equals("rightParen")) {
  1279. return;
  1280. } else {
  1281. error("parseOtherFlagOrKinTerm seeking a comma or rightParen.");
  1282. }
  1283. return;
  1284. } // end of method parseOtherFlagOrKinTerm
  1285. /* OtherFlagOrKinTerm2 -> flag, OtherFlagOrKinTerm.
  1286. | symbol, OtherFlagOrKinTerm.
  1287. First: [flag, symbol]
  1288. Follow: [leftParen, symbol]
  1289. */
  1290. private void parseOtherFlagOrKinTerm2() throws KSParsingErrorException {
  1291. current = scanner.readToken();
  1292. if (current.token.equals("flag")) {
  1293. dTheory.nonTermFlags.add(current.lexeme.substring(1, (current.lexeme.length() - 1)));
  1294. } else if (current.token.equals("symbol")) {
  1295. dTheory.nonTerms.add(current.lexeme);
  1296. } else {
  1297. error("parseFlagOrKinTerm2 seeking a flag or symbol (kinTerm).");
  1298. }
  1299. parseOtherFlagOrKinTerm();
  1300. return;
  1301. } // end of method parseFlagOrKinTerm
  1302. /* LitOrFlag -> flag.
  1303. | Literal.
  1304. */
  1305. private void parseLitOrFlag(ClauseBody claws) throws KSParsingErrorException {
  1306. current = scanner.lookAhead();
  1307. if (current.token.equals("flag")) {
  1308. current = scanner.readToken(); // consume the flag
  1309. claws.flags.add(current.lexeme.substring(1, (current.lexeme.length() - 1))); // post this flag to the clauseBody
  1310. } // end of parsing-the-flag
  1311. else if ((current.token.equals("symbol")) || (current.token.equals("starName"))) {
  1312. parseLiteral(claws);
  1313. } else {
  1314. error("parseLitOrFlag seeking symbol, starName or flag.");
  1315. }
  1316. return;
  1317. } // end of method parseLitOrFlag
  1318. /* Literal -> symbol, leftParen, ArgNest, rightParen.
  1319. | starName, leftParen, ArgNest, rightParen.
  1320. First: [symbol, starName] Follow: [comma, period]
  1321. */
  1322. private void parseLiteral(ClauseBody claws) throws KSParsingErrorException {
  1323. current = scanner.readToken(); // consume next, which must be a symbol or starName
  1324. Literal lit;
  1325. if (!((current.token.equals("symbol")) || (current.token.equals("starName")))) {
  1326. error("parseLiteral seeking symbol or starName.");
  1327. }
  1328. Predicate pred = new Predicate(current.lexeme);
  1329. pred.category = determinePrimitive(current.lexeme, dTheory);
  1330. current = scanner.readToken(); // consume next, which must be a leftParen
  1331. if (!current.token.equals("leftParen")) {
  1332. error("parseLiteral seeking leftParen.");
  1333. }
  1334. lit = new Literal(pred);
  1335. parseArgNest(lit);
  1336. current = scanner.readToken(); // consume next, which must be a rightParen
  1337. if (!current.token.equals("rightParen")) {
  1338. error("parseLiteral seeking rightParen.");
  1339. }
  1340. claws.addLiteral(lit);
  1341. return;
  1342. } // end of method parseLiteral
  1343. /* ArgNest -> var, OtherArgNest.
  1344. | symbol, SymbOrLitRest, OtherArgNest.
  1345. | starName, leftParen, ArgNest, rightParen, OtherArgNest.
  1346. | string, OtherArgNest.
  1347. | integer, OtherArgNest.
  1348. | float, OtherArgNest.
  1349. | \empty.
  1350. First: [var, symbol, starName, string, integer, float] Follow: [rightParen]
  1351. */
  1352. private void parseArgNest(Literal lit) throws KSParsingErrorException {
  1353. current = scanner.lookAhead();
  1354. if (current.token.equals("var")) {
  1355. scanner.readToken(); // consume the var
  1356. lit.args.add(new Variable(current.lexeme));
  1357. parseOtherArgNest(lit);
  1358. return;
  1359. } // end of if = var
  1360. if (current.token.equals("symbol")) {
  1361. scanner.readToken(); // consume the symbol
  1362. parseSymbOrLitRest(lit);
  1363. parseOtherArgNest(lit);
  1364. return;
  1365. } // end of if = symbol
  1366. if (current.token.equals("starName")) {
  1367. scanner.readToken(); // consume the starName
  1368. Literal innerLit;
  1369. Predicate pred = new Predicate(current.lexeme);
  1370. pred.category = determinePrimitive(current.lexeme, dTheory);
  1371. current = scanner.readToken(); // consume next, which must be a leftParen
  1372. if (!current.token.equals("leftParen")) {
  1373. error("parseLiteral seeking leftParen.");
  1374. }
  1375. innerLit = new Literal(pred);
  1376. parseArgNest(innerLit);
  1377. current = scanner.readToken(); // consume next, which must be a rightParen
  1378. if (!current.token.equals("rightParen")) {
  1379. error("parseLiteral seeking rightParen.");
  1380. }
  1381. lit.args.add(innerLit);
  1382. parseOtherArgNest(lit);
  1383. return;
  1384. } // end of if = starName
  1385. if (current.token.equals("string")) {
  1386. scanner.readToken(); // consume the string
  1387. lit.args.add(new ArgString(current.lexeme));
  1388. parseOtherArgNest(lit);
  1389. return;
  1390. } // end of if = string
  1391. if (current.token.equals("integer")) {
  1392. scanner.readToken(); // consume the integer
  1393. Integer newint = Integer.valueOf(current.lexeme);
  1394. Constant konstant = new Constant(current.lexeme);
  1395. lit.args.add(konstant);
  1396. konstant.addVal(newint);
  1397. konstant.valueType = "integer";
  1398. parseOtherArgNest(lit);
  1399. return;
  1400. } // end of if = integer
  1401. if (current.token.equals("float")) {
  1402. scanner.readToken(); // consume the float
  1403. Float newfloat = Float.valueOf(current.lexeme);
  1404. Constant konstant = new Constant(current.l