File indexing completed on 2024-04-14 04:00:04

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