Also added regression test.
EXAMS = exam_paranoia \
exam_heur_gcd \
match_bug \
+ parser_bugs \
exam_numeric_archive \
exam_numeric \
exam_powerlaws \
match_bug_SOURCES = match_bug.cpp error_report.hpp
match_bug_LDADD = ../ginac/libginac.la
+parser_bugs_SOURCES = parser_bugs.cpp
+parser_bugs_LDADD = ../ginac/libginac.la
+
exam_numeric_archive_SOURCES = numeric_archive.cpp
exam_numeric_archive_LDADD = ../ginac/libginac.la
--- /dev/null
+/// @file parser_a_b.cpp Check for some silly bugs in the parser.
+#include "ginac.h"
+#include <string>
+#include <iostream>
+#include <stdexcept>
+#include <sstream>
+using namespace GiNaC;
+
+// - a - b was misparsed as -a + b due to a bug in parser::parse_unary_expr()
+static int check1(std::ostream& err_str)
+{
+ const std::string srep("-a-b");
+ parser reader;
+ ex e = reader(srep);
+ ex a = reader.get_syms()["a"];
+ ex b = reader.get_syms()["b"];
+ ex g = - a - b;
+ ex d = (e - g).expand();
+ if (!d.is_zero()) {
+ err_str << "\"" << srep << "\" was misparsed as \""
+ << e << "\"" << std::endl;
+ return 1;
+ }
+ return 0;
+}
+
+/// Parser was rejecting the valid expression '5 - (3*x)/10'.
+static int check2(std::ostream& err_str)
+{
+ const std::string srep("5-(3*x)/10");
+ parser reader;
+ ex e = reader(srep);
+ ex x = reader.get_syms()["x"];
+ ex g = 5 - (3*x)/10;
+ ex d = (e - g).expand();
+ if (!d.is_zero()) {
+ err_str << "\"" << srep << "\" was misparsed as \""
+ << e << "\"" << std::endl;
+ return 1;
+ }
+ return 0;
+}
+
+int main(int argc, char** argv)
+{
+ std::cout << "checking for parser bugs. " << std::flush;
+ std::ostringstream err_str;
+ int errors = 0;
+ errors += check1(err_str);
+ errors += check2(err_str);
+ if (errors) {
+ std::cout << "Yes, unfortunately:" << std::endl;
+ std::cout << err_str.str();
+ } else {
+ std::cout << "Not found. ";
+ }
+ return errors;
+}
+
}
extern numeric* _num_1_p;
+extern ex _ex0;
/// unary_expr: [+-] expression
-ex parser::parse_unary_expr(const int s)
+ex parser::parse_unary_expr()
{
- // consume '-' (or '+')
- get_next_tok();
- ex v = parse_expression();
- switch (s) {
- case '-':
- return (new mul(v, *_num_1_p))->setflag(status_flags::dynallocated);
- case '+':
- return v;
- default:
- Parse_error_("invalid unary operator \"" << char(s) << "\"");
- }
+ // Unlike most other parse_* method this one does NOT consume
+ // current token so parse_binop_rhs() knows what kind of operator
+ // is being parsed.
+
+ // There are different kinds of expressions which need to be handled:
+ // -a+b
+ // -(a)
+ // +a
+ // +(a)
+ // Delegete the work to parse_binop_rhs(), otherwise we end up
+ // duplicating it here.
+ ex lhs = _ex0; // silly trick
+ ex e = parse_binop_rhs(0, lhs);
+ return e;
}
/// primary: identifier_expr | number_expr | paren_expr | unary_expr
case '(':
return parse_paren_expr();
case '-':
- return parse_unary_expr('-');
case '+':
- return parse_unary_expr('+');
+ return parse_unary_expr();
case lexer::token_type::literal:
return parse_literal_expr();
case lexer::token_type::eof:
ex parse_number_expr();
/// unary_expr: [+-] expression
- ex parse_unary_expr(const int c);
+ ex parse_unary_expr();
/// literal_expr: 'I' | 'Pi' | 'Euler' | 'Catalan'
ex parse_literal_expr();