-#include <stdexcept>
-#include <sstream>
-#include "parser.hpp"
-#include "lexer.hpp"
-#include "debug.hpp"
+/** @file parser.cpp
+ *
+ * Implementation of GiNaC's parser. */
+
+/*
+ * GiNaC Copyright (C) 1999-2020 Johannes Gutenberg University Mainz, Germany
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "parser.h"
+#include "lst.h"
+#include "lexer.h"
+#include "debug.h"
#include "mul.h"
#include "constant.h"
+#include "function.h"
+
+#include <cstdint> // for uintptr_t
+#include <sstream>
+#include <stdexcept>
-namespace GiNaC
+namespace GiNaC {
+
+// <KLUDGE>
+// Find out if ptr is a pointer to a function or a specially crafted integer.
+// It's possible to distinguish between these because functions are aligned.
+// Returns true if ptr is a pointer and false otherwise.
+static bool decode_serial(unsigned& serial, const reader_func ptr)
{
+ uintptr_t u = (uintptr_t)(void *)ptr;
+ if (u & 1) {
+ u >>= 1;
+ serial = (unsigned)u;
+ return false;
+ }
+ return true;
+}
+
+// Figures out if ptr is a pointer to function or a serial of GiNaC function.
+// In the former case calls that function, in the latter case constructs
+// GiNaC function with corresponding serial and arguments.
+static ex dispatch_reader_fcn(const reader_func ptr, const exvector& args)
+{
+ unsigned serial = 0; // dear gcc, could you please shut up?
+ bool is_ptr = decode_serial(serial, ptr);
+ if (is_ptr)
+ return ptr(args);
+ else
+ return function(serial, args);
+}
+// </KLUDGE>
+
/// identifier_expr: identifier | identifier '(' expression* ')'
ex parser::parse_identifier_expr()
// Eat the ')'.
get_next_tok();
prototype the_prototype = make_pair(name, args.size());
- prototype_table::const_iterator reader = funcs.find(the_prototype);
+ auto reader = funcs.find(the_prototype);
if (reader == funcs.end()) {
Parse_error_("no function \"" << name << "\" with " <<
args.size() << " arguments");
}
- ex ret = reader->second(args);
+ // reader->second might be a pointer to a C++ function or a specially
+ // crafted serial of a GiNaC::function.
+ ex ret = dispatch_reader_fcn(reader->second, args);
return ret;
}
return e;
}
-extern numeric* _num_1_p;
-extern ex _ex0;
+/// lst_expr: '{' expression { ',' expression } '}'
+ex parser::parse_lst_expr()
+{
+ get_next_tok(); // eat {.
+
+ lst list;
+ if (token != '}') {
+ while (true) {
+ ex e = parse_expression(); // expression();
+ list.append(e);
+
+ if (token == '}') {
+ break;
+ }
+
+ if (token != ',') {
+ Parse_error("expected '}'");
+ }
+
+ get_next_tok(); // eat ','.
+ }
+ }
+ // Eat the '}'.
+ get_next_tok();
+
+ return list;
+}
+
+extern const ex _ex0;
/// unary_expr: [+-] expression
ex parser::parse_unary_expr()
// -(a)
// +a
// +(a)
- // Delegete the work to parse_binop_rhs(), otherwise we end up
+ // Delegate 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 parse_number_expr();
case '(':
return parse_paren_expr();
+ case '{':
+ return parse_lst_expr();
case '-':
case '+':
return parse_unary_expr();