home *** CD-ROM | disk | FTP | other *** search
/ Gold Fish 3 / goldfish_volume_3.bin / files / text / misc / cvt / source / cvt.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-10-22  |  10.2 KB  |  360 lines

  1. /*                                                               -*- C -*-
  2.  *  CVT.C
  3.  *
  4.  *  (c)Copyright 1991-93 by Tobias Ferber, All Rights Reserved.
  5.  */
  6.  
  7. #include <ctype.h>
  8. #include <stdio.h>
  9. #include <stdarg.h>
  10. #include <stdlib.h>
  11.  
  12. static char rcs_id[]= "$VER: $Id: cvt.c 1.6 93/09/11 15:53:29 tf Exp $";
  13.  
  14. #include "cvt.h"
  15.  
  16.  
  17. /*** / CVTOPEN / ***/
  18.  
  19. FILE *cvtopen(char *fname)
  20. /* cvtopen() "offnet ein (level 3) Textfile zum lesen, wobei zun"achst
  21.  * im aktuellen Verzeichnis nach 'fname' und 'fname.cvt' gesucht wird.
  22.  * Wenn da nix ist, werden die durch PSEP getrennten Pfade aus der
  23.  * Environment Variablen ENV_CVSCRIPTS davorgebaut und dort nachgesehen.
  24.  * Der zur"uckgegebene FILE * kann mit fclose() geschlossen werden. */
  25. {
  26.   FILE *fp= NIL(FILE);
  27.  
  28.   if(fname)
  29.   {
  30.     char pname[MAXIMUM_PATHNAME_LENGTH];
  31.     strcpy(pname,fname);
  32.  
  33. #ifdef DEBUG
  34.     if(debuglevel >= 1)
  35.       printf("> cvtopen() trying '%s'\n",pname);
  36. #endif
  37.  
  38.     if(!(fp=fopen(pname,"r")))
  39.     { 
  40.       strcat(pname,CVT_EXT);
  41.  
  42. #ifdef DEBUG
  43.       if(debuglevel >= 1)
  44.         printf("                   '%s'\n",pname);
  45. #endif
  46.  
  47.       if(!(fp=fopen(pname,"r")))
  48.       { 
  49.         char *ep= getenv(ENV_CVSCRIPTS);
  50.  
  51.         while(ep && *ep && !fp)
  52.         {
  53.           int i;
  54.  
  55.           for(i=0; *ep && (pname[i]= *ep++) != PSEP ; i++) ;
  56.  
  57.           if(i>0)
  58.           { 
  59.             if(pname[i-1]!='\\' && pname[i-1]!=':' && pname[i-1]!='/')
  60.               pname[i++]= PSLASH;
  61.  
  62.             pname[i]= '\0';
  63.             strcat(pname,fname);
  64.  
  65. #ifdef DEBUG
  66.             if(debuglevel >= 1)
  67.               printf("                   '%s'\n",pname);
  68. #endif
  69.  
  70.             if(!(fp=fopen(pname,"r")))
  71.             { strcat(pname,CVT_EXT);
  72.  
  73. #ifdef DEBUG
  74.               if(debuglevel >= 1)
  75.                 printf("                   '%s'\n",pname);
  76. #endif
  77.               fp= fopen(pname,"r");
  78.             }
  79.           }
  80.         }
  81.       }
  82.     }
  83.   }
  84.   return fp;
  85. }
  86.  
  87.  
  88. /*** / PARSEFILE / ***/
  89.  
  90. int parsefile(FILE *fp)
  91. /* liest ein Scriptfile von 'fp' ein und baut die crules auf */
  92. {
  93.   crule_t *rp;
  94.  
  95. #ifdef DEBUG
  96.   if(debuglevel >= 1)
  97.     printf("Starting parse\n");
  98. #endif
  99.  
  100.   while(!feof(fp) && global_numerrors < global_maxerrors)
  101.   {
  102.     if( rp= readcrule(fp) )
  103.     {
  104.       if( addcrule(rp) )
  105.       { 
  106.         lerror(rp->ln,"lhs is ambiguous!");
  107.  
  108. #ifdef DEBUG
  109.         if(debuglevel >= 2)
  110.           print_crule(rp);
  111. #endif /* DEBUG */
  112.  
  113.       }
  114.     }
  115.   }
  116.  
  117. #ifdef DEBUG
  118.   if(debuglevel >= 1)
  119.     printf("> parsefile()  collected %ld rules,  %d errors\n"
  120.            "Exiting parse\n", global_numrules, global_numerrors);
  121. #endif
  122.  
  123.   readcrule( NIL(FILE) );
  124.  
  125.   return global_numerrors;
  126. }
  127.  
  128.  
  129. /*** / PUTRHS / ***/
  130.  
  131. void putrhs(crule_t *rp)
  132. /* screibt das Pendant (rhs) zu der lhs von 'rp' nach 'fout' raus */
  133. { if(rp && rp->rhs)
  134.   { int n;
  135.     for(n=0; n<rp->r; n++)
  136.       fputc((rp->rhs)[n],fout);
  137.   }
  138.   /* otherwise substitute lhs to nothing */
  139. }
  140.  
  141.  
  142. /*** / TAKEITEASY / ***/
  143.  
  144. void takeiteasy(void)
  145. /* konvertiert 'fin' nach 'fout', falls global_maxlhs <= 1 ist */
  146. { while(!feof(fin))
  147.   { char c=fgetc(fin);
  148.     if(!feof(fin)) /* do NOT compare c!=EOF ! */
  149.     { int r= (int)(c & 0xFF);
  150.       if(crules[r]) putrhs(crules[r]);
  151.       else fputc(c,fout);
  152.     }
  153.   }
  154. }
  155.  
  156.  
  157. /* convert scanner modes */
  158. typedef enum { outer_mode,   /* reading chars */
  159.                collect_mode, /* collecting chars for a match */
  160.                look_mode,    /* looking for the first rule */
  161.                match_mode,   /* trying to match buffered chars */
  162.                flush_mode    /* flushing collected chars */
  163.              } csmode_t;
  164.  
  165.  
  166. /*** / DOTHEHARDPART / ***/
  167.  
  168. int dothehardpart(void)
  169. {
  170.   if(global_maxlhs<=1) takeiteasy(); /* optimize speed, better performance */
  171.   else
  172.   { char *cbuf, c;
  173.     int l=0;  /* cbuf index */
  174.     crule_t *ccr= NIL(crule_t); /* current crule */
  175.     csmode_t smode= outer_mode;
  176.     cbuf= malloc(global_maxlhs * sizeof(char));
  177.     if(!cbuf)
  178.     { echo("Ran out of memory to allocate %d bytes lhs buffer",
  179.         global_maxlhs);
  180.       return 1;
  181.     }
  182.  
  183.     /* c==EOF is allowed! do NOT use the following shortcut
  184.      * while((c=fgetc(fin))!=EOF &! feof(fin)) */
  185.  
  186.     while(!feof(fin))
  187.     { c= fgetc(fin);
  188.       if(!feof(fin)) do switch(smode)
  189.       {
  190.         case outer_mode:
  191.          /* In diesem scanner mode wird das eingelesene Zeichen
  192.           * + wieder rausgeschrieben, wenn keine Regeln daf"ur existieren.
  193.           *   Der scanner bleibt dann im outer_mode.
  194.           * + in sein Pendant "ubersetzt und dieses rausgeschrieben, wenn
  195.           *   die Regel keinen rechten Kontext f"ur dieses Zeichen vorsieht.
  196.           * + gepuffert und in den collect_mode "ubergegangen, wenn ein rechter
  197.           *   Kontext "uberpr"uft werden mu\3.
  198.           *   Hierbei wird der Kontext der obersten Regel angestrebt.
  199.           */
  200. #ifdef DEBUG
  201.           if(debuglevel >= 4)
  202.             printf("> outer_mode (c=$%x)\n",c&0xFF);
  203. #endif
  204.           { int r= (int)(c & 0xFF);
  205.             if(ccr= crules[r])
  206.             { if(ccr->l > 1) /* look ahead */
  207.               { l=0;
  208.                 cbuf[l++]= c;
  209.                 smode= collect_mode;
  210.               }
  211.               else putrhs(ccr);
  212.             }
  213.             else fputc(c,fout);
  214.           }
  215.           break;
  216.  
  217.         case collect_mode:
  218.          /* In diesem scanner mode wird "uberpr"uft, ob das eingelesene
  219.           * Zeichen in den rechten Kontext der aktuellen Regel 'ccr' pa\3t
  220.           * und in diesem Fall gepuffert.  Wenn damit der gesamte Kontext
  221.           * erf"ullt ist, wird das Pendant rausgeschrieben und in den
  222.           * outer_mode zur"uckgekehrt.
  223.           * Pa\3t dieses Zeichen nicht zum Kontext der aktuellen Regel,
  224.           * so wird in den match_mode "ubergegangen.
  225.           */
  226. #ifdef DEBUG
  227.           if(debuglevel >= 4)
  228.           { printf("> collect_mode (l=%d) for ",l);
  229.             { int i; for(i=0; i<ccr->l; i++) putchar((ccr->lhs)[i]); }
  230.             putchar('\n');
  231.           }
  232. #endif /* DEBUG */
  233.           if((ccr->lhs)[l]==(cbuf[l]=c))
  234.           { if(ccr->l==l+1) /* lhs matched */
  235.             { putrhs(ccr);
  236.               smode= outer_mode;
  237.             }
  238.             else ++l;
  239.           }
  240.           else { ++l; smode= match_mode; }
  241.           break;
  242.  
  243.         case look_mode:
  244.          /* In diesem scanner mode wird geschaut ob die gepufferten
  245.           * Zeichen den rechten Kontext aus der ersten Regel f"ur das
  246.           * oberste Pufferzeichen bilden.  Ist dies der Fall, so
  247.           * werden die zum Kontext geh"orenden Zeichen aus dem Puffer
  248.           * entfernt, deren Pendant ausgegeben und im look_mode
  249.           * verblieben.  Sind noch nicht gen"ugend Zeichen gelesen,
  250.           * so wird in den collect_mode, ansonsten in den match_mode
  251.           * "ubergegangen.
  252.           */
  253. #ifdef DEBUG
  254.           if(debuglevel >= 4)
  255.             printf("> look_mode (l=%d)\n",l);
  256. #endif
  257.           if(l>0)
  258.           { int r= (int)(cbuf[0] & 0xFF);
  259.             if(ccr= crules[r])
  260.             { int n, L; /* L := MIN(l,ccr->l) */
  261.               L= (l <= ccr->l) ? l : ccr->l;
  262.               for(n=0; n<L && (ccr->lhs)[n]==cbuf[n]; n++) ;
  263. #ifdef DEBUG
  264.               if(debuglevel >= 4)
  265.               {
  266.                 printf("  L=%d, l=%d, ccr->l=%d, n=%d trying ",L,l,ccr->l,n);
  267.                 { int i; for(i=0; i<ccr->l; i++) putchar((ccr->lhs)[i]); }
  268.                 putchar('\n');
  269.               }
  270. #endif /* DEBUG */
  271.               if(n == ccr->l) /* lhs matched */
  272.               { putrhs(ccr);
  273.                 l-= ccr->l;
  274.                 if(l>0) /* some chars left */
  275.                 { int i;
  276.                   for(i=0; i<=l; i++) cbuf[i]= cbuf[n+i];
  277.                   smode= look_mode;
  278.                 }
  279.                 else smode= outer_mode; /* no chars left */
  280.               }
  281.               else if(n==l && l<=ccr->l) smode= collect_mode;
  282.               else smode= match_mode;
  283.             }
  284.             else smode= flush_mode;
  285.           }
  286.           else smode= outer_mode;
  287.           break;
  288.  
  289.  
  290.         case match_mode:
  291.          /* In diesem scanner mode wird versucht eine Regel aus der
  292.           * Liste 'ccr' zu finden, die die gepufferten Zeichen abbaut.
  293.           * Dabei wird der head 'ccr' selbst nicht mehr "uberpr"uft.
  294.           * + Wenn es keine passende Regel gibt, so wird in den flush_mode
  295.           *   "ubergegangen.
  296.           * + Bleiben weitere Zeichen im Puffer "ubrig, so wird in
  297.           *   den look_mode "ubergegangen, es sei denn es
  298.           * + fehlen Zeichen zur "Uberpr"ufung eines Kontextes dann
  299.           *   wird in den collect_mode "ubergegangen.
  300.           * + Ist der Puffer leer, so wird in den outer_mode zur"uckgekehrt.
  301.           */
  302. #ifdef DEBUG
  303.           if(debuglevel >= 4)
  304.             printf("> match_mode (l=%d)\n",l);
  305. #endif
  306.           while((smode==match_mode) && (ccr=ccr->next))
  307.           { int n, L;
  308.             L= (l <= ccr->l) ? l : ccr->l;
  309.             for(n=0; n<L && (ccr->lhs)[n]==cbuf[n]; n++) ;
  310. #ifdef DEBUG
  311.             if(debuglevel >= 4)
  312.             {
  313.               printf("  L=%d, l=%d, ccr->l=%d, n=%d trying ",L,l,ccr->l,n);
  314.               { int i; for(i=0; i<ccr->l; i++) putchar((ccr->lhs)[i]); }
  315.               putchar('\n');
  316.             }
  317. #endif /* DEBUG */
  318.             if(n == ccr->l) /* lhs matched */
  319.             { putrhs(ccr);
  320.               l-= ccr->l;
  321.               if(l>0) /* some chars left */
  322.               { int i;
  323.                 for(i=0; i<=l; i++) cbuf[i]= cbuf[n+i];
  324.                 smode= look_mode;
  325.               }
  326.               else smode= outer_mode; /* no chars left */
  327.             }
  328.             else if(n==l && l<=ccr->l) smode= collect_mode;
  329.           }
  330.           if(smode==match_mode)
  331.             smode= flush_mode; /* couln't match this one */
  332.           break;
  333.  
  334.         case flush_mode:
  335.          /* In diesem scanner mode wird das erste Zeichen des Puffers
  336.           * aus diesem entfernt und im Klartext rausgeschrieben.
  337.           * Wenn der Puffer dadurch leer wurde, wird in den outer_mode
  338.           * "ubergegangen, ansonsten in den look_mode.
  339.           */
  340. #ifdef DEBUG
  341.           if(debuglevel >= 4)
  342.             printf("> flush_mode (l=%d)\n",l);
  343. #endif
  344.           fputc(cbuf[0],fout);
  345.           if(--l>=0)
  346.           { int i;
  347.             for(i=0; i<=l; i++)
  348.               cbuf[i]= cbuf[i+1];
  349.             smode= look_mode;
  350.           }
  351.           else smode= outer_mode;
  352.           break;
  353.  
  354.        } while((smode != outer_mode) && (smode != collect_mode));
  355.      }
  356.      /* EOF */
  357.    }
  358.    return 0;
  359. }
  360.