// FILE. . . . . /home/hak/ilt/dotnet/src/Ilog/Language/Syntax/jacc/Term.grm
// EDIT BY . . . Hassan Ait-Kaci
// ON MACHINE. . Latitude407.Ilog.Biz
// STARTED ON. . Tue May 24 08:27:48 2005

/**
 *
 * This example is a Jacc specification of an interactive parser for
 * Prolog terms (and thus for Prolog). It illustrates the use of dynamic
 * operators and how to specify top-down undo semantic actions. The parser
 * repeatedly reads  a term from the standard input, prints its canonical
 * form - <i>i.e.</i>, <tt>f(t<sub>1</sub>, ... ,t<sub>n</sub>)</tt>. All
 * Prolog dynamic operators are predefined, but may be redefined at parse
 * time. New dynamic operators may also be defined and redefined at parse
 * time as well.
 * <p>
 *
 * @version     Last modified on Tue May 31 14:21:47 2005 by hak
 * @author      <a href="mailto:hak@ilog.fr">Hassan A&iuml;t-Kaci</a>
 * @copyright   &copy; 2000 <a href="http://www.ilog.fr/">ILOG, S.A.</a>
 */

/*
 * Declarations
 */

%import System;
%import System.Text;
%import System.Collections;

%start Session

%token NUMBER FUNCTOR

%dynamic Op     // Prolog operator category
%Op ':-'   1200 xfx
%Op ':-'   1200 fx
%Op '-->'  1200 xfx
%Op ';'    1100 xfy
%Op ','    1000 xfy
%Op '='    700 xfx
%Op '\\='  700 xfx
%Op '=='   700 xfx
%Op '\\==' 700 xfx
%Op '=..'  700 xfx
%Op 'is'   700 xfx
%Op '=:='  700 xfx
%Op '=\\=' 700 xfx
%Op '<'    700 xfx
%Op '<='   700 xfx
%Op '>'    700 xfx
%Op '>='   700 xfx
%Op '+'    500 yfx
%Op '-'    500 yfx
%Op '*'    400 yfx
%Op '/'    400 yfx
%Op '&'    200 xfy
%Op '^'    200 xfy
%Op '-'    200 fy
// we add, with lesser precedence than relational operators's (700):
%Op if   800 fx       // if X                  ==> if(X)
%Op then 850 xfy      // X then Y              ==> then(X,Y)
%Op else 820 xfx      // X else Y              ==> else(X,Y)
         // THEREFORE // if C then T else E    ==> then(if(C),else(T,E))

         // Note that // if A then B         ==> then(if(A),B).
         // However   // if A then B else if C then D else E.
         // parses as //    ==> then(if(A),then(else(B,if(C)),else(D,E)))
         // instead of//    ==> then(if(A),else(B,then(if(C),else(D,E))))
         // which is  // if A then B else (if C then D else E).

%{
  System.Collections.Stack terms = new System.Collections.Stack();
  Term term, temp;
%}

%%
/*
 * Production rules
 */

Session
        : Clauses Exit
        | Exit
        ;

Exit
  	: 'exit'
        {
	  Console.WriteLine("*** Bye bye!...");
	  Environment.Exit(0);
	} '.'
	;

Clauses
        : Clause
        | Clauses Clause
        ;

Clause
        :
        { /* Bottom-up reduction semantic action: */
          terms = new System.Collections.Stack();
        }
          Term
        { /* Bottom-up reduction semantic action: */
          term = (Term)terms.Pop();

          // Operator (re)definition:
          if (term.functor != null && term.functor.Equals("op")
              && term.body != null && term.body.Count == 3)
            {
              try
                {
		  if (!((Term)term.body[0]).IsNumber)
		    throw new Exception("Bad precedence ("+term.body[0]+")");

		  if (((Term)term.body[1]).IsNumber)
		    throw new Exception("Operator specifier can't be a number ("+term.body[1]+")");

		  if (((Term)term.body[2]).IsNumber)
		    throw new Exception("Can't define a number as operator ("+term.body[2]+")");

                  Op(((Term)term.body[2]).functor,
                     ((Term)term.body[1]).functor,
                     (int)((Term)term.body[0]).number);
                }
              catch (Exception e)
                {
                  Console.Error.WriteLine("*** Bad op declaration: "+term+": "
					  +e.Message+" [ see "+$2.LocationString()+"]");		  
                }
            }

          Console.WriteLine(term.ToString()); // print out the term's canonical form
          CutAll();                     // delete all pending token choices
          TermTokenizer.Prompt();
        } '.'
        | error
	{
	  ErrorManager.ReportErrors(true);
          TermTokenizer.Prompt();
	} '.'
	;

Op      : FUNCTOR
        ;

Term
        : NUMBER
        { /* Bottom-up reduction semantic action: */
          terms.Push($1.IsInteger ? new Term((int)$1.NValue)
                                  : new Term($1.NValue));
        }
        { /* Top-down undo semantic action: */
          terms.Pop();
        }
        | Op
        { /* Bottom-up reduction semantic action: */
          terms.Push(new Term($1.SValue));
        }
        { /* Top-down undo semantic action: */
          terms.Pop();
        }
        | Op '('
        { /* Bottom-up reduction semantic action: */
          terms.Push(new Term($1.SValue,new ArrayList()));
        }
        { /* Top-down undo semantic action: */
          terms.Pop();
        }
          Body ')'
        | OP_
        { /* Bottom-up reduction semantic action: */
          terms.Push(new Term($1.SValue,new ArrayList()));
        }
        { /* Top-down undo semantic action: */
          terms.Pop();
        }
          Term
        { /* Bottom-up reduction semantic action: */
          term = (Term)terms.Pop();
          ((Term)terms.Peek()).body.Add(term);
        }
        { /* Top-down undo semantic action: */
          temp = (Term)terms.Peek();
          term = (Term)temp.body[temp.body.Count-1];
          temp.body.RemoveAt(temp.body.Count-1);
          terms.Push(term);
        }
        | Term _OP_
        { /* Bottom-up reduction semantic action: */
          term = (Term)terms.Pop();
          terms.Push(new Term($2.SValue,new ArrayList()));
          ((Term)terms.Peek()).body.Add(term);
        }
        { /* Top-down undo semantic action: */
          temp = (Term)terms.Pop();
          term = (Term)temp.body[temp.body.Count-1];
          terms.Push(term);
        }
          Term
        { /* Bottom-up reduction semantic action: */
          term = (Term)terms.Pop();
          ((Term)terms.Peek()).body.Add(term);
        }
        { /* Top-down undo semantic action: */ 
          temp = (Term)terms.Peek();
          term = (Term)temp.body[temp.body.Count-1];
          temp.body.RemoveAt(temp.body.Count-1);
          terms.Push(term);
        }
        | Term _OP
        { /* Bottom-up reduction semantic action: */
          term = (Term)terms.Pop();
          terms.Push(new Term($2.SValue,new ArrayList()));
          ((Term)terms.Peek()).body.Add(term);
        }
        { /* Top-down undo semantic action: */
          temp = (Term)terms.Pop();
          term = (Term)temp.body[temp.body.Count-1];
          terms.Push(term);
        }
        | '(' Term ')'
        ;

Body
        : Term
        { /* Bottom-up reduction semantic action: */
          term = (Term)terms.Pop();
          ((Term)terms.Peek()).body.Add(term);
        }
        { /* Top-down undo semantic action: */ 
          temp = (Term)terms.Peek();
          term = (Term)temp.body[temp.body.Count-1];
          temp.body.RemoveAt(temp.body.Count-1);
          terms.Push(term);
        }
        | Body ',' Term
        { /* Bottom-up reduction semantic action: */
          term = (Term)terms.Pop();
          ((Term)terms.Peek()).body.Add(term);
        }
        { /* Top-down undo semantic action: */ 
          temp = (Term)terms.Peek();
          term = (Term)temp.body[temp.body.Count-1];
          temp.body.RemoveAt(temp.body.Count-1);
          terms.Push(term);
        }
        ;

%%
/**
 * Ancillary classes
 */

%include "TermClass.grm"
