home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / cproto.zip / cproto46 / lex.l < prev    next >
Text File  |  1996-04-13  |  24KB  |  986 lines

  1. %{
  2. /* $Id: lex.l,v 4.5 1996/04/13 04:29:18 cthuang Exp $
  3.  *
  4.  * Lexical analyzer for C function prototype generator
  5.  *
  6.  *    This is designed to parse lexically at the top level (e.g., of extern
  7.  *    objects such as procedures).  The corresponding yacc-grammar expects
  8.  *    that curly-braces (for function bodies) are recognized as a single
  9.  *    token, BRACES.  Similarly, square-brackets and their contents are
  10.  *    passed back as BRACKETS.
  11.  *
  12.  *    Assignments at the top level are data-initialization statements.
  13.  *    These are returned as INITIALIZER.
  14.  *
  15.  *    The logic here recognizes tokens inside curly-braces, but does not
  16.  *    pass them back to the grammar.
  17.  *
  18.  * Apollo extensions:
  19.  *    "&" is ignored when creating lint-libraries, because we ignore
  20.  *    expressions of all kinds.  Note that function-prototypes may use "&" to
  21.  *    denote reference-parameters.  By ignoring that as well, we make the
  22.  *    output compatible with lint (kludge).
  23.  *
  24.  *    Similarly, ignore "std_$call", since it is not compatible with lint.
  25.  *
  26.  *    CPP_INLINE handles a special case of the Apollo CC 6.7 compiler that
  27.  *    uses inline attribute declarations, e.g.
  28.  *
  29.  *        int    foo #attribute[aligned(1)];
  30.  *
  31.  *    In CC 6.8 this behavior is hidden by a macro.
  32.  *
  33.  * VAX/VMS extensions:
  34.  *    Treat the keywords 'globalref', etc., as 'extern'.
  35.  *
  36.  *    The keywords 'noshare' and 'readonly' are type-qualifiers.
  37.  *
  38.  * GCC extensions:
  39.  *    The keywords '__attribute__', '__inline', '__inline__', '__signed',
  40.  *    '__signed__'.
  41.  */
  42.  
  43. #define    result(nn)    count(); if (!brackets && unnested()) return(nn)
  44.  
  45. #define    is_IDENTIFIER        save_text_offset();\
  46.                 return type_of_name(yytext);
  47.  
  48. #if !OPT_LINTLIBRARY
  49. #define gcc_attribute   absorb_special /* otherwise, we don't care */
  50. #endif
  51.  
  52. #ifdef    apollo
  53. #define    apollo_keyword
  54. #define    apollo_special    absorb_special()
  55. #else
  56. #define    apollo_keyword    is_IDENTIFIER
  57. #define    apollo_special    is_IDENTIFIER
  58. #endif
  59.  
  60. #ifdef    vms
  61. #define    vms_extern    save_text_offset(); return(T_EXTERN);
  62. #define    vms_keyword    save_text_offset();
  63. #else    /* unix */
  64. #define    vms_extern    is_IDENTIFIER
  65. #define    vms_keyword    is_IDENTIFIER
  66. #endif    /* vms/unix */
  67.  
  68. char *    varargs_str;        /* save printflike/scanflike text */
  69. int    varargs_num;        /* code to save "VARARGS" */
  70. int    debug_trace;        /* true if we trace token-level stuff */
  71. char    base_file[BUFSIZ];    /* top-level file name */
  72.  
  73. static int save_cpp;    /* true if cpp-text within curly braces */
  74. static int in_cpp;    /* true while we are within cpp-text */
  75. static int curly;    /* number of curly brace nesting levels */
  76. static int ly_count;    /* number of occurances of %% */
  77.  
  78. #ifdef FLEX_SCANNER
  79. /* flex scanner state */
  80. static YY_BUFFER_STATE buffer_stack[MAX_INC_DEPTH];
  81. #endif
  82.  
  83. static int inc_depth;                /* include nesting level */
  84. static IncludeStack inc_stack[MAX_INC_DEPTH];    /* stack of included files */
  85. static SymbolTable *included_files;        /* files already included */
  86.  
  87. static int  type_of_name      ARGS((char *name));
  88. static void startCpp          ARGS((int level));
  89. static void finishCpp         ARGS((void));
  90. #if defined(apollo) || !OPT_LINTLIBRARY
  91. static void absorb_special    ARGS((void));
  92. #endif
  93. #if OPT_LINTLIBRARY
  94. static void gcc_attribute     ARGS((void));
  95. #endif
  96. static void update_line_num   ARGS((void));
  97. static void save_text         ARGS((void));
  98. static void save_text_offset  ARGS((void));
  99. static void get_quoted        ARGS((void));
  100. static void get_comment       ARGS((void));
  101. static void get_cpp_directive ARGS((char *dest, unsigned n));
  102. static void do_include        ARGS((char *f));
  103. static void include_file      ARGS((char *name, int convert));
  104. static void put_file          ARGS((FILE *outf));
  105. static void put_quoted        ARGS((int c));
  106.  
  107. #if OPT_LINTLIBRARY
  108. static int decipher_comment   ARGS((char *keyword, int len));
  109. #endif
  110.  
  111. #ifdef yywrap
  112. #undef yywrap
  113. #endif
  114. int yywrap ARGS((void));
  115. %}
  116.  
  117. WS        [ \t]
  118. LETTER        [A-Za-z$_]
  119. DIGIT        [0-9]
  120. ID        {LETTER}({LETTER}|{DIGIT})*
  121. QUOTE        [\"\']
  122.  
  123. %s CPP1 INIT1 INIT2 CURLY LEXYACC ASM CPP_INLINE
  124. %%
  125.  
  126. \n            { save_text(); cur_file->line_num++;
  127.                 cur_declarator = NULL; }
  128.  
  129. "/*"            { save_text(); get_comment(); }
  130. "//".*$         save_text();
  131.  
  132. <INITIAL>"&"        { save_text(); return '&'; /* C++ ref-variable? */ }
  133.  
  134. <LEXYACC>^"%%"        { save_text(); if (++ly_count >= 2) BEGIN INITIAL; }
  135. <LEXYACC>^"%{"        { save_text(); BEGIN INITIAL; }
  136. <LEXYACC>{QUOTE}    get_quoted();
  137. <LEXYACC>.        save_text();
  138. <INITIAL>^"%}"        { save_text(); BEGIN LEXYACC; }
  139.  
  140. <INITIAL>#{WS}*     { save_text(); startCpp(0); }
  141. <INITIAL>"??="{WS}*     { save_text(); startCpp(0); }
  142.  
  143. <CPP1>attribute        { BEGIN CPP_INLINE; /* apollo */}
  144. <CPP1>options        { BEGIN CPP_INLINE; /* apollo */}
  145. <CPP_INLINE>[^;]*    finishCpp();
  146.  
  147. <CPP1>define{WS}+{ID}    {
  148.                 char name[MAX_TEXT_SIZE], value[MAX_TEXT_SIZE];
  149.  
  150.                 save_text();
  151.                 sscanf(yytext, "define %s", name);
  152.                 get_cpp_directive(buf, sizeof(buf));
  153.                 sscanf(buf, "%s", value);
  154.                 new_symbol(define_names, name, value, DS_NONE);
  155.             }
  156.  
  157. <CPP1>include{WS}*    {
  158.                 save_text();
  159.                 get_cpp_directive(buf, sizeof(buf));
  160.                 if (buf[0] != '"' && buf[0] != '<') {
  161.                 Symbol *sym = find_symbol(define_names, buf);
  162.                 if (sym != NULL && sym->value != NULL) {
  163.                     strcpy(buf, sym->value);
  164.                 } else {
  165.                     buf[0] = '\0';
  166.                 }
  167.                 }
  168.                 if (buf[0] != '\0')
  169.                 do_include(buf);
  170.             }
  171.  
  172. <CPP1>line{WS}+[0-9]+{WS}+\".*$  {
  173.                 save_text();
  174.                 sscanf(yytext, "line %d \"%[^\"]\"",
  175.                  &cur_file->line_num, cur_file->file_name);
  176.                 cur_file->line_num--;
  177.                 track_in();
  178.                 finishCpp();
  179.             }
  180. <CPP1>[0-9]+{WS}+\".*$  {
  181.                 save_text();
  182.                 sscanf(yytext, "%d \"%[^\"]\"", &cur_file->line_num,
  183.                  cur_file->file_name);
  184.                 cur_file->line_num--;
  185.                 track_in();
  186.                 finishCpp();
  187.             }
  188. <CPP1>[0-9]+.*$     {
  189.                 save_text();
  190.                 sscanf(yytext, "%d ", &cur_file->line_num);
  191.                 cur_file->line_num--;
  192.                 track_in();
  193.                 finishCpp();
  194.             }
  195.  
  196. <CPP1>.         { save_text(); get_cpp_directive(NULL, 0); }
  197.  
  198. <INITIAL>"("        { save_text_offset(); return '('; }
  199. <INITIAL>")"        {
  200.                 save_text();
  201.                 if (cur_file->convert)
  202.                 cur_file->begin_comment =
  203.                  ftell(cur_file->tmp_file);
  204.                 return ')';
  205.             }
  206. <INITIAL>"*"        { save_text_offset(); return '*'; }
  207. <INITIAL>[,;]        {
  208.                 save_text();
  209.                 if (cur_file->convert)
  210.                 cur_file->begin_comment =
  211.                  ftell(cur_file->tmp_file);
  212.                 return yytext[0];
  213.             }
  214. <INITIAL>"..."        { save_text(); return T_ELLIPSIS; }
  215. <INITIAL>\"        {
  216.                 get_quoted();
  217.                 return T_STRING_LITERAL;
  218.             }
  219.  
  220. <INITIAL>asm        { save_text(); BEGIN ASM; return T_ASM; }
  221. <ASM>"("        save_text();
  222. <ASM>")"        { save_text(); BEGIN INITIAL; return T_ASMARG; }
  223. <ASM>{QUOTE}         get_quoted();
  224. <ASM>.             save_text();
  225.  
  226. <INITIAL>__?based[^(]*\([^)]*\)    { save_text_offset(); return T_TYPE_QUALIFIER; }
  227.  
  228. <INITIAL>auto        { save_text_offset(); return T_AUTO; }
  229. <INITIAL>extern     { save_text_offset(); return T_EXTERN; }
  230. <INITIAL>register    { save_text_offset(); return T_REGISTER; }
  231. <INITIAL>static     { save_text_offset(); return T_STATIC; }
  232. <INITIAL>typedef    { save_text_offset(); return T_TYPEDEF; }
  233. <INITIAL>inline     { save_text_offset(); return T_INLINE; }
  234. <INITIAL>char        { save_text_offset(); return T_CHAR; }
  235. <INITIAL>double     { save_text_offset(); return T_DOUBLE; }
  236. <INITIAL>float        { save_text_offset(); return T_FLOAT; }
  237. <INITIAL>int        { save_text_offset(); return T_INT; }
  238. <INITIAL>void        { save_text_offset(); return T_VOID; }
  239. <INITIAL>long        { save_text_offset(); return T_LONG; }
  240. <INITIAL>short        { save_text_offset(); return T_SHORT; }
  241. <INITIAL>signed     { save_text_offset(); return T_SIGNED; }
  242. <INITIAL>unsigned    { save_text_offset(); return T_UNSIGNED; }
  243. <INITIAL>enum        { save_text_offset(); return T_ENUM; }
  244. <INITIAL>struct     { save_text_offset(); return T_STRUCT; }
  245. <INITIAL>union        { save_text_offset(); return T_UNION; }
  246. <INITIAL>va_dcl        { save_text_offset(); return T_VA_DCL; }
  247.  
  248. <INITIAL>__signed     { save_text_offset(); return T_SIGNED; }
  249. <INITIAL>__signed__     { save_text_offset(); return T_SIGNED; }
  250. <INITIAL>__inline     { save_text_offset(); return T_INLINE; }
  251. <INITIAL>__inline__     { save_text_offset(); return T_INLINE; }
  252. <INITIAL>__attribute__    { gcc_attribute(); }
  253.  
  254. <INITIAL>globalvalue    { vms_extern; }
  255. <INITIAL>globalref    { vms_extern; }
  256. <INITIAL>globaldef    { vms_extern; }
  257.  
  258. <INITIAL>"std_$call"    { apollo_keyword; }
  259. <INITIAL>"__attribute"    { apollo_special; }
  260.  
  261. <INITIAL>{ID}        { is_IDENTIFIER }
  262.  
  263. <INITIAL>\[[^\]]*\]    {
  264.                 /* This can't handle the case where a comment
  265.                  * containing a ] appears between the brackets.
  266.                  */
  267.                 save_text_offset();
  268.                 update_line_num();
  269.                 return T_BRACKETS;
  270.             }
  271. <INITIAL>"??("[^?]*"??)"    {
  272.                 save_text_offset();
  273.                 update_line_num();
  274.                 return T_BRACKETS;
  275.             }
  276.  
  277. <INITIAL>"="        { save_text(); BEGIN INIT1; return '='; }
  278. <INIT1>"{"        { save_text(); curly = 1; BEGIN INIT2; }
  279. <INIT1>[,;]        {
  280.                 unput(yytext[yyleng-1]);
  281.                 BEGIN INITIAL;
  282.                 return T_INITIALIZER;
  283.             }
  284. <INIT1>{QUOTE}        get_quoted();
  285. <INIT1>.        save_text();
  286.  
  287. <INIT2>"{"        { save_text(); ++curly; }
  288. <INIT2>"}"        {
  289.                 save_text();
  290.                 if (--curly == 0) {
  291.                 BEGIN INITIAL;
  292.                 return T_INITIALIZER;
  293.                 }
  294.             }
  295. <INIT2>{QUOTE}        get_quoted();
  296. <INIT2>.        save_text();
  297.  
  298. <INITIAL>"{"        {
  299.                 save_text();
  300.                 curly = 1;
  301.                 return_val =
  302.                 returned_at = FALSE;
  303.                 BEGIN CURLY;
  304.                 return T_LBRACE;
  305.             }
  306. <CURLY>"{"        { save_text(); ++curly; }
  307. <CURLY>"}"        {
  308.                 save_text();
  309.                 if (--curly == 0) {
  310.                 BEGIN INITIAL;
  311.                 return T_MATCHRBRACE;
  312.                 }
  313.             }
  314. <CURLY>{QUOTE}        get_quoted();
  315. <CURLY>"return"        { save_text(); returned_at = TRUE; }
  316. <CURLY>";"        { save_text(); returned_at = FALSE; }
  317. <CURLY>#{WS}*         { save_text(); startCpp(1); }
  318. <CURLY>"??="{WS}*     { save_text(); startCpp(1); }
  319. <CURLY>.        { save_text(); return_val |= returned_at; }
  320.  
  321. [ \r\t\f]+        save_text();
  322. .            {
  323.                 save_text();
  324.                 put_error();
  325.                 fprintf(stderr, "bad character '%c'\n", yytext[0]);
  326.             }
  327. %%
  328.  
  329. static void
  330. startCpp (level)
  331. int level;
  332. {
  333.     save_cpp = level;
  334.     in_cpp = TRUE;
  335.     BEGIN CPP1;
  336. }
  337.  
  338. static void
  339. finishCpp()
  340. {
  341.     in_cpp = FALSE;
  342.     if (save_cpp)
  343.         BEGIN CURLY;
  344.     else
  345.     BEGIN INITIAL;
  346. }
  347.  
  348. /*
  349.  * Skip over embedded __attribute/__attribute_ syntax.
  350.  */
  351. #if defined(apollo) || !OPT_LINTLIBRARY
  352. static void
  353. absorb_special ()
  354. {
  355.     int    c;
  356.     int    nest    = 0;
  357.     while ((c = input()) > 0) {
  358.     if (c == '(')
  359.         nest++;
  360.     else if (c == ')') {
  361.         if (--nest <= 0)
  362.         break;
  363.     }
  364.     }
  365. }
  366. #endif
  367.  
  368. #if OPT_LINTLIBRARY
  369. /*
  370.  * This recognizes some of the special attribute macros defined by gcc:
  371.  *    noreturn
  372.  *    format(printf,n,m)
  373.  *    format(scanf,n,m)
  374.  * and uses that information to construct equivalent lint-library text.
  375.  * (It's a distinct piece of code from the 'absorb_special()' function to
  376.  * avoid spurious matches with non-gcc compilers).
  377.  */
  378. static void
  379. gcc_attribute ()
  380. {
  381.     int    c, num1, num2;
  382.     int    nest = 0;
  383.     int    len = 0;
  384.     char bfr[BUFSIZ];
  385.  
  386.     while ((c = input()) > 0) {
  387.     if (len < sizeof(bfr)-1 && !isspace(c))
  388.         bfr[len++] = c;
  389.     if (c == '(')
  390.         nest++;
  391.     else if (c == ')') {
  392.         if (--nest <= 0)
  393.         break;
  394.     }
  395.     }
  396.     bfr[len] = '\0';
  397.     if (!strcmp(bfr, "((noreturn))")) {
  398.     exitlike_func = TRUE;
  399.     } else if (sscanf(bfr, "((format(printf,%d,%d)))", &num1, &num2) == 2) {
  400.     (void)sprintf(bfr, "PRINTFLIKE%d", varargs_num = num1);
  401.     varargs_str = xstrdup(bfr);
  402.     } else if (sscanf(bfr, "((format(scanf,%d,%d)))", &num1, &num2) == 2) {
  403.     (void)sprintf(bfr, "SCANFLIKE%d", varargs_num = num1);
  404.     varargs_str = xstrdup(bfr);
  405.     }
  406. }
  407. #endif
  408.  
  409. /* Decode the current token according to the type-of-name
  410.  */
  411. static int
  412. type_of_name (name)
  413. char *name;
  414. {
  415.     if (find_symbol(type_qualifiers, name) != NULL)
  416.     return T_TYPE_QUALIFIER;
  417.     else if (find_symbol(typedef_names, name) != NULL)
  418.     return T_TYPEDEF_NAME;
  419.     else if (find_symbol(define_names, name) != NULL)
  420.     return T_DEFINE_NAME;
  421.     else
  422.     return T_IDENTIFIER;
  423. }
  424.  
  425. boolean
  426. is_typedef_name (name)
  427. char *name;
  428. {
  429.     return (find_symbol(typedef_names, name) != NULL);
  430. }
  431.  
  432. /* If the matched text contains any new line characters, then update the
  433.  * current line number.
  434.  */
  435. static void
  436. update_line_num ()
  437. {
  438.     char *p = yytext;
  439.     while (*p != '\0') {
  440.     if (*p++ == '\n')
  441.         cur_file->line_num++;
  442.     }
  443. }
  444.  
  445. /* Save the matched text in the temporary file.
  446.  */
  447. static void
  448. save_text ()
  449. {
  450. #if OPT_LINTLIBRARY
  451.     if (!in_cpp)
  452.         copy_typedef(yytext);
  453. #endif    
  454.     if (cur_file->convert) {
  455.     fputs(yytext, cur_file->tmp_file);
  456.     }
  457. }
  458.  
  459. /* Record the current position in the temporary file and write the matched text
  460.  * to the file.
  461.  */
  462. static void
  463. save_text_offset ()
  464. {
  465.     (void)strcpy(yylval.text.text, yytext);
  466. #if OPT_LINTLIBRARY
  467.     copy_typedef(yytext);
  468. #endif
  469.     if (cur_file->convert) {
  470.     yylval.text.begin = ftell(cur_file->tmp_file);
  471.     fputs(yytext, cur_file->tmp_file);
  472.     } else
  473.         yylval.text.begin = 0;
  474. }
  475.  
  476. #if OPT_LINTLIBRARY
  477. /* Decipher comments that are useful for lint (and making lint-libraries)
  478.  */
  479. static struct {
  480.     int    varText;
  481.     int    varargs;
  482.     int    externs;
  483.     int    preproz;
  484. } cmtVal;
  485.  
  486. static int
  487. decipher_comment (keyword, len)
  488. char *keyword;
  489. int len;
  490. {
  491.     if (len != 0) {
  492.     int value;
  493.     keyword[len] = '\0';
  494.  
  495.     /* these are recognized by some lint-programs */
  496.     if (!strcmp(keyword, "VARARGS")) {
  497.         cmtVal.varargs = -1;
  498.     } else if (sscanf(keyword, "VARARGS%d", &value) == 1) {
  499.         cmtVal.varargs = value;
  500.     } else if (!strcmp(keyword, "PRINTFLIKE")) {
  501.         cmtVal.varargs = 1;
  502.         cmtVal.varText = TRUE;
  503.     } else if (sscanf(keyword, "PRINTFLIKE%d", &value) == 1) {
  504.         cmtVal.varargs = value;
  505.         cmtVal.varText = TRUE;
  506.     } else if (!strcmp(keyword, "SCANFLIKE")) {
  507.         cmtVal.varargs = 2;
  508.         cmtVal.varText = TRUE;
  509.     } else if (sscanf(keyword, "SCANFLIKE%d", &value) == 1) {
  510.         cmtVal.varargs = value;
  511.         cmtVal.varText = TRUE;
  512.     /* these are extensions added to simplify library-generation */
  513.     } else if (!strcmp(keyword, "LINT_EXTERN")) {
  514.         cmtVal.externs = MAX_INC_DEPTH;
  515.     } else if (sscanf(keyword, "LINT_EXTERN%d", &value) == 1) {
  516.         cmtVal.externs = value;
  517.     } else if (!strcmp(keyword, "LINT_PREPRO")) {
  518.         cmtVal.preproz = -1;    /* the whole comment */
  519.     } else if (sscanf(keyword, "LINT_PREPRO%d", &value) == 1) {
  520.         cmtVal.preproz = value;
  521.     } else if (!strcmp(keyword, "LINT_SHADOWED")) {
  522.         lint_shadowed = TRUE;
  523.     }
  524.     }
  525.     return 0;
  526. }
  527. #endif
  528.  
  529. static void
  530. put_quoted (c)
  531. int c;
  532. {
  533.     /* Modifying 'yytext[]' doesn't work well with FLEX, which simply
  534.      * maintains 'yytext' as a pointer into its input buffer.  LEX copies
  535.      * characters into the 'yytext[]' array.
  536.      */
  537. #if defined(FLEX_SCANNER) || !defined(YYLMAX)
  538.     if (c != 0) {
  539.     static char    temp[2];
  540.     temp[0] = c;
  541.     /* save_text */
  542. # if OPT_LINTLIBRARY
  543.     if (!in_cpp)
  544.         copy_typedef(temp);
  545. # endif    
  546.     if (cur_file->convert) {
  547.         fputs(temp, cur_file->tmp_file);
  548.     }
  549.     /* update_line_num */
  550.     if (c == '\n')
  551.         cur_file->line_num++;
  552.     }
  553.  
  554. #else    /* this works fine on LEX (e.g., on SunOS 4.x) */
  555.  
  556.     if ((c == 0) || (yyleng+1 >= YYLMAX)) {
  557.     save_text();
  558.     update_line_num();
  559.     yyleng = 0;
  560.     }
  561.     if (c != 0) {
  562.     yytext[yyleng++] = c;
  563.     yytext[yyleng] = 0;
  564.     }
  565. #endif    /* LEX/FLEX */
  566. }
  567.  
  568. /*
  569.  * Scan past the characters in a backslash sequence
  570.  */
  571. /* Scan past quoted string.  Note that some strings may overflow 'yytext[]', so
  572.  * we don't try to eat them in the lexical rules.
  573.  */
  574. static void
  575. get_quoted ()
  576. {
  577.     int    delim = *yytext;
  578.     int    c;
  579.  
  580. #if defined(FLEX_SCANNER) || !defined(YYLMAX)
  581.     put_quoted(delim);
  582. #endif
  583.     while ((c = input()) != 0) {
  584.     if (c == '\\') {
  585.         put_quoted(c);
  586.         if ((c = input()) == 0)
  587.         break;
  588.         put_quoted(c);
  589.     } else {
  590.         put_quoted(c);
  591.         if (c == delim)
  592.         break;
  593.         if (c == '\n') {    /* recover from unbalanced */
  594.         put_error();
  595.         fprintf(stderr, "unbalanced quote character '%c'\n", delim);
  596.         break;
  597.         }
  598.     }
  599.     }
  600.     put_quoted(0);
  601. }
  602.  
  603. /* Scan to end of comment.
  604.  */
  605. static void
  606. get_comment ()
  607. {
  608.     int c, lastc = '\0';
  609.  
  610. #if OPT_LINTLIBRARY
  611.     int len = 0;
  612.     char keyword[BUFSIZ];
  613.  
  614.     keyword[len] = '\0';
  615.     cmtVal.varText = 0;
  616.     cmtVal.varargs = 0;
  617.     cmtVal.externs = -1;
  618.     cmtVal.preproz = 0;
  619. #endif
  620.  
  621.     while ((c = input()) != 0) {
  622.     if (cur_file->convert)
  623.         fputc(c, cur_file->tmp_file);
  624.  
  625. #if OPT_LINTLIBRARY
  626.     if (!(isalnum(c) || c == '_' || c == '$')) {
  627.         int flag = cmtVal.preproz;
  628.         len = decipher_comment(keyword, len);
  629.         if (flag != cmtVal.preproz)
  630.             lastc = '\0';
  631.     } else if (len+1 < sizeof(keyword)) {
  632.         keyword[len++] = c;
  633.     }
  634. #endif
  635.  
  636.     switch (c) {
  637.     case '\n':
  638.         cur_file->line_num++;
  639. #if OPT_LINTLIBRARY
  640.         if (cmtVal.preproz != 0 && lastc != '\0')
  641.         fputc(lastc, stdout); 
  642.         if (cmtVal.preproz > 0)    /* if negative, we pass everything */
  643.         cmtVal.preproz -= 1;
  644. #endif
  645.         break;
  646.     case '/':
  647.         if (lastc == '*') {
  648.         if (cur_file->convert) {
  649.             if (func_params && cur_declarator) {
  650.             cur_declarator->begin_comment = cur_file->begin_comment;
  651.             cur_file->begin_comment = ftell(cur_file->tmp_file);
  652.             cur_declarator->end_comment = cur_file->begin_comment;
  653.             cur_declarator = NULL;
  654.             } else {
  655.             cur_file->end_comment = ftell(cur_file->tmp_file);
  656.             }
  657.         }
  658. #if OPT_LINTLIBRARY
  659.         (void)decipher_comment(keyword, len);
  660.         if (cmtVal.varargs != 0) {
  661.             if ((varargs_num = cmtVal.varargs) != 0
  662.              && cmtVal.varText != 0) {
  663.             if (varargs_str != 0)
  664.                 free(varargs_str);
  665.             varargs_str = xstrdup(keyword);
  666.             }
  667.         }
  668.         if (cmtVal.externs != -1)
  669.             extern_in = cmtVal.externs;
  670.         if (cmtVal.preproz != 0)
  671.             fputc('\n', stdout); 
  672. #endif
  673.         return;
  674.         }
  675.         /* FALLTHRU */
  676.     default:
  677. #if OPT_LINTLIBRARY
  678.         if (cmtVal.preproz != 0 && lastc != '\0')
  679.         fputc(lastc, stdout); 
  680. #endif
  681.         break;
  682.     }
  683.     lastc = c;
  684.     }
  685. }
  686.  
  687. /* Scan rest of preprocessor directive.  If <dest> is not NULL, then store
  688.  * the text in the buffer pointed to by <dest> having size <n>.
  689.  */
  690. static void
  691. get_cpp_directive (dest, n)
  692. char *dest;        /* buffer to store directive text */
  693. unsigned n;        /* size of buffer to store directive text */
  694. {
  695.     char c, lastc[4];
  696.     
  697.     lastc[0] = lastc[1] = lastc[2] = lastc[3] = '\0';
  698.     if (dest != NULL)
  699.     *dest = '\0';
  700.  
  701.     while ((c = input()) != 0) {
  702.     if (cur_file->convert)
  703.         fputc(c, cur_file->tmp_file);
  704.  
  705.     switch (c) {
  706.     case '\n':
  707.         cur_file->line_num++;
  708.         if (lastc[2] != '\\' && strcmp(lastc, "?\?/") != 0) {
  709.         finishCpp();
  710.         return;
  711.         }
  712.         break;
  713.     case '*':
  714.         if (lastc[2] == '/')
  715.         get_comment();
  716.         break;
  717.     }
  718.     lastc[0] = lastc[1];
  719.     lastc[1] = lastc[2];
  720.     lastc[2] = c;
  721.  
  722.     if (dest != NULL && n > 1) {
  723.         *dest++ = c;
  724.         *dest = '\0';
  725.         --n;
  726.     }
  727.     }
  728. }
  729.  
  730. /* Return a pointer to the current file name.
  731.  */
  732. char *
  733. cur_file_name ()
  734. {
  735.     return cur_file->file_name;
  736. }
  737.  
  738. /* Return the current line number.
  739.  */
  740. unsigned
  741. cur_line_num ()
  742. {
  743.     return cur_file->line_num;
  744. }
  745.  
  746. /* Return the current temporary output file.
  747.  */
  748. FILE *
  749. cur_tmp_file ()
  750. {
  751.     return cur_file->tmp_file;
  752. }
  753.  
  754. /* Set the modify flag for the current file.
  755.  */
  756. void
  757. cur_file_changed ()
  758. {
  759.     cur_file->changed = TRUE;
  760. }
  761.  
  762. /* Return the temporary file offset of beginning of the current comment.
  763.  */
  764. long
  765. cur_begin_comment ()
  766. {
  767.     return cur_file->begin_comment;
  768. }
  769.  
  770. /* Return the text of the current lexical token.
  771.  */
  772. char *
  773. cur_text ()
  774. {
  775.     return yytext;
  776. }
  777.  
  778. #if !HAVE_TMPFILE
  779. /*
  780.  * tmpfile() - return a FILE* for a temporary file that will be
  781.  * removed automatically when the program exits.
  782.  * 
  783.  * Not all systems have the ANSI tmpfile() function yet...
  784.  *
  785.  * DaviD W. Sanderson (dws@cs.wisc.edu)
  786.  */
  787. FILE *
  788. tmpfile ()
  789. {
  790.     char name[MAX_TEXT_SIZE];
  791.     char *tmpdir;
  792.     FILE *f;
  793.  
  794.     if ((tmpdir = getenv("TMPDIR")) == (char *)0)
  795.     {
  796.     tmpdir = "/tmp";
  797.     }
  798.     sprintf(name, "%s/TfXXXXXX", tmpdir);
  799.     mktemp(name);
  800.  
  801.     if ((f = fopen(name, "w+")) == (FILE *)0)
  802.     {
  803.     return (FILE *)0;
  804.     }
  805.  
  806.     if (unlink(name) == -1)
  807.     {
  808.     fclose(f);
  809.     return (FILE *)0;
  810.     }
  811.  
  812.     return f;
  813. }
  814. #endif /* !HAVE_TMPFILE */
  815.  
  816. /* Push a file onto the include stack.    The stream yyin must already
  817.  * point to the file.
  818.  */
  819. static void
  820. include_file (name, convert)
  821. char *name;        /* file name */
  822. int convert;        /* if TRUE, convert function definitions */
  823. {
  824.     ++inc_depth;
  825.     cur_file = inc_stack + inc_depth;
  826.     cur_file->file = yyin;
  827.     cur_file->base_name = xstrdup(name);
  828.     cur_file->file_name = strcpy(xmalloc(MAX_TEXT_SIZE), name);
  829.     cur_file->line_num = 1;
  830.     cur_file->convert = convert;
  831.     cur_file->changed = FALSE;
  832.  
  833. #ifdef FLEX_SCANNER
  834.     buffer_stack[inc_depth] = yy_create_buffer(yyin, YY_BUF_SIZE);
  835.     yy_switch_to_buffer(buffer_stack[inc_depth]);
  836. #endif
  837.  
  838.     if (convert) {
  839.     cur_file->begin_comment = cur_file->end_comment = 0;
  840.     cur_file->tmp_file = tmpfile();
  841.     if (cur_file->tmp_file == NULL) {
  842.         fprintf(stderr, "%s: cannot create temporary file\n", progname);
  843.         cur_file->convert = FALSE;
  844.     }
  845.     }
  846. }
  847.  
  848. #define BLOCK_SIZE 2048
  849.  
  850. /* Copy converted C source from the temporary file to the output stream.
  851.  */
  852. static void
  853. put_file (outf)
  854. FILE *outf;
  855. {
  856.     char block[BLOCK_SIZE];
  857.     long filesize;
  858.     unsigned nread, count;
  859.  
  860.     filesize = ftell(cur_file->tmp_file);
  861.     fseek(cur_file->tmp_file, 0L, 0);
  862.     while (filesize > 0) {
  863.     count = (filesize < BLOCK_SIZE) ? (unsigned)filesize : BLOCK_SIZE;
  864.     nread = fread(block, sizeof(char), count, cur_file->tmp_file);
  865.     if (nread == 0)
  866.         break;
  867.     fwrite(block, sizeof(char), nread, outf);
  868.     filesize -= nread;
  869.     }
  870. }
  871.  
  872. /* Remove the top of the include stack.
  873.  */
  874. void
  875. pop_file (closed)
  876. int closed;
  877. {
  878.     FILE *outf;
  879.  
  880.     if (!closed && (yyin != stdin))
  881.     fclose(yyin);
  882.  
  883.     if (cur_file->convert) {
  884.     if (yyin == stdin) {
  885.         put_file(stdout);
  886.     } else if (cur_file->changed) {
  887.         if ((outf = fopen(cur_file->base_name, "w")) != NULL) {
  888.         put_file(outf);
  889.         fclose(outf);
  890.         } else {
  891.         fprintf(stderr, "%s: cannot create file %s\n", progname,
  892.          cur_file->base_name);
  893.         }
  894.     }
  895.  
  896.     fclose(cur_file->tmp_file);
  897.     }
  898.     free(cur_file->base_name);
  899.     free(cur_file->file_name);
  900.  
  901. #ifdef FLEX_SCANNER
  902.     yy_delete_buffer(YY_CURRENT_BUFFER);
  903. #endif
  904.  
  905.     if (--inc_depth >= 0) {
  906.     cur_file = inc_stack + inc_depth;
  907.     yyin = cur_file->file;
  908.  
  909. #ifdef FLEX_SCANNER
  910.     yy_switch_to_buffer(buffer_stack[inc_depth]);
  911. #endif
  912.     }
  913. }
  914.  
  915. /* Process include directive.
  916.  */
  917. static void
  918. do_include (file_spec)
  919. char *file_spec;     /* path surrounded by "" or <> */
  920. {
  921.     int stdinc;     /* 1 = path surrounded by <> */
  922.     char file[MAX_TEXT_SIZE], path[MAX_TEXT_SIZE];
  923.     char match, *s;
  924.     int i;
  925.     unsigned n;
  926.     FILE *fp;
  927.  
  928.     if (inc_depth >= MAX_INC_DEPTH-1) {
  929.     put_error();
  930.     fprintf(stderr, "includes too deeply nested\n");
  931.     return;
  932.     }
  933.  
  934.     if (file_spec[0] == '"') {
  935.     match = '"';
  936.     stdinc = 0;
  937.     } else if (file_spec[0] == '<') {
  938.     match = '>';
  939.     stdinc = 1;
  940.     } else {
  941.     return;
  942.     }
  943.     s = strchr(file_spec+1, match);
  944.     n = (s != NULL) ? (unsigned)(s - file_spec - 1) : 0;
  945.     strncpy(file, file_spec+1, (size_t)n);
  946.     file[n] = '\0';
  947.  
  948.     /* Do nothing if the file was already included. */
  949.     sprintf(path, stdinc ? "<%s>" : "\"%s\"", file);
  950.     if (find_symbol(included_files, path) != NULL)
  951.     return;
  952.     new_symbol(included_files, path, NULL, DS_NONE);
  953.  
  954.     for (i = stdinc != 0; i < num_inc_dir; ++i) {
  955.     if (strlen(inc_dir[i]) == 0) {
  956.         strcpy(path, file);
  957.     } else {
  958.         sprintf(path, "%s/%s", inc_dir[i], file);
  959.     }
  960.     if ((fp = fopen(path, "r")) != NULL) {
  961.         yyin = fp;
  962.         include_file(path, func_style != FUNC_NONE && !stdinc);
  963.         return;
  964.     }
  965.     }
  966.  
  967.     if (!quiet) {
  968.     put_error();
  969.     fprintf(stderr, "cannot read file %s\n", file_spec);
  970.     }
  971. }
  972.  
  973. /* When the end of the current input file is reached, pop a
  974.  * nested include file.
  975.  */
  976. int
  977. yywrap ()
  978. {
  979.     if (inc_depth > 0) {
  980.     pop_file(FALSE);
  981.     return 0;
  982.     } else {
  983.     return 1;
  984.     }
  985. }
  986.