From 3229ec7c42ffc173f94f1c3bffbc30308c93e571 Mon Sep 17 00:00:00 2001 From: Christian Bauer Date: Fri, 12 Jul 2002 18:08:49 +0000 Subject: [PATCH 1/1] the input parser now handles (simple) indexed objects; the indices to be used have to be specified in the same list as the symbols --- ginac/ex.h | 7 ++++--- ginac/input_lexer.h | 3 +++ ginac/input_lexer.ll | 25 +++++++++++++++++++------ ginac/input_parser.yy | 36 ++++++++++++++++++++++++++++++++++-- 4 files changed, 60 insertions(+), 11 deletions(-) diff --git a/ginac/ex.h b/ginac/ex.h index f59cd7ae..9f3dd6b4 100644 --- a/ginac/ex.h +++ b/ginac/ex.h @@ -89,10 +89,11 @@ public: ex(long i); ex(unsigned long i); ex(double const d); + /** Construct ex from string and a list of symbols. The input grammar is - * similar to the GiNaC output format. All symbols to be used in the - * expression must be specified in a lst in the second argument. Undefined - * symbols and other parser errors will throw an exception. */ + * similar to the GiNaC output format. All symbols and indices to be used + * in the expression must be specified in a lst in the second argument. + * Undefined symbols and other parser errors will throw an exception. */ ex(const std::string &s, const ex &l); // non-virtual functions in this class diff --git a/ginac/input_lexer.h b/ginac/input_lexer.h index b7cc3c01..ed3f94c6 100644 --- a/ginac/input_lexer.h +++ b/ginac/input_lexer.h @@ -50,6 +50,9 @@ class ex; /** Set the input string to be parsed by ginac_yyparse() (used internally). */ extern void set_lexer_string(const std::string &s); +/** Get name of symbol/index (used internally). */ +extern std::string get_symbol_name(const ex & s); + /** Set the list of predefined symbols for the lexer (used internally). */ extern void set_lexer_symbols(ex l); diff --git a/ginac/input_lexer.ll b/ginac/input_lexer.ll index 6396248d..4a5a6501 100644 --- a/ginac/input_lexer.ll +++ b/ginac/input_lexer.ll @@ -39,6 +39,7 @@ #include "numeric.h" #include "symbol.h" #include "lst.h" +#include "idx.h" using namespace GiNaC; namespace GiNaC { @@ -47,7 +48,7 @@ namespace GiNaC { } // namespace GiNaC -// Table of all used symbols +// Table of all used symbols/indices struct sym_def { sym_def() : predefined(false) {} sym_def(const ex &s, bool predef) : sym(s), predefined(predef) {} @@ -166,22 +167,34 @@ void set_lexer_string(const std::string &s) curr_pos = 0; } -// Set the list of predefined symbols +// Get name of symbol/index +std::string get_symbol_name(const ex & s) +{ + if (is_a(s)) + return ex_to(s).get_name(); + else if (is_a(s) && is_a(s.op(0))) + return ex_to(s.op(0)).get_name(); + else + throw (std::runtime_error("get_symbol_name(): unexpected expression type")); +} + +// Set the list of predefined symbols/indices void set_lexer_symbols(ex l) { syms.clear(); if (!is_exactly_a(l)) return; for (unsigned i=0; i(l.op(i))) - syms[ex_to(l.op(i)).get_name()] = sym_def(l.op(i), true); + const ex &o = l.op(i); + if (is_a(o) || (is_a(o) && is_a(o.op(0)))) + syms[get_symbol_name(o)] = sym_def(o, true); } } -// Check whether symbol was predefined +// Check whether symbol/index was predefined bool is_lexer_symbol_predefined(const ex &s) { - sym_tab::const_iterator i = syms.find(ex_to(s).get_name()); + sym_tab::const_iterator i = syms.find(get_symbol_name(s)); if (i == syms.end()) return false; else diff --git a/ginac/input_parser.yy b/ginac/input_parser.yy index d3ffd195..c5c78d2d 100644 --- a/ginac/input_parser.yy +++ b/ginac/input_parser.yy @@ -36,6 +36,8 @@ #include "lst.h" #include "power.h" #include "exprseq.h" +#include "idx.h" +#include "indexed.h" #include "matrix.h" #include "inifcns.h" @@ -48,6 +50,9 @@ ex parsed_ex; // Last error message returned by parser static std::string parser_error; + +// Prototypes +ex attach_index(const ex & base, ex i, bool covariant); %} /* Tokens (T_LITERAL means a literal value returned by the parser, but not @@ -62,6 +67,7 @@ static std::string parser_error; %left '*' '/' '%' %nonassoc NEG %right '^' +%left '.' '~' %nonassoc '!' %start input @@ -89,12 +95,12 @@ exp : T_NUMBER {$$ = $1;} if (is_lexer_symbol_predefined($1)) $$ = $1.eval(); else - throw (std::runtime_error("unknown symbol '" + ex_to($1).get_name() + "'")); + throw (std::runtime_error("unknown symbol '" + get_symbol_name($1) + "'")); } | T_LITERAL {$$ = $1;} | T_DIGITS {$$ = $1;} | T_SYMBOL '(' exprseq ')' { - std::string n = ex_to($1).get_name(); + std::string n = get_symbol_name($1); if (n == "sqrt") { if ($3.nops() != 1) throw (std::runtime_error("too many arguments to sqrt()")); @@ -117,6 +123,8 @@ exp : T_NUMBER {$$ = $1;} | '-' exp %prec NEG {$$ = -$2;} | '+' exp %prec NEG {$$ = $2;} | exp '^' exp {$$ = pow($1, $3);} + | exp '.' exp {$$ = attach_index($1, $3, true);} + | exp '~' exp {$$ = attach_index($1, $3, false);} | exp '!' {$$ = factorial($1);} | '(' exp ')' {$$ = $2;} | '{' list_or_empty '}' {$$ = $2;} @@ -149,6 +157,30 @@ row : exp {$$ = lst($1);} */ %% +// Attach index to expression +ex attach_index(const ex & base, ex i, bool covariant) +{ + // Toggle index variance if necessary + if (is_a(i)) { + const varidx &vi = ex_to(i); + if (vi.is_covariant() != covariant) + i = vi.toggle_variance(); + } else if (!covariant) + throw (std::runtime_error("index '" + get_symbol_name(i) + "' is not a varidx and cannot be contravariant")); + + // Add index to an existing indexed object, or create a new indexed + // object if there are no indices yet + if (is_a(base)) { + const ex &b = base.op(0); + exvector iv; + for (unsigned n=1; n