From 842cef088e3cf5d141677ce5d824c98a15c203e8 Mon Sep 17 00:00:00 2001 From: david Date: Fri, 30 Jan 2004 07:41:20 +0000 Subject: [PATCH] 2003/11/13 09:57:57 darcs-hash:20040130074120-0c9ea-442c65a7b20424b81f3b2262379a483fbbbc8496.gz --- src/org/xwt/util/Preprocessor.java | 246 ++++++++++++++++++++++++++---------- 1 file changed, 180 insertions(+), 66 deletions(-) diff --git a/src/org/xwt/util/Preprocessor.java b/src/org/xwt/util/Preprocessor.java index 5232be5..5cff2d0 100644 --- a/src/org/xwt/util/Preprocessor.java +++ b/src/org/xwt/util/Preprocessor.java @@ -11,9 +11,8 @@ import java.io.*; * //#replace foo/bar baz/bop -- DUPLICATE everything between here and //#end, * replacing foo with bar and baz with bop in the *second* copy * //#switch(EXPR) -- switch on strings - * { * case "case1": - * } + * //#end * * Replacements are done on a token basis. Tokens are defined as a * sequence of characters which all belong to a single class. The @@ -24,45 +23,107 @@ import java.io.*; */ public class Preprocessor { - static Hashtable replace = new Hashtable(); - static Hashtable repeatreplace = null; - static Vector sinceLastRepeat = null; - - public static void main(String[] args) throws IOException { + public static void main(String[] args) throws Exception { BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); - String s = null; + BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out)); + + // process stdin to stdout + Preprocessor cc = new Preprocessor(br, bw); + Vector err = cc.process(); + bw.flush(); + + // handle errors + boolean errors = false; + for (int i=0; i < err.size(); i++) { if (err.get(i) instanceof Error) errors = true; System.err.println(err.get(i)); } + if (errors) throw new Exception(); + } + + private Reader r; + private Writer w; + private LineNumberReader in; + private PrintWriter out; + + private Hashtable replace = new Hashtable(); + private Hashtable repeatreplace = null; + private Vector sinceLastRepeat = null; + private Vector err = new Vector(); + + private int enumSwitch = 0; // number appended to variable used in switch implementation + + public Preprocessor(Reader reader, Writer writer) { + setReader(reader); + setWriter(writer); + } + + public void setReader(Reader reader) { r = reader; if (r != null) in = new LineNumberReader(r); } + public Reader getReader() { return r; } - while((s = br.readLine()) != null) { + public void setWriter(Writer writer) { w = writer; if (w != null) out = new PrintWriter(w); } + public Writer getWriter() { return w; } + + + /** process data from reader, write to writer, return vector of errors */ + public Vector process() throws IOException { + err.clear(); + + String s = null; +PROCESS: + while((s = in.readLine()) != null) { if (sinceLastRepeat != null) sinceLastRepeat.addElement(s); String trimmed = s.trim(); + if (trimmed.startsWith("//#define ")) { - trimmed = trimmed.substring(10).trim(); - if (trimmed.indexOf('(') >= 0 && trimmed.indexOf('(') < trimmed.indexOf(' ')) { + if (trimmed.length() == 9 || trimmed.charAt(9) != ' ') { + err.add(new Error("#define badly formed, ignored")); continue PROCESS; + } + int keyStart = indexOfNotWS(trimmed, 9); + if (keyStart == -1) { + err.add(new Error("#define requires KEY")); continue PROCESS; + } + int keyEnd = indexOfWS(trimmed, keyStart); + + int macroStart = trimmed.indexOf('('); + int macroEnd = trimmed.indexOf(')'); + if (macroStart > keyEnd) { + // no macro is defined, just make sure something dumb like KEYNA)ME hasn't been done + if (macroEnd < keyEnd) { err.add(new Error("#define key contains invalid char: ')'")); continue PROCESS; } + macroStart = macroEnd = -1; + } + + if (macroStart == 0) { + err.add(new Error("#define macro requires name")); continue PROCESS; + } else if (macroStart > 0) { + if (macroStart > macroEnd) { err.add(new Error("#define macro badly formed")); continue PROCESS; } + if (macroStart+1 == macroEnd) { err.add(new Error("#define macro requires property name")); continue PROCESS; } + JSFunctionMacro fm = new JSFunctionMacro(); - String key = trimmed.substring(0, trimmed.indexOf('(')); - String unbound = trimmed.substring(trimmed.indexOf('(') + 1, trimmed.indexOf(')')); - if (unbound.indexOf(',') == -1) { + String key = trimmed.substring(keyStart, macroStart); + String unbound = trimmed.substring(macroStart +1, macroEnd); + int unboundDiv = unbound.indexOf(','); + if (unboundDiv == -1) { fm.unbound1 = unbound; } else { - fm.unbound1 = unbound.substring(0, unbound.indexOf(',')); - fm.unbound2 = unbound.substring(unbound.indexOf(',') + 1); + fm.unbound1 = unbound.substring(0, unboundDiv); + fm.unbound2 = unbound.substring(unboundDiv +1); + if (fm.unbound1.length() == 0) { err.add(new Error("#define macro property 1 requires name")); continue PROCESS; } + if (fm.unbound2.length() == 0) { err.add(new Error("#define macro property 1 requires name")); continue PROCESS; } } - fm.expression = trimmed.substring(trimmed.indexOf(')')+1).trim(); + fm.expression = trimmed.substring(keyEnd).trim(); replace.put(key, fm); } else { - String key = trimmed.substring(0, trimmed.indexOf(' ')); - String val = trimmed.substring(trimmed.indexOf(' ')).trim(); + String key = trimmed.substring(keyStart, keyEnd); + String val = trimmed.substring(keyEnd).trim(); replace.put(key, val); } - System.out.println(); // preserve line numbers + out.println(); // preserve line numbers } else if (trimmed.startsWith("//#repeat ")) { trimmed = trimmed.substring(9); while(trimmed.charAt(trimmed.length() - 1) == '\\') { - String s2 = br.readLine().trim(); + String s2 = in.readLine().trim(); if (s2.startsWith("//")) s2 = s2.substring(2).trim(); trimmed += s2; - System.out.println(); // preserve line numbers + out.println(); // preserve line numbers } StringTokenizer st = new StringTokenizer(trimmed, " "); repeatreplace = (Hashtable)replace.clone(); @@ -73,90 +134,109 @@ public class Preprocessor { repeatreplace.put(key, val); } sinceLastRepeat = new Vector(); - System.out.println(); // preserve line numbers + out.println(); // preserve line numbers } else if (trimmed.startsWith("//#end")) { + if (sinceLastRepeat == null) { err.add(new Warning("#end orphaned")); continue PROCESS; } Hashtable save = replace; replace = repeatreplace; - System.out.println(); - for(int i=0; i= s.length()) return -1; + for (; beginIndex < s.length(); beginIndex++) { + if (s.charAt(beginIndex) == ' ') return beginIndex; + } + return s.length(); + } + + private static int indexOfNotWS(String s) { return indexOfWS(s, 0); } + private static int indexOfNotWS(String s, int beginIndex) { + if (s == null || beginIndex >= s.length()) return -1; + for (; beginIndex < s.length(); beginIndex++) { + if (s.charAt(beginIndex) != ' ') return beginIndex; + } + return -1; + } + + public class Warning { + protected String msg; + protected int line; + + public Warning() { msg = ""; } + public Warning(String m) { msg = m; if (in != null) line = in.getLineNumber(); } + + public String toString() { return "WARNING Line "+line+": "+msg; } + } + + public class Error extends Warning { + public Error() { super(); } + public Error(String m) { super(m); } + public String toString() { return "ERROR Line "+line+": "+msg; } + } + public static class JSFunctionMacro { public String unbound1 = null; public String unbound2 = null; -- 1.7.10.4