java/ch/wlkl/wsm/Parser.java
package ch.wlkl.wsm;
import static ch.wlkl.env.Env.*;
import java.util.Arrays;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class Parser {
public static final Pattern eol = Pattern.compile("(\r\n)|\r|\n");
public static final Pattern space = Pattern.compile("\\s+");
public static final Pattern notSpace = Pattern.compile("\\S+");
public static final Pattern notStarSlash = Pattern.compile("[^/*]*");
public static final Pattern number = Pattern.compile("[+-]?((\\d+(\\.\\d*)?)|(\\.\\d+))");
public static final Pattern name = Pattern.compile("[\\w&&[^\\d]][\\w]*");
public static final Pattern string = Pattern.compile("\"([^\\\\\"]|\\\\.)*\"");
public static final Pattern shWord = Pattern.compile("[^${}=�:\\s]+");
int cx;
public String src, tok;
Matcher match = space.matcher("");
public Parser(String s) {
reset(s);
}
void reset (String s) {
src = s;
match.reset(src);
cx = 0;
tok = null;
}
public boolean next(Pattern pat) {
match.region(cx, src.length());
match.usePattern(pat);
if (match.lookingAt()) {
tok = match.group();
cx = match.end();
return true;
} else {
tok = null;
return false;
}
}
public void back() {
cx -= tok.length();
tok = null;
}
public String name(String... names) {
int old = cx;
if (next(name)) {
for (String nm : names) {
if (tok.equals(nm))
return nm;
}
}
cx = old;
fail(Arrays.toString(names) + " expected");
return null;
}
public String look() {
return src.substring(cx);
}
public String look(int len) {
return src.substring(cx, cx + len > src.length() ? src.length() : cx + len);
}
public boolean lit(String lit) {
if (cx + lit.length() > src.length() || ! lit.equals(src.substring(cx, cx +lit.length()))) {
tok = null;
return false;
} else {
tok = lit;
cx += lit.length();
return true;
}
}
public boolean comment() {
if (! lit("/*"))
return false;
int depth = 1;
while (depth > 0) {
next(notStarSlash);
if (lit("/*"))
depth++;
else if (lit("*/"))
depth--;
}
return true;
}
public boolean spaceComment() {
boolean found = false;
while (next(space) || comment())
found = true;
return found;
}
public boolean spaceNlComment() {
boolean found = false;
while (next(space) || comment())
found = true;
return found;
}
public boolean end() {
return cx >= src.length();
}
public Parser skip() {
spaceNlComment();
return this;
}
public void fail(String msg) {
err(msg + "\ntok " + tok + " cx " + cx + ": " + src.substring(cx) + "\nin line " + src);
}
final private static Matcher xQuoteMatcher = Pattern.compile("[^\"\\\\\n]+").matcher("");
public static String xQuote(String src) {
if (src == null)
return "\"\"";
StringBuffer buf = new StringBuffer("\"");
int nx = 0;
xQuoteMatcher.reset(src);
while (true) {
if (xQuoteMatcher.lookingAt()) {
buf.append(xQuoteMatcher.group());
nx = xQuoteMatcher.end();
}
if (nx >= src.length())
return buf.append('"').toString();
buf.append('\\').append(src.charAt(nx) == '\n' ? 'n' : src.charAt(nx));
xQuoteMatcher.region(++nx, src.length());
}
}
public static String xUnquote(String src) {
if (src == null || src.length() <= 1)
err("cannot unquote this string: <" + src + ">");
StringBuffer buf = new StringBuffer("");
final char qu = src.charAt(0);
char c = 0;
int sx = 1, qx = 0, bx = 0;
while (true) {
if (qx < sx)
if ((qx = src.indexOf(qu, sx)) < 0)
qx = src.length();
if (bx < sx)
if ((bx = src.indexOf('\\', sx)) < 0)
bx = src.length();
if (bx < qx) {
if (bx + 1>= src.length())
err("backslash at end of String: <" + src + ">");
buf.append(src, sx, bx).append((c = src.charAt(bx+1)) == 'n' ? '\n' : c == 't' ? 't' : c);
sx = bx+2;
} else {
if (qx + 1 == src.length())
return buf.append(src, sx, qx).toString();
else
err((qx >= src.length() ? "ending quote missing " : "quote with") + "in String: <" + src + ">");
}
}
}
}