4 * Copyright (C) 2014-2022 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 */
27 %option bison-locations
28 %option never-interactive
50 #include "tacontrol-bison.h"
52 /* option `yylineno' resets `yycolumn' to 0 after a newline */
53 /* (since version 2.5.30, March 2003) before the next token gets read; */
54 /* note we want both line number and column start with value 1 */
56 #define YY_USER_ACTION \
57 yylloc->first_line = yylineno + 1; \
58 yylloc->last_line = yylineno + 1; \
59 yylloc->first_column = yycolumn; \
60 yylloc->last_column = yycolumn + (int)yyleng - 1; \
63 #define YY_EXTRA_TYPE Control_Context*
65 #define YY_FATAL_ERROR(msg) TA_control_scanner_fatal_error(msg, yyscanner)
67 /* by default, `yylex' simply calls `exit' (via YY_FATAL_ERROR) */
68 /* in case of a (more or less) fatal error -- */
69 /* this is bad for a library, thus we use `longjmp' to catch this, */
70 /* together with a proper handler for YY_FATAL_ERROR */
72 #define YY_USER_INIT \
75 if (setjmp(yyextra->jump_buffer) != 0) \
77 /* error and error message in `context' already stored by */ \
78 /* `TA_control_scanner_fatal_error' */ \
79 return INTERNAL_FLEX_ERROR; \
83 /* this macro works around flex bug to suppress a compilation warning, */
84 /* cf. https://sourceforge.net/p/flex/bugs/115 */
86 #define YY_EXIT_FAILURE ((void)yyscanner, 2)
91 yylval->name = strdup(yytext); \
93 yyextra->error = TA_Err_Control_Allocation_Error; \
97 TA_control_scanner_fatal_error(const char* msg,
107 /* skip whitespace */
119 /* we want an EOE token at end of file, too */
132 /* skip escaped newline */
137 /* skip line comment */
143 /* values `0' and `-' need special treatment for number ranges */
148 | "0" [xX] [0-9a-fA-F]+
151 /* we don't support localized formats like a thousands separator */
153 yylval->integer = strtol(yytext, NULL, 0);
156 /* overflow or underflow */
157 yyextra->error = TA_Err_Control_Overflow;
162 (?x: [0-9]* "." [0-9]+
165 /* we don't support exponents, */
166 /* and we don't support localized formats like using `,' instead of `.' */
168 yylval->real = strtod(yytext, NULL);
169 if (yylval->real != 0 && errno == ERANGE)
172 yyextra->error = TA_Err_Control_Overflow;
180 /* delimiters, wildcard */
240 (?x: [A-Za-z._] [A-Za-z0-9._]*
250 yylval->character = yytext[0];
251 return INVALID_CHARACTER;
258 /* the following two routines set `context->error' */
261 yyalloc(yy_size_t size,
264 YY_EXTRA_TYPE context;
267 void* p = malloc(size);
270 context = yyget_extra(yyscanner);
271 context->error = TA_Err_Control_Allocation_Error;
282 YY_EXTRA_TYPE context;
285 void* p = realloc(ptr, size);
288 context = yyget_extra(yyscanner);
289 context->error = TA_Err_Control_Allocation_Error;
295 /* we reimplement this routine also to avoid a compiler warning, */
296 /* cf. https://sourceforge.net/p/flex/bugs/115 */
307 TA_control_scanner_fatal_error(const char* msg,
310 YY_EXTRA_TYPE context = yyget_extra(yyscanner);
313 /* allocation routines set a different error value */
315 context->error = TA_Err_Control_Flex_Error;
316 strncpy(context->errmsg, msg, sizeof (context->errmsg));
318 longjmp(context->jump_buffer, 1);
320 /* the next line, which we never reach, suppresses a warning about */
321 /* `yy_fatal_error' defined but not used */
322 yy_fatal_error(msg, yyscanner);
327 TA_control_scanner_init(Control_Context* context,
336 /* this function sets `errno' in case of error */
337 flex_error = yylex_init(&scanner);
338 if (flex_error && errno == ENOMEM)
340 context->error = FT_Err_Out_Of_Memory;
341 context->errmsg[0] = '\0';
345 /* initialize some context fields */
346 context->font = font;
347 context->error = TA_Err_Ok;
348 context->result = NULL;
349 context->scanner = scanner;
352 yyset_extra(context, scanner);
354 /* by default, `yy_scan_bytes' simply calls `exit' */
355 /* (via YY_FATAL_ERROR) in case of a (more or less) fatal error -- */
356 /* this is bad for a library, thus we use `longjmp' to catch this, */
357 /* together with a proper handler for YY_FATAL_ERROR */
358 if (setjmp(context->jump_buffer) != 0)
360 /* error and error message in `context' already stored by */
361 /* `TA_control_scanner_fatal_error' */
365 b = yy_scan_bytes(font->control_buf, font->control_len, scanner);
367 /* flex bug: these two fields are not initialized, */
368 /* causing zillions of valgrind errors; see */
369 /* https://sourceforge.net/p/flex/bugs/180 */
376 TA_control_scanner_done(Control_Context* context)
378 yylex_destroy(context->scanner);
387 "# 0 a p 1-3 x 0.3 y -0.2 @ 20-30; \\\n"
388 "0 exclam p 2-4 x 0.7 y -0.4 @ 6,7,9,10,11; \\\n"
389 "0 a p 2 x 0.5 @ 23-25";
399 Control_Context context;
401 YYSTYPE yylval_param;
402 YYLTYPE yylloc_param;
405 /* we only need the control instructions buffer */
406 font.control_buf = (char*)input;
407 font.control_len = strlen(input);
409 TA_control_scanner_init(&context, &font);
413 yyset_debug(1, context.scanner);
414 while (yylex(&yylval_param, &yylloc_param, context.scanner))
423 TA_control_scanner_done(&context);
430 /* end of tacontrol.flex */