Term.grm

// FILE. . . . . /home/hak/ilt/doc/ilog/jacc/term.grm
// EDIT BY . . . Hassan Ait-Kaci
// ON MACHINE. . Latitude407.Ilog.Biz
// STARTED ON. . Tue Dec 14 18:20:30 2004

// Last modified on Mon Dec 20 18:41:07 2004 by hak



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.e., f(t1, ... ,tn). 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.

Author:  Hassan Aït-Kaci
Copyright:  © 2000 ILOG, S.A.
Version:  Last modified on Mon Nov 27 12:23:05 2000 by hak



/*
 * Declarations
 */

%import java.util.*;
%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 that 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).

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

%%
/*
 * Production rules
 */

Session
        : Clauses Exit
        | Exit
        ;

Exit
  	: 'exit'
        {
	  System.out.println("*** Bye bye!...");
	  System.exit(0);
	} '.'
	;

Clauses
        : Clause
        | Clauses Clause
        ;

Clause
        :
        { /* Bottom-up reduction semantic action: */
          terms = new 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.size() == 3)
            {
              try
                {
                  Op(((Term)term.body.get(2)).functor,
                     ((Term)term.body.get(1)).functor,
                     (int)((Term)term.body.get(0)).number);
                }
              catch (Exception e)
                {
                  System.err.println("*** Bad op declaration: "+term);
                }
            }

          out.println(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 Vector()));
        }
        { /* Top-down undo semantic action: */
          terms.pop();
        }
          Body ')'
        | OP_
        { /* Bottom-up reduction semantic action: */
          terms.push(new Term($1.svalue(),new Vector()));
        }
        { /* 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.lastElement();
          temp.body.removeElementAt(temp.body.size()-1);
          terms.push(term);
        }
        | Term _OP_
        { /* Bottom-up reduction semantic action: */
          term = (Term)terms.pop();
          terms.push(new Term($2.svalue(),new Vector()));
          ((Term)terms.peek()).body.add(term);
        }
        { /* Top-down undo semantic action: */
          temp = (Term)terms.pop();
          term = (Term)temp.body.lastElement();
          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.lastElement();
          temp.body.removeElementAt(temp.body.size()-1);
          terms.push(term);
        }
        | Term _OP
        { /* Bottom-up reduction semantic action: */
          term = (Term)terms.pop();
          terms.push(new Term($2.svalue(),new Vector()));
          ((Term)terms.peek()).body.add(term);
        }
        { /* Top-down undo semantic action: */
          temp = (Term)terms.pop();
          term = (Term)temp.body.lastElement();
          terms.push((Term)temp.body.lastElement());
        }
        | '(' 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.lastElement();
          temp.body.removeElementAt(temp.body.size()-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.lastElement();
          temp.body.removeElementAt(temp.body.size()-1);
          terms.push(term);
        }
        ;

%%


Ancillary classes



class Term
{
  String functor = null;
  Vector body = null;
  double number = Double.NaN;
  boolean isInteger = false;

  Term (double n)
    {
      number = n;
    }

  Term (int n)
    {
      number = n;
      isInteger = true;
    }

  Term (String functor)
    {
      this.functor = functor;
    }

  Term (String functor, Vector body)
    {
      this.functor = functor;
      this.body = body;
    }

  public final boolean isNumber ()
    {
      return !Double.isNaN(number);
    }

  public final boolean hasBody ()
    {
      return (body != null && !body.isEmpty());
    }

  public String toString ()
    {
      if (isNumber())
        return(isInteger ? String.valueOf((int)number)
                         : String.valueOf(number));

      if (!hasBody())
        return functor;
      
      StringBuffer s = new StringBuffer(functor);

      s.append("(");
      for (int i=0; i<body.size(); i++)
        {
          s.append(body.get(i));
          if (i<body.size()-1) s.append(",");
        }
      s.append(")");

      return s.toString();
    }
}


This file was generated on Mon Dec 20 19:03:12 PST 2004 from file Term.grm
by the ilog.language.tools.Hilite Java tool written by Hassan Aït-Kaci