home *** CD-ROM | disk | FTP | other *** search
/ BCI NET 2 / BCI NET 2.iso / archives / programming / c / c2man-2.0pl33.lha / c2man-2.0 / lex.l < prev    next >
Encoding:
Lex Description  |  1995-01-14  |  13.5 KB  |  580 lines

  1. %{
  2. /* $Id: lex.l,v 2.0.1.23 1994/01/21 07:48:57 greyham Exp $
  3.  *
  4.  * C manual page generator
  5.  * Lexical analyzer specification
  6.  */
  7.  
  8. #include <ctype.h>
  9.  
  10. static char *cur_file;            /* current file name (malloced) */
  11. int line_num = 1;        /* current line number in file */
  12. static int curly = 0;        /* number of curly brace nesting levels */
  13. static int square = 0;        /* number of square bracket nesting levels */
  14. static int ly_count = 0;    /* number of occurances of %% */
  15.  
  16. /* temporary string buffer */
  17. static char buf[MAX_TEXT_LENGTH];
  18.  
  19. #define DYNBUF_ALLOC    240    /* size of increment of dynamic buf */
  20. static char *dynbuf;        /* start of dynamic buf */
  21. static int dynbuf_size;        /* number of bytes allocated */
  22. static int dynbuf_current;    /* current end of buffer */
  23.  
  24. static boolean comment_ateol;    /* does comment start & end at end of a line? */
  25. static boolean comment_remember;/* remember contents of current comment? */
  26. static boolean comment_caller;    /* state we were in before */
  27.  
  28. typedef struct {
  29. #ifdef FLEX_SCANNER
  30.     YY_BUFFER_STATE buffer;
  31. #else
  32.     FILE *fp;
  33. #endif
  34.     char *file;
  35.     int line_num;
  36. } IncludeStack;
  37.  
  38. static int inc_depth = 0;            /* include nesting level */
  39. static IncludeStack inc_stack[MAX_INC_DEPTH];    /* stack of included files */
  40.  
  41. static void update_line_num _((void));
  42. static void do_include _((char *filename, int sysinc));
  43. static void new_dynbuf();
  44. static void add_dynbuf _((int c));
  45. static char *return_dynbuf();
  46. static void get_cpp_directive();
  47. static boolean process_line_directive _((const char *new_file));
  48.  
  49. /*
  50.  * The initial comment processing is done primarily by the rather complex lex
  51.  * rules in the various comment start states, the main functions being removal
  52.  * of leading *'s, /'s and whitespace on a line, the removal of trailing
  53.  * whitespace on a line, and the coalescing of separate comments on adjacent
  54.  * lines.  The remaining bits of textual content are collected by the following
  55.  * functions, which simply strip leading and trailing blank lines.
  56.  */
  57. void start_comment _((boolean ateol));
  58. int end_comment _((boolean ateol));
  59. void add_comment _((const char *s));
  60. void newline_comment _((void));
  61.  
  62. static int comment_newlines;    /* number of newlines hit in comment */
  63. static boolean comment_started;    /* have preceeding empty lines been skipped */
  64.  
  65. #ifdef FLEX_SCANNER    /* flex uses YY_START instead of YYSTATE */
  66. #define YYSTATE    YY_START
  67. #ifndef YY_START    /* flex 2.3.8 & before didn't support it at all */
  68. #define YY_START ((yy_start - 1) / 2)
  69. #endif
  70. #endif
  71.  
  72. #undef yywrap    /* for flex */
  73.  
  74. /* SKIP        skipping value assignment in an enum */
  75. %}
  76.  
  77. WS        [ \t]
  78. WLF        [ \t\n\f]*
  79. LETTER        [A-Za-z_]
  80. DIGIT        [0-9]
  81. ID        {LETTER}({LETTER}|{DIGIT})*
  82. STRING        \"(\\.|\\\n|[^"\\])*\"
  83. QUOTED        ({STRING}|\'(\\\'|[^'\n])*\'|\\.)
  84.  
  85. %p 5000
  86. %e 2000
  87. %s CPP1 INIT1 INIT2 CURLY SQUARE LEXYACC SKIP COMMENT COMMLINE CPPCOMMENT
  88. %%
  89.  
  90.  
  91. <LEXYACC>^"%%"        {
  92.                 if (++ly_count >= 2)
  93.                 BEGIN INITIAL;
  94.             }
  95. <LEXYACC>^"%{"        BEGIN INITIAL;
  96. <LEXYACC>{QUOTED}    update_line_num();
  97. <LEXYACC>.        ;
  98. <INITIAL>^"%}"        BEGIN LEXYACC;
  99.  
  100. <INITIAL>^{WS}*#{WS}*    BEGIN CPP1;
  101.  
  102. <CPP1>define{WS}+{ID}    {
  103.                 sscanf(yytext, "define %s", buf);
  104.                 get_cpp_directive();
  105.                 new_symbol(typedef_names, buf, DS_EXTERN);
  106.             }
  107.  
  108. <CPP1>include{WS}*\"[^"]+\"     {
  109.                 sscanf(yytext, "include \"%[^\"]\"", buf);
  110.                 get_cpp_directive();
  111.                 do_include(buf, FALSE);
  112.             }
  113. <CPP1>include{WS}*\<[^>]+\>    {
  114.                 sscanf(yytext, "include <%[^>]>", buf);
  115.                 get_cpp_directive();
  116.                 do_include(buf, TRUE);
  117.             }
  118.  
  119. <CPP1>line{WS}+[0-9]+{WS}+\".*$  {
  120.                 sscanf(yytext, "line %d \"%[^\"]\"",
  121.                     &line_num, buf);
  122.                 --line_num;
  123.                 BEGIN INITIAL;
  124.  
  125.                 if (process_line_directive(buf))
  126.                 return T_BASEFILE;
  127.             }
  128. <CPP1>[0-9]+{WS}+\".*$    {
  129.                 sscanf(yytext, "%d \"%[^\"]\"", &line_num, buf);
  130.                 --line_num;
  131.                 BEGIN INITIAL;
  132.  
  133.                 if (process_line_directive(buf))
  134.                 return T_BASEFILE;
  135.             }
  136. <CPP1>[0-9]+.*$        {
  137.                 sscanf(yytext, "%d ", &line_num);
  138.                 --line_num;
  139.                 BEGIN INITIAL;
  140.             }
  141.  
  142. <CPP1>.            get_cpp_directive();
  143.  
  144. <INITIAL>"("        return '(';
  145. <INITIAL>")"        return ')';
  146. <INITIAL>"*"        return '*';
  147. <INITIAL,SKIP>","    {
  148.                 BEGIN INITIAL;    /* stop skipping */
  149.                 return ',';
  150.             }
  151. <INITIAL>";"        return ';';
  152. <INITIAL>"..."        return T_ELLIPSIS;
  153. <INITIAL>{STRING}    { update_line_num(); return T_STRING_LITERAL; }
  154.  
  155. <INITIAL>auto        return T_AUTO;
  156. <INITIAL>extern        return T_EXTERN;
  157. <INITIAL>register    return T_REGISTER;
  158. <INITIAL>static        return T_STATIC;
  159. <INITIAL>typedef    return T_TYPEDEF;
  160. <INITIAL>char        return T_CHAR;
  161. <INITIAL>double        return T_DOUBLE;
  162. <INITIAL>float        return T_FLOAT;
  163. <INITIAL>int        return T_INT;
  164. <INITIAL>void        return T_VOID;
  165. <INITIAL>long        return T_LONG;
  166. <INITIAL>short        return T_SHORT;
  167. <INITIAL>signed        return T_SIGNED;
  168. <INITIAL>__signed__    return T_SIGNED;
  169. <INITIAL>__signed    return T_SIGNED;
  170. <INITIAL>unsigned    return T_UNSIGNED;
  171. <INITIAL>enum        { enum_state = KEYWORD; return T_ENUM; }
  172. <INITIAL>struct        return T_STRUCT;
  173. <INITIAL>union        return T_UNION;
  174. <INITIAL>const        return T_CONST;
  175. <INITIAL>__const__    return T_CONST;
  176. <INITIAL>__const    return T_CONST;
  177. <INITIAL>volatile    return T_VOLATILE;
  178. <INITIAL>__volatile__    return T_VOLATILE;
  179. <INITIAL>__volatile    return T_VOLATILE;
  180. <INITIAL>inline        return T_INLINE;
  181. <INITIAL>__inline__    return T_INLINE;
  182. <INITIAL>__inline    return T_INLINE;
  183. <INITIAL>cdecl        return T_CDECL;
  184. <INITIAL>far        return T_FAR;
  185. <INITIAL>huge        return T_HUGE;
  186. <INITIAL>interrupt    return T_INTERRUPT;
  187. <INITIAL>near        return T_NEAR;
  188. <INITIAL>pascal        return T_PASCAL;
  189. <INITIAL>__extension__    ;
  190.  
  191. <INITIAL>{ID}        {
  192.                 if (enum_state == BRACES)    BEGIN SKIP;
  193.                 yylval.text = strduplicate(yytext);
  194.                 if (is_typedef_name(yytext))
  195.                 return T_TYPEDEF_NAME;
  196.                 else
  197.                 return T_IDENTIFIER;
  198.             }
  199.  
  200. <INITIAL>"="        BEGIN INIT1;
  201. <INIT1>"{"        { curly = 1; BEGIN INIT2; }
  202. <INIT1>[,;]        {
  203.                 unput(yytext[yyleng-1]);
  204.                 BEGIN INITIAL;
  205.                 return T_INITIALIZER;
  206.             }
  207. <INIT1>{QUOTED}        update_line_num();
  208. <INIT1>.        ;
  209.  
  210. <INIT2>"{"        ++curly;
  211. <INIT2>"}"        {
  212.                 if (--curly == 0) {
  213.                 BEGIN INITIAL;
  214.                 return T_INITIALIZER;
  215.                 }
  216.             }
  217. <INIT2>{QUOTED}        update_line_num();
  218. <INIT2>.        ;
  219.  
  220. <INITIAL,SKIP>"{"    {
  221.                 if (enum_state == KEYWORD)
  222.                 {
  223.                 enum_state = BRACES;
  224.                 return '{';
  225.                 }
  226.                 else
  227.                 {
  228.                 curly = 1;
  229.                 BEGIN CURLY;
  230.                 }
  231.             }
  232. <INITIAL,SKIP>"}"    {
  233.                  BEGIN INITIAL;    /* stop skipping */
  234.                 return '}';
  235.             }
  236.  
  237. <CURLY>"{"        ++curly;
  238. <CURLY>"}"        {
  239.                 if (--curly == 0) {
  240.                 BEGIN INITIAL;
  241.                 return T_BRACES;
  242.                 }
  243.             }
  244. <CURLY,SKIP>{QUOTED}    update_line_num();
  245. <CURLY,SKIP>.        ;
  246.  
  247. <INITIAL>"["        {
  248.               new_dynbuf(); add_dynbuf(yytext[0]);
  249.               square = 1; BEGIN SQUARE;
  250.             }
  251. <SQUARE>"["        { ++square; add_dynbuf(yytext[0]); }
  252. <SQUARE>"]"        {
  253.                 add_dynbuf(yytext[0]);
  254.                 if (--square == 0) {
  255.                 BEGIN INITIAL;
  256.                 yylval.text = return_dynbuf();
  257.                 return T_BRACKETS;
  258.                 }
  259.             }
  260. <SQUARE>{QUOTED}|.    {
  261.                 int i;
  262.                 for (i = 0; i < yyleng; ++i)
  263.                 {
  264.                 if (yytext[i] == '\n') ++line_num;
  265.                 add_dynbuf(yytext[i]);
  266.                 }
  267.             }
  268.  
  269. <INITIAL,INIT1,INIT2,CURLY,SQUARE,LEXYACC,SKIP>^{WS}*"/*""*"*{WS}+    {
  270.                 comment_caller = YYSTATE;
  271.                 start_comment(FALSE);
  272.                 BEGIN COMMENT; }
  273. <INITIAL,INIT1,INIT2,CURLY,SQUARE,LEXYACC,SKIP>^{WS}*"/*""*"*[^/]    {
  274.                 yyless(yyleng-1);
  275.                 comment_caller = YYSTATE;
  276.                 start_comment(FALSE);
  277.                 BEGIN COMMENT; }
  278. <INITIAL,INIT1,INIT2,CURLY,SQUARE,LEXYACC,SKIP>"/*""*"*{WS}+        {
  279.                 comment_caller = YYSTATE;
  280.                 start_comment(TRUE);
  281.                 BEGIN COMMENT; }
  282. <INITIAL,INIT1,INIT2,CURLY,SQUARE,LEXYACC,SKIP>"/*""*"*[^/]        {
  283.                 yyless(yyleng-1);
  284.                 comment_caller = YYSTATE;
  285.                 start_comment(TRUE);
  286.                 BEGIN COMMENT; }
  287. <COMMLINE>^{WS}*"/"+{WS}*    |
  288. <COMMLINE>^{WS}*"/"*"*"*{WS}+    BEGIN COMMENT;
  289. <COMMLINE>^{WS}*"/"*"*"*[^/]    { yyless(yyleng-1); BEGIN COMMENT; }
  290. <COMMLINE>.            { yyless(0); BEGIN COMMENT; }
  291. <COMMLINE>\n            newline_comment();
  292. <COMMENT>{WS}*"*"+"/"{WS}*\n{WS}*"/*""*"*{WS}+    newline_comment();
  293. <COMMENT>{WS}*"*"+"/"{WS}*\n{WS}*"/*""*"*[^/]    {
  294.                 yyless(yyleng-1); newline_comment(); }
  295. <COMMENT>{WS}*"*"+"/"{WS}*$    { int ret = end_comment(TRUE);
  296.                   BEGIN comment_caller;
  297.                   if (ret)    return ret; }
  298. <COMMENT>{WS}*"*"+"/"        { int ret = end_comment(FALSE);
  299.                   BEGIN comment_caller;
  300.                   if (ret)    return ret; }
  301. <COMMENT>[^*\n \t]*        |
  302. <COMMENT>{WS}*            |
  303. <COMMENT>"*"+[^*/\n]*        add_comment(yytext);
  304. <COMMENT>{WS}*\n        { newline_comment(); BEGIN COMMLINE; }
  305.  
  306. <INITIAL,INIT1,INIT2,CURLY,SQUARE,LEXYACC,SKIP>^{WS}*"//"[/*]*{WS}*    {
  307.                 comment_caller = YYSTATE;
  308.                 start_comment(FALSE);
  309.                 BEGIN CPPCOMMENT; }
  310. <INITIAL,INIT1,INIT2,CURLY,SQUARE,LEXYACC,SKIP>"//"[/*]*{WS}*        {
  311.                 comment_caller = YYSTATE;
  312.                 start_comment(TRUE);
  313.                 BEGIN CPPCOMMENT; }
  314. <CPPCOMMENT>.*            add_comment(yytext);
  315. <CPPCOMMENT>\n{WS}*"//"[/*]*{WS}*    newline_comment();
  316. <CPPCOMMENT>\n            { int ret = end_comment(TRUE);
  317.                   ++line_num;
  318.                   BEGIN comment_caller;
  319.                   if (ret)    return ret; }
  320.  
  321. [ \t\f]+        ;
  322. \n            ++line_num;
  323.  
  324. .            {
  325.                 output_error();
  326.                 fprintf(stderr, "bad character '%c'\n", yytext[0]);
  327.             }
  328. %%
  329.  
  330. /* If the matched text contains any new line characters, then update the
  331.  * current line number.
  332.  */
  333. static void
  334. update_line_num ()
  335. {
  336.     char *p = yytext;
  337.     while (*p != '\0') {
  338.     if (*p++ == '\n')
  339.         line_num++;
  340.     }
  341. }
  342.  
  343. void start_comment(ateol)
  344. boolean ateol;    /* does comment start at end of an existing line? */
  345. {
  346.     comment_remember =    (comment_caller == INITIAL || comment_caller == SKIP) &&
  347.             (inbasefile || enum_state == BRACES);
  348.  
  349.     if (comment_remember)
  350.     {
  351.     comment_ateol = ateol;
  352.     comment_newlines = 0;
  353.     comment_started = FALSE;
  354.     new_dynbuf();
  355.     }
  356. }
  357.  
  358. int end_comment(ateol)
  359. boolean ateol;    /* does comment end at end of line? */
  360. {
  361.     if (comment_remember)
  362.     {
  363.     if (!ateol)    comment_ateol = FALSE;
  364.     yylval.text = return_dynbuf();
  365.     if (yylval.text[0] == '\0')
  366.     {
  367.         free(yylval.text);
  368.         return 0;
  369.     }
  370. #ifdef DEBUG
  371.     fprintf(stderr,"`%s'\n", yylval.text);
  372. #endif
  373.     return comment_ateol ? T_EOLCOMMENT : T_COMMENT;
  374.     }
  375.     return 0;
  376. }
  377.  
  378. /* add a newline to the comment, deferring to remove trailing ones */
  379. void newline_comment()
  380. {
  381.     ++line_num;
  382.  
  383.     if (!comment_remember || !comment_started)    return;
  384.  
  385.     comment_newlines++;
  386. }
  387.  
  388. /* add some true text to the comment */
  389. void add_comment(s)
  390. const char *s;
  391. {
  392. #ifdef DEBUG
  393.     fprintf(stderr,"`%s'\n", s);
  394. #endif
  395.     if (!comment_remember)    return;
  396.  
  397.     comment_started = TRUE;
  398.  
  399.     while (comment_newlines)
  400.     {
  401.     add_dynbuf('\n');
  402.     comment_newlines--;
  403.     }
  404.  
  405.     while(*s)
  406.     add_dynbuf(*s++);
  407. }
  408.  
  409. /* Scan rest of preprocessor statement.
  410.  */
  411. static void
  412. get_cpp_directive ()
  413. {
  414.     int c, lastc = '\0';
  415.  
  416.     while ((c = input()) > 0) {
  417.     switch (c) {
  418.     case '\n':
  419.         if (lastc != '\\') {
  420.         unput(c);
  421.         BEGIN INITIAL;
  422.         return;
  423.         }
  424.         line_num++;
  425.         break;
  426.     case '*':
  427.         if (lastc == '/')
  428.         {
  429.         /* might be able to attach comments to #defines one day */
  430.         comment_caller = YYSTATE;
  431.         start_comment(TRUE);
  432.         BEGIN COMMENT;
  433.         }
  434.         break;
  435.     case '/':
  436.         if (lastc == '/')
  437.         {
  438.         /* might be able to attach comments to #defines one day */
  439.         comment_caller = YYSTATE;
  440.         start_comment(TRUE);
  441.         BEGIN CPPCOMMENT;
  442.         }
  443.         break;
  444.     }
  445.     lastc = c;
  446.     }
  447. }
  448.  
  449. /* Process include directive.
  450.  */
  451. static void
  452. do_include (filename, sysinc)
  453. char *filename;        /* file name */
  454. int sysinc;        /* 1 = do not search current directory */
  455. {
  456.     char path[MAX_TEXT_LENGTH];
  457.     int i;
  458.     FILE *fp;
  459.     IncludeStack *sp;
  460.  
  461.     if (inc_depth >= MAX_INC_DEPTH) {
  462.     output_error();
  463.     fprintf(stderr, "includes too deeply nested\n");
  464.     return;
  465.     }
  466.  
  467.     for (i = sysinc != 0; i < num_inc_dir; ++i) {
  468.      strcpy(path, inc_dir[i]);
  469.      strcat(path, filename);
  470.      if ((fp = fopen(path, "r")) != NULL) {
  471.          sp = inc_stack + inc_depth;
  472.          sp->file = cur_file;
  473.          sp->line_num = line_num;
  474. #ifdef FLEX_SCANNER
  475.          sp->buffer = YY_CURRENT_BUFFER;
  476.          yy_switch_to_buffer(yy_create_buffer(fp, YY_BUF_SIZE));
  477. #else
  478.          sp->fp = yyin;
  479.          yyin = fp;
  480. #endif
  481.          ++inc_depth;
  482.          cur_file = strduplicate(filename);
  483.          line_num = 0;
  484.          return;
  485.      }
  486.     }
  487. }
  488.  
  489. /* returns TRUE if the basefile status has changed */
  490. static boolean process_line_directive(new_file)
  491. const char *new_file;
  492. {
  493.     boolean new_stdin;
  494.  
  495.     /* strip leading ./ that Sun acc prepends */
  496.     if (!strncmp(new_file,"./",2))
  497.     new_file += 2;
  498.  
  499.     new_stdin = new_file[0] == '\0' || !strcmp(new_file,"stdin");
  500.  
  501.     /* return BASEFILE token only when file changes */
  502.     if ((cur_file == NULL && !new_stdin) ||
  503.     (cur_file != NULL &&strcmp(cur_file, new_file)))
  504.     {
  505.     safe_free(cur_file);
  506.     cur_file = new_stdin ? NULL : strduplicate(new_file);
  507.     yylval.boolean = basefile ? !strcmp(cur_file,basefile) :
  508.                     cur_file == basefile;
  509.     return TRUE;
  510.     }
  511.     return FALSE;
  512. }
  513.  
  514. /* When the end of the current input file is reached, pop any
  515.  * nested includes.
  516.  */
  517. int
  518. yywrap ()
  519. {
  520.     IncludeStack *sp;
  521.  
  522.     if (inc_depth > 0) {
  523.     --inc_depth;
  524.     sp = inc_stack + inc_depth;
  525.     fclose(yyin);
  526. #ifdef FLEX_SCANNER
  527.     yy_delete_buffer(YY_CURRENT_BUFFER);
  528.     yy_switch_to_buffer(sp->buffer);
  529. #else
  530.     yyin = sp->fp;
  531. #endif
  532.     safe_free(cur_file);
  533.     cur_file = sp->file;
  534.     line_num = sp->line_num + 1;
  535.     return 0;
  536.     } else {
  537.     return 1;
  538.     }
  539. }
  540.  
  541.  
  542. static void new_dynbuf()
  543. {
  544.     if ((dynbuf = malloc(dynbuf_size = DYNBUF_ALLOC)) == 0)
  545.     outmem();
  546.     
  547.     dynbuf_current = 0;
  548. }
  549.  
  550. static void add_dynbuf(c)
  551. int c;
  552. {
  553.     if (dynbuf_current == dynbuf_size &&
  554.     ((dynbuf = realloc(dynbuf,dynbuf_size += DYNBUF_ALLOC)) == 0))
  555.         outmem();
  556.     
  557.     dynbuf[dynbuf_current++] = c;
  558. }
  559.  
  560. static char *return_dynbuf()
  561. {
  562.     add_dynbuf('\0');
  563.  
  564.     /* chop it back to size */
  565.     if ((dynbuf = realloc(dynbuf,dynbuf_current)) == 0)
  566.     outmem();
  567.  
  568.     return dynbuf;    
  569. }
  570.  
  571. /* Output an error message along with the current line number in the
  572.  * source file.
  573.  */
  574. void
  575. output_error ()
  576. {
  577.     errors++;
  578.     fprintf(stderr, "%s:%d: ", cur_file ? cur_file : "stdin", line_num);
  579. }
  580.