#ifndef __SHELL__H #define __SHELL__H /* La clase shell extiende la funcionalidad de la clase application para permitir construir de una manera sencilla aplicaciones que usen intérprete de órdenes (shell). El funcionamiento se basa en tomar la primer palabra de la orden tecleada por el usuario e invocar una función establecida para esa palabra específica. Lo que se necesita es que la clase derivada de shell agregue sus funciones (mediante la función addFunction()) al mapa proporcionado por shell para que puedan ser llamadas cuando el usuario teclee la palabra correspondiente a cada función. Este mecanismo se agregó para que la clase derivada no tenga la necesidad de redefinir la función start() para hacer que el intérprete responda a nuevas órdenes. Aun así, se tiene la libertad de redefinir la función start(). La función otherwise() se creo para responder adecuadamente a otras palabras que no estén especificadas en el mapa, debido a su desconocimiento o a su forma variable (tal como una expresión algebraica, por ejemplo, "-0.512+x", "3*x-y"). Las clases derivadas deberán proporcionar el conjunto de palabras y funciones con las que trabajará el intérprete. Ariel Medina */ #include #include #include #ifdef USE_STL_AMV #include "string_amv.h" #include "exception_amv.h" using namespace amv; #else #include #include using namespace std; #endif #include "amvdefs.h" #include "application.h" namespace amv { class shell: public application { // Se proporciona un mapa para que las clases derivadas de ésta puedan proporcionar funciones // miembro adicionales, se supone que las funciones miembro corresponden a un objeto de una // clase derivada de shell; las nuevas funciones se aplicarán a través de this, que es el // mismo valor para un objeto de la clase shell que para uno de clase derivada de esta misma. std::map funcs; protected: typedef void (shell::*pfshell)(); bool dispatchCommand(const string &s); virtual void otherwise(); public: virtual void start(); void addFunction(const string &name, pfshell pf); }; bool shell::dispatchCommand(const string &s) { // Si está en el mapa de funciones adicionales y la dirección de la función es válida if(funcs.find(s)!=funcs.end() && funcs[s]) { (this->*(funcs[s]))(); // Nota: El compilador supone que el objeto es de tipo shell y que la función es // miembro de de objetos de esta clase, sin embargo, es posible que el objeto sea de un tipo derivado // de shell y que la función sea miembro de este último objeto, ya que el compilador no // hace una verificación profunda en este caso. Esto nos ayuda para que las clases derivadas // puedan agregar funciones al mapa y automáticamente se integren al ciclo principal. return true; } return false; } // Función que deberá ser redefina en caso de que lo que teclee el usuario no sea una palabra // para la que se haya establecido una función específica y se requiera analizar para el // comportamiento correspondiente void shell::otherwise() { std::cerr<<"No se reconoce la orden\n"; } // Función para leer órdenes y aplicar las funciones correspondientes a las órdenes, // Tal vez deba ser redefinida para tener la funcionalidad adecuada a la clase derivada void shell::start() { try { //capturar cualquier objeto lanzado derivado de exception antes de salir de start() string command, squit("exit"); // Ciclo principal del programa while(true) { if(!(std::cin>>command)) command=squit; // Si la palabra es "exit" if(command==squit) { std::cerr<<"\nI will see you later\n"; break; } // Si el símbolo inicial es '/', se pasará al sistema operativo la orden dada para que la ejecute else if(command[0]=='/') { system(command.c_str()+1); } // Si se ha agregado una función para esa palabra else if(dispatchCommand(command)) { } // De otra manera else { otherwise(); } } } // Capturamos excepciones exception o alguna derivada de ésta. catch(exception &e) { std::cerr<