finished exercise
This commit is contained in:
@@ -1,15 +1,15 @@
|
|||||||
package ssw.mj.impl;
|
package ssw.mj.impl;
|
||||||
|
|
||||||
import ssw.mj.Errors;
|
import ssw.mj.Errors;
|
||||||
|
import ssw.mj.Interpreter;
|
||||||
import ssw.mj.scanner.Token;
|
import ssw.mj.scanner.Token;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.Reader;
|
import java.io.Reader;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Optional;
|
|
||||||
|
|
||||||
import static ssw.mj.scanner.Token.Kind.*;
|
import static ssw.mj.scanner.Token.Kind.*;
|
||||||
|
import static ssw.mj.scanner.Token.Kind.number;
|
||||||
|
|
||||||
public class Scanner {
|
public class Scanner {
|
||||||
|
|
||||||
@@ -112,40 +112,60 @@ public class Scanner {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (isDigit(ch)) {
|
if (isDigit(ch)) {
|
||||||
final var number = readNumber();
|
final var stringNumber = readNumber();
|
||||||
|
|
||||||
var token = new Token(Token.Kind.number, ogLine, ogCol);
|
try {
|
||||||
token.numVal = number;
|
final var number = Integer.parseInt(stringNumber);
|
||||||
token.val = number + "";
|
|
||||||
|
|
||||||
return token;
|
var token = new Token(Token.Kind.number, ogLine, ogCol);
|
||||||
|
token.numVal = number;
|
||||||
|
token.val = stringNumber;
|
||||||
|
|
||||||
|
return token;
|
||||||
|
} catch (NumberFormatException exception) {
|
||||||
|
final var token = new Token(number, ogLine, ogCol);
|
||||||
|
error(token, Errors.Message.BIG_NUM, stringNumber);
|
||||||
|
return token;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ch == '\'') {
|
if (ch == '\'') {
|
||||||
nextCh();
|
nextCh();
|
||||||
|
|
||||||
|
if (ch == '\r') {
|
||||||
|
nextCh();
|
||||||
|
}
|
||||||
|
|
||||||
|
var charContent = ch;
|
||||||
|
var lfEscaped = false;
|
||||||
|
var tickEscaped = false;
|
||||||
|
|
||||||
if (ch == '\\') {
|
if (ch == '\\') {
|
||||||
nextCh();
|
nextCh();
|
||||||
final var charContent = switch (ch) {
|
charContent = switch (ch) {
|
||||||
case 'n' -> '\n';
|
case 'n' -> '\n';
|
||||||
case 'r' -> '\r';
|
case 'r' -> '\r';
|
||||||
case 't' -> '\t';
|
case 't' -> '\t';
|
||||||
case '\\' -> '\\';
|
case '\\' -> '\\';
|
||||||
case '\'' -> '\'';
|
case '\'' -> '\'';
|
||||||
default -> ' ';
|
default -> '\0';
|
||||||
};
|
};
|
||||||
|
|
||||||
final var token = new Token(charConst, ogLine, ogCol);
|
if (charContent == '\n') {
|
||||||
token.val = charContent + "";
|
lfEscaped = true;
|
||||||
token.numVal = charContent;
|
}
|
||||||
nextCh();
|
|
||||||
nextCh();
|
if (charContent == '\'') {
|
||||||
return token;
|
tickEscaped = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (charContent == '\0') {
|
||||||
|
final var token = new Token(charConst, ogLine, ogCol);
|
||||||
|
error(token, Errors.Message.UNDEFINED_ESCAPE, ch);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
final var charContent = ch;
|
if (charContent == LF && !lfEscaped || charContent == EOF || charContent == '\'' && !tickEscaped) {
|
||||||
|
|
||||||
if (charContent == LF || charContent == EOF || charContent == '\'') {
|
|
||||||
final var token = new Token(charConst, ogLine, ogCol);
|
final var token = new Token(charConst, ogLine, ogCol);
|
||||||
final var message = switch (charContent) {
|
final var message = switch (charContent) {
|
||||||
case LF -> Errors.Message.ILLEGAL_LINE_END;
|
case LF -> Errors.Message.ILLEGAL_LINE_END;
|
||||||
@@ -191,14 +211,19 @@ public class Scanner {
|
|||||||
case '.' -> new Token(Token.Kind.period, ogLine, ogCol);
|
case '.' -> new Token(Token.Kind.period, ogLine, ogCol);
|
||||||
case '{' -> new Token(Token.Kind.lbrace, ogLine, ogCol);
|
case '{' -> new Token(Token.Kind.lbrace, ogLine, ogCol);
|
||||||
case '}' -> new Token(Token.Kind.rbrace, ogLine, ogCol);
|
case '}' -> new Token(Token.Kind.rbrace, ogLine, ogCol);
|
||||||
|
case '[' -> new Token(Token.Kind.lbrack, ogLine, ogCol);
|
||||||
|
case ']' -> new Token(Token.Kind.rbrack, ogLine, ogCol);
|
||||||
|
case '(' -> new Token(Token.Kind.lpar, ogLine, ogCol);
|
||||||
|
case ')' -> new Token(Token.Kind.rpar, ogLine, ogCol);
|
||||||
case (char) -1 -> new Token(Token.Kind.eof, ogLine, ogCol);
|
case (char) -1 -> new Token(Token.Kind.eof, ogLine, ogCol);
|
||||||
|
case '~' -> new Token(Token.Kind.tilde, ogLine, ogCol);
|
||||||
case '=' -> {
|
case '=' -> {
|
||||||
if (ch == '=') {
|
if (ch == '=') {
|
||||||
nextCh();
|
nextCh();
|
||||||
yield new Token(Token.Kind.eql, ogLine, ogCol);
|
yield new Token(Token.Kind.eql, ogLine, ogCol);
|
||||||
}
|
}
|
||||||
|
|
||||||
yield new Token(Token.Kind.assign, line, col);
|
yield new Token(Token.Kind.assign, ogLine, ogCol);
|
||||||
}
|
}
|
||||||
case '+' -> {
|
case '+' -> {
|
||||||
if (ch == '=') {
|
if (ch == '=') {
|
||||||
@@ -240,6 +265,18 @@ public class Scanner {
|
|||||||
yield new Token(Token.Kind.slashas, ogLine, ogCol);
|
yield new Token(Token.Kind.slashas, ogLine, ogCol);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ch == '*') {
|
||||||
|
nextCh();
|
||||||
|
final var success = skipComment();
|
||||||
|
if (success) {
|
||||||
|
yield next();
|
||||||
|
} else {
|
||||||
|
final var token = new Token(eof, ogLine, ogCol);
|
||||||
|
error(token, Errors.Message.EOF_IN_COMMENT);
|
||||||
|
yield next();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
yield new Token(Token.Kind.slash, ogLine, ogCol);
|
yield new Token(Token.Kind.slash, ogLine, ogCol);
|
||||||
}
|
}
|
||||||
case '%' -> {
|
case '%' -> {
|
||||||
@@ -256,8 +293,9 @@ public class Scanner {
|
|||||||
yield new Token(Token.Kind.neq, ogLine, ogCol);
|
yield new Token(Token.Kind.neq, ogLine, ogCol);
|
||||||
}
|
}
|
||||||
|
|
||||||
error(new Token(none, line, col), Errors.Message.INVALID_CHAR);
|
final var token = new Token(none, ogLine, ogCol);
|
||||||
yield next();
|
error(token, Errors.Message.INVALID_CHAR, ogChar);
|
||||||
|
yield token;
|
||||||
}
|
}
|
||||||
case '>' -> {
|
case '>' -> {
|
||||||
if (ch == '=') {
|
if (ch == '=') {
|
||||||
@@ -268,7 +306,7 @@ public class Scanner {
|
|||||||
yield new Token(Token.Kind.gtr, ogLine, ogCol);
|
yield new Token(Token.Kind.gtr, ogLine, ogCol);
|
||||||
}
|
}
|
||||||
case '<' -> {
|
case '<' -> {
|
||||||
if (ch == '<') {
|
if (ch == '=') {
|
||||||
nextCh();
|
nextCh();
|
||||||
yield new Token(Token.Kind.leq, ogLine, ogCol);
|
yield new Token(Token.Kind.leq, ogLine, ogCol);
|
||||||
}
|
}
|
||||||
@@ -281,21 +319,24 @@ public class Scanner {
|
|||||||
yield new Token(Token.Kind.and, ogLine, ogCol);
|
yield new Token(Token.Kind.and, ogLine, ogCol);
|
||||||
}
|
}
|
||||||
|
|
||||||
error(new Token(none, line, col), Errors.Message.INVALID_CHAR);
|
final var token = new Token(none, ogLine, ogCol);
|
||||||
yield next();
|
error(token, Errors.Message.INVALID_CHAR, ogChar);
|
||||||
|
yield token;
|
||||||
}
|
}
|
||||||
case '|' -> {
|
case '|' -> {
|
||||||
if (ch == '|') {
|
if (ch == '|') {
|
||||||
nextCh();
|
nextCh();
|
||||||
yield new Token(Token.Kind.and, ogLine, ogCol);
|
yield new Token(Token.Kind.or, ogLine, ogCol);
|
||||||
}
|
}
|
||||||
|
|
||||||
error(new Token(none, line, col), Errors.Message.INVALID_CHAR);
|
final var token = new Token(none, ogLine, ogCol);
|
||||||
yield next();
|
error(token, Errors.Message.INVALID_CHAR, ogChar);
|
||||||
|
yield token;
|
||||||
}
|
}
|
||||||
default -> {
|
default -> {
|
||||||
error(new Token(none, line, col), Errors.Message.INVALID_CHAR);
|
final var token = new Token(none, ogLine, ogCol);
|
||||||
yield next();
|
error(token, Errors.Message.INVALID_CHAR, ogChar);
|
||||||
|
yield token;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -333,7 +374,7 @@ public class Scanner {
|
|||||||
public String readName() {
|
public String readName() {
|
||||||
final var builder = new StringBuilder();
|
final var builder = new StringBuilder();
|
||||||
|
|
||||||
while (isLetter(ch)) {
|
while (isLetter(ch) || ch == '_' || isDigit(ch)) {
|
||||||
builder.append(ch);
|
builder.append(ch);
|
||||||
nextCh();
|
nextCh();
|
||||||
}
|
}
|
||||||
@@ -341,7 +382,7 @@ public class Scanner {
|
|||||||
return builder.toString();
|
return builder.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
public int readNumber() {
|
public String readNumber() {
|
||||||
final var builder = new StringBuilder();
|
final var builder = new StringBuilder();
|
||||||
|
|
||||||
while (isDigit(ch)) {
|
while (isDigit(ch)) {
|
||||||
@@ -349,7 +390,7 @@ public class Scanner {
|
|||||||
nextCh();
|
nextCh();
|
||||||
}
|
}
|
||||||
|
|
||||||
return Integer.parseInt(builder.toString());
|
return builder.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
private Token getTokenByName(String name, int line, int col) {
|
private Token getTokenByName(String name, int line, int col) {
|
||||||
@@ -364,6 +405,30 @@ public class Scanner {
|
|||||||
return token;
|
return token;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean skipComment() {
|
||||||
|
var commentCount = 1;
|
||||||
|
while (commentCount != 0) {
|
||||||
|
final var lastCh = ch;
|
||||||
|
nextCh();
|
||||||
|
|
||||||
|
if (lastCh == '/' && ch == '*') {
|
||||||
|
commentCount++;
|
||||||
|
nextCh();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lastCh == '*' && ch == '/') {
|
||||||
|
commentCount--;
|
||||||
|
nextCh();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ch == EOF && commentCount != 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
// ================================================
|
// ================================================
|
||||||
// ================================================
|
// ================================================
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user