├── comp.bat ├── old_version ├── README ├── Environment.h ├── PList.h ├── Procedures.h ├── utils.h └── schm.cpp ├── Cell.h ├── Makefile ├── README ├── Procedure.h ├── Cell.cpp ├── utils.h ├── Procedures.h ├── Procedure.cpp ├── PList.h ├── Object.h ├── Object.cpp ├── Procedures.cpp ├── utils.cpp ├── PList.cpp └── schm.cpp /comp.bat: -------------------------------------------------------------------------------- 1 | cl /Feschm.exe utils.cpp PList.cpp Procedures.cpp Procedure.cpp Object.cpp Cell.cpp schm.cpp -------------------------------------------------------------------------------- /old_version/README: -------------------------------------------------------------------------------- 1 | Here you could find the code for "Implementing Scheme in C++", for more informations visit the project webpage: 2 | 3 | http://solarianprogrammer.com/2011/11/14/scheme-in-cpp/ 4 | 5 | You could use this program under the terms of GPL v3, for more details see: 6 | 7 | http://www.gnu.org/copyleft/gpl.html 8 | 9 | Copyright 2011 Sol from www.solarianprogrammer.com 10 | 11 | 12 | -------------------------------------------------------------------------------- /Cell.h: -------------------------------------------------------------------------------- 1 | //Simple class to store a string or a procedure 2 | class Cell { 3 | string st; 4 | Procedure proc; 5 | 6 | public: 7 | Cell(); 8 | 9 | //Init the Cell with a string 10 | Cell(string aa); 11 | 12 | //Init the Cell with a procedure 13 | Cell(Procedure &procedure); 14 | 15 | //Get the values stored in a Cell (string or procedure) 16 | string get_str(); 17 | Procedure get_proc(); 18 | }; 19 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | obj = Cell.o PList.o Procedures.o utils.o Object.o Procedure.o schm.o 2 | src = Cell.cpp PList.cpp Procedures.cpp utils.cpp Object.cpp Procedure.cpp schm.cpp 3 | 4 | schm: $(obj) 5 | g++ -o schm $(obj) 6 | 7 | Cell.o: PList.h Procedure.h Cell.h 8 | PList.o: PList.h 9 | Procedures.o: Procedures.h 10 | utils.o: utils.h 11 | Object.o: PList.h Procedure.h Object.h 12 | Procedure.o: PList.h Procedure.h 13 | schm.o: utils.h PList.h Procedure.h Object.h Procedures.h Cell.h 14 | 15 | $(obj): $(src) 16 | g++ -c $(src) 17 | 18 | clean: 19 | rm $(obj) schm 20 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | Update: 2011/11/21 Completely changed the structure of the code (the old code is in "old_version" if you are interested). 2 | 3 | Here you could find the code for "Implementing Scheme in C++", for more informations visit the project webpage: 4 | 5 | http://solarianprogrammer.com/2011/11/14/scheme-in-cpp/ 6 | http://solarianprogrammer.com/2011/11/21/implementing-scheme-in-cpp-2/ 7 | 8 | You could use this program under the terms of GPL v3, for more details see: 9 | 10 | http://www.gnu.org/copyleft/gpl.html 11 | 12 | Copyright 2011 Sol from www.solarianprogrammer.com 13 | 14 | 15 | -------------------------------------------------------------------------------- /Procedure.h: -------------------------------------------------------------------------------- 1 | //Class used to store a Scheme defined procedure 2 | //the procedure is stored in two PLists: arguments and body 3 | class Procedure { 4 | PList arg_list; 5 | PList body; 6 | 7 | //Add a PList to the end of the vector V 8 | void addPList(vector&V, PList a); 9 | 10 | public: 11 | Procedure(); 12 | 13 | //Init a procedure from a PList 14 | Procedure(PList &pp); 15 | 16 | //Get the list of arguments of the current procedure 17 | PList get_arg_list(); 18 | 19 | //Get the body of the current procedure 20 | PList get_body(); 21 | }; 22 | -------------------------------------------------------------------------------- /Cell.cpp: -------------------------------------------------------------------------------- 1 | //Simple class to store a string or a procedure 2 | 3 | #include 4 | #include 5 | 6 | using namespace std; 7 | 8 | #include "PList.h" 9 | #include "Procedure.h" 10 | #include "Cell.h" 11 | 12 | Cell::Cell() { 13 | } 14 | 15 | //Init the Cell with a string 16 | Cell::Cell(string aa) { 17 | st = aa; 18 | } 19 | 20 | //Init the Cell with a procedure 21 | Cell::Cell(Procedure &procedure) { 22 | proc = procedure; 23 | st = ""; 24 | } 25 | 26 | //Get the values stored in a Cell (string or procedure) 27 | 28 | string Cell::get_str() { 29 | return st; 30 | } 31 | 32 | Procedure Cell::get_proc() { 33 | return proc; 34 | } 35 | -------------------------------------------------------------------------------- /old_version/Environment.h: -------------------------------------------------------------------------------- 1 | class Object{ 2 | string(*pp)(vector&); 3 | string(*rr)(); 4 | string value; 5 | string kind; 6 | 7 | public: 8 | Object(){}; 9 | Object(string ss){value=ss;kind="variable";pp=NULL;}; 10 | Object(string(*p_)(vector&)){pp=p_;kind="procedure";value="";}; 11 | string get_kind(){ 12 | return kind; 13 | } 14 | string get_value(){ 15 | return value; 16 | } 17 | string apply(vector&V){ 18 | return pp(V); 19 | } 20 | string apply(){ 21 | vectorV; 22 | return pp(V); 23 | } 24 | }; 25 | 26 | typedef map Environment; 27 | -------------------------------------------------------------------------------- /utils.h: -------------------------------------------------------------------------------- 1 | //Utility functions 2 | 3 | //Print the Scheme prompt 4 | void prompt(); 5 | 6 | //Read the user input character by character in a STL string. 7 | string get_input(); 8 | 9 | //START_NOTE 10 | //"replace_substr" and "clean_input" can be replaced by a more elegant regex solution 11 | //unfortunateley gcc does not fully support regex (at the time of this implementation) 12 | //Visual Studio 2010 fully supports regex 13 | //END_NOTE 14 | 15 | //Replace substring target with substring res in string inp 16 | void replace_substr(string &inp, string target, string res); 17 | 18 | //Split the input string in components and store them in a STL vector of strings 19 | vector clean_input(string &str); 20 | 21 | //START_NOTE 22 | //This ugly hack should be replaced with a regex that can decide if we have int,double or complex numbers 23 | //END_NOTE 24 | //Check if the string contains a number 25 | bool number(string inp); 26 | -------------------------------------------------------------------------------- /Procedures.h: -------------------------------------------------------------------------------- 1 | //Basic procedures: 2 | //Each procedure receives as input a vector of strings and returns a string 3 | 4 | //Print one or more variables; e.g. (print aa), (print aa bb cc) 5 | string print(vector&vv); 6 | 7 | //Add one or more variables; e.g. (+ aa), (+ aa bb cc) 8 | string add(vector&vv); 9 | 10 | //Diff, e.g.: (- aa bb) 11 | string diff(vector&vv); 12 | 13 | //Division, e.g. (/ aa bb cc ...) 14 | string divv(vector&vv); 15 | 16 | //Product, e.g. (* aa bb cc ...) 17 | string prod(vector&vv); 18 | 19 | //Quit the interpreter, e.q. (quit) or (exit) 20 | string scheme_quit(vector&vv); 21 | 22 | //Logical operators: <, <=, >, >=, =, != 23 | 24 | string less_than(vector&vv); 25 | 26 | string less_or_equal(vector&vv); 27 | 28 | string great_than(vector&vv); 29 | 30 | string great_or_equal(vector&vv); 31 | 32 | string equall(vector&vv); 33 | 34 | string not_equal(vector&vv); 35 | -------------------------------------------------------------------------------- /Procedure.cpp: -------------------------------------------------------------------------------- 1 | //Class used to store a Scheme defined procedure 2 | //the procedure is stored in two PLists: arguments and body 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | using namespace std; 9 | 10 | #include "PList.h" 11 | #include "Procedure.h" 12 | 13 | Procedure::Procedure() { 14 | } 15 | 16 | //Init a procedure from a PList 17 | Procedure::Procedure(PList &pp) { 18 | arg_list = pp.get(1); 19 | vectoraux; 20 | aux.push_back("("); 21 | aux.push_back("begin"); 22 | for (int i = 2; i < pp.size(); i++) { 23 | addPList(aux, pp.get(i)); 24 | } 25 | aux.push_back(")"); 26 | body = PList(aux); 27 | } 28 | 29 | //Add a PList to the end of the vector V 30 | void Procedure::addPList(vector&V, PList a) { 31 | vectoraux = a.get_store(); 32 | for (int i = 0; i < aux.size(); i++) { 33 | V.push_back(aux[i]); 34 | } 35 | } 36 | 37 | //Get the list of arguments of the current procedure 38 | PList Procedure::get_arg_list() { 39 | return arg_list; 40 | } 41 | 42 | //Get the body of the current procedure 43 | PList Procedure::get_body() { 44 | return body; 45 | } 46 | -------------------------------------------------------------------------------- /PList.h: -------------------------------------------------------------------------------- 1 | //Class to store and process an s-expression 2 | //internally this is a vector of strings 3 | class PList { 4 | vectorstore; 5 | 6 | public: 7 | PList(); 8 | 9 | //Init a PList from a vector of strings 10 | PList(vector&vv); 11 | 12 | //Init a PList from a string 13 | PList(string &ss); 14 | 15 | //Print the content of an s-expression 16 | void print(); 17 | 18 | //Convert the contents to a single string 19 | string toString(); 20 | 21 | //Get a copy of the vector uses to store the PList 22 | vector get_store(); 23 | 24 | //Clear the contents 25 | void clear(); 26 | 27 | //Get the number of s-expressions contained on a level 28 | //for example: 29 | //(+ aa bb) will return 3 30 | //(+ (- 2 3)) will return 2 31 | size_t size(); 32 | 33 | //Get the sub PList stored at pos 34 | //e.g. (+ (- 2 3) (* 1 1)) get(0) will return "+" 35 | PList get(size_t pos); 36 | 37 | //Get the full size of vector used to store the PList 38 | size_t full_size(); 39 | 40 | //Get the elem at pos from the vector used to store the PList 41 | string elem(size_t pos); 42 | 43 | //Add a string at the end of the current vector 44 | void puts(string ss); 45 | }; 46 | -------------------------------------------------------------------------------- /Object.h: -------------------------------------------------------------------------------- 1 | //Class to store a native defined procedures (C++), Scheme defined procedures and strings 2 | 3 | class Object { 4 | string(*pp)(vector&); 5 | Procedure proc; 6 | string value; 7 | string kind; 8 | bool native_proc; 9 | 10 | public: 11 | Object(); 12 | 13 | //Store a string 14 | Object(string &ss); 15 | 16 | //Store a pointer to a C++ function (this can be accessed from Scheme) 17 | Object(string(*p_)(vector&)); 18 | 19 | //Store a Scheme defined procedure 20 | Object(Procedure &procedure); 21 | 22 | //Get the type of data stored - variable or procedure 23 | string get_kind(); 24 | 25 | //Get the value stored 26 | string get_value(); 27 | 28 | //Return true if the procedure is native (C++) and false if it was defined in Scheme 29 | bool check_native_procedure(); 30 | 31 | //Run the current procedure with the arguments V 32 | string apply(vector&V); 33 | 34 | //Run the current procedure with no arguments 35 | string apply(); 36 | 37 | //Get the list of arguments of the current procedure 38 | PList get_arg_list(); 39 | 40 | //Get the body of the current procedure 41 | PList get_body(); 42 | 43 | //Get the Scheme procedure 44 | Procedure get_proc(); 45 | }; 46 | -------------------------------------------------------------------------------- /Object.cpp: -------------------------------------------------------------------------------- 1 | //Class to store a native defined procedures (C++), Scheme defined procedures and strings 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | using namespace std; 9 | 10 | #include "PList.h" 11 | #include "Procedure.h" 12 | #include "Object.h" 13 | 14 | Object::Object() { 15 | } 16 | 17 | //Store a string 18 | Object::Object(string &ss) { 19 | value = ss; 20 | kind = "variable"; 21 | pp = NULL; 22 | native_proc = false; 23 | } 24 | 25 | //Store a pointer to a C++ function (this can be accessed from Scheme) 26 | Object::Object(string(*p_)(vector&)) { 27 | pp = p_; 28 | kind = "procedure"; 29 | value = ""; 30 | native_proc = true; 31 | } 32 | 33 | //Store a Scheme defined procedure 34 | Object::Object(Procedure &procedure) { 35 | proc = procedure; 36 | kind = "procedure"; 37 | value = ""; 38 | native_proc = false; 39 | } 40 | 41 | //Get the type of data stored - variable or procedure 42 | string Object::get_kind() { 43 | return kind; 44 | } 45 | 46 | //Get the value stored 47 | string Object::get_value() { 48 | return value; 49 | } 50 | 51 | //Return true if the procedure is native (C++) and false if it was defined in Scheme 52 | bool Object::check_native_procedure() { 53 | return native_proc; 54 | } 55 | 56 | //Run the current procedure with the arguments V 57 | string Object::apply(vector&V) { 58 | return pp(V); 59 | } 60 | 61 | //Run the current procedure with no arguments 62 | string Object::apply() { 63 | vectorV; 64 | return pp(V); 65 | } 66 | 67 | //Get the list of arguments of the current procedure 68 | PList Object::get_arg_list() { 69 | return proc.get_arg_list(); 70 | } 71 | 72 | //Get the body of the current procedure 73 | PList Object::get_body() { 74 | return proc.get_body(); 75 | } 76 | 77 | //Get the Scheme procedure 78 | Procedure Object::get_proc() { 79 | return proc; 80 | } 81 | -------------------------------------------------------------------------------- /old_version/PList.h: -------------------------------------------------------------------------------- 1 | class PList{ 2 | vectorstore; 3 | 4 | public: 5 | PList(){} 6 | PList(vectorvv){store=vv;} 7 | void print(){for(size_t i=0;i&vv){ 3 | if(vv.size()==0)return "Wrong number of arguments for procedure +"; 4 | stringstream ss; 5 | double sum=strtod(vv[0].c_str(),NULL); 6 | for(size_t i=1;i&vv){ 12 | if(vv.size()==0)return "Wrong number of arguments for procedure -"; 13 | stringstream ss; 14 | double sum=strtod(vv[0].c_str(),NULL); 15 | for(size_t i=1;i&vv){ 21 | if(vv.size()==0)return "Wrong number of arguments for procedure /"; 22 | stringstream ss; 23 | double sum=strtod(vv[0].c_str(),NULL); 24 | for(size_t i=1;i&vv){ 30 | if(vv.size()==0)return "Wrong number of arguments for procedure *"; 31 | stringstream ss; 32 | double sum=strtod(vv[0].c_str(),NULL); 33 | for(size_t i=1;i&vv){ 39 | exit(1); 40 | return "ok"; 41 | } 42 | 43 | string less_than(vector&vv){ 44 | if(vv.size()==1)return "#t"; 45 | for(size_t i=0;i&vv){ 52 | if(vv.size()==1)return "#t"; 53 | for(size_t i=0;i&vv){ 58 | if(vv.size()==1)return "#t"; 59 | for(size_t i=0;istrtod(vv[i+1].c_str(),NULL))) return "#f"; 60 | return "#t"; 61 | } 62 | 63 | string great_or_equal(vector&vv){ 64 | if(vv.size()==1)return "#t"; 65 | for(size_t i=0;i=strtod(vv[i+1].c_str(),NULL))) return "#f"; 66 | return "#t"; 67 | } 68 | 69 | 70 | string equal(vector&vv){ 71 | if(vv.size()==1)return "#t"; 72 | for(size_t i=0;i&vv){ 77 | if(vv.size()==1)return "#t"; 78 | for(size_t i=0;i>>"; } 2 | 3 | /*Read the user input character by character in a STL string.*/ 4 | string get_input(){ 5 | string inp; 6 | char tmp; 7 | int left=0,right=0,ll=0; 8 | for(;;){ 9 | cin.get(tmp); 10 | //If you find ";" on a line ignore everything until the end of line (comment line) 11 | if(tmp==';'){ 12 | while(tmp!='\n')cin.get(tmp); 13 | } 14 | if(tmp!='\n')inp+=tmp; 15 | if(tmp=='(')left++; 16 | else if(tmp==')')right++; 17 | else if(tmp=='\"')ll++; 18 | 19 | //At end of line (user has pressed Enter) check if you have un-matched parantheses or quotation marks 20 | if(tmp=='\n'){ 21 | if(left==0 && right==0 && ll==0)break; 22 | if(left!=0 && (left==right) && (ll==0 || (ll&1)==0))break; 23 | if(left==0 && right==0 && (ll&1)==0)break; 24 | if((ll&1))inp+="\\n"; 25 | else inp+=" "; 26 | } 27 | } 28 | return inp; 29 | } 30 | 31 | //START_NOTE 32 | //"replace_substr" and "clean_input" can be replaced by a more elegant regex solution 33 | //unfortunateley gcc does not fully support regex (at the time of this implementation) 34 | //Visual Studio 2010 fully supports regex 35 | //END_NOTE 36 | 37 | /*Replace substring target with substring res in string inp*/ 38 | void replace_substr(string &inp,string target,string res){ 39 | size_t ind=0; 40 | for(;;){ 41 | ind=inp.find(target,ind); 42 | if(ind==string::npos)break; 43 | inp.replace(ind,1,res); 44 | ind+=res.length(); 45 | } 46 | } 47 | 48 | /*Split the input string in components and store them in a STL vector of strings*/ 49 | vector clean_input(string &str){ 50 | replace_substr(str,"("," ( "); 51 | replace_substr(str,")"," ) "); 52 | 53 | stringstream ss(str); 54 | string aux; 55 | vectorinit_pieces; 56 | while(ss>>aux) init_pieces.push_back(aux); 57 | if(str.find("\"")==string::npos)return init_pieces; 58 | //Treat the case of 'sentences'; for example "aaa bbb ccc" should not be broken into pieces 59 | vectorpieces; 60 | aux=""; 61 | int flag=0; 62 | for(size_t i=0;i 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | using namespace std; 11 | 12 | #include "Procedures.h" 13 | 14 | //Print one or more variables; e.g. (print aa), (print aa bb cc) 15 | string print(vector&vv) { 16 | for (int i = 0; i < vv.size(); i++) { 17 | cout << vv[i] << " "; 18 | } 19 | cout << endl; 20 | return (""); 21 | } 22 | 23 | //Add one or more variables; e.g. (+ aa), (+ aa bb cc) 24 | string add(vector&vv) { 25 | if (vv.size() == 0)return "Wrong number of arguments for procedure +"; 26 | stringstream ss; 27 | double sum = strtod(vv[0].c_str(), NULL); 28 | for (size_t i = 1; i < vv.size(); i++)sum += strtod(vv[i].c_str(), NULL); 29 | ss << sum; 30 | return ss.str(); 31 | } 32 | 33 | //Diff, e.g.: (- aa bb) 34 | string diff(vector&vv) { 35 | if (vv.size() == 0)return "Wrong number of arguments for procedure -"; 36 | stringstream ss; 37 | double sum = strtod(vv[0].c_str(), NULL); 38 | for (size_t i = 1; i < vv.size(); i++)sum -= strtod(vv[i].c_str(), NULL); 39 | ss << sum; 40 | return ss.str(); 41 | } 42 | 43 | //Division, e.g. (/ aa bb cc ...) 44 | string divv(vector&vv) { 45 | if (vv.size() == 0)return "Wrong number of arguments for procedure /"; 46 | stringstream ss; 47 | double sum = strtod(vv[0].c_str(), NULL); 48 | for (size_t i = 1; i < vv.size(); i++)sum /= strtod(vv[i].c_str(), NULL); 49 | ss << sum; 50 | return ss.str(); 51 | } 52 | 53 | //Product, e.g. (* aa bb cc ...) 54 | string prod(vector&vv) { 55 | if (vv.size() == 0)return "Wrong number of arguments for procedure *"; 56 | stringstream ss; 57 | double sum = strtod(vv[0].c_str(), NULL); 58 | for (size_t i = 1; i < vv.size(); i++)sum *= strtod(vv[i].c_str(), NULL); 59 | ss << sum; 60 | return ss.str(); 61 | } 62 | 63 | //Quit the interpreter, e.q. (quit) or (exit) 64 | string scheme_quit(vector&vv) { 65 | exit(1); 66 | return "ok"; 67 | } 68 | 69 | //Logical operators: <, <=, >, >=, =, != 70 | 71 | string less_than(vector&vv) { 72 | if (vv.size() == 1)return "#t"; 73 | for (size_t i = 0; i < vv.size() - 1; i++) { 74 | if (!(strtod(vv[i].c_str(), NULL) < strtod(vv[i + 1].c_str(), NULL))) return "#f"; 75 | } 76 | return "#t"; 77 | } 78 | 79 | string less_or_equal(vector&vv) { 80 | if (vv.size() == 1)return "#t"; 81 | for (size_t i = 0; i < vv.size() - 1; i++)if (!(strtod(vv[i].c_str(), NULL) <= strtod(vv[i + 1].c_str(), NULL))) return "#f"; 82 | return "#t"; 83 | } 84 | 85 | string great_than(vector&vv) { 86 | if (vv.size() == 1)return "#t"; 87 | for (size_t i = 0; i < vv.size() - 1; i++)if (!(strtod(vv[i].c_str(), NULL) > strtod(vv[i + 1].c_str(), NULL))) return "#f"; 88 | return "#t"; 89 | } 90 | 91 | string great_or_equal(vector&vv) { 92 | if (vv.size() == 1)return "#t"; 93 | for (size_t i = 0; i < vv.size() - 1; i++)if (!(strtod(vv[i].c_str(), NULL) >= strtod(vv[i + 1].c_str(), NULL))) return "#f"; 94 | return "#t"; 95 | } 96 | 97 | string equall(vector&vv) { 98 | if (vv.size() == 1)return "#t"; 99 | for (size_t i = 0; i < vv.size() - 1; i++)if (!(strtod(vv[i].c_str(), NULL) == strtod(vv[i + 1].c_str(), NULL))) return "#f"; 100 | return "#t"; 101 | } 102 | 103 | string not_equal(vector&vv) { 104 | if (vv.size() == 1)return "#t"; 105 | for (size_t i = 0; i < vv.size() - 1; i++)if (!(strtod(vv[i].c_str(), NULL) != strtod(vv[i + 1].c_str(), NULL))) return "#f"; 106 | return "#t"; 107 | } 108 | -------------------------------------------------------------------------------- /utils.cpp: -------------------------------------------------------------------------------- 1 | //Utility functions 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | using namespace std; 9 | 10 | #include "utils.h" 11 | 12 | //Print the Scheme prompt 13 | void prompt() { 14 | cout << "schm >>>"; 15 | } 16 | 17 | //Read the user input character by character in a STL string. 18 | 19 | string get_input() { 20 | string inp; 21 | char tmp; 22 | int left = 0, right = 0, ll = 0; 23 | for (;;) { 24 | cin.get(tmp); 25 | //If you find ";" on a line ignore everything until the end of line (comment line) 26 | if (tmp == ';') { 27 | while (tmp != '\n')cin.get(tmp); 28 | } 29 | if (tmp != '\n')inp += tmp; 30 | if (tmp == '(')left++; 31 | else if (tmp == ')')right++; 32 | else if (tmp == '\"')ll++; 33 | 34 | //At end of line (user has pressed Enter) check if you have un-matched parantheses or quotation marks 35 | if (tmp == '\n') { 36 | if (left == 0 && right == 0 && ll == 0)break; 37 | if (left != 0 && (left == right) && (ll == 0 || (ll & 1) == 0))break; 38 | if (left == 0 && right == 0 && (ll & 1) == 0)break; 39 | if ((ll & 1))inp += "\\n"; 40 | else inp += " "; 41 | } 42 | } 43 | return inp; 44 | } 45 | 46 | //START_NOTE 47 | //"replace_substr" and "clean_input" can be replaced by a more elegant regex solution 48 | //unfortunateley gcc does not fully support regex (at the time of this implementation) 49 | //Visual Studio 2010 fully supports regex 50 | //END_NOTE 51 | 52 | //Replace substring target with substring res in string inp 53 | 54 | void replace_substr(string &inp, string target, string res) { 55 | size_t ind = 0; 56 | for (;;) { 57 | ind = inp.find(target, ind); 58 | if (ind == string::npos)break; 59 | inp.replace(ind, 1, res); 60 | ind += res.length(); 61 | } 62 | } 63 | 64 | //Split the input string in components and store them in a STL vector of strings 65 | 66 | vector clean_input(string &str) { 67 | replace_substr(str, "(", " ( "); 68 | replace_substr(str, ")", " ) "); 69 | 70 | stringstream ss(str); 71 | string aux; 72 | vectorinit_pieces; 73 | while (ss >> aux) init_pieces.push_back(aux); 74 | if (str.find("\"") == string::npos)return init_pieces; 75 | //Treat the case of 'sentences'; for example "aaa bbb ccc" should not be broken into pieces 76 | vectorpieces; 77 | aux = ""; 78 | int flag = 0; 79 | for (size_t i = 0; i < init_pieces.size(); i++) { 80 | 81 | if (init_pieces[i].find("\"") != string::npos) { 82 | if (init_pieces[i][0] == '\"' && init_pieces[i][init_pieces[i].size() - 1] == '\"') { 83 | pieces.push_back(init_pieces[i]); 84 | continue; 85 | } 86 | flag = 1; 87 | if (init_pieces[i][0] == '\"')aux = init_pieces[i] + " "; 88 | else if (init_pieces[i][init_pieces[i].size() - 1] == '\"') { 89 | aux += init_pieces[i] + " "; 90 | pieces.push_back(aux); 91 | aux = ""; 92 | flag = 0; 93 | } else 94 | aux += init_pieces[i] + " "; 95 | } else 96 | if (flag == 0) { 97 | pieces.push_back(init_pieces[i]); 98 | } else 99 | aux += init_pieces[i] + " "; 100 | } 101 | return pieces; 102 | } 103 | 104 | //START_NOTE 105 | //This ugly hack should be replaced with a regex that can decide if we have int,double or complex numbers 106 | //END_NOTE 107 | 108 | //Check if the string contains a number 109 | 110 | bool number(string inp) { 111 | char *pend; 112 | double tst = strtod(inp.c_str(), &pend); 113 | if (inp[0] != (*pend))return true; 114 | else return false; 115 | } 116 | -------------------------------------------------------------------------------- /PList.cpp: -------------------------------------------------------------------------------- 1 | //Class to store and process an s-expression 2 | //internally this is a vector of strings 3 | #include 4 | #include 5 | #include 6 | 7 | using namespace std; 8 | 9 | #include "PList.h" 10 | 11 | PList::PList() { 12 | } 13 | 14 | //Init a PList from a vector of strings 15 | PList::PList(vector&vv) { 16 | store = vv; 17 | } 18 | 19 | //Init a PList from a string 20 | PList::PList(string &ss) { 21 | store.push_back("("); 22 | store.push_back(ss); 23 | store.push_back(")"); 24 | } 25 | 26 | //Print the content of an s-expression 27 | void PList::print() { 28 | for (size_t i = 0; i < store.size(); i++) 29 | cout << store[i] << " "; 30 | cout << endl; 31 | } 32 | 33 | //Convert the contents to a single string 34 | string PList::toString() { 35 | string aux = ""; 36 | for (size_t i = 0; i < store.size(); i++)aux = aux + store[i] + " "; 37 | return aux; 38 | } 39 | 40 | //Get a copy of the vector uses to store the PList 41 | vector PList::get_store() { 42 | return store; 43 | } 44 | 45 | //Clear the contents 46 | void PList::clear() { 47 | store.clear(); 48 | } 49 | 50 | //Get the number of s-expressions contained on a level 51 | //for example: 52 | //(+ aa bb) will return 3 53 | //(+ (- 2 3)) will return 2 54 | size_t PList::size() { 55 | size_t nn = 0, flag = 0; 56 | size_t left = 0, right = 0; 57 | if (store.size() == 0)return nn; 58 | if (store.size() == 1) { 59 | nn = 1; 60 | return nn; 61 | } 62 | for (size_t i = 1; i < store.size() - 1; i++) { 63 | if (store[i] == "(")left++; 64 | if (store[i] == ")")right++; 65 | 66 | if (left == 0 && left == right)nn++; 67 | else if (left == 1 && flag == 0) { 68 | nn++; 69 | flag = 1; 70 | } else if (left != 0 && left == right) { 71 | flag = 0; 72 | left = 0; 73 | right = 0; 74 | } 75 | } 76 | return nn; 77 | } 78 | 79 | //Get the sub PList stored at pos 80 | //e.g. (+ (- 2 3) (* 1 1)) get(0) will return "+" 81 | PList PList::get(size_t pos) { 82 | PList pp; 83 | if (store.size() == 1) pp = *this; 84 | size_t nn = 0, flag = 0, flag_read = 0; 85 | size_t left = 0, right = 0; 86 | for (size_t i = 1; i < store.size() - 1; i++) { 87 | if (store[i] == "(")left++; 88 | if (store[i] == ")")right++; 89 | 90 | if (left == 0 && left == right) { 91 | nn++; 92 | if (pos == nn - 1) { 93 | pp.store.push_back(store[i]); 94 | break; 95 | } 96 | } else if (left == 1 && flag == 0) { 97 | nn++; 98 | flag = 1; 99 | if (pos == nn - 1) { 100 | flag_read = 1; 101 | } 102 | } else if (left != 0 && left == right) { 103 | flag = 0; 104 | left = 0; 105 | right = 0; 106 | flag_read = 0; 107 | } else if (flag_read == 1)pp.store.push_back(store[i]); 108 | } 109 | if (pp.store.size() == 1) return pp; 110 | else { 111 | PList cc; 112 | cc.store.push_back("("); 113 | for (size_t ii = 0; ii < pp.full_size(); ii++)cc.store.push_back(pp.store[ii]); 114 | cc.store.push_back(")"); 115 | return cc; 116 | } 117 | } 118 | 119 | //Get the full size of vector used to store the PList 120 | size_t PList::full_size() { 121 | return store.size(); 122 | } 123 | 124 | //Get the elem at pos from the vector used to store the PList 125 | string PList::elem(size_t pos) { 126 | string inp = store[pos]; 127 | //Clean all trailing empty spaces 128 | while (inp[inp.size() - 1] == ' ')inp.erase(inp.size() - 1); //clean some empty spaces 129 | return inp; 130 | } 131 | 132 | //Add a string at the end of the current vector 133 | void PList::puts(string ss) { 134 | store.push_back(ss); 135 | } 136 | -------------------------------------------------------------------------------- /old_version/schm.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | using namespace std; 9 | 10 | #include "utils.h" 11 | #include "PList.h" 12 | #include "Environment.h" 13 | #include "Procedures.h" 14 | 15 | bool show_err1_flag=true; 16 | bool show_err2_flag=true; 17 | 18 | //START_NOTE 19 | //It will be nice to implement some history for the commands, this way a user won't be forced to retype again a command. 20 | //No plan for implementing this now. 21 | //END_NOTE 22 | 23 | string eval(PList &pp,Environment &env){ 24 | int N=pp.size(); 25 | if(N==1){ //Check for symbol, constant literal, procedure with no argument 26 | if(pp.elem(0)=="(" && pp.elem(pp.full_size()-1)==")"){ 27 | PList aux=pp.get(0); string inp=aux.elem(0); 28 | //Check for procedure with no argument, e.g. (quit) 29 | if(env.find(inp)!=env.end()){ 30 | return env[inp].apply(); 31 | } 32 | else{ 33 | return(("Error! Unbound variable: "+inp)); 34 | } 35 | } 36 | else{ 37 | string inp=pp.elem(0); 38 | //Check if character 39 | if(inp[0]=='#' && inp[1]=='\\')return "character type not yet implemented"; 40 | //Check if string 41 | if(inp[0]=='\"' && inp[inp.size()-1]=='\"')return inp; 42 | //Check if number 43 | if(number(inp))return inp; 44 | //Check if variable or procedure 45 | if(env.find(inp)!=env.end()){ 46 | if(env[inp].get_kind()=="variable")return env[inp].get_value(); 47 | else{ 48 | if(show_err1_flag)cout<args; 83 | for(int i=1;iout=clean_input(inp); 102 | //Evaluate an expression and print the result 103 | PList pp = PList(out); 104 | cout<"]=great_than; 123 | env[">="]=great_or_equal; 124 | 125 | REPL(env); 126 | return(0); 127 | } 128 | -------------------------------------------------------------------------------- /schm.cpp: -------------------------------------------------------------------------------- 1 | //Simple Scheme interpreter 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | using namespace std; 9 | 10 | #include "utils.h" 11 | #include "PList.h" 12 | #include "Procedure.h" 13 | #include "Object.h" 14 | #include "Procedures.h" 15 | #include "Cell.h" 16 | 17 | typedef map Environment; 18 | 19 | string apply_proc(Procedure &proc, PList &args, Environment env); 20 | Cell eval(PList &pp, Environment &env); 21 | string apply_proc(Procedure &proc, PList &args, Environment env); 22 | void REPL(Environment &env); 23 | 24 | bool show_err1_flag = true; 25 | bool show_err2_flag = true; 26 | 27 | //START_NOTE 28 | //It will be nice to implement some history for the commands, this way a user won't be forced to retype again a command. 29 | //No plan for implementing this now. 30 | //If you want to use syntax highlighting, paranthese matching etc... you can use schm from Emacs! 31 | //END_NOTE 32 | 33 | Cell eval(PList &pp, Environment &env) { 34 | int N = pp.size(); 35 | if (N == 1) { //Check for symbol, constant literal, procedure with no argument 36 | if (pp.elem(0) == "(" && pp.elem(pp.full_size() - 1) == ")") { 37 | PList aux = pp.get(0); 38 | string inp = aux.elem(0); 39 | for (int i = 1; i < pp.full_size() - 2; i++)inp = inp + pp.elem(i); 40 | //Check for procedure with no argument, e.g. (quit) 41 | if (env.find(inp) != env.end()) { 42 | if (env[inp].get_kind() == "procedure" && env[inp].check_native_procedure() == true) return env[inp].apply(); 43 | else return env[inp].get_value(); 44 | } else { 45 | return (("Error! Unbound variable: " + inp)); 46 | } 47 | } else { 48 | string inp = pp.elem(0); 49 | //Check if character 50 | if (inp[0] == '#' && inp[1] == '\\')return Cell("character type not yet implemented"); 51 | //Check if string 52 | if (inp[0] == '\"' && inp[inp.size() - 1] == '\"')return inp; 53 | //Check if number 54 | if (number(inp))return inp; 55 | //Check if variable or procedure 56 | if (env.find(inp) != env.end()) { 57 | if (env[inp].get_kind() == "variable")return env[inp].get_value(); 58 | else { 59 | if (show_err1_flag)cout << env[inp].get_kind() << " "; 60 | show_err1_flag = true; 61 | return inp; 62 | } 63 | } else { 64 | string res; 65 | if (show_err2_flag)res = "Error! Unbound variable: " + inp; 66 | show_err2_flag = true; 67 | return res; 68 | } 69 | } 70 | } else { 71 | show_err1_flag = false; 72 | show_err2_flag = false; 73 | string proc; 74 | PList aux = pp.get(0); 75 | if (aux.size() == 1) proc = aux.elem(0); 76 | else { 77 | PList aux2 = aux.get(0); 78 | string tst = aux2.elem(0); 79 | if (tst == "lambda") { 80 | Procedure anonymous = Procedure(aux); 81 | //Collect the arguments of the lambda expression: 82 | PList args; 83 | args.puts("("); 84 | for (int i = 1; i < N; i++) { 85 | PList piece = pp.get(i); 86 | string res = (eval(piece, env)).get_str(); 87 | args.puts(res); 88 | } 89 | args.puts(")"); 90 | return apply_proc(anonymous, args, env); 91 | } else { 92 | proc = (eval(aux, env)).get_str(); 93 | } 94 | } 95 | if (proc == "define") { 96 | if (pp.size() != 3)return Cell("Ill-formed special form: define"); 97 | else { 98 | string name = (pp.get(1)).elem(0); 99 | PList value = pp.get(2); 100 | Cell res = eval(value, env); 101 | if (res.get_str() == "") { 102 | Procedure prr = res.get_proc(); 103 | env[name] = prr; 104 | } else { 105 | string stt = res.get_str(); 106 | env[name] = stt; 107 | } 108 | return Cell(""); 109 | } 110 | } else if (proc == "set!") { 111 | if (pp.size() != 3)return Cell("Ill-formed special form: set!"); 112 | else { 113 | string name = (pp.get(1)).elem(0); 114 | if (env.find(name) == env.end()) { 115 | return Cell("Error! Unbound variable: " + name); 116 | } 117 | PList value = pp.get(2); 118 | string res = (eval(value, env)).get_str(); 119 | env[name] = res; 120 | return Cell(""); 121 | } 122 | } else if (proc == "quote") { 123 | if (pp.size() != 2)return Cell("Ill-formed special form: quote"); 124 | else { 125 | PList value = pp.get(1); 126 | return value.toString(); 127 | } 128 | } else if (proc == "if") { 129 | if (pp.size() == 3) { 130 | PList cond = pp.get(1); 131 | PList if_true = pp.get(2); 132 | string aux = (eval(cond, env)).get_str(); 133 | //If cond is a number evaluate the TRUE branch, if cond is a boolean evaluate accordingly 134 | if (number(aux))return eval(if_true, env); 135 | if (aux == "#t")return eval(if_true, env); 136 | else return Cell(""); 137 | } 138 | if (pp.size() == 4) { 139 | PList cond = pp.get(1); 140 | PList if_true = pp.get(2); 141 | PList if_false = pp.get(3); 142 | string aux = (eval(cond, env)).get_str(); 143 | //If cond is a number evaluate the TRUE branch, if cond is a boolean evaluate accordingly 144 | if (number(aux))return eval(if_true, env); 145 | if (aux == "#t")return eval(if_true, env); 146 | else return eval(if_false, env); 147 | } else { 148 | return Cell("Ill-formed special form: if"); 149 | } 150 | } else if (proc == "lambda") { 151 | Procedure pr = Procedure(pp); 152 | return pr; 153 | } else if (proc == "begin") { 154 | if (pp.size() < 2)return Cell("Ill-formed special form: begin"); 155 | string res; 156 | for (int i = 1; i < pp.size(); i++) { 157 | PList aux = pp.get(i); 158 | res = (eval(aux, env)).get_str(); 159 | } 160 | return res; 161 | } else { 162 | PList exps; 163 | exps.puts("("); 164 | for (int i = 0; i < N; i++) { 165 | PList piece = pp.get(i); 166 | string aux = (eval(piece, env)).get_str(); 167 | if (aux == "")aux = (piece.get(0)).elem(0); 168 | exps.puts(aux); 169 | } 170 | exps.puts(")"); 171 | string pr = (exps.get(0)).elem(0); 172 | vectorargs; 173 | for (int i = 1; i < exps.size(); i++)args.push_back((exps.get(i)).elem(0)); 174 | if (env.find(pr) != env.end()) { 175 | if (env[pr].check_native_procedure()) { 176 | return env[pr].apply(args); 177 | } else { 178 | Procedure prt = env[pr].get_proc(); 179 | PList argss; 180 | argss.puts("("); 181 | for (int i = 1; i < N; i++) { 182 | PList piece = pp.get(i); 183 | string res = (eval(piece, env)).get_str(); 184 | argss.puts(res); 185 | } 186 | argss.puts(")"); 187 | return apply_proc(prt, argss, env); 188 | } 189 | 190 | } else { 191 | return Cell("Error! Unbound variable: " + pr); 192 | } 193 | } 194 | } 195 | } 196 | 197 | //Use this for named Scheme procedures, e.g. (define square (lambda (x) (* x x))) 198 | 199 | string apply_proc(Procedure &proc, PList &args, Environment env) { 200 | PList arg_list = proc.get_arg_list(); 201 | PList body = proc.get_body(); 202 | for (int i = 0; i < args.size(); i++) { 203 | string aux = (arg_list.get(i)).elem(0); 204 | PList piece = args.get(i); 205 | string stt = (eval(piece, env)).get_str(); 206 | env[aux] = stt; 207 | } 208 | string res = (eval(body, env)).get_str(); 209 | return res; 210 | } 211 | 212 | 213 | //Simple REPL (read - evaluate - print). 214 | 215 | void REPL(Environment &env) { 216 | prompt(); 217 | for (;;) { 218 | show_err1_flag = true; 219 | show_err2_flag = true; 220 | string inp = get_input(); 221 | if (inp == "")continue; //if the input buffer is empty go to the start of the for loop 222 | vectorout = clean_input(inp); 223 | //Evaluate an expression and print the result 224 | PList pp = PList(out); 225 | string res = (eval(pp, env)).get_str(); 226 | if (res == "") { 227 | prompt(); 228 | continue; 229 | } 230 | cout << res << endl; 231 | prompt(); 232 | } 233 | } 234 | 235 | //Start the interpreter and load the predefined procedures 236 | 237 | int main() { 238 | Environment env; 239 | env["+"] = add; 240 | env["-"] = diff; 241 | env["*"] = prod; 242 | env["/"] = divv; 243 | env["exit"] = scheme_quit; 244 | env["quit"] = scheme_quit; 245 | env["="] = equall; 246 | env["!="] = not_equal; 247 | env["<"] = less_than; 248 | env["<="] = less_or_equal; 249 | env[">"] = great_than; 250 | env[">="] = great_or_equal; 251 | env["print"] = print; 252 | 253 | string ss = "Ill formed special form: lambda."; 254 | env["lambda"] = ss; 255 | ss = "Ill formed special form: quote."; 256 | env["quote"] = ss; 257 | ss = "Ill formed special form: begin."; 258 | env["begin"] = ss; 259 | ss = "Ill formed special form: set!."; 260 | env["set!"] = ss; 261 | ss = "Ill formed special form: define."; 262 | env["define"] = ss; 263 | ss = "Ill formed special form: if."; 264 | env["if"] = ss; 265 | 266 | REPL(env); 267 | return (0); 268 | } 269 | --------------------------------------------------------------------------------