File indexing completed on 2024-06-16 05:12:09
0001 /*************************************************************************** 0002 * Copyright (C) 2016 by Renaud Guezennec * 0003 * https://rolisteam.org/contact * 0004 * * 0005 * rolisteam is free software; you can redistribute it and/or modify * 0006 * it under the terms of the GNU General Public License as published by * 0007 * the Free Software Foundation; either version 2 of the License, or * 0008 * (at your option) any later version. * 0009 * * 0010 * This program is distributed in the hope that it will be useful, * 0011 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 0012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 0013 * GNU General Public License for more details. * 0014 * * 0015 * You should have received a copy of the GNU General Public License * 0016 * along with this program; if not, write to the * 0017 * Free Software Foundation, Inc., * 0018 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * 0019 ***************************************************************************/ 0020 #include "charactersheet_formula/parsingtoolformula.h" 0021 #include "charactersheet_formula/nodes/operator.h" 0022 0023 #include "charactersheet_formula/nodes/parenthesesfnode.h" 0024 #include "charactersheet_formula/nodes/valuefnode.h" 0025 #include <QDebug> 0026 0027 namespace Formula 0028 { 0029 0030 ParsingToolFormula::ParsingToolFormula() 0031 { 0032 // ABS,MIN,MAX,IF,FLOOR,CEIL,AVG 0033 m_hashOp.insert({QStringLiteral("abs"), ABS}); 0034 m_hashOp.insert({QStringLiteral("min"), MIN}); 0035 m_hashOp.insert({QStringLiteral("max"), MAX}); 0036 m_hashOp.insert({QStringLiteral("concat"), CONCAT}); 0037 m_hashOp.insert({QStringLiteral("floor"), FLOOR}); 0038 m_hashOp.insert({QStringLiteral("ceil"), CEIL}); 0039 m_hashOp.insert({QStringLiteral("avg"), AVG}); 0040 0041 m_arithmeticOperation.insert({QStringLiteral("+"), ScalarOperatorFNode::PLUS}); 0042 m_arithmeticOperation.insert({QStringLiteral("-"), ScalarOperatorFNode::MINUS}); 0043 m_arithmeticOperation.insert({QStringLiteral("*"), ScalarOperatorFNode::MULTIPLICATION}); 0044 m_arithmeticOperation.insert({QStringLiteral("x"), ScalarOperatorFNode::MULTIPLICATION}); 0045 m_arithmeticOperation.insert({QStringLiteral("/"), ScalarOperatorFNode::DIVIDE}); 0046 m_arithmeticOperation.insert({QStringLiteral("รท"), ScalarOperatorFNode::DIVIDE}); 0047 } 0048 ParsingToolFormula::~ParsingToolFormula() {} 0049 0050 FormulaNode* ParsingToolFormula::getLatestNode(FormulaNode* node) 0051 { 0052 if(nullptr == node) 0053 return nullptr; 0054 FormulaNode* next= node; 0055 while(nullptr != next->next()) 0056 { 0057 next= next->next(); 0058 } 0059 return next; 0060 } 0061 0062 const QHash<QString, QString> ParsingToolFormula::getVariableHash() const 0063 { 0064 return m_variableHash; 0065 } 0066 0067 void ParsingToolFormula::setVariableHash(const QHash<QString, QString>& variableHash) 0068 { 0069 m_variableHash= variableHash; 0070 } 0071 bool ParsingToolFormula::readFormula(QString& str, FormulaNode*& previous) 0072 { 0073 if(str.startsWith('=')) 0074 { 0075 str= str.remove(0, 1); 0076 } 0077 FormulaNode* operandNode= nullptr; 0078 bool found= false; 0079 if(readParenthese(str, operandNode)) 0080 { 0081 previous= operandNode; 0082 found= true; 0083 } 0084 else if(readOperand(str, operandNode)) 0085 { 0086 previous= operandNode; 0087 found= true; 0088 } 0089 if(found) 0090 { 0091 operandNode= getLatestNode(operandNode); 0092 while(readScalarOperator(str, operandNode)) 0093 ; 0094 } 0095 0096 return found; 0097 } 0098 bool ParsingToolFormula::readParenthese(QString& str, FormulaNode*& previous) 0099 { 0100 if(str.startsWith("(")) 0101 { 0102 str= str.remove(0, 1); 0103 FormulaNode* internalNode= nullptr; 0104 if(readFormula(str, internalNode)) 0105 { 0106 ParenthesesFNode* node= new ParenthesesFNode(); 0107 node->setInternalNode(internalNode); 0108 previous= node; 0109 0110 if(str.startsWith(")")) 0111 { 0112 str= str.remove(0, 1); 0113 return true; 0114 } 0115 } 0116 } 0117 return false; 0118 } 0119 0120 bool ParsingToolFormula::readScalarOperator(QString& str, FormulaNode* previous) 0121 { 0122 ScalarOperatorFNode::ArithmeticOperator ope; 0123 auto it= std::find_if(m_arithmeticOperation.begin(), m_arithmeticOperation.end(), 0124 [str](const std::pair<QString, ScalarOperatorFNode::ArithmeticOperator>& pair) { 0125 return str.startsWith(pair.first); 0126 }); 0127 0128 if(it == m_arithmeticOperation.end()) 0129 return false; 0130 0131 ope= (*it).second; 0132 str= str.remove(0, (*it).first.size()); 0133 0134 ScalarOperatorFNode* node= new ScalarOperatorFNode(); 0135 node->setArithmeticOperator(ope); 0136 0137 FormulaNode* internal= nullptr; 0138 readFormula(str, internal); 0139 0140 node->setInternalNode(internal); 0141 0142 if(nullptr == internal) 0143 { 0144 delete node; 0145 return false; 0146 } 0147 if(node->getPriority() >= internal->getPriority()) 0148 { 0149 node->setNext(internal->next()); 0150 internal->setNext(nullptr); 0151 } 0152 previous->setNext(node); 0153 return true; 0154 } 0155 0156 bool ParsingToolFormula::readOperand(QString& str, FormulaNode*& previous) 0157 { 0158 if(readNumber(str, previous)) 0159 { 0160 return true; 0161 } 0162 else if(readFieldRef(str, previous)) 0163 { 0164 return true; 0165 } 0166 else if(readOperator(str, previous)) 0167 { 0168 return true; 0169 } 0170 else if(readStringValue(str, previous)) 0171 { 0172 return true; 0173 } 0174 return false; 0175 } 0176 bool ParsingToolFormula::readStringValue(QString& str, FormulaNode*& previous) 0177 { 0178 if(str.isEmpty()) 0179 return false; 0180 0181 QString strResult; 0182 if(str.startsWith("\"")) 0183 { 0184 int i= 0; 0185 str= str.remove(0, 1); 0186 while(i < str.length() 0187 && str[i] != '"') //&& (str[i].isLetterOrNumber() || str[i].isPunct() || str[i].isSpace()) 0188 { 0189 strResult+= str[i]; 0190 ++i; 0191 } 0192 0193 str= str.remove(0, strResult.size() + 1); 0194 ValueFNode* nodeV= new ValueFNode(); 0195 nodeV->setValue(strResult); 0196 previous= nodeV; 0197 return true; 0198 } 0199 0200 return false; 0201 } 0202 0203 bool ParsingToolFormula::readOperator(QString& str, FormulaNode*& previous) 0204 { 0205 auto it= std::find_if(m_hashOp.begin(), m_hashOp.end(), 0206 [str](const std::pair<QString, ParsingToolFormula::FormulaOperator>& pair) { 0207 return str.startsWith(pair.first); 0208 }); 0209 0210 if(it == m_hashOp.end()) 0211 return false; 0212 0213 QString key= it->first; 0214 str= str.remove(0, key.size()); 0215 OperatorFNode* node= new OperatorFNode(); 0216 previous= node; 0217 node->setOperator(it->second); 0218 FormulaNode* nextNode= nullptr; 0219 if(str.startsWith("(")) 0220 { 0221 str= str.remove(0, 1); 0222 while(readFormula(str, nextNode)) //&& !str.startsWith(")") 0223 { // reading parameter loop 0224 node->addParameter(nextNode); 0225 nextNode= nullptr; 0226 if(str.startsWith(",")) 0227 { 0228 str= str.remove(0, 1); 0229 } 0230 } 0231 if(str.startsWith(")")) 0232 { 0233 str= str.remove(0, 1); 0234 } 0235 } 0236 return true; 0237 } 0238 0239 bool ParsingToolFormula::readFieldRef(QString& str, FormulaNode*& previous) 0240 { 0241 if(str.isEmpty()) 0242 return false; 0243 if(str.startsWith("${")) 0244 { 0245 str= str.remove(0, 2); 0246 } 0247 QString key; 0248 int post= str.indexOf('}'); 0249 key= str.left(post); 0250 0251 if(m_variableHash.contains(key)) 0252 { 0253 QString value= m_variableHash.value(key); 0254 bool ok; 0255 qreal valueR= value.toDouble(&ok); 0256 if(ok) 0257 { 0258 str= str.remove(0, post + 1); 0259 ValueFNode* nodeV= new ValueFNode(); 0260 nodeV->setValue(valueR); 0261 previous= nodeV; 0262 return true; 0263 } 0264 } 0265 0266 return false; 0267 } 0268 0269 bool ParsingToolFormula::readNumber(QString& str, FormulaNode*& previous) 0270 { 0271 if(str.isEmpty()) 0272 return false; 0273 0274 QString number; 0275 int i= 0; 0276 while(i < str.length() && ((str[i].isNumber()) || (str[i] == '.') || ((i == 0) && (str[i] == '-')))) 0277 { 0278 number+= str[i]; 0279 ++i; 0280 } 0281 0282 bool ok; 0283 qreal r= number.toDouble(&ok); 0284 if(ok) 0285 { 0286 str= str.remove(0, number.size()); 0287 ValueFNode* nodeV= new ValueFNode(); 0288 nodeV->setValue(r); 0289 previous= nodeV; 0290 return true; 0291 } 0292 0293 return false; 0294 } 0295 } // namespace Formula