Feature File Grammar Changes
Adobe has not—at least in recent memory—maintained a document with a formal grammar for feature files. However, when AFDKO feature file parser was ported to ANTLR 4 in 2021 we tried to make the new source files easy to read, in part so that other implementers can refer to them when there are changes. This document shows the differences between the three source files as they were in 2021 and how they are after variable value support has been added.
The tokenizer
The grammar for tokens is contained in FeatLexerBase.g4, which is part of the addfeatures in AFDKO (what used to be makeotfexe. The substantive changes are:
- A number of new keywords
- Separate tokens for the axis units (
u,d, andn -
(,),+, and:are now keywords - Quoted strings are handled differently
-
LNAMEis the token for the restricted (compared with glyph names) grammar of location names -
CATCHTAG(which parsed non-quoted tags with special characters) is removed
/* Copyright 2021 Adobe Systems Incorporated (http://www.adobe.com/). All Rights Reserved. * This software is licensed as OpenSource, under the Apache License, Version 2.0. * This license is available at: http://opensource.org/licenses/Apache-2.0. */ // -------------------------- Feature file tokens --------------------------- lexer grammar FeatLexerBase; COMMENT : '#' ~[\r\n]* -> skip ; WHITESPACE : [ \t\r\n]+ -> skip ; INCLUDE : 'include' -> pushMode(Include) ; FEATURE : 'feature' ; TABLE : 'table' ; SCRIPT : 'script' ; LANGUAGE : 'language' ; LANGSYS : 'languagesystem' ; SUBTABLE : 'subtable'; LOOKUP : 'lookup' ; LOOKUPFLAG : 'lookupflag' ; NOTDEF : '.notdef' ; RIGHT_TO_LEFT : 'RightToLeft' ; IGNORE_BASE_GLYPHS : 'IgnoreBaseGlyphs' ; IGNORE_LIGATURES : 'IgnoreLigatures' ; IGNORE_MARKS : 'IgnoreMarks' ; USE_MARK_FILTERING_SET : 'UseMarkFilteringSet' ; MARK_ATTACHMENT_TYPE : 'MarkAttachmentType' ; ANON : 'anon' ; ANON_v : 'anonymous' ; EXCLUDE_DFLT : 'excludeDFLT' ; INCLUDE_DFLT : 'includeDFLT' ; EXCLUDE_dflt : 'exclude_dflt' ; INCLUDE_dflt : 'include_dflt' ; USE_EXTENSION : 'useExtension' ; BEGINVALUE : '<' ; ENDVALUE : '>' ; ENUMERATE : 'enumerate' ; ENUMERATE_v : 'enum' ; EXCEPT : 'except' ; IGNORE : 'ignore' ; SUBSTITUTE : 'substitute' ; SUBSTITUTE_v : 'sub' ; REVERSE : 'reversesub' ; REVERSE_v : 'rsub' ; BY : 'by' ; FROM : 'from' ; POSITION : 'position' ; POSITION_v : 'pos'; PARAMETERS : 'parameters' ; FEATURE_NAMES : 'featureNames' ; CV_PARAMETERS : 'cvParameters' ; CV_UI_LABEL : 'FeatUILabelNameID' ; CV_TOOLTIP : 'FeatUITooltipTextNameID' ; CV_SAMPLE_TEXT : 'SampleTextNameID' ; CV_PARAM_LABEL : 'ParamUILabelNameID' ; CV_CHARACTER : 'Character' ; SIZEMENUNAME : 'sizemenuname' ; CONTOURPOINT : 'contourpoint' ; ANCHOR : 'anchor' ; ANCHOR_DEF : 'anchorDef' ; VALUE_RECORD_DEF : 'valueRecordDef' ; +LOCATION_DEF : 'locationDef' ; MARK : 'mark'; MARK_CLASS : 'markClass' ; CURSIVE : 'cursive' ; MARKBASE : 'base' ; MARKLIG : 'ligature' ; MARKLIG_v : 'lig' ; LIG_COMPONENT : 'ligComponent' ; KNULL : 'NULL' ; BASE : 'BASE' ; HA_BTL : 'HorizAxis.BaseTagList' ; VA_BTL : 'VertAxis.BaseTagList' ; HA_BSL : 'HorizAxis.BaseScriptList' ; VA_BSL : 'VertAxis.BaseScriptList' ; GDEF : 'GDEF' ; GLYPH_CLASS_DEF : 'GlyphClassDef' ; ATTACH : 'Attach' ; LIG_CARET_BY_POS : 'LigatureCaretByPos' ; LIG_CARET_BY_IDX : 'LigatureCaretByIndex' ; HEAD : 'head' ; FONT_REVISION : 'FontRevision' ; HHEA : 'hhea' ; ASCENDER : 'Ascender' ; DESCENDER : 'Descender' ; LINE_GAP : 'LineGap' ; CARET_OFFSET : 'CaretOffset' ; +CARET_SLOPE_RISE : 'CaretSlopeRise' ; +CARET_SLOPE_RUN : 'CaretSlopeRun' ; NAME : 'name' ; NAMEID : 'nameid' ; OS_2 : 'OS/2' ; FS_TYPE : 'FSType' ; FS_TYPE_v : 'fsType' ; OS2_LOWER_OP_SIZE : 'LowerOpSize' ; OS2_UPPER_OP_SIZE : 'UpperOpSize' ; PANOSE : 'Panose' ; TYPO_ASCENDER : 'TypoAscender' ; TYPO_DESCENDER : 'TypoDescender' ; TYPO_LINE_GAP : 'TypoLineGap' ; WIN_ASCENT : 'winAscent' ; WIN_DESCENT : 'winDescent' ; X_HEIGHT : 'XHeight' ; CAP_HEIGHT : 'CapHeight' ; +SUBSCRIPT_X_SIZE : 'SubscriptXSize' ; +SUBSCRIPT_X_OFFSET : 'SubscriptXOffset' ; +SUBSCRIPT_Y_SIZE : 'SubscriptYSize' ; +SUBSCRIPT_Y_OFFSET : 'SubscriptYOffset' ; +SUPERSCRIPT_X_SIZE : 'SuperscriptXSize' ; +SUPERSCRIPT_X_OFFSET : 'SuperscriptXOffset' ; +SUPERSCRIPT_Y_SIZE : 'SuperscriptYSize' ; +SUPERSCRIPT_Y_OFFSET : 'SuperscriptYOffset' ; +STRIKEOUT_SIZE : 'StrikeoutSize' ; +STRIKEOUT_POSITION : 'StrikeoutPosition' ; WEIGHT_CLASS : 'WeightClass' ; WIDTH_CLASS : 'WidthClass' ; VENDOR : 'Vendor' ; UNICODE_RANGE : 'UnicodeRange' ; CODE_PAGE_RANGE : 'CodePageRange' ; FAMILY_CLASS : 'FamilyClass' ; STAT : 'STAT' ; ELIDED_FALLBACK_NAME : 'ElidedFallbackName' ; ELIDED_FALLBACK_NAME_ID : 'ElidedFallbackNameID' ; DESIGN_AXIS : 'DesignAxis' ; AXIS_VALUE : 'AxisValue'; FLAG : 'flag' ; LOCATION : 'location'; AXIS_EAVN : 'ElidableAxisValueName'; AXIS_OSFA : 'OlderSiblingFontAttribute'; VHEA : 'vhea' ; VERT_TYPO_ASCENDER : 'VertTypoAscender' ; VERT_TYPO_DESCENDER : 'VertTypoDescender' ; VERT_TYPO_LINE_GAP : 'VertTypoLineGap' ; VMTX : 'vmtx' ; VERT_ORIGIN_Y : 'VertOriginY' ; VERT_ADVANCE_Y : 'VertAdvanceY' ; LCBRACE : '{' ; RCBRACE : '}' ; LBRACKET : '[' ; RBRACKET : ']' ; +LPAREN : '(' ; +RPAREN : ')' ; HYPHEN : '-' ; +PLUS : '+' ; SEMI : ';' ; EQUALS : '=' ; MARKER : '\'' ; COMMA : ',' ; -QUOTE : '"' -> pushMode(String) ; +COLON : ':' ; +STRVAL : '"' ( '\\"' | ~["] )* '"' ; fragment GNST : 'A' .. 'Z' | 'a' .. 'z' | '_' ; fragment LCHR : GNST | '0' .. '9' | '.' ; fragment GCCHR : LCHR | '-' ; +LNAME : '@' GNST LCHR* ; GCLASS : '@' GNST GCCHR* ; +AXISUNIT : 'u' | 'd' | 'n' ; CID : '\\' ( '0' .. '9' )+ ; fragment GNCHR : GCCHR | '+' | '*' | ':' | '~' | '^' | '|' ; ESCGNAME : '\\' GNST GNCHR* ; NAMELABEL : GNST LCHR* ; EXTNAME : GNST GNCHR* ; POINTNUM : '-'? ( '0' .. '9' )+ '.' ( '0' .. '9' )+ ; NUMEXT : '0x' ( '0' .. '9' | 'a' .. 'f' | 'A' .. 'F' )+ ; NUMOCT : '0' ( '0' .. '7' )+ ; NUM : '-'? ( '1' .. '9' ( '0' .. '9' )* | '0' ) ; -fragment TSTART : '!' | '$' | '%' | '&' | '*' | '+' | '.' | ':' | '?' | - 'A' .. 'Z' | '^' .. 'z' | '|' | '~' ; -fragment TCHR : TSTART | '0' .. '9' | '-' ; -CATCHTAG : TSTART TCHR? ; mode Include; I_WHITESPACE : [ \t\r\n]+ -> skip ; I_RPAREN : '(' -> mode(Ifile) ; mode Ifile; IFILE : ~')'+ ; I_LPAREN : ')' -> popMode ; - -mode String; - -STRVAL : ~'"'* ; -EQUOTE : '"' -> popMode ;
Anonymous block handling
FeatLexerBase.g4 is imported by FeatLexer.g4, which contains more complex handling for anonymous blocks. The changes to this file have to do with the changes in tag handling in the base token grammar.
/* Copyright 2024 Adobe Systems Incorporated (http://www.adobe.com/). All Rights Reserved.
* This software is licensed as OpenSource, under the Apache License, Version 2.0.
* This license is available at: http://opensource.org/licenses/Apache-2.0.
*/
lexer grammar FeatLexer;
import FeatLexerBase;
@members {
std::string anon_tag;
/* All the TSTART/TCHR characters are grouped together, so just
* look for the string and if its there verify that the characters
* on either side are from the appropriate set (in case there are
* "extra" characters).
*/
bool verify_anon(const std::string &line) {
auto p = line.find(anon_tag);
if ( p == std::string::npos )
return false;
--p;
if ( ! ( line[p] == ' ' || line[p] == '\t' || line[p] == '}' ) )
return false;
p += anon_tag.size() + 1;
if ( ! ( line[p] == ' ' || line[p] == '\t' || line[p] == ';' ) )
return false;
return true;
}
}
ANON : 'anon' -> pushMode(Anon) ;
ANON_v : 'anonymous' -> pushMode(Anon) ;
mode Anon;
A_WHITESPACE : [ \t\r\n]+ -> skip ;
-A_LABEL : TSTART TCHR* { anon_tag = getText(); } ;
+A_LABEL : (NAMELABEL | EXTNAME | STRVAL | MARK) { anon_tag = getText(); } ;
A_LBRACE : '{' -> mode(AnonContent) ;
mode AnonContent;
-A_CLOSE : '\r'? '\n}' [ \t]* TSTART TCHR* [ \t]* ';' { verify_anon(getText()) }? -> popMode ;
+A_CLOSE : '\r'? '\n}' [ \t]* (NAMELABEL | EXTNAME | STRVAL | MARK) [ \t]* ';' { verify_anon(getText()) }? -> popMode ;
A_LINE : '\r'? '\n' ~[\r\n]* ;
The parser
FeatParser.g4 specifies the grammar. The changes here correspond straightforwardly to the changes in the specification. Note that tags with unusual characters must now have quotes around them.
/* Copyright 2024 Adobe Systems Incorporated (http://www.adobe.com/). All Rights Reserved.
* This software is licensed as OpenSource, under the Apache License, Version 2.0.
* This license is available at: http://opensource.org/licenses/Apache-2.0.
*/
// ------------------------- Feature file grammar ---------------------------
parser grammar FeatParser;
options { tokenVocab = FeatLexer; }
file:
( topLevelStatement
| featureBlock
| tableBlock
| anonBlock
| lookupBlockTopLevel
)* EOF
;
topLevelStatement:
( include
| glyphClassAssign
| langsysAssign
| mark_statement
| anchorDef
| valueRecordDef
+ | locationDef
)
SEMI
;
include:
INCLUDE I_RPAREN IFILE I_LPAREN
;
glyphClassAssign:
- GCLASS EQUALS glyphClass
+ gclass EQUALS glyphClass
;
langsysAssign:
LANGSYS script=tag lang=tag
;
mark_statement:
- MARK_CLASS ( glyph | glyphClass ) anchor GCLASS
+ MARK_CLASS ( glyph | glyphClass ) anchor gclass
;
anchorDef:
- ANCHOR_DEF xval=NUM yval=NUM ( CONTOURPOINT cp=NUM )? name=label
+ ANCHOR_DEF anchorLiteral name=label
;
valueRecordDef:
VALUE_RECORD_DEF valueLiteral label
;
+locationDef:
+ LOCATION_DEF locationLiteral LNAME
+;
+
featureBlock:
FEATURE starttag=tag USE_EXTENSION? LCBRACE
featureStatement+
RCBRACE endtag=tag SEMI
;
tableBlock:
TABLE
( table_BASE
| table_GDEF
| table_head
| table_hhea
| table_vhea
| table_name
| table_OS_2
| table_STAT
| table_vmtx
)
;
anonBlock:
anontok A_LABEL A_LBRACE A_LINE* A_CLOSE
;
lookupBlockTopLevel:
LOOKUP startlabel=label USE_EXTENSION? LCBRACE
statement+
RCBRACE endlabel=label SEMI
;
featureStatement:
statement
| lookupBlockOrUse
| cvParameterBlock
;
lookupBlockOrUse:
LOOKUP startlabel=label ( USE_EXTENSION? LCBRACE
statement+
RCBRACE endlabel=label )? SEMI
;
cvParameterBlock:
CV_PARAMETERS LCBRACE
cvParameterStatement*
RCBRACE SEMI
;
cvParameterStatement:
( cvParameter
| include
) SEMI
;
cvParameter:
( CV_UI_LABEL | CV_TOOLTIP | CV_SAMPLE_TEXT | CV_PARAM_LABEL ) LCBRACE
nameEntryStatement+
RCBRACE
| CV_CHARACTER genNum
;
statement:
( featureUse
| scriptAssign
| langAssign
| lookupflagAssign
| glyphClassAssign
| ignoreSubOrPos
| substitute
| mark_statement
| position
| parameters
| sizemenuname
| featureNames
| subtable
| include
) SEMI
;
featureUse:
FEATURE tag
;
scriptAssign:
SCRIPT tag
;
langAssign:
LANGUAGE tag ( EXCLUDE_DFLT | INCLUDE_DFLT | EXCLUDE_dflt | INCLUDE_dflt )?
;
lookupflagAssign:
LOOKUPFLAG ( NUM | lookupflagElement+ )
;
lookupflagElement:
RIGHT_TO_LEFT
| IGNORE_BASE_GLYPHS
| IGNORE_LIGATURES
| IGNORE_MARKS
| ( MARK_ATTACHMENT_TYPE glyphClass )
| ( USE_MARK_FILTERING_SET glyphClass )
;
ignoreSubOrPos:
IGNORE ( subtok | revtok | postok ) lookupPattern ( COMMA lookupPattern )*
;
substitute:
( EXCEPT lookupPattern ( COMMA lookupPattern )* )?
( revtok startpat=lookupPattern ( BY ( KNULL | endpat=lookupPattern ) )?
| subtok startpat=lookupPattern ( ( BY | FROM ) ( KNULL | endpat=lookupPattern ) )? )
;
position:
enumtok? postok startpat=pattern?
(
( valueRecord valuePattern* )
| ( ( LOOKUP label )+ lookupPatternElement* )
| ( CURSIVE cursiveElement endpat=pattern? )
| ( MARKBASE midpat=pattern baseToMarkElement+ endpat=pattern? )
| ( markligtok midpat=pattern ligatureMarkElement+ endpat=pattern? )
| ( MARK midpat=pattern baseToMarkElement+ endpat=pattern? )
)
;
valuePattern:
patternElement valueRecord?
;
valueRecord:
BEGINVALUE valuename=label ENDVALUE | valueLiteral
;
valueLiteral:
- ( BEGINVALUE NUM NUM NUM NUM ENDVALUE ) | NUM
+ singleValueLiteral
+ | ( BEGINVALUE singleValueLiteral singleValueLiteral
+ singleValueLiteral singleValueLiteral ENDVALUE )
+ | ( LPAREN locationMultiValueLiteral+ RPAREN )
+;
+
+singleValueLiteral:
+ NUM | parenLocationValue
+;
+
+parenLocationValue:
+ LPAREN locationValueLiteral+ RPAREN
+;
+
+locationValueLiteral:
+ (locationSpecifier COLON)? NUM
+;
+
+locationMultiValueLiteral:
+ (locationSpecifier COLON)? BEGINVALUE NUM NUM NUM NUM ENDVALUE
+;
+
+locationSpecifier:
+ locationLiteral | LNAME
+;
+
+locationLiteral:
+ axisLocationLiteral ( COMMA axisLocationLiteral )*
+;
+
+axisLocationLiteral:
+ tag EQUALS fixedNum ( HYPHEN | PLUS )? AXISUNIT
;
cursiveElement:
patternElement anchor anchor
;
baseToMarkElement:
- anchor MARK GCLASS MARKER?
+ anchor MARK gclass MARKER?
;
ligatureMarkElement:
- anchor ( MARK GCLASS )? LIG_COMPONENT? MARKER?
+ anchor ( MARK gclass )? LIG_COMPONENT? MARKER?
;
parameters:
PARAMETERS fixedNum+
;
sizemenuname:
- SIZEMENUNAME ( genNum ( genNum genNum )? )? QUOTE STRVAL EQUOTE
+ SIZEMENUNAME ( genNum ( genNum genNum )? )? STRVAL
;
featureNames:
FEATURE_NAMES LCBRACE
nameEntryStatement+
RCBRACE
;
subtable:
SUBTABLE
;
table_BASE:
BASE LCBRACE
baseStatement+
RCBRACE BASE SEMI
;
baseStatement:
( axisTags
| axisScripts
| include
) SEMI
;
axisTags:
( HA_BTL | VA_BTL ) tag+
;
axisScripts:
( HA_BSL | VA_BSL ) baseScript ( COMMA baseScript )*
;
baseScript:
- script=tag db=tag NUM+
+ script=tag db=tag singleValueLiteral+
;
table_GDEF:
GDEF LCBRACE
gdefStatement+
RCBRACE GDEF SEMI
;
gdefStatement:
( gdefGlyphClass
| gdefAttach
| gdefLigCaretPos
| gdefLigCaretIndex
| include
) SEMI
;
gdefGlyphClass:
GLYPH_CLASS_DEF glyphClassOptional COMMA
glyphClassOptional COMMA
glyphClassOptional COMMA
glyphClassOptional
;
gdefAttach:
ATTACH lookupPattern NUM+
;
gdefLigCaretPos:
- LIG_CARET_BY_POS lookupPattern NUM+
+ LIG_CARET_BY_POS lookupPattern singleValueLiteral+
;
gdefLigCaretIndex:
LIG_CARET_BY_IDX lookupPattern NUM+
;
table_head:
HEAD LCBRACE
headStatement+
RCBRACE HEAD SEMI
;
headStatement:
( head
| include
) SEMI
;
head:
FONT_REVISION POINTNUM
;
table_hhea:
HHEA LCBRACE
hheaStatement*
RCBRACE HHEA SEMI
;
hheaStatement:
( hhea
| include
) SEMI
;
hhea:
- ( CARET_OFFSET | ASCENDER | DESCENDER | LINE_GAP ) NUM
+ ( ASCENDER | DESCENDER | LINE_GAP ) NUM
+ | ( CARET_OFFSET | CARET_SLOPE_RISE | CARET_SLOPE_RUN ) singleValueLiteral
;
table_vhea:
VHEA LCBRACE
vheaStatement*
RCBRACE VHEA SEMI
;
vheaStatement:
( vhea
| include
) SEMI
;
vhea:
- ( VERT_TYPO_ASCENDER | VERT_TYPO_DESCENDER | VERT_TYPO_LINE_GAP ) NUM
+ ( VERT_TYPO_ASCENDER | VERT_TYPO_DESCENDER | VERT_TYPO_LINE_GAP
+ | CARET_OFFSET | CARET_SLOPE_RISE | CARET_SLOPE_RUN ) singleValueLiteral
;
table_name:
NAME LCBRACE
nameStatement+
RCBRACE NAME SEMI
;
nameStatement:
( nameID
| include
) SEMI
;
nameID:
- NAMEID id=genNum ( plat=genNum ( spec=genNum lang=genNum )? )? QUOTE STRVAL EQUOTE
+ NAMEID id=genNum ( plat=genNum ( spec=genNum lang=genNum )? )? STRVAL
;
table_OS_2:
OS_2 LCBRACE
os_2Statement+
RCBRACE OS_2 SEMI
;
os_2Statement:
( os_2
| include
) SEMI
;
os_2:
( TYPO_ASCENDER | TYPO_DESCENDER | TYPO_LINE_GAP
- | WIN_ASCENT | WIN_DESCENT | X_HEIGHT | CAP_HEIGHT ) num=NUM
+ | WIN_ASCENT | WIN_DESCENT | X_HEIGHT | CAP_HEIGHT
+ | SUBSCRIPT_X_SIZE | SUBSCRIPT_X_OFFSET
+ | SUBSCRIPT_Y_SIZE | SUBSCRIPT_Y_OFFSET
+ | SUPERSCRIPT_X_SIZE | SUPERSCRIPT_X_OFFSET
+ | SUPERSCRIPT_Y_SIZE | SUPERSCRIPT_Y_OFFSET
+ | STRIKEOUT_SIZE | STRIKEOUT_POSITION ) num=singleValueLiteral
|
( FS_TYPE | FS_TYPE_v | WEIGHT_CLASS | WIDTH_CLASS
| OS2_LOWER_OP_SIZE | OS2_UPPER_OP_SIZE ) unum=NUM
| FAMILY_CLASS gnum=genNum
- | VENDOR QUOTE STRVAL EQUOTE
+ | VENDOR STRVAL
| PANOSE NUM NUM NUM NUM NUM NUM NUM NUM NUM NUM
| ( UNICODE_RANGE | CODE_PAGE_RANGE ) NUM+
;
-
table_STAT:
STAT LCBRACE
statStatement+
RCBRACE STAT SEMI
;
statStatement:
( designAxis
| axisValue
| elidedFallbackName
| elidedFallbackNameID
| include
) SEMI
;
designAxis:
DESIGN_AXIS tag NUM LCBRACE
nameEntryStatement+
RCBRACE
;
axisValue:
AXIS_VALUE LCBRACE
axisValueStatement+
RCBRACE
;
axisValueStatement:
( nameEntry
| axisValueLocation
| axisValueFlags
| include
) SEMI
;
axisValueLocation:
LOCATION tag fixedNum ( fixedNum fixedNum? )?
;
axisValueFlags:
FLAG ( AXIS_OSFA | AXIS_EAVN )+
;
elidedFallbackName:
ELIDED_FALLBACK_NAME LCBRACE
nameEntryStatement+
RCBRACE
;
nameEntryStatement:
( nameEntry
| include
) SEMI
;
elidedFallbackNameID:
ELIDED_FALLBACK_NAME_ID genNum
;
nameEntry:
- NAME ( genNum ( genNum genNum )? )? QUOTE STRVAL EQUOTE
+ NAME ( genNum ( genNum genNum )? )? STRVAL
;
table_vmtx:
VMTX LCBRACE
vmtxStatement+
RCBRACE VMTX SEMI
;
vmtxStatement:
( vmtx
| include
) SEMI
;
vmtx:
- ( VERT_ORIGIN_Y | VERT_ADVANCE_Y ) glyph NUM
+ ( VERT_ORIGIN_Y | VERT_ADVANCE_Y ) glyph singleValueLiteral
;
anchor:
BEGINVALUE ANCHOR
- ( ( xval=NUM yval=NUM ( CONTOURPOINT cp=NUM )? )
+ ( anchorLiteral
| KNULL
| name=label
) ENDVALUE
;
+anchorLiteral:
+ anchorLiteralXY ( CONTOURPOINT cp=NUM )?
+;
+
+anchorLiteralXY:
+ (xval=singleValueLiteral yval=singleValueLiteral)
+ | (LPAREN anchorMultiValueLiteral+ RPAREN)
+;
+
+anchorMultiValueLiteral:
+ (locationSpecifier COLON)? BEGINVALUE NUM NUM ENDVALUE
+;
+
lookupPattern:
lookupPatternElement+
;
lookupPatternElement:
patternElement ( LOOKUP label )*
;
pattern:
patternElement+
;
patternElement:
( glyphClass | glyph ) MARKER?
;
glyphClassOptional:
glyphClass?
;
glyphClass:
- GCLASS | gcLiteral
+ gclass | gcLiteral
;
gcLiteral:
LBRACKET gcLiteralElement+ RBRACKET
;
gcLiteralElement:
startg=glyph ( HYPHEN endg=glyph )?
- | GCLASS
+ | gclass
+;
+
+gclass:
+ LNAME | GCLASS
;
glyph:
glyphName
| CID
;
glyphName:
- ESCGNAME | NAMELABEL | EXTNAME | NOTDEF
+ ESCGNAME | NAMELABEL | EXTNAME | AXISUNIT | NOTDEF
;
label:
- NAMELABEL | MARK
+ NAMELABEL | MARK | AXISUNIT
;
tag:
- NAMELABEL | EXTNAME | CATCHTAG | MARK // MARK included for "feature mark"
+ NAMELABEL | EXTNAME | STRVAL | MARK // MARK included for "feature mark"
;
fixedNum:
POINTNUM | NUM
;
genNum:
NUM | NUMOCT | NUMEXT
;
// These are for an include directive in a block with statements
featureFile:
featureStatement* EOF
;
statementFile:
statement* EOF
;
cvStatementFile:
cvParameterStatement* EOF
;
baseFile:
baseStatement* EOF
;
headFile:
headStatement* EOF
;
hheaFile:
hheaStatement* EOF
;
vheaFile:
vheaStatement* EOF
;
gdefFile:
gdefStatement* EOF
;
nameFile:
nameStatement* EOF
;
vmtxFile:
vmtxStatement* EOF
;
os_2File:
os_2Statement* EOF
;
statFile:
statStatement* EOF
;
axisValueFile:
axisValueStatement* EOF
;
nameEntryFile:
nameEntryStatement* EOF
;
/* These tokens are defined this way because they slightly improves
* Antlr 4's default error reporting. If we wind up overloading the
* class with the token literals at the C++ level I will devolve these
* back into the Lexer grammar.
*/
subtok:
SUBSTITUTE | SUBSTITUTE_v
;
revtok:
REVERSE | REVERSE_v
;
anontok:
ANON | ANON_v
;
enumtok:
ENUMERATE | ENUMERATE_v
;
postok:
POSITION | POSITION_v
;
markligtok:
MARKLIG | MARKLIG_v
;