ovn-controller: Optimize lex_token memory usage.
[cascardo/ovs.git] / ovn / lib / lex.c
1 /*
2  * Copyright (c) 2015 Nicira, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at:
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include <config.h>
18 #include "lex.h"
19 #include <ctype.h>
20 #include <errno.h>
21 #include <stdarg.h>
22 #include "openvswitch/dynamic-string.h"
23 #include "json.h"
24 #include "packets.h"
25 #include "util.h"
26 \f
27 /* Returns a string that represents 'format'. */
28 const char *
29 lex_format_to_string(enum lex_format format)
30 {
31     switch (format) {
32     case LEX_F_DECIMAL:
33         return "decimal";
34     case LEX_F_HEXADECIMAL:
35         return "hexadecimal";
36     case LEX_F_IPV4:
37         return "IPv4";
38     case LEX_F_IPV6:
39         return "IPv6";
40     case LEX_F_ETHERNET:
41         return "Ethernet";
42     default:
43         abort();
44     }
45 }
46 \f
47 /* Initializes 'token'. */
48 void
49 lex_token_init(struct lex_token *token)
50 {
51     token->type = LEX_T_END;
52     token->s = NULL;
53 }
54
55 /* Frees memory owned by 'token'. */
56 void
57 lex_token_destroy(struct lex_token *token)
58 {
59     if (token->s != token->buffer) {
60         free(token->s);
61     }
62     token->s = NULL;
63 }
64
65 /* Exchanges 'a' and 'b'. */
66 void
67 lex_token_swap(struct lex_token *a, struct lex_token *b)
68 {
69     struct lex_token tmp = *a;
70     *a = *b;
71     *b = tmp;
72
73     /* Before swap, if 's' was pointed to 'buffer', its value shall be changed
74      * to point to the 'buffer' with the copied value. */
75     if (a->s == b->buffer) {
76         a->s = a->buffer;
77     }
78     if (b->s == a->buffer) {
79         b->s = b->buffer;
80     }
81 }
82
83 /* The string 's' need not be null-terminated at 'length'. */
84 void
85 lex_token_strcpy(struct lex_token *token, const char *s, size_t length)
86 {
87     lex_token_destroy(token);
88     token->s = (length + 1 <= sizeof token->buffer
89                 ? token->buffer
90                 : xmalloc(length + 1));
91     memcpy(token->s, s, length);
92     token->buffer[length] = '\0';
93 }
94
95 void
96 lex_token_strset(struct lex_token *token, char *s)
97 {
98     lex_token_destroy(token);
99     token->s = s;
100 }
101
102 void
103 lex_token_vsprintf(struct lex_token *token, const char *format, va_list args)
104 {
105     lex_token_destroy(token);
106
107     va_list args2;
108     va_copy(args2, args);
109     token->s = (vsnprintf(token->buffer, sizeof token->buffer, format, args)
110                 < sizeof token->buffer
111                 ? token->buffer
112                 : xvasprintf(format, args2));
113     va_end(args2);
114 }
115 \f
116 /* lex_token_format(). */
117
118 static size_t
119 lex_token_n_zeros(enum lex_format format)
120 {
121     switch (format) {
122     case LEX_F_DECIMAL:     return offsetof(union mf_subvalue, integer);
123     case LEX_F_HEXADECIMAL: return 0;
124     case LEX_F_IPV4:        return offsetof(union mf_subvalue, ipv4);
125     case LEX_F_IPV6:        return offsetof(union mf_subvalue, ipv6);
126     case LEX_F_ETHERNET:    return offsetof(union mf_subvalue, mac);
127     default: OVS_NOT_REACHED();
128     }
129 }
130
131 /* Returns the effective format for 'token', that is, the format in which it
132  * should actually be printed.  This is ordinarily the same as 'token->format',
133  * but it's always possible that someone sets up a token with a format that
134  * won't work for a value, e.g. 'token->value' is wider than 32 bits but the
135  * format is LEX_F_IPV4.  (The lexer itself won't do that; this is an attempt
136  * to avoid confusion in the future.) */
137 static enum lex_format
138 lex_token_get_format(const struct lex_token *token)
139 {
140     size_t n_zeros = lex_token_n_zeros(token->format);
141     return (is_all_zeros(&token->value, n_zeros)
142             && (token->type != LEX_T_MASKED_INTEGER
143                 || is_all_zeros(&token->mask, n_zeros))
144             ? token->format
145             : LEX_F_HEXADECIMAL);
146 }
147
148 static void
149 lex_token_format_value(const union mf_subvalue *value,
150                        enum lex_format format, struct ds *s)
151 {
152     switch (format) {
153     case LEX_F_DECIMAL:
154         ds_put_format(s, "%"PRIu64, ntohll(value->integer));
155         break;
156
157     case LEX_F_HEXADECIMAL:
158         mf_format_subvalue(value, s);
159         break;
160
161     case LEX_F_IPV4:
162         ds_put_format(s, IP_FMT, IP_ARGS(value->ipv4));
163         break;
164
165     case LEX_F_IPV6:
166         ipv6_format_addr(&value->ipv6, s);
167         break;
168
169     case LEX_F_ETHERNET:
170         ds_put_format(s, ETH_ADDR_FMT, ETH_ADDR_ARGS(value->mac));
171         break;
172
173     default:
174         OVS_NOT_REACHED();
175     }
176
177 }
178
179 static void
180 lex_token_format_masked_integer(const struct lex_token *token, struct ds *s)
181 {
182     enum lex_format format = lex_token_get_format(token);
183
184     lex_token_format_value(&token->value, format, s);
185     ds_put_char(s, '/');
186
187     const union mf_subvalue *mask = &token->mask;
188     if (format == LEX_F_IPV4 && ip_is_cidr(mask->ipv4)) {
189         ds_put_format(s, "%d", ip_count_cidr_bits(mask->ipv4));
190     } else if (token->format == LEX_F_IPV6 && ipv6_is_cidr(&mask->ipv6)) {
191         ds_put_format(s, "%d", ipv6_count_cidr_bits(&mask->ipv6));
192     } else {
193         lex_token_format_value(&token->mask, format, s);
194     }
195 }
196
197 /* Appends a string representation of 'token' to 's', in a format that can be
198  * losslessly parsed back by the lexer.  (LEX_T_END and LEX_T_ERROR can't be
199  * parsed back.) */
200 void
201 lex_token_format(const struct lex_token *token, struct ds *s)
202 {
203     switch (token->type) {
204     case LEX_T_END:
205         ds_put_cstr(s, "$");
206         break;
207
208     case LEX_T_ID:
209         ds_put_cstr(s, token->s);
210         break;
211
212     case LEX_T_ERROR:
213         ds_put_cstr(s, "error(");
214         json_string_escape(token->s, s);
215         ds_put_char(s, ')');
216         break;
217
218     case LEX_T_STRING:
219         json_string_escape(token->s, s);
220         break;
221
222     case LEX_T_INTEGER:
223         lex_token_format_value(&token->value, lex_token_get_format(token), s);
224         break;
225
226     case LEX_T_MASKED_INTEGER:
227         lex_token_format_masked_integer(token, s);
228         break;
229
230     case LEX_T_LPAREN:
231         ds_put_cstr(s, "(");
232         break;
233     case LEX_T_RPAREN:
234         ds_put_cstr(s, ")");
235         break;
236     case LEX_T_LCURLY:
237         ds_put_cstr(s, "{");
238         break;
239     case LEX_T_RCURLY:
240         ds_put_cstr(s, "}");
241         break;
242     case LEX_T_LSQUARE:
243         ds_put_cstr(s, "[");
244         break;
245     case LEX_T_RSQUARE:
246         ds_put_cstr(s, "]");
247         break;
248     case LEX_T_EQ:
249         ds_put_cstr(s, "==");
250         break;
251     case LEX_T_NE:
252         ds_put_cstr(s, "!=");
253         break;
254     case LEX_T_LT:
255         ds_put_cstr(s, "<");
256         break;
257     case LEX_T_LE:
258         ds_put_cstr(s, "<=");
259         break;
260     case LEX_T_GT:
261         ds_put_cstr(s, ">");
262         break;
263     case LEX_T_GE:
264         ds_put_cstr(s, ">=");
265         break;
266     case LEX_T_LOG_NOT:
267         ds_put_cstr(s, "!");
268         break;
269     case LEX_T_LOG_AND:
270         ds_put_cstr(s, "&&");
271         break;
272     case LEX_T_LOG_OR:
273         ds_put_cstr(s, "||");
274         break;
275     case LEX_T_ELLIPSIS:
276         ds_put_cstr(s, "..");
277         break;
278     case LEX_T_COMMA:
279         ds_put_cstr(s, ",");
280         break;
281     case LEX_T_SEMICOLON:
282         ds_put_cstr(s, ";");
283         break;
284     case LEX_T_EQUALS:
285         ds_put_cstr(s, "=");
286         break;
287     case LEX_T_EXCHANGE:
288         ds_put_cstr(s, "<->");
289         break;
290     case LEX_T_DECREMENT:
291         ds_put_cstr(s, "--");
292         break;
293     default:
294         OVS_NOT_REACHED();
295     }
296
297 }
298 \f
299 /* lex_token_parse(). */
300
301 static void OVS_PRINTF_FORMAT(2, 3)
302 lex_error(struct lex_token *token, const char *message, ...)
303 {
304     ovs_assert(!token->s);
305     token->type = LEX_T_ERROR;
306
307     va_list args;
308     va_start(args, message);
309     lex_token_vsprintf(token, message, args);
310     va_end(args);
311 }
312
313 static void
314 lex_parse_hex_integer(const char *start, size_t len, struct lex_token *token)
315 {
316     const char *in = start + (len - 1);
317     uint8_t *out = token->value.u8 + (sizeof token->value.u8 - 1);
318
319     for (int i = 0; i < len; i++) {
320         int hexit = hexit_value(in[-i]);
321         if (hexit < 0) {
322             lex_error(token, "Invalid syntax in hexadecimal constant.");
323             return;
324         }
325         if (hexit && i / 2 >= sizeof token->value.u8) {
326             lex_error(token, "Hexadecimal constant requires more than "
327                       "%"PRIuSIZE" bits.", 8 * sizeof token->value.u8);
328             return;
329         }
330         out[-(i / 2)] |= i % 2 ? hexit << 4 : hexit;
331     }
332     token->format = LEX_F_HEXADECIMAL;
333 }
334
335 static const char *
336 lex_parse_integer__(const char *p, struct lex_token *token)
337 {
338     lex_token_init(token);
339     token->type = LEX_T_INTEGER;
340     memset(&token->value, 0, sizeof token->value);
341     const char *start = p;
342     const char *end = start;
343     while (isalnum((unsigned char) *end) || *end == ':'
344            || (*end == '.' && end[1] != '.')) {
345         end++;
346     }
347     size_t len = end - start;
348
349     int n;
350     struct eth_addr mac;
351
352     if (!len) {
353         lex_error(token, "Integer constant expected.");
354     } else if (len == 17
355                && ovs_scan(start, ETH_ADDR_SCAN_FMT"%n",
356                            ETH_ADDR_SCAN_ARGS(mac), &n)
357                && n == len) {
358         token->value.mac = mac;
359         token->format = LEX_F_ETHERNET;
360     } else if (start + strspn(start, "0123456789") == end) {
361         if (p[0] == '0' && len > 1) {
362             lex_error(token, "Decimal constants must not have leading zeros.");
363         } else {
364             unsigned long long int integer;
365             char *tail;
366
367             errno = 0;
368             integer = strtoull(p, &tail, 10);
369             if (tail != end || errno == ERANGE) {
370                 lex_error(token, "Decimal constants must be less than 2**64.");
371             } else {
372                 token->value.integer = htonll(integer);
373                 token->format = LEX_F_DECIMAL;
374             }
375         }
376     } else if (p[0] == '0' && (p[1] == 'x' || p[1] == 'X')) {
377         if (len > 2) {
378             lex_parse_hex_integer(start + 2, len - 2, token);
379         } else {
380             lex_error(token, "Hex digits expected following 0%c.", p[1]);
381         }
382     } else if (len < INET6_ADDRSTRLEN) {
383         char copy[INET6_ADDRSTRLEN];
384         memcpy(copy, p, len);
385         copy[len] = '\0';
386
387         if (ip_parse(copy, &token->value.ipv4)) {
388             token->format = LEX_F_IPV4;
389         } else if (ipv6_parse(copy, &token->value.ipv6)) {
390             token->format = LEX_F_IPV6;
391         } else {
392             lex_error(token, "Invalid numeric constant.");
393         }
394     } else {
395         lex_error(token, "Invalid numeric constant.");
396     }
397
398     ovs_assert(token->type == LEX_T_INTEGER || token->type == LEX_T_ERROR);
399     return end;
400 }
401
402 static const char *
403 lex_parse_mask(const char *p, struct lex_token *token)
404 {
405     struct lex_token mask;
406
407     /* Parse just past the '/' as a second integer.  Handle errors. */
408     p = lex_parse_integer__(p + 1, &mask);
409     if (mask.type == LEX_T_ERROR) {
410         lex_token_swap(&mask, token);
411         lex_token_destroy(&mask);
412         return p;
413     }
414     ovs_assert(mask.type == LEX_T_INTEGER);
415
416     /* Now convert the value and mask into a masked integer token.
417      * We have a few special cases. */
418     token->type = LEX_T_MASKED_INTEGER;
419     memset(&token->mask, 0, sizeof token->mask);
420     uint32_t prefix_bits = ntohll(mask.value.integer);
421     if (token->format == mask.format) {
422         /* Same format value and mask is always OK. */
423         token->mask = mask.value;
424     } else if (token->format == LEX_F_IPV4
425                && mask.format == LEX_F_DECIMAL
426                && prefix_bits <= 32) {
427         /* IPv4 address with decimal mask is a CIDR prefix. */
428         token->mask.integer = htonll(ntohl(be32_prefix_mask(prefix_bits)));
429     } else if (token->format == LEX_F_IPV6
430                && mask.format == LEX_F_DECIMAL
431                && prefix_bits <= 128) {
432         /* IPv6 address with decimal mask is a CIDR prefix. */
433         token->mask.ipv6 = ipv6_create_mask(prefix_bits);
434     } else if (token->format == LEX_F_DECIMAL
435                && mask.format == LEX_F_HEXADECIMAL
436                && token->value.integer == 0) {
437         /* Special case for e.g. 0/0x1234. */
438         token->format = LEX_F_HEXADECIMAL;
439         token->mask = mask.value;
440     } else {
441         lex_error(token, "Value and mask have incompatible formats.");
442         return p;
443     }
444
445     /* Check invariant that a 1-bit in the value corresponds to a 1-bit in the
446      * mask. */
447     for (int i = 0; i < ARRAY_SIZE(token->mask.be32); i++) {
448         ovs_be32 v = token->value.be32[i];
449         ovs_be32 m = token->mask.be32[i];
450
451         if (v & ~m) {
452             lex_error(token, "Value contains unmasked 1-bits.");
453             break;
454         }
455     }
456
457     /* Done! */
458     lex_token_destroy(&mask);
459     return p;
460 }
461
462 static const char *
463 lex_parse_integer(const char *p, struct lex_token *token)
464 {
465     p = lex_parse_integer__(p, token);
466     if (token->type == LEX_T_INTEGER && *p == '/') {
467         p = lex_parse_mask(p, token);
468     }
469     return p;
470 }
471
472 static const char *
473 lex_parse_string(const char *p, struct lex_token *token)
474 {
475     const char *start = ++p;
476     char * s = NULL;
477     for (;;) {
478         switch (*p) {
479         case '\0':
480             lex_error(token, "Input ends inside quoted string.");
481             return p;
482
483         case '"':
484             token->type = (json_string_unescape(start, p - start, &s)
485                            ? LEX_T_STRING : LEX_T_ERROR);
486             lex_token_strset(token, s);
487             return p + 1;
488
489         case '\\':
490             p++;
491             if (*p) {
492                 p++;
493             }
494             break;
495
496         default:
497             p++;
498             break;
499         }
500     }
501 }
502
503 static bool
504 lex_is_id1(unsigned char c)
505 {
506     return ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')
507             || c == '_' || c == '.');
508 }
509
510 static bool
511 lex_is_idn(unsigned char c)
512 {
513     return lex_is_id1(c) || (c >= '0' && c <= '9');
514 }
515
516 static const char *
517 lex_parse_id(const char *p, struct lex_token *token)
518 {
519     const char *start = p;
520
521     do {
522         p++;
523     } while (lex_is_idn(*p));
524
525     token->type = LEX_T_ID;
526     lex_token_strcpy(token, start, p - start);
527     return p;
528 }
529
530 /* Initializes 'token' and parses the first token from the beginning of
531  * null-terminated string 'p' into 'token'.  Stores a pointer to the start of
532  * the token (after skipping white space and comments, if any) into '*startp'.
533  * Returns the character position at which to begin parsing the next token. */
534 const char *
535 lex_token_parse(struct lex_token *token, const char *p, const char **startp)
536 {
537     lex_token_init(token);
538
539 next:
540     *startp = p;
541     switch (*p) {
542     case '\0':
543         token->type = LEX_T_END;
544         return p;
545
546     case ' ': case '\t': case '\n': case '\r':
547         p++;
548         goto next;
549
550     case '/':
551         p++;
552         if (*p == '/') {
553             do {
554                 p++;
555             } while (*p != '\0' && *p != '\n');
556             goto next;
557         } else if (*p == '*') {
558             p++;
559             for (;;) {
560                 if (*p == '*' && p[1] == '/') {
561                     p += 2;
562                     goto next;
563                 } else if (*p == '\0' || *p == '\n') {
564                     lex_error(token, "`/*' without matching `*/'.");
565                     return p;
566                 } else {
567                     p++;
568                 }
569             }
570             goto next;
571         } else {
572             lex_error(token,
573                       "`/' is only valid as part of `//' or `/*'.");
574         }
575         break;
576
577     case '(':
578         token->type = LEX_T_LPAREN;
579         p++;
580         break;
581
582     case ')':
583         token->type = LEX_T_RPAREN;
584         p++;
585         break;
586
587     case '{':
588         token->type = LEX_T_LCURLY;
589         p++;
590         break;
591
592     case '}':
593         token->type = LEX_T_RCURLY;
594         p++;
595         break;
596
597     case '[':
598         token->type = LEX_T_LSQUARE;
599         p++;
600         break;
601
602     case ']':
603         token->type = LEX_T_RSQUARE;
604         p++;
605         break;
606
607     case '=':
608         p++;
609         if (*p == '=') {
610             token->type = LEX_T_EQ;
611             p++;
612         } else {
613             token->type = LEX_T_EQUALS;
614         }
615         break;
616
617     case '!':
618         p++;
619         if (*p == '=') {
620             token->type = LEX_T_NE;
621             p++;
622         } else {
623             token->type = LEX_T_LOG_NOT;
624         }
625         break;
626
627     case '&':
628         p++;
629         if (*p == '&') {
630             token->type = LEX_T_LOG_AND;
631             p++;
632         } else {
633             lex_error(token, "`&' is only valid as part of `&&'.");
634         }
635         break;
636
637     case '|':
638         p++;
639         if (*p == '|') {
640             token->type = LEX_T_LOG_OR;
641             p++;
642         } else {
643             lex_error(token, "`|' is only valid as part of `||'.");
644         }
645         break;
646
647     case '<':
648         p++;
649         if (*p == '=') {
650             token->type = LEX_T_LE;
651             p++;
652         } else if (*p == '-' && p[1] == '>') {
653             token->type = LEX_T_EXCHANGE;
654             p += 2;
655         } else {
656             token->type = LEX_T_LT;
657         }
658         break;
659
660     case '>':
661         p++;
662         if (*p == '=') {
663             token->type = LEX_T_GE;
664             p++;
665         } else {
666             token->type = LEX_T_GT;
667         }
668         break;
669
670     case '.':
671         p++;
672         if (*p == '.') {
673             token->type = LEX_T_ELLIPSIS;
674             p++;
675         } else {
676             lex_error(token, "`.' is only valid as part of `..' or a number.");
677         }
678         break;
679
680     case ',':
681         p++;
682         token->type = LEX_T_COMMA;
683         break;
684
685     case ';':
686         p++;
687         token->type = LEX_T_SEMICOLON;
688         break;
689
690     case '-':
691         p++;
692         if (*p == '-') {
693             token->type = LEX_T_DECREMENT;
694             p++;
695         } else {
696             lex_error(token, "`-' is only valid as part of `--'.");
697         }
698         break;
699
700     case '0': case '1': case '2': case '3': case '4':
701     case '5': case '6': case '7': case '8': case '9':
702     case ':':
703         p = lex_parse_integer(p, token);
704         break;
705
706     case '"':
707         p = lex_parse_string(p, token);
708         break;
709
710     case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
711     case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
712         /* We need to distinguish an Ethernet address or IPv6 address from an
713          * identifier.  Fortunately, Ethernet addresses and IPv6 addresses that
714          * are ambiguous based on the first character, always start with hex
715          * digits followed by a colon, but identifiers never do. */
716         p = (p[strspn(p, "0123456789abcdefABCDEF")] == ':'
717              ? lex_parse_integer(p, token)
718              : lex_parse_id(p, token));
719         break;
720
721     default:
722         if (lex_is_id1(*p)) {
723             p = lex_parse_id(p, token);
724         } else {
725             if (isprint((unsigned char) *p)) {
726                 lex_error(token, "Invalid character `%c' in input.", *p);
727             } else {
728                 lex_error(token, "Invalid byte 0x%d in input.", *p);
729             }
730             p++;
731         }
732         break;
733     }
734
735     return p;
736 }
737 \f
738 /* Initializes 'lexer' for parsing 'input'.
739  *
740  * While the lexer is in use, 'input' must remain available, but the caller
741  * otherwise retains ownership of 'input'.
742  *
743  * The caller must call lexer_get() to obtain the first token. */
744 void
745 lexer_init(struct lexer *lexer, const char *input)
746 {
747     lexer->input = input;
748     lexer->start = NULL;
749     lex_token_init(&lexer->token);
750 }
751
752 /* Frees storage associated with 'lexer'. */
753 void
754 lexer_destroy(struct lexer *lexer)
755 {
756     lex_token_destroy(&lexer->token);
757 }
758
759 /* Obtains the next token from 'lexer' into 'lexer->token', and returns the
760  * token's type.  The caller may examine 'lexer->token' directly to obtain full
761  * information about the token. */
762 enum lex_type
763 lexer_get(struct lexer *lexer)
764 {
765     lex_token_destroy(&lexer->token);
766     lexer->input = lex_token_parse(&lexer->token, lexer->input, &lexer->start);
767     return lexer->token.type;
768 }
769
770 /* Returns the type of the next token that will be fetched by lexer_get(),
771  * without advancing 'lexer->token' to that token. */
772 enum lex_type
773 lexer_lookahead(const struct lexer *lexer)
774 {
775     struct lex_token next;
776     enum lex_type type;
777     const char *start;
778
779     lex_token_parse(&next, lexer->input, &start);
780     type = next.type;
781     lex_token_destroy(&next);
782     return type;
783 }
784
785 /* If 'lexer''s current token has the given 'type', advances 'lexer' to the
786  * next token and returns true.  Otherwise returns false. */
787 bool
788 lexer_match(struct lexer *lexer, enum lex_type type)
789 {
790     if (lexer->token.type == type) {
791         lexer_get(lexer);
792         return true;
793     } else {
794         return false;
795     }
796 }
797
798 /* If 'lexer''s current token is the identifier given in 'id', advances 'lexer'
799  * to the next token and returns true.  Otherwise returns false.  */
800 bool
801 lexer_match_id(struct lexer *lexer, const char *id)
802 {
803     if (lexer->token.type == LEX_T_ID && !strcmp(lexer->token.s, id)) {
804         lexer_get(lexer);
805         return true;
806     } else {
807         return false;
808     }
809 }
810
811 bool
812 lexer_is_int(const struct lexer *lexer)
813 {
814     return (lexer->token.type == LEX_T_INTEGER
815             && lexer->token.format == LEX_F_DECIMAL
816             && ntohll(lexer->token.value.integer) <= INT_MAX);
817 }
818
819 bool
820 lexer_get_int(struct lexer *lexer, int *value)
821 {
822     if (lexer_is_int(lexer)) {
823         *value = ntohll(lexer->token.value.integer);
824         lexer_get(lexer);
825         return true;
826     } else {
827         *value = 0;
828         return false;
829     }
830 }