From 08838458725213ee821ab5da9cbd5d4d65f0670c Mon Sep 17 00:00:00 2001 From: Victor Date: Tue, 30 Jun 2015 16:30:30 +0300 Subject: [PATCH] =?UTF-8?q?=D0=92=D1=8B=D0=B2=D0=BE=D0=B4=20=D0=B8=D0=BD?= =?UTF-8?q?=D1=84=D0=BE=D1=80=D0=BC=D0=B0=D1=86=D0=B8=D0=B8=20=D0=BE=20?= =?UTF-8?q?=D0=BF=D0=BE=D0=B7=D0=B8=D1=86=D0=B8=D0=B8=20=D0=B2=20=D0=B8?= =?UTF-8?q?=D1=81=D1=85=D0=BE=D0=B4=D0=BD=D0=B8=D0=BA=D0=B5,=20=D0=B3?= =?UTF-8?q?=D0=B4=D0=B5=20=D0=BF=D1=80=D0=BE=D0=B8=D0=B7=D0=BE=D1=88=D0=BB?= =?UTF-8?q?=D0=B0=20=D0=BE=D1=88=D0=B8=D0=B1=D0=BA=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/com/annimon/ownlang/parser/Lexer.java | 20 ++++++++++--- .../ownlang/parser/LexerException.java | 16 ++++++++++ .../ownlang/parser/ParseException.java | 16 ++++++++++ src/com/annimon/ownlang/parser/Parser.java | 11 ++++--- src/com/annimon/ownlang/parser/Token.java | 30 +++++++++++-------- 5 files changed, 70 insertions(+), 23 deletions(-) create mode 100644 src/com/annimon/ownlang/parser/LexerException.java create mode 100644 src/com/annimon/ownlang/parser/ParseException.java diff --git a/src/com/annimon/ownlang/parser/Lexer.java b/src/com/annimon/ownlang/parser/Lexer.java index 62b4da0..ff27bc0 100644 --- a/src/com/annimon/ownlang/parser/Lexer.java +++ b/src/com/annimon/ownlang/parser/Lexer.java @@ -59,12 +59,14 @@ public final class Lexer { private final List tokens; private int pos; + private int row, col; public Lexer(String input) { this.input = input; length = input.length(); tokens = new ArrayList<>(); + row = col = 1; } public List tokenize() { @@ -92,7 +94,7 @@ public final class Lexer { char current = peek(0); while (true) { if (current == '.') { - if (buffer.indexOf(".") != -1) throw new RuntimeException("Invalid float number"); + if (buffer.indexOf(".") != -1) throw error("Invalid float number"); } else if (!Character.isDigit(current)) { break; } @@ -178,6 +180,7 @@ public final class Lexer { final StringBuilder buffer = new StringBuilder(); char current = peek(0); while (true) { + if (current == '\0') throw error("Reached end of file while parsing text string."); if (current == '\\') { current = next(); switch (current) { @@ -207,7 +210,7 @@ public final class Lexer { private void tokenizeMultilineComment() { char current = peek(0); while (true) { - if (current == '\0') throw new RuntimeException("Missing close tag"); + if (current == '\0') throw error("Reached end of file while parsing multiline comment"); if (current == '*' && peek(1) == '/') break; current = next(); } @@ -217,7 +220,12 @@ public final class Lexer { private char next() { pos++; - return peek(0); + final char result = peek(0); + if (result == '\n') { + row++; + col = 1; + } else col++; + return result; } private char peek(int relativePosition) { @@ -231,6 +239,10 @@ public final class Lexer { } private void addToken(TokenType type, String text) { - tokens.add(new Token(type, text)); + tokens.add(new Token(type, text, row, col)); + } + + private LexerException error(String text) { + return new LexerException(row, col, text); } } diff --git a/src/com/annimon/ownlang/parser/LexerException.java b/src/com/annimon/ownlang/parser/LexerException.java new file mode 100644 index 0000000..caab066 --- /dev/null +++ b/src/com/annimon/ownlang/parser/LexerException.java @@ -0,0 +1,16 @@ +package com.annimon.ownlang.parser; + +/** + * + * @author aNNiMON + */ +public final class LexerException extends RuntimeException { + + public LexerException(String message) { + super(message); + } + + public LexerException(int row, int col, String message) { + super("["+row+":"+col+"] " + message); + } +} \ No newline at end of file diff --git a/src/com/annimon/ownlang/parser/ParseException.java b/src/com/annimon/ownlang/parser/ParseException.java new file mode 100644 index 0000000..40ae395 --- /dev/null +++ b/src/com/annimon/ownlang/parser/ParseException.java @@ -0,0 +1,16 @@ +package com.annimon.ownlang.parser; + +/** + * + * @author aNNiMON + */ +public final class ParseException extends RuntimeException { + + public ParseException() { + super(); + } + + public ParseException(String string) { + super(string); + } +} \ No newline at end of file diff --git a/src/com/annimon/ownlang/parser/Parser.java b/src/com/annimon/ownlang/parser/Parser.java index 4d82169..3be209d 100644 --- a/src/com/annimon/ownlang/parser/Parser.java +++ b/src/com/annimon/ownlang/parser/Parser.java @@ -10,7 +10,7 @@ import java.util.List; */ public final class Parser { - private static final Token EOF = new Token(TokenType.EOF, ""); + private static final Token EOF = new Token(TokenType.EOF, "", -1, -1); private final List tokens; private final int size; @@ -82,7 +82,6 @@ public final class Parser { } private Statement assignmentStatement() { - // WORD EQ if (lookMatch(0, TokenType.WORD) && lookMatch(1, TokenType.EQ)) { final String variable = consume(TokenType.WORD).getText(); consume(TokenType.EQ); @@ -93,7 +92,7 @@ public final class Parser { consume(TokenType.EQ); return new ArrayAssignmentStatement(array, expression()); } - throw new RuntimeException("Unknown statement"); + throw new ParseException("Unknown statement: " + get(0)); } private Statement ifElse() { @@ -128,7 +127,7 @@ public final class Parser { final Expression termination = expression(); consume(TokenType.COMMA); final Statement increment = assignmentStatement(); - match(TokenType.RPAREN); + match(TokenType.RPAREN); // необязательные скобки final Statement statement = statementOrBlock(); return new ForStatement(initialization, termination, increment, statement); } @@ -409,12 +408,12 @@ public final class Parser { match(TokenType.RPAREN); return result; } - throw new RuntimeException("Unknown expression"); + throw new ParseException("Unknown expression: " + current); } private Token consume(TokenType type) { final Token current = get(0); - if (type != current.getType()) throw new RuntimeException("Token " + current + " doesn't match " + type); + if (type != current.getType()) throw new ParseException("Token " + current + " doesn't match " + type); pos++; return current; } diff --git a/src/com/annimon/ownlang/parser/Token.java b/src/com/annimon/ownlang/parser/Token.java index d8d4b8f..3d4f4e7 100644 --- a/src/com/annimon/ownlang/parser/Token.java +++ b/src/com/annimon/ownlang/parser/Token.java @@ -6,35 +6,39 @@ package com.annimon.ownlang.parser; */ public final class Token { - private TokenType type; - private String text; + private final TokenType type; + private final String text; + private final int row, col; - public Token() { - } - - public Token(TokenType type, String text) { + public Token(TokenType type, String text, int row, int col) { this.type = type; this.text = text; + this.row = row; + this.col = col; } public TokenType getType() { return type; } - public void setType(TokenType type) { - this.type = type; - } - public String getText() { return text; } - public void setText(String text) { - this.text = text; + public int getRow() { + return row; + } + + public int getCol() { + return col; + } + + public String position() { + return "[" + row + " " + col + "]"; } @Override public String toString() { - return type + " " + text; + return type.name() + " " + position() + " " + text; } }