1/** @file ginsh_parser.ypp 2 * 3 * Input grammar definition for ginsh. 4 * This file must be processed with yacc/bison. */ 5 6/* 7 * GiNaC Copyright (C) 1999-2022 Johannes Gutenberg University Mainz, Germany 8 * 9 * This program is free software; you can redistribute it and/or modify 10 * it under the terms of the GNU General Public License as published by 11 * the Free Software Foundation; either version 2 of the License, or 12 * (at your option) any later version. 13 * 14 * This program is distributed in the hope that it will be useful, 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 * GNU General Public License for more details. 18 * 19 * You should have received a copy of the GNU General Public License 20 * along with this program; if not, write to the Free Software 21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 22 */ 23 24 25/* 26 * Definitions 27 */ 28 29%{ 30#ifdef HAVE_CONFIG_H 31#include "config.h" 32#endif 33#ifdef HAVE_RUSAGE 34#include <sys/resource.h> 35#else 36#include <ctime> 37#endif 38 39#ifdef HAVE_UNISTD_H 40#include <sys/types.h> 41#include <unistd.h> 42#endif 43 44#include <stdexcept> 45 46#include "ginsh.h" 47 48using namespace std; 49using namespace GiNaC; 50 51#define YYERROR_VERBOSE 1 52 53#ifdef HAVE_LIBREADLINE 54// Original readline settings 55static int orig_completion_append_character; 56static const char *orig_basic_word_break_characters; 57 58#if (RL_VERSION_MAJOR >= 5) 59#define GINAC_RL_COMPLETER_CAST(a) const_cast<char *>((a)) 60#else 61#define GINAC_RL_COMPLETER_CAST(a) (a) 62#endif 63#endif // HAVE_LIBREADLINE 64 65// Expression stack for %, %% and %%% 66static void push(const ex &e); 67static ex exstack[3]; 68// Assigned symbols 69static exmap assigned_symbol_table; 70 71// Start and end time for the time() function 72#ifdef HAVE_RUSAGE 73static struct rusage start_time, end_time; 74#define START_TIMER getrusage(RUSAGE_SELF, &start_time); 75#define STOP_TIMER getrusage(RUSAGE_SELF, &end_time); 76#define PRINT_TIME_USED cout << \ 77 (end_time.ru_utime.tv_sec - start_time.ru_utime.tv_sec) + \ 78 (end_time.ru_stime.tv_sec - start_time.ru_stime.tv_sec) + \ 79 double(end_time.ru_utime.tv_usec - start_time.ru_utime.tv_usec) / 1e6 + \ 80 double(end_time.ru_stime.tv_usec - start_time.ru_stime.tv_usec) / 1e6 \ 81 << 's' << endl; 82#else 83static std::clock_t start_time, end_time; 84#define START_TIMER start_time = std::clock(); 85#define STOP_TIMER end_time = std::clock(); 86#define PRINT_TIME_USED \ 87 cout << double(end_time - start_time)/CLOCKS_PER_SEC << 's' << endl; 88#endif 89 90// Table of functions (a multimap, because one function may appear with different 91// numbers of parameters) 92typedef ex (*fcnp)(const exprseq &e); 93typedef ex (*fcnp2)(const exprseq &e, int serial); 94 95struct fcn_desc { 96 fcn_desc() : p(nullptr), num_params(0), is_ginac(false), serial(0) {} 97 fcn_desc(fcnp func, int num) : p(func), num_params(num), is_ginac(false), serial(0) {} 98 fcn_desc(fcnp2 func, int num, int ser) : p((fcnp)func), num_params(num), is_ginac(true), serial(ser) {} 99 100 fcnp p; // Pointer to function 101 int num_params; // Number of parameters (0 = arbitrary) 102 bool is_ginac; // Flag: function is GiNaC function 103 int serial; // GiNaC function serial number (if is_ginac == true) 104}; 105 106typedef multimap<string, fcn_desc> fcn_tab; 107static fcn_tab fcns; 108 109static fcn_tab::const_iterator find_function(const ex &sym, int req_params); 110 111// Table to map help topics to help strings 112typedef multimap<string, string> help_tab; 113static help_tab help; 114 115static void insert_fcn_help(const char *name, const char *str); 116static void print_help(const string &topic); 117static void print_help_topics(void); 118%} 119 120/* Tokens (T_LITERAL means a literal value returned by the parser, but not 121 of class numeric or symbol (e.g. a constant or the FAIL object)) */ 122%token T_NUMBER T_SYMBOL T_LITERAL T_DIGITS T_QUOTE T_QUOTE2 T_QUOTE3 123%token T_EQUAL T_NOTEQ T_LESSEQ T_GREATEREQ 124 125%token T_QUIT T_WARRANTY T_PRINT T_IPRINT T_PRINTLATEX T_PRINTCSRC T_TIME 126%token T_XYZZY T_INVENTORY T_LOOK T_SCORE T_COMPLEX_SYMBOLS T_REAL_SYMBOLS 127 128/* Operator precedence and associativity */ 129%right '=' 130%left T_EQUAL T_NOTEQ 131%left '<' '>' T_LESSEQ T_GREATEREQ 132%left '+' '-' 133%left '*' '/' 134%nonassoc NEG 135%right '^' 136%nonassoc '!' 137 138%start input 139 140 141/* 142 * Grammar rules 143 */ 144 145%% 146input : /* empty */ 147 | input line 148 ; 149 150line : ';' 151 | exp ';' { 152 try { 153 cout << $1 << endl; 154 push($1); 155 } catch (exception &e) { 156 cerr << e.what() << endl; 157 YYERROR; 158 } 159 } 160 | exp ':' { 161 try { 162 push($1); 163 } catch (exception &e) { 164 std::cerr << e.what() << endl; 165 YYERROR; 166 } 167 } 168 | T_PRINT '(' exp ')' ';' { 169 try { 170 $3.print(print_tree(std::cout)); 171 } catch (exception &e) { 172 std::cerr << e.what() << endl; 173 YYERROR; 174 } 175 } 176 | T_IPRINT '(' exp ')' ';' { 177 try { 178 ex e = $3; 179 if (!e.info(info_flags::integer)) 180 throw (std::invalid_argument("argument to iprint() must be an integer")); 181 long i = ex_to<numeric>(e).to_long(); 182 cout << i << endl; 183 cout << "#o" << oct << i << endl; 184 cout << "#x" << hex << i << dec << endl; 185 } catch (exception &e) { 186 cerr << e.what() << endl; 187 YYERROR; 188 } 189 } 190 | T_PRINTLATEX '(' exp ')' ';' { 191 try { 192 $3.print(print_latex(std::cout)); cout << endl; 193 } catch (exception &e) { 194 std::cerr << e.what() << endl; 195 YYERROR; 196 } 197 } 198 | T_PRINTCSRC '(' exp ')' ';' { 199 try { 200 $3.print(print_csrc_double(std::cout)); cout << endl; 201 } catch (exception &e) { 202 std::cerr << e.what() << endl; 203 YYERROR; 204 } 205 } 206 | '?' T_SYMBOL {print_help(ex_to<symbol>($2).get_name());} 207 | '?' T_TIME {print_help("time");} 208 | '?' T_PRINT {print_help("print");} 209 | '?' T_IPRINT {print_help("iprint");} 210 | '?' T_PRINTLATEX {print_help("print_latex");} 211 | '?' T_PRINTCSRC {print_help("print_csrc");} 212 | '?' '?' {print_help_topics();} 213 | T_QUIT {YYACCEPT;} 214 | T_WARRANTY { 215 cout << "This program is free software; you can redistribute it and/or modify it under\n"; 216 cout << "the terms of the GNU General Public License as published by the Free Software\n"; 217 cout << "Foundation; either version 2 of the License, or (at your option) any later\n"; 218 cout << "version.\n"; 219 cout << "This program is distributed in the hope that it will be useful, but WITHOUT\n"; 220 cout << "ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS\n"; 221 cout << "FOR A PARTICULAR PURPOSE. See the GNU General Public License for more\n"; 222 cout << "details.\n"; 223 cout << "You should have received a copy of the GNU General Public License along with\n"; 224 cout << "this program. If not, write to the Free Software Foundation,\n"; 225 cout << "51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n"; 226 } 227 | T_XYZZY {cout << "Nothing happens.\n";} 228 | T_INVENTORY {cout << "You're not carrying anything.\n";} 229 | T_LOOK {cout << "You're in a twisty little maze of passages, all alike.\n";} 230 | T_SCORE { 231 cout << "If you were to quit now, you would score "; 232 cout << (syms.size() > 350 ? 350 : syms.size()); 233 cout << " out of a possible 350.\n"; 234 } 235 | T_REAL_SYMBOLS { symboltype = domain::real; } 236 | T_COMPLEX_SYMBOLS { symboltype = domain::complex; } 237 | T_TIME { START_TIMER } '(' exp ')' { STOP_TIMER PRINT_TIME_USED } 238 | error ';' {yyclearin; yyerrok;} 239 | error ':' {yyclearin; yyerrok;} 240 ; 241 242exp : T_NUMBER {$$ = $1;} 243 | T_SYMBOL { 244 auto i = assigned_symbol_table.find($1); 245 if (i == assigned_symbol_table.end()) 246 $$ = $1; 247 else 248 $$ = i->second; 249 } 250 | '\'' T_SYMBOL '\'' {$$ = $2;} 251 | T_LITERAL {$$ = $1;} 252 | T_DIGITS {$$ = $1;} 253 | T_QUOTE {$$ = exstack[0];} 254 | T_QUOTE2 {$$ = exstack[1];} 255 | T_QUOTE3 {$$ = exstack[2];} 256 | T_SYMBOL '(' exprseq ')' { 257 auto i = find_function($1, $3.nops()); 258 if (i->second.is_ginac) { 259 $$ = ((fcnp2)(i->second.p))(ex_to<exprseq>($3), i->second.serial); 260 } else { 261 $$ = (i->second.p)(ex_to<exprseq>($3)); 262 } 263 } 264 | T_DIGITS '=' T_NUMBER {$$ = $3; Digits = ex_to<numeric>($3).to_int();} 265 | T_SYMBOL '=' exp {$$ = $3; assigned_symbol_table[$1] = $3; } 266 | exp T_EQUAL exp {$$ = $1 == $3;} 267 | exp T_NOTEQ exp {$$ = $1 != $3;} 268 | exp '<' exp {$$ = $1 < $3;} 269 | exp T_LESSEQ exp {$$ = $1 <= $3;} 270 | exp '>' exp {$$ = $1 > $3;} 271 | exp T_GREATEREQ exp {$$ = $1 >= $3;} 272 | exp '+' exp {$$ = $1 + $3;} 273 | exp '-' exp {$$ = $1 - $3;} 274 | exp '*' exp {$$ = $1 * $3;} 275 | exp '/' exp {$$ = $1 / $3;} 276 | '-' exp %prec NEG {$$ = -$2;} 277 | '+' exp %prec NEG {$$ = $2;} 278 | exp '^' exp {$$ = power($1, $3);} 279 | exp '!' {$$ = factorial($1);} 280 | '(' exp ')' {$$ = $2;} 281 | '{' list_or_empty '}' {$$ = $2;} 282 | '[' matrix ']' {$$ = lst_to_matrix(ex_to<lst>($2));} 283 ; 284 285exprseq : exp {$$ = exprseq{$1};} 286 | exprseq ',' exp {exprseq es(ex_to<exprseq>($1)); $$ = es.append($3);} 287 ; 288 289list_or_empty: /* empty */ {$$ = *new lst;} 290 | list {$$ = $1;} 291 ; 292 293list : exp {$$ = lst{$1};} 294 | list ',' exp {lst l(ex_to<lst>($1)); $$ = l.append($3);} 295 ; 296 297matrix : '[' row ']' {$$ = lst{$2};} 298 | matrix ',' '[' row ']' {lst l(ex_to<lst>($1)); $$ = l.append($4);} 299 ; 300 301row : exp {$$ = lst{$1};} 302 | row ',' exp {lst l(ex_to<lst>($1)); $$ = l.append($3);} 303 ; 304 305 306/* 307 * Routines 308 */ 309 310%% 311// Error print routine 312int yyerror(const char *s) 313{ 314 cerr << s << " at " << yytext << endl; 315 return 0; 316} 317 318// Push expression "e" onto the expression stack (for ", "" and """) 319static void push(const ex &e) 320{ 321 exstack[2] = exstack[1]; 322 exstack[1] = exstack[0]; 323 exstack[0] = e; 324} 325 326 327/* 328 * Built-in functions 329 */ 330 331static ex f_collect(const exprseq &e) {return e[0].collect(e[1]);} 332static ex f_collect_distributed(const exprseq &e) {return e[0].collect(e[1], true);} 333static ex f_collect_common_factors(const exprseq &e) {return collect_common_factors(e[0]);} 334static ex f_convert_H_to_Li(const exprseq &e) {return convert_H_to_Li(e[0], e[1]);} 335static ex f_degree(const exprseq &e) {return e[0].degree(e[1]);} 336static ex f_denom(const exprseq &e) {return e[0].denom();} 337static ex f_evalf(const exprseq &e) {return e[0].evalf();} 338static ex f_evalm(const exprseq &e) {return e[0].evalm();} 339static ex f_eval_integ(const exprseq &e) {return e[0].eval_integ();} 340static ex f_expand(const exprseq &e) {return e[0].expand();} 341static ex f_factor(const exprseq &e) {return factor(e[0]);} 342static ex f_gcd(const exprseq &e) {return gcd(e[0], e[1]);} 343static ex f_has(const exprseq &e) {return e[0].has(e[1]) ? ex(1) : ex(0);} 344static ex f_lcm(const exprseq &e) {return lcm(e[0], e[1]);} 345static ex f_lcoeff(const exprseq &e) {return e[0].lcoeff(e[1]);} 346static ex f_ldegree(const exprseq &e) {return e[0].ldegree(e[1]);} 347static ex f_lsolve(const exprseq &e) {return lsolve(e[0], e[1]);} 348static ex f_nops(const exprseq &e) {return e[0].nops();} 349static ex f_normal(const exprseq &e) {return e[0].normal();} 350static ex f_numer(const exprseq &e) {return e[0].numer();} 351static ex f_numer_denom(const exprseq &e) {return e[0].numer_denom();} 352static ex f_pow(const exprseq &e) {return pow(e[0], e[1]);} 353static ex f_sqrt(const exprseq &e) {return sqrt(e[0]);} 354static ex f_sqrfree1(const exprseq &e) {return sqrfree(e[0]);} 355static ex f_subs2(const exprseq &e) {return e[0].subs(e[1]);} 356static ex f_tcoeff(const exprseq &e) {return e[0].tcoeff(e[1]);} 357 358#define CHECK_ARG(num, type, fcn) if (!is_a<type>(e[num])) throw(std::invalid_argument("argument " #num " to " #fcn "() must be a " #type)) 359 360static ex f_charpoly(const exprseq &e) 361{ 362 CHECK_ARG(0, matrix, charpoly); 363 return ex_to<matrix>(e[0]).charpoly(e[1]); 364} 365 366static ex f_coeff(const exprseq &e) 367{ 368 CHECK_ARG(2, numeric, coeff); 369 return e[0].coeff(e[1], ex_to<numeric>(e[2]).to_int()); 370} 371 372static ex f_content(const exprseq &e) 373{ 374 return e[0].content(e[1]); 375} 376 377static ex f_decomp_rational(const exprseq &e) 378{ 379 return decomp_rational(e[0], e[1]); 380} 381 382static ex f_determinant(const exprseq &e) 383{ 384 CHECK_ARG(0, matrix, determinant); 385 return ex_to<matrix>(e[0]).determinant(); 386} 387 388static ex f_diag(const exprseq &e) 389{ 390 size_t dim = e.nops(); 391 matrix &m = *new matrix(dim, dim); 392 for (size_t i=0; i<dim; i++) 393 m.set(i, i, e.op(i)); 394 return m; 395} 396 397static ex f_diff2(const exprseq &e) 398{ 399 CHECK_ARG(1, symbol, diff); 400 return e[0].diff(ex_to<symbol>(e[1])); 401} 402 403static ex f_diff3(const exprseq &e) 404{ 405 CHECK_ARG(1, symbol, diff); 406 CHECK_ARG(2, numeric, diff); 407 return e[0].diff(ex_to<symbol>(e[1]), ex_to<numeric>(e[2]).to_int()); 408} 409 410static ex f_divide(const exprseq &e) 411{ 412 ex q; 413 if (divide(e[0], e[1], q)) 414 return q; 415 else 416 return fail(); 417} 418 419static ex f_find(const exprseq &e) 420{ 421 exset found; 422 e[0].find(e[1], found); 423 lst l; 424 for (auto & i : found) 425 l.append(i); 426 return l; 427} 428 429static ex f_fsolve(const exprseq &e) 430{ 431 CHECK_ARG(1, symbol, fsolve); 432 CHECK_ARG(2, numeric, fsolve); 433 CHECK_ARG(3, numeric, fsolve); 434 return fsolve(e[0], ex_to<symbol>(e[1]), ex_to<numeric>(e[2]), ex_to<numeric>(e[3])); 435} 436 437static ex f_integer_content(const exprseq &e) 438{ 439 return e[0].expand().integer_content(); 440} 441 442static ex f_integral(const exprseq &e) 443{ 444 CHECK_ARG(0, symbol, integral); 445 return GiNaC::integral(e[0], e[1], e[2], e[3]); 446} 447 448static ex f_inverse(const exprseq &e) 449{ 450 CHECK_ARG(0, matrix, inverse); 451 return ex_to<matrix>(e[0]).inverse(); 452} 453 454static ex f_is(const exprseq &e) 455{ 456 CHECK_ARG(0, relational, is); 457 return (bool)ex_to<relational>(e[0]) ? ex(1) : ex(0); 458} 459 460class apply_map_function : public map_function { 461 ex apply; 462public: 463 apply_map_function(const ex & a) : apply(a) {} 464 virtual ~apply_map_function() {} 465 ex operator()(const ex & e) override { return apply.subs(wild() == e, true); } 466}; 467 468static ex f_map(const exprseq &e) 469{ 470 apply_map_function fcn(e[1]); 471 return e[0].map(fcn); 472} 473 474static ex f_match(const exprseq &e) 475{ 476 exmap repls; 477 if (e[0].match(e[1], repls)) { 478 lst repl_lst; 479 for (auto & i : repls) 480 repl_lst.append(relational(i.first, i.second, relational::equal)); 481 return repl_lst; 482 } 483 throw std::runtime_error("FAIL"); 484} 485 486static ex f_op(const exprseq &e) 487{ 488 CHECK_ARG(1, numeric, op); 489 int n = ex_to<numeric>(e[1]).to_int(); 490 if (n < 0 || n >= (int)e[0].nops()) 491 throw(std::out_of_range("second argument to op() is out of range")); 492 return e[0].op(n); 493} 494 495static ex f_prem(const exprseq &e) 496{ 497 return prem(e[0], e[1], e[2]); 498} 499 500static ex f_primpart(const exprseq &e) 501{ 502 return e[0].primpart(e[1]); 503} 504 505static ex f_quo(const exprseq &e) 506{ 507 return quo(e[0], e[1], e[2]); 508} 509 510static ex f_rank(const exprseq &e) 511{ 512 CHECK_ARG(0, matrix, rank); 513 return ex_to<matrix>(e[0]).rank(); 514} 515 516static ex f_rem(const exprseq &e) 517{ 518 return rem(e[0], e[1], e[2]); 519} 520 521static ex f_resultant(const exprseq &e) 522{ 523 CHECK_ARG(2, symbol, resultant); 524 return resultant(e[0], e[1], ex_to<symbol>(e[2])); 525} 526 527static ex f_series(const exprseq &e) 528{ 529 CHECK_ARG(2, numeric, series); 530 return e[0].series(e[1], ex_to<numeric>(e[2]).to_int()); 531} 532 533static ex f_sprem(const exprseq &e) 534{ 535 return sprem(e[0], e[1], e[2]); 536} 537 538static ex f_sqrfree2(const exprseq &e) 539{ 540 CHECK_ARG(1, lst, sqrfree); 541 return sqrfree(e[0], ex_to<lst>(e[1])); 542} 543 544static ex f_subs3(const exprseq &e) 545{ 546 CHECK_ARG(1, lst, subs); 547 CHECK_ARG(2, lst, subs); 548 return e[0].subs(ex_to<lst>(e[1]), ex_to<lst>(e[2])); 549} 550 551static ex f_trace(const exprseq &e) 552{ 553 CHECK_ARG(0, matrix, trace); 554 return ex_to<matrix>(e[0]).trace(); 555} 556 557static ex f_transpose(const exprseq &e) 558{ 559 CHECK_ARG(0, matrix, transpose); 560 return ex_to<matrix>(e[0]).transpose(); 561} 562 563static ex f_unassign(const exprseq &e) 564{ 565 CHECK_ARG(0, symbol, unassign); 566 exmap::iterator i = assigned_symbol_table.find(e[0]); 567 if (i != assigned_symbol_table.end()) 568 assigned_symbol_table.erase(i); 569 return e[0]; 570} 571 572static ex f_unit(const exprseq &e) 573{ 574 return e[0].unit(e[1]); 575} 576 577static ex f_basic_log_kernel(const exprseq &e) 578{ 579 return basic_log_kernel(); 580} 581 582static ex f_multiple_polylog_kernel(const exprseq &e) 583{ 584 return multiple_polylog_kernel(e[0]); 585} 586 587static ex f_ELi_kernel(const exprseq &e) 588{ 589 return ELi_kernel(e[0],e[1],e[2],e[3]); 590} 591 592static ex f_Ebar_kernel(const exprseq &e) 593{ 594 return Ebar_kernel(e[0],e[1],e[2],e[3]); 595} 596 597static ex f_Kronecker_dtau_kernel_4(const exprseq &e) 598{ 599 return Kronecker_dtau_kernel(e[0],e[1],e[2],e[3]); 600} 601 602static ex f_Kronecker_dtau_kernel_3(const exprseq &e) 603{ 604 return Kronecker_dtau_kernel(e[0],e[1],e[2]); 605} 606 607static ex f_Kronecker_dtau_kernel_2(const exprseq &e) 608{ 609 return Kronecker_dtau_kernel(e[0],e[1]); 610} 611 612static ex f_Kronecker_dz_kernel_5(const exprseq &e) 613{ 614 return Kronecker_dz_kernel(e[0],e[1],e[2],e[3],e[4]); 615} 616 617static ex f_Kronecker_dz_kernel_4(const exprseq &e) 618{ 619 return Kronecker_dz_kernel(e[0],e[1],e[2],e[3]); 620} 621 622static ex f_Kronecker_dz_kernel_3(const exprseq &e) 623{ 624 return Kronecker_dz_kernel(e[0],e[1],e[2]); 625} 626 627static ex f_Eisenstein_kernel_6(const exprseq &e) 628{ 629 return Eisenstein_kernel(e[0],e[1],e[2],e[3],e[4],e[5]); 630} 631 632static ex f_Eisenstein_kernel_5(const exprseq &e) 633{ 634 return Eisenstein_kernel(e[0],e[1],e[2],e[3],e[4]); 635} 636 637static ex f_Eisenstein_h_kernel_5(const exprseq &e) 638{ 639 return Eisenstein_h_kernel(e[0],e[1],e[2],e[3],e[4]); 640} 641 642static ex f_Eisenstein_h_kernel_4(const exprseq &e) 643{ 644 return Eisenstein_h_kernel(e[0],e[1],e[2],e[3]); 645} 646 647static ex f_modular_form_kernel_3(const exprseq &e) 648{ 649 return modular_form_kernel(e[0],e[1],e[2]); 650} 651 652static ex f_modular_form_kernel_2(const exprseq &e) 653{ 654 return modular_form_kernel(e[0],e[1]); 655} 656 657static ex f_user_defined_kernel(const exprseq &e) 658{ 659 return user_defined_kernel(e[0],e[1]); 660} 661 662static ex f_q_expansion_modular_form(const exprseq &e) 663{ 664 if ( is_a<Eisenstein_kernel>(e[0]) ) { 665 return ex_to<Eisenstein_kernel>(e[0]).q_expansion_modular_form(e[1], ex_to<numeric>(e[2]).to_int()); 666 } 667 if ( is_a<Eisenstein_h_kernel>(e[0]) ) { 668 return ex_to<Eisenstein_h_kernel>(e[0]).q_expansion_modular_form(e[1], ex_to<numeric>(e[2]).to_int()); 669 } 670 if ( is_a<modular_form_kernel>(e[0]) ) { 671 return ex_to<modular_form_kernel>(e[0]).q_expansion_modular_form(e[1], ex_to<numeric>(e[2]).to_int()); 672 } 673 throw(std::invalid_argument("first argument must be a modular form")); 674} 675 676static ex f_dummy(const exprseq &e) 677{ 678 throw(std::logic_error("dummy function called (shouldn't happen)")); 679} 680 681// Tables for initializing the "fcns" map and the function help topics 682struct fcn_init { 683 const char *name; 684 fcnp p; 685 int num_params; 686}; 687 688static const fcn_init builtin_fcns[] = { 689 {"charpoly", f_charpoly, 2}, 690 {"coeff", f_coeff, 3}, 691 {"collect", f_collect, 2}, 692 {"collect_common_factors", f_collect_common_factors, 1}, 693 {"collect_distributed", f_collect_distributed, 2}, 694 {"content", f_content, 2}, 695 {"convert_H_to_Li", f_convert_H_to_Li, 2}, 696 {"decomp_rational", f_decomp_rational, 2}, 697 {"degree", f_degree, 2}, 698 {"denom", f_denom, 1}, 699 {"determinant", f_determinant, 1}, 700 {"diag", f_diag, 0}, 701 {"diff", f_diff2, 2}, 702 {"diff", f_diff3, 3}, 703 {"divide", f_divide, 2}, 704 {"evalf", f_evalf, 1}, 705 {"evalm", f_evalm, 1}, 706 {"eval_integ", f_eval_integ, 1}, 707 {"expand", f_expand, 1}, 708 {"factor", f_factor, 1}, 709 {"find", f_find, 2}, 710 {"fsolve", f_fsolve, 4}, 711 {"gcd", f_gcd, 2}, 712 {"has", f_has, 2}, 713 {"integer_content", f_integer_content, 1}, 714 {"integral", f_integral, 4}, 715 {"inverse", f_inverse, 1}, 716 {"iprint", f_dummy, 0}, // for Tab-completion 717 {"is", f_is, 1}, 718 {"lcm", f_lcm, 2}, 719 {"lcoeff", f_lcoeff, 2}, 720 {"ldegree", f_ldegree, 2}, 721 {"lsolve", f_lsolve, 2}, 722 {"map", f_map, 2}, 723 {"match", f_match, 2}, 724 {"nops", f_nops, 1}, 725 {"normal", f_normal, 1}, 726 {"numer", f_numer, 1}, 727 {"numer_denom", f_numer_denom, 1}, 728 {"op", f_op, 2}, 729 {"pow", f_pow, 2}, 730 {"prem", f_prem, 3}, 731 {"primpart", f_primpart, 2}, 732 {"print", f_dummy, 0}, // for Tab-completion 733 {"print_csrc", f_dummy, 0}, // for Tab-completion 734 {"print_latex", f_dummy, 0}, // for Tab-completion 735 {"quo", f_quo, 3}, 736 {"rank", f_rank, 1}, 737 {"rem", f_rem, 3}, 738 {"resultant", f_resultant, 3}, 739 {"series", f_series, 3}, 740 {"sprem", f_sprem, 3}, 741 {"sqrfree", f_sqrfree1, 1}, 742 {"sqrfree", f_sqrfree2, 2}, 743 {"sqrt", f_sqrt, 1}, 744 {"subs", f_subs2, 2}, 745 {"subs", f_subs3, 3}, 746 {"tcoeff", f_tcoeff, 2}, 747 {"time", f_dummy, 0}, // for Tab-completion 748 {"trace", f_trace, 1}, 749 {"transpose", f_transpose, 1}, 750 {"unassign", f_unassign, 1}, 751 {"unit", f_unit, 2}, 752 {"basic_log_kernel", f_basic_log_kernel, 0}, 753 {"multiple_polylog_kernel", f_multiple_polylog_kernel, 1}, 754 {"ELi_kernel", f_ELi_kernel, 4}, 755 {"Ebar_kernel", f_Ebar_kernel, 4}, 756 {"Kronecker_dtau_kernel", f_Kronecker_dtau_kernel_4, 4}, 757 {"Kronecker_dtau_kernel", f_Kronecker_dtau_kernel_3, 3}, 758 {"Kronecker_dtau_kernel", f_Kronecker_dtau_kernel_2, 2}, 759 {"Kronecker_dz_kernel", f_Kronecker_dz_kernel_5, 5}, 760 {"Kronecker_dz_kernel", f_Kronecker_dz_kernel_4, 4}, 761 {"Kronecker_dz_kernel", f_Kronecker_dz_kernel_3, 3}, 762 {"Eisenstein_kernel", f_Eisenstein_kernel_6, 6}, 763 {"Eisenstein_kernel", f_Eisenstein_kernel_5, 5}, 764 {"Eisenstein_h_kernel", f_Eisenstein_h_kernel_5, 5}, 765 {"Eisenstein_h_kernel", f_Eisenstein_h_kernel_4, 4}, 766 {"modular_form_kernel", f_modular_form_kernel_3, 3}, 767 {"modular_form_kernel", f_modular_form_kernel_2, 2}, 768 {"user_defined_kernel", f_user_defined_kernel, 2}, 769 {"q_expansion_modular_form", f_q_expansion_modular_form, 3}, 770 {nullptr, f_dummy, 0} // End marker 771}; 772 773struct fcn_help_init { 774 const char *name; 775 const char *help; 776}; 777 778static const fcn_help_init builtin_help[] = { 779 {"acos", "inverse cosine function"}, 780 {"acosh", "inverse hyperbolic cosine function"}, 781 {"asin", "inverse sine function"}, 782 {"asinh", "inverse hyperbolic sine function"}, 783 {"atan", "inverse tangent function"}, 784 {"atan2", "inverse tangent function with two arguments"}, 785 {"atanh", "inverse hyperbolic tangent function"}, 786 {"beta", "Beta function"}, 787 {"binomial", "binomial function"}, 788 {"cos", "cosine function"}, 789 {"cosh", "hyperbolic cosine function"}, 790 {"exp", "exponential function"}, 791 {"factorial", "factorial function"}, 792 {"lgamma", "natural logarithm of Gamma function"}, 793 {"tgamma", "Gamma function"}, 794 {"log", "natural logarithm"}, 795 {"psi", "psi function\npsi(x) is the digamma function, psi(n,x) the nth polygamma function"}, 796 {"sin", "sine function"}, 797 {"sinh", "hyperbolic sine function"}, 798 {"tan", "tangent function"}, 799 {"tanh", "hyperbolic tangent function"}, 800 {"zeta", "zeta function\nzeta(x) is Riemann's zeta function, zetaderiv(n,x) its nth derivative.\nIf x is a GiNaC::lst, it is a multiple zeta value\nzeta(x,s) is an alternating Euler sum"}, 801 {"G", "multiple polylogarithm (integral representation)"}, 802 {"Li2", "dilogarithm"}, 803 {"Li3", "trilogarithm"}, 804 {"Li", "(multiple) polylogarithm"}, 805 {"S", "Nielsen's generalized polylogarithm"}, 806 {"H", "harmonic polylogarithm"}, 807 {"EllipticK", "complete elliptic integral of the first kind"}, 808 {"EllipticE", "complete elliptic integral of the second kind"}, 809 {"iterated_integral", "iterated integral"}, 810 {"Order", "order term function (for truncated power series)"}, 811 {"Derivative", "inert differential operator"}, 812 {nullptr, nullptr} // End marker 813}; 814 815#include "ginsh_extensions.h" 816 817 818/* 819 * Add functions to ginsh 820 */ 821 822// Functions from fcn_init array 823static void insert_fcns(const fcn_init *p) 824{ 825 while (p->name) { 826 fcns.insert(make_pair(string(p->name), fcn_desc(p->p, p->num_params))); 827 p++; 828 } 829} 830 831static ex f_ginac_function(const exprseq &es, int serial) 832{ 833 return GiNaC::function(serial, es); 834} 835 836// All registered GiNaC functions 837namespace GiNaC { 838static void ginsh_get_ginac_functions(void) 839{ 840 unsigned serial = 0; 841 for (auto & i : function::get_registered_functions()) { 842 fcns.insert(make_pair(i.get_name(), fcn_desc(f_ginac_function, i.get_nparams(), serial))); 843 serial++; 844 } 845} 846} 847 848 849/* 850 * Find a function given a name and number of parameters. Throw exceptions on error. 851 */ 852 853static fcn_tab::const_iterator find_function(const ex &sym, int req_params) 854{ 855 const string &name = ex_to<symbol>(sym).get_name(); 856 typedef fcn_tab::const_iterator I; 857 pair<I, I> b = fcns.equal_range(name); 858 if (b.first == b.second) 859 throw(std::logic_error("unknown function '" + name + "'")); 860 else { 861 for (I i=b.first; i!=b.second; i++) 862 if ((i->second.num_params == 0) || (i->second.num_params == req_params)) 863 return i; 864 } 865 throw(std::logic_error("invalid number of arguments to " + name + "()")); 866} 867 868 869/* 870 * Insert help strings 871 */ 872 873// Normal help string 874static void insert_help(const char *topic, const char *str) 875{ 876 help.insert(make_pair(string(topic), string(str))); 877} 878 879// Help string for functions, automatically generates synopsis 880static void insert_fcn_help(const char *name, const char *str) 881{ 882 typedef fcn_tab::const_iterator I; 883 pair<I, I> b = fcns.equal_range(name); 884 if (b.first != b.second) { 885 string help_str = string(name) + "("; 886 for (int i=0; i<b.first->second.num_params; i++) { 887 if (i) 888 help_str += ", "; 889 help_str += "expression"; 890 } 891 help_str += ") - "; 892 help_str += str; 893 help.insert(make_pair(string(name), help_str)); 894 } 895} 896 897// Help strings for functions from fcn_help_init array 898static void insert_help(const fcn_help_init *p) 899{ 900 while (p->name) { 901 insert_fcn_help(p->name, p->help); 902 p++; 903 } 904} 905 906 907/* 908 * Print help to cout 909 */ 910 911// Help for a given topic 912static void print_help(const string &topic) 913{ 914 typedef help_tab::const_iterator I; 915 pair<I, I> b = help.equal_range(topic); 916 if (b.first == b.second) 917 cout << "no help for '" << topic << "'\n"; 918 else { 919 for (I i=b.first; i!=b.second; i++) 920 cout << i->second << endl; 921 } 922} 923 924// List of help topics 925static void print_help_topics(void) 926{ 927 cout << "Available help topics:\n"; 928 help_tab::const_iterator i; 929 string last_name = string("*"); 930 int num = 0; 931 for (i=help.begin(); i!=help.end(); i++) { 932 // Don't print duplicates 933 if (i->first != last_name) { 934 if (num) 935 cout << ", "; 936 num++; 937 cout << i->first; 938 last_name = i->first; 939 } 940 } 941 cout << "\nTo get help for a certain topic, type ?topic\n"; 942} 943 944 945/* 946 * Function name completion functions for readline 947 */ 948 949static char *fcn_generator(const char *text, int state) 950{ 951 static int len; // Length of word to complete 952 static fcn_tab::const_iterator index; // Iterator to function being currently considered 953 954 // If this is a new word to complete, initialize now 955 if (state == 0) { 956 index = fcns.begin(); 957 len = strlen(text); 958 } 959 960 // Return the next function which partially matches 961 while (index != fcns.end()) { 962 const char *fcn_name = index->first.c_str(); 963 ++index; 964 if (strncmp(fcn_name, text, len) == 0) 965 return strdup(fcn_name); 966 } 967 return nullptr; 968} 969 970#ifdef HAVE_LIBREADLINE 971static char **fcn_completion(const char *text, int start, int end) 972{ 973 if (rl_line_buffer[0] == '!') { 974 // For shell commands, revert back to filename completion 975 rl_completion_append_character = orig_completion_append_character; 976 rl_basic_word_break_characters = orig_basic_word_break_characters; 977 rl_completer_word_break_characters = GINAC_RL_COMPLETER_CAST(rl_basic_word_break_characters); 978 return rl_completion_matches(text, rl_filename_completion_function); 979 } else { 980 // Otherwise, complete function names 981 rl_completion_append_character = '('; 982 rl_basic_word_break_characters = " \t\n\"#$%&'()*+,-./:;<=>?@[\\]^`{|}~"; 983 rl_completer_word_break_characters = GINAC_RL_COMPLETER_CAST(rl_basic_word_break_characters); 984 return rl_completion_matches(text, fcn_generator); 985 } 986} 987#endif // HAVE_LIBREADLINE 988 989static void ginsh_readline_init(char* name) 990{ 991#ifdef HAVE_LIBREADLINE 992 // Init readline completer 993 rl_readline_name = name; 994 rl_attempted_completion_function = fcn_completion; 995 orig_completion_append_character = rl_completion_append_character; 996 orig_basic_word_break_characters = rl_basic_word_break_characters; 997#endif // HAVE_LIBREADLINE 998} 999 1000void greeting(void) 1001{ 1002 cout << "ginsh - GiNaC Interactive Shell (GiNaC V" << GINACLIB_VERSION << ")" << endl; 1003 cout << " __, _______ Copyright (C) 1999-2022 Johannes Gutenberg University Mainz,\n" 1004 << " (__) * | Germany. This is free software with ABSOLUTELY NO WARRANTY.\n" 1005 << " ._) i N a C | You are welcome to redistribute it under certain conditions.\n" 1006 << "<-------------' For details type `warranty;'.\n" << endl; 1007 cout << "Type ?? for a list of help topics." << endl; 1008} 1009 1010/* 1011 * Main program 1012 */ 1013 1014int main(int argc, char **argv) 1015{ 1016 // Print banner in interactive mode 1017 if (isatty(0)) 1018 greeting(); 1019 assigned_symbol_table = exmap(); 1020 1021 // Init function table 1022 insert_fcns(builtin_fcns); 1023 insert_fcns(extended_fcns); 1024 ginsh_get_ginac_functions(); 1025 1026 // Init help for operators (automatically generated from man page) 1027 insert_help("operators", "Operators in falling order of precedence:"); 1028#include "ginsh_op_help.h" 1029 1030 // Init help for built-in functions (automatically generated from man page) 1031#include "ginsh_fcn_help.h" 1032 1033 // Help for GiNaC functions is added manually 1034 insert_help(builtin_help); 1035 insert_help(extended_help); 1036 1037 // Help for other keywords 1038 insert_help("print", "print(expression) - dumps the internal structure of the given expression (for debugging)"); 1039 insert_help("iprint", "iprint(expression) - prints the given integer expression in decimal, octal, and hexadecimal bases"); 1040 insert_help("print_latex", "print_latex(expression) - prints a LaTeX representation of the given expression"); 1041 insert_help("print_csrc", "print_csrc(expression) - prints a C source code representation of the given expression"); 1042 1043 ginsh_readline_init(argv[0]); 1044 1045 // Init input file list, open first file 1046 num_files = argc - 1; 1047 file_list = argv + 1; 1048 if (num_files) { 1049 yyin = fopen(*file_list, "r"); 1050 if (yyin == nullptr) { 1051 cerr << "Can't open " << *file_list << endl; 1052 exit(1); 1053 } 1054 num_files--; 1055 file_list++; 1056 } 1057 1058 // Parse input, catch all remaining exceptions 1059 int result; 1060again: try { 1061 result = yyparse(); 1062 } catch (exception &e) { 1063 cerr << e.what() << endl; 1064 goto again; 1065 } 1066 return result; 1067} 1068