diff --git a/AUTHORS b/AUTHORS
index bf1ef5c8e9555c6a3f8417f4f73f154aa0bf90a8..1e1c11f9998fc48c03b7c9a461a5b2630fa69b0f 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -1,7 +1,7 @@
Benjie Chen
benjie@lcs.mit.edu
polling extensions, Linux kernel patches, stride scheduling, Linux kernel
-thread, device driver updates, smp click
+thread, device driver updates, SMP patches
Douglas S. J. De Couto
decouto@lcs.mit.edu
@@ -27,7 +27,7 @@ universal improvements, new elements
Robert Morris
rtm@lcs.mit.edu
-design, Ethernet, IP, Linux kernel module, and radio elements, Linux kernel
+design, Ethernet, IP, Linux kernel module, radio elements, Linux kernel
patches, IP router configuration, element documentation, other elements
Massimiliano Poletto
diff --git a/DISTFILES b/DISTFILES
index 052d0d1f029b1feddef134eac6957fbb4cb899a1..1b09be8481929d5b3d1dd34bca98c0cc54d6a631 100644
--- a/DISTFILES
+++ b/DISTFILES
@@ -113,6 +113,7 @@ include/click/string.hh
include/click/subvector.hh
include/click/timer.hh
include/click/userutils.hh
+include/click/variableenv.hh
include/click/vector.cc
include/click/vector.hh
@@ -149,6 +150,7 @@ lib/string.cc
lib/templatei.cc
lib/timer.cc
lib/userutils.cc
+lib/variableenv.cc
lib/vectorv.cc
userlevel
diff --git a/doc/click.5 b/doc/click.5
index cb80f7d554b36dadc33d494f8eb0b47fe3a742f7..b1eab74a8f7ca7820a2aa5f61394b1ce0d1afee0 100644
--- a/doc/click.5
+++ b/doc/click.5
@@ -321,7 +321,7 @@ a -> X -> b;
c -> Y -> d;
.Re
.PP
-The `input' and `output' pseudo-elements have no existence in a running
+The `input' and `output' pseudoelements have no existence in a running
router; they serve as placeholders for connections from outside. (In fact,
they are connection tunnel endpoints. See below for more on connection
tunnels.)
@@ -362,6 +362,11 @@ like
Nothing prevents a user from declaring an element named like a compound
element component. We suggest that users generally avoid using the `/'
character in their element names.
+.PP
+It is an error to use the `input' pseudoelement's input ports or the
+`output' pseudoelement's output ports. It is also an error to leave an
+intermediate port unused\*Efor example, to use `input [0]' and `input [2]'
+but not `input [1]'.
'
.SS "The `elementclass' statement"
'
@@ -449,7 +454,58 @@ expands to this:
.Rs
\&... -> A(1, 100, 3) -> ...
.Re
-You can avoid this substitution by quoting a dollar sign with a backslash.
+You can avoid this substitution by putting the dollar sign inside single
+quotes.
+'
+.SS "Overloading"
+'
+A single compound element may contain multiple overloaded definitions
+separated from one another by two vertical bars "\f(CW||\fR". Different
+definitions may have different numbers of input ports, output ports, or
+configuration arguments. For example, this extended MyQueue compound
+element takes an optional capacity argument, just like Queue itself:
+.Rs
+elementclass MyQueue {
+.br
+\% input -> Queue -> Shaper(1000) -> output;
+.br
+\%||
+.br
+\% $cap | input -> Queue($cap)
+.br
+\% -> Shaper(1000) -> output;
+.br
+}
+.Re
+For each use of an overloaded compound element, Click will choose one
+definition that matches the numbers of input ports, output ports, and
+configuration arguments provided. It is an error if no definition matches
+these properties exactly.
+.PP
+It is also possible to extend an existing element class with new overloaded
+definitions with "\f(CW...\fR". For example, this definition introduces a
+two-argument version of Queue:
+.Rs
+elementclass Queue { ... ||
+.br
+\% $cap, $rate | input -> Queue($cap)
+.br
+\% -> Shaper($rate) -> output;
+.br
+}
+.Re
+(The ellipsis in this example must be typed verbatim.) The overloadings
+visible at a given declaration are those that lexically precede that
+declaration. For example, the following example is an error since the
+two-argument version of Test is not visible at the declaration where it is
+required:
+.Rs
+elementclass Test { $a | /* nothing */ }
+.br
+test :: Test(1, 2);
+.br
+elementclass Test { ... || $a, $b | /* nothing */ }
+.Re
'
.SH "CONNECTION TUNNELS"
'
@@ -562,11 +618,12 @@ The keywords `connectiontunnel', `elementclass' and `require' may not be
used as identifiers. The normal identifiers `input' and `output' have
special meaning inside compound element definitions.
.PP
-The following characters and two-character sequences are single Click
+The following characters and multi-character sequences are single Click
tokens:
.TS
l l l l l l l l l l l l l.
-> :: ; , ( ) [ ] { } |
+ || ...
.\" ^
.TE
.PP
@@ -646,9 +703,13 @@ kernel module will not accept archives; use
.IR element-name " ::= identifier
.\" | ""^"" identifier
.br
-.IR class " ::= identifier | ""{"" " stmts " ""}"""
+.IR class " ::= identifier | ""{"" " compounds " ""}"""
+.br
+.RI " | ""{"" ""..."" ""||"" " compounds " ""}"""
+.br
+.IR compounds " ::= " compound " | " compounds " ""||"" " compound
.br
-.RI " | ""{"" " formals " ""|"" " stmts " ""}"""
+.IR compound " ::= " stmts " | " formals " ""|"" " stmts
.br
.IR formals " ::= parameter | " formals " "","" parameter"
.br
diff --git a/elements/standard/nulls.hh b/elements/standard/nulls.hh
index 0738f9f0187cf96b3fdbf88c62258cd12f5741e3..83cacad812b16555fb363814ba48a698654dcac2 100644
--- a/elements/standard/nulls.hh
+++ b/elements/standard/nulls.hh
@@ -3,21 +3,28 @@
#include <click/element.hh>
/*
- * =c
- * Null1()
- * Null2()
- * Null3()
- * Null4()
- * Null5()
- * Null6()
- * Null7()
- * Null8()
- * =s
- * copies of Null
- * =d
- * Copies of Null that do not share code.
- * =a Null
- */
+=c
+
+Null1()
+Null2()
+Null3()
+Null4()
+Null5()
+Null6()
+Null7()
+Null8()
+
+=s
+
+copy of Null
+
+=d
+
+Each of these elements is a reimplementation of Null. However, each has
+independent code, so the i-cache cost of using all eight elements (Null1
+through Null8) is eight times the cost of eight Null elements.
+
+=a Null */
class Null1 : public Element {
diff --git a/include/click/lexer.hh b/include/click/lexer.hh
index 1656c3c4ddc7ced7290dad17140796b32aaaaebf..fb22a40f507687eb77299b0bf93c687dbd9a175b 100644
--- a/include/click/lexer.hh
+++ b/include/click/lexer.hh
@@ -4,6 +4,7 @@
#include <click/router.hh>
#include <click/glue.hh>
class LexerExtra;
+class VariableEnvironment;
enum Lexemes {
lexEOF = 0,
@@ -11,6 +12,8 @@ enum Lexemes {
lexVariable,
lexArrow,
lex2Colon,
+ lex2Bar,
+ lex3Dot,
lexTunnel,
lexElementclass,
lexRequire,
@@ -38,6 +41,7 @@ class Lexer {
class TunnelEnd;
class Compound;
+ class Synonym;
typedef Router::Hookup Hookup;
// lexer
@@ -70,21 +74,16 @@ class Lexer {
Vector<Element *> _element_types;
Vector<String> _element_type_names;
Vector<int> _element_type_next;
- Element *_tunnel_element_type;
int _last_element_type;
int _free_element_type;
- // configuration arguments for compounds
- HashMap<String, int> _variable_map;
- Vector<String> _variable_values;
-
// elements
HashMap<String, int> _element_map;
- Vector<Element *> _elements;
+ Vector<int> _elements;
Vector<String> _element_names;
Vector<String> _element_configurations;
Vector<String> _element_landmarks;
-
+
Vector<Hookup> _hookup_from;
Vector<Hookup> _hookup_to;
@@ -92,8 +91,8 @@ class Lexer {
TunnelEnd *_defoutputs;
// compound elements
- String _element_prefix;
int _anonymous_offset;
+ int _compound_depth;
// requirements
Vector<String> _requirements;
@@ -107,10 +106,11 @@ class Lexer {
int get_element(String, int, const String & = String(), const String & = String());
int lexical_scoping_in() const;
void lexical_scoping_out(int);
- void lexical_scoping_back(int, Vector<int> &);
- void lexical_scoping_forward(const Vector<int> &);
- int make_compound_element(String, int, const String &);
+ int make_compound_element(int);
+ void expand_compound_element(int, Vector<int> &, Vector<VariableEnvironment *> &);
void add_router_connections(int, const Vector<int> &, Router *);
+
+ friend class Compound;
public:
@@ -128,7 +128,6 @@ class Lexer {
const Lexeme &lex();
void unlex(const Lexeme &);
String lex_config();
- String lex_compound_body();
String landmark() const;
bool expect(int, bool report_error = true);
@@ -142,20 +141,20 @@ class Lexer {
void remove_element_type(int);
- void connect(int f1, int p1, int f2, int p2);
+ void connect(int element1, int port1, int element2, int port2);
String element_name(int) const;
String element_landmark(int) const;
void add_tunnel(String, String);
bool yport(int &port);
- bool yelement_upref(int &element);
bool yelement(int &element, bool comma_ok);
- void ydeclaration(const String &first_element = "");
+ void ydeclaration(const String &first_element = String());
bool yconnection();
void yelementclass();
void ytunnel();
- int ylocal(String = "");
+ void ycompound_arguments(Compound *);
+ int ycompound(String name = String());
void yrequire();
bool ystatement(bool nested = false);
diff --git a/lib/confparse.cc b/lib/confparse.cc
index a4549ab078704a39028e343112d7b33ece4d09f0..6697dbb37d1b04ed3e305c7cf0049392ac0ff16a 100644
--- a/lib/confparse.cc
+++ b/lib/confparse.cc
@@ -2025,7 +2025,7 @@ cp_unparse_ulonglong(unsigned long long q, int base, bool uppercase)
void
cp_va_static_initialize()
{
- cp_add_argtype(cpArgument, "??", 0, default_parsefunc, default_storefunc);
+ cp_add_argtype(cpArgument, "arg", 0, default_parsefunc, default_storefunc);
cp_add_argtype(cpString, "string", 0, default_parsefunc, default_storefunc);
cp_add_argtype(cpWord, "word", 0, default_parsefunc, default_storefunc);
cp_add_argtype(cpBool, "bool", 0, default_parsefunc, default_storefunc);
diff --git a/lib/lexer.cc b/lib/lexer.cc
index a28aa02930295ef2063f64c8181fdda0bf092ce9..49a9db9758927816a08b986739d7a0606b2fe46a 100644
--- a/lib/lexer.cc
+++ b/lib/lexer.cc
@@ -26,6 +26,8 @@
#include <click/error.hh>
#include <click/confparse.hh>
#include <click/glue.hh>
+#include <click/straccum.hh>
+#include <click/variableenv.hh>
#include "elements/standard/errorelement.hh"
//
@@ -56,6 +58,33 @@ class Lexer::TunnelEnd {
};
+//
+// CLASS LEXER::SYNONYM
+//
+
+class Lexer::Synonym : public Element {
+
+ Element *_element;
+
+ public:
+
+ Synonym(Element *e) : _element(e) { }
+
+ const char *class_name() const { return _element->class_name(); }
+ void *cast(const char *);
+ Element *clone() const { return _element->clone(); }
+
+};
+
+void *
+Lexer::Synonym::cast(const char *s)
+{
+ if (strcmp(s, "Lexer::Synonym") == 0)
+ return this;
+ else
+ return _element->cast(s);
+}
+
//
// CLASS LEXER::COMPOUND
//
@@ -63,56 +92,235 @@ class Lexer::TunnelEnd {
class Lexer::Compound : public Element {
mutable String _name;
- String _body;
- String _filename;
- unsigned _lineno;
- Vector<String> _arguments;
- int _scope;
+ String _landmark;
+ int _depth;
+ Element *_next;
+
+ Vector<String> _formals;
+ int _ninputs;
+ int _noutputs;
+
+ Vector<int> _elements;
+ Vector<String> _element_names;
+ Vector<String> _element_configurations;
+ Vector<String> _element_landmarks;
+
+ Vector<Hookup> _hookup_from;
+ Vector<Hookup> _hookup_to;
public:
- Compound(const String &, const String &, const String &, unsigned,
- const Vector<String> &);
- Compound(const Compound &);
+ Compound(const String &, const String &, int, Element *);
+
+ const String &name() const { return _name; }
+ const String &landmark() const { return _landmark; }
+ int nformals() const { return _formals.size(); }
+ const Vector<String> &formals() const { return _formals; }
+ void add_formal(const String &f) { _formals.push_back(f); }
+ int depth() const { return _depth; }
+
+ void swap_router(Lexer *);
+ void finish(ErrorHandler *);
+ void check_duplicates_until(Element *, ErrorHandler *);
+
+ Element *find_relevant_class(int, int, const Vector<String> &);
+ void report_signatures(ErrorHandler *);
+ void expand_into(Lexer *, int, const VariableEnvironment &);
const char *class_name() const { return _name.cc(); }
void *cast(const char *);
Compound *clone() const { return 0; }
- void set_scope(int s) { _scope = s; }
-
- const String &body() const { return _body; }
- const String &filename() const { return _filename; }
- unsigned lineno() const { return _lineno; }
- int narguments() const { return _arguments.size(); }
- const String &argument(int i) const { return _arguments[i]; }
- int scope() const { return _scope; }
+ String signature() const;
+ static String signature(const String &, int, int, int);
};
-Lexer::Compound::Compound(const String &name, const String &body,
- const String &filename, unsigned lineno,
- const Vector<String> &args)
- : _name(name), _body(body), _filename(filename), _lineno(lineno),
- _arguments(args), _scope(-1)
-{
-}
-
-Lexer::Compound::Compound(const Compound &o)
- : Element(), _name(o._name), _body(o._body), _filename(o._filename),
- _lineno(o._lineno), _arguments(o._arguments), _scope(o._scope)
+Lexer::Compound::Compound(const String &name, const String &lm, int depth, Element *next)
+ : _name(name), _landmark(lm), _depth(depth), _next(next),
+ _ninputs(0), _noutputs(0)
{
}
void *
Lexer::Compound::cast(const char *s)
{
- if (String("Lexer::Compound") == s || _name == s)
+ if (strcmp(s, "Lexer::Compound") == 0 || _name == s)
return this;
else
return 0;
}
+void
+Lexer::Compound::swap_router(Lexer *lexer)
+{
+ lexer->_elements.swap(_elements);
+ lexer->_element_names.swap(_element_names);
+ lexer->_element_configurations.swap(_element_configurations);
+ lexer->_element_landmarks.swap(_element_landmarks);
+
+ lexer->_hookup_from.swap(_hookup_from);
+ lexer->_hookup_to.swap(_hookup_to);
+}
+
+void
+Lexer::Compound::finish(ErrorHandler *errh)
+{
+ assert(_element_names[0] == "input" && _element_names[1] == "output");
+
+ // count numbers of inputs and outputs
+ Vector<int> from_in, to_out;
+ bool to_in = false, from_out = false;
+ for (int i = 0; i < _hookup_from.size(); i++) {
+ const Hookup &hf = _hookup_from[i], &ht = _hookup_to[i];
+
+ if (hf.idx == 0) {
+ if (from_in.size() <= hf.port)
+ from_in.resize(hf.port + 1, 0);
+ from_in[hf.port] = 1;
+ } else if (hf.idx == 1)
+ from_out = true;
+
+ if (ht.idx == 1) {
+ if (to_out.size() <= ht.port)
+ to_out.resize(ht.port + 1, 0);
+ to_out[ht.port] = 1;
+ } else if (ht.idx == 0)
+ to_in = true;
+ }
+
+ // store information
+ _ninputs = from_in.size();
+ if (to_in)
+ errh->lerror(_landmark, "`%s' pseudoelement `input' may only be used as output", _name.cc());
+ for (int i = 0; i < from_in.size(); i++)
+ if (!from_in[i])
+ errh->lerror(_landmark, "compound element `%s' input %d unused", _name.cc(), i);
+
+ _noutputs = to_out.size();
+ if (from_out)
+ errh->lerror(_landmark, "`%s' pseudoelement `output' may only be used as input", _name.cc());
+ for (int i = 0; i < to_out.size(); i++)
+ if (!to_out[i])
+ errh->lerror(_landmark, "compound element `%s' output %d unused", _name.cc(), i);
+}
+
+void
+Lexer::Compound::check_duplicates_until(Element *last, ErrorHandler *errh)
+{
+ if (this == last || !_next)
+ return;
+
+ Element *n = _next;
+ while (n && n != last) {
+ Compound *nc = (Compound *)n->cast("Lexer::Compound");
+ if (!nc) break;
+ if (nc->_ninputs == _ninputs && nc->_noutputs == _noutputs && nc->_formals.size() == _formals.size()) {
+ errh->lerror(_landmark, "redeclaration of `%s'", signature().cc());
+ errh->lerror(nc->_landmark, "`%s' previously declared here", signature().cc());
+ break;
+ }
+ n = nc->_next;
+ }
+
+ if (Compound *nc = (Compound *)_next->cast("Lexer::Compound"))
+ nc->check_duplicates_until(last, errh);
+}
+
+Element *
+Lexer::Compound::find_relevant_class(int ninputs, int noutputs, const Vector<String> &args)
+{
+ Compound *ct = this;
+
+ while (1) {
+ if (ct->_ninputs == ninputs && ct->_noutputs == noutputs && ct->_formals.size() == args.size())
+ return ct;
+ Element *e = ct->_next;
+ if (!e)
+ return 0;
+ else if (Compound *next = (Compound *)e->cast("Lexer::Compound"))
+ ct = next;
+ else
+ return e;
+ }
+}
+
+String
+Lexer::Compound::signature(const String &name, int ninputs, int noutputs, int nargs)
+{
+ StringAccum sa;
+ const char *pl_args = (nargs == 1 ? " argument, " : " arguments, ");
+ const char *pl_ins = (ninputs == 1 ? " input, " : " inputs,");
+ const char *pl_outs = (noutputs == 1 ? " output" : " outputs");
+ sa << name << '[' << nargs << pl_args << ninputs << pl_ins << noutputs << pl_outs << ']';
+ return sa.take_string();
+}
+
+String
+Lexer::Compound::signature() const
+{
+ return signature(_name, _ninputs, _noutputs, _formals.size());
+}
+
+void
+Lexer::Compound::report_signatures(ErrorHandler *errh)
+{
+ if (_next) {
+ if (Compound *n = (Compound *)_next->cast("Lexer::Compound"))
+ n->report_signatures(errh);
+ else
+ errh->lmessage(_landmark, "`%s[...]'", _name.cc());
+ }
+ errh->lmessage(_landmark, "`%s'", signature().cc());
+}
+
+void
+Lexer::Compound::expand_into(Lexer *lexer, int which, const VariableEnvironment &ve)
+{
+ ErrorHandler *errh = lexer->_errh;
+
+ // `name_slash' is `name' constrained to end with a slash
+ String ename = lexer->_element_names[which];
+ String ename_slash;
+ if (ename[ename.length() - 1] == '/')
+ ename_slash = ename;
+ else
+ ename_slash = ename + "/";
+
+ assert(_element_names[0] == "input" && _element_names[1] == "output");
+
+ lexer->_elements[which] = TUNNEL_TYPE;
+ lexer->add_tunnel(ename, ename_slash + "input");
+ lexer->add_tunnel(ename_slash + "output", ename);
+
+ Vector<int> eidx_map;
+ eidx_map.push_back(lexer->_element_map[ename_slash + "input"]);
+ eidx_map.push_back(lexer->_element_map[ename_slash + "output"]);
+
+ for (int i = 2; i < _elements.size(); i++) {
+ String cname = ename_slash + _element_names[i];
+ int eidx = lexer->_element_map[cname];
+ if (eidx >= 0) {
+ errh->lerror(lexer->element_landmark(which), "redeclaration of element `%s'", cname.cc());
+ errh->lerror(lexer->element_landmark(eidx), "`%s' previously declared here", cname.cc());
+ eidx_map.push_back(-1);
+ } else {
+ if (lexer->_element_type_map[cname] >= 0)
+ errh->lerror(lexer->element_landmark(which), "`%s' is an element class", cname.cc());
+ eidx = lexer->get_element(cname, _elements[i], ve.interpolate(_element_configurations[i]), _element_landmarks[i]);
+ eidx_map.push_back(eidx);
+ }
+ }
+
+ // now copy hookups
+ int nh = _hookup_from.size();
+ for (int i = 0; i < nh; i++) {
+ const Hookup &hf = _hookup_from[i], &ht = _hookup_to[i];
+ if (eidx_map[hf.idx] >= 0 && eidx_map[ht.idx] >= 0)
+ lexer->connect(eidx_map[hf.idx], hf.port, eidx_map[ht.idx], ht.port);
+ }
+}
+
//
// LEXER
//
@@ -121,26 +329,22 @@ Lexer::Lexer(ErrorHandler *errh)
: _data(0), _len(0), _pos(0), _lineno(1), _lextra(0),
_tpos(0), _tfull(0),
_element_type_map(-1),
- _tunnel_element_type(new ErrorElement),
_last_element_type(-1),
_free_element_type(-1),
- _variable_map(-1),
_element_map(-1),
_definputs(0), _defoutputs(0),
_errh(errh)
{
if (!_errh) _errh = ErrorHandler::default_handler();
end_parse(-1); // clear private state
- add_element_type("<tunnel>", _tunnel_element_type);
+ add_element_type("<tunnel>", new ErrorElement);
add_element_type(new ErrorElement);
- assert(element_type("<tunnel>") == TUNNEL_TYPE
- && element_type("Error") == ERROR_TYPE);
+ assert(element_type("<tunnel>") == TUNNEL_TYPE && element_type("Error") == ERROR_TYPE);
}
Lexer::~Lexer()
{
end_parse(-1);
- // _default_element_type and _tunnel_element_type removed by end_parse()
}
int
@@ -161,17 +365,13 @@ Lexer::begin_parse(const String &data, const String &filename,
_lineno = 1;
_lextra = lextra;
- return _last_element_type;
+ return lexical_scoping_in();
}
void
Lexer::end_parse(int cookie)
{
lexical_scoping_out(cookie);
- for (int i = 0; i < _elements.size(); i++)
- // don't delete _tunnel_element_type!
- if (_elements[i] != _tunnel_element_type)
- delete _elements[i];
delete _definputs;
_definputs = 0;
@@ -198,8 +398,8 @@ Lexer::end_parse(int cookie)
_tpos = 0;
_tfull = 0;
- _element_prefix = "";
_anonymous_offset = 0;
+ _compound_depth = 0;
}
@@ -373,8 +573,15 @@ Lexer::next_lexeme()
} else if (_data[pos] == ':' && _data[pos+1] == ':') {
_pos = pos + 2;
return Lexeme(lex2Colon, _big_string.substring(word_pos, 2));
+ } else if (_data[pos] == '|' && _data[pos+1] == '|') {
+ _pos = pos + 2;
+ return Lexeme(lex2Bar, _big_string.substring(word_pos, 2));
}
}
+ if (pos < _len - 2 && _data[pos] == '.' && _data[pos+1] == '.' && _data[pos+2] == '.') {
+ _pos = pos + 3;
+ return Lexeme(lex3Dot, _big_string.substring(word_pos, 3));
+ }
_pos = pos + 1;
return Lexeme(_data[word_pos], _big_string.substring(word_pos, 1));
@@ -386,7 +593,6 @@ Lexer::lex_config()
unsigned config_pos = _pos;
unsigned pos = _pos;
unsigned paren_depth = 1;
- bool have_arguments = _variable_values.size() != 0;
int quote = 0;
String output;
@@ -413,23 +619,6 @@ Lexer::lex_config()
else if (_data[pos] == '\\' && pos < _len - 1 && quote == '\"') {
if (_data[pos+1] == '\"' || _data[pos+1] == '$')
pos++;
- } else if (_data[pos] == '$' && have_arguments && quote != '\'') {
- unsigned word_pos = pos;
- for (pos++; isalnum(_data[pos]) || _data[pos] == '_'; pos++)
- /* nada */;
- String name = _big_string.substring(word_pos, pos - word_pos);
- int variable = _variable_map[name];
- if (variable >= 0) {
- output += _big_string.substring(config_pos, word_pos - config_pos);
- String value = _variable_values[variable];
- if (quote == '\"') { // interpolate inside the quotes
- value = cp_quote(cp_unquote(value));
- if (value[0] == '\"') value = value.substring(1, value.length() - 2);
- }
- output += value;
- config_pos = pos;
- }
- pos--;
}
_pos = pos;
@@ -439,40 +628,6 @@ Lexer::lex_config()
return output + _big_string.substring(config_pos, pos - config_pos);
}
-String
-Lexer::lex_compound_body()
-{
- unsigned config_pos = _pos;
- unsigned pos = _pos;
- unsigned paren_depth = 0;
- unsigned brace_depth = 1;
- for (; pos < _len; pos++)
- if (_data[pos] == '(')
- paren_depth++;
- else if (_data[pos] == ')' && paren_depth)
- paren_depth--;
- else if (_data[pos] == '{' && !paren_depth)
- brace_depth++;
- else if (_data[pos] == '}' && !paren_depth) {
- brace_depth--;
- if (!brace_depth) break;
- } else if (_data[pos] == '/' && pos < _len - 1) {
- if (_data[pos+1] == '/')
- pos = skip_line(pos + 2) - 1;
- else if (_data[pos+1] == '*')
- pos = skip_slash_star(pos + 2) - 1;
- } else if (_data[pos] == '\n')
- _lineno++;
- else if (_data[pos] == '\r') {
- if (pos < _len - 1 && _data[pos+1] == '\n') pos++;
- _lineno++;
- } else if ((_data[pos] == '\'' || _data[pos] == '\"') && paren_depth)
- pos = skip_quote(pos + 1, _data[pos]) - 1;
-
- _pos = pos;
- return _big_string.substring(config_pos, pos - config_pos);
-}
-
String
Lexer::lexeme_string(int kind)
{
@@ -485,10 +640,16 @@ Lexer::lexeme_string(int kind)
return "`->'";
else if (kind == lex2Colon)
return "`::'";
+ else if (kind == lex2Bar)
+ return "`||'";
+ else if (kind == lex3Dot)
+ return "`...'";
else if (kind == lexTunnel)
return "`connectiontunnel'";
else if (kind == lexElementclass)
return "`elementclass'";
+ else if (kind == lexRequire)
+ return "`require'";
else if (kind >= 32 && kind < 127) {
sprintf(buf, "`%c'", kind);
return buf;
@@ -567,6 +728,7 @@ Lexer::add_element_type(Element *e)
int
Lexer::add_element_type(String name, Element *e)
{
+ assert(e);
// Lexer now owns `e'
int tid;
if (!name)
@@ -673,18 +835,18 @@ Lexer::element_type_names(Vector<String> &v) const
void
Lexer::add_tunnel(String namein, String nameout)
{
- Hookup hin(get_element(_element_prefix + namein, TUNNEL_TYPE), 0);
- Hookup hout(get_element(_element_prefix + nameout, TUNNEL_TYPE), 0);
+ Hookup hin(get_element(namein, TUNNEL_TYPE), 0);
+ Hookup hout(get_element(nameout, TUNNEL_TYPE), 0);
bool ok = true;
- if (_elements[hin.idx] != _tunnel_element_type) {
+ if (_elements[hin.idx] != TUNNEL_TYPE) {
lerror("redeclaration of element `%s'", namein.cc());
- _errh->lerror(_elements[hin.idx]->landmark(), "`%s' previously declared here", namein.cc());
+ _errh->lerror(_element_landmarks[hin.idx], "`%s' previously declared here", namein.cc());
ok = 0;
}
- if (_elements[hout.idx] != _tunnel_element_type) {
+ if (_elements[hout.idx] != TUNNEL_TYPE) {
lerror("redeclaration of element `%s'", nameout.cc());
- _errh->lerror(_elements[hout.idx]->landmark(), "`%s' previously declared here", nameout.cc());
+ _errh->lerror(_element_landmarks[hout.idx], "`%s' previously declared here", nameout.cc());
ok = 0;
}
if (_definputs && _definputs->find(hin))
@@ -710,33 +872,19 @@ Lexer::get_element(String name, int etype, const String &conf,
if (_element_map[name] >= 0)
return _element_map[name];
- // check type
- Element *e;
- Element *et = _element_types[etype];
- if (etype == TUNNEL_TYPE)
- e = et;
- else if ((e = et->clone()))
- /* do nothing */;
- else if (et->cast("Lexer::Compound"))
- return make_compound_element(name, etype, conf);
- else {
- lerror("can't clone `%s'", et->declaration().cc());
- e = 0;
- }
-
int eid = _elements.size();
_element_map.insert(name, eid);
_element_names.push_back(name);
_element_configurations.push_back(conf);
_element_landmarks.push_back(lm ? lm : landmark());
- _elements.push_back(e);
+ _elements.push_back(etype);
return eid;
}
String
Lexer::anon_element_name(const String &class_name) const
{
- String prefix = _element_prefix + class_name + "@";
+ String prefix = class_name + "@";
int anonymizer = _elements.size() - _anonymous_offset + 1;
String name = prefix + String(anonymizer);
while (_element_map[name] >= 0) {
@@ -746,144 +894,6 @@ Lexer::anon_element_name(const String &class_name) const
return name;
}
-void
-Lexer::lexical_scoping_back(int first, Vector<int> &insertions)
-{
- for (int t = _last_element_type; t >= 0; t = _element_type_next[t]) {
- const String &name = _element_type_names[t];
- if (_element_type_map[name] == t) {
- // remove it from map
- int prev = _element_type_next[first];
- while (prev >= 0 && _element_type_names[prev] != name)
- prev = _element_type_next[prev];
- _element_type_map.insert(name, prev);
- insertions.push_back(t);
- }
- if (t == first)
- break;
- }
-}
-
-void
-Lexer::lexical_scoping_forward(const Vector<int> &insertions)
-{
- for (int i = 0; i < insertions.size(); i++) {
- int j = insertions[i];
- _element_type_map.insert(_element_type_names[j], j);
- }
-}
-
-int
-Lexer::make_compound_element(String name, int etype, const String &conf)
-{
- Compound *compound = (Compound *)_element_types[etype];
- if (!name)
- name = anon_element_name(compound->class_name());
- // change `name' to not contain the current prefix
- name = name.substring(_element_prefix.length());
-
- // handle configuration string
- Vector<String> args;
- cp_argvec(conf, args);
- int nargs = compound->narguments();
- if (args.size() != nargs) {
- const char *whoops = (args.size() < nargs ? "few" : "many");
- String signature;
- for (int i = 0; i < nargs; i++) {
- if (i) signature += ", ";
- signature += compound->argument(i);
- }
- lerror("too %s arguments to compound element `%s(%s)'", whoops,
- compound->class_name(), signature.cc());
- for (int i = args.size(); i < nargs; i++)
- args.push_back("");
- }
-
- // store arguments
- Vector<int> prev_variable_value;
- for (int i = 0; i < nargs; i++) {
- const String &name = compound->argument(i);
- int prev = _variable_map[name];
- _variable_values.push_back(args[i]);
- prev_variable_value.push_back(prev);
- _variable_map.insert(name, _variable_values.size() - 1);
- }
-
- // `name_slash' is `name' constrained to end with a slash
- String name_slash;
- if (name[name.length() - 1] == '/')
- name_slash = name;
- else
- name_slash = name + "/";
-
- int fake_index = get_element(_element_prefix + name, TUNNEL_TYPE);
- add_tunnel(name, name_slash + "input");
- add_tunnel(name_slash + "output", name);
-
- // save parser state
- String old_prefix = _element_prefix;
- String old_big_string = _big_string;
- unsigned old_len = _len;
- unsigned old_pos = _pos;
- String old_filename = _filename;
- unsigned old_lineno = _lineno;
- Lexeme old_tcircle[TCIRCLE_SIZE];
- old_tcircle = _tcircle;
- int old_tpos = _tpos;
- int old_tfull = _tfull;
- int old_anonymous_offset = _anonymous_offset;
-
- // reparse the saved compound element's body!
- _element_prefix += name_slash;
- _big_string = compound->body();
- _data = _big_string.data();
- _len = _big_string.length();
- _pos = 0;
- _filename = compound->filename();
- _lineno = compound->lineno();
- _tpos = _tfull;
- // manipulate the anonymous offset so anon elements in 2 instances of the
- // compound have identical suffixes
- int old_elements_size = _elements.size();
- _anonymous_offset = _elements.size();
-
- // lexical scoping of types
- int cookie = lexical_scoping_in();
- Vector<int> lexical_scoping_help;
- lexical_scoping_back(compound->scope(), lexical_scoping_help);
-
- while (ystatement())
- /* do nothing */;
-
- // restore parser state
- _element_prefix = old_prefix;
- _big_string = old_big_string;
- _data = _big_string.data();
- _len = old_len;
- _pos = old_pos;
- _filename = old_filename;
- _lineno = old_lineno;
- _tcircle = old_tcircle;
- _tpos = old_tpos;
- _tfull = old_tfull;
- // manipulate the anonymous offset to get consistent results with tools
- _anonymous_offset = old_anonymous_offset + _elements.size()
- - old_elements_size + 2;
-
- // lexical scoping fixup
- lexical_scoping_out(cookie);
- lexical_scoping_forward(lexical_scoping_help);
-
- // lexical scoping of arguments
- for (int i = nargs - 1; i >= 0; i--) {
- const String &name = compound->argument(i);
- _variable_map.insert(name, prev_variable_value[i]);
- }
- _variable_values.resize(_variable_values.size() - nargs);
-
- return fake_index;
-}
-
void
Lexer::connect(int element1, int port1, int element2, int port2)
{
@@ -903,12 +913,13 @@ Lexer::element_name(int eid) const
else {
char buf[100];
sprintf(buf, "@%d", eid);
- if (_elements[eid] == _tunnel_element_type)
- return "<tunnel " + String(buf) + ">";
- else if (!_elements[eid])
- return "<null " + String(buf) + ">";
+ int t = _elements[eid];
+ if (t == TUNNEL_TYPE)
+ return "<tunnel" + String(buf) + ">";
+ else if (!_element_types[t])
+ return "<null" + String(buf) + ">";
else
- return _elements[eid]->class_name() + String(buf);
+ return _element_types[t]->class_name() + String(buf);
}
}
@@ -954,35 +965,6 @@ Lexer::yport(int &port)
}
}
-bool
-Lexer::yelement_upref(int &element)
-{
- Lexeme t = lex();
- if (!t.is(lexIdent)) {
- lerror("syntax error: expected element name");
- unlex(t);
- return false;
- }
-
- String prefix = _element_prefix;
- while (1) {
- int pos = prefix.find_right('/', prefix.length() - 2);
- prefix = (pos >= 0 ? prefix.substring(0, pos + 1) : String());
-
- String name = prefix + t.string();
- int en = _element_map[name];
- if (en >= 0) {
- element = en;
- return true;
- }
-
- if (!prefix) {
- lerror("`%s' not found in enclosing scopes", t.string().cc());
- return false;
- }
- }
-}
-
bool
Lexer::yelement(int &element, bool comma_ok)
{
@@ -990,13 +972,11 @@ Lexer::yelement(int &element, bool comma_ok)
String name;
int etype;
- if (t.is('^')) {
- return yelement_upref(element);
- } else if (t.is(lexIdent)) {
+ if (t.is(lexIdent)) {
name = t.string();
etype = element_type(name);
} else if (t.is('{')) {
- etype = ylocal();
+ etype = ycompound();
name = _element_types[etype]->class_name();
} else {
unlex(t);
@@ -1016,8 +996,7 @@ Lexer::yelement(int &element, bool comma_ok)
if (etype >= 0)
element = get_element(anon_element_name(name), etype, configuration, lm);
else {
- String lookup_name = _element_prefix + name;
- element = _element_map[lookup_name];
+ element = _element_map[name];
if (element < 0) {
const Lexeme &t2colon = lex();
unlex(t2colon);
@@ -1025,9 +1004,9 @@ Lexer::yelement(int &element, bool comma_ok)
ydeclaration(name);
else {
lerror("undeclared element `%s' (first use this block)", name.cc());
- get_element(lookup_name, ERROR_TYPE);
+ get_element(name, ERROR_TYPE);
}
- element = _element_map[lookup_name];
+ element = _element_map[name];
}
}
@@ -1071,7 +1050,7 @@ Lexer::ydeclaration(const String &first_element)
if (t.is(lexIdent))
etype = force_element_type(t.string());
else if (t.is('{'))
- etype = ylocal();
+ etype = ycompound();
else {
lerror("missing element type in declaration");
return;
@@ -1087,18 +1066,15 @@ Lexer::ydeclaration(const String &first_element)
for (int i = 0; i < decls.size(); i++) {
String name = decls[i];
- String lookup_name = _element_prefix + name;
- if (_element_map[lookup_name] >= 0) {
- int e = _element_map[lookup_name];
+ if (_element_map[name] >= 0) {
+ int e = _element_map[name];
lerror("redeclaration of element `%s'", name.cc());
- if (_elements[e] != _tunnel_element_type)
- _errh->lerror(_elements[e]->landmark(), "element `%s' previously declared here", name.cc());
+ if (_elements[e] != TUNNEL_TYPE)
+ _errh->lerror(_element_landmarks[e], "element `%s' previously declared here", name.cc());
} else if (_element_type_map[name] >= 0)
lerror("`%s' is an element class", name.cc());
- else if (_element_type_map[lookup_name] >= 0)
- lerror("`%s' is an element class", lookup_name.cc());
else
- get_element(lookup_name, etype, configuration, lm);
+ get_element(name, etype, configuration, lm);
}
}
@@ -1146,9 +1122,12 @@ Lexer::yconnection()
goto relex;
case lexIdent:
- case '^':
case '{':
case '}':
+ case lex2Bar:
+ case lexTunnel:
+ case lexElementclass:
+ case lexRequire:
unlex(t);
// FALLTHRU
case ';':
@@ -1184,24 +1163,13 @@ Lexer::yelementclass()
Lexeme tnext = lex();
if (tnext.is('{'))
- ylocal(name);
+ ycompound(name);
else if (tnext.is(lexIdent)) {
- // Go through some rigamarole because other code always assumes that
- // _element_type_map[x] == _element_type_map[y] <==>
+ // define synonym type
int t = force_element_type(tnext.string());
Element *et = _element_types[t];
- Element *e = et->clone();
- if (!e) {
- Compound *comp = static_cast<Compound *>(et->cast("Lexer::Compound"));
- if (comp)
- e = new Compound(*comp);
- }
- if (!e) {
- lerror("can't clone `%s'", et->declaration().cc());
- add_element_type(name, new ErrorElement);
- } else
- add_element_type(name, e);
+ add_element_type(name, new Synonym(et));
} else {
lerror("syntax error near `%s'", String(tnext.string()).cc());
@@ -1238,42 +1206,87 @@ Lexer::ytunnel()
}
}
+void
+Lexer::ycompound_arguments(Compound *comptype)
+{
+ while (1) {
+ const Lexeme &tvar = lex();
+ if (!tvar.is(lexVariable)) {
+ unlex(tvar);
+ return;
+ }
+ comptype->add_formal(tvar.string());
+ const Lexeme &tsep = lex();
+ if (tsep.is('|'))
+ return;
+ else if (!tsep.is(',')) {
+ lerror("expected `,' or `|'");
+ unlex(tsep);
+ return;
+ }
+ }
+}
+
int
-Lexer::ylocal(String name)
+Lexer::ycompound(String name)
{
- // OK because every used ylocal() corresponds to at least one element
+ // OK because every used ycompound() corresponds to at least one element
if (!name)
name = "@Class" + String(_elements.size() - _anonymous_offset + 1);
- // check for arguments
- Vector<String> arguments;
- unsigned old_pos = _pos;
+ HashMap<String, int> old_element_map(-1);
+ old_element_map.swap(_element_map);
+ HashMap<String, int> old_type_map(_element_type_map);
+ int old_offset = _anonymous_offset;
+ Element *created = 0;
+
+ // check for '...'
+ const Lexeme &t = lex();
+ if (t.is(lex3Dot)) {
+ if (_element_type_map[name] < 0) {
+ lerror("extending unknwon element class `%s'", name.cc());
+ add_element_type(name, new ErrorElement);
+ }
+ created = _element_types[ _element_type_map[name] ];
+ expect(lex2Bar);
+ } else
+ unlex(t);
+
+ Element *first = created;
+
while (1) {
- Lexeme t = lex();
- if (!t.is(lexVariable))
- break;
- arguments.push_back(t.string());
- old_pos = _pos;
- const Lexeme &sep = lex();
- if (sep.is('|')) {
- old_pos = _pos;
- break;
- } else if (!sep.is(','))
+ // prepare
+ _element_map.clear();
+ Compound *ct = new Compound(name, landmark(), _compound_depth, created);
+ ct->swap_router(this);
+ get_element("input", TUNNEL_TYPE);
+ get_element("output", TUNNEL_TYPE);
+ _anonymous_offset = 2;
+ _compound_depth++;
+
+ ycompound_arguments(ct);
+ while (ystatement(true))
+ /* nada */;
+
+ _compound_depth--;
+ _anonymous_offset = old_offset;
+ old_type_map.swap(_element_type_map);
+ ct->swap_router(this);
+
+ ct->finish(_errh);
+ created = ct;
+
+ // check for '||' or '}'
+ const Lexeme &t = lex();
+ if (!t.is(lex2Bar))
break;
}
- _pos = old_pos;
- // opening brace was already read
- String body_filename = _filename;
- unsigned body_lineno = _lineno;
- String body = lex_compound_body();
- expect('}');
-
- Compound *c =
- new Compound(name, body, body_filename, body_lineno, arguments);
- int t = add_element_type(name, c);
- c->set_scope(t);
- return t;
+ // on the way out
+ ((Compound *)created)->check_duplicates_until(first, _errh);
+ old_element_map.swap(_element_map);
+
+ return add_element_type(name, created);
}
void
@@ -1304,7 +1317,6 @@ Lexer::ystatement(bool nested)
switch (t.kind()) {
case lexIdent:
- case '^':
case '[':
case '{':
unlex(t);
@@ -1327,8 +1339,10 @@ Lexer::ystatement(bool nested)
return true;
case '}':
+ case lex2Bar:
if (!nested)
goto syntax_error;
+ unlex(t);
return false;
case lexEOF:
@@ -1366,6 +1380,68 @@ Lexer::add_router_connections(int c, const Vector<int> &router_id,
}
}
+void
+Lexer::expand_compound_element(int which, Vector<int> &environment_map, Vector<VariableEnvironment *> &environments)
+{
+ String name = _element_names[which];
+ int etype = _elements[which];
+ assert(name);
+ int old_nelements = _elements.size();
+
+ // find right version
+ Vector<String> args;
+ cp_argvec(_element_configurations[which], args);
+ int inputs_used = 0, outputs_used = 0;
+ for (int i = 0; i < _hookup_from.size(); i++) {
+ const Hookup &hf = _hookup_from[i], &ht = _hookup_to[i];
+ if (ht.idx == which && ht.port >= inputs_used)
+ inputs_used = ht.port + 1;
+ if (hf.idx == which && hf.port >= outputs_used)
+ outputs_used = hf.port + 1;
+ }
+ Compound *c = (Compound *)_element_types[etype];
+ Element *found_c = c->find_relevant_class(inputs_used, outputs_used, args);
+ if (!found_c) {
+ _errh->lerror(c->landmark(), "no match for `%s'", Compound::signature(c->name(), inputs_used, outputs_used, args.size()).cc());
+ ContextErrorHandler cerrh(_errh, "possibilities are:", " ");
+ c->report_signatures(&cerrh);
+ _elements[which] = ERROR_TYPE;
+ return;
+ }
+
+ // have putatively correct version
+ Compound *found_comp = (Compound *)found_c->cast("Lexer::Compound");
+ if (!found_comp) {
+ for (int i = 0; i < _element_types.size(); i++)
+ if (_element_types[i] == found_c) {
+ _elements[which] = i;
+ return;
+ }
+ assert(0);
+ _elements[which] = ERROR_TYPE;
+ return;
+ }
+
+ int vei = environment_map[which];
+ if (args.size() == 0 && found_comp->depth() == 0)
+ vei = 0;
+ else if (args.size() || environments[vei]->depth() >= found_comp->depth()) {
+ VariableEnvironment *new_ve = new VariableEnvironment;
+ if (vei > 0)
+ new_ve->enter(*environments[vei]);
+ new_ve->limit_depth(found_comp->depth());
+ new_ve->enter(found_comp->formals(), args, found_comp->depth());
+ environments.push_back(new_ve);
+ vei = environments.size() - 1;
+ }
+
+ found_comp->expand_into(this, which, *environments[vei]);
+
+ // mark new environments
+ for (int i = old_nelements; i < _elements.size(); i++)
+ environment_map.push_back(vei);
+}
+
Router *
Lexer::create_router()
{
@@ -1373,19 +1449,28 @@ Lexer::create_router()
if (!router)
return 0;
- // check for elements w/o types
- for (int i = 0; i < _elements.size(); i++)
- if (!_elements[i])
- _errh->error("undeclared element `%s'", element_name(i).cc());
+ // expand compounds
+ Vector<int> environment_map(_elements.size(), 0);
+ Vector<VariableEnvironment *> environments;
+ environments.push_back(new VariableEnvironment);
+
+ for (int i = 0; i < _elements.size(); i++) {
+ int t = _elements[i];
+ if (t != TUNNEL_TYPE && _element_types[t]->cast("Lexer::Compound"))
+ expand_compound_element(i, environment_map, environments);
+ }
+
+ for (int i = 0; i < environments.size(); i++)
+ delete environments[i];
// add elements to router
Vector<int> router_id;
for (int i = 0; i < _elements.size(); i++)
- if (_elements[i] && _elements[i] != _tunnel_element_type) {
- int fi = router->add_element
- (_elements[i], _element_names[i], _element_configurations[i],
- _element_landmarks[i]);
- router_id.push_back(fi);
+ if (_elements[i] != TUNNEL_TYPE) {
+ Element *tc = _element_types[_elements[i]];
+ int ei = router->add_element
+ (tc->clone(), _element_names[i], _element_configurations[i], _element_landmarks[i]);
+ router_id.push_back(ei);
} else
router_id.push_back(-1);
@@ -1404,9 +1489,6 @@ Lexer::create_router()
for (int i = 0; i < _requirements.size(); i++)
router->add_requirement(_requirements[i]);
- // clear _elements, as all elements are owned by router
- _elements.assign(_elements.size(), (Element *)0);
-
return router;
}
@@ -1518,7 +1600,7 @@ void
Lexer::expand_connection(const Hookup &this_end, bool is_out,
Vector<Hookup> &into) const
{
- if (_elements[this_end.idx] != _tunnel_element_type)
+ if (_elements[this_end.idx] != TUNNEL_TYPE)
into.push_back(this_end);
else {
TunnelEnd *dp = (is_out ? _defoutputs : _definputs);
diff --git a/linuxmodule/Makefile.in b/linuxmodule/Makefile.in
index 43e99a1d552bae42f6b939654bbb1339029bbe21..cb9f18e98fe305c75fe58fa5d34012d8341d1984 100644
--- a/linuxmodule/Makefile.in
+++ b/linuxmodule/Makefile.in
@@ -45,7 +45,7 @@ GENERIC_OBJS = string.o straccum.o \
packet.o \
error.o glue.o timer.o gaprate.o \
elemlink.o element.o \
- confparse.o lexer.o elemfilter.o router.o \
+ confparse.o variableenv.o lexer.o elemfilter.o router.o \
crc32.o iptable.o iptable2.o ip6table.o radix.o
LINUXMODULE_OBJS = kernelerror.o kernelversion.o module.o sched.o \
diff --git a/tools/click-align/click-align.cc b/tools/click-align/click-align.cc
index 905d9ea0414e530fad87e78681ad7f1ffa23c49b..a59997d7a9c300d0c4bbb2bbd5642336af8a40aa 100644
--- a/tools/click-align/click-align.cc
+++ b/tools/click-align/click-align.cc
@@ -323,9 +323,10 @@ particular purpose.\n");
done:
RouterT *router = read_router_file(router_file, prepared_router(), errh);
+ if (router)
+ router->flatten(errh);
if (!router || errh->nerrors() > 0)
exit(1);
- router->flatten(errh);
int align_tindex = router->type_index("Align");
int original_nelements = router->nelements();
diff --git a/tools/click-check/click-check.cc b/tools/click-check/click-check.cc
index 0a2feff92eb551b62791556463ca856db31f6788..6a790ab81fead225a98f536aef9d5d64759f1b38 100644
--- a/tools/click-check/click-check.cc
+++ b/tools/click-check/click-check.cc
@@ -212,11 +212,12 @@ particular purpose.\n");
done:
RouterT *r = read_router_file(router_file, errh);
+ if (r)
+ r->flatten(errh);
if (!r || errh->nerrors() > 0)
exit(1);
if (!router_file || strcmp(router_file, "-") == 0)
router_file = "<stdin>";
- r->flatten(errh);
// open output file
FILE *outf = stdout;
diff --git a/tools/click-combine/click-combine.cc b/tools/click-combine/click-combine.cc
index e89ce88df9d29ac9ee6b6b33d2c54e0e66072688..34fe2f63e6a40e047771307ebdfa821841a5c92c 100644
--- a/tools/click-combine/click-combine.cc
+++ b/tools/click-combine/click-combine.cc
@@ -27,6 +27,7 @@
#include "toolutils.hh"
#include <click/confparse.hh>
#include <click/straccum.hh>
+#include <click/variableenv.hh>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -446,11 +447,8 @@ particular purpose.\n");
// combine routers
RouterT *combined = new RouterT;
- for (int i = 0; i < routers.size(); i++) {
- int ei = combined->get_eindex(router_names[i], RouterT::TUNNEL_TYPE,
- String(), String());
- routers[i]->expand_into(combined, ei, combined, RouterScope(), errh);
- }
+ for (int i = 0; i < routers.size(); i++)
+ routers[i]->expand_into(combined, VariableEnvironment(router_names[i]), errh);
// nested combinations: change config strings of included RouterLinks
int link_type = combined->type_index("RouterLink");
diff --git a/tools/click-combine/click-uncombine.cc b/tools/click-combine/click-uncombine.cc
index 5b4f3f003b3a225543f712669976bdbd816abd32..a046d420af730cc32fb1df97329434f8f9e17607 100644
--- a/tools/click-combine/click-uncombine.cc
+++ b/tools/click-combine/click-uncombine.cc
@@ -365,13 +365,13 @@ particular purpose.\n");
}
done:
- RouterT *r = 0;
- r = read_router_file(router_file, errh);
+ RouterT *r = read_router_file(router_file, errh);
+ if (r)
+ r->flatten(errh);
if (!r || errh->nerrors() > 0)
exit(1);
if (!router_file || strcmp(router_file, "-") == 0)
router_file = "<stdin>";
- r->flatten(errh);
// find component names
if (r->archive_index("componentmap") < 0)
diff --git a/tools/click-devirtualize/click-devirtualize.cc b/tools/click-devirtualize/click-devirtualize.cc
index 4904c91f1556e4b2d8e6aeb64545108145211dfa..46c9daf6a7e99bd7c6b76f25e2a5dba4b234d2da 100644
--- a/tools/click-devirtualize/click-devirtualize.cc
+++ b/tools/click-devirtualize/click-devirtualize.cc
@@ -322,9 +322,10 @@ particular purpose.\n");
// read router
RouterT *router = read_router_file(router_file, errh);
+ if (router)
+ router->flatten(errh);
if (!router || errh->nerrors() > 0)
exit(1);
- router->flatten(errh);
// open output file
FILE *outf = stdout;
diff --git a/tools/click-fastclassifier/click-fastclassifier.cc b/tools/click-fastclassifier/click-fastclassifier.cc
index afe41261720946ebb7b55f766ea0285e79467816..613c82a7ee4dc1be54c44edaf63a3a408c2e8b5b 100644
--- a/tools/click-fastclassifier/click-fastclassifier.cc
+++ b/tools/click-fastclassifier/click-fastclassifier.cc
@@ -916,9 +916,10 @@ particular purpose.\n");
done:
RouterT *r = read_router_file(router_file, errh);
+ if (r)
+ r->flatten(errh);
if (!r || errh->nerrors() > 0)
exit(1);
- r->flatten(errh);
if (source_only || config_only)
compile_user = compile_kernel = false;
diff --git a/tools/click-install/click-install.cc b/tools/click-install/click-install.cc
index 3538e662b54e4db4f19ed13c75e7f06103922266..09b1f9b582ae1222aa6cf97361811f81e3303ece 100644
--- a/tools/click-install/click-install.cc
+++ b/tools/click-install/click-install.cc
@@ -348,8 +348,8 @@ main(int argc, char **argv)
{
String::static_initialize();
ErrorHandler::static_initialize(new FileErrorHandler(stderr));
- ErrorHandler *errh = new PrefixErrorHandler
- (ErrorHandler::default_handler(), "click-install: ");
+ ErrorHandler *nop_errh = ErrorHandler::default_handler();
+ ErrorHandler *errh = new PrefixErrorHandler(nop_errh, "click-install: ");
// read command line arguments
Clp_Parser *clp =
@@ -424,10 +424,11 @@ particular purpose.\n");
if (hotswap && uninstall)
errh->warning("`--hotswap' and `--uninstall' are mutually exclusive");
- RouterT *r = read_router_file(router_file, errh);
+ RouterT *r = read_router_file(router_file, nop_errh);
+ if (r)
+ r->flatten(nop_errh);
if (!r || errh->nerrors() > 0)
exit(1);
- r->flatten(errh);
// uninstall Click if requested
if (uninstall && access("/proc/click/version", F_OK) >= 0) {
diff --git a/tools/click-undead/click-undead.cc b/tools/click-undead/click-undead.cc
index 1113d51908140b809d7e52b5e106a13a02182515..6e6a611d8bb4b339f0839ba8187cc86337e5e397 100644
--- a/tools/click-undead/click-undead.cc
+++ b/tools/click-undead/click-undead.cc
@@ -647,9 +647,10 @@ particular purpose.\n");
done:
RouterT *r = read_router_file(router_file, default_errh);
+ if (r)
+ r->flatten(default_errh);
if (!r || default_errh->nerrors() > 0)
exit(1);
- r->flatten(default_errh);
// open output file
FILE *outf = stdout;
diff --git a/tools/click-xform/click-xform.cc b/tools/click-xform/click-xform.cc
index 475b060363de823ab3cf1eb3e1dd23f8deb8dbb8..bfa89300f42a2d8a6a1683203d39a0d8ada416c0 100644
--- a/tools/click-xform/click-xform.cc
+++ b/tools/click-xform/click-xform.cc
@@ -24,6 +24,7 @@
#include "lexert.hh"
#include <click/error.hh>
#include <click/confparse.hh>
+#include <click/variableenv.hh>
#include <click/clp.h>
#include "toolutils.hh"
#include "adjacency.hh"
@@ -77,8 +78,6 @@ Matcher::Matcher(RouterT *pat, AdjacencyMatrix *pat_m,
: _pat(pat), _pat_m(pat_m), _body(body), _body_m(body_m), _patid(patid),
_pat_input_idx(-1), _pat_output_idx(-1)
{
- _pat->use();
- _body->use();
// check tunnel situation
for (int i = 0; i < _pat->nelements(); i++) {
ElementT &fac = _pat->element(i);
@@ -97,8 +96,6 @@ Matcher::Matcher(RouterT *pat, AdjacencyMatrix *pat_m,
Matcher::~Matcher()
{
- _pat->unuse();
- _body->unuse();
}
bool
@@ -324,8 +321,14 @@ Matcher::replace(RouterT *replacement, const String &try_prefix,
// add replacement
// collect new element indices in `changed_elements'
_body->set_new_eindex_collector(&changed_elements);
+
+ // make element named `prefix'
int new_eindex = _body->get_eindex(prefix, RouterT::TUNNEL_TYPE, String(), landmark);
- replacement->expand_into(_body, new_eindex, _body, RouterScope(), errh);
+
+ // expand 'replacement' into '_body'; need crap compound element
+ Vector<String> crap_args;
+ CompoundElementClassT comp(replacement);
+ comp.complex_expand_element(_body, new_eindex, String(), crap_args, _body, VariableEnvironment(), errh);
// mark replacement
for (int i = 0; i < changed_elements.size(); i++) {
@@ -340,11 +343,9 @@ Matcher::replace(RouterT *replacement, const String &try_prefix,
for (int i = 0; i < _match.size(); i++)
if (_match[i] >= 0) {
String n = _pat->ename(i);
- if (replacement->eindex(n) >= 0) {
- int new_index = _body->eindex(prefix + "/" + n);
- assert(new_index >= 0);
+ int new_index = _body->eindex(prefix + "/" + n);
+ if (new_index >= 0)
_body->change_ename(new_index, old_names[i]);
- }
}
// find input and output, add connections to tunnels
@@ -577,9 +578,10 @@ particular purpose.\n");
done:
RouterT *r = read_router_file(router_file, errh);
+ if (r)
+ r->flatten(errh);
if (!r || errh->nerrors() > 0)
exit(1);
- r->flatten(errh);
if (!patterns_attempted)
errh->warning("no patterns read");
@@ -593,8 +595,8 @@ particular purpose.\n");
new_patterns.push_back(replacements[i]);
new_replacements.push_back(patterns[i]);
}
- patterns = new_patterns;
- replacements = new_replacements;
+ patterns.swap(new_patterns);
+ replacements.swap(new_replacements);
}
// flatten patterns
@@ -602,6 +604,8 @@ particular purpose.\n");
patterns[i]->flatten(errh);
// unify pattern types
+ // (warning: creates circular element class references, which are
+ // removed below by remove_unused_element_types())
for (int i = 0; i < patterns.size(); i++) {
r->get_types_from(patterns[i]);
r->get_types_from(replacements[i]);
@@ -641,6 +645,7 @@ particular purpose.\n");
// write result
if (nreplace)
r->remove_dead_elements(0);
+ r->remove_unused_element_types(); // remove circular compound elements
if (write_router_file(r, output_file, errh) < 0)
exit(1);
return 0;
diff --git a/tools/lib/Makefile.in b/tools/lib/Makefile.in
index f0ba512f5ddf706248c78b9f3dbdeec3c97c9fe0..1e82796b4ef4293953e6d209bd55aa5dd028dc60 100644
--- a/tools/lib/Makefile.in
+++ b/tools/lib/Makefile.in
@@ -39,7 +39,8 @@ mkinstalldirs = @top_srcdir@/mkinstalldirs
OBJS = vectori.o vectorv.o bitvector.o hashmapi.o straccum.o string.o error.o \
- elementt.o routert.o lexert.o confparse.o archive.o processingt.o \
+ elementt.o routert.o variableenv.o lexert.o confparse.o \
+ archive.o processingt.o \
ipaddress.o ipaddressset.o ip6address.o etheraddress.o \
userutils.o toolutils.o clp.o @LIBOBJS@
diff --git a/tools/lib/elementt.cc b/tools/lib/elementt.cc
index e7dd298e44803095ee8d1dbed89eb2ec61478dff..a268daec4ed87551e6632b997121e65eeff8e791 100644
--- a/tools/lib/elementt.cc
+++ b/tools/lib/elementt.cc
@@ -24,6 +24,8 @@
#include "elementt.hh"
#include "routert.hh"
#include <click/straccum.hh>
+#include <click/confparse.hh>
+#include <click/variableenv.hh>
#include <stdlib.h>
ElementT::ElementT()
@@ -82,77 +84,125 @@ ElementClassT::ElementClassT()
{
}
-static int
-resolve_upref(const String &upref, String prefix, RouterT *r)
+ElementClassT *
+ElementClassT::find_relevant_class(int, int, const Vector<String> &)
{
- while (prefix) {
- int pos = prefix.find_right('/', prefix.length() - 2);
- prefix = (pos >= 0 ? prefix.substring(0, pos + 1) : String());
-
- String try_name = prefix + upref;
- int en = r->eindex(try_name);
- if (en >= 0) return en;
- }
- return -1;
+ return this;
}
-int
-ElementClassT::simple_expand_into(RouterT *fromr, int which,
- RouterT *tor,
- const RouterScope &scope, ErrorHandler *errh)
+void
+ElementClassT::report_signatures(const String &lm, String name, ErrorHandler *errh)
{
- if (fromr == tor)
- return which;
+ errh->lmessage(lm, "`%s[...]'", name.cc());
+}
- const ElementT &e = fromr->element(which);
+int
+ElementClassT::direct_expand_element(RouterT *fromr, int which, ElementClassT *thus, RouterT *tor,
+ const VariableEnvironment &env, ErrorHandler *errh)
+{
+ ElementT &e = fromr->element(which);
+ String new_name = env.prefix() + e.name;
+ String new_configuration = env.interpolate(e.configuration);
- if (e.type == RouterT::UPREF_TYPE) {
- // try and resolve the upref within the current prefix. if not, then
- // pass the upref on up, without tacking on the prefix.
- int new_index = resolve_upref(e.name, scope.prefix(), tor);
- if (new_index < 0)
- new_index = tor->get_anon_eindex(e.name, RouterT::UPREF_TYPE,
- e.configuration, e.landmark);
- return new_index;
+ switch (e.type) {
+
+ case RouterT::TUNNEL_TYPE: {
+ // common case -- expanding router into itself
+ if (fromr == tor && !env.prefix())
+ return which;
+ // make the tunnel or tunnel pair
+ if (e.tunnel_output >= 0 && e.tunnel_output < fromr->nelements()) {
+ tor->add_tunnel(new_name,
+ env.prefix() + fromr->ename(e.tunnel_output),
+ e.landmark, errh);
+ return tor->eindex(new_name);
+ } else
+ return tor->get_eindex
+ (new_name, RouterT::TUNNEL_TYPE, e.configuration, e.landmark);
+ }
+
+ default: {
+ // get element type index. add new "anonymous" element type if needed
+ String type_name = fromr->type_name(e.type);
+ int new_type = tor->get_type_index(type_name, thus);
+ ElementClassT *new_type_class = tor->type_class(new_type);
+ if (thus != new_type_class && new_type_class)
+ new_type = tor->get_anon_type_index(type_name, thus);
+
+ // check for common case -- expanding router into itself
+ if (fromr == tor && !env.prefix()) {
+ e.configuration = new_configuration;
+ e.type = new_type;
+ return which;
+ }
+
+ // check for old element
+ int new_eidx = tor->eindex(new_name);
+ if (new_eidx >= 0) {
+ errh->lerror(e.landmark, "redeclaration of element `%s'", new_name.cc());
+ errh->lerror(tor->elandmark(new_eidx), "`%s' previously declared here", tor->edeclaration(new_eidx).cc());
+ }
+
+ // add element
+ return tor->get_eindex(new_name, new_type, new_configuration, e.landmark);
+ }
+
}
+}
- if (e.type == RouterT::TUNNEL_TYPE) {
- // make the tunnel or tunnel pair
- String new_name = scope.prefix() + e.name;
- if (e.tunnel_output >= 0 && e.tunnel_output < fromr->nelements()) {
- tor->add_tunnel(new_name,
- scope.prefix() + fromr->ename(e.tunnel_output),
- e.landmark, errh);
- return tor->eindex(new_name);
- } else
- return tor->get_eindex
- (new_name, RouterT::TUNNEL_TYPE, e.configuration, e.landmark);
+int
+ElementClassT::expand_element(RouterT *fromr, int which, RouterT *tor,
+ const VariableEnvironment &env, ErrorHandler *errh)
+{
+ ElementClassT *c = fromr->etype_class(which);
+
+ if (!c || c->direct_expansion())
+ return direct_expand_element(fromr, which, c, tor, env, errh);
+
+ // if not direct expansion, do some more work
+ int inputs_used = fromr->ninputs(which);
+ int outputs_used = fromr->noutputs(which);
+
+ Vector<String> args;
+ String new_configuration = env.interpolate(fromr->econfiguration(which));
+ cp_argvec(new_configuration, args);
+
+ ElementClassT *found_c = c->find_relevant_class(inputs_used, outputs_used, args);
+ if (!found_c) {
+ String lm = fromr->elandmark(which), name = fromr->etype_name(which);
+ errh->lerror(lm, "no match for `%s'", name.cc(), signature(name, inputs_used, outputs_used, args.size()).cc());
+ ContextErrorHandler cerrh(errh, "possibilities are:", " ");
+ c->report_signatures(lm, name, &cerrh);
+ if (fromr == tor)
+ tor->kill_element(which);
+ return -1;
}
-
- // get element type index. add new "anonymous" element type if needed
- String type_name = fromr->type_name(e.type);
- ElementClassT *type_class = fromr->type_class(e.type);
- int new_type = tor->get_type_index(type_name, type_class);
- ElementClassT *new_type_class = tor->type_class(new_type);
- if (type_class != new_type_class && new_type_class)
- new_type = tor->get_anon_type_index(type_name, type_class);
-
- // add element
- return tor->get_eindex(scope.prefix() + e.name, new_type,
- scope.interpolate(e.configuration), e.landmark);
+
+ return found_c->complex_expand_element(fromr, which, new_configuration, args,
+ tor, env, errh);
}
int
-ElementClassT::expand_into(RouterT *fromr, int which,
- RouterT *tor, const RouterScope &scope,
- ErrorHandler *errh)
+ElementClassT::complex_expand_element(RouterT *fromr, int which, const String &, Vector<String> &,
+ RouterT *tor, const VariableEnvironment &env, ErrorHandler *errh)
{
- return simple_expand_into(fromr, which, tor, scope, errh);
+ return direct_expand_element(fromr, which, this, tor, env, errh);
}
void
-ElementClassT::compound_declaration_string(StringAccum &, const String &, const String &)
+ElementClassT::declaration_string(StringAccum &, const String &, const String &)
+{
+}
+
+String
+ElementClassT::signature(const String &name, int ninputs, int noutputs, int nargs)
{
+ const char *pl_args = (nargs == 1 ? " argument, " : " arguments, ");
+ const char *pl_ins = (ninputs == 1 ? " input, " : " inputs, ");
+ const char *pl_outs = (noutputs == 1 ? " output" : " outputs");
+ StringAccum sa;
+ sa << name << '[' << nargs << pl_args << ninputs << pl_ins << noutputs << pl_outs << ']';
+ return sa.take_string();
}
@@ -162,9 +212,9 @@ SynonymElementClassT::SynonymElementClassT(const String &name, ElementClassT *ec
}
int
-SynonymElementClassT::expand_into(RouterT *fromr, int which,
- RouterT *tor, const RouterScope &scope,
- ErrorHandler *)
+SynonymElementClassT::complex_expand_element(
+ RouterT *fromr, int which, const String &new_config, Vector<String> &,
+ RouterT *tor, const VariableEnvironment &env, ErrorHandler *errh)
{
// get element type index. add new "anonymous" element type if needed
int new_type = tor->get_type_index(_name, _eclass);
@@ -173,16 +223,212 @@ SynonymElementClassT::expand_into(RouterT *fromr, int which,
new_type = tor->get_anon_type_index(_name, _eclass);
ElementT &e = fromr->element(which);
- if (fromr == tor) {
+ if (fromr == tor && !env.prefix()) {
+ e.configuration = new_config; // interpolated
e.type = new_type;
return which;
- } else
- return tor->get_eindex(scope.prefix() + e.name, new_type,
- scope.interpolate(e.configuration), e.landmark);
+ } else {
+ String new_name = env.prefix() + e.name;
+ int new_eidx = tor->eindex(new_name);
+ if (new_eidx >= 0) {
+ errh->lerror(e.landmark, "redeclaration of element `%s'", new_name.cc());
+ errh->lerror(tor->elandmark(new_eidx), "`%s' previously declared here", tor->edeclaration(new_eidx).cc());
+ return -1;
+ } else
+ return tor->get_eindex(new_name, new_type, new_config, e.landmark);
+ }
}
void
-SynonymElementClassT::compound_declaration_string(StringAccum &sa, const String &name, const String &indent)
+SynonymElementClassT::declaration_string(StringAccum &sa, const String &name, const String &indent)
{
sa << indent << "elementclass " << name << " " << _name << ";\n";
}
+
+
+CompoundElementClassT::CompoundElementClassT(RouterT *r)
+ : _router(r), _depth(0), _ninputs(0), _noutputs(0), _next(0),
+ _circularity_flag(false)
+{
+ _router->use();
+}
+
+CompoundElementClassT::CompoundElementClassT(const String &name, const String &landmark, RouterT *r, ElementClassT *next, int depth)
+ : _name(name), _landmark(landmark), _router(r), _depth(depth),
+ _ninputs(0), _noutputs(0), _next(next),
+ _circularity_flag(false)
+{
+ _router->use();
+ if (_next)
+ _next->use();
+}
+
+CompoundElementClassT::~CompoundElementClassT()
+{
+ _router->unuse();
+ if (_next)
+ _next->unuse();
+}
+
+void
+CompoundElementClassT::finish(ErrorHandler *errh)
+{
+ if (!errh)
+ errh = ErrorHandler::silent_handler();
+
+ int einput = _router->eindex("input");
+ if (einput >= 0) {
+ _ninputs = _router->noutputs(einput);
+
+ if (_router->ninputs(einput))
+ errh->lerror(_landmark, "`%s' pseudoelement `input' may only be used as output", _name.cc());
+
+ if (_ninputs) {
+ Vector<int> used;
+ _router->find_connection_vector_from(einput, used);
+ assert(used.size() == _ninputs);
+ for (int i = 0; i < _ninputs; i++)
+ if (used[i] == -1)
+ errh->lerror(_landmark, "compound element `%s' input %d unused", _name.cc(), i);
+ }
+ } else
+ _ninputs = 0;
+
+ int eoutput = _router->eindex("output");
+ if (eoutput >= 0) {
+ _noutputs = _router->ninputs(eoutput);
+ if (_router->noutputs(eoutput))
+ errh->lerror(_landmark, "`%s' pseudoelement `output' may only be used as input", _name.cc());
+
+ if (_noutputs) {
+ Vector<int> used;
+ _router->find_connection_vector_to(eoutput, used);
+ assert(used.size() == _noutputs);
+ for (int i = 0; i < _noutputs; i++)
+ if (used[i] == -1)
+ errh->lerror(_landmark, "compound element `%s' output %d unused", _name.cc(), i);
+ }
+ } else
+ _noutputs = 0;
+}
+
+void
+CompoundElementClassT::check_duplicates_until(ElementClassT *last, ErrorHandler *errh)
+{
+ if (this == last || !_next)
+ return;
+
+ ElementClassT *n = _next;
+ while (n && n != last) {
+ CompoundElementClassT *nc = n->cast_compound();
+ if (!nc) break;
+ if (nc->_ninputs == _ninputs && nc->_noutputs == _noutputs && nc->_formals.size() == _formals.size()) {
+ errh->lerror(_landmark, "redeclaration of `%s'", signature().cc());
+ errh->lerror(nc->_landmark, "`%s' previously declared here", signature().cc());
+ break;
+ }
+ n = nc->_next;
+ }
+
+ if (CompoundElementClassT *nc = _next->cast_compound())
+ nc->check_duplicates_until(last, errh);
+}
+
+ElementClassT *
+CompoundElementClassT::find_relevant_class(int ninputs, int noutputs, const Vector<String> &args)
+{
+ if (ninputs == _ninputs && noutputs == _noutputs && args.size() == _formals.size())
+ return this;
+ else if (_next)
+ return _next->find_relevant_class(ninputs, noutputs, args);
+ else
+ return 0;
+}
+
+String
+CompoundElementClassT::signature() const
+{
+ return ElementClassT::signature(_name, _ninputs, _noutputs, _formals.size());
+}
+
+void
+CompoundElementClassT::report_signatures(const String &lm, String name, ErrorHandler *errh)
+{
+ if (_next)
+ _next->report_signatures(lm, name, errh);
+ errh->lmessage(lm, "`%s'", signature().cc());
+}
+
+int
+CompoundElementClassT::complex_expand_element(
+ RouterT *fromr, int which, const String &, Vector<String> &args,
+ RouterT *tor, const VariableEnvironment &env, ErrorHandler *errh)
+{
+ assert(fromr != _router && tor != _router);
+ assert(!_circularity_flag);
+ _circularity_flag = true;
+
+ // must make a copy of `compound' because we might be growing the _elements
+ // vector, in which case our reference would die
+ ElementT compound = fromr->element(which);
+
+ // parse configuration string
+ int nargs = _formals.size();
+ if (args.size() != nargs) {
+ const char *whoops = (args.size() < nargs ? "few" : "many");
+ String signature;
+ for (int i = 0; i < nargs; i++) {
+ if (i) signature += ", ";
+ signature += _formals[i];
+ }
+ if (errh)
+ errh->lerror(compound.landmark,
+ "too %s arguments to compound element `%s(%s)'", whoops,
+ compound.name.cc() /* XXX should be class_name */, signature.cc());
+ for (int i = args.size(); i < nargs; i++)
+ args.push_back("");
+ }
+
+ // create prefix
+ assert(compound.name);
+ VariableEnvironment new_env(env, compound.name);
+ String prefix = env.prefix();
+ String new_prefix = new_env.prefix(); // includes previous prefix
+ new_env.limit_depth(_depth);
+ new_env.enter(_formals, args, _depth);
+
+ // create input/output tunnels
+ if (fromr == tor)
+ tor->element(which).type = RouterT::TUNNEL_TYPE;
+ tor->add_tunnel(prefix + compound.name, new_prefix + "input", compound.landmark, errh);
+ tor->add_tunnel(new_prefix + "output", prefix + compound.name, compound.landmark, errh);
+ int new_eindex = tor->eindex(prefix + compound.name);
+
+ // dump compound router into `tor'
+ _router->expand_into(tor, new_env, errh);
+
+ // yes, we expanded it
+ _circularity_flag = false;
+ return new_eindex;
+}
+
+void
+CompoundElementClassT::declaration_string(StringAccum &sa, const String &name, const String &indent)
+{
+ assert(!_circularity_flag);
+ _circularity_flag = true;
+
+ sa << indent << "elementclass " << name << " {";
+
+ // print formals
+ for (int i = 0; i < _formals.size(); i++)
+ sa << (i ? ", " : " ") << _formals[i];
+ if (_formals.size())
+ sa << " |";
+ sa << "\n";
+
+ _router->configuration_string(sa, indent + " ");
+
+ sa << indent << "}\n";
+ _circularity_flag = false;
+}
diff --git a/tools/lib/elementt.hh b/tools/lib/elementt.hh
index 3c98107b61fdeafd2ef02e30c44d47fbf6d50b86..9757bf1819b56c7d7d7727257beb64cdf3896131 100644
--- a/tools/lib/elementt.hh
+++ b/tools/lib/elementt.hh
@@ -4,9 +4,10 @@
#include <stddef.h>
#include <click/vector.hh>
class RouterT;
-class RouterScope;
+class VariableEnvironment;
class ErrorHandler;
class StringAccum;
+class CompoundElementClassT;
struct ElementT {
@@ -47,11 +48,7 @@ struct Hookup {
};
-class ElementClassT {
-
- int _use_count;
-
- public:
+class ElementClassT { public:
ElementClassT();
virtual ~ElementClassT() { }
@@ -59,14 +56,25 @@ class ElementClassT {
void use() { _use_count++; }
void unuse() { if (--_use_count <= 0) delete this; }
- static int simple_expand_into(RouterT *, int, RouterT *,
- const RouterScope &, ErrorHandler *);
- virtual int expand_into(RouterT *, int, RouterT *,
- const RouterScope &, ErrorHandler *);
- virtual void compound_declaration_string(StringAccum &, const String &, const String &);
+ static int expand_element(RouterT *, int, RouterT *, const VariableEnvironment &, ErrorHandler *);
+
+ virtual ElementClassT *find_relevant_class(int ninputs, int noutputs, const Vector<String> &);
+ virtual void report_signatures(const String &, String, ErrorHandler *);
+ virtual int complex_expand_element(RouterT *, int, const String &, Vector<String> &, RouterT *, const VariableEnvironment &, ErrorHandler *);
+
+ virtual void declaration_string(StringAccum &, const String &, const String &);
- virtual bool expands_away() const { return false; }
+ virtual bool direct_expansion() const { return true; }
+ virtual CompoundElementClassT *cast_compound() { return 0; }
virtual RouterT *cast_router() { return 0; }
+
+ static String signature(const String &, int, int, int);
+
+ private:
+
+ int _use_count;
+
+ static int direct_expand_element(RouterT *, int, ElementClassT *, RouterT *, const VariableEnvironment &, ErrorHandler *);
};
@@ -79,12 +87,51 @@ class SynonymElementClassT : public ElementClassT {
SynonymElementClassT(const String &, ElementClassT *);
- int expand_into(RouterT *, int, RouterT *,
- const RouterScope &, ErrorHandler *);
- void compound_declaration_string(StringAccum &, const String &,
- const String &);
+ int complex_expand_element(RouterT *, int, const String &, Vector<String> &, RouterT *, const VariableEnvironment &, ErrorHandler *);
+
+ void declaration_string(StringAccum &, const String &, const String &);
+
+ bool direct_expansion() const { return false; }
+
+};
+
+class CompoundElementClassT : public ElementClassT {
+
+ String _name;
+ String _landmark;
+ RouterT *_router;
+ int _depth;
+ Vector<String> _formals;
+ int _ninputs;
+ int _noutputs;
+
+ ElementClassT *_next;
+
+ bool _circularity_flag;
+
+ int actual_expand(RouterT *, int, RouterT *, const VariableEnvironment &, ErrorHandler *);
+
+ public:
+
+ CompoundElementClassT(RouterT *);
+ CompoundElementClassT(const String &name, const String &landmark, RouterT *, ElementClassT *, int depth);
+ ~CompoundElementClassT();
+
+ void add_formal(const String &n) { _formals.push_back(n); }
+ void finish(ErrorHandler *);
+ void check_duplicates_until(ElementClassT *, ErrorHandler *);
+
+ ElementClassT *find_relevant_class(int ninputs, int noutputs, const Vector<String> &);
+ void report_signatures(const String &, String, ErrorHandler *);
+ int complex_expand_element(RouterT *, int, const String &, Vector<String> &, RouterT *, const VariableEnvironment &, ErrorHandler *);
+
+ void declaration_string(StringAccum &, const String &, const String &);
+
+ bool direct_expansion() const { return false; }
+ CompoundElementClassT *cast_compound() { return this; }
+ RouterT *cast_router() { return _router; }
- bool expands_away() const { return true; }
+ String signature() const;
};
diff --git a/tools/lib/lexert.cc b/tools/lib/lexert.cc
index 6958c0036e2e6b095045d214345e13ca27f78e46..e63fae6c6f9b3d8ff0f57634adb60880135625f2 100644
--- a/tools/lib/lexert.cc
+++ b/tools/lib/lexert.cc
@@ -66,7 +66,7 @@ void
LexerT::clear()
{
if (_router)
- _router->unuse();
+ delete _router;
_router = new RouterT;
_big_string = "";
@@ -79,15 +79,15 @@ LexerT::clear()
_tpos = 0;
_tfull = 0;
- _element_prefix = "";
_anonymous_offset = 0;
+ _compound_depth = 0;
}
void
LexerT::set_router(RouterT *r)
{
if (_router)
- _router->unuse();
+ delete _router;
_router = r;
}
@@ -263,8 +263,15 @@ LexerT::next_lexeme()
} else if (_data[pos] == ':' && _data[pos+1] == ':') {
_pos = pos + 2;
return Lexeme(lex2Colon, _big_string.substring(word_pos, 2));
+ } else if (_data[pos] == '|' && _data[pos+1] == '|') {
+ _pos = pos + 2;
+ return Lexeme(lex2Bar, _big_string.substring(word_pos, 2));
}
}
+ if (pos < _len - 2 && _data[pos] == '.' && _data[pos+1] == '.' && _data[pos+2] == '.') {
+ _pos = pos + 3;
+ return Lexeme(lex3Dot, _big_string.substring(word_pos, 3));
+ }
_pos = pos + 1;
return Lexeme(_data[word_pos], _big_string.substring(word_pos, 1));
@@ -312,10 +319,16 @@ LexerT::lexeme_string(int kind)
return "`->'";
else if (kind == lex2Colon)
return "`::'";
+ else if (kind == lex2Bar)
+ return "`||'";
+ else if (kind == lex3Dot)
+ return "`...'";
else if (kind == lexTunnel)
return "`connectiontunnel'";
else if (kind == lexElementclass)
return "`elementclass'";
+ else if (kind == lexRequire)
+ return "`require'";
else if (kind >= 32 && kind < 127) {
sprintf(buf, "`%c'", kind);
return buf;
@@ -404,7 +417,7 @@ LexerT::force_element_type(String s)
String
LexerT::anon_element_name(const String &class_name) const
{
- String prefix = _element_prefix + class_name + "@";
+ String prefix = class_name + "@";
int anonymizer = _router->nelements() - _anonymous_offset + 1;
String name = prefix + String(anonymizer);
while (_router->eindex(name) >= 0) {
@@ -472,21 +485,6 @@ LexerT::yport(int &port)
}
}
-bool
-LexerT::yelement_upref(int &element)
-{
- Lexeme t = lex();
- if (!t.is(lexIdent)) {
- lerror("syntax error: expected element name");
- unlex(t);
- return false;
- }
-
- element = _router->get_anon_eindex
- (_element_prefix + t.string(), RouterT::UPREF_TYPE, String(), landmark());
- return true;
-}
-
bool
LexerT::yelement(int &element, bool comma_ok)
{
@@ -494,13 +492,11 @@ LexerT::yelement(int &element, bool comma_ok)
String name;
int ftype;
- if (t.is('^')) {
- return yelement_upref(element);
- } else if (t.is(lexIdent)) {
+ if (t.is(lexIdent)) {
name = t.string();
ftype = element_type(name);
} else if (t.is('{')) {
- ftype = ylocal();
+ ftype = ycompound(String());
name = _router->type_name(ftype);
} else {
unlex(t);
@@ -520,15 +516,14 @@ LexerT::yelement(int &element, bool comma_ok)
if (ftype >= 0)
element = make_anon_element(name, ftype, configuration, lm);
else {
- String lookup_name = _element_prefix + name;
- element = _router->eindex(lookup_name);
+ element = _router->eindex(name);
const Lexeme &t2colon = lex();
unlex(t2colon);
if (t2colon.is(lex2Colon) || (t2colon.is(',') && comma_ok)) {
ydeclaration(name);
- element = _router->eindex(lookup_name);
+ element = _router->eindex(name);
} else if (element < 0) {
// assume it's an element type
ftype = force_element_type(name);
@@ -576,7 +571,7 @@ LexerT::ydeclaration(const String &first_element)
if (t.is(lexIdent))
ftype = force_element_type(t.string());
else if (t.is('{'))
- ftype = ylocal();
+ ftype = ycompound(String());
else {
lerror("missing element type in declaration");
return;
@@ -592,17 +587,14 @@ LexerT::ydeclaration(const String &first_element)
for (int i = 0; i < decls.size(); i++) {
String name = decls[i];
- String lookup_name = _element_prefix + name;
- int old_eidx = _router->eindex(lookup_name);
+ int old_eidx = _router->eindex(name);
if (old_eidx >= 0) {
lerror("redeclaration of element `%s'", name.cc());
_errh->lerror(_router->elandmark(old_eidx), "`%s' previously declared here", _router->edeclaration(old_eidx).cc());
} else if (_router->type_index(name) >= 0)
lerror("`%s' is an element class", name.cc());
- else if (_router->type_index(lookup_name) >= 0)
- lerror("`%s' is an element class", lookup_name.cc());
else
- make_element(lookup_name, ftype, configuration, lm);
+ make_element(name, ftype, configuration, lm);
}
}
@@ -650,9 +642,12 @@ LexerT::yconnection()
goto relex;
case lexIdent:
- case '^':
case '{':
case '}':
+ case lex2Bar:
+ case lexTunnel:
+ case lexElementclass:
+ case lexRequire:
unlex(t);
// FALLTHRU
case ';':
@@ -674,27 +669,6 @@ LexerT::yconnection()
}
}
-void
-LexerT::ycompound_arguments()
-{
- while (1) {
- const Lexeme &tvar = lex();
- if (!tvar.is(lexVariable)) {
- unlex(tvar);
- return;
- }
- _router->add_formal(tvar.string());
- const Lexeme &tsep = lex();
- if (tsep.is('|'))
- return;
- else if (!tsep.is(',')) {
- lerror("expected `,' or `|'");
- unlex(tsep);
- return;
- }
- }
-}
-
void
LexerT::yelementclass()
{
@@ -712,29 +686,11 @@ LexerT::yelementclass()
}
Lexeme tnext = lex();
- if (tnext.is('{')) {
- RouterT *old_router = _router;
- int old_offset = _anonymous_offset;
- _router = new RouterT(old_router);
- _router->get_eindex("input", RouterT::TUNNEL_TYPE, String(), landmark());
- _router->get_eindex("output", RouterT::TUNNEL_TYPE, String(), landmark());
- _anonymous_offset = 2;
-
- ycompound_arguments();
- while (ystatement(true))
- /* nada */;
-
- // '}' was consumed
-
- if (facclass_name)
- old_router->add_type_index(facclass_name, _router);
-
- _router->unuse();
- _router = old_router;
- _anonymous_offset = old_offset;
+ if (tnext.is('{'))
+ (void) ycompound(facclass_name);
- } else if (tnext.is(lexIdent)) {
- ElementClassT *tclass = _router->find_type_class(tnext.string());
+ else if (tnext.is(lexIdent)) {
+ ElementClassT *tclass = _router->type_class(tnext.string());
if (facclass_name)
_router->add_type_index(facclass_name, new SynonymElementClassT(tnext.string(), tclass));
@@ -771,31 +727,83 @@ LexerT::ytunnel()
}
}
+void
+LexerT::ycompound_arguments(CompoundElementClassT *comptype)
+{
+ while (1) {
+ const Lexeme &tvar = lex();
+ if (!tvar.is(lexVariable)) {
+ unlex(tvar);
+ return;
+ }
+ comptype->add_formal(tvar.string());
+ const Lexeme &tsep = lex();
+ if (tsep.is('|'))
+ return;
+ else if (!tsep.is(',')) {
+ lerror("expected `,' or `|'");
+ unlex(tsep);
+ return;
+ }
+ }
+}
+
int
-LexerT::ylocal()
+LexerT::ycompound(String name)
{
- // OK because every used ylocal() corresponds to at least one element
- String name = "@Class" + String(_router->nelements() - _anonymous_offset + 1);
+ bool anonymous = (name.length() == 0);
+ if (anonymous)
+ // OK because every used ylocal() corresponds to at least one element
+ name = "@Class" + String(_router->nelements() - _anonymous_offset + 1);
// '{' was already read
RouterT *old_router = _router;
int old_offset = _anonymous_offset;
- _router = new RouterT(old_router);
- _router->get_eindex("input", RouterT::TUNNEL_TYPE, String(), landmark());
- _router->get_eindex("output", RouterT::TUNNEL_TYPE, String(), landmark());
- _anonymous_offset = 2;
+ ElementClassT *created = 0;
- ycompound_arguments();
- while (ystatement(true))
- /* nada */;
+ // check for '...'
+ const Lexeme &t = lex();
+ if (t.is(lex3Dot)) {
+ if (_router->type_index(name) < 0)
+ _router->add_type_index(name, new ElementClassT);
+ created = _router->type_class(name);
+ expect(lex2Bar);
+ } else
+ unlex(t);
+
+ ElementClassT *first = created;
- // '}' was consumed
+ while (1) {
+ _router = new RouterT(old_router);
+ _router->get_eindex("input", RouterT::TUNNEL_TYPE, String(), landmark());
+ _router->get_eindex("output", RouterT::TUNNEL_TYPE, String(), landmark());
+ CompoundElementClassT *ct = new CompoundElementClassT(name, landmark(), _router, created, _compound_depth);
+ _anonymous_offset = 2;
+ _compound_depth++;
- int tindex = old_router->get_anon_type_index(name, _router);
- _router->unuse();
- _router = old_router;
- _anonymous_offset = old_offset;
- return tindex;
+ ycompound_arguments(ct);
+ while (ystatement(true))
+ /* nada */;
+
+ _compound_depth--;
+ _anonymous_offset = old_offset;
+ _router = old_router;
+
+ ct->finish(_errh);
+ created = ct;
+
+ // check for '||' or '}'
+ const Lexeme &t = lex();
+ if (!t.is(lex2Bar))
+ break;
+ }
+
+ created->cast_compound()->check_duplicates_until(first, _errh);
+
+ if (anonymous)
+ return old_router->get_anon_type_index(name, created);
+ else
+ return old_router->add_type_index(name, created);
}
void
@@ -823,7 +831,6 @@ LexerT::ystatement(bool nested)
switch (t.kind()) {
case lexIdent:
- case '^':
case '[':
case '{':
unlex(t);
@@ -846,8 +853,10 @@ LexerT::ystatement(bool nested)
return true;
case '}':
+ case lex2Bar:
if (!nested)
goto syntax_error;
+ unlex(t);
return false;
case lexEOF:
diff --git a/tools/lib/lexert.hh b/tools/lib/lexert.hh
index 087880986fb46033d919d34d8455068400311f35..5a593a63b1b1147a81b2f7e5de13e40526c94bec 100644
--- a/tools/lib/lexert.hh
+++ b/tools/lib/lexert.hh
@@ -3,6 +3,7 @@
#include <click/error.hh>
#include <stdio.h>
class RouterT;
+class CompoundElementClassT;
enum {
lexEOF = 0,
@@ -10,6 +11,8 @@ enum {
lexVariable,
lexArrow,
lex2Colon,
+ lex2Bar,
+ lex3Dot,
lexTunnel,
lexElementclass,
lexRequire,
@@ -64,8 +67,8 @@ class LexerT { protected:
// router
RouterT *_router;
- String _element_prefix;
int _anonymous_offset;
+ int _compound_depth;
// errors
ErrorHandler *_errh;
@@ -99,13 +102,12 @@ class LexerT { protected:
bool yport(int &port);
bool yelement(int &element, bool comma_ok);
- bool yelement_upref(int &element);
void ydeclaration(const String &first_element = "");
bool yconnection();
- void ycompound_arguments();
+ void ycompound_arguments(CompoundElementClassT *);
void yelementclass();
void ytunnel();
- int ylocal();
+ int ycompound(String);
void yrequire();
bool ystatement(bool nested = false);
diff --git a/tools/lib/processingt.cc b/tools/lib/processingt.cc
index 17959576b3812bbe23f245e32d6627bbc5158d6d..770854d5f08847553ecb2efb72791b5fd4810649 100644
--- a/tools/lib/processingt.cc
+++ b/tools/lib/processingt.cc
@@ -130,7 +130,7 @@ ProcessingT::initial_processing_for(int ei, const ElementMap &em, ErrorHandler *
{
// don't handle uprefs or tunnels
int etype = _router->etype(ei);
- if (etype < 0 || etype == RouterT::TUNNEL_TYPE || etype == RouterT::UPREF_TYPE)
+ if (etype < 0 || etype == RouterT::TUNNEL_TYPE)
return;
String etype_name = _router->type_name(etype);
diff --git a/tools/lib/routert.cc b/tools/lib/routert.cc
index 0bfa3ba9c647cc7bf5179271843ce8eb4cdae262..393cf0b5bef702be546e47de4dfad3d432ffec2e 100644
--- a/tools/lib/routert.cc
+++ b/tools/lib/routert.cc
@@ -25,28 +25,28 @@
#include <click/bitvector.hh>
#include <click/confparse.hh>
#include <click/straccum.hh>
+#include <click/variableenv.hh>
#include <stdio.h>
RouterT::RouterT(RouterT *enclosing)
- : _enclosing_scope(enclosing),
- _element_type_map(-1), _element_name_map(-1),
+ : _use_count(0), _element_type_map(-1), _element_name_map(-1),
_free_element(-1), _real_ecount(0), _new_eindex_collector(0),
_free_hookup(-1), _archive_map(-1)
{
- if (_enclosing_scope)
- _enclosing_scope->use();
- // add space for tunnel and upref types
+ // add space for tunnel type
_element_type_names.push_back("<tunnel>");
_element_type_map.insert("<tunnel>", TUNNEL_TYPE);
_element_classes.push_back(0);
- _element_type_names.push_back("<upref>");
- _element_type_map.insert("<upref>", UPREF_TYPE);
- _element_classes.push_back(0);
+ // borrow definitions from `enclosing'
+ if (enclosing) {
+ for (int i = 0; i < enclosing->_element_classes.size(); i++)
+ if (ElementClassT *ec = enclosing->_element_classes[i])
+ add_type_index(enclosing->_element_type_names[i], ec);
+ }
}
RouterT::RouterT(const RouterT &o)
- : ElementClassT(),
- _enclosing_scope(o._enclosing_scope),
+ : _use_count(0),
_element_type_map(o._element_type_map),
_element_type_names(o._element_type_names),
_element_classes(o._element_classes),
@@ -65,8 +65,6 @@ RouterT::RouterT(const RouterT &o)
_archive_map(o._archive_map),
_archive(o._archive)
{
- if (_enclosing_scope)
- _enclosing_scope->use();
for (int i = 0; i < _element_classes.size(); i++)
if (_element_classes[i])
_element_classes[i]->use();
@@ -74,8 +72,6 @@ RouterT::RouterT(const RouterT &o)
RouterT::~RouterT()
{
- if (_enclosing_scope)
- _enclosing_scope->unuse();
for (int i = 0; i < _element_classes.size(); i++)
if (_element_classes[i])
_element_classes[i]->unuse();
@@ -162,30 +158,8 @@ RouterT::is_flat() const
}
-ElementClassT *
-RouterT::find_type_class(const String &s) const
-{
- const RouterT *r = this;
- while (r) {
- int i = r->_element_type_map[s];
- if (i >= 0) return r->_element_classes[i];
- r = r->_enclosing_scope;
- }
- return 0;
-}
-
-int
-RouterT::get_type_index(const String &s)
-{
- int i = _element_type_map[s];
- if (i >= 0)
- return i;
- else
- return get_type_index(s, find_type_class(s));
-}
-
int
-RouterT::get_type_index(const String &name, ElementClassT *eclass)
+RouterT::get_type_index(const String &name, ElementClassT *eclass = 0)
{
int i = _element_type_map[name];
if (i < 0) {
@@ -815,8 +789,7 @@ RouterT::finish_remove_elements(Vector<int> &new_eindex, ErrorHandler *errh)
for (int i = 0; i < nelements; i++) {
j = new_eindex[i];
if (j != i) {
- if (_elements[i].type != UPREF_TYPE)
- _element_name_map.insert(_elements[i].name, j);
+ _element_name_map.insert(_elements[i].name, j);
if (j >= 0) {
_elements[j] = _elements[i];
_hookup_first[j] = _hookup_first[i];
@@ -969,8 +942,8 @@ RouterT::finish_remove_element_types(Vector<int> &new_tindex)
int nelements = _elements.size();
// find new ftypeindexes
- // save TUNNEL_TYPE and UPREF_TYPE
- new_tindex[TUNNEL_TYPE] = new_tindex[UPREF_TYPE] = 0;
+ // save TUNNEL_TYPE
+ new_tindex[TUNNEL_TYPE] = 0;
int j = 0;
for (int i = 0; i < ntype; i++)
if (new_tindex[i] >= 0)
@@ -979,7 +952,6 @@ RouterT::finish_remove_element_types(Vector<int> &new_tindex)
// return if nothing has changed
assert(new_tindex[TUNNEL_TYPE] == TUNNEL_TYPE);
- assert(new_tindex[UPREF_TYPE] == UPREF_TYPE);
if (new_ntype == ntype)
return;
@@ -1015,6 +987,32 @@ RouterT::remove_unused_element_types()
}
+void
+RouterT::expand_into(RouterT *tor, const VariableEnvironment &env, ErrorHandler *errh)
+{
+ assert(tor != this);
+
+ int nelements = _elements.size();
+ Vector<int> new_fidx(nelements, -1);
+
+ // add tunnel pairs and expand below
+ for (int i = 0; i < nelements; i++)
+ new_fidx[i] = ElementClassT::expand_element(this, i, tor, env, errh);
+
+ // add hookup
+ int nh = _hookup_from.size();
+ for (int i = 0; i < nh; i++) {
+ const Hookup &hf = _hookup_from[i], &ht = _hookup_to[i];
+ tor->add_connection(Hookup(new_fidx[hf.idx], hf.port),
+ Hookup(new_fidx[ht.idx], ht.port),
+ _hookup_landmark[i]);
+ }
+
+ // add requirements
+ for (int i = 0; i < _requirements.size(); i++)
+ tor->add_requirement(_requirements[i]);
+}
+
void
RouterT::expand_tunnel(Vector<Hookup> *pp_expansions,
bool is_input, int magice, int which,
@@ -1140,205 +1138,22 @@ RouterT::remove_tunnels()
}
-RouterScope::RouterScope(const RouterScope &o, const String &suffix)
- : _prefix(o._prefix + suffix), _formals(o._formals), _values(o._values)
-{
-}
-
-void
-RouterScope::combine(const Vector<String> &formals, const Vector<String> &values)
-{
- for (int i = 0; i < formals.size(); i++) {
- for (int j = 0; j < _formals.size(); j++)
- if (_formals[j] == formals[i]) {
- _values[j] = values[i];
- goto done;
- }
- _formals.push_back(formals[i]);
- _values.push_back(values[i]);
- done: ;
- }
-}
-
-String
-RouterScope::interpolate(const String &config) const
-{
- if (_formals.size() == 0)
- return config;
-
- const char *data = config.data();
- int config_pos = 0;
- int pos = 0;
- int len = config.length();
- int quote = 0;
- String output;
-
- for (; pos < len; pos++)
- if (data[pos] == '\\' && pos < len - 1 && quote == '\"')
- pos++;
- else if (data[pos] == '\'' && quote == 0)
- quote = '\'';
- else if (data[pos] == '\"' && quote == 0)
- quote = '\"';
- else if (data[pos] == quote)
- quote = 0;
- else if (data[pos] == '/' && pos < len - 1) {
- if (data[pos+1] == '/') {
- for (pos += 2; pos < len && data[pos] != '\n' && data[pos] != '\r'; )
- pos++;
- } else if (data[pos+1] == '*') {
- for (pos += 2; pos < len; pos++)
- if (data[pos] == '*' && pos < len - 1 && data[pos+1] == '/') {
- pos++;
- break;
- }
- }
- } else if (data[pos] == '$' && quote != '\'') {
- unsigned word_pos = pos;
- for (pos++; isalnum(data[pos]) || data[pos] == '_'; pos++)
- /* nada */;
- String name = config.substring(word_pos, pos - word_pos);
- for (int variable = 0; variable < _formals.size(); variable++)
- if (name == _formals[variable]) {
- output += config.substring(config_pos, word_pos - config_pos);
- String value = _values[variable];
- if (quote == '\"') { // interpolate inside the quotes
- value = cp_quote(cp_unquote(value));
- if (value[0] == '\"')
- value = value.substring(1, value.length() - 2);
- }
- output += value;
- config_pos = pos;
- }
- pos--;
- }
-
- if (!output)
- return config;
- else
- return output + config.substring(config_pos, pos - config_pos);
-}
-
-int
-RouterT::expand_into(RouterT *fromr, int which, RouterT *tor,
- const RouterScope &scope, ErrorHandler *errh)
-{
- assert(fromr != this && tor != this);
- // must make a copy of `compound' because we might be growing the _elements
- // vector, in which case our reference would die
- ElementT compound = fromr->element(which);
-
- // parse configuration string
- Vector<String> args;
- int nargs = _formals.size();
- cp_argvec(scope.interpolate(compound.configuration), args);
- if (args.size() != nargs) {
- const char *whoops = (args.size() < nargs ? "few" : "many");
- String signature;
- for (int i = 0; i < nargs; i++) {
- if (i) signature += ", ";
- signature += _formals[i];
- }
- if (errh)
- errh->lerror(compound.landmark,
- "too %s arguments to compound element `%s(%s)'", whoops,
- compound.name.cc() /* XXX should be class_name */, signature.cc());
- for (int i = args.size(); i < nargs; i++)
- args.push_back("");
- }
-
- // create prefix
- String suffix;
- assert(compound.name);
- if (compound.name[compound.name.length() - 1] == '/')
- suffix = compound.name;
- else
- suffix = compound.name + "/";
-
- RouterScope new_scope(scope, suffix);
- String prefix = scope.prefix();
- String new_prefix = new_scope.prefix(); // includes previous prefix
- new_scope.combine(_formals, args);
-
- // create input/output tunnels
- if (fromr == tor)
- tor->element(which).type = TUNNEL_TYPE;
- tor->add_tunnel(prefix + compound.name, new_prefix + "input", compound.landmark, errh);
- tor->add_tunnel(new_prefix + "output", prefix + compound.name, compound.landmark, errh);
- int new_eindex = tor->eindex(prefix + compound.name);
-
- int nelements = _elements.size();
- Vector<int> new_fidx(nelements, -1);
-
- // add tunnel pairs and resolve uprefs
- for (int i = 0; i < nelements; i++) {
- ElementClassT *ect = _element_classes[_elements[i].type];
- if (ect)
- new_fidx[i] = ect->expand_into(this, i, tor, new_scope, errh);
- else
- new_fidx[i] = ElementClassT::simple_expand_into(this, i, tor, new_scope, errh);
- }
-
- // add hookup
- for (int i = 0; i < _hookup_from.size(); i++) {
- Hookup &hfrom = _hookup_from[i], &hto = _hookup_to[i];
- tor->add_connection(Hookup(new_fidx[hfrom.idx], hfrom.port),
- Hookup(new_fidx[hto.idx], hto.port),
- _hookup_landmark[i]);
- }
-
- // add requirements
- for (int i = 0; i < _requirements.size(); i++)
- tor->add_requirement(_requirements[i]);
-
- // yes, we expanded it
- return new_eindex;
-}
-
void
RouterT::remove_compound_elements(ErrorHandler *errh)
{
int nelements = _elements.size();
- RouterScope scope;
+ VariableEnvironment env;
for (int i = 0; i < nelements; i++)
- if (_elements[i].live()) { // allow for deleted elements
- ElementClassT *ect = _element_classes[_elements[i].type];
- if (ect)
- ect->expand_into(this, i, this, scope, errh);
- else
- ElementClassT::simple_expand_into(this, i, this, scope, errh);
- }
+ if (_elements[i].live()) // allow for deleted elements
+ ElementClassT::expand_element(this, i, this, env, errh);
- // remove all compound classes
+ /* // remove all compound classes
int neclass = _element_classes.size();
Vector<int> removed_eclass(neclass, 0);
for (int i = 0; i < neclass; i++)
if (_element_classes[i] && _element_classes[i]->expands_away())
removed_eclass[i] = -1;
- finish_remove_element_types(removed_eclass);
-}
-
-void
-RouterT::remove_unresolved_uprefs(ErrorHandler *errh)
-{
- if (!errh) errh = ErrorHandler::silent_handler();
-
- int nelements = _elements.size();
- Vector<int> new_eindex(nelements, 0);
- bool any = false;
-
- // find uprefs
- for (int i = 0; i < nelements; i++) {
- ElementT &e = _elements[i];
- if (e.type == UPREF_TYPE) {
- errh->lerror(e.landmark, "unresolved upref `%s'", e.name.cc());
- new_eindex[i] = -1;
- any = true;
- }
- }
-
- if (any)
- finish_free_elements(new_eindex);
+ finish_remove_element_types(removed_eclass);*/
}
void
@@ -1346,45 +1161,15 @@ RouterT::flatten(ErrorHandler *errh)
{
remove_compound_elements(errh);
remove_tunnels();
- remove_unresolved_uprefs(errh);
remove_dead_elements();
compact_connections();
+ remove_unused_element_types();
check();
}
// PRINTING
-void
-RouterT::compound_declaration_string(StringAccum &sa, const String &name,
- const String &indent)
-{
- sa << indent << "elementclass " << name << " {";
-
- // print formals
- for (int i = 0; i < _formals.size(); i++)
- sa << (i ? ", " : " ") << _formals[i];
- if (_formals.size())
- sa << " |";
- sa << "\n";
-
- configuration_string(sa, indent + " ");
-
- sa << indent << "}\n";
-}
-
-String
-RouterT::ename_upref(int idx) const
-{
- if (idx >= 0 && idx < _elements.size()) {
- if (_elements[idx].type == UPREF_TYPE)
- return "^" + _elements[idx].name;
- else
- return _elements[idx].name;
- } else
- return String("/*BAD_") + String(idx) + String("*/");
-}
-
static void
add_line_directive(StringAccum &sa, const String &landmark)
{
@@ -1417,7 +1202,7 @@ RouterT::configuration_string(StringAccum &sa, const String &indent) const
int old_sa_len = sa.length();
for (int i = 0; i < nelemtype; i++)
if (_element_classes[i])
- _element_classes[i]->compound_declaration_string
+ _element_classes[i]->declaration_string
(sa, _element_type_names[i], indent);
if (sa.length() != old_sa_len)
sa << "\n";
@@ -1439,8 +1224,8 @@ RouterT::configuration_string(StringAccum &sa, const String &indent) const
int nprinted_elements = 0;
for (int i = 0; i < nelements; i++) {
const ElementT &e = _elements[i];
- if (e.dead() || e.type == TUNNEL_TYPE || e.type == UPREF_TYPE)
- continue; // skip tunnels and uprefs
+ if (e.dead() || e.type == TUNNEL_TYPE)
+ continue; // skip tunnels
add_line_directive(sa, e.landmark);
sa << indent << e.name << " :: ";
if (e.type < nelemtype)
@@ -1501,7 +1286,7 @@ RouterT::configuration_string(StringAccum &sa, const String &indent) const
if (used[c] || !startchain[c])
continue;
- sa << indent << ename_upref(hf.idx);
+ sa << indent << ename(hf.idx);
if (hf.port)
sa << " [" << hf.port << "]";
@@ -1512,7 +1297,7 @@ RouterT::configuration_string(StringAccum &sa, const String &indent) const
const Hookup &ht = _hookup_to[d];
if (ht.port)
sa << "[" << ht.port << "] ";
- sa << ename_upref(ht.idx);
+ sa << ename(ht.idx);
used[d] = true;
d = next[d];
}
diff --git a/tools/lib/routert.hh b/tools/lib/routert.hh
index cdea0e9a4dae134b77ba8637ffb7d61c57fd5dee..60980db65d1a82a6f373eac0c9c1a3bde8d56d78 100644
--- a/tools/lib/routert.hh
+++ b/tools/lib/routert.hh
@@ -6,7 +6,7 @@
#include <click/archive.hh>
typedef HashMap<String, int> StringMap;
-class RouterT : public ElementClassT {
+class RouterT {
struct Pair {
int from;
@@ -15,8 +15,7 @@ class RouterT : public ElementClassT {
Pair(int f, int t) : from(f), to(t) { }
};
- RouterT *_enclosing_scope;
- Vector<String> _formals;
+ int _use_count;
StringMap _element_type_map;
Vector<String> _element_type_names;
@@ -52,24 +51,24 @@ class RouterT : public ElementClassT {
public:
- enum { TUNNEL_TYPE = 0, UPREF_TYPE = 1 };
+ enum { TUNNEL_TYPE = 0 };
RouterT(RouterT * = 0);
RouterT(const RouterT &);
virtual ~RouterT();
+ void use() { _use_count++; }
+ void unuse() { if (--_use_count <= 0) delete this; }
+
void check() const;
bool is_flat() const;
- void add_formal(const String &n) { _formals.push_back(n); }
-
int ntypes() const { return _element_classes.size(); }
const String &type_name(int i) const { return _element_type_names[i]; }
ElementClassT *type_class(int i) const { return _element_classes[i]; }
+ ElementClassT *type_class(const String &) const;
int type_index(const String &s) const { return _element_type_map[s]; }
- ElementClassT *find_type_class(const String &) const;
- int get_type_index(const String &);
- int get_type_index(const String &, ElementClassT *);
+ int get_type_index(const String &, ElementClassT * = 0);
int add_type_index(const String &, ElementClassT *);
int get_anon_type_index(const String &, ElementClassT *);
void get_types_from(const RouterT *);
@@ -83,7 +82,6 @@ class RouterT : public ElementClassT {
bool elive(int ei) const { return _elements[ei].live(); }
bool edead(int ei) const { return _elements[ei].dead(); }
String ename(int) const;
- String ename_upref(int) const;
int etype(int) const;
String etype_name(int) const;
String edeclaration(int) const;
@@ -109,6 +107,7 @@ class RouterT : public ElementClassT {
const Hookup &hookup_from(int i) const { return _hookup_from[i]; }
const Vector<Hookup> &hookup_to() const { return _hookup_to; }
const Hookup &hookup_to(int i) const { return _hookup_to[i]; }
+ const Vector<String> &hookup_landmark() const { return _hookup_landmark; }
const String &hookup_landmark(int i) const { return _hookup_landmark[i]; }
bool hookup_live(int i) const { return _hookup_from[i].live(); }
@@ -153,20 +152,16 @@ class RouterT : public ElementClassT {
void add_components_to(RouterT *, const String &prefix = String()) const;
- int expand_into(RouterT *, int, RouterT *, const RouterScope &, ErrorHandler *);
- bool expands_away() const { return true; }
-
void remove_unused_element_types();
void remove_duplicate_connections();
void remove_dead_elements(ErrorHandler * = 0);
void remove_compound_elements(ErrorHandler *);
void remove_tunnels();
- void remove_unresolved_uprefs(ErrorHandler *);
+ void expand_into(RouterT *, const VariableEnvironment &, ErrorHandler *);
void flatten(ErrorHandler *);
- void compound_declaration_string(StringAccum &, const String &, const String &);
void configuration_string(StringAccum &, const String & = String()) const;
String configuration_string() const;
@@ -174,26 +169,13 @@ class RouterT : public ElementClassT {
};
-class RouterScope {
-
- String _prefix;
- Vector<String> _formals;
- Vector<String> _values;
-
- public:
-
- RouterScope() { }
- RouterScope(const RouterScope &, const String &suffix);
-
- operator bool() const { return _formals.size() != 0; }
- const String &prefix() const { return _prefix; }
-
- void combine(const Vector<String> &, const Vector<String> &);
-
- String interpolate(const String &) const;
-
-};
+inline ElementClassT *
+RouterT::type_class(const String &n) const
+{
+ int i = type_index(n);
+ return (i < 0 ? 0 : _element_classes[i]);
+}
inline String
RouterT::ename(int idx) const
diff --git a/userlevel/Makefile.in b/userlevel/Makefile.in
index df55a1398dbacd45b95ce9372a433768a5b41cc5..41977089de7dc506fd715209f5a5595b4461db7a 100644
--- a/userlevel/Makefile.in
+++ b/userlevel/Makefile.in
@@ -43,7 +43,7 @@ GENERIC_OBJS = string.o straccum.o \
packet.o \
error.o glue.o timer.o gaprate.o \
elemlink.o element.o \
- confparse.o lexer.o archive.o elemfilter.o router.o \
+ confparse.o variableenv.o lexer.o archive.o elemfilter.o router.o \
crc32.o in_cksum.o iptable.o iptable2.o ip6table.o radix.o \
userutils.o