/* * main.cc * * Created on: Feb 8, 2010 * Author: petergoodman * Version: $Id$ */ #include #include #include #include #include "Token.h" #include "TokenGenerator.h" #include "ParseError.h" #include "PrimitiveFunction.h" #include "DerivedFunction.h" #include "primitive.h" using namespace std; /** * The Clyde interpreter. */ static bool interpret(deque &stack, deque &tokens, map &functions, map &symbols, unsigned int line=0) { try { while(!tokens.empty()) { switch(tokens.front()->type) { case Token::INT: case Token::STRING: case Token::VARNAME: stack.push_back(tokens.front()); tokens.pop_front(); break; case Token::OPERATOR: case Token::FUNCTION: // take the function off and copy it string func_name(tokens.front()->str_val); delete tokens.front(); tokens.pop_front(); if(functions.end() == functions.find(func_name)) { stringstream ss; ss << "Function '" << func_name << "' does " << "not exist."; throw runtime_error(ss.str()); } IFunction *func = functions[func_name]; try { func->call(stack, tokens, symbols); } catch(runtime_error) { cout << endl << "Error when calling function '" << func_name << "' on line " << line << "." << endl; throw; } break; } } } catch(runtime_error &ex) { primitive::clear(tokens, tokens, symbols); cout << "An error occurred with the following message:" << endl << ex.what() << endl; } catch(int x) { if(EXIT_SUCCESS != x) { throw; } return true; } return false; } /** * The Clyde read-eval-print-loop. */ static void repl(deque &stack, deque &tokens, map &functions, map &symbols, TokenGenerator &gen) { for(unsigned int line(0); ; ++line) { // get the tokens try { string in; //cout << line << " >>> "; // prompt getline(cin, in); gen.assign(in); tokens.assign(gen.begin(), gen.end()); // report parse error and keep going } catch(ParseError& err) { cout << "Parse Error: " << err.what() \ << " Line [" << line << "]." << endl; primitive::clear(tokens, tokens, symbols); continue; } if(interpret(stack, tokens, functions, symbols, line)) { break; } } } /** * Create the clyde functions. */ static void init_functions(map &F) { // basic primitive functions F["exit"] = new PrimitiveFunction(&primitive::exit); F["clear"] = new PrimitiveFunction(&primitive::clear); F["print"] = new PrimitiveFunction(&primitive::print); F["exec"] = new PrimitiveFunction(&primitive::exec); F["pop"] = new PrimitiveFunction(&primitive::pop); F["dump"] = new PrimitiveFunction(&primitive::dump); F["load"] = new PrimitiveFunction(&primitive::load); F["store"] = new PrimitiveFunction(&primitive::store); F["if"] = new PrimitiveFunction(&primitive::cond); // operators F["+"] = new PrimitiveFunction(&primitive::op2<&primitive::op_add>); F["-"] = new PrimitiveFunction(&primitive::op2<&primitive::op_sub>); F["*"] = new PrimitiveFunction(&primitive::op2<&primitive::op_mul>); F["/"] = new PrimitiveFunction(&primitive::op2<&primitive::op_div>); F["=="] = new PrimitiveFunction(&primitive::op2<&primitive::op_eq>); F["<"] = new PrimitiveFunction(&primitive::op2<&primitive::op_lt>); F[">"] = new PrimitiveFunction(&primitive::op2<&primitive::op_gt>); // non-primitive functions, built from primitive functions F["endl"] = new DerivedFunction<0>("\"\n\" .print .pop"); F["dup"] = new DerivedFunction<1>("r0 .store r0 .load r0 .load"); F["rot"] = new DerivedFunction<2>("r0 .store r1 .store r0 .load r1 .load"); F["rot3"] = new DerivedFunction<3>( "r0 .store r1 .store r2 .store r1 .load r0 .load r2 .load" ); } /** * Run the Clyde REPL. */ int main(void) { cout << "Clyde REPL (author: Peter Goodman)." << endl \ << "Type \".exit\" to exit." << endl; try { deque tokens; deque stack; map functions; map symbols; TokenGenerator gen; // initialize and run the REPL init_functions(functions); repl(stack, tokens, functions, symbols, gen); // clean up primitive::clear(tokens, tokens, symbols); primitive::clear(stack, stack, symbols); map::iterator fit = functions.begin(); map::iterator fit_end = functions.end(); map::iterator sit = symbols.begin(); map::iterator sit_end = symbols.end(); for(; fit != fit_end; fit++) { delete (*fit).second; } for(; sit != sit_end; sit++) { delete (*sit).second; } } catch(exception &ex) { // catch-all for exceptions cout << "An exception occurred with the following message:" << endl << ex.what() << endl; } catch(...) { cout << "An unknown error occurred; terminating Clyde." << endl; } return 0; }