/*
 * $Id: EC.jj,v 1.1.1.1 1998/05/11 18:43:02 metlov Exp $
 *
 * This file is part of the Java Expressions Library (JEL).
 *   For more information about JEL visit :
 *    http://galaxy.fzu.cz/JEL/
 *
 * (c) 1998 by Konstantin Metlov(metlov@fzu.cz);
 *
 * JEL is Distributed under the terms of GNU General Public License.
 *    This code comes with ABSOLUTELY NO WARRANTY.
 *  For license details see COPYING file in this directory.
 */

/*
 * This is the grammar definition for the expression language,
 * compiled by JEL. Requires JavaCC to rebuild parser.
 */
options {
    LOOKAHEAD=1;
    CHOICE_AMBIGUITY_CHECK=2;
    OTHER_AMBIGUITY_CHECK=2;
    OUTPUT_DIRECTORY="generated";
    ERROR_REPORTING=true;
    STATIC=false;
}

PARSER_BEGIN(EC)
package gnu.jel.generated;

import gnu.jel.Optimizer;
import gnu.jel.Library;
import gnu.jel.ExpressionImage;
import gnu.jel.CompilationException;
import java.io.StringReader;
import gnu.jel.debug.Debug;

public class EC { /* EC stands for ExpressionCompiler */
};
PARSER_END(EC)

SKIP :
{
 	" "
  |	"\r"
  |	"\t"
}

TOKEN : /* OPERATORS */
{
	< PLUS: "+" >
  |	< MINUS: "-" >
  |	< MULTIPLY: "*" >
  |	< DIVIDE: "/" >
  |	< AND: "&" >
  |	< OR: "|" >
  |	< XOR: "^" >
}

TOKEN :  // Literals (taken from JavaCC Java grammar example)
{
  < INTEGER_LITERAL:
        <DECIMAL_LITERAL> (["l","L"])?
      | <HEX_LITERAL> (["l","L"])?
      | <OCTAL_LITERAL> (["l","L"])?
  >
|
  < #DECIMAL_LITERAL: ["1"-"9"] (["0"-"9"])* >
|
  < #HEX_LITERAL: "0" ["x","X"] (["0"-"9","a"-"f","A"-"F"])+ >
|
  < #OCTAL_LITERAL: "0" (["0"-"7"])* >
|
  < FLOATING_POINT_LITERAL:
        (["0"-"9"])+ "." (["0"-"9"])* (<EXPONENT>)? (["f","F","d","D"])?
      | "." (["0"-"9"])+ (<EXPONENT>)? (["f","F","d","D"])?
      | (["0"-"9"])+ <EXPONENT> (["f","F","d","D"])?
      | (["0"-"9"])+ (<EXPONENT>)? ["f","F","d","D"]
  >
|
  < #EXPONENT: ["e","E"] (["+","-"])? (["0"-"9"])+ >
|
  < CHARACTER_LITERAL:
      "'"
      (   (~["'","\\","\n","\r"])
        | ("\\"
            ( ["n","t","b","r","f","\\","'","\""]
            | ["0"-"7"] ( ["0"-"7"] )?
            | ["0"-"3"] ["0"-"7"] ["0"-"7"]
            )
          )
      )
      "'"
  >
}

TOKEN : /* Function names */
{
        < ID: ( <LETTER> )+ ( ["0" - "9"] | <LETTER> | "_")* >
  |     < #LETTER: ["a"-"z", "A"-"Z"] >
}

void expression(Optimizer optimizer) throws CompilationException :
{}
{
  [logical(optimizer)] <EOF>
    {
      optimizer.finish();
    }
}

void logical(Optimizer optimizer) throws CompilationException :
{Token x;}
{
  sum(optimizer) 
    (
     ( x=<AND> | x=<OR> | x=<XOR> ) {optimizer.binaryOP_param();} 
     sum(optimizer)
     {
       try {
	 int op=999;
	 switch (x.kind) {
	 case AND: op=ExpressionImage.BI_AN; break;
	 case OR:  op=ExpressionImage.BI_OR; break;
	 case XOR: op=ExpressionImage.BI_XO; break;
	 default:
       };
	 optimizer.binaryOP(op);
       } catch (IllegalStateException e) {
	 throw new CompilationException(x,e.getMessage());
       };
     }
    )*
}

void sum(Optimizer optimizer) throws CompilationException :
{Token x;}
{
  term(optimizer)  
  (  (x=<PLUS> | x=<MINUS>) {optimizer.binaryOP_param();} term(optimizer) 
     {
       try {
	 int op=ExpressionImage.BI_MI;
	 if (x.kind==PLUS) op=ExpressionImage.BI_PL;
	 optimizer.binaryOP(op);
       } catch (IllegalStateException e) {
	 throw new CompilationException(x,e.getMessage());
       };
     }
  )*
}

void term(Optimizer optimizer) throws CompilationException :
{Token x;}
{
  unary(optimizer)
  ( (x=<MULTIPLY> |x=<DIVIDE>) {optimizer.binaryOP_param();} unary(optimizer) 
    {
      try {
	int op=ExpressionImage.BI_MU;
	if (x.kind==DIVIDE) op=ExpressionImage.BI_DI;
	optimizer.binaryOP(op);
      } catch (IllegalStateException e) {
	throw new CompilationException(x,e.getMessage());
      };
    }
  )*
}

void unary(Optimizer optimizer) throws CompilationException :
{Token x;}
{
  x=<MINUS> element(optimizer) 
    {
      try {
	optimizer.unary(ExpressionImage.UN_NE);
      } catch (IllegalStateException e) {
	throw new CompilationException(x,e.getMessage());
      };
    }
  | element(optimizer)
}

void element(Optimizer optimizer)  throws CompilationException :
{}
{
    literal(optimizer)
  | function(optimizer)
  | "(" logical(optimizer) ")"
}

void function(Optimizer optimizer) throws CompilationException :
{ Token id;}
{
  (id=<ID>) {optimizer.function_start();} 
   ["(" 
     [logical(optimizer) {optimizer.function_param();} 
	     ( "," logical(optimizer) {optimizer.function_param();} )* ]
     ")"] 
     {
       try {
	 optimizer.function_call(id.image);
       } catch (IllegalStateException e) {
	 throw new CompilationException(id,e.getMessage());
       };
       
     }
}

void literal(Optimizer optimizer) throws CompilationException :
{}
{
  <INTEGER_LITERAL> {{
    String svalue=token.image.toUpperCase();
    long value=0;
    boolean makelong=svalue.endsWith("L");
    if (makelong) svalue=svalue.substring(0,svalue.length()-1);
    
    try {
      if ( svalue.startsWith("0x") || svalue.startsWith("0X") ) {
	// Hexadecimal number
	svalue=svalue.substring(2);
	value=Long.parseLong(svalue,16);
      } else if (token.image.startsWith("0")) {
	// Octal number
	value=Long.parseLong(svalue,8);
      } else {
	// Decimal number
	value=Long.parseLong(svalue,10);
      };
    } catch (NumberFormatException e) {
      throw new CompilationException(token,"Number \""+token.image+
				     "\" is too large, it does not fit even "+
				     "into 64 bit long."); // Overflow ?
    };
    
    if (!makelong) { // Check ranges
      if (value<=127) optimizer.load((byte)value);
      else if (value<=32767) optimizer.load((short)value);
      else if (value<=2147483647) optimizer.load((int)value);
      else 
	throw 
	  new CompilationException(token,"Integer number \""+token.image+
				   "\" is too large for type 'int'. Be sure"+
				   " to add 'L' suffix to use 'long' type.");
    } else {
      optimizer.load(value);
    };
    
  }}
| <FLOATING_POINT_LITERAL> {{
  char lc=Character.toUpperCase(token.image.charAt(token.image.length()-1));
  boolean makeFloat = (lc=='F');
  String svalue=token.image;
  if ((lc=='D') || (lc=='F')) {
    svalue=svalue.substring(0,svalue.length()-1);
  };
  Double value=null;
  try {
    value=new Double(svalue);
  } catch (NumberFormatException e) {
    // Overflow ? Will produce infinity.
  };
  if (makeFloat) 
    optimizer.load(value.floatValue());
  else
    optimizer.load(value.doubleValue());
  }}
| <CHARACTER_LITERAL> {{
  String sval=token.image.substring(1,token.image.length()-1);
  if (sval.length()==1) 
    optimizer.load(sval.charAt(0)); 
  else{ // escape or number
    char ec=sval.charAt(1);
    try {
      switch (ec) {
      case 'n': ec='\n'; break;
      case 't': ec='\t'; break;
      case 'b': ec='\b'; break;
      case 'r': ec='\r'; break;
      case 'f': ec='\f'; break;
      case '\\': ec='\\'; break;
      case '\'': ec='\''; break;
      case '\"': ec='"'; break;
      default:
	ec=(char) Integer.parseInt(sval.substring(1),8);
      };
    } catch (NumberFormatException e) {/* Can't be */};
    optimizer.load(ec);
  };
  }}
}












