PageRenderTime 62ms CodeModel.GetById 28ms RepoModel.GetById 0ms app.codeStats 0ms

/adela/src/net/sourceforge/adela/interpreter/ADELAParseTree.java

https://github.com/hce/govm
Java | 1561 lines | 1207 code | 84 blank | 270 comment | 191 complexity | d5fe8c88a6beec28da26038cd98153e6 MD5 | raw file
  1. /**
  2. * adela
  3. * An embeddable, secure scripting language
  4. * for java applications
  5. *
  6. * (C) 2007, Hans-Christian Esperer
  7. * hc at hcespererorg
  8. * All rights reserved.
  9. *
  10. * Redistribution and use in source and binary forms, with or without
  11. * modification, are permitted provided that the following conditions
  12. * are met:
  13. *
  14. * * Redistributions of source code must retain the above copyright
  15. * notice, this list of conditions and the following disclaimer.
  16. * * Redistributions in binary form must reproduce the above
  17. * copyright notice, this list of conditions and the following
  18. * disclaimer in the documentation and/or other materials provided
  19. * with the distribution.
  20. * * Neither the name of the H. Ch. Esperer nor the names of his
  21. * contributors may be used to endorse or promote products derived
  22. * from this software without specific prior written permission.
  23. *
  24. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  25. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  26. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  27. * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  28. * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  29. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  30. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  31. * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  32. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
  33. * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  34. * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
  35. * POSSIBILITY OF SUCH DAMAGE
  36. **************************************************************************/
  37. package net.sourceforge.adela.interpreter;
  38. import java.io.DataInput;
  39. import java.io.DataOutput;
  40. import java.io.Externalizable;
  41. import java.io.IOException;
  42. import java.io.ObjectInput;
  43. import java.io.ObjectOutput;
  44. import java.io.PrintStream;
  45. import java.io.UnsupportedEncodingException;
  46. import java.util.ArrayList;
  47. import java.util.Iterator;
  48. import java.util.Map;
  49. import java.util.Random;
  50. import java.util.Vector;
  51. import net.sourceforge.adela.enums.EValueType;
  52. import net.sourceforge.adela.exceptions.ADELASyntaxException;
  53. import net.sourceforge.adela.exceptions.EvaluatorIsNullException;
  54. import net.sourceforge.adela.exceptions.FunctionNotFoundException;
  55. import net.sourceforge.adela.exceptions.WrongParameterCountException;
  56. import net.sourceforge.adela.govm.GOVMWriter;
  57. import net.sourceforge.adela.govm.Opcode;
  58. import net.sourceforge.adela.govm.StatementResolver;
  59. import net.sourceforge.adela.interfaces.IEvaluator;
  60. /**
  61. * A parse tree containing the parsing instructions for one statement
  62. *
  63. * @author hc
  64. */
  65. public class ADELAParseTree implements Externalizable {
  66. /**
  67. *
  68. */
  69. private static final long serialVersionUID = -3172093318940768196L;
  70. /**
  71. * Left part
  72. */
  73. private ADELAParseTree leftTree;
  74. /**
  75. * Right part
  76. */
  77. private ADELAParseTree rightTree;
  78. /**
  79. * The operator to use
  80. */
  81. private char operator;
  82. /**
  83. * Statement to evaluate
  84. */
  85. private String statement;
  86. /**
  87. * Cached int
  88. */
  89. private int intValue;
  90. /**
  91. * Cached long
  92. */
  93. private long longValue;
  94. /**
  95. * cached double
  96. */
  97. private double doubleValue;
  98. /**
  99. * cached string
  100. */
  101. private String stringValue;
  102. /**
  103. * Function to call on evaluation
  104. */
  105. private String functionToCall;
  106. /**
  107. * Parameters to call function with
  108. */
  109. private ADELAParseTree[] functionParameters;
  110. /**
  111. * Type of value we're storing
  112. */
  113. private EValueType valueType;
  114. /**
  115. * True if the result of this parse tree should be returned if used in a
  116. * function block
  117. */
  118. private boolean returnStatement;
  119. /**
  120. * A PRNG for random NOP insertion to prevent cheating.
  121. */
  122. private Random prng = new Random();
  123. /**
  124. * Instanciiate a leaf with an int value
  125. *
  126. * @param value
  127. * int value
  128. */
  129. protected ADELAParseTree(int value) {
  130. this.valueType = EValueType.intValue;
  131. this.intValue = value;
  132. }
  133. /**
  134. * Instanciiate a leaf with a double value
  135. *
  136. * @param value
  137. * double value
  138. */
  139. protected ADELAParseTree(double value) {
  140. this.valueType = EValueType.floatValue;
  141. this.doubleValue = value;
  142. }
  143. /**
  144. * Instanciiate a leaf with a long value
  145. *
  146. * @param value
  147. * long value
  148. */
  149. protected ADELAParseTree(long value) {
  150. this.valueType = EValueType.longValue;
  151. this.longValue = value;
  152. }
  153. /**
  154. * Instanciiate a leaf that calls a function
  155. *
  156. * @param functionToCall
  157. * name of function to call
  158. * @param arguments
  159. * parse trees of arguments to pass to that function
  160. */
  161. protected ADELAParseTree(String functionToCall, ADELAParseTree[] arguments) {
  162. this.functionToCall = functionToCall;
  163. this.functionParameters = arguments;
  164. this.valueType = EValueType.functioncall;
  165. }
  166. /**
  167. * Instanciiate a leaf with a string
  168. *
  169. * @param value
  170. * string to use
  171. * @param evaluate
  172. * evaluate string?
  173. */
  174. protected ADELAParseTree(String value, boolean evaluate) {
  175. if (evaluate) {
  176. this.statement = value;
  177. this.valueType = EValueType.statement;
  178. } else {
  179. this.valueType = EValueType.stringValue;
  180. this.stringValue = value;
  181. }
  182. }
  183. /**
  184. * Instanciiate a node that performs an operation
  185. *
  186. * @param leftTree
  187. * left sub-tree to evaluate
  188. * @param rightTree
  189. * right sub-tree to evaluate
  190. * @param operator
  191. * operator to use for operation
  192. */
  193. protected ADELAParseTree(ADELAParseTree leftTree, ADELAParseTree rightTree,
  194. char operator) {
  195. this.leftTree = leftTree;
  196. this.rightTree = rightTree;
  197. this.operator = operator;
  198. this.valueType = EValueType.operation;
  199. }
  200. /**
  201. * Instanciiate a node that calls a method
  202. *
  203. * @param leftTree
  204. * tree that gives us the class to call into
  205. * @param method
  206. * method to call
  207. * @throws ADELASyntaxException
  208. */
  209. private ADELAParseTree(ADELAParseTree leftTree, String method)
  210. throws ADELASyntaxException {
  211. this.leftTree = leftTree;
  212. this.operator = '.';
  213. this.handleFunction(method);
  214. this.valueType = EValueType.operation;
  215. }
  216. public ADELAParseTree() {
  217. }
  218. /**
  219. * Evaluate this subtree
  220. *
  221. * @param locals
  222. * map of local variables to use for evaluation
  223. * @param evaluator
  224. * evaluator to use
  225. * @return evaluation result
  226. * @throws FunctionNotFoundException
  227. * @throws WrongParameterCountException
  228. * @throws ADELAException
  229. */
  230. public Object doEvaluate(Map<String, Object> locals, IEvaluator evaluator)
  231. throws WrongParameterCountException, FunctionNotFoundException,
  232. ADELAException {
  233. if (evaluator == null) {
  234. throw new EvaluatorIsNullException();
  235. }
  236. return evaluate(locals, evaluator);
  237. }
  238. /**
  239. * @param locals
  240. * @param evaluator
  241. * @return
  242. * @throws WrongParameterCountException
  243. * @throws FunctionNotFoundException
  244. * @throws ADELAException
  245. */
  246. @SuppressWarnings("unchecked")
  247. private Object evaluate(Map<String, Object> locals, IEvaluator evaluator)
  248. throws WrongParameterCountException, FunctionNotFoundException,
  249. ADELAException {
  250. switch (valueType) {
  251. case floatValue:
  252. return Double.valueOf(doubleValue);
  253. case intValue:
  254. return Integer.valueOf(intValue);
  255. case longValue:
  256. return Long.valueOf(longValue);
  257. case stringValue:
  258. case variable:
  259. return stringValue;
  260. case statement:
  261. return evaluator.evaluate(locals, statement);
  262. case functioncall:
  263. return evaluator.callFunction(null, this.functionToCall, locals,
  264. evaluateParameters(this.functionParameters, locals,
  265. evaluator));
  266. default:
  267. ;
  268. }
  269. Object leftValue = leftTree.evaluate(locals, evaluator);
  270. Object rightValue;
  271. if (rightTree != null) {
  272. if (operator != '.') {
  273. if (operator == 'o') {
  274. if (((Boolean) leftValue) == false) {
  275. rightValue = rightTree.evaluate(locals, evaluator);
  276. } else {
  277. rightValue = null;
  278. }
  279. } else if (operator == 'a') {
  280. if (((Boolean) leftValue) == true) {
  281. rightValue = rightTree.evaluate(locals, evaluator);
  282. } else {
  283. rightValue = null;
  284. }
  285. } else {
  286. rightValue = rightTree.evaluate(locals, evaluator);
  287. }
  288. } else {
  289. rightValue = null;
  290. }
  291. } else {
  292. rightValue = null;
  293. }
  294. Comparable cLeft, cRight;
  295. switch (operator) {
  296. case '+': {
  297. if (leftValue.getClass() == Integer.class) {
  298. return (Integer) leftValue + (Integer) rightValue;
  299. } else if (leftValue.getClass() == Double.class) {
  300. return (Double) leftValue + (Double) rightValue;
  301. } else if (leftValue.getClass() == String.class) {
  302. return (String) leftValue + (String) rightValue;
  303. } else if (leftValue.getClass() == Long.class) {
  304. return (Long) leftValue + (Long) rightValue;
  305. }
  306. }
  307. // substraction
  308. case '-':
  309. if (leftValue.getClass() == Integer.class) {
  310. return (Integer) leftValue - (Integer) rightValue;
  311. } else if (leftValue.getClass() == Double.class) {
  312. return (Double) leftValue - (Double) rightValue;
  313. } else if (leftValue.getClass() == Long.class) {
  314. return (Long) leftValue - (Long) rightValue;
  315. }
  316. // division
  317. case '/':
  318. if (leftValue.getClass() == Integer.class) {
  319. return (Integer) leftValue / (Integer) rightValue;
  320. } else if (leftValue.getClass() == Double.class) {
  321. return (Double) leftValue / (Double) rightValue;
  322. } else if (leftValue.getClass() == Long.class) {
  323. return (Long) leftValue / (Long) rightValue;
  324. }
  325. // multiplication
  326. case '*':
  327. if (leftValue.getClass() == Integer.class) {
  328. return (Integer) leftValue * (Integer) rightValue;
  329. } else if (leftValue.getClass() == Double.class) {
  330. return (Double) leftValue * (Double) rightValue;
  331. } else if (leftValue.getClass() == Long.class) {
  332. return (Long) leftValue * (Long) rightValue;
  333. }
  334. // power
  335. case '^':
  336. return Math.pow((Double) leftValue, (Double) rightValue);
  337. // shift right
  338. case 'x':
  339. return ((Integer) leftValue) >> ((Integer) rightValue);
  340. // shift left
  341. case 'y':
  342. return ((Integer) leftValue) << ((Integer) rightValue);
  343. // comparision: smaller than
  344. case '<':
  345. cLeft = (Comparable) leftValue;
  346. cRight = (Comparable) rightValue;
  347. return cLeft.compareTo(cRight) < 0;
  348. // comparision: greater than
  349. case '>':
  350. cLeft = (Comparable) leftValue;
  351. cRight = (Comparable) rightValue;
  352. return cLeft.compareTo(cRight) > 0;
  353. case 'l':
  354. cLeft = (Comparable) leftValue;
  355. cRight = (Comparable) rightValue;
  356. return (cLeft.compareTo(cRight) < 0)
  357. || (leftValue.equals(rightValue));
  358. case 'g':
  359. cLeft = (Comparable) leftValue;
  360. cRight = (Comparable) rightValue;
  361. return (cLeft.compareTo(cRight) > 0)
  362. || (leftValue.equals(rightValue));
  363. case '=':
  364. // assignment
  365. locals.put((String) leftValue, rightValue);
  366. break;
  367. // comparision: equals
  368. case 'e':
  369. return leftValue.equals(rightValue);
  370. // equals not
  371. case 'n':
  372. return !leftValue.equals(rightValue);
  373. // and
  374. case 'a':
  375. return ((Boolean) leftValue && (Boolean) rightValue);
  376. // or
  377. case 'o':
  378. return ((Boolean) leftValue || (Boolean) rightValue);
  379. // someone screwed up
  380. case '&':
  381. return ((Integer) leftValue & (Integer) rightValue);
  382. // or
  383. case '|':
  384. return ((Integer) leftValue | (Integer) rightValue);
  385. // method invocatoin
  386. case '.':
  387. return evaluator.callFunction(leftValue, this.functionToCall,
  388. locals, evaluateParameters(this.functionParameters, locals,
  389. evaluator));
  390. // someone screwed up
  391. default:
  392. System.out.format("Operator %c unknown\n", operator);
  393. }
  394. return null;
  395. }
  396. private Object[] evaluateParameters(ADELAParseTree[] functionParameters,
  397. Map<String, Object> locals, IEvaluator evaluator)
  398. throws WrongParameterCountException, FunctionNotFoundException,
  399. ADELAException {
  400. Object[] params = new Object[functionParameters.length];
  401. for (int i = 0; i < params.length; i++) {
  402. params[i] = functionParameters[i].doEvaluate(locals, evaluator);
  403. }
  404. return params;
  405. }
  406. /**
  407. * The Parser.
  408. *
  409. * @param s
  410. * String to parse
  411. * @return Parsing result
  412. * @throws ADELASyntaxException
  413. * @throws ADELAException
  414. * On shit
  415. * @throws FunctionNotFoundException
  416. * @throws WrongParameterCountException
  417. */
  418. public static ADELAParseTree Parse(String s) throws ADELASyntaxException {
  419. char elem;
  420. char operator;
  421. int i;
  422. int iLen;
  423. int iBrackets;
  424. Boolean bFound;
  425. String sLeft;
  426. String sRight;
  427. ADELAParseTree leftTree;
  428. ADELAParseTree rightTree;
  429. boolean bNegate = false;
  430. if (s == null) {
  431. return null;
  432. }
  433. if (s.length() == 0) {
  434. return null;
  435. }
  436. /*
  437. * trim us
  438. */
  439. s = s.trim();
  440. /*
  441. * our length
  442. */
  443. iLen = s.length();
  444. /*
  445. * Empty string; return null
  446. */
  447. if (iLen == 0) {
  448. return null;
  449. }
  450. if (s.startsWith("return ")) {
  451. ADELAParseTree returnTree = Parse(s.substring(7));
  452. returnTree.returnStatement = true;
  453. return returnTree;
  454. }
  455. /*
  456. * special cases
  457. */
  458. // string? pass to evaluate
  459. if (s.charAt(0) == '"') {
  460. return PreEvaluate(s, false);
  461. }
  462. // negation? mark it, then strip the negation sign
  463. else if (s.charAt(0) == '-') {
  464. bNegate = true;
  465. s = s.substring(1);
  466. iLen--;
  467. if (iLen < 1)
  468. throw new RuntimeException("Error: invalid expression!");
  469. }
  470. /*
  471. * Find the first operator that does not reside within brackets
  472. */
  473. bFound = false;
  474. iBrackets = 0;
  475. for (i = 0; i < iLen; i++) {
  476. elem = s.charAt(i);
  477. switch (elem) {
  478. case '*':
  479. case '/':
  480. case '+':
  481. case '^':
  482. case '-':
  483. case '<':
  484. case '>':
  485. case '&':
  486. case '|':
  487. case '=':
  488. case ':':
  489. case '!':
  490. if (iBrackets == 0) {
  491. bFound = true;
  492. }
  493. break;
  494. case '.':
  495. if ((s.charAt(i + 1) < '0') || (s.charAt(i + 1) > '9')) {
  496. if (iBrackets == 0) {
  497. bFound = true;
  498. }
  499. }
  500. break;
  501. case '(':
  502. case '[':
  503. iBrackets++;
  504. break;
  505. case ')':
  506. case ']':
  507. iBrackets--;
  508. break;
  509. }
  510. if (bFound)
  511. break;
  512. }
  513. /*
  514. * Equal number of opening and closing brackets!?
  515. */
  516. assert (iBrackets == 0);
  517. /*
  518. * Get the part left of the operator
  519. */
  520. sLeft = s.substring(0, i).trim();
  521. // hack:
  522. // if we have _one_ equals sign ('='), the
  523. // left part is a string, never mind the
  524. // fact it isn't quoted ('"')
  525. if (bFound && ((s.length() - i) >= 2) && (s.charAt(i) == '=')
  526. && (s.charAt(i + 1) != '=')) {
  527. leftTree = new ADELAParseTree(sLeft, false);
  528. leftTree.valueType = EValueType.variable;
  529. } else {
  530. leftTree = PreEvaluate(sLeft, bNegate);
  531. }
  532. /*
  533. * We have a right part
  534. */
  535. if (bFound) {
  536. operator = s.charAt(i);
  537. switch (operator) {
  538. case '&':
  539. if (s.charAt(i + 1) == '&') {
  540. operator = 'a';
  541. i++;
  542. }
  543. break;
  544. case '|':
  545. if (s.charAt(i + 1) == '|') {
  546. operator = 'o';
  547. i++;
  548. }
  549. break;
  550. case '=':
  551. if (s.charAt(i + 1) == '=') {
  552. i++;
  553. operator = 'e';
  554. }
  555. break;
  556. case '<':
  557. if (s.charAt(i + 1) == '=') {
  558. i++;
  559. operator = 'l';
  560. } else if (s.charAt(i + 1) == '<') {
  561. i++;
  562. operator = 'y';
  563. }
  564. break;
  565. case '>':
  566. if (s.charAt(i + 1) == '=') {
  567. i++;
  568. operator = 'g';
  569. } else if (s.charAt(i + 1) == '>') {
  570. i++;
  571. operator = 'x';
  572. }
  573. break;
  574. case '!':
  575. if (s.charAt(i + 1) == '=') {
  576. i++;
  577. operator = 'n';
  578. }
  579. break;
  580. default:
  581. ;
  582. }
  583. // get the right term
  584. sRight = s.substring(i + 1);
  585. if (operator == '.') {
  586. // function call
  587. Object[] methodCallParts = getMethodCallParts(sRight);
  588. if (methodCallParts.length == 3) {
  589. rightTree = Parse((String) methodCallParts[2]);
  590. } else {
  591. rightTree = null;
  592. }
  593. String method = (String) methodCallParts[0];
  594. Iterator<String> methods = getMethods(method).iterator();
  595. while (methods.hasNext()) {
  596. leftTree = new ADELAParseTree(leftTree, methods.next());
  597. }
  598. if (rightTree != null) {
  599. return new ADELAParseTree(leftTree, rightTree,
  600. (Character) methodCallParts[1]);
  601. }
  602. return leftTree;
  603. } else {
  604. // parse it
  605. rightTree = Parse(sRight);
  606. return new ADELAParseTree(leftTree, rightTree, operator);
  607. }
  608. }
  609. return leftTree;
  610. }
  611. private static ArrayList<String> getMethods(String s) {
  612. char elem;
  613. int i;
  614. int iLen;
  615. int iBrackets;
  616. Boolean bFound;
  617. ArrayList<String> methods = new ArrayList<String>();
  618. if (s == null) {
  619. return null;
  620. }
  621. if (s.length() == 0) {
  622. return null;
  623. }
  624. bFound = true;
  625. while (bFound) {
  626. s = s.trim();
  627. iLen = s.length();
  628. /*
  629. * Find the first operator that does not reside within brackets
  630. */
  631. bFound = false;
  632. iBrackets = 0;
  633. for (i = 0; i < iLen; i++) {
  634. elem = s.charAt(i);
  635. switch (elem) {
  636. case '.':
  637. if (iBrackets == 0) {
  638. methods.add(s.substring(0, i));
  639. s = s.substring(i + 1);
  640. bFound = true;
  641. }
  642. break;
  643. case '(':
  644. iBrackets++;
  645. break;
  646. case ')':
  647. iBrackets--;
  648. break;
  649. }
  650. if (bFound) {
  651. break;
  652. }
  653. }
  654. }
  655. s = s.trim();
  656. if (s.length() != 0) {
  657. methods.add(s);
  658. }
  659. return methods;
  660. }
  661. private static Object[] getMethodCallParts(String s) {
  662. char elem;
  663. char operator;
  664. int i;
  665. int iLen;
  666. int iBrackets;
  667. Boolean bFound;
  668. if (s == null) {
  669. return null;
  670. }
  671. if (s.length() == 0) {
  672. return null;
  673. }
  674. s = s.trim();
  675. iLen = s.length();
  676. /*
  677. * Find the first operator that does not reside within brackets
  678. */
  679. bFound = false;
  680. iBrackets = 0;
  681. for (i = 0; i < iLen; i++) {
  682. elem = s.charAt(i);
  683. switch (elem) {
  684. case '*':
  685. case '/':
  686. case '+':
  687. case '-':
  688. case '^':
  689. case '<':
  690. case '>':
  691. case '&':
  692. case '|':
  693. case '=':
  694. case ':':
  695. case '!':
  696. if (iBrackets == 0) {
  697. bFound = true;
  698. }
  699. break;
  700. case '(':
  701. iBrackets++;
  702. break;
  703. case ')':
  704. iBrackets--;
  705. break;
  706. }
  707. if (bFound)
  708. break;
  709. }
  710. /*
  711. * Equal number of opening and closing brackets!?
  712. */
  713. assert (iBrackets == 0);
  714. if (bFound) {
  715. Object[] res = new Object[3];
  716. res[0] = s.substring(0, i);
  717. operator = s.charAt(i);
  718. if (operator == '>') {
  719. if (s.charAt(i + 1) == '=') {
  720. operator = 'g';
  721. i++;
  722. }
  723. }
  724. if (operator == '<') {
  725. if (s.charAt(i + 1) == '=') {
  726. operator = 'l';
  727. i++;
  728. }
  729. }
  730. if (operator == '=') {
  731. if (s.charAt(i + 1) == '=') {
  732. operator = 'e';
  733. i++;
  734. }
  735. }
  736. if (operator == '!') {
  737. if (s.charAt(i + 1) == '=') {
  738. operator = 'n';
  739. i++;
  740. }
  741. }
  742. if (operator == '&') {
  743. if (s.charAt(i + 1) == '&') {
  744. operator = 'a';
  745. i++;
  746. }
  747. }
  748. if (operator == '|') {
  749. if (s.charAt(i + 1) == '|') {
  750. operator = 'o';
  751. i++;
  752. }
  753. }
  754. res[1] = Character.valueOf(operator);
  755. res[2] = s.substring(i + 1);
  756. return res;
  757. } else {
  758. Object[] res = new Object[1];
  759. res[0] = s;
  760. return res;
  761. }
  762. }
  763. /**
  764. * Evaulate a function string
  765. *
  766. * @param s
  767. * String to evaluate
  768. * @param locals
  769. * Local variables
  770. * @param negate
  771. * negate value?
  772. * @return Evaluation result
  773. * @throws ADELASyntaxException
  774. * @throws FunctionNotFoundException
  775. * @throws WrongParameterCountException
  776. */
  777. private static ADELAParseTree PreEvaluate(String s, boolean negate)
  778. throws ADELASyntaxException {
  779. int iPos;
  780. char cAT;
  781. String sFuncName;
  782. Vector<String> sParams;
  783. Iterator<String> iParams;
  784. ADELAParseTree[] vParams;
  785. // are we zero-length?
  786. if (s.length() == 0) {
  787. // return null
  788. return null;
  789. }
  790. /*
  791. * Determine the type of term by looking at the very first character
  792. */
  793. cAT = s.charAt(0);
  794. /*
  795. * Are we a bracket? Find the last bracket, then strip them and parse
  796. * the rest
  797. */
  798. if (cAT == '(') {
  799. iPos = s.lastIndexOf(')');
  800. assert (iPos != -1);
  801. return Parse(s.substring(1, iPos));
  802. }
  803. /*
  804. * Are we a string? Return a string class
  805. */
  806. else if (cAT == '"') {
  807. iPos = s.lastIndexOf('"');
  808. assert (iPos != -1);
  809. return new ADELAParseTree(s.substring(1, iPos), false);
  810. }
  811. /*
  812. * Are we a number?
  813. */
  814. else if ((cAT >= '0') && (cAT <= '9')) {
  815. /*
  816. * Int or Double? The '.' says it all...
  817. */
  818. if (s.indexOf('.') == -1) {
  819. String trimmedS = s.trim();
  820. if (trimmedS.endsWith("L")) {
  821. if (!negate) {
  822. return new ADELAParseTree(Long.parseLong(trimmedS
  823. .substring(0, trimmedS.length() - 1)));
  824. } else {
  825. return new ADELAParseTree(Long.valueOf(0 - Long
  826. .parseLong(trimmedS.substring(0, trimmedS
  827. .length() - 1))));
  828. }
  829. } else {
  830. if (!negate) {
  831. return new ADELAParseTree(Integer.parseInt(trimmedS
  832. .trim()));
  833. } else {
  834. return new ADELAParseTree(Integer.valueOf(0 - Integer
  835. .parseInt(trimmedS.trim())));
  836. }
  837. }
  838. } else {
  839. if (!negate) {
  840. return new ADELAParseTree(Double.parseDouble(s.trim()));
  841. } else {
  842. return new ADELAParseTree(Double.valueOf(0 - Double
  843. .parseDouble(s.trim())));
  844. }
  845. }
  846. }
  847. /*
  848. * We're neither. We must be a function or a variable
  849. */
  850. else {
  851. iPos = s.indexOf('(');
  852. sFuncName = s;
  853. /*
  854. * function?
  855. */
  856. if (iPos != -1) {
  857. /*
  858. * yes, collect parameters, then jump into the callback
  859. * interface
  860. */
  861. sFuncName = s.substring(0, iPos);
  862. s = s.substring(iPos);
  863. iPos = s.lastIndexOf(')');
  864. if (iPos == -1) {
  865. throw new ADELASyntaxException("Invalid function call: "
  866. + s);
  867. }
  868. // sParams = s.substring(1, iPos).split(",");
  869. sParams = GetParams(s.substring(1, iPos));
  870. iParams = sParams.iterator();
  871. vParams = new ADELAParseTree[sParams.size()];
  872. for (int i = 0; i < vParams.length; i++) {
  873. vParams[i] = Parse(iParams.next());
  874. }
  875. return new ADELAParseTree(sFuncName, vParams);
  876. // return CallFunction(sFuncName, locals, vParams);
  877. } else {
  878. /*
  879. * Variable, get our value
  880. */
  881. // if (!mVariables.containsKey(sFuncName.trim()))
  882. String sVarName = sFuncName.trim();
  883. return new ADELAParseTree(sVarName, true);
  884. }
  885. }
  886. }
  887. /**
  888. * Get function call parameters
  889. *
  890. * @param s
  891. * parameter string, params must be separated by commas.
  892. * @return param string array
  893. */
  894. public static Vector<String> GetParams(String s) {
  895. int i;
  896. boolean bInString;
  897. int iBR;
  898. boolean bFound;
  899. Vector<String> sParams;
  900. sParams = new Vector<String>();
  901. // iterate linewise
  902. while (s.length() != 0) {
  903. bInString = false;
  904. iBR = 0;
  905. bFound = false;
  906. for (i = 0; i < s.length(); i++) {
  907. switch (s.charAt(i)) {
  908. case '"':
  909. bInString = !bInString;
  910. break;
  911. case '(':
  912. case '{':
  913. iBR++;
  914. break;
  915. case ')':
  916. case '}':
  917. iBR--;
  918. break;
  919. case ',':
  920. if ((!bInString) && (iBR == 0)) {
  921. sParams.add(s.substring(0, i));
  922. s = s.substring(i + 1);
  923. bFound = true;
  924. }
  925. break;
  926. default:
  927. break;
  928. }
  929. if (bFound)
  930. break;
  931. }
  932. if (!bFound) {
  933. sParams.add(s);
  934. s = "";
  935. }
  936. }
  937. // return the result
  938. return sParams;
  939. }
  940. public void compile(GOVMWriter gw, StatementResolver sr,
  941. PrintStream logStream) throws ADELACompilerException {
  942. if (prng.nextBoolean()) {
  943. gw.writeOpcode(Opcode.NOP);
  944. }
  945. switch (this.valueType) {
  946. case floatValue:
  947. break;
  948. case functioncall:
  949. if (this.leftTree == null) {
  950. // syscall
  951. if ("putc".equals(this.functionToCall)) {
  952. this.functionParameters[0].compile(gw, sr, logStream);
  953. gw.writeOpcode(Opcode.LI);
  954. gw.writeShort((short) 1);
  955. gw.writeOpcode(Opcode.SYSCALL);
  956. gw.writeOpcode(Opcode.POP);
  957. gw.writeOpcode(Opcode.POP);
  958. } else if ("open".equals(this.functionToCall)) {
  959. this.functionParameters[0].compile(gw, sr, logStream);
  960. this.functionParameters[1].compile(gw, sr, logStream);
  961. gw.writeOpcode(Opcode.LI);
  962. gw.writeShort((short) 5);
  963. gw.writeOpcode(Opcode.SYSCALL);
  964. } else if ("close".equals(this.functionToCall)) {
  965. this.functionParameters[0].compile(gw, sr, logStream);
  966. gw.writeOpcode(Opcode.LI);
  967. gw.writeShort((short) 6);
  968. gw.writeOpcode(Opcode.SYSCALL);
  969. } else if ("fputc".equals(this.functionToCall)) {
  970. this.functionParameters[0].compile(gw, sr, logStream);
  971. this.functionParameters[1].compile(gw, sr, logStream);
  972. gw.writeOpcode(Opcode.LI);
  973. gw.writeShort((short) 8);
  974. gw.writeOpcode(Opcode.SYSCALL);
  975. } else if ("fgetc".equals(this.functionToCall)) {
  976. this.functionParameters[0].compile(gw, sr, logStream);
  977. gw.writeOpcode(Opcode.LI);
  978. gw.writeShort((short) 7);
  979. gw.writeOpcode(Opcode.SYSCALL);
  980. } else if ("halt".equals(this.functionToCall)) {
  981. gw.writeOpcode(Opcode.LI);
  982. gw.writeShort((short) 0);
  983. gw.writeOpcode(Opcode.SYSCALL);
  984. } else if ("getc".equals(this.functionToCall)) {
  985. gw.writeOpcode(Opcode.LI);
  986. gw.writeShort((short) 2);
  987. gw.writeOpcode(Opcode.SYSCALL);
  988. gw.writeOpcode(Opcode.ROT);
  989. gw.writeOpcode(Opcode.POP);
  990. } else if ("info".equals(this.functionToCall)) {
  991. gw.writeOpcode(Opcode.LI);
  992. gw.writeShort((short) 3);
  993. gw.writeOpcode(Opcode.SYSCALL);
  994. gw.writeOpcode(Opcode.POP);
  995. } else if ("peekw".equals(this.functionToCall)) {
  996. this.functionParameters[0].compile(gw, sr, logStream);
  997. gw.writeOpcode(Opcode.LW);
  998. gw.writeOpcode(Opcode.ROT);
  999. gw.writeOpcode(Opcode.POP);
  1000. } else if ("peekb".equals(this.functionToCall)) {
  1001. this.functionParameters[0].compile(gw, sr, logStream);
  1002. gw.writeOpcode(Opcode.LB);
  1003. gw.writeOpcode(Opcode.ROT);
  1004. gw.writeOpcode(Opcode.POP);
  1005. } else if ("pokew".equals(this.functionToCall)) {
  1006. this.functionParameters[0].compile(gw, sr, logStream);
  1007. this.functionParameters[1].compile(gw, sr, logStream);
  1008. gw.writeOpcode(Opcode.SW);
  1009. gw.writeOpcode(Opcode.POP);
  1010. gw.writeOpcode(Opcode.POP);
  1011. } else if ("pokeb".equals(this.functionToCall)) {
  1012. this.functionParameters[0].compile(gw, sr, logStream);
  1013. this.functionParameters[1].compile(gw, sr, logStream);
  1014. gw.writeOpcode(Opcode.SB);
  1015. gw.writeOpcode(Opcode.POP);
  1016. gw.writeOpcode(Opcode.POP);
  1017. } else if ("JMPABSOLUTE".equals(this.functionToCall)) {
  1018. logStream
  1019. .println("WARNING: using JMPABSOLUTE, which is undocumented.");
  1020. this.functionParameters[0].compile(gw, sr, logStream);
  1021. gw.writeOpcode(Opcode.JMP);
  1022. } else if ("CALLABSOLUTE".equals(this.functionToCall)) {
  1023. logStream
  1024. .println("WARNING: using CALLABSOLUTE, which is undocumented.");
  1025. this.functionParameters[0].compile(gw, sr, logStream);
  1026. gw.writeOpcode(Opcode.CALL);
  1027. } else if ("POKES".equals(this.functionToCall)) {
  1028. logStream
  1029. .println("WARNING: using POKES, which is undocumented.");
  1030. this.functionParameters[0].compile(gw, sr, logStream);
  1031. this.functionParameters[1].compile(gw, sr, logStream);
  1032. gw.writeOpcode(Opcode.SWS);
  1033. } else if ("POP".equals(this.functionToCall)) {
  1034. logStream
  1035. .println("WARNING: using POP, which is undocumented.");
  1036. gw.writeOpcode(Opcode.POP);
  1037. } else {
  1038. for (ADELAParseTree apt : this.functionParameters) {
  1039. apt.compile(gw, sr, logStream);
  1040. }
  1041. gw.setGoto("__FUNCTION__" + this.functionToCall,
  1042. Opcode.CALL);
  1043. // Save retval
  1044. gw.writeOpcode(Opcode.MOVA);
  1045. // Remove parameters from stack
  1046. for (int i = 0; i < this.functionParameters.length; i++) {
  1047. gw.writeOpcode(Opcode.POP);
  1048. }
  1049. // Push retval back on the stack
  1050. gw.writeOpcode(Opcode.AMOV);
  1051. }
  1052. }
  1053. break;
  1054. case intValue:
  1055. gw.writeOpcode(Opcode.LI);
  1056. gw.writeShort((short) this.intValue);
  1057. break;
  1058. case longValue:
  1059. break;
  1060. case operation:
  1061. this.leftTree.compile(gw, sr, logStream);
  1062. this.rightTree.compile(gw, sr, logStream);
  1063. switch (this.operator) {
  1064. case '+':
  1065. gw.writeOpcode(Opcode.ADD);
  1066. break;
  1067. case '-':
  1068. gw.writeOpcode(Opcode.SUB);
  1069. break;
  1070. case '=': {
  1071. String[] varParts = leftTree.stringValue.split("[]\\[]");
  1072. String varName = varParts[0];
  1073. if (sr.globorloc(varName) < 0) {
  1074. gw.writeOpcode(Opcode.SW);
  1075. } else {
  1076. gw.writeOpcode(Opcode.ROT);
  1077. gw.writeOpcode(Opcode.FMOV);
  1078. gw.writeOpcode(Opcode.ADD);
  1079. gw.writeOpcode(Opcode.ROT);
  1080. gw.writeOpcode(Opcode.SWS);
  1081. }
  1082. gw.writeOpcode(Opcode.POP);
  1083. gw.writeOpcode(Opcode.POP);
  1084. }
  1085. break;
  1086. case 'e':
  1087. gw.writeOpcode(Opcode.EQU);
  1088. break;
  1089. case 'n':
  1090. gw.writeOpcode(Opcode.EQU);
  1091. gw.writeOpcode(Opcode.NOT);
  1092. break;
  1093. case 'l':
  1094. gw.writeOpcode(Opcode.LOE);
  1095. break;
  1096. case 'g':
  1097. gw.writeOpcode(Opcode.GOE);
  1098. break;
  1099. case '<':
  1100. gw.writeOpcode(Opcode.LT);
  1101. break;
  1102. case '^':
  1103. gw.writeOpcode(Opcode.XOR);
  1104. break;
  1105. case '>':
  1106. gw.writeOpcode(Opcode.GT);
  1107. break;
  1108. case '*':
  1109. gw.writeOpcode(Opcode.MUL);
  1110. break;
  1111. case '/':
  1112. gw.writeOpcode(Opcode.DIV);
  1113. break;
  1114. case 'y':
  1115. gw.writeOpcode(Opcode.SHL);
  1116. break;
  1117. case 'x':
  1118. gw.writeOpcode(Opcode.SHR);
  1119. break;
  1120. case '&':
  1121. gw.writeOpcode(Opcode.AND);
  1122. break;
  1123. case '|':
  1124. gw.writeOpcode(Opcode.OR);
  1125. break;
  1126. }
  1127. break;
  1128. case statement:
  1129. case variable:
  1130. /*
  1131. * A variable.
  1132. *
  1133. * Reserves or resolves the symbol on the (initialized) data
  1134. * segment. It emits a load instant opcode to push the address onto
  1135. * the stack. In theory, not all symbols have to point to the
  1136. * initialized part of the data segment, but this allows for simpler
  1137. * code :-) And, it's for a ctf service only, anyway
  1138. */
  1139. gw.writeOpcode(Opcode.LI);
  1140. String[] varParts = ((this.valueType == EValueType.statement) ? this.statement
  1141. : this.stringValue).split("[]\\[]");
  1142. String varName = varParts[0];
  1143. int addr = sr.globorloc(varName);
  1144. if (addr < 0) {
  1145. gw.writeShort((short) (-addr));
  1146. } else {
  1147. gw.writeShort((short) addr);
  1148. }
  1149. if (varParts.length > 1) {
  1150. ADELAParseTree valOffset;
  1151. try {
  1152. valOffset = ADELAParseTree.Parse(varParts[1]);
  1153. } catch (ADELASyntaxException e) {
  1154. throw new ADELACompilerException(e);/* ugly */
  1155. }
  1156. valOffset.compile(gw, sr, logStream);
  1157. gw.writeOpcode(Opcode.ADD);
  1158. }
  1159. if (this.valueType == EValueType.statement) {
  1160. /*
  1161. * A statement. Do an LW here. The alternative is to do a SW
  1162. * later.
  1163. */
  1164. if (addr < 0) {
  1165. gw.writeOpcode(Opcode.LW);
  1166. } else {
  1167. // PUSH BP
  1168. gw.writeOpcode(Opcode.FMOV);
  1169. gw.writeOpcode(Opcode.ADD);
  1170. gw.writeOpcode(Opcode.LWS);
  1171. }
  1172. gw.writeOpcode(Opcode.ROT);
  1173. gw.writeOpcode(Opcode.POP);
  1174. }
  1175. break;
  1176. case stringValue:
  1177. byte[] bytes;
  1178. try {
  1179. bytes = (this.stringValue + "\0").getBytes("utf-8");
  1180. } catch (UnsupportedEncodingException e) {
  1181. throw new ADELACompilerException(e);
  1182. }
  1183. if (bytes.length > 65530) {
  1184. throw new ADELACompilerException(
  1185. "WTF!? Who needs strings of that length? No one will ever need string constants longer than 65530 bytes!");
  1186. }
  1187. int addrpos = sr.reserveBytes(null, bytes);
  1188. logStream.println("String constant \"" + this.stringValue + "\" ("
  1189. + bytes.length + " bytes) at " + addrpos);
  1190. gw.writeOpcode(Opcode.LI);
  1191. gw.writeShort((short) addrpos);
  1192. break;
  1193. }
  1194. }
  1195. /*
  1196. * (non-Javadoc)
  1197. *
  1198. * @see java.lang.Object#toString()
  1199. */
  1200. @Override
  1201. public String toString() {
  1202. switch (this.valueType) {
  1203. case floatValue:
  1204. return Double.valueOf(this.doubleValue).toString();
  1205. case intValue:
  1206. return Integer.valueOf(this.intValue).toString();
  1207. case longValue:
  1208. return Long.valueOf(this.longValue).toString();
  1209. case functioncall:
  1210. String parameters = "";
  1211. for (int i = 0; i < this.functionParameters.length; i++) {
  1212. if (parameters.length() != 0) {
  1213. parameters = parameters + ", ";
  1214. }
  1215. parameters = parameters + this.functionParameters[i].toString();
  1216. }
  1217. return this.functionToCall + "(" + parameters + ")";
  1218. case operation:
  1219. if (this.functionToCall == null) {
  1220. return "(" + this.leftTree.toString()
  1221. + Helpers.opToString(this.operator)
  1222. + this.rightTree.toString() + ")";
  1223. }
  1224. if (this.rightTree != null) {
  1225. return "" + this.leftTree.toString()
  1226. + Helpers.opToString(this.operator) + this.stringValue
  1227. + this.rightTree.toString() + "";
  1228. } else {
  1229. String params = "(";
  1230. for (int i = 0; i < this.functionParameters.length; i++) {
  1231. if (params.length() > 1) {
  1232. params = params + "; ";
  1233. }
  1234. params = params + this.functionParameters[i].toString();
  1235. }
  1236. params = params + ")";
  1237. return "" + this.leftTree.toString()
  1238. + Helpers.opToString(this.operator)
  1239. + this.functionToCall + params + "";
  1240. }
  1241. case statement:
  1242. return this.statement;
  1243. case stringValue:
  1244. return "\"" + this.stringValue + "\"";
  1245. case variable:
  1246. return this.stringValue + ":";
  1247. }
  1248. return null;
  1249. }
  1250. /**
  1251. * Like toString, but tries to draw an ASCII-art tree ;-)
  1252. *
  1253. * @return ascii art tree
  1254. */
  1255. public String toStringNonFlat() {
  1256. String leftPart = null, rightPart = null;
  1257. String mePart;
  1258. switch (this.valueType) {
  1259. case floatValue:
  1260. mePart = Double.valueOf(this.doubleValue).toString();
  1261. break;
  1262. case intValue:
  1263. mePart = Integer.valueOf(this.intValue).toString();
  1264. break;
  1265. case longValue:
  1266. mePart = Long.valueOf(this.longValue).toString();
  1267. break;
  1268. case functioncall:
  1269. String parameters = "";
  1270. for (int i = 0; i < this.functionParameters.length; i++) {
  1271. if (parameters.length() != 0) {
  1272. parameters = Helpers.joinTwo(parameters, ", ");
  1273. }
  1274. parameters = Helpers.joinTwo(parameters,
  1275. this.functionParameters[i].toStringNonFlat());
  1276. }
  1277. mePart = Helpers.joinTwo(Helpers.joinTwo(this.functionToCall + "(",
  1278. parameters), ")");
  1279. break;
  1280. case operation:
  1281. if (this.functionToCall == null) {
  1282. mePart = Helpers.opToString(this.operator);
  1283. leftPart = "\n" + this.leftTree.toStringNonFlat();
  1284. rightPart = "\n" + this.rightTree.toStringNonFlat();
  1285. break;
  1286. }
  1287. if (this.rightTree != null) {
  1288. leftPart = "\n" + this.leftTree.toStringNonFlat();
  1289. mePart = this.operator + this.stringValue;
  1290. rightPart = "\n" + this.rightTree.toStringNonFlat();
  1291. break;
  1292. } else {
  1293. String params = "(";
  1294. for (int i = 0; i < this.functionParameters.length; i++) {
  1295. if (params.length() > 1) {
  1296. params = Helpers.joinTwo(params, ", ");
  1297. }
  1298. params = Helpers.joinTwo(params, this.functionParameters[i]
  1299. .toStringNonFlat());
  1300. }
  1301. leftPart = "\n" + this.leftTree.toStringNonFlat();
  1302. mePart = ".";
  1303. rightPart = Helpers.joinTwo(Helpers.joinTwo(
  1304. this.functionToCall, params), ")");
  1305. break;
  1306. }
  1307. case statement:
  1308. mePart = this.statement;
  1309. break;
  1310. case stringValue:
  1311. mePart = "\"" + this.stringValue + "\"";
  1312. break;
  1313. case variable:
  1314. mePart = this.stringValue;
  1315. break;
  1316. default:
  1317. mePart = "";
  1318. }
  1319. return Helpers.makeTree(leftPart, mePart, rightPart);
  1320. }
  1321. public boolean isReturnStatement() {
  1322. return returnStatement;
  1323. }
  1324. public void saveTree(DataOutput out) throws IOException {
  1325. out.writeInt(this.valueType.ordinal());
  1326. out.writeBoolean(this.returnStatement);
  1327. switch (this.valueType) {
  1328. case floatValue:
  1329. out.writeDouble(this.doubleValue);
  1330. break;
  1331. case intValue:
  1332. out.writeInt(this.intValue);
  1333. break;
  1334. case longValue:
  1335. out.writeLong(this.longValue);
  1336. break;
  1337. case stringValue:
  1338. Helpers.writeString(out, this.stringValue);
  1339. break;
  1340. case functioncall:
  1341. Helpers.writeString(out, this.functionToCall);
  1342. out.writeInt(functionParameters.length);
  1343. for (int i = 0; i < functionParameters.length; i++) {
  1344. functionParameters[i].saveTree(out);
  1345. }
  1346. break;
  1347. case operation:
  1348. leftTree.saveTree(out);
  1349. out.writeChar(this.operator);
  1350. if (this.operator == '.') {
  1351. // method calls are special
  1352. Helpers.writeString(out, this.functionToCall);
  1353. out.writeInt(functionParameters.length);
  1354. for (int i = 0; i < functionParameters.length; i++) {
  1355. functionParameters[i].saveTree(out);
  1356. }
  1357. } else {
  1358. rightTree.saveTree(out);
  1359. }
  1360. break;
  1361. case statement:
  1362. Helpers.writeString(out, this.statement);
  1363. break;
  1364. }
  1365. }
  1366. public static ADELAParseTree loadTree(DataInput in) throws IOException {
  1367. ADELAParseTree tree = new ADELAParseTree();
  1368. loadTree(in, tree);
  1369. return tree;
  1370. }
  1371. private static void loadTree(DataInput in, ADELAParseTree tree)
  1372. throws IOException {
  1373. tree.valueType = EValueType.values()[in.readInt()];
  1374. tree.returnStatement = in.readBoolean();
  1375. switch (tree.valueType) {
  1376. case floatValue:
  1377. tree.doubleValue = in.readDouble();
  1378. break;
  1379. case intValue:
  1380. tree.intValue = in.readInt();
  1381. break;
  1382. case longValue:
  1383. tree.longValue = in.readLong();
  1384. break;
  1385. case stringValue:
  1386. tree.stringValue = Helpers.readString(in);
  1387. break;
  1388. case functioncall:
  1389. tree.functionToCall = Helpers.readString(in);
  1390. tree.functionParameters = new ADELAParseTree[in.readInt()];
  1391. for (int i = 0; i < tree.functionParameters.length; i++) {
  1392. tree.functionParameters[i] = loadTree(in);
  1393. }
  1394. break;
  1395. case operation:
  1396. tree.leftTree = loadTree(in);
  1397. tree.operator = in.readChar();
  1398. if (tree.operator == '.') {
  1399. // method calls are special
  1400. tree.functionToCall = Helpers.readString(in);
  1401. tree.functionParameters = new ADELAParseTree[in.readInt()];
  1402. for (int i = 0; i < tree.functionParameters.length; i++) {
  1403. tree.functionParameters[i] = loadTree(in);
  1404. }
  1405. } else {
  1406. tree.rightTree = loadTree(in);
  1407. }
  1408. break;
  1409. case statement:
  1410. tree.statement = Helpers.readString(in);
  1411. break;
  1412. }
  1413. }
  1414. private void handleFunction(String s) throws ADELASyntaxException {
  1415. int iPos;
  1416. iPos = s.indexOf('(');
  1417. /*
  1418. * function?
  1419. */
  1420. if (iPos != -1) {
  1421. /*
  1422. * yes, collect parameters, then jump into the callback interface
  1423. */
  1424. this.functionToCall = s.substring(0, iPos);
  1425. s = s.substring(iPos);
  1426. iPos = s.lastIndexOf(')');
  1427. if (iPos == -1) {
  1428. throw new ADELASyntaxException("Invalid function call: " + s);
  1429. }
  1430. // sParams = s.substring(1, iPos).split(",");
  1431. Vector<String> sParams = GetParams(s.substring(1, iPos));
  1432. Iterator<String> iParams = sParams.iterator();
  1433. this.functionParameters = new ADELAParseTree[sParams.size()];
  1434. for (int i = 0; i < this.functionParameters.length; i++) {
  1435. String nextParameter = iParams.next();
  1436. this.functionParameters[i] = Parse(nextParameter);
  1437. }
  1438. } else {
  1439. this.functionParameters = new ADELAParseTree[0];
  1440. this.functionToCall = "get" + s;
  1441. }
  1442. }
  1443. public void readExternal(ObjectInput in) throws IOException,
  1444. ClassNotFoundException {
  1445. loadTree(in, this);
  1446. }
  1447. public void writeExternal(ObjectOutput out) throws IOException {
  1448. saveTree(out);
  1449. }
  1450. }