VBoxCPP.cpp revision b20cc298c1a3191a4e6ce780c19313117902675d
/* $Id$ */
/** @file
* VBox Build Tool - A mini C Preprocessor.
*
* Purposes to which this preprocessor will be put:
* structure (as well as substructures) from DTrace without having
* to handcraft it all.
* - Removing \#ifdefs relating to a new feature that has become
* stable and no longer needs \#ifdef'ing.
* - Pretty printing preprocessor directives. This will be used by
* SCM.
*/
/*
* Copyright (C) 2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
* General Public License (GPL) as published by the Free Software
* Foundation, in version 2 as it comes in the "COPYING" file of the
* VirtualBox OSE distribution. VirtualBox OSE is distributed in the
* hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
*/
/*******************************************************************************
* Header Files *
*******************************************************************************/
#include <iprt/initterm.h>
#include "scmstream.h"
/*******************************************************************************
* Defined Constants And Macros *
*******************************************************************************/
/** The bitmap type. */
#define VBCPP_BITMAP_TYPE uint64_t
/** The bitmap size as a multiple of VBCPP_BITMAP_TYPE. */
/** Checks if a bit is set. */
/** Sets a bit. */
/** Empties the bitmap. */
/** Joins to bitmaps by OR'ing their values.. */
#define VBCPP_BITMAP_OR(a_bm1, a_bm2) do { (a_bm1)[0] |= (a_bm2)[0]; (a_bm1)[1] |= (a_bm2)[1]; } while (0)
/*******************************************************************************
* Structures and Typedefs *
*******************************************************************************/
/**
* The preprocessor mode.
*/
typedef enum VBCPPMODE
{
kVBCppMode_Invalid = 0,
/* kVBCppMode_Full,*/
} VBCPPMODE;
/**
* A define.
*/
typedef struct VBCPPDEF
{
/** The string space core. */
/** Whether it's a function. */
bool fFunction;
/** Variable argument count. */
bool fVarArg;
/** The number of known arguments.*/
/** Pointer to a list of argument names. */
const char **papszArgs;
/** Lead character bitmap for the argument names. */
/** The define value. (This is followed by the name and arguments.) */
char szValue[1];
} VBCPPDEF;
/** Pointer to a define. */
/**
* Expansion context.
*/
typedef struct VBCPPCTX
{
/** The next context on the stack. */
/** The define being expanded. */
/** Arguments. */
struct VBCPPCTXARG
{
/** The value. */
const char *pchValue;
/** The value length. */
const char *cchValue;
} aArgs[1];
} VBCPPCTX;
/** Pointer to an define expansion context. */
/**
* Evaluation result.
*/
typedef enum VBCPPEVAL
{
kVBCppEval_Invalid = 0,
} VBCPPEVAL;
/**
* The condition kind.
*/
typedef enum VBCPPCONDKIND
{
/** \#if expr */
/** \#ifdef define */
/** \#ifndef define */
/** \#elif expr */
/** The end of valid values. */
/**
* Conditional stack entry.
*/
typedef struct VBCPPCOND
{
/** The next conditional on the stack. */
/** The kind of conditional. This changes on encountering \#elif. */
/** Evaluation result. */
/** The evaluation result of the whole stack. */
/** Whether we've seen the last else. */
bool fSeenElse;
/** The nesting level of this condition. */
/** The nesting level of this condition wrt the ones we keep. */
/** The condition string. (Points within the stream buffer.) */
const char *pchCond;
/** The condition length. */
} VBCPPCOND;
/** Pointer to a conditional stack entry. */
typedef VBCPPCOND *PVBCPPCOND;
/**
* Input buffer stack entry.
*/
typedef struct VBCPPINPUT
{
/** Pointer to the next input on the stack. */
struct VBCPPINPUT *pUp;
/** The input stream. */
/** Pointer into szName to the part which was specified. */
const char *pszSpecified;
/** The input file name with include path. */
char szName[1];
} VBCPPINPUT;
/** Pointer to a input buffer stack entry */
typedef VBCPPINPUT *PVBCPPINPUT;
/**
* C Preprocessor instance data.
*/
typedef struct VBCPP
{
/** @name Options
* @{ */
/** The preprocessing mode. */
/** Whether to keep comments. */
bool fKeepComments;
/** The number of include directories. */
/** Array of directories to search for include files. */
char **papszIncludes;
/** The name of the input file. */
const char *pszInput;
/** The name of the output file. NULL if stdout. */
const char *pszOutput;
/** @} */
/** The define string space. */
/** The string space holding explicitly undefined macros for selective
* preprocessing runs. */
/** Indicates whether a C-word might need expansion.
* The bitmap is indexed by C-word lead character. Bits that are set
* indicates that the lead character is used in a \#define that we know and
* should expand. */
/** Indicates whether a C-word might need argument expansion.
* The bitmap is indexed by C-word lead character. Bits that are set
* indicates that the lead character is used in an argument of an currently
* expanding \#define. */
/** Expansion context stack. */
/** The current expansion stack depth. */
/** The current depth of the conditional stack. */
/** Conditional stack. */
/** The current condition evaluates to kVBCppEval_False, don't output. */
bool fIf0Mode;
/** Whether the current line could be a preprocessor line.
* This is set when EOL is encountered and cleared again when a
* non-comment-or-space character is encountered. See vbcppPreprocess. */
bool fMaybePreprocessorLine;
/** The input stack depth */
/** The input buffer stack. */
/** The output stream. */
/** The status of the whole job, as far as we know. */
/** Whether StrmOutput is valid (for vbcppTerm). */
bool fStrmOutputValid;
} VBCPP;
/** Pointer to the C preprocessor instance data. */
/*******************************************************************************
* Global Variables *
*******************************************************************************/
{
pThis->fKeepComments = true;
pThis->cExpStackDepth = 0;
pThis->cCondStackDepth = 0;
pThis->fMaybePreprocessorLine = true;
pThis->cCondStackDepth = 0;
pThis->fStrmOutputValid = false;
}
/**
* Displays an error message.
*
* @returns RTEXITCODE_FAILURE
* @param pThis The C preprocessor instance.
* @param pszMsg The message.
* @param ... Message arguments.
*/
{
if (pThis->pInputStack)
{
RTPrintf("%s:%d:%zd: error: %N.\n", pThis->pInputStack->szName, iLine + 1, off - offLine + 1, pszMsg, va);
if (pszLine)
RTPrintf(" %.*s\n"
" %*s^\n",
}
else
{
}
}
/**
* Displays an error message.
*
* @returns RTEXITCODE_FAILURE
* @param pThis The C preprocessor instance.
* @param pszPos Pointer to the offending character.
* @param pszMsg The message.
* @param ... Message arguments.
*/
{
}
/**
* Checks if the given character is a valid C identifier lead character.
*
* @returns true / false.
* @param ch The character to inspect.
*/
{
return RT_C_IS_ALPHA(ch)
|| ch == '_';
}
/**
* Checks if the given character is a valid C identifier character.
*
* @returns true / false.
* @param ch The character to inspect.
*/
{
return RT_C_IS_ALNUM(ch)
|| ch == '_';
}
/**
*
* @returns @c true if valid, @c false if not. Error message already displayed
* on failure.
* @param pThis The C preprocessor instance.
* @param pchIdentifier The start of the identifier to validate.
* @param cchIdentifier The length of the identifier. RTSTR_MAX if not
* known.
*/
{
if (cchIdentifier == RTSTR_MAX)
if (cchIdentifier == 0)
{
return false;
}
{
vbcppErrorPos(pThis, pchIdentifier, "Bad lead chararacter in identifier: '%.*s'", cchIdentifier, pchIdentifier);
return false;
}
{
{
vbcppErrorPos(pThis, pchIdentifier + off, "Illegal chararacter in identifier: '%.*s' (#%zu)", cchIdentifier, pchIdentifier, off + 1);
return false;
}
}
return true;
}
/**
* Frees a define.
*
* @returns VINF_SUCCESS (used when called by RTStrSpaceDestroy)
* @param pStr Pointer to the VBCPPDEF::Core member.
* @param pvUser Unused.
*/
{
return VINF_SUCCESS;
}
/**
* Removes a define.
*
* @returns RTEXITCODE_SUCCESS or RTEXITCODE_FAILURE + msg.
* @param pThis The C preprocessor instance.
* @param pszDefine The define name, no argument list or anything.
* @param cchDefine The length of the name. RTSTR_MAX is ok.
* @param fExplicitUndef Explicit undefinition, that is, in a selective
* preprocessing run it will evaluate to undefined.
*/
static RTEXITCODE vbcppDefineUndef(PVBCPP pThis, const char *pszDefine, size_t cchDefine, bool fExplicitUndef)
{
if (pHit)
{
}
if (fExplicitUndef)
{
if (!pStr)
}
return RTEXITCODE_SUCCESS;
}
/**
* Inserts a define.
*
* @returns RTEXITCODE_SUCCESS or RTEXITCODE_FAILURE + msg.
* @param pThis The C preprocessor instance.
* @param pDef The define to insert.
*/
{
else
{
PVBCPPDEF pOld = (PVBCPPDEF)vbcppDefineUndef(pThis, pDef->Core.pszString, pDef->Core.cchString, false);
}
return RTEXITCODE_SUCCESS;
}
/**
* Adds a define.
*
* @returns RTEXITCODE_SUCCESS or RTEXITCODE_FAILURE + msg.
* @param pThis The C preprocessor instance.
* @param pszDefine The define name, no parameter list.
* @param cchDefine The length of the name.
* @param pszParams The parameter list.
* @param cchParams The length of the parameter list.
* @param pszValue The value.
* @param cchDefine The length of the value.
*/
{
/*
* Determin the number of arguments and how much space their names
* requires. Performing syntax validation while parsing.
*/
uint32_t cchArgNames = 0;
{
/* Skip blanks and maybe one comma. */
bool fIgnoreComma = cArgs != 0;
{
{
{
break;
/** @todo variadic macros. */
}
fIgnoreComma = false;
}
off++;
}
break;
/* Found and argument. First character is already validated. */
cArgs++;
cchArgNames += 2;
off++;
off++, cchArgNames++;
}
/*
* Allocate a structure.
*/
+ sizeof(const char *) * cArgs;
if (!pDef)
*pszDst++ = '\0';
/*
* Set up the arguments.
*/
{
/* Skip blanks and maybe one comma. */
bool fIgnoreComma = cArgs != 0;
{
{
break;
fIgnoreComma = false;
}
off++;
}
break;
/* Found and argument. First character is already validated. */
do
{
*pszDst++ = '\0';
iArg++;
}
}
/**
* Adds a define.
*
* @returns RTEXITCODE_SUCCESS or RTEXITCODE_FAILURE + msg.
* @param pThis The C preprocessor instance.
* @param pszDefine The define name and optionally the argument
* list.
* @param cchDefine The length of the name. RTSTR_MAX is ok.
* @param pszValue The value.
* @param cchDefine The length of the value. RTSTR_MAX is ok.
*/
{
/*
* We need the lengths. Trim the input.
*/
cchDefine--;
if (!cchDefine)
cchValue--;
/*
* Arguments make the job a bit more annoying. Handle that elsewhere
*/
if (pszParams)
{
return RTEXITCODE_FAILURE;
pszParams++;
cchParams -= 2;
}
/*
* Simple define, no arguments.
*/
return RTEXITCODE_FAILURE;
PVBCPPDEF pDef = (PVBCPPDEF)RTMemAlloc(RT_OFFSETOF(VBCPPDEF, szValue[cchValue + 1 + cchDefine + 1]));
if (!pDef)
}
/**
* Checks if a define exists.
*
* @returns true or false.
* @param pThis The C preprocessor instance.
* @param pszDefine The define name and optionally the argument
* list.
* @param cchDefine The length of the name. RTSTR_MAX is ok.
*/
{
return cchDefine > 0
}
/**
* Adds an include directory.
*
* @returns Program exit code, with error message on failure.
* @param pThis The C preprocessor instance.
* @param pszDir The directory to add.
*/
{
if (!pv)
if (RT_FAILURE(rc))
return RTEXITCODE_SUCCESS;
}
/**
* Parses the command line options.
*
* @returns Program exit code. Exit on non-success or if *pfExit is set.
* @param pThis The C preprocessor instance.
* @param argc The argument count.
* @param argv The argument vector.
* @param pfExit Pointer to the exit indicator.
*/
{
*pfExit = false;
/*
* Option config.
*/
static RTGETOPTDEF const s_aOpts[] =
{
};
int rc = RTGetOptInit(&GetOptState, argc, argv, &s_aOpts[0], RT_ELEMENTS(s_aOpts), 1, RTGETOPTINIT_FLAGS_OPTS_FIRST);
/*
* Process the options.
*/
{
switch (rc)
{
case 'c':
pThis->fKeepComments = false;
break;
case 'C':
pThis->fKeepComments = false;
break;
case 'd':
pThis->fKeepComments = true;
break;
case 'D':
{
if (pszEqual)
else
if (rcExit != RTEXITCODE_SUCCESS)
return rcExit;
break;
}
case 'I':
if (rcExit != RTEXITCODE_SUCCESS)
return rcExit;
break;
case 'U':
break;
case 'h':
RTPrintf("No help yet, sorry\n");
*pfExit = true;
return RTEXITCODE_SUCCESS;
case 'V':
{
/* The following is assuming that svn does it's job here. */
static const char s_szRev[] = "$Revision$";
*pfExit = true;
return RTEXITCODE_SUCCESS;
}
case VINF_GETOPT_NOT_OPTION:
else
break;
/*
* Errors and bugs.
*/
default:
}
}
return RTEXITCODE_SUCCESS;
}
/**
* Opens the input and output streams.
*
* @returns Exit code.
* @param pThis The C preprocessor instance.
*/
{
if (!pInput)
if (RT_FAILURE(rc))
if (RT_FAILURE(rc))
pThis->fStrmOutputValid = true;
return RTEXITCODE_SUCCESS;
}
/**
* Outputs a character.
*
* @returns RTEXITCODE_SUCCESS or RTEXITCODE_FAILURE+msg.
* @param pThis The C preprocessor instance.
* @param ch The character to output.
*/
{
if (RT_SUCCESS(rc))
return RTEXITCODE_SUCCESS;
}
/**
* Outputs a string.
*
* @returns RTEXITCODE_SUCCESS or RTEXITCODE_FAILURE+msg.
* @param pThis The C preprocessor instance.
* @param pch The string.
* @param cch The number of characters to write.
*/
{
if (RT_SUCCESS(rc))
return RTEXITCODE_SUCCESS;
}
static RTEXITCODE vbcppOutputComment(PVBCPP pThis, PSCMSTREAM pStrmInput, size_t offStart, size_t cchOutputted)
{
{
/*
* Use the same indent, if possible.
*/
if (cchOutputted < cchIndent)
else
if (RT_FAILURE(rc))
/*
* Copy the bytes.
*/
{
if (ch == ~(unsigned)0)
if (RT_FAILURE(rc))
}
}
return RTEXITCODE_SUCCESS;
}
/**
* Processes a multi-line comment.
*
* Must either string the comment or keep it. If the latter, we must refrain
* from replacing C-words in it.
*
* @returns RTEXITCODE_SUCCESS or RTEXITCODE_FAILURE+msg.
* @param pThis The C preprocessor instance.
* @param pStrmInput The input stream.
*/
{
/* The open comment sequence. */
if ( pThis->fKeepComments
/* The comment.*/
unsigned ch;
while ( rcExit == RTEXITCODE_SUCCESS
{
if (ch == '*')
{
/* Closing sequence? */
if (ch2 == '/')
{
if ( pThis->fKeepComments
break;
}
}
if ( ( pThis->fKeepComments
|| ch == '\r'
|| ch == '\n')
{
if (rcExit != RTEXITCODE_SUCCESS)
break;
/* Reset the maybe-preprocessor-line indicator when necessary. */
pThis->fMaybePreprocessorLine = true;
}
}
return rcExit;
}
/**
* Processes a single line comment.
*
* Must either string the comment or keep it. If the latter, we must refrain
* from replacing C-words in it.
*
* @returns RTEXITCODE_SUCCESS or RTEXITCODE_FAILURE+msg.
* @param pThis The C preprocessor instance.
* @param pStrmInput The input stream.
*/
{
for (;;)
{
if ( pThis->fKeepComments
else
if (rcExit != RTEXITCODE_SUCCESS)
break;
if ( cchLine == 0
break;
if (!pszLine)
break;
}
pThis->fMaybePreprocessorLine = true;
return rcExit;
}
/**
* Processes a double quoted string.
*
* Must not replace any C-words in strings.
*
* @returns RTEXITCODE_SUCCESS or RTEXITCODE_FAILURE+msg.
* @param pThis The C preprocessor instance.
* @param pStrmInput The input stream.
*/
{
if (rcExit == RTEXITCODE_SUCCESS)
{
bool fEscaped = false;
for (;;)
{
if (ch == ~(unsigned)0)
{
break;
}
if (rcExit != RTEXITCODE_SUCCESS)
break;
break;
}
}
return rcExit;
}
/**
* Processes a single quoted litteral.
*
* Must not replace any C-words in strings.
*
* @returns RTEXITCODE_SUCCESS or RTEXITCODE_FAILURE+msg.
* @param pThis The C preprocessor instance.
* @param pStrmInput The input stream.
*/
{
if (rcExit == RTEXITCODE_SUCCESS)
{
bool fEscaped = false;
for (;;)
{
if (ch == ~(unsigned)0)
{
break;
}
if (rcExit != RTEXITCODE_SUCCESS)
break;
break;
}
}
return rcExit;
}
/**
* Skips white spaces, including escaped new-lines.
*
* @param pStrmInput The input stream.
*/
{
unsigned chPrev = ~(unsigned)0;
unsigned ch;
{
{
if (chPrev != '\\')
break;
}
else if (RT_C_IS_SPACE(ch))
{
}
else
break;
}
}
/**
* Skips white spaces, escaped new-lines and multi line comments.
*
* @param pThis The C preprocessor instance.
* @param pStrmInput The input stream.
*/
{
unsigned chPrev = ~(unsigned)0;
unsigned ch;
{
if (!RT_C_IS_SPACE(ch))
{
/* Multi-line Comment? */
if (ch != '/')
break; /* most definitely, not. */
{
break; /* no */
}
/* Skip to the end of the comment. */
{
if (ch == '*')
{
if (ch == '/')
break;
if (ch == ~(unsigned)0)
break;
}
}
if (ch == ~(unsigned)0)
chPrev = '/';
}
/* New line (also matched by RT_C_IS_SPACE). */
{
/* Stop if not escaped. */
if (chPrev != '\\')
break;
}
/* Real space char. */
else
{
}
}
return RTEXITCODE_SUCCESS;
}
/**
* Skips white spaces, escaped new-lines, and multi line comments, then checking
* that we're at the end of a line.
*
* @param pThis The C preprocessor instance.
* @param pStrmInput The input stream.
*/
static RTEXITCODE vbcppProcessSkipWhiteEscapedEolAndCommentsCheckEol(PVBCPP pThis, PSCMSTREAM pStrmInput)
{
if (rcExit == RTEXITCODE_SUCCESS)
{
if ( ch != ~(unsigned)0
&& ch != '\r'
&& ch != '\n')
}
return rcExit;
}
/**
* Skips white spaces.
*
* @returns The current location upon return..
* @param pStrmInput The input stream.
*/
{
unsigned ch;
{
break;
}
return ScmStreamTell(pStrmInput);
}
/**
* Processes a abbreviated line number directive.
*
* @returns RTEXITCODE_SUCCESS or RTEXITCODE_FAILURE+msg.
* @param pThis The C preprocessor instance.
* @param pStrmInput The input stream.
* @param offStart The stream position where the directive
* started (for pass thru).
*/
{
/*
* Parse it.
*/
if (rcExit == RTEXITCODE_SUCCESS)
{
size_t cchFileSpec = 0;
const char *pchFileSpec = NULL;
size_t cchFilename = 0;
const char *pchFilename = NULL;
{
{
{
break;
}
}
if (rcExit == RTEXITCODE_SUCCESS)
{
if (ch != ~(unsigned)0)
else
}
}
else if (vbcppIsCIdentifierLeadChar(ch))
{
//pchFileSpec = ScmStreamCGetWord(pStrmInput, &cchFileSpec);
}
else
/*
* Take down the location of the next non-white space, in case we need
* to pass thru the directive further down. Then skip to the end of the
* line.
*/
if (rcExit == RTEXITCODE_SUCCESS)
if (rcExit == RTEXITCODE_SUCCESS)
{
/*
* Execute it.
*/
{
/** @todo Search for the include file and push it onto the input stack.
* Not difficult, just unnecessary rigth now. */
}
{
/* Pretty print the passthru. */
if (chType == '<')
else if (chType == '"')
else
if (cch > 0)
else
}
/* else: drop it */
}
}
return rcExit;
}
/**
* Processes a abbreviated line number directive.
*
* @returns RTEXITCODE_SUCCESS or RTEXITCODE_FAILURE+msg.
* @param pThis The C preprocessor instance.
* @param pStrmInput The input stream.
* @param offStart The stream position where the directive
* started (for pass thru).
*/
{
}
/**
* Processes a abbreviated line number directive.
*
* @returns RTEXITCODE_SUCCESS or RTEXITCODE_FAILURE+msg.
* @param pThis The C preprocessor instance.
* @param pStrmInput The input stream.
* @param offStart The stream position where the directive
* started (for pass thru).
*/
{
}
{
if (enmEvalTop == kVBCppEval_False)
return kVBCppEval_False;
return enmEvalPush;
}
{
/*
* Allocate a new entry and push it.
*/
if (!pCond)
/*
* Do pass thru.
*/
&& enmResult == kVBCppEval_Undecided)
{
/** @todo this is stripping comments of \#ifdef and \#ifndef atm. */
const char *pszDirective;
switch (enmKind)
{
default: AssertFailedReturn(RTEXITCODE_FAILURE);
}
if (cch < 0)
}
return RTEXITCODE_SUCCESS;
}
/**
* Processes a abbreviated line number directive.
*
* @returns RTEXITCODE_SUCCESS or RTEXITCODE_FAILURE+msg.
* @param pThis The C preprocessor instance.
* @param pStrmInput The input stream.
* @param offStart The stream position where the directive
* started (for pass thru).
*/
{
}
/**
* Processes a abbreviated line number directive.
*
* @returns RTEXITCODE_SUCCESS or RTEXITCODE_FAILURE+msg.
* @param pThis The C preprocessor instance.
* @param pStrmInput The input stream.
* @param offStart The stream position where the directive
* started (for pass thru).
*/
{
/*
* Parse it.
*/
if (rcExit == RTEXITCODE_SUCCESS)
{
if (pchDefine)
{
if (rcExit == RTEXITCODE_SUCCESS)
{
/*
* Evaluate it.
*/
else
}
}
else
}
return rcExit;
}
/**
* Processes a abbreviated line number directive.
*
* @returns RTEXITCODE_SUCCESS or RTEXITCODE_FAILURE+msg.
* @param pThis The C preprocessor instance.
* @param pStrmInput The input stream.
* @param offStart The stream position where the directive
* started (for pass thru).
*/
{
/*
* Parse it.
*/
if (rcExit == RTEXITCODE_SUCCESS)
{
if (pchDefine)
{
if (rcExit == RTEXITCODE_SUCCESS)
{
/*
* Evaluate it.
*/
else
}
}
else
}
return rcExit;
}
/**
* Processes a abbreviated line number directive.
*
* @returns RTEXITCODE_SUCCESS or RTEXITCODE_FAILURE+msg.
* @param pThis The C preprocessor instance.
* @param pStrmInput The input stream.
* @param offStart The stream position where the directive
* started (for pass thru).
*/
{
/*
* Nothing to parse, just comment positions to find and note down.
*/
if (rcExit == RTEXITCODE_SUCCESS)
{
/*
* Execute.
*/
if (pCond)
{
{
{
else
}
/*
* Do pass thru.
*/
{
if (cch > 0)
else
}
}
else
}
else
}
return rcExit;
}
/**
* Processes a abbreviated line number directive.
*
* @returns RTEXITCODE_SUCCESS or RTEXITCODE_FAILURE+msg.
* @param pThis The C preprocessor instance.
* @param pStrmInput The input stream.
* @param offStart The stream position where the directive
* started (for pass thru).
*/
{
/*
* Nothing to parse, just comment positions to find and note down.
*/
if (rcExit == RTEXITCODE_SUCCESS)
{
/*
* Execute.
*/
if (pCond)
{
/*
* Do pass thru.
*/
{
if (cch > 0)
else
}
}
else
}
return rcExit;
}
/**
* Processes a abbreviated line number directive.
*
* @returns RTEXITCODE_SUCCESS or RTEXITCODE_FAILURE+msg.
* @param pThis The C preprocessor instance.
* @param pStrmInput The input stream.
* @param offStart The stream position where the directive
* started (for pass thru).
*/
{
}
/**
* Processes a abbreviated line number directive.
*
* @returns RTEXITCODE_SUCCESS or RTEXITCODE_FAILURE+msg.
* @param pThis The C preprocessor instance.
* @param pStrmInput The input stream.
* @param offStart The stream position where the directive
* started (for pass thru).
*/
{
}
/**
* Processes a abbreviated line number directive.
*
* @returns RTEXITCODE_SUCCESS or RTEXITCODE_FAILURE+msg.
* @param pThis The C preprocessor instance.
* @param pStrmInput The input stream.
*/
{
}
/**
* Handles a preprocessor directive.
*
* @returns RTEXITCODE_SUCCESS or RTEXITCODE_FAILURE+msg.
* @param pThis The C preprocessor instance.
* @param pStrmInput The input stream.
*/
{
/*
* Get the directive and do a string switch on it.
*/
if (rcExit != RTEXITCODE_SUCCESS)
return rcExit;
if (pchDirective)
{
#define IS_DIRECTIVE(a_sz) ( sizeof(a_sz) - 1 == cchDirective && strncmp(pchDirective, a_sz, sizeof(a_sz) - 1) == 0)
if (IS_DIRECTIVE("if"))
else if (IS_DIRECTIVE("ifdef"))
else if (IS_DIRECTIVE("ifndef"))
else if (IS_DIRECTIVE("else"))
else if (IS_DIRECTIVE("endif"))
{
if (IS_DIRECTIVE("include"))
else if (IS_DIRECTIVE("define"))
else if (IS_DIRECTIVE("undef"))
else if (IS_DIRECTIVE("pragma"))
else if (IS_DIRECTIVE("line"))
else
}
}
{
/* Could it be a # <num> "file" directive? */
if (RT_C_IS_DIGIT(ch))
else
}
return rcExit;
}
/**
* Processes a C word, possibly replacing it with a definition.
*
* @returns RTEXITCODE_SUCCESS or RTEXITCODE_FAILURE+msg.
* @param pThis The C preprocessor instance.
* @param pStrmInput The input stream.
* @param ch The first character.
*/
{
/** @todo Implement this... */
}
/**
* Does the actually preprocessing of the input file.
*
* @returns Exit code.
* @param pThis The C preprocessor instance.
*/
{
/*
* Parse.
*/
while (pThis->pInputStack)
{
pThis->fMaybePreprocessorLine = true;
unsigned ch;
{
if (ch == '/')
{
if (ch == '*')
else if (ch == '/')
else
{
pThis->fMaybePreprocessorLine = false;
}
}
{
}
{
pThis->fMaybePreprocessorLine = true;
}
else if (RT_C_IS_SPACE(ch))
{
}
else
{
pThis->fMaybePreprocessorLine = false;
{
if (ch == '"')
else if (ch == '\'')
else if (vbcppIsCIdentifierLeadChar(ch))
else
}
}
if (rcExit != RTEXITCODE_SUCCESS)
break;
}
/*
* Check for errors.
*/
if (rcExit != RTEXITCODE_SUCCESS)
break;
/*
* Pop the input stack.
*/
}
return rcExit;
}
/**
* Terminates the preprocessor.
*
* This may return failure if an error was delayed.
*
* @returns Exit code.
* @param pThis The C preprocessor instance.
*/
{
/*
* Flush the output first.
*/
if (pThis->fStrmOutputValid)
{
{
if (RT_FAILURE(rc))
}
else
{
if (RT_FAILURE(rc))
}
}
/*
* Cleanup.
*/
while (pThis->pInputStack)
{
}
while (i-- > 0)
}
{
if (RT_FAILURE(rc))
return RTMsgInitFailure(rc);
/*
* Do the job. The code says it all.
*/
bool fExit;
{
if (rcExit == RTEXITCODE_SUCCESS)
}
if (rcExit == RTEXITCODE_SUCCESS)
else
return rcExit;
}