// FILE. . . . . /home/hak/hlt/src/hlt/osf/v0/sources/OsfV0Ancillary.grm
// EDIT BY . . . Hassan Ait-Kaci
// ON MACHINE. . Hp-Dv7
// STARTED ON. . Fri Nov 02 23:01:30 2012

/**
 * This file defines ancillary code (global variables and methods) for
 * the <a href="OsfV0.html">OSF V0</a> language. It is part of its Jacc
 * grammar specification and is included by the main grammar file <a
 * href="OsfV0Grammar.html">OsgV0Grammar.grm</a> .
 *
 * @version     Last modified on Mon Jan 21 10:07:44 2013 by hak
 * @author      <a href="mailto:hak@acm.org">Hassan A&iuml;t-Kaci</a>
 * @copyright   &copy; <a href="http://www.hassan-ait-kaci.net/">by the author</a>
 */

/* ************************************************************************ */
/* **************************** ANCILLARY CODE **************************** */
/* ************************************************************************ */

%{

/* ************************************************************************ */
/* *************************** GLOBAL VARIABLES *************************** */
/* ************************************************************************ */

/* ************************************************************************ */

/**
 * This is OSF execution context.
 */
Context context = new Context();

/* ************************************************************************ */

/* ************************************************************************ */
/* ************************** TAXONOMY MANAGEMENT ************************* */
/* ************************************************************************ */

/* ************************************************************************ */

/**
 * This is where the "is-a" declarations are stored.
 */
ArrayList isaDeclarations = new ArrayList(50);

/* ************************************************************************ */


void declareIsa (String s1, String s2) throws LockedCodeArrayException
{
  context.declareIsa(s1,s2,location);
}

/* ************************************************************************ */

void processIsaDeclaration (ArrayList lhs, ArrayList rhs)
{
  int lsize = lhs.size();
  int rsize = rhs.size();

  for (int i=0; i<lsize; i++)
    for (int j=0; j<rsize; j++)
      declareIsa((String)lhs.get(i),(String)rhs.get(j));
}

/* ************************************************************************ */

/* ************************************************************************ */
/* ************************* EXPRESSION PROCESSING ************************ */
/* ************************************************************************ */

/* ************************************************************************ */

/**
 * This builds an uninterpreted &psi;-term structure out of the
 * syntactic parts given as arguments as explained in the <a
 * href="#pstconstruc">specification</a>, then interprets its sort
 * expressions in the current context and prints out its interpreted
 * normalized form.
 */
void processPsiTerm (String tag, SortExpression sort, Stack keys, Stack subterms)
{
  PsiTerm pst = buildPsiTerm(new HashSet(),Tag.getTag(tag),sort,keys,subterms);
  try
    {
      displayLine(pst.displayForm());
    }
  catch (RuntimeException e)
    {
      logError(new Error().setMsg(e.getMessage()));
    }
}

/**
 * Using the given hash set of tags already associated to previously
 * constructed &psi;-terms, this builds an uninterpreted &psi;-term
 * structure out of the syntactic parts given as arguments as explained
 * in the <a href="#pstconstruc">specification</a>.
 */
PsiTerm buildPsiTerm (HashSet tags, Tag tag, SortExpression sort, Stack keys, Stack subterms)
{
  tag = tag.deref();	// dereference the tag to get to the correct one if needed
  
  PsiTerm pst = null;	// this is the new psiterm to build and return

  // if the tag is a reoccurring tag
  if (tags.contains(tag))	
    {
      // build this term with a new anonymous tag:
      pst = buildPsiTerm(tags,
			 Tag.getTag(null),
			 sort,
			 keys,
			 subterms);
      // // update the tag to its reference (due to possible mergings building pst)
      // tag = tag.deref();
      // retrieve the tag's term, marking the tag as shared (due to the reoccurrence):
      PsiTerm previous = tag.markAsShared().term();
      // merge the two terms and return:
      previous.merge(pst);
      return previous;
    }

  // the tag has not occurred before
  pst = new PsiTerm(tag).setSort(sort);	// construct a new psiterm with the given tag and sort
  tags.add(tag);			// and add the tag to the tag occurrences

  // if there are any subterms
  if (subterms != null) // then keys != null as well
    while (!subterms.empty())
      {
	// get the current raw subterm to build:
	RawPsiTerm sub = (RawPsiTerm)subterms.pop();
	// build the current subterm
	PsiTerm subterm = buildPsiTerm(tags,
				       Tag.getTag(sub.tag),
				       sub.sort,
				       sub.keys,
				       sub.subterms);

	// get the current subterm's key
	Object key = keys.pop();

	// the possibly existing subterm for this key
	PsiTerm existingSubterm = null;

	if (key == null)
	  // this is an implicitly contiguous position
	  {
	    // retrieve the dereferenced possibly existing subterm:
	    existingSubterm = pst.getNextContiguousPositionSubterm();
	    if (existingSubterm == null)
	      pst.addContiguousPositionSubterm(subterm);
	    else
	      subterm.merge(existingSubterm.deref());

	    continue;
	  }

	if (key instanceof Integer)
	  // this is an explicitly specified position
	  {
	    int position = ((Integer)key).intValue();
	    existingSubterm = pst.getSubterm(position);
	    if (existingSubterm == null)
	      pst.setSubterm(position,subterm);
	    else
	      subterm.merge(existingSubterm.deref());

	    continue;
	  }

	// this is a feature subterm
	Feature feature = Feature.getFeature((String)key);

	existingSubterm = pst.getSubterm(feature);
	if (existingSubterm == null)
	  pst.setSubterm(feature,subterm);
	else
	  subterm.merge(existingSubterm.deref());
      }
  
  return pst;    
}

/**
 * This processes a sort expression in the context of an encoded sort
 * taxonomy. Given the current sort context, it compiles it, evaluates
 * it, and prints out the resulting maximal (possibly disjunctive) sort
 * matching the resulting sort code.  If in timing mode, it also reports
 * the processing time in milliseconds.
 */
void processSortExpression (SortExpression expression)
{
  try
    {
      time = System.currentTimeMillis();
      displayLine("*** " +
		  (Context.isTracing()
		   ? (expression.displayForm() +
		      // " => "+expression.value().toBitString() +
		      " >= ")
		   : "") +
		  expression.maxLowerBound());
      time = System.currentTimeMillis() - time;
      if (isTiming)
	displayLine("*** Processing time = "+time+" ms");
    }
  catch (RuntimeException e)
    {
      logError(new Error().setMsg(e.getMessage()));
    }
}

/* ************************************************************************ */
/* **************************** PRAGMA PROCESSING ************************* */
/* ************************************************************************ */

static boolean isTiming, isMute, showTree;

static long time;

// etc...

// public final void initialize ()
// {
//   Pragmas.AUTOMATIC = false;
//   // etc ...
// }

/* ************************************************************************ */

/**
 * This calls the method in charge of dispatching which action to take
 * depending of the pragma.  If in timing mode, also reports the
 * processing time in milliseconds.
 */
final void processPragma (String pragma, ArrayList args)
{
  time = System.currentTimeMillis();
  executePragma(pragma,args);
  time = System.currentTimeMillis() - time;
  if (isTiming)
    displayLine("*** Processing time = "+time+" ms");
}

/**
 * This is the method in charge of dispatching which action to execute
 * for which pragma.
 */
final void executePragma (String pragma, ArrayList args)
{
  setLocation();

  if (pragma == "exit")
    OsfV0Main.exit();

  if (pragma == "include")
    { // This has a bug in that an extra dot at the console is needed to
      // get the prompt.  The origin of this comes from IncludeReader
      // that swallows the IO.EOI at the end of the file being included
      // and as a result the tokeniser's promptIsNeeded returns
      // false. There is no easy way to fix that besides a deep and
      // careful analysis of how the read() method in IncludeReader and
      // the nextToken() nextChar() methods in (Abstract)StreamTokenizer
      // work. For now, keep it as it is. Note that '%include
      // "foo.osf". %encode.' on the same line works. But the supoosedly
      // equivalent pragma '%load "foo.osf.' as defined below gives an
      // even weirder bug!
      includeFiles((Stack)args);
      return;
    }

  if (pragma == "encode")
    {
      encodeSorts();
      return;
    }	

  if (pragma == "load")
    { // This gives a strange bug !!!
      includeFiles((Stack)args);
      encodeSorts();
      return;
    }	

  if (pragma == "size")
    {
      displaySize();
      return;
    }	

  if (pragma == "sorts")
    {
      displaySorts();
      return;
    }	

  if (pragma == "last")
    {
      displayLastExpression();
      return;
    }	

  // if (pragma == "height")
  //   {
  //     computeHeight(arg1);
  //     return;
  //   }	

  if (pragma == "cleartags")
    {
      Tag.clearKnownTags();
      displayLine("*** Cleared all known tags");
      return;
    }	

  if (pragma == "clear")
    {
      Tag.clearKnownTags();
      context.reset();
      displayLine("*** The sort taxonomy has been cleared ("+
		  (context.taxonomy().size())+" sorts defined)");
      return;
    }	

  if (pragma == "parents")
    {
      displayParents((SortExpression)args.get(0));
      return;
    }

  if (pragma == "children")
    {
      displayChildren((SortExpression)args.get(0));
      return;
    }

  if (pragma == "descendants")
    {
      computeDescendants((SortExpression)args.get(0));
      return;
    }	

  if (pragma == "ancestors")
    {
      computeAncestors((SortExpression)args.get(0));
      return;
    }	

  if (pragma == "maximals")
    {
      try
      	{
  	  displayLine("*** "+displayForm(context.top().getChildren()));
      	}
      catch (RuntimeException e)
      	{
      	  logError(new Error().setMsg(e.getMessage()));
      	}
      return;
    }	

  if (pragma == "minimals")
    {
      try
      	{
  	  displayLine("*** Minimal sorts:");
  	  displayLine("*** "+displayForm(context.bottom().getParents()));
      	}
      catch (RuntimeException e)
      	{
      	  logError(new Error().setMsg(e.getMessage()));
      	}
      return;
    }	

  if (pragma == "evaluate")
    {
      PsiTerm.toggleSortEvaluation();
      if (!isMute)
	display("Sort expression evaluation has been turned "
	       +(PsiTerm.evaluateSorts() ? "on" : "off")+"...\n");
      return;
    }

  if (pragma == "mute")
    {
      isMute = !isMute;
      display("Muted output has been turned "+(isMute ? "on" : "off")+"...\n");
      if (isMute) displayLine("*** ...");
      return;
    }

  if (pragma == "tree")
    {
      parseTreeType = (showTree = !showTree) ? COMPACT_TREE : NO_TREE;
      display("Parse tree display has been turned "+(showTree ? "on" : "off")+"...\n");
      return;
    }

  if (pragma == "time")
    {
      isTiming = !isTiming;
      displayLine("*** Processing timing has been turned "+(isTiming ? "on" : "off")+"...");
      return;
    }

  if (pragma == "trace")
    {
      if (isMute)
	{
	  display("Cannot trace evaluation in mute mode; turn mute mode off with '%mute.'");
	  return;
	}
      
      Context.toggleTracing();
      display("Execution tracing has been turned "+(Context.isTracing() ? "on" : "off")+"...\n");
      return;
    }

  if (pragma == "gc")
    {
      display("\n");
      Misc.forceGC(!isMute,dm.getOutputStream());
      return;
    }

  if (pragma == "syntax")
    {
      toggleTrace();
      display("Parser trace has been turned "+(tracingIsOn() ? "on" : "off")+"...\n");
      return;
    }

  if (pragma == "help")
    {
      helpPragma();
      return;
    }

  displayLine("*** Unknown pragma: '%"+pragma+"' (ignored) - type '%help.' for known pragmas.");
}

/* ************************************************************************ */

/**
 * Given a sort expression, this will display its parents in the current
 * taxonomy. 
 */
final void displayParents (SortExpression exp)
{
  try
    {
      // if this is only a sort symbol, just display its parents:
      if (exp.isSymbol())
	{
	  displayParents(context.getSort(((SymbolSortExpression)exp).name()));
	  return;
	}

      // otherwise, evaluate the expression:
      BitCode value = exp.value();

      // check the code cache in case this value is a defined sort symbol:
      Object sort = context.codeCache().get(value);

      // if so, just display its parents:
      if (sort instanceof Sort)
	{
	  displayParents((Sort)sort);
	  return;
	}

      // if not, compute its MUBs and display them:
      displayLine("*** "+displayForm(context.taxonomy().minUpperBounds(value)));

    }
  catch (RuntimeException e)
    {
      logError(new Error().setMsg(e.getMessage()));
    }
}

final void displayParents (Sort sort)
{
  if (sort.isTop())
    displayLine("*** "+dfm.displayTopForm());
  else
    displayLine("*** "+displayForm(sort.getParents()));
}

/* ************************************************************************ */

/**
 * Given a sort expression, this will display its children in the current
 * taxonomy. 
 */
final void displayChildren (SortExpression exp)
{
  try
    {
      // if this is only a sort symbol, just display its children:
      if (exp.isSymbol())
	{
	  displayChildren(context.getSort(((SymbolSortExpression)exp).name()));
	  return;
	}

      // otherwise, evaluate the expression:
      BitCode value = exp.value();

      // check the code cache in case this value is a defined sort symbol:
      Object sort = context.codeCache().get(value);

      // if so, just display its children:
      if (sort instanceof Sort)
	{
	  displayChildren((Sort)sort);
	  return;
	}

      // if not, compute its MLBs and display them:
      displayLine("*** "+displayForm(context.taxonomy().maxLowerBounds(value)));

    }
  catch (RuntimeException e)
    {
      logError(new Error().setMsg(e.getMessage()));
    }
}

final void displayChildren (Sort sort)
{
  if (sort.isBottom())
    displayLine("*** "+dfm.displayBottomForm());
  else
    displayLine("*** "+displayForm(sort.getChildren()));
}

/* ************************************************************************ */

/**
 * This loads the specified file names in the specified list. Each file
 * name should contain OSF V0 declarations or expressions.
 */
final void includeFiles (Stack files)
{
  if (files == null || files.isEmpty())
    {
      logError(syntaxError("missing file arguments in $include pragma",location));
      return;
    }

  while (!files.isEmpty())
    {
      String fileName = (String)files.pop();
      // displayLine("*** Including file: "+fileName);

      try
	{
	  ((OsfV0Tokenizer)input).include(fileName);
	}
      catch (FileNotFoundException e)
	{
	  logError(syntaxError("file not found: "+fileName,location));
	}
      catch (CircularInclusionException e)
	{
	  logError(syntaxError("circular file inclusion of file: "+fileName,location));
	}

      displayLine("*** Included file: "+fileName);
    }
}

/* ************************************************************************ */

void displayLastExpression ()
{
  try
    {
      SortExpression expression = context.lastExpression();
      displayLine("*** "+expression.displayForm()+"  ==>  "+expression.maxLowerBound());      
    }
  catch (RuntimeException e)
    {
      logError(new Error().setMsg(e.getMessage()));
    }
}

/* ************************************************************************ */

// void computeHeight (String sort)
// {
//   try
//     {
//       displayLine("*** The height of "+sort+" is "+context.getSort(sort).height());
//     }
//   catch (RuntimeException e)
//     {
//       logError(new Error().setMsg(e.getMessage()));
//     }
// }

/* ************************************************************************ */

void computeDescendants (SortExpression exp)
{
  try
    {
      // if this is only a sort symbol, just display its descendants:
      if (exp.isSymbol())
	{
	  Sort sort = context.getSort(((SymbolSortExpression)exp).name());
	  displayLine("*** "+displayForm(sort.descendants()));
	  return;
	}

      // otherwise, evaluate the expression:
      BitCode value = exp.value();

      // check the code cache in case this value is a defined sort symbol:
      Object sort = context.codeCache().get(value);

      // if so, just display its descendants:
      if (sort instanceof Sort)
	{
	  displayLine("*** "+displayForm(((Sort)sort).descendants()));
	  return;
	}

      // otherwise, display the value code as the set of all its descendants:
      displayLine("*** "+displayForm(value));

    }
  catch (RuntimeException e)
    {
      logError(new Error().setMsg(e.getMessage()));
    }
}

/* ************************************************************************ */

void computeAncestors (SortExpression exp)
{
  try
    {
      // if this is only a sort symbol, just display its ancestors:
      if (exp.isSymbol())
	{
	  Sort sort = context.getSort(((SymbolSortExpression)exp).name());
	  displayLine("*** "+displayForm(sort.ancestors()));
	  return;
	}

      // otherwise, evaluate the expression:
      BitCode value = exp.value();

      // check the code cache in case this value is a defined sort symbol:
      Object sort = context.codeCache().get(value);

      // if so, just display its ancestors:
      if (sort instanceof Sort)
	{
	  displayLine("*** "+displayForm(((Sort)sort).ancestors()));
	  return;
	}

      // otherwise, compute and display the value code's ancestors -
      // except top, unless there are no other ancestors:
      BitCode ancestors = new BitCode();
      Taxonomy taxonomy = context.taxonomy();
      for (int i=taxonomy.size()-1; i-->0;)
	{
	  Sort s = (Sort)taxonomy.get(i);
	  if (s.code.isContainedIn(value))
	    break;	// no need to go further
	  if (value.isContainedIn(s.code))
	    ancestors.add(s.index);
	}
      if (ancestors.isEmpty())
	displayLine("*** "+dfm.displayTopForm());
      else
	displayLine("*** "+displayForm(ancestors));
    }
  catch (RuntimeException e)
    {
      logError(new Error().setMsg(e.getMessage()));
    }
}

/* ************************************************************************ */

/**
 * This encodes the sorts declared thus far and locks the sort taxonomy;
 * (<i>i.e.</i>, no new sorts may be declared until this taxononmy has
 * been cleared (see the '<tt>%clear</tt>' pragma).
 */
void encodeSorts ()
{
  try
    {
      context.encodeSorts();
      displayLine("*** The sort taxonomy has been encoded ("+
		  (context.taxonomy().size()-1)+" sorts defined)");
    }
  catch (CyclicSortOrderingException e)
    {
      logError(new Error().setSee("").setMsg(e.getMessage()));
      _criticalError = true;
    }
  catch (RuntimeException e)
    {
      logError(new Error().setMsg(e.getMessage()));
    }
}  

/* ************************************************************************ */

final void helpPragma ()
{
  displayLine("*** Known pragmas (all must be followed by a period - '.'):");
  displayLine("\t------------  ------");
  displayLine("\t      PRAGMA  EFFECT");
  displayLine("\t------------  ------");

  displayLine("\t       %exit  exit session");

  displayLine("\t    %include  read and process the given file (name specified as a quoted string)");
  displayLine("\t     %encode  encode the current sort taxonomy");

  displayLine("\t       %size  print the number of symbols in the current sort taxonomy");
  displayLine("\t      %sorts  display the codes of all symbols in current sort taxonomy");
  displayLine("\t    %defined  list all the non-built-in sorts symbols in the current taxonomy");
  displayLine("\t   %builtins  list all the sorts symbols in the current taxonomy");
  displayLine("\t      %clear  erase the codes of all symbols in current sort taxonomy");

  displayLine("\t   %evaluate  toggle on/off automatic sort evaluation");
  displayLine("\t  %automatic  toggle on/off automatic sort encoding");
  displayLine("\t       %mute  toggle on/off intermediate displays");

  displayLine("\t       %last  print the last evaluated sort expression and its maximal lower bound sort(s)");

  displayLine("\t     %height  print the height of the specified sort (size of longest is-a chain from it to {})");
  displayLine("\t      %width  print the size of the widest maximal antichain containing the specified sort");

  displayLine("\t   %children  print the set of maximal strict lower bounds of the specified sort");
  displayLine("\t%descendants  print the set of strict lower bounds of the specified sort");
  displayLine("\t    %parents  print the set of minimal strict upper bounds of the specified sort");
  displayLine("\t  %ancestors  print the set of strinct upper bounds of the specified sort");

  displayLine("\t        %isa  check whether the first specified sort is a subsort of the second one");

  displayLine("\t       %tree  toggle on/off graphical display of syntax tree");
  displayLine("\t     %timing  toggle on/off execution timing");
  displayLine("\t         %gc  force immediate garbage collection");
  displayLine("\t     %syntax  toggle on/off parser tracing");
  displayLine("\t      %trace  toggle on/off evaluation tracing");
  displayLine("\t       %help  list this information");
  newLine();
}

/* ************************************************************************ */
/* ************************** DISPLAY MANAGEMENT ************************** */
/* ************************************************************************ */

/**
 * The display manager.
 */
DisplayManager dm = context.displayManager();

/**
 * The display form manager.
 */
DisplayFormManager dfm = dm.displayFormManager();

/* ************************************************************************ */

/**
 * Redirect the output to the specified PrintStream.
 */
public final void setOutputStream (PrintStream stream)
{
  dm.setOutputStream(stream);
}

/* ************************************************************************ */

/**
 * Returns the display form of the given sort.
 */
String displayForm (Sort sort)
{
  return dfm.displaySortForm(sort);
}

/* ************************************************************************ */

/**
 * Returns the display form of set of sorts represented by the specified BitCode.
 */
String displayForm (BitCode sorts)
{
  return dfm.displaySortsForm(sorts,context.taxonomy());
}

/* ************************************************************************ */

/**
 * Displays the number of declared sorts on the display manager's output stream.
 */
void displaySize ()
{
  try
    {
      displayLine("*** There are "+context.taxonomy().size()+" sorts defined");
    }
  catch (RuntimeException e)
    {
      logError(new Error().setMsg(e.getMessage()));
    }
}

/* ************************************************************************ */

/**
 * Displays the declared sorts on the display manager's output stream.
 */
void displaySorts ()
{
  try
    {
      displayLine("*** Declared sorts:");
      context.taxonomy().showSortCodes();
      displayLine("*** "+(context.taxonomy().size()-1)+" sorts defined");
    }
  catch (RuntimeException e)
    {
      logError(new Error().setMsg(e.getMessage()));
    }
}

/* ************************************************************************ */

/**
 * If not in mute mode, displays the specified string on the display manager's
 * output stream.
 */
final void display (String s)
{
  if (isMute)
    return;

  dm.print(s);
}

/* ************************************************************************ */

/**
 * If not in mute mode, displays the specified string on the display manager's
 * output stream, and ends it with a newline.
 */
final void displayLine (String s)
{
  if (isMute)
    return;

  dm.println(s);
}

/* ************************************************************************ */

/**
 * Outputs a newline on the display manager's output stream.
 */
final void newLine ()
{
  dm.println();
}


/* ************************************************************************ */
/* *************************** ERROR MANAGEMENT *************************** */
/* ************************************************************************ */

/* ************************************************************************ */

/**
 * This parser's error log.
 */
ErrorLogger errorLogger = context.errorLogger();

/**
 * Records the specified Error in this parser's error log.
 */
final void logError (Error error)
{
  errorLogger.recordError(error);
}

/**
 * When this is true, a context reset is called for upon reporting errors.
 */
private boolean _criticalError = false;

/**
 * When at top level, displays all the errors recorded in the error log
 * and clears it.
 */
void reportErrors ()
{
  if (((OsfV0Tokenizer)input).reader.depth() > 0)
    return;

  int size = errorLogger.size();
  int errorNo = 0;
  int warningNo = 0;

  for (int i=0; i<size; i++)
    {
      Error error = errorLogger.getError(i);
      displayLine(error.toString());
      if (error.isWarning())
	warningNo++;
      else
	errorNo++;
    }

  if (warningNo > 0)
    displayLine("*** There "+(warningNo==1 ? "was " : "were ")+warningNo+" warning"+(warningNo>1 ? "s" : ""));
  if (errorNo > 0)
    displayLine ("*** There "+(errorNo==1 ? "was " : "were ")+errorNo+" error"+(errorNo>1 ? "s" : ""));

  if (_criticalError)
    {
      displayLine("*** Resetting context...");
      context.reset();
      _criticalError = false;
    }

  errorLogger.clearErrors();
}

/* ************************************************************************ */

/* ************************************************************************ */

/**
 * This is used for recording the location of syntactic constructs in the
 * input stream in order to locate where potential errors occur.
 */
Locatable location;

/* ************************************************************************ */

/**
 * Returns a syntax error object with specified message.
 */
final Error syntacticError (String msg)
{
  return new Error().setLabel("Syntax Error: ").setMsg(msg);
}

/* ************************************************************************ */

/**
 * Returns a syntax error object with specified message, and situated
 * as the specifed <tt>Locatable</tt> extent.
 */
final Error syntacticError (String msg, Locatable extent)
{
  return syntacticError(msg).setExtent(extent);
}

/* ************************************************************************ */

/**
 * Returns an evaluation error object with specified message.
 */
final Error evaluationError (String msg)
{
  return new Error().setLabel("Evaluation Error: ").setMsg(msg);
}

/* ************************************************************************ */

/**
 * Returns an evaluation error object with specified message,
 * and situated as the specifed <tt>Locatable</tt> extent.
 */
final Error evaluationError (String msg, Locatable extent)
{
  return evaluationError(msg).setExtent(extent);
}

/* ************************************************************************ */

// /**
//  * This method is used to situate an expression's abstract syntax with respect
//  * to its concrete syntax origin (specified as the given <tt>Locatable</tt>).
//  */
// final Expression locate (Expression e, Locatable l)
// {
//   return e.setExtent(l);
// }

// /**
//  * This method is used to situate an expression's abstract syntax with the
//  * extent of the latest <tt>location</tt>.
//  */
// final Expression locate (Expression e)
// {
//   return e.setExtent(location);
// }

// final Expression locateSymbol (ParseNode node)
// {
//   return locate(symbol(node.svalue()),node);
// }

/* ************************************************************************ */

/**
 * Prints out a prompt if needed for interactive input.
 */
final void prompt ()
{
  ((OsfV0Tokenizer)input).prompt();
}

/**
 * Reports errors if any and, if interactive, prompts the user for more
 * input.
 */
final void commitParse ()
{
  reportErrors();
  prompt();
}

/* ************************************************************************ */

/**
 * Sets the location to that of the specified <tt>Locatable</tt>.
 */
final void setLocation (Locatable locatable)
{
  location = locatable;
}

/* ************************************************************************ */

/**
 * Sets the location to that of the current parse node (<i>i.e.</i>, the node
 * currently at the top of the parse stack).
 */
final void setLocation ()
{
  setLocation(currentNode());
}

/* ************************************************************************ */

%}

/* ************************************************************************ */
/* ************************ END OF ANCILLARY CODE ************************* */
/* ************************************************************************ */
