`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