File indexing completed on 2025-01-12 06:47:23
0001 // arith-exp.cpp - class to compile and evaluate logical/arithmetical expressions 0002 // 0003 // Authors: 0004 /* 0005 Copyright 2005-2011 Tomas Mecir <kmuddy@kmuddy.com> 0006 Copyright 2005 Alex Bache <alexbache@ntlworld.com> 0007 0008 This program is free software; you can redistribute it and/or 0009 modify it under the terms of the GNU General Public License as 0010 published by the Free Software Foundation; either version 2 of 0011 the License, or (at your option) any later version. 0012 0013 This program is distributed in the hope that it will be useful, 0014 but WITHOUT ANY WARRANTY; without even the implied warranty of 0015 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 0016 GNU General Public License for more details. 0017 0018 You should have received a copy of the GNU General Public License 0019 along with this program. If not, see <http://www.gnu.org/licenses/>. 0020 */ 0021 0022 #include <stack> 0023 0024 #include "arith-exp.h" 0025 0026 using namespace std; 0027 0028 0029 //*************************************************************** 0030 // Flex/Bison function prototypes 0031 //*************************************************************** 0032 0033 bool compile(const char *source_code, 0034 list<instruction> *compiled_code); 0035 0036 0037 //*************************************************************** 0038 // Destructor for arith_exp_server class 0039 //*************************************************************** 0040 0041 arith_exp_server::~arith_exp_server() 0042 { 0043 // Empty - keeps compiler quiet 0044 } // arith_exp_server::~arith_exp_server 0045 0046 0047 //*************************************************************** 0048 // Destructor for arith_exp class 0049 //*************************************************************** 0050 0051 arith_exp::~arith_exp() 0052 { 0053 clear_compiled(); 0054 0055 } // arith_exp::~arith_exp 0056 0057 0058 //*************************************************************** 0059 // Function to compile an expression 0060 // Returns true if successful 0061 //*************************************************************** 0062 0063 bool arith_exp::compile (const QString &expression) 0064 { 0065 clear_compiled(); 0066 0067 return ::compile(expression.toLocal8Bit().data(), 0068 &compiled_code); 0069 0070 } // arith_exp::compile 0071 0072 0073 //*************************************************************** 0074 // Function to return result of executing compiled expression 0075 //*************************************************************** 0076 0077 cValue arith_exp::evaluate(arith_exp_server *resolver) 0078 { 0079 cValue result; 0080 cValue data; 0081 0082 typedef list<instruction>::const_iterator iterator; 0083 0084 cValue arg; 0085 stack<cValue> istack; 0086 0087 iterator position = compiled_code.begin(); 0088 iterator end = compiled_code.end(); 0089 0090 while (position != end) 0091 { 0092 switch (position->instr) 0093 { 0094 case instruction::push_value: 0095 istack.push (position->arg); 0096 break; 0097 0098 case instruction::push_variable: 0099 istack.push (resolver->get(position->arg.asString())); 0100 break; 0101 0102 case instruction::and_op: 0103 data = istack.top(); 0104 istack.pop(); 0105 result = istack.top(); 0106 istack.pop(); 0107 arg = cValue (result.asInteger() && data.asInteger()); 0108 istack.push (arg); 0109 break; 0110 0111 case instruction::or_op: 0112 data = istack.top(); 0113 istack.pop(); 0114 result = istack.top(); 0115 istack.pop(); 0116 arg = cValue (result.asInteger() || data.asInteger()); 0117 istack.push (arg); 0118 break; 0119 0120 case instruction::not_op: 0121 result = istack.top(); 0122 istack.pop(); 0123 arg = cValue (!result.asInteger()); 0124 istack.push (arg); 0125 break; 0126 0127 case instruction::greater_than: 0128 data = istack.top(); 0129 istack.pop(); 0130 result = istack.top(); 0131 istack.pop(); 0132 if (result.isString() && data.isString()) // string comparison 0133 arg = cValue (result.asString() > data.asString()); 0134 else 0135 arg = cValue (result.asDouble() > data.asDouble()); 0136 istack.push (arg); 0137 break; 0138 0139 case instruction::greater_or_equal: 0140 data = istack.top(); 0141 istack.pop(); 0142 result = istack.top(); 0143 istack.pop(); 0144 if (result.isString() && data.isString()) // string comparison 0145 arg = cValue (result.asString() >= data.asString()); 0146 else 0147 arg = cValue (result.asDouble() >= data.asDouble()); 0148 istack.push (arg); 0149 break; 0150 0151 case instruction::less_than: 0152 data = istack.top(); 0153 istack.pop(); 0154 result = istack.top(); 0155 istack.pop(); 0156 if (result.isString() && data.isString()) // string comparison 0157 arg = cValue (result.asString() < data.asString()); 0158 else 0159 arg = cValue (result.asDouble() < data.asDouble()); 0160 istack.push (arg); 0161 break; 0162 0163 case instruction::less_or_equal: 0164 data = istack.top(); 0165 istack.pop(); 0166 result = istack.top(); 0167 istack.pop(); 0168 if (result.isString() && data.isString()) // string comparison 0169 arg = cValue (result.asString() <= data.asString()); 0170 else 0171 arg = cValue (result.asDouble() <= data.asDouble()); 0172 istack.push (arg); 0173 break; 0174 0175 case instruction::equals: 0176 data = istack.top(); 0177 istack.pop(); 0178 result = istack.top(); 0179 istack.pop(); 0180 if (result.isString() && data.isString()) // string comparison 0181 arg = cValue (result.asString() == data.asString()); 0182 else 0183 arg = cValue (result.asDouble() == data.asDouble()); 0184 istack.push (arg); 0185 break; 0186 0187 case instruction::not_equal: 0188 data = istack.top(); 0189 istack.pop(); 0190 result = istack.top(); 0191 istack.pop(); 0192 if (result.isString() && data.isString()) // string comparison 0193 arg = cValue (result.asString() != data.asString()); 0194 else 0195 arg = cValue (result.asDouble() != data.asDouble()); 0196 istack.push (arg); 0197 break; 0198 0199 case instruction::add: 0200 data = istack.top(); 0201 istack.pop(); 0202 result = istack.top(); 0203 istack.pop(); 0204 arg = cValue (result.asDouble() + data.asDouble()); 0205 istack.push (arg); 0206 break; 0207 0208 case instruction::sub: 0209 data = istack.top(); 0210 istack.pop(); 0211 result = istack.top(); 0212 istack.pop(); 0213 arg = cValue (result.asDouble() - data.asDouble()); 0214 istack.push (arg); 0215 break; 0216 0217 case instruction::mult: 0218 data = istack.top(); 0219 istack.pop(); 0220 result = istack.top(); 0221 istack.pop(); 0222 arg = cValue (result.asDouble() * data.asDouble()); 0223 istack.push (arg); 0224 break; 0225 0226 case instruction::div: 0227 data = istack.top(); 0228 istack.pop(); 0229 result = istack.top(); 0230 istack.pop(); 0231 if (data.asDouble() != 0) 0232 arg = cValue (result.asDouble() / data.asDouble()); 0233 else 0234 arg = cValue (0); 0235 istack.push (arg); 0236 break; 0237 0238 case instruction::unary_minus: 0239 result = istack.top(); 0240 istack.pop(); 0241 arg = cValue (-result.asDouble()); 0242 istack.push (arg); 0243 break; 0244 0245 case instruction::cast_to_int: 0246 data = istack.top(); 0247 istack.pop(); 0248 arg = cValue (data.asInteger()); 0249 istack.push (arg); 0250 break; 0251 0252 case instruction::cast_to_double: 0253 data = istack.top(); 0254 istack.pop(); 0255 arg = cValue (data.asDouble()); 0256 istack.push (arg); 0257 break; 0258 0259 case instruction::cast_to_string: 0260 data = istack.top(); 0261 istack.pop(); 0262 arg = cValue (data.asString()); 0263 istack.push (arg); 0264 break; 0265 0266 case instruction::string_concat: 0267 data = istack.top(); 0268 istack.pop(); 0269 result = istack.top(); 0270 istack.pop(); 0271 arg = cValue (result.asString() + data.asString()); 0272 istack.push (arg); 0273 break; 0274 0275 case instruction::function_call: { 0276 list<cValue> arguments; 0277 0278 while (!(istack.top().isMarker())) 0279 { 0280 arguments.push_front (istack.top()); 0281 istack.pop(); 0282 0283 } // endwhile more function arguments to process 0284 0285 istack.pop(); 0286 0287 arg = resolver->function_call (position->arg.asString(), arguments); 0288 istack.push (arg); 0289 break; 0290 } 0291 0292 case instruction::push_func_arg_marker: 0293 arg.setAsMarker (); 0294 istack.push (arg); 0295 break; 0296 0297 default: 0298 break; 0299 0300 } // endswitch work out which operation to perform 0301 0302 ++position; 0303 } // endwhile more code to execute 0304 0305 result = istack.top(); 0306 istack.pop(); 0307 return result; 0308 0309 } // arith_exp::evaluate 0310 0311 0312 0313 //*************************************************************** 0314 // Function to free resources used to store compiled code 0315 //*************************************************************** 0316 0317 void arith_exp::clear_compiled() 0318 { 0319 compiled_code.clear(); 0320 } // arith_exp::clear_compiled 0321 0322