From cf98f623b6eaa9324f38ff0f0e99e31945298e7a Mon Sep 17 00:00:00 2001 From: Victor Date: Sun, 7 Jun 2015 16:35:04 +0300 Subject: [PATCH] =?UTF-8?q?=D0=A3=D1=80=D0=BE=D0=BA=207.=20=D0=91=D0=BB?= =?UTF-8?q?=D0=BE=D0=BA=20=D0=BE=D0=BF=D0=B5=D1=80=D0=B0=D1=82=D0=BE=D1=80?= =?UTF-8?q?=D0=BE=D0=B2,=20=D1=86=D0=B8=D0=BA=D0=BB=D1=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- program.txt | 13 ++++- src/com/annimon/ownlang/Main.java | 10 ++-- src/com/annimon/ownlang/parser/Lexer.java | 7 ++- src/com/annimon/ownlang/parser/Parser.java | 47 +++++++++++++++++-- src/com/annimon/ownlang/parser/TokenType.java | 5 ++ .../ownlang/parser/ast/BlockStatement.java | 37 +++++++++++++++ .../ownlang/parser/ast/ForStatement.java | 32 +++++++++++++ .../ownlang/parser/ast/WhileStatement.java | 28 +++++++++++ 8 files changed, 166 insertions(+), 13 deletions(-) create mode 100644 src/com/annimon/ownlang/parser/ast/BlockStatement.java create mode 100644 src/com/annimon/ownlang/parser/ast/ForStatement.java create mode 100644 src/com/annimon/ownlang/parser/ast/WhileStatement.java diff --git a/program.txt b/program.txt index d637fe4..e8f8227 100644 --- a/program.txt +++ b/program.txt @@ -9,5 +9,16 @@ print "\n" if (1 <= 2) print "1 = 1" else print "1 != 1" print "\n" -if (40 < 50 && 50 > 60) print "true" +if (40 < 50 || 50 > 60) { + print "true1\n" + print "true2\n" + i = 0 + while (i < 10) { + print "i = " + i + "\n" + i = i + 1 + } + for i = 0, i < 10, i = i + 1 { + print "i = " + i + "\n" + } +} else print "false" \ No newline at end of file diff --git a/src/com/annimon/ownlang/Main.java b/src/com/annimon/ownlang/Main.java index b5758c2..d4989d3 100644 --- a/src/com/annimon/ownlang/Main.java +++ b/src/com/annimon/ownlang/Main.java @@ -22,12 +22,8 @@ public final class Main { System.out.println(token); } - final List statements = new Parser(tokens).parse(); - for (Statement statement : statements) { - System.out.println(statement); - } - for (Statement statement : statements) { - statement.execute(); - } + final Statement program = new Parser(tokens).parse(); + System.out.println(program.toString()); + program.execute(); } } diff --git a/src/com/annimon/ownlang/parser/Lexer.java b/src/com/annimon/ownlang/parser/Lexer.java index a7f94d8..e10dd30 100644 --- a/src/com/annimon/ownlang/parser/Lexer.java +++ b/src/com/annimon/ownlang/parser/Lexer.java @@ -11,7 +11,7 @@ import java.util.Map; */ public final class Lexer { - private static final String OPERATOR_CHARS = "+-*/()=<>!&|"; + private static final String OPERATOR_CHARS = "+-*/(){}=<>!&|,"; private static final Map OPERATORS; static { @@ -22,9 +22,12 @@ public final class Lexer { OPERATORS.put("/", TokenType.SLASH); OPERATORS.put("(", TokenType.LPAREN); OPERATORS.put(")", TokenType.RPAREN); + OPERATORS.put("{", TokenType.LBRACE); + OPERATORS.put("}", TokenType.RBRACE); OPERATORS.put("=", TokenType.EQ); OPERATORS.put("<", TokenType.LT); OPERATORS.put(">", TokenType.GT); + OPERATORS.put(",", TokenType.COMMA); OPERATORS.put("!", TokenType.EXCL); OPERATORS.put("&", TokenType.AMP); @@ -145,6 +148,8 @@ public final class Lexer { case "print": addToken(TokenType.PRINT); break; case "if": addToken(TokenType.IF); break; case "else": addToken(TokenType.ELSE); break; + case "while": addToken(TokenType.WHILE); break; + case "for": addToken(TokenType.FOR); break; default: addToken(TokenType.WORD, word); break; diff --git a/src/com/annimon/ownlang/parser/Parser.java b/src/com/annimon/ownlang/parser/Parser.java index 8b24c5a..53a9e97 100644 --- a/src/com/annimon/ownlang/parser/Parser.java +++ b/src/com/annimon/ownlang/parser/Parser.java @@ -3,13 +3,16 @@ package com.annimon.ownlang.parser; import com.annimon.ownlang.parser.ast.PrintStatement; import com.annimon.ownlang.parser.ast.AssignmentStatement; import com.annimon.ownlang.parser.ast.BinaryExpression; +import com.annimon.ownlang.parser.ast.BlockStatement; import com.annimon.ownlang.parser.ast.ConditionalExpression; import com.annimon.ownlang.parser.ast.VariabletExpression; import com.annimon.ownlang.parser.ast.Expression; +import com.annimon.ownlang.parser.ast.ForStatement; import com.annimon.ownlang.parser.ast.IfStatement; import com.annimon.ownlang.parser.ast.ValueExpression; import com.annimon.ownlang.parser.ast.Statement; import com.annimon.ownlang.parser.ast.UnaryExpression; +import com.annimon.ownlang.parser.ast.WhileStatement; import java.util.ArrayList; import java.util.List; @@ -31,14 +34,28 @@ public final class Parser { size = tokens.size(); } - public List parse() { - final List result = new ArrayList<>(); + public Statement parse() { + final BlockStatement result = new BlockStatement(); while (!match(TokenType.EOF)) { result.add(statement()); } return result; } + private Statement block() { + final BlockStatement block = new BlockStatement(); + consume(TokenType.LBRACE); + while (!match(TokenType.RBRACE)) { + block.add(statement()); + } + return block; + } + + private Statement statementOrBlock() { + if (get(0).getType() == TokenType.LBRACE) return block(); + return statement(); + } + private Statement statement() { if (match(TokenType.PRINT)) { return new PrintStatement(expression()); @@ -46,6 +63,12 @@ public final class Parser { if (match(TokenType.IF)) { return ifElse(); } + if (match(TokenType.WHILE)) { + return whileStatement(); + } + if (match(TokenType.FOR)) { + return forStatement(); + } return assignmentStatement(); } @@ -62,16 +85,32 @@ public final class Parser { private Statement ifElse() { final Expression condition = expression(); - final Statement ifStatement = statement(); + final Statement ifStatement = statementOrBlock(); final Statement elseStatement; if (match(TokenType.ELSE)) { - elseStatement = statement(); + elseStatement = statementOrBlock(); } else { elseStatement = null; } return new IfStatement(condition, ifStatement, elseStatement); } + private Statement whileStatement() { + final Expression condition = expression(); + final Statement statement = statementOrBlock(); + return new WhileStatement(condition, statement); + } + + private Statement forStatement() { + final Statement initialization = assignmentStatement(); + consume(TokenType.COMMA); + final Expression termination = expression(); + consume(TokenType.COMMA); + final Statement increment = assignmentStatement(); + final Statement statement = statementOrBlock(); + return new ForStatement(initialization, termination, increment, statement); + } + private Expression expression() { return logicalOr(); diff --git a/src/com/annimon/ownlang/parser/TokenType.java b/src/com/annimon/ownlang/parser/TokenType.java index b5860ce..524d1e4 100644 --- a/src/com/annimon/ownlang/parser/TokenType.java +++ b/src/com/annimon/ownlang/parser/TokenType.java @@ -15,6 +15,8 @@ public enum TokenType { PRINT, IF, ELSE, + WHILE, + FOR, PLUS, MINUS, @@ -36,6 +38,9 @@ public enum TokenType { LPAREN, // ( RPAREN, // ) + LBRACE, // { + RBRACE, // } + COMMA, // , EOF } diff --git a/src/com/annimon/ownlang/parser/ast/BlockStatement.java b/src/com/annimon/ownlang/parser/ast/BlockStatement.java new file mode 100644 index 0000000..5eb93b7 --- /dev/null +++ b/src/com/annimon/ownlang/parser/ast/BlockStatement.java @@ -0,0 +1,37 @@ +package com.annimon.ownlang.parser.ast; + +import java.util.ArrayList; +import java.util.List; + +/** + * + * @author aNNiMON + */ +public final class BlockStatement implements Statement { + + private final List statements; + + public BlockStatement() { + statements = new ArrayList<>(); + } + + public void add(Statement statement) { + statements.add(statement); + } + + @Override + public void execute() { + for (Statement statement : statements) { + statement.execute(); + } + } + + @Override + public String toString() { + final StringBuilder result = new StringBuilder(); + for (Statement statement : statements) { + result.append(statement.toString()).append(System.lineSeparator()); + } + return result.toString(); + } +} diff --git a/src/com/annimon/ownlang/parser/ast/ForStatement.java b/src/com/annimon/ownlang/parser/ast/ForStatement.java new file mode 100644 index 0000000..b096dd8 --- /dev/null +++ b/src/com/annimon/ownlang/parser/ast/ForStatement.java @@ -0,0 +1,32 @@ +package com.annimon.ownlang.parser.ast; + +/** + * + * @author aNNiMON + */ +public final class ForStatement implements Statement { + + private final Statement initialization; + private final Expression termination; + private final Statement increment; + private final Statement statement; + + public ForStatement(Statement initialization, Expression termination, Statement increment, Statement block) { + this.initialization = initialization; + this.termination = termination; + this.increment = increment; + this.statement = block; + } + + @Override + public void execute() { + for (initialization.execute(); termination.eval().asNumber() != 0; increment.execute()) { + statement.execute(); + } + } + + @Override + public String toString() { + return "for " + initialization + ", " + termination + ", " + increment + " " + statement; + } +} diff --git a/src/com/annimon/ownlang/parser/ast/WhileStatement.java b/src/com/annimon/ownlang/parser/ast/WhileStatement.java new file mode 100644 index 0000000..18c81c3 --- /dev/null +++ b/src/com/annimon/ownlang/parser/ast/WhileStatement.java @@ -0,0 +1,28 @@ +package com.annimon.ownlang.parser.ast; + +/** + * + * @author aNNiMON + */ +public final class WhileStatement implements Statement { + + private final Expression condition; + private final Statement statement; + + public WhileStatement(Expression condition, Statement statement) { + this.condition = condition; + this.statement = statement; + } + + @Override + public void execute() { + while (condition.eval().asNumber() != 0) { + statement.execute(); + } + } + + @Override + public String toString() { + return "while " + condition + " " + statement; + } +}