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