Main Page | Class List | File List | Class Members | File Members

vm.cpp

Go to the documentation of this file.
00001 
00006 //
00007 // Date:      15 November   2005   
00008 //
00009 // Copyright (c) Sergey Satskiy 2003 - 2005
00010 //               <sergesatsky@yahoo.com>
00011 //
00012 // Permission to copy, use, modify, sell and distribute this software 
00013 // is granted provided this copyright notice appears in all copies. 
00014 // This software is provided "as is" without express or implied
00015 // warranty, and with no claim as to its suitability for any purpose.
00016 //
00017 
00018 
00019 #include <math.h>
00020 
00021 
00022 #include <iostream>
00023 #include <string>
00024 #include <vector>
00025 #include <stdexcept>
00026 using namespace std;
00027 
00028 #include <boost/algorithm/string/trim.hpp>
00029 using namespace boost;
00030 using namespace boost::algorithm;
00031 
00032 
00033 
00034 
00036 class SVMException : public std::exception
00037 {
00038     private:
00039         const std::string      Message;
00040 
00041     public:
00045         SVMException( const std::string &  Msg ) : Message( Msg ) 
00046         {}
00047 
00051         SVMException( const char *         Msg ) : Message( Msg ) 
00052         {}
00053 
00057         virtual const char * what( void ) const throw() 
00058         { return Message.c_str(); }
00059 
00061         virtual ~SVMException() throw () {}
00062 
00063     private:
00064         SVMException();
00065 };
00066 
00067 
00068 
00069 
00071 class SCalculator
00072 {
00073     public:
00077         SCalculator( const vector< string > &  code ) :
00078             Code( code )
00079         {
00080                 // The stack size cannot be larger than the code size
00081             Stack.reserve( Code.size() );
00082         }
00083         
00087         double Calculate( const double &  Value ) 
00088         {
00089                 // Clear the stack for reuse
00090             Stack.clear();
00091             
00092                 // Walk the whole code
00093             for ( vector< string >::const_iterator  k( Code.begin() );
00094                   k != Code.end(); ++k )
00095             {
00096                 if ( *k == "ADD" )
00097                 {
00098                     double      Temp( Stack.back() );
00099                     Stack.pop_back();
00100                     Stack[ Stack.size() - 1 ] = Stack.back() + Temp;
00101                     continue;
00102                 }
00103                 if ( *k == "SUB" )
00104                 {
00105                     double      Temp( Stack.back() );
00106                     Stack.pop_back();
00107                     Stack[ Stack.size() - 1 ] = Stack.back() - Temp;
00108                     continue;
00109                 }
00110                 if ( *k == "DIV" )
00111                 {
00112                     double      Temp( Stack.back() );
00113                     Stack.pop_back();
00114                     Stack[ Stack.size() - 1 ] = Stack.back() / Temp;
00115                     continue;
00116                 }
00117                 if ( *k == "MULT" )
00118                 {
00119                     double      Temp( Stack.back() );
00120                     Stack.pop_back();
00121                     Stack[ Stack.size() - 1 ] = Stack.back() * Temp;
00122                     continue;
00123                 }
00124                 if ( *k == "NEGATE" )
00125                 {
00126                     Stack[ Stack.size() - 1 ] = - Stack.back();
00127                     continue;
00128                 }
00129                 if ( *k == "VALUE" )
00130                 {
00131                     Stack.push_back( Value );
00132                     continue;
00133                 }
00134                 if ( *k == "SIN" )
00135                 {
00136                     Stack[ Stack.size() - 1 ] = sin( Stack.back() );
00137                     continue;
00138                 }
00139                 if ( *k == "COS" )
00140                 {
00141                     Stack[ Stack.size() - 1 ] = cos( Stack.back() );
00142                     continue;
00143                 }
00144                 if ( (*k).compare( 0, 4, "PUSH" ) == 0 ) 
00145                 { 
00146                     Stack.push_back( atof( (*k).c_str() + sizeof( "PUSH" ) ) );
00147                     continue;
00148                 }
00149 
00150                 throw SVMException( "Unexpected virtual machine command '" + 
00151                                     *k + "'" );
00152             }
00153 
00154             if ( Stack.size() != 1 )
00155             {
00156                 throw SVMException( "Unexpected size of stack at the end "
00157                                     "of calculation. " );
00158             }
00159             
00160             return Stack.back();
00161         }
00162 
00163     private:
00164         vector< string >    Code;       // Code storage
00165         vector< double >    Stack;      // Working space - stack of doubles
00166 };
00167 
00168 
00169 
00170 
00171 
00172     // The VM takes a single argument: a value of the argument
00173 int  main( int  argc, char **  argv )
00174 {
00175 
00176         // Check the command line arguments first
00177     if ( argc >= 3 )
00178     {
00179             // Unexpected arguments
00180         cerr << "Unexpected arguments. Type " << argv[ 0 ]
00181              << " --help for usage." << endl;
00182         return 1;
00183     }
00184 
00185 
00186     
00187     if ( ( argc == 2 && string( argv[ 1 ] ) == "-h" )     ||
00188          ( argc == 2 && string( argv[ 1 ] ) == "--help" )    )
00189     {
00190         cout << "Usage: " << argv[ 0 ] << " <double value | -h | --help>" << endl;
00191         return 0;
00192     }
00193 
00194 
00195 
00196     double              Value( 0.0 );   // Default is 0.0
00197     if ( argc == 2 )
00198     {
00199         Value = atof( argv[ 1 ] );      // Input value
00200     }
00201 
00202     
00203         // Code storage
00204     vector< string >    Code;
00205     
00206     
00207         // Input the VM code into the vector
00208     for ( ; ; ) 
00209     {
00210         char        Buffer[ 256 ];      // Single line buffer
00211 
00212         cin.getline( Buffer, sizeof( Buffer ) );
00213 
00214         if ( cin.eof() )    break;
00215         if ( cin.fail() )
00216         {
00217             cerr << "Wrong input stream" << endl;
00218             return 2;
00219         }
00220 
00221         string      Line( Buffer );     // Temporary object - to make trim
00222 
00223         trim( Line );
00224         Code.push_back( Line );
00225     }
00226     
00227 
00228     try
00229     {
00230             // Instance of a calculator
00231             // Could be used many times in the real world application
00232         SCalculator     Calculator( Code );
00233         
00234             // Perform the calculation and print the result
00235         cout << Calculator.Calculate( Value ) << endl;
00236     }
00237     catch ( exception &  Exception )
00238     {
00239         cerr << Exception.what() << endl;
00240         return 3;
00241     }
00242     catch ( ... )
00243     {
00244         cerr << "Unknown exception." << endl;
00245         return 3;
00246     }
00247 
00248     return 0;
00249 }
00250 

Generated on Sun Nov 20 21:09:13 2005 for boost:spirit and virtual machines by  doxygen 1.4.4