Merge branch 'master.msvc.support' of git://github.com/AlexeiSheplyakov/GiNaC
authorRichard Kreckel <kreckel@ginac.de>
Thu, 3 Feb 2011 22:48:21 +0000 (23:48 +0100)
committerRichard Kreckel <kreckel@ginac.de>
Thu, 3 Feb 2011 22:48:21 +0000 (23:48 +0100)
* 'master.msvc.support' of git://github.com/AlexeiSheplyakov/GiNaC:
  Omit extra qualification (as in struct foo f() vs foo f()).
  [msvc] msvc cannot handle string constants above 16k
  [msvc] Yet another compiler bug work around.
  [msvc] Work around strange scoping and name mangling rules.
  Add few defines for msvc (__func__, __alignof__).
  symmetry::compare_same_type(): const-correctness fix
  clifford: fix a few GCCisms (or, not).

13 files changed:
INSTALL
check/bugme_chinrem_gcd.cpp
configure.ac
ginac/Makefile.am
ginac/function.pl
ginac/parser/builtin_fcns.def [new file with mode: 0644]
ginac/parser/default_reader.tpl [new file with mode: 0644]
ginac/parser/parse_context.cpp
ginac/parser/parse_context.h
ginac/parser/parser.cpp
ginac/polynomial/mgcd.cpp
ginac/symbol.cpp
ginac/symbol.h

diff --git a/INSTALL b/INSTALL
index 3c188b667cd4043f941616c2e16546859b3d9ede..3be16c1fe03b0d68341b61cb9cbea84c2e0472cc 100644 (file)
--- a/INSTALL
+++ b/INSTALL
@@ -30,7 +30,8 @@ Known not to work with:
    is missing there.
 
 If you install from git, you also need GNU autoconf (>=2.59), automake (>=1.8),
-libtool (>= 1.5), bison (>= 2.3), flex (>= 2.5.33) to be installed.
+libtool (>= 1.5), bison (>= 2.3), flex (>= 2.5.33), autogen (>= 5.6.0) to be
+installed.
 
 
 INSTALLATION
index 87c718c7114cf4ceff3ad617b092ab959c0454b3..9325e338710c20eaf6387342ccebe418fc049e68 100644 (file)
@@ -54,11 +54,24 @@ static void check_extract_integer_content()
        ex g = chinrem_gcd(A, B);
 }
 
+static void integer_coeff_braindamage()
+{
+       parser readme;
+       ex A = readme("3*x2 + 1");
+       ex B = readme("9*x2 + 1");
+       ex g = chinrem_gcd(A, B);
+       if (!g.is_equal(ex(1))) {
+               std::cerr << "expected 1, got " << g << std::endl;
+               throw std::logic_error("chinrem_gcd miscomputed integer content");
+       }
+}
+
 int main(int argc, char** argv)
 {
        cout << "checking for bugs in poly_cra() and friends " << flush;
        check_poly_cra();
        check_extract_integer_content();
+       integer_coeff_braindamage();
        cout << "not found.";
        return 0;
 }
index 9f7df706bc95126a45414faa7229047670fee26a..9fe9d5f3875634ebd49ebf3aab7ab011b046ddf2 100644 (file)
@@ -119,6 +119,10 @@ AM_CONDITIONAL(CONFIG_TEX, [test ! \( -z "$LATEX" -o -z $"PDFLATEX" -o -z "$MAKE
 AC_PATH_PROG(FIG2DEV, fig2dev, "")
 AM_CONDITIONAL(CONFIG_FIG2DEV, [test ! -z "$FIG2DEV"])
 
+dnl generate boilerplate code for the (new) parser.
+dnl Only developers need this tool.
+AC_PATH_PROG(AUTOGEN, autogen, "")
+
 dnl Output makefiles etc.
 AC_CONFIG_FILES([
 Makefile
index 03e1845b6d27936e8c4824fd799f456b50dcdbb1..bf20afc4b3e807c9b08589da676cde97b226a2d0 100644 (file)
@@ -13,6 +13,7 @@ libginac_la_SOURCES = add.cpp archive.cpp basic.cpp clifford.cpp color.cpp \
   parser/parse_binop_rhs.cpp \
   parser/parser.cpp \
   parser/parse_context.cpp \
+  parser/builtin_fcns.cpp \
   parser/lexer.cpp \
   parser/lexer.h \
   parser/parser_compat.cpp \
@@ -66,7 +67,22 @@ ginacinclude_HEADERS = ginac.h add.h archive.h assertion.h basic.h class_info.h
   parser/parser.h \
   parser/parse_context.h
 
-EXTRA_DIST = function.pl version.h.in
+EXTRA_DIST = function.pl version.h.in \
+parser/default_reader.tpl parser/builtin_fcns.def
+
+# Files produced by autogen(1) from templates
+$(srcdir)/parser/builtin_fcns.cpp: $(srcdir)/parser/builtin_fcns.def $(srcdir)/parser/default_reader.tpl
+       set -e; if [ -n "$(AUTOGEN)" ]; then \
+               cd $(srcdir)/parser; \
+               $(AUTOGEN) -T default_reader.tpl builtin_fcns.def; \
+       elif [ -f $@ ]; then \
+               echo "WARNING: AutoGen is not available, the \"$@\" file WON'T be re-generated"; \
+       else \
+               echo "*** ERROR: the \"$@\" file does not exist, and AutoGen is not installed on your system"; \
+               echo "***        Please install AutoGen (http://www.gnu.org/software/autogen)"; \
+               exit 1; \
+       fi
+               
 
 # Files which are generated by perl scripts
 $(srcdir)/function.h $(srcdir)/function.cpp: $(srcdir)/function.pl
index 07e82e19d2578c73e6c10e3e9cf76caa6a60e797..1ca923d462fb9556442434612e0c9f9c3d6bee3e 100644 (file)
@@ -536,7 +536,6 @@ public:
        static unsigned register_new(function_options const & opt);
        static unsigned current_serial;
        static unsigned find_function(const std::string &name, unsigned nparams);
-       static std::vector<function_options> get_registered_functions() { return registered_functions(); };
        unsigned get_serial() const {return serial;}
        std::string get_name() const;
 
@@ -844,6 +843,9 @@ function::function(unsigned ser, const exprseq & es) : exprseq(es), serial(ser)
 function::function(unsigned ser, const exvector & v, bool discardable) 
   : exprseq(v,discardable), serial(ser)
 {
+       if ( ser >= registered_functions().size() ) {
+               throw std::runtime_error("function does not exist");
+       }
 }
 
 function::function(unsigned ser, std::auto_ptr<exvector> vp) 
@@ -1389,7 +1391,9 @@ unsigned function::find_function(const std::string &name, unsigned nparams)
 /** Return the print name of the function. */
 std::string function::get_name() const
 {
-       GINAC_ASSERT(serial<registered_functions().size());
+       if ( serial >= registered_functions().size() ) {
+               throw std::runtime_error("unknown function");
+       }
        return registered_functions()[serial].name;
 }
 
diff --git a/ginac/parser/builtin_fcns.def b/ginac/parser/builtin_fcns.def
new file mode 100644 (file)
index 0000000..96cd0a2
--- /dev/null
@@ -0,0 +1,14 @@
+Autogen definitions ginacfcns;
+
+/* Thease are not functions, but anyway ... */
+function = { name = "sqrt"; };
+
+function = { 
+       name = "pow";
+       args = 2;
+};
+
+function = {
+       name = "power";
+       args = 2;
+};
diff --git a/ginac/parser/default_reader.tpl b/ginac/parser/default_reader.tpl
new file mode 100644 (file)
index 0000000..006fb90
--- /dev/null
@@ -0,0 +1,145 @@
+[+ AutoGen5 template .cpp +][+ 
+COMMENT a part of GiNaC parser -- construct functions from a byte stream.
++][+
+(use-modules (ice-9 format))
+
+(define (sequence start end . step)
+  (let ((step (if (null? step) 1 (car step))))
+    (let loop ((n start))
+      (if (> n end) '() (cons n (loop (+ step n)))))))
++]/*
+[+ (dne " * " " * " ) +]
+ *
+ * If you want to change this file, edit either `[+ (def-file) +]' or
+ * `[+ (tpl-file) +]' file, and run the following command:
+ *
+ * autogen -T [+ (tpl-file) +] [+ (def-file) +]
+ */
+#include "parse_context.h"
+#include "power.h"
+#include "operators.h"
+#include "inifcns.h"
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef HAVE_STDINT_H
+#include <stdint.h> // for uintptr_t
+#endif
+
+namespace GiNaC
+{
+[+ FOR function +]
+static ex [+ (get "name") +]_reader(const exvector& ev)
+{
+       return GiNaC::[+ (get "name") +]([+
+               (let ((nargs (if (exist? "args")
+                                (string->number (get "args")) 1)))
+                 (format '#f "~{ev[~a]~^, ~}" (sequence 0 (- nargs 1)))) +]);
+}[+ ENDFOR +]
+
+// function::registered_functions() is protected, but we need to access it
+class registered_functions_hack : public function
+{
+public:
+       static const std::vector<function_options>& get_registered_functions()
+       {
+               return function::registered_functions();
+       }
+private:
+       registered_functions_hack();
+       registered_functions_hack(const registered_functions_hack&);
+       registered_functions_hack& operator=(const registered_functions_hack&);
+};
+
+// Encode an integer into a pointer to a function. Since functions
+// are aligned (the minimal alignment depends on CPU architecture)
+// we can distinguish between pointers and integers.
+static reader_func encode_serial_as_reader_func(unsigned serial)
+{
+       uintptr_t u = (uintptr_t)serial;
+       u = (u << 1) | (uintptr_t)1;
+       reader_func ptr = (reader_func)((void *)u);
+       return ptr;
+}
+
+const prototype_table& get_default_reader()
+{
+       using std::make_pair;
+       static bool initialized = false;
+       static prototype_table reader;
+       if (!initialized) {
+               [+ FOR function +]
+               reader[make_pair("[+ (get "name") +]", [+ 
+                       (if (exist? "args") (get "args") "1")
+                       +])] = [+ (get "name") +]_reader;[+
+               ENDFOR +]
+               std::vector<function_options>::const_iterator it =
+                       registered_functions_hack::get_registered_functions().begin();
+               std::vector<function_options>::const_iterator end =
+                       registered_functions_hack::get_registered_functions().end();
+               unsigned serial = 0;
+               for (; it != end; ++it) {
+                       prototype proto = make_pair(it->get_name(), it->get_nparams());
+                       reader[proto] = encode_serial_as_reader_func(serial);
+                       ++serial;
+               }
+               initialized = true;
+       }
+       return reader;
+}
+
+const prototype_table& get_builtin_reader()
+{
+       using std::make_pair;
+       static bool initialized = false;
+       static prototype_table reader;
+       if (!initialized) {
+               [+ FOR function +]
+               reader[make_pair("[+ (get "name") +]", [+ 
+                       (if (exist? "args") (get "args") "1")
+                       +])] = [+ (get "name") +]_reader;[+
+               ENDFOR +]
+               enum {
+                       log,
+                       exp,
+                       sin,
+                       cos,
+                       tan,
+                       asin,
+                       acos,
+                       atan,
+                       sinh,
+                       cosh,
+                       tanh,
+                       asinh,
+                       acosh,
+                       atanh,
+                       atan2,
+                       Li2,
+                       Li3,
+                       zetaderiv,
+                       Li,
+                       S,
+                       H,
+                       lgamma,
+                       tgamma,
+                       beta,
+                       factorial,
+                       binomial,
+                       Order,
+                       NFUNCTIONS
+               };
+               std::vector<function_options>::const_iterator it =
+                       registered_functions_hack::get_registered_functions().begin();
+               unsigned serial = 0;
+               for ( ; serial<NFUNCTIONS; ++it, ++serial ) {
+                       prototype proto = make_pair(it->get_name(), it->get_nparams());
+                       reader[proto] = encode_serial_as_reader_func(serial);
+               }
+               initialized = true;
+       }
+       return reader;
+}
+
+} // namespace GiNaC
index 88b0b30ec9b298cce1652e03318b3bd2ad2590aa..2230d614913fe56fe9a7feb82d5a1070d363092a 100644 (file)
@@ -22,8 +22,6 @@
 
 #include "parse_context.h"
 
-#include "function.h"
-
 #include <sstream>
 #include <stdexcept>
 
@@ -46,22 +44,4 @@ find_or_insert_symbol(const std::string& name, symtab& syms, const bool strict)
        return sy;
 }
 
-const prototype_table& get_default_reader(bool force_init)
-{
-       using std::make_pair;
-       static bool initialized = false;
-       static prototype_table reader;
-       if ( !initialized || force_init ) {
-               std::vector<function_options> flist = function::get_registered_functions();
-               std::vector<function_options>::iterator i = flist.begin(), end = flist.end();
-               for ( ; i != end; ++i ) {
-                       std::string name = i->get_name();
-                       unsigned narg = i->get_nparams();
-                       reader[make_pair(name, narg)] = function::find_function(name, narg);
-               }
-               initialized = true;
-       }
-       return reader;
-}
-
 } // namespace GiNaC
index 07496d7e8e26f0ac13fe0484f42643a2118b0ccd..1145a871cb4b2da67a95373d44ea0812ab2567a5 100644 (file)
@@ -72,18 +72,36 @@ typedef ex (*reader_func)(const exvector& args);
  * foo(x+y, z^2, t)), it looks up such a table to find out which
  * function (or class) corresponds to the given name and has the given
  * number of the arguments.
+ *
+ * N.B.
+ *
+ * 1. The function don't have to return a (GiNaC) function or class, it
+ *    can return any expression.
+ * 2. Overloaded functions/ctors are paritally supported, i.e. there might
+ *    be several functions with the same name, but they should take different
+ *    number of arguments.
+ * 3. User can extend the parser via custom prototype tables. It's possible
+ *    to read user defined classes, create abbreviations, etc.
+ *
+ * NOTE: due to a hack that allows user defined functions to be parsed, the map
+ *       value of type reader_func is internally treated as an unsigned and not as a
+ *       function pointer!! The unsigned has to correspond to the serial number of
+ *       the defined GiNaC function.
  */
-typedef std::map<prototype, unsigned> prototype_table;
+typedef std::map<prototype, reader_func> prototype_table;
 
 /**
- * Creates a default prototype table containing all defined GiNaC functions.
+ * Default prototype table.
+ *
+ * It supports all defined GiNaC functions and "pow", "sqrt", and "power".
+ */
+extern const prototype_table& get_default_reader();
+/**
+ * Builtin prototype table.
  *
- * The data referenced by the return value is only created once when this
- * function is called for the first time. This might cause problems in very
- * rare stituations (i.e. if functions are added after this first call). In
- * that case, a new initialization can be forced with an "true" argument.
+ * It supports only the builtin GiNaC functions and "pow", "sqrt", and "power".
  */
-extern const prototype_table& get_default_reader(bool force_init = false);
+extern const prototype_table& get_builtin_reader();
 
 } // namespace GiNaC
 
index 16eed69dc0f03552ffda7bbdf0ef22bc02a3c634..6c4ebea62563da64dc76983d3b8be83b3128242b 100644 (file)
 #include "lexer.h"
 #include "debug.h"
 #include "mul.h"
-#include "function.h"
 #include "constant.h"
+#include "function.h"
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
 
+#ifdef HAVE_STDINT_H
+#include <stdint.h> // for uintptr_t
+#endif
 #include <sstream>
 #include <stdexcept>
 
 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()
 {
@@ -66,7 +102,9 @@ ex parser::parse_identifier_expr()
                Parse_error_("no function \"" << name << "\" with " <<
                             args.size() << " arguments");
        }
-       ex ret = function(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;
 }
 
index 5b9da128223d8a6d9024b24e775398b2e3ed8b53..901f075a943f467355752a961183c62d83d0ad56 100644 (file)
@@ -40,21 +40,23 @@ static cln::cl_I extract_integer_content(ex& Apr, const ex& A)
 {
        static const cln::cl_I n1(1);
        const numeric icont_ = A.integer_content();
+       if (cln::instanceof(icont_.to_cl_N(), cln::cl_I_ring)) {
+               const cln::cl_I icont = cln::the<cln::cl_I>(icont_.to_cl_N());
+               if (icont != 1) {
+                       Apr = (A/icont_).expand();
+                       return icont;
+               } else {
+                       Apr = A;
+                       return n1;
+               }
+       }
        if (cln::instanceof(icont_.to_cl_N(), cln::cl_RA_ring)) {
                Apr = (A/icont_).expand();
                // A is a polynomail over rationals, so GCD is defined
                // up to arbitrary rational number.
                return n1;
        }
-       GINAC_ASSERT(cln::instanceof(icont_.to_cl_N(), cln::cl_I_ring));
-       const cln::cl_I icont = cln::the<cln::cl_I>(icont_.to_cl_N());
-       if (icont != 1) {
-               Apr = (A/icont_).expand();
-               return icont;
-       } else {
-               Apr = A;
-               return n1;
-       }
+       GINAC_ASSERT(NULL == "expected polynomial over integers or rationals");
 }
 
 ex chinrem_gcd(const ex& A_, const ex& B_, const exvector& vars)
@@ -99,7 +101,7 @@ ex chinrem_gcd(const ex& A_, const ex& B_, const exvector& vars)
                Cp = (Cp*numeric(nlc)).expand().smod(pnum);
                exp_vector_t cp_deg = degree_vector(Cp, vars);
                if (zerop(cp_deg))
-                       return numeric(g_lc);
+                       return numeric(c);
                if (zerop(q)) {
                        H = Cp;
                        n = cp_deg;
index c9db110fdc43a1cfb581128d48f592553644cfae..e7eb9c92317b5d53b55e333b9ec206e4ae4605a3 100644 (file)
@@ -150,12 +150,21 @@ static const std::string& get_default_TeX_name(const std::string& name);
 
 // public
 
+std::string symbol::get_name() const
+{
+       if (name.empty()) {
+               std::ostringstream s;
+               s << "symbol" << serial;
+               name = s.str();
+       }
+       return name;
+}
+
+// protected
+
 void symbol::do_print(const print_context & c, unsigned level) const
 {
-       if (!name.empty())
-               c.s << name;
-       else
-               c.s << "symbol" << serial;
+       c.s << get_name();
 }
 
 void symbol::do_print_latex(const print_latex & c, unsigned level) const
index eefd27c80672583ab37f5ae1be2b544fa0b805c2..ec371f8c3ed8ad40374b8bfc96b845f5d8a66e12 100644 (file)
@@ -69,7 +69,7 @@ protected:
        // non-virtual functions in this class
 public:
        void set_name(const std::string & n) { name = n; }
-       std::string get_name() const { return name; }
+       std::string get_name() const;
        virtual unsigned get_domain() const { return domain::complex; }
 protected:
        void do_print(const print_context & c, unsigned level) const;
@@ -81,7 +81,7 @@ protected:
 
 protected:
        unsigned serial;                 ///< unique serial number for comparison
-       std::string name;                ///< printname of this symbol
+       mutable std::string name;        ///< printname of this symbol
        std::string TeX_name;            ///< LaTeX name of this symbol
 private:
        static unsigned next_serial;
@@ -108,7 +108,7 @@ public:
 GINAC_DECLARE_UNARCHIVER(realsymbol);
 
 
-/** Specialization of symbol to real domain */
+/** Specialization of symbol to real positive domain */
 class possymbol : public realsymbol
 {
 public: