Subversion Repositories wimsdev

Rev

Rev 8161 | Blame | Compare with Previous | Last modification | View Log | RSS feed

  1. /*    Copyright (C) 2002-2003 XIAO, Gang of Universite de Nice - Sophia Antipolis
  2.  *
  3.  *  This program is free software; you can redistribute it and/or modify
  4.  *  it under the terms of the GNU General Public License as published by
  5.  *  the Free Software Foundation; either version 2 of the License, or
  6.  *  (at your option) any later version.
  7.  *
  8.  *  This program is distributed in the hope that it will be useful,
  9.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  10.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  11.  *  GNU General Public License for more details.
  12.  *
  13.  *  You should have received a copy of the GNU General Public License
  14.  *  along with this program; if not, write to the Free Software
  15.  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  16.  */
  17. #include "symtext.h"
  18.  
  19. char cpbuf[MAX_LINELEN+1];
  20. char *cpnext;
  21. int noaddw=0;
  22.  
  23. char Mbuf[MAX_LINELEN+1];
  24. char *Mnext;
  25. struct {
  26.     char *Mptr;
  27.     int blkptr;
  28. } Mind[MAX_BLOCKS];
  29. int Mcnt;
  30.  
  31. struct liststruct {
  32.     listtype lcnt;
  33.     listtype *listlen;
  34.     listtype *list;
  35. } clist;
  36.  
  37. void cp_oneblock(char *p, struct block *blk, int next);
  38.  
  39. /* debugger: show the detail of blocks */
  40. void showblocks(void)
  41. {
  42.     int i, j, k;
  43.     struct block *blk;
  44.     if(!debug) return;
  45.     for(i=0;i<nextblock;i++) {
  46.       blk=blockbuf+i;
  47.       fprintf(stderr,"Block %2d: next=%2d.      ",i,blk->nextblock);
  48.       if(blk->fn==mt_string) {
  49.           fprintf(stderr,"String %s.\n",blk->string);
  50.           continue;
  51.       }
  52.       if(blk->fn==mt_permpick) {
  53.           fprintf(stderr,"Permpick %d items %d lists starting %d\n",
  54.                blk->len, blk->lcnt, blk->sublock);
  55.           for(j=0;j<blk->lcnt;j++) {
  56.             fprintf(stderr,"    list %d: ", j);
  57.             for(k=0;k<blk->listlen[j];k++)
  58.               fprintf(stderr,"%d ",blk->lists[j][k]);
  59.             fprintf(stderr,"\n");
  60.           }
  61.           continue;
  62.       }
  63.       if(blk->fn==mt_m) {
  64.           fprintf(stderr,"Macro starting %d ending %d\n", blk->sublock,
  65.                 blockbuf[blk->sublock].mend);
  66.           continue;
  67.       }
  68.       if(blk->fn==mt_neg) {
  69.           fprintf(stderr,"Neg starting %d\n", blk->sublock);
  70.           continue;
  71.       }
  72.       if(blk->fn==mt_dic) {
  73.           fprintf(stderr,"Dic %s.\n", blk->string);
  74.           continue;
  75.       }
  76.       if(blk->fn==mt_w) {
  77.           fprintf(stderr,"Word list.\n");
  78.           continue;
  79.       }
  80.       if(blk->fn==mt_wild) {
  81.           fprintf(stderr,"Wild min=%d, max=%d.\n", blk->lstart, blk->len+blk->lstart);
  82.           continue;
  83.       }
  84.       if(blk->fn==mt_out) {
  85.           fprintf(stderr,"Output for \"%s\", sub=%d.\n", blk->string,blk->sublock);
  86.           continue;
  87.       }
  88.       fprintf(stderr,"Unknown type!\n");
  89.     }
  90.  
  91. }
  92.  
  93. /* remove punctuations */
  94. void depunct(char *p,char *str)
  95. {
  96.     char *pp;
  97.     for(pp=p; *pp; pp++) {
  98.       if(strchr(str,*pp)==NULL) continue;
  99.       if(*pp=='.' && pp>p && isdigit(pp[-1]) && isdigit(pp[1])) continue;
  100.       *pp=' ';
  101.     }
  102. }
  103.  
  104. /* p must have MAX_LINELEN */
  105. void isolate_punct(char *p)
  106. {
  107.     char buf[MAX_LINELEN+1];
  108.     char *p1, *p2;
  109.     for(p1=p, p2=buf; *p1 && p2<buf+MAX_LINELEN; p1++) {
  110.       if(myisalnum(*p1) || (*p1&128) || *p1==' ' || *p1=='_') {
  111.           *p2++=*p1; continue;
  112.       }
  113.       if((*p1=='.' || *p1==',') && p1>p && isdigit(p1[-1]) && isdigit(p1[1])) {
  114.           *p2++=*p1; continue;
  115.       }
  116.       if(p2>buf && !myisspace(p2[-1])) *p2++=' ';
  117.       *p2++=*p1;
  118.       if(p1[1] && !myisspace(p1[1])) *p2++=' ';
  119.     }
  120.     if(p2>=buf+MAX_LINELEN) sym_error("string_too_long");
  121.     *p2=0;
  122.     snprintf(p,MAX_LINELEN,"%s",buf);
  123. }
  124.  
  125. void alphaonly(char *p)
  126. {
  127.     char *pp;
  128.     for(pp=p; *pp; pp++) if(!myisalpha(*pp)) *pp=' ';
  129. }
  130.  
  131. void alnumonly(char *p)
  132. {
  133.     char *pp;
  134.     for(pp=p; *pp; pp++) if(!myisalnum(*pp)) *pp=' ';
  135. }
  136.  
  137. /* buffer must have MAX_LINELEN */
  138. void strfold(char *p)
  139. {
  140.     char *pp;
  141.     singlespace(p);
  142.     if(noaddw&2) goto fend;
  143.     if(options&op_nocase) for(pp=p; *pp; pp++) *pp=tolower(*pp);
  144.     if(options&op_reaccent) reaccent(p);
  145.     if(options&op_deaccent) deaccent(p);
  146.     if(options&op_alphaonly) alphaonly(p);
  147.     if(options&op_alnumonly) alnumonly(p);
  148.     isolate_punct(p);
  149.     if(options&op_nopunct) depunct(p,char_punct);
  150.     if(options&op_nomath) depunct(p,char_math);
  151.     if(options&op_noparenth) depunct(p,char_parenth);
  152.     if(options&op_nocs) depunct(p,char_cs);
  153.     if(options&op_noquote) depunct(p,char_quote);
  154.     if(suffixcnt>0) suffix_translate(p);
  155.     _translate(p,transdic);
  156.  
  157. fend:
  158.     singlespace(p);strip_trailing_spaces(p);
  159.     if(myisspace(*p)) ovlstrcpy(p,find_word_start(p));
  160. }
  161.  
  162. /* at entry p must point to an atom start! */
  163. char *find_atom_end(char *p)
  164. {
  165.     char *pp;
  166.     if(*p=='[') {
  167.       pp=find_matching(p+1,']');
  168.       if(pp!=NULL) return pp+1;
  169.       else sym_error("unmatched_parentheses %.20s",p);
  170.     }
  171.     return find_word_end(p);
  172. }
  173.  
  174. #define find_atom_start(x) find_word_start(x)
  175. #define next_atom(x) find_atom_start(find_atom_end(x))
  176.  
  177. /* p must have MAX_LINELEN */
  178. void macro_trans(char *p)
  179. {
  180.     char *atoms[MAX_BLOCKS], *atom2[MAX_BLOCKS];
  181.     char tbuf[MAX_LINELEN+1], ttbuf[MAX_LINELEN+1], vbuf[8];
  182.     char *pt, *pp, *pe, *p1, *p2, *p3;
  183.     char *pt1, *pt2;
  184.     int i,k,m,n,repcnt,start,min;
  185.  
  186.     if(dic[macrodic].len<=0) return;
  187.     repcnt=start=0; pt=p;
  188.     recalc:
  189.     repcnt++;
  190.     if(repcnt>=MAX_BLOCKS) sym_error("macro_level_overflow %.20s",p);
  191.     for(i=start, pp=find_atom_start(pt); i<MAX_BLOCKS && *pp; pp=next_atom(pp), i++)
  192.       atoms[i]=pp;
  193.     if(i>=MAX_BLOCKS-1) sym_error("block_overflow %.20s",p);
  194.     atoms[i]=pp+strlen(pp);
  195.     for(k=0;k<i;k++) {
  196.       pp=atoms[k]; switch(*pp) {
  197.           case '[': {
  198.             pe=find_atom_end(pp); pp++;
  199.             if(pe[-1]!=']') break;
  200.             if(myislower(*pp)) {
  201.                 for(p1=pp;myisalnum(*p1) || *p1=='_'; p1++);
  202.                 if(*p1!=':') break;
  203.                 *p1++=0; pe[-1]=0;
  204.                 for(m=0,p2=p1;*p2;m++,p2=p3) {
  205.                   p3=find_item_end(p2); if(*p3) *p3++=0;
  206.                   atom2[m]=p2;
  207.                 }
  208.                 if(m==0) m=1;
  209.                 snprintf(tbuf,sizeof(tbuf),"%s",pp);
  210.                 _translate(tbuf,macrodic);
  211.                 if(tbuf[0]==0) sym_error("bad_macro %.50s",pp);
  212.                 for(p1=strchr(tbuf,'@'); p1; p1=strchr(p1,'@')) {
  213.                   for(p2=p1+1;isdigit(*p2) || *p2=='-';p2++);
  214.                   if(p2==p1+1 || p2>p1+6) sym_error("syntax_error %.20s",p1);
  215.                   memmove(vbuf,p1,p2-p1); vbuf[p2-p1]=0;
  216.                   n=atoi(vbuf+1);
  217.                   if(n<=0 || n>m) sym_error("wrong_parmcnt macro %.50s",pp);
  218.                   string_modify(tbuf,p1,p2,atom2[n-1]);
  219.                 }
  220.                 n=strlen(tbuf); if(n<MAX_LINELEN) {
  221.                   tbuf[n++]=' '; tbuf[n]=0;
  222.                 }
  223.                 string_modify(p,pp-1,pe,tbuf); pt=pp-1; start=k;
  224.                 goto recalc;
  225.             }
  226.             break;
  227.           }
  228.           case '_': {
  229.             pe=find_word_end(pp);
  230.             if(pe-pp>MAX_NAMELEN) sym_error("name_too_long %.20s",pp);
  231.             memmove(tbuf,pp,pe-pp); tbuf[pe-pp]=0;
  232.             _translate(tbuf,macrodic);
  233.             if(tbuf[0]==0) break;
  234.             pt1=pp; pt2=find_atom_end(pt1); min=k;
  235.             for(p1=strchr(tbuf,'@'); p1; p1=strchr(p1,'@')) {
  236.                 for(p2=p1+1;isdigit(*p2) || *p2=='-';p2++);
  237.                 if(p2==p1+1 || p2>p1+6) sym_error("syntax_error %.20s",p1);
  238.                 memmove(vbuf,p1,p2-p1); vbuf[p2-p1]=0;
  239.                 n=atoi(vbuf+1);
  240.                 if(n<-4 || n==0 || n>4) sym_error("bad_macro %.20s",atoms[k]);
  241.                 n+=k;
  242.                 if(n<0 || n>=i) sym_error("bad_macro_position %.20s",atoms[k]);
  243.                 p3=find_atom_end(atoms[n]);
  244.                 if(p3>pt2) pt2=p3;
  245.                 if(atoms[n]<pt1) {min=n;pt1=atoms[n];}
  246.                 memmove(ttbuf,atoms[n],p3-atoms[n]); ttbuf[p3-atoms[n]]=' ';
  247.                 ttbuf[p3-atoms[n]+1]=0;
  248.                 string_modify(tbuf,p1,p2,ttbuf);
  249.             }
  250.             string_modify(p,pt1,pt2,tbuf); pt=pt1; start=min;
  251.             goto recalc;
  252.           }
  253.           default: break;
  254.       }
  255.     }
  256. }
  257.  
  258. char *add2cp(char *p)
  259. {
  260.     char *pp, *p1, *p2, buf[MAX_LINELEN+1];
  261.     int l;
  262.     snprintf(buf,sizeof(buf),"%s",p); strfold(buf); l=strlen(buf);
  263.     if((cpnext-cpbuf)+l>=MAX_LINELEN) sym_error("string_too_long");
  264.     pp=cpnext; memmove(pp,buf,l+1); cpnext+=l+1;
  265.     if(!noaddw) for(p1=find_word_start(buf); *p1; p1=find_word_start(p2)) {
  266.       p2=find_word_end(p1); l=p2-p1;
  267.       if(*p2) *p2++=0;
  268.       if(wordchr(wbuf,p1)!=NULL) continue;
  269.       if(wptr-wbuf>=sizeof(wbuf)-l-2) continue;
  270.       if(wptr>wbuf) *wptr++=' ';
  271.       memmove(wptr,p1,l); wptr+=l; *wptr=0;
  272.     }
  273.     return pp;
  274. }
  275.  
  276. void cp_string(char *p, struct block *blk, int next)
  277. {
  278.     blk->fn=mt_string;
  279.     blk->string=add2cp(p);
  280.     blk->len=strlen(blk->string);
  281.     blk->nextblock=next;
  282.     if(blk==blockbuf+nextblock) nextblock++;
  283. }
  284.  
  285. /* p must have MAX_LINELEN */
  286. void cp_cutline(char *p, struct block *blk, int next)
  287. {
  288.     char *p1, *p2, *p3;
  289.     char buf[MAX_LINELEN+1];
  290.     int l, ll, n, idx, start, end;
  291.     struct block *b;
  292.  
  293.     if(debug>=3) fprintf(stderr,"Cutline %d/%d for %.15s.\n",
  294.                    (int)(blk-blockbuf), nextblock, p);
  295.     for(p1=strstr(p,"[|]"); p1; p1=strstr(p1,"[|]")) memmove(p1," | ",3);
  296.     macro_trans(p);
  297.     singlespace(p);
  298.     p=find_word_start(p); strip_trailing_spaces(p);
  299.     l=0; p3=p; do {
  300.       p1=find_word_start(p3);
  301.       if(*p1) l++;
  302.       p2=strparchr(p1,'[');
  303.       if(p2!=NULL) p3=find_matching(p2+1,']');
  304.       if(p3==NULL) sym_error("unmatched_parentheses %.20s",p);
  305.       if(p2!=NULL && p2>p1) l++;
  306.       p3++;
  307.     } while(p2!=NULL);
  308.     if(l==0) {
  309.       buf[0]=0; cp_string(buf,blk,next);
  310.       return;
  311.     }
  312.     idx=start=nextblock; nextblock+=l-1; end=nextblock;
  313.     if(nextblock > MAX_BLOCKS) sym_error("block_overflow %.20s",p);
  314.     for(p1=find_word_start(p); *p1; p1=find_word_start(p3)) {
  315.       p2=strparchr(p1,'[');
  316.       if(p2==NULL) p2=p1+strlen(p1);
  317.       ll=p2-p1;
  318.       if(ll>0) {
  319.           memmove(buf,p1,ll); buf[ll]=0;
  320.           if(idx==start) b=blk; else b=blockbuf+idx-1;
  321.           if(idx<end) n=idx; else n=next;
  322.           if(debug>=3) fprintf(stderr,"String block %d/%d for %.15s.\n",
  323.                    (int)(b-blockbuf), nextblock, buf);
  324.           cp_string(buf,b,n);
  325.           idx++;
  326.       }
  327.       if(*p2=='[') {
  328.           p2++; p3=find_matching(p2,']');
  329.           memmove(buf,p2,p3-p2); buf[p3-p2]=0; p3++;
  330.           if(idx==start) b=blk; else b=blockbuf+idx-1;
  331.           if(idx<end) n=idx; else n=next;
  332.           cp_oneblock(buf,b,n);
  333.           idx++;
  334.       }
  335.       else p3=p2;
  336.     }
  337. }
  338.  
  339. unsigned int objnum(char *p, char delim)
  340. {
  341.     int i; char *p1, *p2;
  342.  
  343.     if(*p==0) return 1;
  344.     i=0;
  345.     for(p1=p; p1; p1=p2, i++) {
  346.       p2=strparchr(p1,delim); if(p2) p2++;
  347.     }
  348.     return i;
  349. }
  350.  
  351. void _permpick(char *p, int n, struct block *blk, int next, char delim)
  352. {
  353.     int i, t, idx;
  354.     char buf[MAX_LINELEN+1];
  355.     char *pp, *pe;
  356.  
  357.     idx=nextblock; nextblock+=n;
  358.     if(nextblock > MAX_BLOCKS) sym_error("block_overflow %.20s",p);
  359.     blk->len=n;
  360.     blk->sublock=idx;
  361.     blk->fn=mt_permpick;
  362.     blk->lcnt=clist.lcnt;
  363.     blk->nextblock=next;
  364.     if(nextlist+n > MAX_LISTS) sym_error("list_overflow %.20s",p);
  365.     blk->listlen=listbuf+nextlist; nextlist+=n;
  366.     for(i=t=0; i<clist.lcnt; i++) {
  367.       blk->listlen[i]=clist.listlen[i];
  368.       blk->lists[i]=listbuf+nextlist+t;
  369.       t+=clist.listlen[i];
  370.     }
  371.     if(nextlist+t > MAX_LISTS) sym_error("list_overflow %.20s",p);
  372.     memmove(listbuf+nextlist,clist.list,t*sizeof(listtype));
  373.     nextlist+=t;
  374.     for(i=0, pp=find_word_start(p);i<n;i++,idx++,pp=find_word_start(pe)) {
  375.       pe=strparchr(pp,delim);
  376.       if(pe==NULL) pe=pp+strlen(pp); else *pe++=0;
  377.       snprintf(buf,sizeof(buf),"%s",pp);
  378.       cp_cutline(buf,blockbuf+idx,next);
  379.     }
  380. }
  381.  
  382. /* alt for two flavours */
  383. void _alt(char *p, struct block *blk, int next, char delim)
  384. {
  385.     int n;
  386.     listtype ltab[]={-1};
  387.     listtype len[]={1};
  388.  
  389.     clist.lcnt=1; clist.listlen=len; clist.list=ltab;
  390.     n=objnum(p,delim); if(n==0) n=1;
  391.     _permpick(p,n,blk,next,delim);
  392. }
  393.  
  394. void cp_alt(char *p, struct block *blk, int next)
  395. {
  396.     _alt(p,blk,next,',');
  397. }
  398.  
  399. void cp_alt2(char *p, struct block *blk, int next)
  400. {
  401.     _alt(p,blk,next,'|');
  402. }
  403.  
  404. void cp_aperm(char *p, struct block *blk, int next)
  405. {
  406.     int i, n;
  407.     listtype ltab[MAX_BLOCKS];
  408.     listtype len;
  409.  
  410.     n=objnum(p,','); if(n<4) sym_error("wrong_parmcnt ins %.20s",p);
  411.     if(n>=MAX_BLOCKS/2) sym_error("block_overflow %.20s",p);
  412.     clist.lcnt=1; len=2*n-5; clist.listlen=&len;
  413.     for(i=0;i<n-2;i++) ltab[2*i]=-2;
  414.     for(i=0;i<n-4;i++) ltab[2*i+1]=0;
  415.     ltab[len-2]=1;
  416.     clist.list=ltab;
  417.     _permpick(p,n,blk,blk-blockbuf,',');
  418.     blk->lstart=2;
  419. }
  420.  
  421. void cp_apick(char *p, struct block *blk, int next)
  422. {
  423.     int i, n, t;
  424.     char *p1;
  425.     listtype ltab[MAX_BLOCKS];
  426.     listtype len;
  427.  
  428.     n=objnum(p,','); if(n<4) sym_error("wrong_parmcnt ins %.20s",p);
  429.     if(n>=MAX_BLOCKS/2) sym_error("block_overflow %.20s",p);
  430.     p1=find_item_end(p); if(*p1) *p1++=0;
  431.     t=atoi(p); if(t<=0 || t>n-3) sym_error("syntax_error ins %.20s",p);
  432.     clist.lcnt=1; len=2*t-1; clist.listlen=&len;
  433.     for(i=0;i<t;i++) ltab[2*i]=-2;
  434.     for(i=0;i<t-1;i++) ltab[2*i+1]=0;
  435.     ltab[len-2]=1;
  436.     clist.list=ltab;
  437.     _permpick(p1,n,blk,blk-blockbuf,',');
  438.     blk->lstart=2;
  439. }
  440.  
  441. void cp_dic(char *p, struct block *blk, int next)
  442. {
  443.     int i, n;
  444.     char *p1, *p2;
  445.     n=objnum(p,',');
  446.     if(n!=1) sym_error("wrong_parmcnt dic %.20s",p);
  447.     p1=find_word_start(p); p2=find_word_end(p1);
  448.     if(*p2) *p2++=0;
  449.     p2=find_word_start(p2);
  450.     i=getdic(p1);
  451.     if(i<0) sym_error("bad_dictionary %.20s",p1);
  452.     noaddw=3;
  453.     blk->string=add2cp(p2);
  454.     noaddw=0;
  455.     blk->len=strlen(blk->string);
  456.     blk->lind1=i;
  457.     blk->fn=mt_dic;
  458.     blk->nextblock=next;
  459. }
  460.  
  461. void cp_dperm(char *p, struct block *blk, int next)
  462. {
  463.     int n;
  464.     listtype ltab[]={0,1,2,2,3,0};
  465.     listtype len[]={3,3};
  466.  
  467.     clist.lcnt=2; clist.listlen=len; clist.list=ltab;
  468.     n=objnum(p,',');
  469.     if(n!=4) sym_error("wrong_parmcnt dperm %.20s",p);
  470.     _permpick(p,n,blk,blk-blockbuf,',');
  471. }
  472.  
  473. void cp_ins(char *p, struct block *blk, int next)
  474. {
  475.     int i, n;
  476.     listtype ltab[MAX_BLOCKS];
  477.     listtype len;
  478.  
  479.     n=objnum(p,','); if(n<3) sym_error("wrong_parmcnt ins %.20s",p);
  480.     if(n>=MAX_BLOCKS/2) sym_error("block_overflow %.20s",p);
  481.     clist.lcnt=1; len=2*n-2; clist.listlen=&len;
  482.     for(i=1;i<n;i++) ltab[2*i-2]=i;
  483.     for(i=1;i<len;i+=2) ltab[i]=-12;
  484.     ltab[len-1]=-13;
  485.     clist.list=ltab;
  486.     _permpick(p,n,blk,blk-blockbuf,',');
  487.     blk->lstart=1;
  488. }
  489.  
  490. void cp_iperm(char *p, struct block *blk, int next)
  491. {
  492.     int n;
  493.     listtype ltab[]={0,1,2,2,1,0};
  494.     listtype len[]={3,3};
  495.  
  496.     clist.lcnt=2; clist.listlen=len; clist.list=ltab;
  497.     n=objnum(p,',');
  498.     if(n!=3) sym_error("wrong_parmcnt iperm %.20s",p);
  499.     _permpick(p,n,blk,blk-blockbuf,',');
  500. }
  501.  
  502. void cp_m(char *p, struct block *blk, int next)
  503. {
  504.     int i, idx;
  505.     char buf[MAX_LINELEN+1];
  506.  
  507.     i=objnum(p,','); if(i!=1) sym_error("wrong_parmcnt m %.20s",p);
  508.     blk->fn=mt_m;
  509.     blk->string=NULL;
  510.     blk->len=1;
  511.     blk->nextblock=next;
  512.     p=find_word_start(p);singlespace(p);strip_trailing_spaces(p);
  513.     for(i=0;i<Mcnt && strcmp(p,Mind[i].Mptr)!=0;i++);
  514.     if(nextblock >= MAX_BLOCKS-2) sym_error("block_overflow %.20s",p);
  515.     if(i<Mcnt) blk->sublock=Mind[i].blkptr;
  516.     else {
  517.       i=strlen(p);
  518.       if(Mnext-Mbuf+i >= MAX_LINELEN-1) sym_error("Mbuf_overflow %.20s",p);
  519.       if(Mcnt >= MAX_BLOCKS) sym_error("Mind_overflow %.20s",p);
  520.       Mind[Mcnt].Mptr=Mnext; Mind[Mcnt].blkptr=nextblock;
  521.       Mcnt++;
  522.       memcpy(Mnext,p,i+1); Mnext+=i+1;
  523.       idx=nextblock; blk->sublock=idx; nextblock++;
  524.       snprintf(buf,sizeof(buf),"%s",p);
  525.       cp_cutline(buf,blockbuf+idx,-2);
  526.       blockbuf[idx].mend=nextblock;
  527.     }
  528. }
  529.  
  530. void cp_neg(char *p, struct block *blk, int next)
  531. {
  532.     int n, idx;
  533.     char buf[MAX_LINELEN+1];
  534.     n=objnum(p,','); if(n==0) n=1;
  535.     if(n>1) sym_error("wrong_parmcnt neg %.20s",p);
  536.     blk->fn=mt_neg;
  537.     blk->len=1;
  538.     blk->nextblock=next;
  539.     if(nextblock >= MAX_BLOCKS) sym_error("block_overflow %.20s",p);
  540.     idx=nextblock; blk->sublock=idx; nextblock++;
  541.     snprintf(buf,sizeof(buf),"%s",p);
  542.     cp_cutline(buf,blockbuf+idx,blk-blockbuf);
  543. }
  544.  
  545. void cp_none(char *p, struct block *blk, int next)
  546. {
  547.     blk->fn=mt_nomatch;
  548.     blk->string="";
  549.     blk->nextblock=next;
  550. }
  551.  
  552. void _pick(char *p, struct block *blk, int next, int type)
  553. {
  554.     int i, n, t, v;
  555.     listtype ltab[MAX_BLOCKS];
  556.     listtype len;
  557.     char *p1;
  558.  
  559.     n=objnum(p,','); n--;
  560.     if(n<2) sym_error("wrong_parmcnt pick %.20s",p);
  561.     if(n>=MAX_BLOCKS) sym_error("block_overflow %.20s",p);
  562.     p1=strparchr(p,','); *p1++=0;
  563.     p=find_word_start(p); v=0;
  564.     if(*p=='-') {p++; type-=5;}
  565.     else if(*p=='+') {v=2; p++;}
  566.     t=atoi(p); if(t<1 || t>MAX_PICKS || t>n) sym_error("bad_pickcnt %.20s",p);
  567.     clist.lcnt=1; len=t+v; clist.listlen=&len;
  568.     for(i=0;i<t;i++) ltab[i]=type;
  569.     if(v) {ltab[i++]=-6; ltab[i]=-5;}
  570.     clist.list=ltab;
  571.     _permpick(p1,n,blk,blk-blockbuf,',');
  572. }
  573.  
  574. void cp_out(char *p, struct block *blk, int next)
  575. {
  576.     char buf[MAX_LINELEN+1];
  577.     char *p1;
  578.     int n, idx;
  579.     n=objnum(p,','); if(n!=2) sym_error("wrong_parmcnt out %.20s",p);
  580.     p1=strparchr(p,','); if(p1) *p1++=0; else p1=p+strlen(p);
  581.     p=find_word_start(p); *find_word_end(p)=0;
  582.     noaddw=3;
  583.     blk->string=add2cp(p);
  584.     noaddw=0;
  585.     blk->len=strlen(blk->string);
  586.     blk->fn=mt_out;
  587.     blk->nextblock=next;
  588.     if(nextblock >= MAX_BLOCKS) sym_error("block_overflow %.20s",p);
  589.     idx=nextblock; blk->sublock=idx; nextblock++;
  590.     snprintf(buf,sizeof(buf),"%s",p1);
  591.     cp_cutline(buf,blockbuf+idx,blk-blockbuf);
  592. }
  593.  
  594. void cp_opick(char *p, struct block *blk, int next)
  595. {
  596.     _pick(p,blk,next,-3);
  597. }
  598.  
  599. void cp_perm(char *p, struct block *blk, int next)
  600. {
  601.     int i, n;
  602.     listtype ltab[MAX_BLOCKS];
  603.     listtype len;
  604.  
  605.     n=objnum(p,','); if(n==0) n=1;
  606.     if(n>=MAX_BLOCKS) sym_error("block_overflow %.20s",p);
  607.     clist.lcnt=1; len=n; clist.listlen=&len;
  608.     for(i=0;i<n;i++) ltab[i]=-2;
  609.     clist.list=ltab;
  610.     _permpick(p,n,blk,blk-blockbuf,',');
  611. }
  612.  
  613. void cp_pick(char *p, struct block *blk, int next)
  614. {
  615.     _pick(p,blk,next,-2);
  616. }
  617.  
  618. void cp_rep(char *p, struct block *blk, int next)
  619. {
  620.     int n;
  621.     listtype ltab[]={-1,-5};
  622.     listtype len[]={2};
  623.  
  624.     clist.lcnt=1; clist.listlen=len; clist.list=ltab;
  625.     n=objnum(p,','); if(n==0) n=1;
  626.     _permpick(p,n,blk,blk-blockbuf,',');
  627. }
  628.  
  629. void cp_w(char *p, struct block *blk, int next)
  630. {
  631.     items2words(p);
  632.     blk->string=add2cp(p);
  633.     blk->fn=mt_w;
  634.     blk->nextblock=next;
  635. }
  636.  
  637. void cp_wild(char *p, struct block *blk, int next)
  638. {
  639.     int n, min, max;
  640.     char *pp, *pe;
  641.     n=objnum(p,','); if(n!=1) sym_error("wrong_parmcnt wild %.20s\n",p);
  642.     blk->string="";
  643.     max=min=0;
  644.     for(pp=find_word_start(p); *pp; pp=find_word_start(pe)) {
  645.       pe=find_word_end(pp);
  646.       if(pp[0]!='*') sym_error("syntax_error wild %.20s\n",p);
  647.       if(pp[1]!='*') {
  648.           min++; continue;
  649.       }
  650.       if(isdigit(pp[2])) max+=atoi(pp+2);
  651.       else max=MAX_BLOCKS;
  652.     }
  653.     blk->len=max;
  654.     blk->lstart=min;
  655.     blk->fn=mt_wild;
  656.     blk->nextblock=next;
  657. }
  658.  
  659. struct builtin builtin[]={
  660.       {"Alt",           cp_alt},
  661.         {"Aperm",       cp_aperm},
  662.         {"Apick",       cp_apick},
  663.         {"Dic",         cp_dic},
  664.         {"Dperm",       cp_dperm},
  665.         {"Ins",         cp_ins},
  666.         {"Iperm",       cp_iperm},
  667.         {"M",           cp_m},
  668.         {"Neg",         cp_neg},
  669.         {"Nomatch",     cp_none},
  670.         {"None",        cp_none},
  671.         {"Not",         cp_neg},
  672.         {"Opick",       cp_opick},
  673.         {"Out",         cp_out},
  674.         {"Perm",        cp_perm},
  675.         {"Pick",        cp_pick},
  676.         {"Rep",         cp_rep},
  677.         {"W",           cp_w},
  678.         {"Wild",        cp_wild},
  679. };
  680.  
  681. int builtincnt=(sizeof(builtin)/sizeof(builtin[0]));
  682.  
  683. /* p must have MAX_LINELEN */
  684. void cp_oneblock(char *p, struct block *blk, int next)
  685. {
  686.     char *pp, *pe;
  687.     int i;
  688.     if(debug>=3) fprintf(stderr,"Oneblock %d/%d for %.15s.\n",
  689.                    (int)(blk-blockbuf), nextblock, p);
  690.     if(myisupper(*p)) {
  691.       for(pe=p; pe-p < MAX_BINAME && myisalpha(*pe); pe++);
  692.       if(*pe==':') {
  693.           *pe++=0;
  694.           i=search_list(builtin,builtincnt,sizeof(builtin[0]),p);
  695.           if(i<0) sym_error("unknown_cmd %.20s",p);
  696.           builtin[i].fn(pe,blk,next);
  697.           blk->nextblock=next;
  698.           return;
  699.       }
  700.     }
  701.     if(*p=='*') {
  702.       cp_wild(p,blk,next);
  703.       return;
  704.     }
  705.     pp=strparchr(p,'|'); if(pp==NULL) {
  706.       cp_cutline(p,blk,next);
  707.     }
  708.     else cp_alt2(p,blk,next);
  709. }
  710.  
  711. /* p must have MAX_LINELEN */
  712. void compile(char *p)
  713. {
  714.     nextblock=1; nextlist=0;
  715.     cpnext=cpbuf;
  716.     memset(blockbuf,0,sizeof(blockbuf));
  717.     cp_oneblock(p,blockbuf,-1);
  718.     showblocks();
  719. }
  720.  
  721.