home *** CD-ROM | disk | FTP | other *** search
/ Gold Fish 3 / goldfish_volume_3.bin / files / dev / misc / adoc / source / adoc.yy < prev    next >
Text File  |  1995-04-13  |  17KB  |  543 lines

  1. /*
  2.  *  ADOC.YY  -- Specification of the AUTODOC scanner
  3.  *
  4.  *  (c)Copyright 1995 by Tobias Ferber,  All Rights Reserved
  5.  *
  6.  *  This file is part of ADOC.
  7.  *
  8.  *  ADOC is free software; you can redistribute it and/or modify
  9.  *  it under the terms of the GNU General Public License as published
  10.  *  by the Free Software Foundation; either version 1 of the License,
  11.  *  or (at your option) any later version.
  12.  *
  13.  *  ADOC is distributed in the hope that it will be useful,
  14.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  15.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  16.  *  GNU General Public License for more details.
  17.  *
  18.  *  You should have received a copy of the GNU General Public License
  19.  *  along with this program; see the file COPYING.  If not, write to
  20.  *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  21.  */
  22.  
  23. /* $VER: $Id: adoc.yy,v 1.21 1995/04/12 13:33:36 tf Exp $ */
  24.  
  25. %{
  26. #include <ctype.h>
  27. #include <string.h>
  28. #include <stdlib.h>
  29. #include <stdarg.h>
  30.  
  31. #include "adoc.h"
  32. #include "libfun.h"
  33. #include "flist.h"
  34. #include "debug.h"
  35.  
  36. /* In former versions of flex, yywrap had been defined as a macro */
  37.  
  38. #ifdef yywrap
  39. #undef yywrap
  40. #endif
  41.  
  42. /*
  43. ** local variables
  44. */
  45.  
  46. /* scanner's error stream */
  47. static FILE *ferr;
  48.  
  49. /* current input line (used for warnings and error messages) */
  50. static int scanner_line= 1;
  51.  
  52. /* set to the line in this file if an error occurs */
  53. static int scanner_error= 0;
  54.  
  55. /* name of the current input file */
  56. static char *scanner_infile= (char *)0;
  57.  
  58. static int scanner_flags;
  59.  
  60. /* pedanticness of warning method */
  61. static int warn_mask;
  62.  
  63. /* the last function which has been reported by funreport() */
  64. static char *report_fun= (char *)0;
  65.  
  66. /* string containing allowed characters for the comment type */
  67. static char *fun_type;
  68.  
  69. static int have_heading= 0;
  70.  
  71. /*
  72. **  local functions
  73. */
  74.  
  75. static void funreport(const char *fmt, ...)
  76. {
  77.   va_list argp;
  78.   va_start(argp,fmt);
  79.   {
  80.     char *fun= getfun( (char *)0 );
  81.  
  82.     if(fun) {
  83.       if( !report_fun || strcmp(report_fun,fun) )
  84.         fprintf(ferr,"%s: In function `%s':\n",scanner_infile,fun);
  85.     }
  86.     else { /* !fun */
  87.       if(report_fun)
  88.         fprintf(ferr,"%s: At top level:\n",scanner_infile);
  89.     }
  90.     report_fun= fun;
  91.   }
  92.   fprintf(ferr,"%s: %d: ",scanner_infile,scanner_line);
  93.   vfprintf(ferr,(char *)fmt,argp);
  94.   fprintf(ferr,"\n");
  95.   fflush(ferr);
  96.  
  97.   va_end(argp);
  98. }
  99.  
  100.  
  101. /* Check the availability of section keywords in a function description.
  102.    This procedure is called from the scanner at the end of a function */
  103.  
  104. static void funcheck(int line, ...)
  105. {
  106.   char *fun, *arg;
  107.  
  108.   va_list argp;
  109.   va_start(argp,line);
  110.  
  111.   if( (fun= getfun((char *)0)) )
  112.   {
  113.     int missing= 0;
  114.  
  115.     for(arg= va_arg(argp, char *); arg && *arg; arg= va_arg(argp, char *))
  116.     {
  117.       if( !getsec(arg) )
  118.       {
  119.         if(missing)
  120.           fprintf(ferr," `%s'",arg);
  121.  
  122.         else /* first missing keyword */
  123.         {
  124.           if( !report_fun || strcmp(report_fun,fun) )
  125.           {
  126.             fprintf(ferr,"%s: In function `%s':\n",scanner_infile,fun);
  127.             report_fun= fun;
  128.           }
  129.           fprintf(ferr,"%s: %d: warning: missing keyword `%s'",scanner_infile,line,arg);
  130.         }
  131.  
  132.         ++missing;
  133.       }
  134.     }
  135.  
  136.     if(missing)
  137.       fprintf(ferr,"\n");
  138.   }
  139.   va_end(argp);
  140. }
  141.  
  142. /* remove white spaces from the left and/or right end of a string `s' */
  143.  
  144. static char *strip(char *s, char *lr)
  145. {
  146.   char *l, *r, *t;
  147.  
  148.   if( strchr(lr,'l') )
  149.   {
  150.     /* find the first non-white char `l' in `s' */
  151.     for(l=s; *l==' ' || *l=='\t'; l++) ;
  152.   }
  153.   else l=s;
  154.  
  155.   if( strchr(lr,'r') )
  156.   {
  157.     /* find the last non-white char `r' in `s' */
  158.     for(t= r= l; *t; t++)
  159.     {
  160.       if(*t!=' ' && *t!='\t' && *t!='\r' && *t!='\n')
  161.         r= t;
  162.     }
  163.  
  164.     if(r[0])
  165.     {
  166.       if(*r==' ' || *r=='\t' || *r=='\r' || *r=='\n')
  167.         *r= '\0';
  168.  
  169.       else r[1]= '\0';
  170.     }
  171.   }
  172.  
  173.   return l;
  174. }
  175.  
  176. %}
  177.  
  178. BLACK        [^\n\r\f\t ]
  179. IDENT        [a-zA-Z0-9\-_\.]+
  180. AST          "*"
  181. NL           (\r)|(\n)|(\r\n)|(\n\r)
  182.  
  183. /* the context has been moved to the rule section
  184.    because of problems with former versions of lex */
  185.  
  186. FUN_BEGIN    [ \t]*{BLACK}{AST}{3}.{2}{AST}{1}" "
  187. FUN_IDENT    {IDENT}"/"{IDENT}
  188. FUN_SECTION  [ \t]*{BLACK}[ \t]+[A-Z]{2}[A-Z ]*
  189. FUN_TEXT     [ \t]*{BLACK}(([ \t].*)?)
  190. FUN_END      [ \t]*{BLACK}{AST}{2}
  191.  
  192. /*
  193.  *  eXclusive scanner modes:
  194.  *
  195.  *  INITIAL   skip source-code
  196.  *  EXPECT    we just read a {FUN_BEGIN} and expect a {FUN_IDENT} now to enter <SKIP> mode
  197.  *  SKIP      skip the rest of the line, then enter <FUN> mode
  198.  *  FUN       collecting data in a comment section.  {FUN_END} switches back to <INITIAL> mode again
  199.  */
  200.  
  201. %x EXPECT SKIP FUN
  202.  
  203. %%
  204.  
  205. <INITIAL>^{FUN_BEGIN}           { register char *s= yytext;
  206.  
  207.                                   if( (scanner_flags & SCANNER_ALLOW_INDENTED_COMMENTS) || (*s!=' ' && *s!='\t') )
  208.                                   {
  209.                                     while(*s==' ' || *s=='\t')
  210.                                       ++s;
  211.  
  212.                                     if( strchr(fun_type,s[4]) || strchr(fun_type,s[5]) )
  213.                                     {
  214.                                       D(bug("line %ld: <%c%c>",scanner_line,s[4],s[5]));
  215.                                       BEGIN(EXPECT);
  216.                                     }
  217.                                   }
  218.                                   /* else: skip this indented comment */
  219.                                 }
  220.  
  221. <EXPECT>{FUN_IDENT}             { D(bug("BEGIN function `%s'",yytext));
  222.  
  223.                                   if( newfun((char *)yytext) )
  224.                                   {
  225.                                     funreport("error adding function `%s' -- not enough memory?",yytext);
  226.                                     return scanner_error= __LINE__;
  227.                                   }
  228.                                   have_heading= 0;
  229.                                   BEGIN(SKIP);
  230.                                 }
  231.  
  232. <EXPECT>.                       {                  BEGIN(INITIAL); }
  233. <EXPECT>{NL}                    { ++scanner_line;  BEGIN(INITIAL); }
  234.  
  235. <SKIP>.*{NL}                    { yyless(yyleng-1); BEGIN(FUN); }
  236.  
  237.  
  238.  /* There had been warnings because of a "dangerous trailing context"
  239.     when using <FUN>^{FUN_SECTION}/{NL} and <FUN>^{FUN_TEXT}/{NL}.
  240.  
  241.     Note: we currently need the yyless() calls and put back the '\n' into
  242.     the input to make sure the `^' in is recognized afterwards */
  243.  
  244.  
  245. <FUN>^{FUN_SECTION}{NL}         { yyless(yyleng-1);
  246.  
  247.                                   if( (scanner_flags & SCANNER_ALLOW_INDENTED_COMMENTS) || (yytext[0]!=' ' && yytext[0]!='\t') )
  248.                                   {
  249.                                     register char *s, *t;
  250.  
  251.                                     for(s=yytext; *s==' ' || *s=='\t'; s++)
  252.                                       ;
  253.  
  254.                                     /* make a temporary copy of yytext */
  255.                                     if( (t=strdup(&s[1])) )
  256.                                     {
  257.                                       /* strip white chars on both sides of yytext */
  258.                                       s= strip(t,"lr");
  259.                                       D(bug("... section `%s'",s));
  260.  
  261.                                       if( warn_mask & WARN_UNKNOWN_KEYWORDS )
  262.                                       {
  263.                                         if( !strarg(s,"NAME",
  264.                                                       "SYNOPSIS",
  265.                                                       "FUNCTION",
  266.                                                       "INPUTS",
  267.                                                       "RESULT",
  268.                                                       "EXAMPLE",
  269.                                                       "NOTES",
  270.                                                       "BUGS",
  271.                                                       "SEE ALSO", "") )
  272.  
  273.                                           funreport("warning: unknown section keyword `%s'",s);
  274.                                       }
  275.  
  276.                                       if( newsec(s) )
  277.                                       {
  278.                                         funreport("error adding section keyword `%s' -- not enough memory?",s);
  279.                                         return scanner_error= __LINE__;
  280.                                       }
  281.                                       have_heading= 1;
  282.                                       free(t);
  283.                                     }
  284.                                     else /* !t */
  285.                                     {
  286.                                       funreport("ran out of memory");
  287.                                       return scanner_error= __LINE__;
  288.                                     }
  289.                                   }
  290.                                   else
  291.                                   {
  292.                                     funreport("disallowed indentation before section heading");
  293.                                     return scanner_error= __LINE__;
  294.                                   }
  295.                                 }
  296.  
  297. <FUN>^{FUN_TEXT}{NL}            { yyless(yyleng-1);
  298.  
  299.                                   if( (scanner_flags & SCANNER_ALLOW_INDENTED_COMMENTS) || (yytext[0]!=' ' && yytext[0]!='\t') )
  300.                                   {
  301.                                     register char *s, *t;
  302.  
  303.                                     for(s=yytext; *s==' ' || *s=='\t'; s++)
  304.                                       ;
  305.  
  306.                                     /* make a temporary copy of yytext and preserve
  307.                                        the correct indentation of the body text */
  308.  
  309.                                     if( (s[1]=='\t') || (s[1]=='\0') || (s[1]=='\n') )
  310.                                       t= strdup(&s[1]);
  311.  
  312.                                     else if( (t= strdup(s)) )
  313.                                       t[0]= ' ';
  314.  
  315.                                     if(t)
  316.                                     {
  317.                                       /* remove (leading and) trailing white spaces - especially the {NL} */
  318.                                       s= strip(t, (scanner_flags & SCANNER_UNINDENT_BODYTEXT) ? "lr":"r");
  319.  
  320.                                       if(!have_heading && *s)
  321.                                       {
  322.                                         if( newsec("") )
  323.                                         {
  324.                                           funreport("error creating untitled section -- not enough memory?");
  325.                                           return scanner_error= __LINE__;
  326.                                         }
  327.                                         if( warn_mask & WARN_UNTITLED_SECTION )
  328.                                           funreport("warning: untitled section");
  329.                                         have_heading= 1;
  330.                                       }
  331.  
  332.                                       if( addtext(s) > 0 )
  333.                                       {
  334.                                         funreport("error adding text line -- not enough memory?");
  335.                                         return scanner_error= __LINE__;
  336.                                       }
  337.  
  338.                                       free(t);
  339.                                     }
  340.                                     else /* !t */
  341.                                     {
  342.                                       funreport("ran out of memory");
  343.                                       return scanner_error= __LINE__;
  344.                                     }
  345.                                   }
  346.                                   else
  347.                                   {
  348.                                     funreport("disallowed indentation before section body");
  349.                                     return scanner_error= __LINE__;
  350.                                   }
  351.                                 }
  352.  
  353. <FUN>^{FUN_END}.*{NL}           { D(bug("END function"));
  354.  
  355.                                   if( warn_mask & WARN_MISSING_KEYWORDS )
  356.                                   {
  357.                                     funcheck( scanner_line, "NAME",
  358.                                                             "SYNOPSIS",
  359.                                                             "FUNCTION",
  360.                                                             "INPUTS",
  361.                                                             "RESULT",
  362.                                                             "EXAMPLE",
  363.                                                             "NOTES",
  364.                                                             "BUGS",
  365.                                                             "SEE ALSO", "");
  366.                                   }
  367.                                   yyless(yyleng-1);
  368.                                   BEGIN(INITIAL);
  369.                                 }
  370.  
  371. <FUN>^[ \t]*{NL}                { if( warn_mask & WARN_BROKEN_COMMENTS )
  372.                                     funreport("warning: broken autodoc comment");
  373.                                   ++scanner_line;
  374.                                 }
  375.  
  376. <FUN>.                          { if( warn_mask & WARN_STRANGE_TEXT )
  377.                                     funreport("warning: line does not match {FUN_TEXT}");
  378.                                   BEGIN(SKIP);
  379.                                 }
  380.  
  381. <INITIAL,EXPECT,SKIP,FUN>{NL}   { scanner_line++; }
  382. <INITIAL,EXPECT,SKIP,FUN>.      /* eat up everything else in <*> mode */
  383.  
  384. <EXPECT,SKIP,FUN><<EOF>>        { funreport("unterminated comment at the end of file");
  385.                                   return scanner_error= __LINE__;
  386.                                 }
  387.  
  388. <INITIAL><<EOF>>                { D(bug("%d lines at <<EOF>>",scanner_line));
  389.                                   yyterminate();
  390.                                 }
  391.  
  392. %%
  393.  
  394. /* This function opens the scanner stream for the file `fname' and
  395.    initializes `scanner_infile' and `scanner_line'.  It is called 
  396.    by read_source() and yywrap().  If USE_YYRESTART is defined then
  397.    we use yyrestart(fp) to initialize `yyin' to the new FILE *.
  398.    otherwise we assign `yyin' the new FILE * and call YY_NEW_FILE. */
  399.  
  400. static int init_scanner(char *fname)
  401. {
  402.  
  403. #if !defined(USE_YYRESTART)
  404.   static int num_calls= 0;
  405. #endif
  406.  
  407.   int result= 0;
  408.  
  409.   if(fname)
  410.   {
  411.     if(*fname)
  412.     {
  413.       FILE *fp= fopen(fname,"r");
  414.  
  415.       if(fp)
  416.       {
  417.         scanner_infile= fname;
  418.  
  419.         if(yyin && (yyin !=stdin))
  420.           fclose(yyin);
  421.  
  422. #if defined(USE_YYRESTART)
  423.         yyrestart(fp);
  424. #else
  425.         yyin= fp;
  426.         if(++num_calls > 1) YY_NEW_FILE;
  427. #endif
  428.       }
  429.       else /* !fp */
  430.       {
  431.         fprintf(ferr,"scanner error: cannot read from `%s'\n",fname);
  432.         scanner_error= __LINE__;
  433.         result= 1;
  434.       }
  435.     }
  436.     else /* !*fname */
  437.     {
  438.       scanner_infile= "stdin";
  439.  
  440.       if(yyin && (yyin !=stdin))
  441.         fclose(yyin);
  442.  
  443. #if defined(USE_YYRESTART)
  444.       yyrestart(stdin);
  445. #else
  446.       yyin= stdin;
  447.       if(++num_calls > 1) YY_NEW_FILE;
  448. #endif
  449.     }
  450.   }
  451.   else /* !fname */
  452.   {
  453.     /* We used to set `scanner_infile' to (char *)0 here but since
  454.      * the <<EOF>> rule which reports the unterminated comment is
  455.      * executed after the yywrap() call, we need to save the
  456.      * filename for this error message. */
  457.  
  458.     /*scanner_infile= (char *)0;*/
  459.  
  460.     result= 1;
  461.   }
  462.  
  463.   /* reset the line counter */
  464.   scanner_line= 1;
  465.  
  466. #ifdef DEBUG
  467.   if(result == 0)
  468.     D(bug("--> `%s'", scanner_infile));
  469.   else
  470.     D(bug("--> end of scanner input queue"));
  471. #endif /*DEBUG*/
  472.  
  473.   return result;
  474. }
  475.  
  476. /* In former versions of flex, yywrap had been defined as a macro */
  477.  
  478. #ifdef yywrap
  479. #undef yywrap
  480. #endif
  481.  
  482. /*
  483.  *  yywrap() is called by yylex() each time the EOF is reached.
  484.  *  It returns 0 if there is another file to be scanned or
  485.  *             1 if all scanning is done.
  486.  *  Our yywrap() will take the next file from the flist queue.
  487.  */
  488.  
  489. int yywrap()
  490. {
  491.   int result= 1;
  492.  
  493.   if( !scanner_error )
  494.   {
  495.     flist_nextfile();
  496.     result= init_scanner( flist_getname() );
  497.   }
  498.  
  499.   return result;
  500. }
  501.  
  502.  
  503. int read_source(char *_fun_type, int _warn_mask, int flags)
  504. {
  505.   int err= 0;
  506.  
  507.   D(bug_enter("read_source"));
  508.  
  509.   /* copy parameters to the local variables */
  510.  
  511.   fun_type      = _fun_type;
  512.   warn_mask     = _warn_mask;
  513.   scanner_flags = flags;
  514.  
  515.   /* initialize the error stream */
  516.  
  517.   ferr= get_ferr();
  518.  
  519.   /* initialize the scanner */
  520.  
  521.   if( init_scanner( flist_getname() ) == 0 )
  522.   {
  523.     if(scanner_error == 0)
  524.     {
  525.       /* yylex() returns an integer != 0 if an error occured. */
  526.       err= yylex();
  527.     }
  528.   }
  529.   else
  530.   {
  531.     D(bug("ooops!?  filename queue is empty?"));
  532.   }
  533.  
  534.   /* errors from yywrap() are returned as negative values */
  535.  
  536.   if(!err && scanner_error)
  537.     err= -scanner_error;
  538.  
  539.   D(bug_leave("read_source (%s)",err ? "failed":"successful"));
  540.  
  541.   return err;
  542. }
  543.