001 I64 ReadUTF8(U8 *st,U8 **en=NULL) {
002   I64 ch=*st;
003   if(0b10000000&ch==0) {
004     if(en) *en=st+1;
005     return ch;
006   }
007   if(0b11100000&ch==0b11000000) {
008     if(en) *en=st+2;
009     return (st[0]&0b11111)<<6|((st[1]&0b111111));
010   }
011   if(0b11110000&ch==0b11100000) {
012     if(en) *en=st+3;
013     return (st[0]&0b1111)<<12|(st[1]&0b111111)<<6|((st[2]&0b111111));
014   }
015   if(en) *en=st+4;
016   return (st[1]&0b111)<<18|(st[1]&0b111111)<<12|(st[2]&0b111111)<<6|((st[3]&0b111111));  
017 }
018 U8 Transliterate(U64 ch) {
019 //https://en.wiktionary.org/wiki/Appendix:Unicode/Latin_Extended-A
020   switch(ch) {
021     case 0x100...0x105:
022       ch='a';
023       break;
024     case 0x106...0x10D:
025       ch='c';
026       break;
027     case 0x10e...0x11b:
028       ch='e';
029       break;
030     case 0x11f...0x123:
031       ch='e';
032       break;
033     case 0x124...0x127:
034       ch='e';
035       break;
036     case 0x128...0x135:
037       ch='i';
038       break;
039     case 0x136...0x138:
040       ch='k';
041       break;
042     case 0x139...0x142:
043       ch='l';
044       break;
045     case 0x143...0x14b:
046       ch='n';
047       break;
048     case 0x14c...0x151:
049       ch='o';
050       break;
051     case 0x154...0x159:
052       ch='e';
053       break;
054     case 0x15a...0x161:
055       ch='s';
056       break;
057     case 0x162...0x167:
058       ch='t';
059       break;
060     case 0x168...0x173:
061       ch='u';
062       break;
063     case 0x174...0x175:
064       ch='w';
065       break;
066     case 0x176...0x178:
067       ch='y';
068       break;
069     case 0x179...0x17e:
070       ch='z';
071       break;
072     default:
073     if(!ch)
074       return 0;
075     if(!(31<=ch<=128))
076       ch='?';
077   }
078   return ch;
079 }
080 
081 #define J_STR 1
082 #define J_NUM 2
083 #define J_ARRAY 3
084 #define J_NODE 4
085 class CJson {
086   I64 type;
087   union {
088     U8 *str;
089     F64 num;
090     CHashTable *hash_table;
091   }
092   I64 cnt;
093 };
094 
095 U8 *sqstring(U8 *ptr,U8 **en) {
096   U8 *buf=MAlloc(256);
097   I64 ch=0,C;
098   if(en) *en=ptr;
099   if(*ptr!='\'') return NULL;
100   ptr++;
101   while(*ptr&&*ptr!='\'') {
102     if(*ptr=='\\') {
103       ptr++;
104 read_one:
105       C=ReadUTF8(ptr,&ptr);
106       if(ch<255)
107         buf[ch++]=Transliterate(C);
108     } else
109         goto read_one;
110   }
111   buf[ch]=0;
112   if(en) *en=ptr+1;
113   return buf;
114 }
115 
116 U8 *dqstring(U8 *ptr,U8 **en) {
117   U8 *buf=MAlloc(256);
118   I64 ch=0,C;
119   if(en) *en=ptr;
120   if(*ptr!='"') return NULL;
121   ptr++;
122   while(*ptr&&*ptr!='"') {
123     if(*ptr=='\\') {
124       ptr++;
125 read_one:
126       C=ReadUTF8(ptr,&ptr);
127       if(ch<255)
128         buf[ch++]=Transliterate(C);
129     } else
130         goto read_one;
131   }
132   buf[ch]=0;
133   if(en) *en=ptr+1;
134   return buf;
135 }
136 
137 
138 U8 *SkipWhitespace(U8 *s) {
139   while(*s&&Bt(char_bmp_white_space,*s))
140     s++;
141   return s;
142 }
143 U8 *word(U8 *ptr,U8 **en) {
144   U8 *buf=MAlloc(256);
145   I64 ch=0;
146   if(en) *en=ptr;
147   if(!Bt(char_bmp_alpha_numeric,*ptr)) return NULL;
148   while(Bt(char_bmp_alpha_numeric,*ptr))
149     buf[ch++]=*ptr++;
150   buf[ch]=0;
151   if(en) *en=ptr;
152   return buf;
153 }
154 class CIndexBlk {
155     I64 inst_cnt;
156     I64 inst_offsets[32];
157     U8 *body['z'-'a'+1];
158     I64 pad[(BLK_SIZE-8-8*('z'-'a'+1))/8];
159 };
160 CJson *ParseJson(U8 *st,U8 **en=NULL) {
161   CJson *ret=NULL;
162   U8 *name;
163   CHashGeneric *g;
164   st=SkipWhitespace(st);
165   if(*st=='{') {
166     ret=CAlloc(sizeof CJson);
167     ret->type=J_NODE;
168     ret->hash_table=HashTableNew(0x8);
169     st=SkipWhitespace(st+1);
170     while(*st!='}') {
171       if(!*st) throw('JSON');
172       switch(*st) {
173         case '\'':
174         name=sqstring(st,&st);
175         break;
176         case '"':
177         name=dqstring(st,&st);
178         break;
179         default:
180         name=word(st,&st);
181         break;
182       }
183       if(!name) throw('JSON');
184       st=StrFirstOcc(st,":");
185       if(!st) throw('JSON');
186       st++;
187       g=CAlloc(sizeof CHashGeneric);
188       g->str=name;
189       g->type=HTT_WORD;
190       g->user_data0=ParseJson(st,&st);
191       HashAdd(g,ret->hash_table);
192       st=StrFirstOcc(st,",}");
193       if(!st) throw('JSON');
194       if(*st==',') st++;
195       st=SkipWhitespace(st);
196     }
197     st++;
198   } else if(*st=='\'') {
199     ret=CAlloc(sizeof CJson);
200     ret->type=J_STR;
201     ret->str=sqstring(st,&st);
202   } else if(*st=='\"') {
203     ret=CAlloc(sizeof CJson);
204     ret->type=J_STR;
205     ret->str=dqstring(st,&st);
206   } else if(*st=='[') {
207     st=SkipWhitespace(st+1);
208     ret=CAlloc(sizeof CJson);
209     ret->type=J_ARRAY;
210     ret->hash_table=HashTableNew(0x10);
211     while(*st!=']') {
212       g=CAlloc(sizeof CHashGeneric);
213       g->str=MStrPrint("%d",ret->cnt++);
214       g->type=HTT_DICT_WORD;
215       g->user_data0=ParseJson(st,&st);
216       HashAdd(g,ret->hash_table);
217       st=StrFirstOcc(st,",]");
218       if(!st) throw('JSON');
219       if(*st==',') st++;
220       st=SkipWhitespace(st);
221     }
222     st++;
223   } else {
224     name=st;
225     ret=CAlloc(sizeof CJson);
226     ret->type=J_NUM;
227     ret->num=Str2F64(st,&st);
228     if(name==st)
229       throw('JSON');
230   }
231   if(en) *en=st;
232   if(!ret) throw('JSON');
233   return ret;
234 }
235 U0 JsonDel(CJson *j) {
236   I64 bucket;
237   CHashGeneric *g;
238   switch(j->type) {
239     case J_STR:
240       Free(j->str);
241       break;
242     case J_NUM:
243       break;
244     case J_NODE:
245     case J_ARRAY:
246       for(bucket=0;bucket<=j->hash_table->mask;bucket++)
247         for(g=j->hash_table->body[bucket];g;g=g->next) {
248           JsonDel(g->user_data0);
249         }
250       HashTableDel(j->hash_table);
251   }
252   Free(j);
253 }
254 U0 DumpJson(CJson *j) {
255   I64 bucket;
256   CHashGeneric *g;
257   switch(j->type) {
258     case J_STR:
259       "\"%Q\"",j->str;
260       break;
261     case J_NUM:
262       "%n",j->num;
263       break;
264     case J_NODE:
265     case J_ARRAY:
266       "{$ID,2$\n";
267       for(bucket=0;bucket<=j->hash_table->mask;bucket++)
268         for(g=j->hash_table->body[bucket];g;g=g->next) {
269           "%s:",g->str;
270           DumpJson(g->user_data0);
271           ",\n";
272         }
273       "$ID,-2$\n}";
274   }
275 }
276 I64 GetWordPtr(I64 *max,CFile *file,U8 *str,I64 ptr=0,Bool *new=NULL) {
277   if(new) *new=FALSE;
278   if(!*str) return ptr;
279   I64 idx=ToUpper(*str)-'A';
280   CIndexBlk dummy;
281   FBlkRead(file,&dummy,ptr,1);
282   if(new) *new=FALSE;
283   if(!dummy.body[idx]) {
284     dummy.body[idx]=*max;
285     FBlkWrite(file,&dummy,ptr,1);
286     MemSet(&dummy,0,sizeof CIndexBlk);
287     FBlkWrite(file,&dummy,ptr=(*max)++,1);
288     if(new) *new=TRUE;
289     return GetWordPtr(max,file,str+1,ptr);
290   }
291 if(ptr>*max) throw('trie');
292   return GetWordPtr(max,file,str+1,dummy.body[idx],new);
293 }
294 U0 MakeIndex(U8 *outname,U8 *in_name) {
295   CIndexBlk dummy;
296   U8 *optr=FileRead(in_name),*fptr;
297   Bool new;
298   CFile *file;
299   CHeapCtrl *cc;
300   CHashGeneric *g;
301   CJson *j,*str;
302   Del(outname);
303   file=FOpen(outname,"w");
304   MemSet(&dummy,0,sizeof CIndexBlk);
305   FBlkWrite(file,&dummy);
306   fptr=optr;
307   I64 off=0,blk,sz=1;
308   do {
309     fptr=SkipWhitespace(fptr);
310     off=fptr-optr;
311     if(!*fptr) break;
312     j=ParseJson(fptr,&fptr);
313     if(j&&j->type==J_NODE) {
314       g=HashFind("word",j->hash_table,-1);
315       str=g->user_data0;
316       if(str&&str->type=J_STR) {
317 //Ensure all charactors are alpha
318         for(blk=0;blk!=StrLen(str->str);blk++) {
319           if(!('A'<=ToUpper(str->str[blk])<='Z'))
320            goto skip;
321         }
322         blk=GetWordPtr(&sz,file,str->str,,&new);
323         FBlkRead(file,&dummy,blk,1);
324         if(new) {
325           dummy.inst_cnt=1;
326           dummy.inst_offsets[0]=off;
327         } else {
328           if(dummy.inst_cnt<32)
329             dummy.inst_offsets[dummy.inst_cnt++]=off;
330         }
331         FBlkWrite(file,&dummy,blk,1);
332 skip:;
333       }
334     }
335     JsonDel(j);
336   } while(TRUE);
337   file->de.size=sz<<BLK_SIZE_BITS;
338   FClose(file); //Flush to disk to avoid long ram buffering
339   Free(optr);
340 }
341 //Yvng poop poodle https://kaikki.org/dictionary/Latin/kaikki.org-dictionary-Latin.json
342 if(!FileFind("/INDEX.TRIE")&&FileFind("/Latin.json"))
343   MakeIndex("/INDEX.TRIE","/Latin.json");
344 I64 GetWordOffset(U8 *word,U8 *index_file="/INDEX.TRIE",I64 inst=0) {
345   CFile *file=FOpen(index_file,"r");
346   CIndexBlk dummy;
347   I64 blk=0,idx,off=-1;
348   while(*word) {
349     idx=ToUpper(*word)-'A';
350     FBlkRead(file,&dummy,blk,1);    
351     if(!dummy.body[idx]) 
352       break;
353     blk=dummy.body[idx];
354     word++;
355   }
356   if(!*word)  {
357     FBlkRead(file,&dummy,blk,1);
358     off=dummy.inst_offsets[inst];
359     if(!off) off=-1;
360   }
361   FClose(file);
362   return off;
363 }
364 U8 *GetWordString(U8 *word,U8 *json_file="/Latin.json",U8 *index_file="/INDEX.TRIE",I64 inst=0) {
365   I64 off=GetWordOffset(word,index_file,inst),off2;
366   if(off==-1) return NULL;
367   U8 buffer[0x10000],fbuf[BLK_SIZE],*ret,*tmp;
368   I64 bo=0;
369   CFile *file=FOpen(json_file,"r");
370   buffer[bo]=0;
371 loop:
372   FBlkRead(file,fbuf,off2=off>>BLK_SIZE_BITS);
373   off2<<=BLK_SIZE_BITS;
374   if(off!=off2) {
375     MemCpy(buffer+bo,fbuf+off-off2,BLK_SIZE-(off-off2));
376     bo+=BLK_SIZE-(off-off2);
377     off=off2+BLK_SIZE;
378     buffer[bo]=0;
379   } else {
380     MemCpy(buffer+bo,fbuf,BLK_SIZE);
381     bo+=BLK_SIZE;
382     off=off2+BLK_SIZE;
383     buffer[bo]=0;
384   }
385   if(!StrOcc(buffer,'\n')) {
386     goto loop;
387   } else *StrFirstOcc(buffer,"\n")=0;
388   FClose(file);
389   ret=CAlloc(bo+1);
390   tmp=buffer;
391   off=0;
392   while(bo=Transliterate(ReadUTF8(tmp,&tmp))) {
393     ret[off++]=bo;
394   }
395   return ret;
396 }
397 CJson *GetJsonMember(CJson *j,U8 *member,I64 type=-1) {
398   CHashGeneric *g;
399   if(j->type==J_ARRAY||j->type==J_NODE) {
400     g=HashFind(member,j->hash_table,-1);
401     if(g) {
402       j=g->user_data0;
403       if(type==-1) return j;
404       else if(type==j->type) return j;
405     }
406   }
407   return NULL;
408 }
409 U8 *GetBaseWord(U8 *word,I64 inst=0) {
410   U8 *ws=GetWordString(word);
411   if(!ws) return NULL;
412   U8 buf[STR_LEN];
413   I64 idx,idx2;
414   CJson *j=ParseJson(ws,NULL),*s0,*s,*f,*t;
415   Free(ws);
416   if(s0=GetJsonMember(j,"senses",J_ARRAY)) {
417     if(s=GetJsonMember(s0,StrPrint(buf,"%d",inst),J_NODE)) {
418       f=GetJsonMember(s,"form_of",J_ARRAY);
419       if(f) {
420         for(idx=0;t=GetJsonMember(f,StrPrint(buf,"%d",idx),J_NODE);idx++) {
421           if(t) t=GetJsonMember(t,"word",J_STR);
422           if(t) {
423             word=StrNew(t->str);
424             JsonDel(j);  
425             return word;
426           }
427         }
428       }
429     }
430   }
431   JsonDel(j);
432   if(inst)
433     return NULL;
434   return StrNew(word);
435 }
436 Bool IsFormOf(U8 *who,U8 *who2) {
437   I64 i,i2;
438   U8 *b,*b2,ret=FALSE;
439   for(i=0;b=GetBaseWord(who,i);i++) {
440     for(i2=0;b2=GetBaseWord(who,i2);i2++) {
441       if(!StrCmp(b,b2))
442         ret=TRUE;
443       Free(b2);
444     }
445     Free(b);
446   }
447   return ret;
448 }
449 extern U8 *GetTranslation(U8*,Bool recurse=FALSE);
450 U8 *SmallDefinition(U8 *def) {
451   if(!def) return def;
452   U8 buf[STR_LEN],*bptr=buf,*want;
453   Bool changed=TRUE;
454   I64 len1,len2;
455   def=StrNew(def);
456   if(want=StrIMatch("conjugation of",def)) {
457     StrScan(want,"conjugation of %s:",&bptr);
458     return GetTranslation(buf);
459   }
460   if(want=StrIMatch("inflection of",def)) {
461     StrScan(want,"inflection of %s:",&bptr);
462     return GetTranslation(buf);
463   }
464   if(want=StrIMatch("alternative spelling of",def)) {
465     StrScan(want,"alternative spelling of %s:",&bptr);
466     return GetTranslation(buf);
467   }
468   while(changed) {
469     changed=FALSE;
470     U8 *first=StrFirstOcc(def,"("),*last;
471     if(first) {
472       if(last=StrFirstOcc(first,")")) {
473         StrCpy(first,last+1);
474         changed=TRUE;
475       }
476     }
477     if(first=StrFirstOcc(def,",")) {
478       len1=first-def;
479       len2=StrLen(first+1);
480       if(len1<len2) {
481         *first=0;
482       } else {
483         StrCpy(def,first+1);
484       }
485       changed=TRUE;
486     }
487   }
488   return StrUtil(def,SUF_REM_TRAILING|SUF_REM_LEADING);
489 } 
490 //Your on your own
491 U8 *GetTranslation(U8 *word,Bool recurse=TRUE) {
492   I64 inst;
493   U8 *str;
494   if(!word) return NULL;
495   U8 buf[STR_LEN],*best=NULL,buf2[STR_LEN];
496   I64 idx,idx2;
497   CJson *j,*t,*s0,*g,*s,*f;
498   U8 *trans=NULL,*tmp;
499   for(inst=0;str=GetWordString(word,,,inst);inst++) {
500     j=ParseJson(str,NULL);
501    if(s0=GetJsonMember(j,"senses",J_ARRAY)) {
502       if(s=GetJsonMember(s0,"0",J_NODE)) { //Use first (most common ?) sense of the word
503         f=GetJsonMember(s,"form_of",J_ARRAY);
504         if(f) {
505           for(idx=0;t=GetJsonMember(f,StrPrint(buf,"%d",idx),J_NODE);idx++) {
506             if(t) t=GetJsonMember(t,"word",J_STR);
507             if(!t) goto defacto;
508             if(tmp=GetTranslation(t->str,FALSE)) {
509               if(!trans) trans=tmp;
510               else if(StrLen(trans)>StrLen(tmp)) {
511                 Free(trans);
512                 trans=tmp;
513               } else
514                 Free(tmp);
515             }
516           }
517 //Only use definition of root word
518           goto fin;
519         } else {
520 defacto:;
521           g=GetJsonMember(s,"glosses",J_ARRAY);
522 //Pick shortest translation
523           if(g) {
524 //Use 1st (Most common?) defintion
525             if(t=GetJsonMember(g,"0",J_STR)) {
526               tmp=SmallDefinition(t->str);
527               if(!trans) trans=tmp;
528               else if(StrLen(trans)>StrLen(tmp)) {
529                 Free(trans);
530                 trans=tmp;
531               } else
532                 Free(tmp);
533             }
534           }
535         }
536       }
537     }
538 fin:;
539     JsonDel(j);
540     Free(str);
541   }
542   if(!trans)
543     return trans;
544   return StrUtil(trans,SUF_REM_CTRL_CHARS);
545 }
546 //Returns a long list of translations
547 U8 *GetTranslations(U8 *word,Bool recurse=TRUE,I64 *_which=NULL) {
548   I64 inst;
549   U8 *str;
550   if(!word) return NULL;
551   U8 buf[STR_LEN],*best=NULL,buf2[STR_LEN];
552   I64 idx,idx2;
553   CJson *j,*t,*s0,*g,*s,*f;
554   I64 which=1;
555   if(!_which)
556     _which=&which;
557   CDoc *trans=DocNew;
558   for(inst=0;str=GetWordString(word,,,inst);inst++) {
559     j=ParseJson(str,NULL);
560     if(s0=GetJsonMember(j,"senses",J_ARRAY)) {
561       for(idx2=0;s=GetJsonMember(s0,StrPrint(buf,"%d",idx2),J_NODE);idx2++) {
562         f=GetJsonMember(s,"form_of",J_ARRAY);
563         if(f) {
564           for(idx=0;t=GetJsonMember(f,StrPrint(buf,"%d",idx),J_NODE);idx++) {
565             if(t) t=GetJsonMember(t,"word",J_STR);
566             if(!t) goto defacto;
567             if(best=GetTranslations(t->str,FALSE,_which)) {
568               DocPrint(trans,"%s",best);
569               Free(best);
570             }
571           }
572           goto defacto;
573         } else {
574 defacto:
575           g=GetJsonMember(s,"glosses",J_ARRAY);
576 //Pick shortest translation
577           if(g) {
578             for(idx=0;t=GetJsonMember(g,StrPrint(buf,"%d",idx),J_STR);idx++) {
579               DocPrint(trans,"%d: %s\n",(*_which)++,t->str);
580             }
581           }
582         }
583       }
584     }
585     JsonDel(j);
586     Free(str);
587   }
588   best=DocSave(trans);
589   DocDel(trans);
590   return StrUtil(best,SUF_REM_CTRL_CHARS);
591 }
592 CTask *p=Fs;
593 U0 LookUpWord(U8 *word) {
594   if(FramePtr(word,trie_task))
595     return;
596 //avoid renundant
597   FramePtrAdd(word,1,trie_task);
598   U8 dummy[STR_LEN];
599   U8 *json_file="../Latin.json",*index_file="/INDEX.TRIE";
600   U8 *str,*trans;
601   I64 inst=0;
602 PrintI(word,1);
603   trans=GetTranslation(word);
604 PrintI(trans,2);
605 loop:;
606   I64 flags=0,idx,idx2,base_flags=0,idx3,added=0;
607   str=GetWordString(word,json_file,index_file,inst++);
608   if(!str) {
609     Free(trans);
610     return;
611   }
612   CJson *j=ParseJson(str,NULL),*n,*f,*senses;
613   if(n=GetJsonMember(j,"pos",J_STR)) {
614     if(!StrICmp(n->str,"verb")) flags|=VERB;
615     else if(!StrICmp(n->str,"noun")) flags|=NOUN;
616     else if(!StrICmp(n->str,"adj")) flags|=ADJECTIVE;
617     else if(!StrICmp(n->str,"conj")) flags|=CONJUNCTION;
618     else if(!StrICmp(n->str,"prep")) flags|=PREPOSITION;
619     else if(!StrICmp(n->str,"adv")) flags|=ADVERB;
620     else if(!StrICmp(n->str,"pron")) flags|=PRONOUN;
621   }
622   base_flags=flags;
623   for(idx3=0;idx3!=2;idx3++) {
624     if(idx3==0)
625       senses=GetJsonMember(j,"senses",J_ARRAY);
626     else if(idx3==1)
627       senses=GetJsonMember(j,"forms",J_ARRAY);
628     if(senses) {
629       for(idx2=0;idx2!=senses->cnt;idx2++) {
630         StrPrint(dummy,"%d",idx2);
631         n=GetJsonMember(senses,dummy);;
632         flags=base_flags;
633         if(idx3==1) {
634           if(f&&(f=GetJsonMember(n,"form",J_STR))) {
635             if(StrICmp(f->str,word))
636               goto skip;
637           } else
638             goto skip;
639         }
640         if(n&&(n=GetJsonMember(n,"tags",J_ARRAY))) {
641           for(idx=0;idx!=n->cnt;idx++) {
642             StrPrint(dummy,"%d",idx);
643             if(f=GetJsonMember(n,dummy,J_STR)) {
644               DbgPrint("%s for %s\n",f->str,word);
645               if(!StrICmp(f->str,"masculine")) flags|=MASCULINE;
646               if(!StrICmp(f->str,"feminine")) flags|=FEMININE;
647               if(!StrICmp(f->str,"neuter")) flags|=NEUTER;
648               if(!StrICmp(f->str,"singular")) flags|=SINGULAR;
649               if(!StrICmp(f->str,"plural")) flags|=PLURAL;
650               if(!StrICmp(f->str,"nominative")) flags|=NOMITIVE;
651               if(!StrICmp(f->str,"accusative")) flags|=ACCUSATIVE;
652               if(!StrICmp(f->str,"dative")) flags|=DATIVE;
653               if(!StrICmp(f->str,"ablative")) flags|=ABLATIVE;
654               if(!StrICmp(f->str,"genitive")) flags|=GENITIVE;
655               if(!StrICmp(f->str,"infinitive")) flags|=INFINITIVE;
656               if(!StrICmp(f->str,"imperfect")) flags|=IMPERFECT;
657               if(!StrICmp(f->str,"future")) flags|=FUTURE;
658               if(!StrICmp(f->str,"first-person")) flags|=_1P;
659               if(!StrICmp(f->str,"second-person")) flags|=_2P;
660               if(!StrICmp(f->str,"third-person")) flags|=_3P;
661               if(!StrICmp(f->str,"perfect")) flags|=PERFECT;
662               if(!StrICmp(f->str,"pluperfect")) flags|=PLUPERFECT;
663               if(!StrICmp(f->str,"subjunctive")) flags|=SUBJUNCTIVE;
664               if(!StrICmp(f->str,"passive")) flags|=PASSIVE;
665               if(!StrICmp(f->str,"comparative")) flags|=COMPARATIVE;
666               if(!StrICmp(f->str,"superlative")) flags|=SUPERLATIVE;
667               if(!StrICmp(f->str,"participle")) flags|=PARTICIPLE;
668               if(!StrICmp(f->str,"determiner")) flags|=DETIRMINER;
669               if(!StrICmp(f->str,"pronoun")) flags|=PRONOUN;
670               if(!StrICmp(f->str,"declension-1")) flags|=DECLENSION1;
671               if(!StrICmp(f->str,"declension-2")) flags|=DECLENSION2;
672               if(!StrICmp(f->str,"declension-3")) flags|=DECLENSION3;
673               if(!StrICmp(f->str,"declension-4")) flags|=DECLENSION4;
674               if(!StrICmp(f->str,"declension-5")) flags|=DECLENSION5;
675               if(!StrICmp(f->str,"conjugation-1")) flags|=CONJUGATION1;
676               if(!StrICmp(f->str,"conjugation-2")) flags|=CONJUGATION2;
677               if(!StrICmp(f->str,"conjugation-3")) flags|=CONJUGATION3;
678               if(!StrICmp(f->str,"conjugation-4")) flags|=CONJUGATION4;
679               if(!StrICmp(f->str,"active")) flags|=0; //ACTIVE is implicit
680               if(!StrICmp(f->str,"intransitive")) flags|=INTRANSITIVE;
681               if(!StrICmp(f->str,"superlative")) flags|=SUPERLATIVE;
682               if(!StrICmp(f->str,"comparative")) flags|=COMPARATIVE;
683               DbgPrint("%s for %s\n",f->str,word);
684             }
685           }
686           if(!TrieExists(word,flags)) {
687             added++;
688             DeclensionForWord(flags,TrieAdd(word,flags,trans));
689           }
690 skip:;
691         }
692       }
693     }
694   }
695   if(!added)
696     TrieAdd(word,base_flags,trans);
697   JsonDel(j);
698   Free(str);
699   goto loop;
700 }