home *** CD-ROM | disk | FTP | other *** search
/ The C Users' Group Library 1994 August / wc-cdrom-cusersgrouplibrary-1994-08.iso / vol_100 / 172_01 / lex.c < prev    next >
Text File  |  1979-12-31  |  21KB  |  642 lines

  1. /*
  2.   HEADER: CUG     nnn.nn;
  3.   TITLE:     LEX - A Lexical Analyser Generator
  4.   VERSION:     1.0 for IBM-PC
  5.   DATE:      Jan 30, 1985
  6.   DESCRIPTION:     A Lexical Analyser Generator. From UNIX
  7.   KEYWORDS:     Lexical Analyser Generator YACC C PREP
  8.   SYSTEM:     IBM-PC and Compatiables
  9.   FILENAME:      LEX.C
  10.   WARNINGS:     This program is not for the casual user. It will
  11.          be useful primarily to expert developers.
  12.   CRC:         N/A
  13.   SEE-ALSO:     YACC and PREP
  14.   AUTHORS:     Scott Guthery 11100 leafwood lane Austin, TX 78750
  15.   COMPILERS:     LATTICE C 3.0h
  16.   REFERENCES:     UNIX Systems Manuals
  17. */
  18.  
  19. /*
  20.  * Copyright (c) 1978 Charles H. Forsyth
  21.  */
  22.  
  23. /*
  24.  * lex -- initialisation, allocation, set creation
  25.  *
  26.  *     Revised for PDP-11 (Decus) C by Martin Minow
  27.  */
  28.  
  29. /* Modified 02-Dec-80 Bob Denny -- Conditionalized debug code for smaller size
  30.  *                           01 -- Moved calls to dfa build, min, print, write
  31.  *                                  and to stat, and code for ending() into
  32.  *                                  this module so that 'ytab' could be put
  33.  *                                  into overlay region.
  34.  *          29-May-81 Bob Denny -- More extern hacking for RSX overlaying.
  35.  * More     19-Mar-82 Bob Denny -- New C library & compiler
  36.  * More     03-May-82 Bob Denny -- Final touches, remove unreferenced autos
  37.  *          28-Aug-82 Bob Denny -- Add "-s" switch to supress references to
  38.  *                                  "stdio.h" in generated code.  Add switch
  39.  *                                  comments in code. Add -e for "easy" com-
  40.  *                                  mand line. "lex -e file" is the short way
  41.  *                                  of saying:
  42.  *                                      "lex -i file.lxi -o file.c -t file"
  43.  * More(!)  30-Oct-82 Bob Denny -- Fix RSX ODL to put lots of FCS junk into
  44.  *                                  overlay, pick up (badly needed) 3KW for
  45.  *                                  NFA nodes, etc.  Change static allocations
  46.  *                                  in LEXLEX.H for RSX so can do non-trivial
  47.  *                                  things.  Task is now big on RSX and grows
  48.  *                                  from big to huge as it runs.
  49.  *                                 Fix "-s" support so it is again possible
  50.  *                                  to do a lexswitch() (dumb!).
  51.  *          14-Apr-83 Bob Denny    VAX-11 C workarounds.
  52.  *                                 Fix definition of toupper().
  53.  *        20-Nov-83 Scott Guthery  Adapt for IBM PC & DeSmet C
  54.  *          22-Jun-86 Andrew Ward  Adapted for Lattice C ver 3.0h.  Debug and 
  55.  *                    Error detection code installed as aid in 
  56.  *                       detection of wild pointers which result 
  57.  *                                 from interchanging pointers and integers. 
  58.  *                          The interchangable use of pointers and 
  59.  *                                 integers was eliminated. 
  60.  *
  61.  *                                 NOTICE: some Lattice 3.0 functions were used *                   However, these should be easy to recode.  
  62.  *                   Non-ANSII functions will be removed latter
  63.  *          
  64.  */
  65.  
  66. #ifdef  DOCUMENTATION
  67.  
  68. title   lex     A Lexical Analyser Generator
  69. index           A Lexical Analyser Generator
  70.  
  71. synopsis
  72.  
  73.         lex [-options] [-i grammar] [-o outfile] [-t table]
  74.  
  75. description
  76.  
  77.         Lex compiles a lexical analyser from a grammar and description of
  78.         actions.  It is described more fully in lex.doc: only usage is
  79.         described.  The following options are available:
  80.         .lm +16
  81.         .s.i-16;-a              Disable recognition of non-ASCII characters
  82.         (codes > 177 octal) for exception character classes (form [^ ...]).
  83.         .s.i-16;-d              Enable debugging code within lex.  Normally
  84.         needed only for debugging lex.
  85.         .s.i-16;-e              "Easy" command line. Saying "lex#-e#name" is the
  86.         same as saying:
  87.         .s.i 4;"lex -i name.lxi -o name.c -t name"
  88.         .s
  89.         Do not include devices or an extension on "name" or make it longer
  90.         than 8 characters, or you'll get several error messages.
  91.         .s.i-16;-i file         Read the grammar from the file.  If "-i" is not
  92.         specified, input will be read from the standard input.
  93.         .s.i-16;-m              Enable state minimization. Currently not
  94.  
  95.         implemented, switch is a no-op.
  96.         .s.i-16;-o file         Write the output to the file.  If "-o" is not
  97.         specified, output will be written to file "lextab.c".
  98.         .s.i-16;-s              "Stand-alone" switch.  Supresses the line
  99.         "#include <stdio.h>" normally generated in the lex output.  Use this
  100.         if LEX is generating a module to be used in a program which does not
  101.         use the "standard I/O" package.
  102.         .s.i-16;-t table        Name the recognizer "table" instead of the
  103.         default "lextab".  If -o is not given, output will be written to file
  104.         "table.c".
  105.         .s.i-16;-v [file]       Verify -- write internal tables to the
  106.         indicated file.  If "-v" is given without a file name argument,
  107.         tables will be written to "lex.out".
  108.         .lm -16
  109.  
  110. diagnostics
  111.  
  112.         The following error messages may occur on invocation.  See lex
  113.         documentation for information on compilation errors.
  114.         .lm +8
  115.         .s.i -8;Can't create ...
  116.         .s.i -8;Cannot open ...
  117.         .s.i -8;Illegal option.
  118.         .s.i -8;Illegal switch combination.
  119.         .s
  120.         "-i", "-o" or "-t" given with "-e" or vice-versa
  121.         .s.i -8;Table name too long.
  122.         .s
  123.         The table name (argument to "-t") must not be longer than 8 bytes.
  124.         .s.i -8;Missing table name.
  125.         .s.i -8;Missing input file.
  126.         .s.i -8;Missing output file.
  127.         .s.i -8;Missing name.
  128.         .lm -8
  129.  
  130. author
  131.         Charles Forsyth
  132.         Modified by Martin Minnow, Bob Denny & Scott Guthery
  133.         Modified by Andrew M. Ward, Jr.
  134. bugs
  135.  
  136.  
  137. #endif
  138.  
  139. /*
  140.  * LEX -- Lexical scanner acquired from C-users group.
  141.  *      In original form this program was an example of what good C
  142.  *      programing is NOT.  I have tried to eliminate machine dependancies
  143.  *      where ever possible.  In particular, the interchangable use of
  144.  *      pointers and ints has been eliminated.  External fuctions are declared
  145.  *         with argument typed.
  146.  *  1986
  147.  * 02 June AMW: installed Lattice 3.0 functions in place of some combersom routines
  148.  *         used by original code.
  149.  * 04 June routine lexsort: qsort replaced with call to Lattice function of same name.
  150.  *         Result: LEX produces output with proper appearance, but does not
  151.  *         compile correctly.  Dangaling pointer is cause.
  152.  * 22 June My substitution code for NEWCCL was faulty.  Original code replaced
  153.  *         and system behaved properly.  Further, using C-terp it was determined
  154.  *         that the routine lexswitch returned the wrong value, this was corrected.
  155.  * 23 June modifications made to DEBUG segments.  Program LEX produces compilable
  156.  *         output that functions for word.lxi -> word.c as intended.  hword.lxi
  157.  *         does not process to completion.  Symptom: lex hangs-up while displaying
  158.  *         XX nets NN.  The offending code is the DEBUG segment and the surrounding
  159.  *         loop.  Assert lines were installed but detected no errors.
  160.  * 24 June Newset modified to use sqsort() when routine called for DFA request.
  161.  *         This modification may improve execution speed.
  162.  * 25 June The program now compiles and produces functional code for hword.lxi
  163.  *         and word.lxi.  Both programs fuction correctly.  Further, I uncovered
  164.  *         an error in the debug code I installed.  It appears that certain control
  165.  *         codes disable ANSI.SYS and the display can not be restarted.  The code
  166.  *         is in BASE.C and is identified by the UDEBUG segment.
  167.  *
  168.  */
  169. #include <stdio.h>
  170. #include "lexlex.h"  
  171.  
  172. #ifdef LATTICE
  173. #include <assert.h>
  174. #include <stdlib.h>
  175. #include <string.h>
  176. #include <dos.h>
  177.  
  178. /* Set memory size for procedure.  Lattice specific */
  179. int  _STACK = 32000;
  180. long _MNEED = 45000;
  181.  
  182. extern        char  tolower();
  183. extern        char  *calloc();
  184.  
  185. /* Lex functions */
  186. extern        char  *lalloc(unsigned, unsigned, char *);
  187. extern        char  *newccl(char *);             
  188. extern        void  heading(void);             
  189. extern        void  dfabuild(void);             
  190. extern        void  setline(void);             
  191. extern        void  dfawrite( void );             
  192. extern        void  error( char *, char *);          
  193. extern        void  f_error( char *, char *);  /* Fatal error */
  194. extern        int   setcomp( struct nfa **, struct nfa **);
  195. extern struct set   *newset( struct nfa **, int, int);     
  196. extern struct trans *newtrans(struct nfa *, struct nfa *);
  197. extern struct dfa   *newdfa( void );
  198. extern struct nfa   *newnfa(int, struct nfa *, struct nfa *);
  199. extern        int   eqvec( struct nfa **, struct nfa **, int );
  200.  
  201. #else
  202. /* Function types of arguments are removed, otherwise identical to Lattice */
  203. /* section */
  204. extern         char  tolower();
  205. extern         char  *lalloc();
  206. extern         char  *calloc();
  207. extern         char  *newccl();
  208. extern         void  heading();
  209. extern         void  dfabuild();
  210. extern         void  setline();
  211. extern         void  dfawrite();
  212. extern         void  error();
  213. extern         void  f_error();
  214. extern         int   setcomp();
  215. extern struct  set   *newset();
  216. extern struct  trans *newtrans();
  217. extern struct  dfa   *newdfa();
  218. extern struct  nfa   *newnfa();
  219. extern         int   eqvec();
  220.  
  221. #endif
  222.  
  223. /* includes system configuration constants */
  224.  
  225. extern            char  ccls[NCCLS][(NCHARS+1)/NBPC];
  226.  
  227. struct  xset  sets[NCHARS];
  228.  
  229. char    insets[NCHARS];
  230.  
  231. struct  trans   trans[NTRANS];
  232. struct  trans   *transp = &trans[0];
  233.  
  234. FILE    *llout;
  235. FILE    *lexin;
  236. FILE    *lexlog;
  237.  
  238.  
  239. char    infile[FMSIZE]  = "";
  240. char    outfile[FMSIZE] = "";
  241. char    *tabname = "lextab  ";
  242. char    tabfile[FMSIZE];
  243. char    *progname;
  244.  
  245. struct  dfa     dfa[MAXDFA];
  246. struct  move    move[NNEXT];
  247.  
  248. struct  nfa      nfa[MAXNFA];
  249. struct  nfa     *nfap = &nfa[1]; /* &nfa[1]; */
  250. int     ndfa = 0;
  251.  
  252.  
  253. char    ccls[NCCLS][(NCHARS+1)/NBPC];
  254. int     nccls = 0;
  255. int     llnxtmax = 0;
  256. int     yyline;
  257. char    llbuf[100];
  258. char    *llend, *llp2;
  259.  
  260.  
  261.  
  262. /*
  263.  * Flags.  Allow globals only for those requiring same. Some only
  264.  * used for checking for bad combos. this
  265.  */
  266.         int     aflag = 0;      /* Ignore non-ASCII in [^ ...] */
  267. static  int     eflag = 0;      /* Easy command line */
  268. static  int     iflag = 0;      /* "-i" given */
  269.         int     mflag = 0;      /* Enable state minimization (not imp.) */
  270. static  int     oflag = 0;      /* "-o" given */
  271.         int     sflag = 0;      /* Supress "#include <stdio.h>" in output */
  272. static  int     tflag = 0;      /* "-t" given */
  273.  
  274. struct  set     *setlist = NULL;
  275.  
  276.  
  277. void main(argc, argv)
  278. int argc;
  279. char *argv[];
  280. {
  281. #ifdef LATTICE
  282.     progname = argv[0]; /* Who we are */
  283. #endif
  284.        for (; argc>1 && *argv[1]=='-'; argv++, argc--)
  285.        switch (tolower(argv[1][1])) {
  286.  
  287.        /*
  288.         * Enable state minimization. Currently not implemented.
  289.          */
  290.        case 'm':
  291.                mflag++;
  292.                break;
  293.  
  294.        /*
  295.         * Disable matching of non-ASCII characters (codes > 177(8))
  296.         * for exception character classes (form "[^ ...]").
  297.         */
  298.        case 'a':
  299.                aflag++;
  300.                break;
  301.  
  302.        /*
  303.         * Supress "#include <stdio.h>" in generated
  304.         * code for programs not using standard I/O.
  305.         */
  306.        case 's':
  307.                sflag++;
  308.                break;
  309.  
  310.        /*
  311.         * "Easy" command line
  312.         */
  313.        case 'e':
  314.                if(iflag || oflag || tflag) {
  315.                        f_error("Illegal switch combination\n","");
  316.                }
  317.                if(--argc <= 1) {
  318.                        f_error("Missing name\n","");
  319.                }
  320.                if(strlen(tabname = (++argv)[1]) > 8) {
  321.                       f_error("Name too long\n","");
  322.                }
  323.                strmfe(infile, tabname, "lxi");
  324.                printf("Input read from %s\n", infile);
  325.                if( ( lexin = fopen( infile, "r" ) ) == NULL ) {
  326.                        f_error( "Cannot open input \"%s\"\n", infile );
  327.                }
  328.                strmfe( outfile, tabname, "c" );
  329.                break;
  330.  
  331.        /*
  332.         * Specify input file name.
  333.         */
  334.        case 'i':
  335.                if( eflag ) {
  336.                       f_error("Illegal switch combination\n","");
  337.                }
  338.            
  339.                iflag++;
  340.                if( --argc <= 1 ) {
  341.                        f_error( "Missing input file\n","" );
  342.                }
  343.            
  344.                strcpy(infile, (++argv)[1]);
  345.                printf("Input read from %s\n", infile);
  346.                if((lexin = fopen(infile, "r")) == NULL) {
  347.                        f_error("Cannot open input \"%s\"\n", infile);
  348.                }
  349.            
  350.                strcpy( outfile, "lextab.c");
  351.                break;
  352.  
  353.        /*
  354.         * Specify output file name. Default = "lextab.c"
  355.         */
  356.        case 'o':
  357.               if(eflag) {
  358.                        f_error("Illegal switch combination\n","");
  359.                }
  360.                oflag++;
  361.                if(--argc <= 1) {
  362.                        f_error("Missing output file","");
  363.                }
  364.                strcpy(outfile,(++argv)[1]);
  365.                break;
  366.  
  367.        /*
  368.         * Specify table name.  Default = "lextab.c".  If "-o"
  369.         * not given, output will go to "tabname.c".
  370.         */
  371.        case 't':
  372.                if(eflag) {
  373.                        f_error("Illegal switch combination\n","");
  374.                }
  375.               tflag++;
  376.                if(--argc <= 1) {
  377.                        f_error("Missing table name","");
  378.                }
  379.                if(strlen(tabname = (++argv)[1]) > 8) {
  380.                        f_error("Table name too long\n","");
  381.                }
  382.                break;
  383.  
  384.        default:
  385.                f_error("Illegal option: %s\n", argv[1]);
  386.        }
  387.  
  388.        if(!strcmp(infile,"") ) strcpy(infile, "lex.lxi");
  389.        (void)strlwr( infile );
  390.        tabname = strlwr( tabname );
  391.        if( !strcmp(outfile, "") ) {
  392.                strmfe( tabfile, tabname, "c");
  393.                strcpy( outfile, tabfile );
  394.        }
  395.        printf("Analyzer written to %s\n", outfile);
  396.        if((llout = fopen(outfile, "w"))==NULL) {
  397.                f_error("Can't create %s\n", outfile);
  398.        }
  399.  
  400.        /* Now that all the options are set the real work begins */
  401.        heading();
  402.        fprintf(stderr, "Parse LEX source ...\n");
  403.        if(yyparse()) error("Parse failed\n","");
  404.        fprintf(stderr, "Build NFA then DFA ...\n");
  405.        dfabuild();                                             /* 01+ */
  406.        fprintf(stderr, "Minimize DFA ...\n");
  407.        dfamin();
  408.        fprintf(stderr, "Create C source ...\n");
  409.        dfaprint();
  410.        dfawrite();
  411.        fprintf(stderr, "\07LEX done.\n");
  412.        fclose(llout);
  413.        exit(0);
  414. } /** END OF MAIN **/
  415.  
  416. void ending()
  417. {
  418.        static int ended;
  419.  
  420.         if(ended++) return;
  421.        fprintf(llout, "\t}\n\treturn(LEXSKIP);\n}\n");
  422.        setline();
  423. }
  424.  
  425.  
  426. /*
  427.  * The following functions simply
  428.  * allocate various kinds of
  429.  * structures.
  430.  */
  431.  
  432. struct nfa *newnfa(ch, nf1, nf2)
  433. int  ch;
  434. struct nfa *nf1, *nf2;
  435. {
  436.        struct nfa *nf;
  437.        extern struct nfa *nfap;
  438.        /* Pull an NFA slot off the nfa stack and test */
  439.        if ((nf = nfap++) >= &nfa[MAXNFA]) {
  440.                f_error("Too many NFA states","");
  441.        }
  442.         nf->n_char = ch;
  443. #ifdef DEBUG
  444.         if( nf1 !=NULL) assert( isdata( (char *)nf1, sizeof( struct nfa) ) );
  445.         if( nf2 !=NULL) assert( isdata( (char *)nf2, sizeof( struct nfa) ) );
  446. #endif
  447.         nf->n_succ[0] = nf1;
  448.         nf->n_succ[1] = nf2;
  449.         nf->n_trans = (struct trans *)NULL;
  450.         nf->n_flag = '\0';
  451.         nf->n_look = '\0';
  452.         return(nf);
  453. }
  454.  
  455. struct dfa *newdfa()
  456. {
  457.         struct dfa *df;
  458.         /* Pull a DFA slot of the dfa stack and test */
  459.         if ((df = &dfa[ndfa++]) >= &dfa[MAXDFA]) {
  460.                f_error("Out of dfa states","");
  461.         }
  462. #ifdef DEBUG
  463.         fprintf( stdout,"\nCurrent DFA count is: %d", ndfa);
  464. #endif
  465.         return(df);
  466. }
  467.  
  468. char *newccl(ccl)
  469. char *ccl;
  470. {
  471.         int j;
  472.         int i;
  473.         char *p, *q;
  474.         extern int sz_ccl;
  475.         extern int nccls;
  476.         for (j = 0; j < nccls; j++)
  477.         {
  478.             p = ccl;
  479.             q = ccls[j];
  480.             for( i = sizeof( ccls[j]); i--; )
  481.               if(*p++ != *q++) goto cont;
  482.             return( ccls[j] );
  483. cont:       ;
  484.         }
  485.         if (nccls >= NCCLS) {
  486.                f_error("Too many character classes","");
  487.         }
  488.         /* the character block 'ccl' is fixed length */
  489.         /* and may have intervening '\0'             */
  490.         /* return( memcpy(ccls[nccls++], ccl, sz_ccl ) ); */
  491.         p = ccl;
  492.         q = ccls[ j = nccls++];
  493.         for( i = sizeof(ccls[j]); i--; )
  494.            *q++ = *p++;
  495.         return( ccls[j] );
  496. }
  497.  
  498. struct trans *newtrans(st, en)
  499. struct nfa *st, *en;
  500. {
  501.        struct trans *tp;
  502.        extern struct trans *transp;
  503.        if((tp = transp++) >= &trans[NTRANS]) {
  504.                f_error("Too many translations","");
  505.        }
  506. #ifdef DEBUG
  507.     /* Test for valid data */
  508.     if( st !=NULL) assert( isdata( (char *)st, sizeof( struct nfa) ) );
  509.     if( en !=NULL) assert( isdata( (char *)en, sizeof( struct nfa) ) );
  510. #endif
  511.        tp->t_start = st;
  512.        tp->t_final = en;
  513.        en->n_trans = tp;
  514.        return( (struct trans *)tp);
  515. }
  516.  
  517. /*
  518.  * Create a new set. `sf', if set, indicates that the elements of the
  519.  * set are states of an NFA). If `sf' is not set, the elements are state
  520.  * numbers of a DFA.
  521.  */
  522. struct set *newset(v, i, sf)
  523. struct nfa **v;
  524. int i;
  525. int sf;
  526. {
  527.        struct set *t;
  528.        long k;
  529.        int kk;
  530.        extern int setcomp();
  531.  
  532.        if( i != 0 && sf ) {
  533.         qsort((char *)v, i, 4 /*sizeof(struct nfa *)*/, setcomp);
  534.        }
  535.        else
  536.        {
  537.        /* AMW: was (char *) 26 July 1986 */
  538.         sqsort((short *)v, i );
  539.        }
  540. #ifdef DEBUG
  541.        if(setlist !=NULL) assert( isdptr( (char *)setlist ) );
  542.        assert( i >= 0 );
  543. #endif
  544.        for (t = setlist; t != NULL; t = t->s_next)
  545.               if (t->s_len==i && eqvec(t->s_els, v, i)) return(t);
  546.        t = (struct set *)lalloc(1, (unsigned)( sizeof(struct set)+i*sizeof(struct nfa *) ), "set nodes");
  547.        t->s_next = setlist;
  548.  
  549.        setlist = t;
  550.        t->s_final = 0;
  551.        t->s_state =  (struct dfa *)NULL;
  552.        t->s_flag = '\0';
  553.        t->s_len = i;
  554.        t->s_group = (struct set *)NULL;
  555.        t->s_look = 0;
  556.        for (v += i; i;) {
  557.                --v;
  558.               if (sf) {
  559.                        if ((*v)->n_char==FIN)
  560.                        {
  561.                          kk = (*v) - nfa;
  562.                          t->s_final = kk;
  563.                        }
  564.                       if( (*v)->n_flag & LOOK )
  565.                                t->s_look |= 1 << ((*v)->n_look);
  566.                } else {
  567.                       error("\nNEWSET: called for a DFA request","");
  568.                       k = (long)*v;  /* AMW: try to clear warning on invalid conversion */
  569.                       printf("\nLEX (NEWSET) k = %d", k);
  570.                        dfa[k].df_name->s_group = t;
  571.                }
  572. #ifdef DEBUG
  573.                assert( isdata( (char *)v, sizeof( struct nfa ) ) );
  574. #endif
  575.                t->s_els[--i] = *v; /* 'i' must be greater than 0 */
  576.        }
  577.        return(t);
  578. }
  579.  
  580. /* Compare different sets */
  581. int setcomp(n1p, n2p)
  582. struct nfa **n1p, **n2p;
  583. {
  584.        struct nfa *n1, *n2;
  585.  
  586.        n1 = *n1p;
  587.        n2 = *n2p;
  588.        if( n1 > n2 )
  589.                return(1);
  590.        if( n1 == n2 )
  591.               return(0);
  592.        return(-1);
  593. }
  594.  
  595. int eqvec(a, b, i)
  596. struct nfa **a, **b;    /* long *a;long *b;*/
  597. int   i;
  598. {
  599.        if( i )
  600.                do{
  601.                        if( *a++ != *b++ )
  602.                                return(0);
  603.                } while(--i);
  604.        return(1);
  605. }
  606.  
  607.  
  608. /*
  609.  * Ask for core, and complain if there is no more.
  610.  */
  611. char *lalloc(n, s, w)
  612. unsigned n, s;
  613. char *w;
  614. {
  615.        char *cp;
  616.        if ((cp = calloc(n, s)) == NULL) {
  617.               f_error("No space for %s", w);
  618.        }
  619.        return(cp);
  620. }
  621.  
  622. /* Error Functions used by LEX */
  623.  
  624. void error(format, argument)
  625. char *format, *argument;
  626. {
  627.        fprintf(stderr, format, argument);
  628. }
  629.  
  630. void f_error( format, argument )
  631. char *format, *argument;
  632. {
  633.     error( format, argument );
  634.     exit(1);
  635. }
  636.  
  637. #include "stats.c"
  638.  
  639.  
  640.  
  641.  
  642.