/*
 * $Id: EC.jj,v 1.7 1998/11/07 19:30:27 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: "-" >
  |     < BWCOMPL: "~">
  |     < LOGCOMPL: "!">
  |	< MULTIPLY: "*" >
  |	< DIVIDE: "/" >
  |     < REMAINDER: "%" >
  |	< AND: "&" >
  |	< LAND: "&&" >
  |	< OR: "|" >
  |	< LOR: "||" >
  |	< XOR: "^" >
  |     < EQ: "==" >
  |     < NE: "!=" >
  |     < LT: "<" >
  |     < GE: ">=" >
  |     < GT: ">" >
  |     < LE: "<=" >
  |     < LS: "<<" >
  |     < RS: ">>" >
  |     < RUS: ">>>" >
}

TOKEN : /* Boolean Literals */
{
        < FALSE: "false" >
|       < TRUE: "true" >
}

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"]
            )
          )
      )
      "'"
  >
| 
  < STRING_LITERAL:
      "\""
      (   (~["\"","\\","\n","\r"])
        | ("\\"
            ( ["n","t","b","r","f","\\","'","\""]
            | ["0"-"7"] ( ["0"-"7"] )?
            | ["0"-"3"] ["0"-"7"] ["0"-"7"]
            )
          )
      )*
      "\""
  >
}

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

void expression(Optimizer optimizer,Class resultType) 
     throws CompilationException :
{Token x;}
{
  conditional(optimizer) (x=<EOF>)
    {
      try{
	if (resultType!=null) optimizer.convert(resultType,true);
	optimizer.finish();
       } catch (IllegalStateException e) {
	 throw new CompilationException(x,e.getMessage());
       };
    }
}

void conditional(Optimizer optimizer) throws CompilationException :
{}
{
  lor(optimizer) [ "?" {
    try{
      optimizer.conditional_true();
    } catch (IllegalStateException e) {
      throw new CompilationException(token,e.getMessage());
    };
  }
  conditional(optimizer) 
  ":" {
    optimizer.conditional_false();
  }
  conditional(optimizer) {
    try{
      optimizer.conditional_end();
    } catch (IllegalStateException e) {
      throw new CompilationException(token,e.getMessage());
    };
  }
  ]
}

void lor(Optimizer optimizer) throws CompilationException :
{Token x;}
{
  land(optimizer) ( x=<LOR> {optimizer.binaryOP_param();} 
  land(optimizer) {
    try {
      optimizer.binaryOP(ExpressionImage.LOG_OR,true);
    } catch (IllegalStateException e) {
      throw new CompilationException(x,e.getMessage());
    };
  } )*
}

void land(Optimizer optimizer) throws CompilationException :
{Token x;}
{
  bor(optimizer) ( x=<LAND> {optimizer.binaryOP_param();} 
  bor(optimizer) {
    try {
      optimizer.binaryOP(ExpressionImage.LOG_AN,true);
    } catch (IllegalStateException e) {
      throw new CompilationException(x,e.getMessage());
    };
  } )*
}

void bor(Optimizer optimizer) throws CompilationException :
{Token x;}
{
  bxor(optimizer) ( x=<OR> {optimizer.binaryOP_param();} 
  bxor(optimizer) {
    try {
      optimizer.binaryOP(ExpressionImage.BI_OR,false);
    } catch (IllegalStateException e) {
      throw new CompilationException(x,e.getMessage());
    };
  } )*
}


void bxor(Optimizer optimizer) throws CompilationException :
{Token x;}
{
  band(optimizer) ( x=<XOR> {optimizer.binaryOP_param();} 
  band(optimizer) {
    try {
      optimizer.binaryOP(ExpressionImage.BI_XO,false);
    } catch (IllegalStateException e) {
      throw new CompilationException(x,e.getMessage());
    };
  } )*
}

void band(Optimizer optimizer) throws CompilationException :
{Token x;}
{
  equality(optimizer) ( x=<AND> {optimizer.binaryOP_param();} 
  equality(optimizer) {
    try {
      optimizer.binaryOP(ExpressionImage.BI_AN,false);
    } catch (IllegalStateException e) {
      throw new CompilationException(x,e.getMessage());
    };
  } )*
}

void equality(Optimizer optimizer) throws CompilationException :
{Token x;}
{
  relation(optimizer) ( (x=<EQ>|x=<NE>) {optimizer.binaryOP_param();} 
  relation(optimizer) {
    try {
      int op=ExpressionImage.BI_EQ;
      if (x.kind==NE) op=op=ExpressionImage.BI_NE;
      optimizer.binaryOP(op,false);
    } catch (IllegalStateException e) {
      throw new CompilationException(x,e.getMessage());
    };
  } )*
}

void relation(Optimizer optimizer) throws CompilationException :
{Token x;}
{
  shift(optimizer) ( (x=<LT>|x=<GE>|x=<GT>|x=<LE>) 
		     {optimizer.binaryOP_param();} 
  shift(optimizer) {
    try {
      int op=999;
      switch(x.kind) {
      case LT: op=ExpressionImage.BI_LT; break;
      case GE: op=ExpressionImage.BI_GE; break;
      case GT: op=ExpressionImage.BI_GT; break;
      case LE: op=ExpressionImage.BI_LE; break;
      default:
      };
      
      optimizer.binaryOP(op,false);
    } catch (IllegalStateException e) {
      throw new CompilationException(x,e.getMessage());
    };
  } )*
  
}

void shift(Optimizer optimizer) throws CompilationException :
{Token x;}
{
  sum(optimizer) ( (x=<LS>|x=<RS>|x=<RUS>) 
		   {optimizer.binaryOP_param();} 
  sum(optimizer) {
    try {
      int op=999;
      switch(x.kind) {
      case LS : op=ExpressionImage.BI_LS; break;
      case RS : op=ExpressionImage.BI_RSS; break;
      case RUS: op=ExpressionImage.BI_RUS; break;
      default:
      };
      optimizer.binaryOP(op,false);
    } 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,false);
       } catch (IllegalStateException e) {
	 throw new CompilationException(x,e.getMessage());
       };
     }
  )*
}

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

void unary(Optimizer optimizer) throws CompilationException :
{
  Token x;
  Token type_to;
}
{
  x=<MINUS> element(optimizer) 
    {
      try {
	optimizer.unary(ExpressionImage.UN_NE);
      } catch (IllegalStateException e) {
	throw new CompilationException(x,e.getMessage());
      };
    }
|  x=<BWCOMPL> element(optimizer)
    {
      try {
	optimizer.unary(ExpressionImage.UN_NO);
      } catch (IllegalStateException e) {
	throw new CompilationException(x,e.getMessage());
      };
    }
|  x=<LOGCOMPL> {
      optimizer.logical_not_start();
    } 
    element(optimizer) {
      try {
	optimizer.logical_not();
      } catch (IllegalStateException e) {
	throw new CompilationException(x,e.getMessage());
      };
    }
|  LOOKAHEAD(3) "(" (type_to=<ID>) ")" element(optimizer)
    {
      
      Class tc=null;
      for(int i=0;(i<ExpressionImage.primitiveTypeNames.length) && (tc==null);
	  i++) 
	if (type_to.image.equals(ExpressionImage.primitiveTypeNames[i]))
	  tc=ExpressionImage.primitiveTypes[i];
      
      if (tc==null)
	throw new CompilationException(type_to,"The string \""+type_to.image+
				       "\" is not a valid primitive type.");
      
      try {
	optimizer.convert(tc);
      } catch (IllegalStateException e) {
	throw new CompilationException(type_to,e.getMessage());
      };
      
    }
    //  | "!" {} element(optimizer)
| element(optimizer)
}

void element(Optimizer optimizer)  throws CompilationException :
{}
{
    literal(optimizer)
  | <TRUE>  { optimizer.load(true);}
  | <FALSE> { optimizer.load(false);}
  | function(optimizer)
  | "(" conditional(optimizer) ")"
}

void function(Optimizer optimizer) throws CompilationException :
{ Token id;}
{
  (id=<ID>) {optimizer.function_start();} 
   ["(" 
     [conditional(optimizer) {optimizer.function_param();} 
	     ( "," conditional(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);
  };
  }}
| <STRING_LITERAL> {{
  String sval=token.image.substring(1,token.image.length()-1);
  StringBuffer unescaped=new StringBuffer(sval.length());
  for(int i=0;i<sval.length();i++) {
    char ec=sval.charAt(i);
    if (ec=='\\') { // escape
      ec=sval.charAt(++i);
      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:
	int nval=0;
	while ((i<sval.length()) && ((ec=sval.charAt(i))>='0') && (ec<='7')) {
	  nval=nval<<3+(ec-'0');
	  i++;
	};
	i--;
	ec=(char)nval;
      };
    };
    unescaped.append(ec);
  };
  optimizer.load(unescaped.toString());  
  }}
}












