4 * Copyright (C) 2014 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 delta exceptions
18 * Lexing errors are indicated with tokens like `BAD_INTEGER'; fatal lexer
19 * errors return token `INTERNAL_FLEX_ERROR' and set `context->error' to an
23 %option outfile="tadeltas-flex.c"
24 %option header-file="tadeltas-flex.h"
28 %option bison-locations
29 %option never-interactive
45 #include "tadeltas-bison.h"
47 /* option `yylineno' resets `yycolumn' to 0 after a newline */
48 /* (since version 2.5.30, March 2003) before the next token gets read; */
49 /* note we want both line number and column start with value 1 */
51 #define YY_USER_ACTION \
52 yylloc->first_line = yylineno + 1; \
53 yylloc->last_line = yylineno + 1; \
54 yylloc->first_column = yycolumn; \
55 yylloc->last_column = yycolumn + yyleng - 1; \
58 #define YY_EXTRA_TYPE Deltas_Context*
60 #define YY_FATAL_ERROR(msg) TA_deltas_scanner_fatal_error(msg, yyscanner)
62 /* by default, `yylex' simply calls `exit' (via YY_FATAL_ERROR) */
63 /* in case of a (more or less) fatal error -- */
64 /* this is bad for a library, thus we use `longjmp' to catch this, */
65 /* together with a proper handler for YY_FATAL_ERROR */
67 #define YY_USER_INIT \
70 if (setjmp(yyextra->jump_buffer) != 0) \
72 /* error and error message in `context' already stored by */ \
73 /* `TA_deltas_scanner_fatal_error' */ \
74 return INTERNAL_FLEX_ERROR; \
78 /* this macro works around flex bug to suppress a compilation warning, */
79 /* cf. https://sourceforge.net/p/flex/bugs/115 */
81 #define YY_EXIT_FAILURE ((void)yyscanner, 2)
84 TA_deltas_scanner_fatal_error(const char* msg,
108 /* we want an EOE token at end of file, too */
123 /* skip escaped newline */
128 /* skip line comment */
134 /* values `0' and `-' need special treatment for number ranges */
139 | "0" [xX] [0-9a-fA-F]+
142 /* we don't support localized formats like a thousands separator */
144 yylval->integer = strtol(yytext, NULL, 0);
147 /* overflow or underflow */
153 (?x: [0-9]* "." [0-9]+
156 /* we don't support exponents, */
157 /* and we don't support localized formats like using `,' instead of `.' */
159 yylval->real = strtod(yytext, NULL);
160 if (yylval->real && errno == ERANGE)
175 (?x: [A-Za-z._] [A-Za-z0-9._]*
177 yylval->name = strdup(yytext);
180 /* allocation error */
190 return INVALID_CHARACTER;
197 /* the following two routines set `context->error' */
200 yyalloc(yy_size_t size,
203 YY_EXTRA_TYPE context;
206 void* p = malloc(size);
209 context = yyget_extra(yyscanner);
210 context->error = TA_Err_Deltas_Allocation_Error;
221 YY_EXTRA_TYPE context;
224 void* p = realloc(ptr, size);
227 context = yyget_extra(yyscanner);
228 context->error = TA_Err_Deltas_Allocation_Error;
234 /* we reimplement this routine also to avoid a compiler warning, */
235 /* cf. https://sourceforge.net/p/flex/bugs/115 */
246 TA_deltas_scanner_fatal_error(const char* msg,
249 YY_EXTRA_TYPE context = yyget_extra(yyscanner);
252 /* allocation routines set a different error value */
254 context->error = TA_Err_Deltas_Flex_Error;
255 strncpy(context->errmsg, msg, sizeof (context->errmsg));
257 longjmp(context->jump_buffer, 1);
259 /* the next line, which we never reach, suppresses a warning about */
260 /* `yy_fatal_error' defined but not used */
261 yy_fatal_error(msg, yyscanner);
266 TA_deltas_scanner_init(Deltas_Context* context,
275 /* this function sets `errno' in case of error */
276 flex_error = yylex_init(&scanner);
277 if (flex_error && errno == ENOMEM)
279 context->error = FT_Err_Out_Of_Memory;
280 context->errmsg[0] = '\0';
284 /* initialize some context fields */
285 context->font = font;
286 context->error = TA_Err_Ok;
287 context->result = NULL;
288 context->scanner = scanner;
291 yyset_extra(context, scanner);
293 /* by default, `yy_scan_bytes' simply calls `exit' */
294 /* (via YY_FATAL_ERROR) in case of a (more or less) fatal error -- */
295 /* this is bad for a library, thus we use `longjmp' to catch this, */
296 /* together with a proper handler for YY_FATAL_ERROR */
297 if (setjmp(context->jump_buffer) != 0)
299 /* error and error message in `context' already stored by */
300 /* `TA_deltas_scanner_fatal_error' */
304 b = yy_scan_bytes(font->deltas_buf, font->deltas_len, scanner);
306 /* flex bug: these two fields are not initialized, */
307 /* causing zillions of valgrind errors; see */
308 /* https://sourceforge.net/p/flex/bugs/180 */
315 TA_deltas_scanner_done(Deltas_Context* context)
317 yylex_destroy(context->scanner);
326 "# 0 a p 1-3 x 0.3 y -0.2 @ 20-30; \\\n"
327 "0 exclam p 2-4 x 0.7 y -0.4 @ 6,7,9,10,11; \\\n"
328 "0 a p 2 x 0.5 @ 23-25";
338 Deltas_Context context;
340 YYSTYPE yylval_param;
341 YYLTYPE yylloc_param;
344 /* we only need the delta exceptions buffer */
345 font.deltas_buf = (char*)input;
346 font.deltas_len = strlen(input);
348 TA_deltas_scanner_init(&context, &font);
352 yyset_debug(1, context.scanner);
353 while (yylex(&yylval_param, &yylloc_param, context.scanner))
362 TA_deltas_scanner_done(&context);
369 /* end of tadeltas.l */