Update suitable examples and tests to use blank mode
[shapes.git] / source / afmyylex.ll
blob98cc50bbd47feddce9229f147feff0ab3357a302
1 /* This file is part of Shapes.
2  *
3  * Shapes is free software: you can redistribute it and/or modify
4  * it under the terms of the GNU General Public License as published by
5  * the Free Software Foundation, either version 3 of the License, or
6  * any later version.
7  *
8  * Shapes is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11  * GNU General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License
14  * along with Shapes.  If not, see <http://www.gnu.org/licenses/>.
15  *
16  * Copyright 2008, 2010 Henrik Tidefelt
17  */
21 #include <cmath>
23 #include "afmscanner.h"
24 #include "strrefdup.h"
25 #include "exitcodes.h"
27 #include <string.h>
28 #include <iostream>
29 #include <cstdio> // This is a workaround for a bug in Flex.
31 #define YY_EXIT_FAILURE Shapes::Interaction::EXIT_INTERNAL_ERROR
33 // These functions must note be called with invalid arguments!
34 const char * strtoname( char * begin, char ** endp, const char * delim = " \t" );
35 const char * strtoname( char * begin, char ** endp, const char * delim, size_t delimSize );
37 /* The rule HorizontalWhiteSpace is not in agreement with the specification, as far as I can see,
38  * but it's the smallest change I can think of which should make this program work
39  * with DOS files as well as ordiary files.
40  */
44 HorizontalWhiteSpace [ \t\r]*
46 Integer [+-]?[0-9]+
47 HexInteger [0-9A-Fa-f]+
49 Boolean "true"|"false"
51 Number [+-]?(([0-9]*[.][0-9]+)|([0-9]+))
53 Name [^ \t\n\r]+
54 String [^\r\n]*
56 %option c++
57 %option noyywrap
59 %option prefix="afm"
60 %option yyclass="AfmScanner"
62 %x Global
63 %x FinishGlobalLine
64 %x ExpectEOF
65 %x Que
66 %x MetricsSets
67 %x FontName
68 %x FullName
69 %x FamilyName
70 %x Weight
71 %x FontBBox
72 %x Version
73 %x Notice
74 %x EncodingScheme
75 %x CharacterSet
76 %x Characters
77 %x IsBaseFont
78 %x VVector
79 %x IsFixedV
80 %x IsCIDFont
81 %x CapHeight
82 %x XHeight
83 %x Ascender
84 %x Descender
85 %x StdHW
86 %x StdVW
87 %x StartDirection
88 %x UnderlinePosition
89 %x UnderlineThickness
90 %x ItalicAngle
91 %x CharWidth
92 %x IsFixedPitch
93 %x StartCharMetrics
94 %x CharMetrics
95 %x C
96 %x CH
97 %x W0X
98 %x W1X
99 %x W0Y
100 %x W1Y
101 %x W0
102 %x W1
103 %x VV
104 %x N
105 %x B
106 %x L
107 %x KernData
108 %x StartKernPairs
109 %x KernPairs
110 %x StartTrackKern
111 %x TrackKern
115 <INITIAL>"StartFontMetrics ".*[\n] {
116         BEGIN( Global );
119 <Global>"EndFontMetrics"{HorizontalWhiteSpace}[\n] {
120         if( fontMetricsDst_->horizontalMetrics_ != NullPtr< FontMetrics::WritingDirectionMetrics >( ) )
121         {
122                 // I const cast because I'm too tired to think of something better.
123                 FontMetrics::CharacterMetrics * defaultChar = const_cast< FontMetrics::CharacterMetrics * >( horizontalMetrics_typed_->charData_[ 0 ] );
124                 defaultChar->xmin_ = fontMetricsDst_->fontBBoxXMin_;
125                 defaultChar->ymin_ = fontMetricsDst_->fontBBoxYMin_;
126                 defaultChar->xmax_ = fontMetricsDst_->fontBBoxXMax_;
127                 defaultChar->ymax_ = fontMetricsDst_->fontBBoxYMax_;
128                 if( horizontalMetrics_typed_->isFixedPitch_ )
129                 {
130                         defaultChar->horizontalCharWidthX_ = horizontalMetrics_typed_->charWidthX_;
131                         defaultChar->horizontalCharWidthY_ = horizontalMetrics_typed_->charWidthY_;
132                 }
133                 else
134                 {
135                         defaultChar->horizontalCharWidthX_ = defaultChar->xmax_;
136                         defaultChar->horizontalCharWidthY_ = defaultChar->ymax_;
137                 }
138         }
139         if( fontMetricsDst_->verticalMetrics_ != NullPtr< FontMetrics::WritingDirectionMetrics >( ) )
140         {
141                 // I const cast because I'm too tired to thing of something better.
142                 FontMetrics::CharacterMetrics * defaultChar = const_cast< FontMetrics::CharacterMetrics * >( verticalMetrics_typed_->charData_[ 0 ] );
143                 defaultChar->xmin_ = fontMetricsDst_->fontBBoxXMin_;
144                 defaultChar->ymin_ = fontMetricsDst_->fontBBoxYMin_;
145                 defaultChar->xmax_ = fontMetricsDst_->fontBBoxXMax_;
146                 defaultChar->ymax_ = fontMetricsDst_->fontBBoxYMax_;
147                 if( verticalMetrics_typed_->isFixedPitch_ )
148                 {
149                         defaultChar->verticalCharWidthX_ = verticalMetrics_typed_->charWidthX_;
150                         defaultChar->verticalCharWidthY_ = verticalMetrics_typed_->charWidthY_;
151                 }
152                 else
153                 {
154                         defaultChar->verticalCharWidthX_ = defaultChar->xmax_;
155                         defaultChar->verticalCharWidthY_ = defaultChar->ymax_;
156                 }
157         }
159         BEGIN( ExpectEOF );
161 <FinishGlobalLine>{HorizontalWhiteSpace}[\n] {
162         // Skip to next line.
163         BEGIN( Global );
165 <Global>^{HorizontalWhiteSpace} {
166         // Ignore leading whitespace.
169 <ExpectEOF>{HorizontalWhiteSpace}[\n] {
170         // ignore
172 <ExpectEOF><<EOF>> {
173         return 0;
176 <ExpectEOF>.|[\n] {
177         throwError( "Expected EOF." );
180 <Global>"MetricsSets"{HorizontalWhiteSpace} {
181         BEGIN( MetricsSets );
183 <MetricsSets>{Integer} {
184         char * endp;
185         long int tmp = strtol( yytext, & endp, 10 );
186         if( tmp < 0 || tmp > 2 )
187         {
188                 throwError( "MetricsSets out of range." );
189         }
190         metricsSets_ = tmp;
191         BEGIN( FinishGlobalLine );
194 <Global>"FontName"{HorizontalWhiteSpace} {
195         BEGIN( FontName );
197 <FontName>{String} {
198         fontMetricsDst_->fontName_ = strrefdup( yytext );
199         BEGIN( FinishGlobalLine );
202 <Global>"FullName"{HorizontalWhiteSpace} {
203         BEGIN( FullName );
205 <FullName>{String} {
206         fontMetricsDst_->fullName_ = strrefdup( yytext );
207         BEGIN( FinishGlobalLine );
210 <Global>"FamilyName"{HorizontalWhiteSpace} {
211         BEGIN( FamilyName );
213 <FamilyName>{String} {
214         fontMetricsDst_->familyName_ = strrefdup( yytext );
215         BEGIN( FinishGlobalLine );
218 <Global>"Weight"{HorizontalWhiteSpace} {
219         BEGIN( Weight );
221 <Weight>{String} {
222         fontMetricsDst_->weight_ = strrefdup( yytext );
223         BEGIN( FinishGlobalLine );
226 <Global>"FontBBox"{HorizontalWhiteSpace} {
227         BEGIN( FontBBox );
229 <FontBBox>{Number}{HorizontalWhiteSpace}{Number}{HorizontalWhiteSpace}{Number}{HorizontalWhiteSpace}{Number} {
230         char * src = yytext;
231         char * endp;
232         fontMetricsDst_->fontBBoxXMin_ = 0.001 * strtod( src, & endp );
233         src = endp;
234         fontMetricsDst_->fontBBoxYMin_ = 0.001 * strtod( src, & endp );
235         src = endp;
236         fontMetricsDst_->fontBBoxXMax_ = 0.001 * strtod( src, & endp );
237         src = endp;
238         fontMetricsDst_->fontBBoxYMax_ = 0.001 * strtod( src, & endp );
239         BEGIN( FinishGlobalLine );
242 <Global>"Version"{HorizontalWhiteSpace} {
243         BEGIN( Version );
245 <Version>{String} {
246         fontMetricsDst_->version_ = strrefdup( yytext );
247         BEGIN( FinishGlobalLine );
250 <Global>"Notice"{HorizontalWhiteSpace} {
251         BEGIN( Notice );
253 <Notice>{String} {
254         fontMetricsDst_->notice_ = strrefdup( yytext );
255         BEGIN( FinishGlobalLine );
258 <Global>"EncodingScheme"{HorizontalWhiteSpace} {
259         BEGIN( EncodingScheme );
261 <EncodingScheme>{String} {
262         fontMetricsDst_->encodingScheme_ = strrefdup( yytext );
263         BEGIN( FinishGlobalLine );
266 <Global>"CharacterSet"{HorizontalWhiteSpace} {
267         BEGIN( CharacterSet );
269 <CharacterSet>{String} {
270         fontMetricsDst_->characterSet_ = strrefdup( yytext );
271         BEGIN( FinishGlobalLine );
274 <Global>"Characters"{HorizontalWhiteSpace} {
275         BEGIN( Characters );
277 <Characters>{Integer} {
278         char * endp;
279         fontMetricsDst_->charCount_ = strtol( yytext, & endp, 10 );
280         BEGIN( FinishGlobalLine );
283 <Global>"IsBaseFont"{HorizontalWhiteSpace} {
284         BEGIN( IsBaseFont );
286 <IsBaseFont>{Boolean} {
287         if( yytext[ 0 ] != 't' )
288         {
289                 throwError( "Expected \"IsBaseFont true\"." );
290         }
291         BEGIN( FinishGlobalLine );
294 <Global>"VVector"{HorizontalWhiteSpace} {
295         BEGIN( VVector );
297 <FontBBox>{Number}{HorizontalWhiteSpace}{Number} {
298         char * src = yytext;
299         char * endp;
300         fontMetricsDst_->vVectorX_ = 0.001 * strtod( src, & endp );
301         src = endp;
302         fontMetricsDst_->vVectorY_ = 0.001 * strtod( src, & endp );
303         fontMetricsDst_->isFixedV_ = true;
304         BEGIN( FinishGlobalLine );
307 <Global>"IsFixedV"{HorizontalWhiteSpace} {
308         BEGIN( IsFixedV );
310 <IsFixedV>{Boolean} {
311         fontMetricsDst_->isFixedV_ = yytext[0] == 't';
312         BEGIN( FinishGlobalLine );
315 <Global>"IsCIDFont"{HorizontalWhiteSpace} {
316         BEGIN( IsCIDFont );
318 <IsCIDFont>{Boolean} {
319         fontMetricsDst_->isCIDFont_ = yytext[0] == 't';
320         BEGIN( FinishGlobalLine );
323 <Global>"CapHeight"{HorizontalWhiteSpace} {
324         BEGIN( CapHeight );
326 <CapHeight>{Number} {
327         char * endp;
328         fontMetricsDst_->capHeight_ = 0.001 * strtod( yytext, & endp );
329         BEGIN( FinishGlobalLine );
332 <Global>"XHeight"{HorizontalWhiteSpace} {
333         BEGIN( XHeight );
335 <XHeight>{Number} {
336         char * endp;
337         fontMetricsDst_->xHeight_ = 0.001 * strtod( yytext, & endp );
338         BEGIN( FinishGlobalLine );
341 <Global>"Ascender"{HorizontalWhiteSpace} {
342         BEGIN( Ascender );
344 <Ascender>{Number} {
345         char * endp;
346         fontMetricsDst_->ascender_ = 0.001 * strtod( yytext, & endp );
347         BEGIN( FinishGlobalLine );
350 <Global>"Descender"{HorizontalWhiteSpace} {
351         BEGIN( Descender );
353 <Descender>{Number} {
354         char * endp;
355         fontMetricsDst_->descender_ = 0.001 * strtod( yytext, & endp );
356         BEGIN( FinishGlobalLine );
359 <Global>"StdHW"{HorizontalWhiteSpace} {
360         BEGIN( StdHW );
362 <StdHW>{Number} {
363         char * endp;
364         fontMetricsDst_->stdHW_ = 0.001 * strtod( yytext, & endp );
365         BEGIN( FinishGlobalLine );
368 <Global>"StdVW"{HorizontalWhiteSpace} {
369         BEGIN( StdVW );
371 <StdVW>{Number} {
372         char * endp;
373         fontMetricsDst_->stdVW_ = 0.001 * strtod( yytext, & endp );
374         BEGIN( FinishGlobalLine );
378 <Global>"StartDirection"{HorizontalWhiteSpace} {
379         BEGIN( StartDirection );
381 <StartDirection>{Integer} {
382         char * endp;
383         long int tmp = strtol( yytext, & endp, 10 );
384         if( tmp < 0 || tmp > 2 )
385         {
386                 throwError( "StartDirection out of range." );
387         }
388         activateDirectionID_ = tmp;
389         BEGIN( FinishGlobalLine );
392 <Global>"EndDirection"{HorizontalWhiteSpace} {
393         activateDirectionID_ = 0; // This is probably not necessary.
394         BEGIN( FinishGlobalLine );
397 <Global>"UnderlinePosition"{HorizontalWhiteSpace} {
398         BEGIN( UnderlinePosition );
400 <UnderlinePosition>{Number} {
401         synchWritingDirection( );
402         char * endp;
403         currentDirectionDst_->underlinePosition_ = 0.001 * strtod( yytext, & endp );
404         BEGIN( FinishGlobalLine );
407 <Global>"UnderlineThickness"{HorizontalWhiteSpace} {
408         BEGIN( UnderlineThickness );
410 <UnderlineThickness>{Number} {
411         synchWritingDirection( );
412         char * endp;
413         currentDirectionDst_->underlineThickness_ = 0.001 * strtod( yytext, & endp );
414         BEGIN( FinishGlobalLine );
417 <Global>"ItalicAngle"{HorizontalWhiteSpace} {
418         BEGIN( ItalicAngle );
420 <ItalicAngle>{Number} {
421         synchWritingDirection( );
422         char * endp;
423         currentDirectionDst_->italicAngleRadians_ = strtod( yytext, & endp ) * ( M_PI / 180 );  // Note: Don't scale by 0.001!
424         BEGIN( FinishGlobalLine );
427 <Global>"CharWidth"{HorizontalWhiteSpace} {
428         BEGIN( CharWidth );
430 <CharWidth>{Number}{HorizontalWhiteSpace}{Number} {
431         synchWritingDirection( );
432         char * src = yytext;
433         char * endp;
434         currentDirectionDst_->charWidthX_ = 0.001 * strtod( yytext, & endp );
435         src = endp;
436         currentDirectionDst_->charWidthY_ = 0.001 * strtod( yytext, & endp );
437         BEGIN( FinishGlobalLine );
440 <Global>"IsFixedPitch"{HorizontalWhiteSpace} {
441         BEGIN( IsFixedPitch );
443 <IsFixedPitch>{Boolean} {
444         synchWritingDirection( );
445         currentDirectionDst_->isFixedPitch_ = yytext[0] == 't';
446         BEGIN( FinishGlobalLine );
449 <Global>"StartCharMetrics"{HorizontalWhiteSpace} {
450         BEGIN( StartCharMetrics );
452 <StartCharMetrics>{Integer}{HorizontalWhiteSpace}[\n] {
453         synchWritingDirection( );
454         if( currentDirectionDst_->charData_.size( ) > 1 )       // the first entry is the default values
455         {
456                 throwError( "Multiply specified character metrics in this writing direction." );
457         }
458         char * endp;
459         long int tmp = strtol( yytext, & endp, 10 );
460         currentDirectionDst_->charData_.reserve( tmp + 1 ); // the first entry is the default values
461         currentCharacter_ = new FontMetrics::CharacterMetrics( currentDirectionDst_->charData_.size( ) );
462         BEGIN( CharMetrics );
465 <CharMetrics>"EndCharMetrics" {
466         delete currentCharacter_;
467         BEGIN( FinishGlobalLine );
470 <CharMetrics>[\r] {
471         // Ignore DOS crap.
473 <CharMetrics>[\n] {
474         currentDirectionDst_->charData_.push_back( currentCharacter_ );
475         currentCharacter_ = new FontMetrics::CharacterMetrics( currentDirectionDst_->charData_.size( ) );
478 <CharMetrics>^{HorizontalWhiteSpace}[\n] {
479         // A newline at the end of an empty line does not insert the current character.
481 <CharMetrics>{HorizontalWhiteSpace} {
482         // Ingore
485 <CharMetrics>"C"{HorizontalWhiteSpace} {
486         BEGIN( C );
488 <C>{Integer}{HorizontalWhiteSpace}[;] {
489         char * endp;
490         currentCharacter_->characterCode_ = strtol( yytext, & endp, 10 );
491         if( currentCharacter_->characterCode_ >= 0 )
492         {
493                 currentDirectionDst_->codeMap_[ currentCharacter_->characterCode_ ] = currentCharacter_->internalPosition_;
494         }
495         BEGIN( CharMetrics );
498 <CharMetrics>"CH"{HorizontalWhiteSpace} {
499         BEGIN( CH );
501 <CH>{HexInteger}{HorizontalWhiteSpace}[;] {
502         char * endp;
503         currentCharacter_->characterCode_ = strtol( yytext, & endp, 16 );
504         if( currentCharacter_->characterCode_ >= 0 )
505         {
506                 currentDirectionDst_->codeMap_[ currentCharacter_->characterCode_ ] = currentCharacter_->internalPosition_;
507         }
508         BEGIN( CharMetrics );
511 <CharMetrics>("WX"|"W0X"){HorizontalWhiteSpace} {
512         BEGIN( W0X );
514 <W0X>{Number}{HorizontalWhiteSpace}[;] {
515         char * endp;
516         currentCharacter_->horizontalCharWidthX_ = 0.001 * strtod( yytext, & endp );
517         BEGIN( CharMetrics );
520 <CharMetrics>("WY"|"W0Y"){HorizontalWhiteSpace} {
521         BEGIN( W0Y );
523 <W0Y>{Number}{HorizontalWhiteSpace}[;] {
524         char * endp;
525         currentCharacter_->horizontalCharWidthY_ = 0.001 * strtod( yytext, & endp );
526         BEGIN( CharMetrics );
529 <CharMetrics>"W1X"{HorizontalWhiteSpace} {
530         BEGIN( W1X );
532 <W1X>{Number}{HorizontalWhiteSpace}[;] {
533         char * endp;
534         currentCharacter_->verticalCharWidthX_ = 0.001 * strtod( yytext, & endp );
535         BEGIN( CharMetrics );
538 <CharMetrics>"W1Y"{HorizontalWhiteSpace} {
539         BEGIN( W1Y );
541 <W1Y>{Number}{HorizontalWhiteSpace}[;] {
542         char * endp;
543         currentCharacter_->verticalCharWidthY_ = 0.001 * strtod( yytext, & endp );
544         BEGIN( CharMetrics );
547 <CharMetrics>"W0"{HorizontalWhiteSpace} {
548         BEGIN( W0 );
550 <W0>{Number}{HorizontalWhiteSpace}{Number}{HorizontalWhiteSpace}[;] {
551         char * src = yytext;
552         char * endp;
553         currentCharacter_->horizontalCharWidthX_ = 0.001 * strtod( src, & endp );
554         src = endp;
555         currentCharacter_->horizontalCharWidthY_ = 0.001 * strtod( src, & endp );
556         BEGIN( CharMetrics );
559 <CharMetrics>"W1"{HorizontalWhiteSpace} {
560         BEGIN( W1 );
562 <W1>{Number}{HorizontalWhiteSpace}{Number}{HorizontalWhiteSpace}[;] {
563         char * src = yytext;
564         char * endp;
565         currentCharacter_->verticalCharWidthX_ = 0.001 * strtod( src, & endp );
566         src = endp;
567         currentCharacter_->verticalCharWidthY_ = 0.001 * strtod( src, & endp );
568         BEGIN( CharMetrics );
571 <CharMetrics>"VV"{HorizontalWhiteSpace} {
572         BEGIN( VV );
574 <VV>{Number}{HorizontalWhiteSpace}{Number}{HorizontalWhiteSpace}[;] {
575         char * src = yytext;
576         char * endp;
577         currentCharacter_->vX_ = 0.001 * strtod( src, & endp );
578         src = endp;
579         currentCharacter_->vY_ = 0.001 * strtod( src, & endp );
580         BEGIN( CharMetrics );
583 <CharMetrics>"N"{HorizontalWhiteSpace} {
584         BEGIN( N );
586 <N>{Name}{HorizontalWhiteSpace}[;] {
587         char * end = yytext;
588         for( ; *end != ' ' && *end != '\t' && *end != ';'; ++end )
589                 ;
590         *end = '\0';
591         currentDirectionDst_->nameMap_[ strrefdup( yytext ) ] = currentCharacter_->internalPosition_;
592         if( currentCharacter_->characterCode_ < 0 )
593                 {
594                         unsigned char pos;
595                         if( encoding_->name_to_position( yytext, & pos ) )
596                                 {
597                                         currentCharacter_->characterCode_ = pos;
598                                         currentDirectionDst_->codeMap_[ currentCharacter_->characterCode_ ] = currentCharacter_->internalPosition_;
599                                 }
600                 }
602         BEGIN( CharMetrics );
605 <CharMetrics>"B"{HorizontalWhiteSpace} {
606         BEGIN( B );
608 <B>{Number}{HorizontalWhiteSpace}{Number}{HorizontalWhiteSpace}{Number}{HorizontalWhiteSpace}{Number}{HorizontalWhiteSpace}[;] {
609         char * src = yytext;
610         char * endp;
611         currentCharacter_->xmin_ = 0.001 * strtod( src, & endp );
612         src = endp;
613         currentCharacter_->ymin_ = 0.001 * strtod( src, & endp );
614         src = endp;
615         currentCharacter_->xmax_ = 0.001 * strtod( src, & endp );
616         src = endp;
617         currentCharacter_->ymax_ = 0.001 * strtod( src, & endp );
618         BEGIN( CharMetrics );
621 <CharMetrics>"L"{HorizontalWhiteSpace} {
622         BEGIN( L );
624 <L>{Name}{HorizontalWhiteSpace}{Name}{HorizontalWhiteSpace}[;] {
625         char * end1;
626         const char * begin1 = strtoname( yytext, & end1, " \t", 2 );
627         char * end2;
628         const char * begin2 = strtoname( end1, & end2, " ;\t", 3 );
630         currentCharacter_->addLigature( strrefdup( begin1 ), strrefdup( begin2 ) );
631         BEGIN( CharMetrics );
634 <Global>"StartKernData"{HorizontalWhiteSpace}[\n] {
635         BEGIN( KernData );
637 <KernData>"EndKernData"{HorizontalWhiteSpace} {
638         BEGIN( FinishGlobalLine );
640 <KernData>"StartKernPairs"([0]?){HorizontalWhiteSpace} {
641         currentKernPairMapX_ = & fontMetricsDst_->horizontalKernPairsX_;
642         currentKernPairMapY_ = & fontMetricsDst_->horizontalKernPairsY_;
643         if( horizontalMetrics_typed_ == NullPtr< FontMetrics::SingleByte_WritingDirectionMetrics >( ) )
644                 {
645                         throw "It would be nice if the character metrics appeared before the kern pairs.";
646                 }
647         currentNameMap_ = & horizontalMetrics_typed_->nameMap_;
648         BEGIN( StartKernPairs );
650 <KernData>"StartKernPairs1"{HorizontalWhiteSpace} {
651         currentKernPairMapX_ = & fontMetricsDst_->verticalKernPairsX_;
652         currentKernPairMapY_ = & fontMetricsDst_->verticalKernPairsY_;
653         if( verticalMetrics_typed_ == NullPtr< FontMetrics::SingleByte_WritingDirectionMetrics >( ) )
654                 {
655                         throw "It would be nice if the character metrics appeared before the kern pairs.";
656                 }
657         currentNameMap_ = & verticalMetrics_typed_->nameMap_;
658         BEGIN( StartKernPairs );
660 <StartKernPairs>{Integer}{HorizontalWhiteSpace}[\n] {
661         // The number of pairs is not used.
662         BEGIN( KernPairs );
664 <KernPairs>"EndKernPairs"{HorizontalWhiteSpace}[\n] {
665         BEGIN( KernData );
667 <KernData>"StartTrackKern"{HorizontalWhiteSpace} {
668         BEGIN( StartTrackKern );
670 <StartTrackKern>{Integer}{HorizontalWhiteSpace}[\n] {
671         // The number of entries is not used.
672         BEGIN( TrackKern );
674 <TrackKern>"EndTrackKern"{HorizontalWhiteSpace}[\n] {
675         BEGIN( KernData );
678 <KernPairs>"KP"{HorizontalWhiteSpace}{Name}{HorizontalWhiteSpace}{Name}{HorizontalWhiteSpace}{Number}{HorizontalWhiteSpace}{Number}{HorizontalWhiteSpace}[\n] {
679         char * src = yytext + 2;
680         char * end;
681         const char * name1 = strtoname( src, & end, " \t", 2 );
682         src = end;
683         const char * name2 = strtoname( src, & end, " \t", 2 );
684         src = end;
685         double x = 0.001 * strtod( src, & end );
686         src = end;
687         double y = 0.001 * strtod( src, & end );
688         /* The code commented out below was using a name map local to the writing direction.  I cannot see the point of
689          * keeping the name map local to the writing direction, and it makes conversion to a Unicode code point more difficult.
690          * I keep the old code as a reminder of what the code used to look like back in the days when the kern pairs
691          * were indexed using the MacRoman encoding.  Now, we use Unicode code points instead.
692          */
693 //      typedef typeof *currentNameMap_ NameMapType;
694 //      NameMapType::const_iterator i1 = currentNameMap_->find( strrefdup( name1 ) );
695 //      if( i1 == currentNameMap_->end( ) )
696 //      {
697 //              throw "Unable to resolve character name in kern pair.   Perhaps kern pairs appear before character metrics.";
698 //      }
699 //      NameMapType::const_iterator i2 = currentNameMap_->find( strrefdup( name2 ) );
700 //      if( i2 == currentNameMap_->end( ) )
701 //      {
702 //              throw "Unable to resolve character name in kern pair.   Perhaps kern pairs appear before character metrics.";
703 //      }
704         {
705                 typedef typeof *currentKernPairMapX_ MapType;
706                 Shapes::Kernel::UnicodeCodePoint i1u;
707                 i1u.decode_glyph_name( name1 );
708                 Shapes::Kernel::UnicodeCodePoint i2u;
709                 i2u.decode_glyph_name( name2 );
710                 (*currentKernPairMapX_)[ MapType::key_type( i1u, i2u ) ] = x;
711                 (*currentKernPairMapY_)[ MapType::key_type( i1u, i2u ) ] = y;
712         }
715 <KernPairs>"KPH"{HorizontalWhiteSpace}"<"{Name}">"{HorizontalWhiteSpace}"<"{Name}">"{HorizontalWhiteSpace}{Number}{HorizontalWhiteSpace}{Number}{HorizontalWhiteSpace}[\n] {
716 //      char * src = yytext + 3;
717 //      char * end;
718         throw "Kern pairs with hexadecimal names are not understood.";
721 <KernPairs>"KPX"{HorizontalWhiteSpace}{Name}{HorizontalWhiteSpace}{Name}{HorizontalWhiteSpace}{Number}{HorizontalWhiteSpace}[\n] {
722         char * src = yytext + 3;
723         char * end;
724         const char * name1 = strtoname( src, & end, " \t", 2 );
725         src = end;
726         const char * name2 = strtoname( src, & end, " \t", 2 );
727         src = end;
728         double x = 0.001 * strtod( src, & end );
729         /* See comment for "KP". */
730 //      typedef typeof *currentNameMap_ NameMapType;
731 //      NameMapType::const_iterator i1 = currentNameMap_->find( strrefdup( name1 ) );
732 //      if( i1 == currentNameMap_->end( ) )
733 //      {
734 //              throw "Unable to resolve character name in kern pair.   Perhaps kern pairs appear before character metrics.";
735 //      }
736 //      NameMapType::const_iterator i2 = currentNameMap_->find( strrefdup( name2 ) );
737 //      if( i2 == currentNameMap_->end( ) )
738 //      {
739 //              throw "Unable to resolve character name in kern pair.   Perhaps kern pairs appear before character metrics.";
740 //      }
741 //      (*currentKernPairMapX_)[ std::pair< size_t, size_t >( i1->second, i2->second ) ] = x;
742         {
743                 typedef typeof *currentKernPairMapX_ MapType;
744                 Shapes::Kernel::UnicodeCodePoint i1u;
745                 i1u.decode_glyph_name( name1 );
746                 Shapes::Kernel::UnicodeCodePoint i2u;
747                 i2u.decode_glyph_name( name2 );
748                 (*currentKernPairMapX_)[ MapType::key_type( i1u, i2u ) ] = x;
749         }
752 <KernPairs>"KPY"{HorizontalWhiteSpace}{Name}{HorizontalWhiteSpace}{Name}{HorizontalWhiteSpace}{Number}{HorizontalWhiteSpace}[\n] {
753         char * src = yytext + 3;
754         char * end;
755         const char * name1 = strtoname( src, & end, " \t", 2 );
756         src = end;
757         const char * name2 = strtoname( src, & end, " \t", 2 );
758         src = end;
759         double y = 0.001 * strtod( src, & end );
760         /* See comment for "KP". */
761 //      typedef typeof *currentNameMap_ NameMapType;
762 //      NameMapType::const_iterator i1 = currentNameMap_->find( strrefdup( name1 ) );
763 //      if( i1 == currentNameMap_->end( ) )
764 //      {
765 //              throw "Unable to resolve character name in kern pair.   Perhaps kern pairs appear before character metrics.";
766 //      }
767 //      NameMapType::const_iterator i2 = currentNameMap_->find( strrefdup( name2 ) );
768 //      if( i2 == currentNameMap_->end( ) )
769 //      {
770 //              throw "Unable to resolve character name in kern pair.   Perhaps kern pairs appear before character metrics.";
771 //      }
772 //      (*currentKernPairMapY_)[ std::pair< size_t, size_t >( i1->second, i2->second ) ] = y;
773         {
774                 typedef typeof *currentKernPairMapX_ MapType;
775                 Shapes::Kernel::UnicodeCodePoint i1u;
776                 i1u.decode_glyph_name( name1 );
777                 Shapes::Kernel::UnicodeCodePoint i2u;
778                 i2u.decode_glyph_name( name2 );
779                 (*currentKernPairMapY_)[ MapType::key_type( i1u, i2u ) ] = y;
780         }
784 <TrackKern>{HorizontalWhiteSpace}{Integer}{HorizontalWhiteSpace}{Number}{HorizontalWhiteSpace}{Number}{HorizontalWhiteSpace}{Number}{HorizontalWhiteSpace}{Number}{HorizontalWhiteSpace}[\n] {
785         char * src = yytext;
786         char * endp;
787         int degree = strtol( src, & endp, 10 );
788         src = endp;
789         double sizeLow = strtod( src, & endp );
790         src = endp;
791         double trackLow = 0.001 * strtod( src, & endp );
792         src = endp;
793         double sizeHigh = strtod( src, & endp );
794         src = endp;
795         double trackHigh = 0.001 * strtod( src, & endp );
796         typedef typeof fontMetricsDst_->trackKernings_ MapType;
797         fontMetricsDst_->trackKernings_.insert( MapType::value_type( degree, RefCountPtr< FontMetrics::TrackKerning >( new FontMetrics::TrackKerning( sizeLow, trackLow, sizeHigh, trackHigh ) ) ) );
801 <*>^"Comment"{HorizontalWhiteSpace}.*[\n] {
802         // Ignore comments.
805 <Global>{Name} {
806         // If we match the whole line here, it will be a _very_ good match for anything.        Hence we do things in two steps.
807         if( tellQue_ )
808         {
809                 std::cerr << "The afm parser was unable to understand the key \"" << yytext << "\", with data: " ;
810         }
811         BEGIN( Que );
813 <Que>{String} {
814         // Ignore things we don't understand.
815         if( tellQue_ )
816         {
817                 std::cerr << yytext << std::endl ;
818         }
819         BEGIN( FinishGlobalLine );
822 <*>. { throwError( "Unrecognized token." ); }
825 /* The closing %% above marks the end of the Rules section and the beginning
826  * of the User Subroutines section. All text from here to the end of the
827  * file is copied verbatim to the end of the generated lex.pdf.c file.
828  * This section is where you put definitions of helper functions.
829  */
831 const char *
832 strtoname( char * begin, char ** endp, const char * delim )
834         for( ; memchr( " \t", *begin, 2 ) != 0; ++begin )
835                 ;
837         char * end = begin;
838         for( ; strchr( delim, *end ) == 0; ++end )
839                 ;
841         *end = '\0';
842         *endp = end + 1;
843         return begin;
846 const char *
847 strtoname( char * begin, char ** endp, const char * delim, size_t delimSize )
849         for( ; memchr( " \t", *begin, 2 ) != 0; ++begin )
850                 ;
852         char * end = begin;
853         for( ; memchr( delim, *end, delimSize ) == 0; ++end )
854                 ;
856         *end = '\0';
857         *endp = end + 1;
858         return begin;