From 434205ebc29c9da561a6c1cd4f869cc6d2b9bec4 Mon Sep 17 00:00:00 2001 From: megacz Date: Fri, 30 Jan 2004 07:44:07 +0000 Subject: [PATCH] 2004/01/08 05:02:19 darcs-hash:20040130074407-2ba56-d3d9b7423f033c8daa6329ed6265d79dc3cbb6e6.gz --- src/org/xwt/js/ByteCodes.java | 5 +- src/org/xwt/js/Interpreter.java | 22 ++++++++ src/org/xwt/js/JSFunction.java | 1 + src/org/xwt/js/Lexer.java | 3 +- src/org/xwt/js/Parser.java | 45 +++++++++++++++++ src/org/xwt/js/Tokens.java | 7 +-- src/org/xwt/util/Grammar.java | 105 +++++++++++++++++++++++++++++++++++++++ 7 files changed, 183 insertions(+), 5 deletions(-) create mode 100644 src/org/xwt/util/Grammar.java diff --git a/src/org/xwt/js/ByteCodes.java b/src/org/xwt/js/ByteCodes.java index e270885..4a603a7 100644 --- a/src/org/xwt/js/ByteCodes.java +++ b/src/org/xwt/js/ByteCodes.java @@ -82,10 +82,13 @@ interface ByteCodes { /** finish a finally block and carry out whatever instruction initiated the finally block */ public static final byte FINALLY_DONE = -24; + /** finish a finally block and carry out whatever instruction initiated the finally block */ + public static final byte MAKE_GRAMMAR = -25; + public static final String[] bytecodeToString = new String[] { "", "", "LITERAL", "ARRAY", "OBJECT", "NEWFUNCTION", "DECLARE", "TOPSCOPE", "GET", "GET_PRESERVE", "PUT", "JT", "JF", "JMP", "POP", "CALL", "PUSHKEYS", "SWAP", "NEWSCOPE", "OLDSCOPE", "DUP", "LABEL", "LOOP", "CALLMETHOD", - "FINALLY_DONE" + "FINALLY_DONE", "MAKE_GRAMMAR" }; } diff --git a/src/org/xwt/js/Interpreter.java b/src/org/xwt/js/Interpreter.java index ae8dc1f..32bf03e 100644 --- a/src/org/xwt/js/Interpreter.java +++ b/src/org/xwt/js/Interpreter.java @@ -356,6 +356,28 @@ class Interpreter implements ByteCodes, Tokens { case THROW: throw new JSExn(stack.pop()); + case MAKE_GRAMMAR: { + final Grammar r = (Grammar)arg; + final JSScope final_scope = scope; + Grammar r2 = new Grammar() { + public int match(String s, int start, Hash v, JSScope scope) throws JSExn { + return r.match(s, start, v, final_scope); + } + public int matchAndWrite(String s, int start, Hash v, JSScope scope, String key) throws JSExn { + return r.matchAndWrite(s, start, v, final_scope, key); + } + public Object call(Object a0, Object a1, Object a2, Object[] rest, int nargs) throws JSExn { + Hash v = new Hash(); + r.matchAndWrite((String)a0, 0, v, final_scope, "foo"); + return v.get("foo"); + } + }; + Object obj = stack.pop(); + if (obj != null && obj instanceof Grammar) r2 = new Grammar.Alternative((Grammar)obj, r2); + stack.push(r2); + break; + } + case ASSIGN_SUB: case ASSIGN_ADD: { Object val = stack.pop(); Object key = stack.pop(); diff --git a/src/org/xwt/js/JSFunction.java b/src/org/xwt/js/JSFunction.java index 2f24e9a..d200909 100644 --- a/src/org/xwt/js/JSFunction.java +++ b/src/org/xwt/js/JSFunction.java @@ -72,6 +72,7 @@ public class JSFunction extends JS implements ByteCodes, Tokens, org.xwt.Schedul return cx.resume(); } + public JSScope getParentScope() { return parentScope; } // Adding and Altering Bytecodes /////////////////////////////////////////////////// diff --git a/src/org/xwt/js/Lexer.java b/src/org/xwt/js/Lexer.java index 6e541c1..b8ce343 100644 --- a/src/org/xwt/js/Lexer.java +++ b/src/org/xwt/js/Lexer.java @@ -265,7 +265,7 @@ class Lexer implements Tokens { case ')': return RP; case ',': return COMMA; case '?': return HOOK; - case ':': return COLON; + case ':': return !in.match(':') ? COLON : in.match('=') ? GRAMMAR : le(":: is not a valid token"); case '.': return DOT; case '|': return in.match('|') ? OR : (in.match('=') ? ASSIGN_BITOR : BITOR); case '^': return in.match('=') ? ASSIGN_BITXOR : BITXOR; @@ -295,6 +295,7 @@ class Lexer implements Tokens { } } + private int le(String s) throws LexerException { if (true) throw new LexerException(s); return 0; } // SmartReader //////////////////////////////////////////////////////////////// diff --git a/src/org/xwt/js/Parser.java b/src/org/xwt/js/Parser.java index 4bf273d..66084e0 100644 --- a/src/org/xwt/js/Parser.java +++ b/src/org/xwt/js/Parser.java @@ -314,6 +314,36 @@ class Parser extends Lexer implements ByteCodes { continueExpr(b, minPrecedence); } + private Grammar parseGrammar(Grammar g) throws IOException { + int tok = getToken(); + if (g != null) + switch(tok) { + case BITOR: return new Grammar.Alternative(g, parseGrammar(null)); + case ADD: return new Grammar.Repetition(g, 1, Integer.MAX_VALUE); + case MUL: return new Grammar.Repetition(g, 0, Integer.MAX_VALUE); + case HOOK: return new Grammar.Repetition(g, 0, 1); + } + Grammar g0 = null; + switch(tok) { + //case NUMBER: g0 = new Grammar.Literal(number); break; + case NAME: g0 = new Grammar.Reference(string); break; + case STRING: + g0 = new Grammar.Literal(string); + if (peekToken() == DOT) { + String old = string; + consume(DOT); + consume(DOT); + consume(STRING); + if (old.length() != 1 || string.length() != 1) throw pe("literal ranges must be single-char strings"); + g0 = new Grammar.Range(old.charAt(0), string.charAt(0)); + } + break; + case LP: g0 = parseGrammar(null); consume(RP); break; + default: pushBackToken(); return g; + } + if (g == null) return parseGrammar(g0); + return new Grammar.Juxtaposition(g, g0); + } /** * Assuming that a complete assignable (lvalue) has just been @@ -334,6 +364,21 @@ class Parser extends Lexer implements ByteCodes { // force the default case tok = -1; switch(tok) { + + case GRAMMAR: { + b.add(parserLine, GET_PRESERVE); + Grammar g = parseGrammar(null); + if (peekToken() == LC) { + g.action = new JSFunction(sourceName, parserLine, null); + parseBlock(g.action); + g.action.add(parserLine, LITERAL, null); // in case we "fall out the bottom", return NULL + g.action.add(parserLine, RETURN); + } + b.add(parserLine, MAKE_GRAMMAR, g); + b.add(parserLine, PUT); + break; + } + case ASSIGN_BITOR: case ASSIGN_BITXOR: case ASSIGN_BITAND: case ASSIGN_LSH: case ASSIGN_RSH: case ASSIGN_URSH: case ASSIGN_MUL: case ASSIGN_DIV: case ASSIGN_MOD: case ASSIGN_ADD: case ASSIGN_SUB: { if (tok != ASSIGN_ADD && tok != ASSIGN_SUB) b.add(parserLine, GET_PRESERVE); diff --git a/src/org/xwt/js/Tokens.java b/src/org/xwt/js/Tokens.java index fc70577..d61b17e 100644 --- a/src/org/xwt/js/Tokens.java +++ b/src/org/xwt/js/Tokens.java @@ -93,9 +93,10 @@ interface Tokens { public static final int CATCH = 75; // catch keyword public static final int FINALLY = 76; // finally keyword public static final int RESERVED = 77; // reserved keyword + public static final int GRAMMAR = 78; // the grammar-definition operator (::=) - public static final int MAX_TOKEN = RESERVED; - + public static final int MAX_TOKEN = GRAMMAR; + public final static String[] codeToString = new String[] { "BITOR", "ASSIGN_BITOR", "BITXOR", "ASSIGN_BITXOR", "BITAND", "ASSIGN_BITAND", "LSH", "ASSIGN_LSH", "RSH", "ASSIGN_RSH", @@ -108,7 +109,7 @@ interface Tokens { "SEMI", "LB", "RB", "LC", "RC", "LP", "RP", "COMMA", "ASSIGN", "HOOK", "COLON", "INC", "DEC", "DOT", "FUNCTION", "IF", "ELSE", "SWITCH", "CASE", "DEFAULT", "WHILE", "DO", "FOR", - "VAR", "WITH", "CATCH", "FINALLY", "RESERVED" + "VAR", "WITH", "CATCH", "FINALLY", "RESERVED", "GRAMMAR" }; } diff --git a/src/org/xwt/util/Grammar.java b/src/org/xwt/util/Grammar.java new file mode 100644 index 0000000..678a63a --- /dev/null +++ b/src/org/xwt/util/Grammar.java @@ -0,0 +1,105 @@ +package org.xwt.util; + +import java.util.*; +import java.io.*; +import org.xwt.js.*; + +public abstract class Grammar extends JS { + + public JSFunction action = null; + public Grammar() { } + + // means we call()ed a Grammar that hasn't been bound to a scope yet + public Object call(Object a0, Object a1, Object a2, Object[] rest, int nargs) throws JSExn { + throw new Error("this should never happen"); + } + + public abstract int match(String s, int start, Hash v, JSScope scope) throws JSExn; + public int matchAndWrite(final String s, final int start, Hash v, JSScope scope, String key) throws JSExn { + final Hash v2 = new Hash(); + final int ret = match(s, start, v2, scope); + if (ret == -1) return -1; + Object result = action == null ? + s.substring(start, ret) : + action.cloneWithNewParentScope(new JSScope(scope) { + public Object get(Object key) throws JSExn { + if (v2.get(key) != null) return v2.get(key); + if (key.equals("whole")) return s.substring(start, ret); + return super.get(key); + } + }).call(null, null, null, null, 0); + if (key != null) { + Object old = v.get(key); + if (old == null) { } + else if (old instanceof JSArray) { ((JSArray)old).addElement(result); result = old; } + else { JSArray j = new JSArray(); j.addElement(old); j.addElement(result); result = j; } + v.put(key, result); + } + return ret; + } + + public static class Alternative extends Grammar { + private Grammar r1, r2; + public Alternative(Grammar r1, Grammar r2) { this.r1 = r1; this.r2 = r2; } + public int match(String s, int start, Hash v, JSScope r) throws JSExn { + int s1 = r1.match(s, start, v, r); + if (s1 != -1) return s1; + int s2 = r2.match(s, start, v, r); + if (s2 != -1) return s2; + return -1; + } + } + + public static class Juxtaposition extends Grammar { + private Grammar r1, r2; + public Juxtaposition(Grammar r1, Grammar r2) { this.r1 = r1; this.r2 = r2; } + public int match(String s, int start, Hash v, JSScope r) throws JSExn { + int s1 = r1.match(s, start, v, r); + if (s1 == -1) return -1; + int s2 = r2.match(s, s1, v, r); + if (s2 == -1) return -1; + return s2; + } + } + + public static class Repetition extends Grammar { + private Grammar r1; + private int min, max; + public Repetition(Grammar r1, int min, int max) { this.r1 = r1; this.min = min; this.max = max; } + public int match(String s, int start, Hash v, JSScope r) throws JSExn { + int i; + for(i=0; i= min && s.charAt(start) <= max)) return -1; + return start + 1; + } + } + + public static class Reference extends Grammar { + String key; + public Reference(String key) { this.key = key; } + public int match(String s, int start, Hash v, JSScope scope) throws JSExn { + return ((Grammar)scope.get(key)).matchAndWrite(s, start, v, scope, key); + } + } +} -- 1.7.10.4