]> www.ginac.de Git - ginac.git/blob - ginac/input_parser.yy
Allow user to disable GiNaC::compile_ex (e.g. for security reasons).
[ginac.git] / ginac / input_parser.yy
1 /** @file input_parser.yy
2  *
3  *  Input grammar definition for reading expressions.
4  *  This file must be processed with yacc/bison. */
5
6 /*
7  *  GiNaC Copyright (C) 1999-2008 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 #include <stdexcept>
31
32 #include "ex.h"
33 #include "input_lexer.h"
34 #include "relational.h"
35 #include "operators.h"
36 #include "symbol.h"
37 #include "lst.h"
38 #include "power.h"
39 #include "exprseq.h"
40 #include "idx.h"
41 #include "indexed.h"
42 #include "matrix.h"
43 #include "inifcns.h"
44
45 namespace GiNaC {
46
47 #define YYERROR_VERBOSE 1
48
49 // Parsed output expression
50 ex parsed_ex;
51
52 // Last error message returned by parser
53 static std::string parser_error;
54
55 // Prototypes
56 ex attach_index(const ex & base, ex i, bool covariant);
57 %}
58
59 /* Tokens (T_LITERAL means a literal value returned by the parser, but not
60    of class numeric or symbol (e.g. a constant or the FAIL object)) */
61 %token T_EOF T_NUMBER T_SYMBOL T_LITERAL T_DIGITS T_EQUAL T_NOTEQ T_LESSEQ T_GREATEREQ
62
63 /* Operator precedence and associativity */
64 %right '='
65 %left T_EQUAL T_NOTEQ
66 %left '<' '>' T_LESSEQ T_GREATEREQ
67 %left '+' '-'
68 %left '*' '/' '%'
69 %nonassoc NEG
70 %right '^'
71 %left '.' '~'
72 %nonassoc '!'
73
74 %start input
75
76
77 /*
78  *  Grammar rules
79  */
80
81 %%
82 input   : exp T_EOF {
83                 try {
84                         parsed_ex = $1;
85                         YYACCEPT;
86                 } catch (std::exception &err) {
87                         parser_error = err.what();
88                         YYERROR;
89                 }
90         }
91         ;
92
93 exp     : T_NUMBER              {$$ = $1;}
94         | T_SYMBOL {
95                 if (is_lexer_symbol_predefined($1))
96                         $$ = $1.eval();
97                 else
98                         throw (std::runtime_error("unknown symbol '" + get_symbol_name($1) + "'"));
99         }
100         | T_LITERAL             {$$ = $1;}
101         | T_DIGITS              {$$ = $1;}
102         | T_SYMBOL '(' exprseq ')' {
103                 std::string n = get_symbol_name($1);
104                 if (n == "sqrt") {
105                         if ($3.nops() != 1)
106                                 throw (std::runtime_error("too many arguments to sqrt()"));
107                         $$ = sqrt($3.op(0));
108                 } else if (n == "pow" || n == "power") {
109                   if ($3.nops() != 2) 
110                           throw std::invalid_argument("wrong number of arguments to pow()");
111                         $$ = power($3.op(0), $3.op(0));
112                 } else {
113                         unsigned i = function::find_function(n, $3.nops());
114                         $$ = function(i, ex_to<exprseq>($3)).eval(1);
115                 }
116         }
117         | exp T_EQUAL exp       {$$ = $1 == $3;}
118         | exp T_NOTEQ exp       {$$ = $1 != $3;}
119         | exp '<' exp           {$$ = $1 < $3;}
120         | exp T_LESSEQ exp      {$$ = $1 <= $3;}
121         | exp '>' exp           {$$ = $1 > $3;}
122         | exp T_GREATEREQ exp   {$$ = $1 >= $3;}
123         | exp '+' exp           {$$ = $1 + $3;}
124         | exp '-' exp           {$$ = $1 - $3;}
125         | exp '*' exp           {$$ = $1 * $3;}
126         | exp '/' exp           {$$ = $1 / $3;}
127         | '-' exp %prec NEG     {$$ = -$2;}
128         | '+' exp %prec NEG     {$$ = $2;}
129         | exp '^' exp           {$$ = pow($1, $3);}
130         | exp '.' exp           {$$ = attach_index($1, $3, true);}
131         | exp '~' exp           {$$ = attach_index($1, $3, false);}
132         | exp '!'               {$$ = factorial($1);}
133         | '(' exp ')'           {$$ = $2;}
134         | '{' list_or_empty '}' {$$ = $2;}
135         | '[' matrix ']'        {$$ = lst_to_matrix(ex_to<lst>($2));}
136         ;
137
138 exprseq : exp                   {$$ = exprseq($1);}
139         | exprseq ',' exp       {exprseq es(ex_to<exprseq>($1)); $$ = es.append($3);}
140         ;
141
142 list_or_empty: /* empty */      {$$ = *new lst;}
143         | list                  {$$ = $1;}
144         ;
145
146 list    : exp                   {$$ = lst($1);}
147         | list ',' exp          {lst l(ex_to<lst>($1)); $$ = l.append($3);}
148         ;
149
150 matrix  : '[' row ']'           {$$ = lst($2);}
151         | matrix ',' '[' row ']' {lst l(ex_to<lst>($1)); $$ = l.append($4);}
152         ;
153
154 row     : exp                   {$$ = lst($1);}
155         | row ',' exp           {lst l(ex_to<lst>($1)); $$ = l.append($3);}
156         ;
157
158
159 /*
160  *  Routines
161  */
162
163 %%
164 // Attach index to expression
165 ex attach_index(const ex & base, ex i, bool covariant)
166 {
167         // Toggle index variance if necessary
168         if (is_a<varidx>(i)) {
169                 const varidx &vi = ex_to<varidx>(i);
170                 if (vi.is_covariant() != covariant)
171                         i = vi.toggle_variance();
172         } else if (!covariant)
173                 throw (std::runtime_error("index '" + get_symbol_name(i) + "' is not a varidx and cannot be contravariant"));
174
175         // Add index to an existing indexed object, or create a new indexed
176         // object if there are no indices yet
177         if (is_a<indexed>(base)) {
178                 const ex &b = base.op(0);
179                 exvector iv;
180                 for (unsigned n=1; n<base.nops(); n++)
181                         iv.push_back(base.op(n));
182                 iv.push_back(i);
183                 return indexed(b, iv);
184         } else
185                 return indexed(base, i);
186 }
187
188 // Get last error encountered by parser
189 std::string get_parser_error(void)
190 {
191         return parser_error;
192 }
193
194 } // namespace GiNaC
195
196 // Error print routine (store error string in parser_error)
197 int ginac_yyerror(char *s)
198 {
199         GiNaC::parser_error = std::string(s) + " at " + std::string(ginac_yytext);
200         return 0;
201 }