RCSNUSP/C++

From Rosetta Code

This is a simple C++ implementation of Core and Modular SNUSP, Bloated will (maybe) come in the future.

To execute the SNUSP program just start the interpreter with its file name as parameter, like so: interpreter name SNUSP program.

It has a simple Log future, to use it type: interpreter name /L SNUSP program.

Input and output are thru Console.

C++

<lang cpp>

  1. include <iostream>
  2. include <sstream>
  3. include <fstream>
  4. include <vector>
  5. include <iomanip>
  1. define msg0 "| *** end of code *** |"
  2. define msg1 "| *** stack is empty *** |"
  3. define msg2 "| *?* step out *?* |"
  4. define msg3 "| *!* step out *!* |"
  5. define msg4 "| *** memory blows up *** |"

typedef unsigned char u8;

enum direction {

   UP, DOWN, LEFT, RIGHT

};

class stackFrame { public:

   stackFrame() { }
   stackFrame( int ipc, int ipl, direction dir) :
   IPC( ipc ), IPL( ipl ), DIR( dir ) { }
   int IPC, IPL;
   direction DIR;

} ;

class SNUSP { public:

   SNUSP() : IPC( 0 ), IPL( 0 ), MPT( 0 ), DIR( RIGHT ) { 
       memory.push_back( 0 ); 
   }
   ~SNUSP() { 
       memory.clear();
       code.clear();
   }
   void run( std::string filename, bool lg ) {
       logging = lg;
       if( logging ) {
           std::ofstream o( "log.txt", std::ios_base::trunc );
           strm << "+------+-------+-------+-------+-------+-------+\n| INST |  IPC  |  IPL  |  MPT  |  DIR  |  MEM  |";
           log( strm.str() );
       }
       if( !openFile( filename ) ) {
           std::cout << "Cannot open file '" << filename << "'\n";
           return;
       }
       while( execute( code[IPL][IPC] ) );
       std::cout << "\n\n" << memory[MPT];
   }

private:

   bool execute( u8 u ) {
       stackFrame sf;
       switch( u ) {
           case '<':
               if( --MPT < 0 ) {
                   if( logging ) log( msg4 );
                   return false;
               }
           break;
           case '>':
               if( ++MPT >= static_cast<int>( memory.size() ) ) { memory.push_back( 0 ); }
           break;
           case '+':
               memory[MPT]++;
           break;
           case '-':
               memory[MPT]--;
           break;
           case ',':
               std::cin >> memory[MPT];
           break;
           case '.':
               std::cout << static_cast<u8>( memory[MPT] );
           break;
           case '!':
               if( step() ) {
                   if( logging ) log( msg3 );
                   return false;
               }
           break;
           case '?':
               if( !memory[MPT] ) {
                   if( step() ) {
                       if( logging ) log( msg2 );
                       return false;
                   }
               }
           break;
           case '@':
               stack.push_back( stackFrame( IPC + ( DIR == RIGHT ? 1 : DIR == LEFT ? -1 : 0 ), 
                                            IPL + ( DIR == DOWN  ? 1 : DIR == UP   ? -1 : 0 ), DIR ) );
           break;
           case '#':
               if( !stack.size() ) {
                   if( logging ) log( msg1);
                   return false;
               }
               sf = stack.back();
               stack.pop_back();
               IPC = sf.IPC; IPL = sf.IPL; DIR = sf.DIR;
           break;
           case '/':
               DIR = DIR == RIGHT ? UP : DIR == LEFT ? DOWN : DIR == DOWN ? LEFT : RIGHT;
           break;
           case '\\':
               DIR = DIR == RIGHT ? DOWN : DIR == LEFT ? UP : DIR == DOWN ? RIGHT : LEFT;
           break;
       }
       if( logging ) {
           strm << "|" << std::setw( 5 ) << u  << " |" << std::setw( 6 ) << IPC << " |" << std::setw( 6 ) 
           << IPL << " |" << std::setw( 6 ) << MPT << " |" << std::setw( 6 ) << DIR << " |" << std::setw( 6 )           << memory[MPT] << " |";
           log( strm.str() );
       }
       if( step() ) {
           if( logging ) log( msg0 );
           return false;
       }
       return true;
   }
   bool step() {
       IPC += DIR == RIGHT ? 1 : DIR == LEFT ? -1 : 0;
       IPL += DIR == DOWN  ? 1 : DIR == UP   ? -1 : 0;
       return ( IPL >= static_cast<int>( code.size() ) || IPL < 0 || 
                IPC >= static_cast<int>( code[IPL].length() ) || IPC < 0 );
   }
   bool openFile( std::string filename ) {
       std::ifstream in;
       in.open( filename.c_str() );
       if( !in.good() ) {
           return false;
       }
       std::string line;
       size_t max_len = 0, len;
       while( std::getline( in, line ) ) {
           len = line.length();
           if( max_len < len ) max_len = len;
           code.push_back( line );
           if( !IPC && !IPL ) {
               std::size_t i = static_cast<int>( line.find( '$' ) );
               if( i < line.npos ) {
                   IPL = code.size() - 1;
                   IPC = i;
               }
           }
       }
       in.close();
       for( std::vector<std::string>::iterator i = code.begin(); i != code.end(); i++ ) {
           if( ( *i ).length() < max_len ) ( *i ).insert( ( *i ).end(), max_len - ( *i ).length(), ' ' );
       }
       return true;
   }
   void log( std::string msg )
   {
       std::ofstream logDegug( "log.txt", std::ios_base::out | std::ios_base::app );
       logDegug << msg << "\n+------+-------+-------+-------+-------+-------+" << std::endl;
       strm.str( "" );
   }
   std::vector<std::string>            code;
   std::vector<stackFrame>             stack;
   std::vector<int>                    memory;
   std::stringstream                   strm;
   int                                 IPC, IPL, MPT;
   direction                           DIR;
   bool                                logging;

};

int main( int argc, char* argv[] ) {

   if( argc < 2 ) {
       std::cout << "\nDoh!!!\n\nUsage:\t[/L] Filename\n\n\t/L\tLog each command to a log file";
   } else {
       SNUSP s;
       s.run( argv[argc == 3 ? 2 : 1], ( argv[1][0] == '/' && toupper( argv[1][1] ) == 'L' ) );
   }
   std::cout << "\n\n";
   return 0;

} </lang>