浏览代码

Optional -> SyntaxException

pull/1/head
Malte Schmitz 9 年前
父节点
当前提交
5a0820b9b5
共有 2 个文件被更改,包括 146 次插入177 次删除
  1. +133
    -138
      src/parser/Parser.java
  2. +13
    -39
      test/parser/ParserTest.java

+ 133
- 138
src/parser/Parser.java 查看文件

@@ -6,7 +6,6 @@ import program.*;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

public class Parser {

@@ -18,8 +17,7 @@ public class Parser {
}

public Program parse() {
Optional<Program> programOpt = program();
Program program = programOpt.orElseThrow(() -> new SyntaxException("Program", position));
Program program = program();
whitespace();
if (position < input.length()) {
throw new SyntaxException("End of input", position);
@@ -27,92 +25,73 @@ public class Parser {
return program;
}

Optional<Program> program() {
List<Program> statements = new ArrayList<>();
boolean run = true;
int start = position;
while (run) {
Optional<Program> statement = statement();
statement.ifPresent(stmt -> statements.add(stmt));
if (statement.isPresent()) {
start = position;
run = token(";");
} else {
position = start;
run = false;
}
Program program() {
Program firstStatement = statement();
List<Program> moreStatements = new ArrayList<>();
while (test(";")) {
consume(";");
Program statement = statement();
moreStatements.add(statement);
}
Optional<Program> program = Optional.empty();
for (Program statement: statements) {
if (!program.isPresent()) {
program = Optional.of(statement);
} else {
program = program.map(pgm -> new Composition(pgm, statement));
}
Program program = firstStatement;
for (Program statement: moreStatements) {
program = new Composition(program, statement);
}
return program;
}

Optional<Program> statement() {
Program statement() {
int start = position;
Optional<Program> result = assignment();
if (!result.isPresent()) {
Program statement;
try {
statement = assignment();
} catch (SyntaxException se) {
position = start;
result = conditional();
if (!result.isPresent()) {
try {
statement = conditional();
} catch (SyntaxException se2) {
position = start;
result = loop();
statement = loop();
}
}
return result;
return statement;
}

Optional<Program> loop() {
if (token("while") && token("(")) {
Optional<Expression> condition = expression();
return condition.flatMap(cond -> {
if (token(")") && token("{")) {
Optional<Program> program = program();
return program.filter(pgm -> token("}")).map(pgm -> new Loop(cond, pgm));
}
return Optional.empty();
});
}
return Optional.empty();
}

Optional<Program> conditional() {
if (token("if") && token("(")) {
Optional<Expression> condition = expression();
return condition.flatMap(cond -> {
if (token(")") && token("then") && token("{")) {
Optional<Program> thenCase = program();
return thenCase.flatMap(thenC -> {
if (token("}") && token("else") && token("{")) {
Optional<Program> elseCase = program();
return elseCase.filter(elseC -> token("}")).map(elseC -> new Conditional(cond, thenC, elseC));
}
return Optional.empty();
});
}
return Optional.empty();
});
}
return Optional.empty();
}

Optional<Program> assignment() {
Optional<Identifier> identifier = identifier();
return identifier.flatMap(id -> {
if (token(":=")) {
Optional<Expression> expression = expression();
return expression.map(exp -> new Assignment(id, exp));
}
return Optional.empty();
});
Program loop() {
consume("while");
consume("(");
Expression condition = expression();
consume(")");
consume("{");
Program program = program();
consume("}");
return new Loop(condition, program);
}

Program conditional() {
consume("if");
consume("(");
Expression condition = expression();
consume(")");
consume("then");
consume("{");
Program thenCase = program();
consume("}");
consume("else");
consume("{");
Program elseCase = program();
consume("}");
return new Conditional(condition, thenCase, elseCase);
}

static class OperatorWithExpression {
Program assignment() {
Identifier identifier = identifier();
consume(":=");
Expression expression = expression();
return new Assignment(identifier, expression);
}

private static class OperatorWithExpression {
private final Operator operator;
private final Expression expression;

@@ -122,79 +101,82 @@ public class Parser {
}
}

enum Operator {
PLUS, MINUS, NONE;

Expression toOperation(Expression leftHandSide, Expression rightHandSide) {
if (this == Operator.PLUS) {
return new Addition(leftHandSide, rightHandSide);
} else if (this == Operator.MINUS) {
return new Subtraction(leftHandSide, rightHandSide);
} else {
throw new RuntimeException("Operator invalid");
}
}
}
private enum Operator { PLUS, MINUS }

Optional<Expression> expression() {
List<OperatorWithExpression> atoms = new ArrayList<>();
Operator operator = Operator.PLUS;
private boolean testOperator() {
int start = position;
while (operator != Operator.NONE) {
Optional<Expression> atom = atom();
Operator op = operator;
atom.ifPresent(at -> atoms.add(new OperatorWithExpression(op, at)));
if (atom.isPresent()) {
start = position;
operator = operator();
} else {
operator = Operator.NONE;
position = start;
}
}
Optional<Expression> expression = Optional.empty();
for (OperatorWithExpression atom: atoms) {
if (!expression.isPresent()) {
expression = Optional.of(atom.expression);
} else {
expression = expression.map(expr -> atom.operator.toOperation(expr, atom.expression));
}
}
return expression;
boolean result;
try {
operator();
result = true;
} catch (SyntaxException se) {
result = false;
}
position = start;
return result;
}

Operator operator() {
if (token("+")) {
private Operator operator() {
whitespace();
char next = (char) 0;
if (position < input.length()) {
next = input.charAt(position);
position += 1;
}
if (next == '+') {
return Operator.PLUS;
} else if (token("-")) {
} else if (next == '-') {
return Operator.MINUS;
} else {
return Operator.NONE;
throw new SyntaxException("Operator", position);
}
}

Expression expression() {
Expression firstAtom = atom();
List<OperatorWithExpression> moreAtoms = new ArrayList<>();
while(testOperator()) {
Operator operator = operator();
Expression expression = atom();
moreAtoms.add(new OperatorWithExpression(operator, expression));
}
Expression expression = firstAtom;
for (OperatorWithExpression atom: moreAtoms) {
switch (atom.operator) {
case PLUS:
expression = new Addition(expression, atom.expression);
break;
case MINUS:
expression = new Subtraction(expression, atom.expression);
break;
}
}
return expression;
}

Optional<Expression> atom() {
Expression atom() {
int start = position;
Optional<Expression> result;
if (token("(")) {
Optional<Expression> expression = expression();
result = expression.filter(exp -> token(")"));
} else {
Expression result;
try {
consume("(");
result = expression();
consume(")");
} catch (SyntaxException se) {
position = start;
result = integer();
if (!result.isPresent()) {
position = start;
result = identifier().map(id -> id);
try {
result = integer();
} catch (SyntaxException se2) {
result = identifier();
}
}
return result;
}

boolean isLowerLetter(char ch) {
private boolean isLowerLetter(char ch) {
return ch >= 'a' && ch <= 'z';
}

Optional<Expression> integer() {
Expression integer() {
whitespace();
int start = position;
boolean minus = position < input.length() && input.charAt(position) == '-';
@@ -207,37 +189,50 @@ public class Parser {
digitsFound = true;
}
if (digitsFound) {
return Optional.of(new Int(Integer.parseInt(input.substring(start, position))));
return new Int(Integer.parseInt(input.substring(start, position)));
} else {
return Optional.empty();
throw new SyntaxException("Integer", position);
}
}

Optional<Identifier> identifier() {
Identifier identifier() {
whitespace();
int start = position;
while (position < input.length() && isLowerLetter(input.charAt(position))) {
position += 1;
}
if (position > start) {
Identifier identifier = new Identifier(input.substring(start, position));
return Optional.of(identifier);
return new Identifier(input.substring(start, position));
} else {
throw new SyntaxException("Identifier", position);
}
return Optional.empty();
}

void whitespace() {
private void whitespace() {
while(position < input.length() && Character.isWhitespace(input.charAt(position))) {
position += 1;
}
}

boolean token(String token) {
private void consume(String token) {
whitespace();
boolean success = position + token.length() <= input.length() && input.substring(position, position + token.length()).equals(token);
if (success) {
if (position + token.length() <= input.length() && input.substring(position, position + token.length()).equals(token)) {
position += token.length();
} else {
throw new SyntaxException(token, position);
}
}

private boolean test(String token) {
int start = position;
boolean success;
try {
consume(token);
success = true;
} catch (SyntaxException se) {
success = false;
}
position = start;
return success;
}
}

+ 13
- 39
test/parser/ParserTest.java 查看文件

@@ -1,7 +1,6 @@
package parser;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;

import org.junit.Test;
import expression.*;
@@ -35,43 +34,43 @@ public class ParserTest {
@Test
public void testProgram() {
Parser parser = new Parser(programCode);
assertEquals(Optional.of(program), parser.program());
assertEquals(program, parser.program());
}

@Test
public void testStatementAssignment() {
Parser parser = new Parser(assignmentCode);
assertEquals(Optional.of(assignment), parser.statement());
assertEquals(assignment, parser.statement());
}

@Test
public void testStatementConditional() {
Parser parser = new Parser(conditionalCode);
assertEquals(Optional.of(conditional), parser.statement());
assertEquals(conditional, parser.statement());
}

@Test
public void testStatementLoop() {
Parser parser = new Parser(loopCode);
assertEquals(Optional.of(loop), parser.statement());
assertEquals(loop, parser.statement());
}

@Test
public void testAssignment() {
Parser parser = new Parser(assignmentCode);
assertEquals(Optional.of(assignment), parser.assignment());
assertEquals(assignment, parser.assignment());
}

@Test
public void testConditional() {
Parser parser = new Parser(conditionalCode);
assertEquals(Optional.of(conditional), parser.conditional());
assertEquals(conditional, parser.conditional());
}

@Test
public void testLoop() {
Parser parser = new Parser(loopCode);
assertEquals(Optional.of(loop), parser.loop());
assertEquals(loop, parser.loop());
}

final String expressionCode = "a+b - (c - 56) + -47";
@@ -80,61 +79,36 @@ public class ParserTest {
@Test
public void testExpression() {
Parser parser = new Parser(expressionCode);
assertEquals(Optional.of(expression), parser.expression());
}

@Test
public void testOperatorMinus() {
Parser parser = new Parser("-");
assertEquals(Operator.MINUS, parser.operator());
}

@Test
public void testOperatorPlus() {
Parser parser = new Parser("+");
assertEquals(Operator.PLUS, parser.operator());
assertEquals(expression, parser.expression());
}

@Test
public void testAtomExpression() {
Parser parser = new Parser("(" + expressionCode + ")");
assertEquals(Optional.of(expression), parser.atom());
assertEquals(expression, parser.atom());
}

@Test
public void testAtomNumber() {
Parser parser = new Parser("37658");
assertEquals(Optional.of(new Int(37658)), parser.atom());
assertEquals(new Int(37658), parser.atom());
}

@Test
public void testAtomIdentifier() {
Parser parser = new Parser("egjfd");
assertEquals(Optional.of(new Identifier("egjfd")), parser.atom());
assertEquals(new Identifier("egjfd"), parser.atom());
}

@Test
public void testNumber() {
Parser parser = new Parser("37658");
assertEquals(Optional.of(new Int(37658)), parser.integer());
assertEquals(new Int(37658), parser.integer());
}

@Test
public void testIdentifier() {
Parser parser = new Parser("egjfd");
assertEquals(Optional.of(new Identifier("egjfd")), parser.identifier());
}

@Test
public void testWhitespace() {
Parser parser = new Parser(" \n\t x");
parser.whitespace();
assertEquals('x', parser.input.charAt(parser.position));
}

@Test
public void testToken() {
Parser parser = new Parser("gehjfwdk");
assertTrue(parser.token("gehjfwdk"));
assertEquals(new Identifier("egjfd"), parser.identifier());
}
}

正在加载...
取消
保存