Commit a91b31d6 authored by Vivien Delmon's avatar Vivien Delmon
Browse files

Add krat_exp_parser and adapt test-suite.

	* bootstrap: Add bison generation of krat_exp_bison.
	* data/automata/b/Makefile.am: Modify CPPFLAGS and LDADD to link with libkrat_exp.
	* data/automata/tdc/Makefile.am: Modify CPPFLAGS and LDADD to link with libkrat_exp.
	* data/automata/z/Makefile.am: Modify CPPFLAGS and LDADD to link with libkrat_exp.
	* include/vaucanson/algebra/implementation/series/krat_exp_parser.hh: New.
	* include/vaucanson/algebra/implementation/series/krat_exp_parser.hxx: New.
	* include/vaucanson/algebra/implementation/series/krat_exp_proxy.hh: New proxy for krat_exp_parser.
	* include/vaucanson/algebra/implementation/series/krat_exp_proxy.hxx: New proxy for krat_exp_parser.
	* include/vaucanson/algebra/implementation/series/polynoms.hxx: Add "{" and "}" around weight.
	* include/vaucanson/algebra/implementation/series/rat/dump_visitor.hxx: Add "{" and "}" around weight.
	* lib/Makefile.am: Add include of libkrat_exp.mk.
	* lib/generate_libvcsn.rb: Modify CXXFLAGS to link with libkrat_exp.
	* lib/krat_exp/krat_exp_bison.yy: New bison grammar file.
	* lib/krat_exp/libkrat_exp.mk: New.
	* lib/krat_exp: New.
	* src/tests/include/tests/algebra/series/krat/main/krat_exp_expand_test.hh: Patch test with the new format.
	* src/tests/include/tests/algebra/series/krat/main/krat_exp_parse_test.hh: Patch test with the new format.
	* src/tests/sanity/Makefile.am: Modify CXXFLAGS to link with libkrat_exp.
	* src/tests/test-suites/test-suite.mk: Modify CXXFLAGS, CPPFLAGS and LDADD to link with libkrat_exp.
	* src/tests/xml/Makefile.am: Modify CPPFLAGS and LDADD to link with libkrat_exp.
	* src/tests/xml/label_node_ref.dot: Add "{" and "}" around weight.
	* src/tests/xml/xml_label_node_tester.cc: Add "{" and "}" around weight.
	* taf-kit/src/Makefile.am: Modify CPPFLAGS and LDADD to link with libkrat_exp.
	* taf-kit/tests/vcsn-z.test: Add "{" and "}" around weight.
parent 03acc7f0
2008-05-31 Vivien Delmon <vivien.delmon@lrde.epita.fr>
Add krat_exp_parser and adapt test-suite.
* bootstrap: Add bison generation of krat_exp_bison.
* data/automata/b/Makefile.am: Modify CPPFLAGS and LDADD to link with libkrat_exp.
* data/automata/tdc/Makefile.am: Modify CPPFLAGS and LDADD to link with libkrat_exp.
* data/automata/z/Makefile.am: Modify CPPFLAGS and LDADD to link with libkrat_exp.
* include/vaucanson/algebra/implementation/series/krat_exp_parser.hh: New.
* include/vaucanson/algebra/implementation/series/krat_exp_parser.hxx: New.
* include/vaucanson/algebra/implementation/series/krat_exp_proxy.hh: New proxy for krat_exp_parser.
* include/vaucanson/algebra/implementation/series/krat_exp_proxy.hxx: New proxy for krat_exp_parser.
* include/vaucanson/algebra/implementation/series/polynoms.hxx: Add "{" and "}" around weight.
* include/vaucanson/algebra/implementation/series/rat/dump_visitor.hxx: Add "{" and "}" around weight.
* lib/Makefile.am: Add include of libkrat_exp.mk.
* lib/generate_libvcsn.rb: Modify CXXFLAGS to link with libkrat_exp.
* lib/krat_exp/krat_exp_bison.yy: New bison grammar file.
* lib/krat_exp/libkrat_exp.mk: New.
* lib/krat_exp: New.
* src/tests/include/tests/algebra/series/krat/main/krat_exp_expand_test.hh: Patch test with the new format.
* src/tests/include/tests/algebra/series/krat/main/krat_exp_parse_test.hh: Patch test with the new format.
* src/tests/sanity/Makefile.am: Modify CXXFLAGS to link with libkrat_exp.
* src/tests/test-suites/test-suite.mk: Modify CXXFLAGS, CPPFLAGS and LDADD to link with libkrat_exp.
* src/tests/xml/Makefile.am: Modify CPPFLAGS and LDADD to link with libkrat_exp.
* src/tests/xml/label_node_ref.dot: Add "{" and "}" around weight.
* src/tests/xml/xml_label_node_tester.cc: Add "{" and "}" around weight.
* taf-kit/src/Makefile.am: Modify CPPFLAGS and LDADD to link with libkrat_exp.
* taf-kit/tests/vcsn-z.test: Add "{" and "}" around weight.
2008-05-28 Jimmy Ma <jimmy.ma@lrde.epita.fr>
Add benchs and tests on the delta iterators.
......
......@@ -67,6 +67,7 @@ run src/benchs ./generate_benchs.sh --all
run . build-aux/find_tests.sh
run include ./generate_headers.sh
run lib ./generate_libvcsn.rb
run lib/krat_exp bison krat_exp_bison.yy
# Will also boostrap argp/.
run . $AUTORECONF -v -f -i
......
......@@ -25,6 +25,8 @@ dist_b_automata_DATA = \
EXTRA_DIST = $(XML_SAMPLES)
MAINTAINERCLEANFILES = $(dist_b_automata_DATA)
a1_CPPFLAGS = $(AM_CPPFLAGS) -I$(top_srcdir)/lib/krat_exp
a1_LDADD = $(top_builddir)/lib/libkrat_exp.la
a1_SOURCES = a1.cc
$(srcdir)/a1.xml: a1.cc $(top_srcdir)/configure.ac
......@@ -34,24 +36,32 @@ $(srcdir)/a1.xml: a1.cc $(top_srcdir)/configure.ac
# Accepts words with a `b'.
# See ETA Fig. III.2.3, p. 434.
b1_CPPFLAGS = $(AM_CPPFLAGS) -I$(top_srcdir)/lib/krat_exp
b1_LDADD = $(top_builddir)/lib/libkrat_exp.la
b1_SOURCES = b1.cc
$(srcdir)/b1.xml: b1.cc $(top_srcdir)/configure.ac
$(MAKE) $(AM_MAKEFLAGS) b1$(EXEEXT)
./b1$(EXEEXT) xml >$@.tmp
mv $@.tmp $@
divkbaseb_CPPFLAGS = $(AM_CPPFLAGS) -I$(top_srcdir)/lib/krat_exp
divkbaseb_LDADD = $(top_builddir)/lib/libkrat_exp.la
divkbaseb_SOURCES = divkbaseb.cc
$(srcdir)/div3base2.xml: divkbaseb.cc $(top_srcdir)/configure.ac
$(MAKE) $(AM_MAKEFLAGS) divkbaseb$(EXEEXT)
./divkbaseb$(EXEEXT) 3 2 xml >$@.tmp
mv $@.tmp $@
ladybird_CPPFLAGS = $(AM_CPPFLAGS) -I$(top_srcdir)/lib/krat_exp
ladybird_LDADD = $(top_builddir)/lib/libkrat_exp.la
ladybird_SOURCES = ladybird.cc
$(srcdir)/ladybird-6.xml: ladybird.cc $(top_srcdir)/configure.ac
$(MAKE) $(AM_MAKEFLAGS) ladybird$(EXEEXT)
./ladybird$(EXEEXT) 6 xml >$@.tmp
mv $@.tmp $@
double_ring_CPPFLAGS = $(AM_CPPFLAGS) -I$(top_srcdir)/lib/krat_exp
double_ring_LDADD = $(top_builddir)/lib/libkrat_exp.la
double_ring_SOURCES = double_ring.cc
$(srcdir)/double-3-1.xml: double_ring.cc $(top_srcdir)/configure.ac
$(MAKE) $(AM_MAKEFLAGS) double_ring$(EXEEXT)
......
......@@ -22,6 +22,8 @@ dist_tdc_automata_DATA = \
EXTRA_DIST = $(XML_SAMPLES)
MAINTAINERCLEANFILES = $(dist_tdc_automata_DATA)
t1_CPPFLAGS = $(AM_CPPFLAGS) -I$(top_srcdir)/lib/krat_exp
t1_LDADD = $(top_builddir)/lib/libkrat_exp.la
t1_SOURCES = t1.cc
$(srcdir)/t1.xml: t1.cc $(top_srcdir)/configure.ac
......@@ -29,7 +31,8 @@ $(srcdir)/t1.xml: t1.cc $(top_srcdir)/configure.ac
./t1$(EXEEXT) >$@.tmp
mv $@.tmp $@
u1_CPPFLAGS = $(AM_CPPFLAGS) -I$(top_srcdir)/lib/krat_exp
u1_LDADD = $(top_builddir)/lib/libkrat_exp.la
u1_SOURCES = u1.cc
$(srcdir)/u1.xml: u1.cc $(top_srcdir)/configure.ac
......
......@@ -27,6 +27,8 @@ $(srcdir)/b1.xml: $(top_srcdir)/data/automata/b/b1.xml
sed -e 's/set="B"/set="Z"/g' $< >$@.tmp
mv $@.tmp $@
c1_CPPFLAGS = $(AM_CPPFLAGS) -I$(top_srcdir)/lib/krat_exp
c1_LDADD = $(top_builddir)/lib/libkrat_exp.la
c1_SOURCES = c1.cc
$(srcdir)/c1.xml: c1.cc $(top_srcdir)/configure.ac
$(MAKE) $(AM_MAKEFLAGS) c1$(EXEEXT)
......
......@@ -2,7 +2,7 @@
//
// Vaucanson, a generic library for finite state machines.
//
// Copyright (C) 2001, 2002, 2003, 2004, 2005 The Vaucanson Group.
// Copyright (C) 2001, 2002, 2003, 2004, 2005, 2008 The Vaucanson Group.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
......@@ -14,6 +14,7 @@
//
// The Vaucanson Group consists of people listed in the `AUTHORS' file.
//
#ifndef VCSN_ALGEBRA_IMPLEMENTATION_SERIES_KRAT_EXP_PARSER_HH
# define VCSN_ALGEBRA_IMPLEMENTATION_SERIES_KRAT_EXP_PARSER_HH
......@@ -26,14 +27,13 @@
*
* @author Yann Régis-Gianas <yann@lrde.epita.fr>,
* Thomas Claveirole <thomas@lrde.epita.fr>
* Vivien Delmon <vivien@lrde.epita.fr>
* @see parse()
*/
/** @} */
/** @} */
# include <vaucanson/design_pattern/design_pattern.hh>
# include <utility>
# include <string>
namespace vcsn {
......@@ -45,36 +45,32 @@ namespace vcsn {
/**
* Parse a rational expression.
*
* This functions parses any numerical rational expression.
* The grammar is:
* This fonction parses any kind of rational expression using the bison
* generated parser.
*
* The grammar is :
*
@verbatim
exp ::= '(' exp ')'
| exp '+' exp
| exp '.' exp
| exp exp
| exp '*'
| weight ' ' exp
| exp ' ' weight
| 0
| 1
| word
%start rexp
rexp ::= OPAR exp CPAR
| rexp PLUS rexp
| rexp TIMES rexp
| rexp rexp
| rexp STAR
| WEIGHT rexp
| rexp WEIGHT
| ONE
| ZERO
| WORD
@endverbatim
*
* Priority for operators is, from the most important to the least
* important:
*
* - * (star), to star a series.
* - ' ' (space), to weight a series either on the right or on the left.
* - . (dot), to concatenate two series.
* - + (plus), to do the union of two series.
* @todo The token representation must be contain in the automaton.
*
* This function returns a pair which first element is a Boolean
* indicating whether an error occured or not. The second element
* is an error message when a parse error have been ecountered.
*
* Note that this function requires exception support from the compiler.
*
* @param from The rational expression, as a string.
* @param exp The element to store the result in. Be sure its set
* is correct before calling parse.
......@@ -83,7 +79,10 @@ namespace vcsn {
*
* @author Yann Régis-Gianas <yann@lrde.epita.fr>,
* Thomas Claveirole <thomas@lrde.epita.fr>
* Vivien Delmon <vivien@lrde.epita.fr>
*/
template <class S, class T>
std::pair<bool, std::string>
parse(const std::string& from,
......
// krat_exp_proxy.hh: this file is part of the Vaucanson project.
//
// Vaucanson, a generic library for finite state machines.
//
// Copyright (C) 2008 The Vaucanson Group.
//
// 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.
//
// The complete GNU General Public Licence Notice can be found as the
// `COPYING' file in the root directory.
//
// The Vaucanson Group consists of people listed in the `AUTHORS' file.
//
#ifndef VCSN_ALGEBRA_IMPLEMENTATION_SERIES_KRAT_EXP_PROXY_HH
# define VCSN_ALGEBRA_IMPLEMENTATION_SERIES_KRAT_EXP_PROXY_HH
# include <vaucanson/design_pattern/design_pattern.hh>
namespace vcsn {
namespace algebra {
/** @addtogroup algebra *//** @{ */
/** @addtogroup series *//** @{ */
/**
** @interface semiring_virtual
** @brief Virtual pure class used by bison to deal with vaucanson's
** templated structures
*/
struct semiring_virtual
{
virtual semiring_virtual& operator=(semiring_virtual& sem) = 0;
virtual ~semiring_virtual() {}
};
/**
** @interface krat_exp_virtual
** @brief Virtual pure class used by bison to deal with vaucanson's
** templated structures
*/
struct krat_exp_virtual
{
/* Virtual fonctions used in the parser */
virtual krat_exp_virtual& operator=(krat_exp_virtual& exp) = 0;
virtual krat_exp_virtual* operator+(krat_exp_virtual* exp) = 0;
virtual krat_exp_virtual* operator*(krat_exp_virtual* exp) = 0;
virtual void star() = 0;
virtual void left_weight(semiring_virtual* sem) = 0;
virtual void right_weight(semiring_virtual* sem) = 0;
virtual ~krat_exp_virtual() {}
};
/**
** @struct krat_exp_proxy
** @brief Proxy over Vaucanson Element
*/
template <class S, class T>
struct krat_exp_proxy : public krat_exp_virtual
{
typedef typename Element<S, T>::monoid_elt_t monoid_elt_t;
// Constructors && Destructor
krat_exp_proxy(Element<S, T> exp);
~krat_exp_proxy() {}
krat_exp_virtual& operator=(krat_exp_virtual& exp);
krat_exp_virtual* operator+(krat_exp_virtual* exp);
krat_exp_virtual* operator*(krat_exp_virtual* exp);
void star();
void left_weight(semiring_virtual* sem);
void right_weight(semiring_virtual* sem);
// Attibutes
Element<S, T> self;
};
/**
** @struct semiring_proxy
** @brief Proxy over Vaucanson Semiring
*/
template <class S, class T>
struct semiring_proxy : public semiring_virtual
{
typedef typename Element<S, T>::semiring_elt_t semiring_elt_t;
//Constructor && Destructor
semiring_proxy(semiring_elt_t& sem);
~semiring_proxy() {}
semiring_virtual& operator=(semiring_virtual& sem);
// Attibutes
semiring_elt_t self;
};
/** @} */
/** @} */
} // algebra
} // vcsn
# if !defined VCSN_USE_INTERFACE_ONLY || defined VCSN_USE_LIB
# include <vaucanson/algebra/implementation/series/krat_exp_proxy.hxx>
# endif // VCSN_USE_INTERFACE_ONLY
#endif // !VCSN_ALGEBRA_IMPLEMENTATION_SERIES_KRAT_EXP_PROXY_HH //
// krat_exp_proxy.hxx: this file is part of the Vaucanson project.
//
// Vaucanson, a generic library for finite state machines.
//
// Copyright (C) 2008 The Vaucanson Group.
//
// 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.
//
// The complete GNU General Public Licence Notice can be found as the
// `COPYING' file in the root directory.
//
// The Vaucanson Group consists of people listed in the `AUTHORS' file.
//
#ifndef VCSN_ALGEBRA_IMPLEMENTATION_SERIES_KRAT_EXP_PROXY_HXX
# define VCSN_ALGEBRA_IMPLEMENTATION_SERIES_KRAT_EXP_PROXY_HXX
namespace vcsn {
namespace algebra {
template <class S, class T>
krat_exp_proxy<S, T>::krat_exp_proxy(Element<S, T> exp) :
self(exp)
{
}
template <class S, class T>
krat_exp_virtual&
krat_exp_proxy<S, T>::operator=(krat_exp_virtual& exp)
{
self = (dynamic_cast<krat_exp_proxy<S, T>*> (&exp))->self;
return *this;
}
template <class S, class T>
krat_exp_virtual*
krat_exp_proxy<S, T>::operator+(krat_exp_virtual* exp)
{
return new krat_exp_proxy<S, T>(self + (dynamic_cast<krat_exp_proxy<S, T>*> (exp))->self);
}
template <class S, class T>
krat_exp_virtual*
krat_exp_proxy<S, T>::operator*(krat_exp_virtual* exp)
{
return new krat_exp_proxy<S, T>(self * (dynamic_cast<krat_exp_proxy<S, T>*> (exp))->self);
}
template <class S, class T>
void
krat_exp_proxy<S, T>::star()
{
self.star();
}
template <class S, class T>
void
krat_exp_proxy<S, T>::left_weight(semiring_virtual* sem)
{
self = (dynamic_cast<semiring_proxy<S, T>*> (sem))->self * self;
}
template <class S, class T>
void
krat_exp_proxy<S, T>::right_weight(semiring_virtual* sem)
{
self = self * (dynamic_cast<semiring_proxy<S, T>*> (sem))->self;
}
template <class S, class T>
semiring_proxy<S, T>::semiring_proxy(semiring_elt_t& sem) :
self(sem)
{
}
template <class S, class T>
semiring_virtual&
semiring_proxy<S, T>::operator=(semiring_virtual& sem)
{
self = (dynamic_cast<semiring_proxy<S, T>*> (&sem))->self;
return *this;
}
} // algebra
} // vcsn
#endif // !VCSN_ALGEBRA_IMPLEMENTATION_SERIES_KRAT_EXP_PROXY_HXX //
......@@ -629,9 +629,9 @@ namespace vcsn {
if (i->second != identity_value(SELECT(W), SELECT(Tw)))
{
st << "(";
st << "({";
op_rout(s.semiring(), st, i->second);
st << " ";
st << "} ";
}
if (i->first != identity_value(SELECT(M), SELECT(Tm)))
......@@ -766,7 +766,7 @@ namespace std {
{
if (i != p.begin())
out << "+";
out << "(" << i->second << " "
out << "({" << i->second << "} "
<< vcsn::misc::make_escaper(i->first) << ")";
++i;
}
......
......@@ -219,7 +219,7 @@ namespace vcsn {
if (enclose_all)
ostr_ << "(";
ostr_ << w << " ";
ostr_ << "{" << w << "} ";
enclose_if(verbose, node);
if (enclose_all)
......@@ -253,7 +253,7 @@ namespace vcsn {
ostr_ << "(";
enclose_if(verbose, node);
ostr_ << " " << w;
ostr_ << " {" << w << "}";
if (enclose_all)
ostr_ << ")";
......
......@@ -18,6 +18,7 @@ AUTOMAKE_OPTIONS = subdir-objects
lib_LTLIBRARIES =
MAINTAINERCLEANFILES =
include krat_exp/libkrat_exp.mk
include vcsn-b/libvcsn-b.mk
include vcsn-r/libvcsn-r.mk
include vcsn-z/libvcsn-z.mk
......
......@@ -115,7 +115,7 @@ def write_makefile(type, context)
"##",
"",
"lib_LTLIBRARIES\t+= lib" + type + ".la",
"lib" + type.gsub(/-/, "_") + "_la_CXXFLAGS\t= $(CXXFLAGS) -DVCSN_CONTEXT=" + context,
"lib" + type.gsub(/-/, "_") + "_la_CXXFLAGS\t= $(CXXFLAGS) -I$(top_srcdir)/lib/krat_exp/ -DVCSN_CONTEXT=" + context,
"lib" + type.gsub(/-/, "_") + "_la_LIBADD\t= $(LIBOBJS)")
out.print "lib" + type.gsub(/-/, "_") + "_la_SOURCES\t= "
files = Dir.glob(type + "/*cc").sort!
......
%skeleton "lalr1.cc"
%defines
%define "parser_class_name" "krat_exp_parser"
%error-verbose
%{
# include <vaucanson/algebra/implementation/series/krat_exp_proxy.hh>
# include <map>
# include <queue>
//_DEBUG_
# include <iostream>
%}
%parse-param { std::queue<std::pair<krat_exp_parser::token_type, krat_exp_parser::semantic_type> >& tok_q }
%parse-param { vcsn::algebra::krat_exp_virtual& exp }
%lex-param { std::queue<std::pair<krat_exp_parser::token_type, krat_exp_parser::semantic_type> >& tok_q }
%union
{
vcsn::algebra::krat_exp_virtual * rexp;
vcsn::algebra::semiring_virtual * sem;
std::string * str;
}
%{
int
yylex(yy::krat_exp_parser::semantic_type* yylval,
std::queue<std::pair<yy::krat_exp_parser::token_type, yy::krat_exp_parser::semantic_type> >& tok_q);
%}
%token <str> OPAR
%token <str> CPAR
%token <str> PLUS
%token <str> TIMES
%token <str> STAR
%token <sem> WEIGHT
%token <rexp> ONE
%token <rexp> ZERO
%token <rexp> WORD
%token LPROD
%type <rexp> rexp
%left OPAR;
%left PLUS;
%left TIMES;
%left TIMES2;
%left WEIGHT;
%left LPROD;
%left STAR;
%nonassoc ONE;
%nonassoc ZERO;
%nonassoc WORD;
%%
%start exp;
exp :
rexp {exp = *$1}
;
rexp :
OPAR rexp CPAR {$$ = $2}
| rexp PLUS rexp {$$ = *$1 + $3; delete $1; delete $3}
| rexp TIMES rexp {$$ = *$1 * $3; delete $1; delete $3}
| rexp rexp %prec TIMES2{$$ = *$1 * $2; delete $1; delete $2}
| rexp STAR {$1->star(); $$ = $1}
| WEIGHT rexp %prec LPROD {$2->left_weight($1); delete $1; $$ = $2}
| rexp WEIGHT {$1->right_weight($2); delete $2;$$ = $1}
| ONE {$$ = $1}
| ZERO {$$ = $1}
| WORD {$$ = $1}
;
%%
int
yylex(yy::krat_exp_parser::semantic_type* yylval,
std::queue<std::pair<yy::krat_exp_parser::token_type, yy::krat_exp_parser::semantic_type> >& tok_q)
{
yy::krat_exp_parser::token_type res;
if (tok_q.empty())
return 0;
else
{
*yylval = tok_q.front().second;
res = tok_q.front().first;
tok_q.pop();
return res;
}
}
void
yy::krat_exp_parser::error(const yy::krat_exp_parser::location_type& loc, const std::string& s)
{
std::cout << s << std::endl;
}
## Vaucanson, a generic library for finite state machines.
## Copyright (C) 2008 The Vaucanson Group.
##
## 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.
##
## The complete GNU General Public Licence Notice can be found as the
## `COPYING' file in the root directory.
##
## The Vaucanson Group consists of people listed in the `AUTHORS' file.
lib_LTLIBRARIES += libkrat_exp.la
libkrat_exp_la_CXXFLAGS = $(CXXFLAGS)
libkrat_exp_la_LIBADD = $(LIBOBJS)
libkrat_exp_la_SOURCES = krat_exp/krat_exp_bison.tab.cc
MAINTAINERCLEANFILES += $(libkrat_exp_la_SOURCES) \
krat_exp/krat_exp_bison.tab.hh \
stack.hh \
location.hh \
position.hh
......@@ -45,34 +45,34 @@ struct specialized_tests
test(t, e, "0", "0");
test(t, e, "1", "1");
test(t, e, "a", "a");
test(t, e, "(5 1)", "(5 1)");
test(t, e, "(2 a)", "(2 a)");
test(t, e, "({5} 1)", "({5} 1)");
test(t, e, "({2} a)", "({2} a)");
test(t, e, "(a+b)", "(a+b)");
test(t, e, "a.(a+b)", "(aa+ab)");
test(t, e, "(a+b).a", "(aa+ba)");
test(t, e, "a+a", "(2 a)");
test(t, e, "(2 a)+a", "(3 a)");
test(t, e, "a+(2 a)", "(3 a)");
test(t, e, "(a+(2 a+b))", "((3 a)+b)");