You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

239 lines
6.4 KiB

  1. package parser;
  2. import expression.*;
  3. import expression.Int;
  4. import program.*;
  5. import java.util.ArrayList;
  6. import java.util.List;
  7. public class Parser {
  8. int position = 0;
  9. String input;
  10. public Parser(String input) {
  11. this.input = input;
  12. }
  13. public Program parse() {
  14. Program program = program();
  15. whitespace();
  16. if (position < input.length()) {
  17. throw new SyntaxException("End of input", position);
  18. }
  19. return program;
  20. }
  21. Program program() {
  22. Program firstStatement = statement();
  23. List<Program> moreStatements = new ArrayList<>();
  24. while (test(";")) {
  25. consume(";");
  26. Program statement = statement();
  27. moreStatements.add(statement);
  28. }
  29. Program program = firstStatement;
  30. for (Program statement: moreStatements) {
  31. program = new Composition(program, statement);
  32. }
  33. return program;
  34. }
  35. Program statement() {
  36. int start = position;
  37. Program statement;
  38. try {
  39. statement = assignment();
  40. } catch (SyntaxException se) {
  41. position = start;
  42. try {
  43. statement = conditional();
  44. } catch (SyntaxException se2) {
  45. position = start;
  46. statement = loop();
  47. }
  48. }
  49. return statement;
  50. }
  51. Program loop() {
  52. consume("while");
  53. consume("(");
  54. Expression condition = expression();
  55. consume(")");
  56. consume("{");
  57. Program program = program();
  58. consume("}");
  59. return new Loop(condition, program);
  60. }
  61. Program conditional() {
  62. consume("if");
  63. consume("(");
  64. Expression condition = expression();
  65. consume(")");
  66. consume("then");
  67. consume("{");
  68. Program thenCase = program();
  69. consume("}");
  70. consume("else");
  71. consume("{");
  72. Program elseCase = program();
  73. consume("}");
  74. return new Conditional(condition, thenCase, elseCase);
  75. }
  76. Program assignment() {
  77. Identifier identifier = identifier();
  78. consume(":=");
  79. Expression expression = expression();
  80. return new Assignment(identifier, expression);
  81. }
  82. private static class OperatorWithExpression {
  83. private final Operator operator;
  84. private final Expression expression;
  85. OperatorWithExpression(Operator operator, Expression expression) {
  86. this.operator = operator;
  87. this.expression = expression;
  88. }
  89. }
  90. private enum Operator { PLUS, MINUS }
  91. private boolean testOperator() {
  92. int start = position;
  93. boolean result;
  94. try {
  95. operator();
  96. result = true;
  97. } catch (SyntaxException se) {
  98. result = false;
  99. }
  100. position = start;
  101. return result;
  102. }
  103. private Operator operator() {
  104. whitespace();
  105. char next = (char) 0;
  106. if (position < input.length()) {
  107. next = input.charAt(position);
  108. position += 1;
  109. }
  110. if (next == '+') {
  111. return Operator.PLUS;
  112. } else if (next == '-') {
  113. return Operator.MINUS;
  114. } else {
  115. throw new SyntaxException("Operator", position);
  116. }
  117. }
  118. Expression expression() {
  119. Expression firstAtom = atom();
  120. List<OperatorWithExpression> moreAtoms = new ArrayList<>();
  121. while(testOperator()) {
  122. Operator operator = operator();
  123. Expression expression = atom();
  124. moreAtoms.add(new OperatorWithExpression(operator, expression));
  125. }
  126. Expression expression = firstAtom;
  127. for (OperatorWithExpression atom: moreAtoms) {
  128. switch (atom.operator) {
  129. case PLUS:
  130. expression = new Addition(expression, atom.expression);
  131. break;
  132. case MINUS:
  133. expression = new Subtraction(expression, atom.expression);
  134. break;
  135. }
  136. }
  137. return expression;
  138. }
  139. Expression atom() {
  140. int start = position;
  141. Expression result;
  142. try {
  143. consume("(");
  144. result = expression();
  145. consume(")");
  146. } catch (SyntaxException se) {
  147. position = start;
  148. try {
  149. result = integer();
  150. } catch (SyntaxException se2) {
  151. result = identifier();
  152. }
  153. }
  154. return result;
  155. }
  156. private boolean isLowerLetter(char ch) {
  157. return ch >= 'a' && ch <= 'z';
  158. }
  159. Expression integer() {
  160. whitespace();
  161. int start = position;
  162. boolean minus = position < input.length() && input.charAt(position) == '-';
  163. if (minus) {
  164. position += 1;
  165. }
  166. boolean digitsFound = false;
  167. while (position < input.length() && Character.isDigit(input.charAt(position))) {
  168. position += 1;
  169. digitsFound = true;
  170. }
  171. if (digitsFound) {
  172. return new Int(Integer.parseInt(input.substring(start, position)));
  173. } else {
  174. throw new SyntaxException("Integer", position);
  175. }
  176. }
  177. Identifier identifier() {
  178. whitespace();
  179. int start = position;
  180. while (position < input.length() && isLowerLetter(input.charAt(position))) {
  181. position += 1;
  182. }
  183. if (position > start) {
  184. return new Identifier(input.substring(start, position));
  185. } else {
  186. throw new SyntaxException("Identifier", position);
  187. }
  188. }
  189. private void whitespace() {
  190. while(position < input.length() && Character.isWhitespace(input.charAt(position))) {
  191. position += 1;
  192. }
  193. }
  194. private void consume(String token) {
  195. whitespace();
  196. if (position + token.length() <= input.length() && input.substring(position, position + token.length()).equals(token)) {
  197. position += token.length();
  198. } else {
  199. throw new SyntaxException(token, position);
  200. }
  201. }
  202. private boolean test(String token) {
  203. int start = position;
  204. boolean success;
  205. try {
  206. consume(token);
  207. success = true;
  208. } catch (SyntaxException se) {
  209. success = false;
  210. }
  211. position = start;
  212. return success;
  213. }
  214. }