]> www.ginac.de Git - ginac.git/blob - ginsh/ginsh_parser.yy
Fixed 50 percent of the bugs on Alex' list. More, soon...
[ginac.git] / ginsh / ginsh_parser.yy
1 /** @file ginsh_parser.yy
2  *
3  *  Input grammar definition for ginsh.
4  *  This file must be processed with yacc/bison.
5  *
6  *  GiNaC Copyright (C) 1999 Johannes Gutenberg University Mainz, Germany
7  *
8  *  This program is free software; you can redistribute it and/or modify
9  *  it under the terms of the GNU General Public License as published by
10  *  the Free Software Foundation; either version 2 of the License, or
11  *  (at your option) any later version.
12  *
13  *  This program is distributed in the hope that it will be useful,
14  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  *  GNU General Public License for more details.
17  *
18  *  You should have received a copy of the GNU General Public License
19  *  along with this program; if not, write to the Free Software
20  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  */
22
23
24 /*
25  *  Definitions
26  */
27
28 %{
29 #include "config.h"
30
31 #include <sys/resource.h>
32
33 #if HAVE_UNISTD_H
34 #include <sys/types.h>
35 #include <unistd.h>
36 #endif
37
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <string.h>
41
42 extern "C" {
43 #include <readline/readline.h>
44 #include <readline/history.h>
45 }
46
47 #include <map>
48 #include <string>
49 #include <stdexcept>
50
51 #include <ginac/ginac.h>
52 #include "ginsh.h"
53
54 // Original readline settings
55 static int orig_completion_append_character;
56 static char *orig_basic_word_break_characters;
57
58 // Expression stack for ", "" and """
59 static void push(const ex &e);
60 static ex exstack[3];
61
62 // Start and end time for the time() function
63 static struct rusage start_time, end_time;
64
65 // Table of functions (a multimap, because one function may appear with different
66 // numbers of parameters)
67 typedef ex (*fcnp)(const exprseq &e);
68 typedef ex (*fcnp2)(const exprseq &e, int serial);
69
70 struct fcn_desc {
71         fcn_desc() : p(NULL), num_params(0) {}
72         fcn_desc(fcnp func, int num) : p(func), num_params(num), is_ginac(false) {}
73         fcn_desc(fcnp2 func, int num, int ser) : p((fcnp)func), num_params(num), is_ginac(true), serial(ser) {}
74
75         fcnp p;         // Pointer to function
76         int num_params; // Number of parameters (0 = arbitrary)
77         bool is_ginac;  // Flag: function is GiNaC function
78         int serial;     // GiNaC function serial number (if is_ginac == true)
79 };
80
81 typedef multimap<string, fcn_desc> fcn_tab;
82 static fcn_tab fcns;
83
84 static fcn_tab::const_iterator find_function(const ex &sym, int req_params);
85
86 static ex lst2matrix(const ex &l);
87 %}
88
89 /* Tokens (T_LITERAL means a literal value returned by the parser, but not
90    of class numeric or symbol (e.g. a constant or the FAIL object)) */
91 %token T_NUMBER T_SYMBOL T_LITERAL T_DIGITS T_QUOTE T_QUOTE2 T_QUOTE3
92 %token T_EQUAL T_NOTEQ T_LESSEQ T_GREATEREQ T_MATRIX_BEGIN T_MATRIX_END
93
94 %token T_QUIT T_PRINT T_TIME T_XYZZY T_INVENTORY T_LOOK T_SCORE
95
96 /* Operator precedence and associativity */
97 %right '='
98 %left T_EQUAL T_NOTEQ
99 %left '<' '>' T_LESSEQ T_GREATEREQ
100 %left '+' '-'
101 %left '*' '/' '%'
102 %nonassoc NEG
103 %right '^'
104 %nonassoc '!'
105
106 %start input
107
108
109 /*
110  *  Grammar rules
111  */
112
113 %%
114 input   : /* empty */
115         | input line
116         ;
117
118 line    : ';'
119         | exp ';'
120                 {
121                         try {
122                                 cout << $1 << endl;
123                                 push($1);
124                         } catch (exception &e) {
125                                 cerr << e.what() << endl;
126                                 YYERROR;
127                         }
128                 }
129         | T_PRINT '(' exp ')' ';'
130                 {
131                         try {
132                                 $3.printtree(cout);
133                         } catch (exception &e) {
134                                 cerr << e.what() << endl;
135                                 YYERROR;
136                         }
137                 }
138         | T_QUIT                {YYACCEPT;}
139         | T_XYZZY               {cout << "Nothing happens.\n";}
140         | T_INVENTORY           {cout << "You're not carrying anything.\n";}
141         | T_LOOK                {cout << "You're in a twisty little maze of passages, all alike.\n";}
142         | T_SCORE
143                 {
144                         cout << "If you were to quit now, you would score ";
145                         cout << (syms.size() > 350 ? 350 : syms.size());
146                         cout << " out of a possible 350.\n";
147                 }
148         | error ';'             {yyclearin; yyerrok;}
149         ;
150
151 exp     : T_NUMBER              {$$ = $1;}
152         | T_SYMBOL              {$$ = $1.eval();}
153         | '\'' T_SYMBOL '\''    {$$ = $2;}
154         | T_LITERAL             {$$ = $1;}
155         | T_DIGITS              {$$ = $1;}
156         | T_QUOTE               {$$ = exstack[0];}
157         | T_QUOTE2              {$$ = exstack[1];}
158         | T_QUOTE3              {$$ = exstack[2];}
159         | T_TIME {getrusage(RUSAGE_SELF, &start_time);} '(' exp ')'
160                 {
161                         getrusage(RUSAGE_SELF, &end_time);
162                         $$ = (end_time.ru_utime.tv_sec - start_time.ru_utime.tv_sec) +
163                              (end_time.ru_stime.tv_sec - start_time.ru_stime.tv_sec) +
164                              double(end_time.ru_utime.tv_usec - start_time.ru_utime.tv_usec) / 1e6 +
165                              double(end_time.ru_stime.tv_usec - start_time.ru_stime.tv_usec) / 1e6;
166                 }
167         | T_SYMBOL '(' exprseq ')'
168                 {
169                         fcn_tab::const_iterator i = find_function($1, $3.nops());
170                         if (i->second.is_ginac) {
171                                 $$ = ((fcnp2)(i->second.p))(static_cast<const exprseq &>(*($3.bp)), i->second.serial);
172                         } else {
173                                 $$ = (i->second.p)(static_cast<const exprseq &>(*($3.bp)));
174                         }
175                 }
176         | T_DIGITS '=' T_NUMBER
177                 {$$ = $3; Digits = ex_to_numeric($3).to_int();}
178         | T_SYMBOL '=' exp
179                 {$$ = $3; const_cast<symbol *>(&ex_to_symbol($1))->assign($3);}
180         | exp T_EQUAL exp       {$$ = $1 == $3;}
181         | exp T_NOTEQ exp       {$$ = $1 != $3;}
182         | exp '<' exp           {$$ = $1 < $3;}
183         | exp T_LESSEQ exp      {$$ = $1 <= $3;}
184         | exp '>' exp           {$$ = $1 > $3;}
185         | exp T_GREATEREQ exp   {$$ = $1 >= $3;}
186         | exp '+' exp           {$$ = $1 + $3;}
187         | exp '-' exp           {$$ = $1 - $3;}
188         | exp '*' exp           {$$ = $1 * $3;}
189         | exp '/' exp           {$$ = $1 / $3;}
190         | exp '%' exp           {$$ = $1 % $3;}
191         | '-' exp %prec NEG     {$$ = -$2;}
192         | '+' exp %prec NEG     {$$ = $2;}
193         | exp '^' exp           {$$ = power($1, $3);}
194         | exp '!'               {$$ = factorial($1);}
195         | '(' exp ')'           {$$ = $2;}
196         | '[' list_or_empty ']' {$$ = $2;}
197         | T_MATRIX_BEGIN matrix T_MATRIX_END    {$$ = lst2matrix($2);}
198         ;
199
200 exprseq : exp                   {$$ = exprseq($1);}
201         | exprseq ',' exp       {exprseq es(static_cast<exprseq &>(*($1.bp))); $$ = es.append($3);}
202         ;
203
204 list_or_empty: /* empty */      {$$ = *new lst;}
205         | list                  {$$ = $1;}
206         ;
207
208 list    : exp                   {$$ = lst($1);}
209         | list ',' exp          {lst l(static_cast<lst &>(*($1.bp))); $$ = l.append($3);}
210         ;
211
212 matrix  : T_MATRIX_BEGIN row T_MATRIX_END               {$$ = lst($2);}
213         | matrix ',' T_MATRIX_BEGIN row T_MATRIX_END    {lst l(static_cast<lst &>(*($1.bp))); $$ = l.append($4);}
214         ;
215
216 row     : exp                   {$$ = lst($1);}
217         | row ',' exp           {lst l(static_cast<lst &>(*($1.bp))); $$ = l.append($3);}
218         ;
219
220
221 /*
222  *  Routines
223  */
224
225 %%
226 // Error print routine
227 int yyerror(char *s)
228 {
229         cerr << s << " at " << yytext << endl;
230         return 0;
231 }
232
233 // Push expression "e" onto the expression stack (for ", "" and """)
234 static void push(const ex &e)
235 {
236         exstack[2] = exstack[1];
237         exstack[1] = exstack[0];
238         exstack[0] = e;
239 }
240
241
242 /*
243  *  Built-in functions
244  */
245
246 static ex f_beta(const exprseq &e) {return gamma(e[0])*gamma(e[1])/gamma(e[0]+e[1]);}
247 static ex f_denom(const exprseq &e) {return e[0].denom();}
248 static ex f_eval1(const exprseq &e) {return e[0].eval();}
249 static ex f_evalf1(const exprseq &e) {return e[0].evalf();}
250 static ex f_expand(const exprseq &e) {return e[0].expand();}
251 static ex f_gcd(const exprseq &e) {return gcd(e[0], e[1]);}
252 static ex f_lcm(const exprseq &e) {return lcm(e[0], e[1]);}
253 static ex f_lsolve(const exprseq &e) {return lsolve(e[0], e[1]);}
254 static ex f_nops(const exprseq &e) {return e[0].nops();}
255 static ex f_normal1(const exprseq &e) {return e[0].normal();}
256 static ex f_numer(const exprseq &e) {return e[0].numer();}
257 static ex f_power(const exprseq &e) {return power(e[0], e[1]);}
258 static ex f_sqrt(const exprseq &e) {return sqrt(e[0]);}
259 static ex f_subs2(const exprseq &e) {return e[0].subs(e[1]);}
260
261 #define CHECK_ARG(num, type, fcn) if (!is_ex_of_type(e[num], type)) throw(std::invalid_argument("argument " #num " to " #fcn " must be a " #type))
262
263 static ex f_charpoly(const exprseq &e)
264 {
265         CHECK_ARG(0, matrix, charpoly);
266         CHECK_ARG(1, symbol, charpoly);
267         return ex_to_matrix(e[0]).charpoly(ex_to_symbol(e[1]));
268 }
269
270 static ex f_coeff(const exprseq &e)
271 {
272         CHECK_ARG(1, symbol, coeff);
273         CHECK_ARG(2, numeric, coeff);
274         return e[0].coeff(ex_to_symbol(e[1]), ex_to_numeric(e[2]).to_int());
275 }
276
277 static ex f_collect(const exprseq &e)
278 {
279         CHECK_ARG(1, symbol, collect);
280         return e[0].collect(ex_to_symbol(e[1]));
281 }
282
283 static ex f_content(const exprseq &e)
284 {
285         CHECK_ARG(1, symbol, content);
286         return e[0].content(ex_to_symbol(e[1]));
287 }
288
289 static ex f_degree(const exprseq &e)
290 {
291         CHECK_ARG(1, symbol, degree);
292         return e[0].degree(ex_to_symbol(e[1]));
293 }
294
295 static ex f_determinant(const exprseq &e)
296 {
297         CHECK_ARG(0, matrix, determinant);
298         return ex_to_matrix(e[0]).determinant();
299 }
300
301 static ex f_diag(const exprseq &e)
302 {
303         int dim = e.nops();
304         matrix &m = *new matrix(dim, dim);
305         for (int i=0; i<dim; i++)
306                 m.set(i, i, e.op(i));
307         return m;
308 }
309
310 static ex f_diff2(const exprseq &e)
311 {
312         CHECK_ARG(1, symbol, diff);
313         return e[0].diff(ex_to_symbol(e[1]));
314 }
315
316 static ex f_diff3(const exprseq &e)
317 {
318         CHECK_ARG(1, symbol, diff);
319         CHECK_ARG(2, numeric, diff);
320         return e[0].diff(ex_to_symbol(e[1]), ex_to_numeric(e[2]).to_int());
321 }
322
323 static ex f_divide(const exprseq &e)
324 {
325         ex q;
326         if (divide(e[0], e[1], q))
327                 return q;
328         else
329                 return *new fail();
330 }
331
332 static ex f_eval2(const exprseq &e)
333 {
334         CHECK_ARG(1, numeric, eval);
335         return e[0].eval(ex_to_numeric(e[1]).to_int());
336 }
337
338 static ex f_evalf2(const exprseq &e)
339 {
340         CHECK_ARG(1, numeric, evalf);
341         return e[0].evalf(ex_to_numeric(e[1]).to_int());
342 }
343
344 static ex f_has(const exprseq &e)
345 {
346         return e[0].has(e[1]) ? exONE() : exZERO();
347 }
348
349 static ex f_inverse(const exprseq &e)
350 {
351         CHECK_ARG(0, matrix, inverse);
352         return ex_to_matrix(e[0]).inverse();
353 }
354
355 static ex f_is(const exprseq &e)
356 {
357         CHECK_ARG(0, relational, is);
358         return (bool)ex_to_relational(e[0]) ? exONE() : exZERO();
359 }
360
361 static ex f_lcoeff(const exprseq &e)
362 {
363         CHECK_ARG(1, symbol, lcoeff);
364         return e[0].lcoeff(ex_to_symbol(e[1]));
365 }
366
367 static ex f_ldegree(const exprseq &e)
368 {
369         CHECK_ARG(1, symbol, ldegree);
370         return e[0].ldegree(ex_to_symbol(e[1]));
371 }
372
373 static ex f_normal2(const exprseq &e)
374 {
375         CHECK_ARG(1, numeric, normal);
376         return e[0].normal(ex_to_numeric(e[1]).to_int());
377 }
378
379 static ex f_op(const exprseq &e)
380 {
381         CHECK_ARG(1, numeric, op);
382         int n = ex_to_numeric(e[1]).to_int();
383         if (n < 0 || n >= e[0].nops())
384                 throw(std::out_of_range("second argument to op() is out of range"));
385         return e[0].op(n);
386 }
387
388 static ex f_prem(const exprseq &e)
389 {
390         CHECK_ARG(2, symbol, prem);
391         return prem(e[0], e[1], ex_to_symbol(e[2]));
392 }
393
394 static ex f_primpart(const exprseq &e)
395 {
396         CHECK_ARG(1, symbol, primpart);
397         return e[0].primpart(ex_to_symbol(e[1]));
398 }
399
400 static ex f_quo(const exprseq &e)
401 {
402         CHECK_ARG(2, symbol, quo);
403         return quo(e[0], e[1], ex_to_symbol(e[2]));
404 }
405
406 static ex f_rem(const exprseq &e)
407 {
408         CHECK_ARG(2, symbol, rem);
409         return rem(e[0], e[1], ex_to_symbol(e[2]));
410 }
411
412 static ex f_series2(const exprseq &e)
413 {
414         CHECK_ARG(1, symbol, series);
415         return e[0].series(ex_to_symbol(e[1]), exZERO());
416 }
417
418 static ex f_series3(const exprseq &e)
419 {
420         CHECK_ARG(1, symbol, series);
421         return e[0].series(ex_to_symbol(e[1]), e[2]);
422 }
423
424 static ex f_series4(const exprseq &e)
425 {
426         CHECK_ARG(1, symbol, series);
427         CHECK_ARG(3, numeric, series);
428         return e[0].series(ex_to_symbol(e[1]), e[2], ex_to_numeric(e[3]).to_int());
429 }
430
431 static ex f_sqrfree(const exprseq &e)
432 {
433         CHECK_ARG(1, symbol, sqrfree);
434         return sqrfree(e[0], ex_to_symbol(e[1]));
435 }
436
437 static ex f_subs3(const exprseq &e)
438 {
439         CHECK_ARG(1, lst, subs);
440         CHECK_ARG(2, lst, subs);
441         return e[0].subs(ex_to_lst(e[1]), ex_to_lst(e[2]));
442 }
443
444 static ex f_tcoeff(const exprseq &e)
445 {
446         CHECK_ARG(1, symbol, tcoeff);
447         return e[0].tcoeff(ex_to_symbol(e[1]));
448 }
449
450 static ex f_trace(const exprseq &e)
451 {
452         CHECK_ARG(0, matrix, trace);
453         return ex_to_matrix(e[0]).trace();
454 }
455
456 static ex f_transpose(const exprseq &e)
457 {
458         CHECK_ARG(0, matrix, transpose);
459         return ex_to_matrix(e[0]).transpose();
460 }
461
462 static ex f_unassign(const exprseq &e)
463 {
464         CHECK_ARG(0, symbol, unassign);
465         (const_cast<symbol *>(&ex_to_symbol(e[0])))->unassign();
466         return e[0];
467 }
468
469 static ex f_unit(const exprseq &e)
470 {
471         CHECK_ARG(1, symbol, unit);
472         return e[0].unit(ex_to_symbol(e[1]));
473 }
474
475 static ex f_dummy(const exprseq &e)
476 {
477         throw(std::logic_error("dummy function called (shouldn't happen)"));
478 }
479
480
481 /*
482  *  Add all registered GiNaC functions to ginsh
483  */
484
485 static ex f_ginac_function(const exprseq &es, int serial)
486 {
487         return function(serial, es).eval(1);
488 }
489
490 void ginsh_get_ginac_functions(void)
491 {
492         vector<registered_function_info>::const_iterator i = function::registered_functions().begin(), end = function::registered_functions().end();
493         unsigned serial = 0;
494         while (i != end) {
495                 fcns.insert(make_pair(i->name, fcn_desc(f_ginac_function, i->nparams, serial)));
496                 i++;
497                 serial++;
498         }
499 }
500
501
502 /*
503  *  Find a function given a name and number of parameters. Throw exceptions on error.
504  */
505
506 static fcn_tab::const_iterator find_function(const ex &sym, int req_params)
507 {
508         const string &name = ex_to_symbol(sym).getname();
509         typedef fcn_tab::const_iterator I;
510         pair<I, I> b = fcns.equal_range(name);
511         if (b.first == b.second)
512                 throw(std::logic_error("unknown function '" + name + "'"));
513         else {
514                 for (I i=b.first; i!=b.second; i++)
515                         if ((i->second.num_params == 0) || (i->second.num_params == req_params))
516                                 return i;
517         }
518         throw(std::logic_error("invalid number of arguments to " + name + "()"));
519 }
520
521
522 /*
523  *  Convert list of lists to matrix
524  */
525
526 static ex lst2matrix(const ex &l)
527 {
528         if (!is_ex_of_type(l, lst))
529                 throw(std::logic_error("internal error: argument to lst2matrix() is not a list"));
530
531         // Find number of rows and columns
532         int rows = l.nops(), cols = 0, i, j;
533         for (i=0; i<rows; i++)
534                 if (l.op(i).nops() > cols)
535                         cols = l.op(i).nops();
536
537         // Allocate and fill matrix
538         matrix &m = *new matrix(rows, cols);
539         for (i=0; i<rows; i++)
540                 for (j=0; j<cols; j++)
541                         if (l.op(i).nops() > j)
542                                 m.set(i, j, l.op(i).op(j));
543                         else
544                                 m.set(i, j, exZERO());
545         return m;
546 }
547
548
549 /*
550  *  Function name completion functions for readline
551  */
552
553 static char *fcn_generator(char *text, int state)
554 {
555         static int len;                         // Length of word to complete
556         static fcn_tab::const_iterator index;   // Iterator to function being currently considered
557
558         // If this is a new word to complete, initialize now
559         if (state == 0) {
560                 index = fcns.begin();
561                 len = strlen(text);
562         }
563
564         // Return the next function which partially matches
565         while (index != fcns.end()) {
566                 const char *fcn_name = index->first.c_str();
567                 index++;
568                 if (strncmp(fcn_name, text, len) == 0)
569                         return strdup(fcn_name);
570         }
571         return NULL;
572 }
573
574 static char **fcn_completion(char *text, int start, int end)
575 {
576         if (rl_line_buffer[0] == '!') {
577                 // For shell commands, revert back to filename completion
578                 rl_completion_append_character = orig_completion_append_character;
579                 rl_basic_word_break_characters = orig_basic_word_break_characters;
580                 return completion_matches(text, filename_completion_function);
581         } else {
582                 // Otherwise, complete function names
583                 rl_completion_append_character = '(';
584                 rl_basic_word_break_characters = " \t\n\"#$%&'()*+,-./:;<=>?@[\\]^`{|}~";
585                 return completion_matches(text, fcn_generator);
586         }
587 }
588
589
590 /*
591  *  Main program
592  */
593
594 int main(int argc, char **argv)
595 {
596         // Print banner in interactive mode
597         if (isatty(0)) {
598                 cout << "ginsh - GiNaC Interactive Shell (" << PACKAGE << " " << VERSION << ")\n";
599                 cout << "Copyright (C) 1999 Johannes Gutenberg Universitaet Mainz, Germany\n";
600                 cout << "This is free software, and you are welcome to redistribute it\n";
601                 cout << "under certain conditions; see the file COPYING for details.\n"; 
602         }
603
604         // Init table of built-in functions
605         fcns.insert(make_pair(string("beta"), fcn_desc(f_beta, 2)));
606         fcns.insert(make_pair(string("charpoly"), fcn_desc(f_charpoly, 2)));
607         fcns.insert(make_pair(string("coeff"), fcn_desc(f_coeff, 3)));
608         fcns.insert(make_pair(string("collect"), fcn_desc(f_collect, 2)));
609         fcns.insert(make_pair(string("content"), fcn_desc(f_content, 2)));
610         fcns.insert(make_pair(string("degree"), fcn_desc(f_degree, 2)));
611         fcns.insert(make_pair(string("denom"), fcn_desc(f_denom, 1)));
612         fcns.insert(make_pair(string("determinant"), fcn_desc(f_determinant, 1)));
613         fcns.insert(make_pair(string("diag"), fcn_desc(f_diag, 0)));
614         fcns.insert(make_pair(string("diff"), fcn_desc(f_diff2, 2)));
615         fcns.insert(make_pair(string("diff"), fcn_desc(f_diff3, 3)));
616         fcns.insert(make_pair(string("divide"), fcn_desc(f_divide, 2)));
617         fcns.insert(make_pair(string("eval"), fcn_desc(f_eval1, 1)));
618         fcns.insert(make_pair(string("eval"), fcn_desc(f_eval2, 2)));
619         fcns.insert(make_pair(string("evalf"), fcn_desc(f_evalf1, 1)));
620         fcns.insert(make_pair(string("evalf"), fcn_desc(f_evalf2, 2)));
621         fcns.insert(make_pair(string("expand"), fcn_desc(f_expand, 1)));
622         fcns.insert(make_pair(string("gcd"), fcn_desc(f_gcd, 2)));
623         fcns.insert(make_pair(string("has"), fcn_desc(f_has, 2)));
624         fcns.insert(make_pair(string("inverse"), fcn_desc(f_inverse, 1)));
625         fcns.insert(make_pair(string("is"), fcn_desc(f_is, 1)));
626         fcns.insert(make_pair(string("lcm"), fcn_desc(f_lcm, 2)));
627         fcns.insert(make_pair(string("lcoeff"), fcn_desc(f_lcoeff, 2)));
628         fcns.insert(make_pair(string("ldegree"), fcn_desc(f_ldegree, 2)));
629         fcns.insert(make_pair(string("lsolve"), fcn_desc(f_lsolve, 2)));
630         fcns.insert(make_pair(string("nops"), fcn_desc(f_nops, 1)));
631         fcns.insert(make_pair(string("normal"), fcn_desc(f_normal1, 1)));
632         fcns.insert(make_pair(string("normal"), fcn_desc(f_normal2, 2)));
633         fcns.insert(make_pair(string("numer"), fcn_desc(f_numer, 1)));
634         fcns.insert(make_pair(string("op"), fcn_desc(f_op, 2)));
635         fcns.insert(make_pair(string("power"), fcn_desc(f_power, 2)));
636         fcns.insert(make_pair(string("prem"), fcn_desc(f_prem, 3)));
637         fcns.insert(make_pair(string("primpart"), fcn_desc(f_primpart, 2)));
638         fcns.insert(make_pair(string("quo"), fcn_desc(f_quo, 3)));
639         fcns.insert(make_pair(string("rem"), fcn_desc(f_rem, 3)));
640         fcns.insert(make_pair(string("series"), fcn_desc(f_series2, 2)));
641         fcns.insert(make_pair(string("series"), fcn_desc(f_series3, 3)));
642         fcns.insert(make_pair(string("series"), fcn_desc(f_series4, 4)));
643         fcns.insert(make_pair(string("sqrfree"), fcn_desc(f_sqrfree, 2)));
644         fcns.insert(make_pair(string("sqrt"), fcn_desc(f_sqrt, 1)));
645         fcns.insert(make_pair(string("subs"), fcn_desc(f_subs2, 2)));
646         fcns.insert(make_pair(string("subs"), fcn_desc(f_subs3, 3)));
647         fcns.insert(make_pair(string("tcoeff"), fcn_desc(f_tcoeff, 2)));
648         fcns.insert(make_pair(string("time"), fcn_desc(f_dummy, 0)));
649         fcns.insert(make_pair(string("trace"), fcn_desc(f_trace, 1)));
650         fcns.insert(make_pair(string("transpose"), fcn_desc(f_transpose, 1)));
651         fcns.insert(make_pair(string("unassign"), fcn_desc(f_unassign, 1)));
652         fcns.insert(make_pair(string("unit"), fcn_desc(f_unit, 2)));
653         ginsh_get_ginac_functions();
654
655         // Init readline completer
656         rl_readline_name = argv[0];
657         rl_attempted_completion_function = (CPPFunction *)fcn_completion;
658         orig_completion_append_character = rl_completion_append_character;
659         orig_basic_word_break_characters = rl_basic_word_break_characters;
660
661         // Parse input, catch all remaining exceptions
662         int result;
663 again:  try {
664                 result = yyparse();
665         } catch (exception &e) {
666                 cerr << e.what() << endl;
667                 goto again;
668         }
669         return result;
670 }