// This file is part of fityk program. Copyright (C) Marcin Wojdyr // Licence: GNU General Public License version 2 // $Id: cmd2.cpp 297 2007-05-25 02:33:19Z wojdyr $ /// big grammars in Spirit take a lot of time and memory to compile /// so they must be splitted into separate compilation units /// that's the only reason why this file is not a part of cmd.cpp #include #include #include #include #include #include #include #include "cmd2.h" #include "optional_suffix.h" #include "logic.h" #include "data.h" #include "sum.h" #include "ui.h" #include "fit.h" #include "settings.h" #include "datatrans.h" #include "guess.h" #include "var.h" #include "func.h" #include "ast.h" #ifndef CONFIGURE_BUILD # define CONFIGURE_BUILD "UNKNOWN" #endif #ifndef CONFIGURE_ARGS # define CONFIGURE_ARGS "UNKNOWN" #endif using namespace std; namespace cmdgram { bool with_plus, deep_cp; string t, t2, t3, output_redir; string prepared_info; bool info_append; int tmp_int, tmp_int2, ds_pref; double tmp_real, tmp_real2; vector vt, vr; vector vn, vds; const int new_dataset = -1; const int all_datasets = -2; bool outdated_plot = false; bool no_info_output = false; vector get_datasets_from_indata() { vector result; if (vds.empty()) { if (AL->get_ds_count() == 1) result.push_back(AL->get_ds(0)); else throw ExecuteError("Dataset must be specified (eg. 'in @0')."); } else if (vds.size() == 1 && vds[0] == all_datasets) for (int i = 0; i < AL->get_ds_count(); ++i) result.push_back(AL->get_ds(i)); else for (vector::const_iterator i = vds.begin(); i != vds.end(); ++i) result.push_back(AL->get_ds(*i)); return result; } IntRangeGrammar IntRangeG; } //namespace cmdgram using namespace cmdgram; namespace { void do_import_dataset(char const*, char const*) { AL->import_dataset(tmp_int, t, t2, vn); outdated_plot=true; } void do_export_dataset(char const*, char const*) { vector const& ff_names = AL->get_sum(tmp_int)->get_ff_names(); AL->get_data(tmp_int)->export_to_file(t, vt, ff_names); } void do_append_data(char const*, char const*) { int n = AL->append_ds(); AL->activate_ds(n); outdated_plot=true; } void do_load_data_sum(char const*, char const*) { vector dd; for (vector::const_iterator i = vn.begin(); i != vn.end(); ++i) dd.push_back(AL->get_data(*i)); if (tmp_int == new_dataset) tmp_int = AL->append_ds(); AL->get_data(tmp_int)->load_data_sum(dd, t); AL->activate_ds(tmp_int); outdated_plot=true; } void do_plot(char const*, char const*) { if (vds.size() == 1 && vds[0] >= 0) AL->activate_ds(vds[0]); bool need_ds = false; for (vector::const_iterator i = vr.begin(); i != vr.end(); ++i) if (i->empty()) need_ds = true; if (need_ds) { vector dsds = get_datasets_from_indata(); //move active ds to the front DataWithSum* ads = AL->get_ds(AL->get_active_ds_position()); vector::iterator pos = find(dsds.begin(),dsds.end(), ads); if (pos != dsds.end() && pos != dsds.begin()) { *pos = dsds[0]; dsds[0] = ads; } AL->view.set_datasets(dsds); } AL->view.parse_and_set(vr); AL->get_ui()->draw_plot(1, true); outdated_plot = false; } void do_output_info(char const*, char const*) { prepared_info = strip_string(prepared_info); if (no_info_output) return; if (output_redir.empty()) AL->rmsg(prepared_info); else { ofstream os(output_redir.c_str(), ios::out | (info_append ? ios::app : ios::trunc)); if (!os) throw ExecuteError("Can't open file: " + output_redir); os << prepared_info << endl; } } void do_print_info(char const* a, char const* b) { string s = string(a,b); string m; vector const &variables = AL->get_variables(); vector const &functions = AL->get_functions(); if (s.empty()) m = "info about what?"; else if (s == "version") { if (with_plus) { m = "Version: " VERSION "\nBuild system type: " CONFIGURE_BUILD "\nConfigured with: " CONFIGURE_ARGS #ifdef __GNUC__ "\nCompiler: GCC" #endif #ifdef __VERSION__ "\nCompiler version: " __VERSION__ #endif "\nCompilation date: " __DATE__ "\nBoost.Spirit version: " + S(SPIRIT_VERSION / 0x1000) + "." + S(SPIRIT_VERSION % 0x1000 / 0x0100) + "." + S(SPIRIT_VERSION % 0x0100); } else m = VERSION; } else if (s == "variables") { if (variables.empty()) m = "No variables found."; else { m = "Defined variables: "; for (vector::const_iterator i = variables.begin(); i != variables.end(); ++i) if (with_plus) m += "\n" + (*i)->get_info(AL->get_parameters(), false); else if ((*i)->is_visible()) m += (*i)->xname + " "; } } else if (s[0] == '$') { const Variable* v = AL->find_variable(string(s, 1)); m = v->get_info(AL->get_parameters(), with_plus); if (with_plus) { vector refs = AL->get_variable_references(string(s, 1)); if (!refs.empty()) m += "\nreferenced by: " + join_vector(refs, ", "); } } else if (s == "functions") { if (functions.empty()) m = "No functions found."; else { m = "Defined functions: "; for (vector::const_iterator i = functions.begin(); i != functions.end(); ++i) if (with_plus) m += "\n" + (*i)->get_info(variables, AL->get_parameters()); else m += (*i)->xname + " "; } } else if (s == "types") { m = "Defined function types: "; vector const& types = Function::get_all_types(); for (vector::const_iterator i = types.begin(); i != types.end(); ++i) if (with_plus) m += "\n" + Function::get_formula(*i); else m += *i + " "; } else if (s[0] == '%') { const Function* f = AL->find_function(string(s, 1)); m = f->get_info(variables, AL->get_parameters(), with_plus); } else if (s == "datasets") { m = S(AL->get_ds_count()) + " datasets."; if (with_plus) for (int i = 0; i < AL->get_ds_count(); ++i) m += "\n@" + S(i) + ": " + AL->get_data(i)->get_title(); } else if (s[0] == '@') { Data const* data = AL->get_data(tmp_int); if (s.find(".title") != string::npos) m = data->get_title(); else if (s.find(".filename") != string::npos) m = data->get_filename(); else m = data->get_info(); } else if (s == "view") { m = AL->view.str(); } else if (s == "set") m = AL->get_settings()->print_usage(); else if (startswith(s, "fit-history")) m = AL->get_fit_container()->param_history_info(); else if (startswith(s, "fit")) m = AL->get_fit()->get_info(get_datasets_from_indata()); else if (startswith(s, "errors")) m = AL->get_fit()->getErrorInfo(get_datasets_from_indata(), with_plus); else if (startswith(s, "peaks")) { vector errors; vector v = get_datasets_from_indata(); if (with_plus) errors = AL->get_fit()->get_symmetric_errors(v); for (vector::const_iterator i=v.begin(); i!=v.end(); ++i){ m += "# " + (*i)->get_data()->get_title() + "\n"; m += (*i)->get_sum()->get_peak_parameters(errors) + "\n"; } } else if (startswith(s, "formula")) { vector v = get_datasets_from_indata(); for (vector::const_iterator i=v.begin(); i!=v.end(); ++i){ m += "# " + (*i)->get_data()->get_title() + "\n"; bool gnuplot = AL->get_settings()->get_e("formula-export-style")==1; m += (*i)->get_sum()->get_formula(!with_plus, gnuplot) + "\n"; } } else if (s == "commands") m = AL->get_ui()->get_commands().get_info(with_plus); else if (startswith(s, "guess")) { vector v = get_datasets_from_indata(); for (vector::const_iterator i = v.begin(); i != v.end(); ++i) m += get_guess_info(*i, vr); } prepared_info += "\n" + m; } void do_print_func(char const*, char const*) { vector const &names = AL->get_sum(ds_pref)->get_names(t2[0]); if (tmp_int < 0) tmp_int += names.size(); if (is_index(tmp_int, names)) prepared_info += "\n" + AL->find_function(names[tmp_int]) ->get_info(AL->get_variables(), AL->get_parameters(), with_plus); else prepared_info += "\nNot found."; } void do_print_sum_info(char const*, char const*) { string m = t2 + ": "; vector const &idx = AL->get_sum(ds_pref)->get_indices(t2[0]); for (vector::const_iterator i = idx.begin(); i != idx.end(); ++i) { Function const* f = AL->get_function(*i); if (with_plus) m += "\n" + f->get_info(AL->get_variables(), AL->get_parameters()); else m += f->xname + " "; } prepared_info += "\n" + m; } void do_print_sum_derivatives_info(char const*, char const*) { fp x = get_transform_expression_value(t2, AL->get_data(ds_pref)); Sum const* sum = AL->get_sum(ds_pref); vector symb = sum->get_symbolic_derivatives(x); vector num = sum->get_numeric_derivatives(x, 1e-4); assert (symb.size() == num.size()); string m = "F(" + S(x) + ")=" + S(sum->value(x)); for (int i = 0; i < size(num); ++i) { if (is_neq(symb[i], 0) || is_neq(num[i], 0)) m += "\ndF / d " + AL->find_variable_handling_param(i)->xname + " = (symb.) " + S(symb[i]) + " = (num.) " + S(num[i]); } prepared_info += "\n" + m; } void do_print_deriv(char const* a, char const* b) { string s = string(a, b); prepared_info += "\n" + get_derivatives_str(s); } void do_print_debug_info(char const*, char const*) { string m; if (t == "idx") { // show varnames and var_idx from VariableUser for (int i = 0; i < size(AL->get_functions()); ++i) m += S(i) + ": " + AL->get_function(i)->get_debug_idx_info() +"\n"; for (int i = 0; i < size(AL->get_variables()); ++i) m += S(i) + ": " + AL->get_variable(i)->get_debug_idx_info() +"\n"; } else if (t == "rd") { // show values of derivatives for all variables for (int i = 0; i < size(AL->get_variables()); ++i) { Variable const* var = AL->get_variable(i); m += var->xname + ": "; vector const& rd = var->get_recursive_derivatives(); for (vector::const_iterator i = rd.begin(); i != rd.end(); ++i) m += S(i->p) + "/" + AL->find_variable_handling_param(i->p)->xname + "/" + S(i->mult) + " "; m += "\n"; } } else if (t.size() > 0 && t[0] == '%') { // show bytecode Function const* f = AL->find_function(t); m = f->get_bytecode(); } AL->rmsg(m); } void do_print_data_expr(char const*, char const*) { string s; if (vds.empty() && !is_data_dependent_expression(t2)) //no data s = S(get_transform_expression_value(t2, 0)); else { vector v = get_datasets_from_indata(); if (v.size() == 1) s = S(get_transform_expression_value(t2, v[0]->get_data())); else { map m; for (int i = 0; i < AL->get_ds_count(); ++i) m[AL->get_ds(i)] = i; for (vector::const_iterator i = v.begin(); i != v.end(); ++i) { fp k = get_transform_expression_value(t2, (*i)->get_data()); if (i != v.begin()) s += "\n"; s += "in @" + S(m[*i]); if (with_plus) s += " " + (*i)->get_data()->get_title(); s += ": " + S(k); } } } prepared_info += "\n" + s; } void do_print_func_type(char const* a, char const* b) { string s = string(a,b); string m = Function::get_formula(s); if (m.empty()) m = "Undefined function type: " + s; prepared_info += "\n" + m; } void do_guess(char const*, char const*) { vector v = get_datasets_from_indata(); for (vector::const_iterator i = v.begin(); i != v.end(); ++i) guess_and_add(*i, t, t2, vr, vt); outdated_plot=true; } void set_data_title(char const*, char const*) { AL->get_data(ds_pref)->title = t; } void do_list_commands(char const*, char const*) { vector cc = AL->get_ui()->get_commands().get_commands(tmp_int, tmp_int2, with_plus); prepared_info += "\n" + join_vector(cc, "\n"); } } //namespace template Cmd2Grammar::definition::definition(Cmd2Grammar const& /*self*/) { //these static constants for assign_a are workaround for assign_a //problems, as proposed by Joao Abecasis at Spirit-general ML //Message-ID: <435FB3DD.8030205@gmail.com> //Subject: [Spirit-general] Re: weird assign_a(x,y) problem static const bool true_ = true; static const bool false_ = false; static const int minus_one = -1; static const char *dot = "."; static const char *empty = ""; in_data = eps_p [clear_a(vds)] >> !("in" >> (lexeme_d['@' >> uint_p [push_back_a(vds)] ] % ',' | str_p("@*") [push_back_a(vds, all_datasets)] ) ) ; ds_prefix = lexeme_d['@' >> uint_p [assign_a(ds_pref)] >> '.'] | eps_p [assign_a(ds_pref, minus_one)] ; compact_str = lexeme_d['\'' >> (+~ch_p('\''))[assign_a(t)] >> '\''] | lexeme_d[+chset<>(anychar_p - chset<>(" \t\n\r;,#"))] [assign_a(t)] ; type_name = lexeme_d[(upper_p >> +alnum_p)] ; function_param = lexeme_d[alpha_p >> *(alnum_p | '_')] ; existing_dataset_nr = lexeme_d['@' >> uint_p [assign_a(tmp_int)] ] ; dataset_nr = str_p("@+") [assign_a(tmp_int, new_dataset)] | existing_dataset_nr ; dataset_handling = (dataset_nr >> ch_p('<') >> compact_str //load from file >> lexeme_d[!(alpha_p >> *alnum_p)] [assign_a(t2)] [clear_a(vn)] >> !(uint_p [push_back_a(vn)] % ',') ) [&do_import_dataset] | dataset_nr >> ch_p('=') [clear_a(vn)] [assign_a(t, empty)] //sum/dup >> !(lexeme_d[lower_p >> +(alnum_p | '-' | '_')] [assign_a(t)]) >> (lexeme_d['@' >> uint_p [push_back_a(vn)] ] % '+') [&do_load_data_sum] | (existing_dataset_nr [clear_a(vt)] >> !('(' >> ((DataExpressionG | ("*F(" >> DataExpressionG >> ")") ) [push_back_a(vt)] % ',') >> ')') >> '>' >> compact_str) [&do_export_dataset] | str_p("@+")[&do_append_data] ; plot_range //first clear vr if needed = (ch_p('[') >> ']') [push_back_a(vr,empty)][push_back_a(vr,empty)] | '[' >> (real_p|"."|eps_p) [push_back_a(vr)] >> ':' >> (real_p|"."|eps_p) [push_back_a(vr)] >> ']' | str_p(".") [push_back_a(vr,dot)][push_back_a(vr,dot)] // [.:.] | eps_p [push_back_a(vr,empty)][push_back_a(vr,empty)] // [:] ; info_arg = (str_p("commands") >> IntRangeG) [&do_list_commands] | ( str_p("version") | str_p("variables") | VariableLhsG | str_p("types") | str_p("functions") | str_p("datasets") | str_p("commands") | str_p("view") | str_p("set")) [&do_print_info] | ((str_p("fit-history") | "fit" | "errors" | "peaks" | "formula" ) >> in_data) [&do_print_info] | (str_p("guess") [clear_a(vr)] >> plot_range >> in_data) [&do_print_info] | type_name[&do_print_func_type] | (no_actions_d[DataExpressionG][assign_a(t2)] >> in_data) [&do_print_data_expr] | FunctionLhsG [&do_print_info] | ds_prefix >> (str_p("F")|"Z")[assign_a(t2)] >> ( ('[' >> int_p [assign_a(tmp_int)] >> ']') [&do_print_func] | eps_p [&do_print_sum_info] ) | (ds_prefix >> str_p("dF") >> '(' >> no_actions_d[DataExpressionG][assign_a(t2)] >> ')') [&do_print_sum_derivatives_info] | (existing_dataset_nr >> (str_p(".filename") | ".title" | eps_p)) [&do_print_info] | "debug " >> compact_str [&do_print_debug_info] //no output_redir // this will eat also ',', because voigt(x,y) needs it // unfortunatelly "i der x^2, sin(x)" is made impossible | "der " >> (+chset<>(anychar_p - chset<>(";#"))) [&do_print_deriv] | eps_p [&do_print_info] ; guess = (FunctionLhsG [assign_a(t)] >> '=' | eps_p [assign_a(t, empty)] ) >> optional_suffix_p("g","uess")[clear_a(vt)] [clear_a(vr)] >> type_name [assign_a(t2)] >> plot_range >> !((function_param >> '=' >> no_actions_d[FuncG]) [push_back_a(vt)] % ',') >> in_data ; optional_plus = str_p("+") [assign_a(with_plus, true_)] | eps_p [assign_a(with_plus, false_)] ; statement = (optional_suffix_p("i","nfo") [assign_a(output_redir, empty)] [assign_a(prepared_info, empty)] >> optional_plus >> (info_arg % ',') >> !( ( str_p(">>") [assign_a(info_append, true_)] | str_p(">") [assign_a(info_append, false_)] ) >> compact_str [assign_a(output_redir, t)] ) ) [&do_output_info] | (optional_suffix_p("p","lot") [clear_a(vr)] >> plot_range >> plot_range >> in_data) [&do_plot] | guess [&do_guess] | (ds_prefix >> "title" >> '=' >> compact_str)[&set_data_title] | dataset_handling ; } template Cmd2Grammar::definition, match_policy, action_policy> > >::definition(Cmd2Grammar const&); template Cmd2Grammar::definition, match_policy, no_actions_action_policy > > >::definition(Cmd2Grammar const&); Cmd2Grammar cmd2G;