VBoxCPP.cpp revision 8014d9e85803119a55d697b5b802d73c011d1f53
d38598568c6e70e0644317f24dc89e1221218524vboxsync * VBox Build Tool - A mini C Preprocessor.
d38598568c6e70e0644317f24dc89e1221218524vboxsync * Purposes to which this preprocessor will be put:
d38598568c6e70e0644317f24dc89e1221218524vboxsync * - Preprocessig vm.h into dtrace/lib/vm.d so we can access the VM
d38598568c6e70e0644317f24dc89e1221218524vboxsync * structure (as well as substructures) from DTrace without having
d38598568c6e70e0644317f24dc89e1221218524vboxsync * to handcraft it all.
d38598568c6e70e0644317f24dc89e1221218524vboxsync * - Removing \#ifdefs relating to a new feature that has become
d38598568c6e70e0644317f24dc89e1221218524vboxsync * stable and no longer needs \#ifdef'ing.
d38598568c6e70e0644317f24dc89e1221218524vboxsync * - Pretty printing preprocessor directives. This will be used by
d38598568c6e70e0644317f24dc89e1221218524vboxsync * Copyright (C) 2012 Oracle Corporation
d38598568c6e70e0644317f24dc89e1221218524vboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
d38598568c6e70e0644317f24dc89e1221218524vboxsync * available from http://www.virtualbox.org. This file is free software;
d38598568c6e70e0644317f24dc89e1221218524vboxsync * you can redistribute it and/or modify it under the terms of the GNU
d38598568c6e70e0644317f24dc89e1221218524vboxsync * General Public License (GPL) as published by the Free Software
d38598568c6e70e0644317f24dc89e1221218524vboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
d38598568c6e70e0644317f24dc89e1221218524vboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
d38598568c6e70e0644317f24dc89e1221218524vboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
d38598568c6e70e0644317f24dc89e1221218524vboxsync/*******************************************************************************
d38598568c6e70e0644317f24dc89e1221218524vboxsync* Header Files *
d38598568c6e70e0644317f24dc89e1221218524vboxsync*******************************************************************************/
d38598568c6e70e0644317f24dc89e1221218524vboxsync/*******************************************************************************
d38598568c6e70e0644317f24dc89e1221218524vboxsync* Defined Constants And Macros *
d38598568c6e70e0644317f24dc89e1221218524vboxsync*******************************************************************************/
d38598568c6e70e0644317f24dc89e1221218524vboxsync/** The bitmap type. */
d38598568c6e70e0644317f24dc89e1221218524vboxsync/** The bitmap size as a multiple of VBCPP_BITMAP_TYPE. */
d38598568c6e70e0644317f24dc89e1221218524vboxsync/** Checks if a bit is set. */
d38598568c6e70e0644317f24dc89e1221218524vboxsync#define VBCPP_BITMAP_IS_SET(a_bm, a_ch) ASMBitTest(a_bm, (a_ch) & 0x7f)
d38598568c6e70e0644317f24dc89e1221218524vboxsync/** Sets a bit. */
d38598568c6e70e0644317f24dc89e1221218524vboxsync#define VBCPP_BITMAP_SET(a_bm, a_ch) ASMBitSet(a_bm, (a_ch) & 0x7f)
d38598568c6e70e0644317f24dc89e1221218524vboxsync/** Empties the bitmap. */
d38598568c6e70e0644317f24dc89e1221218524vboxsync#define VBCPP_BITMAP_EMPTY(a_bm) do { (a_bm)[0] = 0; (a_bm)[1] = 0; } while (0)
d38598568c6e70e0644317f24dc89e1221218524vboxsync/** Joins to bitmaps by OR'ing their values.. */
d38598568c6e70e0644317f24dc89e1221218524vboxsync#define VBCPP_BITMAP_OR(a_bm1, a_bm2) do { (a_bm1)[0] |= (a_bm2)[0]; (a_bm1)[1] |= (a_bm2)[1]; } while (0)
d38598568c6e70e0644317f24dc89e1221218524vboxsync/*******************************************************************************
d38598568c6e70e0644317f24dc89e1221218524vboxsync* Structures and Typedefs *
d38598568c6e70e0644317f24dc89e1221218524vboxsync*******************************************************************************/
d38598568c6e70e0644317f24dc89e1221218524vboxsync * The preprocessor mode.
d38598568c6e70e0644317f24dc89e1221218524vboxsync/* kVBCppMode_Full,*/
d38598568c6e70e0644317f24dc89e1221218524vboxsync * A define.
d38598568c6e70e0644317f24dc89e1221218524vboxsynctypedef struct VBCPPDEF
d38598568c6e70e0644317f24dc89e1221218524vboxsync /** The string space core. */
d38598568c6e70e0644317f24dc89e1221218524vboxsync /** Whether it's a function. */
d38598568c6e70e0644317f24dc89e1221218524vboxsync /** Variable argument count. */
d38598568c6e70e0644317f24dc89e1221218524vboxsync /** Set if originating on the command line. */
d38598568c6e70e0644317f24dc89e1221218524vboxsync /** The number of known arguments.*/
d38598568c6e70e0644317f24dc89e1221218524vboxsync /** Pointer to a list of argument names. */
d38598568c6e70e0644317f24dc89e1221218524vboxsync const char **papszArgs;
d38598568c6e70e0644317f24dc89e1221218524vboxsync /** Lead character bitmap for the argument names. */
d38598568c6e70e0644317f24dc89e1221218524vboxsync /** The define value. (This is followed by the name and arguments.) */
d38598568c6e70e0644317f24dc89e1221218524vboxsync/** Pointer to a define. */
d38598568c6e70e0644317f24dc89e1221218524vboxsync * Expansion context.
d38598568c6e70e0644317f24dc89e1221218524vboxsynctypedef struct VBCPPCTX
d38598568c6e70e0644317f24dc89e1221218524vboxsync /** The next context on the stack. */
d38598568c6e70e0644317f24dc89e1221218524vboxsync /** The define being expanded. */
d38598568c6e70e0644317f24dc89e1221218524vboxsync /** Arguments. */
d38598568c6e70e0644317f24dc89e1221218524vboxsync /** The value. */
d38598568c6e70e0644317f24dc89e1221218524vboxsync const char *pchValue;
d38598568c6e70e0644317f24dc89e1221218524vboxsync /** The value length. */
d38598568c6e70e0644317f24dc89e1221218524vboxsync const char *cchValue;
d38598568c6e70e0644317f24dc89e1221218524vboxsync/** Pointer to an define expansion context. */
d38598568c6e70e0644317f24dc89e1221218524vboxsync * Evaluation result.
d38598568c6e70e0644317f24dc89e1221218524vboxsync * The condition kind.
d38598568c6e70e0644317f24dc89e1221218524vboxsync /** \#if expr */
d38598568c6e70e0644317f24dc89e1221218524vboxsync /** \#ifdef define */
d38598568c6e70e0644317f24dc89e1221218524vboxsync /** \#ifndef define */
d38598568c6e70e0644317f24dc89e1221218524vboxsync /** \#elif expr */
d38598568c6e70e0644317f24dc89e1221218524vboxsync /** The end of valid values. */
d38598568c6e70e0644317f24dc89e1221218524vboxsync * Conditional stack entry.
d38598568c6e70e0644317f24dc89e1221218524vboxsynctypedef struct VBCPPCOND
d38598568c6e70e0644317f24dc89e1221218524vboxsync /** The next conditional on the stack. */
d38598568c6e70e0644317f24dc89e1221218524vboxsync /** The kind of conditional. This changes on encountering \#elif. */
d38598568c6e70e0644317f24dc89e1221218524vboxsync /** Evaluation result. */
d38598568c6e70e0644317f24dc89e1221218524vboxsync /** The evaluation result of the whole stack. */
d38598568c6e70e0644317f24dc89e1221218524vboxsync /** Whether we've seen the last else. */
d38598568c6e70e0644317f24dc89e1221218524vboxsync /** The nesting level of this condition. */
d38598568c6e70e0644317f24dc89e1221218524vboxsync /** The nesting level of this condition wrt the ones we keep. */
d38598568c6e70e0644317f24dc89e1221218524vboxsync /** The condition string. (Points within the stream buffer.) */
d38598568c6e70e0644317f24dc89e1221218524vboxsync const char *pchCond;
d38598568c6e70e0644317f24dc89e1221218524vboxsync /** The condition length. */
d38598568c6e70e0644317f24dc89e1221218524vboxsync/** Pointer to a conditional stack entry. */
d38598568c6e70e0644317f24dc89e1221218524vboxsync * Input buffer stack entry.
d38598568c6e70e0644317f24dc89e1221218524vboxsynctypedef struct VBCPPINPUT
d38598568c6e70e0644317f24dc89e1221218524vboxsync /** Pointer to the next input on the stack. */
d38598568c6e70e0644317f24dc89e1221218524vboxsync /** The input stream. */
d38598568c6e70e0644317f24dc89e1221218524vboxsync /** Pointer into szName to the part which was specified. */
d38598568c6e70e0644317f24dc89e1221218524vboxsync /** The input file name with include path. */
d38598568c6e70e0644317f24dc89e1221218524vboxsync/** Pointer to a input buffer stack entry */
d38598568c6e70e0644317f24dc89e1221218524vboxsync * C Preprocessor instance data.
d38598568c6e70e0644317f24dc89e1221218524vboxsynctypedef struct VBCPP
d38598568c6e70e0644317f24dc89e1221218524vboxsync /** @name Options
d38598568c6e70e0644317f24dc89e1221218524vboxsync /** The preprocessing mode. */
d38598568c6e70e0644317f24dc89e1221218524vboxsync /** Whether to keep comments. */
d38598568c6e70e0644317f24dc89e1221218524vboxsync /** The number of include directories. */
d38598568c6e70e0644317f24dc89e1221218524vboxsync /** Array of directories to search for include files. */
d38598568c6e70e0644317f24dc89e1221218524vboxsync /** The name of the input file. */
d38598568c6e70e0644317f24dc89e1221218524vboxsync const char *pszInput;
d38598568c6e70e0644317f24dc89e1221218524vboxsync /** The name of the output file. NULL if stdout. */
d38598568c6e70e0644317f24dc89e1221218524vboxsync /** The define string space. */
d38598568c6e70e0644317f24dc89e1221218524vboxsync /** The string space holding explicitly undefined macros for selective
d38598568c6e70e0644317f24dc89e1221218524vboxsync * preprocessing runs. */
d38598568c6e70e0644317f24dc89e1221218524vboxsync /** Indicates whether a C-word might need expansion.
d38598568c6e70e0644317f24dc89e1221218524vboxsync * The bitmap is indexed by C-word lead character. Bits that are set
d38598568c6e70e0644317f24dc89e1221218524vboxsync * indicates that the lead character is used in a \#define that we know and
d38598568c6e70e0644317f24dc89e1221218524vboxsync * should expand. */
d38598568c6e70e0644317f24dc89e1221218524vboxsync /** Indicates whether a C-word might need argument expansion.
d38598568c6e70e0644317f24dc89e1221218524vboxsync * The bitmap is indexed by C-word lead character. Bits that are set
d38598568c6e70e0644317f24dc89e1221218524vboxsync * indicates that the lead character is used in an argument of an currently
d38598568c6e70e0644317f24dc89e1221218524vboxsync * expanding \#define. */
d38598568c6e70e0644317f24dc89e1221218524vboxsync /** Expansion context stack. */
d38598568c6e70e0644317f24dc89e1221218524vboxsync /** The current expansion stack depth. */
d38598568c6e70e0644317f24dc89e1221218524vboxsync /** The current depth of the conditional stack. */
d38598568c6e70e0644317f24dc89e1221218524vboxsync /** Conditional stack. */
d38598568c6e70e0644317f24dc89e1221218524vboxsync /** The current condition evaluates to kVBCppEval_False, don't output. */
d38598568c6e70e0644317f24dc89e1221218524vboxsync /** Whether the current line could be a preprocessor line.
bool fMaybePreprocessorLine;
bool fStrmOutputValid;
} VBCPP;
RTPrintf("%s:%d:%zd: error: %N.\n", pThis->pInputStack->szName, iLine + 1, off - offLine + 1, pszMsg, va);
if (pszLine)
if (cchIdentifier == 0)
vbcppErrorPos(pThis, pchIdentifier, "Bad lead chararacter in identifier: '%.*s'", cchIdentifier, pchIdentifier);
vbcppErrorPos(pThis, pchIdentifier + off, "Illegal chararacter in identifier: '%.*s' (#%zu)", cchIdentifier, pchIdentifier, off + 1);
return VINF_SUCCESS;
static RTEXITCODE vbcppDefineUndef(PVBCPP pThis, const char *pszDefine, size_t cchDefine, bool fExplicitUndef)
if (pHit)
if (fExplicitUndef)
if (!pStr)
return RTEXITCODE_SUCCESS;
PVBCPPDEF pOld = (PVBCPPDEF)vbcppDefineUndef(pThis, pDef->Core.pszString, pDef->Core.cchString, false);
return RTEXITCODE_SUCCESS;
bool fCmdLine)
fIgnoreComma = false;
off++;
cArgs++;
off++;
+ sizeof(const char *) * cArgs;
if (!pDef)
fIgnoreComma = false;
off++;
iArg++;
cchDefine--;
if (!cchDefine)
cchValue--;
if (pszParams)
return RTEXITCODE_FAILURE;
pszParams++;
return vbcppDefineAddFn(pThis, pszDefine, cchDefine, pszParams, cchParams, pszValue, cchValue, fCmdLine);
return RTEXITCODE_FAILURE;
PVBCPPDEF pDef = (PVBCPPDEF)RTMemAlloc(RT_OFFSETOF(VBCPPDEF, szValue[cchValue + 1 + cchDefine + 1]));
if (!pDef)
return cchDefine > 0
if (!pv)
return RTEXITCODE_SUCCESS;
*pfExit = false;
int rc = RTGetOptInit(&GetOptState, argc, argv, &s_aOpts[0], RT_ELEMENTS(s_aOpts), 1, RTGETOPTINIT_FLAGS_OPTS_FIRST);
switch (rc)
if (pszEqual)
rcExit = vbcppDefineAdd(pThis, ValueUnion.psz, pszEqual - ValueUnion.psz, pszEqual + 1, RTSTR_MAX, true);
return rcExit;
return rcExit;
*pfExit = true;
return RTEXITCODE_SUCCESS;
*pfExit = true;
return RTEXITCODE_SUCCESS;
case VINF_GETOPT_NOT_OPTION:
return RTEXITCODE_SUCCESS;
if (!pInput)
return RTEXITCODE_SUCCESS;
return RTEXITCODE_SUCCESS;
return RTEXITCODE_SUCCESS;
static RTEXITCODE vbcppOutputComment(PVBCPP pThis, PSCMSTREAM pStrmInput, size_t offStart, size_t cchOutputted,
if (ch == ~(unsigned)0)
return RTEXITCODE_SUCCESS;
unsigned ch;
return rcExit;
if ( cchLine == 0
if (!pszLine)
return rcExit;
bool fEscaped = false;
if (ch == ~(unsigned)0)
return rcExit;
bool fEscaped = false;
if (ch == ~(unsigned)0)
return rcExit;
unsigned chPrev = ~(unsigned)0;
unsigned ch;
unsigned chPrev = ~(unsigned)0;
unsigned ch;
if (ch == ~(unsigned)0)
if (ch == ~(unsigned)0)
return RTEXITCODE_SUCCESS;
static RTEXITCODE vbcppProcessSkipWhiteEscapedEolAndCommentsCheckEol(PVBCPP pThis, PSCMSTREAM pStrmInput)
if ( ch != ~(unsigned)0
return rcExit;
unsigned ch;
if (ch != ~(unsigned)0)
if (cch > 0)
return rcExit;
if (pchDefine)
if (pchParams)
rcExit = vbcppDefineAddFn(pThis, pchDefine, cchDefine, pchParams, cchParams, pchValue, cchValue, false);
if (pchParams)
if (cch > 0)
return rcExit;
return kVBCppEval_False;
return enmEvalPush;
if (!pCond)
const char *pszDirective;
switch (enmKind)
if (cch < 0)
return RTEXITCODE_SUCCESS;
if (pchDefine)
return rcExit;
if (pchDefine)
return rcExit;
if (pCond)
if (cch > 0)
return rcExit;
if (pCond)
if (cch > 0)
return rcExit;
return rcExit;
if (pchDirective)
#define IS_DIRECTIVE(a_sz) ( sizeof(a_sz) - 1 == cchDirective && strncmp(pchDirective, a_sz, sizeof(a_sz) - 1) == 0)
return rcExit;
unsigned ch;
return rcExit;
bool fExit;
return rcExit;