/* gpl.cpp provides the main() function for the gpl interpreter It is designed to work for phases p3 - p8 of the assignment. It is customized by using the C preprocessor to turn on and off segments of code. The symbols used are: SYMBOL_TABLE assume that the symbol table exists PRINT_SYMBOL_TABLE print the symbol table GRAPHICS open a window and show graphics __APPLE__ compiled for OSX Symbols can be defined by using the -D argument to the compiler. For example the following command: g++ -DPRINT_SYMBOL_TABLE gpl.cpp will define the C preprocessor variable PRINT_SYMBOL_TABLE before it start compilation. Edit the Makefile so it uses the correct gpl.cpp flags for the given phase. */ #ifdef SYMBOL_TABLE #include "symbol_table.h" #endif #include "parser.h" // substitute for y.tab.h #include "error.h" #ifdef GRAPHICS #include "window.h" #endif #include "gpl_assert.h" #include #include #include #include #include // for fopen() using namespace std; extern int yylex(); extern int yyparse(); const int DEFAULT_WINDOW_X = 200; const int DEFAULT_WINDOW_Y = 200; const int DEFAULT_WINDOW_WIDTH = 500; const int DEFAULT_WINDOW_HEIGHT = 500; const double DEFAULT_WINDOW_RED = 1.0; const double DEFAULT_WINDOW_GREEN = 1.0; const double DEFAULT_WINDOW_BLUE = 1.0; const string DEFAULT_WINDOW_TITLE = "gpl window"; const int DEFAULT_ANIMATION_SPEED = 88; // there does not appear to be a default yywrap in OSX #ifdef __APPLE__ extern "C" int yywrap ( ); int yywrap(void) { return true; } #endif int yyerror(char *str) { Error::error(Error::PARSE_ERROR, str); return 1; } #ifdef SYMBOL_TABLE static Symbol_table *symbol_table = Symbol_table::instance(); #endif void illegal_usage() { cerr << "illegal command line argument(s)" << endl << "Usage: $ gpl [-s seed] [-stdin] filename[.gpl]" << endl; exit(1); } void signal_handler(int signo) { // we expect to only handle SIGUSR1 signals assert(signo == SIGUSR1); #ifdef PRINT_SYMBOL_TABLE cout << endl << "Printing the symbol table from signal_handler()" << endl; static Symbol_table *symbol_table = Symbol_table::instance(); symbol_table->print(cout); #endif } int main(int argc, char **argv) { bool symbol_table_flag = false; bool print_symbol_table_flag = false; bool graphics_flag = false; // set local flags based on the command line argument when compiling gpl.cpp // (see comments in Makefile) #ifdef SYMBOL_TABLE symbol_table_flag = true; #endif #ifdef PRINT_SYMBOL_TABLE print_symbol_table_flag = true; #endif #ifdef GRAPHICS graphics_flag = true; #endif extern FILE *yyin; char *filename = 0; int seed = time(0); bool read_keypresses_from_standard_input = false; signal(SIGUSR1, signal_handler); // I use to use getopt() to parse the command line arguments // BUT it was not working on OS-X, so I wrote the following hack // if any argument is -stdin, set the flag // if any argument is -s, the next one must be a number // if it is a number use it as the srand seed // any other argument is assumed to be the filename for (int i = 1; i < argc; i++) { if (!strcmp(argv[i], "-stdin")) read_keypresses_from_standard_input = true; else if (!strcmp(argv[i], "-s")) { if (i+1 >= argc) illegal_usage(); // make sure the argument after the -s is a number for (char *c = argv[i+1]; *c; c++) { if (!isdigit(*c)) { cerr << "Illegal random number generator seed: " << argv[i+1] << endl; exit(1); } } seed = atoi(argv[i+1]); i += 1; } else { // can only specify one filename if (filename != 0) illegal_usage(); filename = argv[i]; } } if (!filename) illegal_usage(); char filename_with_extension[strlen(filename) + 4]; strcpy(filename_with_extension, filename); yyin = fopen(filename,"r"); // if open failed, append .gpl to the filename and try again if (!yyin) { strcat(filename_with_extension, ".gpl"); yyin = fopen(filename_with_extension,"r"); } // cannot open filename or filename+.gpl if (!yyin) { cerr << "Cannot open input file <" << filename << ">." << endl; exit(1); } srand(seed); cout << "gpl.cpp::main()" << endl << " input file(" << filename_with_extension << ")" << endl << " random seed(" << seed << ")" << endl << " read_keypresses_from_standard_input" << "(" << (read_keypresses_from_standard_input ? "true" : "false") << ")" << endl << " symbol_table(" << (symbol_table_flag ? "true" : "false") << ")" << endl << " print_symbol_table(" << (print_symbol_table_flag ? "true" : "false") << ")" <get_type("window_x", type)) { // if this variable does not have the type INT if (type != INT) Error::error(Error::INVALID_TYPE_FOR_RESERVED_VARIABLE, "window_x", gpl_type_to_string(type), "int" ); // else this variable has the correct type, override the default else symbol_table->get("window_x", window_x); } if (symbol_table->get_type("window_y", type)) { if (type != INT) Error::error(Error::INVALID_TYPE_FOR_RESERVED_VARIABLE, "window_y", gpl_type_to_string(type), "int" ); else symbol_table->get("window_y", window_y); } if (symbol_table->get_type("window_width", type)) { if (type != INT) Error::error(Error::INVALID_TYPE_FOR_RESERVED_VARIABLE, "window_width", gpl_type_to_string(type), "int" ); else symbol_table->get("window_width", window_width); } if (symbol_table->get_type("window_height", type)) { if (type != INT) Error::error(Error::INVALID_TYPE_FOR_RESERVED_VARIABLE, "window_height", gpl_type_to_string(type), "int" ); else symbol_table->get("window_height", window_height); } if (symbol_table->get_type("window_title", type)) { if (type != STRING) Error::error(Error::INVALID_TYPE_FOR_RESERVED_VARIABLE, "window_title", gpl_type_to_string(type), "string" ); else symbol_table->get("window_title", window_title); } if (symbol_table->get_type("window_red", type)) { if (type != DOUBLE) Error::error(Error::INVALID_TYPE_FOR_RESERVED_VARIABLE, "window_red", gpl_type_to_string(type), "double" ); else symbol_table->get("window_red", window_red); } if (symbol_table->get_type("window_green", type)) { if (type != DOUBLE) Error::error(Error::INVALID_TYPE_FOR_RESERVED_VARIABLE, "window_green", gpl_type_to_string(type), "double" ); else symbol_table->get("window_green", window_green); } if (symbol_table->get_type("window_blue", type)) { if (type != DOUBLE) Error::error(Error::INVALID_TYPE_FOR_RESERVED_VARIABLE, "window_blue", gpl_type_to_string(type), "double" ); else symbol_table->get("window_blue", window_blue); } if (symbol_table->get_type("animation_speed", type)) { if (type != INT) Error::error(Error::INVALID_TYPE_FOR_RESERVED_VARIABLE, "animation_speed", gpl_type_to_string(type), "int" ); else symbol_table->get("animation_speed", animation_speed); } #endif if (parse_result != 0 || Error::num_errors() != 0) { // This is sent to cout instead of cerr so it // ends up in the .out files // It makes it easier to understand what happened when // reading the .out files cout << Error::num_errors() << " error"; if (Error::num_errors() > 1) cout << "s"; cout << " found." << endl << "gpl giving up." << endl; exit(1); } #ifndef GRAPHICS else { cout << "No errors found (parser probably worked correctly)." << endl << endl; } #endif #ifdef PRINT_SYMBOL_TABLE if (parse_result == 0 && Error::num_errors() == 0) { cout << endl << "Printing the symbol table from main()" << endl; static Symbol_table *symbol_table = Symbol_table::instance(); symbol_table->print(cout); } #endif #ifndef GRAPHICS cout << "If graphics was enabled gpl program would execute now." << endl << endl; cout << "gpl.cpp::main() done." << endl; #endif #ifdef GRAPHICS Window window(window_x, window_y, window_width, window_height, window_title, animation_speed, window_red, window_green, window_blue, read_keypresses_from_standard_input ); // tell the Error object that execution is starting // Error class prints different messages once execution starts Error::starting_execution(); cout << "gpl.cpp::main() Calling window->initialize()." << endl; window.initialize(); cout << "gpl.cpp::main() Passing control to window->main_loop()." << endl; // Tell glut to start the main event loop window.main_loop(); #endif }