Some fixes found by cppcheck.
[ttfautohint.git] / lib / tacontrol.bison
blob3eb94d416bb19b79524dede42b1a7bf3a9d2993c
1 /* tacontrol.bison */
3 /*
4 * Copyright (C) 2014-2019 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 ttfautohint control instructions
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
23 * `TA_control_error'.
27 * Edsko de Vries's article `Writing a Reentrant Parser with Flex and Bison'
28 * (https://web.archive.org/web/20160130155657/http://www.phpcompiler.org:80/articles/reentrantparser.html)
29 * was extremely helpful in writing this code.
32 %require "2.5" /* we use named references */
34 %output "tacontrol-bison.c"
35 %defines "tacontrol-bison.h"
37 %define api.pure
38 %error-verbose
39 %expect 7
40 %glr-parser
41 %lex-param { void* scanner }
42 %locations
43 %name-prefix "TA_control_"
44 %parse-param { Control_Context* context }
46 %code requires {
47 #include "ta.h"
48 #include "tashaper.h"
50 /* we don't change the name prefix of flex functions */
51 #define TA_control_lex yylex
54 %union {
55 char character;
56 Control_Type type;
57 long integer;
58 char* name;
59 number_range* range;
60 double real;
61 Control* control;
65 #include <limits.h>
66 #include "tacontrol-flex.h"
68 void
69 TA_control_error(YYLTYPE *locp,
70 Control_Context* context,
71 char const* msg);
73 void
74 store_error_data(const YYLTYPE *locp,
75 Control_Context* context,
76 TA_Error error);
79 /* calls to `yylex' in the generated bison code use `scanner' directly */
80 #define scanner context->scanner
83 /* INVALID_CHARACTER and INTERNAL_FLEX_ERROR are flex errors */
84 %token EOE
85 %token <integer> INTEGER "integer number"
86 %token INTERNAL_FLEX_ERROR "internal flex error"
87 %token <character> INVALID_CHARACTER "invalid character"
88 %token <name> LEFT "left"
89 %token <name> NAME "glyph name"
90 %token <name> NODIR "no direction"
91 %token <name> POINT "point"
92 %token <real> REAL "real number"
93 %token <name> RIGHT "right"
94 %token <name> TOUCH "touch"
95 %token <name> WIDTH "width"
96 %token <name> XSHIFT "x shift"
97 %token <name> YSHIFT "y shift"
99 %type <control> entry
100 %type <integer> font_idx
101 %type <integer> glyph_idx
102 %type <range> glyph_idx_range
103 %type <range> glyph_idx_range_elem
104 %type <range> glyph_idx_range_elems
105 %type <range> glyph_idx_set
106 %type <name> glyph_name
107 %type <name> glyph_name_
108 %type <control> input
109 %type <integer> integer
110 %type <type> left_right
111 %type <type> left_right_
112 %type <type> point_touch
113 %type <type> point_touch_
114 %type <range> left_limited
115 %type <type> no_dir
116 %type <range> number_set
117 %type <integer> offset
118 %type <range> ppem_set
119 %type <range> range
120 %type <range> range_elem
121 %type <range> range_elems
122 %type <real> real
123 %type <range> right_limited
124 %type <integer> script_feature
125 %type <real> shift
126 %type <integer> signed_integer
127 %type <range> unlimited
128 %type <range> width_elem
129 %type <range> width_elems
130 %type <range> width_set
131 %type <integer> wildcard_script_feature
132 %type <real> x_shift
133 %type <real> y_shift
135 %destructor { TA_control_free($$); } <control>
136 %destructor { number_set_free($$); } <range>
138 %printer { fprintf(yyoutput, "`%ld'", $$); } <integer>
139 %printer { fprintf(yyoutput, "`%s'", $$); } <name>
140 %printer { fprintf(yyoutput, "`%g'", $$); } <real>
141 %printer {
142 char* s;
143 number_range* nr;
146 nr = number_set_reverse($$);
147 s = number_set_show(nr, -1, -1);
148 (void)number_set_reverse(nr);
149 if (s)
151 fprintf(yyoutput, "`%s'", s);
152 free(s);
154 else
155 fprintf(yyoutput, "allocation error");
156 } <range>
157 %printer { fprintf(yyoutput, "`%c'", $$); } INVALID_CHARACTER
163 /* `number_range' list elements are stored in reversed order; */
164 /* the call to `TA_control_new' fixes this */
166 /* `Control' list elements are stored in reversed order, too; */
167 /* this gets fixed by an explicit call to `TA_control_reverse' */
169 start:
170 input
171 { context->result = TA_control_reverse($input); }
174 input[result]:
175 /* empty */
176 { $result = NULL; }
177 | input[left] entry
178 { $result = TA_control_prepend($left, $entry); }
181 entry:
183 { $entry = NULL; }
184 | font_idx glyph_idx point_touch number_set x_shift y_shift ppem_set EOE
186 $entry = TA_control_new($point_touch,
187 $font_idx,
188 $glyph_idx,
189 $number_set,
190 $x_shift,
191 $y_shift,
192 $ppem_set,
193 @$.first_line);
194 if (!$entry)
196 store_error_data(&@$, context, TA_Err_Control_Allocation_Error);
197 YYABORT;
200 | font_idx glyph_idx left_right number_set EOE
202 $entry = TA_control_new($left_right,
203 $font_idx,
204 $glyph_idx,
205 $number_set,
208 NULL,
209 @$.first_line);
210 if (!$entry)
212 store_error_data(&@$, context, TA_Err_Control_Allocation_Error);
213 YYABORT;
216 | font_idx glyph_idx left_right number_set '(' offset[left] ',' offset[right] ')' EOE
218 $entry = TA_control_new($left_right,
219 $font_idx,
220 $glyph_idx,
221 $number_set,
222 $left,
223 $right,
224 NULL,
225 @$.first_line);
226 if (!$entry)
228 store_error_data(&@$, context, TA_Err_Control_Allocation_Error);
229 YYABORT;
232 | font_idx glyph_idx no_dir number_set EOE
234 $entry = TA_control_new($no_dir,
235 $font_idx,
236 $glyph_idx,
237 $number_set,
240 NULL,
241 @$.first_line);
242 if (!$entry)
244 store_error_data(&@$, context, TA_Err_Control_Allocation_Error);
245 YYABORT;
248 | font_idx script_feature glyph_idx_set EOE
250 $entry = TA_control_new(Control_Script_Feature_Glyphs,
251 $font_idx,
252 $script_feature,
253 $glyph_idx_set,
256 NULL,
257 @$.first_line);
258 if (!$entry)
260 store_error_data(&@$, context, TA_Err_Control_Allocation_Error);
261 YYABORT;
264 | font_idx wildcard_script_feature width_set EOE
266 $entry = TA_control_new(Control_Script_Feature_Widths,
267 $font_idx,
268 $wildcard_script_feature,
269 $width_set,
272 NULL,
273 @$.first_line);
274 if (!$entry)
276 store_error_data(&@$, context, TA_Err_Control_Allocation_Error);
277 YYABORT;
282 font_idx:
283 /* empty */
285 $font_idx = 0;
286 context->font_idx = $font_idx;
288 | integer
290 $font_idx = $integer;
291 if ($font_idx >= context->font->num_sfnts)
293 store_error_data(&@$, context, TA_Err_Control_Invalid_Font_Index);
294 YYABORT;
296 context->font_idx = $font_idx;
300 glyph_idx:
301 integer
303 FT_Face face = context->font->sfnts[context->font_idx].face;
306 $glyph_idx = $integer;
307 if ($glyph_idx >= face->num_glyphs)
309 store_error_data(&@$, context, TA_Err_Control_Invalid_Glyph_Index);
310 YYABORT;
312 context->glyph_idx = $glyph_idx;
314 | glyph_name
316 FT_Face face = context->font->sfnts[context->font_idx].face;
319 /* explicitly compare with `.notdef' */
320 /* since `FT_Get_Name_Index' returns glyph index 0 */
321 /* for both this glyph name and invalid ones */
322 if (!strcmp($glyph_name, ".notdef"))
323 $glyph_idx = 0;
324 else
326 $glyph_idx = (long)FT_Get_Name_Index(face, $glyph_name);
327 if ($glyph_idx == 0)
328 $glyph_idx = -1;
331 free($glyph_name);
333 if ($glyph_idx < 0)
335 store_error_data(&@$, context, TA_Err_Control_Invalid_Glyph_Name);
336 YYABORT;
338 context->glyph_idx = $glyph_idx;
342 glyph_name:
343 glyph_name_
345 /* `$glyph_name_' was allocated in the lexer */
346 if (context->error)
348 /* lexing error */
349 store_error_data(&@$, context, context->error);
350 YYABORT;
353 $glyph_name = $glyph_name_;
357 glyph_name_:
358 LEFT
359 | NAME
360 | NODIR
361 | POINT
362 | RIGHT
363 | TOUCH
364 | WIDTH
365 | XSHIFT
366 | YSHIFT
369 point_touch:
370 point_touch_
372 FT_Error error;
373 FT_Face face = context->font->sfnts[context->font_idx].face;
374 int num_points;
377 error = FT_Load_Glyph(face,
378 (FT_UInt)context->glyph_idx,
379 FT_LOAD_NO_SCALE);
380 if (error)
382 store_error_data(&@$, context, TA_Err_Control_Invalid_Glyph);
383 YYABORT;
386 num_points = face->glyph->outline.n_points;
388 context->number_set_min = 0;
389 context->number_set_max = num_points - 1;
391 $point_touch = $point_touch_;
395 point_touch_:
396 POINT
398 $point_touch_ = Control_Delta_after_IUP;
399 free($POINT);
401 | TOUCH
403 $point_touch_ = Control_Delta_before_IUP;
404 free($TOUCH);
408 left_right:
409 left_right_
411 FT_Error error;
412 FT_Face face = context->font->sfnts[context->font_idx].face;
413 int num_points;
416 error = FT_Load_Glyph(face,
417 (FT_UInt)context->glyph_idx,
418 FT_LOAD_NO_SCALE);
419 if (error)
421 store_error_data(&@$, context, TA_Err_Control_Invalid_Glyph);
422 YYABORT;
425 num_points = face->glyph->outline.n_points;
427 context->number_set_min = 0;
428 context->number_set_max = num_points - 1;
430 $left_right = $left_right_;
434 left_right_:
435 LEFT
437 $left_right_ = Control_Single_Point_Segment_Left;
438 free($LEFT);
440 | RIGHT
442 $left_right_ = Control_Single_Point_Segment_Right;
443 free($RIGHT);
447 no_dir:
448 NODIR
450 FT_Error error;
451 FT_Face face = context->font->sfnts[context->font_idx].face;
452 int num_points;
455 error = FT_Load_Glyph(face,
456 (FT_UInt)context->glyph_idx,
457 FT_LOAD_NO_SCALE);
458 if (error)
460 store_error_data(&@$, context, TA_Err_Control_Invalid_Glyph);
461 YYABORT;
464 num_points = face->glyph->outline.n_points;
466 context->number_set_min = 0;
467 context->number_set_max = num_points - 1;
469 $no_dir = Control_Single_Point_Segment_None;
470 free($NODIR);
474 wildcard_script_feature:
475 script_feature
476 { $wildcard_script_feature = $script_feature; }
477 | '*' glyph_name[feature]
479 size_t i;
480 size_t feature_idx = 0;
481 char feature_name[5];
484 feature_name[4] = '\0';
486 for (i = 0; i < feature_tags_size; i++)
488 hb_tag_to_string(feature_tags[i], feature_name);
490 if (!strcmp($feature, feature_name))
492 feature_idx = i;
493 break;
497 free($feature);
499 if (i == feature_tags_size)
501 store_error_data(&@2, context, TA_Err_Control_Invalid_Feature);
502 YYABORT;
505 /* simply use negative values for features applied to all scripts */
506 $wildcard_script_feature = -(long)feature_idx;
509 script_feature:
510 glyph_name[script] glyph_name[feature]
512 long ss;
513 size_t i, j;
514 size_t script_idx = 0;
515 size_t feature_idx = 0;
516 char feature_name[5];
519 for (i = 0; i < script_names_size; i++)
521 if (!strcmp($script, script_names[i]))
523 script_idx = i;
524 break;
528 feature_name[4] = '\0';
530 for (j = 0; j < feature_tags_size; j++)
532 hb_tag_to_string(feature_tags[j], feature_name);
534 if (!strcmp($feature, feature_name))
536 feature_idx = j;
537 break;
541 free($script);
542 free($feature);
544 if (i == script_names_size)
546 store_error_data(&@1, context, TA_Err_Control_Invalid_Script);
547 YYABORT;
549 if (j == feature_tags_size)
551 store_error_data(&@2, context, TA_Err_Control_Invalid_Feature);
552 YYABORT;
555 for (ss = 0; ta_style_classes[ss]; ss++)
557 TA_StyleClass style_class = ta_style_classes[ss];
560 if (script_idx == style_class->script
561 && feature_idx == style_class->coverage)
563 $script_feature = ss;
564 break;
567 if (!ta_style_classes[ss])
569 store_error_data(&@$, context, TA_Err_Control_Invalid_Style);
570 YYABORT;
575 x_shift:
576 /* empty */
577 { $x_shift = 0; }
578 | XSHIFT shift
580 $x_shift = $shift;
581 free($XSHIFT);
585 y_shift:
586 /* empty */
587 { $y_shift = 0; }
588 | YSHIFT shift
590 $y_shift = $shift;
591 free($YSHIFT);
595 shift:
596 real
598 if ($real < CONTROL_DELTA_SHIFT_MIN || $real > CONTROL_DELTA_SHIFT_MAX)
600 store_error_data(&@$, context, TA_Err_Control_Invalid_Shift);
601 YYABORT;
603 $shift = $real;
607 offset:
608 signed_integer
610 if ($signed_integer < SHRT_MIN || $signed_integer > SHRT_MAX)
612 store_error_data(&@$, context, TA_Err_Control_Invalid_Offset);
613 YYABORT;
615 $offset = $signed_integer;
619 ppem_set:
622 context->number_set_min = CONTROL_DELTA_PPEM_MIN;
623 context->number_set_max = CONTROL_DELTA_PPEM_MAX;
625 number_set
626 { $ppem_set = $number_set; }
629 integer:
631 { $integer = 0; }
632 | INTEGER
634 if (context->error)
636 /* lexing error */
637 store_error_data(&@$, context, context->error);
638 YYABORT;
641 $integer = $INTEGER;
645 signed_integer:
646 integer
647 { $signed_integer = $integer; }
648 | '+' integer
649 { $signed_integer = $integer; }
650 | '-' integer
651 { $signed_integer = -$integer; }
654 real:
655 signed_integer
656 { $real = $signed_integer; }
657 | REAL
659 if (context->error)
661 /* lexing error */
662 store_error_data(&@$, context, context->error);
663 YYABORT;
666 $real = $REAL;
668 | '+' REAL
669 { $real = $REAL; }
670 | '-' REAL
671 { $real = -$REAL; }
674 number_set:
675 unlimited
676 { $number_set = $unlimited; }
677 | right_limited
678 { $number_set = $right_limited; }
679 | left_limited
680 { $number_set = $left_limited; }
681 | range_elems
682 { $number_set = $range_elems; }
683 | right_limited ',' range_elems
685 $number_set = number_set_prepend($right_limited, $range_elems);
686 if ($number_set == NUMBERSET_NOT_ASCENDING)
688 number_set_free($right_limited);
689 number_set_free($range_elems);
690 store_error_data(&@3, context, TA_Err_Control_Ranges_Not_Ascending);
691 YYABORT;
693 if ($number_set == NUMBERSET_OVERLAPPING_RANGES)
695 number_set_free($right_limited);
696 number_set_free($range_elems);
697 store_error_data(&@3, context, TA_Err_Control_Overlapping_Ranges);
698 YYABORT;
701 | range_elems ',' left_limited
703 $number_set = number_set_prepend($range_elems, $left_limited);
704 if ($number_set == NUMBERSET_NOT_ASCENDING)
706 number_set_free($range_elems);
707 number_set_free($left_limited);
708 store_error_data(&@3, context, TA_Err_Control_Ranges_Not_Ascending);
709 YYABORT;
711 if ($number_set == NUMBERSET_OVERLAPPING_RANGES)
713 number_set_free($range_elems);
714 number_set_free($left_limited);
715 store_error_data(&@3, context, TA_Err_Control_Overlapping_Ranges);
716 YYABORT;
721 unlimited:
724 $unlimited = number_set_new(context->number_set_min,
725 context->number_set_max,
726 context->number_set_min,
727 context->number_set_max);
728 /* range of `$unlimited' is always valid */
729 if ($unlimited == NUMBERSET_ALLOCATION_ERROR)
731 store_error_data(&@$, context, TA_Err_Control_Allocation_Error);
732 YYABORT;
737 right_limited:
738 '-' integer
740 $right_limited = number_set_new(context->number_set_min,
741 (int)$integer,
742 context->number_set_min,
743 context->number_set_max);
744 if ($right_limited == NUMBERSET_INVALID_RANGE)
746 store_error_data(&@$, context, TA_Err_Control_Invalid_Range);
747 YYABORT;
749 if ($right_limited == NUMBERSET_ALLOCATION_ERROR)
751 store_error_data(&@$, context, TA_Err_Control_Allocation_Error);
752 YYABORT;
757 left_limited:
758 integer '-'
760 $left_limited = number_set_new((int)$integer,
761 context->number_set_max,
762 context->number_set_min,
763 context->number_set_max);
764 if ($left_limited == NUMBERSET_INVALID_RANGE)
766 store_error_data(&@$, context, TA_Err_Control_Invalid_Range);
767 YYABORT;
769 if ($left_limited == NUMBERSET_ALLOCATION_ERROR)
771 store_error_data(&@$, context, TA_Err_Control_Allocation_Error);
772 YYABORT;
777 range_elems[result]:
778 range_elem
779 { $result = $range_elem; }
780 | range_elems[left] ',' range_elem
782 $result = number_set_prepend($left, $range_elem);
783 if ($result == NUMBERSET_NOT_ASCENDING)
785 number_set_free($left);
786 number_set_free($range_elem);
787 store_error_data(&@3, context, TA_Err_Control_Ranges_Not_Ascending);
788 YYABORT;
790 if ($result == NUMBERSET_OVERLAPPING_RANGES)
792 number_set_free($left);
793 number_set_free($range_elem);
794 store_error_data(&@3, context, TA_Err_Control_Overlapping_Ranges);
795 YYABORT;
800 range_elem:
801 integer
803 $range_elem = number_set_new((int)$integer,
804 (int)$integer,
805 context->number_set_min,
806 context->number_set_max);
807 if ($range_elem == NUMBERSET_INVALID_RANGE)
809 store_error_data(&@$, context, TA_Err_Control_Invalid_Range);
810 YYABORT;
812 if ($range_elem == NUMBERSET_ALLOCATION_ERROR)
814 store_error_data(&@$, context, TA_Err_Control_Allocation_Error);
815 YYABORT;
818 | range
819 { $range_elem = $range; }
822 range:
823 integer[left] '-' integer[right]
825 $range = number_set_new((int)$left,
826 (int)$right,
827 context->number_set_min,
828 context->number_set_max);
829 if ($range == NUMBERSET_INVALID_RANGE)
831 store_error_data(&@$, context, TA_Err_Control_Invalid_Range);
832 YYABORT;
834 if ($range == NUMBERSET_ALLOCATION_ERROR)
836 store_error_data(&@$, context, TA_Err_Control_Allocation_Error);
837 YYABORT;
842 glyph_idx_set:
845 FT_Face face = context->font->sfnts[context->font_idx].face;
848 context->number_set_min = 0;
849 context->number_set_max = (int)(face->num_glyphs - 1);
851 glyph_idx_range_elems
852 { $glyph_idx_set = $glyph_idx_range_elems; }
855 glyph_idx_range_elems[result]:
856 glyph_idx_range_elem
857 { $result = $glyph_idx_range_elem; }
858 | glyph_idx_range_elems[left] ',' glyph_idx_range_elem
860 /* for glyph_idx_set, ascending order is not enforced */
861 $result = number_set_insert($left, $glyph_idx_range_elem);
862 if ($result == NUMBERSET_OVERLAPPING_RANGES)
864 number_set_free($left);
865 number_set_free($glyph_idx_range_elem);
866 store_error_data(&@3, context, TA_Err_Control_Overlapping_Ranges);
867 YYABORT;
872 glyph_idx_range_elem:
873 glyph_idx
875 $glyph_idx_range_elem = number_set_new((int)$glyph_idx,
876 (int)$glyph_idx,
877 context->number_set_min,
878 context->number_set_max);
879 /* glyph_idx is always valid */
880 /* since its value was already tested for validity */
881 if ($glyph_idx_range_elem == NUMBERSET_ALLOCATION_ERROR)
883 store_error_data(&@$, context, TA_Err_Control_Allocation_Error);
884 YYABORT;
887 | glyph_idx_range
888 { $glyph_idx_range_elem = $glyph_idx_range; }
891 glyph_idx_range:
892 glyph_idx[left] '-' glyph_idx[right]
894 $glyph_idx_range = number_set_new((int)$left,
895 (int)$right,
896 context->number_set_min,
897 context->number_set_max);
898 /* glyph range is always valid */
899 /* since both `glyph_idx' values were already tested for validity */
900 if ($glyph_idx_range == NUMBERSET_ALLOCATION_ERROR)
902 store_error_data(&@$, context, TA_Err_Control_Allocation_Error);
903 YYABORT;
908 width_set:
909 WIDTH
911 context->number_set_min = 1;
912 context->number_set_max = 65535;
913 context->number_set_num_elems = 0;
915 width_elems
916 { $width_set = $width_elems; }
919 width_elems[result]:
920 width_elem
922 context->number_set_num_elems++;
923 $result = $width_elem;
925 | width_elems[left] ',' width_elem
927 context->number_set_num_elems++;
928 if (context->number_set_num_elems > TA_LATIN_MAX_WIDTHS)
930 number_set_free($left);
931 number_set_free($width_elem);
932 store_error_data(&@3, context, TA_Err_Control_Too_Much_Widths);
933 YYABORT;
936 /* for width_set, the order of entries is preserved */
937 $result = number_set_prepend_unsorted($left, $width_elem);
941 width_elem:
942 integer
944 $width_elem = number_set_new($integer,
945 $integer,
946 context->number_set_min,
947 context->number_set_max);
948 if ($width_elem == NUMBERSET_ALLOCATION_ERROR)
950 store_error_data(&@$, context, TA_Err_Control_Allocation_Error);
951 YYABORT;
960 void
961 TA_control_error(YYLTYPE *locp,
962 Control_Context* context,
963 char const* msg)
965 /* if `error' is already set, we have a fatal flex error */
966 if (!context->error)
968 context->error = TA_Err_Control_Syntax_Error;
969 strncpy(context->errmsg, msg, sizeof (context->errmsg));
972 context->errline_num = locp->first_line;
973 context->errline_pos_left = locp->first_column;
974 context->errline_pos_right = locp->last_column;
978 void
979 store_error_data(const YYLTYPE *locp,
980 Control_Context* context,
981 TA_Error error)
983 context->error = error;
985 context->errline_num = locp->first_line;
986 context->errline_pos_left = locp->first_column;
987 context->errline_pos_right = locp->last_column;
989 context->errmsg[0] = '\0';
993 #if 0
996 * compile this test program with
998 * make libnumberset.la
1000 * flex -d tacontrol.flex \
1001 * && bison -t tacontrol.bison \
1002 * && gcc -g3 -O0 \
1003 * -Wall -W \
1004 * -I.. \
1005 * -I. \
1006 * -I/usr/local/include/freetype2 \
1007 * -I/usr/local/include/harfbuzz \
1008 * -L.libs \
1009 * -o tacontrol-bison \
1010 * tacontrol-bison.c \
1011 * tacontrol-flex.c \
1012 * tacontrol.c \
1013 * -lfreetype \
1014 * -lnumberset
1017 const char* input =
1018 "# Test\n"
1019 "\n"
1020 "# 0 a p 1-3 x 0.3 y -0.2 @ 20-30; \\\n"
1021 "0 exclam p 2-4 x 0.7 y -0.4 @ 6,7,9,10,11; \\\n"
1022 "a p / 12 x 0.5 @ 23-25";
1025 #undef scanner
1028 main(int argc,
1029 char** argv)
1031 TA_Error error;
1032 int bison_error;
1033 int retval = 1;
1035 Control_Context context;
1036 FONT font;
1037 SFNT sfnts[1];
1038 FT_Library library;
1039 FT_Face face;
1040 const char* filename;
1043 if (argc != 2)
1045 fprintf(stderr, "need an outline font as an argument\n");
1046 goto Exit0;
1049 filename = argv[1];
1051 error = FT_Init_FreeType(&library);
1052 if (error)
1054 fprintf(stderr, "error while initializing FreeType library (0x%X)\n",
1055 error);
1056 goto Exit0;
1059 error = FT_New_Face(library, filename, 0, &face);
1060 if (error)
1062 fprintf(stderr, "error while loading font `%s' (0x%X)\n",
1063 filename,
1064 error);
1065 goto Exit1;
1068 /* we construct a minumum `Font' object */
1069 sfnts[0].face = face;
1071 font.num_sfnts = 1;
1072 font.sfnts = sfnts;
1073 font.control_buf = (char*)input;
1074 font.control_len = strlen(input);
1076 TA_control_debug = 1;
1078 TA_control_scanner_init(&context, &font);
1079 if (context.error)
1080 goto Exit2;
1082 bison_error = TA_control_parse(&context);
1083 if (bison_error)
1084 goto Exit3;
1086 retval = 0;
1088 Exit3:
1089 TA_control_scanner_done(&context);
1090 TA_control_free(context.result);
1092 Exit2:
1093 FT_Done_Face(face);
1095 Exit1:
1096 FT_Done_FreeType(library);
1098 Exit0:
1099 return retval;
1102 #endif
1104 /* end of tacontrol.bison */