Logo Search packages:      
Sourcecode: uncrustify version File versions

static void parse_cleanup ( struct parse_frame *  frm,
chunk_t pc 
) [static]

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 statment 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 statment 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.

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?

Adjust the level for opens & create a stack entry Note that CT_VBRACE_OPEN has already been handled.

Create a stack entry for complex statments IF/DO/FOR/WHILE/SWITCH

Definition at line 228 of file brace_cleanup.cpp.

References chunk_t::brace_level, check_complex_statements(), chunk_get_prev_ncnl(), close_statement(), chunk_t::flags, get_token_pattern_class(), handle_complex_close(), chunk_t::len, chunk_t::level, chunk_t::orig_line, chunk_t::parent_type, chunk_t::str, and chunk_t::type.

Referenced by brace_cleanup().

{
   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))
   {
      pc->flags |= PCF_EXPR_START;
      pc->flags |= (frm->stmt_count == 0) ? PCF_STMT_START : 0;
      LOG_FMT(LSTMT, "%d] 1.marked %.*s as stmt start st:%d ex:%d\n",
              pc->orig_line, pc->len, pc->str, 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)
         {
            LOG_FMT(LWARN, "%s:%d Error: Unexpected '%.*s' for '%s'\n",
                    cpd.filename, pc->orig_line, pc->len, pc->str,
                    get_token_name(frm->pse[frm->pse_tos].type));
            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))
         {
            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);
         }
      }
   }

   if ((pc->type == CT_SEMICOLON) &&
       (frm->pse[frm->pse_tos].stage == BS_WOD_SEMI))
   {
      cpd.consumed    = true;
      pc->parent_type = CT_WHILE_OF_DO;
      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++;
      }
      frm->pse_tos++;
      frm->pse[frm->pse_tos].type   = pc->type;
      frm->pse[frm->pse_tos].stage  = BS_NONE;
      frm->pse[frm->pse_tos].parent = parent;
      pc->parent_type = parent;

      print_stack(LBCSPUSH, "+Open   ", frm, pc);
   }

   pattern_class patcls = get_token_pattern_class(pc->type);

   /** Create a stack entry for complex statments IF/DO/FOR/WHILE/SWITCH */
   if (patcls == PATCLS_BRACED)
   {
      frm->pse_tos++;
      frm->pse[frm->pse_tos].type  = pc->type;
      frm->pse[frm->pse_tos].stage = (pc->type == CT_DO) ? BS_BRACE_DO : BS_BRACE2;

      print_stack(LBCSPUSH, "+ComplexBraced", frm, pc);
   }
   else if (patcls == PATCLS_PBRACED)
   {
      frm->pse_tos++;
      frm->pse[frm->pse_tos].type  = pc->type;
      frm->pse[frm->pse_tos].stage = BS_PAREN1;

      print_stack(LBCSPUSH, "+ComplexParenBraced", frm, pc);
   }
   else if (patcls == PATCLS_OPBRACED)
   {
      frm->pse_tos++;
      frm->pse[frm->pse_tos].type  = pc->type;
      frm->pse[frm->pse_tos].stage = BS_OP_PAREN1;

      print_stack(LBCSPUSH, "+ComplexOpParenBraced", frm, pc);
   }

   /* 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> reset stmt on %.*s\n",
              __func__, pc->orig_line, pc->len, pc->str);
      frm->stmt_count = 0;
      frm->expr_count = 0;
   }

   /* Mark expression starts */
   if ((pc->type == CT_ARITH) ||
       (pc->type == CT_ASSIGN) ||
       (pc->type == CT_COMPARE) ||
       (pc->type == CT_STAR) ||
       (pc->type == CT_BOOL) ||
       (pc->type == CT_MINUS) ||
       (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_COLON) ||
       (pc->type == CT_QUESTION))
   {
      frm->expr_count = 0;
      LOG_FMT(LSTMT, "%s: %d> reset expr on %.*s\n",
              __func__, pc->orig_line, pc->len, pc->str);
   }
}


Generated by  Doxygen 1.6.0   Back to index