package ql.parser;
import java.io.IOException;
import java.io.Reader;
import java.util.HashMap;
import java.util.Map;
import ql.ast.QLNode;
import ql.ast.expression.Identifier;
import ql.ast.expression.literal.BooleanLiteral;
import ql.ast.expression.literal.FloatLiteral;
import ql.ast.expression.literal.IntegerLiteral;
import ql.ast.expression.literal.StringLiteral;
public class QLLexer implements QLTokens {
private static final Map<String, Integer> KEYWORDS;
static {
KEYWORDS = new HashMap<String, Integer>();
KEYWORDS.put("form", FORM);
KEYWORDS.put("boolean", BOOLEAN);
KEYWORDS.put("string", STRING);
KEYWORDS.put("assign", ASSIGN);
KEYWORDS.put("integer", INTEGER);
KEYWORDS.put("float", FLOAT);
KEYWORDS.put("money", MONEY);
KEYWORDS.put("if", IF);
KEYWORDS.put("else", ELSE);
KEYWORDS.put("true", BOOLEANLITERAL);
KEYWORDS.put("false", BOOLEANLITERAL);
}
private int token;
private int c = ' ';
private QLNode yylval;
private final Reader input;
public QLLexer(Reader input) {
this.input = input;
nextChar();
}
private void nextChar() {
if (c >= 0) {
try {
c = input.read();
}
catch (IOException e) {
c = -1;
}
}
}
public int nextToken() {
boolean inComment = false;
for (;;) {
if (inComment) {
while (c != '*' && c != -1) {
nextChar();
}
if (c == '*') {
nextChar();
if (c == '/') {
nextChar();
inComment = false;
}
continue;
}
}
while (c == ' ' || c == '\t' || c == '\n' || c == '\r') {
nextChar();
}
if (c < 0) {
return token = ENDINPUT;
}
switch (c) {
case '/': {
nextChar();
if (c == '*') {
inComment = true;
nextChar();
continue;
}
else if (c == '/') {
while (c != '\n') {
nextChar();
}
continue;
}
return token = '/';
}
case ':': nextChar(); return token = ':';
case '}': nextChar(); return token = '}';
case '{': nextChar(); return token = '{';
case ')': nextChar(); return token = ')';
case '(': nextChar(); return token = '(';
case '*': {
nextChar();
if (inComment && c == '/') {
inComment = false;
nextChar();
continue;
}
return token = '*';
}
case '+': nextChar(); return token = '+';
case '-': nextChar(); return token = '-';
case '&': {
nextChar();
if (c == '&') {
nextChar();
return token = AND;
}
throw new RuntimeException("Unexpected character: " + (char)c);
}
case '|': {
nextChar();
if (c == '|') {
nextChar();
return token = OR;
}
throw new RuntimeException("Unexpected character: " + (char)c);
}
case '!': {
nextChar();
if(c == '=') {
nextChar();
return token = NEQ;
}
return token = '!';
}
case '<': {
nextChar();
if (c == '=') {
nextChar();
return token = LEQ;
}
return '<';
}
case '=': {
nextChar();
if (c == '=') {
nextChar();
return token = EQ;
}
throw new RuntimeException("Unexpected character: " + (char)c);
}
case '>': {
nextChar();
if (c == '=') {
nextChar();
return token = GEQ;
}
return token = '>';
}
case '"': {
StringBuilder sb = new StringBuilder();
// Skip opening quote.
nextChar();
// Build a string from everything between the quotes.
while (c != '"') {
// Detected escaped quotes.
if(c == '\\') {
nextChar();
if(c == '"') {
sb.append((char)c);
nextChar();
continue;
}
}
sb.append((char)c);
nextChar();
}
// Skip closing quote.
nextChar();
String string = sb.toString();
yylval = new StringLiteral(string);
return token = STRINGLITERAL;
}
default: {
if (Character.isDigit(c)) {
boolean isFloat = false;
double n = 0;
int decs = 1;
do {
if(c == '.') {
isFloat = true;
nextChar();
continue;
}
if(isFloat) {
n = n + (1.0 / (10 * decs)) * (c - '0');
decs *= 10;
} else {
n = 10 * n + (c - '0');
}
nextChar();
} while (Character.isDigit(c) || (c == '.' && !isFloat));
yylval = isFloat ? new FloatLiteral((float)n) : new IntegerLiteral((int)n);
return token = isFloat ? FLOATLITERAL : INTEGERLITERAL;
}
if (Character.isLetter(c)) {
StringBuilder sb = new StringBuilder();
do {
sb.append((char)c);
nextChar();
} while (Character.isLetterOrDigit(c));
String name = sb.toString();
// Boolean literals
if (name.equals("true")) {
yylval = new BooleanLiteral(true);
}
if (name.equals("false")) {
yylval = new BooleanLiteral(false);
}
if (KEYWORDS.containsKey(name)) {
return token = KEYWORDS.get(name);
}
yylval = new Identifier(name);
return token = IDENTIFIER;
}
throw new RuntimeException("Unexpected character: " + (char)c);
}
}
}
}
public int getToken() {
return token;
}
public QLNode getSemantic() {
return yylval;
}
}