- JavaDoc

# JEP

- Introduction
- Basic Usage
- Variables
- Data types
- Operators
- Functions
- BigDecimal
- Manipulating Expressions
- Components
- Configurable Parser
- Grammar
- FAQ
- Migration
- Version History

# Operators

## Built in operators

All common arithmetic operators are supported, these are provided by the StandardOperatorTable. Boolean operators are also fully supported. Relational and logical operators (>, <, >=, <=, ==, !=, !) are evaluated as Boolean types either as `Boolean.TRUE` or `Boolean.FALSE`.

An indicates that the operator can be used with the specific type of variable. Refer to the grammar for detailed information about operator precedence.

|  | Double | Complex | String | Vector
Power | ^ |  |  |  |
Boolean Not | ! |  |  |  |
Unary Plus, Unary Minus | +x, -x |  |  |  |
Dot product, cross product | ., ^^ |  |  |  |
Modulus | % |  |  |  |
Division | / |  |  |  |
Multiplication | * |  |  |  |
Addition, Subtraction | +, - |  |  | (only +) |
Less or Equal, More or Equal | <=, >= |  |  |  |
Less Than, Greater Than | <, > |  |  |  |
Not Equal, Equal | !=, == |  |  |  |
Boolean And | && |  |  |  |
Boolean Or | || |  |  |  |
Assignment | = |  |  |  |

## Adding operators

Both supplied parsers allow new operators to be added. The configurable parser makes the process quite simple but more steps are needed for using the default JavaCC parser. In both cases new operators should be added to the OperatorTable used by the Jep instance.

Before attempting to add an operator you should be familiar with adding a custom function to JEP. An instance PostfixMathCommandI (pfmc) is used to control how the operator is evaluated.

### Precedence and binding

Operators can either be binary operators (a+b), prefix unary operators (!a), suffix unary operators (i.e. like Java's x++ although no suffix operators are defined as standard), or ternary operators (i.e. like java's cond?tval:fval) No ternary operators defined in JEP as standard. Static fields defining flags for each of these are defined in the Operator class, these are `Operator.BINARY`, `Operator.UNARY`, `Operator.PREFIX`, `Operator.SUFFIX`, `Operator.TERNARY`.

The order in which operators are parsed depends on their precedence. For instance 1+2*3 is interpreted as 1+(2*3). The * operator has precedence over + (or in other words, it is "more tightly bound"). In JEP we use the convention that low values for precedence give a tighter binding, so the numeric value of the precedence of * is less than that of +. Precedences are always set in a relative manner as discussed below.

The parsing of operators also depends on their binding or associativity. This can either be left-associative (use `Operator.LEFT)`, like = where a=b=c is interpreted as a=(b=c), or right-associative (`Operator.RIGHT`), like - where a-b-c is interpreted as (a-b)-c. Left or right should be specified for all binary operators. A third flag `Operator.ASSOCIATIVE` is used to indicate associative operators like + this is used by print routine to determine whether to include brackets or not.

To construct an operator the constructor `public Operator(String name,PostfixMathCommandI pfmc,int flags)` is used giving the symbol used for the operator, the PostfixMathCommandI used and the sum of the flags. A second constructor `public Operator(String name,String symbol,PostfixMathCommandI pfmc,int flags)` is used when two operators share the same symbol, for example

    Operator add = new Operator("+",new Add(),
    	Operator.BINARY+Operator.LEFT+Operator.ASSOCIATIVE);
    Operator sub = new Operator("-",new Subtract(),
    	Operator.BINARY+Operator.LEFT);
    Operator mul = new Operator("*",new Multiply(),
    	Operator.BINARY+Operator.LEFT+Operator.ASSOCIATIVE);
    Operator div = new Operator("/",new Add(),
    	Operator.BINARY+Operator.LEFT);
    Operator umin = new Operator("UMinus","-",new UMinus(),
    	Operator.UNARY+Operator.RIGHT+Operator.PREFIX);
    Operator equals = new Operator("=",new Assign(),
    	Operator.BINARY+Operator.RIGHT);

There are further flags available, these specify other mathematical properties of the operators which are not currently used.

Once the new operators are created they need to be added to the operator table there are four methods for doing this.

    public Operator addOperator(int key,Operator op);
    public Operator addOperator(int key,Operator op,Operator existingOp);
    public Operator insertOperator(int key,Operator op,Operator existingOp);
    public Operator appendOperator(int key,Operator op,Operator existingOp);

The first adds an operator with no precedence set, the second adds an operator with the same precedence as an existing operator, the third and forth create a new precedence level which is either before (i.e. tighter) or after (i.e. looser) than the existing operator. The first argument in each is a numeric value used to represent the operator, for new operators use

    OperatorTable ot = jep.getOperatorTable();
    addOperator(ot.getNumOps(),new Operator("~",new bitComp(),Operator.UNARY+Operator.PREFIX));

If you are replacing one of the standard operator use the values of one of the static fields this will mean that the corresponding get...() methods will make the operator available

    addOperator(ot.OP_AND,new Operator("AND",new And(),new Logical(0),
    	Operator.BINARY+Operator.LEFT+Operator.ASSOCIATIVE));
    ot.getAnd(); // returns the AND operator.

An alternative way of setting operator precedence is the setPrecedenceTable method which sets the precedence of all operators at once.

Once the operators have been added then the `jep.reinitializeComponents();` to update jep instance with the new operators.

The following is example output of the `OperatorTable.toString()` method.

    Operator: "^-1" UDivide unary, prefix, right binding, precedence -1.
    Operator: "LIST" variable number of arguments, infix, right binding, precedence -1.
    Operator: "[]" variable number of arguments, infix, right binding, precedence -1.
    Operator: "-" UMinus unary, prefix, right binding, precedence 0.
    Operator: "+" UPlus unary, prefix, right binding, precedence 0.
    Operator: "!" unary, prefix, right binding, precedence 0.
    Operator: "^" binary, infix, right binding, precedence 1.
    Operator: "*" binary, infix, left binding, associative, commutative, precedence 2.
    Operator: "/" binary, infix, left binding, precedence 2.
    Operator: "%" binary, infix, left binding, precedence 2.
    Operator: "." binary, infix, left binding, precedence 2.
    Operator: "^^" binary, infix, left binding, precedence 2.
    Operator: "+" binary, infix, left binding, associative, commutative, precedence 3.
    Operator: "-" binary, infix, left binding, precedence 3.
    Operator: ">" binary, infix, left binding, precedence 4, transitive.
    Operator: "<" binary, infix, left binding, precedence 4, transitive.
    Operator: "<=" binary, infix, left binding, precedence 4, reflexive, transitive.
    Operator: ">=" binary, infix, left binding, precedence 4, reflexive, transitive.
    Operator: "==" binary, infix, left binding, precedence 5, equivalence relation.
    Operator: "!=" binary, infix, left binding, precedence 5, symmetric.
    Operator: "&&" binary, infix, left binding, associative, commutative, precedence 6.
    Operator: "||" binary, infix, left binding, associative, commutative, precedence 7.
    Operator: "=" binary, infix, right binding, precedence 8.

## Adding operators using the configurable parser

Once the operators have been added then the `jep.reinitializeComponents();` method must be called to inform the parser about the new operators. Once this is done the parser will be able to use the new operators. It is important that the precedence and associatitivity of the operators has been set correctly.

## Adding operators using the JavaCC parser

Adding operators to the standard parser is currently only possible by modifying the JEP source code. To add an operator to the parser, several steps are needed:

- Create a new token with the descriptive name AT, say, and a string representing the operator.
- Modify the grammar rules to include a rule for the new operator
- Add an operator as discussed above.

## Editing the standard parser grammar

The standard parser is created using the JavaCC parser/scanner generator. JavaCC reads the JccParser.jjt file which is written in a special language, defining the grammar. It outputs JccParser.java and some other Java files which implement the parser.

You should read some of the documentation on JavaCC and JJTree before attempting to modify the parser.

There is a three step process used to generate the parser.

1. JJTree is run. This reads the file JccParser.jjt and creates a file JccParser.jj. The purpose of this step is to add code needed to handle Abstract Syntax Trees which are tree structures used represent a mathematical expression. As well as creating JccParser.jj it also creates some other Java files: Node.java which represents the basic node in the parser; ASTConstant.java a node representing a constant value "0" or "1", ASTVarNode.java a node representing a variable, and ASTFunNode.java a node representing a function or operator.
2. JavaCC is run. This reads JccParser.jj and creates JccParser.java -- the actual code for implementing the Parser. JccParser.java is a very complicated file with nearly 2000 lines of code and is difficult to edit.
3. Normal Java compilation JccParser.java and the other classes generated by JavaCC.

This process is automatically carried out when the project is built using the ANT build.xml file. It is not sufficient to simply recompile all the Java files.

Only the JccParser.jjt file should be modified, JccParser.jj, JccParser.java should not be modified as they will be overwritten during the build process. Furthermore ASTConstant.java, ASTFunNode.java, ASTStart.java, ASTVarNode.java, JavaCharStream.java, JJTParserState.java, Node.java, SimpleNode.java, ParseException.java, JccParserConstants.java, JccParserTokenManager.java, JccParseTreeConstants.java, Token.java, and TokenMgrError.java should not normally be modified as these are also automatically generated.