#include "dat.h" #include "fn.h" enum { Sbase = 0xAC00, Ncho = 19, Njung = 21, Njong = 28, }; static Rune cho[] = { L'ㄱ', L'ㄲ', L'ㄴ', L'ㄷ', L'ㄸ', L'ㄹ', L'ㅁ', L'ㅂ', L'ㅃ', L'ㅅ', L'ㅆ', L'ㅇ', L'ㅈ', L'ㅉ', L'ㅊ', L'ㅋ', L'ㅌ', L'ㅍ', L'ㅎ', }; static Rune jung[] = { L'ㅏ', L'ㅐ', L'ㅑ', L'ㅒ', L'ㅓ', L'ㅔ', L'ㅕ', L'ㅖ', L'ㅗ', L'ㅘ', L'ㅙ', L'ㅚ', L'ㅛ', L'ㅜ', L'ㅝ', L'ㅞ', L'ㅟ', L'ㅠ', L'ㅡ', L'ㅢ', L'ㅣ', }; static Rune jong[] = { 0, L'ㄱ', L'ㄲ', L'ㄳ', L'ㄴ', L'ㄵ', L'ㄶ', L'ㄷ', L'ㄹ', L'ㄺ', L'ㄻ', L'ㄼ', L'ㄽ', L'ㄾ', L'ㄿ', L'ㅀ', L'ㅁ', L'ㅂ', L'ㅄ', L'ㅅ', L'ㅆ', L'ㅇ', L'ㅈ', L'ㅊ', L'ㅋ', L'ㅌ', L'ㅍ', L'ㅎ', }; /* A jamo's index in cho, jung, or jong, or -1; jong[0] is no jong. */ static int idx(Rune *t, int n, Rune r) { int i; for(i = 0; i < n; i++) if(t[i] == r) return i; return -1; } #define Choidx(r) idx(cho, Ncho, r) #define Jungidx(r) idx(jung, Njung, r) #define Jongidx(r) idx(jong, Njong, r) static Rune jamomap[128] = { ['r'] = L'ㄱ', ['R'] = L'ㄲ', ['s'] = L'ㄴ', ['S'] = L'ㄴ', ['e'] = L'ㄷ', ['E'] = L'ㄸ', ['f'] = L'ㄹ', ['F'] = L'ㄹ', ['a'] = L'ㅁ', ['A'] = L'ㅁ', ['q'] = L'ㅂ', ['Q'] = L'ㅃ', ['t'] = L'ㅅ', ['T'] = L'ㅆ', ['d'] = L'ㅇ', ['D'] = L'ㅇ', ['w'] = L'ㅈ', ['W'] = L'ㅉ', ['c'] = L'ㅊ', ['C'] = L'ㅊ', ['z'] = L'ㅋ', ['Z'] = L'ㅋ', ['x'] = L'ㅌ', ['X'] = L'ㅌ', ['v'] = L'ㅍ', ['V'] = L'ㅍ', ['g'] = L'ㅎ', ['G'] = L'ㅎ', ['k'] = L'ㅏ', ['K'] = L'ㅏ', ['o'] = L'ㅐ', ['O'] = L'ㅒ', ['i'] = L'ㅑ', ['I'] = L'ㅑ', ['j'] = L'ㅓ', ['J'] = L'ㅓ', ['p'] = L'ㅔ', ['P'] = L'ㅖ', ['u'] = L'ㅕ', ['U'] = L'ㅕ', ['h'] = L'ㅗ', ['H'] = L'ㅗ', ['y'] = L'ㅛ', ['Y'] = L'ㅛ', ['n'] = L'ㅜ', ['N'] = L'ㅜ', ['b'] = L'ㅠ', ['B'] = L'ㅠ', ['m'] = L'ㅡ', ['M'] = L'ㅡ', ['l'] = L'ㅣ', ['L'] = L'ㅣ', }; typedef struct Cpair Cpair; struct Cpair { Rune b; Rune a; Rune r; }; static Cpair cvow[] = { {L'ㅗ', L'ㅏ', L'ㅘ'}, {L'ㅗ', L'ㅐ', L'ㅙ'}, {L'ㅗ', L'ㅣ', L'ㅚ'}, {L'ㅜ', L'ㅓ', L'ㅝ'}, {L'ㅜ', L'ㅔ', L'ㅞ'}, {L'ㅜ', L'ㅣ', L'ㅟ'}, {L'ㅡ', L'ㅣ', L'ㅢ'}, }; static Cpair cjong[] = { {L'ㄱ', L'ㅅ', L'ㄳ'}, {L'ㄴ', L'ㅈ', L'ㄵ'}, {L'ㄴ', L'ㅎ', L'ㄶ'}, {L'ㄹ', L'ㄱ', L'ㄺ'}, {L'ㄹ', L'ㅁ', L'ㄻ'}, {L'ㄹ', L'ㅂ', L'ㄼ'}, {L'ㄹ', L'ㅅ', L'ㄽ'}, {L'ㄹ', L'ㅌ', L'ㄾ'}, {L'ㄹ', L'ㅍ', L'ㄿ'}, {L'ㄹ', L'ㅎ', L'ㅀ'}, {L'ㅂ', L'ㅅ', L'ㅄ'}, }; static Rune keytojamo(int c) { if(c >= 0 && c < 128) return jamomap[c]; return 0; } static Rune combine(Cpair *t, int n, Rune b, Rune a) { int i; for(i = 0; i < n; i++) if(t[i].b == b && t[i].a == a) return t[i].r; return 0; } static int splitpair(Cpair *t, int n, Rune c, Rune *stay, Rune *next) { int i; for(i = 0; i < n; i++){ if(t[i].r == c){ *stay = t[i].b; *next = t[i].a; return 1; } } return 0; } static Rune compose(int c, int j, int jo) { return Sbase + c*Njung*Njong + j*Njong + jo; } static void decompose(Rune s, int *c, int *j, int *jo) { int i; i = s - Sbase; *c = i / (Njung * Njong); *j = (i / Njong) % Njung; *jo = i % Njong; } static int issyl(Rune r) { return r >= Sbase && r < Sbase + Ncho*Njung*Njong; } /* * The pending text is at most one syllable; a key either extends it, * commits it and starts another, or commits it and passes through. */ Emit transko(Im *im, Rune c) { Emit e; Rune jm, jc, last, comb, stay, next; int ci, ji, joi, ni, si, vi; memset(&e, 0, sizeof e); jm = keytojamo(c); if(jm == 0){ e.s = im->pre; return e; } e.eat = 1; last = slastr(&im->pre); if(last == 0){ sputr(&e.next, jm); return e; } if(!issyl(last)){ ci = Choidx(last); ji = Jungidx(jm); if(ci >= 0 && ji >= 0){ sputr(&e.next, compose(ci, ji, 0)); return e; } /* A vowel typed first is reordered under its consonant. */ if(Jungidx(last) >= 0 && Choidx(jm) >= 0){ sputr(&e.next, compose(Choidx(jm), Jungidx(last), 0)); return e; } /* Two vowels or two consonants may be one jamo, ㅘ or ㄳ. */ comb = combine(cvow, nelem(cvow), last, jm); if(comb == 0) comb = combine(cjong, nelem(cjong), last, jm); if(comb){ sputr(&e.next, comb); return e; } if(ji >= 0 && splitpair(cjong, nelem(cjong), last, &stay, &next)){ sputr(&e.s, stay); sputr(&e.next, compose(Choidx(next), ji, 0)); return e; } e.s = im->pre; sputr(&e.next, jm); return e; } decompose(last, &ci, &ji, &joi); if(joi == 0){ ni = Jongidx(jm); if(ni > 0){ sputr(&e.next, compose(ci, ji, ni)); return e; } vi = Jungidx(jm); if(vi >= 0){ comb = combine(cvow, nelem(cvow), jung[ji], jm); if(comb){ ni = Jungidx(comb); sputr(&e.next, compose(ci, ni, 0)); return e; } } } if(joi > 0){ comb = combine(cjong, nelem(cjong), jong[joi], jm); if(comb){ ni = Jongidx(comb); if(ni > 0){ sputr(&e.next, compose(ci, ji, ni)); return e; } } vi = Jungidx(jm); if(vi >= 0){ jc = jong[joi]; if(splitpair(cjong, nelem(cjong), jc, &stay, &next)){ si = Jongidx(stay); ni = Choidx(next); sputr(&e.s, compose(ci, ji, si)); sputr(&e.next, compose(ni, vi, 0)); return e; } ni = Choidx(jc); if(ni >= 0){ sputr(&e.s, compose(ci, ji, 0)); sputr(&e.next, compose(ni, vi, 0)); return e; } } } e.s = im->pre; sputr(&e.next, jm); return e; } void backko(Im *im) { Rune last; int c, j, jo; Rune stay, next; last = slastr(&im->pre); if(!issyl(last)){ spopr(&im->pre); if(splitpair(cvow, nelem(cvow), last, &stay, &next) || splitpair(cjong, nelem(cjong), last, &stay, &next)) sputr(&im->pre, stay); return; } decompose(last, &c, &j, &jo); spopr(&im->pre); if(jo > 0 && splitpair(cjong, nelem(cjong), jong[jo], &stay, &next)){ sputr(&im->pre, compose(c, j, Jongidx(stay))); return; } if(jo > 0){ sputr(&im->pre, compose(c, j, 0)); return; } if(splitpair(cvow, nelem(cvow), jung[j], &stay, &next)){ sputr(&im->pre, compose(c, Jungidx(stay), 0)); return; } sputr(&im->pre, cho[c]); }