diff anagram/agcore/ftpar.cpp @ 0:13d2b8934445

Import AnaGram (near-)release tree into Mercurial.
author David A. Holland
date Sat, 22 Dec 2007 17:52:45 -0500
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/anagram/agcore/ftpar.cpp	Sat Dec 22 17:52:45 2007 -0500
@@ -0,0 +1,1286 @@
+/*
+ * AnaGram, A System for Syntax Directed Programming
+ * Copyright 1993-2002 Parsifal Software. All Rights Reserved.
+ * See the file COPYING for license and usage terms.
+ *
+ * ftpar.cpp
+ */
+
+#include "agarray.h"
+#include "arrays.h"
+#include "bpe3.h"
+#include "cd.h"
+#include "config.h"
+#include "csexp.h"
+#include "dict.h"
+#include "ftpar.h"
+#include "keyword.h"
+#include "q1glbl.h"
+#include "rule.h"
+#include "token.h"
+#include "tsd.h"
+
+//#define INCLUDE_LOGGING
+#include "log.h"
+
+
+AgArray<unsigned> traceCounts;
+
+//static dc_ref trace_count_display;
+
+
+int precedes(cint a, cint b) {
+  if (a.y < b.y) return 1;
+  if (a.y > b.y) return 0;
+  if (a.x < b.x) return 1;
+  return 0;
+}
+
+
+FtParser::FtParser(AgString t)
+  : text(t)
+  , state(t.pointer())
+  , initialStack(0)
+  , lookAhead(state.pointer)
+  , endPointer(state.pointer +
+	       (state.pointer != 0 ? strlen((const char *) state.pointer) : 0))
+  , inputToken(0)
+  , nNullShifts(0)
+  , processState(ready)
+  , ruleToReduce(0)
+  , reductionSelection(0)
+  , stackChanged(*this)
+  , testingKeyword(0)
+{
+  LOGSECTION("FtParser::FtParser");
+  LOGV((int) state.pointer);
+  LOGV((int) lookAhead);
+  getToken();
+  if (!traceCounts.exists()) {
+    traceCounts = AgArray<unsigned>(nforms_base + 1);
+    memset(traceCounts.pointer(), 0, sizeof(unsigned)*traceCounts.size());
+/*
+    trace_count_display =
+      dc_ref(new rule_count_dc("Trace Coverage", traceCounts));
+*/
+  }
+}
+
+FtParser::FtParser()
+  : initialStack(0)
+  , lookAhead(0)
+  , inputToken(0)
+  , nNullShifts(0)
+  , processState(ready)
+  , ruleToReduce(0)
+  , reductionSelection(0)
+  , stackChanged(*this)
+  , testingKeyword(0)
+{
+  LOGSECTION("FtParser::FtParser");
+  LOGV((int) state.pointer);
+  LOGV((int) lookAhead);
+  if (!traceCounts.exists()) {
+    traceCounts = AgArray<unsigned>(nforms_base + 1);
+    memset(traceCounts.pointer(), 0, sizeof(unsigned)*traceCounts.size());
+/*
+    trace_count_display =
+      dc_ref(new rule_count_dc("Trace Coverage", traceCounts));
+*/
+  }
+}
+
+FtParser::FtParser(tsd *initialStack_)
+  : initialStack(initialStack_ ? copy_tuple_set(initialStack_) : 0)
+  , lookAhead(0)
+  , inputToken(0)
+  , nNullShifts(0)
+  , processState(ready)
+  , ruleToReduce(0)
+  , reductionSelection(0)
+  , stackChanged(*this)
+  , testingKeyword(0)
+{
+  LOGSECTION("FtParser::FtParser");
+  LOGV((int) state.pointer);
+  LOGV((int) lookAhead);
+  LOGV((int) initialStack);
+  if (initialStack) {
+    LOGV(initialStack->nt);
+    for (unsigned i = 0; i < initialStack->nt; i++) {
+      unsigned sn, tn;
+      xtx(initialStack,i, &sn, &tn);
+      stateStack.push(State(sn,tn));
+    }
+    state = stateStack.pop();
+  }
+  LOGV(stateStack.size());
+  if (!traceCounts.exists()) {
+    traceCounts = AgArray<unsigned>(nforms_base + 1);
+    memset(traceCounts.pointer(), 0, sizeof(unsigned)*traceCounts.size());
+/*
+    trace_count_display =
+      dc_ref(new rule_count_dc("Trace Coverage", traceCounts));
+*/
+  }
+}
+
+FtParser::~FtParser() {
+  if (initialStack) {
+    delete_tsd(initialStack);
+  }
+}
+
+FtParser &FtParser::reset() {
+  LOGSECTION("FtParser::reset");
+  stateStack.discardData();
+  auxStack.discardData();
+  transStack.discardData();
+  LOGV(auxStack.size());
+  LOGV((int) initialStack);
+  inputToken = 0;
+  if (initialStack) {
+    LOGV(initialStack->nt);
+    for (unsigned i = 0; i < initialStack->nt; i++) {
+      unsigned sn, tn;
+      xtx(initialStack,i, &sn, &tn);
+      stateStack.push(State(sn, tn));
+    }
+    state = stateStack.pop();
+  }
+  else {
+    state = State(text.pointer());
+    lookAhead = state.pointer;
+    endPointer = state.pointer +
+      (state.pointer != 0 ? strlen((const char *) state.pointer) : 0);
+    getToken();
+  }
+  LOGV(stateStack.size());
+  reductionState = State();
+  nNullShifts = 0;
+  processState = ready;
+  //if ((dc *)displayControl) {
+  //  displayControl->des->d_size.y = stateStack.size();
+  //}
+  stackChanged(stateStack.size() + 1);
+  return *this;
+}
+
+void FtParser::track(void) {
+  LOGSECTION("FtParser::track");
+  LOGV((int) state.pointer);
+  LOGV((int) lookAhead);
+  if (lookAhead != 0) {
+    while (state.pointer < lookAhead) {
+      switch (*state.pointer++) {
+	case '\n':
+	  if (*state.pointer) state.column = state.charPos = 0, state.line++;
+	case '\f':
+	  break;
+	case '\t':
+	  state.column += tab_spacing - state.column % tab_spacing;
+	  state.charPos++;
+	  break;
+	default:
+	  state.column++;
+	  state.charPos++;
+      }
+    }
+  }
+  state.token = inputToken = 0;
+  auxStack.discardData();
+  transStack.discardData();
+  LOGV(auxStack.size());
+  nNullShifts = 0;
+  LOGV(state.line) LCV(state.column);
+}
+
+void FtParser::shiftTerminalAndAccept(void) {
+  LOGSECTION("FtParser::shiftTerminalAndAccept");
+  processState = finished;
+  track();
+}
+
+void FtParser::shiftTerminal() {
+  LOGSECTION("FtParser::shiftTerminal");
+  LOGV(state.number) LCV(state.token) LCV((int) state.pointer);
+  LOGV(stateStack.size());
+  state.token = map_state_number[actionParameter].char_token;
+  stateStack.push(state);
+  state.number = actionParameter;
+  track();
+  LOGV(state.token);
+  LOGV(state.number) LCV((int) state.pointer);
+  LOGV(stateStack.size());
+}
+
+void FtParser::requestSelection(int actionParameter) {
+  LOGSECTION("FtParser::requestSelection");
+  processState = selectionRequired;
+  ruleToReduce = actionParameter;
+  reductionSelection = 0;
+  while (!validSelection(reductionSelection, reductionState.number)) {
+    reductionSelection++;
+  }
+  LOGV(ruleToReduce);
+  LOGV(reductionIndex);
+  LOGV(state.number) LCV((int) state.pointer);
+  LOGV(reductionState.number);
+  reductionState.token = ibnfs[ibnfb[ruleToReduce]];
+  LOGV(stateStack.size());
+}
+
+/*
+ * State stack discipline
+ *   reduce
+ *     If n is the length of the rule, n states are popped from the
+ *     state stack.
+ *     If n > 0, the state number becomes the state number of the
+ *     last state popped.
+ *
+ *   shiftTerminalAndReduce
+ *     If n is the length of the rule, n-1 states are popped from
+ *     the state stack.
+ *     If n > 1, the state number becomes the state number of the
+ *     last state popped.
+ *
+ *   shiftNonterminalAndReduce
+ *     If n is the length of the rule, n-1 states are popped from
+ *     the state stack.
+ *     If n > 1, the state number becomes the state number of the
+ *     last state popped.
+ *
+ *   shiftNull
+ *     The current state is pushed to the state stack and the
+ *     new state number is given by the action parameter.
+ *
+ *   shiftNonterminal
+ *     The current state is pushed to the state stack and the
+ *     new state number is given by the action parameter
+ */
+
+void FtParser::shiftTerminalAndReduce() {
+  LOGSECTION("FtParser::shiftTerminalAndReduce");
+  LOGV(state.number) LCV(state.token) LCV((int) state.pointer);
+  LOGV(location());
+  LOGV(actionParameter);
+  //form_number_map *fp = &map_form_number[actionParameter];
+  Rule rule(actionParameter);
+  RuleDescriptor &ruleDescriptor(rule);
+  //ruleLength = rule->length();
+  ruleLength = ruleDescriptor.length();
+  LOGV(ruleLength);
+  if (actionParameter <= nforms_base) {
+    traceCounts[actionParameter]++;
+  }
+  int nStackedStates = ruleLength - 1;
+  if (nStackedStates > 0) {
+    reductionState = stateStack[stateStack.size() - nStackedStates];
+  }
+  else {
+    reductionState = state;
+  }
+  track();
+  if (ibnfn[actionParameter] > 1) {
+    reductionIndex = stateStack.size() - (ruleLength - 1);
+    assert((unsigned) reductionIndex <= (unsigned) stateStack.size());
+    requestSelection(actionParameter);
+    return;
+  }
+  assert((unsigned)nStackedStates <= stateStack.size());
+  stateStack.discardData(nStackedStates);
+  //reductionState.token = rule->prim_tkn;
+  reductionState.token = ruleDescriptor.prim_tkn;
+  state.number = reductionState.number;
+  dispatchReductionToken();
+  LOGV(location());
+  LOGV(state.number);
+  LOGV(state.token) LCV((int) state.pointer);
+  auxStack.discardData();
+  transStack.discardData();
+  LOGV(auxStack.size());
+}
+
+void FtParser::reduce(void) {
+  LOGSECTION("FtParser::reduce");
+  LOGV(state.number) LCV(state.token) LCV((int) state.pointer);
+  //form_number_map *fp = &map_form_number[actionParameter];
+  Rule rule(actionParameter);
+  RuleDescriptor &ruleDescriptor(rule);
+  //ruleLength = rule->length();
+  ruleLength = ruleDescriptor.length();
+  LOGV(actionParameter);
+  LOGV(ruleLength);
+  LOGV(stateStack.size());
+  if (actionParameter <= nforms_base) {
+    traceCounts[actionParameter]++;
+  }
+  if (ruleLength) {
+    reductionState = stateStack[stateStack.size() - ruleLength];
+  }
+  else {
+    reductionState = state;
+  }
+  if (ibnfn[actionParameter] > 1) {
+    reductionIndex = stateStack.size() - ruleLength;
+    assert((unsigned) reductionIndex <= (unsigned) stateStack.size());
+    requestSelection(actionParameter);
+    return;
+  }
+  int k = ruleLength;
+  transStack.push(Transaction(k, state));
+  LOGV(transStack.size());
+  LOGV(k) LCV(state.number) LCV(state.token);
+  LOGV(nNullShifts);
+  while (k--) {
+    LOGV(stateStack.top().number) LCV(stateStack.top().token) 
+      LCV((int) state.pointer);
+    auxStack.push(stateStack.pop());
+  }
+  LOGV(auxStack.size());
+  //reductionState.token = rule->prim_tkn;
+  reductionState.token = ruleDescriptor.prim_tkn;
+  state.number = reductionState.number;
+  LOGV(reductionState.token);
+  LOGV(stateStack.size());
+  dispatchReductionToken();
+  LOGV(stateStack.size());
+  if (lookAhead) {
+    lookAhead = state.pointer;
+  }
+  state.token = 0;
+}
+
+void FtParser::skip(void) {
+  LOGSECTION("FtParser::skip");
+  LOGV(state.number) LCV(state.token);
+  if (actionParameter <= nforms_base) {
+    traceCounts[actionParameter]++;
+  }
+  track();
+}
+
+void FtParser::shiftNull(void) {
+  LOGSECTION("FtParser::shiftNull");
+  LOGV(state.number) LCV(state.token) LCV((int) state.pointer);
+  transStack.push(Transaction(-1, state));
+  LOGV(transStack.size());
+  state.token = map_state_number[actionParameter].char_token;
+  stateStack.push(state);
+  state.number = actionParameter;
+  if (lookAhead) {
+    lookAhead = state.pointer;
+  }
+  state.token = 0;
+}
+
+void FtParser::error() {
+  LOGSECTION("FtParser::error");
+  LOGV(stateStack.size());
+  LOGV(state.number) LCV(state.token) LCV((int) state.pointer);
+  LOGV(state.number) LCV(state.token) LCV((int) state.pointer);
+  LOGV(auxStack.size());
+  int k = transStack.size();
+  LOGV(transStack.size());
+  while (k--) {
+    Transaction trans = transStack.pop();
+    int n = trans.count;
+    LOGV(trans.count) LCV(trans.state.number) LCV(trans.state.token);
+    while (n < 0) {
+      stateStack.pop();
+      n++;
+    }
+    while (n > 0) {
+      stateStack.push(auxStack.pop());
+      n--;
+    }
+    state.number = trans.state.number;
+    state.token = trans.state.token;
+    LOGV(trans.count) LCV(state.number) LCV(state.token);
+  }
+  auxStack.discardData();
+  transStack.discardData();
+  processState = syntaxError;
+  if (lookAhead) {
+    lookAhead = state.pointer;
+  }
+  state.token = 0;
+}
+
+
+void FtParser::accept(void) {
+  LOGSECTION("FtParser::accept");
+  state.number = stateStack.top().number;
+  state.token = stateStack.top().token;
+  stateStack.pop();
+  LOGV(stateStack.size());
+  processState = finished;
+}
+
+int FtParser::shiftNonterminal() {
+  LOGSECTION("FtParser::shiftNonterminal");
+  LOGV(state.number) LCV(state.token) LCV((int) state.pointer);
+  transStack.push(Transaction(-1, state));
+  LOGV(transStack.size());
+  LOGV(actionParameter) LCV(nstates);
+  reductionState.token = map_state_number[actionParameter].char_token;
+#ifdef INCLUDE_LOGGING
+  ics();
+  atkn(reductionState.token);
+  LOGV(reductionState.token) LCV(string_base);
+  rcs();
+#endif
+  stateStack.push(reductionState);
+  state.number = actionParameter;
+  LOGV(stateStack.size());
+  LOGV(state.number) LCV((int) state.pointer);
+  return 0;
+}
+
+int FtParser::shiftNonterminalAndReduce() {
+  LOGSECTION("FtParser::shiftNonterminalAndReduce");
+  LOGV(location());
+  LOGV(reductionState.number) LCV(reductionState.token);
+  //form_number_map *fp = &map_form_number[actionParameter];
+  Rule rule(actionParameter);
+  RuleDescriptor &ruleDescriptor(rule);
+  //ruleLength = rule->length();
+  ruleLength = ruleDescriptor.length();
+  LOGS("rule number") LCV(actionParameter);
+  LOGV(ruleLength);
+  LOGV(rule->prim_tkn);
+  LOGV(stateStack.size());
+  if (actionParameter <= nforms_base) {
+    traceCounts[actionParameter]++;
+  }
+  int nStackedStates = ruleLength - 1;
+  if (nStackedStates > 0) {
+    reductionState = stateStack[stateStack.size() - nStackedStates];
+  }
+  if (ibnfn[actionParameter] > 1) {
+    reductionIndex = stateStack.size() - (ruleLength - 1);
+    assert((unsigned) reductionIndex <= (unsigned) stateStack.size());
+    requestSelection(actionParameter);
+    return 0;
+  }
+  transStack.push(Transaction(nStackedStates, state));
+  LOGV(transStack.size());
+  LOGV(nStackedStates) LCV(state.number) LCV(state.token);
+  LOGV(auxStack.size());
+  while (nStackedStates--) {
+    LOGV(stateStack.top().number) LCV(stateStack.top().token) 
+      LCV((int) state.pointer);
+    auxStack.push(stateStack.pop());
+  }
+  LOGV(auxStack.size());
+  //reductionState.token = rule->prim_tkn;
+  reductionState.token = ruleDescriptor.prim_tkn;
+  state.number = reductionState.number;
+  LOGV(location());
+  LOGV(stateStack.size());
+  return 1;
+}
+
+int FtParser::shiftNonterminalAndAccept() {
+  LOGSECTION("FtParser::shiftNonTerminalAndAccept");
+  state.number = reductionState.number;
+  state.token = reductionState.token;
+  LOGV(state.number);
+  LOGV(state.token) LCV((int) state.pointer);
+  processState = finished;
+  return 0;
+}
+
+int (FtParser::*FtParser::nonterminalAction[4])() = {
+  &FtParser::shiftNonterminalAndAccept,
+  &FtParser::shiftNonterminal,
+  &FtParser::shiftNonterminalAndReduce,
+  &FtParser::shiftNonterminalAndReduce
+};
+
+void (FtParser::*FtParser::terminalAction[11])() = {
+  &FtParser::shiftTerminalAndAccept,
+  &FtParser::shiftTerminal,
+  &FtParser::shiftTerminalAndReduce,
+  &FtParser::shiftTerminalAndReduce,
+  &FtParser::reduce,
+  &FtParser::reduce,
+  &FtParser::accept,
+  &FtParser::error,
+  &FtParser::shiftNull,
+  &FtParser::skip,
+  &FtParser::skip
+};
+
+static int different(const unsigned char *s1, const unsigned char *s2, unsigned n) {
+  LOGSECTION("different");
+  LOGV(n);
+  //if (n > strlen((const char *)s2)) return 1;
+  if (case_sensitive) {
+    return strncmp((const char *)s1, (const char *) s2, n);
+  }
+  while (n--) {
+    if (agToUpper(*s1++) != agToUpper(*s2++)) {
+      return 1;
+    }
+  }
+  return 0;
+}
+
+
+Token FtParser::keyToken(void) {
+  LOGSECTION("FtParser::keyToken");
+  int matchLength = 0;
+  //int key = 0;
+  Keyword key;
+  int keyListNumber = map_state_number[state.number].key_list;
+  if (keyListNumber == 0) {
+    return Token();
+  }
+
+  int *keyList = dict_str(key_list_dict, keyListNumber);
+  int nKeys = *keyList++ - 1;
+  LOGV(lookAhead) LCV(nKeys);
+  while (nKeys--) {
+    Keyword keyNumber = map_token_number[*keyList++].key;
+    KeywordDescriptor &keyDescriptor(keyNumber);
+    //unsigned char *keyString = (unsigned char *)keyNumber->string.pointer();
+    unsigned char *keyString = (unsigned char *)keyDescriptor.string.pointer();
+    //AgString keyString = keyNumber->string;
+    int length = strlen((const char *) keyString);
+    //int length = keyString.size();
+    if (length <= matchLength) {
+      continue;
+    }
+    if ((lookAhead + length) > endPointer) {
+      continue;
+    }
+    if (different(keyString, lookAhead, length)) {
+      continue;
+    }
+    //if (different((unsigned char *)keyString.pointer(), lookAhead, length)) {
+    //  continue;
+    //}
+    //int charSetNumber = keyNumber->reserve;
+    int charSetNumber = keyDescriptor.reserve;
+    if (charSetNumber) {
+      int *reservedCharSet = dict_str(char_set_dict, charSetNumber);
+      int nReservedCharSet = *reservedCharSet++ - 1;
+      if (lookAhead + length < endPointer) {
+        unsigned char fc = state.pointer[length];
+        while (nReservedCharSet && fc != *reservedCharSet++) {
+	  nReservedCharSet--;
+	}
+        if (nReservedCharSet) {
+	  continue;
+	}
+      }
+    }
+    matchLength = length;
+    key = keyNumber;
+  }
+  LOGV((int) lookAhead) LCV(matchLength);
+  LOGV(key) LCV(testingKeyword);
+  if (key.isNotNull() && (int) key != testingKeyword) {
+    lookAhead = state.pointer + matchLength;
+    LOGV(key->token_number);
+    return key->token_number;
+  }
+  return Token();
+}
+
+
+void FtParser::getToken() {
+  LOGSECTION("FtParser::getToken");
+  LOGV(stateStack.size());
+  LOGV(state.number) LCV((int) state.pointer);
+  LOGV((int) lookAhead);
+  LOGV((int) endPointer);
+  LOGV(inputToken);
+  if (inputToken) {
+    state.token = inputToken;
+  }
+  else if (lookAhead != 0 && lookAhead >= endPointer) {
+    if (text.exists() && eof_token) {
+      token_number_map &eofTokenMap = map_token_number[eof_token];
+      //if (map_token_number[eof_token].non_terminal_flag) {
+      if (eofTokenMap.non_terminal_flag) {
+        //unsigned charSet = map_token_number[eof_token].token_set_id;
+        unsigned charSet = eofTokenMap.token_set_id;
+        unsigned *list = (unsigned *) dict_str(char_set_dict,charSet);
+        int character = list[1];
+        LOGV(charSet);
+        LOGV(character);
+        state.token = map_char_number[character].token_number;
+      }
+      else {
+	state.token = eof_token;
+      }
+      LOGV(state.token) LCV((int) state.pointer);
+    }
+    else {
+      processState = unexpectedEndOfFile;
+      state.token = 0;
+    }
+  }
+  else if (lookAhead != 0) {
+    state.token = keyToken();
+    LOGV(state.token) LCV((int) state.pointer);
+    if (state.token == 0) {
+      state.token = 
+	map_char_number[*lookAhead++ - min_char_number].token_number;
+    }
+  }
+  LOGV(state.token) LCV((int) state.pointer);
+  LOGV(auxStack.size());
+}
+
+/*
+unsigned FtParser::inspectToken() {
+  LOGSECTION("FtParser::inspectToken");
+  LOGV((int) lookAhead);
+  LOGV((int) endPointer);
+  unsigned token = 0;
+  if (inputToken) {
+    token = inputToken;
+  }
+  else if (lookAhead !=0 && lookAhead >= endPointer) {
+    if (text.exists() && eof_token) {
+      if (map_token_number[eof_token].non_terminal_flag) {
+        unsigned charSet = map_token_number[eof_token].token_set_id;
+        unsigned *list = (unsigned *) dict_str(char_set_dict,charSet);
+        int character = list[1];
+        LOGV(charSet);
+        LOGV(character);
+        token = map_char_number[character].token_number;
+      }
+      else {
+        token = eof_token;
+      }
+      LOGV(token);
+    }
+    else {
+      token = 0;
+    }
+  }
+  else if (lookAhead != 0) {
+    const unsigned char *save = lookAhead;
+    token = keyToken();
+    lookAhead = save;
+    LOGV(token);
+    if (token == 0) {
+      token = map_char_number[*lookAhead - min_char_number].token_number;
+    }
+  }
+  LOGV(token);
+  LOGV(auxStack.size());
+  return token;
+}
+*/
+
+void FtParser::dispatchReductionToken() {
+  LOGSECTION("FtParser::dispatchReductionToken");
+  unsigned k;
+  state_number_map *sp;
+
+  do {
+    LOGV(reductionState.number);
+    LOGV(reductionState.token);
+    sp = &map_state_number[reductionState.number];
+    unsigned *tokenPointer = lstptr(*sp,t_actions);
+    for (k = sp->n_actions; k && tokenPointer[--k] != reductionState.token;) {
+      /* nothing */
+    }
+    LOGV(k) LCV(tokenPointer[k]);
+    assert(tokenPointer[k] == reductionState.token);
+    actionParameter = lstptr(*sp,p_actions)[k];
+    LOGV(k) LCV(actionParameter);
+    if (k == 0) {
+      shiftNonterminal();
+      processState = selectionError;
+      stackChanged(stateStack.size()+1);
+      return;
+    }
+  } while ((this->*(nonterminalAction[lstptr(*sp,a_actions)[k]]))());
+  stackChanged(stateStack.size()+1);
+}
+
+void FtParser::completeReduction(int token) {
+  LOGSECTION("FtParser::completeReduction(int)");
+  int k = stateStack.size() - reductionIndex;
+  assert((unsigned) k <= (unsigned) stateStack.size());
+  LOGV(k);
+  stateStack.discardData(k);
+  reductionState.token = token;
+  LOGV(token);
+  processState = running;
+  dispatchReductionToken();
+  if (processState == running &&
+      state.pointer == lookAhead &&
+      state.token == 0) {
+    getToken();
+  }
+  nNullShifts = 0;
+  auxStack.discardData();
+  transStack.discardData();
+  LOGV(auxStack.size());
+}
+
+void FtParser::completeReduction() {
+  LOGSECTION("FtParser::completeReduction()");
+  int token = ibnfs[ibnfb[ruleToReduce]+reductionSelection];
+  completeReduction(token);
+}
+
+void FtParser::parseAction() {
+  LOGSECTION("FtParser::parseAction");
+  state_number_map *sp = &map_state_number[state.number];
+  unsigned *tokenPointer = lstptr(*sp, t_actions);
+
+  if (processState < running) {
+    processState = running;
+  }
+  int k = 0;
+  while (tokenPointer[k] != (unsigned) state.token && tokenPointer[k]) {
+    k++;
+  }
+
+  actionParameter = lstptr(*sp, p_actions)[k];
+  ((*this).*( terminalAction[lstptr(*sp, a_actions)[k]] ))();
+
+  if (processState <= running && state.token == 0) {
+    getToken();
+  }
+  stackChanged(stateStack.size()+1);
+}
+
+void FtParser::stepToken(unsigned token) {
+  LOGSECTION("FtParser::stepToken");
+  LOGV(state.number);
+  LOGV(state.token) LCV((int) state.pointer);
+  lookAhead = state.pointer = 0;
+  inputToken = token;
+  processState = running;
+
+  if (map_token_number[token].non_terminal_flag) {
+    reductionState = state;
+    reductionState.token = token;
+    state.token = inputToken = 0;
+    dispatchReductionToken();
+    transStack.discardData();
+    auxStack.discardData();
+    if (processState <= running && state.token == 0) {
+      getToken();
+    }
+    stackChanged(stateStack.size());
+    return;
+  }
+  inputToken = token;
+  state_number_map *sp = &map_state_number[state.number];
+  unsigned *tokenPointer = lstptr(*sp, t_actions);
+  state.token = token;
+
+  int k = 0;
+  while(tokenPointer[k] != (unsigned) state.token && tokenPointer[k]) {
+    k++;
+  }
+
+  actionParameter = lstptr(*sp, p_actions)[k];
+  ((*this).*( terminalAction[lstptr(*sp, a_actions)[k]] ))();
+  LOGV(processState) LCV(state.token);
+  if (processState <= running && state.token == 0) {
+    getToken();
+  }
+  stackChanged(stateStack.size()+1);
+}
+
+void FtParser::parseToken(unsigned token) {
+  LOGSECTION("FtParser::parseToken");
+  LOGV(state.number) LCV(token);
+  LOGV(state.token) LCV((int) state.pointer);
+  lookAhead = state.pointer = 0;
+  inputToken = token;
+  processState = token ? running : syntaxError;
+  if (processState == syntaxError) {
+    return;
+  }
+
+  if (map_token_number[token].non_terminal_flag) {
+    reductionState = state;
+    reductionState.token = token;
+    state.token = inputToken = 0;
+    dispatchReductionToken();
+    if (processState <= running && state.token == 0) {
+      getToken();
+    }
+    return;
+  }
+  inputToken = state.token = token;
+
+  while (processState <= running && inputToken != 0) {
+    state_number_map *sp = &map_state_number[state.number];
+    unsigned *tokenPointer = lstptr(*sp, t_actions);
+    int k = 0;
+    while(tokenPointer[k] != (unsigned) state.token && tokenPointer[k]) {
+      k++;
+    }
+    LOGV(k) LCV(sp->n_actions);
+    assert((unsigned) k < sp->n_actions);
+    actionParameter = lstptr(*sp, p_actions)[k];
+    ((*this).*( terminalAction[lstptr(*sp, a_actions)[k]] ))();
+    LOGV(processState) LCV(state.token);
+    if (processState <= running && inputToken != 0) {
+      state.token = inputToken;
+    }
+  }
+  if (processState <= running && state.token == 0) {
+    getToken();
+  }
+  stackChanged(stateStack.size()+1);
+}
+
+
+
+int FtParser::validToken(unsigned token, unsigned sn) {
+  LOGSECTION("FtParser::validToken");
+  state_number_map *sp = &map_state_number[sn];
+  unsigned *tokenPointer = lstptr(*sp, t_actions);
+
+  int k = 0;
+  while (tokenPointer[k] && tokenPointer[k] != token && tokenPointer[k]) {
+    k++;
+  }
+  if (k == 0 && lstptr(*sp, a_actions)[k] == pe_syn_error) {
+    return 0;
+  }
+  LOGV(sn);
+  LOGV(token);
+  LOGV(k);
+  LOGV(tokenPointer[k]);
+  return 1;
+}
+
+int FtParser::validSelection(unsigned selection, unsigned sn) {
+  LOGSECTION("FtParser::validSelection");
+  state_number_map *sp = &map_state_number[sn];
+  unsigned *tokenPointer = lstptr(*sp, t_actions);
+
+  unsigned token = ibnfs[ibnfb[ruleToReduce] + selection];
+
+  int k;
+  for (k = sp->n_actions; k && tokenPointer[--k] != token; ) {
+    LOGV(k);
+    LOGV(tokenPointer[k]);
+  }
+  LOGV(sn);
+  LOGV(token);
+  LOGV(k);
+  LOGV(tokenPointer[k]);
+  return k != 0;
+}
+
+FtParser &FtParser::parseTo(unsigned char *target) {
+  LOGSECTION("FtParser::parseTo");
+  int backup = 0;
+  while (stateStack.size() && state.pointer <= target) {
+    stateStack.pop(state);
+    backup = 1;
+  }
+  if (backup) {
+    processState = running;
+    lookAhead = state.pointer;
+    auxStack.discardData();
+    transStack.discardData();
+    LOGV(auxStack.size());
+    nNullShifts = 0;
+    getToken();
+  }
+  else if (processState == finished) {
+    reset();
+  }
+  if (processState < running) {
+    processState = running;
+  }
+  LOGV(state.token) LCV((int) state.pointer);
+  while (processState <= running && state.pointer < target) {
+    parseAction();
+  }
+  //if ((dc *)displayControl) {
+  //  displayControl->des->d_size.y = stateStack.size()+1;
+  //}
+  stackChanged(stateStack.size()+1);
+  return *this;
+}
+
+FtParser &FtParser::parse() {
+  if (processState < running) {
+    processState = running;
+  }
+  while (processState <= running) {
+    parseAction();
+  }
+  //if ((dc *)displayControl) {
+  //  displayControl->des->d_size.y = stateStack.size()+1;
+  //}
+  stackChanged(stateStack.size()+1);
+  return *this;
+}
+
+FtParser &FtParser::parse(const char *fragment) {
+  LOGSECTION("FtParser::parse(const char *)");
+  LOGV(fragment);
+  lookAhead = state.pointer = (const unsigned char *) fragment;
+  inputToken = 0;
+  endPointer = (const unsigned char *) fragment + strlen(fragment);
+  getToken();
+  LOGV(processState) LCV(inputToken);
+
+  while (processState <= running) {
+    parseAction();
+    LOGV(state.pointer);
+  }
+  //if ((dc *)displayControl) {
+  //  displayControl->des->d_size.y = stateStack.size()+1;
+  //}
+  stackChanged(stateStack.size()+1);
+  if (processState == unexpectedEndOfFile) {
+    processState = ready;
+  }
+  return *this;
+}
+
+FtParser &FtParser::prime(const char *fragment) {
+  LOGSECTION("FtParser::parse(const char *)");
+  LOGV(fragment);
+  lookAhead = state.pointer = (const unsigned char *) fragment;
+  endPointer = (const unsigned char *) fragment + strlen(fragment);
+  getToken();
+  LOGV(processState);
+  stackChanged(stateStack.size()+1);
+  return *this;
+}
+
+FtParser &FtParser::parseTo(cint *loc) {
+  LOGSECTION("FtParser::parseTo");
+  LOGV(*loc);
+  LOGV(stateStack.size());
+  LOGV(location());
+  int backup = 0;
+  LOGV(processState);
+  while (stateStack.size()
+	 && (loc->y < state.line
+	     || (loc->y == state.line && loc->x <= state.charPos))) {
+    stateStack.pop(state);
+    backup = 1;
+  }
+  LOGV(*loc) LCV(location());
+  LOGV(precedes(*loc, location()));
+  if (backup) {
+    processState = running;
+    lookAhead = state.pointer;
+    getToken();
+  }
+  else if (precedes(*loc, location())) {
+    reset();
+  }
+  LOGV(backup);
+  LOGV(processState);
+  LOGV(stateStack.size());
+  LOGV(state.number) LCV((int) state.pointer);
+  LOGV(location());
+  if (processState < running) {
+    processState = running;
+  }
+  while (processState == running &&
+         (state.line < loc->y || (state.line == loc->y &&
+				  state.charPos < loc->x))) {
+    parseAction();
+  }
+  LOGV(location());
+  //if ((dc *)displayControl) {
+  //  displayControl->des->d_size.y = stateStack.size()+1;
+  //}
+  stackChanged(stateStack.size()+1);
+  return *this;
+}
+
+FtParser &FtParser::step() {
+  LOGSECTION("FtParser::step");
+  LOGV(location());
+  if (processState < running) {
+    processState = running;
+  }
+  if (processState == running) {
+    parseAction();
+  }
+  //if ((dc *)displayControl) {
+  //  displayControl->des->d_size.y = stateStack.size()+1;
+  //}
+  stackChanged(stateStack.size()+1);
+  return *this;
+}
+
+FtParser &FtParser::step(char *fragment) {
+  LOGSECTION("FtParser::step(const char *)");
+  LOGV(fragment);
+  lookAhead = state.pointer = (unsigned char *) fragment;
+  endPointer = (unsigned char *) fragment + strlen(fragment);
+  getToken();
+  LOGV(processState);
+  if (processState <= running) {
+    parseAction();
+  }
+  //if ((dc *)displayControl) {
+  //  displayControl->des->d_size.y = stateStack.size()+1;
+  //}
+  stackChanged(stateStack.size()+1);
+  if (processState <= running && state.token == 0) {
+    getToken();
+  }
+  if (processState == unexpectedEndOfFile) {
+    processState = ready;
+  }
+  return *this;
+}
+
+const char *FtParser::processStateText[] = {
+  "Ready",
+  "Ready",                                   //running,
+  "Parse complete",                          //finished,
+  "Syntax error",           //syntaxError,
+  "Unexpected end of file", //unexpectedEndOfFile,
+  "Select reduction token",  //selectionRequired
+  "Selection error"
+};
+
+#if 0 /* unused */
+tsd *x1x_new(pcb_type *pcb) {
+  int sx, sn, tn, /*fn,*/ fx;
+  int *items;
+  int nitems;
+  tsd *isl = init_tsd(4);
+
+  ok_ptr(pcb);
+  sn = PCB.s.sn;
+  tn = PCB.token_number;
+  if (PCB.exit_flag) {
+    tn = 0;
+  }
+  sx = PCB.ssx;
+  if (PCB.reduction_token) {
+    sx -= PCB.rule_length;
+  }
+
+  {
+    tuple_dict *d;
+    d = xis(sn);
+    items = d->text;
+    nitems = d->nsx;
+    items += 2*nitems;
+    while (nitems--) {
+      fx = *--items;
+      Rule rule = *--items;
+      if (tn == 0 ||
+          fx >= rule->non_vanishing_length ||
+          rule.token(fx).isExpansionToken(tn)) {
+	//x2(Rule(fn)->token(fx), tn))
+	//x2(lstptr(map_form_number[fn],tokens)[fx], tn))
+        at(isl,sx,sn,(int) rule,fx);
+      }
+    }
+    delete_tuple_dict(d);
+  }
+
+  while (sx-- > 0) {
+    tuple_dict *d;
+    tn = map_state_number[sn].char_token;
+    sn = PCB.ss[sx].sn;
+    d = xis(sn);
+    items = d->text;
+    nitems = d->nsx;
+    items += 2*nitems;
+    while (nitems--) {
+      fx = *--items;
+      Rule rule = *--items;
+      if (fx >= rule->length()) {
+	continue;
+      }
+      if (x3(isl, sx, (int)rule, fx)) {
+	at(isl, sx, sn, (int) rule, fx);
+      }
+    }
+    delete_tuple_dict(d);
+  }
+  return isl;
+}
+#endif /* 0 - unused */
+
+tsd *FtParser::x1x_new() {
+  LOGSECTION("FtParser::x1x_new");
+  int sx, sn, fn, fx;
+  tsd *isl = init_tsd(4);
+
+  sn = state.number;
+  Token tn = state.token;
+  if (processState == selectionRequired) {
+    sn = reductionState.number;
+    tn = reductionState.token;
+  }
+  else if (processState == syntaxError) {
+    tn = 0;
+  }
+  tuple_dict *d = xis(sn);
+  int *items = d->text;
+  int nitems = d->nsx;
+  items += 2*nitems;
+  LOGV(state.number);
+  LOGV(state.token);
+  LOGV(stateStack.size());
+  LOGV(processState);
+  LOGV(ntkns);
+  sx = stateStack.size();
+  if (processState == selectionRequired) {
+    int rx = Rule(ruleToReduce)->length();
+    int n = stateStack.size();
+    for (sx = reductionIndex; rx >= 0; rx--) {
+      int index = sx + rx;
+      if (index > n) {
+	continue;
+      }
+      if (index < n) {
+	sn = stateStack[index].number;
+      }
+      at(isl, index, sn, ruleToReduce, rx);
+    }
+    tuple_dict *d = xis(reductionState.number);
+    int *items = d->text;
+    int nitems = d->nsx;
+    items += 2*nitems;
+    while (nitems--) {
+      fx = *--items;
+      fn = *--items;
+      LOGV(fn);
+      LOGV(fx);
+      if ((unsigned) fx >= Rule(fn)->length()) {
+	continue;
+      }
+      if (x3a(isl, sx, fn, fx)) {
+	at(isl, sx, sn, fn, fx);
+      }
+    }
+  }
+  else {
+    state_number_map *sp = &map_state_number[sn];
+    unsigned *tokenPointer = lstptr(*sp, t_actions);
+
+    unsigned k = 0;
+    while (tokenPointer[k] && 
+	   tokenPointer[k] != (unsigned) tn && tokenPointer[k]) {
+      k++;
+    }
+    if (k == 0 && lstptr(*sp, a_actions)[k] == pe_syn_error) {
+      tn = 0;
+    }
+    LOGV(k);
+    LOGV(tn);
+    LOGV(nitems);
+    if (tn.isNotNull()) {
+      while (nitems--) {
+        fx = *--items;
+        fn = *--items;
+        LOGV(fn);
+        LOGV(fx);
+        //if (x4(tn, fn)) {
+        if (tn.isExpansionRule(fn)) {
+          at(isl, sx, sn, fn, fx);
+          continue;
+        }
+        Rule rule = fn;
+        if ((unsigned) fx >= rule->length()) {
+	  continue;
+	}
+        //if (lstptr(map_form_number[fn],tokens)[fx] == tn) {
+	//  at(isl, sx, sn, fn, fx);
+	//}
+        if (rule.token(fx) == tn) {
+	  at(isl, sx, sn, (int) rule, fx);
+	}
+      }
+      LOGV(isl->nt);
+      for (k = 0; k < sp->n_completed_forms; k++) {
+        unsigned rule = lstptr(*sp,completed_forms)[k];
+        LOGV(rule);
+        at(isl, sx, sn, rule, Rule(rule)->length());
+      }
+      LOGV(isl->nt);
+      if (isl->nt) {
+        items = d->text;
+        nitems = d->nsx;
+        items += 2*nitems;
+        while (nitems--) {
+          fx = *--items;
+          fn = *--items;
+          LOGV(fn);
+          LOGV(fx);
+          if ((unsigned) fx >= Rule(fn)->length()) {
+	    continue;
+	  }
+          if (x3a(isl, sx, fn, fx)) {
+	    at(isl, sx, sn, fn, fx);
+	  }
+        }
+      }
+      else {
+        items = d->text;
+        nitems = d->nsx;
+        items += 2*nitems;
+        while (nitems--) {
+          fx = *--items;
+          fn = *--items;
+          LOGV(fn);
+          LOGV(fx);
+          at(isl, sx, sn, fn, fx);
+        }
+      }
+    }
+    else while (nitems--) {
+      fx = *--items;
+      fn = *--items;
+      LOGV(fn);
+      LOGV(fx);
+      at(isl, sx, sn, fn, fx);
+    }
+  }
+  LOGV(isl->nt);
+  LOGV((int) d);
+  delete_tuple_dict(d);
+  LOGV(sx);
+  while (sx-- > 0) {
+    tuple_dict *d;
+    tn = stateStack[sx].token;
+    sn = stateStack[sx].number;
+    LOGV(sn);
+    LOGV(tn);
+    d = xis(sn);
+    items = d->text;
+    nitems = d->nsx;
+    items += 2*nitems;
+    while (nitems--) {
+      fx = *--items;
+      fn = *--items;
+      LOGV(fn);
+      LOGV(fx);
+
+      if ((unsigned) fx >= Rule(fn)->length()) {
+	continue;
+      }
+      if (x3(isl, sx, fn, fx)) {
+	at(isl, sx, sn, fn, fx);
+      }
+    }
+    delete_tuple_dict(d);
+  }
+  LOGV(isl->nt);
+  return isl;
+}
+