From 65d054b36ee03927a784d3522ea862e60182147f Mon Sep 17 00:00:00 2001 From: clanmills Date: Wed, 16 Feb 2011 08:21:19 -0800 Subject: [PATCH] Three lots of changes: 1) Changes post code review by Jason 2) Fixing bug in end of line processing on Windows with cr-lf 3) Adding command-line options to chai --- .../chaiscript/language/chaiscript_engine.hpp | 2 +- .../chaiscript/language/chaiscript_parser.hpp | 125 ++++++-------- src/main.cpp | 152 ++++++++++++------ 3 files changed, 156 insertions(+), 123 deletions(-) diff --git a/include/chaiscript/language/chaiscript_engine.hpp b/include/chaiscript/language/chaiscript_engine.hpp index ff37c7f..f21754f 100644 --- a/include/chaiscript/language/chaiscript_engine.hpp +++ b/include/chaiscript/language/chaiscript_engine.hpp @@ -492,7 +492,7 @@ namespace chaiscript * Helper function for loading a file */ std::string load_file(const std::string &t_filename) { - std::ifstream infile(t_filename.c_str(), std::ios::in | std::ios::ate); + std::ifstream infile(t_filename.c_str(), std::ios::in | std::ios::ate | std::ios::binary ); if (!infile.is_open()) { throw File_Not_Found_Error(t_filename); diff --git a/include/chaiscript/language/chaiscript_parser.hpp b/include/chaiscript/language/chaiscript_parser.hpp index 9a53c63..0dfdccd 100644 --- a/include/chaiscript/language/chaiscript_parser.hpp +++ b/include/chaiscript/language/chaiscript_parser.hpp @@ -7,7 +7,6 @@ #ifndef CHAISCRIPT_PARSER_HPP_ #define CHAISCRIPT_PARSER_HPP_ - #include #include #include @@ -15,9 +14,6 @@ #include "chaiscript_prelude.hpp" #include "chaiscript_common.hpp" -#define lengthof(x) (((int)sizeof(x))/((int)sizeof(x[0]))) - - namespace chaiscript { enum Alphabet @@ -32,6 +28,7 @@ namespace chaiscript , id_alphabet , white_alphabet , max_alphabet + , lengthof_alphabet = 256 }; class ChaiScript_Parser { @@ -43,13 +40,13 @@ namespace chaiscript std::string m_singleline_comment; boost::shared_ptr m_filename; std::vector m_match_stack; - bool alphabet[max_alphabet][256]; + bool alphabet[max_alphabet][lengthof_alphabet]; std::vector > m_operator_matches; std::vector m_operators; public: - ChaiScript_Parser() + ChaiScript_Parser() : m_multiline_comment_begin("/*"), m_multiline_comment_end("*/"), m_singleline_comment("//") @@ -60,7 +57,7 @@ namespace chaiscript ChaiScript_Parser(const ChaiScript_Parser &); // explicitly unimplemented copy constructor ChaiScript_Parser &operator=(const ChaiScript_Parser &); // explicitly unimplemented assignment operator - void setup_operators() + void setup_operators() { m_operators.push_back(AST_Node_Type::Logical_Or); std::vector logical_or; @@ -80,7 +77,7 @@ namespace chaiscript m_operators.push_back(AST_Node_Type::Bitwise_Xor); std::vector bitwise_xor; bitwise_xor.push_back("^"); - m_operator_matches.push_back(bitwise_xor); + m_operator_matches.push_back(bitwise_xor); m_operators.push_back(AST_Node_Type::Bitwise_And); std::vector bitwise_and; @@ -91,7 +88,7 @@ namespace chaiscript std::vector equality; equality.push_back("=="); equality.push_back("!="); - m_operator_matches.push_back(equality); + m_operator_matches.push_back(equality); m_operators.push_back(AST_Node_Type::Comparison); std::vector comparison; @@ -105,7 +102,7 @@ namespace chaiscript std::vector shift; shift.push_back("<<"); shift.push_back(">>"); - m_operator_matches.push_back(shift); + m_operator_matches.push_back(shift); m_operators.push_back(AST_Node_Type::Additive); std::vector additive; @@ -124,29 +121,29 @@ namespace chaiscript std::vector dot_access; dot_access.push_back("."); m_operator_matches.push_back(dot_access); - - int c; - for ( c = 0 ; c < lengthof(alphabet[0]) ; c++ ) { + + int c; + for ( c = 0 ; c < lengthof_alphabet ; c++ ) { for ( int a = 0 ; a < max_alphabet ; a ++ ) { alphabet[a][c]=false; } - } - alphabet[symbol_alphabet]['+']=true; - alphabet[symbol_alphabet]['-']=true; - alphabet[symbol_alphabet]['*']=true; - alphabet[symbol_alphabet]['/']=true; - alphabet[symbol_alphabet]['|']=true; - alphabet[symbol_alphabet]['&']=true; - alphabet[symbol_alphabet]['^']=true; - alphabet[symbol_alphabet]['=']=true; - alphabet[symbol_alphabet]['.']=true; - alphabet[symbol_alphabet]['<']=true; - alphabet[symbol_alphabet]['>']=true; - + } + alphabet[symbol_alphabet]['+']=true; + alphabet[symbol_alphabet]['-']=true; + alphabet[symbol_alphabet]['*']=true; + alphabet[symbol_alphabet]['/']=true; + alphabet[symbol_alphabet]['|']=true; + alphabet[symbol_alphabet]['&']=true; + alphabet[symbol_alphabet]['^']=true; + alphabet[symbol_alphabet]['=']=true; + alphabet[symbol_alphabet]['.']=true; + alphabet[symbol_alphabet]['<']=true; + alphabet[symbol_alphabet]['>']=true; + for ( c = 'a' ; c <= 'z' ; c++ ) alphabet[keyword_alphabet][c]=true; - for ( c = 'A' ; c <= 'Z' ; c++ ) alphabet[keyword_alphabet][c]=true; - for ( c = '0' ; c <= '9' ; c++ ) alphabet[keyword_alphabet][c]=true; - alphabet[keyword_alphabet]['_']=true; + for ( c = 'A' ; c <= 'Z' ; c++ ) alphabet[keyword_alphabet][c]=true; + for ( c = '0' ; c <= '9' ; c++ ) alphabet[keyword_alphabet][c]=true; + alphabet[keyword_alphabet]['_']=true; for ( c = '0' ; c <= '9' ; c++ ) alphabet[int_alphabet][c]=true; for ( c = '0' ; c <= '9' ; c++ ) alphabet[float_alphabet][c]=true; @@ -171,10 +168,10 @@ namespace chaiscript alphabet[white_alphabet]['\t']=true; } - /** - * test a char in an alphabet - */ - bool char_in_alphabet(unsigned char c,Alphabet a) { return alphabet[a][c]; } + /** + * test a char in an alphabet + */ + bool char_in_alphabet(unsigned char c,Alphabet a) { return alphabet[a][c]; } /** * Prints the parsed ast_nodes as a tree @@ -218,7 +215,7 @@ namespace chaiscript void build_match(AST_NodePtr t_t, size_t t_match_start) { int pos_line_start, pos_col_start, pos_line_stop, pos_col_stop; int is_deep = false; - + //so we want to take everything to the right of this and make them children if (t_match_start != m_match_stack.size()) { pos_line_start = m_match_stack[t_match_start]->start.line; @@ -239,7 +236,7 @@ namespace chaiscript t_t->start.column = pos_col_start; t_t->end.line = pos_line_stop; t_t->end.column = pos_col_stop; - + if (is_deep) { t_t->children.assign(m_match_stack.begin() + t_match_start, m_match_stack.end()); m_match_stack.erase(m_match_stack.begin() + t_match_start, m_match_stack.end()); @@ -251,26 +248,13 @@ namespace chaiscript } } - /** - * Does ranged char check - */ -/* - inline bool char_between(char t_start, char t_end) { - if ((*m_input_pos >= t_start) && (*m_input_pos <= t_end)) { - return true; - } - else { - return false; - } - } -*/ /** * Check to see if there is more text parse */ inline bool has_more_input() { return (m_input_pos != m_input_end); } - + /** * Skips any multi-line or single-line comment */ @@ -315,7 +299,7 @@ namespace chaiscript bool SkipWS() { bool retval = false; while (has_more_input()) { - if ( char_in_alphabet(*m_input_pos,white_alphabet) ) { // (*m_input_pos == ' ') || (*m_input_pos == '\t')) { + if ( char_in_alphabet(*m_input_pos,white_alphabet) ) { ++m_input_pos; ++m_col; retval = true; @@ -337,17 +321,17 @@ namespace chaiscript bool retval = false; std::string::const_iterator start = m_input_pos; - if (has_more_input() && char_in_alphabet(*m_input_pos,float_alphabet) ) { // (char_between('0', '9') || (*m_input_pos == '.'))) { - while (has_more_input() && char_in_alphabet(*m_input_pos,int_alphabet) ) { // char_between('0', '9')) { + if (has_more_input() && char_in_alphabet(*m_input_pos,float_alphabet) ) { + while (has_more_input() && char_in_alphabet(*m_input_pos,int_alphabet) ) { ++m_input_pos; ++m_col; } if (has_more_input() && (*m_input_pos == '.')) { ++m_input_pos; ++m_col; - if (has_more_input() && char_in_alphabet(*m_input_pos,int_alphabet)) { // char_between('0', '9')) { + if (has_more_input() && char_in_alphabet(*m_input_pos,int_alphabet)) { retval = true; - while (has_more_input() && char_in_alphabet(*m_input_pos,int_alphabet) ) { //char_between('0', '9')) { + while (has_more_input() && char_in_alphabet(*m_input_pos,int_alphabet) ) { ++m_input_pos; ++m_col; } @@ -370,16 +354,12 @@ namespace chaiscript ++m_input_pos; ++m_col; - if (has_more_input() && char_in_alphabet(*m_input_pos,x_alphabet) ) { // ((*m_input_pos == 'x') || (*m_input_pos == 'X'))) { + if (has_more_input() && char_in_alphabet(*m_input_pos,x_alphabet) ) { ++m_input_pos; ++m_col; - if (has_more_input() && char_in_alphabet(*m_input_pos,hex_alphabet)) { // (char_between('0', '9') || - // char_between('a', 'f') || - // char_between('A', 'F'))) { + if (has_more_input() && char_in_alphabet(*m_input_pos,hex_alphabet)) { retval = true; - while (has_more_input() && char_in_alphabet(*m_input_pos,hex_alphabet) ) { // (char_between('0', '9') || - // char_between('a', 'f') || - // char_between('A', 'F'))) { + while (has_more_input() && char_in_alphabet(*m_input_pos,hex_alphabet) ) { ++m_input_pos; ++m_col; } @@ -407,12 +387,12 @@ namespace chaiscript ++m_input_pos; ++m_col; - if (has_more_input() && char_in_alphabet(*m_input_pos,b_alphabet) ) { // ((*m_input_pos == 'b') || (*m_input_pos == 'B'))) { + if (has_more_input() && char_in_alphabet(*m_input_pos,b_alphabet) ) { ++m_input_pos; ++m_col; - if (has_more_input() && char_in_alphabet(*m_input_pos,bin_alphabet) ) { // char_between('0', '1')) { + if (has_more_input() && char_in_alphabet(*m_input_pos,bin_alphabet) ) { retval = true; - while (has_more_input() && char_in_alphabet(*m_input_pos,bin_alphabet) ) { // char_between('0', '1')) { + while (has_more_input() && char_in_alphabet(*m_input_pos,bin_alphabet) ) { ++m_input_pos; ++m_col; } @@ -444,7 +424,7 @@ namespace chaiscript std::string::const_iterator start = m_input_pos; int prev_col = m_col; int prev_line = m_line; - if (has_more_input() && char_in_alphabet(*m_input_pos,float_alphabet) ) { // (char_between('0', '9') || (*m_input_pos == '.')) ) { + if (has_more_input() && char_in_alphabet(*m_input_pos,float_alphabet) ) { if (Hex_()) { std::string match(start, m_input_pos); std::stringstream ss(match); @@ -512,11 +492,9 @@ namespace chaiscript */ bool Id_() { bool retval = false; - if (has_more_input() && char_in_alphabet(*m_input_pos,id_alphabet)) { // (char_between('A', 'Z') || (*m_input_pos == '_') || char_between('a', 'z'))) { + if (has_more_input() && char_in_alphabet(*m_input_pos,id_alphabet)) { retval = true; while (has_more_input() && char_in_alphabet(*m_input_pos,keyword_alphabet) ) { - // (char_between('A', 'Z') || (*m_input_pos == '_') || - // char_between('a', 'z') || char_between('0', '9'))) { ++m_input_pos; ++m_col; } @@ -526,7 +504,7 @@ namespace chaiscript ++m_col; ++m_input_pos; std::string::const_iterator start = m_input_pos; - + while (has_more_input() && (*m_input_pos != '`')) { if (Eol()) { throw Eval_Error("Carriage return in identifier literal", File_Position(m_line, m_col), *m_filename); @@ -1702,7 +1680,7 @@ namespace chaiscript return false; } } - + bool Operator_Helper(size_t t_precedence) { for (size_t i = 0; i < m_operator_matches[t_precedence].size(); ++i) { if (Symbol(m_operator_matches[t_precedence][i].c_str(), true)) { @@ -1723,7 +1701,7 @@ namespace chaiscript if (Operator_Helper(t_precedence)) { do { if (!Operator(t_precedence+1)) { - throw Eval_Error("Incomplete " + throw Eval_Error("Incomplete " + std::string(ast_node_type_to_string(m_operators[t_precedence])) + " expression", File_Position(m_line, m_col), *m_filename); } @@ -1764,7 +1742,7 @@ namespace chaiscript build_match(AST_NodePtr(new Logical_Or_AST_Node()), prev_stack_top); break; default: - throw Eval_Error("Internal error: unhandled ast_node", File_Position(m_line, m_col), *m_filename); + throw Eval_Error("Internal error: unhandled ast_node", File_Position(m_line, m_col), *m_filename); } } } @@ -1964,7 +1942,7 @@ namespace chaiscript bool parse(const std::string &t_input, const std::string &t_fname) { m_input_pos = t_input.begin(); m_input_end = t_input.end(); - m_line = 1; + m_line = 1; m_col = 1; m_filename = boost::shared_ptr(new std::string(t_fname)); @@ -1972,6 +1950,7 @@ namespace chaiscript while ((m_input_pos != m_input_end) && (!Eol())) { ++m_input_pos; } + // TODO: respect // -*- coding: utf-8 -*- on line 1 or 2 see: http://evanjones.ca/python-utf8.html) } if (Statements()) { diff --git a/src/main.cpp b/src/main.cpp index 11d39fe..bcc1bc7 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -24,14 +24,27 @@ static void add_history(const char*){} static void using_history(){} #endif -void print_help() { - std::cout << "ChaiScript evaluator. To evaluate an expression, type it and press ." << std::endl; - std::cout << "Additionally, you can inspect the runtime system using:" << std::endl; - std::cout << " dump_system() - outputs all functions registered to the system" << std::endl; - std::cout << " dump_object(x) - dumps information about the given symbol" << std::endl; +static void help(int n) { + if ( n >= 0 ) { + std::cout << "ChaiScript evaluator. To evaluate an expression, type it and press ." << std::endl; + std::cout << "Additionally, you can inspect the runtime system using:" << std::endl; + std::cout << " dump_system() - outputs all functions registered to the system" << std::endl; + std::cout << " dump_object(x) - dumps information about the given symbol" << std::endl; + } else { + std::cout << "usage: chai [option]+" << std::endl; + std::cout << " -h | --help" << std::endl; + std::cout << " -i | --interactive" << std::endl; + std::cout << " -c | --command cmd" << std::endl; + std::cout << " -v | --version" << std::endl; + std::cout << " - --stdin" << std::endl; + } } -bool throws_exception(const chaiscript::Proxy_Function &f) +static void version(int){ + std::cout << "chai: compiled " << __TIME__ << " " << __DATE__ << std::endl; +} + +static bool throws_exception(const chaiscript::Proxy_Function &f) { try { chaiscript::functor(f)(); @@ -42,34 +55,41 @@ bool throws_exception(const chaiscript::Proxy_Function &f) return false; } -std::string get_next_command() { +static std::string trim(std::string source,const std::string& t) +{ + std::string result = source ; + result.erase(result.find_last_not_of(t)+1); + result.erase(0, result.find_first_not_of(t)); + return result ; +} + +static std::string get_next_command() { std::string retval("quit"); if ( ! std::cin.eof() ) { char *input_raw = readline("eval> "); if ( input_raw ) { add_history(input_raw); - retval = input_raw; + retval = trim(std::string(input_raw),std::string(" \t")); ::free(input_raw); - if ( retval == "help" ) { - print_help(); - retval=""; - } - if ( retval == "quit" || retval == "exit" ) { - retval="exit(0)"; - } } } + if(retval == "quit" + || retval == "exit" + || retval == "help" + || retval == "version" + ){ + retval += "(0)"; + } return retval; } // We have to wrap exit with our own because Clang has a hard time with // function pointers to functions with special attributes (system exit being marked NORETURN) -void myexit(int return_val) { - std::cout << "thanks for using ChaiScript" << std::endl ; +static void myexit(int return_val) { exit(return_val); } -void interactive(chaiscript::ChaiScript& chai) +static void interactive(chaiscript::ChaiScript& chai) { using_history(); @@ -103,23 +123,21 @@ void interactive(chaiscript::ChaiScript& chai) int main(int argc, char *argv[]) { - int error = EXIT_SUCCESS; - std::vector usepaths; std::vector modulepaths; // Disable deprecation warning for getenv call. - #ifdef BOOST_MSVC - #pragma warning(push) - #pragma warning(disable : 4996) - #endif +#ifdef BOOST_MSVC +#pragma warning(push) +#pragma warning(disable : 4996) +#endif const char *usepath = getenv("CHAI_USE_PATH"); const char *modulepath = getenv("CHAI_MODULE_PATH"); - #ifdef BOOST_MSVC - #pragma warning(pop) - #endif +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif usepaths.push_back(""); if (usepath) @@ -136,34 +154,70 @@ int main(int argc, char *argv[]) chaiscript::ChaiScript chai(modulepaths,usepaths); chai.add(chaiscript::fun(&myexit), "exit"); + chai.add(chaiscript::fun(&myexit), "quit"); + chai.add(chaiscript::fun(&help), "help"); + chai.add(chaiscript::fun(&version), "version"); chai.add(chaiscript::fun(&throws_exception), "throws_exception"); - if (argc < 2) { - interactive(chai); - } else { - for (int i = 1; !error && (i < argc); ++i) { - try { - chaiscript::Boxed_Value val = chai.eval_file(argv[i]); + for (int i = 0; i < argc; ++i) { + if ( i == 0 && argc > 1 ) i++ ; + std::string arg( i ? argv[i] : "--interactive" ); + enum + { eInteractive + , eCommand + , eFile + } mode = eCommand ; + if ( arg == "-c" || arg == "--command" ) { + if ( (i+1) >= argc ) { + std::cout << "insufficient input following " << arg << std::endl; + return EXIT_FAILURE; + } else { + arg = argv[++i]; } - catch (chaiscript::Eval_Error &ee) { - std::cout << ee.what(); - if (ee.call_stack.size() > 0) { - std::cout << "during evaluation at (" << *(ee.call_stack[0]->filename) << " " << ee.call_stack[0]->start.line << ", " << ee.call_stack[0]->start.column << ")"; - for (unsigned int j = 1; j < ee.call_stack.size(); ++j) { - std::cout << std::endl; - std::cout << " from " << *(ee.call_stack[j]->filename) << " (" << ee.call_stack[j]->start.line << ", " << ee.call_stack[j]->start.column << ")"; - } + } else if ( arg == "-" || arg == "--stdin" ) { + arg = "" ; + std::string line; + while ( std::getline(std::cin, line) ) { + arg += line ; + } + } else if ( arg == "-v" || arg == "--version" ) { + arg = "version(0)" ; + } else if ( arg == "-h" || arg == "--help" ) { + arg = "help(-1)"; + } else if ( arg == "-i" || arg == "--interactive" ) { + mode = eInteractive ; + } else if ( (arg.length() ? arg[0] : ' ') == '-' ) { + std::cout << "unrecognised argument " << arg << std::endl; + return EXIT_FAILURE; + } else { + mode = eFile; + } + + chaiscript::Boxed_Value val ; + try { + switch ( mode ) { + case eInteractive : interactive(chai); break; + case eCommand : val = chai.eval(arg); break; + case eFile : val = chai.eval_file(arg); break; + } + } + catch (chaiscript::Eval_Error &ee) { + std::cout << ee.what(); + if (ee.call_stack.size() > 0) { + std::cout << "during evaluation at (" << *(ee.call_stack[0]->filename) << " " << ee.call_stack[0]->start.line << ", " << ee.call_stack[0]->start.column << ")"; + for (unsigned int j = 1; j < ee.call_stack.size(); ++j) { + std::cout << std::endl; + std::cout << " from " << *(ee.call_stack[j]->filename) << " (" << ee.call_stack[j]->start.line << ", " << ee.call_stack[j]->start.column << ")"; } - std::cout << std::endl; - error = EXIT_FAILURE; - } - catch (std::exception &e) { - std::cout << e.what() << std::endl; - error = EXIT_FAILURE; } + std::cout << std::endl; + return EXIT_FAILURE; + } + catch (std::exception &e) { + std::cout << e.what() << std::endl; + return EXIT_FAILURE; } } - return error ; + return EXIT_SUCCESS; } -