### CSS example with multiple Graphite font features Source: https://graphite.sil.org/graphite_firefox.html Shows how to specify multiple Graphite font features using a comma delimiter. Includes both new and old syntax. ```css .alternate_font_style { font-family: "My Graphite Font", ; /* new syntax: */ -moz-font-feature-settings: "fea1" 2, "fea2" 6, "fea3"; /* fea3 is 1 or 'on' */ /* old syntax: */ -moz-font-feature-settings: "fea1=2,fea2=6,fea3"; } ``` -------------------------------- ### Graphite rule with context example Source: https://graphite.sil.org/tutorial/graide_tutorial6 Example rule that replaces A with X, B with Y, and C with Z, but only fires when the context 'P A Q B C R' is present. The underscores in the context correspond one-to-one with the items on the left- and right-hand sides. ```graphite gA gB gC > gX gY gZ / gP _ gQ _ _ gR; ``` -------------------------------- ### Graphite rule example Source: https://graphite.sil.org/tutorial/graide_tutorial1 A simple Graphite rule that maps lowercase letters to uppercase, used in the tutorial's font. ```text clsLowerCase > clsUpperCase; ``` -------------------------------- ### codepoint function examples Source: https://graphite.sil.org/tutorial/graide_tutorial3 Uses the codepoint function with a string or a numeric value. The optional second argument specifies the codepage; 1252 is the default. ```GDL codepoint(“a”); codepoint(97, 1252); ``` -------------------------------- ### General GDL table syntax Source: https://graphite.sil.org/tutorial/graide_tutorial2 Shows the structure for defining a rule table. Replace with lb, sub, or pos. Substitution rules like the example go in the sub table. ```GDL table() endtable; ``` -------------------------------- ### Example CSS style using Graphite font feature 'alts' Source: https://graphite.sil.org/graphite_firefox.html Defines a CSS style using a Graphite font with the feature 'alts' set to value 2. Includes both new and old syntax for compatibility. ```css .alternate_font_style { font-family: "My Graphite Font", ; /* new syntax: */ -moz-font-feature-settings: "alts" 2; /* old syntax: */ -moz-font-feature-settings: "alts=2"; } ``` -------------------------------- ### Run Graide with configuration file Source: https://graphite.sil.org/tutorial/graide_tutorial1 Use the -p option to start Graide with a specific configuration file, useful for automating project setup. ```text graide -p tutorial.cfg ``` -------------------------------- ### Exercise 5b: Insert u after q/Q with @ syntax alternative Source: https://graphite.sil.org/tutorial/graphite_tut_solutions Exercise 5b: defines a class for q/Q and a glyph for u, then inserts u after any q/Q. The commented line shows an alternative using @1 to copy the item unchanged. ```gdl #include "stddef.gdh" table(glyph) clsQ = (unicode(0x71), unicode(0x51)); gU = unicode(0x75); endtable; table(sub) clsQ _ > clsQ gU:1; // Note: you can also use the @ syntax to copy an item through unchanged: // clsQ _ > @1 gU:1; endtable; ``` -------------------------------- ### Exercise 4a: uppercase mapping via class ranges Source: https://graphite.sil.org/tutorial/graphite_tut_solutions Defines lower and upper letter classes for 0x61..0x7A and 0x41..0x5A, then maps the lowercase class to the uppercase class. ```gdl #include "stddef.gdh" table(glyph) clsLower = unicode(0x61..0x7A); clsUpper = unicode(0x41..0x5A); endtable; table(sub) clsLower > clsUpper; endtable; ``` -------------------------------- ### Exercise 13c: Greek Transliteration Feature (r2gk) Source: https://graphite.sil.org/tutorial/graphite_tut_solutions Sets up a 'r2gk' Greek transliteration feature. The glyph table is commented as 'same as previous', and the substitution table contains a placeholder comment for rules to be added. ```GDL #include "stddef.gdh" table(glyph) // same as previous endtable; table(feature) greek_xlit { id = "r2gk" name.LG_USENG = string("Greek Transliteration"); } endtable; table(sub) if (greek_xlit) // rules go here endif; endtable; ``` -------------------------------- ### Original class definition with codepoint Source: https://graphite.sil.org/tutorial/graide_tutorial1 The original class definition for uppercase letters, which is highlighted in the editor. This line is used as a starting point for introducing errors. ```gdl clsUpperCase = codepoint(“ABCDEFGHIJKLMNOPQRSTUVWXYZ”); ``` -------------------------------- ### Exercise 3a: map glyphs using gDollar and gPound Source: https://graphite.sil.org/tutorial/graphite_tut_solutions Defines a glyph table with the named glyphs gDollar and gPound, then a substitution table that maps gDollar to gPound. ```gdl #include "stddef.gdh" table(glyph) gDollar = unicode(0x0024); gPound = unicode(0x00A3); endtable; table(sub) gDollar > gPound; endtable; ``` -------------------------------- ### Exercise 14c: Tone glyph classes and substitution rules Source: https://graphite.sil.org/tutorial/graphite_tut_solutions Defines glyph classes for numbers (one, two, thr) and tone combinations (two-tone and three-tone). Substitution rules match sequences of numbers and replace them with tone ligatures, assigning component references (@1, @2, @3) for tone1, tone2, and tone3. The rules cover two-tone (low2, mid2, high2) and three-tone (lowLow3, lowMid3, etc.) combinations, each with component boxes for positioning tones. ```Graphite GDL #include "stddef.gdh" table(glyph) one = U+0031; // 1 two = U+0032; // 2 thr = U+0033; // 3 clsNumber = (one, two, thr); oneTone = (glyphid(381), glyphid(368), glyphid(354)); // Two-tone combinations: low2 = (glyphid(381), glyphid(382), glyphid(383)); mid2 = (glyphid(367), glyphid(368), glyphid(369)); high2 = (glyphid(352), glyphid(353), glyphid(354)); twoTone = (low2, mid2, high2) { comp { tone1 = box(0, -descent, aw/2, ascent); tone2 = box(aw/2, -descent, aw, ascent) } }; // Three-tone combinations: lowLow3 = (glyphid(381), glyphid(391), glyphid(392)); lowMid3 = (glyphid(446), glyphid(447), glyphid(383)); lowHigh3 = (glyphid(450), glyphid(451), glyphid(452)); midLow3 = (glyphid(376), glyphid(377), glyphid(378)); midMid3 = (glyphid(433), glyphid(368), glyphid(434)); midHigh3 = (glyphid(437), glyphid(438), glyphid(439)); highLow3 = (glyphid(362), glyphid(363), glyphid(364)); highMid3 = (glyphid(352), glyphid(420), glyphid(421)); highHigh3 = (glyphid(424), glyphid(425), glyphid(354)); threeTone = (lowLow3, lowMid3, lowHigh3, midLow3, midMid3, midHigh3, highLow3, highMid3, highHigh3) { comp{ tone1 = box(0, -descent, aw/3, ascent); tone2 = box(aw/3, -descent, aw * 2/3, ascent); tone3 = box(aw * 2/3, -descent, aw, ascent) } }; endtable; table(sub) // Three-tone sequences: one one clsNumber > _ _ lowLow3:(1 2 3) {comp { tone1.ref = @1; tone2.ref = @2; tone3.ref = @3 }}}; one two clsNumber > _ _ lowMid3:(1 2 3) {comp { tone1.ref = @1; tone2.ref = @2; tone3.ref = @3 }}}; one thr clsNumber > _ _ lowHigh3:(1 2 3) {comp { tone1.ref = @1; tone2.ref = @2; tone3.ref = @3 }}}; two one clsNumber > _ _ midLow3:(1 2 3) {comp { tone1.ref = @1; tone2.ref = @2; tone3.ref = @3 }}}; two two clsNumber > _ _ midMid3:(1 2 3) {comp { tone1.ref = @1; tone2.ref = @2; tone3.ref = @3 }}}; two thr clsNumber > _ _ midHigh3:(1 2 3) {comp { tone1.ref = @1; tone2.ref = @2; tone3.ref = @3 }}}; thr one clsNumber > _ _ highLow3:(1 2 3) {comp { tone1.ref = @1; tone2.ref = @2; tone3.ref = @3 }}}; thr two clsNumber > _ _ highMid3:(1 2 3) {comp { tone1.ref = @1; tone2.ref = @2; tone3.ref = @3 }}}; thr thr clsNumber > _ _ highHigh3:(1 2 3) {comp { tone1.ref = @1; tone2.ref = @2; tone3.ref = @3 }}}; // Two-tone sequences: one clsNumber > _ _ low2:(1 2) {comp { tone1.ref = @1; tone2.ref = @2 }}}; two clsNumber > _ _ mid2:(1 2) {comp { tone1.ref = @1; tone2.ref = @2 }}}; thr clsNumber > _ _ high2:(1 2) {comp { tone1.ref = @1; tone2.ref = @2 }}}; // Single tones: clsNumber > _ _ oneTone; endtable; ``` -------------------------------- ### Enable bidi pass with Bidi = true; Source: https://graphite.sil.org/tutorial/graide_tutorial15 Turns on the bidi pass in a Graphite font. Place this statement in the font's GDL code to enable bidirectional reordering. ```gdl Bidi = true; ``` -------------------------------- ### GDL: Defining a user-defined slot attribute with #define Source: https://graphite.sil.org/tutorial/graide_tutorial9 Shows how to define a user-defined slot attribute using the #define directive. This example defines 'hardC' as 'user1', making it number 1 in the list of user attributes. ```gdl #define hardC user1 ``` -------------------------------- ### Exercise 14b: Fraction glyph classes and substitution rules Source: https://graphite.sil.org/tutorial/graphite_tut_solutions Defines glyph classes for digits 1, 3, 4, slash, and fraction ligatures (1/4, 1/2, 3/4). Each fraction component (num, slash, denom) is positioned using box() with coordinates relative to the bounding box. Substitution rules match a numerator, slash, and denominator and replace them with the corresponding ligature, assigning component references (@1, @2, @3). ```Graphite GDL #include "stddef.gdh" table(glyph) gNum1 = unicode(0x31); // 1 gNum3 = unicode(0x33); // 3 clsDenom1 = (unicode(0x34), unicode(0x32)); // 4,2 clsDenom3 = unicode(0x34); // 4 gSlash = unicode(0x2f); clsLig1 = (unicode(0xbc), unicode(0xbd)); // 1/4, 1/2 clsLig3 = unicode(0xbe); // 3/4 // Each component is half the width of the bounding box: clsLig = unicode(0xbc..0xbe) // 1/4, 1/2, 3/4 { comp.num = box(bb.left, bb.bottom + 200m, lsb + bb.width*3/8, bb.top); comp.slash = box(lsb + bb.width/3, bb.bottom, (lsb + bb.width*2/3, bb.top) ; comp.denom = box(lsb + bb.width*5/8, bb.bottom – 100m, bb.right, bb.bottom + 600m) }; endtable; table(sub) // 1/4, 1/2 gNum1 gSlash clsDenom1 > _ _ clsLig1:(1 2 3) { comp {num.ref = @1; slash.ref = @2; denom.ref = @3}}}; // 3/4 gNum3 gSlash clsDenom3 > _ _ clsLig3:(1 2 3) { comp {num.ref = @1; slash.ref = @2; denom.ref = @3}}}; endtable; ``` -------------------------------- ### Exercise 4b: vowel and consonant class mappings Source: https://graphite.sil.org/tutorial/graphite_tut_solutions Defines lowercase and uppercase vowel classes (a e i o u) and consonant classes, then maps lowercase vowels to uppercase vowels and uppercase consonants to lowercase consonants in one substitution table. ```gdl #include "stddef.gdh" table(glyph) clsLowerVowel = (U+0061, U+0065, U+0069, U+006F, U+0075); // a e i o u clsUpperVowel = (U+0041, U+0045, U+0049, U+004F, U+0055); // A E I O U clsLowerCons = ((U+0062..U+0064), // b..d (U+0066..U+0068), // f..h (U+006A..U+006E), // j..n (U+0070..U+0074), // p..t (U+0076..U+007A)); // v..z clsUpperCons = ((U+0042..U+0044), // B..D (U+0046..U+0048), // F..H (U+004A..U+004E), // J..N (U+0050..U+0054), // P..T (U+0056..U+005A)); // V..Z endtable; table(sub) clsLowerVowel > clsUpperVowel; clsUpperCons > clsLowerCons; endtable; ``` -------------------------------- ### Graide test data: Unicode codepoint syntax Source: https://graphite.sil.org/tutorial/graide_tutorial11 Syntax for entering non-ASCII characters in Graide test data using Unicode codepoints. Replace with the Unicode scalar value. For example, X\u0308 enters X with diaeresis. ```text \u ``` -------------------------------- ### Exercise 14a: Ligature Feature with Component Composition (ligs) Source: https://graphite.sil.org/tutorial/graphite_tut_solutions Untested solution for a ligature feature. Defines ligature components (off, eil, and ligature glyphs) and a substitution rule that composes ligatures from two components using comp.c1 and comp.c2 references. Note the warning that this solution has not been tested. ```GDL #include "stddef.gdh" table(glyph) clsLigComp1 = (unicode(0x6f), unicode(0x66), unicode(0x66)); // off clsLigComp2 = (unicode(0x65), unicode(0x69), unicode(0x6c)); // eil // Each component is half the width of the bounding box: clsLig = (glyphid(155), // oe glyphid(168), // fi glyphid(169)) // fl { comp.c1 = box(bb.left, bb.bottom, bb.width/2, bb.top); comp.c2 = box(bb.width/2, bb.bottom, bb.right, bb.top) }; endtable; table(feature) lig { id = "ligs"; name.LG_USENG = string("Ligatures"); } endtable; table(sub) if (lig) // Note: we use the second character as the selector of // the replacement ligature, since it can unambiguously // identify it clsLigComp1 clsLigComp2 > _ clsLig:(1 2) { comp.c1.ref = @1; comp.c2.ref = @2 }; endif; endtable; ``` -------------------------------- ### Exercise 17: Reordering with context pattern Source: https://graphite.sil.org/tutorial/graphite_tut_solutions Extends Exercise 16 by adding a context pattern to the substitution rule. The rule reorders a consonant and back-rounded vowel, but only when followed by an optional consonant or pair of consonants and an underscore. ```graphite #include "stddef.gdh" table(glyph) clsBackRoundedVowel = (unicode(0x6f), unicode(0x75)); // o, u clsCons = (unicode(0x62..0x64), // b..d unicode(0x66..0x68), // f..h unicode(0x6A..0x6E), // j..n unicode(0x70..0x74) // p..t unicode(0x76..0x7A)); // v..z endtable; table(sub) _ clsCons clsBackRoundedVowel > @5 @2 _ / _ _ [clsCons clsCons? ]? _; endtable; ``` -------------------------------- ### Use AttributeOverride and followsHardC to change C based on vowel class (Exercise 7) Source: https://graphite.sil.org/tutorial/graphite_tut_solutions Gramble (GDL) program for Exercise 7. Uses AttributeOverride to override followsHardC for soft vowels (§ Exercise 7). ```gd #include "stddef.gdh" // The following is true by default, so does not really need to // be stated. It needs to be true because we are overriding // the value of followsHardC for soft vowels in the glyph table. environment { AttributeOverride = true }; table(glyph) gC = (U+0063 U+0043); gK = (U+006b U+004b); gS = (U+0073 U+0053); clsLetter = ((U+0061..U+007a), (U+0041..U+005a)) {followsHardC = true}; clsSoftVowel = (U+0065, U+0069, U+0079, // eiy U+0045, U+0049, U+0059) // EIY {followsHardC = false}; // overrides above endtable; table(sub) gC > gK / _ clsLetter { followsHardC }; gC > gS / _ clsLetter { !followsHardC }; endtable; endenvironment; ``` -------------------------------- ### Exercise 18: Case-sensitive reordering with context Source: https://graphite.sil.org/tutorial/graphite_tut_solutions Defines separate lower-case and upper-case classes for back-rounded vowels and consonants, then combines them. Substitution rules reorder consonant-vowel pairs with case-specific handling, using context patterns and explicit slot references. The note explains that `clsConsLC$2:2` can be written as `clsConsLC` for clarity. ```graphite #include "stddef.gdh" table(glyph) clsBackRndVowelLC = (unicode(0x6f), unicode(0x75)); // o, u clsBackRndVowelUC = (unicode(0x4f), unicode(0x55)); // O, U clsBackRndVowel = (clsBackRndVowelLC clsBackRndVowelUC); clsConsLC = (unicode(0x62..0x64), // b..d unicode(0x66..0x68), // f..h unicode(0x6A..0x6E), // j..n unicode(0x70..0x74), // p..t unicode(0x76..0x7A)); // v..z clsConsUC = (unicode(0x42..0x44), // B..D unicode(0x46..0x48), // F..H unicode(0x4A..0x4E), // J..N unicode(0x50..0x54), // P..T unicode(0x56..0x5A)); // V..Z clsCons = (clsConsLC clsConsUC); endtable; table(sub) // Move upper-case from consonant to reordered vowel. _ clsConsUC clsBackRndVowelLC > clsBackRndVowelUC$5:5 clsConsLC$2:2 _ // see note below / _ _ [clsCons clsCons? ]? _; // Move upper-case from vowel to consonant (odd, but you never know!). _ clsConsLC clsBackRndVowelUC > clsBackRndVowelLC$5:5 clsConsUC$2:2 / _ _ [clsCons clsCons? ]? _; // Otherwise, case matches on vowel and consonant; just reorder. _ clsCons clsBackRndVowel > @5 @2 _ / _ _ [clsCons clsCons? ]? _; endtable; ``` -------------------------------- ### Exercise 19a: Define hyphen-like glyph class with intra-word breaks Source: https://graphite.sil.org/tutorial/graphite_tut_solutions Defines a glyph class 'clsHyphenLike' containing hyphen, equals, underscore, and tilde, and sets their break property to BREAK_INTRA. No additional rules are needed for this exercise. ```graphite #include "stddef.gdh" table(glyph) clsHyphenLike = (unicode(0x2d), unicode(0x003d), unicode(0x5f), unicode(0x7e)) { break = BREAK_INTRA }; endtable; // No rules needed! ``` -------------------------------- ### Exercise 5a: Roman-to-Greek substitution with deletion rules Source: https://graphite.sil.org/tutorial/graphite_tut_solutions Exercise 5a: defines glyph classes for Roman and Greek letters, then deletes j and v and maps sequences like t+h to theta. Note: this program generates warnings for the deletion rules, and Linux users have reported compilation errors. ```gdl #include "stddef.gdh" table(glyph) // Roman clsRoman = ((U+0061..U+0069), // a..i (U+006B..U+0075), // k..u (U+0077..U+007a)); // w..z gJ = U+006a; gV = U+0076; gH = U+0068; gT = U+0074; gP = U+0070; gS = U+0073; // Greek clsGreek = (U+03b1, // alpha U+03b2, // beta U+03c7, // chi U+03b4, // delta U+03b5, // epsilon U+03c6, // phi U+03b3, // gamma U+03b7, // eta U+03b9, // iota U+03ba, // kappa U+03BB, // lambda - use BB to avoid compiler bug U+03bc, // mu U+03bd, // nu U+03bf, // omicron U+03d0, // pi U+03b8, // theta U+03c1, // rho U+03c2, // sigma U+03c4, // tau U+03c5, // upsilon U+03c9, // omega U+03be, // xi U+03c8, // psi U+03b6); // zeta gTheta = U+03b8; gPhi = U+03c6; gPsi = U+03c8; endtable; table(sub) // Delete j and v. Here we do not associate them // with any surface glyph, so it will be impossible // to select or manipulate them. gJ > _; gV > _; // Handle sequences. gT gH > gTheta:(1 2) _; gP gH > gPhi:(1 2) _; gP gS > gPsi:(1 2) _; // Everything else: clsRoman > clsGreek; endtable; ``` -------------------------------- ### Exercise 12c: Manual attachment points with overrides Source: https://graphite.sil.org/tutorial/graphite_tut_solutions Defines attachment points for base letters, iota subscript, and breathing marks. Overrides the attachment point for eta (gEta) and uses a negative offset for breathing marks. ```graphite #include "stddef.gdh" table(glyph) clsBase = (unicode(0x03b1) unicode(0x03b7), unicode(0x03c9)) { attPtIota = point(lsb + bb.width/2, bb.bottom); attPtBreath = point(lsb + bb.width/2, bb.top) }; // Adjust x-position of attachment point for eta. We are in // effect overriding the value set above. gEta = unicode(0x03b7) { attPtIota = point(lsb + (bb.width*3/8), bb.bottom + 160m) }; gIotaDiac = unicode(0x0345) { attPt = point(lsb + bb.width/2, bb.bottom + 50m) }; clsBreathDiac = unicode(0x0313..0x0314) { attPt = point(lsb + bb.width/2, bb.bottom – 50m) }; endtable; table(pos) clsBase clsBreathDiac { attach { to=@1; at=attPtBreath; with=attPt } } gIotaDiac { attach { to=@1; at=attPtIota; with=attPt } }; clsBase gIotaDiac { attach { to=@1; at= attPtIota; with=attPt } }; endtable; ``` -------------------------------- ### Mark C with hardC attribute and substitute in two passes (Exercise 9) Source: https://graphite.sil.org/tutorial/graphite_tut_solutions Gramble (GDL) program for Exercise 9. Defines hardC as user1 and uses two passes: first marks C based on context, then substitutes. (§ Exercise 9) ```gd #include "stddef.gdh" #define hardC user1 table(glyph) gC = (U+0063 U+0043); gK = (U+006b U+004b); gS = (U+0073 U+0053); clsHardLetter = ( (U+0061..U+0064), // a..d (U+0066..U+0068), // f..h (U+006A..U+0078), // j..x U+007A, // z (U+0041..U+0044), // A..D (U+0046..U+0058), // F..H (U+004A..U+0058), // J..X U+005A); // Z clsSoftLetter = (U+0065, U+0069, U+0079, // eiy U+0045, U+0049, U+0059) // EIY endtable; table(sub) pass(1) // Mark the C based on its context. gC {hardC = true} / _ clsHardLetter; gC {hardC = false} / _ clsSoftLetter; endpass; pass(2); // Make the substitution. gC > gK / _ {hardC}; gC > gS / _ {!hardC}; endpass; endtable; ``` -------------------------------- ### Exercise 12b: Manual attachment points for diacritics Source: https://graphite.sil.org/tutorial/graphite_tut_solutions Defines attachment points lowerM and lowerS for diacritic and base glyph classes, then attaches them in the pos table. Uses a workaround for a hinting bug by setting PointRadius to 0. ```graphite #include "stddef.gdh" environment { PointRadius = 0 } // workaround for hinting bug table(glyph) clsDiac = (unicode(0x0316) unicode(0x0317), unicode(0x031f), unicode(0x0327..0x0330)) { lowerM = point(lsb + bb.width/2, bb.top + 50m) }; clsBase = (unicode(0x61..0x7a), unicode(0x41..0x5a)) // An alternative to "advancewidth/2" is lsb + bb.width/2. { lowerS = point(advancewidth/2, bb.bottom) }; endtable; table(pos) clsBase clsDiac { attach { to=@1; at=lowerS; with=lowerM } }; endtable; endenvironment; ``` -------------------------------- ### Include stddef.gdh in GDL file Source: https://graphite.sil.org/tutorial/graide_tutorial2 Adds standard definitions and abbreviations from the stddef.gdh file. Place at the beginning of the GDL file. ```GDL #include "stddef.gdh" ``` -------------------------------- ### Exercise 2: map $ to £ as table(sub) Source: https://graphite.sil.org/tutorial/graphite_tut_solutions Defines a substitution table that maps the dollar sign (U+0024) to the pound sign (U+00A3). The source shows a comment indicating the alternative syntax 'U+0024 > U+00A3'. ```gdl #include "stddef.gdh" table(sub) unicode(0x0024) > unicode(0x00A3); // or U+0024 > U+00A3 endtable; ``` -------------------------------- ### Exercise 3b: map a digit class to an asterisk Source: https://graphite.sil.org/tutorial/graphite_tut_solutions Defines a glyph class clsDigit for the range U+0030..U+0039 and a glyph gAsterisk, then maps the entire class to the asterisk glyph in a substitution table. ```gdl #include "stddef.gdh" table(glyph) clsDigit = (U+0030..U+0039); gAsterisk = U+002A; endtable; table(sub) clsDigit > gAsterisk; endtable; ``` -------------------------------- ### Range with codepoint and comment Source: https://graphite.sil.org/tutorial/graide_tutorial3 Defines a class using a range of codepoint values. Comments are preceded by two slashes. ```GDL clsLowercase = codepoint(97..122); // a through z ``` -------------------------------- ### GDL rule using U+ codepoint syntax Source: https://graphite.sil.org/tutorial/graide_tutorial2 Alternative syntax for specifying Unicode codepoints. Does not require '0x' prefix, but the 'U' must be capitalized. ```GDL U+0061 > U+0062; ``` -------------------------------- ### Graphite rule with context syntax Source: https://graphite.sil.org/tutorial/graide_tutorial6 Shows the general syntax for a Graphite rule with context. The context follows a slash after the right-hand side, and each item from the left- and right-hand sides is represented by an underscore in the context. ```graphite left-hand-side > right-hand-side / context; ``` -------------------------------- ### Exercise 15: Minimal glyph table with upper-case class Source: https://graphite.sil.org/tutorial/graphite_tut_solutions Defines a glyph table with a single class for upper-case letters (U+0041..U+005A) with right direction. The lower-case class is commented out because it is true by default. No rules are needed. ```graphite #include "stddef.gdh" Bidi = true; table(glyph) // Not needed; true by default: //clsLower = (U+0061..U+007a) { dir = DIR_LEFT }; clsUpper = (U+0041..U+005a) { dir = DIR_RIGHT }; endtable; // No rules needed! ```