home *** CD-ROM | disk | FTP | other *** search
/ C/C++ Users Group Library 1996 July / C-C++ Users Group Library July 1996.iso / vol_400 / 405_01 / flexpp / scan.l < prev    next >
Encoding:
Text File  |  1993-08-28  |  14.5 KB  |  601 lines

  1.  
  2. /* scan.l - scanner for flex input */
  3.  
  4. %{
  5. /*-
  6.  * Copyright (c) 1990 The Regents of the University of California.
  7.  * All rights reserved.
  8.  *
  9.  * This code is derived from software contributed to Berkeley by
  10.  * Vern Paxson.
  11.  * 
  12.  * The United States Government has rights in this work pursuant
  13.  * to contract no. DE-AC03-76SF00098 between the United States
  14.  * Department of Energy and the University of California.
  15.  *
  16.  * Redistribution and use in source and binary forms are permitted provided
  17.  * that: (1) source distributions retain this entire copyright notice and
  18.  * comment, and (2) distributions including binaries display the following
  19.  * acknowledgement:  ``This product includes software developed by the
  20.  * University of California, Berkeley and its contributors'' in the
  21.  * documentation or other materials provided with the distribution and in
  22.  * all advertising materials mentioning features or use of this software.
  23.  * Neither the name of the University nor the names of its contributors may
  24.  * be used to endorse or promote products derived from this software without
  25.  * specific prior written permission.
  26.  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
  27.  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
  28.  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  29.  */
  30.  
  31. #ifndef lint
  32. static char rcsid[] =
  33.     "@(#) $Header: /usr/fsys/odin/a/vern/flex/RCS/scan.l,v 2.9 90/06/27 23:48:34 vern Exp $ (LBL)";
  34. #endif
  35.  
  36. #undef yywrap
  37.  
  38. #include "flexdef.h"
  39. #include "parse.h"
  40.  
  41. #define HEADER_ECHO fprintf(headerfile,"%s",yytext )
  42. #define ACTION_ECHO fprintf( temp_action_file, "%s", yytext )
  43. #define MARK_END_OF_PROLOG fprintf( temp_action_file, "%%%% end of prolog\n" );
  44.  
  45. #undef YY_DECL
  46. #define YY_DECL \
  47.     int flexscan()
  48.  
  49. #define RETURNCHAR \
  50.     yylval = yytext[0]; \
  51.     return ( CHAR );
  52.  
  53. #define RETURNNAME \
  54.     (void) strcpy( nmstr, (char *) yytext ); \
  55.     return ( NAME );
  56.  
  57. #define PUT_BACK_STRING(str, start) \
  58.     for ( i = strlen( (char *) (str) ) - 1; i >= start; --i ) \
  59.         unput((str)[i])
  60.  
  61. #define CHECK_REJECT(str) \
  62.     if ( all_upper( str ) ) \
  63.         reject = true;
  64.  
  65. #define CHECK_YYMORE(str) \
  66.     if ( all_lower( str ) ) \
  67.         yymore_used = true;
  68. %}
  69.  
  70. %x SECT2 SECT2PROLOG SECT3 CODEBLOCK PICKUPDEF SC CARETISBOL NUM QUOTE
  71. %x FIRSTCCL CCL ACTION RECOVER BRACEERROR C_COMMENT ACTION_COMMENT
  72. %x ACTION_STRING PERCENT_BRACE_ACTION USED_LIST CODEBLOCK_2 XLATION
  73. %x HEADER_BLOC HEADER2_BLOC NAME_DECLARE DEFINE_DECLARE DEFINE_CONTENT
  74.  
  75. WS        [ \t\f]+
  76. OPTWS        [ \t\f]*
  77. NOT_WS        [^ \t\f\n\r]
  78.  
  79. NAME        [a-z_][a-z_0-9-]*
  80. NOT_NAME    [^a-z_\n\r]+
  81.  
  82. SCNAME        {NAME}
  83. LINEFEED    ("\n"|"\r"|"\r\n")
  84. ESCSEQ        \\([^\n\r]|[0-9]{1,3}|x[0-9a-f]{1,2})
  85.  
  86. %%
  87.     static int bracelevel, didadef;
  88.     int i, indented_code, checking_used, new_xlation;
  89.     int doing_codeblock = false;
  90.     Char nmdef[MAXLINE], myesc();
  91.  
  92. ^{WS}            indented_code = true; BEGIN(CODEBLOCK);
  93. ^#.*{LINEFEED}            ++linenum; /* treat as a comment */
  94. ^"//".*{LINEFEED}        ++linenum;  /* treat as a c++ comment */
  95. ^"/*"            ECHO; BEGIN(C_COMMENT);
  96. ^"%s"{NAME}?        return ( SCDECL );
  97. ^"%x"{NAME}?        return ( XSCDECL );
  98. ^"%name"{WS}        BEGIN(NAME_DECLARE);
  99. ^"%define"{WS}        BEGIN(DEFINE_DECLARE);
  100.     
  101.  
  102. ^"%{".*{LINEFEED}        {
  103.             ++linenum;
  104.             line_directive_out( stdout );
  105.             indented_code = false;
  106.             BEGIN(CODEBLOCK);
  107.             }
  108. ^"%header{".*{LINEFEED}        {
  109.             ++linenum;
  110.             line_directive_out( headerfile );
  111.             BEGIN(HEADER_BLOC);
  112.             }
  113.  
  114. {WS}            return ( WHITESPACE );
  115.  
  116. ^"%%".*            {
  117.             set_lexer_name((char *)0);
  118.             sectnum = 2;
  119.             line_directive_out( headerfile );
  120.                   if(headerfilename!=NULL)
  121.                 {
  122.                    fprintf(stdout,
  123.                           "#include \"%s\"\n",includefilename);
  124.               header_skeleton_out();
  125.                  };
  126.             line_directive_out( stdout );
  127.             BEGIN(SECT2PROLOG);
  128.             return ( SECTEND );
  129.             }
  130.  
  131. ^"%used"        {
  132.     pinpoint_message( "warning - %%used/%%unused have been deprecated" );
  133.             checking_used = REALLY_USED; BEGIN(USED_LIST);
  134.             }
  135. ^"%unused"        {
  136.             checking_used = REALLY_NOT_USED; BEGIN(USED_LIST);
  137.     pinpoint_message( "warning - %%used/%%unused have been deprecated" );
  138.             checking_used = REALLY_NOT_USED; BEGIN(USED_LIST);
  139.             }
  140.  
  141.  
  142. ^"%"[aeknopt]{WS}.*{LINEFEED}    {
  143. #ifdef NOTDEF
  144.             fprintf( stderr,
  145.                  "old-style lex command at line %d ignored:\n\t%s",
  146.                  linenum, yytext );
  147. #endif
  148.             ++linenum;
  149.             }
  150.  
  151. ^"%"[cr]{OPTWS}        /* ignore old lex directive */
  152.  
  153. %t{OPTWS}{LINEFEED}        {
  154.             ++linenum;
  155.             xlation =
  156.                 (int *) malloc( sizeof( int ) * (unsigned) csize );
  157.  
  158.             if ( ! xlation )
  159.                 flexfatal(
  160.                 "dynamic memory failure building %t table" );
  161.  
  162.             for ( i = 0; i < csize; ++i )
  163.                 xlation[i] = 0;
  164.  
  165.             num_xlations = 0;
  166.  
  167.             BEGIN(XLATION);
  168.             }
  169.  
  170. ^"%"[^sxanpekotcru{}]{OPTWS}    synerr( "unrecognized '%' directive" );
  171.  
  172. ^{NAME}            {
  173.             (void) strcpy( nmstr, (char *) yytext );
  174.             didadef = false;
  175.             BEGIN(PICKUPDEF);
  176.             }
  177.  
  178. {SCNAME}        RETURNNAME;
  179. ^{OPTWS}{LINEFEED}        ++linenum; /* allows blank lines in section 1 */
  180. {OPTWS}{LINEFEED}        ++linenum; return ( '\n' );
  181. .            {synerr( "illegal character" ); 
  182.                          fprintf(stderr,
  183.                            "Char : \\0x%x\n",yytext[yyleng-1]);
  184.             BEGIN(RECOVER);}
  185.  
  186. <NAME_DECLARE>{NAME}    {set_lexer_name((char *)yytext);}
  187. <NAME_DECLARE>{WS}    ;
  188. <NAME_DECLARE>{LINEFEED}    ++linenum;BEGIN(INITIAL);
  189. <NAME_DECLARE>.        synerr( "illegal character" );BEGIN(RECOVER);
  190.  
  191. <DEFINE_DECLARE>{NAME}    { set_lexer_name((char *)0);
  192.             line_directive_out( headerfile );
  193.             fprintf(headerfile,"#define YY_%s_%s ",lexer_name,yytext);
  194.              BEGIN(DEFINE_CONTENT);
  195.             }
  196.  
  197. <DEFINE_DECLARE>.    synerr( "illegal character" ); BEGIN(RECOVER);
  198. <DEFINE_DECLARE>{LINEFEED}    ++linenum;BEGIN(INITIAL);
  199.  
  200. <DEFINE_CONTENT>\\{LINEFEED}    HEADER_ECHO;++linenum;
  201. <DEFINE_CONTENT>{LINEFEED}    ++linenum;HEADER_ECHO;BEGIN(INITIAL);
  202. <DEFINE_CONTENT>.    HEADER_ECHO;
  203.  
  204. <C_COMMENT>"*/"        ECHO; BEGIN(INITIAL);
  205. <C_COMMENT>"*/".*{LINEFEED}    ++linenum; ECHO; BEGIN(INITIAL);
  206. <C_COMMENT>[^*\n\r]+    ECHO;
  207. <C_COMMENT>"*"        ECHO;
  208. <C_COMMENT>{LINEFEED}        ++linenum; ECHO;
  209.  
  210. <HEADER_BLOC>^"%}".*{LINEFEED}    ++linenum; BEGIN(INITIAL);
  211. <HEADER_BLOC>"reject"    HEADER_ECHO; CHECK_REJECT(yytext);
  212. <HEADER_BLOC>"yymore"    HEADER_ECHO; CHECK_YYMORE(yytext);
  213. <HEADER_BLOC>{NAME}|{NOT_NAME}|.    HEADER_ECHO;
  214. <HEADER_BLOC>{LINEFEED}        {
  215.             ++linenum;
  216.             HEADER_ECHO;
  217.             }
  218.  
  219.  
  220. <HEADER2_BLOC>^"%}".*{LINEFEED}    ++linenum; BEGIN(SECT2);
  221. <HEADER2_BLOC>"reject"    HEADER_ECHO; CHECK_REJECT(yytext);
  222. <HEADER2_BLOC>"yymore"    HEADER_ECHO; CHECK_YYMORE(yytext);
  223. <HEADER2_BLOC>{NAME}|{NOT_NAME}|.    HEADER_ECHO;
  224. <HEADER2_BLOC>{LINEFEED}        {
  225.             ++linenum;
  226.             HEADER_ECHO;
  227.             }
  228.  
  229.  
  230.  
  231.  
  232. <CODEBLOCK>^"%}".*{LINEFEED}    ++linenum; BEGIN(INITIAL);
  233. <CODEBLOCK>"reject"    ECHO; CHECK_REJECT(yytext);
  234. <CODEBLOCK>"yymore"    ECHO; CHECK_YYMORE(yytext);
  235. <CODEBLOCK>{NAME}|{NOT_NAME}|.    ECHO;
  236. <CODEBLOCK>{LINEFEED}        {
  237.             ++linenum;
  238.             ECHO;
  239.             if ( indented_code )
  240.                 BEGIN(INITIAL);
  241.             }
  242.  
  243.  
  244. <PICKUPDEF>{WS}        /* separates name and definition */
  245.  
  246. <PICKUPDEF>{NOT_WS}.*    {
  247.             (void) strcpy( (char *) nmdef, (char *) yytext );
  248.  
  249.             for ( i = strlen( (char *) nmdef ) - 1;
  250.                   i >= 0 &&
  251.                   nmdef[i] == ' ' || nmdef[i] == '\t';
  252.                   --i )
  253.                 ;
  254.  
  255.             nmdef[i + 1] = '\0';
  256.  
  257.                         ndinstal( nmstr, nmdef );
  258.             didadef = true;
  259.             }
  260.  
  261. <PICKUPDEF>{LINEFEED}        {
  262.             if ( ! didadef )
  263.                 synerr( "incomplete name definition" );
  264.             BEGIN(INITIAL);
  265.             ++linenum;
  266.             }
  267.  
  268. <RECOVER>.*{LINEFEED}        ++linenum; BEGIN(INITIAL); RETURNNAME;
  269.  
  270.  
  271. <USED_LIST>{LINEFEED}        ++linenum; BEGIN(INITIAL);
  272. <USED_LIST>{WS}
  273. <USED_LIST>"reject"    {
  274.             if ( all_upper( yytext ) )
  275.                 reject_really_used = checking_used;
  276.             else
  277.                 synerr( "unrecognized %used/%unused construct" );
  278.             }
  279. <USED_LIST>"yymore"    {
  280.             if ( all_lower( yytext ) )
  281.                 yymore_really_used = checking_used;
  282.             else
  283.                 synerr( "unrecognized %used/%unused construct" );
  284.             }
  285. <USED_LIST>{NOT_WS}+    synerr( "unrecognized %used/%unused construct" );
  286.  
  287.  
  288. <XLATION>"%t"{OPTWS}{LINEFEED}    ++linenum; BEGIN(INITIAL);
  289. <XLATION>^{OPTWS}[0-9]+    ++num_xlations; new_xlation = true;
  290. <XLATION>^.        synerr( "bad row in translation table" );
  291. <XLATION>{WS}        /* ignore whitespace */
  292.  
  293. <XLATION>{ESCSEQ}    {
  294.             xlation[myesc( yytext )] =
  295.                 (new_xlation ? num_xlations : -num_xlations);
  296.             new_xlation = false;
  297.             }
  298. <XLATION>.        {
  299.             xlation[yytext[0]] =
  300.                 (new_xlation ? num_xlations : -num_xlations);
  301.             new_xlation = false;
  302.             }
  303.  
  304. <XLATION>{LINEFEED}        ++linenum;
  305.  
  306.  
  307. <SECT2PROLOG>.*{LINEFEED}/{NOT_WS}    {
  308.             ++linenum;
  309.             ACTION_ECHO;
  310.             MARK_END_OF_PROLOG;
  311.             BEGIN(SECT2);
  312.             }
  313.  
  314. <SECT2PROLOG>.*{LINEFEED}    ++linenum; ACTION_ECHO;
  315.  
  316. <SECT2PROLOG><<EOF>>    MARK_END_OF_PROLOG; yyterminate();
  317.  
  318. <SECT2>^{OPTWS}{LINEFEED}    ++linenum; /* allow blank lines in section 2 */
  319.  
  320. <SECT2>^"%header{".*{LINEFEED}    {
  321.             line_directive_out( headerfile );
  322.             BEGIN(HEADER2_BLOC);
  323.             }
  324. <SECT2>^({WS}|"%{")    {
  325.             indented_code = (yytext[0] != '%');
  326.             doing_codeblock = true;
  327.             bracelevel = 1;
  328.  
  329.             if ( indented_code )
  330.                 ACTION_ECHO;
  331.  
  332.             BEGIN(CODEBLOCK_2);
  333.             }
  334.  
  335. <SECT2>"<"        BEGIN(SC); return ( '<' );
  336. <SECT2>^"^"        return ( '^' );
  337. <SECT2>\"        BEGIN(QUOTE); return ( '"' );
  338. <SECT2>"{"/[0-9]        BEGIN(NUM); return ( '{' );
  339. <SECT2>"{"[^0-9\n\r][^}\n\r]*    BEGIN(BRACEERROR);
  340. <SECT2>"$"/[ \t\n\r]    return ( '$' );
  341.  
  342. <SECT2>{WS}"%{"        {
  343.             bracelevel = 1;
  344.             BEGIN(PERCENT_BRACE_ACTION);
  345.             return ( '\n' );
  346.             }
  347. <SECT2>{WS}"|".*{LINEFEED}    continued_action = true; ++linenum; return ( '\n' );
  348.  
  349. <SECT2>{WS}        {
  350.             /* this rule is separate from the one below because
  351.              * otherwise we get variable trailing context, so
  352.              * we can't build the scanner using -{f,F}
  353.              */
  354.             bracelevel = 0;
  355.             continued_action = false;
  356.             BEGIN(ACTION);
  357.             return ( '\n' );
  358.             }
  359.  
  360. <SECT2>{OPTWS}/{LINEFEED}    {
  361.             bracelevel = 0;
  362.             continued_action = false;
  363.             BEGIN(ACTION);
  364.             return ( '\n' );
  365.             }
  366.  
  367. <SECT2>^{OPTWS}{LINEFEED}    ++linenum; return ( '\n' );
  368.  
  369. <SECT2>"<<EOF>>"    return ( EOF_OP );
  370.  
  371. <SECT2>^"%%".*        {
  372.             sectnum = 3;
  373.             BEGIN(SECT3);
  374.             return ( EOF ); /* to stop the parser */
  375.             }
  376.  
  377. <SECT2>"["([^\\\]\n\r]|{ESCSEQ})+"]"    {
  378.             int cclval;
  379.  
  380.             (void) strcpy( nmstr, (char *) yytext );
  381.  
  382.             /* check to see if we've already encountered this ccl */
  383.             if ( (cclval = ccllookup( (Char *) nmstr )) )
  384.                 {
  385.                 yylval = cclval;
  386.                 ++cclreuse;
  387.                 return ( PREVCCL );
  388.                 }
  389.             else
  390.                 {
  391.                 /* we fudge a bit.  We know that this ccl will
  392.                  * soon be numbered as lastccl + 1 by cclinit
  393.                  */
  394.                 cclinstal( (Char *) nmstr, lastccl + 1 );
  395.  
  396.                 /* push back everything but the leading bracket
  397.                  * so the ccl can be rescanned
  398.                  */
  399.                 PUT_BACK_STRING((Char *) nmstr, 1);
  400.  
  401.                 BEGIN(FIRSTCCL);
  402.                 return ( '[' );
  403.                 }
  404.             }
  405.  
  406. <SECT2>"{"{NAME}"}"    {
  407.             register Char *nmdefptr;
  408.             Char *ndlookup();
  409.  
  410.             (void) strcpy( nmstr, (char *) yytext );
  411.             nmstr[yyleng - 1] = '\0';  /* chop trailing brace */
  412.  
  413.             /* lookup from "nmstr + 1" to chop leading brace */
  414.             if ( ! (nmdefptr = ndlookup( nmstr + 1 )) )
  415.                 synerr( "undefined {name}" );
  416.  
  417.             else
  418.                 { /* push back name surrounded by ()'s */
  419.                 unput(')');
  420.                 PUT_BACK_STRING(nmdefptr, 0);
  421.                 unput('(');
  422.                 }
  423.             }
  424.  
  425. <SECT2>[/|*+?.()]    return ( yytext[0] );
  426. <SECT2>.        RETURNCHAR;
  427. <SECT2>{LINEFEED}        ++linenum; return ( '\n' );
  428.  
  429.  
  430. <SC>","            return ( ',' );
  431. <SC>">"            BEGIN(SECT2); return ( '>' );
  432. <SC>">"/"^"        BEGIN(CARETISBOL); return ( '>' );
  433. <SC>{SCNAME}        RETURNNAME;
  434. <SC>.            synerr( "bad start condition name" );
  435.  
  436. <CARETISBOL>"^"        BEGIN(SECT2); return ( '^' );
  437.  
  438.  
  439. <QUOTE>[^"\n\r]        RETURNCHAR;
  440. <QUOTE>\"        BEGIN(SECT2); return ( '"' );
  441.  
  442. <QUOTE>{LINEFEED}        {
  443.             synerr( "missing quote" );
  444.             BEGIN(SECT2);
  445.             ++linenum;
  446.             return ( '"' );
  447.             }
  448.  
  449.  
  450. <FIRSTCCL>"^"/[^-\n\r]    BEGIN(CCL); return ( '^' );
  451. <FIRSTCCL>"^"/-        return ( '^' );
  452. <FIRSTCCL>-        BEGIN(CCL); yylval = '-'; return ( CHAR );
  453. <FIRSTCCL>.        BEGIN(CCL); RETURNCHAR;
  454.  
  455. <CCL>-/[^\]\n\r]        return ( '-' );
  456. <CCL>[^\]\n\r]        RETURNCHAR;
  457. <CCL>"]"        BEGIN(SECT2); return ( ']' );
  458.  
  459.  
  460. <NUM>[0-9]+        {
  461.             yylval = myctoi( yytext );
  462.             return ( NUMBER );
  463.             }
  464.  
  465. <NUM>","            return ( ',' );
  466. <NUM>"}"            BEGIN(SECT2); return ( '}' );
  467.  
  468. <NUM>.            {
  469.             synerr( "bad character inside {}'s" );
  470.             BEGIN(SECT2);
  471.             return ( '}' );
  472.             }
  473.  
  474. <NUM>{LINEFEED}            {
  475.             synerr( "missing }" );
  476.             BEGIN(SECT2);
  477.             ++linenum;
  478.             return ( '}' );
  479.             }
  480.  
  481.  
  482. <BRACEERROR>"}"        synerr( "bad name in {}'s" ); BEGIN(SECT2);
  483. <BRACEERROR>{LINEFEED}        synerr( "missing }" ); ++linenum; BEGIN(SECT2);
  484.  
  485.  
  486. <PERCENT_BRACE_ACTION,CODEBLOCK_2>{OPTWS}"%}".*        bracelevel = 0;
  487. <PERCENT_BRACE_ACTION,CODEBLOCK_2,ACTION>"reject"    {
  488.             ACTION_ECHO;
  489.             CHECK_REJECT(yytext);
  490.             }
  491. <PERCENT_BRACE_ACTION,CODEBLOCK_2,ACTION>"yymore"    {
  492.             ACTION_ECHO;
  493.             CHECK_YYMORE(yytext);
  494.             }
  495. <PERCENT_BRACE_ACTION,CODEBLOCK_2>{NAME}|{NOT_NAME}|.    ACTION_ECHO;
  496. <PERCENT_BRACE_ACTION,CODEBLOCK_2>{LINEFEED}            {
  497.             ++linenum;
  498.             ACTION_ECHO;
  499.             if ( bracelevel == 0 ||
  500.                  (doing_codeblock && indented_code) )
  501.                 {
  502.                 if ( ! doing_codeblock )
  503.                 fputs( "\tYY_BREAK\n", temp_action_file );
  504.                 
  505.                 doing_codeblock = false;
  506.                 BEGIN(SECT2);
  507.                 }
  508.             }
  509.  
  510.  
  511.     /* Reject and YYmore() are checked for above, in PERCENT_BRACE_ACTION */
  512. <ACTION>"{"        ACTION_ECHO; ++bracelevel;
  513. <ACTION>"}"        ACTION_ECHO; --bracelevel;
  514. <ACTION>[^a-z_{}"'/\n\r]+    ACTION_ECHO;
  515. <ACTION>{NAME}        ACTION_ECHO;
  516. <ACTION>"//".*{LINEFEED}    ++linenum;ACTION_ECHO; 
  517. <ACTION>"/*"        ACTION_ECHO; BEGIN(ACTION_COMMENT);
  518. <ACTION>"'"([^'\\\n\r]|\\.)*"'"    ACTION_ECHO; /* character constant */
  519. <ACTION>\"        ACTION_ECHO; BEGIN(ACTION_STRING);
  520. <ACTION>{LINEFEED}        {
  521.             ++linenum;
  522.             ACTION_ECHO;
  523.             if ( bracelevel == 0 )
  524.                 {
  525.                 fputs( "\tYY_BREAK\n", temp_action_file );
  526.                 BEGIN(SECT2);
  527.                 }
  528.             }
  529. <ACTION>.        ACTION_ECHO;
  530.  
  531. <ACTION_COMMENT>"*/"    ACTION_ECHO; BEGIN(ACTION);
  532. <ACTION_COMMENT>[^*\n\r]+    ACTION_ECHO;
  533. <ACTION_COMMENT>"*"    ACTION_ECHO;
  534. <ACTION_COMMENT>{LINEFEED}    ++linenum; ACTION_ECHO;
  535. <ACTION_COMMENT>.    ACTION_ECHO;
  536.  
  537. <ACTION_STRING>[^"\\\n\r]+    ACTION_ECHO;
  538. <ACTION_STRING>\\.    ACTION_ECHO;
  539. <ACTION_STRING>{LINEFEED}    ++linenum; ACTION_ECHO;
  540. <ACTION_STRING>\"    ACTION_ECHO; BEGIN(ACTION);
  541. <ACTION_STRING>.    ACTION_ECHO;
  542.  
  543. <ACTION,ACTION_COMMENT,ACTION_STRING><<EOF>>    {
  544.             synerr( "EOF encountered inside an action" );
  545.             yyterminate();
  546.             }
  547.  
  548.  
  549. <SECT2,QUOTE,CCL>{ESCSEQ}    {
  550.             yylval = myesc( yytext );
  551.             return ( CHAR );
  552.             }
  553.  
  554. <FIRSTCCL>{ESCSEQ}    {
  555.             yylval = myesc( yytext );
  556.             BEGIN(CCL);
  557.             return ( CHAR );
  558.             }
  559.  
  560.  
  561. <SECT3>.*({LINEFEED}?)        ECHO;
  562. %%
  563.  
  564.  
  565. int yywrap()
  566.  
  567.     {
  568.     if ( --num_input_files > 0 )
  569.     {
  570.     set_input_file( *++input_files );
  571.     return ( 0 );
  572.     }
  573.  
  574.     else
  575.     return ( 1 );
  576.     }
  577.  
  578.  
  579. /* set_input_file - open the given file (if NULL, stdin) for scanning */
  580.  
  581. void set_input_file( file )
  582. char *file;
  583.  
  584.     {
  585.     if ( file )
  586.     {
  587.     infilename = file;
  588.     yyin = fopen( infilename, "r" );
  589.  
  590.     if ( yyin == NULL )
  591.         lerrsf( "can't open %s", file );
  592.     }
  593.  
  594.     else
  595.     {
  596.     yyin = stdin;
  597.     infilename = "<stdin>";
  598.     }
  599.     }
  600.  
  601.