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 /* grammar for parsing delta exceptions */
19 * Edsko de Vries's article `Writing a Reentrant Parser with Flex and Bison'
20 * (http://www.phpcompiler.org/articles/reentrantparser.html)
21 * was extremely helpful in writing this code.
24 %output
"tadeltas-bison.c"
25 %defines
"tadeltas-bison.h"
31 %lex
-param
{ void* scanner
}
33 %name
-prefix
"TA_deltas_"
34 %parse
-param
{ Deltas_Context
* context
}
40 /* we don't change the name prefix of flex functions */
41 #define TA_deltas_lex yylex
53 #include "tadeltas-flex.h"
56 TA_deltas_error
(YYLTYPE *locp
,
57 Deltas_Context
* context
,
61 /* calls to `yylex' in the generated bison code use `scanner' directly */
62 #define scanner context->scanner
65 %token BAD
/* indicates a flex error */
67 %token
<integer
> INTEGER
72 %type
<integer
> font_idx
73 %type
<integer
> glyph_idx
74 %type
<name
> glyph_name
76 %type
<integer
> integer
77 %type
<range
> left_limited
78 %type
<range
> number_set
79 %type
<range
> point_set
80 %type
<range
> ppem_set
82 %type
<range
> range_elem
83 %type
<range
> range_elems
85 %type
<range
> right_limited
87 %type
<range
> unlimited
91 %destructor
{ TA_deltas_free
($$
); } <deltas
>
92 %destructor
{ number_set_free
($$
); } <range
>
98 /* `number_range' list elements are stored in reversed order; */
99 /* the call to `TA_deltas_new' fixes this */
100 /* (`Deltas' list elements are stored in reversed order, too, */
101 /* but they don't need to be sorted so we don't care */
105 { context
->result
= $input; }
112 { $result = TA_deltas_prepend
($left, $entry); }
118 | font_idx glyph_idx point_set x_shift y_shift ppem_set EOE
120 $entry = TA_deltas_new
($font_idx,
128 context
->error = TA_Err_Deltas_Allocation_Error
;
138 context
->font_idx
= $font_idx;
142 $font_idx = $integer;
143 if
($font_idx >= context
->font
->num_sfnts
)
145 context
->error = TA_Err_Deltas_Invalid_Font_Index
;
148 context
->font_idx
= $font_idx;
155 FT_Face face
= context
->font
->sfnts
[context
->font_idx
].face
;
158 $glyph_idx = $integer;
159 if
($glyph_idx >= face
->num_glyphs
)
161 context
->error = TA_Err_Deltas_Invalid_Glyph_Index
;
164 context
->glyph_idx
= $glyph_idx;
168 FT_Face face
= context
->font
->sfnts
[context
->font_idx
].face
;
171 /* explicitly compare with `.notdef' */
172 /* since `FT_Get_Name_Index' returns glyph index 0 */
173 /* for both this glyph name and invalid ones */
174 if
(!strcmp
($glyph_name, ".notdef"))
178 $glyph_idx = FT_Get_Name_Index
(face
, $glyph_name);
187 context
->error = TA_Err_Deltas_Invalid_Glyph_Name
;
190 context
->glyph_idx
= $glyph_idx;
197 $glyph_name = strdup
("p");
200 context
->error = TA_Err_Deltas_Allocation_Error
;
206 $glyph_name = strdup
("x");
209 context
->error = TA_Err_Deltas_Allocation_Error
;
215 $glyph_name = strdup
("y");
218 context
->error = TA_Err_Deltas_Allocation_Error
;
224 /* `$NAME' was allocated in the lexer */
233 FT_Face face
= context
->font
->sfnts
[context
->font_idx
].face
;
237 error = FT_Load_Glyph
(face
, context
->glyph_idx
, FT_LOAD_NO_SCALE
);
240 context
->error = TA_Err_Deltas_Invalid_Glyph
;
244 num_points
= face
->glyph
->outline.n_points
;
246 context
->number_set_min
= 0;
247 context
->number_set_max
= num_points
- 1;
250 { $point_set = $number_set; }
257 { $x_shift = $shift; }
264 { $y_shift = $shift; }
270 if
($real < DELTA_SHIFT_MIN ||
$real > DELTA_SHIFT_MAX
)
272 context
->error = TA_Err_Deltas_Invalid_Shift
;
282 context
->number_set_min
= DELTA_PPEM_MIN
;
283 context
->number_set_max
= DELTA_PPEM_MAX
;
286 { $ppem_set = $number_set; }
293 { $integer = $INTEGER; }
298 { $real = $integer; }
300 { $real = $integer; }
302 { $real = -$integer; }
313 { $number_set = $unlimited; }
315 { $number_set = $right_limited; }
317 { $number_set = $left_limited; }
319 { $number_set = $range_elems; }
320 | right_limited
',' range_elems
322 $number_set = number_set_prepend
($right_limited, $range_elems);
323 if
($number_set == NUMBERSET_NOT_ASCENDING
)
325 context
->error = TA_Err_Deltas_Ranges_Not_Ascending
;
328 if
($number_set == NUMBERSET_OVERLAPPING_RANGES
)
330 context
->error = TA_Err_Deltas_Overlapping_Ranges
;
334 | range_elems
',' left_limited
336 $number_set = number_set_prepend
($range_elems, $left_limited);
337 if
($number_set == NUMBERSET_NOT_ASCENDING
)
339 context
->error = TA_Err_Deltas_Ranges_Not_Ascending
;
342 if
($number_set == NUMBERSET_OVERLAPPING_RANGES
)
344 context
->error = TA_Err_Deltas_Overlapping_Ranges
;
353 $unlimited = number_set_new
(context
->number_set_min
,
354 context
->number_set_max
,
355 context
->number_set_min
,
356 context
->number_set_max
);
357 /* range of `$unlimited' is always valid */
358 if
($unlimited == NUMBERSET_ALLOCATION_ERROR
)
360 context
->error = TA_Err_Deltas_Allocation_Error
;
369 $right_limited = number_set_new
(context
->number_set_min
,
371 context
->number_set_min
,
372 context
->number_set_max
);
373 if
($right_limited == NUMBERSET_INVALID_RANGE
)
375 context
->error = TA_Err_Deltas_Invalid_Range
;
378 if
($right_limited == NUMBERSET_ALLOCATION_ERROR
)
380 context
->error = TA_Err_Deltas_Allocation_Error
;
389 $left_limited = number_set_new
($integer,
390 context
->number_set_max
,
391 context
->number_set_min
,
392 context
->number_set_max
);
393 if
($left_limited == NUMBERSET_INVALID_RANGE
)
395 context
->error = TA_Err_Deltas_Invalid_Range
;
398 if
($left_limited == NUMBERSET_ALLOCATION_ERROR
)
400 context
->error = TA_Err_Deltas_Allocation_Error
;
408 { $result = $range_elem; }
409 | range_elems
[left
] ',' range_elem
411 $result = number_set_prepend
($left, $range_elem);
412 if
($result == NUMBERSET_NOT_ASCENDING
)
414 context
->error = TA_Err_Deltas_Ranges_Not_Ascending
;
417 if
($result == NUMBERSET_OVERLAPPING_RANGES
)
419 context
->error = TA_Err_Deltas_Overlapping_Ranges
;
428 $range_elem = number_set_new
($integer,
430 context
->number_set_min
,
431 context
->number_set_max
);
432 if
($range_elem == NUMBERSET_INVALID_RANGE
)
434 context
->error = TA_Err_Deltas_Invalid_Range
;
437 if
($range_elem == NUMBERSET_ALLOCATION_ERROR
)
439 context
->error = TA_Err_Deltas_Allocation_Error
;
444 { $range_elem = $range; }
448 integer
[left
] '-' integer
[right
]
450 $range = number_set_new
($left,
452 context
->number_set_min
,
453 context
->number_set_max
);
454 if
($range == NUMBERSET_INVALID_RANGE
)
456 context
->error = TA_Err_Deltas_Invalid_Range
;
459 if
($range == NUMBERSET_ALLOCATION_ERROR
)
461 context
->error = TA_Err_Deltas_Allocation_Error
;
472 TA_deltas_error
(YYLTYPE *locp
,
473 Deltas_Context
* context
,
479 fprintf
(stderr
, "%s\n", msg
);
488 "# 0 a p 1-3 x 0.3 y -0.2 @ 20-30; \\\n"
489 "0 exclam p 2-4 x 0.7 y -0.4 @ 6,7,9,10,11; \\\n"
490 "a p 12345678901234567890 x 0.5 @ 23-25";
500 Deltas_Context context
;
505 const char* filename
;
510 fprintf
(stderr
, "need an outline font as an argument\n");
516 error = FT_Init_FreeType
(&library
);
519 fprintf
(stderr
, "error while initializing FreeType library (0x%X)\n",
524 error = FT_New_Face
(library
, filename
, 0, &face
);
527 fprintf
(stderr
, "error while loading font `%s' (0x%X)\n",
533 /* we construct a minumum Deltas_Context */
534 sfnts
[0].face
= face
;
539 context.font
= &font
;
542 error = TA_deltas_scanner_init
(&context
, input
);
545 TA_deltas_parse
(&context
);
546 TA_deltas_scanner_done
(&context
);
548 TA_deltas_free
(context.result
);
551 FT_Done_FreeType
(library
);
558 /* end of tadeltas.y */