001 Cd(__DIR__); 002 #include "GrammarAST.HC" 003 #define LIMIT_FP "GenCap" 004 #define CNT_FP "GenCnt" 005 #define RESULTS_FP "Results" 006 CTask *grammar_task=Fs; 007 class CRule { 008 U8 name[STR_LEN]; //Rule name or word name 009 I64 raw_type; 010 U8 *validate_fun; //CallExtStr HasForm Bool Fun(I64 argc,CAST **argc); 011 U8 *flags_fun; //CallExtStr HasForm Bool Fun(...); Sets the flags of the node 012 I64Set *made_from; 013 //add_to_member is a list of member types (AST_xxx) to add made_from's too 014 //NULL for default 015 I64Set *member_types; 016 I64 main_item_idx; 017 I64 is_word; 018 I64 word_flags; //Flags to match 019 F64 weight; //.5 by default 020 }; 021 022 I64 MemberNameToI64(U8 *str) { 023 if(!StrCmp(str,"NOUN")) 024 return AST_NOUN; 025 else if(!StrCmp(str,"VERB")) 026 return AST_VERB; 027 else if(!StrCmp(str,"CONJUNCTION")) 028 return AST_CONJUNCTION; 029 else if(!StrCmp(str,"OF")) 030 return AST_OF; 031 else if(!StrCmp(str,"WHERE")) 032 return AST_WHERE; 033 else if(!StrCmp(str,"ADJECTIVE")) 034 return AST_ADJECTIVE; 035 else if(!StrCmp(str,"INFINITIVE")) 036 return AST_INFINITIVE; 037 else if(!StrCmp(str,"MEASURE")) 038 return AST_MEASURE; 039 else if(!StrCmp(str,"ADVERB")) 040 return AST_ADVERB; 041 else if(!StrCmp(str,"CLAUSE")) 042 return AST_INDIRECT_CLAUSE; 043 else if(!StrCmp(str,"COMPARE")) 044 return AST_COMPARSION; 045 else if(!StrCmp(str,"QUESTION")) 046 return AST_QUESTION; 047 else 048 return -1; 049 } 050 #define CASE_MASK (NOMITIVE|ACCUSATIVE|ABLATIVE|DATIVE|GENITIVE) 051 #define NUMBER_MASK (PLURAL) 052 I64 FlagsSingle(I64 argc,AST **argv) { 053 I64 i=0; 054 AST *ast; 055 I64 or=0; 056 for(i=0;i!=argc;i++) { 057 ast=argv[i]; 058 if(ast->act_as_type==AST_NOUN) 059 or|=ast->flags; 060 } 061 return or; 062 } 063 I64 FlagsPlural(I64 argc,AST **argv) { 064 I64 i=0; 065 AST *ast; 066 I64 or=PLURAL; 067 for(i=0;i!=argc;i++) { 068 ast=argv[i]; 069 if(ast->act_as_type==AST_NOUN) 070 or|=ast->flags; 071 } 072 return or; 073 } 074 I64 FlagsAppositive(I64 argc,AST **argv) { 075 I64 i=0; 076 AST *ast; 077 I64 or=0; 078 for(i=0;i!=argc;i++) { 079 ast=argv[i]; 080 if(ast->act_as_type==AST_NOUN) 081 or|=ast->flags; 082 } 083 return or; 084 } 085 I64 FlagsTransfer(I64 argc,AST **argv) { 086 I64 i=0; 087 AST *ast; 088 I64 or=0; 089 for(i=0;i!=argc;i++) { 090 ast=argv[i]; 091 or|=ast->flags; 092 } 093 return or; 094 } 095 I64 FlagsAcc(I64 argc,AST **argv) { 096 I64 i=0; 097 AST *ast; 098 I64 or=ACCUSATIVE; 099 for(i=0;i!=argc;i++) { 100 ast=argv[i]; 101 or|=ast->flags; 102 } 103 return or; 104 } 105 106 Bool NumberAgree(I64 argc,AST **argv) { 107 I64 i=0; 108 AST *ast; 109 Bool plural=FALSE; 110 Bool nomitive_only=FALSE; 111 for(i=0;i!=argc;i++) { 112 ast=argv[i]; 113 if(ast->act_as_type==AST_ADJECTIVE) { 114 if(ast->flags&PLURAL) 115 plural=TRUE; 116 } else if(ast->act_as_type==AST_VERB) { 117 nomitive_only=TRUE; 118 if(ast->flags&PLURAL) 119 plural=TRUE; 120 } 121 } 122 for(i=0;i!=argc;i++) { 123 ast=argv[i]; 124 if(ast->act_as_type==AST_NOUN) 125 if(nomitive_only) { 126 if(ast->flags&NOMITIVE) 127 if(ToBool(ast->flags&PLURAL)^^plural) 128 return FALSE; 129 } else if(ToBool(ast->flags&PLURAL)^^plural) 130 return FALSE; 131 } 132 return TRUE; 133 } 134 135 Bool Transitive(I64 argc,AST **argv) { 136 if(!NumberAgree(argc,argv)) 137 return FALSE; 138 I64 i=0; 139 AST *ast; 140 for(i=0;i!=argc;i++) { 141 ast=argv[i]; 142 if(ast->act_as_type==AST_VERB) 143 if(ast->flags&INTRANSITIVE) 144 return FALSE; 145 } 146 return TRUE; 147 } 148 Bool Intransitive(I64 argc,AST **argv) { 149 if(!NumberAgree(argc,argv)) 150 return FALSE; 151 I64 i=0; 152 AST *ast; 153 for(i=0;i!=argc;i++) { 154 ast=argv[i]; 155 if(ast->act_as_type==AST_VERB) 156 if(ast->flags&INTRANSITIVE) 157 return TRUE; 158 } 159 return FALSE; 160 } 161 162 163 Bool CaseAgree(I64 argc,AST **argv) { 164 I64 i=0; 165 AST *ast; 166 I64 cs=0,mask=CASE_MASK; 167 while(i<argc) { 168 ast=argv[i]; 169 if(ast->act_as_type==AST_NOUN) { 170 if(!cs) { 171 cs=ast->flags&mask; 172 } else { 173 if((ast->flags&mask)!=cs) { 174 return FALSE; 175 } 176 } 177 } 178 i++; 179 } 180 return TRUE; 181 } 182 //Momitive quam albative 183 Bool CaseQuam(I64 argc,AST **argv) { 184 I64 i=0; 185 AST *ast; 186 I64 cs=NOMITIVE,mask=CASE_MASK; 187 Bool has_nomitive=FALSE; 188 Bool has_ablative=FALSE; 189 while(i<argc) { 190 ast=argv[i]; 191 if(ast->act_as_type==AST_NOUN) { 192 if((ast->flags&mask)!=cs) { 193 return FALSE; 194 } 195 if(cs&mask==NOMITIVE) { 196 has_nomitive=TRUE; 197 cs=ABLATIVE; 198 } 199 if(cs&mask==ABLATIVE) { 200 has_ablative=TRUE; 201 cs=ABLATIVE; 202 } 203 } 204 i++; 205 } 206 return has_nomitive&&has_ablative; 207 } 208 Bool CaseX(I64 x,I64 argc,AST **argv) { 209 I64 i=0; 210 AST *ast; 211 I64 cs=x,mask=CASE_MASK; 212 while(i<argc) { 213 ast=argv[i]; 214 if(ast->act_as_type==AST_NOUN) { 215 if(!cs) { 216 cs=ast->flags&mask; 217 } else { 218 if(ast->flags&mask!=cs) { 219 return FALSE; 220 } 221 } 222 } 223 i++; 224 } 225 return TRUE; 226 } 227 Bool CaseNom(I64 argc,AST **argv) { 228 return CaseX(NOMITIVE,argc,argv); 229 } 230 Bool CaseAcc(I64 argc,AST **argv) { 231 return CaseX(ACCUSATIVE,argc,argv); 232 } 233 Bool CaseAbl(I64 argc,AST **argv) { 234 return CaseX(ABLATIVE,argc,argv); 235 } 236 Bool CaseDat(I64 argc,AST **argv) { 237 return CaseX(DATIVE,argc,argv); 238 } 239 Bool CaseGen(I64 argc,AST **argv) { 240 return CaseX(GENITIVE,argc,argv); 241 } 242 243 U0 ParseRules(U8 *text) { 244 CCmpCtrl *cc=CmpCtrlNew(text,CCF_DONT_FREE_BUF|CCF_NO_DEFINES); 245 CRule *rule; 246 I64 s,member_type; 247 Lex(cc); 248 while(cc->token) { 249 rule=CAlloc(sizeof CRule); 250 rule->weight=.5; 251 //Name 252 if(cc->token!=TK_IDENT) 253 LexExcept(cc,"Expected a rule name at "); 254 rule->name[0]='!'; 255 StrCpy(rule->name+1,cc->cur_str); 256 Lex(cc); 257 if(cc->token=='(') { 258 Lex(cc); 259 if(cc->token==TK_IDENT) { 260 rule->validate_fun=StrNew(cc->cur_str); 261 } else 262 LexExcept(cc,"Expected function name at "); 263 Lex(cc); //')' 264 if(cc->token!=')') 265 LexExcept(cc,"Expected ')' at "); 266 Lex(cc); 267 } 268 if(cc->token=='[') { 269 Lex(cc); 270 if(cc->token==TK_IDENT) { 271 rule->flags_fun=StrNew(cc->cur_str); 272 } else 273 LexExcept(cc,"Expected function name at "); 274 Lex(cc); //')' 275 if(cc->token!=']') 276 LexExcept(cc,"Expected ']' at "); 277 Lex(cc); 278 } 279 //Put in member 280 if(cc->token!=TK_IDENT) 281 LexExcept(cc,"Expected a rule class at "); 282 rule->raw_type=MemberNameToI64(cc->cur_str); 283 if(rule->raw_type==-1) 284 LexExcept(cc,"Expected valid type at "); 285 Lex(cc); 286 if(cc->token==TK_DEREFERENCE) { //-> 287 rule->main_item_idx=-1; 288 Lex(cc); 289 while(cc->token==TK_IDENT||cc->token=='!'||cc->token==TK_STR) { 290 member_type=-1; 291 if(cc->token=='!') { 292 Lex(cc); 293 if(!rule->made_from) 294 rule->main_item_idx=0; 295 else 296 rule->main_item_idx=rule->made_from->cnt; 297 if(cc->token!=TK_IDENT&&cc->token!=TK_STR) 298 LexExcept(cc,"Expected a rule name at "); 299 } 300 rule->made_from=I64SetAdd(rule->made_from,StrNew(cc->cur_str),TRUE); 301 Lex(cc); 302 if(cc->token=='(') { 303 if(Lex(cc)!=TK_IDENT) 304 LexExcept(cc,"Expected a valid member type at "); 305 member_type=MemberNameToI64(cc->cur_str);; 306 if(member_type==-1) 307 LexExcept(cc,"Expected a valid member type at "); 308 if(Lex(cc)!=')') 309 LexExcept(cc,"Expected a ')' at "); 310 Lex(cc); 311 } 312 rule->member_types=I64SetAdd(rule->member_types,member_type,TRUE); 313 } 314 if(cc->token!=';') 315 LexExcept(cc,"Expected a ',' or a ';' at "); 316 } else if(cc->token=='=') { 317 rule->is_word=TRUE; 318 Lex(cc); 319 while(cc->token==TK_IDENT) { 320 rule->word_flags|=ExePrint("%s;",Define(cc->cur_str)); 321 if(Lex(cc)==',') 322 Lex(cc); 323 else 324 break; 325 } 326 if(cc->token!=';') 327 LexExcept(cc,"Expected a ',' or a ';' at "); 328 } 329 Lex(cc); 330 if(cc->token=='(') { 331 Lex(cc); 332 if(cc->token==TK_F64) { 333 rule->weight=cc->cur_f64; 334 } else 335 LexExcept(cc,"Expected a rule weight at "); 336 Lex(cc); 337 if(cc->token!=')') 338 LexExcept(cc,"Expected a ')' at "); 339 Lex(cc); 340 } 341 FramePtrAdd(rule->name,rule); 342 } 343 CmpCtrlDel(cc); 344 } 345 U0 AddThingToAST(AST *have,AST *to,I64 where=-1) { 346 if(where==-1) 347 where=have->raw_type; 348 to->prob*=have->prob; 349 to->args=I64SetAdd(to->args,have); 350 switch(where) { 351 case AST_NOUN: 352 if(have->flags&CASE_MASK==0) { 353 //??? 354 to->nomitive=ASTSetAdd(to->nomitive,have); 355 } else if(have->flags&NOMITIVE){ 356 to->flags|=NOMITIVE; 357 to->nomitive=ASTSetAdd(to->nomitive,have); 358 } else if(have->flags&ACCUSATIVE){ 359 to->flags|=ACCUSATIVE; 360 to->accusative=ASTSetAdd(to->accusative,have); 361 } else if(have->flags&DATIVE){ 362 to->flags|=DATIVE; 363 to->dative=ASTSetAdd(to->dative,have); 364 } else if(have->flags&ABLATIVE){ 365 to->flags|=ABLATIVE; 366 to->ablative=ASTSetAdd(to->ablative,have); 367 } else if(have->flags&GENITIVE){ 368 to->flags|=GENITIVE; 369 to->genitive=ASTSetAdd(to->genitive,have); 370 } 371 break; 372 case AST_CONJUNCTION: 373 to->flags|=PLURAL|have->flags; 374 to->conjunction=ASTSetAdd(to->conjunction,have); 375 break; 376 case AST_OF: 377 to->genitive=ASTSetAdd(to->genitive,have); 378 break; 379 case AST_WHERE: 380 to->flags|=PREPOSITION; 381 to->preposition=ASTSetAdd(to->preposition,have); 382 break; 383 case AST_ADJECTIVE: 384 to->flags|=ADJECTIVE; 385 to->adjective=ASTSetAdd(to->adjective,have); 386 break; 387 case AST_INFINITIVE: 388 to->flags|=INFINITIVE; 389 to->nomitive=ASTSetAdd(to->nomitive,have); 390 break; 391 case AST_MEASURE: 392 to->measurement=ASTSetAdd(to->measurement,have); 393 break; 394 case AST_ADVERB: 395 to->flags|=ADVERB; 396 to->adverb=ASTSetAdd(to->adverb,have); 397 break; 398 case AST_INDIRECT_CLAUSE: 399 to->nomitive=ASTSetAdd(to->nomitive,have); 400 break; 401 case AST_COMPARSION: 402 to->measurement=ASTSetAdd(to->measurement,have); 403 break; 404 case AST_QUESTION: 405 to->question=ASTSetAdd(to->question,have); 406 break; 407 default: 408 } 409 } 410 extern U0 Chain(CRule *chain,I64 idx,ASTSet *add_to,CGrammarState *st,I64 start_woff=0,I64 recursion_level=0); 411 412 Bool IsLeftRecursive(CRule *r) { 413 if(!r) return FALSE; 414 if(r->made_from) 415 //r->name starts with a "!" 416 return !StrCmp(r->name+1,r->made_from->body[0]); 417 return FALSE; 418 } 419 420 U0 RunRule(CGrammarState *st) { 421 if(st->cnt<=0) return; 422 U8 dummy[STR_LEN]; 423 StrPrint(dummy,"!%s",st->rule); 424 FramePtrAdd(RESULTS_FP,NULL); 425 I64 inst=1,idx,depth,en2,try2; 426 I64 left_recursive=0; 427 I64 attempt=0,find_cnt; 428 CHashGeneric *h; 429 CRule *r; 430 AST *ret; 431 CTrie **flat; 432 ASTSet *results=NULL,*dummy_set; 433 CGenerator *g; 434 CGrammarState orig,clone; 435 CTrie *word; 436 MemCpy(&orig,st,sizeof CGrammarState); 437 again: 438 for(inst=1;h=HashFind(dummy,grammar_task->hash_table,HTT_FRAME_PTR,inst);inst++) { 439 MemCpy(st,&orig,sizeof CGrammarState); 440 MemCpy(&clone,st,sizeof CGrammarState); 441 r=h->user_data0; 442 left_recursive|=IsLeftRecursive(r); 443 //TODO allow other forms of the word 444 if(GetWord(r->name)&&IsFormOf(r->name,st->words[0])) { 445 word=GetWord(st->words[0]); 446 while(word) { 447 ret=CAlloc(sizeof(AST),mem_task); 448 ret->prob=1.; 449 ret->word_idx=st->woff; 450 if(r->raw_type) { 451 ret->act_as_type=ret->raw_type=r->raw_type; 452 } else if(word->flags&NOUN) { 453 ret->act_as_type=ret->raw_type=AST_NOUN; 454 } else if(word->flags&VERB) { 455 ret->act_as_type=ret->raw_type=AST_VERB; 456 } else if(word->flags&CONJUNCTION) { 457 ret->act_as_type=ret->raw_type=AST_CONJUNCTION; 458 } else if(word->flags&ADJECTIVE) { 459 ret->act_as_type=ret->raw_type=AST_ADJECTIVE; 460 } else if(word->flags&INFINITIVE) { 461 ret->act_as_type=ret->raw_type=AST_INFINITIVE; 462 } else if(word->flags&ADVERB) { 463 ret->act_as_type=ret->raw_type=AST_ADVERB; 464 } 465 466 ret->word=word; 467 ret->flags=word->flags; 468 ret->end=1; 469 ret->prob=r->weight; 470 ret->args=I64SetAdd(ret->args,ret); 471 FramePtrSet(RESULTS_FP,ASTSetAdd(FramePtr(RESULTS_FP),ASTClone(ret))); 472 GeneratorYield(ret); 473 word=word->next; 474 } 475 } 476 if(r->is_word) { 477 word=GetWord(st->words[0]); 478 while(word&&!attempt) { 479 if(st->en) *st->en=1; 480 if(word->flags&r->word_flags==r->word_flags) { 481 ret=CAlloc(sizeof(AST),mem_task); 482 ret->prob=1.; 483 ret->word_idx=st->woff; 484 ret->act_as_type=ret->raw_type=r->raw_type; 485 ret->word=word; 486 ret->flags=word->flags; 487 ret->end=1; 488 ret->prob=r->weight; 489 ret->args=I64SetAdd(ret->args,ret); 490 FramePtrSet(RESULTS_FP,ASTSetAdd(FramePtr(RESULTS_FP),ASTClone(ret))); 491 GeneratorYield(ret); 492 } 493 word=word->next; 494 } 495 } else { 496 if(r->made_from) { 497 if(attempt) { 498 if(results&&IsLeftRecursive(r)) { 499 for(idx=0;idx!=results->cnt;idx++) { 500 ret=results->body[idx]; 501 dummy_set=ASTSetAdd(NULL,ASTClone(ret)); 502 MemCpy(&clone,st,sizeof CGrammarState); 503 clone.is_conj2=TRUE; 504 clone.woff+=ret->end; 505 clone.cnt-=ret->end; 506 clone.words+=ret->end; 507 Chain(r,1,dummy_set,&clone,st->woff,attempt); 508 ASTSetDel(dummy_set); 509 } 510 } 511 } else if(!IsLeftRecursive(r)) { 512 MemCpy(&clone,st,sizeof CGrammarState); 513 Chain(r,0,NULL,&clone,st->woff,attempt); 514 } 515 } 516 } 517 skip:; 518 } 519 //Do "sub-parts" outside of the nain loop;WE ONLY NEED TO COMPUTE ONCE 520 if(!attempt) 521 if(!StrCmp(st->words[0],"[")) { 522 depth=0; 523 for(idx=0;idx<st->cnt;idx++) { 524 if(!StrCmp(st->words[idx],"[")) 525 depth++; 526 else if(!StrCmp(st->words[idx],"]")) 527 depth--; 528 if(!depth) break; 529 } 530 if(!depth) { 531 MemCpy(&clone,st,sizeof CGrammarState); 532 clone.woff++; 533 clone.words++; 534 clone.cnt=idx-1; 535 clone.en=&en2; 536 g=GeneratorNewC(&RunRule,&clone); 537 while(GeneratorGet(g,&ret)) { 538 if(en2==idx-1) { 539 if(st->en) *st->en=idx+1; 540 ret->end=idx+1; 541 FramePtrSet(RESULTS_FP,ASTSetAdd(FramePtr(RESULTS_FP),ASTClone(ret))); 542 GeneratorYield(ret); 543 } else 544 ASTDel(ret); 545 } 546 } 547 } 548 if(!left_recursive) 549 goto fin; 550 results=FramePtr(RESULTS_FP); 551 FramePtrSet(RESULTS_FP,NULL); 552 if(attempt++) { 553 fin: 554 if(FramePtr(RESULTS_FP)) 555 ASTSetDel(FramePtr(RESULTS_FP)); 556 FramePtrDel(RESULTS_FP); 557 return; 558 } 559 goto again; 560 } 561 562 U0 Chain(CRule *rule,I64 idx,ASTSet *add_to,CGrammarState *st,I64 start_woff=0,I64) { 563 CGrammarState orig,clone,clone2; 564 AST *grab,*tmp,*main=NULL,*conj2; 565 CGenerator *g; 566 I64Set *chain=rule->made_from; 567 I64 width,dummy,main_idx,depth,idx2,cnt; 568 CTrie **flat; 569 //Avoid infinitie left recursion 570 CHashGeneric *h; 571 U8 buf[STR_LEN]; 572 StrPrint(buf,"PrntRule:%d,%x",st->woff,rule); 573 if(!idx) { 574 dummy=1; 575 if(FramePtr(buf)) { 576 return; 577 } 578 FramePtrAdd(buf,1); 579 } 580 if(!st->en) st->en=&dummy; 581 if(idx>chain->cnt) 582 return; 583 if(idx==chain->cnt) { 584 if(!add_to) return; 585 if(st->en) *st->en=st->woff-start_woff; 586 for(idx=0;idx!=add_to->cnt;idx++) { 587 if(idx==rule->main_item_idx) { 588 main=add_to->body[idx]; 589 main_idx=idx; 590 break; 591 } 592 } 593 594 if(!main) { 595 main=add_to->body[0]; 596 main_idx=0; 597 } 598 599 main=ASTClone(main); 600 main->end=st->woff-start_woff; 601 main->raw_type=main->act_as_type=rule->raw_type; 602 for(idx=0;idx!=add_to->cnt;idx++) { 603 if(main_idx!=idx) 604 AddThingToAST(ASTClone(add_to->body[idx]),main,rule->member_types->body[idx]); 605 } 606 main->prob*=rule->weight; 607 if(rule->flags_fun&&main->args) 608 main->flags|=CallExtStr(rule->flags_fun,main->args->cnt,main->args->body); 609 if(rule->validate_fun&&main->args) { 610 if(CallExtStr(rule->validate_fun,main->args->cnt,main->args->body)) { 611 FramePtrSet(RESULTS_FP,ASTSetAdd(FramePtr(RESULTS_FP),ASTClone(main))); 612 GeneratorYield(main); 613 } 614 } else { 615 FramePtrSet(RESULTS_FP,ASTSetAdd(FramePtr(RESULTS_FP),ASTClone(main))); 616 GeneratorYield(main); 617 } 618 return; 619 } 620 MemCpy(&orig,st,sizeof CGrammarState); 621 MemCpy(&clone,st,sizeof CGrammarState); 622 clone.en=&width; 623 clone.rule=chain->body[idx]; 624 g=GeneratorNewC(&RunRule,&clone); 625 while(GeneratorGet(g,&grab)) { 626 MemCpy(&clone2,&orig,sizeof CGrammarState); 627 clone2.woff+=width; 628 clone2.cnt-=width; 629 clone2.words+=width; 630 tmp=ASTSetClone(add_to); 631 tmp=ASTSetAdd(tmp,ASTClone(grab)); 632 Chain(rule,idx+1,tmp,&clone2,start_woff,0); 633 if(!st->is_conj2) { 634 MemCpy(&clone2,&orig,sizeof CGrammarState); 635 clone2.woff+=width; 636 clone2.cnt-=width; 637 clone2.words+=width; 638 cnt=ASTGetTrieWords(grab,NULL); 639 flat=CAlloc(8*(cnt+1)); //cnt here is the last word_idx,add 1 640 ASTGetTrieWords(grab,flat); 641 for(idx2=0;idx2<=cnt;idx2++) { 642 if(flat[idx2]) { 643 if(flat[idx2]->flags&CONJUNCTION2) { 644 main=CAlloc(sizeof(AST),mem_task); 645 main->prob=1.; 646 main->word_idx=st->woff; 647 main->act_as_type=main->raw_type=AST_CONJUNCTION; 648 main->word=flat[idx2]; 649 main->end=1; 650 main->args=I64SetAdd(main->args,main); 651 conj2=ASTSetClone(add_to); 652 conj2=ASTSetAdd(conj2,main); 653 conj2=ASTSetAdd(conj2,ASTClone(grab)); 654 Chain(rule,idx+2,tmp,&clone2,start_woff,0); 655 } 656 break; 657 } 658 } 659 Free(flat); 660 } 661 ASTDel(grab); 662 ASTSetDel(tmp); 663 } 664 if(!idx) 665 FramePtrDel(buf); 666 } 667 U8 *rules=FileRead("Latin.GMR"); 668 ParseRules(rules); 669 Free(rules);