package lexer;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class OracleLexer {
public static final String[] keywords = {"SELECT", "FROM", "WHERE", "AND", "OR", "INSERT", "UPDATE", "DELETE", "VALUES", "INTO",
"CREATE", "TABLE", "TEMPORARY", "GLOBAL",
"NUMBER", "INTEGER", "SMALLIN", "BINARY_INTEGER", "DECIMAL", "REAL", "FLOAT", "DOUBLE PRECISION", "CHAR", "VARCHAR2",
"NCHAR", "NVARCHAR2", "CLOB", "NCLOB", "DATE", "TIMESTAMP", "TIMESTAMP WITH TIME ZONE", "TIMESTAMP WITH LOCAL TIME ZONE", "BLOB", "RAW",
"LONG RAW", "BOOLEAN", "INTERVAL YEAR TO MONTH", "INTERVAL DAY TO SECOND", "ROWID", "UROWID", "REF CURSOR",
"NOT NULL", "PRIMARY KEY", "UNIQUE", "CHECK", "REFERENCES", "DEFAULT", "CONSTRAINT", "FOREIGN KEY"
, "DROP", "CASCADE"
, "DISTINCT", "JOIN", "GROUP BY", "ORDER BY", "HAVING", "UNION", "CASE", "WHEN", "END", "AS", "||"
, "INNER JOIN", "LEFT JOIN", "LEFT OUTER JOIN", "RIGHT JOIN", "RIGHT OUTER JOIN", "FULL JOIN", "FULL OUTER JOIN", "CROSS JOIN", "JOIN", "ON", "USING"
, "THEN", "ELSE"
, "SET"
, "ALTER", "ADD", "DROP", "MODIFY", "RENAME", "TO", "COLUMN"
, "REPLACE", "VIEW"
, ":=", "IF", "ELSIF", "BEGIN", "..", "DECLARE"
, "LOOP", "EXIT", "WHILE", "FOR", "IN", "CONTINUE"
, "EXCEPTION", "SQLERRM", "ZERO_DIVIDE", "INVALID_NUMBER", "OTHERS"
, "PROCEDURE", "IS", "IN", "OUT", "$$", "COMMIT", "ROLLBACK", "EXEC", "EXECUTE"
, "FUNCTION", "RETURN"
, "TRIGGER", "BEFORE", "AFTER", "INSTEAD OF", "REFERENCING", "NEW", "OLD", "EACH", "ROW"
};
private static final Pattern TOKEN_PATTERN = Pattern.compile(
"(NUMBER\\(.*?\\))|" +
"(DECIMAL\\(.*?\\))|" +
"(FLOAT\\(.*?\\))|" +
"(CHAR\\(.*?\\))|" +
"(VARCHAR2\\(.*?\\))|" +
"(NCHAR\\(.*?\\))|" +
"(NVARCHAR2\\(.*?\\))|" +
"(RAW\\(.*?\\))|" +
"(COUNT\\(.*?\\))|" +
"(SUM\\(.*?\\))|" +
"(AVG\\(.*?\\))|" +
"(MAX\\(.*?\\))|" +
"(MIN\\(.*?\\))|" +
"(\\|\\|\\s*'.*?'\\s*\\|\\|)|" +
"(DBMS_OUTPUT.PUT_LINE\\(.*?\\))|" +
"(LENGTH\\(.*?\\))|" +
"(NOT NULL)|" +
"(PRIMARY KEY)|" +
"(FOREIGN KEY)|" +
"(DOUBLE PRECISION)|" +
"(TIMESTAMP WITH TIME ZONE)|" +
"(TIMESTAMP WITH LOCAL TIME ZONE)|" +
"(LONG RAW)|" +
"(INTERVAL YEAR TO MONTH)|" +
"(INTERVAL DAY TO SECOND)|" +
"(REF CURSOR)|" +
"(GROUP BY)|" +
"(ORDER BY)|" +
"(INNER JOIN)|" +
"(LEFT JOIN)|" +
"(LEFT OUTER JOIN)|" +
"(RIGHT JOIN)|" +
"(RIGHT OUTER JOIN)|" +
"(FULL JOIN)|" +
"(FULL OUTER JOIN)|" +
"(CROSS JOIN)|" +
"(INSTEAD OF)|" +
"(\\|\\|)|" +
"(:=)|" +
"(\\.\\.)|" +
"(\\b[A-Za-z_][A-Za-z0-9_.%]*\\b)|" +
"(\\d+\\.?\\d*)|" +
"(\"[^\"]*\")|" +
"('([^']|\\\\')*)'|" +
"([;,()])|" +
"([=<>+\\-*/<<>>])|" +
"(\\s+)",
Pattern.CASE_INSENSITIVE
);
private final List<Token> tokens = new ArrayList<>();
private final String input;
private int position = 0;
public OracleLexer(String input) {
this.input = dataProcess(input);
tokenize();
}
public List<Token> tokenize() {
Matcher matcher = TOKEN_PATTERN.matcher(input);
while (matcher.find()) {
String tokenValue = matcher.group();
Token token = createToken(tokenValue);
if (token != null) {
tokens.add(token);
position += tokenValue.length();
} else {
position += tokenValue.length();
}
}
tokens.add(new Token(Token.TokenType.EOF, ""));
return tokens;
}
private Token createToken(String tokenValue) {
if (tokenValue.matches("\\d+(\\.\\d+)?")) {
return new Token(Token.TokenType.NUMBER, tokenValue);
} else if (tokenValue.matches("\"[^\"]*\"")) {
return new Token(Token.TokenType.STRING, tokenValue);
} else if (tokenValue.matches("'([^']|\\\\')*'")) {
return new Token(Token.TokenType.STRING, tokenValue);
} else if (tokenValue.matches("([;(),])")) {
return new Token(Token.TokenType.SYMBOL, tokenValue);
} else if (tokenValue.matches("[=<>+\\-*/<<>>]")) {
return new Token(Token.TokenType.OPERATOR, tokenValue);
}
else if (tokenValue.matches("(?i)NUMBER\\(.*?\\)")) {
return new Token(Token.TokenType.KEYWORD, tokenValue);
} else if (tokenValue.matches("(?i)DECIMAL\\(.*?\\)")) {
return new Token(Token.TokenType.KEYWORD, tokenValue);
} else if (tokenValue.matches("(?i)FLOAT\\(.*?\\)")) {
return new Token(Token.TokenType.KEYWORD, tokenValue);
} else if (tokenValue.matches("(?i)CHAR\\(.*?\\)")) {
return new Token(Token.TokenType.KEYWORD, tokenValue);
} else if (tokenValue.matches("(?i)VARCHAR2\\(.*?\\)")) {
return new Token(Token.TokenType.KEYWORD, tokenValue);
} else if (tokenValue.matches("(?i)NCHAR\\(.*?\\)")) {
return new Token(Token.TokenType.KEYWORD, tokenValue);
} else if (tokenValue.matches("(?i)NVARCHAR2\\(.*?\\)")) {
return new Token(Token.TokenType.KEYWORD, tokenValue);
} else if (tokenValue.matches("(?i)RAW\\(.*?\\)")) {
return new Token(Token.TokenType.KEYWORD, tokenValue);
} else if (tokenValue.matches("(?i)COUNT\\(.*?\\)")) {
return new Token(Token.TokenType.KEYWORD, tokenValue);
} else if (tokenValue.matches("(?i)SUM\\(.*?\\)")) {
return new Token(Token.TokenType.KEYWORD, tokenValue);
} else if (tokenValue.matches("(?i)AVG\\(.*?\\)")) {
return new Token(Token.TokenType.KEYWORD, tokenValue);
} else if (tokenValue.matches("(?i)MAX\\(.*?\\)")) {
return new Token(Token.TokenType.KEYWORD, tokenValue);
} else if (tokenValue.matches("(?i)MIN\\(.*?\\)")) {
return new Token(Token.TokenType.KEYWORD, tokenValue);
} else if (tokenValue.matches("\\|\\|\\s*'.*?'\\s*\\|\\|")) {
return new Token(Token.TokenType.KEYWORD, tokenValue);
} else if (tokenValue.matches("(?i)DBMS_OUTPUT.PUT_LINE\\(.*?\\)")) {
return new Token(Token.TokenType.KEYWORD, tokenValue);
} else if (tokenValue.matches("(?i)LENGTH\\(.*?\\)")) {
return new Token(Token.TokenType.KEYWORD, tokenValue);
}
else if (isKeyword(tokenValue)) {
return new Token(Token.TokenType.KEYWORD, tokenValue);
} else if (tokenValue.matches("[a-zA-Z_][a-zA-Z0-9_.%]*")) {
return new Token(Token.TokenType.IDENTIFIER, tokenValue);
}
return null;
}
private boolean isKeyword(String tokenValue) {
for (String keyword : keywords) {
if (keyword.equalsIgnoreCase(tokenValue)) {
return true;
}
}
return false;
}
private static String dataProcess(String input){
while (input.contains(" ")) {
input = input.replace(" ", " ");
}
input = input.replace(" (", "(");
input = input.replace("..", " .. ");
return input;
}
public void printTokens() {
for (Token token : tokens) {
System.out.println(token);
}
}
public List<Token> getTokens() {
return tokens;
}
}