diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..79d8ebbc --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +IP/out +.idea/ + diff --git a/IP/go.sh b/IP/go.sh index 28b5e6df..4e236688 100755 --- a/IP/go.sh +++ b/IP/go.sh @@ -1,11 +1,13 @@ #echo go.sh assumed in dir ./progs -mkdir out -mkdir out/production -mkdir out/production/IP +mkdir -p out +mkdir -p out/production +mkdir -p out/production/IP export TARGET="out/production/IP" -mkdir "$TARGET" +mkdir -p "$TARGET" rm -r -f $TARGET/iProlog -rm -f progs/*.pl.nl + +#rm -f progs/*.pl.nl + javac -O -d "$TARGET" src/iProlog/*.java swipl -f pl2nl.pl -g "pl('$1'),halt" java -cp "$TARGET" iProlog.Main "progs/$1.pl" diff --git a/IP/progs/queens.pl.nl b/IP/progs/queens.pl.nl new file mode 100644 index 00000000..7b499515 --- /dev/null +++ b/IP/progs/queens.pl.nl @@ -0,0 +1,40 @@ +place_queen I _0 _1 _2 and + _0 holds list I _3 and + _1 holds list I _4 and + _2 holds list I _5 . + +place_queen I _0 _1 _2 and + _0 holds list _3 Cs and + _1 holds list _4 Us and + _2 holds list _5 Ds +if + place_queen I Cs Us Ds . + +place_queens nil _0 _1 _2 . + +place_queens _0 Cs Us _1 and + _0 holds list I Is and + _1 holds list _2 Ds +if + place_queens Is Cs _3 Ds and + _3 holds list _4 Us and + place_queen I Cs Us Ds . + +gen_places nil nil . + +gen_places _0 _1 and + _0 holds list _2 Qs and + _1 holds list _3 Ps +if + gen_places Qs Ps . + +qs Qs Ps +if + gen_places Qs Ps and + place_queens Qs Ps _0 _1 . + +goal Ps +if + qs _0 Ps and + _0 lists 0 1 2 3 4 5 6 7 8 9 10 11 . + diff --git a/IP/progs/sud4x.pl.nl b/IP/progs/sud4x.pl.nl new file mode 100644 index 00000000..7f01423d --- /dev/null +++ b/IP/progs/sud4x.pl.nl @@ -0,0 +1,63 @@ +s4x4 _0 and + _0 lists _1 _2 _3 and + _1 lists _4 _5 _6 _7 and + _4 lists S11 S12 S13 S14 and + _5 lists S21 S22 S23 S24 and + _6 lists S31 S32 S33 S34 and + _7 lists S41 S42 S43 S44 and + _2 lists _8 _9 _10 _11 and + _8 lists S11 S21 S31 S41 and + _9 lists S12 S22 S32 S42 and + _10 lists S13 S23 S33 S43 and + _11 lists S14 S24 S34 S44 and + _3 lists _12 _13 _14 _15 and + _12 lists S11 S12 S21 S22 and + _13 lists S13 S14 S23 S24 and + _14 lists S31 S32 S41 S42 and + _15 lists S33 S34 S43 S44 . + +sudoku Xss +if + s4x4 _0 and + _0 holds list Xss Xsss and + map11 permute _1 _2 and + _1 lists 1 2 3 4 and + _2 holds list Xss Xsss . + +map1x _0 _1 nil . + +map1x F Y _0 and + _0 holds list X Xs +if + F Y X and + map1x F Y Xs . + +map11 _0 _1 nil . + +map11 F X _0 and + _0 holds list Y Ys +if + map1x F X Y and + map11 F X Ys . + +permute nil nil . + +permute _0 Zs and + _0 holds list X Xs +if + permute Xs Ys and + ins X Ys Zs . + +ins X Xs _0 and + _0 holds list X Xs . + +ins X _0 _1 and + _0 holds list Y Xs and + _1 holds list Y Ys +if + ins X Xs Ys . + +goal Xss +if + sudoku Xss . + diff --git a/IP/src/iProlog/Clause.java b/IP/src/iProlog/Clause.java index b61d1950..efb4075a 100644 --- a/IP/src/iProlog/Clause.java +++ b/IP/src/iProlog/Clause.java @@ -1,20 +1,19 @@ - package iProlog; + /** * representation of a clause */ class Clause { - Clause(final int len, final int[] hgs, final int base, final int neck, final int[] xs) { - this.hgs = hgs; // head+goals pointing to cells in cs - this.base = base; // heap where this starts - this.len = len; // length of heap slice - this.neck = neck; // first after the end of the head - this.xs = xs; // indexables in head - } - - final int len; - final int[] hgs; - final int base; - final int neck; - final int[] xs; + final int len; + final int[] hgs; + final int base; + final int neck; + final int[] xs; + Clause(int len, int[] hgs, int base, int neck, int[] xs) { + this.hgs = hgs; // head+goals pointing to cells in cs + this.base = base; // heap where this starts + this.len = len; // length of heap slice + this.neck = neck; // first after the end of the head + this.xs = xs; // indexables in head + } } diff --git a/IP/src/iProlog/Engine.java b/IP/src/iProlog/Engine.java index c746ebfa..50bb9ffc 100644 --- a/IP/src/iProlog/Engine.java +++ b/IP/src/iProlog/Engine.java @@ -1,1035 +1,1017 @@ package iProlog; -import java.util.*; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.LinkedHashMap; /** * Implements execution mechanism */ class Engine { - final static int MAXIND = 3; // number of index args - final static int START_INDEX = 20; - // switches off indexing for less then START_INDEX clauses e.g. <20 - - /** - * Builds a new engine from a natural-language style assembler.nl file - */ - Engine(final String fname) { - syms = new LinkedHashMap(); - slist = new ArrayList(); - - makeHeap(); - - trail = new IntStack(); - ustack = new IntStack(); - - clauses = dload(fname); - - cls = toNums(clauses); - - query = init(); - - vmaps = vcreate(MAXIND); - imaps = index(clauses, vmaps); - } - - /** - * trimmed down clauses ready to be quickly relocated to the heap - */ - final Clause[] clauses; - - final int[] cls; - /** symbol table made of map + reverse map from ints to syms */ - - final LinkedHashMap syms; - final private ArrayList slist; - - /** runtime areas: - * - * the heap contains code for and clauses their their copies - * created during execution - * - * the trail is an undo list for variable bindings - * that facilitates retrying failed goals with alternative - * matching clauses - * - * the unification stack ustack helps handling term unification non-recursively - * - * the spines stack contains abstractions of clauses and goals and performs the - * functions of both a choice-point stack and goal stack - * - * imaps: contains indexes for up toMAXIND>0 arg positions (0 for pred symbol itself) - * - * vmaps: contains clause numbers for which vars occur in indexed arg positions - */ - - private int heap[]; - private int top; - static int MINSIZE = 1 << 15; // power of 2 - - final private IntStack trail; - final private IntStack ustack; - final private ObStack spines = new ObStack(); - - Spine query; - - final IMap[] imaps; - final IntMap[] vmaps; - - /** - * tags of our heap cells - that can also be seen as - * instruction codes in a compiled implementation - */ - final private static int V = 0; - final private static int U = 1; - final private static int R = 2; - - final private static int C = 3; - final private static int N = 4; - - final private static int A = 5; - - // G - ground? - - final private static int BAD = 7; - - /** - * tags an integer value while fliping it into a negative - * number to ensure that untagged cells are always negative and the tagged - * ones are always positive - a simple way to ensure we do not mix them up - * at runtime - */ - final private static int tag(final int t, final int w) { - return -((w << 3) + t); - } - - /** - * removes tag after flipping sign - */ - final private static int detag(final int w) { - return -w >> 3; - } - - /** - * extracts the tag of a cell - */ - final private static int tagOf(final int w) { - return -w & 7; - } - - /** - * places an identifier in the symbol table - */ - final private int addSym(final String sym) { - Integer I = syms.get(sym); - if (null == I) { - final int i = syms.size(); - I = new Integer(i); - syms.put(sym, I); - slist.add(sym); + private static final int MAXIND = 3; // number of index args + private static final int START_INDEX = 20; + // switches off indexing for less then START_INDEX clauses e.g. <20 + /** + * tags of our heap cells - that can also be seen as + * instruction codes in a compiled implementation + */ + private static final int V = 0; + private static final int U = 1; + private static final int R = 2; + private static final int C = 3; + private static final int N = 4; + private static final int A = 5; + private static final int BAD = 7; + private static final int MINSIZE = 1 << 15; // power of 2 + /** + * trimmed down clauses ready to be quickly relocated to the heap + */ + final Clause[] clauses; + private final int[] cls; + /** + * symbol table made of map + reverse map from ints to syms + */ + + final LinkedHashMap syms; + private final IMap[] imaps; + private final IntMap[] vmaps; + private final ArrayList slist; + private final IntStack trail; + private final IntStack ustack; + private final ObStack spines = new ObStack<>(); + private Spine query; + /** + * runtime areas: + *

+ * the heap contains code for and clauses their their copies + * created during execution + *

+ * the trail is an undo list for variable bindings + * that facilitates retrying failed goals with alternative + * matching clauses + *

+ * the unification stack ustack helps handling term unification non-recursively + *

+ * the spines stack contains abstractions of clauses and goals and performs the + * functions of both a choice-point stack and goal stack + *

+ * imaps: contains indexes for up toMAXIND>0 arg positions (0 for pred symbol itself) + *

+ * vmaps: contains clause numbers for which vars occur in indexed arg positions + */ + + private int heap[]; + private int top; + + // G - ground? + + /** + * Builds a new engine from a natural-language style assembler.nl file + */ + Engine(String fname) { + syms = new LinkedHashMap<>(); + slist = new ArrayList<>(); + + makeHeap(); + + trail = new IntStack(); + ustack = new IntStack(); + + clauses = dload(fname); + + cls = toNums(clauses); + + query = init(); + + vmaps = vcreate(MAXIND); + imaps = index(clauses, vmaps); } - return I.intValue(); - } - - /** - * returns the symbol associated to an integer index - * in the symbol table - */ - final private String getSym(final int w) { - if (w < 0 || w >= slist.size()) - return "BADSYMREF=" + w; - return slist.get(w); - } - - private final void makeHeap() { - makeHeap(MINSIZE); - } - - private final void makeHeap(final int size) { - heap = new int[size]; - clear(); - } - - private final int getTop() { - return top; - } - - private final int setTop(final int top) { - return this.top = top; - } - - private final void clear() { - //for (int i = 0; i <= top; i++) - //heap[i] = 0; - top = -1; - } - - /** - * Pushes an element - top is incremented frirst than the - * element is assigned. This means top point to the last assigned - * element - which can be returned with peek(). - */ - private final void push(final int i) { - heap[++top] = i; - } - - final int size() { - return top + 1; - } - - /** - * dynamic array operation: doubles when full - */ - private final void expand() { - final int l = heap.length; - final int[] newstack = new int[l << 1]; - - System.arraycopy(heap, 0, newstack, 0, l); - heap = newstack; - } - - private void ensureSize(final int more) { - if (1 + top + more >= heap.length) { - expand(); + + /** + * tags an integer value while fliping it into a negative + * number to ensure that untagged cells are always negative and the tagged + * ones are always positive - a simple way to ensure we do not mix them up + * at runtime + */ + private static final int tag(int t, int w) { + return -((w << 3) + t); } - } - - /** - * expands a "Xs lists .." statements to "Xs holds" statements - */ - - private final static ArrayList maybeExpand(final ArrayList Ws) { - final String W = Ws.get(0); - if (W.length() < 2 || !"l:".equals(W.substring(0, 2))) - return null; - - final int l = Ws.size(); - final ArrayList Rss = new ArrayList(); - final String V = W.substring(2); - for (int i = 1; i < l; i++) { - final String[] Rs = new String[4]; - final String Vi = 1 == i ? V : V + "__" + (i - 1); - final String Vii = V + "__" + i; - Rs[0] = "h:" + Vi; - Rs[1] = "c:list"; - Rs[2] = Ws.get(i); - Rs[3] = i == l - 1 ? "c:nil" : "v:" + Vii; - Rss.add(Rs); + + /** + * removes tag after flipping sign + */ + private static final int detag(int w) { + return -w >> 3; } - return Rss; - } + /** + * extracts the tag of a cell + */ + private static final int tagOf(int w) { + return -w & 7; + } - /** - * expands, if needed, "lists" statements in sequence of statements - */ - private final static ArrayList mapExpand(final ArrayList> Wss) { - final ArrayList Rss = new ArrayList(); - for (final ArrayList Ws : Wss) { + /** + * expands a "Xs lists .." statements to "Xs holds" statements + */ + + private static final ArrayList maybeExpand(ArrayList Ws) { + String W = Ws.get(0); + if (W.length() < 2 || !"l:".equals(W.substring(0, 2))) + return null; + + int l = Ws.size(); + ArrayList Rss = new ArrayList<>(); + String V = W.substring(2); + for (int i = 1; i < l; i++) { + String[] Rs = new String[4]; + String Vi = 1 == i ? V : V + "__" + (i - 1); + String Vii = V + "__" + i; + Rs[0] = "h:" + Vi; + Rs[1] = "c:list"; + Rs[2] = Ws.get(i); + Rs[3] = i == l - 1 ? "c:nil" : "v:" + Vii; + Rss.add(Rs); + } + return Rss; - final ArrayList Hss = maybeExpand(Ws); + } - if (null == Hss) { - final String[] ws = new String[Ws.size()]; - for (int i = 0; i < ws.length; i++) { - ws[i] = Ws.get(i); + /** + * expands, if needed, "lists" statements in sequence of statements + */ + private static final ArrayList mapExpand(ArrayList> Wss) { + ArrayList Rss = new ArrayList<>(); + for (ArrayList Ws : Wss) { + + ArrayList Hss = maybeExpand(Ws); + + if (null == Hss) { + String[] ws = new String[Ws.size()]; + for (int i = 0; i < ws.length; i++) { + ws[i] = Ws.get(i); + } + Rss.add(ws); + } else { + Rss.addAll(Hss); + } } - Rss.add(ws); - } else { - for (final String[] X : Hss) { - Rss.add(X); + return Rss; + } + + private static final int[] toNums(Clause[] clauses) { + int l = clauses.length; + int[] cls = new int[l]; + for (int i = 0; i < l; i++) { + cls[i] = i; } - } + return cls; } - return Rss; - } - /** - * loads a program from a .nl file of - * "natural language" equivalents of Prolog/HiLog statements - */ - Clause[] dload(final String s) { - final boolean fromFile = true; - final ArrayList>> Wsss = Toks.toSentences(s, fromFile); + /** + * true if cell x is a variable + * assumes that variables are tagged with 0 or 1 + */ + private static final boolean isVAR(int x) { + //final int t = tagOf(x); + //return V == t || U == t; + return tagOf(x) < 2; + } - final ArrayList Cs = new ArrayList(); + /** + * extracts an integer array pointing to + * the skeleton of a clause: a cell + * pointing to its head followed by cells pointing to its body's + * goals + */ + static int[] getSpine(int[] cs) { + int a = cs[1]; + int w = detag(a); + int[] rs = new int[w - 1]; + for (int i = 0; i < w - 1; i++) { + int x = cs[3 + i]; + int t = tagOf(x); + if (R != t) { + Main.pp("*** getSpine: unexpected tag=" + t); + return null; + } + rs[i] = detag(x); + } + return rs; + } - for (final ArrayList> Wss : Wsss) { - // clause starts here + /** + * relocates a variable or array reference cell by b + * assumes var/ref codes V,U,R are 0,1,2 + */ + private static final int relocate(int b, int cell) { + return tagOf(cell) < 3 ? cell + b : cell; + } - final LinkedHashMap refs = new LinkedHashMap(); - final IntStack cs = new IntStack(); - final IntStack gs = new IntStack(); + /** + * tests if the head of a clause, not yet copied to the heap + * for execution could possibly match the current goal, an + * abstraction of which has been place in xs + */ + static boolean match(int[] xs, Clause C0) { + for (int i = 0; i < MAXIND; i++) { + int x = xs[i]; + if (0 == x) + continue; + int y = C0.xs[i]; + if (0 == y) { + continue; + } + if (x != y) + return false; + } + return true; + } - final ArrayList Rss = mapExpand(Wss); - int k = 0; - for (final String[] ws : Rss) { + /** + * detects availability of alternative clauses for the + * top goal of this spine + */ + private static boolean hasClauses(Spine S) { + return S.k < S.cs.length; + } - // head or body element starts here + /** + * true when there are no more goals left to solve + */ + private static boolean hasGoals(Spine S) { + return !IntList.isEmpty(S.gs); + } - final int l = ws.length; - gs.push(tag(R, k++)); - cs.push(tag(A, l)); + private static IntMap[] vcreate(int l) { + IntMap[] vss = new IntMap[l]; + for (int i = 0; i < l; i++) { + vss[i] = new IntMap(); + } + return vss; + } - for (String w : ws) { + private static void put(IMap[] imaps, IntMap[] vss, int[] keys, int val) { + for (int i = 0; i < imaps.length; i++) { + int key = keys[i]; + if (key != 0) { + IMap.put(imaps, i, key, val); + } else { + vss[i].add(val); + } + } + } - // head or body subterm starts here + private static IMap[] index(Clause[] clauses, IntMap[] vmaps) { + if (clauses.length < START_INDEX) + return null; - if (1 == w.length()) { - w = "c:" + w; - } + IMap[] imaps = IMap.create(vmaps.length); + for (int i = 0; i < clauses.length; i++) { + Clause c = clauses[i]; - final String L = w.substring(2); + put(imaps, vmaps, c.xs, i + 1); // $$$ UGLY INC - switch (w.charAt(0)) { - case 'c': - cs.push(encode(C, L)); - k++; - break; - case 'n': - cs.push(encode(N, L)); - k++; - break; - case 'v': { - IntStack Is = refs.get(L); - if (null == Is) { - Is = new IntStack(); - refs.put(L, Is); - } - Is.push(k); - cs.push(tag(BAD, k)); // just in case we miss this - k++; - } - break; - case 'h': { - IntStack Is = refs.get(L); - if (null == Is) { - Is = new IntStack(); - refs.put(L, Is); - } - Is.push(k - 1); - cs.set(k - 1, tag(A, l - 1)); - gs.pop(); - } - break; - default: - Main.pp("FORGOTTEN=" + w); - } // end subterm - } // end element - } // end clause + } + Main.pp("INDEX"); + Main.pp(IMap.show(imaps)); + Main.pp(Arrays.toString(vmaps)); + Main.pp(""); + return imaps; + } + + /** + * places an identifier in the symbol table + */ + private final int addSym(String sym) { + Integer I = syms.get(sym); + if (null == I) { + int i = syms.size(); + I = i; + syms.put(sym, I); + slist.add(sym); + } + return I; + } - // linker - final Iterator K = refs.values().iterator(); + /** + * returns the symbol associated to an integer index + * in the symbol table + */ + private final String getSym(int w) { + if (w < 0 || w >= slist.size()) + return "BADSYMREF=" + w; + return slist.get(w); + } - while (K.hasNext()) { - final IntStack Is = K.next(); + private final void makeHeap() { + makeHeap(MINSIZE); + } - // finding the A among refs - int leader = -1; - for (final int j : Is.toArray()) { - if (A == tagOf(cs.get(j))) { - leader = j; + private final void makeHeap(int size) { + heap = new int[size]; + clear(); + } - break; - } + private final int getTop() { + return top; + } + + private final int setTop(int top) { + return this.top = top; + } + + private final void clear() { + //for (int i = 0; i <= top; i++) + //heap[i] = 0; + top = -1; + } + + /** + * Pushes an element - top is incremented frirst than the + * element is assigned. This means top point to the last assigned + * element - which can be returned with peek(). + */ + private final void push(int i) { + heap[++top] = i; + } + + private int size() { + return top + 1; + } + + /** + * dynamic array operation: doubles when full + */ + private final void expand() { + int l = heap.length; + int[] newstack = new int[l << 1]; + + System.arraycopy(heap, 0, newstack, 0, l); + heap = newstack; + } + + private void ensureSize(int more) { + if (1 + top + more >= heap.length) { + expand(); } - if (-1 == leader) { - // for vars, first V others U - leader = Is.get(0); - for (final int i : Is.toArray()) { - if (i == leader) { - cs.set(i, tag(V, i)); - } else { - cs.set(i, tag(U, leader)); - } + } - } - } else { - for (final int i : Is.toArray()) { - if (i == leader) { - continue; + /** + * loads a program from a .nl file of + * "natural language" equivalents of Prolog/HiLog statements + */ + private Clause[] dload(String s) { + boolean fromFile = true; + ArrayList>> Wsss = Toks.sentences(s, fromFile); + + ArrayList Cs = new ArrayList<>(); + + for (ArrayList> Wss : Wsss) { + // clause starts here + + LinkedHashMap refs = new LinkedHashMap<>(); + IntStack cs = new IntStack(); + IntStack gs = new IntStack(); + + ArrayList Rss = mapExpand(Wss); + int k = 0; + for (String[] ws : Rss) { + + // head or body element starts here + + int l = ws.length; + gs.push(tag(R, k++)); + cs.push(tag(A, l)); + + for (String w : ws) { + + // head or body subterm starts here + + if (1 == w.length()) { + w = "c:" + w; + } + + String L = w.substring(2); + + switch (w.charAt(0)) { + case 'c': + cs.push(encode(C, L)); + k++; + break; + case 'n': + cs.push(encode(N, L)); + k++; + break; + case 'v': { + IntStack Is = refs.computeIfAbsent(L, k1 -> new IntStack()); + Is.push(k); + cs.push(tag(BAD, k)); // just in case we miss this + k++; + } + break; + case 'h': { + IntStack Is = refs.computeIfAbsent(L, k1 -> new IntStack()); + Is.push(k - 1); + cs.set(k - 1, tag(A, l - 1)); + gs.pop(); + } + break; + default: + Main.pp("FORGOTTEN=" + w); + } // end subterm + } // end element + } // end clause + + // linker + + for (IntStack Is : refs.values()) { + // finding the A among refs + int leader = -1; + for (int j : Is.toArray()) { + if (A == tagOf(cs.get(j))) { + leader = j; + + break; + } + } + if (-1 == leader) { + // for vars, first V others U + leader = Is.get(0); + for (int i : Is.toArray()) { + if (i == leader) { + cs.set(i, tag(V, i)); + } else { + cs.set(i, tag(U, leader)); + } + + } + } else { + for (int i : Is.toArray()) { + if (i == leader) { + continue; + } + cs.set(i, tag(R, leader)); + } + } } - cs.set(i, tag(R, leader)); - } - } - } - final int neck = 1 == gs.size() ? cs.size() : detag(gs.get(1)); - final int[] tgs = gs.toArray(); + int neck = 1 == gs.size() ? cs.size() : detag(gs.get(1)); + int[] tgs = gs.toArray(); - final Clause C = putClause(cs.toArray(), tgs, neck); + Clause C = putClause(cs.toArray(), tgs, neck); - Cs.add(C); + Cs.add(C); - } // end clause set + } // end clause set - final int ccount = Cs.size(); - final Clause[] cls = new Clause[ccount]; - for (int i = 0; i < ccount; i++) { - cls[i] = Cs.get(i); + int ccount = Cs.size(); + Clause[] cls = new Clause[ccount]; + for (int i = 0; i < ccount; i++) { + cls[i] = Cs.get(i); + } + return cls; } - return cls; - } - - private static final int[] toNums(final Clause[] clauses) { - final int l = clauses.length; - final int[] cls = new int[l]; - for (int i = 0; i < l; i++) { - cls[i] = i; + + /* + * encodes string constants into symbols while leaving + * other data types untouched + */ + private final int encode(int t, String s) { + int w; + try { + w = Integer.parseInt(s); + } catch (Exception ignored) { + if (C == t) { + w = addSym(s); + } else + //pp("bad in encode=" + t + ":" + s); + return tag(BAD, 666); + } + return tag(t, w); + } + + /** + * returns the heap cell another cell points to + */ + private int getRef(int x) { + return heap[detag(x)]; } - return cls; - } - - /* - * encodes string constants into symbols while leaving - * other data types untouched - */ - private final int encode(final int t, final String s) { - int w; - try { - w = Integer.parseInt(s); - } catch (final Exception e) { - if (C == t) { - w = addSym(s); - } else - //pp("bad in encode=" + t + ":" + s); - return tag(BAD, 666); + + /* + * sets a heap cell to point to another one + */ + private final void setRef(int w, int r) { + heap[detag(w)] = r; } - return tag(t, w); - } - - /** - * true if cell x is a variable - * assumes that variables are tagged with 0 or 1 - */ - final private static boolean isVAR(final int x) { - //final int t = tagOf(x); - //return V == t || U == t; - return tagOf(x) < 2; - } - - /** - * returns the heap cell another cell points to - */ - final int getRef(final int x) { - return heap[detag(x)]; - } - - /* - * sets a heap cell to point to another one - */ - final private void setRef(final int w, final int r) { - heap[detag(w)] = r; - } - - /** - * removes binding for variable cells - * above savedTop - */ - private void unwindTrail(final int savedTop) { - while (savedTop < trail.getTop()) { - final int href = trail.pop(); - // assert href is var - - setRef(href, href); + + /** + * removes binding for variable cells + * above savedTop + */ + private void unwindTrail(int savedTop) { + while (savedTop < trail.getTop()) { + int href = trail.pop(); + // assert href is var + + setRef(href, href); + } } - } - - /** - * scans reference chains starting from a variable - * until it points to an unbound root variable or some - * non-variable cell - */ - final private int deref(int x) { - while (isVAR(x)) { - final int r = getRef(x); - if (r == x) { - break; - } - x = r; + + /** + * scans reference chains starting from a variable + * until it points to an unbound root variable or some + * non-variable cell + */ + private final int deref(int x) { + while (isVAR(x)) { + int r = getRef(x); + if (r == x) { + break; + } + x = r; + } + return x; } - return x; - } - - /** - * raw display of a term - to be overridden - */ - String showTerm(final int x) { - return showTerm(exportTerm(x)); - } - - /** - * raw display of a externalized term - */ - String showTerm(final Object O) { - if (O instanceof Object[]) - return Arrays.deepToString((Object[]) O); - return O.toString(); - } - - /** - * prints out content of the trail - */ - void ppTrail() { - for (int i = 0; i <= trail.getTop(); i++) { - final int t = trail.get(i); - Main.pp("trail[" + i + "]=" + showCell(t) + ":" + showTerm(t)); + + /** + * raw display of a term - to be overridden + */ + String showTerm(int x) { + return showTerm(exportTerm(x)); } - } - - /** - * builds an array of embedded arrays from a heap cell - * representing a term for interaction with an external function - * including a displayer - */ - Object exportTerm(int x) { - x = deref(x); - - final int t = tagOf(x); - final int w = detag(x); - - Object res = null; - switch (t) { - case C: - res = getSym(w); - break; - case N: - res = new Integer(w); - break; - case V: - //case U: - res = "V" + w; - break; - case R: { - - final int a = heap[w]; - if (A != tagOf(a)) - return "*** should be A, found=" + showCell(a); - final int n = detag(a); - final Object[] arr = new Object[n]; - final int k = w + 1; - for (int i = 0; i < n; i++) { - final int j = k + i; - arr[i] = exportTerm(heap[j]); + + /** + * raw display of a externalized term + */ + String showTerm(Object O) { + if (O instanceof Object[]) + return Arrays.deepToString((Object[]) O); + return O.toString(); + } + + /** + * prints out content of the trail + */ + void ppTrail() { + for (int i = 0; i <= trail.getTop(); i++) { + int t = trail.get(i); + Main.pp("trail[" + i + "]=" + showCell(t) + ':' + showTerm(t)); } - res = arr; - } - break; - default: - res = "*BAD TERM*" + showCell(x); } - return res; - } - - /** - * extracts an integer array pointing to - * the skeleton of a clause: a cell - * pointing to its head followed by cells pointing to its body's - * goals - */ - static int[] getSpine(final int[] cs) { - final int a = cs[1]; - final int w = detag(a); - final int[] rs = new int[w - 1]; - for (int i = 0; i < w - 1; i++) { - final int x = cs[3 + i]; - final int t = tagOf(x); - if (R != t) { - Main.pp("*** getSpine: unexpected tag=" + t); - return null; - } - rs[i] = detag(x); + + /** + * builds an array of embedded arrays from a heap cell + * representing a term for interaction with an external function + * including a displayer + */ + private Object exportTerm(int x) { + x = deref(x); + + int t = tagOf(x); + int w = detag(x); + + Object res = null; + switch (t) { + case C: + res = getSym(w); + break; + case N: + res = w; + break; + case V: + //case U: + res = "V" + w; + break; + case R: { + + int a = heap[w]; + if (A != tagOf(a)) + return "*** should be A, found=" + showCell(a); + int n = detag(a); + Object[] arr = new Object[n]; + int k = w + 1; + for (int i = 0; i < n; i++) { + int j = k + i; + arr[i] = exportTerm(heap[j]); + } + res = arr; + } + break; + default: + res = "*BAD TERM*" + showCell(x); + } + return res; } - return rs; - } - - /** - * raw display of a cell as tag : value - */ - final String showCell(final int w) { - final int t = tagOf(w); - final int val = detag(w); - String s = null; - switch (t) { - case V: - s = "v:" + val; - break; - case U: - s = "u:" + val; - break; - case N: - s = "n:" + val; - break; - case C: - s = "c:" + getSym(val); - break; - case R: - s = "r:" + val; - break; - case A: - s = "a:" + val; - break; - default: - s = "*BAD*=" + w; + + /** + * raw display of a cell as tag : value + */ + final String showCell(int w) { + int t = tagOf(w); + int val = detag(w); + String s = null; + switch (t) { + case V: + s = "v:" + val; + break; + case U: + s = "u:" + val; + break; + case N: + s = "n:" + val; + break; + case C: + s = "c:" + getSym(val); + break; + case R: + s = "r:" + val; + break; + case A: + s = "a:" + val; + break; + default: + s = "*BAD*=" + w; + } + return s; } - return s; - } - /** - * a displayer for cells - */ + /** + * a displayer for cells + */ - String showCells(final int base, final int len) { - final StringBuffer buf = new StringBuffer(); - for (int k = 0; k < len; k++) { - final int instr = heap[base + k]; + String showCells(int base, int len) { + StringBuilder buf = new StringBuilder(); + for (int k = 0; k < len; k++) { + int instr = heap[base + k]; - buf.append("[" + (base + k) + "]"); - buf.append(showCell(instr)); - buf.append(" "); + buf.append("[").append(base + k).append(']'); + buf.append(showCell(instr)); + buf.append(' '); + } + return buf.toString(); } - return buf.toString(); - } - - String showCells(final int[] cs) { - final StringBuffer buf = new StringBuffer(); - for (int k = 0; k < cs.length; k++) { - buf.append("[" + k + "]"); - buf.append(showCell(cs[k])); - buf.append(" "); + + String showCells(int[] cs) { + StringBuilder buf = new StringBuilder(); + for (int k = 0; k < cs.length; k++) { + buf.append("[").append(k).append(']'); + buf.append(showCell(cs[k])); + buf.append(' '); + } + return buf.toString(); } - return buf.toString(); - } - - /** - * to be overridden as a printer of a spine - */ - void ppc(final Spine C) { - // override - } - - /** - * to be overridden as a printer for current goals - * in a spine - */ - void ppGoals(final IntList gs) { - // override - } - - /** - * to be overriden as a printer for spines - */ - void ppSpines() { - // override - } - - /** - * unification algorithm for cells X1 and X2 on ustack that also takes care - * to trail bindigs below a given heap address "base" - */ - final private boolean unify(final int base) { - while (!ustack.isEmpty()) { - final int x1 = deref(ustack.pop()); - final int x2 = deref(ustack.pop()); - if (x1 != x2) { - final int t1 = tagOf(x1); - final int t2 = tagOf(x2); - final int w1 = detag(x1); - final int w2 = detag(x2); - - if (isVAR(x1)) { /* unb. var. v1 */ - if (isVAR(x2) && w2 > w1) { /* unb. var. v2 */ - heap[w2] = x1; - if (w2 <= base) { - trail.push(x2); - } - } else { // x2 nonvar or older - heap[w1] = x2; - if (w1 <= base) { - trail.push(x1); - } - } - } else if (isVAR(x2)) { /* x1 is NONVAR */ - heap[w2] = x1; - if (w2 <= base) { - trail.push(x2); - } - } else if (R == t1 && R == t2) { // both should be R - if (!unify_args(w1, w2)) - return false; - } else - return false; - } + + /** + * to be overridden as a printer of a spine + */ + void ppc(Spine C) { + // override } - return true; - } - - final private boolean unify_args(final int w1, final int w2) { - final int v1 = heap[w1]; - final int v2 = heap[w2]; - // both should be A - final int n1 = detag(v1); - final int n2 = detag(v2); - if (n1 != n2) - return false; - final int b1 = 1 + w1; - final int b2 = 1 + w2; - for (int i = n1 - 1; i >= 0; i--) { - final int i1 = b1 + i; - final int i2 = b2 + i; - final int u1 = heap[i1]; - final int u2 = heap[i2]; - if (u1 == u2) { - continue; - } - ustack.push(u2); - ustack.push(u1); + + /** + * to be overridden as a printer for current goals + * in a spine + */ + void ppGoals(IntList gs) { + // override } - return true; - } - - /** - * places a clause built by the Toks reader on the heap - */ - Clause putClause(final int[] cs, final int[] gs, final int neck) { - final int base = size(); - final int b = tag(V, base); - final int len = cs.length; - pushCells(b, 0, len, cs); - for (int i = 0; i < gs.length; i++) { - gs[i] = relocate(b, gs[i]); + + /** + * to be overriden as a printer for spines + */ + void ppSpines() { + // override } - final int[] xs = getIndexables(gs[0]); - return new Clause(len, gs, base, neck, xs); - } - - /** - * relocates a variable or array reference cell by b - * assumes var/ref codes V,U,R are 0,1,2 - */ - final private static int relocate(final int b, final int cell) { - return tagOf(cell) < 3 ? cell + b : cell; - } - - /** - * pushes slice[from,to] of array cs of cells to heap - */ - final private void pushCells(final int b, final int from, final int to, final int base) { - ensureSize(to - from); - for (int i = from; i < to; i++) { - push(relocate(b, heap[base + i])); + + /** + * unification algorithm for cells X1 and X2 on ustack that also takes care + * to trail bindigs below a given heap address "base" + */ + private final boolean unify(int base) { + while (!ustack.isEmpty()) { + int x1 = deref(ustack.pop()); + int x2 = deref(ustack.pop()); + if (x1 != x2) { + int t1 = tagOf(x1); + int t2 = tagOf(x2); + int w1 = detag(x1); + int w2 = detag(x2); + + if (isVAR(x1)) { /* unb. var. v1 */ + if (isVAR(x2) && w2 > w1) { /* unb. var. v2 */ + heap[w2] = x1; + if (w2 <= base) { + trail.push(x2); + } + } else { // x2 nonvar or older + heap[w1] = x2; + if (w1 <= base) { + trail.push(x1); + } + } + } else if (isVAR(x2)) { /* x1 is NONVAR */ + heap[w2] = x1; + if (w2 <= base) { + trail.push(x2); + } + } else if (R == t1 && R == t2) { // both should be R + if (!unify_args(w1, w2)) + return false; + } else + return false; + } + } + return true; } - } - - /** - * pushes slice[from,to] of array cs of cells to heap - */ - final private void pushCells(final int b, final int from, final int to, final int[] cs) { - ensureSize(to - from); - for (int i = from; i < to; i++) { - push(relocate(b, cs[i])); + + private final boolean unify_args(int w1, int w2) { + int v1 = heap[w1]; + int v2 = heap[w2]; + // both should be A + int n1 = detag(v1); + int n2 = detag(v2); + if (n1 != n2) + return false; + int b1 = 1 + w1; + int b2 = 1 + w2; + for (int i = n1 - 1; i >= 0; i--) { + int i1 = b1 + i; + int i2 = b2 + i; + int u1 = heap[i1]; + int u2 = heap[i2]; + if (u1 == u2) { + continue; + } + ustack.push(u2); + ustack.push(u1); + } + return true; } - } - - /** - * copies and relocates head of clause at offset from heap to heap - */ - final private int pushHead(final int b, final Clause C) { - pushCells(b, 0, C.neck, C.base); - final int head = C.hgs[0]; - return relocate(b, head); - } - - /** - * copies and relocates body of clause at offset from heap to heap - * while also placing head as the first element of array gs that - * when returned contains references to the toplevel spine of the clause - */ - final private int[] pushBody(final int b, final int head, final Clause C) { - pushCells(b, C.neck, C.len, C.base); - final int l = C.hgs.length; - final int[] gs = new int[l]; - gs[0] = head; - for (int k = 1; k < l; k++) { - final int cell = C.hgs[k]; - gs[k] = relocate(b, cell); + + /** + * places a clause built by the Toks reader on the heap + */ + private Clause putClause(int[] cs, int[] gs, int neck) { + int base = size(); + int b = tag(V, base); + int len = cs.length; + pushCells(b, 0, len, cs); + for (int i = 0; i < gs.length; i++) { + gs[i] = relocate(b, gs[i]); + } + int[] xs = getIndexables(gs[0]); + return new Clause(len, gs, base, neck, xs); } - return gs; - } - - /** - * makes, if needed, registers associated to top goal of a Spine - * these registers will be reused when matching with candidate clauses - * note that xs contains dereferenced cells - this is done once for - * each goal's toplevel subterms - */ - final private void makeIndexArgs(final Spine G, final int goal) { - if (null != G.xs) - return; - - final int p = 1 + detag(goal); - final int n = Math.min(MAXIND, detag(getRef(goal))); - - final int[] xs = new int[MAXIND]; - - for (int i = 0; i < n; i++) { - final int cell = deref(heap[p + i]); - xs[i] = cell2index(cell); + + /** + * pushes slice[from,to] of array cs of cells to heap + */ + private final void pushCells(int b, int from, int to, int base) { + ensureSize(to - from); + for (int i = from; i < to; i++) { + push(relocate(b, heap[base + i])); + } } - G.xs = xs; - - if (null == imaps) - return; - final int[] cs = IMap.get(imaps, vmaps, xs); - G.cs = cs; - } - - final private int[] getIndexables(final int ref) { - final int p = 1 + detag(ref); - final int n = detag(getRef(ref)); - final int[] xs = new int[MAXIND]; - for (int i = 0; i < MAXIND && i < n; i++) { - final int cell = deref(heap[p + i]); - xs[i] = cell2index(cell); + /** + * pushes slice[from,to] of array cs of cells to heap + */ + private final void pushCells(int b, int from, int to, int[] cs) { + ensureSize(to - from); + for (int i = from; i < to; i++) { + push(relocate(b, cs[i])); + } } - return xs; - } - - final private int cell2index(final int cell) { - int x = 0; - final int t = tagOf(cell); - switch (t) { - case R: - x = getRef(cell); - break; - case C: - case N: - x = cell; - break; - // 0 otherwise - assert: tagging with R,C,N <>0 + + /** + * copies and relocates head of clause at offset from heap to heap + */ + private final int pushHead(int b, Clause C) { + pushCells(b, 0, C.neck, C.base); + int head = C.hgs[0]; + return relocate(b, head); } - return x; - } - - /** - * tests if the head of a clause, not yet copied to the heap - * for execution could possibly match the current goal, an - * abstraction of which has been place in xs - */ - private final boolean match(final int[] xs, final Clause C0) { - for (int i = 0; i < MAXIND; i++) { - final int x = xs[i]; - final int y = C0.xs[i]; - if (0 == x || 0 == y) { - continue; - } - if (x != y) - return false; + + /** + * copies and relocates body of clause at offset from heap to heap + * while also placing head as the first element of array gs that + * when returned contains references to the toplevel spine of the clause + */ + private final int[] pushBody(int b, int head, Clause C) { + pushCells(b, C.neck, C.len, C.base); + int l = C.hgs.length; + int[] gs = new int[l]; + gs[0] = head; + for (int k = 1; k < l; k++) { + int cell = C.hgs[k]; + gs[k] = relocate(b, cell); + } + return gs; } - return true; - } - - /** - * transforms a spine containing references to choice point and - * immutable list of goals into a new spine, by reducing the - * first goal in the list with a clause that successfully - * unifies with it - in which case places the goals of the - * clause at the top of the new list of goals, in reverse order - */ - final private Spine unfold(final Spine G) { - - final int ttop = trail.getTop(); - final int htop = getTop(); - final int base = htop + 1; - - final int goal = IntList.head(G.gs); - - makeIndexArgs(G, goal); - - final int last = G.cs.length; - for (int k = G.k; k < last; k++) { - final Clause C0 = clauses[G.cs[k]]; - - if (!match(G.xs, C0)) - continue; - - final int base0 = base - C0.base; - final int b = tag(V, base0); - final int head = pushHead(b, C0); - - ustack.clear(); // set up unification stack - - ustack.push(head); - ustack.push(goal); - - if (!unify(base)) { - unwindTrail(ttop); - setTop(htop); - continue; - } - final int[] gs = pushBody(b, head, C0); - final IntList newgs = IntList.tail(IntList.app(gs, IntList.tail(G.gs))); - G.k = k + 1; - if (!IntList.isEmpty(newgs)) - return new Spine(gs, base, IntList.tail(G.gs), ttop, 0, cls); - else - return answer(ttop); - } // end for - return null; - } - - /** - * extracts a query - by convention of the form - * goal(Vars):-body to be executed by the engine - */ - Clause getQuery() { - return clauses[clauses.length - 1]; - } - - /** - * returns the initial spine built from the - * query from which execution starts - */ - Spine init() { - final int base = size(); - - final Clause G = getQuery(); - final Spine Q = new Spine(G.hgs, base, IntList.empty, trail.getTop(), 0, cls); - spines.push(Q); - return Q; - } - - /** - * returns an answer as a Spine while recording in it - * the top of the trail to allow the caller to retrieve - * more answers by forcing backtracking - */ - final private Spine answer(final int ttop) { - return new Spine(spines.get(0).hd, ttop); - } - - /** - * detects availability of alternative clauses for the - * top goal of this spine - */ - final private boolean hasClauses(final Spine S) { - return S.k < S.cs.length; - } - - /** - * true when there are no more goals left to solve - */ - final private boolean hasGoals(final Spine S) { - return !IntList.isEmpty(S.gs); - } - - /** - * removes this spines for the spine stack and - * resets trail and heap to where they where at its - * creating time - while undoing variable binding - * up to that point - */ - final private void popSpine() { - final Spine G = spines.pop(); - unwindTrail(G.ttop); - setTop(G.base - 1); - } - - /** - * main interpreter loop: starts from a spine and works - * though a stream of answers, returned to the caller one - * at a time, until the spines stack is empty - when it - * returns null - */ - final Spine yield() { - while (!spines.isEmpty()) { - final Spine G = spines.peek(); - if (!hasClauses(G)) { - popSpine(); // no clauses left - continue; - } - final Spine C = unfold(G); - if (null == C) { - popSpine(); // no matches - continue; - } - if (hasGoals(C)) { - spines.push(C); - continue; - } - return C; // answer + + /** + * makes, if needed, registers associated to top goal of a Spine + * these registers will be reused when matching with candidate clauses + * note that xs contains dereferenced cells - this is done once for + * each goal's toplevel subterms + */ + private final void makeIndexArgs(Spine G, int goal) { + if (null != G.xs) + return; + + int p = 1 + detag(goal); + int n = Math.min(MAXIND, detag(getRef(goal))); + + int[] xs = new int[MAXIND]; + + for (int i = 0; i < n; i++) { + int cell = deref(heap[p + i]); + xs[i] = cell2index(cell); + } + + G.xs = xs; + + if (null == imaps) + return; + int[] cs = IMap.get(imaps, vmaps, xs); + G.cs = cs; + } + + private final int[] getIndexables(int ref) { + int p = 1 + detag(ref); + int n = detag(getRef(ref)); + int[] xs = new int[MAXIND]; + for (int i = 0; i < MAXIND && i < n; i++) { + int cell = deref(heap[p + i]); + xs[i] = cell2index(cell); + } + return xs; } - return null; - } - - /** - * retrieves an answers and ensure the engine can be resumed - * by unwinding the trail of the query Spine - * returns an external "human readable" representation of the answer - */ - Object ask() { - query = yield(); - if (null == query) - return null; - final int res = answer(query.ttop).hd; - final Object R = exportTerm(res); - unwindTrail(query.ttop); - return R; - } - - /** - * initiator and consumer of the stream of answers - * generated by this engine - */ - void run() { - long ctr = 0L; - for (;; ctr++) { - final Object A = ask(); - if (null == A) { - break; - } - if(ctr<5) Prog.println("[" + ctr + "] " + "*** ANSWER=" + showTerm(A)); + + private final int cell2index(int cell) { + int x = 0; + int t = tagOf(cell); + switch (t) { + case R: + x = getRef(cell); + break; + case C: + case N: + x = cell; + break; + // 0 otherwise - assert: tagging with R,C,N <>0 + } + return x; + } + + /** + * transforms a spine containing references to choice point and + * immutable list of goals into a new spine, by reducing the + * first goal in the list with a clause that successfully + * unifies with it - in which case places the goals of the + * clause at the top of the new list of goals, in reverse order + */ + private final Spine unfold(Spine G) { + + int ttop = trail.getTop(); + int htop = getTop(); + int base = htop + 1; + + int goal = IntList.head(G.gs); + + makeIndexArgs(G, goal); + + int last = G.cs.length; + for (int k = G.k; k < last; k++) { + Clause C0 = clauses[G.cs[k]]; + + if (!match(G.xs, C0)) + continue; + + int base0 = base - C0.base; + int b = tag(V, base0); + int head = pushHead(b, C0); + + ustack.clear(); // set up unification stack + + ustack.push(head); + ustack.push(goal); + + if (!unify(base)) { + unwindTrail(ttop); + setTop(htop); + continue; + } + int[] gs = pushBody(b, head, C0); + IntList newgs = IntList.tail(IntList.app(gs, IntList.tail(G.gs))); + G.k = k + 1; + return !IntList.isEmpty(newgs) ? new Spine(gs, base, IntList.tail(G.gs), ttop, 0, cls) : answer(ttop); + } // end for + return null; } - if(ctr>5) Prog.println("..."); - Prog.println("TOTAL ANSWERS=" + ctr); - } - // indexing extensions - ony active if START_INDEX clauses or more + /** + * extracts a query - by convention of the form + * goal(Vars):-body to be executed by the engine + */ + private Clause getQuery() { + return clauses[clauses.length - 1]; + } - public static IntMap[] vcreate(final int l) { - final IntMap[] vss = new IntMap[l]; - for (int i = 0; i < l; i++) { - vss[i] = new IntMap(); + /** + * returns the initial spine built from the + * query from which execution starts + */ + private Spine init() { + int base = size(); + + Clause G = getQuery(); + Spine Q = new Spine(G.hgs, base, IntList.empty, trail.getTop(), 0, cls); + spines.push(Q); + return Q; } - return vss; - } - - final static void put(final IMap[] imaps, final IntMap[] vss, final int[] keys, final int val) { - for (int i = 0; i < imaps.length; i++) { - final int key = keys[i]; - if (key != 0) { - IMap.put(imaps, i, key, val); - } else { - vss[i].add(val); - } + + /** + * returns an answer as a Spine while recording in it + * the top of the trail to allow the caller to retrieve + * more answers by forcing backtracking + */ + private final Spine answer(int ttop) { + return new Spine(spines.get(0).hd, ttop); } - } - final IMap[] index(final Clause[] clauses, final IntMap[] vmaps) { - if (clauses.length < START_INDEX) - return null; + /** + * removes this spines for the spine stack and + * resets trail and heap to where they where at its + * creating time - while undoing variable binding + * up to that point + */ + private final void popSpine() { + Spine G = spines.pop(); + unwindTrail(G.ttop); + setTop(G.base - 1); + } - final IMap[] imaps = IMap.create(vmaps.length); - for (int i = 0; i < clauses.length; i++) { - final Clause c = clauses[i]; + // indexing extensions - ony active if START_INDEX clauses or more + + /** + * main interpreter loop: starts from a spine and works + * though a stream of answers, returned to the caller one + * at a time, until the spines stack is empty - when it + * returns null + */ + private Spine yield() { + while (!spines.isEmpty()) { + Spine G = spines.peek(); + if (!hasClauses(G)) { + popSpine(); // no clauses left + continue; + } + Spine C = unfold(G); + if (null == C) { + popSpine(); // no matches + continue; + } + if (hasGoals(C)) { + spines.push(C); + continue; + } + return C; // answer + } + return null; + } - put(imaps, vmaps, c.xs, i + 1); // $$$ UGLY INC + /** + * retrieves an answers and ensure the engine can be resumed + * by unwinding the trail of the query Spine + * returns an external "human readable" representation of the answer + */ + Object ask() { + query = yield(); + if (null == query) + return null; + int res = answer(query.ttop).hd; + Object R = exportTerm(res); + unwindTrail(query.ttop); + return R; + } + /** + * initiator and consumer of the stream of answers + * generated by this engine + */ + void run() { + long ctr = 0L; + for (; ; ctr++) { + Object A = ask(); + if (null == A) { + break; + } + if (ctr < 5) Prog.println("[" + ctr + "] " + "*** ANSWER=" + showTerm(A)); + } + if (ctr > 5) Prog.println("..."); + Prog.println("TOTAL ANSWERS=" + ctr); } - Main.pp("INDEX"); - Main.pp(IMap.show(imaps)); - Main.pp(Arrays.toString(vmaps)); - Main.pp(""); - return imaps; - } } diff --git a/IP/src/iProlog/IMap.java b/IP/src/iProlog/IMap.java index 8768fe7b..654db321 100644 --- a/IP/src/iProlog/IMap.java +++ b/IP/src/iProlog/IMap.java @@ -1,137 +1,132 @@ - package iProlog; + import java.util.*; final class IMap implements java.io.Serializable { - private static final long serialVersionUID = 1L; + private static final long serialVersionUID = 1L; - private final HashMap map; + private final HashMap map; - IMap() { - map = new HashMap(); - } + private IMap() { + map = new HashMap<>(); + } - public final void clear() { - map.clear(); - } + static final IMap[] create(int l) { + IMap first = new IMap<>(); + @SuppressWarnings("unchecked") IMap[] imaps = (IMap[]) java.lang.reflect.Array.newInstance(first.getClass(), l); + //new IMap[l]; + imaps[0] = first; + for (int i = 1; i < l; i++) { + imaps[i] = new IMap<>(); + } + return imaps; + } - final boolean put(final K key, final int val) { - IntMap vals = map.get(key); - if (null == vals) { - vals = new IntMap(); - map.put(key, vals); + static final boolean put(IMap[] imaps, int pos, int key, int val) { + return imaps[pos].put(key, val); } - return vals.add(val); - } - final IntMap get(final K key) { - IntMap s = map.get(key); - if (null == s) { - s = new IntMap(); + static final int[] get(IMap[] iMaps, IntMap[] vmaps, int[] keys) { + int l = iMaps.length; + ArrayList ms = new ArrayList<>(); + ArrayList vms = new ArrayList<>(); + + for (int i = 0; i < l; i++) { + int key = keys[i]; + if (0 == key) { + continue; + } + //Main.pp("i=" + i + " ,key=" + key); + IntMap m = iMaps[i].get(key); + //Main.pp("m=" + m); + ms.add(m); + vms.add(vmaps[i]); + } + IntMap[] ims = new IntMap[ms.size()]; + IntMap[] vims = new IntMap[vms.size()]; + + for (int i = 0; i < ims.length; i++) { + IntMap im = ms.get(i); + ims[i] = im; + IntMap vim = vms.get(i); + vims[i] = vim; + } + + //Main.pp("-------ims=" + Arrays.toString(ims)); + //Main.pp("-------vims=" + Arrays.toString(vims)); + + IntStack cs = IntMap.intersect(ims, vims); // $$$ add vmaps here + int[] is = cs.toArray(); + for (int i = 0; i < is.length; i++) { + is[i] -= 1; + } + java.util.Arrays.sort(is); + return is; } - return s; - } - - final boolean remove(final K key, final int val) { - final IntMap vals = get(key); - final boolean ok = vals.delete(val); - if (vals.isEmpty()) { - map.remove(key); + + static final String show(IMap[] imaps) { + return Arrays.toString(imaps); } - return ok; - } - - public final boolean remove(final K key) { - return null != map.remove(key); - } - - public final int size() { - final Iterator I = map.keySet().iterator(); - int s = 0; - while (I.hasNext()) { - final K key = I.next(); - final IntMap vals = get(key); - s += vals.size(); + + static final String show(int[] is) { + return Arrays.toString(is); } - return s; - } - - public final Set keySet() { - return map.keySet(); - } - - public final Iterator keyIterator() { - return keySet().iterator(); - } - - @Override - public String toString() { - return map.toString(); - } - - // specialization for array of int maps - - final static IMap[] create(final int l) { - final IMap first = new IMap(); - @SuppressWarnings("unchecked") - final IMap[] imaps = (IMap[]) java.lang.reflect.Array.newInstance(first.getClass(), l); - //new IMap[l]; - imaps[0] = first; - for (int i = 1; i < l; i++) { - imaps[i] = new IMap(); + + public final void clear() { + map.clear(); } - return imaps; - } - - final static boolean put(final IMap[] imaps, final int pos, final int key, final int val) { - return imaps[pos].put(new Integer(key), val); - } - - final static int[] get(final IMap[] iMaps, final IntMap[] vmaps, final int[] keys) { - final int l = iMaps.length; - final ArrayList ms = new ArrayList(); - final ArrayList vms = new ArrayList(); - - for (int i = 0; i < l; i++) { - final int key = keys[i]; - if (0 == key) { - continue; - } - //Main.pp("i=" + i + " ,key=" + key); - final IntMap m = iMaps[i].get(new Integer(key)); - //Main.pp("m=" + m); - ms.add(m); - vms.add(vmaps[i]); + + final boolean put(K key, int val) { + IntMap vals = map.computeIfAbsent(key, k -> new IntMap()); + return vals.add(val); } - final IntMap[] ims = new IntMap[ms.size()]; - final IntMap[] vims = new IntMap[vms.size()]; - - for (int i = 0; i < ims.length; i++) { - final IntMap im = ms.get(i); - ims[i] = im; - final IntMap vim = vms.get(i); - vims[i] = vim; + + final IntMap get(K key) { + IntMap s = map.get(key); + if (null == s) { + s = new IntMap(); + } + return s; } - //Main.pp("-------ims=" + Arrays.toString(ims)); - //Main.pp("-------vims=" + Arrays.toString(vims)); + final boolean remove(K key, int val) { + IntMap vals = get(key); + boolean ok = vals.delete(val); + if (vals.isEmpty()) { + map.remove(key); + } + return ok; + } + + // specialization for array of int maps + + public final boolean remove(K key) { + return null != map.remove(key); + } - final IntStack cs = IntMap.intersect(ims, vims); // $$$ add vmaps here - final int[] is = cs.toArray(); - for (int i = 0; i < is.length; i++) { - is[i] = is[i] - 1; + public final int size() { + Iterator I = map.keySet().iterator(); + int s = 0; + while (I.hasNext()) { + K key = I.next(); + IntMap vals = get(key); + s += vals.size(); + } + return s; } - java.util.Arrays.sort(is); - return is; - } - final static String show(final IMap[] imaps) { - return Arrays.toString(imaps); - } + private Set keySet() { + return map.keySet(); + } + + public final Iterator keyIterator() { + return keySet().iterator(); + } - final static String show(final int[] is) { - return Arrays.toString(is); - } + @Override + public String toString() { + return map.toString(); + } /* public static void main(final String[] args) { diff --git a/IP/src/iProlog/IntList.java b/IP/src/iProlog/IntList.java index 139b690b..2eb38658 100644 --- a/IP/src/iProlog/IntList.java +++ b/IP/src/iProlog/IntList.java @@ -1,61 +1,60 @@ - package iProlog; -class IntList { - private final int head; - private final IntList tail; +class IntList { - private IntList(final int head) { - this.head = head; - tail = null; - } + static final IntList empty = null; + private final int head; + private final IntList tail; - private IntList(final int X, final IntList Xs) { - head = X; - tail = Xs; - } + private IntList(int head) { + this.head = head; + tail = null; + } - static final boolean isEmpty(final IntList Xs) { - return null == Xs; - } + private IntList(int X, IntList Xs) { + head = X; + tail = Xs; + } - static final int head(final IntList Xs) { - return Xs.head; - } + static final boolean isEmpty(IntList Xs) { + return null == Xs; + } - static final IntList empty = null; + static final int head(IntList Xs) { + return Xs.head; + } - static final IntList tail(final IntList Xs) { - return Xs.tail; - } + static final IntList tail(IntList Xs) { + return Xs.tail; + } - static final IntList cons(final int X, final IntList Xs) { - return new IntList(X, Xs); - } + private static IntList cons(int X, IntList Xs) { + return new IntList(X, Xs); + } - static final IntList app(final int[] xs, final IntList Ys) { - IntList Zs = Ys; - for (int i = xs.length - 1; i >= 0; i--) { - Zs = cons(xs[i], Zs); + static final IntList app(int[] xs, IntList Ys) { + IntList Zs = Ys; + for (int i = xs.length - 1; i >= 0; i--) { + Zs = cons(xs[i], Zs); + } + return Zs; } - return Zs; - } - static final IntStack toInts(IntList Xs) { - final IntStack is = new IntStack(); - while (!isEmpty(Xs)) { - is.push(head(Xs)); - Xs = tail(Xs); + private static IntStack toInts(IntList Xs) { + IntStack is = new IntStack(); + while (!isEmpty(Xs)) { + is.push(head(Xs)); + Xs = tail(Xs); + } + return is; } - return is; - } - static final int len(final IntList Xs) { - return toInts(Xs).size(); - } + static final int len(IntList Xs) { + return toInts(Xs).size(); + } - @Override - public String toString() { - return toInts(this).toString(); - } + @Override + public String toString() { + return toInts(this).toString(); + } } diff --git a/IP/src/iProlog/IntMap.java b/IP/src/iProlog/IntMap.java index 5e2315e2..252dc8ca 100644 --- a/IP/src/iProlog/IntMap.java +++ b/IP/src/iProlog/IntMap.java @@ -2,323 +2,333 @@ * derived from code at https://github.com/mikvor/hashmapTest */ package iProlog; + class IntMap implements java.io.Serializable { - private static final long serialVersionUID = 1L; - - private static final int FREE_KEY = 0; - - static final int NO_VALUE = 0; - - /** Keys and values */ - private int[] m_data; - - /** Do we have 'free' key in the map? */ - private boolean m_hasFreeKey; - /** Value of 'free' key */ - private int m_freeValue; - - /** Fill factor, must be between (0 and 1) */ - private final float m_fillFactor; - /** We will resize a map once it reaches this size */ - private int m_threshold; - /** Current map size */ - private int m_size; - - /** Mask to calculate the original position */ - private int m_mask; - private int m_mask2; - - IntMap() { - this(1 << 2); - } - - IntMap(final int size) { - this(size, 0.75f); - } - - IntMap(final int size, final float fillFactor) { - if (fillFactor <= 0 || fillFactor >= 1) - throw new IllegalArgumentException("FillFactor must be in (0, 1)"); - if (size <= 0) - throw new IllegalArgumentException("Size must be positive!"); - final int capacity = arraySize(size, fillFactor); - m_mask = capacity - 1; - m_mask2 = capacity * 2 - 1; - m_fillFactor = fillFactor; - - m_data = new int[capacity * 2]; - m_threshold = (int) (capacity * fillFactor); - } - - final int get(final int key) { - int ptr = (phiMix(key) & m_mask) << 1; - - if (key == FREE_KEY) - return m_hasFreeKey ? m_freeValue : NO_VALUE; - - int k = m_data[ptr]; - - if (k == FREE_KEY) - return NO_VALUE; //end of chain already - if (k == key) //we check FREE prior to this call - return m_data[ptr + 1]; - - while (true) { - ptr = ptr + 2 & m_mask2; //that's next index - k = m_data[ptr]; - if (k == FREE_KEY) - return NO_VALUE; - if (k == key) - return m_data[ptr + 1]; + private static final int NO_VALUE = 0; + private static final long serialVersionUID = 1L; + private static final int FREE_KEY = 0; + //taken from FastUtil + private static final int INT_PHI = 0x9E3779B9; + /** + * Fill factor, must be between (0 and 1) + */ + private final float m_fillFactor; + /** + * Keys and values + */ + private int[] m_data; + /** + * Do we have 'free' key in the map? + */ + private boolean m_hasFreeKey; + /** + * Value of 'free' key + */ + private int m_freeValue; + /** + * We will resize a map once it reaches this size + */ + private int m_threshold; + /** + * Current map size + */ + private int m_size; + /** + * Mask to calculate the original position + */ + private int m_mask; + private int m_mask2; + + IntMap() { + this(1 << 2); + } + + private IntMap(int size) { + this(size, 0.75f); + } + + private IntMap(int size, float fillFactor) { + if (fillFactor <= 0 || fillFactor >= 1) + throw new IllegalArgumentException("FillFactor must be in (0, 1)"); + if (size <= 0) + throw new IllegalArgumentException("Size must be positive!"); + int capacity = arraySize(size, fillFactor); + m_mask = capacity - 1; + m_mask2 = capacity * 2 - 1; + m_fillFactor = fillFactor; + + m_data = new int[capacity * 2]; + m_threshold = (int) (capacity * fillFactor); } - } - - // for use as IntSet - Paul Tarau - - final boolean contains(final int key) { - return NO_VALUE != get(key); - } - - final boolean add(final int key) { - return NO_VALUE != put(key, 666); - } - - boolean delete(final int key) { - return NO_VALUE != remove(key); - } - - final boolean isEmpty() { - return 0 == m_size; - } - - final static void intersect0(final IntMap m, final IntMap[] maps, final IntMap[] vmaps, final IntStack r) { - final int[] data = m.m_data; - for (int k = 0; k < data.length; k += 2) { - boolean found = true; - final int key = data[k]; - if (FREE_KEY == key) { - continue; - } - for (int i = 1; i < maps.length; i++) { - final IntMap map = maps[i]; - final int val = map.get(key); - - if (NO_VALUE == val) { - final IntMap vmap = vmaps[i]; - final int vval = vmap.get(key); - if (NO_VALUE == vval) { - found = false; - break; - } + + // for use as IntSet - Paul Tarau + + private static void intersect0(IntMap m, IntMap[] maps, IntMap[] vmaps, IntStack r) { + int[] data = m.m_data; + for (int k = 0; k < data.length; k += 2) { + boolean found = true; + int key = data[k]; + if (FREE_KEY == key) { + continue; + } + for (int i = 1; i < maps.length; i++) { + IntMap map = maps[i]; + int val = map.get(key); + + if (NO_VALUE == val) { + IntMap vmap = vmaps[i]; + int vval = vmap.get(key); + if (NO_VALUE == vval) { + found = false; + break; + } + } + } + if (found) { + r.push(key); + } } - } - if (found) { - r.push(key); - } } - } - - final static IntStack intersect(final IntMap[] maps, final IntMap[] vmaps) { - final IntStack r = new IntStack(); - - intersect0(maps[0], maps, vmaps, r); - intersect0(vmaps[0], maps, vmaps, r); - return r; - } - - // end changes - - final int put(final int key, final int value) { - if (key == FREE_KEY) { - final int ret = m_freeValue; - if (!m_hasFreeKey) { - ++m_size; - } - m_hasFreeKey = true; - m_freeValue = value; - return ret; + + static final IntStack intersect(IntMap[] maps, IntMap[] vmaps) { + IntStack r = new IntStack(); + + intersect0(maps[0], maps, vmaps, r); + intersect0(vmaps[0], maps, vmaps, r); + return r; + } + + /** + * Return the least power of two greater than or equal to the specified value. + *

+ *

Note that this function will return 1 when the argument is 0. + * + * @param x a long integer smaller than or equal to 262. + * @return the least power of two greater than or equal to the specified value. + */ + private static final long nextPowerOfTwo(long x) { + if (x == 0) + return 1; + x--; + x |= x >> 1; + x |= x >> 2; + x |= x >> 4; + x |= x >> 8; + x |= x >> 16; + return (x | x >> 32) + 1; } - int ptr = (phiMix(key) & m_mask) << 1; - int k = m_data[ptr]; - if (k == FREE_KEY) //end of chain already - { - m_data[ptr] = key; - m_data[ptr + 1] = value; - if (m_size >= m_threshold) { - rehash(m_data.length * 2); //size is set inside - } else { - ++m_size; - } - return NO_VALUE; - } else if (k == key) //we check FREE prior to this call - { - final int ret = m_data[ptr + 1]; - m_data[ptr + 1] = value; - return ret; + /** + * Returns the least power of two smaller than or equal to 230 + * and larger than or equal to Math.ceil( expected / f ). + * + * @param expected the expected number of elements in a hash table. + * @param f the load factor. + * @return the minimum possible size for a backing array. + * @throws IllegalArgumentException if the necessary size is larger than 230. + */ + private static final int arraySize(int expected, float f) { + long s = Math.max(2, nextPowerOfTwo((long) Math.ceil(expected / f))); + if (s > 1 << 30) + throw new IllegalArgumentException("Too large (" + expected + " expected elements with load factor " + f + ')'); + return (int) s; } - while (true) { - ptr = ptr + 2 & m_mask2; //that's next index calculation - k = m_data[ptr]; - if (k == FREE_KEY) { - m_data[ptr] = key; - m_data[ptr + 1] = value; - if (m_size >= m_threshold) { - rehash(m_data.length * 2); //size is set inside - } else { - ++m_size; + private static final int phiMix(int x) { + int h = x * INT_PHI; + return h ^ h >> 16; + } + + private int get(int key) { + int ptr = (phiMix(key) & m_mask) << 1; + + if (key == FREE_KEY) + return m_hasFreeKey ? m_freeValue : NO_VALUE; + + int k = m_data[ptr]; + + if (k == FREE_KEY) + return NO_VALUE; //end of chain already + if (k == key) //we check FREE prior to this call + return m_data[ptr + 1]; + + while (true) { + ptr = ptr + 2 & m_mask2; //that's next index + k = m_data[ptr]; + if (k == FREE_KEY) + return NO_VALUE; + if (k == key) + return m_data[ptr + 1]; } - return NO_VALUE; - } else if (k == key) { - final int ret = m_data[ptr + 1]; - m_data[ptr + 1] = value; - return ret; - } } - } - - final int remove(final int key) { - if (key == FREE_KEY) { - if (!m_hasFreeKey) - return NO_VALUE; - m_hasFreeKey = false; - --m_size; - return m_freeValue; //value is not cleaned + + // end changes + + final boolean contains(int key) { + return NO_VALUE != get(key); + } + + final boolean add(int key) { + return NO_VALUE != put(key, 666); + } + + boolean delete(int key) { + return NO_VALUE != remove(key); } - int ptr = (phiMix(key) & m_mask) << 1; - int k = m_data[ptr]; - if (k == key) //we check FREE prior to this call - { - final int res = m_data[ptr + 1]; - shiftKeys(ptr); - --m_size; - return res; - } else if (k == FREE_KEY) - return NO_VALUE; //end of chain already - while (true) { - ptr = ptr + 2 & m_mask2; //that's next index calculation - k = m_data[ptr]; - if (k == key) { - final int res = m_data[ptr + 1]; - shiftKeys(ptr); - --m_size; - return res; - } else if (k == FREE_KEY) - return NO_VALUE; + final boolean isEmpty() { + return 0 == m_size; } - } - - final private int shiftKeys(int pos) { - // Shift entries with the same hash. - int last, slot; - int k; - final int[] data = m_data; - while (true) { - pos = (last = pos) + 2 & m_mask2; - while (true) { - if ((k = data[pos]) == FREE_KEY) { - data[last] = FREE_KEY; - return last; + + private int put(int key, int value) { + if (key == FREE_KEY) { + int ret = m_freeValue; + if (!m_hasFreeKey) { + ++m_size; + } + m_hasFreeKey = true; + m_freeValue = value; + return ret; + } + + int ptr = (phiMix(key) & m_mask) << 1; + int k = m_data[ptr]; + if (k == FREE_KEY) //end of chain already + { + m_data[ptr] = key; + m_data[ptr + 1] = value; + if (m_size >= m_threshold) { + rehash(m_data.length * 2); //size is set inside + } else { + ++m_size; + } + return NO_VALUE; + } else if (k == key) //we check FREE prior to this call + { + int ret = m_data[ptr + 1]; + m_data[ptr + 1] = value; + return ret; } - slot = (phiMix(k) & m_mask) << 1; //calculate the starting slot for the current key - if (last <= pos ? last >= slot || slot > pos : last >= slot && slot > pos) { - break; + + while (true) { + ptr = ptr + 2 & m_mask2; //that's next index calculation + k = m_data[ptr]; + if (k == FREE_KEY) { + m_data[ptr] = key; + m_data[ptr + 1] = value; + if (m_size >= m_threshold) { + rehash(m_data.length * 2); //size is set inside + } else { + ++m_size; + } + return NO_VALUE; + } else if (k == key) { + int ret = m_data[ptr + 1]; + m_data[ptr + 1] = value; + return ret; + } } - pos = pos + 2 & m_mask2; //go to the next entry - } - data[last] = k; - data[last + 1] = data[pos + 1]; } - } - final int size() { - return m_size; - } + /** Taken from FastUtil implementation */ - final private void rehash(final int newCapacity) { - m_threshold = (int) (newCapacity / 2 * m_fillFactor); - m_mask = newCapacity / 2 - 1; - m_mask2 = newCapacity - 1; + private int remove(int key) { + if (key == FREE_KEY) { + if (!m_hasFreeKey) + return NO_VALUE; + m_hasFreeKey = false; + --m_size; + return m_freeValue; //value is not cleaned + } - final int oldCapacity = m_data.length; - final int[] oldData = m_data; + int ptr = (phiMix(key) & m_mask) << 1; + int k = m_data[ptr]; + if (k == key) //we check FREE prior to this call + { + int res = m_data[ptr + 1]; + shiftKeys(ptr); + --m_size; + return res; + } else if (k == FREE_KEY) + return NO_VALUE; //end of chain already + while (true) { + ptr = ptr + 2 & m_mask2; //that's next index calculation + k = m_data[ptr]; + if (k == key) { + int res = m_data[ptr + 1]; + shiftKeys(ptr); + --m_size; + return res; + } else if (k == FREE_KEY) + return NO_VALUE; + } + } - m_data = new int[newCapacity]; - m_size = m_hasFreeKey ? 1 : 0; + private final int shiftKeys(int pos) { + // Shift entries with the same hash. + int last, slot; + int k; + int[] data = m_data; + while (true) { + pos = (last = pos) + 2 & m_mask2; + while (true) { + if ((k = data[pos]) == FREE_KEY) { + data[last] = FREE_KEY; + return last; + } + slot = (phiMix(k) & m_mask) << 1; //calculate the starting slot for the current key + if (last <= pos ? last >= slot || slot > pos : last >= slot && slot > pos) { + break; + } + pos = pos + 2 & m_mask2; //go to the next entry + } + data[last] = k; + data[last + 1] = data[pos + 1]; + } + } - for (int i = 0; i < oldCapacity; i += 2) { - final int oldKey = oldData[i]; - if (oldKey != FREE_KEY) { - put(oldKey, oldData[i + 1]); - } + final int size() { + return m_size; } - } - - /** Taken from FastUtil implementation */ - - /** Return the least power of two greater than or equal to the specified value. - * - *

Note that this function will return 1 when the argument is 0. - * - * @param x a long integer smaller than or equal to 262. - * @return the least power of two greater than or equal to the specified value. - */ - final private static long nextPowerOfTwo(long x) { - if (x == 0) - return 1; - x--; - x |= x >> 1; - x |= x >> 2; - x |= x >> 4; - x |= x >> 8; - x |= x >> 16; - return (x | x >> 32) + 1; - } - - /** Returns the least power of two smaller than or equal to 230 - * and larger than or equal to Math.ceil( expected / f ). - * - * @param expected the expected number of elements in a hash table. - * @param f the load factor. - * @return the minimum possible size for a backing array. - * @throws IllegalArgumentException if the necessary size is larger than 230. - */ - final private static int arraySize(final int expected, final float f) { - final long s = Math.max(2, nextPowerOfTwo((long) Math.ceil(expected / f))); - if (s > 1 << 30) - throw new IllegalArgumentException("Too large (" + expected + " expected elements with load factor " + f + ")"); - return (int) s; - } - - //taken from FastUtil - private static final int INT_PHI = 0x9E3779B9; - - final private static int phiMix(final int x) { - final int h = x * INT_PHI; - return h ^ h >> 16; - } - - @Override - public String toString() { - //return java.util.Arrays.toString(m_data); - final StringBuffer b = new StringBuffer("{"); - final int l = m_data.length; - boolean first = true; - for (int i = 0; i < l; i += 2) { - - final int v = m_data[i]; - if (v != FREE_KEY) { - if (!first) { - b.append(','); + + private final void rehash(int newCapacity) { + m_threshold = (int) (newCapacity / 2 * m_fillFactor); + m_mask = newCapacity / 2 - 1; + m_mask2 = newCapacity - 1; + + int oldCapacity = m_data.length; + int[] oldData = m_data; + + m_data = new int[newCapacity]; + m_size = m_hasFreeKey ? 1 : 0; + + for (int i = 0; i < oldCapacity; i += 2) { + int oldKey = oldData[i]; + if (oldKey != FREE_KEY) { + put(oldKey, oldData[i + 1]); + } + } + } + + @Override + public String toString() { + //return java.util.Arrays.toString(m_data); + StringBuilder b = new StringBuilder("{"); + int l = m_data.length; + boolean first = true; + for (int i = 0; i < l; i += 2) { + + int v = m_data[i]; + if (v != FREE_KEY) { + if (!first) { + b.append(','); + } + first = false; + b.append(v - 1); + } } - first = false; - b.append(v - 1); - } + b.append('}'); + return b.toString(); } - b.append("}"); - return b.toString(); - } } diff --git a/IP/src/iProlog/IntStack.java b/IP/src/iProlog/IntStack.java index cd08edf2..aed170b2 100644 --- a/IP/src/iProlog/IntStack.java +++ b/IP/src/iProlog/IntStack.java @@ -1,128 +1,125 @@ - /** -Dynamic Stack for int data. + * Dynamic Stack for int data. */ package iProlog; + import java.util.Arrays; class IntStack { - private int stack[]; - - private int top; - - static int SIZE = 16; // power of 2 - - static int MINSIZE = 1 << 15; // power of 2 - - IntStack() { - this(SIZE); - } - - IntStack(final int size) { - stack = new int[size]; - clear(); - } - - final int getTop() { - return top; - } - - final int setTop(final int top) { - return this.top = top; - } - - final void clear() { - //for (int i = 0; i <= top; i++) - //stack[i] = 0; - top = -1; - } - - final boolean isEmpty() { - return top < 0; - } - - /** - * Pushes an element - top is incremented first than the - * element is assigned. This means top point to the last assigned - * element - which can be returned with peek(). - */ - final void push(final int i) { - // IO.dump("push:"+i); - if (++top >= stack.length) { - expand(); - } - stack[top] = i; - } - - final int pop() { - final int r = stack[top--]; - shrink(); - return r; - } - - final int get(final int i) { - return stack[i]; - } - - final void set(final int i, final int val) { - stack[i] = val; - } - - final int size() { - return top + 1; - } - - /** - * dynamic array operation: doubles when full - */ - private final void expand() { - final int l = stack.length; - final int[] newstack = new int[l << 1]; - - System.arraycopy(stack, 0, newstack, 0, l); - stack = newstack; - } - - /** - * dynamic array operation: shrinks to 1/2 if more than than 3/4 empty - */ - private final void shrink() { - int l = stack.length; - if (l <= MINSIZE || top << 2 >= l) - return; - l = 1 + (top << 1); // still means shrink to at 1/2 or less of the heap - if (top < MINSIZE) { - l = MINSIZE; - } - - final int[] newstack = new int[l]; - System.arraycopy(stack, 0, newstack, 0, top + 1); - stack = newstack; - } - - int[] toArray() { - final int[] array = new int[size()]; - if (size() > 0) { - System.arraycopy(stack, 0, array, 0, size()); - } - return array; - } - - public final void reverse() { - int l = size(); - int h = l >> 1; - // Prolog.dump("l="+l); - for (int i = 0; i < h; i++) { - int temp = stack[i]; - stack[i] = stack[l - i - 1]; - stack[l - i - 1] = temp; - } - } - - @Override - public String toString() { - return Arrays.toString(toArray()); - } + private static final int SIZE = 16; // power of 2 + private static final int MINSIZE = 1 << 15; // power of 2 + private int stack[]; + private int top; + + IntStack() { + this(SIZE); + } + + private IntStack(int size) { + stack = new int[size]; + clear(); + } + + final int getTop() { + return top; + } + + final int setTop(int top) { + return this.top = top; + } + + final void clear() { + //for (int i = 0; i <= top; i++) + //stack[i] = 0; + top = -1; + } + + final boolean isEmpty() { + return top < 0; + } + + /** + * Pushes an element - top is incremented first than the + * element is assigned. This means top point to the last assigned + * element - which can be returned with peek(). + */ + final void push(int i) { + // IO.dump("push:"+i); + if (++top >= stack.length) { + expand(); + } + stack[top] = i; + } + + final int pop() { + int r = stack[top--]; + shrink(); + return r; + } + + final int get(int i) { + return stack[i]; + } + + final void set(int i, int val) { + stack[i] = val; + } + + final int size() { + return top + 1; + } + + /** + * dynamic array operation: doubles when full + */ + private final void expand() { + int l = stack.length; + int[] newstack = new int[l << 1]; + + System.arraycopy(stack, 0, newstack, 0, l); + stack = newstack; + } + + /** + * dynamic array operation: shrinks to 1/2 if more than than 3/4 empty + */ + private final void shrink() { + int l = stack.length; + if (l <= MINSIZE || top << 2 >= l) + return; + l = 1 + (top << 1); + if (top < MINSIZE) { + l = MINSIZE; + } + + int[] newstack = new int[l]; + System.arraycopy(stack, 0, newstack, 0, top + 1); + stack = newstack; + } + + int[] toArray() { + int[] array = new int[size()]; + if (size() > 0) { + System.arraycopy(stack, 0, array, 0, size()); + } + return array; + } + + public final void reverse() { + int l = size(); + int h = l >> 1; + // Prolog.dump("l="+l); + for (int i = 0; i < h; i++) { + int temp = stack[i]; + stack[i] = stack[l - i - 1]; + stack[l - i - 1] = temp; + } + } + + @Override + public String toString() { + return Arrays.toString(toArray()); + } } diff --git a/IP/src/iProlog/Main.java b/IP/src/iProlog/Main.java index 06252e74..2d758f62 100644 --- a/IP/src/iProlog/Main.java +++ b/IP/src/iProlog/Main.java @@ -1,57 +1,59 @@ package iProlog; + import java.util.stream.Stream; -public class Main { +enum Main { + ; - static void println(final Object o) { - System.out.println(o); - } + static void println(Object o) { + System.out.println(o); + } - static void pp(final Object o) { - System.out.println(o); - } + static void pp(Object o) { + System.out.println(o); + } - public static void run(final String fname0) { - final boolean p = true; + private static void run(String fname0) { + boolean p = true; - final String fname = fname0 + ".nl"; - Engine P; + String fname = fname0 + ".nl"; + Engine P; - if (p) { - P = new Prog(fname); - pp("CODE"); - ((Prog) P).ppCode(); - } else { - P = new Engine(fname); - } + if (p) { + P = new Prog(fname); + pp("CODE"); + ((Prog) P).ppCode(); + } else { + P = new Engine(fname); + } - pp("RUNNING"); - final long t1 = System.nanoTime(); - P.run(); - final long t2 = System.nanoTime(); - System.out.println("time=" + (t2 - t1) / 1000000000.0); + pp("RUNNING"); + long t1 = System.nanoTime(); + P.run(); + long t2 = System.nanoTime(); + System.out.println("time=" + (t2 - t1) / 1000000000.0); - } + } - public static void srun(final String fname0) { - final String fname = fname0 + ".nl"; - final Prog P = new Prog(fname); + public static void srun(String fname0) { + String fname = fname0 + ".nl"; + Prog P = new Prog(fname); - pp("CODE"); - P.ppCode(); + pp("CODE"); + P.ppCode(); - pp("RUNNING"); - final long t1 = System.nanoTime(); + pp("RUNNING"); + long t1 = System.nanoTime(); - final Stream S = P.stream(); - S.forEach(x -> Main.pp(P.showTerm(x))); + Stream S = P.stream(); + S.forEach(x -> pp(P.showTerm(x))); - final long t2 = System.nanoTime(); - System.out.println("time=" + (t2 - t1) / 1000000000.0); - } + long t2 = System.nanoTime(); + System.out.println("time=" + (t2 - t1) / 1000000000.0); + } - public static void main(final String[] args) { - String fname=args[0]; - run(fname); - } + public static void main(String[] args) { + String fname = args[0]; + run(fname); + } } diff --git a/IP/src/iProlog/ObStack.java b/IP/src/iProlog/ObStack.java index ba6bfc43..3b56ff43 100644 --- a/IP/src/iProlog/ObStack.java +++ b/IP/src/iProlog/ObStack.java @@ -1,20 +1,21 @@ package iProlog; + import java.util.ArrayList; class ObStack extends ArrayList { - private static final long serialVersionUID = 1L; + private static final long serialVersionUID = 1L; - final T pop() { - final int last = this.size() - 1; - return this.remove(last); - } + final T pop() { + int last = size() - 1; + return remove(last); + } - final void push(final T O) { - add(O); - } + final void push(T O) { + add(O); + } - final T peek() { - return get(this.size() - 1); - } + final T peek() { + return get(size() - 1); + } } diff --git a/IP/src/iProlog/Prog.java b/IP/src/iProlog/Prog.java index e6b944c9..938cad16 100644 --- a/IP/src/iProlog/Prog.java +++ b/IP/src/iProlog/Prog.java @@ -1,151 +1,155 @@ - package iProlog; //import java.util.Arrays; -import java.util.stream.Stream; + +import java.util.Set; import java.util.Spliterator; import java.util.function.Consumer; +import java.util.stream.Stream; import java.util.stream.StreamSupport; -public class Prog extends Engine implements Spliterator { - Prog(final String fname) { - super(fname); - } +class Prog extends Engine implements Spliterator { + private static final Set LIST_CONS = Set.of(".", "[|]", "list"); + private static final Set OPS = Set.of("/", "-", "+", "="); - static void pp(final Object o) { - Main.pp(o); - } + Prog(String fname) { + super(fname); + } - static void println(final Object o) { - Main.println(o); - } + private static void pp(Object o) { + Main.pp(o); + } - @Override - String showTerm(final Object O) { - if (O instanceof Object[]) - return st0((Object[]) O); - return O.toString(); - } + static void println(Object o) { + Main.println(o); + } - static String maybeNull(final Object O) { - if (null == O) - return "$null"; - if (O instanceof Object[]) - return st0((Object[]) O); - return O.toString(); - } + private static String maybeNull(Object O) { + if (null == O) + return "$null"; + if (O instanceof Object[]) + return st0((Object[]) O); + return O.toString(); + } - static boolean isListCons(final Object name) { - return ".".equals(name) || "[|]".equals(name) || "list".equals(name); - } + private static boolean isListCons(Object name) { + return LIST_CONS.contains(name); + } - static boolean isOp(final Object name) { - return "/".equals(name) || "-".equals(name) || "+".equals(name) || "=".equals(name); - } + private static boolean isOp(Object name) { + return OPS.contains(name); + } - static String st0(final Object[] args) { - final StringBuffer buf = new StringBuffer(); - final String name = args[0].toString(); - if (args.length == 3 && isOp(name)) { - buf.append("("); - buf.append(maybeNull(args[0])); - buf.append(" " + name + " "); - buf.append(maybeNull(args[1])); - buf.append(")"); - } else if (args.length == 3 && isListCons(name)) { - buf.append('['); - { - buf.append(maybeNull(args[1])); - Object tail = args[2]; - for (;;) { - - if ("[]".equals(tail) || "nil".equals(tail)) { - break; - } - if (!(tail instanceof Object[])) { - buf.append('|'); - buf.append(maybeNull(tail)); - break; - } - final Object[] list = (Object[]) tail; - if (!(list.length == 3 && isListCons(list[0]))) { - buf.append('|'); - buf.append(maybeNull(tail)); - break; - } else { - //if (i > 1) - buf.append(','); - buf.append(maybeNull(list[1])); - tail = list[2]; - } + private static String st0(Object[] args) { + StringBuilder buf = new StringBuilder(); + String name = args[0].toString(); + if (args.length == 3 && isOp(name)) { + buf.append('('); + buf.append(maybeNull(args[0])); + buf.append(' ').append(name).append(' '); + buf.append(maybeNull(args[1])); + buf.append(')'); + } else if (args.length == 3 && isListCons(name)) { + buf.append('['); + { + buf.append(maybeNull(args[1])); + Object tail = args[2]; + for (; ; ) { + + if ("[]".equals(tail) || "nil".equals(tail)) { + break; + } + if (!(tail instanceof Object[])) { + buf.append('|'); + buf.append(maybeNull(tail)); + break; + } + Object[] list = (Object[]) tail; + if (!(list.length == 3 && isListCons(list[0]))) { + buf.append('|'); + buf.append(maybeNull(tail)); + break; + } else { + //if (i > 1) + buf.append(','); + buf.append(maybeNull(list[1])); + tail = list[2]; + } + } + } + buf.append(']'); + } else if (args.length == 2 && "$VAR".equals(name)) { + buf.append("_").append(args[1]); + } else { + String qname = maybeNull(args[0]); + buf.append(qname); + buf.append('('); + for (int i = 1; i < args.length; i++) { + Object O = args[i]; + buf.append(maybeNull(O)); + if (i < args.length - 1) { + buf.append(','); + } + } + buf.append(')'); } - } - buf.append(']'); - } else if (args.length == 2 && "$VAR".equals(name)) { - buf.append("_" + args[1]); - } else { - final String qname = maybeNull(args[0]); - buf.append(qname); - buf.append("("); - for (int i = 1; i < args.length; i++) { - final Object O = args[i]; - buf.append(maybeNull(O)); - if (i < args.length - 1) { - buf.append(","); - } - } - buf.append(")"); + return buf.toString(); } - return buf.toString(); - } - void ppCode() { - pp("\nSYMS:"); - pp(syms); - pp("\nCLAUSES:\n"); + @Override + String showTerm(Object O) { + if (O instanceof Object[]) + return st0((Object[]) O); + return O.toString(); + } + + void ppCode() { + pp("\nSYMS:"); + pp(syms); + pp("\nCLAUSES:\n"); + + for (int i = 0; i < clauses.length; i++) { - for (int i = 0; i < clauses.length; i++) { + Clause C = clauses[i]; + pp("[" + i + "]:" + showClause(C)); + } + pp(""); - final Clause C = clauses[i]; - pp("[" + i + "]:" + showClause(C)); } - pp(""); - } + private String showClause(Clause s) { + StringBuilder buf = new StringBuilder(); + int l = s.hgs.length; + buf.append("---base:[").append(s.base).append("] neck: ").append(s.neck).append("-----\n"); + buf.append(showCells(s.base, s.len)); // TODO + buf.append('\n'); + buf.append(showCell(s.hgs[0])); + + buf.append(" :- ["); + for (int i = 1; i < l; i++) { + + int e = s.hgs[i]; + buf.append(showCell(e)); + if (i < l - 1) { + buf.append(", "); + } + } - String showClause(final Clause s) { - final StringBuffer buf = new StringBuffer(); - final int l = s.hgs.length; - buf.append("---base:[" + s.base + "] neck: " + s.neck + "-----\n"); - buf.append(showCells(s.base, s.len)); // TODO - buf.append("\n"); - buf.append(showCell(s.hgs[0])); - - buf.append(" :- ["); - for (int i = 1; i < l; i++) { - - final int e = s.hgs[i]; - buf.append(showCell(e)); - if (i < l - 1) { - buf.append(", "); - } - } - - buf.append("]\n"); - - buf.append(showTerm(s.hgs[0])); - if (l > 1) { - buf.append(" :- \n"); - for (int i = 1; i < l; i++) { - final int e = s.hgs[i]; - buf.append(" "); - buf.append(showTerm(e)); - buf.append("\n"); - } - } else { - buf.append("\n"); - } - return buf.toString(); - } + buf.append("]\n"); + + buf.append(showTerm(s.hgs[0])); + if (l > 1) { + buf.append(" :- \n"); + for (int i = 1; i < l; i++) { + int e = s.hgs[i]; + buf.append(" "); + buf.append(showTerm(e)); + buf.append('\n'); + } + } else { + buf.append('\n'); + } + return buf.toString(); + } /* String showHead(final Cls s) { @@ -154,54 +158,54 @@ String showHead(final Cls s) { } */ - @Override - void ppGoals(IntList bs) { - while (!IntList.isEmpty(bs)) { - pp(showTerm(IntList.head(bs))); - bs = IntList.tail(bs); - } + @Override + void ppGoals(IntList bs) { + while (!IntList.isEmpty(bs)) { + pp(showTerm(IntList.head(bs))); + bs = IntList.tail(bs); + } - } + } - @Override - void ppc(final Spine S) { - //stats(); - final IntList bs = S.gs; - pp("\nppc: t=" + S.ttop + ",k=" + S.k + "len=" + IntList.len(bs)); - ppGoals(bs); - } + @Override + void ppc(Spine S) { + //stats(); + IntList bs = S.gs; + pp("\nppc: t=" + S.ttop + ",k=" + S.k + "len=" + IntList.len(bs)); + ppGoals(bs); + } - /////////////// end of show + /////////////// end of show - // possibly finite Stream support + // possibly finite Stream support - public Stream stream() { - return StreamSupport.stream(this, false); - } + public Stream stream() { + return StreamSupport.stream(this, false); + } - @Override - public Spliterator trySplit() { - return null; - } + @Override + public Spliterator trySplit() { + return null; + } - @Override - public int characteristics() { - return (Spliterator.ORDERED | Spliterator.NONNULL) & ~Spliterator.SIZED; - } + @Override + public int characteristics() { + return (Spliterator.ORDERED | Spliterator.NONNULL) & ~Spliterator.SIZED; + } - @Override - public long estimateSize() { - return Long.MAX_VALUE; - } + @Override + public long estimateSize() { + return Long.MAX_VALUE; + } - @Override - public boolean tryAdvance(final Consumer action) { - final Object R = ask(); - final boolean ok = null != R; - if (ok) { - action.accept(R); + @Override + public boolean tryAdvance(Consumer action) { + Object R = ask(); + boolean ok = null != R; + if (ok) { + action.accept(R); + } + return ok; } - return ok; - } } diff --git a/IP/src/iProlog/Spine.java b/IP/src/iProlog/Spine.java index 765fd00a..e5d602bc 100644 --- a/IP/src/iProlog/Spine.java +++ b/IP/src/iProlog/Spine.java @@ -1,48 +1,45 @@ package iProlog; + /** * runtime representation of an immutable list of goals * together with top of heap and trail pointers * and current clause tried out by head goal * as well as registers associated to it - * + *

* note that parts of this immutable lists * are shared among alternative branches */ class Spine { - /** - * creates a spine - as a snapshot of some runtime elements - */ - Spine(final int[] gs0, final int base, final IntList gs, final int ttop, final int k, final int[] cs) { - hd = gs0[0]; - this.base = base; - this.gs = IntList.tail(IntList.app(gs0, gs)); // prepends the goals of clause with head hs - this.ttop = ttop; - this.k = k; - this.cs = cs; - } - - /** - * creates a specialized spine returning an answer (with no goals left to solve) - */ - Spine(final int hd, final int ttop) { - this.hd = hd; - base = 0; - gs = IntList.empty; - this.ttop = ttop; - - k = -1; - cs = null; - } - - final int hd; // head of the clause to which this corresponds - final int base; // top of the heap when this was created - - final IntList gs; // goals - with the top one ready to unfold - final int ttop; // top of the trail when this was created + final int hd; // head of the clause to which this corresponds + final int base; // top of the heap when this was created + final IntList gs; // goals - with the top one ready to unfold + final int ttop; // top of the trail when this was created + int k; + int[] xs; // index elements + int[] cs; // array of clauses known to be unifiable with top goal in gs - int k; + /** + * creates a spine - as a snapshot of some runtime elements + */ + Spine(int[] gs0, int base, IntList gs, int ttop, int k, int[] cs) { + hd = gs0[0]; + this.base = base; + this.gs = IntList.tail(IntList.app(gs0, gs)); // prepends the goals of clause with head hs + this.ttop = ttop; + this.k = k; + this.cs = cs; + } + /** + * creates a specialized spine returning an answer (with no goals left to solve) + */ + Spine(int hd, int ttop) { + this.hd = hd; + base = 0; + gs = IntList.empty; + this.ttop = ttop; - int[] xs; // index elements - int[] cs; // array of clauses known to be unifiable with top goal in gs + k = -1; + cs = null; + } } diff --git a/IP/src/iProlog/Toks.java b/IP/src/iProlog/Toks.java index 30b57cf6..61dc15c9 100644 --- a/IP/src/iProlog/Toks.java +++ b/IP/src/iProlog/Toks.java @@ -1,145 +1,140 @@ package iProlog; + import java.io.*; -import java.util.*; +import java.util.ArrayList; +import java.util.Arrays; /** * Reads chars from char streams using the current default encoding */ public class Toks extends StreamTokenizer { - // reserved words - with syntactic function - - public static String IF = "if"; - public static String AND = "and"; - public static String DOT = "."; - public static String HOLDS = "holds"; - public static String LISTS = "lists"; // todo - public static String IS = "is"; // todo - - public static Toks makeToks(final String s, final boolean fromFile) { - try { - Reader R; - if (fromFile) { - R = new FileReader(s); - } else { - R = new StringReader(s); - } - final Toks T = new Toks(R); - return T; - - } catch (final IOException e) { - e.printStackTrace(); - return null; + // reserved words - with syntactic function + + private static final String IF = "if"; + private static final String AND = "and"; + private static final String DOT = "."; + private static final String HOLDS = "holds"; + private static final String LISTS = "lists"; // todo + private static final String IS = "is"; // todo + + private Toks(Reader reader) { + super(reader); + resetSyntax(); + eolIsSignificant(false); + ordinaryChar('.'); + ordinaryChars('!', '/'); // 33-47 + ordinaryChars(':', '@'); // 55-64 + ordinaryChars('[', '`'); // 91-96 + ordinaryChars('{', '~'); // 123-126 + wordChars('_', '_'); + wordChars('a', 'z'); + wordChars('A', 'Z'); + wordChars('0', '9'); + slashStarComments(true); + slashSlashComments(true); + ordinaryChar('%'); } - } - - public Toks(final Reader reader) { - super(reader); - resetSyntax(); - eolIsSignificant(false); - ordinaryChar('.'); - ordinaryChars('!', '/'); // 33-47 - ordinaryChars(':', '@'); // 55-64 - ordinaryChars('[', '`'); // 91-96 - ordinaryChars('{', '~'); // 123-126 - wordChars('_', '_'); - wordChars('a', 'z'); - wordChars('A', 'Z'); - wordChars('0', '9'); - slashStarComments(true); - slashSlashComments(true); - ordinaryChar('%'); - } - - public String getWord() { - String t = null; - - int c = TT_EOF; - try { - c = nextToken(); - while (Character.isWhitespace(c) && c != TT_EOF) { - c = nextToken(); - } - } catch (final IOException e) { - return "*** tokenizer error:" + t; + + private static Toks toks(String s, boolean fromFile) { + try { + Reader R; + R = fromFile ? new FileReader(s) : new StringReader(s); + Toks T = new Toks(R); + return T; + + } catch (IOException e) { + e.printStackTrace(); + return null; + } } - switch (c) { - case TT_WORD: { - final char first = sval.charAt(0); - if (Character.isUpperCase(first) || '_' == first) { - t = "v:" + sval; - } else { - try { - final int n = Integer.parseInt(sval); - if (Math.abs(n) < 1 << 28) { - t = "n:" + sval; + public static ArrayList>> sentences(String s, boolean fromFile) { + ArrayList>> Wsss = new ArrayList<>(); + ArrayList> Wss = new ArrayList<>(); + ArrayList Ws = new ArrayList<>(); + Toks toks = toks(s, fromFile); + String t = null; + while (null != (t = toks.getWord())) { + + if (DOT.equals(t)) { + Wss.add(Ws); + Wsss.add(Wss); + Wss = new ArrayList<>(); + Ws = new ArrayList<>(); + } else if (("c:" + IF).equals(t)) { + + Wss.add(Ws); + + Ws = new ArrayList<>(); + } else if (("c:" + AND).equals(t)) { + Wss.add(Ws); + + Ws = new ArrayList<>(); + } else if (("c:" + HOLDS).equals(t)) { + String w = Ws.get(0); + Ws.set(0, "h:" + w.substring(2)); + } else if (("c:" + LISTS).equals(t)) { + String w = Ws.get(0); + Ws.set(0, "l:" + w.substring(2)); + } else if (("c:" + IS).equals(t)) { + String w = Ws.get(0); + Ws.set(0, "f:" + w.substring(2)); } else { - t = "c:" + sval; + Ws.add(t); } - } catch (final Exception e) { - t = "c:" + sval; - } } - } - break; + return Wsss; + } - case StreamTokenizer.TT_EOF: { - t = null; - } - break; + static String toString(Object[] Wsss) { + return Arrays.deepToString(Wsss); + } - default: { - t = "" + (char) c; - } + public static void main(String[] args) { + Main.pp(sentences("prog.nl", true)); } - return t; - } - - public static ArrayList>> toSentences(final String s, final boolean fromFile) { - final ArrayList>> Wsss = new ArrayList>>(); - ArrayList> Wss = new ArrayList>(); - ArrayList Ws = new ArrayList(); - final Toks toks = makeToks(s, fromFile); - String t = null; - while (null != (t = toks.getWord())) { - - if (DOT.equals(t)) { - Wss.add(Ws); - Wsss.add(Wss); - Wss = new ArrayList>(); - Ws = new ArrayList(); - } else if (("c:" + IF).equals(t)) { - - Wss.add(Ws); - - Ws = new ArrayList(); - } else if (("c:" + AND).equals(t)) { - Wss.add(Ws); - - Ws = new ArrayList(); - } else if (("c:" + HOLDS).equals(t)) { - final String w = Ws.get(0); - Ws.set(0, "h:" + w.substring(2)); - } else if (("c:" + LISTS).equals(t)) { - final String w = Ws.get(0); - Ws.set(0, "l:" + w.substring(2)); - } else if (("c:" + IS).equals(t)) { - final String w = Ws.get(0); - Ws.set(0, "f:" + w.substring(2)); - } else { - Ws.add(t); - } - } - return Wsss; - } - static String toString(final Object[] Wsss) { - return Arrays.deepToString(Wsss); - } + private String getWord() { + String t = null; + + int c = StreamTokenizer.TT_EOF; + try { + c = nextToken(); + while (Character.isWhitespace(c) && c != StreamTokenizer.TT_EOF) { + c = nextToken(); + } + } catch (IOException ignored) { + return "*** tokenizer error:" + ignored; + } + + switch (c) { + case StreamTokenizer.TT_WORD: { + char first = sval.charAt(0); + if (Character.isUpperCase(first) || '_' == first) { + t = "v:" + sval; + } else { + try { + int n = Integer.parseInt(sval); + t = Math.abs(n) < 1 << 28 ? "n:" + sval : "c:" + sval; + } catch (Exception ignored) { + t = "c:" + sval; + } + } + } + break; + + case StreamTokenizer.TT_EOF: { + t = null; + } + break; - public static void main(final String[] args) { - Main.pp(toSentences("prog.nl", true)); - } + default: { + t = "" + (char) c; + } + + } + return t; + } } \ No newline at end of file