All Downloads are FREE. Search and download functionalities are using the official Maven repository.

info.bliki.wiki.template.expr.Parser Maven / Gradle / Ivy

The newest version!
package info.bliki.wiki.template.expr;

import info.bliki.wiki.template.expr.ast.ASTNode;
import info.bliki.wiki.template.expr.ast.IParserFactory;
import info.bliki.wiki.template.expr.ast.NumberNode;
import info.bliki.wiki.template.expr.operator.ASTNodeFactory;
import info.bliki.wiki.template.expr.operator.InfixOperator;
import info.bliki.wiki.template.expr.operator.Operator;
import info.bliki.wiki.template.expr.operator.PostfixOperator;
import info.bliki.wiki.template.expr.operator.PrefixOperator;

/**
 * Create an expression of the ASTNode class-hierarchy from a math
 * formulas string representation.
 *
 * See Operator
 * -precedence parser for the idea, how to parse the operators depending on
 * their precedence.
 */
public class Parser extends Scanner {
    /**
     * Use '('...')' as brackets for arguments
     */
    boolean fRelaxedSyntax;

    public Parser() {
        this(ASTNodeFactory.MMA_STYLE_FACTORY, false);
    }

    public Parser(final boolean relaxedSyntax) throws SyntaxError {
        this(ASTNodeFactory.MMA_STYLE_FACTORY, relaxedSyntax);
    }

    public Parser(IParserFactory factory, final boolean relaxedSyntax) throws SyntaxError {
        super();
        fRelaxedSyntax = relaxedSyntax;
        fFactory = factory;
    }

    public void setFactory(final IParserFactory factory) {
        this.fFactory = factory;
    }

    public IParserFactory getFactory() {
        return fFactory;
    }

    /**
     * Determine the current PrefixOperator
     *
     * @return null if no prefix operator could be determined
     */
    private PrefixOperator determinePrefixOperator() {
        Operator oper = null;
        for (int i = 0; i < fOperList.size(); i++) {
            oper = (Operator) fOperList.get(i);
            if (oper instanceof PrefixOperator) {
                return (PrefixOperator) oper;
            }
        }
        return null;
    }

    /**
     * Determine the current PostfixOperator
     *
     * @return null if no postfix operator could be determined
     */
    private PostfixOperator determinePostfixOperator() {
        Operator oper = null;
        for (int i = 0; i < fOperList.size(); i++) {
            oper = (Operator) fOperList.get(i);
            if (oper instanceof PostfixOperator) {
                return (PostfixOperator) oper;
            }
        }
        return null;
    }

    /**
     * Determine the current BinaryOperator
     *
     * @return null if no binary operator could be determined
     */
    private InfixOperator determineBinaryOperator() {
        Operator oper = null;
        for (int i = 0; i < fOperList.size(); i++) {
            oper = (Operator) fOperList.get(i);
            if (oper instanceof InfixOperator) {
                return (InfixOperator) oper;
            }
        }
        return null;
    }

    private ASTNode parsePrimary() {
        if (fToken == TT_OPERATOR) {
            final Operator oper = determinePrefixOperator();

            if (oper instanceof PrefixOperator) {
                getNextToken();
                final ASTNode temp = parseLookaheadOperator(oper.getPrecedence());
                if (oper.getFunctionName().equals("PreMinus")) {
                    // special cases for negative numbers
                    if (temp instanceof NumberNode) {
                        ((NumberNode) temp).toggleSign();
                        return temp;
                    }
                }
                return ((PrefixOperator) oper).createFunction(fFactory, temp);
            }
            throwSyntaxError("Operator: " + fOperatorString + " is no prefix operator.");

        }
        return getFactor();
    }

    private ASTNode parseLookaheadOperator(final int min_precedence) {
        ASTNode rhs = parsePrimary();
        Operator operLookahead;
        InfixOperator binOper;
        while (true) {
            final int lookahead = fToken;
            if (lookahead != TT_OPERATOR) {
                break;
            }
            operLookahead = determineBinaryOperator();
            if (operLookahead instanceof InfixOperator) {
                binOper = (InfixOperator) operLookahead;
                if (binOper.getPrecedence() > min_precedence) {
                    rhs = parseOperators(rhs, operLookahead.getPrecedence());
                    continue;
                } else if ((binOper.getPrecedence() == min_precedence) && (binOper.getGrouping() == InfixOperator.RIGHT_ASSOCIATIVE)) {
                    rhs = parseOperators(rhs, operLookahead.getPrecedence());
                    continue;
                }
            } else {
                operLookahead = determinePostfixOperator();

                if (operLookahead instanceof PostfixOperator) {
                    if (operLookahead.getPrecedence() > min_precedence) {
                        getNextToken();
                        rhs = ((PostfixOperator) operLookahead).createFunction(fFactory, rhs);
                        continue;
                    }
                }
            }
            break;
        }
        return rhs;
    }

    /**
     * See Operator
     * -precedence parser for the idea, how to parse the operators depending
     * on their precedence.
     *
     * @param lhs
     *          the already parsed left-hand-side of the operator
     * @param min_precedence
     * @return
     */
    private ASTNode parseOperators(ASTNode lhs, final int min_precedence) {
        ASTNode rhs = null;
        Operator oper;
        while (true) {
            if (fToken != TT_OPERATOR) {
                break;
            }
            oper = determineBinaryOperator();

            if (oper instanceof InfixOperator) {
                if (oper.getPrecedence() >= min_precedence) {
                    getNextToken();
                    rhs = parseLookaheadOperator(oper.getPrecedence());
                    lhs = ((InfixOperator) oper).createFunction(fFactory, lhs, rhs);
                    continue;
                }
            } else {
                oper = determinePostfixOperator();

                if (oper instanceof PostfixOperator) {
                    getNextToken();
                    lhs = ((PostfixOperator) oper).createFunction(fFactory, lhs);
                    continue;
                }
                throwSyntaxError("Operator: " + fOperatorString + " is no infix or postfix operator.");
            }
            break;
        }
        return lhs;
    }

    /**
     * Parse the given expression String into an ASTNode.
     *
     * @param expression
     *          a formula string which should be parsed.
     * @return the parsed ASTNode representation of the given formula string
     * @throws SyntaxError
     */
    public ASTNode parse(final String expression) throws SyntaxError {
        initialize(expression);
        final ASTNode temp = parseOperators(parsePrimary(), 0);
        if (fToken != TT_EOF) {
            if (fToken == TT_PRECEDENCE_CLOSE) {
                throwSyntaxError("Too many closing ')'; End-of-file not reached.");
            }

            if (fOperatorString == "E") {
                fCurrentPosition--;
            }
            throwSyntaxError("End-of-file not reached.");
        }

        return temp;
    }

    /**
     * Method Declaration.
     *
     * @return
     * @see
     */
    private ASTNode getNumber(final boolean negative) throws SyntaxError {
        ASTNode temp = null;
        final Object[] result = getNumberString();
        String number = (String) result[0];
        final int numFormat = ((Integer) result[1]).intValue();
        try {
            if (negative) {
                number = '-' + number;
            }
            if (numFormat < 0) {
                temp = fFactory.createDouble(number);
            } else {
                temp = fFactory.createInteger(number, numFormat);
            }
        } catch (final Throwable e) {
            throwSyntaxError("Number format error: " + number, number.length());
        }
        getNextToken();
        return temp;
    }

    private ASTNode getFactor() throws SyntaxError {
        ASTNode temp;

        if (fToken == TT_CONSTANT) {
            temp = fFactory.createSymbol(fOperatorString);
            getNextToken();
            return temp;
        }
        if (fToken == TT_DIGIT) {
            return getNumber(false);
        }
        if (fToken == TT_PRECEDENCE_OPEN) {
            getNextToken();

            temp = parseOperators(parsePrimary(), 0);

            if (fToken != TT_PRECEDENCE_CLOSE) {
                throwSyntaxError("\')\' expected.");
            }

            getNextToken();

            return temp;
        }

        switch (fToken) {

        case TT_PRECEDENCE_CLOSE:
            throwSyntaxError("Too much open ) in factor.");
            break;
        }

        throwSyntaxError("Error in factor at character: '" + fCurrentChar + "' (" + fToken + ")");
        return null;
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy