File indexing completed on 2024-05-19 04:56:01

0001 /**
0002  * \file expressionparser.h
0003  * Simple parser for expressions.
0004  *
0005  * \b Project: Kid3
0006  * \author Urs Fleisch
0007  * \date 23 Jan 2008
0008  *
0009  * Copyright (C) 2008-2018  Urs Fleisch
0010  *
0011  * This file is part of Kid3.
0012  *
0013  * Kid3 is free software; you can redistribute it and/or modify
0014  * it under the terms of the GNU General Public License as published by
0015  * the Free Software Foundation; either version 2 of the License, or
0016  * (at your option) any later version.
0017  *
0018  * Kid3 is distributed in the hope that it will be useful,
0019  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0020  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0021  * GNU General Public License for more details.
0022  *
0023  * You should have received a copy of the GNU General Public License
0024  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
0025  */
0026 
0027 #pragma once
0028 
0029 #include <QString>
0030 #include <QStringList>
0031 
0032 /**
0033  * Simple parser for expressions with boolean not, and, or and
0034  * other binary operations.
0035  */
0036 class ExpressionParser {
0037 public:
0038   /**
0039    * Constructor.
0040    *
0041    * @param operators additional operators (besides not, and, or),
0042    *                  highest priority first
0043    */
0044   explicit ExpressionParser(QStringList operators);
0045 
0046   /**
0047    * Destructor.
0048    */
0049   ~ExpressionParser() = default;
0050 
0051   /**
0052    * Tokenize an expression in reverse polish notation.
0053    *
0054    * @param expr with strings, operators, not, and, or, (, ).
0055    */
0056   void tokenizeRpn(const QString& expr);
0057 
0058   /**
0059    * Clear the variable stack before restarting an evaluation.
0060    */
0061   void clearEvaluation();
0062 
0063   /**
0064    * Evaluate the RPN stack.
0065    * Boolean operations and, or, not are performed automatically. If another
0066    * operation has to be performed, the method stops and returns operator
0067    * and variables. The result can then be pushed onto the stack using
0068    * pushBool() and then the method can be called again.
0069    *
0070    * @param op the operator is returned here
0071    * @param var1 the first variable is returned here
0072    * @param var2 the second variable is returned here
0073    *
0074    * @return true if the RPN stack has more to evaluate,
0075    *         if false, the evaluation is finished.
0076    */
0077   bool evaluate(QString& op, QString& var1, QString& var2);
0078 
0079   /**
0080    * Push a boolean to the variable stack.
0081    * Can be used to push the result of the operation returned by
0082    * evaluate() back onto the variable stack.
0083    *
0084    * @param var boolean to  push
0085    */
0086   void pushBool(bool var);
0087 
0088   /**
0089    * Check if an error occurred.
0090    * @return true if an error occurred.
0091    */
0092   bool hasError() const { return m_error; }
0093 
0094   /**
0095    * Pop a boolean from the variable stack.
0096    * Can be used to get the result after evaluate() returns false and
0097    * no error occurred.
0098    *
0099    * @param var the boolean is returned here
0100    *
0101    * @return true if ok.
0102    */
0103   bool popBool(bool& var);
0104 
0105 private:
0106   /**
0107    * Compare operator priority.
0108    *
0109    * @return true if op1 has less priority than op2.
0110    */
0111   bool lessPriority(const QString& op1, const QString& op2) const;
0112 
0113   /**
0114    * Pop two booleans from the variable stack.
0115    *
0116    * @param var1 first boolean
0117    * @param var2 second boolean
0118    *
0119    * @return true if ok.
0120    */
0121   bool popTwoBools(bool& var1, bool& var2);
0122 
0123   QStringList m_rpnStack;
0124   QStringList m_varStack;
0125   const QStringList m_operators;
0126   QStringList::const_iterator m_rpnIterator;
0127   bool m_error;
0128 };