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?"); }
};
}