Fix OTS warning about `maxp.maxSizeOfInstructions`.
[ttfautohint.git] / lib / tacontrol.flex
blob80e3c932d6e9e06e9e4168e6b611f862982cd444
1 /* tacontrol.flex */
3 /*
4  * Copyright (C) 2014-2022 by Werner Lemberg.
5  *
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.
10  *
11  * The file `COPYING' mentioned in the previous paragraph is distributed
12  * with the ttfautohint library.
13  */
16  * lexical analyzer for parsing ttfautohint control instructions
17  *
18  * Lexing errors are indicated by setting `context->error' to an appropriate
19  * value; fatal lexer errors return token `INTERNAL_FLEX_ERROR'.
20  */
22 /* you should use flex version >= 2.5.39 to avoid various buglets */
23 /* that don't have work-arounds */
25 %option batch
26 %option bison-bridge
27 %option bison-locations
28 %option never-interactive
29 %option noinput
30 %option nounput
31 %option noyyalloc
32 %option noyyfree
33 %option noyyrealloc
34 %option noyywrap
35 %option reentrant
36 %option yylineno
39 %top {
40 #include "config.h"
46 #include <stdio.h>
47 #include <string.h>
49 #include "ta.h"
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; \
61           yycolumn += yyleng;
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 \
73           do \
74           { \
75             if (setjmp(yyextra->jump_buffer) != 0) \
76             { \
77               /* error and error message in `context' already stored by */ \
78               /* `TA_control_scanner_fatal_error' */ \
79               return INTERNAL_FLEX_ERROR; \
80             } \
81           } while (0)
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)
88 #define NAME_ASSIGN \
89           do \
90           { \
91             yylval->name = strdup(yytext); \
92             if (!yylval->name) \
93               yyextra->error = TA_Err_Control_Allocation_Error; \
94           } while (0)
96 void
97 TA_control_scanner_fatal_error(const char* msg,
98                                yyscan_t yyscanner);
105 (?x: [ \t\f]+
106 ) {
107   /* skip whitespace */
110 (?x: ( "\n"
111      | ";"
112      )+
113 ) {
114   /* end of entry */
115   return EOE;
118 <<EOF>> {
119   /* we want an EOE token at end of file, too */
120   if (!yyextra->eof)
121   {
122     yyextra->eof = 1;
123     return EOE;
124   }
125   else
126     yyterminate();
129 (?x: ( "\\\n"
130      )+
131 ) {
132   /* skip escaped newline */
135 (?x: "#" [^\n]*
136 ) {
137   /* skip line comment */
141 (?x: [0+-]
142 ) {
143   /* values `0' and `-' need special treatment for number ranges */
144   return yytext[0];
147 (?x:   [1-9] [0-9]*
148      | "0" [xX] [0-9a-fA-F]+
149      | "0" [0-7]+
150 ) {
151   /* we don't support localized formats like a thousands separator */
152   errno = 0;
153   yylval->integer = strtol(yytext, NULL, 0);
154   if (errno == ERANGE)
155   {
156     /* overflow or underflow */
157     yyextra->error = TA_Err_Control_Overflow;
158   }
159   return INTEGER;
162 (?x:   [0-9]* "." [0-9]+
163      | [0-9]+ "." [0-9]*
164 ) {
165   /* we don't support exponents, */
166   /* and we don't support localized formats like using `,' instead of `.' */
167   errno = 0;
168   yylval->real = strtod(yytext, NULL);
169   if (yylval->real != 0 && errno == ERANGE)
170   {
171     /* overflow */
172     yyextra->error = TA_Err_Control_Overflow;
173   }
174   return REAL;
178 (?x: [@,()*]
179 ) {
180   /* delimiters, wildcard */
181   return yytext[0];
184 (?x:   "point"
185      | "p"
186 ) {
187   NAME_ASSIGN;
188   return POINT;
191 (?x:   "touch"
192      | "t"
193 ) {
194   NAME_ASSIGN;
195   return TOUCH;
198 (?x:   "xshift"
199      | "x"
200 ) {
201   NAME_ASSIGN;
202   return XSHIFT;
205 (?x:   "yshift"
206      | "y"
207 ) {
208   NAME_ASSIGN;
209   return YSHIFT;
212 (?x:   "left"
213      | "l"
214 ) {
215   NAME_ASSIGN;
216   return LEFT;
219 (?x:   "right"
220      | "r"
221 ) {
222   NAME_ASSIGN;
223   return RIGHT;
226 (?x:   "nodir"
227      | "n"
228 ) {
229   NAME_ASSIGN;
230   return NODIR;
233 (?x:   "width"
234      | "w"
235 ) {
236   NAME_ASSIGN;
237   return WIDTH;
240 (?x: [A-Za-z._] [A-Za-z0-9._]*
241 ) {
242   NAME_ASSIGN;
243   return NAME;
247 (?x: .
248 ) {
249   /* invalid input */
250   yylval->character = yytext[0];
251   return INVALID_CHARACTER;
258 /* the following two routines set `context->error' */
260 void*
261 yyalloc(yy_size_t size,
262         yyscan_t yyscanner)
264   YY_EXTRA_TYPE context;
267   void* p = malloc(size);
268   if (!p && yyscanner)
269   {
270     context = yyget_extra(yyscanner);
271     context->error = TA_Err_Control_Allocation_Error;
272   }
273   return p;
277 void*
278 yyrealloc(void* ptr,
279           yy_size_t size,
280           yyscan_t yyscanner)
282   YY_EXTRA_TYPE context;
285   void* p = realloc(ptr, size);
286   if (!p && yyscanner)
287   {
288     context = yyget_extra(yyscanner);
289     context->error = TA_Err_Control_Allocation_Error;
290   }
291   return p;
295 /* we reimplement this routine also to avoid a compiler warning, */
296 /* cf. https://sourceforge.net/p/flex/bugs/115 */
297 void
298 yyfree(void* ptr,
299        yyscan_t yyscanner)
301   (void)yyscanner;
302   free(ptr);
306 void
307 TA_control_scanner_fatal_error(const char* msg,
308                                yyscan_t yyscanner)
310   YY_EXTRA_TYPE context = yyget_extra(yyscanner);
313   /* allocation routines set a different error value */
314   if (!context->error)
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);
326 void
327 TA_control_scanner_init(Control_Context* context,
328                         FONT* font)
330   int flex_error;
332   yyscan_t scanner;
333   YY_BUFFER_STATE b;
336   /* this function sets `errno' in case of error */
337   flex_error = yylex_init(&scanner);
338   if (flex_error && errno == ENOMEM)
339   {
340     context->error = FT_Err_Out_Of_Memory;
341     context->errmsg[0] = '\0';
342     return;
343   }
345   /* initialize some context fields */
346   context->font = font;
347   context->error = TA_Err_Ok;
348   context->result = NULL;
349   context->scanner = scanner;
350   context->eof = 0;
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)
359   {
360     /* error and error message in `context' already stored by */
361     /* `TA_control_scanner_fatal_error' */
362     return;
363   }
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 */
370   b->yy_bs_lineno = 0;
371   b->yy_bs_column = 0;
375 void
376 TA_control_scanner_done(Control_Context* context)
378   yylex_destroy(context->scanner);
382 #if 0
384 const char* input =
385   "# Test\n"
386   "\n"
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";
393 main(void)
395   TA_Error error;
396   int retval = 1;
398   FONT font;
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);
410   if (context.error)
411     goto Exit;
413   yyset_debug(1, context.scanner);
414   while (yylex(&yylval_param, &yylloc_param, context.scanner))
415   {
416     if (context.error)
417       goto Exit;
418   }
420   retval = 0;
422 Exit:
423   TA_control_scanner_done(&context);
425   return retval;
428 #endif
430 /* end of tacontrol.flex */