PageRenderTime 37ms CodeModel.GetById 0ms RepoModel.GetById 0ms app.codeStats 1ms

/code/Parser.java

http://silkin.googlecode.com/
Java | 1484 lines | 1190 code | 71 blank | 223 comment | 336 complexity | a14be171636dfe0a638ad31664634ce2 MD5 | raw file

Large files files are truncated, but you can click here to view the full 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 = curr

Large files files are truncated, but you can click here to view the full file