- JavaDoc

# Jep Java

- Introduction
- Basic Usage
- Variables
- Data types
- Operators
- Functions
- Custom Functions
- BigDecimal
- Modules
- Printing
- FAQ
- Migration
- Version History

# Advanced Features

- Manipulating Expressions
- Components
- Configurable Parser
- Serialization
- Threads
- Localization
- Grammar
- Other advanced features
- Use of Design Patterns in Jep

# Operators

## Built in operators

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

The following table shows the operators in order of precedence. A check mark indicates that the operator can be used with the specific type of variable. Refer to the grammar for detailed information on the operator precedence.

|  | Double | Complex | String | Vector
Power | ^ |  |  |  |
Boolean Not | ! |  |  |  |
Unary Plus, Unary Minus | +x, -x |  |  |  |
Dot product, cross product | ., ^^ |  |  |  |
Modulus | % |  |  |  |
Division | / |  |  |  |
Multiplication | * |  |  |  |
Addition | + |  |  |  |
Subtraction | - |  |  |  |
Less than or equal to, greater than or equals to | <=, >= |  |  |  |
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.

## Adding and manipulating operators for the configurable parser

To add operators to the configurable parser, they must first be added to the Operator table. 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 associativity of the operators has been set correctly prior to calling the method.

### Modifying an existing operator

If you just wish to change the underlying PostfixMathCommandI of an operator, for example to allow it to work with a new type of value and keeping the existing precedence and associativity and symbol, then the `setPFMC()` method of Operator can be called. The operator can be recovered from the various get methods of the OperatorTable, for instance to change the PostfixMathCommandI of the And (&&) operator use:

    jep.getOperatorTable().getAnd().setPFMC(new LazyLogical(LazyLogical.AND));

If you wish to change the symbol used to represent an operator you can use:

    jep.getOperatorTable().getAnd().setSymbol("AND");
    jep.reinitializeComponents();

Note the call to `jep.reinitializeComponents()` which is needed to inform the other components of the new symbol.

It is possible to allow alternate symbols for and operator which will be recognized by the parser. For example Unicode has particular characters for the minus sign, U+2212, (−). Devices like android phones often use these symbols. Such alternate symbols can be set via the `Operator.addAltSymbol(String)` method. Other possible alternative characters include U+2264 less-than or equals (≤), U+2265 greater-than or equals (≥), U+00D7 multiplication sign (×), U+00F7 division sign (÷), U+2044 fraction slash (⁄) and U+2215 division slash (∕). The following code adds some common alternate symbols

    Jep jep = new Jep(new StandardConfigurableParser());
    jep.getOperatorTable().getUMinus().addAltSymbol("\u2212");
    jep.getOperatorTable().getSubtract().addAltSymbol("\u2212");
    jep.getOperatorTable().getMultiply().addAltSymbol("\u00d7");
    jep.getOperatorTable().getDivide().addAltSymbol("\u00f7");
    jep.reinitializeComponents();

When printing equations with an alphabetical operator symbols like "AND" it is better to include spaces before and after the operator. This can be achieved by setting the `setPrintSymbol(String)` of the operator.

    jep.getOperatorTable().getAnd().setPrintSymbol(" AND ");

### 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 like Java's `a?b:c`, again not defined 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`, and `Operator.NARY` for operators with 3 or more arguments.

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 Divide(),
    	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. For Ternary operators use the com.singularsys.jep.configurableparser.TernaryOperator.

### Adding operators to the operator table

Since version 3.3 a new com.singularsys.jep.OperatorTable2 class have been introduced. It can found from the main jep instance.

    OperatorTable2 table = jep.getOperatorTable2();

Each type of is given a key. For example `OperatorTable2.BasicOperators.ADD` is the key for the addition operator. Operators can be replaced using the `replaceOperator(OperatorKey key,Operator op)` and removed using `removeOperator(OperatorKey key)`. Operators can be retrieved from the table by using `Operator getOperator(OperatorKey key)` To add a new operator a new key which implements `OperatorTable2.OperatorKey` must be defined and added to the table using one of

- `Operator addOperator(OperatorKey key, Operator op)`
- `public Operator addOperator(Operator op, Operator existingOp)`
- `public Operator insertOperator(Operator op, Operator existingOp)`
- `public Operator appendOperator(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.

    // Set up the keys
    public enum MyOperators implements OperatorKey {FACT,PERCENT}

    // Build the operator
    Operator factop = new Operator("FACT","!",
                           new Factorial(),
                           Operator.SUFFIX+Operator.UNARY+Operator.LEFT);
    Operator pcop = new Operator("PERCENT","%",
                               new Percent(),
                               Operator.SUFFIX+Operator.UNARY+Operator.LEFT);

    // Add operators with same precedence as the POSFIX operator
    table.addOperator(FACT, factop,  getOperator(POSTFIX));
    table.addOperator(PERCENT, pcop, getOperator(POSTFIX));

A simpler method just uses an abstract class for a key

    var table = jep.getOperatorTable2();
    Operator op = new Operator(...);
    table.addOperator(new OperatorKey(){},op);

or just

    jep.getOperatorTable2().addOperator(new OperatorKey(){},op);

Once the operators have been added, call `jep.reinitializeComponents()` to update the Jep instance with the new operators.

The old operator table OperatorTable is still available for compatibility. Both tables implement the OperatorTableI interface.

### Bindings and precedence for standard operators

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

    Operator UDivide "^-1":  Null function.
        unary, prefix, right binding, not in parser, precedence -1.
    Operator "LIST":  list of the arguments
        variable number of arguments, infix, right binding, not in parser,
        precedence -1.
    Operator "[]":  element of a vector, list or string
        variable number of arguments, infix, right binding, not in parser,
        precedence -1.
    Operator "POSTFIX":  Null function.
        unary, suffix, not in parser, precedence 0.
    Operator "^":  power
        binary, infix, right binding, precedence 1.
    Operator UMinus "-", "−":  unary minus
        unary, prefix, right binding, precedence 2.
    Operator UPlus "+":  identity function, identity(x) = x
        unary, prefix, right binding, precedence 2.
    Operator "PREFIX":  Null function.
        unary, prefix, not in parser, precedence 2.
    Operator "!":  logical not
        unary, prefix, right binding, precedence 2.
    Operator "*", "×":  multiplication
        binary, infix, left binding, associative, commutative, precedence 3.
    Operator "%":  modulus, mod(x,y) = x % y
        binary, infix, left binding, precedence 3.
    Operator ".":  dot product of two vectors
        binary, infix, left binding, precedence 3.
    Operator "^^":  cross product of two vectors
        binary, infix, left binding, precedence 3.
    Operator "/", "÷":  division
        binary, infix, left binding, precedence 3.
    Operator "-", "−":  subtraction
        binary, infix, left binding, precedence 4.
    Operator "+":  addition
        binary, infix, left binding, associative, commutative, precedence 4.
    Operator ">=":  greater than or equal to
        binary, infix, left binding, reflexive, transitive, precedence 5.
    Operator "<":  less than
        binary, infix, left binding, transitive, precedence 5.
    Operator "<=":  less than or equal to
        binary, infix, left binding, reflexive, transitive, precedence 5.
    Operator ">":  greater than
        binary, infix, left binding, transitive, precedence 5.
    Operator "!=":  not equal to
        binary, infix, left binding, symmetric, precedence 6.
    Operator "==":  equal to
        binary, infix, left binding, equivalence relation, precedence 6.
    Operator "&&":  logical and
        binary, infix, left binding, associative, commutative, precedence 7.
    Operator "||":  logical or
        binary, infix, left binding, associative, commutative, precedence 8.
    Operator "=":  assignment, x=y assigns the value of y to variable x
        binary, infix, right binding, precedence 9.

## Adding operators using the standard 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 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` and`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.

## Additional operator sets

The com.singularsys.jep.misc package contains two operators tables which contain additional operators: com.singularsys.jep.misc.bitwise.BitwiseOperatorTable and com.singularsys.jep.misc.javaops.JavaOperatorTable.

| Standard symbol | Bitwise OperatorTable | Java OperatorTable | Arguments
--- | --- | --- | --- | ---
Bitwise and | & |  |  | Integer
Bitwise or | | |  |  | Integer
Bitwise xor[1] | ^ |  |  | Integer
Bitwise complement | ~ |  |  | Integer
Leftshift | << |  |  | Integer
Signed rightshift | >> |  |  | Integer
Unsigned rightshift | >>> |  |  | Integer
Pre-increment/decrement | ++x, --x |  |  | Double variable
Post-increment/decrement | x++, x-- |  |  | Double variable
Conditional | ?: |  |  | Double
Assignment | +=, -=, *=, /=, %= |  |  | Double
Bitwise assignment | &=, |=, ^=, <<=, >>=, >>>= |  |  | Integer

Note 1: the bitwise xor operator has the same symbol as normally used for power. The constructors for the tables allow the symbol to be specified, the defaults are power (**) and xor (^). Bitwise operators and assignment convert their arguments to Integer and return arguments as `java.lang.Integer`. Pre and post increment/decrement operators require a variable as argument whose value will be treated as a Double.

The com.singularsys.jep.misc.nullwrapper.NullWrappedOperatorTable adds a single operator, NullSafeEquals, `<=>` which can compare null values.