#include "stddef.gdh" table(sub) unicode(0x0024) > unicode(0x00A3); // or U+0024 > U+00A3 endtable;
#include "stddef.gdh" table(glyph) gDollar = unicode(0x0024); gPound = unicode(0x00A3); endtable; table(sub) gDollar > gPound; endtable;
#include "stddef.gdh" table(glyph) clsDigit = (U+0030..U+0039); gAsterisk = U+002A; endtable; table(sub) clsDigit > gAsterisk; endtable;
#include "stddef.gdh" table(glyph) clsLower = unicode(0x61..0x7A); clsUpper = unicode(0x41..0x5A); endtable; table(sub) clsLower > clsUpper; endtable;
#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;
#include "stddef.gdh" table(glyph) clsRoman = ((U+0061..U+0069), // a..i (U+006B..U+0075), // k..u (U+0077..U+007a)); // w..z 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 endtable; table(sub) clsRoman > clsGreek; endtable;
Note that this program will generate warnings for the deletion rules.
Note
Linux users have reported compilation errors for this exercise.
#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;
#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;
#include "stddef.gdh" table(glyph) gC = (U+0063, U+0043); gK = (U+006b, U+004b); gS = (U+0073, U+0053); clsSoftVowel = (U+0065, U+0069, U+0079, // eiy U+0045, U+0049, U+0059); // EIY endtable; table(sub) gC > gS / _ clsSoftVowel; gC > gK; endtable;
#include "stddef.gdh" table(glyph) gQLower = unicode(0x71); gQUpper = unicode(0x51); gULower = unicode(0x75) ; gUUpper = unicode(0x55); clsUpper = unicode(0x41..0x5a); endtable; table(sub) _ > gUUpper:1 / gQUpper _ clsUpper; _ > gULower:1 / (gQUpper gQLower) _; endtable;
#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; gSigma = U+03c3; gSigmaFinal = U+03c2; 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 > _; // Replace s with the right kind of sigma. gS > gSigma / _ clsRoman; // ie, a Roman letter follows gS > gSigmaFinal; // followed by space, punctuation, or nothing at all // Handle sequences. gT gH > gTheta:(1 2) _; gP gH > gPhi:(1 2) _; gP gS > gPsi:(1 2) _; // Everything else: clsRoman > clsGreek; endtable;
#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;
#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;
#include "stddef.gdh" table(glyph) clsDigit = (U+0030..U+0039); endtable; table(pos) { MUnits = 1000 } clsDigit {shift.y = -300m} ; endtable;
#include "stddef.gdh" table(glyph) clsAUpper = U+0041; clsVWUpper = (U+0056, U+0057); endtable; table(pos) clsAUpper { kern.x = -175m } / clsVWUpper _ ; clsVWUpper { kern.x = -175m } / clsAUpper _ ; endtable;
#include "stddef.gdh" table(glyph) clsDotted = (unicode(0x69), unicode(0x6a)); // i, j clsDotless = (glyphid(194), glyphid(195)); clsDiac = (unicode(0x0300..0x0304), unicode(0x0308), unicode(0x030c)) { halfWidth = bb.width/2 }; clsBase = (unicode(0x61..0x7a), unicode(0x41..0x5a), clsDotless) { halfWidth = bb.width/2; baseHt = bb.top + 100m; rtSide = rsb; }; endtable; table(sub) // Remove any dot. clsDotted > clsDotless / _ clsDiac; endtable; table(pos) clsBase clsDiac { // "0 – lsb - ... " is a workaround for a bug in the compiler. shift { x = 0 - lsb - halfWidth - @1.halfWidth - @1.rtSide; y = @1.baseHt - bb.bottom } }; endtable;
#include "stddef.gdh" environment { PointRadius = 0 } // workaround for hinting bug table(glyph) clsDotted = (unicode(0x69), unicode(0x6a)); // i, j clsDotless = (glyphid(194), glyphid(195)); clsDiac = (unicode(0x0300..0x0304), unicode(0x0308), unicode(0x030c)) { upperAttPtM= point(lsb + bb.width/2, bb.bottom – 50m) }; clsBase = (unicode(0x61..0x7a), unicode(0x41..0x5a), clsDotless) // An alternative to "advancewidth/2" is "lsb + bb.width/2". { upperAttPtS = point(advancewidth/2, bb.top) }; endtable; table(sub) // Remove any dot. clsDotted > clsDotless / _ clsDiac; endtable; table(pos) clsBase clsDiac { attach { to=@1; at=upperAttPtS; with=upperAttPtM } }; endtable; endenvironment;
The following is the result when using Graide to create attachment points:
#include "stddef.gdh" table(glyph) clsDotted = (unicode(0x69), unicode(0x6a)); // i, j clsDotless = (glyphid(194), glyphid(195)); endtable; table(sub) // Remove any dot. clsDotted > clsDotless / _ cupperDia; endtable; // upperS and upperM are defined in the auto-generated file table(pos) cTakesupperDia cupperDia { attach { to=@1; at=upperS; with=upperM } }; endtable;
#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;
The following is the result when using Graide to create attachment points:
#include "stddef.gdh" // lowerS and lowerM are defined in the auto-generated file table(pos) cTakeslowerDia clowerDia { attach { to=@1; at=lowerS; with=lowerM } }; endtable;
#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;
The following is the result when using Graide to create attachment points:
#include "stddef.gdh" // lowerIotaS and lowerIotaM are defined in the auto-generated file table(pos) cTakeslowerIotaDia clowerIotaDia {attach {to = @1; at = lowerIotaS; with = lowerIotaM}}; endtable;
#include "stddef.gdh" table(glyph) clsDigit = (U+0030..U+0039); endtable; table(feature) supersub { id = "digt"; name.LG_USENG = string("Superscript or Subscript"); default = super; settings { no { value = 0; name.LG_USENG=string("Neither") } super { value = 1; name.LG_USENG=string("Superscript") } subsc { // unfortunately, can't call it "sub" value = 2; name.LG_USENG=string("Subscript") } } } endtable; table(pos) if (supersub == super) clsDigit {shift.y = 300m}; elseif (supersub == subsc) clsDigit {shift.y = -300m}; endif; endtable;
#include "stddef.gdh" table(glyph) clsAUpper = U+0041; clsVWUpper = (U+0056, U+0057); endtable; table(feature) doKerning { id = "k_wv" ; name.LG_USENG = string("Kerning"); } endtable; table(pos) if (doKerning) clsAUpper { kern.x = -175m } / clsVWUpper _ ; clsVWUpper { kern.x = -175m } / clsAUpper _ ; endif; endtable;
#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;
Note
This solution has not been tested. Try at your own risk!
#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;
#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;
#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;
#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!
#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 > @2 @1; endtable;
#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;
#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;
Note that clsConsLC$2:2 could be written as clsConsLC; the $2:2 is included only to make the code clearer.
#include "stddef.gdh" table(glyph) clsHyphenLike = (unicode(0x2d), unicode(0x003d), unicode(0x5f), unicode(0x7e)) { break = BREAK_INTRA }; endtable; // No rules needed!
#include "stddef.gdh" table(glyph) clsSylBreak = U+002a { break = BREAK_INTRA }; gHyphen = U+002d; endtable; table(sub) // Replace an * with a hyphen at a line break, otherwise delete it. clsSylBreak > gHyphen / _ # {break == BREAK_INTRA}; clsSylBreak > _; endtable;
#include "stddef.gdh" table(glyph) clsConsStop = (unicode(0x70), // p unicode(0x62), // b unicode(0x74), // t unicode(0x64), // d unicode(0x6b), // k unicode(0x67)); // g gHyphen = unicode(0x2d); endtable; table(lb) clsConsStop {break = BREAK_INTRA} / _ clsConsStop; endtable; table(sub) _ > gHyphen:1 / clsConsStop { break == BREAK_INTRA } _ #; endtable;
Modifying 19a:
#include "stddef.gdh" table(glyph) clsHyphenLike = (unicode(0x2d), unicode(0x003d), unicode(0x5f), unicode(0x7e)) { break = BREAK_INTRA }; endtable; table(sub) // Insert a copy of the "hyphen" at the beginning of the following line. _ > @1 / clsHyphenLike # _; endtable;
Modifying 19b:
#include "stddef.gdh" table(glyph) clsSylBreak = U+002a { break = BREAK_INTRA }; gHyphen = U+002d; endtable; table(sub) // Replace an * with a hyphen at a line break; // also insert a hyphen at the beginning of the following line. clsSylBreak _ > gHyphen gHyphen:1 / _ # {break == BREAK_INTRA} _; // Otherwise delete it. clsSylBreak > _; endtable;
Modifying 19c:
#include "stddef.gdh" table(glyph) clsConsStop = (unicode(0x70), // p unicode(0x62), // b unicode(0x74), // t unicode(0x64), // d unicode(0x6b), // k unicode(0x67)); // g gHyphen = unicode(0x2d); endtable; table(lb) clsConsStop {break = BREAK_INTRA} / _ clsConsStop; endtable; table(sub) // A bug in the Graphite engine forces us to test the // breakweight of the line-break itself, not the consonant. _ _ > gHyphen:1 gHyphen:1 / clsConsStop _ # { break == BREAK_INTRA } _; endtable;
Copyright © 2012 SIL International® and released under the Creative Commons Attribution-ShareAlike 3.0 license (CC-BY-SA) unless noted otherwise.