// FILE. . . . . d:/hak/hlt/src/hlt/osf/hoot/sources/HootRules.grm
// EDIT BY . . . Hassan Ait-Kaci
// ON MACHINE. . Hak-Laptop
// STARTED ON. . Mon May  6 10:29:54 2019

/**
 * @version     Last modified on Fri Sep 13 16:26:24 2019 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>
 */

/* ************************************************************************ */
/* **************************** GRAMMAR RULES ***************************** */
/* ************************************************************************ */

%%

/**
 * <kbd>HootProgram</kbd> is the grammar's start symbol. It denotes a HOOT
 * program, which consists in an optional sequence of <kbd>Statement</kbd>
 * constructs.
 */
HootProgram
  : Statements_opt 
  ;

/**
 * A <kbd>Statements_opt</kbd> is a possibly empty sequence of
 * <kbd>Statement</kbd> constructs.
 */
Statements_opt
  : // Empty programs are ok. */
  | Statements_opt Statement
  ;

/**
 * A <kbd>Statement</kbd> consists of a <kbd>StatementType</kbd> followed by
 * an end of statement marker <kbd>EndOfStatement</kbd>.
 */
Statement
  : StatementType EndOfStatement
  ;

/**
 * <kbd>EndOfStatement</kbd> denotes the end of a statement. Upon
 * reading the end of statement marker <kbd>EOS</kbd>, the statement
 * just parsed is processed by HOOT and errors that may have occurred
 * are reported. In interactive mode, it also triggers a prompt for
 * additional statements. In case of syntax error, error recovery skips
 * all input from the error-causing token until the next
 * end-of-statement marker <kbd>EOS</kbd>.
 */
EndOfStatement
  : {
      commitParse();
    }
    EOS
  ;

/**
 * A <kbd>StatementType</kbd> is the main language unit; it is an element
 * of the sequence of statements that make up a HOOT program being
 * parsed.  It can be one of the following:
 *
 * <ul>
 *
 * <li><b>empty</b> - this has no effect: it is simply
 * skipped; </li>
 *
 * <p>
 *
 * <li><b>pragma</b> - an extra-language command among the several
 * provided for user-interaction convenience for inspecting the defined
 * grammar; </li>
 *
 * <p>
 *
 * <li><b>sort declaration</b> - used to declare sorts related in the
 * concept taxonomy; </li>
 *
 * <p>
 *
 * <li>HOOT <b>expression</b> - to evaluate and print the result;
 * </li>
 *
 * <p>
 *
 * <li><b>error</b> - last-resort rule to enable error recovery
 * <i>&agrave; la</i> yacc.  This is what makes <kbd>Statement</kbd> a
 * unit of parsing for HOOT: in case of syntax error, HOOT's parser
 * ignores everything past the last successfully parsed
 * <kbd>Statement</kbd> and up to the next end-of-statement marker. </li>
 *
 * </ul>
 */

StatementType
  : // Empty statements are ok. */
  | PragmaStatement 
  | SortDeclarationStatement
  | HootExpression
  | error
  ;

SortDeclarationStatement
  : IsaDeclarationStatement
    {
      setLocation();
      processIsaDeclaration($1.lhs,$1.rhs);
    }
  // | SortNameDeclarationStatement
  //   {
  //     setLocation();
  //     processtSortNameDeclaration($1.symbols);
  //   }
  ;

IsaDeclarationStatement
  : SortSymbols ISA SortSymbols
    {
      $$.lhs = $1.symbols;
      $$.rhs = $3.symbols;
    }
  ; 

// SortNameDeclarationStatement
//   : DECLARESORTS SortSymbols
//     {
//       $$.symbols = $2.symbols;
//     }      
//   ;

SortSymbol
  : IDENTIFIER
  ;

SortSymbols
  : SortSymbol
    {
      $$.symbols = new Stack();
      $$.symbols.push($1.svalue());
    }
  | SortSymbol ',' SortSymbols
    {
      ($$.symbols = $3.symbols).push($1.svalue());
    }
  ;

HootExpression
  :
  //   SortExpression
  //   {
  //     processSortExpression($1.expression);
  //   }
  // | 
    PsiTerm
    {
      processPsiTerm($1.tag,$1.sort,$1.keys,$1.subterms);
    }
  ;

PsiTerm
  : TAG
    {
      $$.tag = $1.svalue();
      $$.sort = new SymbolSortExpression("@",context);
    }
    // XML serialization:
    [ n:"hoot" l:"term" a:{tag=1/value} ]
  | UntaggedPsiTerm
    {
      $$.sort = $1.sort;
      $$.keys = $1.keys;
      $$.subterms = $1.subterms;
    }
  | TAG ':' UntaggedPsiTerm
    {
      $$.tag = $1.svalue();
      $$.sort = $3.sort;
      $$.keys = $3.keys;
      $$.subterms = $3.subterms;
    }
    // XML serialization:
    [ n:"hoot" l:"term" a:{tag=1/value} c:(3[0]) ]
  ;

UntaggedPsiTerm
  : SortExpression Body_opt
    {
      $$.sort = $1.expression;
      $$.keys = $2.keys;
      $$.subterms = $2.subterms;
    }
    // XML serialization:
    [ n:"hoot" l:"term" c:(1 2) ]
  ;

Body_opt
  : /* empty */
  | '(' SubTerms ')'
    {
      $$.keys = $2.keys;
      $$.subterms = $2.subterms;
    }
  ;

SubTerms
  : SubTerm
    {
      $$.keys = new Stack();
      $$.keys.push($1.key);
      $$.subterms = new Stack();
      $$.subterms.push($1.psiterm);
    }
  | SubTerm ',' SubTerms
    {
      ($$.keys = $3.keys).push($1.key);
      ($$.subterms = $3.subterms).push($1.psiterm);
    }
  ;

SubTerm
  : PsiTerm
    {
      $$.key = null;
      $$.psiterm = new RawPsiTerm($1.tag,$1.sort,$1.keys,$1.subterms);
    }
  | Feature ARROW PsiTerm
    {
      $$.key = $1.feature;
      $$.psiterm = new RawPsiTerm($3.tag,$3.sort,$3.keys,$3.subterms);
    }
    // XML serialization:
    [ n:"hoot" l:"feature" a:{name=1/value} c:(3) ]
  ;

Feature
  : INTEGER
    {
      $$.feature = Integer.valueOf((int)$1.nvalue());
    }
  | IDENTIFIER
    {
      $$.feature = $1.svalue();
    }
  ;

SortExpression
  : Constant
    {
      $$.expression = new ConstantSortExpression($1.constant);
    }
  | Sort
    {
      $$.expression = new SymbolSortExpression($1.svalue(),context);
    }
  | '{' SortList '}'
    {
      $$.expression = new DisjunctiveSort($2.sortList,context);
    }
    // XML serialization:
    [ n:"hoot" l:"disjunction" c:(2) ]
  | NOT SortExpression
    {
      $$.expression = new NotSortExpression($2.expression);
    }
    // XML serialization:
    [ n:"hoot" l:"not" c:(2) ]
  | SortExpression AND SortExpression
    {
      $$.expression = new AndSortExpression($1.expression,$3.expression);
    }
    // XML serialization:
    [ n:"hoot" l:"and" c:(1 3) ]
  | SortExpression OR SortExpression
    {
      $$.expression = new OrSortExpression($1.expression,$3.expression);
    }
    // XML serialization:
    [ n:"hoot" l:"or" c:(1 3) ]
  | SortExpression BUTNOT SortExpression
    {
      $$.expression = new ButnotSortExpression($1.expression,$3.expression);
    }
    // XML serialization:
    [ n:"hoot" l:"butnot" c:(1 3) ]
  | '(' SortExpression ')'
    {
      $$.expression = $2.expression.setParenthesized(true);
    }
    // XML serialization:
    [ n:"hoot" l:"parenthesis" c:(2) ]
  ;

Constant
  : INTEGER
    { $$.constant = new IntegerConstant((int)$1.nvalue()); }
  | CHAR // should check that there's exactly one character!
    { $$.constant = new CharConstant($1.svalue().charAt(0)); }
  | FLOAT
    { $$.constant = new FloatConstant($1.nvalue()); }
  | STRING
    { $$.constant = new StringConstant($1.svalue()); }
  | BOOLEAN
    { $$.constant = new BooleanConstant($1.svalue() == "true" ? true : false); }
  // | 'null'
  //   { $$.constant = Constant.NULL(); }
  ;

Sort
  : TOP
  | BOTTOM
  | IDENTIFIER
    // XML serialization:
    [ n:"hoot" l:"sort" a:{symbol=1/value} ]
  ;

SortList
  : Sort
    {
      ($$.sortList = new Stack()).push($1.svalue());
    }
  | Sort ';' SortList
    {
      ($$.sortList = $3.sortList).push($1.svalue());
    }
  ;

// /**
//  * This non-terminal denotes statements used to define a global
//  * name associated to a &psi;-term.
//  */
// DefinitionStatement
//   : DEF '=' PsiTerm
//   {
//     processDefinition($1.name,$3.psiterm);
//   }
//   ;
   
/**
 * This node stands for a pragma statement which allows the user to
 * query state parameters or up some options using a few built-in
 * extra-language commands of the form <font
 * color="brown"><kbd>&#37;<i>pragma</i></kbd></font> where <font
 * color="brown"><kbd><i>pragma</i></kbd></font> is an identifier,
 * possibly followed by arguments.
 *
 * <p/>
 *
 * The following is a list of pragmas we found useful. It is a partial
 * list as one could add whatever other pragma one deems useful. Not all
 * the pragmas listed below have been implemented yet (some are quite
 * tricky), but all those listed will be supported eventually.
 *
 * <p>
 * <center>
 * <table border="1" width="90&#37;" cellpadding="5">
 * <col width="25&#37;">
 * <col width="75&#37;">
 *
 * <tr><th align="left">Pragma</th><th align="left">Effect</th></tr>
 *
 * <tr><td valign="top"><font color="brown"><b><i><kbd>&#37;help</kbd></i></b></font></td>
 * <td valign="top">List this information.</td></tr>
 *
 * <tr><td valign="top"><font color="brown"><b><i><kbd>&#37;exit</kbd></i></b></font></td>
 * <td valign="top">End the session and exit HOOT.</td></tr>
 *
 * <tr><td valign="top"><font color="brown"><b><i><kbd>&#37;include "file<sub>1</sub>" ... "file<sub>n</sub>"</kbd></i></b></font></td>
 * <td valign="top">Read and process the contents of the <i>n</i> files in the specified order (names specified as quoted strings);  <i>n</i> &geq; 1.</td></tr>
 *
 * <tr><td valign="top"><font color="brown"><b><i><kbd>&#37;encode</kbd></i></b></font></td>
 * <td valign="top">Trigger the bit-vector encoding of the current sort hierarchy.</td></tr>
 *
 * <tr><td valign="top"><font color="brown"><b><i><kbd>&#37;sorts</kbd></i></b></font></td>
 * <td valign="top">Display all sorts as a bitcode array (must come after <kbd>%encode.</kbd>).</td></tr>
 *
 * <tr><td valign="top"><font color="brown"><b><i><kbd>&#37;defined</kbd></i></b></font></td>
 * <td valign="top">List all the currently defined symbols.</td></tr>
 *
 * <tr><td valign="top"><font color="brown"><b><i><kbd>&#37;symbols</kbd></i></b></font></td>
 * <td valign="top">List all the known (built-in and defined) symbols</td></tr>
 *
 * <tr><td valign="top"><font color="brown"><b><i><kbd>&#37;automatic</kbd></i></b></font></td>
 * <td valign="top">Toggle on/off automatic sort encoding
 *     at the first expression evaluation without prompting the user;
 *     the default is to prompt the user.</td></tr>
 *
 * <tr><td valign="top"><font color="brown"><b><i><kbd>&#37;mute</kbd></i></b></font></td>
 * <td valign="top">Toggle on/off result displays.</td></tr>
 *
 * <tr><td valign="top"><font color="brown"><b><i><kbd>&#37;size</kbd></i></b></font></td>
 * <td valign="top">Print the number of concepts in the sort hierarchy.</td></tr>
 *
 * <tr><td valign="top"><font color="brown"><b><i><kbd>&#37;height</kbd></i></b></font></td> <td valign="top">Print the
 * height of the sort hierarchy; that is, the length of the longest
 * <i>is-a</i> concept chain from <kbd>{}</kbd> to <kbd>&#64;</kbd>.</td></tr>
 *
 * <tr><td valign="top"><font color="brown"><b><i><kbd>&#37;width</kbd></i></b></font></td>
 * <td valign="top">Print the size of the widest
 *   is-a concept cochain; that is, the size of the largest
 *   set of mutually unrelated concepts in the hierarchy.</td></tr>
 *
 * <tr><td valign="top"><font color="brown"><b><i><kbd>&#37;children s</kbd></i></b></font></td> <td
 * valign="top">Prints the set of immediate subconcepts of <kbd>s</kbd>;
 * in other words, the set of strict greatest lower bounds of
 * <kbd>s</kbd>.</td></tr>
 *
 * <tr><td valign="top"><font color="brown"><b><i><kbd>&#37;descendants s</kbd></i></b></font></td> <td
 * valign="top">Print the set of all strict lower bounds of <kbd>s</kbd>;
 * in other words, the set of all subconcepts of <kbd>s</kbd> besides
 * itself nor <kbd>{}</kbd>, or <kbd>{}</kbd> if <kbd>s</kbd> is immediately
 * above <kbd>{}</kbd>.</td></tr>
 *
 * <tr><td valign="top"><font color="brown"><b><i><kbd>&#37;parents s</kbd></i></b></font></td> <td
 * valign="top">Print the set of immediate superconcepts of <kbd>s</kbd>;
 * in other words, the set of strict least upper bounds of
 * <kbd>s</kbd>;  besides <kbd>&#64;</kbd>, or <kbd>&#64;</kbd> if
 * <kbd>s</kbd> is immediately below <kbd>&#64;</kbd>.</td></tr>
 *
 * <tr><td valign="top"><font color="brown"><b><i><kbd>&#37;ancestors s</kbd></i></b></font></td> <td
 * valign="top">Print the set of all superconcepts of <kbd>s</kbd>; in
 * other words, the set of all strict upper bounds of <kbd>s</kbd> besides
 * <kbd>&#64;</kbd>, or <kbd>&#64;</kbd> if <kbd>s</kbd> is immediately below
 * <kbd>&#64;</kbd>.</td></tr>
 *
 * <tr><td valign="top"><font color="brown"><b><i><kbd>&#37;enumsize <i>n</i></kbd></i></b></font></td> <td
 * valign="top">Set to <i>n</i> the size of disjunctive enumerations to
 * display (number of symbols before <i>etc.</i>, ...). Default is
 * 10. </td></tr>
 *
 * <tr><td valign="top"><font color="brown"><b><i><kbd>&#37;isa s t</kbd></i></b></font></td>
 * <td valign="top">Return <kbd>true</kbd> if <kbd>s</kbd>
 *   is a subconcept of <kbd>t</kbd>, and <kbd>false</kbd> otherwise.</td></tr>
 *
 * <tr><td valign="top"><font color="brown"><b><i><kbd>&#37;refresh</kbd></i></b></font></td>
 * <td valign="top">Erase the codes for
 *     all known sorts (but not the sorts nor their <kbd>is-a</kbd>
 *     relations). After this pragma has been invoked, new sort
 *     declarations may then be added to those
 *     previously recorded, and then the hierarchy may be reencoded
 *     taking into account the new declared sorts.</td>
 * </tr>
 *
 * <tr><td valign="top"><font color="brown"><b><i><kbd>&#37;tree</kbd></i></b></font></td>
 * <td valign="top">Toggle on/off display of syntax tree.</td></tr>
 *
 * <tr><td valign="top"><font color="brown"><b><i><kbd>&#37;timing</kbd></i></b></font></td>
 * <td valign="top">Toggle on/off execution timing.</td></tr>
 *
 * <tr><td valign="top"><font color="brown"><b><i><kbd>&#37;gc</kbd></i></b></font></td>
 * <td valign="top">Force immediate garbage collection.</td></tr>
 *
 * <tr><td valign="top"><font color="brown"><b><i><kbd>&#37;syntax</kbd></i></b></font></td>
 * <td valign="top">Toggle on/off parser tracing.</td></tr>
 *
 * <tr><td valign="top"><font color="brown"><b><i><kbd>&#37;trace</kbd></i></b></font></td>
 * <td valign="top">Toggle on/off evaluation tracing.</td></tr>
 *
 * </table>
 * </center>
 */
PragmaStatement
  : HELP_PRAGMA // %help
    {
      setLocation();
      helpPragma();
    }
  | EXIT_PRAGMA // %exit
    {
      setLocation();
      HootMain.exit();
    }
  | INCLUDE_PRAGMA FileList // %include
    {
      setLocation();
      includeFiles($2.files);
    }
  | ENCODE_PRAGMA // %encode
    {
      setLocation();
      displaySize();
      encodeSorts();
    }
  | EVAL_PRAGMA // %eval
    {
      setLocation();
      PsiTerm.evaluateSorts(true);
      displayLine("*** Sort expression evaluation has been turned on...");
    }
  | SORTS_PRAGMA // %sorts
    {
      setLocation();
      displaySorts();
    }
  | DEFINED_PRAGMA // %defined
    {
      setLocation();
      // to do
    }
  | SYMBOLS_PRAGMA // %symbols
    {
      setLocation();
    }
  | MUTE_PRAGMA // %mute
    {
      setLocation();
      isMute = !isMute;
      display("Muted output has been turned "+(isMute ? "on" : "off")+"...\n");
      if (isMute) displayLine("*** ...");
    }
  | SIZE_PRAGMA // %size
    {
      setLocation();
      displaySize();
    }
  | HEIGHT_PRAGMA // %height
    {
      setLocation();
      // to do
    }
  | WIDTH_PRAGMA // %width
    {
      setLocation();
      // to do
    }
  | CHILDREN_PRAGMA SortExpression // %children
    {
      setLocation();
      displayChildren($2.expression);
    }
  | DESCENDANTS_PRAGMA SortExpression // %descendants
    {
      setLocation();
      showDescendants($2.expression);
    }
  | PARENTS_PRAGMA SortExpression // %parents
    {
      setLocation();
      displayParents($2.expression);
    }
  | ANCESTORS_PRAGMA SortExpression // %ancestors
    {
      setLocation();
      showAncestors($2.expression);
    }
  | ENUMSIZE_PRAGMA INTEGER // %enumsize
    {
      setLocation();
      Decoded.setEnumSize((int)$2.nvalue());
    }
  | ISA_PRAGMA SortExpression SortExpression // %isa
    {
      setLocation();
      // to do
    }
  | REFRESH_PRAGMA // %refresh
    {
      setLocation();
      Tag.clearKnownTags();
      context.reset();
      displayLine("*** The sort taxonomy has been cleared ("+
		  numberOfSorts(context.taxonomy().size())+" defined)");
    }
  | TREE_PRAGMA // %tree
    {
      setLocation();
      parseTreeType = (showTree = !showTree) ? COMPACT_TREE : NO_TREE;
      display("Parse tree display has been turned "+(showTree ? "on" : "off")+"...\n");
    }
  | TIMING_PRAGMA // %timing
    {
      setLocation();
      Context.toggleTiming();
      displayLine("*** Processing timing has been turned "+(Context.isTiming() ? "on" : "off")+"...");
    }
  | GC_PRAGMA // %gc
    {
      setLocation();
      display("\n");
      Misc.forceGC(!isMute,dm.getOutputStream());
    }
  | SYNTAX_PRAGMA // %syntax
    {
      setLocation();
      toggleTrace();
      display("Parser trace has been turned "+(tracingIsOn() ? "on" : "off")+"...\n");
    }
  | TRACE_PRAGMA // %trace
    {
      setLocation();
      if (isMute)
	{
	  display("Cannot trace evaluation in mute mode; turn mute mode off with '%mute.'");
	  break;
	}
      Context.toggleTracing();
      display("Execution tracing has been turned "+(Context.isTracing() ? "on" : "off")+"...\n");
    }
  | UNKNOWN_PRAGMA // %unknown
    {
      setLocation();
      displayLine("*** Unknown pragma (ignored) - type '%help.' for known pragmas.");
      //      displayLine("*** Unknown pragma: '%"+pragma+"' (ignored) - type '%help.' for known pragmas.");
    }
  ;

// PragmaArguments_opt
//   : /* empty */
//   | INTEGER // integer argument to a pragma %setenum
//     {
//       Decoded.setEnumSize((int)$1.nvalue());
//     }
//   | FileList
//     {
//       $$.args = $1.files;
//     }
//   | SortExpression // argument to pragmas %parents, %ancestors, %children, %descendants, etc., ...
//     {
//       ($$.args = new Stack(1)).add($1.expression);
//     }
//   | SortExpression SortExpression // arguments to pragma %isa
//     {
//       ($$.args = new Stack(2)).add($1.expression);
//       $$.args.add($2.expression);
//     }
//   ;

FileList
  : STRING
    {
      ($$.files = new Stack()).push($1.svalue());
    }
  | STRING FileList
    {
      ($$.files = $2.files).push($1.svalue());
    }
  ;

%%

/* ************************************************************************ */
/* ************************* END OF GRAMMAR RULES ************************* */
/* ************************************************************************ */
