dhcp6_lexer.ll 33.5 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14
/* Copyright (C) 2015-2016 Internet Systems Consortium, Inc. ("ISC")

   This Source Code Form is subject to the terms of the Mozilla Public
   License, v. 2.0. If a copy of the MPL was not distributed with this
   file, You can obtain one at http://mozilla.org/MPL/2.0/. */

%{ /* -*- C++ -*- */
#include <cerrno>
#include <climits>
#include <cstdlib>
#include <string>
#include <dhcp6/parser_context.h>
#include <asiolink/io_address.h>
#include <boost/lexical_cast.hpp>
Tomek Mrugalski's avatar
Tomek Mrugalski committed
15
#include <exceptions/exceptions.h>
16 17 18 19 20 21 22 23

// Work around an incompatibility in flex (at least versions
// 2.5.31 through 2.5.33): it generates code that does
// not conform to C89.  See Debian bug 333231
// <http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=333231>.
# undef yywrap
# define yywrap() 1

Francis Dupont's avatar
Francis Dupont committed
24 25 26 27 28
namespace {

bool start_token_flag = false;

isc::dhcp::Parser6Context::ParserType start_token_value;
29
unsigned int comment_start_line = 0;
Francis Dupont's avatar
Francis Dupont committed
30 31

};
32

33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
// To avoid the call to exit... oops!
#define YY_FATAL_ERROR(msg) isc::dhcp::Parser6Context::fatal(msg)
%}

/* noyywrap disables automatic rewinding for the next file to parse. Since we
   always parse only a single string, there's no need to do any wraps. And
   using yywrap requires linking with -lfl, which provides the default yywrap
   implementation that always returns 1 anyway. */
%option noyywrap

/* nounput simplifies the lexer, by removing support for putting a character
   back into the input stream. We never use such capability anyway. */
%option nounput

/* batch means that we'll never use the generated lexer interactively. */
%option batch

50 51 52
/* avoid to get static global variables to remain with C++. */
/* in last resort %option reentrant */

53 54 55 56 57 58 59 60 61
/* Enables debug mode. To see the debug messages, one needs to also set
   yy_flex_debug to 1, then the debug messages will be printed on stderr. */
%option debug

/* I have no idea what this option does, except it was specified in the bison
   examples and Postgres folks added it to remove gcc 4.3 warnings. Let's
   be on the safe side and keep it. */
%option noinput

Tomek Mrugalski's avatar
Tomek Mrugalski committed
62
%x COMMENT
Francis Dupont's avatar
Francis Dupont committed
63
%x DIR_ENTER DIR_INCLUDE DIR_EXIT
Tomek Mrugalski's avatar
Tomek Mrugalski committed
64

65 66 67 68 69 70
/* These are not token expressions yet, just convenience expressions that
   can be used during actual token definitions. Note some can match
   incorrect inputs (e.g., IP addresses) which must be checked. */
int   \-?[0-9]+
blank [ \t]

71 72 73 74 75 76
UnicodeEscapeSequence           u[0-9A-Fa-f]{4}
JSONEscapeCharacter             ["\\/bfnrt]
JSONEscapeSequence              {JSONEscapeCharacter}|{UnicodeEscapeSequence}
JSONStandardCharacter           [^\x00-\x1f"\\]
JSONStringCharacter             {JSONStandardCharacter}|\\{JSONEscapeSequence}
JSONString                      \"{JSONStringCharacter}*\"
77

78 79 80 81 82 83
/* for errors */

BadUnicodeEscapeSequence        u[0-9A-Fa-f]{0,3}[^0-9A-Fa-f]
BadJSONEscapeSequence           [^"\\/bfnrtu]|{BadUnicodeEscapeSequence}
ControlCharacter                [\x00-\x1f]
ControlCharacterFill            [^"\\]|\\{JSONEscapeSequence}
84 85 86 87 88

%{
// This code run each time a pattern is matched. It updates the location
// by moving it ahead by yyleng bytes. yyleng specifies the length of the
// currently matched token.
89
#define YY_USER_ACTION  driver.loc_.columns(yyleng);
90 91 92 93 94
%}

%%

%{
95 96 97 98
    // This part of the code is copied over to the verbatim to the top
    // of the generated yylex function. Explanation:
    // http://www.gnu.org/software/bison/manual/html_node/Multiple-start_002dsymbols.html

99
    // Code run each time yylex is called.
100
    driver.loc_.step();
Tomek Mrugalski's avatar
Tomek Mrugalski committed
101

102 103 104
    if (start_token_flag) {
        start_token_flag = false;
        switch (start_token_value) {
105 106 107
        case Parser6Context::PARSER_GENERIC_JSON:
        default:
            return isc::dhcp::Dhcp6Parser::make_TOPLEVEL_GENERIC_JSON(driver.loc_);
108
        case Parser6Context::PARSER_DHCP6:
109
            return isc::dhcp::Dhcp6Parser::make_TOPLEVEL_DHCP6(driver.loc_);
110 111
        case Parser6Context::SUBPARSER_DHCP6:
            return isc::dhcp::Dhcp6Parser::make_SUB_DHCP6(driver.loc_);
112 113 114 115 116 117 118 119 120 121 122 123 124 125
        case Parser6Context::SUBPARSER_INTERFACES6:
            return isc::dhcp::Dhcp6Parser::make_SUB_INTERFACES6(driver.loc_);
        case Parser6Context::SUBPARSER_SUBNET6:
            return isc::dhcp::Dhcp6Parser::make_SUB_SUBNET6(driver.loc_);
        case Parser6Context::SUBPARSER_POOL6:
            return isc::dhcp::Dhcp6Parser::make_SUB_POOL6(driver.loc_);
        case Parser6Context::SUBPARSER_PD_POOL:
            return isc::dhcp::Dhcp6Parser::make_SUB_PD_POOL(driver.loc_);
        case Parser6Context::SUBPARSER_HOST_RESERVATION6:
            return isc::dhcp::Dhcp6Parser::make_SUB_RESERVATION(driver.loc_);
        case Parser6Context::SUBPARSER_OPTION_DATA:
            return isc::dhcp::Dhcp6Parser::make_SUB_OPTION_DATA(driver.loc_);
        case Parser6Context::SUBPARSER_HOOKS_LIBRARY:
            return isc::dhcp::Dhcp6Parser::make_SUB_HOOKS_LIBRARY(driver.loc_);
126 127
        case Parser6Context::SUBPARSER_JSON:
            return isc::dhcp::Dhcp6Parser::make_SUB_JSON(driver.loc_);
128 129
        }
    }
130 131
%}

Tomek Mrugalski's avatar
Tomek Mrugalski committed
132 133 134 135 136 137
#.* ;

"//"(.*) ;

"/*" {
  BEGIN(COMMENT);
138
  comment_start_line = driver.loc_.end.line;;
Tomek Mrugalski's avatar
Tomek Mrugalski committed
139 140 141
}

<COMMENT>"*/" BEGIN(INITIAL);
142
<COMMENT>. ;
Tomek Mrugalski's avatar
Tomek Mrugalski committed
143
<COMMENT><<EOF>> {
144
    isc_throw(Dhcp6ParseError, "Comment not closed. (/* in line " << comment_start_line);
Tomek Mrugalski's avatar
Tomek Mrugalski committed
145 146
}

Francis Dupont's avatar
Francis Dupont committed
147 148 149 150 151 152 153 154 155
"<?" BEGIN(DIR_ENTER);
<DIR_ENTER>"include" BEGIN(DIR_INCLUDE);
<DIR_INCLUDE>\"([^\"\n])+\" {
    // Include directive.

    // Extract the filename.
    std::string tmp(yytext+1);
    tmp.resize(tmp.size() - 1);

156
    driver.includeFile(tmp);
Francis Dupont's avatar
Francis Dupont committed
157
}
158
<DIR_ENTER,DIR_INCLUDE,DIR_EXIT><<EOF>> {
159
    isc_throw(Dhcp6ParseError, "Directive not closed.");
160
}
Francis Dupont's avatar
Francis Dupont committed
161 162 163
<DIR_EXIT>"?>" BEGIN(INITIAL);
    

164
<*>{blank}+   {
165
    // Ok, we found a with space. Let's ignore it and update loc variable.
166
    driver.loc_.step();
167
}
168

169
<*>[\n]+      {
170
    // Newline found. Let's update the location and continue.
171 172
    driver.loc_.lines(yyleng);
    driver.loc_.step();
173 174
}

175

176 177 178
\"Dhcp6\"  {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::CONFIG:
179
        return isc::dhcp::Dhcp6Parser::make_DHCP6(driver.loc_);
180
    default:
181
        return isc::dhcp::Dhcp6Parser::make_STRING("Dhcp6", driver.loc_);
182 183 184 185 186 187
    }
}

\"interfaces-config\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::DHCP6:
188
        return  isc::dhcp::Dhcp6Parser::make_INTERFACES_CONFIG(driver.loc_);
189
    default:
190
        return isc::dhcp::Dhcp6Parser::make_STRING("interfaces-config", driver.loc_);
191 192 193 194 195 196
    }
}

\"interfaces\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::INTERFACES_CONFIG:
197
        return  isc::dhcp::Dhcp6Parser::make_INTERFACES(driver.loc_);
198
    default:
199
        return isc::dhcp::Dhcp6Parser::make_STRING("interfaces", driver.loc_);
200 201 202 203 204 205
    }
}

\"lease-database\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::DHCP6:
206
        return isc::dhcp::Dhcp6Parser::make_LEASE_DATABASE(driver.loc_);
207
    default:
208
        return isc::dhcp::Dhcp6Parser::make_STRING("lease-database", driver.loc_);
209 210 211 212 213 214
    }
}

\"hosts-database\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::DHCP6:
215
        return isc::dhcp::Dhcp6Parser::make_HOSTS_DATABASE(driver.loc_);
216
    default:
217
        return isc::dhcp::Dhcp6Parser::make_STRING("hosts-database", driver.loc_);
218 219 220 221 222
    }
}

\"type\" {
    switch(driver.ctx_) {
223 224
    case isc::dhcp::Parser6Context::LEASE_DATABASE:
    case isc::dhcp::Parser6Context::HOSTS_DATABASE:
225
    case isc::dhcp::Parser6Context::OPTION_DEF:
226
    case isc::dhcp::Parser6Context::SERVER_ID:
227
        return isc::dhcp::Dhcp6Parser::make_TYPE(driver.loc_);
228
    default:
229
        return isc::dhcp::Dhcp6Parser::make_STRING("type", driver.loc_);
230 231 232 233 234
    }
}

\"user\" {
    switch(driver.ctx_) {
235 236
    case isc::dhcp::Parser6Context::LEASE_DATABASE:
    case isc::dhcp::Parser6Context::HOSTS_DATABASE:
237
        return isc::dhcp::Dhcp6Parser::make_USER(driver.loc_);
238
    default:
239
        return isc::dhcp::Dhcp6Parser::make_STRING("user", driver.loc_);
240 241 242 243 244
    }
}

\"password\" {
    switch(driver.ctx_) {
245 246
    case isc::dhcp::Parser6Context::LEASE_DATABASE:
    case isc::dhcp::Parser6Context::HOSTS_DATABASE:
247
        return isc::dhcp::Dhcp6Parser::make_PASSWORD(driver.loc_);
248
    default:
249
        return isc::dhcp::Dhcp6Parser::make_STRING("password", driver.loc_);
250 251 252 253 254
    }
}

\"host\" {
    switch(driver.ctx_) {
255 256
    case isc::dhcp::Parser6Context::LEASE_DATABASE:
    case isc::dhcp::Parser6Context::HOSTS_DATABASE:
257
        return isc::dhcp::Dhcp6Parser::make_HOST(driver.loc_);
258
    default:
259
        return isc::dhcp::Dhcp6Parser::make_STRING("host", driver.loc_);
260 261 262 263 264
    }
}

\"persist\" {
    switch(driver.ctx_) {
265 266
    case isc::dhcp::Parser6Context::LEASE_DATABASE:
    case isc::dhcp::Parser6Context::HOSTS_DATABASE:
267
    case isc::dhcp::Parser6Context::SERVER_ID:
268
        return isc::dhcp::Dhcp6Parser::make_PERSIST(driver.loc_);
269
    default:
270
        return isc::dhcp::Dhcp6Parser::make_STRING("persist", driver.loc_);
271 272 273 274 275
    }
}

\"lfc-interval\" {
    switch(driver.ctx_) {
276 277
    case isc::dhcp::Parser6Context::LEASE_DATABASE:
    case isc::dhcp::Parser6Context::HOSTS_DATABASE:
278
        return isc::dhcp::Dhcp6Parser::make_LFC_INTERVAL(driver.loc_);
279
    default:
280
        return isc::dhcp::Dhcp6Parser::make_STRING("lfc-interval", driver.loc_);
281 282 283 284 285 286
    }
}

\"preferred-lifetime\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::DHCP6:
287
    case isc::dhcp::Parser6Context::SUBNET6:
288
        return isc::dhcp::Dhcp6Parser::make_PREFERRED_LIFETIME(driver.loc_);
289
    default:
290
        return isc::dhcp::Dhcp6Parser::make_STRING("preferred-lifetime", driver.loc_);
291 292 293 294 295 296
    }
}

\"valid-lifetime\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::DHCP6:
297
    case isc::dhcp::Parser6Context::SUBNET6:
298
        return isc::dhcp::Dhcp6Parser::make_VALID_LIFETIME(driver.loc_);
299
    default:
300
        return isc::dhcp::Dhcp6Parser::make_STRING("valid-lifetime", driver.loc_);
301 302 303 304 305 306
    }
}

\"renew-timer\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::DHCP6:
307
    case isc::dhcp::Parser6Context::SUBNET6:
308
        return isc::dhcp::Dhcp6Parser::make_RENEW_TIMER(driver.loc_);
309
    default:
310
        return isc::dhcp::Dhcp6Parser::make_STRING("renew-timer", driver.loc_);
311 312 313 314 315 316
    }
}

\"rebind-timer\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::DHCP6:
317
    case isc::dhcp::Parser6Context::SUBNET6:
318
        return isc::dhcp::Dhcp6Parser::make_REBIND_TIMER(driver.loc_);
319
    default:
320
        return isc::dhcp::Dhcp6Parser::make_STRING("rebind-timer", driver.loc_);
321 322 323
    }
}

324 325 326 327 328 329 330 331 332
\"decline-probation-period\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::DHCP6:
        return isc::dhcp::Dhcp6Parser::make_DECLINE_PROBATION_PERIOD(driver.loc_);
    default:
        return isc::dhcp::Dhcp6Parser::make_STRING("decline-probation-period", driver.loc_);
    }
}

333 334 335
\"subnet6\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::DHCP6:
336
        return isc::dhcp::Dhcp6Parser::make_SUBNET6(driver.loc_);
337
    default:
338
        return isc::dhcp::Dhcp6Parser::make_STRING("subnet6", driver.loc_);
339 340 341
    }
}

342 343 344 345 346 347 348 349 350
\"option-def\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::DHCP6:
        return isc::dhcp::Dhcp6Parser::make_OPTION_DEF(driver.loc_);
    default:
        return isc::dhcp::Dhcp6Parser::make_STRING("option-def", driver.loc_);
    }
}

351 352 353 354 355 356 357 358 359
\"option-data\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::DHCP6:
    case isc::dhcp::Parser6Context::SUBNET6:
    case isc::dhcp::Parser6Context::POOLS:
    case isc::dhcp::Parser6Context::PD_POOLS:
    case isc::dhcp::Parser6Context::RESERVATIONS:
    case isc::dhcp::Parser6Context::CLIENT_CLASSES:
    case isc::dhcp::Parser6Context::CLIENT_CLASS:
360
        return isc::dhcp::Dhcp6Parser::make_OPTION_DATA(driver.loc_);
361
    default:
362
        return isc::dhcp::Dhcp6Parser::make_STRING("option-data", driver.loc_);
363 364 365 366 367
    }
}

\"name\" {
    switch(driver.ctx_) {
368 369
    case isc::dhcp::Parser6Context::LEASE_DATABASE:
    case isc::dhcp::Parser6Context::HOSTS_DATABASE:
370
    case isc::dhcp::Parser6Context::OPTION_DEF:
371 372 373 374
    case isc::dhcp::Parser6Context::OPTION_DATA:
    case isc::dhcp::Parser6Context::CLIENT_CLASSES:
    case isc::dhcp::Parser6Context::CLIENT_CLASS:
    case isc::dhcp::Parser6Context::LOGGERS:
375
        return isc::dhcp::Dhcp6Parser::make_NAME(driver.loc_);
376
    default:
377
        return isc::dhcp::Dhcp6Parser::make_STRING("name", driver.loc_);
378 379 380 381 382 383
    }
}

\"data\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::OPTION_DATA:
384
        return isc::dhcp::Dhcp6Parser::make_DATA(driver.loc_);
385
    default:
386
        return isc::dhcp::Dhcp6Parser::make_STRING("data", driver.loc_);
387 388 389 390 391 392
    }
}

\"pools\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::SUBNET6:
393
        return isc::dhcp::Dhcp6Parser::make_POOLS(driver.loc_);
394
    default:
395
        return isc::dhcp::Dhcp6Parser::make_STRING("pools", driver.loc_);
396 397 398 399 400 401
    }
}

\"pd-pools\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::SUBNET6:
402
        return isc::dhcp::Dhcp6Parser::make_PD_POOLS(driver.loc_);
403
    default:
404
        return isc::dhcp::Dhcp6Parser::make_STRING("pd-pools", driver.loc_);
405 406 407 408 409 410
    }
}

\"prefix\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::PD_POOLS:
411
        return isc::dhcp::Dhcp6Parser::make_PREFIX(driver.loc_);
412
    default:
413
        return isc::dhcp::Dhcp6Parser::make_STRING("prefix", driver.loc_);
414 415 416 417 418 419
    }
}

\"prefix-len\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::PD_POOLS:
420
        return isc::dhcp::Dhcp6Parser::make_PREFIX_LEN(driver.loc_);
421
    default:
422
        return isc::dhcp::Dhcp6Parser::make_STRING("prefix-len", driver.loc_);
423 424 425 426 427 428
    }
}

\"delegated-len\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::PD_POOLS:
429
        return isc::dhcp::Dhcp6Parser::make_DELEGATED_LEN(driver.loc_);
430
    default:
431
        return isc::dhcp::Dhcp6Parser::make_STRING("delegated-len", driver.loc_);
432 433 434 435 436 437
    }
}

\"pool\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::POOLS:
438
        return isc::dhcp::Dhcp6Parser::make_POOL(driver.loc_);
439
    default:
440
        return isc::dhcp::Dhcp6Parser::make_STRING("pool", driver.loc_);
441 442 443 444 445 446
    }
}

\"subnet\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::SUBNET6:
447
        return isc::dhcp::Dhcp6Parser::make_SUBNET(driver.loc_);
448
    default:
449
        return isc::dhcp::Dhcp6Parser::make_STRING("subnet", driver.loc_);
450 451 452 453 454 455
    }
}

\"interface\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::SUBNET6:
456
        return isc::dhcp::Dhcp6Parser::make_INTERFACE(driver.loc_);
457
    default:
458
        return isc::dhcp::Dhcp6Parser::make_STRING("interface", driver.loc_);
459 460 461
    }
}

462 463 464 465 466 467 468 469 470
\"interface-id\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::SUBNET6:
        return isc::dhcp::Dhcp6Parser::make_INTERFACE_ID(driver.loc_);
    default:
        return isc::dhcp::Dhcp6Parser::make_STRING("interface-id", driver.loc_);
    }
}

471 472 473
\"id\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::SUBNET6:
474
        return isc::dhcp::Dhcp6Parser::make_ID(driver.loc_);
475
    default:
476
        return isc::dhcp::Dhcp6Parser::make_STRING("id", driver.loc_);
477 478 479
    }
}

480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497
\"rapid-commit\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::SUBNET6:
        return isc::dhcp::Dhcp6Parser::make_RAPID_COMMIT(driver.loc_);
    default:
        return isc::dhcp::Dhcp6Parser::make_STRING("rapid-commit", driver.loc_);
    }
}

\"reservation-mode\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::SUBNET6:
        return isc::dhcp::Dhcp6Parser::make_RESERVATION_MODE(driver.loc_);
    default:
        return isc::dhcp::Dhcp6Parser::make_STRING("reservation-mode", driver.loc_);
    }
}

498 499
\"code\" {
    switch(driver.ctx_) {
500
    case isc::dhcp::Parser6Context::OPTION_DEF:
501
    case isc::dhcp::Parser6Context::OPTION_DATA:
502
        return isc::dhcp::Dhcp6Parser::make_CODE(driver.loc_);
503
    default:
504
        return isc::dhcp::Dhcp6Parser::make_STRING("code", driver.loc_);
505 506 507 508 509 510
    }
}

\"mac-sources\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::DHCP6:
511
        return isc::dhcp::Dhcp6Parser::make_MAC_SOURCES(driver.loc_);
512
    default:
513
        return isc::dhcp::Dhcp6Parser::make_STRING("mac-sources", driver.loc_);
514 515 516 517 518 519
    }
}

\"relay-supplied-options\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::DHCP6:
520
        return isc::dhcp::Dhcp6Parser::make_RELAY_SUPPLIED_OPTIONS(driver.loc_);
521
    default:
522
        return isc::dhcp::Dhcp6Parser::make_STRING("relay-supplied-options", driver.loc_);
523 524 525 526 527 528
    }
}

\"host-reservation-identifiers\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::DHCP6:
529
        return isc::dhcp::Dhcp6Parser::make_HOST_RESERVATION_IDENTIFIERS(driver.loc_);
530
    default:
531
        return isc::dhcp::Dhcp6Parser::make_STRING("host-reservation-identifiers", driver.loc_);
532 533 534 535 536 537
    }
}

\"Logging\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::CONFIG:
538
        return isc::dhcp::Dhcp6Parser::make_LOGGING(driver.loc_);
539
    default:
540
        return isc::dhcp::Dhcp6Parser::make_STRING("Logging", driver.loc_);
541 542 543 544 545 546
    }
}

\"loggers\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::LOGGING:
547
        return isc::dhcp::Dhcp6Parser::make_LOGGERS(driver.loc_);
548
    default:
549
        return isc::dhcp::Dhcp6Parser::make_STRING("loggers", driver.loc_);
550 551 552 553 554 555
    }
}

\"output_options\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::LOGGERS:
556
        return isc::dhcp::Dhcp6Parser::make_OUTPUT_OPTIONS(driver.loc_);
557
    default:
558
        return isc::dhcp::Dhcp6Parser::make_STRING("output_options", driver.loc_);
559 560 561 562 563 564
    }
}

\"output\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::OUTPUT_OPTIONS:
565
        return isc::dhcp::Dhcp6Parser::make_OUTPUT(driver.loc_);
566
    default:
567
        return isc::dhcp::Dhcp6Parser::make_STRING("output", driver.loc_);
568 569 570 571 572 573
    }
}

\"debuglevel\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::LOGGERS:
574
        return isc::dhcp::Dhcp6Parser::make_DEBUGLEVEL(driver.loc_);
575
    default:
576
        return isc::dhcp::Dhcp6Parser::make_STRING("debuglevel", driver.loc_);
577 578 579 580 581 582
    }
}

\"severity\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::LOGGERS:
583
        return isc::dhcp::Dhcp6Parser::make_SEVERITY(driver.loc_);
584
    default:
585
        return isc::dhcp::Dhcp6Parser::make_STRING("severity", driver.loc_);
586 587 588 589 590 591 592
    }
}

\"client-classes\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::DHCP6:
    case isc::dhcp::Parser6Context::RESERVATIONS:
593
        return isc::dhcp::Dhcp6Parser::make_CLIENT_CLASSES(driver.loc_);
594
    default:
595
        return isc::dhcp::Dhcp6Parser::make_STRING("client-classes", driver.loc_);
596 597 598 599 600 601 602
    }
}

\"client-class\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::SUBNET6:
    case isc::dhcp::Parser6Context::CLIENT_CLASSES:
603
        return isc::dhcp::Dhcp6Parser::make_CLIENT_CLASS(driver.loc_);
604
    default:
605
        return isc::dhcp::Dhcp6Parser::make_STRING("client-class", driver.loc_);
606 607 608 609 610 611 612
    }
}

\"test\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::CLIENT_CLASSES:
    case isc::dhcp::Parser6Context::CLIENT_CLASS:
613
        return isc::dhcp::Dhcp6Parser::make_TEST(driver.loc_);
614
    default:
615
        return isc::dhcp::Dhcp6Parser::make_STRING("test", driver.loc_);
616 617 618 619 620 621
    }
}

\"reservations\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::SUBNET6:
622
        return isc::dhcp::Dhcp6Parser::make_RESERVATIONS(driver.loc_);
623
    default:
624
        return isc::dhcp::Dhcp6Parser::make_STRING("reservations", driver.loc_);
625 626 627 628 629 630
    }
}

\"ip-addresses\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::RESERVATIONS:
631
        return isc::dhcp::Dhcp6Parser::make_IP_ADDRESSES(driver.loc_);
632
    default:
633
        return isc::dhcp::Dhcp6Parser::make_STRING("ip-addresses", driver.loc_);
634 635 636 637 638 639
    }
}

\"prefixes\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::RESERVATIONS:
640
        return isc::dhcp::Dhcp6Parser::make_PREFIXES(driver.loc_);
641
    default:
642
        return isc::dhcp::Dhcp6Parser::make_STRING("prefixes", driver.loc_);
643 644 645 646 647 648 649 650
    }
}

\"duid\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::MAC_SOURCES:
    case isc::dhcp::Parser6Context::HOST_RESERVATION_IDENTIFIERS:
    case isc::dhcp::Parser6Context::RESERVATIONS:
651
        return isc::dhcp::Dhcp6Parser::make_DUID(driver.loc_);
652
    default:
653
        return isc::dhcp::Dhcp6Parser::make_STRING("duid", driver.loc_);
654 655 656 657 658 659 660
    }
}

\"hw-address\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::HOST_RESERVATION_IDENTIFIERS:
    case isc::dhcp::Parser6Context::RESERVATIONS:
661
        return isc::dhcp::Dhcp6Parser::make_HW_ADDRESS(driver.loc_);
662
    default:
663
        return isc::dhcp::Dhcp6Parser::make_STRING("hw-address", driver.loc_);
664 665 666 667 668 669
    }
}

\"hostname\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::RESERVATIONS:
670
        return isc::dhcp::Dhcp6Parser::make_HOSTNAME(driver.loc_);
671
    default:
672
        return isc::dhcp::Dhcp6Parser::make_STRING("hostname", driver.loc_);
673 674 675 676 677
    }
}

\"space\" {
    switch(driver.ctx_) {
678
    case isc::dhcp::Parser6Context::OPTION_DEF:
679
    case isc::dhcp::Parser6Context::OPTION_DATA:
680
        return isc::dhcp::Dhcp6Parser::make_SPACE(driver.loc_);
681
    default:
682
        return isc::dhcp::Dhcp6Parser::make_STRING("space", driver.loc_);
683 684 685 686 687 688
    }
}

\"csv-format\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::OPTION_DATA:
689
        return isc::dhcp::Dhcp6Parser::make_CSV_FORMAT(driver.loc_);
690
    default:
691
        return isc::dhcp::Dhcp6Parser::make_STRING("csv-format", driver.loc_);
692 693 694
    }
}

695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739
\"record-types\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::OPTION_DEF:
        return isc::dhcp::Dhcp6Parser::make_RECORD_TYPES(driver.loc_);
    default:
        return isc::dhcp::Dhcp6Parser::make_STRING("record-types", driver.loc_);
    }
}

\"encapsulate\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::OPTION_DEF:
        return isc::dhcp::Dhcp6Parser::make_ENCAPSULATE(driver.loc_);
    default:
        return isc::dhcp::Dhcp6Parser::make_STRING("encapsulate", driver.loc_);
    }
}

\"array\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::OPTION_DEF:
        return isc::dhcp::Dhcp6Parser::make_ARRAY(driver.loc_);
    default:
        return isc::dhcp::Dhcp6Parser::make_STRING("array", driver.loc_);
    }
}

\"relay\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::SUBNET6:
        return isc::dhcp::Dhcp6Parser::make_RELAY(driver.loc_);
    default:
        return isc::dhcp::Dhcp6Parser::make_STRING("relay", driver.loc_);
    }
}

\"ip-address\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::RELAY:
    return isc::dhcp::Dhcp6Parser::make_IP_ADDRESS(driver.loc_);
    default:
        return isc::dhcp::Dhcp6Parser::make_STRING("ip-address", driver.loc_);
    }
}

740 741 742
\"hooks-libraries\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::DHCP6:
743
        return isc::dhcp::Dhcp6Parser::make_HOOKS_LIBRARIES(driver.loc_);
744
    default:
745
        return isc::dhcp::Dhcp6Parser::make_STRING("hooks-libraries", driver.loc_);
746 747 748 749 750 751
    }
}

\"library\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::HOOKS_LIBRARIES:
752
        return isc::dhcp::Dhcp6Parser::make_LIBRARY(driver.loc_);
753
    default:
754
        return isc::dhcp::Dhcp6Parser::make_STRING("library", driver.loc_);
755 756 757 758 759 760
    }
}

\"server-id\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::DHCP6:
761
        return isc::dhcp::Dhcp6Parser::make_SERVER_ID(driver.loc_);
762
    default:
763
        return isc::dhcp::Dhcp6Parser::make_STRING("server-id", driver.loc_);
764 765 766 767 768 769
    }
}

\"identifier\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::SERVER_ID:
770
        return isc::dhcp::Dhcp6Parser::make_IDENTIFIER(driver.loc_);
771
    default:
772
        return isc::dhcp::Dhcp6Parser::make_STRING("identifier", driver.loc_);
773 774 775 776 777 778
    }
}

\"htype\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::SERVER_ID:
779
        return isc::dhcp::Dhcp6Parser::make_HTYPE(driver.loc_);
780
    default:
781
        return isc::dhcp::Dhcp6Parser::make_STRING("htype", driver.loc_);
782 783 784 785 786 787
    }
}

\"time\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::SERVER_ID:
788
        return isc::dhcp::Dhcp6Parser::make_TIME(driver.loc_);
789
    default:
790
        return isc::dhcp::Dhcp6Parser::make_STRING("time", driver.loc_);
791 792 793 794 795 796
    }
}

\"enterprise-id\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::SERVER_ID:
797
        return isc::dhcp::Dhcp6Parser::make_ENTERPRISE_ID(driver.loc_);
798
    default:
799
        return isc::dhcp::Dhcp6Parser::make_STRING("enterprise-id", driver.loc_);
800 801 802 803 804 805
    }
}

\"expired-leases-processing\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::DHCP6:
806
        return isc::dhcp::Dhcp6Parser::make_EXPIRED_LEASES_PROCESSING(driver.loc_);
807
    default:
808
        return isc::dhcp::Dhcp6Parser::make_STRING("expired-leases-processing", driver.loc_);
809 810 811 812 813 814
    }
}

\"dhcp4o6-port\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::DHCP6:
815
        return isc::dhcp::Dhcp6Parser::make_DHCP4O6_PORT(driver.loc_);
816
    default:
817
        return isc::dhcp::Dhcp6Parser::make_STRING("dhcp4o6-port", driver.loc_);
818 819 820
    }
}

821
\"version\" {
822 823
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::DHCP6:
824
        return isc::dhcp::Dhcp6Parser::make_VERSION(driver.loc_);
825
    default:
826 827 828 829 830 831 832 833 834 835
        return isc::dhcp::Dhcp6Parser::make_STRING("version", driver.loc_);
    }
}

\"control-socket\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::DHCP6:
        return isc::dhcp::Dhcp6Parser::make_CONTROL_SOCKET(driver.loc_);
    default:
        return isc::dhcp::Dhcp6Parser::make_STRING("control-socket", driver.loc_);
836 837 838
    }
}

839
\"socket-type\" {
840
    switch(driver.ctx_) {
841 842
    case isc::dhcp::Parser6Context::CONTROL_SOCKET:
        return isc::dhcp::Dhcp6Parser::make_SOCKET_TYPE(driver.loc_);
843
    default:
844
        return isc::dhcp::Dhcp6Parser::make_STRING("socket-type", driver.loc_);
845 846 847
    }
}

848
\"socket-name\" {
849
    switch(driver.ctx_) {
850 851
    case isc::dhcp::Parser6Context::CONTROL_SOCKET:
        return isc::dhcp::Dhcp6Parser::make_SOCKET_NAME(driver.loc_);
852
    default:
853 854 855 856 857 858 859 860 861 862
        return isc::dhcp::Dhcp6Parser::make_STRING("socket-name", driver.loc_);
    }
}

\"dhcp-ddns\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::DHCP6:
        return isc::dhcp::Dhcp6Parser::make_DHCP_DDNS(driver.loc_);
    default:
        return isc::dhcp::Dhcp6Parser::make_STRING("dhcp-ddns", driver.loc_);
863 864
    }
}
865

866 867 868
\"Dhcp4\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::CONFIG:
869
        return isc::dhcp::Dhcp6Parser::make_DHCP4(driver.loc_);
870
    default:
871
        return isc::dhcp::Dhcp6Parser::make_STRING("Dhcp4", driver.loc_);
872 873 874 875 876 877
    }
}

\"DhcpDdns\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::CONFIG:
878
        return isc::dhcp::Dhcp6Parser::make_DHCPDDNS(driver.loc_);
879
    default:
880
        return isc::dhcp::Dhcp6Parser::make_STRING("DhcpDdns", driver.loc_);
881 882
    }
}
883

884 885 886 887
{JSONString} {
    // A string has been matched. It contains the actual string and single quotes.
    // We need to get those quotes out of the way and just use its content, e.g.
    // for 'foo' we should get foo
888 889 890 891 892 893 894 895 896 897
    std::string raw(yytext+1);
    size_t len = raw.size() - 1;
    raw.resize(len);
    std::string decoded;
    decoded.reserve(len);
    for (size_t pos = 0; pos < len; ++pos) {
        char c = raw[pos];
        switch (c) {
        case '"':
            // impossible condition
898
            driver.error(driver.loc_, "Bad quote in \"" + raw + "\"");
899 900 901 902
        case '\\':
            ++pos;
            if (pos >= len) {
                // impossible condition
903
                driver.error(driver.loc_, "Overflow escape in \"" + raw + "\"");
904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928
            }
            c = raw[pos];
            switch (c) {
            case '"':
            case '\\':
            case '/':
                decoded.push_back(c);
                break;
            case 'b':
                decoded.push_back('\b');
                break;
            case 'f':
                decoded.push_back('\f');
                break;
            case 'n':
                decoded.push_back('\n');
                break;
            case 'r':
                decoded.push_back('\r');
                break;
            case 't':
                decoded.push_back('\t');
                break;
            case 'u':
                // not yet implemented
929
                driver.error(driver.loc_, "Unsupported unicode escape in \"" + raw + "\"");
930 931
            default:
                // impossible condition
932
                driver.error(driver.loc_, "Bad escape in \"" + raw + "\"");
933 934 935 936 937
            }
            break;
        default:
            if (c < 0x20) {
                // impossible condition
938
                driver.error(driver.loc_, "Invalid control in \"" + raw + "\"");
939 940 941 942
            }
            decoded.push_back(c);
        }
    }
943

944
    return isc::dhcp::Dhcp6Parser::make_STRING(decoded, driver.loc_);
945 946 947 948
}

\"{JSONStringCharacter}*{ControlCharacter}{ControlCharacterFill}*\" {
    // Bad string with a forbidden control character inside
949
    driver.error(driver.loc_, "Invalid control in " + std::string(yytext));
950 951 952 953
}

\"{JSONStringCharacter}*\\{BadJSONEscapeSequence}[^\x00-\x1f"]*\" {
    // Bad string with a bad escape inside
954
    driver.error(driver.loc_, "Bad escape in " + std::string(yytext));
955 956 957 958
}
    
\"{JSONStringCharacter}*\\\" {
    // Bad string with an open escape at the end
959
    driver.error(driver.loc_, "Overflow escape in " + std::string(yytext));
960 961
}

962 963 964 965 966 967
"["    { return isc::dhcp::Dhcp6Parser::make_LSQUARE_BRACKET(driver.loc_); }
"]"    { return isc::dhcp::Dhcp6Parser::make_RSQUARE_BRACKET(driver.loc_); }
"{"    { return isc::dhcp::Dhcp6Parser::make_LCURLY_BRACKET(driver.loc_); }
"}"    { return isc::dhcp::Dhcp6Parser::make_RCURLY_BRACKET(driver.loc_); }
","    { return isc::dhcp::Dhcp6Parser::make_COMMA(driver.loc_); }
":"    { return isc::dhcp::Dhcp6Parser::make_COLON(driver.loc_); }
968 969 970 971 972 973 974 975 976 977 978 979

{int} {
    // An integer was found.
    std::string tmp(yytext);
    int64_t integer = 0;
    try {
        // In substring we want to use negative values (e.g. -1).
        // In enterprise-id we need to use values up to 0xffffffff.
        // To cover both of those use cases, we need at least
        // int64_t.
        integer = boost::lexical_cast<int64_t>(tmp);
    } catch (const boost::bad_lexical_cast &) {
980
        driver.error(driver.loc_, "Failed to convert " + tmp + " to an integer.");
981 982 983
    }

    // The parser needs the string form as double conversion is no lossless
984
    return isc::dhcp::Dhcp6Parser::make_INTEGER(integer, driver.loc_);
985
}
986

987 988 989 990 991 992 993
[-+]?[0-9]*\.?[0-9]*([eE][-+]?[0-9]+)? {
    // A floating point was found.
    std::string tmp(yytext);
    double fp = 0.0;
    try {
        fp = boost::lexical_cast<double>(tmp);
    } catch (const boost::bad_lexical_cast &) {
994
        driver.error(driver.loc_, "Failed to convert " + tmp + " to a floating point.");
995 996
    }

997
    return isc::dhcp::Dhcp6Parser::make_FLOAT(fp, driver.loc_);
998 999 1000 1001
}

true|false {
    string tmp(yytext);
1002
    return isc::dhcp::Dhcp6Parser::make_BOOLEAN(tmp == "true", driver.loc_);
1003 1004 1005
}

null {
1006
   return isc::dhcp::Dhcp6Parser::make_NULL_TYPE(driver.loc_);
1007 1008
}

1009
<*>.   driver.error (driver.loc_, "Invalid character: " + std::string(yytext));
1010

1011
<<EOF>> {
1012 1013
    if (driver.states_.empty()) {
        return isc::dhcp::Dhcp6Parser::make_END(driver.loc_);
Francis Dupont's avatar
Francis Dupont committed
1014
    }
1015 1016 1017 1018
    driver.loc_ = driver.locs_.back();
    driver.locs_.pop_back();
    driver.file_ = driver.files_.back();
    driver.files_.pop_back();
1019 1020 1021 1022 1023 1024 1025 1026
    if (driver.sfile_) {
        fclose(driver.sfile_);
        driver.sfile_ = 0;
    }
    if (!driver.sfiles_.empty()) {
        driver.sfile_ = driver.sfiles_.back();
        driver.sfiles_.pop_back();
    }
Francis Dupont's avatar
Francis Dupont committed
1027
    parser6__delete_buffer(YY_CURRENT_BUFFER);
1028 1029
    parser6__switch_to_buffer(driver.states_.back());
    driver.states_.pop_back();
Francis Dupont's avatar
Francis Dupont committed
1030 1031 1032 1033

    BEGIN(DIR_EXIT);
}

1034 1035 1036 1037 1038
%%

using namespace isc::dhcp;

void
1039
Parser6Context::scanStringBegin(const std::string& str, ParserType parser_type)
1040
{
1041 1042 1043
    start_token_flag = true;
    start_token_value = parser_type;

1044
    file_ = "<string>";
1045
    sfile_ = 0;
1046
    loc_.initialize(&file_);
1047 1048
    yy_flex_debug = trace_scanning_;
    YY_BUFFER_STATE buffer;
1049
    buffer = yy_scan_bytes(str.c_str(), str.size());
1050 1051 1052 1053 1054 1055
    if (!buffer) {
        fatal("cannot scan string");
        // fatal() throws an exception so this can't be reached
    }
}

1056
void