209 lines
5.6 KiB
Java
209 lines
5.6 KiB
Java
package me.legrange.mikrotik;
|
|
|
|
import java.util.Arrays;
|
|
import java.util.HashMap;
|
|
import java.util.LinkedList;
|
|
import java.util.List;
|
|
import java.util.Map;
|
|
import java.util.StringTokenizer;
|
|
|
|
/**
|
|
* Parse the pseudo-command line into command objects.
|
|
* @author GideonLeGrange
|
|
*/
|
|
class Parser {
|
|
|
|
/** parse the given bit of text into a Command object */
|
|
static Command parse(String text) throws ParseException {
|
|
Parser parser = new Parser(text);
|
|
return parser.parse();
|
|
}
|
|
|
|
/** run parse on the internal data and return the command object */
|
|
private Command parse() throws ParseException {
|
|
next();
|
|
expect(Token.COMMAND);
|
|
cmd = new Command(text);
|
|
next();
|
|
while (!((token == Token.WHERE) || (token == Token.RETURN) || (token == Token.EOL))) {
|
|
param();
|
|
}
|
|
if (token == Token.WHERE) {
|
|
where();
|
|
}
|
|
if (token == Token.RETURN) {
|
|
returns();
|
|
}
|
|
expect(Token.EOL);
|
|
return cmd;
|
|
}
|
|
|
|
private void param() throws ParseException {
|
|
String name = text;
|
|
next();
|
|
if (token == Token.EQUALS) {
|
|
next();
|
|
expect(Token.NAME);
|
|
cmd.addParameter(new Parameter(name, text));
|
|
next();
|
|
}
|
|
else {
|
|
cmd.addParameter(new Parameter(name));
|
|
}
|
|
}
|
|
|
|
private void where() throws ParseException {
|
|
next(); // swallow the word "where"
|
|
expr();
|
|
}
|
|
|
|
private void expr() throws ParseException {
|
|
expect(Token.NOT, Token.NAME);
|
|
switch (token) {
|
|
case NOT:
|
|
notExpr();
|
|
break;
|
|
case NAME: {
|
|
String name = text;
|
|
next();
|
|
expect(Token.EQUALS, Token.LESS, Token.MORE);
|
|
switch (token) {
|
|
case EQUALS:
|
|
eqExpr(name);
|
|
break;
|
|
case LESS:
|
|
lessExpr(name);
|
|
break;
|
|
case MORE:
|
|
moreExpr(name);
|
|
break;
|
|
default:
|
|
hasExpr(name);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
// if you get here, you had a expression, see if you want more.
|
|
switch (token) {
|
|
case AND : andExpr();
|
|
break;
|
|
case OR : orExpr();
|
|
}
|
|
}
|
|
|
|
private void andExpr() throws ParseException {
|
|
next(); // eat and
|
|
expr();
|
|
cmd.addQuery("?#&");
|
|
}
|
|
|
|
private void orExpr() throws ParseException {
|
|
next(); // eat or
|
|
expr();
|
|
cmd.addQuery("?#|");
|
|
}
|
|
|
|
|
|
private void notExpr() throws ParseException {
|
|
next(); // eat not
|
|
expr();
|
|
cmd.addQuery("?#!");
|
|
}
|
|
|
|
private void eqExpr(String name) {
|
|
next(); // eat =
|
|
cmd.addQuery(String.format("?%s=%s", name, text));
|
|
next();
|
|
}
|
|
|
|
private void lessExpr(String name) {
|
|
next(); // eat <
|
|
cmd.addQuery(String.format("?<%s=%s", name, text));
|
|
next();
|
|
}
|
|
|
|
private void moreExpr(String name) {
|
|
next(); // eat >
|
|
cmd.addQuery(String.format("?>%s=%s", name, text));
|
|
next();
|
|
}
|
|
|
|
private void hasExpr(String name) {
|
|
cmd.addQuery(String.format("?%s", name));
|
|
}
|
|
|
|
private void returns() throws ParseException {
|
|
next();
|
|
expect(Token.NAME);
|
|
List<String> props = new LinkedList<String>();
|
|
while (!(token == Token.EOL)) {
|
|
if (token != Token.COMMA) {
|
|
props.add(text);
|
|
}
|
|
next();
|
|
}
|
|
cmd.addProperty(props.toArray(new String[]{}));
|
|
}
|
|
|
|
private void expect(Token...tokens) throws ParseException {
|
|
for (Token want : tokens) {
|
|
if (this.token == want) return;
|
|
}
|
|
throw new ParseException(String.format("Expected %s but found %s", Arrays.asList(tokens), this.token));
|
|
}
|
|
|
|
private void next() {
|
|
if (!words.isEmpty()) {
|
|
text = words.remove(0);
|
|
if (text.startsWith("/")) {
|
|
token = Token.COMMAND;
|
|
} else {
|
|
Token t = lookup.get(text);
|
|
if (t != null) {
|
|
token = t;
|
|
text = "";
|
|
} else {
|
|
token = Token.NAME;
|
|
}
|
|
}
|
|
} else {
|
|
token = Token.EOL;
|
|
text = "";
|
|
}
|
|
// System.out.printf("%s: %s\n", token, text);
|
|
}
|
|
|
|
private Parser(String text) {
|
|
text = text.trim();
|
|
StringTokenizer st = new StringTokenizer(text, " \t,=", true);
|
|
while (st.hasMoreElements()) {
|
|
String t = st.nextToken().trim();
|
|
if (!t.equals("")) {
|
|
words.add(t);
|
|
}
|
|
}
|
|
}
|
|
private final List<String> words = new LinkedList<String>();
|
|
private String text;
|
|
private Token token;
|
|
private Command cmd;
|
|
private static final Map<String, Token> lookup = new HashMap<String, Token>();
|
|
|
|
private enum Token {
|
|
|
|
COMMAND, WHERE, RETURN, EOL, NOT, AND, OR, NAME, EQUALS, MORE, LESS, COMMA;
|
|
}
|
|
|
|
static {
|
|
lookup.put("where", Token.WHERE);
|
|
lookup.put("return", Token.RETURN);
|
|
lookup.put("not", Token.NOT);
|
|
lookup.put("and", Token.AND);
|
|
lookup.put("or", Token.OR);
|
|
lookup.put("=", Token.EQUALS);
|
|
lookup.put(">", Token.MORE);
|
|
lookup.put("<", Token.LESS);
|
|
lookup.put(",", Token.COMMA);
|
|
}
|
|
}
|