/** @license 2022 Neil Edelman, distributed under the terms of the [MIT License](https://opensource.org/licenses/MIT). Lexer for journal entries. @std C89/90 */ #include #include #include #include #include static int parse_uint(const char *s, const char *e, unsigned *u) { uint32_t n = 0; for ( ; s < e; ++s) { unsigned digit = (unsigned)(*s - '0'); assert(digit < 10); if(n > (UINT_MAX - digit) / 10) return errno = ERANGE, 0; /* check */ n = n * 10 + digit; } *u = n; return 1; } static int parse_double(const char *s0, const char *s1, double *d) { char *finish; assert(d && s0 && s0 < s1); *d = strtod(s0, &finish); return !errno && ((finish == s1) || (errno = EDOM, 0)); } static int lex_line(const char *YYCURSOR, unsigned *const u) { const char *YYMARKER, *o1, *o2, *o3, *o4; double d; /*!stags:re2c format = 'const char *@@;\n'; */ /*!re2c re2c:yyfill:enable = 0; re2c:flags:tags = 1; re2c:define:YYCTYPE = char; keyword = [a-z][a-z0-9_-]{0,64}; // uppercase is lame octet = [0-9] | [1-9][0-9] | [1][0-9][0-9] | [2][0-4][0-9] | [2][5][0-5]; dot = [.]; end = [\x00]; eol = [\n]; w = [ \t]*; double = [0-9]* "." [0-9]+ | [0-9]+; */ errno = 0; /* For accuracy detecting errors. */ text: /*!re2c "\\[" | "\\![" { goto text; } "[" { goto custom; } "![" { goto image; } @o1 octet dot @o2 octet dot @o3 octet dot @o4 octet end { unsigned u1, u2, u3, u4; if(!parse_uint(o1, o2 - 1, &u1) || !parse_uint(o2, o3 - 1, &u2) || !parse_uint(o3, o4 - 1, &u3) || !parse_uint(o4, YYCURSOR - 1, &u4)) return 0; *u = u4 + (u3 << 8) + (u2 << 16) + (u1 << 24); return 1; } * { return errno = EILSEQ, 0; } */ image: /*!re2c "osm" "](" @o1 double @o2 "," @o3 double @o4 ")" { printf("Got a map.\n"); if(!parse_double(o1, o2, &d)) return 0; printf("Latitude %f.\n", d); if(!parse_double(o3, o4, &d)) return 0; printf("Longitude %f.\n", d); goto text; } * { return errno = EILSEQ, 0; } */ custom: /*!re2c glider = "glider" ":" ; flight = "flight" ":" ; * { return errno = EILSEQ, 0; } */ } int main(int argc, char **argv) { unsigned u; if(!lex_line("1.2.3.4", &u)) goto catch; printf("0x%x\n", u); if(!lex_line("1.2.3.49999999999999999", &u)) goto catch; return EXIT_SUCCESS; catch: perror("interpret"); return EXIT_FAILURE; }