Minor.
[ttfautohint.git] / lib / tadeltas.l
blob3b5f4b5b87702baaadb16d0f82e7026830c210e8
1 /* tadeltas.l */
3 /*
4  * Copyright (C) 2014 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 delta exceptions
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 %option outfile="tadeltas-flex.c"
23 %option header-file="tadeltas-flex.h"
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
40 #include <stdio.h>
41 #include <string.h>
43 #include "ta.h"
44 #include "tadeltas-bison.h"
46 /* option `yylineno' resets `yycolumn' to 0 after a newline */
47 /* (since version 2.5.30, March 2003) before the next token gets read; */
48 /* note we want both line number and column start with value 1 */
50 #define YY_USER_ACTION \
51   yylloc->first_line = yylineno + 1; \
52   yylloc->last_line = yylineno + 1; \
53   yylloc->first_column = yycolumn; \
54   yylloc->last_column = yycolumn + yyleng - 1; \
55   yycolumn += yyleng;
57 #define YY_EXTRA_TYPE Deltas_Context*
59 #define YY_FATAL_ERROR(msg) TA_deltas_scanner_fatal_error(msg, yyscanner)
61 /* by default, `yylex' simply calls `exit' (via YY_FATAL_ERROR) */
62 /* in case of a (more or less) fatal error -- */
63 /* this is bad for a library, thus we use `longjmp' to catch this, */
64 /* together with a proper handler for YY_FATAL_ERROR */
66 #define YY_USER_INIT \
67           do \
68           { \
69             if (setjmp(yyextra->jump_buffer) != 0) \
70             { \
71               /* error and error message in `context' already stored by */ \
72               /* `TA_deltas_scanner_fatal_error' */ \
73               return INTERNAL_FLEX_ERROR; \
74             } \
75           } while (0)
77 /* this macro works around flex bug to suppress a compilation warning, */
78 /* cf. https://sourceforge.net/p/flex/bugs/115 */
80 #define YY_EXIT_FAILURE ((void)yyscanner, 2)
82 void
83 TA_deltas_scanner_fatal_error(const char* msg,
84                               yyscan_t yyscanner);
91 (?x: [ \t\f]+
92 ) {
93   /* skip whitespace */
96 (?x: ( "\r\n"
97      | "\n"
98      | "\r"
99      | ";"
100      )+
101 ) {
102   /* end of entry */
103   return EOE;
106 <<EOF>> {
107   /* we want an EOE token at end of file, too */
108   if (!yyextra->eof)
109   {
110     yyextra->eof = 1;
111     return EOE;
112   }
113   else
114     yyterminate();
117 (?x: ( "\\\r\n"
118      | "\\\n"
119      | "\\\r"
120      )+
121 ) {
122   /* skip escaped newline */
125 (?x: "#" [^\n]*
126 ) {
127   /* skip line comment */
131 (?x: [0+-]
132 ) {
133   /* values `0' and `-' need special treatment for number ranges */
134   return yytext[0];
137 (?x:   [1-9] [0-9]*
138      | "0" [xX] [0-9a-fA-F]+
139      | "0" [0-7]+
140 ) {
141   /* we don't support localized formats like a thousands separator */
142   errno = 0;
143   yylval->integer = strtol(yytext, NULL, 0);
144   if (errno == ERANGE)
145   {
146     /* overflow or underflow */
147     yyextra->error = TA_Err_Deltas_Overflow;
148   }
149   return INTEGER;
152 (?x:   [0-9]* "." [0-9]+
153      | [0-9]+ "." [0-9]*
154 ) {
155   /* we don't support exponents, */
156   /* and we don't support localized formats like using `,' instead of `.' */
157   errno = 0;
158   yylval->real = strtod(yytext, NULL);
159   if (yylval->real && errno == ERANGE)
160   {
161     /* overflow */
162     yyextra->error = TA_Err_Deltas_Overflow;
163   }
164   return REAL;
168 (?x: [pxy@,]
169 ) {
170   /* delimiters */
171   return yytext[0];
174 (?x: [A-Za-z._] [A-Za-z0-9._]*
175 ) {
176   yylval->name = strdup(yytext);
177   if (!yylval->name)
178   {
179     /* allocation error */
180     yyextra->error = TA_Err_Deltas_Allocation_Error;
181   }
182   return NAME;
186 (?x: .
187 ) {
188   /* invalid input */
189   yylval->character = yytext[0];
190   return INVALID_CHARACTER;
197 /* the following two routines set `context->error' */
199 void*
200 yyalloc(yy_size_t size,
201         yyscan_t yyscanner)
203   YY_EXTRA_TYPE context;
206   void* p = malloc(size);
207   if (!p && yyscanner)
208   {
209     context = yyget_extra(yyscanner);
210     context->error = TA_Err_Deltas_Allocation_Error;
211   }
212   return p;
216 void*
217 yyrealloc(void* ptr,
218           yy_size_t size,
219           yyscan_t yyscanner)
221   YY_EXTRA_TYPE context;
224   void* p = realloc(ptr, size);
225   if (!p && yyscanner)
226   {
227     context = yyget_extra(yyscanner);
228     context->error = TA_Err_Deltas_Allocation_Error;
229   }
230   return p;
234 /* we reimplement this routine also to avoid a compiler warning, */
235 /* cf. https://sourceforge.net/p/flex/bugs/115 */
236 void
237 yyfree(void* ptr,
238        yyscan_t yyscanner)
240   (void)yyscanner;
241   free(ptr);
245 void
246 TA_deltas_scanner_fatal_error(const char* msg,
247                               yyscan_t yyscanner)
249   YY_EXTRA_TYPE context = yyget_extra(yyscanner);
252   /* allocation routines set a different error value */
253   if (!context->error)
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);
265 void
266 TA_deltas_scanner_init(Deltas_Context* context,
267                        FONT* font)
269   int flex_error;
271   yyscan_t scanner;
272   YY_BUFFER_STATE b;
275   /* this function sets `errno' in case of error */
276   flex_error = yylex_init(&scanner);
277   if (flex_error && errno == ENOMEM)
278   {
279     context->error = FT_Err_Out_Of_Memory;
280     context->errmsg[0] = '\0';
281     return;
282   }
284   /* initialize some context fields */
285   context->font = font;
286   context->error = TA_Err_Ok;
287   context->result = NULL;
288   context->scanner = scanner;
289   context->eof = 0;
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)
298   {
299     /* error and error message in `context' already stored by */
300     /* `TA_deltas_scanner_fatal_error' */
301     return;
302   }
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 */
309   b->yy_bs_lineno = 0;
310   b->yy_bs_column = 0;
314 void
315 TA_deltas_scanner_done(Deltas_Context* context)
317   yylex_destroy(context->scanner);
321 #if 0
323 const char* input =
324   "# Test\n"
325   "\n"
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";
332 main(void)
334   TA_Error error;
335   int retval = 1;
337   FONT font;
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);
349   if (context.error)
350     goto Exit;
352   yyset_debug(1, context.scanner);
353   while (yylex(&yylval_param, &yylloc_param, context.scanner))
354   {
355     if (context.error)
356       goto Exit;
357   }
359   retval = 0;
361 Exit:
362   TA_deltas_scanner_done(&context);
364   return retval;
367 #endif
369 /* end of tadeltas.l */