]> www.ginac.de Git - ginac.git/blob - check/exam_parser.cpp
Fix GiNaC's internal parsing of expressions.
[ginac.git] / check / exam_parser.cpp
1 /** @file parser_bugs.cpp
2  *
3  *  Check for some silly bugs in the parser. */
4
5 /*
6  *  GiNaC Copyright (C) 1999-2023 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
21  */
22
23 #include "ginac.h"
24 using namespace GiNaC;
25
26 #include <iostream>
27 #include <sstream>
28 #include <stdexcept>
29 #include <string>
30
31 using namespace std;
32
33 // - a - b was misparsed as -a + b due to a bug in parser::parse_unary_expr()
34 static int check1(ostream& err_str)
35 {
36         const string srep("-a-b");
37         parser reader;
38         ex e = reader(srep);
39         ex a = reader.get_syms()["a"];
40         ex b = reader.get_syms()["b"];
41         ex g = - a - b;
42         ex d = (e - g).expand();
43         if (!d.is_zero()) {
44                 err_str << "\"" << srep << "\" was misparsed as \""
45                         << e << "\"" << endl;
46                 return 1;
47         }
48         return 0;
49 }
50
51 /// Parser was rejecting the valid expression '5 - (3*x)/10'.
52 static int check2(ostream& err_str)
53 {
54         const string srep("5-(3*x)/10");
55         parser reader;
56         ex e = reader(srep);
57         ex x = reader.get_syms()["x"];
58         ex g = 5 - (3*x)/10;
59         ex d = (e - g).expand();
60         if (!d.is_zero()) {
61                 err_str << "\"" << srep << "\" was misparsed as \""
62                         << e << "\"" << endl;
63                 return 1;
64         }
65         return 0;
66 }
67
68 /// parse_literal_expr forget to consume the token, so parser get
69 /// very confused.
70 static int check3(ostream& err_str)
71 {
72         const string srep("5-(2*I)/3");
73         parser reader;
74         ex e = reader(srep);
75         ex g = numeric(5) - (numeric(2)*I)/3;
76         ex d = (e - g).expand();
77         if (!d.is_zero()) {
78                 err_str << "\"" << srep << "\" was misparsed as \""
79                         << e << "\"" << endl;
80                 return 1;
81         }
82         return 0;
83 }
84
85 /// parser happily accepted various junk like 'x^2()+1'
86 static int check4(ostream& err_str)
87 {
88         const string junk("x^2()+1");
89         parser reader;
90         ex e;
91         try {
92                 e = reader(junk);
93                 err_str << "parser accepts junk: \"" << junk << "\"" << endl;
94                 return 1;
95         } catch (parse_error& err) {
96                 // Ok, parser rejects the nonsense.
97                 return 0;
98         }
99 }
100
101 // Check that two strings parse to equal expressions.
102 static int check_eq(ostream &err_str, parser &reader, const char *expr1, const char *expr2)
103 {
104         const string srep1(expr1);
105         const string srep2(expr2);
106         ex e1, e2;
107         try{ e1 = reader(srep1); } catch (const exception &e) {
108                 err_str << "\"" << srep1 << "\" failed to parse: "
109                         << e.what() << endl;
110                 return 1;
111         }
112         try{ e2 = reader(srep2); } catch (const exception &e) {
113                 err_str << "\"" << srep2 << "\" failed to parse: "
114                         << e.what() << endl;
115                 return 1;
116         }
117         if (!(e1-e2).expand().is_zero()) {
118                 err_str << "\"" << srep1 << "\" was misparsed as \""
119                         << e1 << "\"" << endl;
120                 return 1;
121         }
122         return 0;
123 }
124
125 // Tests for the interaction of the '^' operator with
126 // the unary '+' and the unary '-' operators
127 static int check5(ostream& err_str)
128 {
129         parser reader;
130         return
131                 +check_eq(err_str, reader, "3^2+1", "10")
132                 +check_eq(err_str, reader, "3^+2-1", "8")
133                 +check_eq(err_str, reader, "3^-2+1", "10/9")
134                 +check_eq(err_str, reader, "3^-2/5", "1/45")
135                 +check_eq(err_str, reader, "3^-2*5", "5/9")
136                 +check_eq(err_str, reader, "3^-2-5", "-44/9")
137                 +check_eq(err_str, reader, "3^(-2)+1", "10/9")
138                 +check_eq(err_str, reader, "(3)^(-2)+1", "10/9")
139                 +check_eq(err_str, reader, "+3^2+1", "10")
140                 +check_eq(err_str, reader, "+3^+2+1", "10")
141                 +check_eq(err_str, reader, "+3^-2+1", "10/9")
142                 +check_eq(err_str, reader, "+3^-2/5", "1/45")
143                 +check_eq(err_str, reader, "+3^-2*5", "5/9")
144                 +check_eq(err_str, reader, "+3^-2-5", "-44/9")
145                 +check_eq(err_str, reader, "-3^2+1", "-8")
146                 +check_eq(err_str, reader, "-3^+2+1", "-8")
147                 +check_eq(err_str, reader, "-3^-2+1", "8/9")
148                 +check_eq(err_str, reader, "-3^-2/3", "-1/27")
149                 +check_eq(err_str, reader, "1+2^3^4", "1+(2^81)")
150                 +check_eq(err_str, reader, "2^3^4+1", "1+(2^81)")
151                 +check_eq(err_str, reader, "2^+3^4+1", "1+(2^81)")
152                 +check_eq(err_str, reader, "2^3^+4+1", "1+(2^81)");
153 }
154
155 // Tests for the interaction of the '*' operator with
156 // the unary '+' and the unary '-' operators
157 static int check6(ostream& err_str)
158 {
159         parser reader;
160         return
161                 +check_eq(err_str, reader, "3*+2-1", "5")
162                 +check_eq(err_str, reader, "3*2+1", "7")
163                 +check_eq(err_str, reader, "3*+2+1", "7")
164                 +check_eq(err_str, reader, "3*-2+1", "-5")
165                 +check_eq(err_str, reader, "3*-2/5", "-6/5")
166                 +check_eq(err_str, reader, "3*-2*5", "-30")
167                 +check_eq(err_str, reader, "3*-2-5", "-11")
168                 +check_eq(err_str, reader, "3*(-2)+1", "-5")
169                 +check_eq(err_str, reader, "(3)*(-2)+1", "-5")
170                 +check_eq(err_str, reader, "+3*2+1", "7")
171                 +check_eq(err_str, reader, "+3*+2+1", "7")
172                 +check_eq(err_str, reader, "+3*-2+1", "-5")
173                 +check_eq(err_str, reader, "+3*-2/5", "-6/5")
174                 +check_eq(err_str, reader, "+3*-2*5", "-30")
175                 +check_eq(err_str, reader, "+3*-2-5", "-11")
176                 +check_eq(err_str, reader, "-3*2+1", "-5")
177                 +check_eq(err_str, reader, "-3*+2+1", "-5")
178                 +check_eq(err_str, reader, "-3*-2+1", "7")
179                 +check_eq(err_str, reader, "-3*-2/3", "2")
180                 +check_eq(err_str, reader, "1+2*3*4", "25")
181                 +check_eq(err_str, reader, "2*3*4+1", "25")
182                 +check_eq(err_str, reader, "2*+3*4+1", "25")
183                 +check_eq(err_str, reader, "2*3*+4+1", "25");
184 }
185
186 // Tests for nested unary + and unary -
187 static int check7(ostream& err_str)
188 {
189         parser reader;
190         return
191                 +check_eq(err_str, reader, "+1", "1")
192                 +check_eq(err_str, reader, "++1", "1")
193                 +check_eq(err_str, reader, "+-+1", "-1")
194                 +check_eq(err_str, reader, "+-+-1", "1")
195                 +check_eq(err_str, reader, "+-+-+1", "1")
196                 +check_eq(err_str, reader, "100++--+1+10", "111");
197 }
198
199 int main(int argc, char** argv)
200 {
201         cout << "examining old parser bugs" << flush;
202         ostringstream err_str;
203         int errors = 0;
204         errors += check1(err_str);  cout << '.' << flush;
205         errors += check2(err_str);  cout << '.' << flush;
206         errors += check3(err_str);  cout << '.' << flush;
207         errors += check4(err_str);  cout << '.' << flush;
208         errors += check5(err_str);  cout << '.' << flush;
209         errors += check6(err_str);  cout << '.' << flush;
210         errors += check7(err_str);  cout << '.' << flush;
211         if (errors) {
212                 cout << "Yes, unfortunately:" << endl;
213                 cout << err_str.str();
214         } else {
215                 cout << "Not found. ";
216         }
217         return errors;
218 }