dhcp6_lexer.ll 30 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 112 113 114 115 116 117 118 119 120 121 122 123
        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_);
124 125
        case Parser6Context::SUBPARSER_JSON:
            return isc::dhcp::Dhcp6Parser::make_SUB_JSON(driver.loc_);
126 127
        }
    }
128 129
%}

Tomek Mrugalski's avatar
Tomek Mrugalski committed
130 131 132 133 134 135
#.* ;

"//"(.*) ;

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

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

Francis Dupont's avatar
Francis Dupont committed
145 146 147 148 149 150 151 152 153
"<?" 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);

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

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

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

173

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

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

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

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

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

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

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

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

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

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

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

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

\"valid-lifetime\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::DHCP6:
293
        return isc::dhcp::Dhcp6Parser::make_VALID_LIFETIME(driver.loc_);
294
    default:
295
        return isc::dhcp::Dhcp6Parser::make_STRING("valid-lifetime", driver.loc_);
296 297 298 299 300 301
    }
}

\"renew-timer\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::DHCP6:
302
        return isc::dhcp::Dhcp6Parser::make_RENEW_TIMER(driver.loc_);
303
    default:
304
        return isc::dhcp::Dhcp6Parser::make_STRING("renew-timer", driver.loc_);
305 306 307 308 309 310
    }
}

\"rebind-timer\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::DHCP6:
311
        return isc::dhcp::Dhcp6Parser::make_REBIND_TIMER(driver.loc_);
312
    default:
313
        return isc::dhcp::Dhcp6Parser::make_STRING("rebind-timer", driver.loc_);
314 315 316 317 318 319
    }
}

\"subnet6\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::DHCP6:
320
        return isc::dhcp::Dhcp6Parser::make_SUBNET6(driver.loc_);
321
    default:
322
        return isc::dhcp::Dhcp6Parser::make_STRING("subnet6", driver.loc_);
323 324 325 326 327 328 329 330 331 332 333 334
    }
}

\"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:
335
        return isc::dhcp::Dhcp6Parser::make_OPTION_DATA(driver.loc_);
336
    default:
337
        return isc::dhcp::Dhcp6Parser::make_STRING("option-data", driver.loc_);
338 339 340 341 342
    }
}

\"name\" {
    switch(driver.ctx_) {
343 344
    case isc::dhcp::Parser6Context::LEASE_DATABASE:
    case isc::dhcp::Parser6Context::HOSTS_DATABASE:
345 346 347 348
    case isc::dhcp::Parser6Context::OPTION_DATA:
    case isc::dhcp::Parser6Context::CLIENT_CLASSES:
    case isc::dhcp::Parser6Context::CLIENT_CLASS:
    case isc::dhcp::Parser6Context::LOGGERS:
349
        return isc::dhcp::Dhcp6Parser::make_NAME(driver.loc_);
350
    default:
351
        return isc::dhcp::Dhcp6Parser::make_STRING("name", driver.loc_);
352 353 354 355 356 357
    }
}

\"data\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::OPTION_DATA:
358
        return isc::dhcp::Dhcp6Parser::make_DATA(driver.loc_);
359
    default:
360
        return isc::dhcp::Dhcp6Parser::make_STRING("data", driver.loc_);
361 362 363 364 365 366
    }
}

\"pools\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::SUBNET6:
367
        return isc::dhcp::Dhcp6Parser::make_POOLS(driver.loc_);
368
    default:
369
        return isc::dhcp::Dhcp6Parser::make_STRING("pools", driver.loc_);
370 371 372 373 374 375
    }
}

\"pd-pools\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::SUBNET6:
376
        return isc::dhcp::Dhcp6Parser::make_PD_POOLS(driver.loc_);
377
    default:
378
        return isc::dhcp::Dhcp6Parser::make_STRING("pd-pools", driver.loc_);
379 380 381 382 383 384
    }
}

\"prefix\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::PD_POOLS:
385
        return isc::dhcp::Dhcp6Parser::make_PREFIX(driver.loc_);
386
    default:
387
        return isc::dhcp::Dhcp6Parser::make_STRING("prefix", driver.loc_);
388 389 390 391 392 393
    }
}

\"prefix-len\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::PD_POOLS:
394
        return isc::dhcp::Dhcp6Parser::make_PREFIX_LEN(driver.loc_);
395
    default:
396
        return isc::dhcp::Dhcp6Parser::make_STRING("prefix-len", driver.loc_);
397 398 399 400 401 402
    }
}

\"delegated-len\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::PD_POOLS:
403
        return isc::dhcp::Dhcp6Parser::make_DELEGATED_LEN(driver.loc_);
404
    default:
405
        return isc::dhcp::Dhcp6Parser::make_STRING("delegated-len", driver.loc_);
406 407 408 409 410 411
    }
}

\"pool\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::POOLS:
412
        return isc::dhcp::Dhcp6Parser::make_POOL(driver.loc_);
413
    default:
414
        return isc::dhcp::Dhcp6Parser::make_STRING("pool", driver.loc_);
415 416 417 418 419 420
    }
}

\"subnet\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::SUBNET6:
421
        return isc::dhcp::Dhcp6Parser::make_SUBNET(driver.loc_);
422
    default:
423
        return isc::dhcp::Dhcp6Parser::make_STRING("subnet", driver.loc_);
424 425 426 427 428 429
    }
}

\"interface\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::SUBNET6:
430
        return isc::dhcp::Dhcp6Parser::make_INTERFACE(driver.loc_);
431
    default:
432
        return isc::dhcp::Dhcp6Parser::make_STRING("interface", driver.loc_);
433 434 435 436 437 438
    }
}

\"id\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::SUBNET6:
439
        return isc::dhcp::Dhcp6Parser::make_ID(driver.loc_);
440
    default:
441
        return isc::dhcp::Dhcp6Parser::make_STRING("id", driver.loc_);
442 443 444 445 446 447
    }
}

\"code\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::OPTION_DATA:
448
        return isc::dhcp::Dhcp6Parser::make_CODE(driver.loc_);
449
    default:
450
        return isc::dhcp::Dhcp6Parser::make_STRING("code", driver.loc_);
451 452 453 454 455 456
    }
}

\"mac-sources\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::DHCP6:
457
        return isc::dhcp::Dhcp6Parser::make_MAC_SOURCES(driver.loc_);
458
    default:
459
        return isc::dhcp::Dhcp6Parser::make_STRING("mac-sources", driver.loc_);
460 461 462 463 464 465
    }
}

\"relay-supplied-options\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::DHCP6:
466
        return isc::dhcp::Dhcp6Parser::make_RELAY_SUPPLIED_OPTIONS(driver.loc_);
467
    default:
468
        return isc::dhcp::Dhcp6Parser::make_STRING("relay-supplied-options", driver.loc_);
469 470 471 472 473 474
    }
}

\"host-reservation-identifiers\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::DHCP6:
475
        return isc::dhcp::Dhcp6Parser::make_HOST_RESERVATION_IDENTIFIERS(driver.loc_);
476
    default:
477
        return isc::dhcp::Dhcp6Parser::make_STRING("host-reservation-identifiers", driver.loc_);
478 479 480 481 482 483
    }
}

\"Logging\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::CONFIG:
484
        return isc::dhcp::Dhcp6Parser::make_LOGGING(driver.loc_);
485
    default:
486
        return isc::dhcp::Dhcp6Parser::make_STRING("Logging", driver.loc_);
487 488 489 490 491 492
    }
}

\"loggers\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::LOGGING:
493
        return isc::dhcp::Dhcp6Parser::make_LOGGERS(driver.loc_);
494
    default:
495
        return isc::dhcp::Dhcp6Parser::make_STRING("loggers", driver.loc_);
496 497 498 499 500 501
    }
}

\"output_options\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::LOGGERS:
502
        return isc::dhcp::Dhcp6Parser::make_OUTPUT_OPTIONS(driver.loc_);
503
    default:
504
        return isc::dhcp::Dhcp6Parser::make_STRING("output_options", driver.loc_);
505 506 507 508 509 510
    }
}

\"output\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::OUTPUT_OPTIONS:
511
        return isc::dhcp::Dhcp6Parser::make_OUTPUT(driver.loc_);
512
    default:
513
        return isc::dhcp::Dhcp6Parser::make_STRING("output", driver.loc_);
514 515 516 517 518 519
    }
}

\"debuglevel\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::LOGGERS:
520
        return isc::dhcp::Dhcp6Parser::make_DEBUGLEVEL(driver.loc_);
521
    default:
522
        return isc::dhcp::Dhcp6Parser::make_STRING("debuglevel", driver.loc_);
523 524 525 526 527 528
    }
}

\"severity\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::LOGGERS:
529
        return isc::dhcp::Dhcp6Parser::make_SEVERITY(driver.loc_);
530
    default:
531
        return isc::dhcp::Dhcp6Parser::make_STRING("severity", driver.loc_);
532 533 534 535 536 537 538
    }
}

\"client-classes\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::DHCP6:
    case isc::dhcp::Parser6Context::RESERVATIONS:
539
        return isc::dhcp::Dhcp6Parser::make_CLIENT_CLASSES(driver.loc_);
540
    default:
541
        return isc::dhcp::Dhcp6Parser::make_STRING("client-classes", driver.loc_);
542 543 544 545 546 547 548
    }
}

\"client-class\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::SUBNET6:
    case isc::dhcp::Parser6Context::CLIENT_CLASSES:
549
        return isc::dhcp::Dhcp6Parser::make_CLIENT_CLASS(driver.loc_);
550
    default:
551
        return isc::dhcp::Dhcp6Parser::make_STRING("client-class", driver.loc_);
552 553 554 555 556 557 558
    }
}

\"test\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::CLIENT_CLASSES:
    case isc::dhcp::Parser6Context::CLIENT_CLASS:
559
        return isc::dhcp::Dhcp6Parser::make_TEST(driver.loc_);
560
    default:
561
        return isc::dhcp::Dhcp6Parser::make_STRING("test", driver.loc_);
562 563 564 565 566 567
    }
}

\"reservations\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::SUBNET6:
568
        return isc::dhcp::Dhcp6Parser::make_RESERVATIONS(driver.loc_);
569
    default:
570
        return isc::dhcp::Dhcp6Parser::make_STRING("reservations", driver.loc_);
571 572 573 574 575 576
    }
}

\"ip-addresses\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::RESERVATIONS:
577
        return isc::dhcp::Dhcp6Parser::make_IP_ADDRESSES(driver.loc_);
578
    default:
579
        return isc::dhcp::Dhcp6Parser::make_STRING("ip-addresses", driver.loc_);
580 581 582 583 584 585
    }
}

\"prefixes\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::RESERVATIONS:
586
        return isc::dhcp::Dhcp6Parser::make_PREFIXES(driver.loc_);
587
    default:
588
        return isc::dhcp::Dhcp6Parser::make_STRING("prefixes", driver.loc_);
589 590 591 592 593 594 595 596
    }
}

\"duid\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::MAC_SOURCES:
    case isc::dhcp::Parser6Context::HOST_RESERVATION_IDENTIFIERS:
    case isc::dhcp::Parser6Context::RESERVATIONS:
597
        return isc::dhcp::Dhcp6Parser::make_DUID(driver.loc_);
598
    default:
599
        return isc::dhcp::Dhcp6Parser::make_STRING("duid", driver.loc_);
600 601 602 603 604 605 606
    }
}

\"hw-address\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::HOST_RESERVATION_IDENTIFIERS:
    case isc::dhcp::Parser6Context::RESERVATIONS:
607
        return isc::dhcp::Dhcp6Parser::make_HW_ADDRESS(driver.loc_);
608
    default:
609
        return isc::dhcp::Dhcp6Parser::make_STRING("hw-address", driver.loc_);
610 611 612 613 614 615
    }
}

\"hostname\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::RESERVATIONS:
616
        return isc::dhcp::Dhcp6Parser::make_HOSTNAME(driver.loc_);
617
    default:
618
        return isc::dhcp::Dhcp6Parser::make_STRING("hostname", driver.loc_);
619 620 621 622 623 624
    }
}

\"space\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::OPTION_DATA:
625
        return isc::dhcp::Dhcp6Parser::make_SPACE(driver.loc_);
626
    default:
627
        return isc::dhcp::Dhcp6Parser::make_STRING("space", driver.loc_);
628 629 630 631 632 633
    }
}

\"csv-format\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::OPTION_DATA:
634
        return isc::dhcp::Dhcp6Parser::make_CSV_FORMAT(driver.loc_);
635
    default:
636
        return isc::dhcp::Dhcp6Parser::make_STRING("csv-format", driver.loc_);
637 638 639 640 641 642
    }
}

\"hooks-libraries\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::DHCP6:
643
        return isc::dhcp::Dhcp6Parser::make_HOOKS_LIBRARIES(driver.loc_);
644
    default:
645
        return isc::dhcp::Dhcp6Parser::make_STRING("hooks-libraries", driver.loc_);
646 647 648 649 650 651
    }
}

\"library\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::HOOKS_LIBRARIES:
652
        return isc::dhcp::Dhcp6Parser::make_LIBRARY(driver.loc_);
653
    default:
654
        return isc::dhcp::Dhcp6Parser::make_STRING("library", driver.loc_);
655 656 657 658 659 660
    }
}

\"server-id\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::DHCP6:
661
        return isc::dhcp::Dhcp6Parser::make_SERVER_ID(driver.loc_);
662
    default:
663
        return isc::dhcp::Dhcp6Parser::make_STRING("server-id", driver.loc_);
664 665 666 667 668 669
    }
}

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

\"htype\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::SERVER_ID:
679
        return isc::dhcp::Dhcp6Parser::make_HTYPE(driver.loc_);
680
    default:
681
        return isc::dhcp::Dhcp6Parser::make_STRING("htype", driver.loc_);
682 683 684 685 686 687
    }
}

\"time\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::SERVER_ID:
688
        return isc::dhcp::Dhcp6Parser::make_TIME(driver.loc_);
689
    default:
690
        return isc::dhcp::Dhcp6Parser::make_STRING("time", driver.loc_);
691 692 693 694 695 696
    }
}

\"enterprise-id\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::SERVER_ID:
697
        return isc::dhcp::Dhcp6Parser::make_ENTERPRISE_ID(driver.loc_);
698
    default:
699
        return isc::dhcp::Dhcp6Parser::make_STRING("enterprise-id", driver.loc_);
700 701 702 703 704 705
    }
}

\"expired-leases-processing\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::DHCP6:
706
        return isc::dhcp::Dhcp6Parser::make_EXPIRED_LEASES_PROCESSING(driver.loc_);
707
    default:
708
        return isc::dhcp::Dhcp6Parser::make_STRING("expired-leases-processing", driver.loc_);
709 710 711 712 713 714
    }
}

\"dhcp4o6-port\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::DHCP6:
715
        return isc::dhcp::Dhcp6Parser::make_DHCP4O6_PORT(driver.loc_);
716
    default:
717
        return isc::dhcp::Dhcp6Parser::make_STRING("dhcp4o6-port", driver.loc_);
718 719 720 721 722 723
    }
}

\"dhcp-ddns\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::DHCP6:
724
        return isc::dhcp::Dhcp6Parser::make_DHCP_DDNS(driver.loc_);
725
    default:
726
        return isc::dhcp::Dhcp6Parser::make_STRING("dhcp-ddns", driver.loc_);
727 728 729 730 731 732
    }
}

\"enable-updates\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::DHCP_DDNS:
733
        return isc::dhcp::Dhcp6Parser::make_ENABLE_UPDATES(driver.loc_);
734
    default:
735
        return isc::dhcp::Dhcp6Parser::make_STRING("enable-updates", driver.loc_);
736 737 738 739 740 741
    }
}

\"qualifying-suffix\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::DHCP_DDNS:
742
        return isc::dhcp::Dhcp6Parser::make_QUALIFYING_SUFFIX(driver.loc_);
743
    default:
744
        return isc::dhcp::Dhcp6Parser::make_STRING("qualifying-suffix", driver.loc_);
745 746
    }
}
747

748 749 750
\"Dhcp4\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::CONFIG:
751
        return isc::dhcp::Dhcp6Parser::make_DHCP4(driver.loc_);
752
    default:
753
        return isc::dhcp::Dhcp6Parser::make_STRING("Dhcp4", driver.loc_);
754 755 756 757 758 759
    }
}

\"DhcpDdns\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::CONFIG:
760
        return isc::dhcp::Dhcp6Parser::make_DHCPDDNS(driver.loc_);
761
    default:
762
        return isc::dhcp::Dhcp6Parser::make_STRING("DhcpDdns", driver.loc_);
763 764
    }
}
765

766 767 768 769
{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
770 771 772 773 774 775 776 777 778 779
    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
780
            driver.error(driver.loc_, "Bad quote in \"" + raw + "\"");
781 782 783 784
        case '\\':
            ++pos;
            if (pos >= len) {
                // impossible condition
785
                driver.error(driver.loc_, "Overflow escape in \"" + raw + "\"");
786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810
            }
            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
811
                driver.error(driver.loc_, "Unsupported unicode escape in \"" + raw + "\"");
812 813
            default:
                // impossible condition
814
                driver.error(driver.loc_, "Bad escape in \"" + raw + "\"");
815 816 817 818 819
            }
            break;
        default:
            if (c < 0x20) {
                // impossible condition
820
                driver.error(driver.loc_, "Invalid control in \"" + raw + "\"");
821 822 823 824
            }
            decoded.push_back(c);
        }
    }
825

826
    return isc::dhcp::Dhcp6Parser::make_STRING(decoded, driver.loc_);
827 828 829 830
}

\"{JSONStringCharacter}*{ControlCharacter}{ControlCharacterFill}*\" {
    // Bad string with a forbidden control character inside
831
    driver.error(driver.loc_, "Invalid control in " + std::string(yytext));
832 833 834 835
}

\"{JSONStringCharacter}*\\{BadJSONEscapeSequence}[^\x00-\x1f"]*\" {
    // Bad string with a bad escape inside
836
    driver.error(driver.loc_, "Bad escape in " + std::string(yytext));
837 838 839 840
}
    
\"{JSONStringCharacter}*\\\" {
    // Bad string with an open escape at the end
841
    driver.error(driver.loc_, "Overflow escape in " + std::string(yytext));
842 843
}

844 845 846 847 848 849
"["    { 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_); }
850 851 852 853 854 855 856 857 858 859 860 861

{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 &) {
862
        driver.error(driver.loc_, "Failed to convert " + tmp + " to an integer.");
863 864 865
    }

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

869 870 871 872 873 874 875
[-+]?[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 &) {
876
        driver.error(driver.loc_, "Failed to convert " + tmp + " to a floating point.");
877 878
    }

879
    return isc::dhcp::Dhcp6Parser::make_FLOAT(fp, driver.loc_);
880 881 882 883
}

true|false {
    string tmp(yytext);
884
    return isc::dhcp::Dhcp6Parser::make_BOOLEAN(tmp == "true", driver.loc_);
885 886 887
}

null {
888
   return isc::dhcp::Dhcp6Parser::make_NULL_TYPE(driver.loc_);
889 890
}

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

893
<<EOF>> {
894 895
    if (driver.states_.empty()) {
        return isc::dhcp::Dhcp6Parser::make_END(driver.loc_);
Francis Dupont's avatar
Francis Dupont committed
896
    }
897 898 899 900
    driver.loc_ = driver.locs_.back();
    driver.locs_.pop_back();
    driver.file_ = driver.files_.back();
    driver.files_.pop_back();
901 902 903 904 905 906 907 908
    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
909
    parser6__delete_buffer(YY_CURRENT_BUFFER);
910 911
    parser6__switch_to_buffer(driver.states_.back());
    driver.states_.pop_back();
Francis Dupont's avatar
Francis Dupont committed
912 913 914 915

    BEGIN(DIR_EXIT);
}

916 917 918 919 920
%%

using namespace isc::dhcp;

void
921
Parser6Context::scanStringBegin(const std::string& str, ParserType parser_type)
922
{
923 924 925
    start_token_flag = true;
    start_token_value = parser_type;

926
    file_ = "<string>";
927
    sfile_ = 0;
928
    loc_.initialize(&file_);
929 930
    yy_flex_debug = trace_scanning_;
    YY_BUFFER_STATE buffer;
931
    buffer = yy_scan_bytes(str.c_str(), str.size());
932 933 934 935 936 937
    if (!buffer) {
        fatal("cannot scan string");
        // fatal() throws an exception so this can't be reached
    }
}

938
void
Francis Dupont's avatar
Francis Dupont committed
939 940
Parser6Context::scanFileBegin(FILE * f,
                              const std::string& filename,
941 942
                              ParserType parser_type)
{
943 944 945
    start_token_flag = true;
    start_token_value = parser_type;

946
    file_ = filename;
947
    sfile_ = f;
948
    loc_.initialize(&file_);
949 950 951 952 953 954
    yy_flex_debug = trace_scanning_;
    YY_BUFFER_STATE buffer;

    // See dhcp6_lexer.cc header for available definitions
    buffer = parser6__create_buffer(f, 65536 /*buffer size*/);
    if (!buffer) {
Francis Dupont's avatar
Francis Dupont committed
955
        fatal("cannot scan file " + filename);
956
    }
957
    parser6__switch_to_buffer(buffer);
958 959 960
}

void
961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978
Parser6Context::scanEnd() {
    if (sfile_)
        fclose(sfile_);
    sfile_ = 0;
    static_cast<void>(parser6_lex_destroy());
    // Close files
    while (!sfiles_.empty()) {
        FILE* f = sfiles_.back();
        if (f) {
            fclose(f);
        }
        sfiles_.pop_back();
    }
    // Delete states
    while (!states_.empty()) {
        parser6__delete_buffer(states_.back());
        states_.pop_back();
    }
979 980
}

981 982
void
Parser6Context::includeFile(const std::string& filename) {
983
    if (states_.size() > 10) {
Francis Dupont's avatar
Francis Dupont committed
984 985 986 987 988 989 990
        fatal("Too many nested include.");
    }

    FILE* f = fopen(filename.c_str(), "r");
    if (!f) {
        fatal("Can't open include file " + filename);
    }
991 992 993 994
    if (sfile_) {
        sfiles_.push_back(sfile_);
    }
    sfile_ = f;
995
    states_.push_back(YY_CURRENT_BUFFER);
Francis Dupont's avatar
Francis Dupont committed
996 997 998 999 1000 1001
    YY_BUFFER_STATE buffer;
    buffer = parser6__create_buffer(f, 65536 /*buffer size*/);
    if (!buffer) {
        fatal( "Can't scan include file " + filename);
    }
    parser6__switch_to_buffer(buffer);
1002 1003 1004 1005
    files_.push_back(file_);
    file_ = filename;
    locs_.push_back(loc_);
    loc_.initialize(&file_);
Francis Dupont's avatar
Francis Dupont committed
1006 1007

    BEGIN(INITIAL);
1008 1009
}

1010 1011 1012 1013 1014 1015 1016
namespace {
/// To avoid unused function error
class Dummy {
    // cppcheck-suppress unusedPrivateFunction
    void dummy() { yy_fatal_error("Fix me: how to disable its definition?"); }
};
}