Back to index

wims  3.65+svn20090927
compile.c
Go to the documentation of this file.
00001 /*    Copyright (C) 2002-2003 XIAO, Gang of Universite de Nice - Sophia Antipolis
00002  *
00003  *  This program is free software; you can redistribute it and/or modify
00004  *  it under the terms of the GNU General Public License as published by
00005  *  the Free Software Foundation; either version 2 of the License, or
00006  *  (at your option) any later version.
00007  *
00008  *  This program is distributed in the hope that it will be useful,
00009  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00010  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00011  *  GNU General Public License for more details.
00012  *
00013  *  You should have received a copy of the GNU General Public License
00014  *  along with this program; if not, write to the Free Software
00015  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00016  */
00017 
00018 char cpbuf[MAX_LINELEN+1];
00019 char *cpnext;
00020 int noaddw=0;
00021 
00022 char Mbuf[MAX_LINELEN+1];
00023 char *Mnext;
00024 struct {
00025     char *Mptr;
00026     int blkptr;
00027 } Mind[MAX_BLOCKS];
00028 int Mcnt;
00029 
00030 struct liststruct {
00031     listtype lcnt;
00032     listtype *listlen;
00033     listtype *list;
00034 } clist;
00035 
00036 void cp_oneblock(char *p, struct block *blk, int next);
00037 
00038        /* debugger: show the detail of blocks */
00039 void showblocks(void)
00040 {
00041     int i, j, k;
00042     struct block *blk;
00043     if(!debug) return;
00044     for(i=0;i<nextblock;i++) {
00045        blk=blockbuf+i;
00046        fprintf(stderr,"Block %2d: next=%2d.      ",i,blk->nextblock);
00047        if(blk->fn==mt_string) {
00048            fprintf(stderr,"String %s.\n",blk->string);
00049            continue;
00050        }
00051        if(blk->fn==mt_permpick) {
00052            fprintf(stderr,"Permpick %d items %d lists starting %d\n",
00053                  blk->len, blk->lcnt, blk->sublock);
00054            for(j=0;j<blk->lcnt;j++) {
00055               fprintf(stderr,"     list %d: ", j);
00056               for(k=0;k<blk->listlen[j];k++)
00057                 fprintf(stderr,"%d ",blk->lists[j][k]);
00058               fprintf(stderr,"\n");
00059            }
00060            continue;
00061        }
00062        if(blk->fn==mt_m) {
00063            fprintf(stderr,"Macro starting %d ending %d\n", blk->sublock,
00064                   blockbuf[blk->sublock].mend);
00065            continue;
00066        }
00067        if(blk->fn==mt_neg) {
00068            fprintf(stderr,"Neg starting %d\n", blk->sublock);
00069            continue;
00070        }
00071        if(blk->fn==mt_dic) {
00072            fprintf(stderr,"Dic %s.\n", blk->string);
00073            continue;
00074        }
00075        if(blk->fn==mt_w) {
00076            fprintf(stderr,"Word list.\n");
00077            continue;
00078        }
00079        if(blk->fn==mt_wild) {
00080            fprintf(stderr,"Wild min=%d, max=%d.\n", blk->lstart, blk->len+blk->lstart);
00081            continue;
00082        }
00083        if(blk->fn==mt_out) {
00084            fprintf(stderr,"Output for \"%s\", sub=%d.\n", blk->string,blk->sublock);
00085            continue;
00086        }
00087        fprintf(stderr,"Unknown type!\n");
00088     }
00089     
00090 }
00091 
00092        /* remove punctuations */
00093 void depunct(char *p,char *str)
00094 {
00095     char *pp;
00096     for(pp=p; *pp; pp++) {
00097        if(strchr(str,*pp)==NULL) continue;
00098        if(*pp=='.' && pp>p && isdigit(pp[-1]) && isdigit(pp[1])) continue;
00099        *pp=' ';
00100     }
00101 }
00102 
00103        /* p must have MAX_LINELEN */
00104 void isolate_punct(char *p)
00105 {
00106     char buf[MAX_LINELEN+1];
00107     char *p1, *p2;
00108     for(p1=p, p2=buf; *p1 && p2<buf+MAX_LINELEN; p1++) {
00109        if(myisalnum(*p1) || (*p1&128) || *p1==' ' || *p1=='_') {
00110            *p2++=*p1; continue;
00111        }
00112        if((*p1=='.' || *p1==',') && p1>p && isdigit(p1[-1]) && isdigit(p1[1])) {
00113            *p2++=*p1; continue;
00114        }
00115        if(p2>buf && !myisspace(p2[-1])) *p2++=' ';
00116        *p2++=*p1;
00117        if(p1[1] && !myisspace(p1[1])) *p2++=' ';
00118     }
00119     if(p2>=buf+MAX_LINELEN) error("string_too_long");
00120     *p2=0;
00121     snprintf(p,MAX_LINELEN,"%s",buf);
00122 }
00123 
00124 void alphaonly(char *p)
00125 {
00126     char *pp;
00127     for(pp=p; *pp; pp++) if(!myisalpha(*pp)) *pp=' ';
00128 }
00129 
00130 void alnumonly(char *p)
00131 {
00132     char *pp;
00133     for(pp=p; *pp; pp++) if(!myisalnum(*pp)) *pp=' ';
00134 }
00135 
00136        /* buffer must have MAX_LINELEN */
00137 void strfold(char *p)
00138 {
00139     char *pp;
00140     singlespace(p);
00141     if(noaddw&2) goto fend;
00142     if(options&op_nocase) for(pp=p; *pp; pp++) *pp=tolower(*pp);
00143     if(options&op_reaccent) reaccent(p);
00144     if(options&op_deaccent) deaccent(p);
00145     if(options&op_alphaonly) alphaonly(p);
00146     if(options&op_alnumonly) alnumonly(p);
00147     isolate_punct(p);
00148     if(options&op_nopunct) depunct(p,char_punct);
00149     if(options&op_nomath) depunct(p,char_math);
00150     if(options&op_noparenth) depunct(p,char_parenth);
00151     if(options&op_nocs) depunct(p,char_cs);
00152     if(options&op_noquote) depunct(p,char_quote);
00153     if(suffixcnt>0) suffix_translate(p);
00154     _translate(p,transdic);
00155     
00156 fend:
00157     singlespace(p);strip_trailing_spaces(p);
00158     if(myisspace(*p)) strcpy(p,find_word_start(p));
00159 }
00160 
00161        /* at entry p must point to an atom start! */
00162 char *find_atom_end(char *p)
00163 {
00164     char *pp;
00165     if(*p=='[') {
00166        pp=find_matching(p+1,']');
00167        if(pp!=NULL) return pp+1;
00168        else error("unmatched_parentheses %.20s",p);
00169     }
00170     return find_word_end(p);
00171 }
00172 
00173 #define find_atom_start(x) find_word_start(x)
00174 #define next_atom(x) find_atom_start(find_atom_end(x))
00175 
00176        /* p must have MAX_LINELEN */
00177 void macro_trans(char *p)
00178 {
00179     char *atoms[MAX_BLOCKS], *atom2[MAX_BLOCKS];
00180     char tbuf[MAX_LINELEN+1], ttbuf[MAX_LINELEN+1], vbuf[8];
00181     char *pt, *pp, *pe, *p1, *p2, *p3;
00182     char *pt1, *pt2;
00183     int i,k,m,n,repcnt,start,min;
00184     
00185     if(dic[macrodic].len<=0) return;
00186     repcnt=start=0; pt=p;
00187     recalc:
00188     repcnt++;
00189     if(repcnt>=MAX_BLOCKS) error("macro_level_overflow %.20s",p);
00190     for(i=start, pp=find_atom_start(pt); i<MAX_BLOCKS && *pp; pp=next_atom(pp), i++)
00191       atoms[i]=pp;
00192     if(i>=MAX_BLOCKS-1) error("block_overflow %.20s",p);
00193     atoms[i]=pp+strlen(pp);
00194     for(k=0;k<i;k++) {
00195        pp=atoms[k]; switch(*pp) {
00196            case '[': {
00197               pe=find_atom_end(pp); pp++;
00198               if(pe[-1]!=']') break;
00199               if(myislower(*pp)) {
00200                   for(p1=pp;myisalnum(*p1) || *p1=='_'; p1++);
00201                   if(*p1!=':') break;
00202                   *p1++=0; pe[-1]=0;
00203                   for(m=0,p2=p1;*p2;m++,p2=p3) {
00204                      p3=find_item_end(p2); if(*p3) *p3++=0;
00205                      atom2[m]=p2;
00206                   }
00207                   if(m==0) m=1;
00208                   snprintf(tbuf,sizeof(tbuf),"%s",pp);
00209                   _translate(tbuf,macrodic);
00210                   if(tbuf[0]==0) error("bad_macro %.50s",pp);
00211                   for(p1=strchr(tbuf,'@'); p1; p1=strchr(p1,'@')) {
00212                      for(p2=p1+1;isdigit(*p2) || *p2=='-';p2++);
00213                      if(p2==p1+1 || p2>p1+6) error("syntax_error %.20s",p1);
00214                      memmove(vbuf,p1,p2-p1); vbuf[p2-p1]=0;
00215                      n=atoi(vbuf+1);
00216                      if(n<=0 || n>m) error("wrong_parmcnt macro %.50s",pp);
00217                      string_modify(tbuf,p1,p2,atom2[n-1]);
00218                   }
00219                   n=strlen(tbuf); if(n<MAX_LINELEN) {
00220                      tbuf[n++]=' '; tbuf[n]=0;
00221                   }
00222                   string_modify(p,pp-1,pe,tbuf); pt=pp-1; start=k;
00223                   goto recalc;
00224               }
00225               break;
00226            }
00227            case '_': {
00228               pe=find_word_end(pp);
00229               if(pe-pp>MAX_NAMELEN) error("name_too_long %.20s",pp);
00230               memmove(tbuf,pp,pe-pp); tbuf[pe-pp]=0;
00231               _translate(tbuf,macrodic);
00232               if(tbuf[0]==0) break;
00233               pt1=pp; pt2=find_atom_end(pt1); min=k;
00234               for(p1=strchr(tbuf,'@'); p1; p1=strchr(p1,'@')) {
00235                   for(p2=p1+1;isdigit(*p2) || *p2=='-';p2++);
00236                   if(p2==p1+1 || p2>p1+6) error("syntax_error %.20s",p1);
00237                   memmove(vbuf,p1,p2-p1); vbuf[p2-p1]=0;
00238                   n=atoi(vbuf+1);
00239                   if(n<-4 || n==0 || n>4) error("bad_macro %.20s",atoms[k]);
00240                   n+=k;
00241                   if(n<0 || n>=i) error("bad_macro_position %.20s",atoms[k]);
00242                   p3=find_atom_end(atoms[n]);
00243                   if(p3>pt2) pt2=p3;
00244                   if(atoms[n]<pt1) {min=n;pt1=atoms[n];}
00245                   memmove(ttbuf,atoms[n],p3-atoms[n]); ttbuf[p3-atoms[n]]=' ';
00246                   ttbuf[p3-atoms[n]+1]=0;
00247                   string_modify(tbuf,p1,p2,ttbuf);
00248               }
00249               string_modify(p,pt1,pt2,tbuf); pt=pt1; start=min;
00250               goto recalc;
00251            }
00252            default: break;
00253        }
00254     }
00255 }
00256 
00257 char *add2cp(char *p)
00258 {
00259     char *pp, *p1, *p2, buf[MAX_LINELEN+1];
00260     int l;
00261     snprintf(buf,sizeof(buf),"%s",p); strfold(buf); l=strlen(buf);
00262     if((cpnext-cpbuf)+l>=MAX_LINELEN) error("string_too_long");
00263     pp=cpnext; memmove(pp,buf,l+1); cpnext+=l+1;
00264     if(!noaddw) for(p1=find_word_start(buf); *p1; p1=find_word_start(p2)) {
00265        p2=find_word_end(p1); l=p2-p1;
00266        if(*p2) *p2++=0;
00267        if(wordchr(wbuf,p1)!=NULL) continue;
00268        if(wptr-wbuf>=sizeof(wbuf)-l-2) continue;
00269        if(wptr>wbuf) *wptr++=' ';
00270        memmove(wptr,p1,l); wptr+=l; *wptr=0;
00271     }
00272     return pp;
00273 }
00274 
00275 void cp_string(char *p, struct block *blk, int next)
00276 {
00277     blk->fn=mt_string;
00278     blk->string=add2cp(p);
00279     blk->len=strlen(blk->string);
00280     blk->nextblock=next;
00281     if(blk==blockbuf+nextblock) nextblock++;
00282 }
00283 
00284        /* p must have MAX_LINELEN */
00285 void cp_cutline(char *p, struct block *blk, int next)
00286 {
00287     char *p1, *p2, *p3;
00288     char buf[MAX_LINELEN+1];
00289     int l, ll, n, idx, start, end;
00290     struct block *b;
00291 
00292     if(debug>=3) fprintf(stderr,"Cutline %d/%d for %.15s.\n",
00293                       blk-blockbuf, nextblock, p);
00294     for(p1=strstr(p,"[|]"); p1; p1=strstr(p1,"[|]")) memmove(p1," | ",3);
00295     macro_trans(p);
00296     singlespace(p);
00297     p=find_word_start(p); strip_trailing_spaces(p);
00298     l=0; p3=p; do {
00299        p1=find_word_start(p3);
00300        if(*p1) l++;
00301        p2=strparchr(p1,'[');
00302        if(p2!=NULL) p3=find_matching(p2+1,']');
00303        if(p3==NULL) error("unmatched_parentheses %.20s",p);
00304        if(p2!=NULL && p2>p1) l++;
00305        p3++;
00306     } while(p2!=NULL);
00307     if(l==0) {
00308        buf[0]=0; cp_string(buf,blk,next);
00309        return;
00310     }
00311     idx=start=nextblock; nextblock+=l-1; end=nextblock;
00312     if(nextblock > MAX_BLOCKS) error("block_overflow %.20s",p);
00313     for(p1=find_word_start(p); *p1; p1=find_word_start(p3)) {
00314        p2=strparchr(p1,'[');
00315        if(p2==NULL) p2=p1+strlen(p1);
00316        ll=p2-p1;
00317        if(ll>0) {
00318            memmove(buf,p1,ll); buf[ll]=0;
00319            if(idx==start) b=blk; else b=blockbuf+idx-1;
00320            if(idx<end) n=idx; else n=next;
00321            if(debug>=3) fprintf(stderr,"String block %d/%d for %.15s.\n",
00322                       b-blockbuf, nextblock, buf);
00323            cp_string(buf,b,n);
00324            idx++;
00325        }
00326        if(*p2=='[') {
00327            p2++; p3=find_matching(p2,']');
00328            memmove(buf,p2,p3-p2); buf[p3-p2]=0; p3++;
00329            if(idx==start) b=blk; else b=blockbuf+idx-1;
00330            if(idx<end) n=idx; else n=next;
00331            cp_oneblock(buf,b,n);
00332            idx++;
00333        }
00334        else p3=p2;
00335     }
00336 }
00337 
00338 unsigned int objnum(char *p, char delim)
00339 {
00340     int i; char *p1, *p2;
00341 
00342     if(*p==0) return 1;
00343     i=0;
00344     for(p1=p; p1; p1=p2, i++) {
00345        p2=strparchr(p1,delim); if(p2) p2++;
00346     }
00347     return i;
00348 }
00349 
00350 void _permpick(char *p, int n, struct block *blk, int next, char delim)
00351 {
00352     int i, t, idx;
00353     char buf[MAX_LINELEN+1];
00354     char *pp, *pe;
00355     
00356     idx=nextblock; nextblock+=n;
00357     if(nextblock > MAX_BLOCKS) error("block_overflow %.20s",p);
00358     blk->len=n;
00359     blk->sublock=idx;
00360     blk->fn=mt_permpick;
00361     blk->lcnt=clist.lcnt;
00362     blk->nextblock=next;
00363     if(nextlist+n > MAX_LISTS) error("list_overflow %.20s",p);
00364     blk->listlen=listbuf+nextlist; nextlist+=n;
00365     for(i=t=0; i<clist.lcnt; i++) {
00366        blk->listlen[i]=clist.listlen[i];
00367        blk->lists[i]=listbuf+nextlist+t;
00368        t+=clist.listlen[i];
00369     }
00370     if(nextlist+t > MAX_LISTS) error("list_overflow %.20s",p);
00371     memmove(listbuf+nextlist,clist.list,t*sizeof(listtype));
00372     nextlist+=t;
00373     for(i=0, pp=find_word_start(p);i<n;i++,idx++,pp=find_word_start(pe)) {
00374        pe=strparchr(pp,delim);
00375        if(pe==NULL) pe=pp+strlen(pp); else *pe++=0;
00376        snprintf(buf,sizeof(buf),"%s",pp);
00377        cp_cutline(buf,blockbuf+idx,next);
00378     }
00379 }
00380 
00381        /* alt for two flavours */
00382 void _alt(char *p, struct block *blk, int next, char delim)
00383 {
00384     int n;
00385     listtype ltab[]={-1};
00386     listtype len[]={1};
00387     
00388     clist.lcnt=1; clist.listlen=len; clist.list=ltab;
00389     n=objnum(p,delim); if(n==0) n=1;
00390     _permpick(p,n,blk,next,delim);
00391 }
00392 
00393 void cp_alt(char *p, struct block *blk, int next)
00394 {
00395     _alt(p,blk,next,',');
00396 }
00397 
00398 void cp_alt2(char *p, struct block *blk, int next)
00399 {
00400     _alt(p,blk,next,'|');
00401 }
00402 
00403 void cp_aperm(char *p, struct block *blk, int next)
00404 {
00405     int i, n;
00406     listtype ltab[MAX_BLOCKS];
00407     listtype len;
00408 
00409     n=objnum(p,','); if(n<4) error("wrong_parmcnt ins %.20s",p);
00410     if(n>=MAX_BLOCKS/2) error("block_overflow %.20s",p);
00411     clist.lcnt=1; len=2*n-5; clist.listlen=&len;
00412     for(i=0;i<n-2;i++) ltab[2*i]=-2;
00413     for(i=0;i<n-4;i++) ltab[2*i+1]=0;
00414     ltab[len-2]=1;
00415     clist.list=ltab;
00416     _permpick(p,n,blk,blk-blockbuf,',');
00417     blk->lstart=2;
00418 }
00419 
00420 void cp_apick(char *p, struct block *blk, int next)
00421 {
00422     int i, n, t;
00423     char *p1;
00424     listtype ltab[MAX_BLOCKS];
00425     listtype len;
00426 
00427     n=objnum(p,','); if(n<4) error("wrong_parmcnt ins %.20s",p);
00428     if(n>=MAX_BLOCKS/2) error("block_overflow %.20s",p);
00429     p1=find_item_end(p); if(*p1) *p1++=0;
00430     t=atoi(p); if(t<=0 || t>n-3) error("syntax_error ins %.20s",p);
00431     clist.lcnt=1; len=2*t-1; clist.listlen=&len;
00432     for(i=0;i<t;i++) ltab[2*i]=-2;
00433     for(i=0;i<t-1;i++) ltab[2*i+1]=0;
00434     ltab[len-2]=1;
00435     clist.list=ltab;
00436     _permpick(p1,n,blk,blk-blockbuf,',');
00437     blk->lstart=2;
00438 }
00439 
00440 void cp_dic(char *p, struct block *blk, int next)
00441 {
00442     int i, n;
00443     char *p1, *p2;
00444     n=objnum(p,',');
00445     if(n!=1) error("wrong_parmcnt dic %.20s",p);
00446     p1=find_word_start(p); p2=find_word_end(p1);
00447     if(*p2) *p2++=0;
00448     p2=find_word_start(p2);
00449     i=getdic(p1);
00450     if(i<0) error("bad_dictionary %.20s",p1);
00451     noaddw=3;
00452     blk->string=add2cp(p2);
00453     noaddw=0;
00454     blk->len=strlen(blk->string);
00455     blk->lind1=i;
00456     blk->fn=mt_dic;
00457     blk->nextblock=next;
00458 }
00459 
00460 void cp_dperm(char *p, struct block *blk, int next)
00461 {
00462     int n;
00463     listtype ltab[]={0,1,2,2,3,0};
00464     listtype len[]={3,3};
00465     
00466     clist.lcnt=2; clist.listlen=len; clist.list=ltab;
00467     n=objnum(p,',');
00468     if(n!=4) error("wrong_parmcnt dperm %.20s",p);
00469     _permpick(p,n,blk,blk-blockbuf,',');
00470 }
00471 
00472 void cp_ins(char *p, struct block *blk, int next)
00473 {
00474     int i, n;
00475     listtype ltab[MAX_BLOCKS];
00476     listtype len;
00477 
00478     n=objnum(p,','); if(n<3) error("wrong_parmcnt ins %.20s",p);
00479     if(n>=MAX_BLOCKS/2) error("block_overflow %.20s",p);
00480     clist.lcnt=1; len=2*n-2; clist.listlen=&len;
00481     for(i=1;i<n;i++) ltab[2*i-2]=i;
00482     for(i=1;i<len;i+=2) ltab[i]=-12;
00483     ltab[len-1]=-13;
00484     clist.list=ltab;
00485     _permpick(p,n,blk,blk-blockbuf,',');
00486     blk->lstart=1;
00487 }
00488 
00489 void cp_iperm(char *p, struct block *blk, int next)
00490 {
00491     int n;
00492     listtype ltab[]={0,1,2,2,1,0};
00493     listtype len[]={3,3};
00494 
00495     clist.lcnt=2; clist.listlen=len; clist.list=ltab;
00496     n=objnum(p,',');
00497     if(n!=3) error("wrong_parmcnt iperm %.20s",p);
00498     _permpick(p,n,blk,blk-blockbuf,',');
00499 }
00500 
00501 void cp_m(char *p, struct block *blk, int next)
00502 {
00503     int i, idx;
00504     char buf[MAX_LINELEN+1];
00505     
00506     i=objnum(p,','); if(i!=1) error("wrong_parmcnt m %.20s",p);
00507     blk->fn=mt_m;
00508     blk->string=NULL;
00509     blk->len=1;
00510     blk->nextblock=next;
00511     p=find_word_start(p);singlespace(p);strip_trailing_spaces(p);
00512     for(i=0;i<Mcnt && strcmp(p,Mind[i].Mptr)!=0;i++);
00513     if(nextblock >= MAX_BLOCKS-2) error("block_overflow %.20s",p);
00514     if(i<Mcnt) blk->sublock=Mind[i].blkptr;
00515     else {
00516        i=strlen(p);
00517        if(Mnext-Mbuf+i >= MAX_LINELEN-1) error("Mbuf_overflow %.20s",p);
00518        if(Mcnt >= MAX_BLOCKS) error("Mind_overflow %.20s",p);
00519        Mind[Mcnt].Mptr=Mnext; Mind[Mcnt].blkptr=nextblock;
00520        Mcnt++;
00521        memcpy(Mnext,p,i+1); Mnext+=i+1;
00522        idx=nextblock; blk->sublock=idx; nextblock++;
00523        snprintf(buf,sizeof(buf),"%s",p);
00524        cp_cutline(buf,blockbuf+idx,-2);
00525        blockbuf[idx].mend=nextblock;
00526     }
00527 }
00528 
00529 void cp_neg(char *p, struct block *blk, int next)
00530 {
00531     int n, idx;
00532     char buf[MAX_LINELEN+1];
00533     n=objnum(p,','); if(n==0) n=1;
00534     if(n>1) error("wrong_parmcnt neg %.20s",p);
00535     blk->fn=mt_neg;
00536     blk->len=1;
00537     blk->nextblock=next;
00538     if(nextblock >= MAX_BLOCKS) error("block_overflow %.20s",p);
00539     idx=nextblock; blk->sublock=idx; nextblock++;
00540     snprintf(buf,sizeof(buf),"%s",p);
00541     cp_cutline(buf,blockbuf+idx,blk-blockbuf);
00542 }
00543 
00544 void cp_none(char *p, struct block *blk, int next)
00545 {
00546     blk->fn=mt_nomatch;
00547     blk->string="";
00548     blk->nextblock=next;
00549 }
00550 
00551 void _pick(char *p, struct block *blk, int next, int type)
00552 {
00553     int i, n, t, v;
00554     listtype ltab[MAX_BLOCKS];
00555     listtype len;
00556     char *p1;
00557 
00558     n=objnum(p,','); n--;
00559     if(n<2) error("wrong_parmcnt pick %.20s",p);
00560     if(n>=MAX_BLOCKS) error("block_overflow %.20s",p);
00561     p1=strparchr(p,','); *p1++=0;
00562     p=find_word_start(p); v=0;
00563     if(*p=='-') {p++; type-=5;}
00564     else if(*p=='+') {v=2; p++;}
00565     t=atoi(p); if(t<1 || t>MAX_PICKS || t>n) error("bad_pickcnt %.20s",p);
00566     clist.lcnt=1; len=t+v; clist.listlen=&len;
00567     for(i=0;i<t;i++) ltab[i]=type;
00568     if(v) {ltab[i++]=-6; ltab[i]=-5;}
00569     clist.list=ltab;
00570     _permpick(p1,n,blk,blk-blockbuf,',');
00571 }
00572 
00573 void cp_out(char *p, struct block *blk, int next)
00574 {
00575     char buf[MAX_LINELEN+1];
00576     char *p1;
00577     int n, idx;
00578     n=objnum(p,','); if(n!=2) error("wrong_parmcnt out %.20s",p);
00579     p1=strparchr(p,','); if(p1) *p1++=0; else p1=p+strlen(p);
00580     p=find_word_start(p); *find_word_end(p)=0;
00581     noaddw=3;
00582     blk->string=add2cp(p);
00583     noaddw=0;
00584     blk->len=strlen(blk->string);
00585     blk->fn=mt_out;
00586     blk->nextblock=next;
00587     if(nextblock >= MAX_BLOCKS) error("block_overflow %.20s",p);
00588     idx=nextblock; blk->sublock=idx; nextblock++;
00589     snprintf(buf,sizeof(buf),"%s",p1);
00590     cp_cutline(buf,blockbuf+idx,blk-blockbuf);
00591 }
00592 
00593 void cp_opick(char *p, struct block *blk, int next)
00594 {
00595     _pick(p,blk,next,-3);
00596 }
00597 
00598 void cp_perm(char *p, struct block *blk, int next)
00599 {
00600     int i, n;
00601     listtype ltab[MAX_BLOCKS];
00602     listtype len;
00603 
00604     n=objnum(p,','); if(n==0) n=1;
00605     if(n>=MAX_BLOCKS) error("block_overflow %.20s",p);
00606     clist.lcnt=1; len=n; clist.listlen=&len;
00607     for(i=0;i<n;i++) ltab[i]=-2;
00608     clist.list=ltab;
00609     _permpick(p,n,blk,blk-blockbuf,',');
00610 }
00611 
00612 void cp_pick(char *p, struct block *blk, int next)
00613 {
00614     _pick(p,blk,next,-2);
00615 }
00616 
00617 void cp_rep(char *p, struct block *blk, int next)
00618 {
00619     int n;
00620     listtype ltab[]={-1,-5};
00621     listtype len[]={2};
00622 
00623     clist.lcnt=1; clist.listlen=len; clist.list=ltab;
00624     n=objnum(p,','); if(n==0) n=1;
00625     _permpick(p,n,blk,blk-blockbuf,',');
00626 }
00627 
00628 void cp_w(char *p, struct block *blk, int next)
00629 {
00630     items2words(p);
00631     blk->string=add2cp(p);
00632     blk->fn=mt_w;
00633     blk->nextblock=next;
00634 }
00635 
00636 void cp_wild(char *p, struct block *blk, int next)
00637 {
00638     int n, min, max;
00639     char *pp, *pe;
00640     n=objnum(p,','); if(n!=1) error("wrong_parmcnt wild %.20s\n",p);
00641     blk->string="";
00642     max=min=0;
00643     for(pp=find_word_start(p); *pp; pp=find_word_start(pe)) {
00644        pe=find_word_end(pp);
00645        if(pp[0]!='*') error("syntax_error wild %.20s\n",p);
00646        if(pp[1]!='*') {
00647            min++; continue;
00648        }
00649        if(isdigit(pp[2])) max+=atoi(pp+2);
00650        else max=MAX_BLOCKS;
00651     }
00652     blk->len=max;
00653     blk->lstart=min;
00654     blk->fn=mt_wild;
00655     blk->nextblock=next;
00656 }
00657 
00658 struct {
00659     char *name;
00660     void (*fn) (char *p, struct block *blk, int next);
00661 } builtin[]={
00662        {"Alt",              cp_alt},
00663        {"Aperm",     cp_aperm},
00664        {"Apick",     cp_apick},
00665        {"Dic",              cp_dic},
00666        {"Dperm",     cp_dperm},
00667        {"Ins",              cp_ins},
00668        {"Iperm",     cp_iperm},
00669        {"M",         cp_m},
00670        {"Neg",              cp_neg},
00671        {"Nomatch",   cp_none},
00672        {"None",      cp_none},
00673        {"Not",              cp_neg},
00674        {"Opick",     cp_opick},
00675        {"Out",              cp_out},
00676        {"Perm",      cp_perm},
00677        {"Pick",      cp_pick},
00678        {"Rep",              cp_rep},
00679        {"W",         cp_w},
00680        {"Wild",      cp_wild},
00681 };
00682 
00683 #define builtincnt (sizeof(builtin)/sizeof(builtin[0]))
00684 
00685        /* p must have MAX_LINELEN */
00686 void cp_oneblock(char *p, struct block *blk, int next)
00687 {
00688     char *pp, *pe;
00689     int i;
00690     if(debug>=3) fprintf(stderr,"Oneblock %d/%d for %.15s.\n",
00691                       blk-blockbuf, nextblock, p);
00692     if(myisupper(*p)) {
00693        for(pe=p; pe-p < MAX_BINAME && myisalpha(*pe); pe++);
00694        if(*pe==':') {
00695            *pe++=0;
00696            i=search_list(builtin,builtincnt,sizeof(builtin[0]),p);
00697            if(i<0) error("unknown_cmd %.20s",p);
00698            builtin[i].fn(pe,blk,next);
00699            blk->nextblock=next;
00700            return;
00701        }
00702     }
00703     if(*p=='*') {
00704        cp_wild(p,blk,next);
00705        return;
00706     }
00707     pp=strparchr(p,'|'); if(pp==NULL) {
00708        cp_cutline(p,blk,next);
00709     }
00710     else cp_alt2(p,blk,next);
00711 }
00712 
00713        /* p must have MAX_LINELEN */
00714 void compile(char *p)
00715 {
00716     nextblock=1; nextlist=0;
00717     cpnext=cpbuf;
00718     memset(blockbuf,0,sizeof(blockbuf));
00719     cp_oneblock(p,blockbuf,-1);
00720     showblocks();
00721 }
00722