blob: c31c9762173a6f674933454138ca8ff2f44c6dde [file] [log] [blame]
/**
* @file parse_frame.cpp
* Does the parse frame stuff, which is used to handle #ifdef stuff
*
* @author Ben Gardner
* @license GPL v2+
*/
#include "uncrustify_types.h"
#include "prototypes.h"
#include "chunk_list.h"
#include <cstdio>
#include <cstring>
#include <cstdlib>
/**
* Logs one parse frame
*/
void pf_log(log_sev_t logsev, struct parse_frame *pf)
{
int idx;
LOG_FMT(logsev, "[%s] BrLevel=%d Level=%d PseTos=%d\n",
get_token_name(pf->in_ifdef),
pf->brace_level, pf->level, pf->pse_tos);
LOG_FMT(logsev, " *");
for (idx = 1; idx <= pf->pse_tos; idx++)
{
LOG_FMT(logsev, " [%s-%d]",
get_token_name(pf->pse[idx].type),
pf->pse[idx].stage);
}
LOG_FMT(logsev, "\n");
}
static void pf_log_frms(log_sev_t logsev, const char *txt, struct parse_frame *pf)
{
int idx;
LOG_FMT(logsev, "%s Parse Frames(%d):", txt, cpd.frame_count);
for (idx = 0; idx < cpd.frame_count; idx++)
{
LOG_FMT(logsev, " [%s-%d]",
get_token_name(cpd.frames[idx].in_ifdef),
cpd.frames[idx].ref_no);
}
LOG_FMT(logsev, "-[%s-%d]\n", get_token_name(pf->in_ifdef), pf->ref_no);
}
/**
* Logs the entire parse frame stack
*/
void pf_log_all(log_sev_t logsev)
{
int idx;
LOG_FMT(logsev, "##=- Parse Frame : %d entries\n", cpd.frame_count);
for (idx = 0; idx < cpd.frame_count; idx++)
{
LOG_FMT(logsev, "## <%d> ", idx);
pf_log(logsev, &cpd.frames[idx]);
}
LOG_FMT(logsev, "##=-\n");
}
/**
* Copies src to dst.
*/
void pf_copy(struct parse_frame *dst, const struct parse_frame *src)
{
memcpy(dst, src, sizeof(struct parse_frame));
}
/**
* Push a copy of the parse frame onto the stack.
* This is called on #if and #ifdef.
*/
void pf_push(struct parse_frame *pf)
{
static int ref_no = 1;
if (cpd.frame_count < (int)ARRAY_SIZE(cpd.frames))
{
pf_copy(&cpd.frames[cpd.frame_count], pf);
cpd.frame_count++;
pf->ref_no = ref_no++;
}
LOG_FMT(LPF, "%s: count = %d\n", __func__, cpd.frame_count);
}
/**
* Push a copy of the parse frame onto the stack, under the tos.
* If this were a linked list, just add before the last item.
* This is called on the first #else and #elif.
*/
void pf_push_under(struct parse_frame *pf)
{
struct parse_frame *npf1;
struct parse_frame *npf2;
LOG_FMT(LPF, "%s: before count = %d\n", __func__, cpd.frame_count);
if ((cpd.frame_count < (int)ARRAY_SIZE(cpd.frames)) &&
(cpd.frame_count >= 1))
{
npf1 = &cpd.frames[cpd.frame_count - 1];
npf2 = &cpd.frames[cpd.frame_count];
pf_copy(npf2, npf1);
pf_copy(npf1, pf);
cpd.frame_count++;
}
LOG_FMT(LPF, "%s: after count = %d\n", __func__, cpd.frame_count);
}
/**
* Copy the top item off the stack into pf.
* This is called on #else and #elif.
*/
void pf_copy_tos(struct parse_frame *pf)
{
if (cpd.frame_count > 0)
{
pf_copy(pf, &cpd.frames[cpd.frame_count - 1]);
}
LOG_FMT(LPF, "%s: count = %d\n", __func__, cpd.frame_count);
}
/**
* Copy the 2nd top item off the stack into pf.
* This is called on #else and #elif.
* The stack contains [...] [base] [if] at this point.
* We want to copy [base].
*/
static void pf_copy_2nd_tos(struct parse_frame *pf)
{
if (cpd.frame_count > 1)
{
pf_copy(pf, &cpd.frames[cpd.frame_count - 2]);
}
LOG_FMT(LPF, "%s: count = %d\n", __func__, cpd.frame_count);
}
/**
* Deletes the top frame from the stack.
*/
void pf_trash_tos(void)
{
if (cpd.frame_count > 0)
{
cpd.frame_count--;
}
LOG_FMT(LPF, "%s: count = %d\n", __func__, cpd.frame_count);
}
/**
* Pop the top item off the stack and copy into pf.
* This is called on #endif
*/
void pf_pop(struct parse_frame *pf)
{
if (cpd.frame_count > 0)
{
pf_copy_tos(pf);
pf_trash_tos();
}
//fprintf(stderr, "%s: count = %d\n", __func__, cpd.frame_count);
}
/**
* Returns the pp_indent to use for this line
*/
int pf_check(struct parse_frame *frm, chunk_t *pc)
{
int in_ifdef = frm->in_ifdef;
int b4_cnt = cpd.frame_count;
int pp_level = cpd.pp_level;
const char *txt = NULL;
chunk_t *next;
if (pc->type != CT_PREPROC)
{
return(pp_level);
}
next = chunk_get_next(pc);
if (pc->parent_type != next->type)
{
LOG_FMT(LNOTE, "%s: Preproc parent not set correctly on line %d: got %s expected %s\n",
__func__, pc->orig_line, get_token_name(pc->parent_type),
get_token_name(next->type));
set_chunk_parent(pc, next->type);
}
LOG_FMT(LPFCHK, "%s: %5d] %s\n",
__func__, pc->orig_line, get_token_name(pc->parent_type));
pf_log_frms(LPFCHK, "TOP", frm);
if ((pc->flags & PCF_IN_PREPROC) != 0)
{
LOG_FMT(LPF, " <In> ");
pf_log(LPF, frm);
if (pc->parent_type == CT_PP_IF)
{
/* An #if pushes a copy of the current frame on the stack */
cpd.pp_level++;
pf_push(frm);
frm->in_ifdef = CT_PP_IF;
txt = "if-push";
}
else if (pc->parent_type == CT_PP_ELSE)
{
pp_level--;
/**
* For #else of #elif, we want to keep the #if part and throw out the
* else parts.
* We check to see what the top type is to see if we just push or
* pop and then push.
* We need to use the copy right before the if.
*/
if (frm->in_ifdef == CT_PP_IF)
{
/* we have [...] [base]-[if], so push an [else] */
pf_push(frm);
frm->in_ifdef = CT_PP_ELSE;
}
/* we have [...] [base] [if]-[else], copy [base] over [else] */
pf_copy_2nd_tos(frm);
frm->in_ifdef = CT_PP_ELSE;
txt = "else-push";
}
else if (pc->parent_type == CT_PP_ENDIF)
{
/**
* we may have [...] [base] [if]-[else] or [...] [base]-[if].
* Throw out the [else].
*/
cpd.pp_level--;
pp_level--;
if (frm->in_ifdef == CT_PP_ELSE)
{
/**
* We have: [...] [base] [if]-[else]
* We want: [...]-[if]
*/
pf_copy_tos(frm); /* [...] [base] [if]-[if] */
frm->in_ifdef = cpd.frames[cpd.frame_count - 2].in_ifdef;
pf_trash_tos(); /* [...] [base]-[if] */
pf_trash_tos(); /* [...]-[if] */
txt = "endif-trash/pop";
}
else if (frm->in_ifdef == CT_PP_IF)
{
/**
* We have: [...] [base] [if]
* We want: [...] [base]
*/
pf_pop(frm);
txt = "endif-pop";
}
else
{
txt = "???";
}
}
}
if (txt != NULL)
{
LOG_FMT(LPF, "%s: %d> %s: %s in_ifdef=%d/%d counts=%d/%d\n", __func__,
pc->orig_line, get_token_name(pc->parent_type), txt,
in_ifdef, frm->in_ifdef, b4_cnt, cpd.frame_count);
pf_log_all(LPF);
LOG_FMT(LPF, " <Out>");
pf_log(LPF, frm);
}
pf_log_frms(LPFCHK, "END", frm);
return(pp_level);
}