Plan 9 from Bell Labs’s /usr/web/sources/contrib/steve/root/sys/src/cmd/indent/parse.c

Copyright © 2021 Plan 9 Foundation.
Distributed under the MIT License.
Download the Plan 9 distribution.


/* Copyright (c) 1999, 2000 Carlo Wood.  All rights reserved.
 * Copyright (c) 1994 Joseph Arceneaux.  All rights reserved.
 * Copyright (c) 1985 Sun Microsystems, Inc. Copyright (c) 1980 The Regents
 * of the University of California. Copyright (c) 1976 Board of Trustees of
 * the University of Illinois. All rights reserved.
 *
 * Redistribution and use in source and binary forms are permitted provided
 * that the above copyright notice and this paragraph are duplicated in all
 * such forms and that any documentation, advertising materials, and other
 * materials related to such distribution and use acknowledge that the
 * software was developed by the University of California, Berkeley, the
 * University of Illinois, Urbana, and Sun Microsystems, Inc.  The name of
 * either University or Sun Microsystems may not be used to endorse or
 * promote products derived from this software without specific prior written
 * permission. THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES
 * OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. */

#include "sys.h"
#include "indent.h"
#include "parse.h"
#include "globs.h"

RCSTAG_CC ("$Id: parse.c,v 1.31 2002/08/04 17:08:41 david Exp $");

parser_state_ty *parser_state_tos = NULL;

#define INITIAL_BUFFER_SIZE 1000
#define INITIAL_STACK_SIZE 2

void init_parser (void)
{
    parser_state_tos = (parser_state_ty *) xmalloc (sizeof (parser_state_ty));
    /* GDB_HOOK_parser_state_tos */
    parser_state_tos->p_stack_size  = INITIAL_STACK_SIZE;
    parser_state_tos->p_stack       = (codes_ty *) xmalloc (INITIAL_STACK_SIZE * sizeof (codes_ty));
    parser_state_tos->il            = (int *) xmalloc (INITIAL_STACK_SIZE * sizeof (int));
    parser_state_tos->cstk          = (int *) xmalloc (INITIAL_STACK_SIZE * sizeof (int));
    parser_state_tos->paren_indents_size = 8;
    parser_state_tos->paren_indents = (short *) xmalloc (parser_state_tos->paren_indents_size * sizeof (short));

    /* Although these are supposed to grow if we reach the end,
     * I can find no place in the code which does this. */
  
    combuf = (char *) xmalloc (INITIAL_BUFFER_SIZE);
    labbuf = (char *) xmalloc (INITIAL_BUFFER_SIZE);
    codebuf = (char *) xmalloc (INITIAL_BUFFER_SIZE);

    save_com.size = INITIAL_BUFFER_SIZE;
    save_com.end = save_com.ptr = xmalloc (save_com.size);
    save_com.len = save_com.column = 0;

    di_stack_alloc = 2;
    di_stack = (int *) xmalloc (di_stack_alloc * sizeof (*di_stack));

}

void reset_parser (void)
{
    parser_state_tos->next             = 0;
    parser_state_tos->tos              = 0;
    parser_state_tos->p_stack[0]       = stmt;        /* this is the parser's stack */
    parser_state_tos->last_nl          = true;        /* this is true if the last thing
                                                   * scanned was a newline */
    parser_state_tos->last_token       = start_token;
    parser_state_tos->last_saw_nl      = false;
    parser_state_tos->broken_at_non_nl = false;
    parser_state_tos->box_com          = false;
    parser_state_tos->cast_mask        = 0;
    parser_state_tos->noncast_mask     = 0;
    parser_state_tos->sizeof_mask      = 0;
    parser_state_tos->block_init       = 0;
    parser_state_tos->block_init_level = 0;
    parser_state_tos->col_1            = false;
    parser_state_tos->com_col          = 0;
    parser_state_tos->dec_nest         = 0;
    parser_state_tos->i_l_follow       = 0;
    parser_state_tos->ind_level        = 0;
    parser_state_tos->last_u_d         = false;
    parser_state_tos->p_l_follow       = 0;
    parser_state_tos->paren_level      = 0;
    parser_state_tos->paren_depth      = 0;
    parser_state_tos->search_brace     = false;
    parser_state_tos->use_ff           = false;
    parser_state_tos->its_a_keyword    = false;
    parser_state_tos->sizeof_keyword   = false;
    parser_state_tos->in_parameter_declaration = false;
    parser_state_tos->just_saw_decl    = 0;
    parser_state_tos->in_decl          = false;
    parser_state_tos->decl_on_line     = false;
    parser_state_tos->in_or_st         = 0;
    parser_state_tos->want_blank       = false;
    parser_state_tos->in_stmt          = false;
    parser_state_tos->ind_stmt         = false;
    parser_state_tos->procname         = "\0";
    parser_state_tos->procname_end     = "\0";
    parser_state_tos->classname        = "\0";
    parser_state_tos->classname_end    = "\0";
    parser_state_tos->pcase            = false;
    parser_state_tos->dec_nest         = 0;
    parser_state_tos->can_break        = bb_none;
    parser_state_tos->saw_double_colon = false;

    parser_state_tos->il[0]            = 0;
    parser_state_tos->cstk[0]          = 0;

    save_com.len = save_com.column = 0;

    di_stack[parser_state_tos->dec_nest] = 0;

    l_com = combuf + INITIAL_BUFFER_SIZE - 5;
    l_lab = labbuf + INITIAL_BUFFER_SIZE - 5;
    l_code = codebuf + INITIAL_BUFFER_SIZE - 5;
    combuf[0] = codebuf[0] = labbuf[0] = ' ';
    combuf[1] = codebuf[1] = labbuf[1] = '\0';

    else_or_endif = false;
    s_lab = e_lab = labbuf + 1;
    s_code = e_code = codebuf + 1;
    s_com = e_com = combuf + 1;

    line_no = 1;
    had_eof = false;
    break_comma = false;
    bp_save = 0;
    be_save = 0;
  
    if (settings.tabsize <= 0)
    {
        settings.tabsize = 1;
    }
  
    prefix_blankline_requested = 0;
}

/* like ++parser_state_tos->tos but checks for stack overflow and extends
 * stack if necessary.  */

int inc_pstack (void)
{
    if (++parser_state_tos->tos >= parser_state_tos->p_stack_size)
    {
        parser_state_tos->p_stack_size *= 2;
        parser_state_tos->p_stack =
                (codes_ty *) xrealloc ((char *) parser_state_tos->p_stack,
                                       parser_state_tos->p_stack_size * sizeof (codes_ty));
        parser_state_tos->il =
                (int *) xrealloc ((char *) parser_state_tos->il, parser_state_tos->p_stack_size * sizeof (int));
        parser_state_tos->cstk =
                (int *) xrealloc ((char *) parser_state_tos->cstk, parser_state_tos->p_stack_size * sizeof (int));
    }

    parser_state_tos->cstk[parser_state_tos->tos] = parser_state_tos->cstk[parser_state_tos->tos - 1];
    return parser_state_tos->tos;
}

#ifdef DEBUG
static char **debug_symbol_strings;

void debug_init (void)
{
    int size = ((int) number_of_codes) * sizeof (char *);

    debug_symbol_strings = (char **) xmalloc (size);

    debug_symbol_strings[code_eof]      = "code_eof";
    debug_symbol_strings[newline]       = "newline";
    debug_symbol_strings[lparen]        = "lparen";
    debug_symbol_strings[rparen]        = "rparen";
    debug_symbol_strings[start_token]   = "start_token";
    debug_symbol_strings[unary_op]      = "unary_op";
    debug_symbol_strings[binary_op]     = "binary_op";
    debug_symbol_strings[postop]        = "postop";
    debug_symbol_strings[question]      = "question";
    debug_symbol_strings[casestmt]      = "casestmt";
    debug_symbol_strings[colon]         = "colon";
    debug_symbol_strings[doublecolon]   = "doublecolon";
    debug_symbol_strings[semicolon]     = "semicolon";
    debug_symbol_strings[lbrace]        = "lbrace";
    debug_symbol_strings[rbrace]        = "rbrace";
    debug_symbol_strings[ident]         = "ident";
    debug_symbol_strings[overloaded]    = "overloaded";
    debug_symbol_strings[cpp_operator]  = "cpp_operator";
    debug_symbol_strings[comma]         = "comma";
    debug_symbol_strings[comment]       = "comment";
    debug_symbol_strings[cplus_comment] = "cplus_comment";
    debug_symbol_strings[swstmt]        = "swstmt";
    debug_symbol_strings[preesc]        = "preesc";
    debug_symbol_strings[form_feed]     = "form_feed";
    debug_symbol_strings[decl]          = "decl";
    debug_symbol_strings[sp_paren]      = "sp_paren";
    debug_symbol_strings[sp_nparen]     = "sp_nparen";
    debug_symbol_strings[sp_else]       = "sp_else";
    debug_symbol_strings[ifstmt]        = "ifstmt";
    debug_symbol_strings[elseifstmt]    = "elseifstmt";
    debug_symbol_strings[whilestmt]     = "whilestmt";
    debug_symbol_strings[forstmt]       = "forstmt";
    debug_symbol_strings[stmt]          = "stmt";
    debug_symbol_strings[stmtl]         = "stmtl";
    debug_symbol_strings[elselit]       = "elselit";
    debug_symbol_strings[dolit]         = "dolit";
    debug_symbol_strings[dohead]        = "dohead";
    debug_symbol_strings[dostmt]        = "dostmt";
    debug_symbol_strings[ifhead]        = "ifhead";
    debug_symbol_strings[elsehead]      = "elsehead";
    debug_symbol_strings[struct_delim]  = "struct_delim";
    debug_symbol_strings[attribute]     = "attribute";
}

#endif

exit_values_ty parse (
     codes_ty tk)               /* the code for the construct scanned */
{
    int i;

#ifdef DEBUG
    if (debug)
    {
        if (tk >= code_eof && tk < number_of_codes)
        {
            printf ("Parse: %s\n", debug_symbol_strings[tk]);
        }
        else
        {
            printf ("Parse: Unknown code: %d for %s\n", (int) tk, token ? token : "NULL");
        }
    }
#endif

    while ((parser_state_tos->p_stack[parser_state_tos->tos] == ifhead) &&
           (tk != elselit))
    {
        /* true if we have an if without an else */

        /* apply the if(..) stmt ::= stmt reduction */
        
        parser_state_tos->p_stack[parser_state_tos->tos] = stmt;
        reduce ();              /* see if this allows any reduction */
    }


    switch (tk)
    {
        /* go on and figure out what to do with the input */

        case decl:
            /* scanned a declaration word */
            parser_state_tos->search_brace = settings.braces_on_struct_decl_line;

            /* indicate that following brace should be on same line */
            
            if ((parser_state_tos->p_stack[parser_state_tos->tos] != decl) &&
                (parser_state_tos->block_init == 0))
            {
                /* only put one declaration onto stack */

                break_comma = true;     /* while in declaration, newline should be
                                         * forced after comma */
                inc_pstack ();
                parser_state_tos->p_stack[parser_state_tos->tos] = decl;
                parser_state_tos->il[parser_state_tos->tos] = parser_state_tos->i_l_follow;

                if (settings.ljust_decl)
                {                       /* only do if we want left justified
                                         * declarations */
                    parser_state_tos->ind_level = 0;
                    for (i = parser_state_tos->tos - 1; i > 0; --i)
                    {
                        if (parser_state_tos->p_stack[i] == decl)
                        {
                            /* indentation is number of declaration levels deep we are
                             * times spaces per level */
                            parser_state_tos->ind_level += settings.ind_size;
                        }
                    }
                    
                    parser_state_tos->i_l_follow = parser_state_tos->ind_level;
                }
            }
            break;

        case ifstmt:            /* scanned if (...) */
            if (parser_state_tos->p_stack[parser_state_tos->tos] == elsehead)
            {
                parser_state_tos->i_l_follow = parser_state_tos->il[parser_state_tos->tos];
            }
            
        case dolit:             /* 'do' */
        case forstmt:           /* for (...) */
        case casestmt:          /* case n: */
            inc_pstack ();
            parser_state_tos->p_stack[parser_state_tos->tos] = tk;
            parser_state_tos->ind_level                 = parser_state_tos->i_l_follow;
            parser_state_tos->il[parser_state_tos->tos] = parser_state_tos->ind_level;
            
            if (tk != casestmt)
            {
                parser_state_tos->i_l_follow += settings.ind_size;       /* subsequent statements
                                                                 * should be indented */
            }
            
            parser_state_tos->search_brace = settings.btype_2;
            break;

        case lbrace:            /* scanned { */
            break_comma = false;        /* don't break comma in an initial list */
            if (parser_state_tos->p_stack[parser_state_tos->tos] == stmt
                || parser_state_tos->p_stack[parser_state_tos->tos] == stmtl)
            {
                /* it is a random, isolated stmt group or a declaration */
                parser_state_tos->i_l_follow += settings.ind_size;
            }
            else if (parser_state_tos->p_stack[parser_state_tos->tos] == decl)
            {
                parser_state_tos->i_l_follow += settings.ind_size;
                
                if ( ( (parser_state_tos->last_rw == rw_struct_like) ||
                       (parser_state_tos->last_rw == rw_enum)) &&
                     ( (parser_state_tos->block_init != 1) ||
                       (parser_state_tos->block_init_level == 0)) &&
                     (parser_state_tos->last_token != rparen) &&
                     (!settings.braces_on_struct_decl_line))
                {
                    parser_state_tos->ind_level += settings.struct_brace_indent;
                    parser_state_tos->i_l_follow += settings.struct_brace_indent;
                }
            }
            else if (parser_state_tos->p_stack[parser_state_tos->tos] == casestmt)
            {
                parser_state_tos->ind_level += settings.case_brace_indent - settings.ind_size;
                parser_state_tos->i_l_follow += settings.case_brace_indent;
            }
            else
            {
                /* It is a group as part of a while, for, etc. */

                /* Only do this if there is nothing on the line */
                if (s_code == e_code)
                {
                    parser_state_tos->ind_level -= settings.ind_size;
                }

                /* For -bl formatting, indent by settings.brace_indent additional spaces
                 * e.g. if (foo == bar) { <--> settings.brace_indent spaces (in this
                 * example, 4) */
                
                if (!settings.btype_2)
                {
                    parser_state_tos->ind_level += settings.brace_indent;
                    parser_state_tos->i_l_follow += settings.brace_indent;
                }

                if (parser_state_tos->p_stack[parser_state_tos->tos] == swstmt)
                {
                    parser_state_tos->i_l_follow += settings.case_indent;
                }
            }

            inc_pstack ();
            parser_state_tos->p_stack[parser_state_tos->tos] = lbrace;
            parser_state_tos->il[parser_state_tos->tos] = parser_state_tos->ind_level;
            
            inc_pstack ();
            parser_state_tos->p_stack[parser_state_tos->tos] = stmt;
            
            /* allow null stmt between braces */
            
            parser_state_tos->il[parser_state_tos->tos] = parser_state_tos->i_l_follow;
            break;

        case whilestmt:         /* scanned while (...) */
            if (parser_state_tos->p_stack[parser_state_tos->tos] == dohead)
            {
                /* it is matched with do stmt */
                parser_state_tos->i_l_follow = parser_state_tos->il[parser_state_tos->tos];
                parser_state_tos->ind_level   = parser_state_tos->il[parser_state_tos->tos];
                inc_pstack ();
                parser_state_tos->p_stack[parser_state_tos->tos] = whilestmt;

                parser_state_tos->ind_level                 = parser_state_tos->i_l_follow;
                parser_state_tos->il[parser_state_tos->tos] = parser_state_tos->i_l_follow;
            }
            else
            {                   /* it is a while loop */
                inc_pstack ();
                parser_state_tos->p_stack[parser_state_tos->tos] = whilestmt;
                parser_state_tos->il[parser_state_tos->tos] = parser_state_tos->i_l_follow;
                parser_state_tos->i_l_follow += settings.ind_size;
                parser_state_tos->search_brace = settings.btype_2;
            }

            break;

        case elselit:           /* scanned an else */

            if (parser_state_tos->p_stack[parser_state_tos->tos] != ifhead)
            {
                ERROR (_("Unmatched 'else'"), 0, 0);
            }
            else
            {
                /* indentation for else should be same as for if */
                parser_state_tos->ind_level = parser_state_tos->il[parser_state_tos->tos];
                
                /* everything following should be in 1 level */
                parser_state_tos->i_l_follow = (parser_state_tos->ind_level + settings.ind_size);

                parser_state_tos->p_stack[parser_state_tos->tos] = elsehead;
                /* remember if with else */
                parser_state_tos->search_brace = true;
            }
            break;

        case rbrace:            /* scanned a } */
            /* stack should have <lbrace> <stmt> or <lbrace> <stmtl> */
            if (parser_state_tos->p_stack[parser_state_tos->tos - 1] == lbrace)
            {
                parser_state_tos->i_l_follow = parser_state_tos->il[--parser_state_tos->tos];
                parser_state_tos->ind_level  = parser_state_tos->i_l_follow;
                parser_state_tos->p_stack[parser_state_tos->tos] = stmt;
            }
            else
            {
                ERROR (_("Stmt nesting error."), 0, 0);
            }
            break;

        case swstmt:            /* had switch (...) */
            inc_pstack ();
            parser_state_tos->p_stack[parser_state_tos->tos] = swstmt;
            parser_state_tos->cstk[parser_state_tos->tos] = settings.case_indent + parser_state_tos->i_l_follow;
            if (!settings.btype_2)
            {
                parser_state_tos->cstk[parser_state_tos->tos] += settings.brace_indent;
            }

            /* save current case indent level */
            parser_state_tos->il[parser_state_tos->tos] = parser_state_tos->i_l_follow;
            
            /* case labels should be one level down from switch, plus
             * `settings.case_indent' if any.  Then, statements should be the `settings.ind_size'
             * further. */
            
            parser_state_tos->i_l_follow += settings.ind_size;
            parser_state_tos->search_brace = settings.btype_2;
            break;

        case semicolon:         /* this indicates a simple stmt */
            break_comma = false;        /* turn off flag to break after commas in a
                                         * declaration */
            
            if (parser_state_tos->p_stack[parser_state_tos->tos] == dostmt)
            {
                parser_state_tos->p_stack[parser_state_tos->tos] = stmt;
            }
            else
            {
                inc_pstack ();
                parser_state_tos->p_stack[parser_state_tos->tos] = stmt;
                parser_state_tos->il[parser_state_tos->tos] = parser_state_tos->ind_level;
            }
            break;

            /* This is a fatal error which cases the program to exit. */
        default:
            fatal (_("Unknown code to parser"), 0);
    }

    reduce ();                  /* see if any reduction can be done */

#ifdef DEBUG
    if (debug)
    {
        printf ("\n");
        
        printf (_("ParseStack [%d]:\n"), (int) parser_state_tos->p_stack_size);
        
        for (i = 1; i <= parser_state_tos->tos; ++i)
        {
            printf (_("  stack[%d] =>   stack: %d   ind_level: %d\n"),
                    (int) i, (int) parser_state_tos->p_stack[i],
                    (int) parser_state_tos->il[i]);
        }
        
        printf ("\n");
    }
#endif

    return total_success;
}

/* NAME: reduce
 *
 * FUNCTION: Implements the reduce part of the parsing algorithm
 *
 * ALGORITHM: The following reductions are done.  Reductions are repeated until
 *  no more are possible.
 *  
 *  Old TOS              New TOS <stmt> <stmt>           <stmtl> <stmtl> <stmt>
 *     <stmtl> do <stmt>                 dohead <dohead> <whilestmt>
 *     <dostmt> if <stmt>                "ifstmt" switch <stmt>          <stmt>
 *     decl <stmt>               <stmt> "ifelse" <stmt>          <stmt> for
 *     <stmt>                    <stmt> while <stmt>                     <stmt>
 *     "dostmt" while            <stmt>
 *  
 *  On each reduction, parser_state_tos->i_l_follow (the indentation for the
 *     following line) is set to the indentation level associated with the old
 *     TOS.
 *  
 *  PARAMETERS: None
 *  
 *  RETURNS: Nothing
 *  
 *  GLOBALS: parser_state_tos->cstk parser_state_tos->i_l_follow =
 *     parser_state_tos->il parser_state_tos->p_stack = parser_state_tos->tos =
 *  
 *  CALLS: None
 *  
 *  CALLED BY: parse
 *  
 *  HISTORY: initial coding         November 1976   D A Willcox of CAC
 *  
*/
/*----------------------------------------------*\
|   REDUCTION PHASE                                 |
\*----------------------------------------------*/

void reduce (void)
{
    int i;

    for (;;)
    {
        /* keep looping until there is nothing left to reduce */

        switch (parser_state_tos->p_stack[parser_state_tos->tos])
        {
            case stmt:
                switch (parser_state_tos->p_stack[parser_state_tos->tos - 1])
                {
                    case stmt:
                    case stmtl:
                        /* stmtl stmt or stmt stmt */
                        parser_state_tos->p_stack[--parser_state_tos->tos] = stmtl;
                        break;

                    case dolit: /* <do> <stmt> */
                        parser_state_tos->p_stack[--parser_state_tos->tos] = dohead;
                        parser_state_tos->i_l_follow = parser_state_tos->il[parser_state_tos->tos];
                        break;

                    case ifstmt:
                        /* <if> <stmt> */
                        parser_state_tos->p_stack[--parser_state_tos->tos] = ifhead;
                        for (i = parser_state_tos->tos - 1;
                             ( (parser_state_tos->p_stack[i] != stmt) &&
                               (parser_state_tos->p_stack[i] != stmtl) &&
                               (parser_state_tos->p_stack[i] != lbrace));
                             --i)
                        {
                        }
                        
                        parser_state_tos->i_l_follow = parser_state_tos->il[i];
                        
                        /* for the time being, we will assume that there is no else on
                         * this if, and set the indentation level accordingly. If an
                         * else is scanned, it will be fixed up later */
                        
                        break;

                    case swstmt:
                        /* <switch> <stmt> */
                    case decl:          /* finish of a declaration */
                    case elsehead:
                        /* <<if> <stmt> else> <stmt> */
                    case forstmt:
                        /* <for> <stmt> */
                    case casestmt:
                        /* <case n:> <stmt> */
                    case whilestmt:
                        /* <while> <stmt> */
                        parser_state_tos->p_stack[--parser_state_tos->tos] = stmt;
                        parser_state_tos->i_l_follow = parser_state_tos->il[parser_state_tos->tos];
                        break;

                    default:            /* <anything else> <stmt> */
                        return;

                }                       /* end of section for <stmt> on top of stack */
                break;

            case whilestmt:     /* while (...) on top */
                if (parser_state_tos->p_stack[parser_state_tos->tos - 1] == dohead)
                {
                    /* it is termination of a do while */
                    parser_state_tos->p_stack[--parser_state_tos->tos] = dostmt;
                    break;
                }
                else
                    return;

            default:            /* anything else on top */
                return;

        }
    }
}

/* This kludge is called from main.  It is just like parse(semicolon) except
 * that it does not clear break_comma.  Leaving break_comma alone is
 * necessary to make sure that "int foo(), bar()" gets formatted correctly
 * under -bc.  */

void parse_lparen_in_decl (void)
{
  inc_pstack ();
  parser_state_tos->p_stack[parser_state_tos->tos] = stmt;
  parser_state_tos->il[parser_state_tos->tos]      = parser_state_tos->ind_level;

  reduce ();
}

Bell Labs OSI certified Powered by Plan 9

(Return to Plan 9 Home Page)

Copyright © 2021 Plan 9 Foundation. All Rights Reserved.
Comments to webmaster@9p.io.