home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / bsd_srcs / usr.bin / lex / parse.y < prev    next >
Encoding:
Text File  |  1991-04-12  |  14.9 KB  |  716 lines

  1. /* parse.y - parser for flex input */
  2.  
  3. %token CHAR NUMBER SECTEND SCDECL XSCDECL WHITESPACE NAME PREVCCL EOF_OP
  4.  
  5. %{
  6.  
  7. /*-
  8.  * Copyright (c) 1990 The Regents of the University of California.
  9.  * All rights reserved.
  10.  *
  11.  * This code is derived from software contributed to Berkeley by
  12.  * Vern Paxson of Lawrence Berkeley Laboratory.
  13.  * 
  14.  * The United States Government has rights in this work pursuant
  15.  * to contract no. DE-AC03-76SF00098 between the United States
  16.  * Department of Energy and the University of California.
  17.  *
  18.  * Redistribution and use in source and binary forms, with or without
  19.  * modification, are permitted provided that the following conditions
  20.  * are met:
  21.  * 1. Redistributions of source code must retain the above copyright
  22.  *    notice, this list of conditions and the following disclaimer.
  23.  * 2. Redistributions in binary form must reproduce the above copyright
  24.  *    notice, this list of conditions and the following disclaimer in the
  25.  *    documentation and/or other materials provided with the distribution.
  26.  * 3. All advertising materials mentioning features or use of this software
  27.  *    must display the following acknowledgement:
  28.  *    This product includes software developed by the University of
  29.  *    California, Berkeley and its contributors.
  30.  * 4. Neither the name of the University nor the names of its contributors
  31.  *    may be used to endorse or promote products derived from this software
  32.  *    without specific prior written permission.
  33.  *
  34.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  35.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  36.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  37.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  38.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  39.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  40.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  41.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  42.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  43.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  44.  * SUCH DAMAGE.
  45.  */
  46.  
  47. #ifndef lint
  48. static char sccsid[] = "@(#)parse.y    5.2 (Berkeley) 6/18/90";
  49. #endif /* not lint */
  50.  
  51. #include "flexdef.h"
  52.  
  53. int pat, scnum, eps, headcnt, trailcnt, anyccl, lastchar, i, actvp, rulelen;
  54. int trlcontxt, xcluflg, cclsorted, varlength, variable_trail_rule;
  55. Char clower();
  56.  
  57. static int madeany = false;  /* whether we've made the '.' character class */
  58. int previous_continued_action;    /* whether the previous rule's action was '|' */
  59.  
  60. %}
  61.  
  62. %%
  63. goal            :  initlex sect1 sect1end sect2 initforrule
  64.             { /* add default rule */
  65.             int def_rule;
  66.  
  67.             pat = cclinit();
  68.             cclnegate( pat );
  69.  
  70.             def_rule = mkstate( -pat );
  71.  
  72.             finish_rule( def_rule, false, 0, 0 );
  73.  
  74.             for ( i = 1; i <= lastsc; ++i )
  75.                 scset[i] = mkbranch( scset[i], def_rule );
  76.  
  77.             if ( spprdflt )
  78.                 fputs( "YY_FATAL_ERROR( \"flex scanner jammed\" )",
  79.                    temp_action_file );
  80.             else
  81.                 fputs( "ECHO", temp_action_file );
  82.  
  83.             fputs( ";\n\tYY_BREAK\n", temp_action_file );
  84.             }
  85.         ;
  86.  
  87. initlex         :
  88.             {
  89.             /* initialize for processing rules */
  90.  
  91.             /* create default DFA start condition */
  92.             scinstal( "INITIAL", false );
  93.             }
  94.         ;
  95.  
  96. sect1        :  sect1 startconddecl WHITESPACE namelist1 '\n'
  97.         |
  98.         |  error '\n'
  99.             { synerr( "unknown error processing section 1" ); }
  100.         ;
  101.  
  102. sect1end    :  SECTEND
  103.         ;
  104.  
  105. startconddecl   :  SCDECL
  106.             {
  107.             /* these productions are separate from the s1object
  108.              * rule because the semantics must be done before
  109.              * we parse the remainder of an s1object
  110.              */
  111.  
  112.             xcluflg = false;
  113.             }
  114.  
  115.         |  XSCDECL
  116.             { xcluflg = true; }
  117.         ;
  118.  
  119. namelist1    :  namelist1 WHITESPACE NAME
  120.             { scinstal( nmstr, xcluflg ); }
  121.  
  122.         |  NAME
  123.             { scinstal( nmstr, xcluflg ); }
  124.  
  125.         |  error
  126.                         { synerr( "bad start condition list" ); }
  127.         ;
  128.  
  129. sect2           :  sect2 initforrule flexrule '\n'
  130.         |
  131.         ;
  132.  
  133. initforrule     :
  134.             {
  135.             /* initialize for a parse of one rule */
  136.             trlcontxt = variable_trail_rule = varlength = false;
  137.             trailcnt = headcnt = rulelen = 0;
  138.             current_state_type = STATE_NORMAL;
  139.             previous_continued_action = continued_action;
  140.             new_rule();
  141.             }
  142.         ;
  143.  
  144. flexrule        :  scon '^' rule
  145.                         {
  146.             pat = $3;
  147.             finish_rule( pat, variable_trail_rule,
  148.                      headcnt, trailcnt );
  149.  
  150.             for ( i = 1; i <= actvp; ++i )
  151.                 scbol[actvsc[i]] =
  152.                 mkbranch( scbol[actvsc[i]], pat );
  153.  
  154.             if ( ! bol_needed )
  155.                 {
  156.                 bol_needed = true;
  157.  
  158.                 if ( performance_report )
  159.                 pinpoint_message( 
  160.                 "'^' operator results in sub-optimal performance" );
  161.                 }
  162.             }
  163.  
  164.         |  scon rule
  165.                         {
  166.             pat = $2;
  167.             finish_rule( pat, variable_trail_rule,
  168.                      headcnt, trailcnt );
  169.  
  170.             for ( i = 1; i <= actvp; ++i )
  171.                 scset[actvsc[i]] =
  172.                 mkbranch( scset[actvsc[i]], pat );
  173.             }
  174.  
  175.                 |  '^' rule
  176.             {
  177.             pat = $2;
  178.             finish_rule( pat, variable_trail_rule,
  179.                      headcnt, trailcnt );
  180.  
  181.             /* add to all non-exclusive start conditions,
  182.              * including the default (0) start condition
  183.              */
  184.  
  185.             for ( i = 1; i <= lastsc; ++i )
  186.                 if ( ! scxclu[i] )
  187.                 scbol[i] = mkbranch( scbol[i], pat );
  188.  
  189.             if ( ! bol_needed )
  190.                 {
  191.                 bol_needed = true;
  192.  
  193.                 if ( performance_report )
  194.                 pinpoint_message(
  195.                 "'^' operator results in sub-optimal performance" );
  196.                 }
  197.             }
  198.  
  199.                 |  rule
  200.             {
  201.             pat = $1;
  202.             finish_rule( pat, variable_trail_rule,
  203.                      headcnt, trailcnt );
  204.  
  205.             for ( i = 1; i <= lastsc; ++i )
  206.                 if ( ! scxclu[i] )
  207.                 scset[i] = mkbranch( scset[i], pat );
  208.             }
  209.  
  210.                 |  scon EOF_OP
  211.             { build_eof_action(); }
  212.  
  213.                 |  EOF_OP
  214.             {
  215.             /* this EOF applies to all start conditions
  216.              * which don't already have EOF actions
  217.              */
  218.             actvp = 0;
  219.  
  220.             for ( i = 1; i <= lastsc; ++i )
  221.                 if ( ! sceof[i] )
  222.                 actvsc[++actvp] = i;
  223.  
  224.             if ( actvp == 0 )
  225.                 pinpoint_message(
  226.         "warning - all start conditions already have <<EOF>> rules" );
  227.  
  228.             else
  229.                 build_eof_action();
  230.             }
  231.  
  232.                 |  error
  233.             { synerr( "unrecognized rule" ); }
  234.         ;
  235.  
  236. scon            :  '<' namelist2 '>'
  237.         ;
  238.  
  239. namelist2       :  namelist2 ',' NAME
  240.                         {
  241.             if ( (scnum = sclookup( nmstr )) == 0 )
  242.                 format_pinpoint_message(
  243.                 "undeclared start condition %s", nmstr );
  244.  
  245.             else
  246.                 actvsc[++actvp] = scnum;
  247.             }
  248.  
  249.         |  NAME
  250.             {
  251.             if ( (scnum = sclookup( nmstr )) == 0 )
  252.                 format_pinpoint_message(
  253.                 "undeclared start condition %s", nmstr );
  254.             else
  255.                 actvsc[actvp = 1] = scnum;
  256.             }
  257.  
  258.         |  error
  259.             { synerr( "bad start condition list" ); }
  260.         ;
  261.  
  262. rule            :  re2 re
  263.             {
  264.             if ( transchar[lastst[$2]] != SYM_EPSILON )
  265.                 /* provide final transition \now/ so it
  266.                  * will be marked as a trailing context
  267.                  * state
  268.                  */
  269.                 $2 = link_machines( $2, mkstate( SYM_EPSILON ) );
  270.  
  271.             mark_beginning_as_normal( $2 );
  272.             current_state_type = STATE_NORMAL;
  273.  
  274.             if ( previous_continued_action )
  275.                 {
  276.                 /* we need to treat this as variable trailing
  277.                  * context so that the backup does not happen
  278.                  * in the action but before the action switch
  279.                  * statement.  If the backup happens in the
  280.                  * action, then the rules "falling into" this
  281.                  * one's action will *also* do the backup,
  282.                  * erroneously.
  283.                  */
  284.                 if ( ! varlength || headcnt != 0 )
  285.                 {
  286.                 fprintf( stderr,
  287.     "%s: warning - trailing context rule at line %d made variable because\n",
  288.                      program_name, linenum );
  289.                 fprintf( stderr,
  290.                      "      of preceding '|' action\n" );
  291.                 }
  292.  
  293.                 /* mark as variable */
  294.                 varlength = true;
  295.                 headcnt = 0;
  296.                 }
  297.  
  298.             if ( varlength && headcnt == 0 )
  299.                 { /* variable trailing context rule */
  300.                 /* mark the first part of the rule as the accepting
  301.                  * "head" part of a trailing context rule
  302.                  */
  303.                 /* by the way, we didn't do this at the beginning
  304.                  * of this production because back then
  305.                  * current_state_type was set up for a trail
  306.                  * rule, and add_accept() can create a new
  307.                  * state ...
  308.                  */
  309.                 add_accept( $1, num_rules | YY_TRAILING_HEAD_MASK );
  310.                 variable_trail_rule = true;
  311.                 }
  312.             
  313.             else
  314.                 trailcnt = rulelen;
  315.  
  316.             $$ = link_machines( $1, $2 );
  317.             }
  318.  
  319.         |  re2 re '$'
  320.             { synerr( "trailing context used twice" ); }
  321.  
  322.         |  re '$'
  323.                         {
  324.             if ( trlcontxt )
  325.                 {
  326.                 synerr( "trailing context used twice" );
  327.                 $$ = mkstate( SYM_EPSILON );
  328.                 }
  329.  
  330.             else if ( previous_continued_action )
  331.                 {
  332.                 /* see the comment in the rule for "re2 re"
  333.                  * above
  334.                  */
  335.                 if ( ! varlength || headcnt != 0 )
  336.                 {
  337.                 fprintf( stderr,
  338.     "%s: warning - trailing context rule at line %d made variable because\n",
  339.                      program_name, linenum );
  340.                 fprintf( stderr,
  341.                      "      of preceding '|' action\n" );
  342.                 }
  343.  
  344.                 /* mark as variable */
  345.                 varlength = true;
  346.                 headcnt = 0;
  347.                 }
  348.  
  349.             trlcontxt = true;
  350.  
  351.             if ( ! varlength )
  352.                 headcnt = rulelen;
  353.  
  354.             ++rulelen;
  355.             trailcnt = 1;
  356.  
  357.             eps = mkstate( SYM_EPSILON );
  358.             $$ = link_machines( $1,
  359.                  link_machines( eps, mkstate( '\n' ) ) );
  360.             }
  361.  
  362.         |  re
  363.             {
  364.                 $$ = $1;
  365.  
  366.             if ( trlcontxt )
  367.                 {
  368.                 if ( varlength && headcnt == 0 )
  369.                 /* both head and trail are variable-length */
  370.                 variable_trail_rule = true;
  371.                 else
  372.                 trailcnt = rulelen;
  373.                 }
  374.                 }
  375.         ;
  376.  
  377.  
  378. re              :  re '|' series
  379.                         {
  380.             varlength = true;
  381.             $$ = mkor( $1, $3 );
  382.             }
  383.  
  384.         |  series
  385.             { $$ = $1; }
  386.         ;
  387.  
  388.  
  389. re2        :  re '/'
  390.             {
  391.             /* this rule is written separately so
  392.              * the reduction will occur before the trailing
  393.              * series is parsed
  394.              */
  395.  
  396.             if ( trlcontxt )
  397.                 synerr( "trailing context used twice" );
  398.             else
  399.                 trlcontxt = true;
  400.  
  401.             if ( varlength )
  402.                 /* we hope the trailing context is fixed-length */
  403.                 varlength = false;
  404.             else
  405.                 headcnt = rulelen;
  406.  
  407.             rulelen = 0;
  408.  
  409.             current_state_type = STATE_TRAILING_CONTEXT;
  410.             $$ = $1;
  411.             }
  412.         ;
  413.  
  414. series          :  series singleton
  415.                         {
  416.             /* this is where concatenation of adjacent patterns
  417.              * gets done
  418.              */
  419.             $$ = link_machines( $1, $2 );
  420.             }
  421.  
  422.         |  singleton
  423.             { $$ = $1; }
  424.         ;
  425.  
  426. singleton       :  singleton '*'
  427.                         {
  428.             varlength = true;
  429.  
  430.             $$ = mkclos( $1 );
  431.             }
  432.  
  433.         |  singleton '+'
  434.             {
  435.             varlength = true;
  436.  
  437.             $$ = mkposcl( $1 );
  438.             }
  439.  
  440.         |  singleton '?'
  441.             {
  442.             varlength = true;
  443.  
  444.             $$ = mkopt( $1 );
  445.             }
  446.  
  447.         |  singleton '{' NUMBER ',' NUMBER '}'
  448.             {
  449.             varlength = true;
  450.  
  451.             if ( $3 > $5 || $3 < 0 )
  452.                 {
  453.                 synerr( "bad iteration values" );
  454.                 $$ = $1;
  455.                 }
  456.             else
  457.                 {
  458.                 if ( $3 == 0 )
  459.                 $$ = mkopt( mkrep( $1, $3, $5 ) );
  460.                 else
  461.                 $$ = mkrep( $1, $3, $5 );
  462.                 }
  463.             }
  464.  
  465.         |  singleton '{' NUMBER ',' '}'
  466.             {
  467.             varlength = true;
  468.  
  469.             if ( $3 <= 0 )
  470.                 {
  471.                 synerr( "iteration value must be positive" );
  472.                 $$ = $1;
  473.                 }
  474.  
  475.             else
  476.                 $$ = mkrep( $1, $3, INFINITY );
  477.             }
  478.  
  479.         |  singleton '{' NUMBER '}'
  480.             {
  481.             /* the singleton could be something like "(foo)",
  482.              * in which case we have no idea what its length
  483.              * is, so we punt here.
  484.              */
  485.             varlength = true;
  486.  
  487.             if ( $3 <= 0 )
  488.                 {
  489.                 synerr( "iteration value must be positive" );
  490.                 $$ = $1;
  491.                 }
  492.  
  493.             else
  494.                 $$ = link_machines( $1, copysingl( $1, $3 - 1 ) );
  495.             }
  496.  
  497.         |  '.'
  498.             {
  499.             if ( ! madeany )
  500.                 {
  501.                 /* create the '.' character class */
  502.                 anyccl = cclinit();
  503.                 ccladd( anyccl, '\n' );
  504.                 cclnegate( anyccl );
  505.  
  506.                 if ( useecs )
  507.                 mkeccl( ccltbl + cclmap[anyccl],
  508.                     ccllen[anyccl], nextecm,
  509.                     ecgroup, csize, csize );
  510.  
  511.                 madeany = true;
  512.                 }
  513.  
  514.             ++rulelen;
  515.  
  516.             $$ = mkstate( -anyccl );
  517.             }
  518.  
  519.         |  fullccl
  520.             {
  521.             if ( ! cclsorted )
  522.                 /* sort characters for fast searching.  We use a
  523.                  * shell sort since this list could be large.
  524.                  */
  525.                 cshell( ccltbl + cclmap[$1], ccllen[$1], true );
  526.  
  527.             if ( useecs )
  528.                 mkeccl( ccltbl + cclmap[$1], ccllen[$1],
  529.                     nextecm, ecgroup, csize, csize );
  530.  
  531.             ++rulelen;
  532.  
  533.             $$ = mkstate( -$1 );
  534.             }
  535.  
  536.         |  PREVCCL
  537.             {
  538.             ++rulelen;
  539.  
  540.             $$ = mkstate( -$1 );
  541.             }
  542.  
  543.         |  '"' string '"'
  544.             { $$ = $2; }
  545.  
  546.         |  '(' re ')'
  547.             { $$ = $2; }
  548.  
  549.         |  CHAR
  550.             {
  551.             ++rulelen;
  552.  
  553.             if ( caseins && $1 >= 'A' && $1 <= 'Z' )
  554.                 $1 = clower( $1 );
  555.  
  556.             $$ = mkstate( $1 );
  557.             }
  558.         ;
  559.  
  560. fullccl        :  '[' ccl ']'
  561.             { $$ = $2; }
  562.  
  563.         |  '[' '^' ccl ']'
  564.             {
  565.             /* *Sigh* - to be compatible Unix lex, negated ccls
  566.              * match newlines
  567.              */
  568. #ifdef NOTDEF
  569.             ccladd( $3, '\n' ); /* negated ccls don't match '\n' */
  570.             cclsorted = false; /* because we added the newline */
  571. #endif
  572.             cclnegate( $3 );
  573.             $$ = $3;
  574.             }
  575.         ;
  576.  
  577. ccl             :  ccl CHAR '-' CHAR
  578.                         {
  579.             if ( $2 > $4 )
  580.                 synerr( "negative range in character class" );
  581.  
  582.             else
  583.                 {
  584.                 if ( caseins )
  585.                 {
  586.                 if ( $2 >= 'A' && $2 <= 'Z' )
  587.                     $2 = clower( $2 );
  588.                 if ( $4 >= 'A' && $4 <= 'Z' )
  589.                     $4 = clower( $4 );
  590.                 }
  591.  
  592.                 for ( i = $2; i <= $4; ++i )
  593.                     ccladd( $1, i );
  594.  
  595.                 /* keep track if this ccl is staying in alphabetical
  596.                  * order
  597.                  */
  598.                 cclsorted = cclsorted && ($2 > lastchar);
  599.                 lastchar = $4;
  600.                 }
  601.  
  602.             $$ = $1;
  603.             }
  604.  
  605.         |  ccl CHAR
  606.                 {
  607.             if ( caseins )
  608.                 if ( $2 >= 'A' && $2 <= 'Z' )
  609.                 $2 = clower( $2 );
  610.  
  611.             ccladd( $1, $2 );
  612.             cclsorted = cclsorted && ($2 > lastchar);
  613.             lastchar = $2;
  614.             $$ = $1;
  615.             }
  616.  
  617.         |
  618.             {
  619.             cclsorted = true;
  620.             lastchar = 0;
  621.             $$ = cclinit();
  622.             }
  623.         ;
  624.  
  625. string        :  string CHAR
  626.                         {
  627.             if ( caseins )
  628.                 if ( $2 >= 'A' && $2 <= 'Z' )
  629.                 $2 = clower( $2 );
  630.  
  631.             ++rulelen;
  632.  
  633.             $$ = link_machines( $1, mkstate( $2 ) );
  634.             }
  635.  
  636.         |
  637.             { $$ = mkstate( SYM_EPSILON ); }
  638.         ;
  639.  
  640. %%
  641.  
  642.  
  643. /* build_eof_action - build the "<<EOF>>" action for the active start
  644.  *                    conditions
  645.  */
  646.  
  647. void build_eof_action()
  648.  
  649.     {
  650.     register int i;
  651.  
  652.     for ( i = 1; i <= actvp; ++i )
  653.     {
  654.     if ( sceof[actvsc[i]] )
  655.         format_pinpoint_message(
  656.         "multiple <<EOF>> rules for start condition %s",
  657.             scname[actvsc[i]] );
  658.  
  659.     else
  660.         {
  661.         sceof[actvsc[i]] = true;
  662.         fprintf( temp_action_file, "case YY_STATE_EOF(%s):\n",
  663.              scname[actvsc[i]] );
  664.         }
  665.     }
  666.  
  667.     line_directive_out( temp_action_file );
  668.     }
  669.  
  670.  
  671. /* synerr - report a syntax error */
  672.  
  673. void synerr( str )
  674. char str[];
  675.  
  676.     {
  677.     syntaxerror = true;
  678.     pinpoint_message( str );
  679.     }
  680.  
  681.  
  682. /* format_pinpoint_message - write out a message formatted with one string,
  683.  *                 pinpointing its location
  684.  */
  685.  
  686. void format_pinpoint_message( msg, arg )
  687. char msg[], arg[];
  688.  
  689.     {
  690.     char errmsg[MAXLINE];
  691.  
  692.     (void) sprintf( errmsg, msg, arg );
  693.     pinpoint_message( errmsg );
  694.     }
  695.  
  696.  
  697. /* pinpoint_message - write out a message, pinpointing its location */
  698.  
  699. void pinpoint_message( str )
  700. char str[];
  701.  
  702.     {
  703.     fprintf( stderr, "\"%s\", line %d: %s\n", infilename, linenum, str );
  704.     }
  705.  
  706.  
  707. /* yyerror - eat up an error message from the parser;
  708.  *         currently, messages are ignore
  709.  */
  710.  
  711. void yyerror( msg )
  712. char msg[];
  713.  
  714.     {
  715.     }
  716.