Пример #1
0
/**
 * Change the top-level indentation only by changing the column member in
 * the chunk structures.
 * The level indicator must already be set.
 */
void indent_text(void)
{
    chunk_t            *pc;
    chunk_t            *next;
    chunk_t            *prev       = NULL;
    bool did_newline = true;
    int idx;
    int vardefcol   = 0;
    int indent_size = cpd.settings[UO_indent_columns].n;
    int tmp;
    struct parse_frame frm;
    bool in_preproc = false, was_preproc = false;
    int indent_column;
    int cout_col            = 0;                 // for aligning << stuff
    int cout_level          = 0;                 // for aligning << stuff
    int parent_token_indent = 0;

    memset(&frm, 0, sizeof(frm));

    /* dummy top-level entry */
    frm.pse[0].indent     = 1;
    frm.pse[0].indent_tmp = 1;
    frm.pse[0].type       = CT_EOF;

    pc = chunk_get_head();

    while (pc != NULL)
    {
        /* Handle proprocessor transitions */
        was_preproc = in_preproc;
        in_preproc  = (pc->flags & PCF_IN_PREPROC) != 0;

        if (cpd.settings[UO_indent_brace_parent].b)
            parent_token_indent = token_indent(pc->parent_type);

        /* Clean up after a #define */
        if (!in_preproc)
            while ((frm.pse_tos > 0) && frm.pse[frm.pse_tos].in_preproc)
                indent_pse_pop(frm, pc);

        else
        {
            pf_check(&frm, pc);

            if (!was_preproc)
            {
                /* Transition into a preproc by creating a dummy indent */
                frm.level++;
                indent_pse_push(frm, pc);

                frm.pse[frm.pse_tos].indent     = 1 + indent_size;
                frm.pse[frm.pse_tos].indent_tmp = frm.pse[frm.pse_tos].indent;
            }
        }

        if ((cout_col > 0) &&
                (chunk_is_semicolon(pc) ||
                 (pc->level < cout_level)))
        {
            cout_col   = 0;
            cout_level = 0;
        }

        /**
         * Handle non-brace closures
         */

        int old_pse_tos;

        do
        {
            old_pse_tos = frm.pse_tos;

            /* End anything that drops a level
             * REVISIT: not sure about the preproc check
             */
            if (!chunk_is_newline(pc) &&
                    !chunk_is_comment(pc) &&
                    ((pc->flags & PCF_IN_PREPROC) == 0) &&
                    (frm.pse[frm.pse_tos].level > pc->level))
                indent_pse_pop(frm, pc);

            if (frm.pse[frm.pse_tos].level == pc->level)
            {
                /* process virtual braces closes (no text output) */
                if ((pc->type == CT_VBRACE_CLOSE) &&
                        (frm.pse[frm.pse_tos].type == CT_VBRACE_OPEN))
                {
                    indent_pse_pop(frm, pc);
                    frm.level--;
                    pc = chunk_get_next(pc);
                }

                /* End any assign operations with a semicolon on the same level */
                if ((frm.pse[frm.pse_tos].type == CT_ASSIGN) &&
                        (chunk_is_semicolon(pc) ||
                         (pc->type == CT_COMMA) ||
                         (pc->type == CT_BRACE_OPEN)))
                    indent_pse_pop(frm, pc);

                /* End any CPP class colon crap */
                if ((frm.pse[frm.pse_tos].type == CT_CLASS_COLON) &&
                        ((pc->type == CT_BRACE_OPEN) ||
                         chunk_is_semicolon(pc)))
                    indent_pse_pop(frm, pc);

                /* a case is ended with another case or a close brace */
                if ((frm.pse[frm.pse_tos].type == CT_CASE) &&
                        ((pc->type == CT_BRACE_CLOSE) ||
                         (pc->type == CT_CASE)))
                    indent_pse_pop(frm, pc);

                /* a return is ended with a semicolon */
                if ((frm.pse[frm.pse_tos].type == CT_RETURN) &&
                        chunk_is_semicolon(pc))
                    indent_pse_pop(frm, pc);

                /* Close out parens and squares */
                if ((frm.pse[frm.pse_tos].type == (pc->type - 1)) &&
                        ((pc->type == CT_PAREN_CLOSE) ||
                         (pc->type == CT_SPAREN_CLOSE) ||
                         (pc->type == CT_FPAREN_CLOSE) ||
                         (pc->type == CT_SQUARE_CLOSE) ||
                         (pc->type == CT_ANGLE_CLOSE)))
                {
                    indent_pse_pop(frm, pc);
                    frm.paren_count--;
                }
            }
        }
        while (old_pse_tos > frm.pse_tos);

        /* Grab a copy of the current indent */
        indent_column = frm.pse[frm.pse_tos].indent_tmp;

        if (!chunk_is_newline(pc) && !chunk_is_comment(pc))
        {
            LOG_FMT(LINDPC, " -=[ %.*s ]=- top=%d %s %d/%d\n",
                    pc->len, pc->str,
                    frm.pse_tos,
                    get_token_name(frm.pse[frm.pse_tos].type),
                    frm.pse[frm.pse_tos].indent_tmp,
                    frm.pse[frm.pse_tos].indent);
        }

        /**
         * Handle stuff that can affect the current indent:
         *  - brace close
         *  - vbrace open
         *  - brace open
         *  - case         (immediate)
         *  - labels       (immediate)
         *  - class colons (immediate)
         *
         * And some stuff that can't
         *  - open paren
         *  - open square
         *  - assignment
         *  - return
         */

        if (pc->type == CT_BRACE_CLOSE)
        {
            if (frm.pse[frm.pse_tos].type == CT_BRACE_OPEN)
            {
                indent_pse_pop(frm, pc);
                frm.level--;

                /* Update the indent_column if needed */
                if (!cpd.settings[UO_indent_braces].b &&
                        (parent_token_indent == 0))
                    indent_column = frm.pse[frm.pse_tos].indent_tmp;

                if ((pc->parent_type == CT_IF) ||
                        (pc->parent_type == CT_ELSE) ||
                        (pc->parent_type == CT_ELSEIF) ||
                        (pc->parent_type == CT_DO) ||
                        (pc->parent_type == CT_WHILE) ||
                        (pc->parent_type == CT_SWITCH) ||
                        (pc->parent_type == CT_FOR))
                    indent_column += cpd.settings[UO_indent_brace].n;
            }
        }
        else if (pc->type == CT_VBRACE_OPEN)
        {
            frm.level++;
            indent_pse_push(frm, pc);

            frm.pse[frm.pse_tos].indent     = frm.pse[frm.pse_tos - 1].indent + indent_size;
            frm.pse[frm.pse_tos].indent_tmp = frm.pse[frm.pse_tos].indent;

            /* Always indent on virtual braces */
            indent_column = frm.pse[frm.pse_tos].indent_tmp;
        }
        else if (pc->type == CT_BRACE_OPEN)
        {
            frm.level++;
            indent_pse_push(frm, pc);

            if (frm.paren_count != 0)
                /* We are inside ({ ... }) -- indent one tab from the paren */
                frm.pse[frm.pse_tos].indent = frm.pse[frm.pse_tos - 1].indent_tmp + indent_size;
            else
            {
                /* Use the prev indent level + indent_size. */
                frm.pse[frm.pse_tos].indent = frm.pse[frm.pse_tos - 1].indent + indent_size;

                /* If this brace is part of a statement, bump it out by indent_brace */
                if ((pc->parent_type == CT_IF) ||
                        (pc->parent_type == CT_ELSE) ||
                        (pc->parent_type == CT_ELSEIF) ||
                        (pc->parent_type == CT_DO) ||
                        (pc->parent_type == CT_WHILE) ||
                        (pc->parent_type == CT_SWITCH) ||
                        (pc->parent_type == CT_FOR))
                {
                    if (parent_token_indent != 0)
                        frm.pse[frm.pse_tos].indent += parent_token_indent - indent_size;
                    else
                    {
                        frm.pse[frm.pse_tos].indent += cpd.settings[UO_indent_brace].n;
                        indent_column += cpd.settings[UO_indent_brace].n;
                    }
                }
                else if (pc->parent_type == CT_CASE)
                {
                    /* The indent_case_brace setting affects the parent CT_CASE */
                    frm.pse[frm.pse_tos].indent_tmp += cpd.settings[UO_indent_case_brace].n;
                    frm.pse[frm.pse_tos].indent     += cpd.settings[UO_indent_case_brace].n;
                }
                else if ((pc->parent_type == CT_CLASS) && !cpd.settings[UO_indent_class].b)
                    frm.pse[frm.pse_tos].indent -= indent_size;
                else if ((pc->parent_type == CT_NAMESPACE) && !cpd.settings[UO_indent_namespace].b)
                    frm.pse[frm.pse_tos].indent -= indent_size;
            }

            if ((pc->flags & PCF_DONT_INDENT) != 0)
            {
                frm.pse[frm.pse_tos].indent = pc->column;
                indent_column = pc->column;
            }
            else
            {
                /**
                 * If there isn't a newline between the open brace and the next
                 * item, just indent to wherever the next token is.
                 * This covers this sort of stuff:
                 * { a++;
                 *   b--; };
                 */
                next = chunk_get_next_ncnl(pc);

                if (!chunk_is_newline_between(pc, next))
                    frm.pse[frm.pse_tos].indent = next->column;

                frm.pse[frm.pse_tos].indent_tmp = frm.pse[frm.pse_tos].indent;
                frm.pse[frm.pse_tos].open_line  = pc->orig_line;

                /* Update the indent_column if needed */
                if (cpd.settings[UO_indent_braces].n ||
                        (parent_token_indent != 0))
                    indent_column = frm.pse[frm.pse_tos].indent_tmp;
            }
        }
        else if (pc->type == CT_CASE)
        {
            /* Start a case - indent UO_indent_switch_case from the switch level */
            tmp = frm.pse[frm.pse_tos].indent + cpd.settings[UO_indent_switch_case].n;

            indent_pse_push(frm, pc);

            frm.pse[frm.pse_tos].indent     = tmp;
            frm.pse[frm.pse_tos].indent_tmp = tmp - indent_size;

            /* Always set on case statements */
            indent_column = frm.pse[frm.pse_tos].indent_tmp;
        }
        else if (pc->type == CT_LABEL)
        {
            /* Labels get sent to the left or backed up */
            if (cpd.settings[UO_indent_label].n > 0)
                indent_column = cpd.settings[UO_indent_label].n;
            else
                indent_column = frm.pse[frm.pse_tos].indent +
                                cpd.settings[UO_indent_label].n;
        }
        else if (pc->type == CT_CLASS_COLON)
        {
            /* just indent one level */
            indent_pse_push(frm, pc);
            frm.pse[frm.pse_tos].indent     = frm.pse[frm.pse_tos - 1].indent_tmp + indent_size;
            frm.pse[frm.pse_tos].indent_tmp = frm.pse[frm.pse_tos].indent;

            indent_column = frm.pse[frm.pse_tos].indent_tmp;

            if (cpd.settings[UO_indent_class_colon].b)
            {
                prev = chunk_get_prev(pc);

                if (chunk_is_newline(prev))
                    frm.pse[frm.pse_tos].indent += 2;
                /* don't change indent of current line */
            }
        }
        else if ((pc->type == CT_PAREN_OPEN) ||
                 (pc->type == CT_SPAREN_OPEN) ||
                 (pc->type == CT_FPAREN_OPEN) ||
                 (pc->type == CT_SQUARE_OPEN) ||
                 (pc->type == CT_ANGLE_OPEN))
        {
            /* Open parens and squares - never update indent_column */
            indent_pse_push(frm, pc);
            frm.pse[frm.pse_tos].indent = pc->column + pc->len;

            if (cpd.settings[UO_indent_func_call_param].b &&
                    (pc->type == CT_FPAREN_OPEN) &&
                    (pc->parent_type == CT_FUNC_CALL))
                frm.pse[frm.pse_tos].indent = frm.pse[frm.pse_tos - 1].indent + indent_size;

            if ((chunk_is_str(pc, "(", 1) && !cpd.settings[UO_indent_paren_nl].b) ||
                    (chunk_is_str(pc, "[", 1) && !cpd.settings[UO_indent_square_nl].b))
            {
                next = chunk_get_next_nc(pc);

                if (chunk_is_newline(next))
                {
                    int sub = 1;

                    if (frm.pse[frm.pse_tos - 1].type == CT_ASSIGN)
                        sub = 2;

                    frm.pse[frm.pse_tos].indent = frm.pse[frm.pse_tos - sub].indent + indent_size;
                }
            }

            frm.pse[frm.pse_tos].indent_tmp = frm.pse[frm.pse_tos].indent;
            frm.paren_count++;
        }
        else if (pc->type == CT_ASSIGN)
        {
            /**
             * if there is a newline after the '=', just indent one level,
             * otherwise align on the '='.
             * Never update indent_column.
             */
            next = chunk_get_next(pc);

            if (next != NULL)
            {
                indent_pse_push(frm, pc);

                if (chunk_is_newline(next))
                    frm.pse[frm.pse_tos].indent = frm.pse[frm.pse_tos - 1].indent_tmp + indent_size;
                else
                    frm.pse[frm.pse_tos].indent = pc->column + pc->len + 1;

                frm.pse[frm.pse_tos].indent_tmp = frm.pse[frm.pse_tos].indent;
            }
        }
        else if (pc->type == CT_RETURN)
        {
            /* don't count returns inside a () or [] */
            if (pc->level == pc->brace_level)
            {
                indent_pse_push(frm, pc);
                frm.pse[frm.pse_tos].indent     = frm.pse[frm.pse_tos - 1].indent + pc->len + 1;
                frm.pse[frm.pse_tos].indent_tmp = frm.pse[frm.pse_tos - 1].indent;
            }
        }
        else if (chunk_is_str(pc, "<<", 2))
        {
            if (cout_col == 0)
            {
                cout_col   = pc->column;
                cout_level = pc->level;
            }
        }
        else
        {
            /* anything else? */
        }

        /**
         * Indent the line if needed
         */
        if (did_newline && !chunk_is_newline(pc) && (pc->len != 0))
        {
            /**
             * Check for special continuations.
             * Note that some of these could be done as a stack item like
             * everything else
             */

            prev = chunk_get_prev_ncnl(pc);

            if ((pc->type == CT_MEMBER) ||
                    (pc->type == CT_DC_MEMBER) ||
                    ((prev != NULL) &&
                     ((prev->type == CT_MEMBER) ||
                      (prev->type == CT_DC_MEMBER))))
            {
                tmp = cpd.settings[UO_indent_member].n + indent_column;
                LOG_FMT(LINDENT, "%s: %d] member => %d\n",
                        __func__, pc->orig_line, tmp);
                reindent_line(pc, tmp);
            }
            else if (chunk_is_str(pc, "<<", 2) && (cout_col > 0))
            {
                LOG_FMT(LINDENT, "%s: %d] cout_col => %d\n",
                        __func__, pc->orig_line, cout_col);
                reindent_line(pc, cout_col);
            }
            else if ((vardefcol > 0) &&
                     (pc->type == CT_WORD) &&
                     ((pc->flags & PCF_VAR_DEF) != 0) &&
                     (prev != NULL) && (prev->type == CT_COMMA))
            {
                LOG_FMT(LINDENT, "%s: %d] Vardefcol => %d\n",
                        __func__, pc->orig_line, vardefcol);
                reindent_line(pc, vardefcol);
            }
            else if ((pc->type == CT_STRING) && (prev->type == CT_STRING) &&
                     cpd.settings[UO_indent_align_string].b)
            {
                LOG_FMT(LINDENT, "%s: %d] String => %d\n",
                        __func__, pc->orig_line, prev->column);
                reindent_line(pc, prev->column);
            }
            else if (chunk_is_comment(pc))
            {
                LOG_FMT(LINDENT, "%s: %d] comment => %d\n",
                        __func__, pc->orig_line, frm.pse[frm.pse_tos].indent_tmp);
                indent_comment(pc, frm.pse[frm.pse_tos].indent_tmp);
            }
            else if (pc->type == CT_PREPROC)
            {
                /* Preprocs are always in column 1. See indent_preproc() */
                if (pc->column != 1)
                    reindent_line(pc, 1);
            }
            else
            {
                if (pc->column != indent_column)
                {
                    LOG_FMT(LINDENT, "%s: %d] indent => %d [%.*s]\n",
                            __func__, pc->orig_line, indent_column, pc->len, pc->str);
                    reindent_line(pc, indent_column);
                }
            }

            did_newline = false;
        }

        /**
         * Handle variable definition continuation indenting
         */
        if ((pc->type == CT_WORD) &&
                ((pc->flags & PCF_IN_FCN_DEF) == 0) &&
                ((pc->flags & PCF_VAR_1ST_DEF) == PCF_VAR_1ST_DEF))
            vardefcol = pc->column;

        if (chunk_is_semicolon(pc) ||
                ((pc->type == CT_BRACE_OPEN) && (pc->parent_type == CT_FUNCTION)))
            vardefcol = 0;

        /* if we hit a newline, reset indent_tmp */
        if (chunk_is_newline(pc) ||
                (pc->type == CT_COMMENT_MULTI) ||
                (pc->type == CT_COMMENT_CPP))
        {
            frm.pse[frm.pse_tos].indent_tmp = frm.pse[frm.pse_tos].indent;

            /**
             * Handle the case of a multi-line #define w/o anything on the
             * first line (indent_tmp will be 1 or 0)
             */
            if ((pc->type == CT_NL_CONT) &&
                    (frm.pse[frm.pse_tos].indent_tmp <= indent_size))
                frm.pse[frm.pse_tos].indent_tmp = indent_size + 1;

            /* Get ready to indent the next item */
            did_newline = true;
        }

        if (!chunk_is_comment(pc) && !chunk_is_newline(pc))
            prev = pc;

        pc = chunk_get_next(pc);
    }

    /* Throw out any stuff inside a preprocessor - no need to warn */
    while ((frm.pse_tos > 0) && frm.pse[frm.pse_tos].in_preproc)
        indent_pse_pop(frm, pc);

    for (idx = 1; idx <= frm.pse_tos; idx++)
    {
        LOG_FMT(LWARN, "%s:%d Unmatched %s\n",
                cpd.filename, frm.pse[idx].open_line,
                get_token_name(frm.pse[idx].type));
        cpd.error_count++;
    }
}
Пример #2
0
/**
 * At the heart of this algorithm are two stacks.
 * There is the Paren Stack (PS) and the Frame stack.
 *
 * The PS (pse in the code) keeps track of braces, parens,
 * if/else/switch/do/while/etc items -- anything that is nestable.
 * Complex statements go through stages.
 * Take this simple if statement as an example:
 *   if ( x ) { x--; }
 *
 * The stack would change like so: 'token' stack afterwards
 * 'if' [IF - 1]
 * '('  [IF - 1] [PAREN OPEN]
 * 'x'  [IF - 1] [PAREN OPEN]
 * ')'  [IF - 2]       <- note that the state was incremented
 * '{'  [IF - 2] [BRACE OPEN]
 * 'x'  [IF - 2] [BRACE OPEN]
 * '--' [IF - 2] [BRACE OPEN]
 * ';'  [IF - 2] [BRACE OPEN]
 * '}'  [IF - 3]
 *                             <- lack of else kills the IF, closes statement
 *
 * Virtual braces example:
 *   if ( x ) x--; else x++;
 *
 * 'if'   [IF - 1]
 * '('    [IF - 1] [PAREN OPEN]
 * 'x'    [IF - 1] [PAREN OPEN]
 * ')'    [IF - 2]
 * 'x'    [IF - 2] [VBRACE OPEN]   <- VBrace open inserted before because '{' was not next
 * '--'   [IF - 2] [VBRACE OPEN]
 * ';'    [IF - 3]                 <- VBrace close inserted after semicolon
 * 'else' [ELSE - 0]               <- IF changed into ELSE
 * 'x'    [ELSE - 0] [VBRACE OPEN] <- lack of '{' -> VBrace
 * '++'   [ELSE - 0] [VBRACE OPEN]
 * ';'    [ELSE - 0]               <- VBrace close inserted after semicolon
 *                                 <- ELSE removed after statement close
 *
 * The pse stack is kept on a frame stack.
 * The frame stack is need for languages that support preprocessors (C, C++, C#)
 * that can arbitrarily change code flow. It also isolates #define macros so
 * that they are indented independently and do not affect the rest of the program.
 *
 * When an #if is hit, a copy of the current frame is push on the frame stack.
 * When an #else/#elif is hit, a copy of the current stack is pushed under the
 * #if frame and the original (pre-#if) frame is copied to the current frame.
 * When #endif is hit, the top frame is popped.
 * This has the following effects:
 *  - a simple #if / #endif does not affect program flow
 *  - #if / #else /#endif - continues from the #if clause
 *
 * When a #define is entered, the current frame is pushed and cleared.
 * When a #define is exited, the frame is popped.
 */
static void parse_cleanup(struct parse_frame *frm, chunk_t *pc)
{
   c_token_t parent = CT_NONE;
   chunk_t   *prev;

   LOG_FMT(LTOK, "%s:%d] %16s - tos:%d/%16s stg:%d\n",
           __func__, pc->orig_line, get_token_name(pc->type),
           frm->pse_tos, get_token_name(frm->pse[frm->pse_tos].type),
           frm->pse[frm->pse_tos].stage);

   /* Mark statement starts */
   if (((frm->stmt_count == 0) || (frm->expr_count == 0)) &&
       !chunk_is_semicolon(pc) &&
       (pc->type != CT_BRACE_CLOSE) &&
       (pc->type != CT_VBRACE_CLOSE) &&
       !chunk_is_str(pc, ")", 1) &&
       !chunk_is_str(pc, "]", 1))
   {
      pc->flags |= PCF_EXPR_START;
      pc->flags |= (frm->stmt_count == 0) ? PCF_STMT_START : 0;
      LOG_FMT(LSTMT, "%d] 1.marked %s as %s start st:%d ex:%d\n",
              pc->orig_line, pc->str.c_str(), (pc->flags &PCF_STMT_START) ? "stmt" : "expr",
              frm->stmt_count, frm->expr_count);
   }
   frm->stmt_count++;
   frm->expr_count++;

   if (frm->sparen_count > 0)
   {
      int tmp;

      pc->flags |= PCF_IN_SPAREN;

      /* Mark everything in the a for statement */
      for (tmp = frm->pse_tos - 1; tmp >= 0; tmp--)
      {
         if (frm->pse[tmp].type == CT_FOR)
         {
            pc->flags |= PCF_IN_FOR;
            break;
         }
      }

      /* Mark the parent on semicolons in for() stmts */
      if ((pc->type == CT_SEMICOLON) &&
          (frm->pse_tos > 1) &&
          (frm->pse[frm->pse_tos - 1].type == CT_FOR))
      {
         pc->parent_type = CT_FOR;
      }
   }

   /* Check the progression of complex statements */
   if (frm->pse[frm->pse_tos].stage != BS_NONE)
   {
      if (check_complex_statements(frm, pc))
      {
         return;
      }
   }

   /**
    * Check for a virtual brace statement close due to a semicolon.
    * The virtual brace will get handled the next time through.
    * The semicolon isn't handled at all.
    * TODO: may need to float VBRACE past comments until newline?
    */
   if (frm->pse[frm->pse_tos].type == CT_VBRACE_OPEN)
   {
      if (chunk_is_semicolon(pc))
      {
         cpd.consumed = true;
         close_statement(frm, pc);
      }
      else if ((cpd.lang_flags & LANG_PAWN) != 0)
      {
         if (pc->type == CT_BRACE_CLOSE)
         {
            close_statement(frm, pc);
         }
      }
   }

   /* Handle close paren, vbrace, brace, and square */
   if ((pc->type == CT_PAREN_CLOSE) ||
       (pc->type == CT_BRACE_CLOSE) ||
       (pc->type == CT_VBRACE_CLOSE) ||
       (pc->type == CT_ANGLE_CLOSE) ||
       (pc->type == CT_MACRO_CLOSE) ||
       (pc->type == CT_SQUARE_CLOSE))
   {
      /* Change CT_PAREN_CLOSE into CT_SPAREN_CLOSE or CT_FPAREN_CLOSE */
      if ((pc->type == CT_PAREN_CLOSE) &&
          ((frm->pse[frm->pse_tos].type == CT_FPAREN_OPEN) ||
           (frm->pse[frm->pse_tos].type == CT_SPAREN_OPEN)))
      {
         pc->type = (c_token_t)(frm->pse[frm->pse_tos].type + 1);
         if (pc->type == CT_SPAREN_CLOSE)
         {
            frm->sparen_count--;
            pc->flags &= ~PCF_IN_SPAREN;
         }
      }

      /* Make sure the open / close match */
      if (pc->type != (frm->pse[frm->pse_tos].type + 1))
      {
         if ((frm->pse[frm->pse_tos].type != CT_NONE) &&
             (frm->pse[frm->pse_tos].type != CT_PP_DEFINE))
         {
            LOG_FMT(LWARN, "%s:%d Error: Unexpected '%s' for '%s', which was on line %d\n",
                    cpd.filename, pc->orig_line, pc->str.c_str(),
                    get_token_name(frm->pse[frm->pse_tos].pc->type),
                    frm->pse[frm->pse_tos].pc->orig_line);
            print_stack(LBCSPOP, "=Error  ", frm, pc);
            cpd.error_count++;
         }
      }
      else
      {
         cpd.consumed = true;

         /* Copy the parent, update the paren/brace levels */
         pc->parent_type = frm->pse[frm->pse_tos].parent;
         frm->level--;
         if ((pc->type == CT_BRACE_CLOSE) ||
             (pc->type == CT_VBRACE_CLOSE) ||
             (pc->type == CT_MACRO_CLOSE))
         {
            frm->brace_level--;
         }
         pc->level       = frm->level;
         pc->brace_level = frm->brace_level;

         /* Pop the entry */
         frm->pse_tos--;
         print_stack(LBCSPOP, "-Close  ", frm, pc);

         /* See if we are in a complex statement */
         if (frm->pse[frm->pse_tos].stage != BS_NONE)
         {
            handle_complex_close(frm, pc);
         }
      }
   }

   /* In this state, we expect a semicolon, but we'll also hit the closing
    * sparen, so we need to check cpd.consumed to see if the close sparen was
    * aleady handled.
    */
   if (frm->pse[frm->pse_tos].stage == BS_WOD_SEMI)
   {
      chunk_t *tmp = pc;

      if (cpd.consumed)
      {
         /* If consumed, then we are on the close sparen.
          * PAWN: Check the next chunk for a semicolon. If it isn't, then
          * add a virtual semicolon, which will get handled on the next pass.
          */
         if (cpd.lang_flags & LANG_PAWN)
         {
            tmp = chunk_get_next_ncnl(pc);

            if ((tmp->type != CT_SEMICOLON) && (tmp->type != CT_VSEMICOLON))
            {
               pawn_add_vsemi_after(pc);
            }
         }
      }
      else
      {
         /* Complain if this ISN'T a semicolon, but close out WHILE_OF_DO anyway */
         if ((pc->type == CT_SEMICOLON) || (pc->type == CT_VSEMICOLON))
         {
            cpd.consumed    = true;
            pc->parent_type = CT_WHILE_OF_DO;
         }
         else
         {
            LOG_FMT(LWARN, "%s:%d: Error: Expected a semicolon for WHILE_OF_DO, but got '%s'\n",
                    cpd.filename, pc->orig_line, get_token_name(pc->type));
            cpd.error_count++;
         }
         handle_complex_close(frm, pc);
      }
   }

   /* Get the parent type for brace and paren open */
   parent = pc->parent_type;
   if ((pc->type == CT_PAREN_OPEN) ||
       (pc->type == CT_FPAREN_OPEN) ||
       (pc->type == CT_SPAREN_OPEN) ||
       (pc->type == CT_BRACE_OPEN))
   {
      prev = chunk_get_prev_ncnl(pc);
      if (prev != NULL)
      {
         if ((pc->type == CT_PAREN_OPEN) ||
             (pc->type == CT_FPAREN_OPEN) ||
             (pc->type == CT_SPAREN_OPEN))
         {
            /* Set the parent for parens and change paren type */
            if (frm->pse[frm->pse_tos].stage != BS_NONE)
            {
               pc->type = CT_SPAREN_OPEN;
               parent   = frm->pse[frm->pse_tos].type;
               frm->sparen_count++;
            }
            else if (prev->type == CT_FUNCTION)
            {
               pc->type = CT_FPAREN_OPEN;
               parent   = CT_FUNCTION;
            }
            else
            {
               /* no need to set parent */
            }
         }
         else  /* must be CT_BRACE_OPEN */
         {
            /* Set the parent for open braces */
            if (frm->pse[frm->pse_tos].stage != BS_NONE)
            {
               parent = frm->pse[frm->pse_tos].type;
            }
            else if ((prev->type == CT_ASSIGN) && (prev->str[0] == '='))
            {
               parent = CT_ASSIGN;
            }
            else if (prev->type == CT_FPAREN_CLOSE)
            {
               parent = CT_FUNCTION;
            }
            else
            {
               /* no need to set parent */
            }
         }
      }
   }

   /**
    * Adjust the level for opens & create a stack entry
    * Note that CT_VBRACE_OPEN has already been handled.
    */
   if ((pc->type == CT_BRACE_OPEN) ||
       (pc->type == CT_PAREN_OPEN) ||
       (pc->type == CT_FPAREN_OPEN) ||
       (pc->type == CT_SPAREN_OPEN) ||
       (pc->type == CT_ANGLE_OPEN) ||
       (pc->type == CT_MACRO_OPEN) ||
       (pc->type == CT_SQUARE_OPEN))
   {
      frm->level++;
      if ((pc->type == CT_BRACE_OPEN) ||
          (pc->type == CT_MACRO_OPEN))
      {
         frm->brace_level++;
      }
      push_fmr_pse(frm, pc, BS_NONE, "+Open   ");
      frm->pse[frm->pse_tos].parent = parent;
      pc->parent_type = parent;
   }

   pattern_class patcls = get_token_pattern_class(pc->type);

   /** Create a stack entry for complex statements IF/DO/FOR/WHILE/SWITCH */
   if (patcls == PATCLS_BRACED)
   {
      push_fmr_pse(frm, pc,
                   (pc->type == CT_DO) ? BS_BRACE_DO : BS_BRACE2,
                   "+ComplexBraced");
   }
   else if (patcls == PATCLS_PBRACED)
   {
      brstage_e bs = BS_PAREN1;

      if ((pc->type == CT_WHILE) && maybe_while_of_do(pc))
      {
         pc->type = CT_WHILE_OF_DO;
         bs       = BS_WOD_PAREN;
      }
      push_fmr_pse(frm, pc, bs, "+ComplexParenBraced");
   }
   else if (patcls == PATCLS_OPBRACED)
   {
      push_fmr_pse(frm, pc, BS_OP_PAREN1, "+ComplexOpParenBraced");
   }
   else if (patcls == PATCLS_ELSE)
   {
      push_fmr_pse(frm, pc, BS_ELSEIF, "+ComplexElse");
   }

   /* Mark simple statement/expression starts
    *  - after { or }
    *  - after ';', but not if the paren stack top is a paren
    *  - after '(' that has a parent type of CT_FOR
    */
   if ((pc->type == CT_SQUARE_OPEN) ||
       ((pc->type == CT_BRACE_OPEN) && (pc->parent_type != CT_ASSIGN)) ||
       (pc->type == CT_BRACE_CLOSE) ||
       (pc->type == CT_VBRACE_CLOSE) ||
       ((pc->type == CT_SPAREN_OPEN) && (pc->parent_type == CT_FOR)) ||
       (chunk_is_semicolon(pc) &&
        (frm->pse[frm->pse_tos].type != CT_PAREN_OPEN) &&
        (frm->pse[frm->pse_tos].type != CT_FPAREN_OPEN) &&
        (frm->pse[frm->pse_tos].type != CT_SPAREN_OPEN)))
   {
      LOG_FMT(LSTMT, "%s: %d> reset1 stmt on %s\n",
              __func__, pc->orig_line, pc->str.c_str());
      frm->stmt_count = 0;
      frm->expr_count = 0;
   }

   /* Mark expression starts */
   chunk_t *tmp = chunk_get_next_ncnl(pc);
   if ((pc->type == CT_ARITH) ||
       (pc->type == CT_ASSIGN) ||
       (pc->type == CT_CASE) ||
       (pc->type == CT_COMPARE) ||
       ((pc->type == CT_STAR) && tmp && (tmp->type != CT_STAR)) ||
       (pc->type == CT_BOOL) ||
       (pc->type == CT_MINUS) ||
       (pc->type == CT_PLUS) ||
       (pc->type == CT_ANGLE_OPEN) ||
       (pc->type == CT_ANGLE_CLOSE) ||
       (pc->type == CT_RETURN) ||
       (pc->type == CT_GOTO) ||
       (pc->type == CT_CONTINUE) ||
       (pc->type == CT_PAREN_OPEN) ||
       (pc->type == CT_FPAREN_OPEN) ||
       (pc->type == CT_SPAREN_OPEN) ||
       (pc->type == CT_BRACE_OPEN) ||
       chunk_is_semicolon(pc) ||
       (pc->type == CT_COMMA) ||
       (pc->type == CT_NOT) ||
       (pc->type == CT_INV) ||
       (pc->type == CT_COLON) ||
       (pc->type == CT_QUESTION))
   {
      frm->expr_count = 0;
      LOG_FMT(LSTMT, "%s: %d> reset expr on %s\n",
              __func__, pc->orig_line, pc->str.c_str());
   }
}
Пример #3
0
static void examine_brace(chunk_t *bopen)
{
   LOG_FUNC_ENTRY();
   chunk_t *next;
   chunk_t *prev      = NULL;
   size_t  semi_count = 0;
   size_t  level      = bopen->level + 1;
   bool    hit_semi   = false;
   bool    was_fcn    = false;
   size_t  nl_max     = cpd.settings[UO_mod_full_brace_nl].u;
   size_t  nl_count   = 0;
   size_t  if_count   = 0;
   int     br_count   = 0;

   LOG_FMT(LBRDEL, "%s: start on %zu : ", __func__, bopen->orig_line);

   chunk_t *pc = chunk_get_next_nc(bopen);
   while ((pc != NULL) && (pc->level >= level))
   {
      if (pc->flags & PCF_IN_PREPROC)
      {
         LOG_FMT(LBRDEL, " PREPROC\n");
         return;
      }

      if (chunk_is_newline(pc))
      {
         nl_count += pc->nl_count;
         if ((nl_max > 0) && (nl_count > nl_max))
         {
            LOG_FMT(LBRDEL, " exceeded %zu newlines\n", nl_max);
            return;
         }
      }
      else
      {
         if (pc->type == CT_BRACE_OPEN)
         {
            br_count++;
         }
         else if (pc->type == CT_BRACE_CLOSE)
         {
            br_count--;
            if (br_count == 0)
            {
               next = chunk_get_next_ncnl(pc, CNAV_PREPROC);
               if ((next == NULL) || (next->type != CT_BRACE_CLOSE))
               {
                  LOG_FMT(LBRDEL, " junk after close brace\n");
                  return;
               }
            }
         }
         else if ((pc->type == CT_IF) || (pc->type == CT_ELSEIF))
         {
            if (br_count == 0)
            {
               if_count++;
            }
         }

         if (pc->level == level)
         {
            if ((semi_count > 0) && hit_semi)
            {
               /* should have bailed due to close brace level drop */
               LOG_FMT(LBRDEL, " no close brace\n");
               return;
            }

            LOG_FMT(LBRDEL, " [%s %zu-%zu]", pc->text(), pc->orig_line, semi_count);

            if (pc->type == CT_ELSE)
            {
               LOG_FMT(LBRDEL, " bailed on %s on line %zu\n",
                       pc->text(), pc->orig_line);
               return;
            }

            was_fcn = (prev != NULL) && (prev->type == CT_FPAREN_CLOSE);

            if (chunk_is_semicolon(pc) ||
                (pc->type == CT_IF) ||
                (pc->type == CT_ELSEIF) ||
                (pc->type == CT_FOR) ||
                (pc->type == CT_DO) ||
                (pc->type == CT_WHILE) ||
                (pc->type == CT_SWITCH) ||
                (pc->type == CT_USING_STMT) ||
                ((pc->type == CT_BRACE_OPEN) && was_fcn))
            {
               hit_semi |= chunk_is_semicolon(pc);
               if (++semi_count > 1)
               {
                  LOG_FMT(LBRDEL, " bailed on %zu because of %s on line %zu\n",
                          bopen->orig_line, pc->text(), pc->orig_line);
                  return;
               }
            }
         }
      }
      prev = pc;
      pc   = chunk_get_next_nc(pc);
   }

   if (pc == NULL)
   {
      LOG_FMT(LBRDEL, " NULL\n");
      return;
   }

   LOG_FMT(LBRDEL, " - end on '%s' on line %zu. if_count=%zu semi_count=%zu\n",
           get_token_name(pc->type), pc->orig_line, if_count, semi_count);

   if (pc->type == CT_BRACE_CLOSE)
   {
      next = chunk_get_next_ncnl(pc);
      while ((next != NULL) && (next->type == CT_VBRACE_CLOSE))
      {
         next = chunk_get_next_ncnl(next);
      }
      LOG_FMT(LBRDEL, " next is '%s'\n", get_token_name(next->type));
      if ((if_count > 0) &&
          ((next->type == CT_ELSE) || (next->type == CT_ELSEIF)))
      {
         LOG_FMT(LBRDEL, " bailed on because 'else' is next and %zu ifs\n", if_count);
         return;
      }

      if (semi_count > 0)
      {
         if (bopen->parent_type == CT_ELSE)
         {
            next = chunk_get_next_ncnl(bopen);
            if (next->type == CT_IF)
            {
               prev = chunk_get_prev_ncnl(bopen);
               LOG_FMT(LBRDEL, " else-if removing braces on line %zu and %zu\n",
                       bopen->orig_line, pc->orig_line);

               chunk_del(bopen);
               chunk_del(pc);
               newline_del_between(prev, next);
               if (cpd.settings[UO_nl_else_if].a & AV_ADD)
               {
                  newline_add_between(prev, next);
               }
               return;
            }
         }

         /* we have a pair of braces with only 1 statement inside */
         convert_brace(bopen);
         convert_brace(pc);

         LOG_FMT(LBRDEL, " removing braces on line %zu and %zu\n",
                 bopen->orig_line, pc->orig_line);
      }
      else
      {
         LOG_FMT(LBRDEL, " empty statement\n");
      }
   }
   else
   {
      LOG_FMT(LBRDEL, " not a close brace? - '%s'\n", pc->text());
   }
} // examine_brace
Пример #4
0
static bool can_remove_braces(chunk_t *bopen)
{
   LOG_FUNC_ENTRY();

   chunk_t *prev      = NULL;
   size_t  semi_count = 0;
   size_t  level      = bopen->level + 1;
   bool    hit_semi   = false;
   bool    was_fcn    = false;
   size_t  nl_max     = cpd.settings[UO_mod_full_brace_nl].u;
   size_t  nl_count   = 0;
   size_t  if_count   = 0;
   int     br_count   = 0;

   /* Cannot remove braces inside a preprocessor */
   if (bopen->flags & PCF_IN_PREPROC)
   {
      return(false);
   }
   chunk_t *pc = chunk_get_next_ncnl(bopen, CNAV_PREPROC);
   if ((pc != NULL) && (pc->type == CT_BRACE_CLOSE))
   {
      /* Can't remove empty statement */
      return(false);
   }

   LOG_FMT(LBRDEL, "%s: start on %zu : ", __func__, bopen->orig_line);

   pc = chunk_get_next_nc(bopen, CNAV_ALL);
   while ((pc != NULL) && (pc->level >= level))
   {
      if (pc->flags & PCF_IN_PREPROC)
      {
         /* Cannot remove braces that contain a preprocessor */
         return(false);
      }

      if (chunk_is_newline(pc))
      {
         nl_count += pc->nl_count;
         if ((nl_max > 0) && (nl_count > nl_max))
         {
            LOG_FMT(LBRDEL, " exceeded %zu newlines\n", nl_max);
            return(false);
         }
      }
      else
      {
         if (pc->type == CT_BRACE_OPEN)
         {
            br_count++;
         }
         else if (pc->type == CT_BRACE_CLOSE)
         {
            br_count--;
         }
         else if ((pc->type == CT_IF) || (pc->type == CT_ELSEIF))
         {
            if (br_count == 0)
            {
               if_count++;
            }
         }

         if (pc->level == level)
         {
            if ((semi_count > 0) && hit_semi)
            {
               /* should have bailed due to close brace level drop */
               LOG_FMT(LBRDEL, " no close brace\n");
               return(false);
            }

            LOG_FMT(LBRDEL, " [%s %zu-%zu]", pc->text(), pc->orig_line, semi_count);

            if (pc->type == CT_ELSE)
            {
               LOG_FMT(LBRDEL, " bailed on %s on line %zu\n",
                       pc->text(), pc->orig_line);
               return(false);
            }

            was_fcn = (prev != NULL) && (prev->type == CT_FPAREN_CLOSE);

            if (chunk_is_semicolon(pc) ||
                (pc->type == CT_IF) ||
                (pc->type == CT_ELSEIF) ||
                (pc->type == CT_FOR) ||
                (pc->type == CT_DO) ||
                (pc->type == CT_WHILE) ||
                (pc->type == CT_USING_STMT) ||
                ((pc->type == CT_BRACE_OPEN) && was_fcn))
            {
               hit_semi |= chunk_is_semicolon(pc);
               if (++semi_count > 1)
               {
                  LOG_FMT(LBRDEL, " bailed on %zu because of %s on line %zu\n",
                          bopen->orig_line, pc->text(), pc->orig_line);
                  return(false);
               }
            }
         }
      }
      prev = pc;
      pc   = chunk_get_next_nc(pc);
   }

   if (pc == NULL)
   {
      LOG_FMT(LBRDEL, " NULL\n");
      return(false);
   }

   if ((pc->type == CT_BRACE_CLOSE) && (pc->parent_type == CT_IF))
   {
      chunk_t *next = chunk_get_next_ncnl(pc, CNAV_PREPROC);

      prev = chunk_get_prev_ncnl(pc, CNAV_PREPROC);

      if ((next != NULL) && (next->type == CT_ELSE) &&
          ((prev->type == CT_BRACE_CLOSE) || (prev->type == CT_VBRACE_CLOSE)) &&
          (prev->parent_type == CT_IF))
      {
         LOG_FMT(LBRDEL, " - bailed on '%s'[%s] on line %zu due to 'if' and 'else' sequence\n",
                 get_token_name(pc->type), get_token_name(pc->parent_type),
                 pc->orig_line);
         return(false);
      }
   }

   LOG_FMT(LBRDEL, " - end on '%s' on line %zu. if_count=%zu semi_count=%zu\n",
           get_token_name(pc->type), pc->orig_line, if_count, semi_count);

   return((pc->type == CT_BRACE_CLOSE) && (pc->pp_level == bopen->pp_level));
} // can_remove_braces
Пример #5
0
/**
 * Aligns OC declarations on the colon
 * -(void) doSomething: (NSString*) param1
 *                with: (NSString*) param2
 */
static void align_oc_decl_colon(void)
{
   chunk_t    *pc = chunk_get_head();
   chunk_t    *tmp;
   chunk_t    *tmp2;
   AlignStack cas;   /* for the colons */
   AlignStack nas;   /* for the parameter label */
   int        level;
   bool       did_line;

   cas.Start(4);
   nas.Start(4);
   nas.m_right_align = true;

   while (pc != NULL)
   {
      if (pc->type != CT_OC_SCOPE)
      {
         pc = chunk_get_next(pc);
         continue;
      }

      nas.Reset();
      cas.Reset();

      level = pc->level;
      pc    = chunk_get_next_ncnl(pc, CNAV_PREPROC);

      did_line = false;

      while ((pc != NULL) && (pc->level >= level))
      {
         /* The decl ends with an open brace or semicolon */
         if ((pc->type == CT_BRACE_OPEN) || chunk_is_semicolon(pc))
         {
            break;
         }

         if (chunk_is_newline(pc))
         {
            nas.NewLines(pc->nl_count);
            cas.NewLines(pc->nl_count);
            did_line  = false;
         }
         else if (!did_line && (pc->type == CT_OC_COLON))
         {
            cas.Add(pc);

            tmp = chunk_get_prev(pc, CNAV_PREPROC);
            tmp2 = chunk_get_prev_ncnl(tmp, CNAV_PREPROC);

            /* Check for an un-labeled parameter */
            if ((tmp != NULL) &&
                (tmp2 != NULL)
                &&
                ((tmp->type == CT_WORD) ||
                 (tmp->type == CT_TYPE) ||
                 (tmp->type == CT_OC_MSG_DECL))
                &&
                ((tmp2->type == CT_WORD) ||
                 (tmp2->type == CT_TYPE) ||
                 (tmp2->type == CT_PAREN_CLOSE)))
            {
               nas.Add(tmp);
            }
            did_line = true;
         }
         pc = chunk_get_next(pc, CNAV_PREPROC);
      }
      nas.End();
      cas.End();
   }
}
Пример #6
0
/**
 * At the heart of this algorithm are two stacks.
 * There is the Paren Stack (PS) and the Frame stack.
 *
 * The PS (pse in the code) keeps track of braces, parens,
 * if/else/switch/do/while/etc items -- anything that is nestable.
 * Complex statements go through stages.
 * Take this simple if statement as an example:
 *   if ( x ) { x--; }
 *
 * The stack would change like so: 'token' stack afterwards
 * 'if' [IF - 1]
 * '('  [IF - 1] [PAREN OPEN]
 * 'x'  [IF - 1] [PAREN OPEN]
 * ')'  [IF - 2]       <- note that the state was incremented
 * '{'  [IF - 2] [BRACE OPEN]
 * 'x'  [IF - 2] [BRACE OPEN]
 * '--' [IF - 2] [BRACE OPEN]
 * ';'  [IF - 2] [BRACE OPEN]
 * '}'  [IF - 3]
 *                             <- lack of else kills the IF, closes statement
 *
 * Virtual braces example:
 *   if ( x ) x--; else x++;
 *
 * 'if'   [IF - 1]
 * '('    [IF - 1] [PAREN OPEN]
 * 'x'    [IF - 1] [PAREN OPEN]
 * ')'    [IF - 2]
 * 'x'    [IF - 2] [VBRACE OPEN]   <- VBrace open inserted before because '{' was not next
 * '--'   [IF - 2] [VBRACE OPEN]
 * ';'    [IF - 3]                 <- VBrace close inserted after semicolon
 * 'else' [ELSE - 0]               <- IF changed into ELSE
 * 'x'    [ELSE - 0] [VBRACE OPEN] <- lack of '{' -> VBrace
 * '++'   [ELSE - 0] [VBRACE OPEN]
 * ';'    [ELSE - 0]               <- VBrace close inserted after semicolon
 *                                 <- ELSE removed after statement close
 *
 * The pse stack is kept on a frame stack.
 * The frame stack is need for languages that support preprocessors (C, C++, C#)
 * that can arbitrarily change code flow. It also isolates #define macros so
 * that they are indented independently and do not affect the rest of the program.
 *
 * When an #if is hit, a copy of the current frame is push on the frame stack.
 * When an #else/#elif is hit, a copy of the current stack is pushed under the
 * #if frame and the original (pre-#if) frame is copied to the current frame.
 * When #endif is hit, the top frame is popped.
 * This has the following effects:
 *  - a simple #if / #endif does not affect program flow
 *  - #if / #else /#endif - continues from the #if clause
 *
 * When a #define is entered, the current frame is pushed and cleared.
 * When a #define is exited, the frame is popped.
 */
static void parse_cleanup(parse_frame_t *frm, chunk_t *pc)
{
   LOG_FUNC_ENTRY();

   LOG_FMT(LTOK, "%s(%d): orig_line is %zu, type is %s, tos is %zu, TOS.type is %s, TOS.stage is %u\n",
           __func__, __LINE__, pc->orig_line, get_token_name(pc->type),
           frm->pse_tos, get_token_name(frm->pse[frm->pse_tos].type),
           (unsigned int)frm->pse[frm->pse_tos].stage);

   // Mark statement starts
   if (  (frm->stmt_count == 0 || frm->expr_count == 0)
      && !chunk_is_semicolon(pc)
      && pc->type != CT_BRACE_CLOSE
      && pc->type != CT_VBRACE_CLOSE
      && !chunk_is_str(pc, ")", 1)
      && !chunk_is_str(pc, "]", 1))
   {
      chunk_flags_set(pc, PCF_EXPR_START | ((frm->stmt_count == 0) ? PCF_STMT_START : 0));
      LOG_FMT(LSTMT, "%s(%d): orig_line is %zu, 1.marked '%s' as %s, start stmt_count is %d, expr_count is %d\n",
              __func__, __LINE__, pc->orig_line, pc->text(), (pc->flags & PCF_STMT_START) ? "stmt" : "expr",
              frm->stmt_count, frm->expr_count);
   }
   frm->stmt_count++;
   frm->expr_count++;

   if (frm->sparen_count > 0)
   {
      chunk_flags_set(pc, PCF_IN_SPAREN);

      // Mark everything in the for statement
      for (int tmp = frm->pse_tos - 1; tmp >= 0; tmp--)
      {
         if (frm->pse[tmp].type == CT_FOR)
         {
            chunk_flags_set(pc, PCF_IN_FOR);
            break;
         }
      }

      // Mark the parent on semicolons in for() statements
      if (  pc->type == CT_SEMICOLON
         && frm->pse_tos > 1
         && (frm->pse[frm->pse_tos - 1].type == CT_FOR))
      {
         set_chunk_parent(pc, CT_FOR);
      }
   }

   // Check the progression of complex statements
   if (frm->pse[frm->pse_tos].stage != brace_stage_e::NONE)
   {
      if (check_complex_statements(frm, pc))
      {
         return;
      }
   }

   /*
    * Check for a virtual brace statement close due to a semicolon.
    * The virtual brace will get handled the next time through.
    * The semicolon isn't handled at all.
    * TODO: may need to float VBRACE past comments until newline?
    */
   if (frm->pse[frm->pse_tos].type == CT_VBRACE_OPEN)
   {
      if (chunk_is_semicolon(pc))
      {
         cpd.consumed = true;
         close_statement(frm, pc);
      }
      else if (cpd.lang_flags & LANG_PAWN)
      {
         if (pc->type == CT_BRACE_CLOSE)
         {
            close_statement(frm, pc);
         }
      }
   }

   // Handle close parenthesis, vbrace, brace, and square
   if (  pc->type == CT_PAREN_CLOSE
      || pc->type == CT_BRACE_CLOSE
      || pc->type == CT_VBRACE_CLOSE
      || pc->type == CT_ANGLE_CLOSE
      || pc->type == CT_MACRO_CLOSE
      || pc->type == CT_SQUARE_CLOSE)
   {
      // Change CT_PAREN_CLOSE into CT_SPAREN_CLOSE or CT_FPAREN_CLOSE
      if (  pc->type == CT_PAREN_CLOSE
         && (  (frm->pse[frm->pse_tos].type == CT_FPAREN_OPEN)
            || (frm->pse[frm->pse_tos].type == CT_SPAREN_OPEN)))
      {
         set_chunk_type(pc, (c_token_t)(frm->pse[frm->pse_tos].type + 1));
         if (pc->type == CT_SPAREN_CLOSE)
         {
            frm->sparen_count--;
            chunk_flags_clr(pc, PCF_IN_SPAREN);
         }
      }

      // Make sure the open / close match
      if (pc->type != (frm->pse[frm->pse_tos].type + 1))
      {
         if (  (frm->pse[frm->pse_tos].type != CT_NONE)
            && (frm->pse[frm->pse_tos].type != CT_PP_DEFINE))
         {
            LOG_FMT(LWARN, "%s(%d): %s, orig_line is %zu, Error: Unexpected '%s' for '%s', which was on line %zu\n",
                    __func__, __LINE__, cpd.filename, pc->orig_line, pc->text(),
                    get_token_name(frm->pse[frm->pse_tos].pc->type),
                    frm->pse[frm->pse_tos].pc->orig_line);
            print_stack(LBCSPOP, "=Error  ", frm, pc);
            cpd.error_count++;
         }
      }
      else
      {
         cpd.consumed = true;

         // Copy the parent, update the parenthesis/brace levels
         set_chunk_parent(pc, frm->pse[frm->pse_tos].parent);
         frm->level--;
         if (  pc->type == CT_BRACE_CLOSE
            || pc->type == CT_VBRACE_CLOSE
            || pc->type == CT_MACRO_CLOSE)
         {
            frm->brace_level--;
         }
         pc->level       = frm->level;
         pc->brace_level = frm->brace_level;

         // Pop the entry
         frm->pse_tos--;
         print_stack(LBCSPOP, "-Close  ", frm, pc);

         // See if we are in a complex statement
         if (frm->pse[frm->pse_tos].stage != brace_stage_e::NONE)
         {
            handle_complex_close(frm, pc);
         }
      }
   }

   /*
    * In this state, we expect a semicolon, but we'll also hit the closing
    * sparen, so we need to check cpd.consumed to see if the close sparen was
    * aleady handled.
    */
   if (frm->pse[frm->pse_tos].stage == brace_stage_e::WOD_SEMI)
   {
      chunk_t *tmp = pc;

      if (cpd.consumed)
      {
         /*
          * If consumed, then we are on the close sparen.
          * PAWN: Check the next chunk for a semicolon. If it isn't, then
          * add a virtual semicolon, which will get handled on the next pass.
          */
         if (cpd.lang_flags & LANG_PAWN)
         {
            tmp = chunk_get_next_ncnl(pc);

            if (tmp->type != CT_SEMICOLON && tmp->type != CT_VSEMICOLON)
            {
               pawn_add_vsemi_after(pc);
            }
         }
      }
      else
      {
         // Complain if this ISN'T a semicolon, but close out WHILE_OF_DO anyway
         if (pc->type == CT_SEMICOLON || pc->type == CT_VSEMICOLON)
         {
            cpd.consumed = true;
            set_chunk_parent(pc, CT_WHILE_OF_DO);
         }
         else
         {
            LOG_FMT(LWARN, "%s: %s(%d): %zu: Error: Expected a semicolon for WHILE_OF_DO, but got '%s'\n",
                    cpd.filename, __func__, __LINE__, pc->orig_line, get_token_name(pc->type));
            cpd.error_count++;
         }
         handle_complex_close(frm, pc);
      }
   }

   // Get the parent type for brace and parenthesis open
   c_token_t parent = pc->parent_type;
   if (  pc->type == CT_PAREN_OPEN
      || pc->type == CT_FPAREN_OPEN
      || pc->type == CT_SPAREN_OPEN
      || pc->type == CT_BRACE_OPEN)
   {
      chunk_t *prev = chunk_get_prev_ncnl(pc);
      if (prev != nullptr)
      {
         if (  pc->type == CT_PAREN_OPEN
            || pc->type == CT_FPAREN_OPEN
            || pc->type == CT_SPAREN_OPEN)
         {
            // Set the parent for parenthesis and change parenthesis type
            if (frm->pse[frm->pse_tos].stage != brace_stage_e::NONE)
            {
               set_chunk_type(pc, CT_SPAREN_OPEN);
               parent = frm->pse[frm->pse_tos].type;
               frm->sparen_count++;
            }
            else if (prev->type == CT_FUNCTION)
            {
               set_chunk_type(pc, CT_FPAREN_OPEN);
               parent = CT_FUNCTION;
            }
            // NS_ENUM and NS_OPTIONS are followed by a (type, name) pair
            else if (prev->type == CT_ENUM && (cpd.lang_flags & LANG_OC))
            {
               // Treat both as CT_ENUM since the syntax is identical
               set_chunk_type(pc, CT_FPAREN_OPEN);
               parent = CT_ENUM;
            }
            else
            {
               // no need to set parent
            }
         }
         else  // must be CT_BRACE_OPEN
         {
            // Set the parent for open braces
            if (frm->pse[frm->pse_tos].stage != brace_stage_e::NONE)
            {
               parent = frm->pse[frm->pse_tos].type;
            }
            else if (prev->type == CT_ASSIGN && (prev->str[0] == '='))
            {
               parent = CT_ASSIGN;
            }
            // Carry through CT_ENUM parent in NS_ENUM (type, name) {
            else if (  prev->type == CT_FPAREN_CLOSE
                    && (cpd.lang_flags & LANG_OC)
                    && prev->parent_type == CT_ENUM)
            {
               parent = CT_ENUM;
            }
            else if (prev->type == CT_FPAREN_CLOSE)
            {
               parent = CT_FUNCTION;
            }
            else
            {
               // no need to set parent
            }
         }
      }
   }

   /*
    * Adjust the level for opens & create a stack entry
    * Note that CT_VBRACE_OPEN has already been handled.
    */
   if (  pc->type == CT_BRACE_OPEN
      || pc->type == CT_PAREN_OPEN
      || pc->type == CT_FPAREN_OPEN
      || pc->type == CT_SPAREN_OPEN
      || pc->type == CT_ANGLE_OPEN
      || pc->type == CT_MACRO_OPEN
      || pc->type == CT_SQUARE_OPEN)
   {
      frm->level++;
      if (pc->type == CT_BRACE_OPEN || pc->type == CT_MACRO_OPEN)
      {
         frm->brace_level++;
      }
      push_fmr_pse(frm, pc, brace_stage_e::NONE, "+Open   ");
      frm->pse[frm->pse_tos].parent = parent;
      set_chunk_parent(pc, parent);
   }

   pattern_class_e patcls = get_token_pattern_class(pc->type);

   /*
    * Create a stack entry for complex statements:
    * if, elseif, switch, for, while, synchronized, using, lock, with,
    * version, CT_D_SCOPE_IF
    */
   if (patcls == pattern_class_e::BRACED)
   {
      push_fmr_pse(frm, pc,
                   (pc->type == CT_DO) ? brace_stage_e::BRACE_DO : brace_stage_e::BRACE2,
                   "+ComplexBraced");
   }
   else if (patcls == pattern_class_e::PBRACED)
   {
      brace_stage_e bs = brace_stage_e::PAREN1;

      if (pc->type == CT_WHILE && maybe_while_of_do(pc))
      {
         set_chunk_type(pc, CT_WHILE_OF_DO);
         bs = brace_stage_e::WOD_PAREN;
      }
      push_fmr_pse(frm, pc, bs, "+ComplexParenBraced");
   }
   else if (patcls == pattern_class_e::OPBRACED)
   {
      push_fmr_pse(frm, pc, brace_stage_e::OP_PAREN1, "+ComplexOpParenBraced");
   }
   else if (patcls == pattern_class_e::ELSE)
   {
      push_fmr_pse(frm, pc, brace_stage_e::ELSEIF, "+ComplexElse");
   }

   /*
    * Mark simple statement/expression starts
    *  - after { or }
    *  - after ';', but not if the paren stack top is a paren
    *  - after '(' that has a parent type of CT_FOR
    */
   if (  pc->type == CT_SQUARE_OPEN
      || (pc->type == CT_BRACE_OPEN && pc->parent_type != CT_ASSIGN)
      || pc->type == CT_BRACE_CLOSE
      || pc->type == CT_VBRACE_CLOSE
      || (pc->type == CT_SPAREN_OPEN && pc->parent_type == CT_FOR)
      || pc->type == CT_COLON
      || pc->type == CT_OC_END
      || (  chunk_is_semicolon(pc)
         && frm->pse[frm->pse_tos].type != CT_PAREN_OPEN
         && frm->pse[frm->pse_tos].type != CT_FPAREN_OPEN
         && frm->pse[frm->pse_tos].type != CT_SPAREN_OPEN))
   {
      LOG_FMT(LSTMT, "%s(%d): orig_line is %zu, reset1 stmt on '%s'\n",
              __func__, __LINE__, pc->orig_line, pc->text());
      frm->stmt_count = 0;
      frm->expr_count = 0;
   }

   // Mark expression starts
   chunk_t *tmp = chunk_get_next_ncnl(pc);
   if (  pc->type == CT_ARITH
      || pc->type == CT_ASSIGN
      || pc->type == CT_CASE
      || pc->type == CT_COMPARE
      || (  pc->type == CT_STAR
         && tmp != nullptr && tmp->type != CT_STAR)
      || pc->type == CT_BOOL
      || pc->type == CT_MINUS
      || pc->type == CT_PLUS
      || pc->type == CT_CARET
      || pc->type == CT_ANGLE_OPEN
      || pc->type == CT_ANGLE_CLOSE
      || pc->type == CT_RETURN
      || pc->type == CT_THROW
      || pc->type == CT_GOTO
      || pc->type == CT_CONTINUE
      || pc->type == CT_PAREN_OPEN
      || pc->type == CT_FPAREN_OPEN
      || pc->type == CT_SPAREN_OPEN
      || pc->type == CT_BRACE_OPEN
      || chunk_is_semicolon(pc)
      || pc->type == CT_COMMA
      || pc->type == CT_NOT
      || pc->type == CT_INV
      || pc->type == CT_COLON
      || pc->type == CT_QUESTION)
   {
      frm->expr_count = 0;
      LOG_FMT(LSTMT, "%s(%d): orig_line is %zu, reset expr on '%s'\n",
              __func__, __LINE__, pc->orig_line, pc->text());
   }
   else if (pc->type == CT_BRACE_CLOSE)
   {
      if (!cpd.consumed)
      {
         size_t file_pp_level = ifdef_over_whole_file() ? 1 : 0;
         if (!cpd.unc_off_used && pc->pp_level == file_pp_level)
         {
            // fatal error
            char *outputMessage;
            if (cpd.settings[UO_tok_split_gte].b)
            {
               outputMessage = make_message("Unmatched BRACE_CLOSE\nat orig_line=%zu, orig_col=%zu\n",
                                            pc->orig_line, pc->orig_col);
            }
            else
            {
               outputMessage = make_message("Unmatched BRACE_CLOSE\nat orig_line=%zu, orig_col=%zu\nTry the option 'tok_split_gte = true'\n",
                                            pc->orig_line, pc->orig_col);
            }
            fprintf(stderr, "%s", outputMessage);
            free(outputMessage);
            log_flush(true);
            exit(EXIT_FAILURE);
         }
      }
   }
} // parse_cleanup
Пример #7
0
/**
 * Checks to see if the braces can be removed.
 *  - less than a certain length
 *  - doesn't mess up if/else stuff
 */
static bool can_remove_braces(chunk_t *bopen)
{
   chunk_t *pc;
   chunk_t *prev      = NULL;
   int     semi_count = 0;
   int     level      = bopen->level + 1;
   bool    hit_semi   = false;
   bool    was_fcn    = false;
   int     nl_max     = cpd.settings[UO_mod_full_brace_nl].n;
   int     nl_count   = 0;
   int     if_count   = 0;
   int     br_count   = 0;

   /* Cannot remove braces inside a preprocessor */
   if (bopen->flags & PCF_IN_PREPROC)
   {
      return(false);
   }
   pc = chunk_get_next_ncnl(bopen, CNAV_PREPROC);
   if ((pc != NULL) && (pc->type == CT_BRACE_CLOSE))
   {
      /* Can't remove empty statement */
      return(false);
   }

   LOG_FMT(LBRDEL, "%s: start on %d : ", __func__, bopen->orig_line);

   pc = chunk_get_next_nc(bopen, CNAV_PREPROC);
   while ((pc != NULL) && (pc->level >= level))
   {
      if (chunk_is_newline(pc))
      {
         nl_count += pc->nl_count;
         if ((nl_max > 0) && (nl_count > nl_max))
         {
            LOG_FMT(LBRDEL, " exceeded %d newlines\n", nl_max);
            return(false);
         }
      }
      else
      {
         if (pc->type == CT_BRACE_OPEN)
         {
            br_count++;
         }
         else if (pc->type == CT_BRACE_CLOSE)
         {
            br_count--;
         }
         else if ((pc->type == CT_IF) || (pc->type == CT_ELSEIF))
         {
            if (br_count == 0)
            {
               if_count++;
            }
         }

         if (pc->level == level)
         {
            if ((semi_count > 0) && hit_semi)
            {
               /* should have bailed due to close brace level drop */
               LOG_FMT(LBRDEL, " no close brace\n");
               return(false);
            }

            LOG_FMT(LBRDEL, " [%.*s %d-%d]", pc->len, pc->str, pc->orig_line, semi_count);

            if (pc->type == CT_ELSE)
            {
               LOG_FMT(LBRDEL, " bailed on %.*s on line %d\n",
                       pc->len, pc->str, pc->orig_line);
               return(false);
            }

            was_fcn = (prev != NULL) && (prev->type == CT_FPAREN_CLOSE);

            if (chunk_is_semicolon(pc) ||
                (pc->type == CT_IF) ||
                (pc->type == CT_ELSEIF) ||
                (pc->type == CT_FOR) ||
                (pc->type == CT_DO) ||
                (pc->type == CT_WHILE) ||
                ((pc->type == CT_BRACE_OPEN) && was_fcn))
            {
               hit_semi |= chunk_is_semicolon(pc);
               if (++semi_count > 1)
               {
                  LOG_FMT(LBRDEL, " bailed on %d because of %.*s on line %d\n",
                          bopen->orig_line, pc->len, pc->str, pc->orig_line);
                  return(false);
               }
            }
         }
      }
      prev = pc;
      pc   = chunk_get_next_nc(pc, CNAV_PREPROC);
   }

   if (pc == NULL)
   {
      LOG_FMT(LBRDEL, " NULL\n");
      return(false);
   }

   LOG_FMT(LBRDEL, " - end on '%s' on line %d. if_count=%d semi_count=%d\n",
           get_token_name(pc->type), pc->orig_line, if_count, semi_count);

   return((pc->type == CT_BRACE_CLOSE) && (pc->pp_level == bopen->pp_level));
}