package org.uva.sea.ql.parser.jacc;
import java.io.IOException;
import java.io.Reader;
import java.util.HashMap;
import java.util.Map;
import org.uva.sea.ql.ast.ASTNode;
import org.uva.sea.ql.ast.Identifier;
import org.uva.sea.ql.ast.literal.BooleanLiteral;
import org.uva.sea.ql.ast.literal.IntegerLiteral;
import org.uva.sea.ql.ast.literal.StringLiteral;
public class QLLexer implements QLTokens {
private static final Map<String, Integer> KEYWORDS;
static {
KEYWORDS = new HashMap<String, Integer>();
KEYWORDS.put("true", BOOLEANLITERAL);
KEYWORDS.put("false", BOOLEANLITERAL);
KEYWORDS.put("form", FORM);
KEYWORDS.put("if", IF);
KEYWORDS.put("else", ELSE);
KEYWORDS.put("integer", INTEGER);
KEYWORDS.put("boolean", BOOLEAN);
KEYWORDS.put("string", STRING);
KEYWORDS.put("money", MONEY);
}
private int token;
private int c = ' ';
private ASTNode 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 inCommentMultipleLines = false;
boolean inCommentSingleLine = false;
for (;;) {
if (inCommentMultipleLines) {
while (c != '*' && c != -1) {
nextChar();
}
if (c == '*') {
nextChar();
if (c == '/') {
nextChar();
inCommentMultipleLines = false;
}
continue;
}
}
if(inCommentSingleLine){
while(c != '\n'&& c != -1){
nextChar();
}
if(c == '\n'){
nextChar();
inCommentSingleLine = false;
}
//if the comment is the last line (no \n)
else if(c < 0)
{
return token = ENDINPUT;
}
continue;
}
while (c == ' ' || c == '\t' || c == '\n' || c == '\r') {
nextChar();
}
if (c < 0) {
return token = ENDINPUT;
}
switch (c) {
case '/': {
nextChar();
if (c == '*') {
inCommentMultipleLines = true;
nextChar();
continue;
}
else if(c == '/'){
inCommentSingleLine = true;
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 (inCommentMultipleLines && c == '/') {
inCommentMultipleLines = 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 token = '<';
}
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 '"':{
nextChar();
StringBuilder sb = new StringBuilder();
while(c != '"'){
sb.append((char)c);
nextChar();
}
String name = sb.toString();
yylval = new StringLiteral(name);
nextChar();
return token = STRINGLITERAL;
}
default: {
if (Character.isDigit(c)) {
int n = 0;
do {
n = 10 * n + (c - '0');
nextChar();
} while (Character.isDigit(c));
yylval = new IntegerLiteral(n);
return token = INTEGERLITERAL;
}
if (Character.isLetter(c)) {
StringBuilder sb = new StringBuilder();
do {
sb.append((char)c);
nextChar();
}
while (Character.isLetterOrDigit(c));
String name = sb.toString();
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 ASTNode getSemantic() {
return yylval;
}
}