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.
17 * grammar for parsing delta exceptions
19 * Parsing errors that essentially belong to the lexing stage are handled
20 * with `store_error_data'; in case the lexer detects an error, it returns
21 * the right token type but sets `context->error'. Syntax errors and fatal
22 * lexer errors (token `INTERNAL_FLEX_ERROR') are handled with
27 * Edsko de Vries's article `Writing a Reentrant Parser with Flex and Bison'
28 * (http://www.phpcompiler.org/articles/reentrantparser.html)
29 * was extremely helpful in writing this code.
32 %output
"tadeltas-bison.c"
33 %defines
"tadeltas-bison.h"
39 %lex
-param
{ void* scanner
}
41 %name
-prefix
"TA_deltas_"
42 %parse
-param
{ Deltas_Context
* context
}
48 /* we don't change the name prefix of flex functions */
49 #define TA_deltas_lex yylex
62 #include "tadeltas-flex.h"
65 TA_deltas_error
(YYLTYPE *locp
,
66 Deltas_Context
* context
,
70 store_error_data
(YYLTYPE *locp
,
71 Deltas_Context
* context
,
75 /* calls to `yylex' in the generated bison code use `scanner' directly */
76 #define scanner context->scanner
79 /* INVALID_CHARACTER and INTERNAL_FLEX_ERROR are flex errors */
81 %token
<integer
> INTEGER
82 %token INTERNAL_FLEX_ERROR
"internal flex error"
83 %token
<character
> INVALID_CHARACTER
"invalid character"
88 %type
<integer
> font_idx
89 %type
<integer
> glyph_idx
90 %type
<name
> glyph_name
92 %type
<integer
> integer
93 %type
<range
> left_limited
94 %type
<range
> number_set
95 %type
<range
> point_set
96 %type
<range
> ppem_set
98 %type
<range
> range_elem
99 %type
<range
> range_elems
101 %type
<range
> right_limited
103 %type
<range
> unlimited
107 %destructor
{ TA_deltas_free
($$
); } <deltas
>
108 %destructor
{ number_set_free
($$
); } <range
>
110 %printer
{ fprintf
(yyoutput
, "`%ld'", $$
); } <integer
>
111 %printer
{ fprintf
(yyoutput
, "`%s'", $$
); } <name
>
112 %printer
{ fprintf
(yyoutput
, "`%g'", $$
); } <real
>
118 nr
= number_set_reverse
($$
);
119 s
= number_set_show
(nr
, -1, -1);
120 (void)number_set_reverse
(nr
);
123 fprintf
(yyoutput
, "`%s'", s
);
127 fprintf
(yyoutput
, "allocation error");
129 %printer
{ fprintf
(yyoutput
, "`%c'", $$
); } INVALID_CHARACTER
134 /* `number_range' list elements are stored in reversed order; */
135 /* the call to `TA_deltas_new' fixes this */
137 /* `Deltas' list elements are stored in reversed order, too; */
138 /* this gets fixed by an explicit call to `TA_deltas_reverse' */
142 { context
->result
= TA_deltas_reverse
($input); }
149 { $result = TA_deltas_prepend
($left, $entry); }
155 | font_idx glyph_idx point_set x_shift y_shift ppem_set EOE
157 $entry = TA_deltas_new
($font_idx,
165 store_error_data
(&@$
, context
, TA_Err_Deltas_Allocation_Error
);
175 context
->font_idx
= $font_idx;
179 $font_idx = $integer;
180 if
($font_idx >= context
->font
->num_sfnts
)
182 store_error_data
(&@$
, context
, TA_Err_Deltas_Invalid_Font_Index
);
185 context
->font_idx
= $font_idx;
192 FT_Face face
= context
->font
->sfnts
[context
->font_idx
].face
;
195 $glyph_idx = $integer;
196 if
($glyph_idx >= face
->num_glyphs
)
198 store_error_data
(&@$
, context
, TA_Err_Deltas_Invalid_Glyph_Index
);
201 context
->glyph_idx
= $glyph_idx;
205 FT_Face face
= context
->font
->sfnts
[context
->font_idx
].face
;
208 /* explicitly compare with `.notdef' */
209 /* since `FT_Get_Name_Index' returns glyph index 0 */
210 /* for both this glyph name and invalid ones */
211 if
(!strcmp
($glyph_name, ".notdef"))
215 $glyph_idx = FT_Get_Name_Index
(face
, $glyph_name);
224 store_error_data
(&@$
, context
, TA_Err_Deltas_Invalid_Glyph_Name
);
227 context
->glyph_idx
= $glyph_idx;
234 $glyph_name = strdup
("p");
237 store_error_data
(&@$
, context
, TA_Err_Deltas_Allocation_Error
);
243 $glyph_name = strdup
("x");
246 store_error_data
(&@$
, context
, TA_Err_Deltas_Allocation_Error
);
252 $glyph_name = strdup
("y");
255 store_error_data
(&@$
, context
, TA_Err_Deltas_Allocation_Error
);
261 /* `$NAME' was allocated in the lexer */
265 store_error_data
(&@$
, context
, context
->error);
277 FT_Face face
= context
->font
->sfnts
[context
->font_idx
].face
;
281 error = FT_Load_Glyph
(face
, context
->glyph_idx
, FT_LOAD_NO_SCALE
);
284 store_error_data
(&@$
, context
, TA_Err_Deltas_Invalid_Glyph
);
288 num_points
= face
->glyph
->outline.n_points
;
290 context
->number_set_min
= 0;
291 context
->number_set_max
= num_points
- 1;
294 { $point_set = $number_set; }
301 { $x_shift = $shift; }
308 { $y_shift = $shift; }
314 if
($real < DELTA_SHIFT_MIN ||
$real > DELTA_SHIFT_MAX
)
316 store_error_data
(&@$
, context
, TA_Err_Deltas_Invalid_Shift
);
326 context
->number_set_min
= DELTA_PPEM_MIN
;
327 context
->number_set_max
= DELTA_PPEM_MAX
;
330 { $ppem_set = $number_set; }
341 store_error_data
(&@$
, context
, context
->error);
351 { $result = $integer; }
357 store_error_data
(&@$
, context
, context
->error);
364 { $result = $unsigned; }
366 { $result = -$unsigned; }
371 { $number_set = $unlimited; }
373 { $number_set = $right_limited; }
375 { $number_set = $left_limited; }
377 { $number_set = $range_elems; }
378 | right_limited
',' range_elems
380 $number_set = number_set_prepend
($right_limited, $range_elems);
381 if
($number_set == NUMBERSET_NOT_ASCENDING
)
383 number_set_free
($right_limited);
384 number_set_free
($range_elems);
385 store_error_data
(&@$
, context
, TA_Err_Deltas_Ranges_Not_Ascending
);
388 if
($number_set == NUMBERSET_OVERLAPPING_RANGES
)
390 number_set_free
($right_limited);
391 number_set_free
($range_elems);
392 store_error_data
(&@$
, context
, TA_Err_Deltas_Overlapping_Ranges
);
396 | range_elems
',' left_limited
398 $number_set = number_set_prepend
($range_elems, $left_limited);
399 if
($number_set == NUMBERSET_NOT_ASCENDING
)
401 number_set_free
($range_elems);
402 number_set_free
($left_limited);
403 store_error_data
(&@$
, context
, TA_Err_Deltas_Ranges_Not_Ascending
);
406 if
($number_set == NUMBERSET_OVERLAPPING_RANGES
)
408 number_set_free
($range_elems);
409 number_set_free
($left_limited);
410 store_error_data
(&@$
, context
, TA_Err_Deltas_Overlapping_Ranges
);
419 $unlimited = number_set_new
(context
->number_set_min
,
420 context
->number_set_max
,
421 context
->number_set_min
,
422 context
->number_set_max
);
423 /* range of `$unlimited' is always valid */
424 if
($unlimited == NUMBERSET_ALLOCATION_ERROR
)
426 store_error_data
(&@$
, context
, TA_Err_Deltas_Allocation_Error
);
435 $right_limited = number_set_new
(context
->number_set_min
,
437 context
->number_set_min
,
438 context
->number_set_max
);
439 if
($right_limited == NUMBERSET_INVALID_RANGE
)
441 store_error_data
(&@$
, context
, TA_Err_Deltas_Invalid_Range
);
444 if
($right_limited == NUMBERSET_ALLOCATION_ERROR
)
446 store_error_data
(&@$
, context
, TA_Err_Deltas_Allocation_Error
);
455 $left_limited = number_set_new
($integer,
456 context
->number_set_max
,
457 context
->number_set_min
,
458 context
->number_set_max
);
459 if
($left_limited == NUMBERSET_INVALID_RANGE
)
461 store_error_data
(&@$
, context
, TA_Err_Deltas_Invalid_Range
);
464 if
($left_limited == NUMBERSET_ALLOCATION_ERROR
)
466 store_error_data
(&@$
, context
, TA_Err_Deltas_Allocation_Error
);
474 { $result = $range_elem; }
475 | range_elems
[left
] ',' range_elem
477 $result = number_set_prepend
($left, $range_elem);
478 if
($result == NUMBERSET_NOT_ASCENDING
)
480 number_set_free
($left);
481 number_set_free
($range_elem);
482 store_error_data
(&@$
, context
, TA_Err_Deltas_Ranges_Not_Ascending
);
485 if
($result == NUMBERSET_OVERLAPPING_RANGES
)
487 number_set_free
($left);
488 number_set_free
($range_elem);
489 store_error_data
(&@$
, context
, TA_Err_Deltas_Overlapping_Ranges
);
498 $range_elem = number_set_new
($integer,
500 context
->number_set_min
,
501 context
->number_set_max
);
502 if
($range_elem == NUMBERSET_INVALID_RANGE
)
504 store_error_data
(&@$
, context
, TA_Err_Deltas_Invalid_Range
);
507 if
($range_elem == NUMBERSET_ALLOCATION_ERROR
)
509 store_error_data
(&@$
, context
, TA_Err_Deltas_Allocation_Error
);
514 { $range_elem = $range; }
518 integer
[left
] '-' integer
[right
]
520 $range = number_set_new
($left,
522 context
->number_set_min
,
523 context
->number_set_max
);
524 if
($range == NUMBERSET_INVALID_RANGE
)
526 store_error_data
(&@$
, context
, TA_Err_Deltas_Invalid_Range
);
529 if
($range == NUMBERSET_ALLOCATION_ERROR
)
531 store_error_data
(&@$
, context
, TA_Err_Deltas_Allocation_Error
);
542 TA_deltas_error
(YYLTYPE *locp
,
543 Deltas_Context
* context
,
546 /* if `error' is already set, we have a fatal flex error */
549 context
->error = TA_Err_Deltas_Syntax_Error
;
550 strncpy
(context
->errmsg
, msg
, sizeof
(context
->errmsg
));
553 context
->errline_num
= locp
->first_line
;
554 context
->errline_pos_left
= locp
->first_column
;
555 context
->errline_pos_right
= locp
->last_column
;
560 store_error_data
(YYLTYPE *locp
,
561 Deltas_Context
* context
,
564 context
->error = error;
566 context
->errline_num
= locp
->first_line
;
567 context
->errline_pos_left
= locp
->first_column
;
568 context
->errline_pos_right
= locp
->last_column
;
570 context
->errmsg
[0] = '\0';
579 "# 0 a p 1-3 x 0.3 y -0.2 @ 20-30; \\\n"
580 "0 exclam p 2-4 x 0.7 y -0.4 @ 6,7,9,10,11; \\\n"
581 "a p / 12 x 0.5 @ 23-25";
594 Deltas_Context context
;
599 const char* filename
;
604 fprintf
(stderr
, "need an outline font as an argument\n");
610 error = FT_Init_FreeType
(&library
);
613 fprintf
(stderr
, "error while initializing FreeType library (0x%X)\n",
618 error = FT_New_Face
(library
, filename
, 0, &face
);
621 fprintf
(stderr
, "error while loading font `%s' (0x%X)\n",
627 /* we construct a minumum `Font' object */
628 sfnts
[0].face
= face
;
632 font.deltas_buf
= (char*)input
;
633 font.deltas_len
= strlen
(input
);
637 TA_deltas_scanner_init
(&context
, &font
);
641 bison_error
= TA_deltas_parse
(&context
);
648 TA_deltas_scanner_done
(&context
);
649 TA_deltas_free
(context.result
);
655 FT_Done_FreeType
(library
);
663 /* end of tadeltas.y */