/* * OpenClinica is distributed under the * GNU Lesser General Public License (GNU LGPL). * For details see: http://www.openclinica.org/license * * Copyright 2003-2008 Akaza Research */ package org.akaza.openclinica.logic.expressionTree; import java.util.HashMap; import org.akaza.openclinica.domain.rule.expression.ExpressionBeanObjectWrapper; import org.akaza.openclinica.domain.rule.expression.ExpressionObjectWrapper; import org.akaza.openclinica.exception.OpenClinicaSystemException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * @author Krikor Krumlian * */ public class OpenClinicaExpressionParser { protected final Logger logger = LoggerFactory.getLogger(getClass().getName()); TextIO textIO; ExpressionObjectWrapper expressionWrapper; private final String ERROR_MESSAGE_KEY = "OCRERR_0005"; private HashMap<String, String> testValues; private HashMap<String, String> responseTestValues; private ExpressionBeanObjectWrapper expressionBeanWrapper; public OpenClinicaExpressionParser(ExpressionBeanObjectWrapper expressionBeanWrapper) { textIO = new TextIO(); this.expressionBeanWrapper = expressionBeanWrapper; } public OpenClinicaExpressionParser() { textIO = new TextIO(); } public HashMap<String, String> getTestValues() { return testValues; } public void setTestValues(HashMap<String, String> testValues) { this.testValues = testValues; } public HashMap<String, String> getResponseTestValues() { if (responseTestValues == null) { responseTestValues = new HashMap<String, String>(); } return responseTestValues; } public void setResponseTestValues(HashMap<String, String> responseTestValues) { this.responseTestValues = responseTestValues; } public OpenClinicaExpressionParser(ExpressionObjectWrapper expressionWrapper) { textIO = new TextIO(); this.expressionWrapper = expressionWrapper; } public void parseExpression(String expression) throws OpenClinicaSystemException { getTextIO().fillBuffer(expression); getTextIO().skipBlanks(); ExpressionNode exp = expressionTree(); if (getTextIO().peek() != '\n') throw new OpenClinicaSystemException(ERROR_MESSAGE_KEY); exp.printStackCommands(); } public Object parseAndEvaluateExpression(String expression) throws OpenClinicaSystemException { getTextIO().fillBuffer(expression); getTextIO().skipBlanks(); ExpressionNode exp = expressionTree(); if (getTextIO().peek() != '\n') throw new OpenClinicaSystemException(ERROR_MESSAGE_KEY); return exp.value(); } public String parseAndTestEvaluateExpression(String expression) throws OpenClinicaSystemException { if(expression.length()>2040) throw new OpenClinicaSystemException("OCRERR_0052"); getTextIO().fillBuffer(expression); getTextIO().skipBlanks(); ExpressionNode exp = expressionTree(); if (getTextIO().peek() != '\n') throw new OpenClinicaSystemException(ERROR_MESSAGE_KEY); return exp.testValue(); } public HashMap<String, String> parseAndTestEvaluateExpression(String expression, HashMap<String, String> h) throws OpenClinicaSystemException { getTextIO().fillBuffer(expression); getTextIO().skipBlanks(); ExpressionNode exp = expressionTree(); if (getTextIO().peek() != '\n') throw new OpenClinicaSystemException(ERROR_MESSAGE_KEY); setTestValues(h); // HashMap<String, String> theTestValues = getTestValues(); HashMap<String, String> theTestValues = getResponseTestValues(); theTestValues.put("result", exp.testValue()); return theTestValues; } /** * Reads an expression from the current line of input and builds an expression tree that represents the expression. * * @return an ExpNode which is a pointer to the root node of the expression tree * @throws OpenClinicaSystemException * if a syntax error is found in the input */ private ExpressionNode expressionTree() throws OpenClinicaSystemException { try { textIO.skipBlanks(); boolean negative; // True if there is a leading minus sign. negative = false; if (textIO.peek() == '-') { textIO.getAnyChar(); negative = true; } ExpressionNode exp; // The expression tree for the expression. exp = termTree3(); // Start with the first term. if (negative) exp = new UnaryMinusNode(exp); textIO.skipBlanks(); while (textIO.peek() == 'o' && textIO.peek(3).matches("or ") || textIO.peek() == 'a' && textIO.peek(4).matches("and ")) { // Read the next term and combine it with the // previous terms into a bigger expression tree. // char op = textIO.getAnyChar(); String op = textIO.peek() == 'o' ? textIO.getAnyString(3) : textIO.getAnyString(4); logger.debug("Operator" + op); ExpressionNode nextTerm = termTree3(); exp = ExpressionNodeFactory.getExpNode(Operator.getByDescription(op), exp, nextTerm); textIO.skipBlanks(); } return exp; } catch (NullPointerException e) { throw new OpenClinicaSystemException(ERROR_MESSAGE_KEY); } catch (OpenClinicaSystemException e) { throw e; } } // end expressionTree() private ExpressionNode termTree3() throws OpenClinicaSystemException { textIO.skipBlanks(); ExpressionNode term; // The expression tree representing the term. term = termTree2(); textIO.skipBlanks(); while (textIO.peek() == 'e' && textIO.peek(3).matches("eq ") || textIO.peek() == 'n' && textIO.peek(3).matches("ne ") || textIO.peek() == 'c' && textIO.peek(3).matches("ct ") || textIO.peek() == 'g' && textIO.peek(3).matches("gt ") || textIO.peek() == 'g' && textIO.peek(4).matches("gte ") || textIO.peek() == 'l' && textIO.peek(3).matches("lt ") || textIO.peek() == 'l' && textIO.peek(4).matches("lte ")) { // Read the next term and combine it with the // previous terms into a bigger expression tree. // char op = textIO.getAnyChar(); String op = textIO.peek(4).matches("gte ") || textIO.peek(4).matches("lte ") ? textIO.getAnyString(4) : textIO.getAnyString(3); ExpressionNode nextTerm = termTree2(); term = ExpressionNodeFactory.getExpNode(Operator.getByDescription(String.valueOf(op)), term, nextTerm); // term = new BooleanOpNode(Operator.getByDescription(op), term, // nextTerm); textIO.skipBlanks(); } return term; } // end termValue() private ExpressionNode termTree2() throws OpenClinicaSystemException { textIO.skipBlanks(); ExpressionNode term; // The expression tree representing the term. term = termTree(); textIO.skipBlanks(); while (textIO.peek() == '+' || textIO.peek() == '-') { // Read the next term and combine it with the // previous terms into a bigger expression tree. char op = textIO.getAnyChar(); ExpressionNode nextTerm = termTree(); term = ExpressionNodeFactory.getExpNode(Operator.getByDescription(String.valueOf(op)), term, nextTerm); // term = new // BinOpNode(Operator.getByDescription(String.valueOf(op)), term, // nextTerm); textIO.skipBlanks(); } return term; } // end termValue() /** * Reads a term from the current line of input and builds an expression tree that represents the expression. * * @return an ExpNode which is a pointer to the root node of the expression tree * @throws OpenClinicaSystemException * if a syntax error is found in the input */ private ExpressionNode termTree() throws OpenClinicaSystemException { textIO.skipBlanks(); ExpressionNode term; // The expression tree representing the term. term = factorTree(); textIO.skipBlanks(); while (textIO.peek() == '*' || textIO.peek() == '/') { // Read the next factor, and combine it with the // previous factors into a bigger expression tree. char op = textIO.getAnyChar(); ExpressionNode nextFactor = factorTree(); term = ExpressionNodeFactory.getExpNode(Operator.getByDescription(String.valueOf(op)), term, nextFactor); // term = new // BinOpNode(Operator.getByDescription(String.valueOf(op)), term, // nextFactor); textIO.skipBlanks(); } return term; } // end termValue() /** * Reads a factor from the current line of input and builds an expression tree that represents the expression. * * @return an ExpNode which is a pointer to the root node of the expression tree * @throws OpenClinicaSystemException * if a syntax error is found in the input */ private ExpressionNode factorTree() throws OpenClinicaSystemException { textIO.skipBlanks(); char ch = textIO.peek(); logger.debug("TheChar is : " + ch); if (Character.isDigit(ch)) { String dateOrNum = textIO.getDate(); if (dateOrNum == null) { dateOrNum = String.valueOf(textIO.getDouble()); } logger.debug("TheNum is : " + dateOrNum); return new ConstantNode(dateOrNum); } else if (ch == '(') { // The factor is an expression in parentheses. // Return a tree representing that expression. textIO.getAnyChar(); // Read the "(" ExpressionNode exp = expressionTree(); textIO.skipBlanks(); if (textIO.peek() != ')') throw new OpenClinicaSystemException("OCRERR_0006"); textIO.getAnyChar(); // Read the ")" return exp; } else if (String.valueOf(ch).matches("\\w+")) { String k = textIO.getWord(); logger.debug("TheWord 1 is : " + k); if(null != expressionWrapper){ return new OpenClinicaVariableNode(k, expressionWrapper, this); }else{ return new OpenClinicaBeanVariableNode(k, expressionBeanWrapper, this); } }else if (String.valueOf(ch).matches("\"")) { String k = textIO.getDoubleQuoteWord(); logger.debug("TheWord 2 is : " + k); return new ConstantNode(k); } else if (ch == '\n') throw new OpenClinicaSystemException("OCRERR_0007"); else if (ch == ')') throw new OpenClinicaSystemException("OCRERR_0008"); else if (ch == '+' || ch == '-' || ch == '*' || ch == '/') throw new OpenClinicaSystemException("OCRERR_0009"); else throw new OpenClinicaSystemException("OCRERR_0010", new Object[] { ch }); } // end factorTree() /** * @return the textIO */ public TextIO getTextIO() { return textIO; } /** * @param textIO * the textIO to set */ public void setTextIO(TextIO textIO) { this.textIO = textIO; } /* * public static void main(String[] args) { SimpleParser4 smp4 = new SimpleParser4(); // textIO.putln("\n\nEnter an expression, or press return to * end."); // textIO.put("\n? "); smp4.getTextIO().fillBuffer(" ((2 +2 * 4+2 *2 gte 15) or false or false or 3+4 * 2 lt 10) and yellow eq \"yellow\" "); // * smp4.getTextIO().fillBuffer(" \"yellow\" eq yellow "); smp4.getTextIO().skipBlanks(); try { ExpNode exp = smp4.expressionTree(); * logger.info("\nValue 1 is " + exp.value()); logger.info("\nOrder of postfix evaluation is:\n"); exp.printStackCommands(); } catch * (OpenClinicaSystemException e) { logger.info("\n*** Error in input: " + e.getMessage()); logger.info("*** Discarding input: " + * smp4.getTextIO().getln()); } } // end main() */ }