Re-wrote scanning and parsing to handle problems from issues #3 and #4

This commit is contained in:
GideonLeGrange 2014-04-14 14:42:51 +02:00
parent 2633088303
commit 7c73559bb1
3 changed files with 74 additions and 88 deletions

View File

@ -1,23 +0,0 @@
/** A Mikrotik API Command grammar */
grammar Command;
line: command param* where? retrn? ;
command: CMD ;
param: NAME ('=' text )? ;
text: (QUOTED|VALUE) ;
where: 'where' expr ;
expr: ( eqExpr | hasExpr | moreExpr | lessExpr ) binExpr? ;
binExpr: andExpr | orExpr ;
eqExpr: NAME '=' text ;
hasExpr: NAME ;
moreExpr: NAME '>' text;
lessExpr: NAME '<' text;
andExpr: expr 'and' expr ;
orExpr: expr 'or' expr ;
retrn: 'returns' NAME (',' NAME )* ;
NAME : ('a'..'z'|'A'..'Z'|'-')+ ;
CMD : (('/')(NAME))+ ;
QUOTED : ('"')(.*?)('"') ;
VALUE : (~[ \t\r\n="])+ ;
WS: [ \n\t\r]+ -> skip;

View File

@ -1,12 +1,9 @@
package me.legrange.mikrotik.impl;
import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Scanner;
import java.util.StringTokenizer;
import me.legrange.mikrotik.impl.Scanner.Token;
/**
* Parse the pseudo-command line into command objects.
@ -14,6 +11,15 @@ import java.util.StringTokenizer;
*/
class Parser {
public static void main(String...args) throws Exception {
/* System.out.println(parse("/system/reboot"));
System.out.println(parse("/interface/print where type=ether"));
System.out.println(parse("/interface/wireless/monitor .id=wlan1"));
System.out.println(parse("/ip/firewall/filter/add action=drop chain=forward in-interface=gre1 protocol=udp dst-port=78,80"));
System.out.println(parse("/file/print detail where name=conf.rsc"));
System.out.println(parse("/ip/firewall/filter/add action=drop chain=forward in-interface=aps_hs protocol=udp dst-port=78,80,32")); */
System.out.println(parse("/interface/gre/set .id=gre1 comment=\"test coment\""));
}
/** parse the given bit of text into a Command object */
static Command parse(String text) throws ParseException {
Parser parser = new Parser(text);
@ -22,10 +28,7 @@ class Parser {
/** 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();
command();
while (!((token == Token.WHERE) || (token == Token.RETURN) || (token == Token.EOL))) {
param();
}
@ -38,20 +41,36 @@ class Parser {
expect(Token.EOL);
return cmd;
}
private void command() throws ParseException {
StringBuilder path = new StringBuilder();
do {
expect(Token.SLASH);
path.append("/");
next();
expect(Token.TEXT);
path.append(text);
next();
} while (token == Token.SLASH);
cmd = new Command(path.toString());
}
private void param() throws ParseException {
String name = text;
next();
if (token == Token.EQUALS) {
next();
expect(Token.NAME);
String val = text;
expect(Token.TEXT);
StringBuilder val = new StringBuilder(text);
next();
while (token == Token.COMMA) {
val.append(",");
next();
expect(Token.TEXT);
val.append(text);
next();
val = val + "," + text;
}
cmd.addParameter(new Parameter(name, val));
cmd.addParameter(new Parameter(name, val.toString()));
}
else {
cmd.addParameter(new Parameter(name));
@ -64,12 +83,12 @@ class Parser {
}
private void expr() throws ParseException {
expect(Token.NOT, Token.NAME);
expect(Token.NOT, Token.TEXT);
switch (token) {
case NOT:
notExpr();
break;
case NAME: {
case TEXT: {
String name = text;
next();
expect(Token.EQUALS, Token.LESS, Token.MORE);
@ -116,19 +135,20 @@ class Parser {
cmd.addQuery("?#!");
}
private void eqExpr(String name) {
private void eqExpr(String name) throws ParseException {
next(); // eat =
expect(Token.TEXT);
cmd.addQuery(String.format("?%s=%s", name, text));
next();
}
private void lessExpr(String name) {
private void lessExpr(String name) throws ScanException {
next(); // eat <
cmd.addQuery(String.format("?<%s=%s", name, text));
next();
}
private void moreExpr(String name) {
private void moreExpr(String name) throws ScanException {
next(); // eat >
cmd.addQuery(String.format("?>%s=%s", name, text));
next();
@ -140,8 +160,8 @@ class Parser {
private void returns() throws ParseException {
next();
expect(Token.NAME);
List<String> props = new LinkedList<String>();
expect(Token.TEXT);
List<String> props = new LinkedList<>();
while (!(token == Token.EOL)) {
if (token != Token.COMMA) {
props.add(text);
@ -158,59 +178,27 @@ class Parser {
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 = "";
private void next() throws ScanException {
// Token was = token;
token = scanner.next();
// System.out.printf("'%s' => '%s'\n", was, token);
while (token == Token.WS) {
token = scanner.next();
}
// System.out.printf("%s: %s\n", token, text);
text = scanner.text();
}
private Parser(String line) {
private Parser(String line) throws ScanException {
line = line.trim();
StringTokenizer st = new StringTokenizer(line, " \t,=", true);
boolean quote = false;
while (st.hasMoreElements()) {
String t = st.nextToken().trim();
if (!t.equals("")) {
words.add(t);
}
}
scanner = new Scanner(line);
next();
}
private final List<String> words = new LinkedList<String>();
private String text;
private final Scanner scanner;
private Token token;
private String text;
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);
}
}

View File

@ -0,0 +1,21 @@
package me.legrange.mikrotik.impl;
import me.legrange.mikrotik.MikrotikApiException;
/**
* Exception thrown if the scanner encounters an error while scanning a command line.
* @author GideonLeGrange
*/
public class ScanException extends ParseException {
ScanException(String msg) {
super(msg);
}
ScanException(String msg, Throwable err) {
super(msg, err);
}
}