java/ch/wlkl/wsh/Parser.java
package ch.wlkl.wsh;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class Parser extends Top {
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 number = Pattern.compile("[+-]?((\\d+(\\.\\d*)?)|(\\.\\d+))");
public static final Pattern shName = Pattern.compile("[\\w&&[^\\d]][\\w]*");
public static final Pattern string = Pattern.compile("\"([^\"]|\"\")*\"|'([^']|'')*'");
public static final Pattern notDo = Pattern.compile("[^$]+");
public static final Pattern shWord = Pattern.compile("[^${}=?:\\s]+");
Read<String> in = null;
boolean atEnd = true;
int inIx, lineBeg, lineEnd, charIx;
public String src, tok, key, val;
String lines;
Matcher match = space.matcher("");
public Parser(Read<String> i) {
reset(i);
}
public Parser(String i) {
reset(i);
}
void reset () {
in = null;
lines = "";
src = "";
inIx = charIx = -1;
lineBeg = lineEnd = 0;
atEnd = false;
tok = key = val = null;
}
public void reset(Read<String> i) {
reset();
in = i;
in.open("r");
switchLine();
}
public void reset(String ss) {
reset();
lines = ss;
switchLine();
}
public boolean switchLine() {
if (atEnd)
return false;
tok = null;
if (lineEnd >= lines.length()) {
if (in == null || null == (lines = in.read())) {
atEnd = true;
charIx = src.length();
return false;
} else
inIx++;
lineEnd = 0;
}
match.usePattern(eol).reset(lines);
if (match.find(lineBeg = lineEnd)) {
src = lines.substring(lineBeg, match.start());
lineEnd = match.end();
} else {
src = lines.substring(lineBeg);
lineEnd = lines.length();
}
charIx = 0;
match.reset(src);
return true;
}
public boolean atEnd() {
return atEnd;
}
public boolean atEol() {
return charIx >= src.length() || src.charAt(charIx) == '\n' || src.charAt(charIx) == '\r';
}
public boolean nl() {
return atEol() ? switchLine() : false;
}
public boolean next(Pattern pat) {
match.region(charIx, src.length());
match.usePattern(pat);
if (match.lookingAt()) {
tok = match.group();
charIx = match.end();
sTrc(null, "next(" + pat + ") found " + tok);
return true;
} else {
tok = null;
return false;
}
}
public String look() {
return src.substring(charIx);
}
public String look(int len) {
return src.substring(charIx, charIx + len > src.length() ? src.length() : charIx + len);
}
public boolean lit(String lit) {
if (charIx + lit.length() > src.length() || ! lit.equals(src.substring(charIx, charIx +lit.length()))) {
tok = null;
return false;
} else {
tok = lit;
charIx += lit.length();
return true;
}
}
public String chars(String chars) {
String res = "";
for (int cx=0; cx<chars.length();cx++) {
if (lit(chars.substring(cx, cx+1)))
res += chars.charAt(cx);
}
return res;
}
public boolean comment() {
int depth = 0;
boolean found = false;
while (true) {
if (lit("$**")) {
charIx = src.length(); // move to end of line, just before nl
} else if (lit("$*+")) {
switchLine(); // move to next line
} else if (lit("$*(")) {
depth++;
} else if (depth == 0){
return found;
} else if (lit("$*)")) {
depth--;
} else if (lit("$")) {
next(string); // skip over $ and possibly string
} else if (next(notDo) || nl()) {
} else {
fail("source end (depth " + depth + ") in comment");
}
found = true;
}
}
public boolean spaceComment() {
boolean found = false;
while (next(space) || comment())
found = true;
return found;
}
public boolean spaceNlComment() {
boolean found = false;
while (next(space) || nl() || comment())
found = true;
return found;
}
public boolean keyValue() {
spaceComment();
if ( ! next(notSpace))
return false;
if (tok.startsWith("-")) {
key = tok.length() > 1 ? tok.substring(1,2) : "";
val = tok.length() > 2 ? tok.substring(2) : "";
} else {
key = null;
val = tok;
}
return true;
}
public void fail(String msg) {
super.fail(msg + "\ntok " + tok + " charIx " + (lineBeg + charIx) + ": " + src.substring(charIx) + "\nin line " + inIx + ": " + lines);
}
public String loc () {
return String.valueOf(inIx) + "." + '.'+ (lineBeg + charIx);
}
public static int matchesEnd(CharSequence src, Pattern pat) {
Matcher match = pat.matcher(src);
return match.lookingAt() ? match.end() : 0;
}
public static int findEndStart(CharSequence src, Pattern pat) {
Matcher match = pat.matcher(src);
while (match.find()) {
if (match.hitEnd())
return match.start();
}
return src.length();
}
public static String skipScan(String src, Pattern ski, Pattern sca) {
Matcher match = ski.matcher(src);
if (match.lookingAt())
match.region(match.end(), src.length());
match.usePattern(sca);
return match.lookingAt() ? match.group() : null;
}
}