dhcp6_lexer.ll 28.6 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
        case Parser6Context::PARSER_GENERIC_JSON:
108
        default:
109
            return isc::dhcp::Dhcp6Parser::make_TOPLEVEL_GENERIC_JSON(driver.loc_);
110 111
        }
    }
112 113
%}

Tomek Mrugalski's avatar
Tomek Mrugalski committed
114 115 116 117 118 119
#.* ;

"//"(.*) ;

"/*" {
  BEGIN(COMMENT);
120
  comment_start_line = driver.loc_.end.line;;
Tomek Mrugalski's avatar
Tomek Mrugalski committed
121 122 123
}

<COMMENT>"*/" BEGIN(INITIAL);
124
<COMMENT>. ;
Tomek Mrugalski's avatar
Tomek Mrugalski committed
125
<COMMENT><<EOF>> {
126
    isc_throw(Dhcp6ParseError, "Comment not closed. (/* in line " << comment_start_line);
Tomek Mrugalski's avatar
Tomek Mrugalski committed
127 128
}

Francis Dupont's avatar
Francis Dupont committed
129 130 131 132 133 134 135 136 137
"<?" 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);

138
    driver.includeFile(tmp);
Francis Dupont's avatar
Francis Dupont committed
139
}
140
<DIR_ENTER,DIR_INCLUDE,DIR_EXIT><<EOF>> {
141
    isc_throw(Dhcp6ParseError, "Directive not closed.");
142
}
Francis Dupont's avatar
Francis Dupont committed
143 144 145
<DIR_EXIT>"?>" BEGIN(INITIAL);
    

146
<*>{blank}+   {
147
    // Ok, we found a with space. Let's ignore it and update loc variable.
148
    driver.loc_.step();
149
}
150

151
<*>[\n]+      {
152
    // Newline found. Let's update the location and continue.
153 154
    driver.loc_.lines(yyleng);
    driver.loc_.step();
155 156
}

157

158 159 160
\"Dhcp6\"  {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::CONFIG:
161
        return isc::dhcp::Dhcp6Parser::make_DHCP6(driver.loc_);
162
    default:
163
        return isc::dhcp::Dhcp6Parser::make_STRING("Dhcp6", driver.loc_);
164 165 166 167 168 169
    }
}

\"interfaces-config\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::DHCP6:
170
        return  isc::dhcp::Dhcp6Parser::make_INTERFACES_CONFIG(driver.loc_);
171
    default:
172
        return isc::dhcp::Dhcp6Parser::make_STRING("interfaces-config", driver.loc_);
173 174 175 176 177 178
    }
}

\"interfaces\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::INTERFACES_CONFIG:
179
        return  isc::dhcp::Dhcp6Parser::make_INTERFACES(driver.loc_);
180
    default:
181
        return isc::dhcp::Dhcp6Parser::make_STRING("interfaces", driver.loc_);
182 183 184 185 186 187
    }
}

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

\"hosts-database\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::DHCP6:
197
        return isc::dhcp::Dhcp6Parser::make_HOSTS_DATABASE(driver.loc_);
198
    default:
199
        return isc::dhcp::Dhcp6Parser::make_STRING("hosts-database", driver.loc_);
200 201 202 203 204
    }
}

\"type\" {
    switch(driver.ctx_) {
205 206
    case isc::dhcp::Parser6Context::LEASE_DATABASE:
    case isc::dhcp::Parser6Context::HOSTS_DATABASE:
207
    case isc::dhcp::Parser6Context::SERVER_ID:
208
        return isc::dhcp::Dhcp6Parser::make_TYPE(driver.loc_);
209
    default:
210
        return isc::dhcp::Dhcp6Parser::make_STRING("type", driver.loc_);
211 212 213 214 215
    }
}

\"user\" {
    switch(driver.ctx_) {
216 217
    case isc::dhcp::Parser6Context::LEASE_DATABASE:
    case isc::dhcp::Parser6Context::HOSTS_DATABASE:
218
        return isc::dhcp::Dhcp6Parser::make_USER(driver.loc_);
219
    default:
220
        return isc::dhcp::Dhcp6Parser::make_STRING("user", driver.loc_);
221 222 223 224 225
    }
}

\"password\" {
    switch(driver.ctx_) {
226 227
    case isc::dhcp::Parser6Context::LEASE_DATABASE:
    case isc::dhcp::Parser6Context::HOSTS_DATABASE:
228
        return isc::dhcp::Dhcp6Parser::make_PASSWORD(driver.loc_);
229
    default:
230
        return isc::dhcp::Dhcp6Parser::make_STRING("password", driver.loc_);
231 232 233 234 235
    }
}

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

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

\"lfc-interval\" {
    switch(driver.ctx_) {
257 258
    case isc::dhcp::Parser6Context::LEASE_DATABASE:
    case isc::dhcp::Parser6Context::HOSTS_DATABASE:
259
        return isc::dhcp::Dhcp6Parser::make_LFC_INTERVAL(driver.loc_);
260
    default:
261
        return isc::dhcp::Dhcp6Parser::make_STRING("lfc-interval", driver.loc_);
262 263 264 265 266 267
    }
}

\"preferred-lifetime\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::DHCP6:
268
        return isc::dhcp::Dhcp6Parser::make_PREFERRED_LIFETIME(driver.loc_);
269
    default:
270
        return isc::dhcp::Dhcp6Parser::make_STRING("preferred-lifetime", driver.loc_);
271 272 273 274 275 276
    }
}

\"valid-lifetime\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::DHCP6:
277
        return isc::dhcp::Dhcp6Parser::make_VALID_LIFETIME(driver.loc_);
278
    default:
279
        return isc::dhcp::Dhcp6Parser::make_STRING("valid-lifetime", driver.loc_);
280 281 282 283 284 285
    }
}

\"renew-timer\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::DHCP6:
286
        return isc::dhcp::Dhcp6Parser::make_RENEW_TIMER(driver.loc_);
287
    default:
288
        return isc::dhcp::Dhcp6Parser::make_STRING("renew-timer", driver.loc_);
289 290 291 292 293 294
    }
}

\"rebind-timer\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::DHCP6:
295
        return isc::dhcp::Dhcp6Parser::make_REBIND_TIMER(driver.loc_);
296
    default:
297
        return isc::dhcp::Dhcp6Parser::make_STRING("rebind-timer", driver.loc_);
298 299 300 301 302 303
    }
}

\"subnet6\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::DHCP6:
304
        return isc::dhcp::Dhcp6Parser::make_SUBNET6(driver.loc_);
305
    default:
306
        return isc::dhcp::Dhcp6Parser::make_STRING("subnet6", driver.loc_);
307 308 309 310 311 312 313 314 315 316 317 318
    }
}

\"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:
319
        return isc::dhcp::Dhcp6Parser::make_OPTION_DATA(driver.loc_);
320
    default:
321
        return isc::dhcp::Dhcp6Parser::make_STRING("option-data", driver.loc_);
322 323 324 325 326
    }
}

\"name\" {
    switch(driver.ctx_) {
327 328
    case isc::dhcp::Parser6Context::LEASE_DATABASE:
    case isc::dhcp::Parser6Context::HOSTS_DATABASE:
329 330 331 332
    case isc::dhcp::Parser6Context::OPTION_DATA:
    case isc::dhcp::Parser6Context::CLIENT_CLASSES:
    case isc::dhcp::Parser6Context::CLIENT_CLASS:
    case isc::dhcp::Parser6Context::LOGGERS:
333
        return isc::dhcp::Dhcp6Parser::make_NAME(driver.loc_);
334
    default:
335
        return isc::dhcp::Dhcp6Parser::make_STRING("name", driver.loc_);
336 337 338 339 340 341
    }
}

\"data\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::OPTION_DATA:
342
        return isc::dhcp::Dhcp6Parser::make_DATA(driver.loc_);
343
    default:
344
        return isc::dhcp::Dhcp6Parser::make_STRING("data", driver.loc_);
345 346 347 348 349 350
    }
}

\"pools\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::SUBNET6:
351
        return isc::dhcp::Dhcp6Parser::make_POOLS(driver.loc_);
352
    default:
353
        return isc::dhcp::Dhcp6Parser::make_STRING("pools", driver.loc_);
354 355 356 357 358 359
    }
}

\"pd-pools\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::SUBNET6:
360
        return isc::dhcp::Dhcp6Parser::make_PD_POOLS(driver.loc_);
361
    default:
362
        return isc::dhcp::Dhcp6Parser::make_STRING("pd-pools", driver.loc_);
363 364 365 366 367 368
    }
}

\"prefix\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::PD_POOLS:
369
        return isc::dhcp::Dhcp6Parser::make_PREFIX(driver.loc_);
370
    default:
371
        return isc::dhcp::Dhcp6Parser::make_STRING("prefix", driver.loc_);
372 373 374 375 376 377
    }
}

\"prefix-len\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::PD_POOLS:
378
        return isc::dhcp::Dhcp6Parser::make_PREFIX_LEN(driver.loc_);
379
    default:
380
        return isc::dhcp::Dhcp6Parser::make_STRING("prefix-len", driver.loc_);
381 382 383 384 385 386
    }
}

\"delegated-len\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::PD_POOLS:
387
        return isc::dhcp::Dhcp6Parser::make_DELEGATED_LEN(driver.loc_);
388
    default:
389
        return isc::dhcp::Dhcp6Parser::make_STRING("delegated-len", driver.loc_);
390 391 392 393 394 395
    }
}

\"pool\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::POOLS:
396
        return isc::dhcp::Dhcp6Parser::make_POOL(driver.loc_);
397
    default:
398
        return isc::dhcp::Dhcp6Parser::make_STRING("pool", driver.loc_);
399 400 401 402 403 404
    }
}

\"subnet\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::SUBNET6:
405
        return isc::dhcp::Dhcp6Parser::make_SUBNET(driver.loc_);
406
    default:
407
        return isc::dhcp::Dhcp6Parser::make_STRING("subnet", driver.loc_);
408 409 410 411 412 413
    }
}

\"interface\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::SUBNET6:
414
        return isc::dhcp::Dhcp6Parser::make_INTERFACE(driver.loc_);
415
    default:
416
        return isc::dhcp::Dhcp6Parser::make_STRING("interface", driver.loc_);
417 418 419 420 421 422
    }
}

\"id\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::SUBNET6:
423
        return isc::dhcp::Dhcp6Parser::make_ID(driver.loc_);
424
    default:
425
        return isc::dhcp::Dhcp6Parser::make_STRING("id", driver.loc_);
426 427 428 429 430 431
    }
}

\"code\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::OPTION_DATA:
432
        return isc::dhcp::Dhcp6Parser::make_CODE(driver.loc_);
433
    default:
434
        return isc::dhcp::Dhcp6Parser::make_STRING("code", driver.loc_);
435 436 437 438 439 440
    }
}

\"mac-sources\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::DHCP6:
441
        return isc::dhcp::Dhcp6Parser::make_MAC_SOURCES(driver.loc_);
442
    default:
443
        return isc::dhcp::Dhcp6Parser::make_STRING("mac-sources", driver.loc_);
444 445 446 447 448 449
    }
}

\"relay-supplied-options\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::DHCP6:
450
        return isc::dhcp::Dhcp6Parser::make_RELAY_SUPPLIED_OPTIONS(driver.loc_);
451
    default:
452
        return isc::dhcp::Dhcp6Parser::make_STRING("relay-supplied-options", driver.loc_);
453 454 455 456 457 458
    }
}

\"host-reservation-identifiers\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::DHCP6:
459
        return isc::dhcp::Dhcp6Parser::make_HOST_RESERVATION_IDENTIFIERS(driver.loc_);
460
    default:
461
        return isc::dhcp::Dhcp6Parser::make_STRING("host-reservation-identifiers", driver.loc_);
462 463 464 465 466 467
    }
}

\"Logging\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::CONFIG:
468
        return isc::dhcp::Dhcp6Parser::make_LOGGING(driver.loc_);
469
    default:
470
        return isc::dhcp::Dhcp6Parser::make_STRING("Logging", driver.loc_);
471 472 473 474 475 476
    }
}

\"loggers\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::LOGGING:
477
        return isc::dhcp::Dhcp6Parser::make_LOGGERS(driver.loc_);
478
    default:
479
        return isc::dhcp::Dhcp6Parser::make_STRING("loggers", driver.loc_);
480 481 482 483 484 485
    }
}

\"output_options\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::LOGGERS:
486
        return isc::dhcp::Dhcp6Parser::make_OUTPUT_OPTIONS(driver.loc_);
487
    default:
488
        return isc::dhcp::Dhcp6Parser::make_STRING("output_options", driver.loc_);
489 490 491 492 493 494
    }
}

\"output\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::OUTPUT_OPTIONS:
495
        return isc::dhcp::Dhcp6Parser::make_OUTPUT(driver.loc_);
496
    default:
497
        return isc::dhcp::Dhcp6Parser::make_STRING("output", driver.loc_);
498 499 500 501 502 503
    }
}

\"debuglevel\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::LOGGERS:
504
        return isc::dhcp::Dhcp6Parser::make_DEBUGLEVEL(driver.loc_);
505
    default:
506
        return isc::dhcp::Dhcp6Parser::make_STRING("debuglevel", driver.loc_);
507 508 509 510 511 512
    }
}

\"severity\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::LOGGERS:
513
        return isc::dhcp::Dhcp6Parser::make_SEVERITY(driver.loc_);
514
    default:
515
        return isc::dhcp::Dhcp6Parser::make_STRING("severity", driver.loc_);
516 517 518 519 520 521 522
    }
}

\"client-classes\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::DHCP6:
    case isc::dhcp::Parser6Context::RESERVATIONS:
523
        return isc::dhcp::Dhcp6Parser::make_CLIENT_CLASSES(driver.loc_);
524
    default:
525
        return isc::dhcp::Dhcp6Parser::make_STRING("client-classes", driver.loc_);
526 527 528 529 530 531 532
    }
}

\"client-class\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::SUBNET6:
    case isc::dhcp::Parser6Context::CLIENT_CLASSES:
533
        return isc::dhcp::Dhcp6Parser::make_CLIENT_CLASS(driver.loc_);
534
    default:
535
        return isc::dhcp::Dhcp6Parser::make_STRING("client-class", driver.loc_);
536 537 538 539 540 541 542
    }
}

\"test\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::CLIENT_CLASSES:
    case isc::dhcp::Parser6Context::CLIENT_CLASS:
543
        return isc::dhcp::Dhcp6Parser::make_TEST(driver.loc_);
544
    default:
545
        return isc::dhcp::Dhcp6Parser::make_STRING("test", driver.loc_);
546 547 548 549 550 551
    }
}

\"reservations\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::SUBNET6:
552
        return isc::dhcp::Dhcp6Parser::make_RESERVATIONS(driver.loc_);
553
    default:
554
        return isc::dhcp::Dhcp6Parser::make_STRING("reservations", driver.loc_);
555 556 557 558 559 560
    }
}

\"ip-addresses\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::RESERVATIONS:
561
        return isc::dhcp::Dhcp6Parser::make_IP_ADDRESSES(driver.loc_);
562
    default:
563
        return isc::dhcp::Dhcp6Parser::make_STRING("ip-addresses", driver.loc_);
564 565 566 567 568 569
    }
}

\"prefixes\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::RESERVATIONS:
570
        return isc::dhcp::Dhcp6Parser::make_PREFIXES(driver.loc_);
571
    default:
572
        return isc::dhcp::Dhcp6Parser::make_STRING("prefixes", driver.loc_);
573 574 575 576 577 578 579 580
    }
}

\"duid\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::MAC_SOURCES:
    case isc::dhcp::Parser6Context::HOST_RESERVATION_IDENTIFIERS:
    case isc::dhcp::Parser6Context::RESERVATIONS:
581
        return isc::dhcp::Dhcp6Parser::make_DUID(driver.loc_);
582
    default:
583
        return isc::dhcp::Dhcp6Parser::make_STRING("duid", driver.loc_);
584 585 586 587 588 589 590
    }
}

\"hw-address\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::HOST_RESERVATION_IDENTIFIERS:
    case isc::dhcp::Parser6Context::RESERVATIONS:
591
        return isc::dhcp::Dhcp6Parser::make_HW_ADDRESS(driver.loc_);
592
    default:
593
        return isc::dhcp::Dhcp6Parser::make_STRING("hw-address", driver.loc_);
594 595 596 597 598 599
    }
}

\"hostname\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::RESERVATIONS:
600
        return isc::dhcp::Dhcp6Parser::make_HOSTNAME(driver.loc_);
601
    default:
602
        return isc::dhcp::Dhcp6Parser::make_STRING("hostname", driver.loc_);
603 604 605 606 607 608
    }
}

\"space\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::OPTION_DATA:
609
        return isc::dhcp::Dhcp6Parser::make_SPACE(driver.loc_);
610
    default:
611
        return isc::dhcp::Dhcp6Parser::make_STRING("space", driver.loc_);
612 613 614 615 616 617
    }
}

\"csv-format\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::OPTION_DATA:
618
        return isc::dhcp::Dhcp6Parser::make_CSV_FORMAT(driver.loc_);
619
    default:
620
        return isc::dhcp::Dhcp6Parser::make_STRING("csv-format", driver.loc_);
621 622 623 624 625 626
    }
}

\"hooks-libraries\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::DHCP6:
627
        return isc::dhcp::Dhcp6Parser::make_HOOKS_LIBRARIES(driver.loc_);
628
    default:
629
        return isc::dhcp::Dhcp6Parser::make_STRING("hooks-libraries", driver.loc_);
630 631 632 633 634 635
    }
}

\"library\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::HOOKS_LIBRARIES:
636
        return isc::dhcp::Dhcp6Parser::make_LIBRARY(driver.loc_);
637
    default:
638
        return isc::dhcp::Dhcp6Parser::make_STRING("library", driver.loc_);
639 640 641 642 643 644
    }
}

\"server-id\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::DHCP6:
645
        return isc::dhcp::Dhcp6Parser::make_SERVER_ID(driver.loc_);
646
    default:
647
        return isc::dhcp::Dhcp6Parser::make_STRING("server-id", driver.loc_);
648 649 650 651 652 653
    }
}

\"identifier\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::SERVER_ID:
654
        return isc::dhcp::Dhcp6Parser::make_IDENTIFIER(driver.loc_);
655
    default:
656
        return isc::dhcp::Dhcp6Parser::make_STRING("identifier", driver.loc_);
657 658 659 660 661 662
    }
}

\"htype\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::SERVER_ID:
663
        return isc::dhcp::Dhcp6Parser::make_HTYPE(driver.loc_);
664
    default:
665
        return isc::dhcp::Dhcp6Parser::make_STRING("htype", driver.loc_);
666 667 668 669 670 671
    }
}

\"time\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::SERVER_ID:
672
        return isc::dhcp::Dhcp6Parser::make_TIME(driver.loc_);
673
    default:
674
        return isc::dhcp::Dhcp6Parser::make_STRING("time", driver.loc_);
675 676 677 678 679 680
    }
}

\"enterprise-id\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::SERVER_ID:
681
        return isc::dhcp::Dhcp6Parser::make_ENTERPRISE_ID(driver.loc_);
682
    default:
683
        return isc::dhcp::Dhcp6Parser::make_STRING("enterprise-id", driver.loc_);
684 685 686 687 688 689
    }
}

\"expired-leases-processing\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::DHCP6:
690
        return isc::dhcp::Dhcp6Parser::make_EXPIRED_LEASES_PROCESSING(driver.loc_);
691
    default:
692
        return isc::dhcp::Dhcp6Parser::make_STRING("expired-leases-processing", driver.loc_);
693 694 695 696 697 698
    }
}

\"dhcp4o6-port\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::DHCP6:
699
        return isc::dhcp::Dhcp6Parser::make_DHCP4O6_PORT(driver.loc_);
700
    default:
701
        return isc::dhcp::Dhcp6Parser::make_STRING("dhcp4o6-port", driver.loc_);
702 703 704 705 706 707
    }
}

\"dhcp-ddns\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::DHCP6:
708
        return isc::dhcp::Dhcp6Parser::make_DHCP_DDNS(driver.loc_);
709
    default:
710
        return isc::dhcp::Dhcp6Parser::make_STRING("dhcp-ddns", driver.loc_);
711 712 713 714 715 716
    }
}

\"enable-updates\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::DHCP_DDNS:
717
        return isc::dhcp::Dhcp6Parser::make_ENABLE_UPDATES(driver.loc_);
718
    default:
719
        return isc::dhcp::Dhcp6Parser::make_STRING("enable-updates", driver.loc_);
720 721 722 723 724 725
    }
}

\"qualifying-suffix\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::DHCP_DDNS:
726
        return isc::dhcp::Dhcp6Parser::make_QUALIFYING_SUFFIX(driver.loc_);
727
    default:
728
        return isc::dhcp::Dhcp6Parser::make_STRING("qualifying-suffix", driver.loc_);
729 730
    }
}
731

732 733 734
\"Dhcp4\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::CONFIG:
735
        return isc::dhcp::Dhcp6Parser::make_DHCP4(driver.loc_);
736
    default:
737
        return isc::dhcp::Dhcp6Parser::make_STRING("Dhcp4", driver.loc_);
738 739 740 741 742 743
    }
}

\"DhcpDdns\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::CONFIG:
744
        return isc::dhcp::Dhcp6Parser::make_DHCPDDNS(driver.loc_);
745
    default:
746
        return isc::dhcp::Dhcp6Parser::make_STRING("DhcpDdns", driver.loc_);
747 748
    }
}
749

750 751 752 753
{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
754 755 756 757 758 759 760 761 762 763
    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
764
            driver.error(driver.loc_, "Bad quote in \"" + raw + "\"");
765 766 767 768
        case '\\':
            ++pos;
            if (pos >= len) {
                // impossible condition
769
                driver.error(driver.loc_, "Overflow escape in \"" + raw + "\"");
770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794
            }
            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
795
                driver.error(driver.loc_, "Unsupported unicode escape in \"" + raw + "\"");
796 797
            default:
                // impossible condition
798
                driver.error(driver.loc_, "Bad escape in \"" + raw + "\"");
799 800 801 802 803
            }
            break;
        default:
            if (c < 0x20) {
                // impossible condition
804
                driver.error(driver.loc_, "Invalid control in \"" + raw + "\"");
805 806 807 808
            }
            decoded.push_back(c);
        }
    }
809

810
    return isc::dhcp::Dhcp6Parser::make_STRING(decoded, driver.loc_);
811 812 813 814
}

\"{JSONStringCharacter}*{ControlCharacter}{ControlCharacterFill}*\" {
    // Bad string with a forbidden control character inside
815
    driver.error(driver.loc_, "Invalid control in " + std::string(yytext));
816 817 818 819
}

\"{JSONStringCharacter}*\\{BadJSONEscapeSequence}[^\x00-\x1f"]*\" {
    // Bad string with a bad escape inside
820
    driver.error(driver.loc_, "Bad escape in " + std::string(yytext));
821 822 823 824
}
    
\"{JSONStringCharacter}*\\\" {
    // Bad string with an open escape at the end
825
    driver.error(driver.loc_, "Overflow escape in " + std::string(yytext));
826 827
}

828 829 830 831 832 833
"["    { 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_); }
834 835 836 837 838 839 840 841 842 843 844 845

{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 &) {
846
        driver.error(driver.loc_, "Failed to convert " + tmp + " to an integer.");
847 848 849
    }

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

853 854 855 856 857 858 859
[-+]?[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 &) {
860
        driver.error(driver.loc_, "Failed to convert " + tmp + " to a floating point.");
861 862
    }

863
    return isc::dhcp::Dhcp6Parser::make_FLOAT(fp, driver.loc_);
864 865 866 867
}

true|false {
    string tmp(yytext);
868
    return isc::dhcp::Dhcp6Parser::make_BOOLEAN(tmp == "true", driver.loc_);
869 870 871
}

null {
872
   return isc::dhcp::Dhcp6Parser::make_NULL_TYPE(driver.loc_);
873 874
}

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

877
<<EOF>> {
878 879
    if (driver.states_.empty()) {
        return isc::dhcp::Dhcp6Parser::make_END(driver.loc_);
Francis Dupont's avatar
Francis Dupont committed
880
    }
881 882 883 884
    driver.loc_ = driver.locs_.back();
    driver.locs_.pop_back();
    driver.file_ = driver.files_.back();
    driver.files_.pop_back();
Francis Dupont's avatar
Francis Dupont committed
885
    parser6__delete_buffer(YY_CURRENT_BUFFER);
886 887
    parser6__switch_to_buffer(driver.states_.back());
    driver.states_.pop_back();
Francis Dupont's avatar
Francis Dupont committed
888 889 890 891

    BEGIN(DIR_EXIT);
}

892 893 894 895 896
%%

using namespace isc::dhcp;

void
897
Parser6Context::scanStringBegin(const std::string& str, ParserType parser_type)
898
{
899
    static_cast<void>(parser6_lex_destroy());
900 901 902
    start_token_flag = true;
    start_token_value = parser_type;

903 904
    file_ = "<string>";
    loc_.initialize(&file_);
905 906
    yy_flex_debug = trace_scanning_;
    YY_BUFFER_STATE buffer;
907
    buffer = yy_scan_bytes(str.c_str(), str.size());
908 909 910 911 912 913 914 915 916 917 918 919
    if (!buffer) {
        fatal("cannot scan string");
        // fatal() throws an exception so this can't be reached
    }
}

void
Parser6Context::scanStringEnd()
{
    yy_delete_buffer(YY_CURRENT_BUFFER);
}

920
void
Francis Dupont's avatar
Francis Dupont committed
921 922
Parser6Context::scanFileBegin(FILE * f,
                              const std::string& filename,
923 924 925
                              ParserType parser_type)
{
    static_cast<void>(parser6_lex_destroy());
926 927 928
    start_token_flag = true;
    start_token_value = parser_type;

929 930
    file_ = filename;
    loc_.initialize(&file_);
931 932 933 934 935 936
    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
937
        fatal("cannot scan file " + filename);
938
    }
939
    parser6__switch_to_buffer(buffer);
940 941 942 943 944 945 946 947
}

void
Parser6Context::scanFileEnd(FILE * f) {
    fclose(f);
    yy_delete_buffer(YY_CURRENT_BUFFER);
}

948 949
void
Parser6Context::includeFile(const std::string& filename) {
950
    if (states_.size() > 10) {
Francis Dupont's avatar
Francis Dupont committed
951 952 953 954 955 956 957
        fatal("Too many nested include.");
    }

    FILE* f = fopen(filename.c_str(), "r");
    if (!f) {
        fatal("Can't open include file " + filename);
    }
958
    states_.push_back(YY_CURRENT_BUFFER);
Francis Dupont's avatar
Francis Dupont committed
959 960 961 962 963 964
    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);
965 966 967 968
    files_.push_back(file_);
    file_ = filename;
    locs_.push_back(loc_);
    loc_.initialize(&file_);
Francis Dupont's avatar
Francis Dupont committed
969 970

    BEGIN(INITIAL);
971 972
}

973 974 975 976 977 978 979
namespace {
/// To avoid unused function error
class Dummy {
    // cppcheck-suppress unusedPrivateFunction
    void dummy() { yy_fatal_error("Fix me: how to disable its definition?"); }
};
}