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

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

"//"(.*) ;

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

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

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

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

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

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

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

175

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

\"subnet6\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::DHCP6:
323
        return isc::dhcp::Dhcp6Parser::make_SUBNET6(driver.loc_);
324
    default:
325
        return isc::dhcp::Dhcp6Parser::make_STRING("subnet6", driver.loc_);
326 327 328
    }
}

329 330 331 332 333 334 335 336 337
\"option-def\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::DHCP6:
        return isc::dhcp::Dhcp6Parser::make_OPTION_DEF(driver.loc_);
    default:
        return isc::dhcp::Dhcp6Parser::make_STRING("option-def", driver.loc_);
    }
}

338 339 340 341 342 343 344 345 346
\"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:
347
        return isc::dhcp::Dhcp6Parser::make_OPTION_DATA(driver.loc_);
348
    default:
349
        return isc::dhcp::Dhcp6Parser::make_STRING("option-data", driver.loc_);
350 351 352 353 354
    }
}

\"name\" {
    switch(driver.ctx_) {
355 356
    case isc::dhcp::Parser6Context::LEASE_DATABASE:
    case isc::dhcp::Parser6Context::HOSTS_DATABASE:
357
    case isc::dhcp::Parser6Context::OPTION_DEF:
358 359 360 361
    case isc::dhcp::Parser6Context::OPTION_DATA:
    case isc::dhcp::Parser6Context::CLIENT_CLASSES:
    case isc::dhcp::Parser6Context::CLIENT_CLASS:
    case isc::dhcp::Parser6Context::LOGGERS:
362
        return isc::dhcp::Dhcp6Parser::make_NAME(driver.loc_);
363
    default:
364
        return isc::dhcp::Dhcp6Parser::make_STRING("name", driver.loc_);
365 366 367 368 369 370
    }
}

\"data\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::OPTION_DATA:
371
        return isc::dhcp::Dhcp6Parser::make_DATA(driver.loc_);
372
    default:
373
        return isc::dhcp::Dhcp6Parser::make_STRING("data", driver.loc_);
374 375 376 377 378 379
    }
}

\"pools\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::SUBNET6:
380
        return isc::dhcp::Dhcp6Parser::make_POOLS(driver.loc_);
381
    default:
382
        return isc::dhcp::Dhcp6Parser::make_STRING("pools", driver.loc_);
383 384 385 386 387 388
    }
}

\"pd-pools\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::SUBNET6:
389
        return isc::dhcp::Dhcp6Parser::make_PD_POOLS(driver.loc_);
390
    default:
391
        return isc::dhcp::Dhcp6Parser::make_STRING("pd-pools", driver.loc_);
392 393 394 395 396 397
    }
}

\"prefix\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::PD_POOLS:
398
        return isc::dhcp::Dhcp6Parser::make_PREFIX(driver.loc_);
399
    default:
400
        return isc::dhcp::Dhcp6Parser::make_STRING("prefix", driver.loc_);
401 402 403 404 405 406
    }
}

\"prefix-len\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::PD_POOLS:
407
        return isc::dhcp::Dhcp6Parser::make_PREFIX_LEN(driver.loc_);
408
    default:
409
        return isc::dhcp::Dhcp6Parser::make_STRING("prefix-len", driver.loc_);
410 411 412 413 414 415
    }
}

\"delegated-len\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::PD_POOLS:
416
        return isc::dhcp::Dhcp6Parser::make_DELEGATED_LEN(driver.loc_);
417
    default:
418
        return isc::dhcp::Dhcp6Parser::make_STRING("delegated-len", driver.loc_);
419 420 421 422 423 424
    }
}

\"pool\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::POOLS:
425
        return isc::dhcp::Dhcp6Parser::make_POOL(driver.loc_);
426
    default:
427
        return isc::dhcp::Dhcp6Parser::make_STRING("pool", driver.loc_);
428 429 430 431 432 433
    }
}

\"subnet\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::SUBNET6:
434
        return isc::dhcp::Dhcp6Parser::make_SUBNET(driver.loc_);
435
    default:
436
        return isc::dhcp::Dhcp6Parser::make_STRING("subnet", driver.loc_);
437 438 439 440 441 442
    }
}

\"interface\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::SUBNET6:
443
        return isc::dhcp::Dhcp6Parser::make_INTERFACE(driver.loc_);
444
    default:
445
        return isc::dhcp::Dhcp6Parser::make_STRING("interface", driver.loc_);
446 447 448 449 450 451
    }
}

\"id\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::SUBNET6:
452
        return isc::dhcp::Dhcp6Parser::make_ID(driver.loc_);
453
    default:
454
        return isc::dhcp::Dhcp6Parser::make_STRING("id", driver.loc_);
455 456 457 458 459
    }
}

\"code\" {
    switch(driver.ctx_) {
460
    case isc::dhcp::Parser6Context::OPTION_DEF:
461
    case isc::dhcp::Parser6Context::OPTION_DATA:
462
        return isc::dhcp::Dhcp6Parser::make_CODE(driver.loc_);
463
    default:
464
        return isc::dhcp::Dhcp6Parser::make_STRING("code", driver.loc_);
465 466 467 468 469 470
    }
}

\"mac-sources\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::DHCP6:
471
        return isc::dhcp::Dhcp6Parser::make_MAC_SOURCES(driver.loc_);
472
    default:
473
        return isc::dhcp::Dhcp6Parser::make_STRING("mac-sources", driver.loc_);
474 475 476 477 478 479
    }
}

\"relay-supplied-options\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::DHCP6:
480
        return isc::dhcp::Dhcp6Parser::make_RELAY_SUPPLIED_OPTIONS(driver.loc_);
481
    default:
482
        return isc::dhcp::Dhcp6Parser::make_STRING("relay-supplied-options", driver.loc_);
483 484 485 486 487 488
    }
}

\"host-reservation-identifiers\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::DHCP6:
489
        return isc::dhcp::Dhcp6Parser::make_HOST_RESERVATION_IDENTIFIERS(driver.loc_);
490
    default:
491
        return isc::dhcp::Dhcp6Parser::make_STRING("host-reservation-identifiers", driver.loc_);
492 493 494 495 496 497
    }
}

\"Logging\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::CONFIG:
498
        return isc::dhcp::Dhcp6Parser::make_LOGGING(driver.loc_);
499
    default:
500
        return isc::dhcp::Dhcp6Parser::make_STRING("Logging", driver.loc_);
501 502 503 504 505 506
    }
}

\"loggers\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::LOGGING:
507
        return isc::dhcp::Dhcp6Parser::make_LOGGERS(driver.loc_);
508
    default:
509
        return isc::dhcp::Dhcp6Parser::make_STRING("loggers", driver.loc_);
510 511 512 513 514 515
    }
}

\"output_options\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::LOGGERS:
516
        return isc::dhcp::Dhcp6Parser::make_OUTPUT_OPTIONS(driver.loc_);
517
    default:
518
        return isc::dhcp::Dhcp6Parser::make_STRING("output_options", driver.loc_);
519 520 521 522 523 524
    }
}

\"output\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::OUTPUT_OPTIONS:
525
        return isc::dhcp::Dhcp6Parser::make_OUTPUT(driver.loc_);
526
    default:
527
        return isc::dhcp::Dhcp6Parser::make_STRING("output", driver.loc_);
528 529 530 531 532 533
    }
}

\"debuglevel\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::LOGGERS:
534
        return isc::dhcp::Dhcp6Parser::make_DEBUGLEVEL(driver.loc_);
535
    default:
536
        return isc::dhcp::Dhcp6Parser::make_STRING("debuglevel", driver.loc_);
537 538 539 540 541 542
    }
}

\"severity\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::LOGGERS:
543
        return isc::dhcp::Dhcp6Parser::make_SEVERITY(driver.loc_);
544
    default:
545
        return isc::dhcp::Dhcp6Parser::make_STRING("severity", driver.loc_);
546 547 548 549 550 551 552
    }
}

\"client-classes\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::DHCP6:
    case isc::dhcp::Parser6Context::RESERVATIONS:
553
        return isc::dhcp::Dhcp6Parser::make_CLIENT_CLASSES(driver.loc_);
554
    default:
555
        return isc::dhcp::Dhcp6Parser::make_STRING("client-classes", driver.loc_);
556 557 558 559 560 561 562
    }
}

\"client-class\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::SUBNET6:
    case isc::dhcp::Parser6Context::CLIENT_CLASSES:
563
        return isc::dhcp::Dhcp6Parser::make_CLIENT_CLASS(driver.loc_);
564
    default:
565
        return isc::dhcp::Dhcp6Parser::make_STRING("client-class", driver.loc_);
566 567 568 569 570 571 572
    }
}

\"test\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::CLIENT_CLASSES:
    case isc::dhcp::Parser6Context::CLIENT_CLASS:
573
        return isc::dhcp::Dhcp6Parser::make_TEST(driver.loc_);
574
    default:
575
        return isc::dhcp::Dhcp6Parser::make_STRING("test", driver.loc_);
576 577 578 579 580 581
    }
}

\"reservations\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::SUBNET6:
582
        return isc::dhcp::Dhcp6Parser::make_RESERVATIONS(driver.loc_);
583
    default:
584
        return isc::dhcp::Dhcp6Parser::make_STRING("reservations", driver.loc_);
585 586 587 588 589 590
    }
}

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

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

\"duid\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::MAC_SOURCES:
    case isc::dhcp::Parser6Context::HOST_RESERVATION_IDENTIFIERS:
    case isc::dhcp::Parser6Context::RESERVATIONS:
611
        return isc::dhcp::Dhcp6Parser::make_DUID(driver.loc_);
612
    default:
613
        return isc::dhcp::Dhcp6Parser::make_STRING("duid", driver.loc_);
614 615 616 617 618 619 620
    }
}

\"hw-address\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::HOST_RESERVATION_IDENTIFIERS:
    case isc::dhcp::Parser6Context::RESERVATIONS:
621
        return isc::dhcp::Dhcp6Parser::make_HW_ADDRESS(driver.loc_);
622
    default:
623
        return isc::dhcp::Dhcp6Parser::make_STRING("hw-address", driver.loc_);
624 625 626 627 628 629
    }
}

\"hostname\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::RESERVATIONS:
630
        return isc::dhcp::Dhcp6Parser::make_HOSTNAME(driver.loc_);
631
    default:
632
        return isc::dhcp::Dhcp6Parser::make_STRING("hostname", driver.loc_);
633 634 635 636 637
    }
}

\"space\" {
    switch(driver.ctx_) {
638
    case isc::dhcp::Parser6Context::OPTION_DEF:
639
    case isc::dhcp::Parser6Context::OPTION_DATA:
640
        return isc::dhcp::Dhcp6Parser::make_SPACE(driver.loc_);
641
    default:
642
        return isc::dhcp::Dhcp6Parser::make_STRING("space", driver.loc_);
643 644 645 646 647
    }
}

\"csv-format\" {
    switch(driver.ctx_) {
648
    case isc::dhcp::Parser6Context::OPTION_DEF:
649
    case isc::dhcp::Parser6Context::OPTION_DATA:
650
        return isc::dhcp::Dhcp6Parser::make_CSV_FORMAT(driver.loc_);
651
    default:
652
        return isc::dhcp::Dhcp6Parser::make_STRING("csv-format", driver.loc_);
653 654 655 656 657 658
    }
}

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

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

\"server-id\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::DHCP6:
677
        return isc::dhcp::Dhcp6Parser::make_SERVER_ID(driver.loc_);
678
    default:
679
        return isc::dhcp::Dhcp6Parser::make_STRING("server-id", driver.loc_);
680 681 682 683 684 685
    }
}

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

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

\"time\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::SERVER_ID:
704
        return isc::dhcp::Dhcp6Parser::make_TIME(driver.loc_);
705
    default:
706
        return isc::dhcp::Dhcp6Parser::make_STRING("time", driver.loc_);
707 708 709 710 711 712
    }
}

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

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

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

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

\"enable-updates\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::DHCP_DDNS:
749
        return isc::dhcp::Dhcp6Parser::make_ENABLE_UPDATES(driver.loc_);
750
    default:
751
        return isc::dhcp::Dhcp6Parser::make_STRING("enable-updates", driver.loc_);
752 753 754 755 756 757
    }
}

\"qualifying-suffix\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::DHCP_DDNS:
758
        return isc::dhcp::Dhcp6Parser::make_QUALIFYING_SUFFIX(driver.loc_);
759
    default:
760
        return isc::dhcp::Dhcp6Parser::make_STRING("qualifying-suffix", driver.loc_);
761 762
    }
}
763

764 765 766
\"Dhcp4\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::CONFIG:
767
        return isc::dhcp::Dhcp6Parser::make_DHCP4(driver.loc_);
768
    default:
769
        return isc::dhcp::Dhcp6Parser::make_STRING("Dhcp4", driver.loc_);
770 771 772 773 774 775
    }
}

\"DhcpDdns\" {
    switch(driver.ctx_) {
    case isc::dhcp::Parser6Context::CONFIG:
776
        return isc::dhcp::Dhcp6Parser::make_DHCPDDNS(driver.loc_);
777
    default:
778
        return isc::dhcp::Dhcp6Parser::make_STRING("DhcpDdns", driver.loc_);
779 780
    }
}
781

782 783 784 785
{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
786 787 788 789 790 791 792 793 794 795
    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
796
            driver.error(driver.loc_, "Bad quote in \"" + raw + "\"");
797 798 799 800
        case '\\':
            ++pos;
            if (pos >= len) {
                // impossible condition
801
                driver.error(driver.loc_, "Overflow escape in \"" + raw + "\"");
802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826
            }
            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
827
                driver.error(driver.loc_, "Unsupported unicode escape in \"" + raw + "\"");
828 829
            default:
                // impossible condition
830
                driver.error(driver.loc_, "Bad escape in \"" + raw + "\"");
831 832 833 834 835
            }
            break;
        default:
            if (c < 0x20) {
                // impossible condition
836
                driver.error(driver.loc_, "Invalid control in \"" + raw + "\"");
837 838 839 840
            }
            decoded.push_back(c);
        }
    }
841

842
    return isc::dhcp::Dhcp6Parser::make_STRING(decoded, driver.loc_);
843 844 845 846
}

\"{JSONStringCharacter}*{ControlCharacter}{ControlCharacterFill}*\" {
    // Bad string with a forbidden control character inside
847
    driver.error(driver.loc_, "Invalid control in " + std::string(yytext));
848 849 850 851
}

\"{JSONStringCharacter}*\\{BadJSONEscapeSequence}[^\x00-\x1f"]*\" {
    // Bad string with a bad escape inside
852
    driver.error(driver.loc_, "Bad escape in " + std::string(yytext));
853 854 855 856
}
    
\"{JSONStringCharacter}*\\\" {
    // Bad string with an open escape at the end
857
    driver.error(driver.loc_, "Overflow escape in " + std::string(yytext));
858 859
}

860 861 862 863 864 865
"["    { 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_); }
866 867 868 869 870 871 872 873 874 875 876 877

{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 &) {
878
        driver.error(driver.loc_, "Failed to convert " + tmp + " to an integer.");
879 880 881
    }

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

885 886 887 888 889 890 891
[-+]?[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 &) {
892
        driver.error(driver.loc_, "Failed to convert " + tmp + " to a floating point.");
893 894
    }

895
    return isc::dhcp::Dhcp6Parser::make_FLOAT(fp, driver.loc_);
896 897 898 899
}

true|false {
    string tmp(yytext);
900
    return isc::dhcp::Dhcp6Parser::make_BOOLEAN(tmp == "true", driver.loc_);
901 902 903
}

null {
904
   return isc::dhcp::Dhcp6Parser::make_NULL_TYPE(driver.loc_);
905 906
}

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

909
<<EOF>> {
910 911
    if (driver.states_.empty()) {
        return isc::dhcp::Dhcp6Parser::make_END(driver.loc_);
Francis Dupont's avatar
Francis Dupont committed
912
    }
913 914 915 916
    driver.loc_ = driver.locs_.back();
    driver.locs_.pop_back();
    driver.file_ = driver.files_.back();
    driver.files_.pop_back();
917 918 919 920 921 922 923 924
    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
925
    parser6__delete_buffer(YY_CURRENT_BUFFER);
926 927
    parser6__switch_to_buffer(driver.states_.back());
    driver.states_.pop_back();
Francis Dupont's avatar
Francis Dupont committed
928 929 930 931

    BEGIN(DIR_EXIT);
}

932 933 934 935 936
%%

using namespace isc::dhcp;

void
937
Parser6Context::scanStringBegin(const std::string& str, ParserType parser_type)
938
{
939 940 941
    start_token_flag = true;
    start_token_value = parser_type;

942
    file_ = "<string>";
943
    sfile_ = 0;
944
    loc_.initialize(&file_);
945 946
    yy_flex_debug = trace_scanning_;
    YY_BUFFER_STATE buffer;
947
    buffer = yy_scan_bytes(str.c_str(), str.size());
948 949 950 951 952 953
    if (!buffer) {
        fatal("cannot scan string");
        // fatal() throws an exception so this can't be reached
    }
}

954
void
Francis Dupont's avatar
Francis Dupont committed
955 956
Parser6Context::scanFileBegin(FILE * f,
                              const std::string& filename,
957 958
                              ParserType parser_type)
{
959 960 961
    start_token_flag = true;
    start_token_value = parser_type;

962
    file_ = filename;
963
    sfile_ = f;
964
    loc_.initialize(&file_);
965 966 967 968 969 970
    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
971
        fatal("cannot scan file " + filename);
972
    }
973
    parser6__switch_to_buffer(buffer);
974 975 976
}

void
977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994
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();
    }
995 996
}

997 998
void
Parser6Context::includeFile(const std::string& filename) {
999
    if (states_.size() > 10) {
Francis Dupont's avatar
Francis Dupont committed
1000 1001 1002 1003 1004 1005 1006
        fatal("Too many nested include.");
    }

    FILE* f = fopen(filename.c_str(), "r");
    if (!f) {
        fatal("Can't open include file " + filename);
    }
1007 1008 1009 1010
    if (sfile_) {
        sfiles_.push_back(sfile_);
    }
    sfile_ = f;
1011
    states_.push_back(YY_CURRENT_BUFFER);
Francis Dupont's avatar
Francis Dupont committed
1012 1013 1014 1015 1016 1017
    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);
1018 1019 1020 1021
    files_.push_back(file_);
    file_ = filename;
    locs_.push_back(loc_);
    loc_.initialize(&file_);
Francis Dupont's avatar
Francis Dupont committed
1022 1023

    BEGIN(INITIAL);