From 05157f89a3db97fff79e33fd53156b380107011f Mon Sep 17 00:00:00 2001 From: Alexei Sheplyakov Date: Sun, 14 Sep 2008 03:19:05 +0400 Subject: [PATCH] [bugfix]: parser::parse_unary_expr() parses '-a-b' correctly now. Also added regression test. --- check/Makefile.am | 4 +++ check/parser_bugs.cpp | 59 +++++++++++++++++++++++++++++++++++++++++ ginac/parser/parser.cpp | 31 ++++++++++++---------- ginac/parser/parser.hpp | 2 +- 4 files changed, 81 insertions(+), 15 deletions(-) create mode 100644 check/parser_bugs.cpp diff --git a/check/Makefile.am b/check/Makefile.am index de86f5cd..87b489d1 100644 --- a/check/Makefile.am +++ b/check/Makefile.am @@ -8,6 +8,7 @@ CHECKS = check_numeric \ EXAMS = exam_paranoia \ exam_heur_gcd \ match_bug \ + parser_bugs \ exam_numeric_archive \ exam_numeric \ exam_powerlaws \ @@ -78,6 +79,9 @@ exam_heur_gcd_LDADD = ../ginac/libginac.la 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 diff --git a/check/parser_bugs.cpp b/check/parser_bugs.cpp new file mode 100644 index 00000000..340fe20f --- /dev/null +++ b/check/parser_bugs.cpp @@ -0,0 +1,59 @@ +/// @file parser_a_b.cpp Check for some silly bugs in the parser. +#include "ginac.h" +#include +#include +#include +#include +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; +} + diff --git a/ginac/parser/parser.cpp b/ginac/parser/parser.cpp index 0ee682ab..f48d37fd 100644 --- a/ginac/parser/parser.cpp +++ b/ginac/parser/parser.cpp @@ -60,21 +60,25 @@ ex parser::parse_paren_expr() } 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 @@ -88,9 +92,8 @@ ex parser::parse_primary() 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: diff --git a/ginac/parser/parser.hpp b/ginac/parser/parser.hpp index eb50adc0..b46ec650 100644 --- a/ginac/parser/parser.hpp +++ b/ginac/parser/parser.hpp @@ -49,7 +49,7 @@ class parser 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(); -- 2.44.0