2024-12-26 13:25:10 +11:00
# include <iostream>
2024-12-26 20:46:52 +11:00
# include <cstdlib>
2024-12-26 15:11:28 +11:00
# include <fstream>
2024-12-26 13:25:10 +11:00
# include <string>
2024-12-26 20:46:52 +11:00
# include <cstring>
2024-12-27 20:55:19 +11:00
# include <map>
# include <variant>
# include <vector>
2024-12-26 13:25:10 +11:00
using namespace std ;
2024-12-27 20:55:19 +11:00
enum class VarType {
INTEGER ,
DECIMAL ,
STRING ,
UNKNOWN
} ;
2024-12-26 13:25:10 +11:00
2024-12-27 20:55:19 +11:00
struct Variable {
VarType type ;
variant < int , double , string > value ;
Variable ( ) : type ( VarType : : UNKNOWN ) { }
Variable ( VarType t , const variant < int , double , string > & v ) : type ( t ) , value ( v ) { }
string toString ( ) const {
switch ( type ) {
case VarType : : INTEGER :
return to_string ( get < int > ( value ) ) ;
case VarType : : DECIMAL :
return to_string ( get < double > ( value ) ) ;
case VarType : : STRING :
return get < string > ( value ) ;
default :
return " unknown " ;
2024-12-26 15:11:28 +11:00
}
2024-12-26 13:25:10 +11:00
}
2024-12-27 20:55:19 +11:00
} ;
2024-12-26 13:25:10 +11:00
2024-12-27 20:55:19 +11:00
class Interpreter {
private :
map < string , Variable > variables ;
bool isVerbose = false ;
const vector < string > builtInFunctions = {
" exit " , " log " , " type " , " run " , " verbose " , " str " , " dec " , " int "
} ;
2024-12-26 20:46:52 +11:00
2024-12-27 20:55:19 +11:00
const vector < string > operators = {
" + " , " - " , " * " , " / "
} ;
2024-12-26 20:46:52 +11:00
2024-12-27 20:55:19 +11:00
const vector < string > incrementors = {
" ++ " , " -- "
} ;
2024-12-26 20:46:52 +11:00
2024-12-27 20:55:19 +11:00
const vector < string > modifiers = {
" += " , " -= " , " *= " , " /= "
} ;
2024-12-26 20:46:52 +11:00
2024-12-27 20:55:19 +11:00
const vector < string > comparitors = {
" == " , " > " , " >= " , " =< " , " != " , " !< " , " !> " , " !=< " , " !>= "
} ;
2024-12-26 20:46:52 +11:00
2024-12-27 20:55:19 +11:00
bool checkForDec ( const string & str ) {
try {
return stoi ( str ) * 1.0 ! = stod ( str ) ;
} catch ( . . . ) {
return false ;
}
}
2024-12-26 20:46:52 +11:00
2024-12-27 20:55:19 +11:00
bool checkForInt ( const string & str ) {
try {
return stoi ( str ) * 1.0 = = stod ( str ) ;
} catch ( . . . ) {
return false ;
}
}
2024-12-26 20:46:52 +11:00
2024-12-27 20:55:19 +11:00
void error ( const string & str ) {
cout < < " \u001b [31m Error running code: " < < str < < " \u001b [39m " < < endl ;
}
2024-12-26 20:46:52 +11:00
2024-12-27 20:55:19 +11:00
void verbose ( const string & str ) {
if ( isVerbose ) cout < < " \u001b [36m Info: " < < str < < " \u001b [39m " < < endl ;
}
2024-12-26 20:46:52 +11:00
2024-12-27 20:55:19 +11:00
vector < pair < string , string > > tokenize ( const string & input ) {
vector < pair < string , string > > tokens ;
string currentToken ;
bool stringOpen = false ;
2024-12-26 20:46:52 +11:00
2024-12-27 20:55:19 +11:00
for ( char c : input ) {
if ( c = = ' ' & & ! stringOpen ) {
if ( ! currentToken . empty ( ) ) {
tokens . push_back ( { currentToken , getTokenType ( currentToken ) } ) ;
currentToken . clear ( ) ;
}
} else {
currentToken + = c ;
}
if ( c = = ' " ' ) stringOpen = ! stringOpen ;
}
if ( ! currentToken . empty ( ) ) {
tokens . push_back ( { currentToken , getTokenType ( currentToken ) } ) ;
}
2024-12-26 20:46:52 +11:00
2024-12-27 20:55:19 +11:00
return tokens ;
}
2024-12-26 20:46:52 +11:00
2024-12-27 20:55:19 +11:00
auto handleVariable ( Variable var ) {
2024-12-26 13:25:10 +11:00
}
2024-12-27 20:55:19 +11:00
double doDecMath ( ) {
}
2024-12-26 13:25:10 +11:00
2024-12-27 20:55:19 +11:00
string getTokenType ( const string & token ) {
for ( const auto & func : builtInFunctions ) {
if ( token = = func ) return " function " ;
}
for ( const auto & inc : incrementors ) {
if ( token = = inc ) return " incrementor " ;
}
for ( const auto & mod : modifiers ) {
if ( token = = mod ) return " modifier " ;
}
for ( const auto & op : operators ) {
if ( token = = op ) return " operator " ;
}
for ( const auto & comp : comparitors ) {
if ( token = = comp ) return " comparitor " ;
}
if ( variables . find ( token ) ! = variables . end ( ) ) return " variable " ;
2024-12-26 13:25:10 +11:00
2024-12-27 20:55:19 +11:00
if ( token = = " = " ) return " equals " ;
if ( token [ 0 ] = = ' " ' ) return " str " ;
if ( checkForInt ( token ) ) return " int " ;
if ( checkForDec ( token ) ) return " dec " ;
2024-12-26 13:25:10 +11:00
2024-12-27 20:55:19 +11:00
return " unknown " ;
2024-12-26 15:11:28 +11:00
}
2024-12-27 20:55:19 +11:00
public :
auto executeCommand ( const string & input ) {
auto tokens = tokenize ( input ) ;
if ( tokens . empty ( ) ) return 0 ;
if ( tokens [ 0 ] . first = = " log " ) {
verbose ( " Log command run " ) ;
if ( tokens . size ( ) < 2 ) {
error ( " log requires an argument " ) ;
return 0 ;
}
const auto & [ token , type ] = tokens [ 1 ] ;
if ( type = = " str " | | type = = " int " | | type = = " dec " ) {
cout < < token < < endl ;
}
else if ( type = = " variable " ) {
auto it = variables . find ( token ) ;
if ( it ! = variables . end ( ) ) {
cout < < it - > second . toString ( ) < < endl ;
}
}
else if ( type = = " function " ) {
error ( " for now, functions cannot be logged " ) ;
}
else if ( type = = " unknown " ) {
error ( " that type is unknown " ) ;
}
return 0 ;
2024-12-26 15:11:28 +11:00
}
2024-12-26 13:25:10 +11:00
2024-12-27 20:55:19 +11:00
else if ( tokens [ 0 ] . first = = " exit " ) {
if ( tokens . size ( ) < 2 ) {
exit ( 0 ) ;
} else if ( tokens . size ( ) > 1 ) {
const auto & [ token , type ] = tokens [ 1 ] ;
if ( type = = " int " ) {
exit ( stoi ( token ) ) ;
} else {
error ( " exit argument must be integer " ) ;
2024-12-26 13:25:10 +11:00
}
}
2024-12-27 20:55:19 +11:00
return 0 ;
}
else if ( tokens [ 0 ] . first = = " type " ) {
if ( tokens . size ( ) < 2 ) {
error ( " type requires an argument " ) ;
return 0 ;
2024-12-26 13:25:10 +11:00
}
2024-12-27 20:55:19 +11:00
const auto & [ token , type ] = tokens [ 1 ] ;
cout < < type < < endl ;
return 0 ;
}
2024-12-26 13:25:10 +11:00
2024-12-27 20:55:19 +11:00
else if ( tokens [ 0 ] . first = = " run " ) {
if ( tokens . size ( ) < 2 ) {
error ( " run requires an argument " ) ;
return 0 ;
}
string inputStr = tokens [ 1 ] . first ;
char input [ inputStr . length ( ) + 1 ] ;
strcpy ( input , inputStr . c_str ( ) ) ;
int returnCode = system ( input ) ;
return 0 ;
2024-12-26 13:25:10 +11:00
}
2024-12-27 20:55:19 +11:00
else if ( tokens [ 0 ] . first = = " str " ) {
verbose ( " String command run " ) ;
if ( tokens . size ( ) < 2 ) {
error ( " variable must have a name " ) ;
return 0 ;
2024-12-26 13:25:10 +11:00
}
2024-12-27 20:55:19 +11:00
if ( tokens . size ( ) < 4 ) {
error ( " when defining a variable, set what the variable means " ) ;
return 0 ;
2024-12-26 13:25:10 +11:00
}
2024-12-27 20:55:19 +11:00
const auto & varName = tokens [ 1 ] . first ;
if ( tokens [ 2 ] . first ! = " = " ) {
error ( " when defining a variable, use '=' " ) ;
return 0 ;
}
if ( variables . find ( varName ) ! = variables . end ( ) ) {
error ( " variable is already initialized " ) ;
return 0 ;
}
if ( tokens [ 3 ] . second ! = " str " ) {
error ( " you've initialized a string, but set it's value to a different type " ) ;
return 0 ;
2024-12-26 13:25:10 +11:00
}
2024-12-27 20:55:19 +11:00
string value = tokens [ 3 ] . first ;
value = value . substr ( 1 , value . length ( ) - 2 ) ;
variables [ varName ] = Variable ( VarType : : STRING , value ) ;
verbose ( " String variable " + varName + " defined as " + value ) ;
return 0 ;
2024-12-26 13:25:10 +11:00
}
2024-12-27 20:55:19 +11:00
else if ( tokens [ 0 ] . first = = " int " ) {
verbose ( " Integer command run " ) ;
if ( tokens . size ( ) < 2 ) {
error ( " variable must have a name " ) ;
2024-12-26 13:25:10 +11:00
return 0 ;
2024-12-27 20:55:19 +11:00
}
if ( tokens . size ( ) < 4 ) {
error ( " when defining a variable, set what the variable means " ) ;
2024-12-26 13:25:10 +11:00
return 0 ;
}
2024-12-27 20:55:19 +11:00
const auto & varName = tokens [ 1 ] . first ;
if ( tokens [ 2 ] . first ! = " = " ) {
error ( " when defining a variable, use '=' " ) ;
return 0 ;
2024-12-26 13:25:10 +11:00
}
2024-12-27 20:55:19 +11:00
if ( variables . find ( varName ) ! = variables . end ( ) ) {
error ( " variable is already initialized " ) ;
return 0 ;
2024-12-26 13:25:10 +11:00
}
2024-12-27 20:55:19 +11:00
if ( tokens [ 3 ] . second ! = " int " ) {
error ( " you've initialized an integer, but set it's value to a different type " ) ;
return 0 ;
2024-12-26 13:25:10 +11:00
}
2024-12-27 20:55:19 +11:00
int value = stoi ( tokens [ 3 ] . first ) ;
variables [ varName ] = Variable ( VarType : : INTEGER , value ) ;
verbose ( " Integer variable " + varName + " defined as " + to_string ( value ) ) ;
return 0 ;
}
else if ( tokens [ 0 ] . first = = " dec " ) {
2024-12-26 13:25:10 +11:00
verbose ( " Decimal command run " ) ;
2024-12-27 20:55:19 +11:00
if ( tokens . size ( ) < 2 ) {
2024-12-26 13:25:10 +11:00
error ( " variable must have a name " ) ;
2024-12-27 20:55:19 +11:00
return 0 ;
2024-12-26 13:25:10 +11:00
}
2024-12-27 20:55:19 +11:00
if ( tokens . size ( ) < 4 ) {
error ( " when defining a variable, set what the variable means " ) ;
return 0 ;
2024-12-26 13:25:10 +11:00
}
2024-12-27 20:55:19 +11:00
const auto & varName = tokens [ 1 ] . first ;
if ( tokens [ 2 ] . first ! = " = " ) {
error ( " when defining a variable, use '=' " ) ;
return 0 ;
2024-12-26 15:11:28 +11:00
}
2024-12-27 20:55:19 +11:00
if ( variables . find ( varName ) ! = variables . end ( ) ) {
error ( " variable is already initialized " ) ;
return 0 ;
}
if ( tokens [ 3 ] . second ! = " dec " ) {
error ( " you've initialized a decimal, but set it's value to a different type " ) ;
return 0 ;
}
double value = stod ( tokens [ 3 ] . first ) ;
variables [ varName ] = Variable ( VarType : : DECIMAL , value ) ;
verbose ( " Decimal variable " + varName + " defined as " + to_string ( value ) ) ;
return 0 ;
}
else if ( tokens [ 0 ] . first = = " verbose " ) {
2024-12-26 13:25:10 +11:00
isVerbose = ! isVerbose ;
2024-12-27 20:55:19 +11:00
return 0 ;
}
else if ( tokens [ 0 ] . first = = " help " ) {
cout < < " Oktolang Help \n Built In Functions: \n help: This current help function \n log: Log something to the command line \n type: Find the type of the input \n str: Define a string \n int: Define a whole number \n dec: Define a number with a decimal place \n " ;
return 0 ;
}
else if ( variables . find ( tokens [ 0 ] . first ) ! = variables . end ( ) ) {
if ( tokens . size ( ) < 2 ) {
error ( " Expected an operator " ) ;
return 0 ;
2024-12-26 13:25:10 +11:00
}
2024-12-27 20:55:19 +11:00
auto & var = variables [ tokens [ 0 ] . first ] ;
if ( var . type = = VarType : : INTEGER ) {
if ( tokens [ 1 ] . second = = " incrementor " ) {
if ( tokens [ 1 ] . first = = " ++ " ) {
int currentValue = get < int > ( var . value ) ;
var . value = currentValue + 1 ;
} else if ( tokens [ 1 ] . second = = " -- " ) {
int currentValue = get < int > ( var . value ) ;
var . value = currentValue - 1 ;
}
} else if ( tokens [ 1 ] . second = = " operator " ) { }
} else if ( var . type = = VarType : : DECIMAL ) {
if ( tokens [ 1 ] . second = = " incrementor " ) {
if ( tokens [ 1 ] . first = = " ++ " ) {
double currentValue = get < double > ( var . value ) ;
var . value = currentValue + 1 ;
} else if ( tokens [ 1 ] . second = = " -- " ) {
double currentValue = get < double > ( var . value ) ;
var . value = currentValue - 1 ;
}
}
2024-12-26 20:46:52 +11:00
}
2024-12-27 20:55:19 +11:00
return 0 ;
}
if ( ! tokens [ 0 ] . first . empty ( ) ) {
error ( " I don't know how that works " ) ;
return 0 ;
}
return 0 ;
}
} ;
int main ( int argc , char * argv [ ] ) {
cout < < " Oktolang interpreter \n " ;
Interpreter interpreter ;
if ( argc > 1 ) {
ifstream inFile ( argv [ 1 ] ) ;
string line ;
while ( getline ( inFile , line ) ) {
if ( line [ 0 ] = = ' # ' ) continue ;
if ( interpreter . executeCommand ( line ) ! = 0 ) return 1 ;
}
} else {
string input ;
while ( true ) {
cout < < " > " ;
getline ( cin , input ) ;
if ( interpreter . executeCommand ( input ) ! = 0 ) break ;
2024-12-26 13:25:10 +11:00
}
}
return 0 ;
}
2024-12-27 20:55:19 +11:00