├── Makefile ├── Parser.cpp ├── Parser.h ├── TODO ├── config-parser.cpp ├── test-url-parses ├── test-url-parses.out └── url-parser.cpp /Makefile: -------------------------------------------------------------------------------- 1 | CXXFLAGS=-g -Os -Wall -Werror -pipe 2 | LDFLAGS=-lstdc++ 3 | 4 | all: url-parser config-parser 5 | 6 | clean: 7 | rm -f url-parser config-parser url-parser.o config-parser.o Parser.o 8 | 9 | url-parser: url-parser.o Parser.o 10 | config-parser: config-parser.o Parser.o 11 | 12 | Parser.o: Parser.cpp Parser.h 13 | url-parser.o: url-parser.cpp Parser.h 14 | config-parser.o: config-parser.cpp Parser.h 15 | -------------------------------------------------------------------------------- /Parser.cpp: -------------------------------------------------------------------------------- 1 | #include "Parser.h" 2 | 3 | using std::ostream; 4 | using std::list; 5 | using std::set; 6 | using std::string; 7 | using std::numeric_limits; 8 | 9 | void ParseEnv::out(ostream& o, const ParseSource& ps, int indent) { 10 | for (list::iterator it=env.begin(); it!=env.end(); ++it) { 11 | it->out(o, ps, indent); o << "\n"; 12 | } 13 | } 14 | 15 | void ParseCapture::out(ostream& o, const ParseSource& ps, int indent) { 16 | o 17 | << string(indent, ' ') << "[" << tag << ": " 18 | << ps.substr(s, e) << "(" << s << "," << e << ")"; 19 | if (!subEnv.empty()) { 20 | o << "\n"; 21 | for (list::iterator it=subEnv.begin(); it!=subEnv.end(); ++it) { 22 | it->out(o, ps, indent+1); o << "\n"; 23 | } 24 | o << string(indent, ' ') << "]"; 25 | } else { 26 | o << "]"; 27 | } 28 | } 29 | 30 | void Parser::doPrint(ostream& o) const { 31 | set printed; 32 | set toParse; 33 | printed.insert(this); 34 | o << name << "="; 35 | print(o, toParse); 36 | o << "\n"; 37 | while (!toParse.empty()) { 38 | set leftover; 39 | for (set::iterator i = toParse.begin(); i!=toParse.end(); ++i) { 40 | if (printed.insert(*i).second) { 41 | o << (*i)->name << "="; 42 | (*i)->print(o, leftover); 43 | o << "\n"; 44 | } 45 | } 46 | toParse.swap(leftover); 47 | } 48 | } 49 | 50 | void Parser::doPrint(ostream& o, std::set< Parser const* >& notParsed) const { 51 | if (!name.empty()) { 52 | o << name; 53 | notParsed.insert(this); 54 | } else { 55 | print(o, notParsed); 56 | } 57 | } 58 | 59 | bool Parser::doParse(ParseSource& in, ParseEnv& env) const { 60 | unsigned s =in.getPos(); 61 | ParseEnv en; 62 | bool r = parse(in, en); 63 | unsigned e =in.getPos(); 64 | if (r) { 65 | // Only add the parsed environment if parse succeeded 66 | if (capture) { 67 | if (en.empty()) { 68 | env.add(captureTag, s, e); 69 | } else { 70 | env.add(captureTag, s, e, en); 71 | } 72 | } else { 73 | env.add(en); 74 | } 75 | } 76 | return r; 77 | } 78 | 79 | const string Null::id("Null"); 80 | const string Fail::id("Fail"); 81 | const string End::id("End"); 82 | const string Literal::id("Literal"); 83 | const string And::id("And"); 84 | const string Or::id("Or"); 85 | const string Optional::id("Optional"); 86 | const string Any::id("Any"); 87 | const string None::id("None"); 88 | const string Repeat::id("Repeat"); 89 | 90 | bool Null::parse(ParseSource&, ParseEnv&) const { 91 | return true; 92 | } 93 | 94 | bool Fail::parse(ParseSource&, ParseEnv&) const { 95 | return false; 96 | } 97 | 98 | bool End::parse(ParseSource& in, ParseEnv&) const { 99 | return in.atEnd(); 100 | } 101 | 102 | bool Literal::parse(ParseSource& in, ParseEnv&) const { 103 | bool r = in.match(s); 104 | in += s.size(); 105 | return r; 106 | } 107 | 108 | bool And::parse(ParseSource& in, ParseEnv& env) const { 109 | return 110 | p1.doParse(in, env) && 111 | p2.doParse(in, env) && 112 | p3.doParse(in, env) && 113 | p4.doParse(in, env) && 114 | p5.doParse(in, env) && 115 | p6.doParse(in, env); 116 | } 117 | 118 | bool Or::parse(ParseSource& in, ParseEnv& env) const { 119 | int pos = in.getPos(); 120 | if (p1.doParse(in, env)) return true; 121 | in.setPos(pos); 122 | if (p2.doParse(in, env)) return true; 123 | in.setPos(pos); 124 | if (p3.doParse(in, env)) return true; 125 | in.setPos(pos); 126 | if (p4.doParse(in, env)) return true; 127 | in.setPos(pos); 128 | if (p5.doParse(in, env)) return true; 129 | in.setPos(pos); 130 | if (p6.doParse(in, env)) return true; 131 | return false; 132 | } 133 | 134 | bool Optional::parse(ParseSource& in, ParseEnv& env) const { 135 | int pos = in.getPos(); 136 | if (p.doParse(in, env)) return true; 137 | in.setPos(pos); 138 | return true; 139 | } 140 | 141 | bool Any::parse(ParseSource& in, ParseEnv&) const { 142 | bool r = cs.find(*in) != std::string::npos; 143 | ++in; 144 | return r; 145 | } 146 | 147 | bool None::parse(ParseSource& in, ParseEnv&) const { 148 | bool r = cs.find(*in) == std::string::npos; 149 | ++in; 150 | return r; 151 | } 152 | 153 | bool Repeat::parse(ParseSource& in, ParseEnv& env) const { 154 | int pos = in.getPos(); 155 | int count = 0; 156 | bool r; 157 | while ( (r=p.doParse(in, env)) ) { 158 | ++count; 159 | if (in.atEnd()) break; 160 | pos = in.getPos(); 161 | } 162 | // Rewind to before the failed match (if there was one) 163 | if (!r) in.setPos(pos); 164 | 165 | bool s = count >= min && count <= max; 166 | return s; 167 | } 168 | 169 | void Null::print(ostream& o, std::set< Parser const* >& notParsed) const { 170 | } 171 | 172 | void Fail::print(ostream& o, std::set< Parser const* >& notParsed) const { 173 | } 174 | 175 | void End::print(ostream& o, std::set< Parser const* >& notParsed) const { 176 | o << "$"; 177 | } 178 | 179 | void Literal::print(ostream& o, std::set< Parser const* >& notParsed) const { 180 | o << "\"" << s << "\""; 181 | } 182 | 183 | void And::print(ostream& o, std::set< Parser const* >& notParsed) const { 184 | o << "("; 185 | p1.doPrint(o, notParsed); 186 | o << " "; 187 | p2.doPrint(o, notParsed); 188 | if (&p3 != &null) { 189 | o << " "; 190 | p3.doPrint(o, notParsed); 191 | } 192 | if (&p4 != &null) { 193 | o << " "; 194 | p4.doPrint(o, notParsed); 195 | } 196 | if (&p5 != &null) { 197 | o << " "; 198 | p5.doPrint(o, notParsed); 199 | } 200 | if (&p6 != &null) { 201 | o << " "; 202 | p6.doPrint(o, notParsed); 203 | } 204 | o << ")"; 205 | } 206 | 207 | void Or::print(ostream& o, std::set< Parser const* >& notParsed) const { 208 | o << "("; 209 | p1.doPrint(o, notParsed); 210 | o << "|"; 211 | p2.doPrint(o, notParsed); 212 | if (&p3 != &fail) { 213 | o << "|"; 214 | p3.doPrint(o, notParsed); 215 | } 216 | if (&p4 != &fail) { 217 | o << "|"; 218 | p4.doPrint(o, notParsed); 219 | } 220 | if (&p5 != &fail) { 221 | o << "|"; 222 | p5.doPrint(o, notParsed); 223 | } 224 | if (&p6 != &fail) { 225 | o << "|"; 226 | p6.doPrint(o, notParsed); 227 | } 228 | o << ")"; 229 | } 230 | 231 | void Optional::print(ostream& o, std::set< Parser const* >& notParsed) const { 232 | p.doPrint(o, notParsed); 233 | o << "?"; 234 | } 235 | 236 | namespace { 237 | // Printable representations for control characters 238 | const char* p[32] = { 239 | "\\x00", "\\x01", "\\x02", "\\x03", "\\x04", "\\x05", "\\x06", "\a", 240 | "\\a", "\\t", "\\n", "\\v", "\\f", "\\r", "\\x0e", "\\x0f", 241 | "\\x10", "\\x11", "\\x12", "\\x13", "\\x14", "\\x15", "\\x16", "\\x17", 242 | "\\x18", "\\x19", "\\x1a", "\\x1b", "\\x1c", "\\x1d", "\\x1e", "\\x1f", 243 | }; 244 | 245 | // Make all characters printable 246 | void quotedprint(ostream& o, const string& s) { 247 | for (unsigned i = 0; i < s.size(); ++i) { 248 | if (s[i] == '\\') o << "\\"; 249 | else if (s[i] < 32) o << p[(unsigned char)s[i]]; 250 | else o << s[i]; 251 | } 252 | } 253 | } 254 | void Any::print(ostream& o, std::set< Parser const* >& notParsed) const { 255 | if (cs[0] != '^') 256 | o << "["; 257 | else 258 | o << "[\\"; 259 | quotedprint(o, cs); 260 | o << "]"; 261 | } 262 | 263 | void None::print(ostream& o, std::set< Parser const* >& notParsed) const { 264 | o << "[^"; 265 | quotedprint(o, cs); 266 | o << "]"; 267 | } 268 | 269 | void Repeat::print(ostream& o, std::set< Parser const* >& notParsed) const { 270 | p.doPrint(o, notParsed); 271 | if (min == max) { 272 | o << "{" << min << "}"; 273 | } else if (max == numeric_limits::max()) { 274 | switch (min) { 275 | case 0: o << "*"; break; 276 | case 1: o << "+"; break; 277 | default: o << "{" << min << ",}"; 278 | } 279 | } else { 280 | o << "{" << min << "," << max << "}"; 281 | } 282 | } 283 | 284 | // Useful character classes 285 | 286 | Any alpha0("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"); 287 | Any digit0("0123456789"); 288 | Any alphanum0(alpha0, digit0); 289 | Any hexdigit0(digit0, Any("abcdefABCDEF")); // Using this temporary is ok 290 | Any punct0(".,!?:;'\"@&-/"); 291 | Any ws0(" \t\n"); 292 | 293 | Parser& alpha = alpha0.Name("alpha"); 294 | Parser& digit = digit0.Name("digit"); 295 | Parser& alphanum = alphanum0.Name("alphanum"); 296 | Parser& hexdigit = hexdigit0.Name("hexdigit"); 297 | Parser& punct = punct0.Name("punct"); 298 | Parser& ws = ws0; 299 | 300 | // Singleton parsers 301 | 302 | Null null0; 303 | Fail fail0; 304 | End end0; 305 | 306 | Parser& null = null0; 307 | Parser& fail = fail0; 308 | Parser& end = end0; 309 | 310 | -------------------------------------------------------------------------------- /Parser.h: -------------------------------------------------------------------------------- 1 | // General parsing framework 2 | #ifndef Parser_h 3 | #define Parser_h 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | class ParseSource { 12 | const std::string input; 13 | unsigned pos; 14 | 15 | public: 16 | ParseSource(const std::string& s); 17 | char operator*() const; 18 | void operator++(); 19 | void operator+=(int i); 20 | bool match(const std::string& s) const; 21 | std::string substr(int s, int e) const; 22 | bool atEnd() const; 23 | unsigned getPos() const; 24 | void setPos(int p); 25 | }; 26 | 27 | class ParseCapture { 28 | const std::string tag; // Capture name 29 | unsigned s; // start position 30 | unsigned e; // end position 31 | std::list subEnv; 32 | 33 | public: 34 | ParseCapture(const std::string& tag_, unsigned s_, unsigned e_); 35 | ParseCapture(const std::string& tag_, unsigned s_, unsigned e_, std::list& env_); 36 | void out(std::ostream& o, const ParseSource& ps, int indent = 0); 37 | }; 38 | 39 | class ParseEnv { 40 | std::list env; 41 | 42 | public: 43 | bool empty(); 44 | void add(const std::string& tag, unsigned s, unsigned e); 45 | void add(const std::string& tag, unsigned s, unsigned e, ParseEnv& en); 46 | void add(ParseEnv& pe); 47 | void out(std::ostream& o, const ParseSource& ps, int indent = 0); 48 | }; 49 | 50 | class Parser { 51 | const std::string& id; 52 | std::string name; 53 | std::string captureTag; 54 | bool capture; 55 | 56 | virtual bool parse(ParseSource& in, ParseEnv& env) const = 0; 57 | virtual void print(std::ostream& o, std::set& notParsed) const = 0; 58 | 59 | protected: 60 | Parser(const std::string& id_); 61 | virtual ~Parser(); 62 | 63 | public: 64 | const std::string& type(); 65 | void doPrint(std::ostream& o) const; 66 | void doPrint(std::ostream& o, std::set< const Parser* >& notParsed) const; 67 | bool doParse(ParseSource& in, ParseEnv& env) const; 68 | Parser& Capture(const std::string& tag); 69 | Parser& Name(const std::string& name); 70 | }; 71 | 72 | inline ParseSource::ParseSource(const std::string& s) : 73 | input(s), 74 | pos(0) 75 | {} 76 | 77 | inline char ParseSource::operator*() const { 78 | return input[pos]; 79 | } 80 | 81 | inline void ParseSource::operator++() { 82 | ++pos; 83 | } 84 | 85 | inline void ParseSource::operator+=(int i) { 86 | pos += i; 87 | } 88 | 89 | inline bool ParseSource::match(const std::string& s) const { 90 | if (atEnd()) return false; 91 | return input.compare(pos, s.size(), s)==0; 92 | } 93 | 94 | inline std::string ParseSource::substr(int s, int e) const { 95 | return input.substr(s, e-s); 96 | } 97 | 98 | inline bool ParseSource::atEnd() const { 99 | return pos >= input.size(); 100 | } 101 | 102 | inline unsigned ParseSource::getPos() const { 103 | return pos; 104 | } 105 | 106 | inline void ParseSource::setPos(int p) { 107 | pos = p; 108 | } 109 | 110 | inline bool ParseEnv::empty() { 111 | return env.empty(); 112 | } 113 | 114 | inline void ParseEnv::add(const std::string& tag, unsigned s, unsigned e) { 115 | env.push_back(ParseCapture(tag, s, e)); 116 | } 117 | 118 | inline void ParseEnv::add(const std::string& tag, unsigned s, unsigned e, ParseEnv& en) { 119 | env.push_back(ParseCapture(tag, s, e, en.env)); 120 | } 121 | 122 | inline void ParseEnv::add(ParseEnv& pe) { 123 | env.splice(env.end(), pe.env); 124 | } 125 | 126 | inline ParseCapture::ParseCapture(const std::string& tag_, unsigned s_, unsigned e_) : 127 | tag(tag_), 128 | s(s_), 129 | e(e_) 130 | {} 131 | 132 | inline ParseCapture::ParseCapture(const std::string& tag_, unsigned s_, unsigned e_, std::list& env_) : 133 | tag(tag_), 134 | s(s_), 135 | e(e_) 136 | { 137 | subEnv.swap(env_); 138 | } 139 | 140 | inline Parser::Parser(const std::string& id_) : 141 | id(id_), 142 | capture(false) { 143 | } 144 | 145 | inline Parser::~Parser(){ 146 | } 147 | 148 | inline const std::string& Parser::type() { 149 | return id; 150 | } 151 | 152 | inline Parser& Parser::Capture(const std::string& tag) { 153 | capture = true; 154 | captureTag = tag; 155 | return *this; 156 | } 157 | 158 | inline Parser& Parser::Name(const std::string& name) { 159 | this->name = name; 160 | return *this; 161 | } 162 | 163 | class Null : public Parser { 164 | static const std::string id; 165 | public: 166 | Null() : 167 | Parser(id) 168 | {} 169 | 170 | void print(std::ostream& o, std::set& notParsed) const; 171 | bool parse(ParseSource& in, ParseEnv& env) const; 172 | }; 173 | 174 | class Fail : public Parser { 175 | static const std::string id; 176 | public: 177 | Fail() : 178 | Parser(id) 179 | {} 180 | 181 | void print(std::ostream& o, std::set& notParsed) const; 182 | bool parse(ParseSource& in, ParseEnv& env) const; 183 | }; 184 | 185 | class End : public Parser { 186 | static const std::string id; 187 | public: 188 | End() : 189 | Parser(id) 190 | {} 191 | 192 | void print(std::ostream& o, std::set& notParsed) const; 193 | bool parse(ParseSource& in, ParseEnv& env) const; 194 | }; 195 | 196 | // Only ever need one of these 197 | 198 | extern Parser& null; 199 | extern Parser& fail; 200 | extern Parser& end; 201 | 202 | class Literal : public Parser { 203 | static const std::string id; 204 | 205 | const std::string s; 206 | 207 | public: 208 | Literal(char c) : 209 | Parser(id), 210 | s(1, c) 211 | {} 212 | 213 | Literal(const std::string& s_) : 214 | Parser(id), 215 | s(s_) 216 | {} 217 | 218 | void print(std::ostream& o, std::set& notParsed) const; 219 | bool parse(ParseSource& in, ParseEnv& env) const; 220 | }; 221 | 222 | class And : public Parser { 223 | static const std::string id; 224 | 225 | const Parser& p1; 226 | const Parser& p2; 227 | const Parser& p3; 228 | const Parser& p4; 229 | const Parser& p5; 230 | const Parser& p6; 231 | 232 | public: 233 | And(const Parser& p1_, 234 | const Parser& p2_, 235 | const Parser& p3_=null, 236 | const Parser& p4_=null, 237 | const Parser& p5_=null, 238 | const Parser& p6_=null 239 | ) : 240 | Parser(id), 241 | p1(p1_), 242 | p2(p2_), 243 | p3(p3_), 244 | p4(p4_), 245 | p5(p5_), 246 | p6(p6_) 247 | {} 248 | 249 | void print(std::ostream& o, std::set& notParsed) const; 250 | bool parse(ParseSource& in, ParseEnv& env) const; 251 | }; 252 | 253 | class Or : public Parser { 254 | static const std::string id; 255 | 256 | const Parser& p1; 257 | const Parser& p2; 258 | const Parser& p3; 259 | const Parser& p4; 260 | const Parser& p5; 261 | const Parser& p6; 262 | 263 | public: 264 | Or(const Parser& p1_, 265 | const Parser& p2_, 266 | const Parser& p3_=fail, 267 | const Parser& p4_=fail, 268 | const Parser& p5_=fail, 269 | const Parser& p6_=fail 270 | ) : 271 | Parser(id), 272 | p1(p1_), 273 | p2(p2_), 274 | p3(p3_), 275 | p4(p4_), 276 | p5(p5_), 277 | p6(p6_) 278 | {} 279 | 280 | void print(std::ostream& o, std::set& notParsed) const; 281 | bool parse(ParseSource& in, ParseEnv& env) const; 282 | }; 283 | 284 | class Optional : public Parser { 285 | static const std::string id; 286 | 287 | const Parser& p; 288 | 289 | public: 290 | Optional(const Parser& p_) : 291 | Parser(id), 292 | p(p_) 293 | {} 294 | 295 | void print(std::ostream& o, std::set& notParsed) const; 296 | bool parse(ParseSource& in, ParseEnv& env) const; 297 | }; 298 | 299 | class Any : public Parser { 300 | static const std::string id; 301 | 302 | const std::string cs; 303 | 304 | public: 305 | Any(const std::string& cs_) : 306 | Parser(id), 307 | cs(cs_) 308 | {} 309 | 310 | Any(const Any& a1, const Any& a2) : 311 | Parser(id), 312 | cs(a1.cs+a2.cs) 313 | {} 314 | 315 | Any(const Any& a1, const Any& a2, const Any& a3) : 316 | Parser(id), 317 | cs(a1.cs+a2.cs+a3.cs) 318 | {} 319 | 320 | Any(const Any& a1, const Any& a2, const Any& a3, const Any& a4) : 321 | Parser(id), 322 | cs(a1.cs+a2.cs+a3.cs+a4.cs) 323 | {} 324 | 325 | void print(std::ostream& o, std::set& notParsed) const; 326 | bool parse(ParseSource& in, ParseEnv& env) const; 327 | }; 328 | 329 | class None : public Parser { 330 | static const std::string id; 331 | 332 | const std::string cs; 333 | 334 | public: 335 | None(const std::string& cs_) : 336 | Parser(id), 337 | cs(cs_) 338 | {} 339 | 340 | void print(std::ostream& o, std::set& notParsed) const; 341 | bool parse(ParseSource& in, ParseEnv& env) const; 342 | }; 343 | 344 | class Repeat : public Parser { 345 | static const std::string id; 346 | 347 | const Parser& p; 348 | const int min; 349 | const int max; 350 | 351 | public: 352 | Repeat(const Parser& p_, int min_, int max_ = std::numeric_limits::max()) : 353 | Parser(id), 354 | p(p_), 355 | min(min_), 356 | max(max_) 357 | {} 358 | 359 | void print(std::ostream& o, std::set& notParsed) const; 360 | bool parse(ParseSource& in, ParseEnv& env) const; 361 | }; 362 | 363 | // Useful character classes 364 | 365 | extern Parser& alpha; 366 | extern Parser& digit; 367 | extern Parser& alphanum; 368 | extern Parser& hexdigit; 369 | extern Parser& punct; 370 | extern Parser& ws; 371 | 372 | #endif // Parser_h 373 | 374 | -------------------------------------------------------------------------------- /TODO: -------------------------------------------------------------------------------- 1 | Write Readme 2 | 3 | Decide which License to use 4 | 5 | It would be nice to use ABNF (http://tools.ietf.org/html/rfc5234) as a source form 6 | for the parser syntax. 7 | 8 | Finish extracting information from the parse. 9 | 10 | Finish some more useful examples. 11 | -------------------------------------------------------------------------------- /config-parser.cpp: -------------------------------------------------------------------------------- 1 | // Parse AMQP urls 2 | 3 | #include "Parser.h" 4 | 5 | #include 6 | 7 | using std::cout; 8 | using std::cin; 9 | using std::boolalpha; 10 | 11 | using std::string; 12 | 13 | Any otherhostchars("_-.%~/"); 14 | Or hostchars(alpha, digit, otherhostchars); 15 | None idchars("/:@ \t\n"); 16 | Literal osbrace('['); 17 | Literal csbrace(']'); 18 | Literal equals("="); 19 | 20 | Optional ows(ws); 21 | Or identifier(hostchars); // Fix this definition 22 | And header(osbrace, identifier, csbrace, ows); 23 | And definition(identifier, ows, equals, ows, identifier); 24 | And definitionlistel(ws, definition); 25 | Repeat definitionlist(definitionlistel, 0); 26 | And definitions(definition, definitionlist); 27 | And stanza(header, definitions); 28 | Repeat configfile(stanza, 0); 29 | 30 | int main() { 31 | // Set up captures 32 | 33 | cout << "Parse:\n"; 34 | configfile.doPrint(cout); 35 | cout << boolalpha; 36 | string i; 37 | bool r = true; 38 | for (getline(cin, i); !!cin; getline(cin, i)) { 39 | ParseSource ps(i); 40 | ParseEnv env; 41 | r = configfile.doParse(ps, env); 42 | cout << i << ": " << r << "\n"; 43 | cout << "Captures:\n"; 44 | env.out(cout, ps); 45 | } 46 | return !r; 47 | } 48 | -------------------------------------------------------------------------------- /test-url-parses: -------------------------------------------------------------------------------- 1 | amqp: 2 | amqps: 3 | amqp:// 4 | amqps:// 5 | amqp:/// 6 | amqps://andrew/ 7 | blahname/$%pwd 8 | blahname/$%pwd@ 9 | blahname/$%pwd@tcp 10 | blh: 11 | tcp:adfg: 12 | /tmp/socket 13 | host:80 14 | tcp:80 15 | rdma:host:658 16 | amqp://user@host1,host2, 17 | amqp://user@host1,host2 18 | host1:846,ho45,rdma:home:8765 19 | 5675675,676:80 20 | 3434:3434343 21 | -------------------------------------------------------------------------------- /test-url-parses.out: -------------------------------------------------------------------------------- 1 | false 2 | false 3 | false 4 | false 5 | true 6 | [endpoint: /] 7 | [host: /] 8 | [scheme: amqp] 9 | true 10 | [endpoint: andrew/] 11 | [host: andrew/] 12 | [scheme: amqps] 13 | false 14 | false 15 | true 16 | [endpoint: tcp] 17 | [host: tcp] 18 | [password: $%pwd] 19 | [username: blahname] 20 | false 21 | false 22 | true 23 | [endpoint: /tmp/socket] 24 | [host: /tmp/socket] 25 | true 26 | [endpoint: host:80] 27 | [port: 80] 28 | [host: host] 29 | true 30 | [endpoint: tcp:80] 31 | [port: 80] 32 | [host: tcp] 33 | true 34 | [endpoint: rdma:host:658] 35 | [port: 658] 36 | [host: host] 37 | [protocol: rdma] 38 | false 39 | true 40 | [endpoint: host2] 41 | [host: host2] 42 | [endpoint: host1] 43 | [host: host1] 44 | [username: user] 45 | [scheme: amqp] 46 | true 47 | [endpoint: rdma:home:8765] 48 | [port: 8765] 49 | [host: home] 50 | [protocol: rdma] 51 | [endpoint: ho45] 52 | [host: ho45] 53 | [endpoint: host1:846] 54 | [port: 846] 55 | [host: host1] 56 | true 57 | [endpoint: 676:80] 58 | [port: 80] 59 | [host: 676] 60 | [endpoint: 5675675] 61 | [host: 5675675] 62 | false 63 | -------------------------------------------------------------------------------- /url-parser.cpp: -------------------------------------------------------------------------------- 1 | // Parse AMQP urls 2 | 3 | #include "Parser.h" 4 | 5 | #include 6 | 7 | using std::cout; 8 | using std::cin; 9 | using std::boolalpha; 10 | 11 | using std::string; 12 | 13 | Any otherhostchars("_-.%~/"); 14 | Or hostchars(alphanum, otherhostchars); 15 | None idchars("/:@ \t\n"); 16 | Any litip6chars("0123456789abcdefABCDEF.:"); 17 | 18 | Literal amqp("amqp"); 19 | Literal amqps("amqps"); 20 | Literal tcp("tcp"); 21 | Literal ssl("ssl"); 22 | Literal rdma("rdma"); 23 | Literal ib("ib"); 24 | Literal unx("unix"); 25 | Literal at('@'); 26 | Literal slash('/'); 27 | Literal colon(':'); 28 | Literal comma(","); 29 | Literal urlschemeterm("://"); 30 | Literal osbrace('['); 31 | Literal csbrace(']'); 32 | 33 | Or scheme(amqps, amqp); 34 | Or schemeterm(urlschemeterm, colon); 35 | And schemepart(scheme, schemeterm); 36 | Optional oschemepart(schemepart); 37 | 38 | Repeat username(idchars, 1); 39 | Repeat password(idchars, 1); 40 | And passpart(slash, password); 41 | Optional opasspart(passpart); 42 | And userpart(username, opasspart, at); 43 | Optional ouserpart(userpart); 44 | 45 | Or protocol(tcp, ssl, rdma, ib, unx); 46 | Repeat rehost(hostchars, 1); 47 | Repeat host6(litip6chars, 2); 48 | And ip6literal(osbrace, host6, csbrace); 49 | Or host(ip6literal, rehost); 50 | Repeat port(digit, 1, 5); 51 | 52 | And hostport(host, colon, port); 53 | And protocolhost(protocol, colon, host); 54 | And protocolhostport(protocol, colon, host, colon, port); 55 | 56 | Or endpoint(protocolhostport, hostport, protocolhost, host); 57 | And endpointlistel(comma, endpoint); 58 | Repeat endpointlist(endpointlistel, 0); 59 | And endpoints(endpoint, endpointlist); 60 | And url(oschemepart, ouserpart, endpoints, end); 61 | 62 | int main() { 63 | // Set up captures 64 | scheme.Capture("scheme").Name("scheme"); 65 | username.Capture("username").Name("username"); 66 | password.Capture("password").Name("password"); 67 | protocol.Capture("protocol").Name("protocol"); 68 | rehost.Capture("host").Name("rehost"); 69 | host6.Capture("host").Name("host6"); 70 | port.Capture("port").Name("port"); 71 | endpoint.Capture("endpoint").Name("endpoint"); 72 | url.Name("url"); 73 | hostport.Name("hostport"); 74 | protocolhostport.Name("protocolhostport"); 75 | protocolhost.Name("protocolhost"); 76 | 77 | cout << "Parse:\n"; 78 | url.doPrint(cout); 79 | cout << boolalpha; 80 | string i; 81 | bool r = true; 82 | for (getline(cin, i); !!cin; getline(cin, i)) { 83 | ParseSource ps(i); 84 | ParseEnv env; 85 | r = url.doParse(ps, env); 86 | cout << i << ": " << r << "\n"; 87 | cout << "Captures:\n"; 88 | env.out(cout, ps); 89 | } 90 | return !r; 91 | } 92 | --------------------------------------------------------------------------------