dhcp6_lexer.ll 29.9 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 105
    if (start_token_flag) {
        start_token_flag = false;
        switch (start_token_value) {
        case Parser6Context::PARSER_DHCP6:
106
            return isc::dhcp::Dhcp6Parser::make_TOPLEVEL_DHCP6(driver.loc_);
107 108 109 110 111 112 113 114 115 116 117 118 119 120
        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_);
121
        case Parser6Context::PARSER_GENERIC_JSON:
122
        default:
123
            return isc::dhcp::Dhcp6Parser::make_TOPLEVEL_GENERIC_JSON(driver.loc_);
124 125
        }
    }
126 127
%}

Tomek Mrugalski's avatar
Tomek Mrugalski committed
128 129 130 131 132 133
#.* ;

"//"(.*) ;

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

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

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

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

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

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

171

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    BEGIN(DIR_EXIT);
}

914 915 916 917 918
%%

using namespace isc::dhcp;

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

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

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

944
    file_ = filename;
945
    sfile_ = f;
946
    loc_.initialize(&file_);
947 948 949 950 951 952
    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
953
        fatal("cannot scan file " + filename);
954
    }
955
    parser6__switch_to_buffer(buffer);
956 957 958
}

void
959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976
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();
    }
977 978
}

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

    FILE* f = fopen(filename.c_str(), "r");
    if (!f) {
        fatal("Can't open include file " + filename);
    }
989 990 991 992
    if (sfile_) {
        sfiles_.push_back(sfile_);
    }
    sfile_ = f;
993
    states_.push_back(YY_CURRENT_BUFFER);
Francis Dupont's avatar
Francis Dupont committed
994 995 996 997 998 999
    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);
1000 1001 1002 1003
    files_.push_back(file_);
    file_ = filename;
    locs_.push_back(loc_);
    loc_.initialize(&file_);
Francis Dupont's avatar
Francis Dupont committed
1004 1005

    BEGIN(INITIAL);
1006 1007
}

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