mirror of
https://github.com/aNNiMON/Own-Programming-Language-Tutorial.git
synced 2024-09-20 08:44:20 +03:00
Вывод информации о позиции в исходнике, где произошла ошибка
This commit is contained in:
parent
ef175a71af
commit
0883845872
@ -59,12 +59,14 @@ public final class Lexer {
|
|||||||
private final List<Token> tokens;
|
private final List<Token> tokens;
|
||||||
|
|
||||||
private int pos;
|
private int pos;
|
||||||
|
private int row, col;
|
||||||
|
|
||||||
public Lexer(String input) {
|
public Lexer(String input) {
|
||||||
this.input = input;
|
this.input = input;
|
||||||
length = input.length();
|
length = input.length();
|
||||||
|
|
||||||
tokens = new ArrayList<>();
|
tokens = new ArrayList<>();
|
||||||
|
row = col = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<Token> tokenize() {
|
public List<Token> tokenize() {
|
||||||
@ -92,7 +94,7 @@ public final class Lexer {
|
|||||||
char current = peek(0);
|
char current = peek(0);
|
||||||
while (true) {
|
while (true) {
|
||||||
if (current == '.') {
|
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)) {
|
} else if (!Character.isDigit(current)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -178,6 +180,7 @@ public final class Lexer {
|
|||||||
final StringBuilder buffer = new StringBuilder();
|
final StringBuilder buffer = new StringBuilder();
|
||||||
char current = peek(0);
|
char current = peek(0);
|
||||||
while (true) {
|
while (true) {
|
||||||
|
if (current == '\0') throw error("Reached end of file while parsing text string.");
|
||||||
if (current == '\\') {
|
if (current == '\\') {
|
||||||
current = next();
|
current = next();
|
||||||
switch (current) {
|
switch (current) {
|
||||||
@ -207,7 +210,7 @@ public final class Lexer {
|
|||||||
private void tokenizeMultilineComment() {
|
private void tokenizeMultilineComment() {
|
||||||
char current = peek(0);
|
char current = peek(0);
|
||||||
while (true) {
|
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;
|
if (current == '*' && peek(1) == '/') break;
|
||||||
current = next();
|
current = next();
|
||||||
}
|
}
|
||||||
@ -217,7 +220,12 @@ public final class Lexer {
|
|||||||
|
|
||||||
private char next() {
|
private char next() {
|
||||||
pos++;
|
pos++;
|
||||||
return peek(0);
|
final char result = peek(0);
|
||||||
|
if (result == '\n') {
|
||||||
|
row++;
|
||||||
|
col = 1;
|
||||||
|
} else col++;
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private char peek(int relativePosition) {
|
private char peek(int relativePosition) {
|
||||||
@ -231,6 +239,10 @@ public final class Lexer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void addToken(TokenType type, String text) {
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
16
src/com/annimon/ownlang/parser/LexerException.java
Normal file
16
src/com/annimon/ownlang/parser/LexerException.java
Normal file
@ -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);
|
||||||
|
}
|
||||||
|
}
|
16
src/com/annimon/ownlang/parser/ParseException.java
Normal file
16
src/com/annimon/ownlang/parser/ParseException.java
Normal file
@ -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);
|
||||||
|
}
|
||||||
|
}
|
@ -10,7 +10,7 @@ import java.util.List;
|
|||||||
*/
|
*/
|
||||||
public final class Parser {
|
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<Token> tokens;
|
private final List<Token> tokens;
|
||||||
private final int size;
|
private final int size;
|
||||||
@ -82,7 +82,6 @@ public final class Parser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private Statement assignmentStatement() {
|
private Statement assignmentStatement() {
|
||||||
// WORD EQ
|
|
||||||
if (lookMatch(0, TokenType.WORD) && lookMatch(1, TokenType.EQ)) {
|
if (lookMatch(0, TokenType.WORD) && lookMatch(1, TokenType.EQ)) {
|
||||||
final String variable = consume(TokenType.WORD).getText();
|
final String variable = consume(TokenType.WORD).getText();
|
||||||
consume(TokenType.EQ);
|
consume(TokenType.EQ);
|
||||||
@ -93,7 +92,7 @@ public final class Parser {
|
|||||||
consume(TokenType.EQ);
|
consume(TokenType.EQ);
|
||||||
return new ArrayAssignmentStatement(array, expression());
|
return new ArrayAssignmentStatement(array, expression());
|
||||||
}
|
}
|
||||||
throw new RuntimeException("Unknown statement");
|
throw new ParseException("Unknown statement: " + get(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
private Statement ifElse() {
|
private Statement ifElse() {
|
||||||
@ -128,7 +127,7 @@ public final class Parser {
|
|||||||
final Expression termination = expression();
|
final Expression termination = expression();
|
||||||
consume(TokenType.COMMA);
|
consume(TokenType.COMMA);
|
||||||
final Statement increment = assignmentStatement();
|
final Statement increment = assignmentStatement();
|
||||||
match(TokenType.RPAREN);
|
match(TokenType.RPAREN); // необязательные скобки
|
||||||
final Statement statement = statementOrBlock();
|
final Statement statement = statementOrBlock();
|
||||||
return new ForStatement(initialization, termination, increment, statement);
|
return new ForStatement(initialization, termination, increment, statement);
|
||||||
}
|
}
|
||||||
@ -409,12 +408,12 @@ public final class Parser {
|
|||||||
match(TokenType.RPAREN);
|
match(TokenType.RPAREN);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
throw new RuntimeException("Unknown expression");
|
throw new ParseException("Unknown expression: " + current);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Token consume(TokenType type) {
|
private Token consume(TokenType type) {
|
||||||
final Token current = get(0);
|
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++;
|
pos++;
|
||||||
return current;
|
return current;
|
||||||
}
|
}
|
||||||
|
@ -6,35 +6,39 @@ package com.annimon.ownlang.parser;
|
|||||||
*/
|
*/
|
||||||
public final class Token {
|
public final class Token {
|
||||||
|
|
||||||
private TokenType type;
|
private final TokenType type;
|
||||||
private String text;
|
private final String text;
|
||||||
|
private final int row, col;
|
||||||
|
|
||||||
public Token() {
|
public Token(TokenType type, String text, int row, int col) {
|
||||||
}
|
|
||||||
|
|
||||||
public Token(TokenType type, String text) {
|
|
||||||
this.type = type;
|
this.type = type;
|
||||||
this.text = text;
|
this.text = text;
|
||||||
|
this.row = row;
|
||||||
|
this.col = col;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TokenType getType() {
|
public TokenType getType() {
|
||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setType(TokenType type) {
|
|
||||||
this.type = type;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getText() {
|
public String getText() {
|
||||||
return text;
|
return text;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setText(String text) {
|
public int getRow() {
|
||||||
this.text = text;
|
return row;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getCol() {
|
||||||
|
return col;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String position() {
|
||||||
|
return "[" + row + " " + col + "]";
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return type + " " + text;
|
return type.name() + " " + position() + " " + text;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user