200 lines
4.6 KiB
Java
200 lines
4.6 KiB
Java
/*
|
|
* Copyright 2014 GideonLeGrange.
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
package me.legrange.mikrotik.impl;
|
|
|
|
import java.util.Locale;
|
|
import static me.legrange.mikrotik.impl.Scanner.Token.*;
|
|
/**
|
|
* A simple scanner.
|
|
*
|
|
* @author gideon
|
|
*/
|
|
class Scanner {
|
|
|
|
enum Token {
|
|
|
|
SLASH("/"), COMMA(","), EOL(), WS, TEXT,
|
|
LESS("<"), MORE(">"), EQUALS("="), NOT_EQUALS("!="), PIPE("!"),
|
|
WHERE, NOT, AND, OR, RETURN;
|
|
|
|
@Override
|
|
public String toString() {
|
|
return (symb == null) ? name() : symb;
|
|
}
|
|
|
|
private Token(String symb) {
|
|
this.symb = symb;
|
|
}
|
|
|
|
private Token() {
|
|
symb = null;
|
|
}
|
|
|
|
private final String symb;
|
|
}
|
|
|
|
/**
|
|
* create a scanner for the given line of text
|
|
*/
|
|
Scanner(String line) {
|
|
this.line = line;
|
|
nextChar();
|
|
}
|
|
|
|
/**
|
|
* return the next token from the text
|
|
*/
|
|
Token next() throws ScanException {
|
|
text = null;
|
|
switch (c) {
|
|
case '\n':
|
|
return EOL;
|
|
case ' ':
|
|
case '\t':
|
|
return whiteSpace();
|
|
case ',':
|
|
nextChar();
|
|
return COMMA;
|
|
case '/':
|
|
nextChar();
|
|
return SLASH;
|
|
case '<':
|
|
nextChar();
|
|
return LESS;
|
|
case '>':
|
|
nextChar();
|
|
return MORE;
|
|
case '=':
|
|
nextChar();
|
|
return EQUALS;
|
|
case '!':
|
|
return pipe();
|
|
case '"':
|
|
return quotedText('"');
|
|
case '\'':
|
|
return quotedText('\'');
|
|
default:
|
|
return name();
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* return the text associated with the last token returned
|
|
*/
|
|
String text() {
|
|
if (text != null) {
|
|
return text.toString();
|
|
}
|
|
return "";
|
|
}
|
|
|
|
/**
|
|
* return the position of the scanner
|
|
*/
|
|
int pos() {
|
|
return pos;
|
|
}
|
|
|
|
/**
|
|
* process 'name' tokens which could be key words or text
|
|
*/
|
|
private Token name() throws ScanException {
|
|
text = new StringBuilder();
|
|
while (!in(c, "[ \t\r\n=<>!]")) {
|
|
text.append(c);
|
|
nextChar();
|
|
}
|
|
String val = text.toString().toLowerCase(Locale.getDefault());
|
|
switch (val) {
|
|
case "where":
|
|
return WHERE;
|
|
case "not":
|
|
return NOT;
|
|
case "and":
|
|
return AND;
|
|
case "or":
|
|
return OR;
|
|
case "return":
|
|
return RETURN;
|
|
}
|
|
return TEXT;
|
|
}
|
|
|
|
/**
|
|
* process quoted text
|
|
*/
|
|
private Token quotedText(char quote) throws ScanException {
|
|
nextChar(); // eat the '"'
|
|
text = new StringBuilder();
|
|
while (c != quote) {
|
|
if (c == '\n') {
|
|
throw new ScanException("Unclosed quoted text, reached end of line.");
|
|
}
|
|
text.append(c);
|
|
nextChar();
|
|
}
|
|
nextChar(); // eat the '"'
|
|
return TEXT;
|
|
}
|
|
|
|
/**
|
|
* process notEquals !
|
|
*/
|
|
private Token pipe() {
|
|
nextChar(); // eat !
|
|
if (c == '=') {
|
|
nextChar(); // eat =
|
|
return NOT_EQUALS;
|
|
}
|
|
return PIPE;
|
|
}
|
|
|
|
/**
|
|
* process white space
|
|
*/
|
|
private Token whiteSpace() {
|
|
while ((c == ' ') || (c == '\t')) {
|
|
nextChar();
|
|
}
|
|
return WS;
|
|
}
|
|
|
|
/**
|
|
* return the next character from the line of text
|
|
*/
|
|
private void nextChar() {
|
|
if (pos < line.length()) {
|
|
c = line.charAt(pos);
|
|
pos++;
|
|
} else {
|
|
c = '\n';
|
|
}
|
|
}
|
|
|
|
/**
|
|
* check if the character matches the give expression
|
|
*/
|
|
private boolean in(char c, String cs) {
|
|
return ("" + c).matches(cs);
|
|
}
|
|
|
|
private final String line;
|
|
private int pos = 0;
|
|
private char c;
|
|
private StringBuilder text;
|
|
}
|