246 lines
7.8 KiB
Java
Executable File
246 lines
7.8 KiB
Java
Executable File
package frontend.lexer;
|
|
|
|
import java.util.ArrayList;
|
|
|
|
import error.Error;
|
|
import error.ErrorType;
|
|
import error.Errors;
|
|
import java.nio.file.Files;
|
|
import java.nio.file.Paths;
|
|
import java.io.IOException;
|
|
|
|
public class Lexer {
|
|
private String input;
|
|
private ArrayList<Token> tokens;
|
|
private int position;
|
|
private int line;
|
|
private char currentChar;
|
|
|
|
public Lexer(String input) {
|
|
this.input = input;
|
|
this.tokens = new ArrayList<Token>();
|
|
this.position = 0;
|
|
this.line = 1;
|
|
}
|
|
|
|
public void lex(Errors errors) {
|
|
int sigComment = 0;
|
|
while (this.position < this.input.length()) {
|
|
currentChar = this.input.charAt(this.position);
|
|
if (currentChar == ' ' || currentChar == '\t') {
|
|
this.position++;
|
|
continue;
|
|
}
|
|
if (currentChar == '\n' || currentChar == '\r') {
|
|
if (currentChar == '\r') {
|
|
if (this.position + 1 < this.input.length() &&
|
|
this.input.charAt(this.position + 1) == '\n') {
|
|
this.position++;
|
|
}
|
|
}
|
|
this.line++;
|
|
this.position++;
|
|
if (sigComment == 1) {
|
|
sigComment = 0;
|
|
}
|
|
continue;
|
|
}
|
|
if (sigComment == 0) {
|
|
if (currentChar == '/') {
|
|
if (this.position + 1 < this.input.length() &&
|
|
this.input.charAt(this.position + 1) == '/') {
|
|
sigComment = 1;
|
|
this.position += 2;
|
|
continue;
|
|
}
|
|
if (this.position + 1 < this.input.length() &&
|
|
this.input.charAt(this.position + 1) == '*') {
|
|
sigComment = 2;
|
|
this.position += 2;
|
|
continue;
|
|
}
|
|
}
|
|
if (this.isIntCons()) {
|
|
lexInt();
|
|
continue;
|
|
}
|
|
if (this.isStrCons()) {
|
|
lexStr();
|
|
continue;
|
|
}
|
|
if (this.isIdenfr()) {
|
|
lexIdenfr();
|
|
continue;
|
|
}
|
|
lexOp(errors);
|
|
}
|
|
if (sigComment == 2) {
|
|
if (this.position + 1 < this.input.length() &&
|
|
this.currentChar == '*' && this.input.charAt(this.position + 1) == '/') {
|
|
sigComment = 0;
|
|
this.position += 2;
|
|
continue;
|
|
}
|
|
}
|
|
if (sigComment != 0) {
|
|
this.position++;
|
|
}
|
|
}
|
|
}
|
|
|
|
public boolean isIntCons() {
|
|
return Character.isDigit(this.currentChar);
|
|
}
|
|
|
|
public boolean isStrCons() {
|
|
return this.currentChar == '"';
|
|
}
|
|
|
|
public boolean isIdenfr() {
|
|
return Character.isLowerCase(this.currentChar) || Character.isUpperCase(this.currentChar)
|
|
|| this.currentChar == '_';
|
|
}
|
|
|
|
public boolean isNotWp() {
|
|
return !Character.isWhitespace(this.currentChar);
|
|
}
|
|
|
|
public boolean isOp() {
|
|
return !this.isIntCons() && !this.isStrCons() && !this.isIdenfr();
|
|
}
|
|
|
|
public void lexInt() {
|
|
StringBuilder sb = new StringBuilder();
|
|
while (this.position < this.input.length() && this.isIntCons()) {
|
|
sb.append(this.currentChar);
|
|
this.position++;
|
|
updateCurrentChar();
|
|
}
|
|
this.tokens.add(new Token(sb.toString(), this.line));
|
|
}
|
|
|
|
public void lexStr() {
|
|
StringBuilder sb = new StringBuilder();
|
|
sb.append(this.currentChar);
|
|
this.position++;
|
|
updateCurrentChar();
|
|
while (this.position < this.input.length() && this.currentChar != '"') {
|
|
sb.append(this.currentChar);
|
|
this.position++;
|
|
updateCurrentChar();
|
|
}
|
|
if (this.position < this.input.length() && this.currentChar == '"') {
|
|
sb.append(this.currentChar);
|
|
this.position++;
|
|
}
|
|
this.tokens.add(new Token(sb.toString(), this.line));
|
|
}
|
|
|
|
public void lexIdenfr() {
|
|
StringBuilder sb = new StringBuilder();
|
|
while (this.position < this.input.length() && (this.isIdenfr() || this.isIntCons())) {
|
|
sb.append(this.currentChar);
|
|
this.position++;
|
|
updateCurrentChar();
|
|
}
|
|
this.tokens.add(new Token(sb.toString(), this.line));
|
|
}
|
|
|
|
public void lexOp(Errors errors) {
|
|
StringBuilder sb = new StringBuilder();
|
|
if (this.currentChar == '/' && this.position + 1 < this.input.length() &&
|
|
(this.input.charAt(this.position + 1) == '/' ||
|
|
this.input.charAt(this.position + 1) == '*')) {
|
|
return;
|
|
}
|
|
sb.append(this.currentChar);
|
|
switch (this.currentChar) {
|
|
case '&':
|
|
readAnd(sb);
|
|
break;
|
|
case '|':
|
|
readOr(sb);
|
|
break;
|
|
case '<':
|
|
readEq(sb);
|
|
break;
|
|
case '>':
|
|
readEq(sb);
|
|
break;
|
|
case '=':
|
|
readEq(sb);
|
|
break;
|
|
case '!':
|
|
readEq(sb);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
this.position++;
|
|
if (sb.toString().equals("&") || sb.toString().equals("|")) {
|
|
errors.addError(new Error(this.line, ErrorType.a));
|
|
}
|
|
this.tokens.add(new Token(sb.toString(), this.line));
|
|
}
|
|
|
|
public void readAnd(StringBuilder sb) {
|
|
if (this.position + 1 < this.input.length() &&
|
|
this.input.charAt(this.position + 1) == '&') {
|
|
this.position++;
|
|
currentChar = this.input.charAt(this.position);
|
|
sb.append(currentChar);
|
|
}
|
|
}
|
|
|
|
public void readOr(StringBuilder sb) {
|
|
if (this.position + 1 < this.input.length() &&
|
|
this.input.charAt(this.position + 1) == '|') {
|
|
this.position++;
|
|
currentChar = this.input.charAt(this.position);
|
|
sb.append(currentChar);
|
|
}
|
|
}
|
|
|
|
public void readEq(StringBuilder sb) {
|
|
if (this.position + 1 < this.input.length() &&
|
|
this.input.charAt(this.position + 1) == '=') {
|
|
this.position++;
|
|
currentChar = this.input.charAt(this.position);
|
|
sb.append(currentChar);
|
|
}
|
|
}
|
|
|
|
public void updateCurrentChar() {
|
|
if (this.position < this.input.length()) {
|
|
currentChar = this.input.charAt(this.position);
|
|
}
|
|
}
|
|
|
|
public void printTokens() {
|
|
for (Token token : this.tokens) {
|
|
token.adjustType();
|
|
System.out.println(token.getType() + " " + token.getValue() + " " + token.getLine());
|
|
}
|
|
}
|
|
|
|
public void writeToFile(String fileName) {
|
|
try {
|
|
StringBuilder sb = new StringBuilder();
|
|
for (Token token : this.tokens) {
|
|
token.adjustType();
|
|
sb.append(token.toString());
|
|
}
|
|
Files.write(Paths.get(fileName), sb.toString().getBytes());
|
|
} catch (IOException e) {
|
|
e.printStackTrace();
|
|
}
|
|
}
|
|
|
|
public ArrayList<Token> getTokens() {
|
|
for (Token token : this.tokens) {
|
|
token.adjustType();
|
|
}
|
|
return this.tokens;
|
|
}
|
|
}
|