4 * Copyright (C) 2014-2017 by Werner Lemberg.
6 * This file is part of the ttfautohint library, and may only be used,
7 * modified, and distributed under the terms given in `COPYING'. By
8 * continuing to use, modify, or distribute this file you indicate that you
9 * have read `COPYING' and understand and accept it fully.
11 * The file `COPYING' mentioned in the previous paragraph is distributed
12 * with the ttfautohint library.
16 * lexical analyzer for parsing ttfautohint control instructions
18 * Lexing errors are indicated by setting `context->error' to an appropriate
19 * value; fatal lexer errors return token `INTERNAL_FLEX_ERROR'.
22 /* you should use flex version >= 2.5.39 to avoid various buglets */
23 /* that don't have work-arounds */
25 %option outfile="tacontrol-flex.c"
26 %option header-file="tacontrol-flex.h"
30 %option bison-locations
31 %option never-interactive
53 #include "tacontrol-bison.h"
55 /* option `yylineno' resets `yycolumn' to 0 after a newline */
56 /* (since version 2.5.30, March 2003) before the next token gets read; */
57 /* note we want both line number and column start with value 1 */
59 #define YY_USER_ACTION \
60 yylloc->first_line = yylineno + 1; \
61 yylloc->last_line = yylineno + 1; \
62 yylloc->first_column = yycolumn; \
63 yylloc->last_column = yycolumn + (int)yyleng - 1; \
66 #define YY_EXTRA_TYPE Control_Context*
68 #define YY_FATAL_ERROR(msg) TA_control_scanner_fatal_error(msg, yyscanner)
70 /* by default, `yylex' simply calls `exit' (via YY_FATAL_ERROR) */
71 /* in case of a (more or less) fatal error -- */
72 /* this is bad for a library, thus we use `longjmp' to catch this, */
73 /* together with a proper handler for YY_FATAL_ERROR */
75 #define YY_USER_INIT \
78 if (setjmp(yyextra->jump_buffer) != 0) \
80 /* error and error message in `context' already stored by */ \
81 /* `TA_control_scanner_fatal_error' */ \
82 return INTERNAL_FLEX_ERROR; \
86 /* this macro works around flex bug to suppress a compilation warning, */
87 /* cf. https://sourceforge.net/p/flex/bugs/115 */
89 #define YY_EXIT_FAILURE ((void)yyscanner, 2)
94 yylval->name = strdup(yytext); \
96 yyextra->error = TA_Err_Control_Allocation_Error; \
100 TA_control_scanner_fatal_error(const char* msg,
110 /* skip whitespace */
122 /* we want an EOE token at end of file, too */
135 /* skip escaped newline */
140 /* skip line comment */
146 /* values `0' and `-' need special treatment for number ranges */
151 | "0" [xX] [0-9a-fA-F]+
154 /* we don't support localized formats like a thousands separator */
156 yylval->integer = strtol(yytext, NULL, 0);
159 /* overflow or underflow */
160 yyextra->error = TA_Err_Control_Overflow;
165 (?x: [0-9]* "." [0-9]+
168 /* we don't support exponents, */
169 /* and we don't support localized formats like using `,' instead of `.' */
171 yylval->real = strtod(yytext, NULL);
172 if (yylval->real != 0 && errno == ERANGE)
175 yyextra->error = TA_Err_Control_Overflow;
183 /* delimiters, wildcard */
243 (?x: [A-Za-z._] [A-Za-z0-9._]*
253 yylval->character = yytext[0];
254 return INVALID_CHARACTER;
261 /* the following two routines set `context->error' */
264 yyalloc(yy_size_t size,
267 YY_EXTRA_TYPE context;
270 void* p = malloc(size);
273 context = yyget_extra(yyscanner);
274 context->error = TA_Err_Control_Allocation_Error;
285 YY_EXTRA_TYPE context;
288 void* p = realloc(ptr, size);
291 context = yyget_extra(yyscanner);
292 context->error = TA_Err_Control_Allocation_Error;
298 /* we reimplement this routine also to avoid a compiler warning, */
299 /* cf. https://sourceforge.net/p/flex/bugs/115 */
310 TA_control_scanner_fatal_error(const char* msg,
313 YY_EXTRA_TYPE context = yyget_extra(yyscanner);
316 /* allocation routines set a different error value */
318 context->error = TA_Err_Control_Flex_Error;
319 strncpy(context->errmsg, msg, sizeof (context->errmsg));
321 longjmp(context->jump_buffer, 1);
323 /* the next line, which we never reach, suppresses a warning about */
324 /* `yy_fatal_error' defined but not used */
325 yy_fatal_error(msg, yyscanner);
330 TA_control_scanner_init(Control_Context* context,
339 /* this function sets `errno' in case of error */
340 flex_error = yylex_init(&scanner);
341 if (flex_error && errno == ENOMEM)
343 context->error = FT_Err_Out_Of_Memory;
344 context->errmsg[0] = '\0';
348 /* initialize some context fields */
349 context->font = font;
350 context->error = TA_Err_Ok;
351 context->result = NULL;
352 context->scanner = scanner;
355 yyset_extra(context, scanner);
357 /* by default, `yy_scan_bytes' simply calls `exit' */
358 /* (via YY_FATAL_ERROR) in case of a (more or less) fatal error -- */
359 /* this is bad for a library, thus we use `longjmp' to catch this, */
360 /* together with a proper handler for YY_FATAL_ERROR */
361 if (setjmp(context->jump_buffer) != 0)
363 /* error and error message in `context' already stored by */
364 /* `TA_control_scanner_fatal_error' */
368 b = yy_scan_bytes(font->control_buf, font->control_len, scanner);
370 /* flex bug: these two fields are not initialized, */
371 /* causing zillions of valgrind errors; see */
372 /* https://sourceforge.net/p/flex/bugs/180 */
379 TA_control_scanner_done(Control_Context* context)
381 yylex_destroy(context->scanner);
390 "# 0 a p 1-3 x 0.3 y -0.2 @ 20-30; \\\n"
391 "0 exclam p 2-4 x 0.7 y -0.4 @ 6,7,9,10,11; \\\n"
392 "0 a p 2 x 0.5 @ 23-25";
402 Control_Context context;
404 YYSTYPE yylval_param;
405 YYLTYPE yylloc_param;
408 /* we only need the control instructions buffer */
409 font.control_buf = (char*)input;
410 font.control_len = strlen(input);
412 TA_control_scanner_init(&context, &font);
416 yyset_debug(1, context.scanner);
417 while (yylex(&yylval_param, &yylloc_param, context.scanner))
426 TA_control_scanner_done(&context);
433 /* end of tacontrol.flex */