[41177] | 1 | /* $Id: VBoxCPP.cpp 103384 2024-02-15 12:10:06Z vboxsync $ */
|
---|
| 2 | /** @file
|
---|
[41186] | 3 | * VBox Build Tool - A mini C Preprocessor.
|
---|
| 4 | *
|
---|
[41194] | 5 | * Purposes to which this preprocessor will be put:
|
---|
[41186] | 6 | * - Preprocessig vm.h into dtrace/lib/vm.d so we can access the VM
|
---|
| 7 | * structure (as well as substructures) from DTrace without having
|
---|
| 8 | * to handcraft it all.
|
---|
| 9 | * - Removing \#ifdefs relating to a new feature that has become
|
---|
| 10 | * stable and no longer needs \#ifdef'ing.
|
---|
| 11 | * - Pretty printing preprocessor directives. This will be used by
|
---|
| 12 | * SCM.
|
---|
[41177] | 13 | */
|
---|
| 14 |
|
---|
| 15 | /*
|
---|
[98103] | 16 | * Copyright (C) 2012-2023 Oracle and/or its affiliates.
|
---|
[41177] | 17 | *
|
---|
[96407] | 18 | * This file is part of VirtualBox base platform packages, as
|
---|
| 19 | * available from https://www.virtualbox.org.
|
---|
| 20 | *
|
---|
| 21 | * This program is free software; you can redistribute it and/or
|
---|
| 22 | * modify it under the terms of the GNU General Public License
|
---|
| 23 | * as published by the Free Software Foundation, in version 3 of the
|
---|
| 24 | * License.
|
---|
| 25 | *
|
---|
| 26 | * This program is distributed in the hope that it will be useful, but
|
---|
| 27 | * WITHOUT ANY WARRANTY; without even the implied warranty of
|
---|
| 28 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
---|
| 29 | * General Public License for more details.
|
---|
| 30 | *
|
---|
| 31 | * You should have received a copy of the GNU General Public License
|
---|
| 32 | * along with this program; if not, see <https://www.gnu.org/licenses>.
|
---|
| 33 | *
|
---|
| 34 | * SPDX-License-Identifier: GPL-3.0-only
|
---|
[41177] | 35 | */
|
---|
| 36 |
|
---|
| 37 |
|
---|
[57353] | 38 | /*********************************************************************************************************************************
|
---|
| 39 | * Header Files *
|
---|
| 40 | *********************************************************************************************************************************/
|
---|
[41177] | 41 | #include <VBox/VBoxTpG.h>
|
---|
| 42 |
|
---|
| 43 | #include <iprt/alloca.h>
|
---|
| 44 | #include <iprt/assert.h>
|
---|
[41179] | 45 | #include <iprt/asm.h>
|
---|
[41177] | 46 | #include <iprt/ctype.h>
|
---|
| 47 | #include <iprt/err.h>
|
---|
| 48 | #include <iprt/file.h>
|
---|
| 49 | #include <iprt/getopt.h>
|
---|
| 50 | #include <iprt/initterm.h>
|
---|
| 51 | #include <iprt/list.h>
|
---|
| 52 | #include <iprt/mem.h>
|
---|
| 53 | #include <iprt/message.h>
|
---|
| 54 | #include <iprt/path.h>
|
---|
| 55 | #include <iprt/stream.h>
|
---|
| 56 | #include <iprt/string.h>
|
---|
| 57 |
|
---|
| 58 | #include "scmstream.h"
|
---|
| 59 |
|
---|
| 60 |
|
---|
[57353] | 61 | /*********************************************************************************************************************************
|
---|
| 62 | * Defined Constants And Macros *
|
---|
| 63 | *********************************************************************************************************************************/
|
---|
[41179] | 64 | /** The bitmap type. */
|
---|
| 65 | #define VBCPP_BITMAP_TYPE uint64_t
|
---|
| 66 | /** The bitmap size as a multiple of VBCPP_BITMAP_TYPE. */
|
---|
| 67 | #define VBCPP_BITMAP_SIZE (128 / 64)
|
---|
| 68 | /** Checks if a bit is set. */
|
---|
| 69 | #define VBCPP_BITMAP_IS_SET(a_bm, a_ch) ASMBitTest(a_bm, (a_ch) & 0x7f)
|
---|
| 70 | /** Sets a bit. */
|
---|
| 71 | #define VBCPP_BITMAP_SET(a_bm, a_ch) ASMBitSet(a_bm, (a_ch) & 0x7f)
|
---|
| 72 | /** Empties the bitmap. */
|
---|
| 73 | #define VBCPP_BITMAP_EMPTY(a_bm) do { (a_bm)[0] = 0; (a_bm)[1] = 0; } while (0)
|
---|
| 74 | /** Joins to bitmaps by OR'ing their values.. */
|
---|
| 75 | #define VBCPP_BITMAP_OR(a_bm1, a_bm2) do { (a_bm1)[0] |= (a_bm2)[0]; (a_bm1)[1] |= (a_bm2)[1]; } while (0)
|
---|
[41177] | 76 |
|
---|
[41179] | 77 |
|
---|
[57353] | 78 | /*********************************************************************************************************************************
|
---|
| 79 | * Structures and Typedefs *
|
---|
| 80 | *********************************************************************************************************************************/
|
---|
[41266] | 81 | /** Pointer to the C preprocessor instance data. */
|
---|
| 82 | typedef struct VBCPP *PVBCPP;
|
---|
| 83 |
|
---|
| 84 |
|
---|
[41177] | 85 | /**
|
---|
[41246] | 86 | * Variable string buffer (very simple version of SCMSTREAM).
|
---|
| 87 | */
|
---|
| 88 | typedef struct VBCPPSTRBUF
|
---|
| 89 | {
|
---|
| 90 | /** The preprocessor instance (for error reporting). */
|
---|
| 91 | struct VBCPP *pThis;
|
---|
| 92 | /** The length of the string in the buffer. */
|
---|
| 93 | size_t cchBuf;
|
---|
| 94 | /** The string storage. */
|
---|
| 95 | char *pszBuf;
|
---|
| 96 | /** Allocated buffer space. */
|
---|
| 97 | size_t cbBufAllocated;
|
---|
| 98 | } VBCPPSTRBUF;
|
---|
| 99 | /** Pointer to a variable string buffer. */
|
---|
| 100 | typedef VBCPPSTRBUF *PVBCPPSTRBUF;
|
---|
| 101 |
|
---|
| 102 |
|
---|
| 103 | /**
|
---|
[41177] | 104 | * The preprocessor mode.
|
---|
| 105 | */
|
---|
| 106 | typedef enum VBCPPMODE
|
---|
| 107 | {
|
---|
| 108 | kVBCppMode_Invalid = 0,
|
---|
[41202] | 109 | kVBCppMode_Standard,
|
---|
[41177] | 110 | kVBCppMode_Selective,
|
---|
| 111 | kVBCppMode_SelectiveD,
|
---|
| 112 | kVBCppMode_End
|
---|
| 113 | } VBCPPMODE;
|
---|
| 114 |
|
---|
| 115 |
|
---|
[41186] | 116 | /**
|
---|
[41297] | 117 | * A macro (aka define).
|
---|
[41177] | 118 | */
|
---|
[41297] | 119 | typedef struct VBCPPMACRO
|
---|
[41177] | 120 | {
|
---|
| 121 | /** The string space core. */
|
---|
| 122 | RTSTRSPACECORE Core;
|
---|
[41301] | 123 | #if 0
|
---|
[41246] | 124 | /** For linking macros that have the fExpanding flag set. */
|
---|
[41297] | 125 | struct VBCPPMACRO *pUpExpanding;
|
---|
[41301] | 126 | #endif
|
---|
[41177] | 127 | /** Whether it's a function. */
|
---|
| 128 | bool fFunction;
|
---|
| 129 | /** Variable argument count. */
|
---|
| 130 | bool fVarArg;
|
---|
[41195] | 131 | /** Set if originating on the command line. */
|
---|
| 132 | bool fCmdLine;
|
---|
[41246] | 133 | /** Set if this macro is currently being expanded and should not be
|
---|
| 134 | * recursively applied. */
|
---|
| 135 | bool fExpanding;
|
---|
| 136 | /** The number of known arguments. */
|
---|
[41177] | 137 | uint32_t cArgs;
|
---|
[41179] | 138 | /** Pointer to a list of argument names. */
|
---|
| 139 | const char **papszArgs;
|
---|
| 140 | /** Lead character bitmap for the argument names. */
|
---|
| 141 | VBCPP_BITMAP_TYPE bmArgs[VBCPP_BITMAP_SIZE];
|
---|
[41209] | 142 | /** The value length. */
|
---|
| 143 | size_t cchValue;
|
---|
[41179] | 144 | /** The define value. (This is followed by the name and arguments.) */
|
---|
[41177] | 145 | char szValue[1];
|
---|
[41297] | 146 | } VBCPPMACRO;
|
---|
| 147 | /** Pointer to a macro. */
|
---|
| 148 | typedef VBCPPMACRO *PVBCPPMACRO;
|
---|
[41177] | 149 |
|
---|
| 150 |
|
---|
| 151 | /**
|
---|
[41246] | 152 | * Macro expansion data.
|
---|
| 153 | */
|
---|
| 154 | typedef struct VBCPPMACROEXP
|
---|
| 155 | {
|
---|
| 156 | /** The expansion buffer. */
|
---|
[41263] | 157 | VBCPPSTRBUF StrBuf;
|
---|
[41301] | 158 | #if 0
|
---|
[41246] | 159 | /** List of expanding macros (Stack). */
|
---|
[41297] | 160 | PVBCPPMACRO pMacroStack;
|
---|
[41301] | 161 | #endif
|
---|
[41246] | 162 | /** The input stream (in case we want to look for parameter lists). */
|
---|
| 163 | PSCMSTREAM pStrmInput;
|
---|
| 164 | /** Array of argument values. Used when expanding function style macros. */
|
---|
| 165 | char **papszArgs;
|
---|
| 166 | /** The number of argument values current in papszArgs. */
|
---|
[42548] | 167 | uint32_t cArgs;
|
---|
[41246] | 168 | /** The number of argument values papszArgs can currently hold */
|
---|
[42548] | 169 | uint32_t cArgsAlloced;
|
---|
[41246] | 170 | } VBCPPMACROEXP;
|
---|
| 171 | /** Pointer to macro expansion data. */
|
---|
| 172 | typedef VBCPPMACROEXP *PVBCPPMACROEXP;
|
---|
| 173 |
|
---|
| 174 |
|
---|
| 175 | /**
|
---|
[41263] | 176 | * The vbcppMacroExpandReScan mode of operation.
|
---|
| 177 | */
|
---|
| 178 | typedef enum VBCPPMACRORESCANMODE
|
---|
| 179 | {
|
---|
| 180 | /** Invalid mode. */
|
---|
| 181 | kMacroReScanMode_Invalid = 0,
|
---|
| 182 | /** Normal expansion mode. */
|
---|
| 183 | kMacroReScanMode_Normal,
|
---|
| 184 | /** Replaces known macros and heeds the 'defined' operator. */
|
---|
| 185 | kMacroReScanMode_Expression,
|
---|
| 186 | /** End of valid modes. */
|
---|
| 187 | kMacroReScanMode_End
|
---|
| 188 | } VBCPPMACRORESCANMODE;
|
---|
| 189 |
|
---|
| 190 |
|
---|
| 191 | /**
|
---|
[41266] | 192 | * Expression node type.
|
---|
| 193 | */
|
---|
| 194 | typedef enum VBCPPEXPRKIND
|
---|
| 195 | {
|
---|
| 196 | kVBCppExprKind_Invalid = 0,
|
---|
| 197 | kVBCppExprKind_Unary,
|
---|
| 198 | kVBCppExprKind_Binary,
|
---|
| 199 | kVBCppExprKind_Ternary,
|
---|
| 200 | kVBCppExprKind_SignedValue,
|
---|
| 201 | kVBCppExprKind_UnsignedValue,
|
---|
[100618] | 202 | kVBCppExprKind_UndefMacroCall,
|
---|
[41266] | 203 | kVBCppExprKind_End
|
---|
| 204 | } VBCPPEXPRKIND;
|
---|
| 205 |
|
---|
| 206 |
|
---|
| 207 | /** Macro used for the precedence field. */
|
---|
| 208 | #define VBCPPOP_PRECEDENCE(a_iPrecedence) ((a_iPrecedence) << 8)
|
---|
| 209 | /** Mask for getting the precedence field value. */
|
---|
| 210 | #define VBCPPOP_PRECEDENCE_MASK 0xff00
|
---|
| 211 | /** Operator associativity - Left to right. */
|
---|
| 212 | #define VBCPPOP_L2R (1 << 16)
|
---|
| 213 | /** Operator associativity - Right to left. */
|
---|
| 214 | #define VBCPPOP_R2L (2 << 16)
|
---|
| 215 |
|
---|
| 216 | /**
|
---|
| 217 | * Unary operators.
|
---|
| 218 | */
|
---|
| 219 | typedef enum VBCPPUNARYOP
|
---|
| 220 | {
|
---|
| 221 | kVBCppUnaryOp_Invalid = 0,
|
---|
| 222 | kVBCppUnaryOp_Pluss = VBCPPOP_R2L | VBCPPOP_PRECEDENCE( 3) | 5,
|
---|
| 223 | kVBCppUnaryOp_Minus = VBCPPOP_R2L | VBCPPOP_PRECEDENCE( 3) | 6,
|
---|
| 224 | kVBCppUnaryOp_LogicalNot = VBCPPOP_R2L | VBCPPOP_PRECEDENCE( 3) | 7,
|
---|
| 225 | kVBCppUnaryOp_BitwiseNot = VBCPPOP_R2L | VBCPPOP_PRECEDENCE( 3) | 8,
|
---|
| 226 | kVBCppUnaryOp_Parenthesis = VBCPPOP_R2L | VBCPPOP_PRECEDENCE(15) | 9,
|
---|
| 227 | kVBCppUnaryOp_End
|
---|
| 228 | } VBCPPUNARYOP;
|
---|
| 229 |
|
---|
| 230 | /**
|
---|
| 231 | * Binary operators.
|
---|
| 232 | */
|
---|
| 233 | typedef enum VBCPPBINARYOP
|
---|
| 234 | {
|
---|
| 235 | kVBCppBinary_Invalid = 0,
|
---|
| 236 | kVBCppBinary_Multiplication = VBCPPOP_L2R | VBCPPOP_PRECEDENCE( 5) | 2,
|
---|
| 237 | kVBCppBinary_Division = VBCPPOP_L2R | VBCPPOP_PRECEDENCE( 5) | 4,
|
---|
| 238 | kVBCppBinary_Modulo = VBCPPOP_L2R | VBCPPOP_PRECEDENCE( 5) | 5,
|
---|
| 239 | kVBCppBinary_Addition = VBCPPOP_L2R | VBCPPOP_PRECEDENCE( 6) | 6,
|
---|
| 240 | kVBCppBinary_Subtraction = VBCPPOP_L2R | VBCPPOP_PRECEDENCE( 6) | 7,
|
---|
| 241 | kVBCppBinary_LeftShift = VBCPPOP_L2R | VBCPPOP_PRECEDENCE( 7) | 8,
|
---|
| 242 | kVBCppBinary_RightShift = VBCPPOP_L2R | VBCPPOP_PRECEDENCE( 7) | 9,
|
---|
| 243 | kVBCppBinary_LessThan = VBCPPOP_L2R | VBCPPOP_PRECEDENCE( 8) | 10,
|
---|
| 244 | kVBCppBinary_LessThanOrEqual = VBCPPOP_L2R | VBCPPOP_PRECEDENCE( 8) | 11,
|
---|
| 245 | kVBCppBinary_GreaterThan = VBCPPOP_L2R | VBCPPOP_PRECEDENCE( 8) | 12,
|
---|
| 246 | kVBCppBinary_GreaterThanOrEqual = VBCPPOP_L2R | VBCPPOP_PRECEDENCE( 8) | 13,
|
---|
| 247 | kVBCppBinary_EqualTo = VBCPPOP_L2R | VBCPPOP_PRECEDENCE( 9) | 14,
|
---|
| 248 | kVBCppBinary_NotEqualTo = VBCPPOP_L2R | VBCPPOP_PRECEDENCE( 9) | 15,
|
---|
| 249 | kVBCppBinary_BitwiseAnd = VBCPPOP_L2R | VBCPPOP_PRECEDENCE(10) | 16,
|
---|
| 250 | kVBCppBinary_BitwiseXor = VBCPPOP_L2R | VBCPPOP_PRECEDENCE(11) | 17,
|
---|
| 251 | kVBCppBinary_BitwiseOr = VBCPPOP_L2R | VBCPPOP_PRECEDENCE(12) | 18,
|
---|
| 252 | kVBCppBinary_LogicalAnd = VBCPPOP_L2R | VBCPPOP_PRECEDENCE(13) | 19,
|
---|
| 253 | kVBCppBinary_LogicalOr = VBCPPOP_L2R | VBCPPOP_PRECEDENCE(14) | 20,
|
---|
| 254 | kVBCppBinary_End
|
---|
| 255 | } VBCPPBINARYOP;
|
---|
| 256 |
|
---|
| 257 | /** The precedence of the ternary operator (expr ? true : false). */
|
---|
| 258 | #define VBCPPTERNAROP_PRECEDENCE VBCPPOP_PRECEDENCE(16)
|
---|
| 259 |
|
---|
| 260 |
|
---|
| 261 | /** Pointer to an expression parsing node. */
|
---|
| 262 | typedef struct VBCPPEXPR *PVBCPPEXPR;
|
---|
| 263 | /**
|
---|
| 264 | * Expression parsing node.
|
---|
| 265 | */
|
---|
| 266 | typedef struct VBCPPEXPR
|
---|
| 267 | {
|
---|
| 268 | /** Parent expression. */
|
---|
| 269 | PVBCPPEXPR pParent;
|
---|
| 270 | /** Whether the expression is complete or not. */
|
---|
| 271 | bool fComplete;
|
---|
| 272 | /** The kind of expression. */
|
---|
| 273 | VBCPPEXPRKIND enmKind;
|
---|
| 274 | /** Kind specific content. */
|
---|
| 275 | union
|
---|
| 276 | {
|
---|
| 277 | /** kVBCppExprKind_Unary */
|
---|
| 278 | struct
|
---|
| 279 | {
|
---|
| 280 | VBCPPUNARYOP enmOperator;
|
---|
| 281 | PVBCPPEXPR pArg;
|
---|
| 282 | } Unary;
|
---|
| 283 |
|
---|
| 284 | /** kVBCppExprKind_Binary */
|
---|
| 285 | struct
|
---|
| 286 | {
|
---|
| 287 | VBCPPBINARYOP enmOperator;
|
---|
| 288 | PVBCPPEXPR pLeft;
|
---|
| 289 | PVBCPPEXPR pRight;
|
---|
| 290 | } Binary;
|
---|
| 291 |
|
---|
| 292 | /** kVBCppExprKind_Ternary */
|
---|
| 293 | struct
|
---|
| 294 | {
|
---|
| 295 | PVBCPPEXPR pExpr;
|
---|
| 296 | PVBCPPEXPR pTrue;
|
---|
| 297 | PVBCPPEXPR pFalse;
|
---|
| 298 | } Ternary;
|
---|
| 299 |
|
---|
| 300 | /** kVBCppExprKind_SignedValue */
|
---|
| 301 | struct
|
---|
| 302 | {
|
---|
| 303 | int64_t s64;
|
---|
| 304 | } SignedValue;
|
---|
| 305 |
|
---|
| 306 | /** kVBCppExprKind_UnsignedValue */
|
---|
| 307 | struct
|
---|
| 308 | {
|
---|
| 309 | uint64_t u64;
|
---|
| 310 | } UnsignedValue;
|
---|
[100618] | 311 |
|
---|
| 312 | /** kVBCppExprKind_UndefMacroCall */
|
---|
| 313 | struct
|
---|
| 314 | {
|
---|
| 315 | char *pszName;
|
---|
| 316 | size_t cArgs;
|
---|
| 317 | PVBCPPEXPR *papArgs;
|
---|
| 318 | } UndefMacroCall;
|
---|
[41266] | 319 | } u;
|
---|
| 320 | } VBCPPEXPR;
|
---|
| 321 |
|
---|
| 322 |
|
---|
| 323 | /**
|
---|
| 324 | * Operator return statuses.
|
---|
| 325 | */
|
---|
| 326 | typedef enum VBCPPEXPRRET
|
---|
| 327 | {
|
---|
| 328 | kExprRet_Error = -1,
|
---|
| 329 | kExprRet_Ok = 0,
|
---|
| 330 | kExprRet_UnaryOperator,
|
---|
| 331 | kExprRet_Value,
|
---|
| 332 | kExprRet_EndOfExpr,
|
---|
| 333 | kExprRet_End
|
---|
| 334 | } VBCPPEXPRRET;
|
---|
| 335 |
|
---|
| 336 | /**
|
---|
| 337 | * Expression parser context.
|
---|
| 338 | */
|
---|
| 339 | typedef struct VBCPPEXPRPARSER
|
---|
| 340 | {
|
---|
| 341 | /** The current expression posistion. */
|
---|
| 342 | const char *pszCur;
|
---|
| 343 | /** The root node. */
|
---|
| 344 | PVBCPPEXPR pRoot;
|
---|
| 345 | /** The current expression node. */
|
---|
| 346 | PVBCPPEXPR pCur;
|
---|
| 347 | /** Where to insert the next expression. */
|
---|
| 348 | PVBCPPEXPR *ppCur;
|
---|
| 349 | /** The expression. */
|
---|
| 350 | const char *pszExpr;
|
---|
| 351 | /** The number of undefined macros we've encountered while parsing. */
|
---|
| 352 | size_t cUndefined;
|
---|
| 353 | /** Pointer to the C preprocessor instance. */
|
---|
| 354 | PVBCPP pThis;
|
---|
| 355 | } VBCPPEXPRPARSER;
|
---|
| 356 | /** Pointer to an expression parser context. */
|
---|
| 357 | typedef VBCPPEXPRPARSER *PVBCPPEXPRPARSER;
|
---|
| 358 |
|
---|
| 359 |
|
---|
| 360 | /**
|
---|
[41186] | 361 | * Evaluation result.
|
---|
| 362 | */
|
---|
| 363 | typedef enum VBCPPEVAL
|
---|
| 364 | {
|
---|
| 365 | kVBCppEval_Invalid = 0,
|
---|
| 366 | kVBCppEval_True,
|
---|
| 367 | kVBCppEval_False,
|
---|
| 368 | kVBCppEval_Undecided,
|
---|
| 369 | kVBCppEval_End
|
---|
| 370 | } VBCPPEVAL;
|
---|
[41179] | 371 |
|
---|
[41186] | 372 |
|
---|
[41179] | 373 | /**
|
---|
[41186] | 374 | * The condition kind.
|
---|
| 375 | */
|
---|
| 376 | typedef enum VBCPPCONDKIND
|
---|
| 377 | {
|
---|
| 378 | kVBCppCondKind_Invalid = 0,
|
---|
| 379 | /** \#if expr */
|
---|
| 380 | kVBCppCondKind_If,
|
---|
| 381 | /** \#ifdef define */
|
---|
| 382 | kVBCppCondKind_IfDef,
|
---|
| 383 | /** \#ifndef define */
|
---|
| 384 | kVBCppCondKind_IfNDef,
|
---|
| 385 | /** \#elif expr */
|
---|
| 386 | kVBCppCondKind_ElIf,
|
---|
| 387 | /** The end of valid values. */
|
---|
| 388 | kVBCppCondKind_End
|
---|
| 389 | } VBCPPCONDKIND;
|
---|
| 390 |
|
---|
| 391 |
|
---|
| 392 | /**
|
---|
| 393 | * Conditional stack entry.
|
---|
| 394 | */
|
---|
| 395 | typedef struct VBCPPCOND
|
---|
| 396 | {
|
---|
| 397 | /** The next conditional on the stack. */
|
---|
| 398 | struct VBCPPCOND *pUp;
|
---|
| 399 | /** The kind of conditional. This changes on encountering \#elif. */
|
---|
| 400 | VBCPPCONDKIND enmKind;
|
---|
| 401 | /** Evaluation result. */
|
---|
| 402 | VBCPPEVAL enmResult;
|
---|
| 403 | /** The evaluation result of the whole stack. */
|
---|
| 404 | VBCPPEVAL enmStackResult;
|
---|
| 405 |
|
---|
| 406 | /** Whether we've seen the last else. */
|
---|
| 407 | bool fSeenElse;
|
---|
[41263] | 408 | /** Set if we have an else if which has already been decided. */
|
---|
| 409 | bool fElIfDecided;
|
---|
[41186] | 410 | /** The nesting level of this condition. */
|
---|
| 411 | uint16_t iLevel;
|
---|
| 412 | /** The nesting level of this condition wrt the ones we keep. */
|
---|
| 413 | uint16_t iKeepLevel;
|
---|
| 414 |
|
---|
| 415 | /** The condition string. (Points within the stream buffer.) */
|
---|
| 416 | const char *pchCond;
|
---|
| 417 | /** The condition length. */
|
---|
| 418 | size_t cchCond;
|
---|
| 419 | } VBCPPCOND;
|
---|
| 420 | /** Pointer to a conditional stack entry. */
|
---|
| 421 | typedef VBCPPCOND *PVBCPPCOND;
|
---|
| 422 |
|
---|
| 423 |
|
---|
| 424 | /**
|
---|
| 425 | * Input buffer stack entry.
|
---|
| 426 | */
|
---|
| 427 | typedef struct VBCPPINPUT
|
---|
| 428 | {
|
---|
| 429 | /** Pointer to the next input on the stack. */
|
---|
| 430 | struct VBCPPINPUT *pUp;
|
---|
| 431 | /** The input stream. */
|
---|
| 432 | SCMSTREAM StrmInput;
|
---|
| 433 | /** Pointer into szName to the part which was specified. */
|
---|
| 434 | const char *pszSpecified;
|
---|
| 435 | /** The input file name with include path. */
|
---|
| 436 | char szName[1];
|
---|
| 437 | } VBCPPINPUT;
|
---|
| 438 | /** Pointer to a input buffer stack entry */
|
---|
| 439 | typedef VBCPPINPUT *PVBCPPINPUT;
|
---|
| 440 |
|
---|
| 441 |
|
---|
| 442 | /**
|
---|
[41202] | 443 | * The action to take with \#include.
|
---|
| 444 | */
|
---|
| 445 | typedef enum VBCPPINCLUDEACTION
|
---|
| 446 | {
|
---|
| 447 | kVBCppIncludeAction_Invalid = 0,
|
---|
| 448 | kVBCppIncludeAction_Include,
|
---|
| 449 | kVBCppIncludeAction_PassThru,
|
---|
| 450 | kVBCppIncludeAction_Drop,
|
---|
| 451 | kVBCppIncludeAction_End
|
---|
| 452 | } VBCPPINCLUDEACTION;
|
---|
| 453 |
|
---|
| 454 |
|
---|
| 455 | /**
|
---|
[41177] | 456 | * C Preprocessor instance data.
|
---|
| 457 | */
|
---|
| 458 | typedef struct VBCPP
|
---|
| 459 | {
|
---|
| 460 | /** @name Options
|
---|
[41186] | 461 | * @{ */
|
---|
[41177] | 462 | /** The preprocessing mode. */
|
---|
[41179] | 463 | VBCPPMODE enmMode;
|
---|
[41177] | 464 | /** Whether to keep comments. */
|
---|
[41179] | 465 | bool fKeepComments;
|
---|
[41202] | 466 | /** Whether to respect source defines. */
|
---|
| 467 | bool fRespectSourceDefines;
|
---|
| 468 | /** Whether to let source defines overrides the ones on the command
|
---|
| 469 | * line. */
|
---|
| 470 | bool fAllowRedefiningCmdLineDefines;
|
---|
| 471 | /** Whether to pass thru defines. */
|
---|
| 472 | bool fPassThruDefines;
|
---|
| 473 | /** Whether to allow undecided conditionals. */
|
---|
| 474 | bool fUndecidedConditionals;
|
---|
[41217] | 475 | /** Whether to pass thru D pragmas. */
|
---|
| 476 | bool fPassThruPragmaD;
|
---|
| 477 | /** Whether to pass thru STD pragmas. */
|
---|
| 478 | bool fPassThruPragmaSTD;
|
---|
| 479 | /** Whether to pass thru other pragmas. */
|
---|
| 480 | bool fPassThruPragmaOther;
|
---|
[100618] | 481 | /** Whether to pass thru \#error directives or execute them. */
|
---|
| 482 | bool fPassThruError;
|
---|
[41217] | 483 | /** Whether to remove dropped lines from the output. */
|
---|
| 484 | bool fRemoveDroppedLines;
|
---|
[41202] | 485 | /** Whether to preforme line splicing.
|
---|
| 486 | * @todo implement line splicing */
|
---|
| 487 | bool fLineSplicing;
|
---|
| 488 | /** What to do about include files. */
|
---|
| 489 | VBCPPINCLUDEACTION enmIncludeAction;
|
---|
[41177] | 490 |
|
---|
| 491 | /** The number of include directories. */
|
---|
[41179] | 492 | uint32_t cIncludes;
|
---|
[41177] | 493 | /** Array of directories to search for include files. */
|
---|
[41179] | 494 | char **papszIncludes;
|
---|
[41177] | 495 |
|
---|
| 496 | /** The name of the input file. */
|
---|
[41179] | 497 | const char *pszInput;
|
---|
[41177] | 498 | /** The name of the output file. NULL if stdout. */
|
---|
[41179] | 499 | const char *pszOutput;
|
---|
[41177] | 500 | /** @} */
|
---|
[41186] | 501 |
|
---|
[41177] | 502 | /** The define string space. */
|
---|
[41179] | 503 | RTSTRSPACE StrSpace;
|
---|
[41186] | 504 | /** The string space holding explicitly undefined macros for selective
|
---|
| 505 | * preprocessing runs. */
|
---|
| 506 | RTSTRSPACE UndefStrSpace;
|
---|
[41177] | 507 | /** Indicates whether a C-word might need expansion.
|
---|
[41186] | 508 | * The bitmap is indexed by C-word lead character. Bits that are set
|
---|
| 509 | * indicates that the lead character is used in a \#define that we know and
|
---|
| 510 | * should expand. */
|
---|
[41179] | 511 | VBCPP_BITMAP_TYPE bmDefined[VBCPP_BITMAP_SIZE];
|
---|
| 512 |
|
---|
[41186] | 513 | /** The current depth of the conditional stack. */
|
---|
| 514 | uint32_t cCondStackDepth;
|
---|
| 515 | /** Conditional stack. */
|
---|
| 516 | PVBCPPCOND pCondStack;
|
---|
| 517 | /** The current condition evaluates to kVBCppEval_False, don't output. */
|
---|
| 518 | bool fIf0Mode;
|
---|
[41217] | 519 | /** Just dropped a line and should maybe drop the current line. */
|
---|
| 520 | bool fJustDroppedLine;
|
---|
[41186] | 521 |
|
---|
[41179] | 522 | /** Whether the current line could be a preprocessor line.
|
---|
[41186] | 523 | * This is set when EOL is encountered and cleared again when a
|
---|
| 524 | * non-comment-or-space character is encountered. See vbcppPreprocess. */
|
---|
[41179] | 525 | bool fMaybePreprocessorLine;
|
---|
| 526 |
|
---|
[41186] | 527 | /** The input stack depth */
|
---|
| 528 | uint32_t cInputStackDepth;
|
---|
| 529 | /** The input buffer stack. */
|
---|
| 530 | PVBCPPINPUT pInputStack;
|
---|
| 531 |
|
---|
[41179] | 532 | /** The output stream. */
|
---|
| 533 | SCMSTREAM StrmOutput;
|
---|
| 534 |
|
---|
| 535 | /** The status of the whole job, as far as we know. */
|
---|
| 536 | RTEXITCODE rcExit;
|
---|
| 537 | /** Whether StrmOutput is valid (for vbcppTerm). */
|
---|
| 538 | bool fStrmOutputValid;
|
---|
[41177] | 539 | } VBCPP;
|
---|
| 540 |
|
---|
| 541 |
|
---|
[57353] | 542 | /*********************************************************************************************************************************
|
---|
| 543 | * Internal Functions *
|
---|
| 544 | *********************************************************************************************************************************/
|
---|
[100618] | 545 | static VBCPPEXPRRET vbcppExprParseUnaryOrValue(PVBCPPEXPRPARSER pParser);
|
---|
[41297] | 546 | static PVBCPPMACRO vbcppMacroLookup(PVBCPP pThis, const char *pszDefine, size_t cchDefine);
|
---|
[41303] | 547 | static RTEXITCODE vbcppMacroExpandIt(PVBCPP pThis, PVBCPPMACROEXP pExp, size_t offMacro, PVBCPPMACRO pMacro, size_t offParameters);
|
---|
[100618] | 548 | static RTEXITCODE vbcppMacroExpandReScan(PVBCPP pThis, PVBCPPMACROEXP pExp, VBCPPMACRORESCANMODE enmMode,
|
---|
| 549 | size_t *pcReplacements, size_t *pcDefinedUnknown);
|
---|
[41246] | 550 | static void vbcppMacroExpandCleanup(PVBCPPMACROEXP pExp);
|
---|
[41177] | 551 |
|
---|
| 552 |
|
---|
| 553 |
|
---|
[41204] | 554 | /*
|
---|
[41202] | 555 | *
|
---|
[41204] | 556 | *
|
---|
| 557 | * Message Handling.
|
---|
| 558 | * Message Handling.
|
---|
| 559 | * Message Handling.
|
---|
| 560 | * Message Handling.
|
---|
| 561 | * Message Handling.
|
---|
| 562 | *
|
---|
| 563 | *
|
---|
[41202] | 564 | */
|
---|
[41177] | 565 |
|
---|
[41179] | 566 |
|
---|
| 567 | /**
|
---|
[41186] | 568 | * Displays an error message.
|
---|
| 569 | *
|
---|
[41179] | 570 | * @returns RTEXITCODE_FAILURE
|
---|
| 571 | * @param pThis The C preprocessor instance.
|
---|
| 572 | * @param pszMsg The message.
|
---|
[41263] | 573 | * @param va Message arguments.
|
---|
[41179] | 574 | */
|
---|
[41263] | 575 | static RTEXITCODE vbcppErrorV(PVBCPP pThis, const char *pszMsg, va_list va)
|
---|
[41179] | 576 | {
|
---|
| 577 | NOREF(pThis);
|
---|
[41186] | 578 | if (pThis->pInputStack)
|
---|
| 579 | {
|
---|
| 580 | PSCMSTREAM pStrm = &pThis->pInputStack->StrmInput;
|
---|
| 581 |
|
---|
| 582 | size_t const off = ScmStreamTell(pStrm);
|
---|
| 583 | size_t const iLine = ScmStreamTellLine(pStrm);
|
---|
| 584 | ScmStreamSeekByLine(pStrm, iLine);
|
---|
| 585 | size_t const offLine = ScmStreamTell(pStrm);
|
---|
| 586 |
|
---|
| 587 | RTPrintf("%s:%d:%zd: error: %N.\n", pThis->pInputStack->szName, iLine + 1, off - offLine + 1, pszMsg, va);
|
---|
| 588 |
|
---|
| 589 | size_t cchLine;
|
---|
| 590 | SCMEOL enmEof;
|
---|
| 591 | const char *pszLine = ScmStreamGetLineByNo(pStrm, iLine, &cchLine, &enmEof);
|
---|
| 592 | if (pszLine)
|
---|
| 593 | RTPrintf(" %.*s\n"
|
---|
| 594 | " %*s^\n",
|
---|
| 595 | cchLine, pszLine, off - offLine, "");
|
---|
| 596 |
|
---|
| 597 | ScmStreamSeekAbsolute(pStrm, off);
|
---|
| 598 | }
|
---|
| 599 | else
|
---|
| 600 | RTMsgErrorV(pszMsg, va);
|
---|
[41179] | 601 | return pThis->rcExit = RTEXITCODE_FAILURE;
|
---|
[41177] | 602 | }
|
---|
| 603 |
|
---|
| 604 |
|
---|
| 605 | /**
|
---|
[41186] | 606 | * Displays an error message.
|
---|
| 607 | *
|
---|
[41179] | 608 | * @returns RTEXITCODE_FAILURE
|
---|
[41186] | 609 | * @param pThis The C preprocessor instance.
|
---|
[41263] | 610 | * @param pszMsg The message.
|
---|
| 611 | * @param ... Message arguments.
|
---|
| 612 | */
|
---|
| 613 | static RTEXITCODE vbcppError(PVBCPP pThis, const char *pszMsg, ...)
|
---|
| 614 | {
|
---|
| 615 | va_list va;
|
---|
| 616 | va_start(va, pszMsg);
|
---|
| 617 | RTEXITCODE rcExit = vbcppErrorV(pThis, pszMsg, va);
|
---|
| 618 | va_end(va);
|
---|
| 619 | return rcExit;
|
---|
| 620 | }
|
---|
| 621 |
|
---|
| 622 |
|
---|
| 623 | /**
|
---|
| 624 | * Displays an error message.
|
---|
| 625 | *
|
---|
| 626 | * @returns RTEXITCODE_FAILURE
|
---|
| 627 | * @param pThis The C preprocessor instance.
|
---|
[41179] | 628 | * @param pszPos Pointer to the offending character.
|
---|
| 629 | * @param pszMsg The message.
|
---|
| 630 | * @param ... Message arguments.
|
---|
| 631 | */
|
---|
| 632 | static RTEXITCODE vbcppErrorPos(PVBCPP pThis, const char *pszPos, const char *pszMsg, ...)
|
---|
| 633 | {
|
---|
| 634 | NOREF(pszPos); NOREF(pThis);
|
---|
| 635 | va_list va;
|
---|
| 636 | va_start(va, pszMsg);
|
---|
[100618] | 637 | //RTMsgErrorV(pszMsg, va);
|
---|
| 638 | RTEXITCODE rcExit = vbcppErrorV(pThis, pszMsg, va);
|
---|
[41179] | 639 | va_end(va);
|
---|
[100618] | 640 | return rcExit;
|
---|
[41179] | 641 | }
|
---|
| 642 |
|
---|
| 643 |
|
---|
[41204] | 644 |
|
---|
| 645 |
|
---|
| 646 |
|
---|
[41246] | 647 |
|
---|
| 648 |
|
---|
[41204] | 649 | /*
|
---|
| 650 | *
|
---|
| 651 | *
|
---|
[41246] | 652 | * Variable String Buffers.
|
---|
| 653 | * Variable String Buffers.
|
---|
| 654 | * Variable String Buffers.
|
---|
| 655 | * Variable String Buffers.
|
---|
| 656 | * Variable String Buffers.
|
---|
| 657 | *
|
---|
| 658 | *
|
---|
| 659 | */
|
---|
| 660 |
|
---|
| 661 |
|
---|
[41266] | 662 | /**
|
---|
| 663 | * Initializes a string buffer.
|
---|
| 664 | *
|
---|
| 665 | * @param pStrBuf The buffer structure to initialize.
|
---|
| 666 | * @param pThis The C preprocessor instance.
|
---|
| 667 | */
|
---|
[41246] | 668 | static void vbcppStrBufInit(PVBCPPSTRBUF pStrBuf, PVBCPP pThis)
|
---|
| 669 | {
|
---|
| 670 | pStrBuf->pThis = pThis;
|
---|
| 671 | pStrBuf->cchBuf = 0;
|
---|
| 672 | pStrBuf->cbBufAllocated = 0;
|
---|
| 673 | pStrBuf->pszBuf = NULL;
|
---|
| 674 | }
|
---|
| 675 |
|
---|
| 676 |
|
---|
[41266] | 677 | /**
|
---|
| 678 | * Deletes a string buffer.
|
---|
| 679 | *
|
---|
| 680 | * @param pStrBuf Pointer to the string buffer.
|
---|
| 681 | */
|
---|
[41246] | 682 | static void vbcppStrBufDelete(PVBCPPSTRBUF pStrBuf)
|
---|
| 683 | {
|
---|
| 684 | RTMemFree(pStrBuf->pszBuf);
|
---|
| 685 | pStrBuf->pszBuf = NULL;
|
---|
| 686 | }
|
---|
| 687 |
|
---|
| 688 |
|
---|
[41266] | 689 | /**
|
---|
| 690 | * Ensures that sufficient bufferspace is available, growing the buffer if
|
---|
| 691 | * necessary.
|
---|
| 692 | *
|
---|
| 693 | * @returns RTEXITCODE_SUCCESS or RTEXITCODE_FAILURE+msg.
|
---|
| 694 | * @param pStrBuf Pointer to the string buffer.
|
---|
| 695 | * @param cbMin The minimum buffer size.
|
---|
| 696 | */
|
---|
[41246] | 697 | static RTEXITCODE vbcppStrBufGrow(PVBCPPSTRBUF pStrBuf, size_t cbMin)
|
---|
| 698 | {
|
---|
| 699 | if (pStrBuf->cbBufAllocated >= cbMin)
|
---|
| 700 | return RTEXITCODE_SUCCESS;
|
---|
| 701 |
|
---|
| 702 | size_t cbNew = pStrBuf->cbBufAllocated * 2;
|
---|
| 703 | if (cbNew < cbMin)
|
---|
| 704 | cbNew = RT_ALIGN_Z(cbMin, _1K);
|
---|
| 705 | void *pv = RTMemRealloc(pStrBuf->pszBuf, cbNew);
|
---|
| 706 | if (!pv)
|
---|
| 707 | return vbcppError(pStrBuf->pThis, "out of memory (%zu bytes)", cbNew);
|
---|
| 708 |
|
---|
| 709 | pStrBuf->pszBuf = (char *)pv;
|
---|
| 710 | pStrBuf->cbBufAllocated = cbNew;
|
---|
| 711 | return RTEXITCODE_SUCCESS;
|
---|
| 712 | }
|
---|
| 713 |
|
---|
| 714 |
|
---|
[41266] | 715 | /**
|
---|
| 716 | * Appends a substring.
|
---|
| 717 | *
|
---|
| 718 | * @returns RTEXITCODE_SUCCESS or RTEXITCODE_FAILURE+msg.
|
---|
| 719 | * @param pStrBuf Pointer to the string buffer.
|
---|
| 720 | * @param pchSrc Pointer to the first character in the substring.
|
---|
| 721 | * @param cchSrc The length of the substring.
|
---|
| 722 | */
|
---|
[41246] | 723 | static RTEXITCODE vbcppStrBufAppendN(PVBCPPSTRBUF pStrBuf, const char *pchSrc, size_t cchSrc)
|
---|
| 724 | {
|
---|
| 725 | size_t cchBuf = pStrBuf->cchBuf;
|
---|
| 726 | if (cchBuf + cchSrc + 1 > pStrBuf->cbBufAllocated)
|
---|
| 727 | {
|
---|
| 728 | RTEXITCODE rcExit = vbcppStrBufGrow(pStrBuf, cchBuf + cchSrc + 1);
|
---|
| 729 | if (rcExit != RTEXITCODE_SUCCESS)
|
---|
| 730 | return rcExit;
|
---|
| 731 | }
|
---|
| 732 |
|
---|
| 733 | memcpy(&pStrBuf->pszBuf[cchBuf], pchSrc, cchSrc);
|
---|
| 734 | cchBuf += cchSrc;
|
---|
| 735 | pStrBuf->pszBuf[cchBuf] = '\0';
|
---|
| 736 | pStrBuf->cchBuf = cchBuf;
|
---|
| 737 |
|
---|
| 738 | return RTEXITCODE_SUCCESS;
|
---|
| 739 | }
|
---|
| 740 |
|
---|
| 741 |
|
---|
[41266] | 742 | /**
|
---|
| 743 | * Appends a character.
|
---|
| 744 | *
|
---|
| 745 | * @returns RTEXITCODE_SUCCESS or RTEXITCODE_FAILURE+msg.
|
---|
| 746 | * @param pStrBuf Pointer to the string buffer.
|
---|
| 747 | * @param ch The charater to append.
|
---|
| 748 | */
|
---|
[41246] | 749 | static RTEXITCODE vbcppStrBufAppendCh(PVBCPPSTRBUF pStrBuf, char ch)
|
---|
| 750 | {
|
---|
| 751 | size_t cchBuf = pStrBuf->cchBuf;
|
---|
| 752 | if (cchBuf + 2 > pStrBuf->cbBufAllocated)
|
---|
| 753 | {
|
---|
| 754 | RTEXITCODE rcExit = vbcppStrBufGrow(pStrBuf, cchBuf + 2);
|
---|
| 755 | if (rcExit != RTEXITCODE_SUCCESS)
|
---|
| 756 | return rcExit;
|
---|
| 757 | }
|
---|
| 758 |
|
---|
| 759 | pStrBuf->pszBuf[cchBuf++] = ch;
|
---|
| 760 | pStrBuf->pszBuf[cchBuf] = '\0';
|
---|
| 761 | pStrBuf->cchBuf = cchBuf;
|
---|
| 762 |
|
---|
| 763 | return RTEXITCODE_SUCCESS;
|
---|
| 764 | }
|
---|
| 765 |
|
---|
| 766 |
|
---|
[41266] | 767 | /**
|
---|
| 768 | * Appends a string to the buffer.
|
---|
| 769 | *
|
---|
| 770 | * @returns RTEXITCODE_SUCCESS or RTEXITCODE_FAILURE+msg.
|
---|
| 771 | * @param pStrBuf Pointer to the string buffer.
|
---|
| 772 | * @param psz The string to append.
|
---|
| 773 | */
|
---|
[41246] | 774 | static RTEXITCODE vbcppStrBufAppend(PVBCPPSTRBUF pStrBuf, const char *psz)
|
---|
| 775 | {
|
---|
| 776 | return vbcppStrBufAppendN(pStrBuf, psz, strlen(psz));
|
---|
| 777 | }
|
---|
| 778 |
|
---|
| 779 |
|
---|
[41266] | 780 | /**
|
---|
| 781 | * Gets the last char in the buffer.
|
---|
| 782 | *
|
---|
| 783 | * @returns Last character, 0 if empty.
|
---|
| 784 | * @param pStrBuf Pointer to the string buffer.
|
---|
| 785 | */
|
---|
[41246] | 786 | static char vbcppStrBufLastCh(PVBCPPSTRBUF pStrBuf)
|
---|
| 787 | {
|
---|
| 788 | if (!pStrBuf->cchBuf)
|
---|
| 789 | return '\0';
|
---|
| 790 | return pStrBuf->pszBuf[pStrBuf->cchBuf - 1];
|
---|
| 791 | }
|
---|
| 792 |
|
---|
| 793 |
|
---|
| 794 |
|
---|
| 795 |
|
---|
| 796 |
|
---|
| 797 |
|
---|
| 798 |
|
---|
| 799 | /*
|
---|
| 800 | *
|
---|
| 801 | *
|
---|
[41204] | 802 | * C Identifier/Word Parsing.
|
---|
| 803 | * C Identifier/Word Parsing.
|
---|
| 804 | * C Identifier/Word Parsing.
|
---|
| 805 | * C Identifier/Word Parsing.
|
---|
| 806 | * C Identifier/Word Parsing.
|
---|
| 807 | *
|
---|
| 808 | *
|
---|
| 809 | */
|
---|
| 810 |
|
---|
| 811 |
|
---|
[41179] | 812 | /**
|
---|
[41186] | 813 | * Checks if the given character is a valid C identifier lead character.
|
---|
| 814 | *
|
---|
[41179] | 815 | * @returns true / false.
|
---|
| 816 | * @param ch The character to inspect.
|
---|
| 817 | */
|
---|
| 818 | DECLINLINE(bool) vbcppIsCIdentifierLeadChar(char ch)
|
---|
| 819 | {
|
---|
| 820 | return RT_C_IS_ALPHA(ch)
|
---|
| 821 | || ch == '_';
|
---|
| 822 | }
|
---|
| 823 |
|
---|
| 824 |
|
---|
| 825 | /**
|
---|
[41186] | 826 | * Checks if the given character is a valid C identifier character.
|
---|
| 827 | *
|
---|
[41179] | 828 | * @returns true / false.
|
---|
| 829 | * @param ch The character to inspect.
|
---|
| 830 | */
|
---|
| 831 | DECLINLINE(bool) vbcppIsCIdentifierChar(char ch)
|
---|
| 832 | {
|
---|
| 833 | return RT_C_IS_ALNUM(ch)
|
---|
| 834 | || ch == '_';
|
---|
| 835 | }
|
---|
| 836 |
|
---|
| 837 |
|
---|
| 838 |
|
---|
| 839 | /**
|
---|
[41186] | 840 | *
|
---|
| 841 | * @returns @c true if valid, @c false if not. Error message already displayed
|
---|
[41179] | 842 | * on failure.
|
---|
| 843 | * @param pThis The C preprocessor instance.
|
---|
| 844 | * @param pchIdentifier The start of the identifier to validate.
|
---|
[41186] | 845 | * @param cchIdentifier The length of the identifier. RTSTR_MAX if not
|
---|
[41179] | 846 | * known.
|
---|
| 847 | */
|
---|
| 848 | static bool vbcppValidateCIdentifier(PVBCPP pThis, const char *pchIdentifier, size_t cchIdentifier)
|
---|
| 849 | {
|
---|
| 850 | if (cchIdentifier == RTSTR_MAX)
|
---|
| 851 | cchIdentifier = strlen(pchIdentifier);
|
---|
| 852 |
|
---|
| 853 | if (cchIdentifier == 0)
|
---|
| 854 | {
|
---|
| 855 | vbcppErrorPos(pThis, pchIdentifier, "Zero length identifier");
|
---|
| 856 | return false;
|
---|
| 857 | }
|
---|
| 858 |
|
---|
| 859 | if (!vbcppIsCIdentifierLeadChar(*pchIdentifier))
|
---|
| 860 | {
|
---|
| 861 | vbcppErrorPos(pThis, pchIdentifier, "Bad lead chararacter in identifier: '%.*s'", cchIdentifier, pchIdentifier);
|
---|
| 862 | return false;
|
---|
| 863 | }
|
---|
| 864 |
|
---|
| 865 | for (size_t off = 1; off < cchIdentifier; off++)
|
---|
| 866 | {
|
---|
| 867 | if (!vbcppIsCIdentifierChar(pchIdentifier[off]))
|
---|
| 868 | {
|
---|
| 869 | vbcppErrorPos(pThis, pchIdentifier + off, "Illegal chararacter in identifier: '%.*s' (#%zu)", cchIdentifier, pchIdentifier, off + 1);
|
---|
| 870 | return false;
|
---|
| 871 | }
|
---|
| 872 | }
|
---|
| 873 |
|
---|
| 874 | return true;
|
---|
| 875 | }
|
---|
| 876 |
|
---|
[41266] | 877 | #if 0
|
---|
[41179] | 878 |
|
---|
[41246] | 879 | /**
|
---|
| 880 | * Checks if the given character is valid C punctuation.
|
---|
| 881 | *
|
---|
| 882 | * @returns true / false.
|
---|
| 883 | * @param ch The character to inspect.
|
---|
| 884 | */
|
---|
| 885 | DECLINLINE(bool) vbcppIsCPunctuationLeadChar(char ch)
|
---|
| 886 | {
|
---|
| 887 | switch (ch)
|
---|
| 888 | {
|
---|
| 889 | case '!':
|
---|
| 890 | case '#':
|
---|
| 891 | case '%':
|
---|
| 892 | case '&':
|
---|
| 893 | case '(':
|
---|
| 894 | case ')':
|
---|
| 895 | case '*':
|
---|
| 896 | case '+':
|
---|
| 897 | case ',':
|
---|
| 898 | case '-':
|
---|
| 899 | case '.':
|
---|
| 900 | case '/':
|
---|
| 901 | case ':':
|
---|
| 902 | case ';':
|
---|
| 903 | case '<':
|
---|
| 904 | case '=':
|
---|
| 905 | case '>':
|
---|
| 906 | case '?':
|
---|
| 907 | case '[':
|
---|
| 908 | case ']':
|
---|
| 909 | case '^':
|
---|
| 910 | case '{':
|
---|
| 911 | case '|':
|
---|
| 912 | case '}':
|
---|
| 913 | case '~':
|
---|
| 914 | return true;
|
---|
| 915 | default:
|
---|
| 916 | return false;
|
---|
| 917 | }
|
---|
| 918 | }
|
---|
[41204] | 919 |
|
---|
| 920 |
|
---|
[41246] | 921 | /**
|
---|
| 922 | * Checks if the given string start with valid C punctuation.
|
---|
| 923 | *
|
---|
| 924 | * @returns 0 if not, otherwise the length of the punctuation.
|
---|
| 925 | * @param pch The which start we should evaluate.
|
---|
| 926 | * @param cchMax The maximum string length.
|
---|
| 927 | */
|
---|
| 928 | static size_t vbcppIsCPunctuationLeadChar(const char *psz, size_t cchMax)
|
---|
| 929 | {
|
---|
| 930 | if (!cchMax)
|
---|
| 931 | return 0;
|
---|
[41204] | 932 |
|
---|
[41246] | 933 | switch (psz[0])
|
---|
| 934 | {
|
---|
| 935 | case '!':
|
---|
| 936 | case '*':
|
---|
| 937 | case '/':
|
---|
| 938 | case '=':
|
---|
| 939 | case '^':
|
---|
| 940 | if (cchMax >= 2 && psz[1] == '=')
|
---|
| 941 | return 2;
|
---|
| 942 | return 1;
|
---|
| 943 |
|
---|
| 944 | case '#':
|
---|
| 945 | if (cchMax >= 2 && psz[1] == '#')
|
---|
| 946 | return 2;
|
---|
| 947 | return 1;
|
---|
| 948 |
|
---|
| 949 | case '%':
|
---|
| 950 | if (cchMax >= 2 && (psz[1] == '=' || psz[1] == '>'))
|
---|
| 951 | return 2;
|
---|
| 952 | if (cchMax >= 2 && psz[1] == ':')
|
---|
| 953 | {
|
---|
| 954 | if (cchMax >= 4 && psz[2] == '%' && psz[3] == ':')
|
---|
| 955 | return 4;
|
---|
| 956 | return 2;
|
---|
| 957 | }
|
---|
| 958 | return 1;
|
---|
| 959 |
|
---|
| 960 | case '&':
|
---|
| 961 | if (cchMax >= 2 && (psz[1] == '=' || psz[1] == '&'))
|
---|
| 962 | return 2;
|
---|
| 963 | return 1;
|
---|
| 964 |
|
---|
| 965 | case '(':
|
---|
| 966 | case ')':
|
---|
| 967 | case ',':
|
---|
| 968 | case '?':
|
---|
| 969 | case '[':
|
---|
| 970 | case ']':
|
---|
| 971 | case '{':
|
---|
| 972 | case '}':
|
---|
| 973 | return 1;
|
---|
| 974 |
|
---|
| 975 | case '+':
|
---|
| 976 | if (cchMax >= 2 && (psz[1] == '=' || psz[1] == '+'))
|
---|
| 977 | return 2;
|
---|
| 978 | return 1;
|
---|
| 979 |
|
---|
| 980 | case '-':
|
---|
| 981 | if (cchMax >= 2 && (psz[1] == '=' || psz[1] == '-' || psz[1] == '>'))
|
---|
| 982 | return 2;
|
---|
| 983 | return 1;
|
---|
| 984 |
|
---|
| 985 | case ':':
|
---|
| 986 | if (cchMax >= 2 && psz[1] == '>')
|
---|
| 987 | return 2;
|
---|
| 988 | return 1;
|
---|
| 989 |
|
---|
| 990 | case ';':
|
---|
| 991 | return 1;
|
---|
| 992 |
|
---|
| 993 | case '<':
|
---|
| 994 | if (cchMax >= 2 && psz[1] == '<')
|
---|
| 995 | {
|
---|
| 996 | if (cchMax >= 3 && psz[2] == '=')
|
---|
| 997 | return 3;
|
---|
| 998 | return 2;
|
---|
| 999 | }
|
---|
| 1000 | if (cchMax >= 2 && (psz[1] == '=' || psz[1] == ':' || psz[1] == '%'))
|
---|
| 1001 | return 2;
|
---|
| 1002 | return 1;
|
---|
| 1003 |
|
---|
| 1004 | case '.':
|
---|
| 1005 | if (cchMax >= 3 && psz[1] == '.' && psz[2] == '.')
|
---|
| 1006 | return 3;
|
---|
| 1007 | return 1;
|
---|
| 1008 |
|
---|
| 1009 | case '>':
|
---|
| 1010 | if (cchMax >= 2 && psz[1] == '>')
|
---|
| 1011 | {
|
---|
| 1012 | if (cchMax >= 3 && psz[2] == '=')
|
---|
| 1013 | return 3;
|
---|
| 1014 | return 2;
|
---|
| 1015 | }
|
---|
| 1016 | if (cchMax >= 2 && psz[1] == '=')
|
---|
| 1017 | return 2;
|
---|
| 1018 | return 1;
|
---|
| 1019 |
|
---|
| 1020 | case '|':
|
---|
| 1021 | if (cchMax >= 2 && (psz[1] == '=' || psz[1] == '|'))
|
---|
| 1022 | return 2;
|
---|
| 1023 | return 1;
|
---|
| 1024 |
|
---|
| 1025 | case '~':
|
---|
| 1026 | return 1;
|
---|
| 1027 |
|
---|
| 1028 | default:
|
---|
| 1029 | return 0;
|
---|
| 1030 | }
|
---|
| 1031 | }
|
---|
| 1032 |
|
---|
[41266] | 1033 | #endif
|
---|
[41246] | 1034 |
|
---|
| 1035 |
|
---|
| 1036 |
|
---|
[41266] | 1037 |
|
---|
| 1038 |
|
---|
[41204] | 1039 | /*
|
---|
[41186] | 1040 | *
|
---|
[41204] | 1041 | *
|
---|
| 1042 | * Output
|
---|
| 1043 | * Output
|
---|
| 1044 | * Output
|
---|
| 1045 | * Output
|
---|
| 1046 | * Output
|
---|
| 1047 | *
|
---|
| 1048 | *
|
---|
[41179] | 1049 | */
|
---|
| 1050 |
|
---|
| 1051 |
|
---|
| 1052 | /**
|
---|
[41204] | 1053 | * Outputs a character.
|
---|
[41186] | 1054 | *
|
---|
[41204] | 1055 | * @returns RTEXITCODE_SUCCESS or RTEXITCODE_FAILURE+msg.
|
---|
[41179] | 1056 | * @param pThis The C preprocessor instance.
|
---|
[41204] | 1057 | * @param ch The character to output.
|
---|
[41177] | 1058 | */
|
---|
[41204] | 1059 | static RTEXITCODE vbcppOutputCh(PVBCPP pThis, char ch)
|
---|
[41177] | 1060 | {
|
---|
[41204] | 1061 | int rc = ScmStreamPutCh(&pThis->StrmOutput, ch);
|
---|
| 1062 | if (RT_SUCCESS(rc))
|
---|
| 1063 | return RTEXITCODE_SUCCESS;
|
---|
| 1064 | return vbcppError(pThis, "Output error: %Rrc", rc);
|
---|
[41177] | 1065 | }
|
---|
| 1066 |
|
---|
[41186] | 1067 |
|
---|
[41179] | 1068 | /**
|
---|
[41204] | 1069 | * Outputs a string.
|
---|
[41186] | 1070 | *
|
---|
[41204] | 1071 | * @returns RTEXITCODE_SUCCESS or RTEXITCODE_FAILURE+msg.
|
---|
[41179] | 1072 | * @param pThis The C preprocessor instance.
|
---|
[41204] | 1073 | * @param pch The string.
|
---|
| 1074 | * @param cch The number of characters to write.
|
---|
[41179] | 1075 | */
|
---|
[41204] | 1076 | static RTEXITCODE vbcppOutputWrite(PVBCPP pThis, const char *pch, size_t cch)
|
---|
[41179] | 1077 | {
|
---|
[41204] | 1078 | int rc = ScmStreamWrite(&pThis->StrmOutput, pch, cch);
|
---|
| 1079 | if (RT_SUCCESS(rc))
|
---|
[41202] | 1080 | return RTEXITCODE_SUCCESS;
|
---|
[41204] | 1081 | return vbcppError(pThis, "Output error: %Rrc", rc);
|
---|
[41179] | 1082 | }
|
---|
| 1083 |
|
---|
| 1084 |
|
---|
[41204] | 1085 | static RTEXITCODE vbcppOutputComment(PVBCPP pThis, PSCMSTREAM pStrmInput, size_t offStart, size_t cchOutputted,
|
---|
| 1086 | size_t cchMinIndent)
|
---|
[41179] | 1087 | {
|
---|
[62594] | 1088 | RT_NOREF_PV(cchMinIndent); /** @todo cchMinIndent */
|
---|
| 1089 |
|
---|
[41204] | 1090 | size_t offCur = ScmStreamTell(pStrmInput);
|
---|
| 1091 | if (offStart < offCur)
|
---|
[41179] | 1092 | {
|
---|
[41204] | 1093 | int rc = ScmStreamSeekAbsolute(pStrmInput, offStart);
|
---|
| 1094 | AssertRCReturn(rc, vbcppError(pThis, "Input seek error: %Rrc", rc));
|
---|
[41179] | 1095 |
|
---|
[41204] | 1096 | /*
|
---|
| 1097 | * Use the same indent, if possible.
|
---|
| 1098 | */
|
---|
| 1099 | size_t cchIndent = offStart - ScmStreamTellOffsetOfLine(pStrmInput, ScmStreamTellLine(pStrmInput));
|
---|
| 1100 | if (cchOutputted < cchIndent)
|
---|
| 1101 | rc = ScmStreamPrintf(&pThis->StrmOutput, "%*s", cchIndent - cchOutputted, "");
|
---|
| 1102 | else
|
---|
| 1103 | rc = ScmStreamPutCh(&pThis->StrmOutput, ' ');
|
---|
| 1104 | if (RT_FAILURE(rc))
|
---|
| 1105 | return vbcppError(pThis, "Output error: %Rrc", rc);
|
---|
[41179] | 1106 |
|
---|
[41204] | 1107 | /*
|
---|
| 1108 | * Copy the bytes.
|
---|
| 1109 | */
|
---|
| 1110 | while (ScmStreamTell(pStrmInput) < offCur)
|
---|
[41179] | 1111 | {
|
---|
[41204] | 1112 | unsigned ch = ScmStreamGetCh(pStrmInput);
|
---|
| 1113 | if (ch == ~(unsigned)0)
|
---|
| 1114 | return vbcppError(pThis, "Input error: %Rrc", rc);
|
---|
| 1115 | rc = ScmStreamPutCh(&pThis->StrmOutput, ch);
|
---|
| 1116 | if (RT_FAILURE(rc))
|
---|
| 1117 | return vbcppError(pThis, "Output error: %Rrc", rc);
|
---|
[41179] | 1118 | }
|
---|
| 1119 | }
|
---|
| 1120 |
|
---|
[41204] | 1121 | return RTEXITCODE_SUCCESS;
|
---|
[41179] | 1122 | }
|
---|
| 1123 |
|
---|
| 1124 |
|
---|
| 1125 |
|
---|
[41177] | 1126 |
|
---|
| 1127 |
|
---|
[41204] | 1128 | /*
|
---|
[41186] | 1129 | *
|
---|
[41204] | 1130 | *
|
---|
| 1131 | * Input
|
---|
| 1132 | * Input
|
---|
| 1133 | * Input
|
---|
| 1134 | * Input
|
---|
| 1135 | * Input
|
---|
| 1136 | *
|
---|
| 1137 | *
|
---|
[41186] | 1138 | */
|
---|
| 1139 |
|
---|
| 1140 |
|
---|
[62450] | 1141 | #if 0 /* unused */
|
---|
[41186] | 1142 | /**
|
---|
[41204] | 1143 | * Skips white spaces, including escaped new-lines.
|
---|
[41186] | 1144 | *
|
---|
[41204] | 1145 | * @param pStrmInput The input stream.
|
---|
[41179] | 1146 | */
|
---|
[41204] | 1147 | static void vbcppProcessSkipWhiteAndEscapedEol(PSCMSTREAM pStrmInput)
|
---|
[41177] | 1148 | {
|
---|
[41204] | 1149 | unsigned chPrev = ~(unsigned)0;
|
---|
| 1150 | unsigned ch;
|
---|
| 1151 | while ((ch = ScmStreamPeekCh(pStrmInput)) != ~(unsigned)0)
|
---|
| 1152 | {
|
---|
| 1153 | if (ch == '\r' || ch == '\n')
|
---|
| 1154 | {
|
---|
| 1155 | if (chPrev != '\\')
|
---|
| 1156 | break;
|
---|
| 1157 | chPrev = ch;
|
---|
| 1158 | ScmStreamSeekByLine(pStrmInput, ScmStreamTellLine(pStrmInput) + 1);
|
---|
| 1159 | }
|
---|
| 1160 | else if (RT_C_IS_SPACE(ch))
|
---|
| 1161 | {
|
---|
[52843] | 1162 | chPrev = ch;
|
---|
[41204] | 1163 | ch = ScmStreamGetCh(pStrmInput);
|
---|
| 1164 | Assert(ch == chPrev);
|
---|
| 1165 | }
|
---|
| 1166 | else
|
---|
| 1167 | break;
|
---|
| 1168 | }
|
---|
[41177] | 1169 | }
|
---|
[62450] | 1170 | #endif
|
---|
[41177] | 1171 |
|
---|
| 1172 |
|
---|
| 1173 | /**
|
---|
[41204] | 1174 | * Skips white spaces, escaped new-lines and multi line comments.
|
---|
[41186] | 1175 | *
|
---|
[41177] | 1176 | * @param pThis The C preprocessor instance.
|
---|
[41204] | 1177 | * @param pStrmInput The input stream.
|
---|
[41177] | 1178 | */
|
---|
[41204] | 1179 | static RTEXITCODE vbcppProcessSkipWhiteEscapedEolAndComments(PVBCPP pThis, PSCMSTREAM pStrmInput)
|
---|
[41177] | 1180 | {
|
---|
[41204] | 1181 | unsigned chPrev = ~(unsigned)0;
|
---|
| 1182 | unsigned ch;
|
---|
| 1183 | while ((ch = ScmStreamPeekCh(pStrmInput)) != ~(unsigned)0)
|
---|
[41177] | 1184 | {
|
---|
[41204] | 1185 | if (!RT_C_IS_SPACE(ch))
|
---|
[41177] | 1186 | {
|
---|
[41204] | 1187 | /* Multi-line Comment? */
|
---|
| 1188 | if (ch != '/')
|
---|
| 1189 | break; /* most definitely, not. */
|
---|
[41179] | 1190 |
|
---|
[41204] | 1191 | size_t offSaved = ScmStreamTell(pStrmInput);
|
---|
| 1192 | ScmStreamGetCh(pStrmInput);
|
---|
| 1193 | if (ScmStreamPeekCh(pStrmInput) != '*')
|
---|
[41177] | 1194 | {
|
---|
[41204] | 1195 | ScmStreamSeekAbsolute(pStrmInput, offSaved);
|
---|
| 1196 | break; /* no */
|
---|
[41177] | 1197 | }
|
---|
| 1198 |
|
---|
[41204] | 1199 | /* Skip to the end of the comment. */
|
---|
| 1200 | while ((ch = ScmStreamGetCh(pStrmInput)) != ~(unsigned)0)
|
---|
[41177] | 1201 | {
|
---|
[41204] | 1202 | if (ch == '*')
|
---|
| 1203 | {
|
---|
| 1204 | ch = ScmStreamGetCh(pStrmInput);
|
---|
| 1205 | if (ch == '/')
|
---|
| 1206 | break;
|
---|
| 1207 | if (ch == ~(unsigned)0)
|
---|
| 1208 | break;
|
---|
| 1209 | }
|
---|
[41177] | 1210 | }
|
---|
[41204] | 1211 | if (ch == ~(unsigned)0)
|
---|
| 1212 | return vbcppError(pThis, "unterminated multi-line comment");
|
---|
| 1213 | chPrev = '/';
|
---|
| 1214 | }
|
---|
| 1215 | /* New line (also matched by RT_C_IS_SPACE). */
|
---|
| 1216 | else if (ch == '\r' || ch == '\n')
|
---|
| 1217 | {
|
---|
| 1218 | /* Stop if not escaped. */
|
---|
| 1219 | if (chPrev != '\\')
|
---|
[41177] | 1220 | break;
|
---|
[41204] | 1221 | chPrev = ch;
|
---|
| 1222 | ScmStreamSeekByLine(pStrmInput, ScmStreamTellLine(pStrmInput) + 1);
|
---|
[41177] | 1223 | }
|
---|
[41204] | 1224 | /* Real space char. */
|
---|
| 1225 | else
|
---|
| 1226 | {
|
---|
| 1227 | chPrev = ch;
|
---|
| 1228 | ch = ScmStreamGetCh(pStrmInput);
|
---|
| 1229 | Assert(ch == chPrev);
|
---|
| 1230 | }
|
---|
[41177] | 1231 | }
|
---|
| 1232 | return RTEXITCODE_SUCCESS;
|
---|
| 1233 | }
|
---|
| 1234 |
|
---|
| 1235 |
|
---|
[41179] | 1236 | /**
|
---|
[41204] | 1237 | * Skips white spaces, escaped new-lines, and multi line comments, then checking
|
---|
| 1238 | * that we're at the end of a line.
|
---|
[41186] | 1239 | *
|
---|
[41179] | 1240 | * @param pThis The C preprocessor instance.
|
---|
[41204] | 1241 | * @param pStrmInput The input stream.
|
---|
[41179] | 1242 | */
|
---|
[41204] | 1243 | static RTEXITCODE vbcppProcessSkipWhiteEscapedEolAndCommentsCheckEol(PVBCPP pThis, PSCMSTREAM pStrmInput)
|
---|
[41179] | 1244 | {
|
---|
[41204] | 1245 | RTEXITCODE rcExit = vbcppProcessSkipWhiteEscapedEolAndComments(pThis, pStrmInput);
|
---|
| 1246 | if (rcExit == RTEXITCODE_SUCCESS)
|
---|
| 1247 | {
|
---|
| 1248 | unsigned ch = ScmStreamPeekCh(pStrmInput);
|
---|
| 1249 | if ( ch != ~(unsigned)0
|
---|
| 1250 | && ch != '\r'
|
---|
| 1251 | && ch != '\n')
|
---|
| 1252 | rcExit = vbcppError(pThis, "Did not expected anything more on this line");
|
---|
| 1253 | }
|
---|
| 1254 | return rcExit;
|
---|
[41179] | 1255 | }
|
---|
| 1256 |
|
---|
| 1257 |
|
---|
| 1258 | /**
|
---|
[41204] | 1259 | * Skips white spaces.
|
---|
[41186] | 1260 | *
|
---|
[41246] | 1261 | * @returns The current location upon return.
|
---|
[41204] | 1262 | * @param pStrmInput The input stream.
|
---|
[41179] | 1263 | */
|
---|
[41204] | 1264 | static size_t vbcppProcessSkipWhite(PSCMSTREAM pStrmInput)
|
---|
[41179] | 1265 | {
|
---|
[41204] | 1266 | unsigned ch;
|
---|
| 1267 | while ((ch = ScmStreamPeekCh(pStrmInput)) != ~(unsigned)0)
|
---|
[41194] | 1268 | {
|
---|
[41204] | 1269 | if (!RT_C_IS_SPACE(ch) || ch == '\r' || ch == '\n')
|
---|
| 1270 | break;
|
---|
| 1271 | unsigned chCheck = ScmStreamGetCh(pStrmInput);
|
---|
| 1272 | AssertBreak(chCheck == ch);
|
---|
[41194] | 1273 | }
|
---|
[41204] | 1274 | return ScmStreamTell(pStrmInput);
|
---|
[41194] | 1275 | }
|
---|
| 1276 |
|
---|
| 1277 |
|
---|
[41179] | 1278 | /**
|
---|
[41226] | 1279 | * Looks for a left parenthesis in the input stream.
|
---|
| 1280 | *
|
---|
| 1281 | * Used during macro expansion. Will ignore comments, newlines and other
|
---|
| 1282 | * whitespace.
|
---|
| 1283 | *
|
---|
| 1284 | * @retval true if found. The stream position at opening parenthesis.
|
---|
| 1285 | * @retval false if not found. The stream position is unchanged.
|
---|
| 1286 | *
|
---|
| 1287 | * @param pThis The C preprocessor instance.
|
---|
| 1288 | * @param pStrmInput The input stream.
|
---|
| 1289 | */
|
---|
| 1290 | static bool vbcppInputLookForLeftParenthesis(PVBCPP pThis, PSCMSTREAM pStrmInput)
|
---|
| 1291 | {
|
---|
| 1292 | size_t offSaved = ScmStreamTell(pStrmInput);
|
---|
[62450] | 1293 | /*RTEXITCODE rcExit =*/ vbcppProcessSkipWhiteEscapedEolAndComments(pThis, pStrmInput);
|
---|
[41226] | 1294 | unsigned ch = ScmStreamPeekCh(pStrmInput);
|
---|
| 1295 | if (ch == '(')
|
---|
| 1296 | return true;
|
---|
| 1297 |
|
---|
| 1298 | int rc = ScmStreamSeekAbsolute(pStrmInput, offSaved);
|
---|
| 1299 | AssertFatalRC(rc);
|
---|
| 1300 | return false;
|
---|
| 1301 | }
|
---|
| 1302 |
|
---|
| 1303 |
|
---|
| 1304 | /**
|
---|
[41217] | 1305 | * Skips input until the real end of the current directive line has been
|
---|
| 1306 | * reached.
|
---|
| 1307 | *
|
---|
| 1308 | * This includes multiline comments starting on the same line
|
---|
| 1309 | *
|
---|
| 1310 | * @returns RTEXITCODE_SUCCESS or RTEXITCODE_FAILURE+msg.
|
---|
| 1311 | * @param pThis The C preprocessor instance.
|
---|
| 1312 | * @param pStrmInput The input stream.
|
---|
| 1313 | * @param poffComment Where to note down the position of the final
|
---|
| 1314 | * comment. Optional.
|
---|
| 1315 | */
|
---|
| 1316 | static RTEXITCODE vbcppInputSkipToEndOfDirectiveLine(PVBCPP pThis, PSCMSTREAM pStrmInput, size_t *poffComment)
|
---|
| 1317 | {
|
---|
| 1318 | if (poffComment)
|
---|
| 1319 | *poffComment = ~(size_t)0;
|
---|
| 1320 |
|
---|
| 1321 | RTEXITCODE rcExit = RTEXITCODE_SUCCESS;
|
---|
| 1322 | bool fInComment = false;
|
---|
| 1323 | unsigned chPrev = 0;
|
---|
| 1324 | unsigned ch;
|
---|
| 1325 | while ((ch = ScmStreamPeekCh(pStrmInput)) != ~(unsigned)0)
|
---|
| 1326 | {
|
---|
| 1327 | if (ch == '\r' || ch == '\n')
|
---|
| 1328 | {
|
---|
| 1329 | if (chPrev == '\\')
|
---|
| 1330 | {
|
---|
| 1331 | ScmStreamSeekByLine(pStrmInput, ScmStreamTellLine(pStrmInput) + 1);
|
---|
| 1332 | continue;
|
---|
| 1333 | }
|
---|
| 1334 | if (!fInComment)
|
---|
| 1335 | break;
|
---|
| 1336 | /* The expression continues after multi-line comments. Cool. :-) */
|
---|
| 1337 | }
|
---|
| 1338 | else if (!fInComment)
|
---|
| 1339 | {
|
---|
| 1340 | if (chPrev == '/' && ch == '*' )
|
---|
| 1341 | {
|
---|
| 1342 | fInComment = true;
|
---|
| 1343 | if (poffComment)
|
---|
| 1344 | *poffComment = ScmStreamTell(pStrmInput) - 1;
|
---|
| 1345 | }
|
---|
| 1346 | else if (chPrev == '/' && ch == '/')
|
---|
| 1347 | {
|
---|
| 1348 | if (poffComment)
|
---|
| 1349 | *poffComment = ScmStreamTell(pStrmInput) - 1;
|
---|
| 1350 | rcExit = vbcppProcessSkipWhiteEscapedEolAndComments(pThis, pStrmInput);
|
---|
| 1351 | break; /* done */
|
---|
| 1352 | }
|
---|
| 1353 | }
|
---|
| 1354 | else if (ch == '/' && chPrev == '*')
|
---|
| 1355 | fInComment = false;
|
---|
| 1356 |
|
---|
| 1357 | /* advance */
|
---|
| 1358 | chPrev = ch;
|
---|
| 1359 | ch = ScmStreamGetCh(pStrmInput); Assert(ch == chPrev);
|
---|
| 1360 | }
|
---|
| 1361 | return rcExit;
|
---|
| 1362 | }
|
---|
| 1363 |
|
---|
| 1364 |
|
---|
| 1365 | /**
|
---|
[41179] | 1366 | * Processes a multi-line comment.
|
---|
[41186] | 1367 | *
|
---|
| 1368 | * Must either string the comment or keep it. If the latter, we must refrain
|
---|
| 1369 | * from replacing C-words in it.
|
---|
| 1370 | *
|
---|
[41179] | 1371 | * @returns RTEXITCODE_SUCCESS or RTEXITCODE_FAILURE+msg.
|
---|
| 1372 | * @param pThis The C preprocessor instance.
|
---|
| 1373 | * @param pStrmInput The input stream.
|
---|
| 1374 | */
|
---|
| 1375 | static RTEXITCODE vbcppProcessMultiLineComment(PVBCPP pThis, PSCMSTREAM pStrmInput)
|
---|
| 1376 | {
|
---|
| 1377 | /* The open comment sequence. */
|
---|
| 1378 | ScmStreamGetCh(pStrmInput); /* '*' */
|
---|
| 1379 | RTEXITCODE rcExit = RTEXITCODE_SUCCESS;
|
---|
[41194] | 1380 | if ( pThis->fKeepComments
|
---|
| 1381 | && !pThis->fIf0Mode)
|
---|
[41179] | 1382 | rcExit = vbcppOutputWrite(pThis, "/*", 2);
|
---|
| 1383 |
|
---|
| 1384 | /* The comment.*/
|
---|
| 1385 | unsigned ch;
|
---|
| 1386 | while ( rcExit == RTEXITCODE_SUCCESS
|
---|
| 1387 | && (ch = ScmStreamGetCh(pStrmInput)) != ~(unsigned)0 )
|
---|
| 1388 | {
|
---|
| 1389 | if (ch == '*')
|
---|
| 1390 | {
|
---|
| 1391 | /* Closing sequence? */
|
---|
| 1392 | unsigned ch2 = ScmStreamPeekCh(pStrmInput);
|
---|
| 1393 | if (ch2 == '/')
|
---|
| 1394 | {
|
---|
| 1395 | ScmStreamGetCh(pStrmInput);
|
---|
[41194] | 1396 | if ( pThis->fKeepComments
|
---|
| 1397 | && !pThis->fIf0Mode)
|
---|
[41179] | 1398 | rcExit = vbcppOutputWrite(pThis, "*/", 2);
|
---|
| 1399 | break;
|
---|
| 1400 | }
|
---|
| 1401 | }
|
---|
| 1402 |
|
---|
[41217] | 1403 | if (ch == '\r' || ch == '\n')
|
---|
[41179] | 1404 | {
|
---|
[41217] | 1405 | if ( ( pThis->fKeepComments
|
---|
| 1406 | && !pThis->fIf0Mode)
|
---|
| 1407 | || !pThis->fRemoveDroppedLines
|
---|
| 1408 | || !ScmStreamIsAtStartOfLine(&pThis->StrmOutput))
|
---|
| 1409 | rcExit = vbcppOutputCh(pThis, ch);
|
---|
| 1410 | pThis->fJustDroppedLine = false;
|
---|
| 1411 | pThis->fMaybePreprocessorLine = true;
|
---|
| 1412 | }
|
---|
| 1413 | else if ( pThis->fKeepComments
|
---|
| 1414 | && !pThis->fIf0Mode)
|
---|
[41179] | 1415 | rcExit = vbcppOutputCh(pThis, ch);
|
---|
| 1416 |
|
---|
[41217] | 1417 | if (rcExit != RTEXITCODE_SUCCESS)
|
---|
| 1418 | break;
|
---|
[41179] | 1419 | }
|
---|
| 1420 | return rcExit;
|
---|
| 1421 | }
|
---|
| 1422 |
|
---|
| 1423 |
|
---|
| 1424 | /**
|
---|
[41186] | 1425 | * Processes a single line comment.
|
---|
| 1426 | *
|
---|
| 1427 | * Must either string the comment or keep it. If the latter, we must refrain
|
---|
| 1428 | * from replacing C-words in it.
|
---|
| 1429 | *
|
---|
[41179] | 1430 | * @returns RTEXITCODE_SUCCESS or RTEXITCODE_FAILURE+msg.
|
---|
| 1431 | * @param pThis The C preprocessor instance.
|
---|
| 1432 | * @param pStrmInput The input stream.
|
---|
| 1433 | */
|
---|
| 1434 | static RTEXITCODE vbcppProcessOneLineComment(PVBCPP pThis, PSCMSTREAM pStrmInput)
|
---|
| 1435 | {
|
---|
[41217] | 1436 | RTEXITCODE rcExit = RTEXITCODE_SUCCESS;
|
---|
[41179] | 1437 | SCMEOL enmEol;
|
---|
| 1438 | size_t cchLine;
|
---|
| 1439 | const char *pszLine = ScmStreamGetLine(pStrmInput, &cchLine, &enmEol); Assert(pszLine);
|
---|
| 1440 | pszLine--; cchLine++; /* unfetching the first slash. */
|
---|
| 1441 | for (;;)
|
---|
| 1442 | {
|
---|
[41194] | 1443 | if ( pThis->fKeepComments
|
---|
| 1444 | && !pThis->fIf0Mode)
|
---|
[41179] | 1445 | rcExit = vbcppOutputWrite(pThis, pszLine, cchLine + enmEol);
|
---|
[41217] | 1446 | else if ( !pThis->fIf0Mode
|
---|
| 1447 | || !pThis->fRemoveDroppedLines
|
---|
| 1448 | || !ScmStreamIsAtStartOfLine(&pThis->StrmOutput) )
|
---|
[41179] | 1449 | rcExit = vbcppOutputWrite(pThis, pszLine + cchLine, enmEol);
|
---|
| 1450 | if (rcExit != RTEXITCODE_SUCCESS)
|
---|
| 1451 | break;
|
---|
| 1452 | if ( cchLine == 0
|
---|
| 1453 | || pszLine[cchLine - 1] != '\\')
|
---|
| 1454 | break;
|
---|
| 1455 |
|
---|
| 1456 | pszLine = ScmStreamGetLine(pStrmInput, &cchLine, &enmEol);
|
---|
| 1457 | if (!pszLine)
|
---|
| 1458 | break;
|
---|
| 1459 | }
|
---|
[41217] | 1460 | pThis->fJustDroppedLine = false;
|
---|
[41179] | 1461 | pThis->fMaybePreprocessorLine = true;
|
---|
| 1462 | return rcExit;
|
---|
| 1463 | }
|
---|
| 1464 |
|
---|
| 1465 |
|
---|
| 1466 | /**
|
---|
[41186] | 1467 | * Processes a double quoted string.
|
---|
| 1468 | *
|
---|
| 1469 | * Must not replace any C-words in strings.
|
---|
| 1470 | *
|
---|
[41179] | 1471 | * @returns RTEXITCODE_SUCCESS or RTEXITCODE_FAILURE+msg.
|
---|
| 1472 | * @param pThis The C preprocessor instance.
|
---|
| 1473 | * @param pStrmInput The input stream.
|
---|
| 1474 | */
|
---|
[41226] | 1475 | static RTEXITCODE vbcppProcessStringLitteral(PVBCPP pThis, PSCMSTREAM pStrmInput)
|
---|
[41179] | 1476 | {
|
---|
| 1477 | RTEXITCODE rcExit = vbcppOutputCh(pThis, '"');
|
---|
| 1478 | if (rcExit == RTEXITCODE_SUCCESS)
|
---|
| 1479 | {
|
---|
| 1480 | bool fEscaped = false;
|
---|
| 1481 | for (;;)
|
---|
| 1482 | {
|
---|
| 1483 | unsigned ch = ScmStreamGetCh(pStrmInput);
|
---|
| 1484 | if (ch == ~(unsigned)0)
|
---|
| 1485 | {
|
---|
| 1486 | rcExit = vbcppError(pThis, "Unterminated double quoted string");
|
---|
| 1487 | break;
|
---|
| 1488 | }
|
---|
| 1489 |
|
---|
| 1490 | rcExit = vbcppOutputCh(pThis, ch);
|
---|
| 1491 | if (rcExit != RTEXITCODE_SUCCESS)
|
---|
| 1492 | break;
|
---|
| 1493 |
|
---|
| 1494 | if (ch == '"' && !fEscaped)
|
---|
| 1495 | break;
|
---|
| 1496 | fEscaped = !fEscaped && ch == '\\';
|
---|
[41186] | 1497 | }
|
---|
[41179] | 1498 | }
|
---|
| 1499 | return rcExit;
|
---|
| 1500 | }
|
---|
| 1501 |
|
---|
| 1502 |
|
---|
| 1503 | /**
|
---|
[41246] | 1504 | * Processes a single quoted constant.
|
---|
[41186] | 1505 | *
|
---|
[41266] | 1506 | * Must not replace any C-words in character constants.
|
---|
[41186] | 1507 | *
|
---|
[41179] | 1508 | * @returns RTEXITCODE_SUCCESS or RTEXITCODE_FAILURE+msg.
|
---|
| 1509 | * @param pThis The C preprocessor instance.
|
---|
| 1510 | * @param pStrmInput The input stream.
|
---|
| 1511 | */
|
---|
[41226] | 1512 | static RTEXITCODE vbcppProcessCharacterConstant(PVBCPP pThis, PSCMSTREAM pStrmInput)
|
---|
[41179] | 1513 | {
|
---|
| 1514 | RTEXITCODE rcExit = vbcppOutputCh(pThis, '\'');
|
---|
| 1515 | if (rcExit == RTEXITCODE_SUCCESS)
|
---|
| 1516 | {
|
---|
| 1517 | bool fEscaped = false;
|
---|
| 1518 | for (;;)
|
---|
| 1519 | {
|
---|
| 1520 | unsigned ch = ScmStreamGetCh(pStrmInput);
|
---|
| 1521 | if (ch == ~(unsigned)0)
|
---|
| 1522 | {
|
---|
| 1523 | rcExit = vbcppError(pThis, "Unterminated singled quoted string");
|
---|
| 1524 | break;
|
---|
| 1525 | }
|
---|
| 1526 |
|
---|
| 1527 | rcExit = vbcppOutputCh(pThis, ch);
|
---|
| 1528 | if (rcExit != RTEXITCODE_SUCCESS)
|
---|
| 1529 | break;
|
---|
| 1530 |
|
---|
| 1531 | if (ch == '\'' && !fEscaped)
|
---|
| 1532 | break;
|
---|
| 1533 | fEscaped = !fEscaped && ch == '\\';
|
---|
[41186] | 1534 | }
|
---|
[41179] | 1535 | }
|
---|
| 1536 | return rcExit;
|
---|
| 1537 | }
|
---|
| 1538 |
|
---|
| 1539 |
|
---|
| 1540 | /**
|
---|
[41226] | 1541 | * Processes a integer or floating point number constant.
|
---|
[41186] | 1542 | *
|
---|
[41266] | 1543 | * Must not replace the type suffix.
|
---|
| 1544 | *
|
---|
[41204] | 1545 | * @returns RTEXITCODE_SUCCESS or RTEXITCODE_FAILURE+msg.
|
---|
| 1546 | * @param pThis The C preprocessor instance.
|
---|
[41186] | 1547 | * @param pStrmInput The input stream.
|
---|
[41226] | 1548 | * @param chFirst The first character.
|
---|
| 1549 | */
|
---|
| 1550 | static RTEXITCODE vbcppProcessNumber(PVBCPP pThis, PSCMSTREAM pStrmInput, char chFirst)
|
---|
| 1551 | {
|
---|
| 1552 | RTEXITCODE rcExit = vbcppOutputCh(pThis, chFirst);
|
---|
| 1553 |
|
---|
| 1554 | unsigned ch;
|
---|
| 1555 | while ( rcExit == RTEXITCODE_SUCCESS
|
---|
| 1556 | && (ch = ScmStreamPeekCh(pStrmInput)) != ~(unsigned)0)
|
---|
| 1557 | {
|
---|
| 1558 | if ( !vbcppIsCIdentifierChar(ch)
|
---|
| 1559 | && ch != '.')
|
---|
| 1560 | break;
|
---|
| 1561 |
|
---|
| 1562 | unsigned ch2 = ScmStreamGetCh(pStrmInput);
|
---|
| 1563 | AssertBreakStmt(ch2 == ch, rcExit = vbcppError(pThis, "internal error"));
|
---|
| 1564 | rcExit = vbcppOutputCh(pThis, ch);
|
---|
| 1565 | }
|
---|
| 1566 |
|
---|
| 1567 | return rcExit;
|
---|
| 1568 | }
|
---|
| 1569 |
|
---|
| 1570 |
|
---|
| 1571 | /**
|
---|
| 1572 | * Processes a identifier, possibly replacing it with a definition.
|
---|
| 1573 | *
|
---|
| 1574 | * @returns RTEXITCODE_SUCCESS or RTEXITCODE_FAILURE+msg.
|
---|
| 1575 | * @param pThis The C preprocessor instance.
|
---|
| 1576 | * @param pStrmInput The input stream.
|
---|
[41186] | 1577 | */
|
---|
[62594] | 1578 | static RTEXITCODE vbcppProcessIdentifier(PVBCPP pThis, PSCMSTREAM pStrmInput)
|
---|
[41186] | 1579 | {
|
---|
[41246] | 1580 | RTEXITCODE rcExit;
|
---|
[41217] | 1581 | size_t cchDefine;
|
---|
| 1582 | const char *pchDefine = ScmStreamCGetWordM1(pStrmInput, &cchDefine);
|
---|
| 1583 | AssertReturn(pchDefine, vbcppError(pThis, "Internal error in ScmStreamCGetWordM1"));
|
---|
| 1584 |
|
---|
| 1585 | /*
|
---|
| 1586 | * Does this look like a define we know?
|
---|
| 1587 | */
|
---|
[41297] | 1588 | PVBCPPMACRO pMacro = vbcppMacroLookup(pThis, pchDefine, cchDefine);
|
---|
[41226] | 1589 | if ( pMacro
|
---|
| 1590 | && ( !pMacro->fFunction
|
---|
| 1591 | || vbcppInputLookForLeftParenthesis(pThis, pStrmInput)) )
|
---|
[41217] | 1592 | {
|
---|
[41246] | 1593 | /*
|
---|
| 1594 | * Expand it.
|
---|
| 1595 | */
|
---|
| 1596 | VBCPPMACROEXP ExpCtx;
|
---|
[41301] | 1597 | #if 0
|
---|
[41246] | 1598 | ExpCtx.pMacroStack = NULL;
|
---|
[41301] | 1599 | #endif
|
---|
[41246] | 1600 | ExpCtx.pStrmInput = pStrmInput;
|
---|
| 1601 | ExpCtx.papszArgs = NULL;
|
---|
| 1602 | ExpCtx.cArgs = 0;
|
---|
| 1603 | ExpCtx.cArgsAlloced = 0;
|
---|
[41263] | 1604 | vbcppStrBufInit(&ExpCtx.StrBuf, pThis);
|
---|
| 1605 | rcExit = vbcppStrBufAppendN(&ExpCtx.StrBuf, pchDefine, cchDefine);
|
---|
| 1606 | if (rcExit == RTEXITCODE_SUCCESS)
|
---|
[41303] | 1607 | rcExit = vbcppMacroExpandIt(pThis, &ExpCtx, 0 /* offset */, pMacro, cchDefine);
|
---|
[41263] | 1608 | if (rcExit == RTEXITCODE_SUCCESS)
|
---|
[100618] | 1609 | rcExit = vbcppMacroExpandReScan(pThis, &ExpCtx, kMacroReScanMode_Normal, NULL, NULL);
|
---|
[41263] | 1610 | if (rcExit == RTEXITCODE_SUCCESS)
|
---|
| 1611 | {
|
---|
| 1612 | /*
|
---|
| 1613 | * Insert it into the output stream. Make sure there is a
|
---|
| 1614 | * whitespace following it.
|
---|
| 1615 | */
|
---|
| 1616 | int rc = ScmStreamWrite(&pThis->StrmOutput, ExpCtx.StrBuf.pszBuf, ExpCtx.StrBuf.cchBuf);
|
---|
| 1617 | if (RT_SUCCESS(rc))
|
---|
[41246] | 1618 | {
|
---|
[41263] | 1619 | unsigned chAfter = ScmStreamPeekCh(pStrmInput);
|
---|
| 1620 | if (chAfter != ~(unsigned)0 && !RT_C_IS_SPACE(chAfter))
|
---|
| 1621 | rcExit = vbcppOutputCh(pThis, ' ');
|
---|
[41246] | 1622 | }
|
---|
[41263] | 1623 | else
|
---|
| 1624 | rcExit = vbcppError(pThis, "Output error: %Rrc", rc);
|
---|
[41217] | 1625 | }
|
---|
[41263] | 1626 | vbcppMacroExpandCleanup(&ExpCtx);
|
---|
[41217] | 1627 | }
|
---|
| 1628 | else
|
---|
| 1629 | {
|
---|
| 1630 | /*
|
---|
[41226] | 1631 | * Not a macro or a function-macro name match but no invocation, just
|
---|
| 1632 | * output the text unchanged.
|
---|
[41217] | 1633 | */
|
---|
[41246] | 1634 | int rc = ScmStreamWrite(&pThis->StrmOutput, pchDefine, cchDefine);
|
---|
| 1635 | if (RT_SUCCESS(rc))
|
---|
| 1636 | rcExit = RTEXITCODE_SUCCESS;
|
---|
| 1637 | else
|
---|
[41217] | 1638 | rcExit = vbcppError(pThis, "Output error: %Rrc", rc);
|
---|
| 1639 | }
|
---|
| 1640 | return rcExit;
|
---|
[41186] | 1641 | }
|
---|
| 1642 |
|
---|
| 1643 |
|
---|
[41204] | 1644 |
|
---|
| 1645 |
|
---|
| 1646 |
|
---|
| 1647 |
|
---|
| 1648 |
|
---|
| 1649 | /*
|
---|
| 1650 | *
|
---|
| 1651 | *
|
---|
[41226] | 1652 | * D E F I N E S / M A C R O S
|
---|
| 1653 | * D E F I N E S / M A C R O S
|
---|
| 1654 | * D E F I N E S / M A C R O S
|
---|
| 1655 | * D E F I N E S / M A C R O S
|
---|
| 1656 | * D E F I N E S / M A C R O S
|
---|
[41204] | 1657 | *
|
---|
| 1658 | *
|
---|
| 1659 | */
|
---|
| 1660 |
|
---|
| 1661 |
|
---|
[41186] | 1662 | /**
|
---|
[41204] | 1663 | * Checks if a define exists.
|
---|
[41186] | 1664 | *
|
---|
[41204] | 1665 | * @returns true or false.
|
---|
[41186] | 1666 | * @param pThis The C preprocessor instance.
|
---|
[41204] | 1667 | * @param pszDefine The define name and optionally the argument
|
---|
| 1668 | * list.
|
---|
| 1669 | * @param cchDefine The length of the name. RTSTR_MAX is ok.
|
---|
[41186] | 1670 | */
|
---|
[41226] | 1671 | static bool vbcppMacroExists(PVBCPP pThis, const char *pszDefine, size_t cchDefine)
|
---|
[41186] | 1672 | {
|
---|
[41204] | 1673 | return cchDefine > 0
|
---|
| 1674 | && VBCPP_BITMAP_IS_SET(pThis->bmDefined, *pszDefine)
|
---|
| 1675 | && RTStrSpaceGetN(&pThis->StrSpace, pszDefine, cchDefine) != NULL;
|
---|
| 1676 | }
|
---|
[41186] | 1677 |
|
---|
| 1678 |
|
---|
[41204] | 1679 | /**
|
---|
[41209] | 1680 | * Looks up a define.
|
---|
| 1681 | *
|
---|
| 1682 | * @returns Pointer to the define if found, NULL if not.
|
---|
| 1683 | * @param pThis The C preprocessor instance.
|
---|
| 1684 | * @param pszDefine The define name and optionally the argument
|
---|
| 1685 | * list.
|
---|
| 1686 | * @param cchDefine The length of the name. RTSTR_MAX is ok.
|
---|
| 1687 | */
|
---|
[41297] | 1688 | static PVBCPPMACRO vbcppMacroLookup(PVBCPP pThis, const char *pszDefine, size_t cchDefine)
|
---|
[41209] | 1689 | {
|
---|
| 1690 | if (!cchDefine)
|
---|
| 1691 | return NULL;
|
---|
| 1692 | if (!VBCPP_BITMAP_IS_SET(pThis->bmDefined, *pszDefine))
|
---|
| 1693 | return NULL;
|
---|
[41297] | 1694 | return (PVBCPPMACRO)RTStrSpaceGetN(&pThis->StrSpace, pszDefine, cchDefine);
|
---|
[41209] | 1695 | }
|
---|
| 1696 |
|
---|
| 1697 |
|
---|
[41297] | 1698 | static uint32_t vbcppMacroLookupArg(PVBCPPMACRO pMacro, const char *pchName, size_t cchName)
|
---|
[41246] | 1699 | {
|
---|
| 1700 | Assert(cchName > 0);
|
---|
[41226] | 1701 |
|
---|
[41246] | 1702 | char const ch = *pchName;
|
---|
| 1703 | for (uint32_t i = 0; i < pMacro->cArgs; i++)
|
---|
| 1704 | if ( pMacro->papszArgs[i][0] == ch
|
---|
| 1705 | && !strncmp(pMacro->papszArgs[i], pchName, cchName)
|
---|
| 1706 | && pMacro->papszArgs[i][cchName] == '\0')
|
---|
| 1707 | return i;
|
---|
| 1708 |
|
---|
| 1709 | if ( pMacro->fVarArg
|
---|
| 1710 | && cchName == sizeof("__VA_ARGS__") - 1
|
---|
| 1711 | && !strncmp(pchName, "__VA_ARGS__", sizeof("__VA_ARGS__") - 1) )
|
---|
| 1712 | return pMacro->cArgs;
|
---|
| 1713 |
|
---|
| 1714 | return UINT32_MAX;
|
---|
| 1715 | }
|
---|
| 1716 |
|
---|
| 1717 |
|
---|
| 1718 | static RTEXITCODE vbcppMacroExpandReplace(PVBCPP pThis, PVBCPPMACROEXP pExp, size_t off, size_t cchToReplace,
|
---|
| 1719 | const char *pchReplacement, size_t cchReplacement)
|
---|
[41226] | 1720 | {
|
---|
[62594] | 1721 | RT_NOREF_PV(pThis);
|
---|
| 1722 |
|
---|
[41246] | 1723 | /*
|
---|
| 1724 | * Figure how much space we actually need.
|
---|
| 1725 | * (Hope this whitespace stuff is correct...)
|
---|
| 1726 | */
|
---|
| 1727 | bool const fLeadingSpace = off > 0
|
---|
[41263] | 1728 | && !RT_C_IS_SPACE(pExp->StrBuf.pszBuf[off - 1]);
|
---|
| 1729 | bool const fTrailingSpace = off + cchToReplace < pExp->StrBuf.cchBuf
|
---|
| 1730 | && !RT_C_IS_SPACE(pExp->StrBuf.pszBuf[off + cchToReplace]);
|
---|
[41246] | 1731 | size_t const cchActualReplacement = fLeadingSpace + cchReplacement + fTrailingSpace;
|
---|
| 1732 |
|
---|
| 1733 | /*
|
---|
| 1734 | * Adjust the buffer size and contents.
|
---|
| 1735 | */
|
---|
| 1736 | if (cchActualReplacement > cchToReplace)
|
---|
| 1737 | {
|
---|
| 1738 | size_t const offMore = cchActualReplacement - cchToReplace;
|
---|
| 1739 |
|
---|
| 1740 | /* Ensure enough buffer space. */
|
---|
[41263] | 1741 | size_t cbMinBuf = offMore + pExp->StrBuf.cchBuf + 1;
|
---|
| 1742 | RTEXITCODE rcExit = vbcppStrBufGrow(&pExp->StrBuf, cbMinBuf);
|
---|
| 1743 | if (rcExit != RTEXITCODE_SUCCESS)
|
---|
| 1744 | return rcExit;
|
---|
[41246] | 1745 |
|
---|
| 1746 | /* Push the chars following the replacement area down to make room. */
|
---|
[41263] | 1747 | memmove(&pExp->StrBuf.pszBuf[off + cchToReplace + offMore],
|
---|
| 1748 | &pExp->StrBuf.pszBuf[off + cchToReplace],
|
---|
| 1749 | pExp->StrBuf.cchBuf - off - cchToReplace + 1);
|
---|
| 1750 | pExp->StrBuf.cchBuf += offMore;
|
---|
[41246] | 1751 |
|
---|
| 1752 | }
|
---|
| 1753 | else if (cchActualReplacement < cchToReplace)
|
---|
| 1754 | {
|
---|
| 1755 | size_t const offLess = cchToReplace - cchActualReplacement;
|
---|
| 1756 |
|
---|
| 1757 | /* Pull the chars following the replacement area up. */
|
---|
[41263] | 1758 | memmove(&pExp->StrBuf.pszBuf[off + cchToReplace - offLess],
|
---|
| 1759 | &pExp->StrBuf.pszBuf[off + cchToReplace],
|
---|
| 1760 | pExp->StrBuf.cchBuf - off - cchToReplace + 1);
|
---|
| 1761 | pExp->StrBuf.cchBuf -= offLess;
|
---|
[41246] | 1762 | }
|
---|
| 1763 |
|
---|
| 1764 | /*
|
---|
| 1765 | * Insert the replacement string.
|
---|
| 1766 | */
|
---|
[41263] | 1767 | char *pszCur = &pExp->StrBuf.pszBuf[off];
|
---|
[41246] | 1768 | if (fLeadingSpace)
|
---|
| 1769 | *pszCur++ = ' ';
|
---|
| 1770 | memcpy(pszCur, pchReplacement, cchReplacement);
|
---|
| 1771 | if (fTrailingSpace)
|
---|
| 1772 | *pszCur++ = ' ';
|
---|
| 1773 |
|
---|
[41263] | 1774 | Assert(strlen(pExp->StrBuf.pszBuf) == pExp->StrBuf.cchBuf);
|
---|
[41246] | 1775 |
|
---|
[41226] | 1776 | return RTEXITCODE_SUCCESS;
|
---|
| 1777 | }
|
---|
| 1778 |
|
---|
| 1779 |
|
---|
[41246] | 1780 | static unsigned vbcppMacroExpandPeekCh(PVBCPPMACROEXP pExp, size_t *poff)
|
---|
[41226] | 1781 | {
|
---|
[41246] | 1782 | size_t off = *poff;
|
---|
[41263] | 1783 | if (off >= pExp->StrBuf.cchBuf)
|
---|
| 1784 | return pExp->pStrmInput ? ScmStreamPeekCh(pExp->pStrmInput) : ~(unsigned)0;
|
---|
| 1785 | return pExp->StrBuf.pszBuf[off];
|
---|
[41226] | 1786 | }
|
---|
| 1787 |
|
---|
| 1788 |
|
---|
[41246] | 1789 | static unsigned vbcppMacroExpandGetCh(PVBCPPMACROEXP pExp, size_t *poff)
|
---|
| 1790 | {
|
---|
| 1791 | size_t off = *poff;
|
---|
[41263] | 1792 | if (off >= pExp->StrBuf.cchBuf)
|
---|
| 1793 | return pExp->pStrmInput ? ScmStreamGetCh(pExp->pStrmInput) : ~(unsigned)0;
|
---|
[41246] | 1794 | *poff = off + 1;
|
---|
[41263] | 1795 | return pExp->StrBuf.pszBuf[off];
|
---|
[41246] | 1796 | }
|
---|
[41226] | 1797 |
|
---|
[41246] | 1798 |
|
---|
| 1799 | static RTEXITCODE vbcppMacroExpandSkipEolEx(PVBCPP pThis, PVBCPPMACROEXP pExp, size_t *poff, unsigned chFirst)
|
---|
| 1800 | {
|
---|
| 1801 | if (chFirst == '\r')
|
---|
| 1802 | {
|
---|
| 1803 | unsigned ch2 = vbcppMacroExpandPeekCh(pExp, poff);
|
---|
| 1804 | if (ch2 == '\n')
|
---|
| 1805 | {
|
---|
| 1806 | ch2 = ScmStreamGetCh(pExp->pStrmInput);
|
---|
| 1807 | AssertReturn(ch2 == '\n', vbcppError(pThis, "internal error"));
|
---|
| 1808 | }
|
---|
| 1809 | }
|
---|
| 1810 | return RTEXITCODE_SUCCESS;
|
---|
| 1811 | }
|
---|
| 1812 |
|
---|
| 1813 |
|
---|
| 1814 | static RTEXITCODE vbcppMacroExpandSkipEol(PVBCPP pThis, PVBCPPMACROEXP pExp, size_t *poff)
|
---|
| 1815 | {
|
---|
| 1816 | unsigned ch = vbcppMacroExpandGetCh(pExp, poff);
|
---|
| 1817 | AssertReturn(ch == '\r' || ch == '\n', vbcppError(pThis, "internal error"));
|
---|
| 1818 | return vbcppMacroExpandSkipEolEx(pThis, pExp, poff, ch);
|
---|
| 1819 | }
|
---|
| 1820 |
|
---|
| 1821 |
|
---|
| 1822 | static RTEXITCODE vbcppMacroExpandSkipCommentLine(PVBCPP pThis, PVBCPPMACROEXP pExp, size_t *poff)
|
---|
| 1823 | {
|
---|
| 1824 | unsigned ch = vbcppMacroExpandGetCh(pExp, poff);
|
---|
| 1825 | AssertReturn(ch == '/', vbcppError(pThis, "Internal error - expected '/' got '%c'", ch));
|
---|
| 1826 |
|
---|
| 1827 | unsigned chPrev = 0;
|
---|
| 1828 | while ((ch = vbcppMacroExpandGetCh(pExp, poff)) != ~(unsigned)0)
|
---|
| 1829 | {
|
---|
| 1830 | if (ch == '\r' || ch == '\n')
|
---|
| 1831 | {
|
---|
| 1832 | RTEXITCODE rcExit = vbcppMacroExpandSkipEolEx(pThis, pExp, poff, ch);
|
---|
| 1833 | if (rcExit != RTEXITCODE_SUCCESS)
|
---|
| 1834 | return rcExit;
|
---|
| 1835 | if (chPrev != '\\')
|
---|
| 1836 | break;
|
---|
| 1837 | }
|
---|
| 1838 |
|
---|
| 1839 | chPrev = ch;
|
---|
| 1840 | }
|
---|
| 1841 | return RTEXITCODE_SUCCESS;
|
---|
| 1842 | }
|
---|
| 1843 |
|
---|
| 1844 |
|
---|
| 1845 | static RTEXITCODE vbcppMacroExpandSkipComment(PVBCPP pThis, PVBCPPMACROEXP pExp, size_t *poff)
|
---|
| 1846 | {
|
---|
| 1847 | unsigned ch = vbcppMacroExpandGetCh(pExp, poff);
|
---|
| 1848 | AssertReturn(ch == '*', vbcppError(pThis, "Internal error - expected '*' got '%c'", ch));
|
---|
| 1849 |
|
---|
| 1850 | unsigned chPrev2 = 0;
|
---|
| 1851 | unsigned chPrev = 0;
|
---|
| 1852 | while ((ch = vbcppMacroExpandGetCh(pExp, poff)) != ~(unsigned)0)
|
---|
| 1853 | {
|
---|
| 1854 | if (ch == '/' && chPrev == '*')
|
---|
| 1855 | break;
|
---|
| 1856 |
|
---|
| 1857 | if (ch == '\r' || ch == '\n')
|
---|
| 1858 | {
|
---|
| 1859 | RTEXITCODE rcExit = vbcppMacroExpandSkipEolEx(pThis, pExp, poff, ch);
|
---|
| 1860 | if (rcExit != RTEXITCODE_SUCCESS)
|
---|
| 1861 | return rcExit;
|
---|
| 1862 | if (chPrev == '\\')
|
---|
| 1863 | {
|
---|
| 1864 | chPrev = chPrev2; /* for line splicing */
|
---|
| 1865 | continue;
|
---|
| 1866 | }
|
---|
| 1867 | }
|
---|
| 1868 |
|
---|
| 1869 | chPrev2 = chPrev;
|
---|
| 1870 | chPrev = ch;
|
---|
| 1871 | }
|
---|
| 1872 | return RTEXITCODE_SUCCESS;
|
---|
| 1873 | }
|
---|
| 1874 |
|
---|
| 1875 |
|
---|
| 1876 | static RTEXITCODE vbcppMacroExpandGrowArgArray(PVBCPP pThis, PVBCPPMACROEXP pExp, uint32_t cMinArgs)
|
---|
| 1877 | {
|
---|
| 1878 | if (cMinArgs > pExp->cArgsAlloced)
|
---|
| 1879 | {
|
---|
| 1880 | void *pv = RTMemRealloc(pExp->papszArgs, cMinArgs * sizeof(char *));
|
---|
| 1881 | if (!pv)
|
---|
| 1882 | return vbcppError(pThis, "out of memory");
|
---|
| 1883 | pExp->papszArgs = (char **)pv;
|
---|
| 1884 | pExp->cArgsAlloced = cMinArgs;
|
---|
| 1885 | }
|
---|
| 1886 | return RTEXITCODE_SUCCESS;
|
---|
| 1887 | }
|
---|
| 1888 |
|
---|
| 1889 |
|
---|
| 1890 | static RTEXITCODE vbcppMacroExpandAddEmptyParameter(PVBCPP pThis, PVBCPPMACROEXP pExp)
|
---|
| 1891 | {
|
---|
| 1892 | RTEXITCODE rcExit = vbcppMacroExpandGrowArgArray(pThis, pExp, pExp->cArgs + 1);
|
---|
| 1893 | if (rcExit == RTEXITCODE_SUCCESS)
|
---|
| 1894 | {
|
---|
| 1895 | char *pszArg = (char *)RTMemAllocZ(1);
|
---|
| 1896 | if (pszArg)
|
---|
| 1897 | pExp->papszArgs[pExp->cArgs++] = pszArg;
|
---|
| 1898 | else
|
---|
| 1899 | rcExit = vbcppError(pThis, "out of memory");
|
---|
| 1900 | }
|
---|
| 1901 | return rcExit;
|
---|
| 1902 | }
|
---|
| 1903 |
|
---|
| 1904 |
|
---|
| 1905 | static RTEXITCODE vbcppMacroExpandGatherParameters(PVBCPP pThis, PVBCPPMACROEXP pExp, size_t *poff, uint32_t cArgsHint)
|
---|
| 1906 | {
|
---|
| 1907 | RTEXITCODE rcExit = RTEXITCODE_SUCCESS;
|
---|
| 1908 |
|
---|
| 1909 | /*
|
---|
| 1910 | * Free previous argument values.
|
---|
| 1911 | */
|
---|
| 1912 | while (pExp->cArgs > 0)
|
---|
| 1913 | {
|
---|
| 1914 | RTMemFree(pExp->papszArgs[--pExp->cArgs]);
|
---|
| 1915 | pExp->papszArgs[pExp->cArgs] = NULL;
|
---|
| 1916 | }
|
---|
| 1917 |
|
---|
| 1918 | /*
|
---|
| 1919 | * The current character should be an opening parenthsis.
|
---|
| 1920 | */
|
---|
| 1921 | unsigned ch = vbcppMacroExpandGetCh(pExp, poff);
|
---|
| 1922 | if (ch != '(')
|
---|
| 1923 | return vbcppError(pThis, "Internal error - expected '(', found '%c' (#x)", ch, ch);
|
---|
| 1924 |
|
---|
| 1925 | /*
|
---|
| 1926 | * Parse the argument list.
|
---|
| 1927 | */
|
---|
| 1928 | char chQuote = 0;
|
---|
| 1929 | size_t cbArgAlloc = 0;
|
---|
| 1930 | size_t cchArg = 0;
|
---|
| 1931 | char *pszArg = NULL;
|
---|
| 1932 | size_t cParentheses = 1;
|
---|
| 1933 | unsigned chPrev = 0;
|
---|
| 1934 | while ((ch = vbcppMacroExpandGetCh(pExp, poff)) != ~(unsigned)0)
|
---|
| 1935 | {
|
---|
[41263] | 1936 | /** @todo check for '#directives'! */
|
---|
[41246] | 1937 | if (ch == ')' && !chQuote)
|
---|
| 1938 | {
|
---|
| 1939 | Assert(cParentheses >= 1);
|
---|
| 1940 | cParentheses--;
|
---|
| 1941 |
|
---|
| 1942 | /* The end? */
|
---|
| 1943 | if (!cParentheses)
|
---|
| 1944 | {
|
---|
| 1945 | if (cchArg)
|
---|
| 1946 | while (cchArg > 0 && RT_C_IS_SPACE(pszArg[cchArg - 1]))
|
---|
| 1947 | pszArg[--cchArg] = '\0';
|
---|
| 1948 | else if (pExp->cArgs || cArgsHint > 0)
|
---|
| 1949 | rcExit = vbcppMacroExpandAddEmptyParameter(pThis, pExp);
|
---|
| 1950 | break;
|
---|
| 1951 | }
|
---|
| 1952 | }
|
---|
| 1953 | else if (ch == '(' && !chQuote)
|
---|
| 1954 | cParentheses++;
|
---|
| 1955 | else if (ch == ',' && cParentheses == 1 && !chQuote)
|
---|
| 1956 | {
|
---|
| 1957 | /* End of one argument, start of the next. */
|
---|
| 1958 | if (cchArg)
|
---|
| 1959 | while (cchArg > 0 && RT_C_IS_SPACE(pszArg[cchArg - 1]))
|
---|
| 1960 | pszArg[--cchArg] = '\0';
|
---|
| 1961 | else
|
---|
| 1962 | {
|
---|
| 1963 | rcExit = vbcppMacroExpandAddEmptyParameter(pThis, pExp);
|
---|
| 1964 | if (rcExit != RTEXITCODE_SUCCESS)
|
---|
| 1965 | break;
|
---|
| 1966 | }
|
---|
| 1967 |
|
---|
| 1968 | cbArgAlloc = 0;
|
---|
| 1969 | cchArg = 0;
|
---|
| 1970 | pszArg = NULL;
|
---|
| 1971 | continue;
|
---|
| 1972 | }
|
---|
| 1973 | else if (ch == '/' && !chQuote)
|
---|
| 1974 | {
|
---|
| 1975 | /* Comment? */
|
---|
| 1976 | unsigned ch2 = vbcppMacroExpandPeekCh(pExp, poff);
|
---|
| 1977 | /** @todo This ain't right wrt line splicing. */
|
---|
[103384] | 1978 | if (ch2 == '/' || ch2 == '*')
|
---|
[41246] | 1979 | {
|
---|
| 1980 | if (ch2 == '/')
|
---|
| 1981 | rcExit = vbcppMacroExpandSkipCommentLine(pThis, pExp, poff);
|
---|
| 1982 | else
|
---|
| 1983 | rcExit = vbcppMacroExpandSkipComment(pThis, pExp, poff);
|
---|
| 1984 | if (rcExit != RTEXITCODE_SUCCESS)
|
---|
| 1985 | break;
|
---|
| 1986 | continue;
|
---|
| 1987 | }
|
---|
| 1988 | }
|
---|
| 1989 | else if (ch == '"')
|
---|
| 1990 | {
|
---|
| 1991 | if (!chQuote)
|
---|
| 1992 | chQuote = '"';
|
---|
| 1993 | else if (chPrev != '\\')
|
---|
| 1994 | chQuote = 0;
|
---|
| 1995 | }
|
---|
| 1996 | else if (ch == '\'')
|
---|
| 1997 | {
|
---|
| 1998 | if (!chQuote)
|
---|
| 1999 | chQuote = '\'';
|
---|
| 2000 | else if (chPrev != '\\')
|
---|
| 2001 | chQuote = 0;
|
---|
| 2002 | }
|
---|
| 2003 | else if (ch == '\\')
|
---|
| 2004 | {
|
---|
| 2005 | /* Splice lines? */
|
---|
| 2006 | unsigned ch2 = vbcppMacroExpandPeekCh(pExp, poff);
|
---|
| 2007 | if (ch2 == '\r' || ch2 == '\n')
|
---|
| 2008 | {
|
---|
| 2009 | rcExit = vbcppMacroExpandSkipEol(pThis, pExp, poff);
|
---|
| 2010 | if (rcExit != RTEXITCODE_SUCCESS)
|
---|
| 2011 | break;
|
---|
| 2012 | continue;
|
---|
| 2013 | }
|
---|
| 2014 | }
|
---|
| 2015 | else if (cchArg == 0 && RT_C_IS_SPACE(ch))
|
---|
| 2016 | continue; /* ignore spaces leading up to an argument value */
|
---|
| 2017 |
|
---|
| 2018 | /* Append the character to the argument value, adding the argument
|
---|
| 2019 | to the output array if it's first character in it. */
|
---|
| 2020 | if (cchArg + 1 >= cbArgAlloc)
|
---|
| 2021 | {
|
---|
| 2022 | /* Add argument to the vector. */
|
---|
| 2023 | if (!cchArg)
|
---|
| 2024 | {
|
---|
| 2025 | rcExit = vbcppMacroExpandGrowArgArray(pThis, pExp, RT_MAX(pExp->cArgs + 1, cArgsHint));
|
---|
| 2026 | if (rcExit != RTEXITCODE_SUCCESS)
|
---|
| 2027 | break;
|
---|
| 2028 | pExp->papszArgs[pExp->cArgs++] = pszArg;
|
---|
| 2029 | }
|
---|
| 2030 |
|
---|
| 2031 | /* Resize the argument value buffer. */
|
---|
| 2032 | cbArgAlloc = cbArgAlloc ? cbArgAlloc * 2 : 16;
|
---|
| 2033 | pszArg = (char *)RTMemRealloc(pszArg, cbArgAlloc);
|
---|
| 2034 | if (!pszArg)
|
---|
| 2035 | {
|
---|
| 2036 | rcExit = vbcppError(pThis, "out of memory");
|
---|
| 2037 | break;
|
---|
| 2038 | }
|
---|
| 2039 | pExp->papszArgs[pExp->cArgs - 1] = pszArg;
|
---|
| 2040 | }
|
---|
| 2041 |
|
---|
| 2042 | pszArg[cchArg++] = ch;
|
---|
| 2043 | pszArg[cchArg] = '\0';
|
---|
| 2044 | }
|
---|
| 2045 |
|
---|
| 2046 | /*
|
---|
| 2047 | * Check that we're leaving on good terms.
|
---|
| 2048 | */
|
---|
| 2049 | if (rcExit == RTEXITCODE_SUCCESS)
|
---|
| 2050 | {
|
---|
| 2051 | if (cParentheses)
|
---|
| 2052 | rcExit = vbcppError(pThis, "Missing ')'");
|
---|
| 2053 | }
|
---|
| 2054 |
|
---|
| 2055 | return rcExit;
|
---|
| 2056 | }
|
---|
| 2057 |
|
---|
| 2058 |
|
---|
[41209] | 2059 | /**
|
---|
[41246] | 2060 | * Expands the arguments referenced in the macro value.
|
---|
| 2061 | *
|
---|
| 2062 | * @returns RTEXITCODE_SUCCESS or RTEXITCODE_FAILURE + msg.
|
---|
| 2063 | * @param pThis The C preprocessor instance.
|
---|
| 2064 | * @param pExp The expansion context.
|
---|
| 2065 | * @param pMacro The macro. Must be a function macro.
|
---|
| 2066 | * @param pStrBuf String buffer containing the result. The caller
|
---|
| 2067 | * should initialize and destroy this!
|
---|
| 2068 | */
|
---|
[41297] | 2069 | static RTEXITCODE vbcppMacroExpandValueWithArguments(PVBCPP pThis, PVBCPPMACROEXP pExp, PVBCPPMACRO pMacro,
|
---|
[41246] | 2070 | PVBCPPSTRBUF pStrBuf)
|
---|
| 2071 | {
|
---|
| 2072 | Assert(pMacro->fFunction);
|
---|
| 2073 |
|
---|
| 2074 | /*
|
---|
| 2075 | * Empty?
|
---|
| 2076 | */
|
---|
| 2077 | if ( !pMacro->cchValue
|
---|
[41359] | 2078 | || (pMacro->cchValue == 1 && pMacro->szValue[0] == '#'))
|
---|
[41246] | 2079 | return RTEXITCODE_SUCCESS;
|
---|
| 2080 |
|
---|
| 2081 | /*
|
---|
| 2082 | * Parse the value.
|
---|
| 2083 | */
|
---|
| 2084 | RTEXITCODE rcExit = RTEXITCODE_SUCCESS;
|
---|
| 2085 | const char *pszSrc = pMacro->szValue;
|
---|
| 2086 | const char *pszSrcSeq;
|
---|
| 2087 | char ch;
|
---|
| 2088 | while ((ch = *pszSrc++) != '\0')
|
---|
| 2089 | {
|
---|
| 2090 | Assert(ch != '\r'); Assert(ch != '\n'); /* probably not true atm. */
|
---|
| 2091 | if (ch == '#')
|
---|
| 2092 | {
|
---|
| 2093 | if (*pszSrc == '#')
|
---|
| 2094 | {
|
---|
| 2095 | /* Concatenate operator. */
|
---|
| 2096 | rcExit = vbcppError(pThis, "The '##' operatore is not yet implemented");
|
---|
| 2097 | }
|
---|
| 2098 | else
|
---|
| 2099 | {
|
---|
| 2100 | /* Stringify macro argument. */
|
---|
| 2101 | rcExit = vbcppError(pThis, "The '#' operatore is not yet implemented");
|
---|
| 2102 | }
|
---|
| 2103 | return rcExit;
|
---|
| 2104 | }
|
---|
| 2105 | else if (ch == '"')
|
---|
| 2106 | {
|
---|
| 2107 | /* String litteral. */
|
---|
| 2108 | pszSrcSeq = pszSrc - 1;
|
---|
| 2109 | while ((ch = *pszSrc++) != '"')
|
---|
| 2110 | {
|
---|
| 2111 | if (ch == '\\')
|
---|
| 2112 | ch = *pszSrc++;
|
---|
| 2113 | if (ch == '\0')
|
---|
| 2114 | {
|
---|
| 2115 | rcExit = vbcppError(pThis, "String litteral is missing closing quote (\").");
|
---|
| 2116 | break;
|
---|
| 2117 | }
|
---|
| 2118 | }
|
---|
| 2119 | rcExit = vbcppStrBufAppendN(pStrBuf, pszSrcSeq, pszSrc - pszSrcSeq);
|
---|
| 2120 | }
|
---|
| 2121 | else if (ch == '\'')
|
---|
| 2122 | {
|
---|
| 2123 | /* Character constant. */
|
---|
| 2124 | pszSrcSeq = pszSrc - 1;
|
---|
| 2125 | while ((ch = *pszSrc++) != '\'')
|
---|
| 2126 | {
|
---|
| 2127 | if (ch == '\\')
|
---|
| 2128 | ch = *pszSrc++;
|
---|
| 2129 | if (ch == '\0')
|
---|
| 2130 | {
|
---|
| 2131 | rcExit = vbcppError(pThis, "Character constant is missing closing quote (').");
|
---|
| 2132 | break;
|
---|
| 2133 | }
|
---|
| 2134 | }
|
---|
| 2135 | rcExit = vbcppStrBufAppendN(pStrBuf, pszSrcSeq, pszSrc - pszSrcSeq);
|
---|
| 2136 | }
|
---|
| 2137 | else if (RT_C_IS_DIGIT(ch))
|
---|
| 2138 | {
|
---|
| 2139 | /* Process numerical constants correctly (i.e. don't mess with the suffix). */
|
---|
| 2140 | pszSrcSeq = pszSrc - 1;
|
---|
| 2141 | while ( (ch = *pszSrc) != '\0'
|
---|
| 2142 | && ( vbcppIsCIdentifierChar(ch)
|
---|
| 2143 | || ch == '.') )
|
---|
| 2144 | pszSrc++;
|
---|
| 2145 | rcExit = vbcppStrBufAppendN(pStrBuf, pszSrcSeq, pszSrc - pszSrcSeq);
|
---|
| 2146 | }
|
---|
| 2147 | else if (RT_C_IS_SPACE(ch))
|
---|
| 2148 | {
|
---|
| 2149 | /* join spaces */
|
---|
| 2150 | if (RT_C_IS_SPACE(vbcppStrBufLastCh(pStrBuf)))
|
---|
| 2151 | continue;
|
---|
| 2152 | rcExit = vbcppStrBufAppendCh(pStrBuf, ch);
|
---|
| 2153 | }
|
---|
| 2154 | else if (vbcppIsCIdentifierLeadChar(ch))
|
---|
| 2155 | {
|
---|
| 2156 | /* Something we should replace? */
|
---|
| 2157 | pszSrcSeq = pszSrc - 1;
|
---|
| 2158 | while ( (ch = *pszSrc) != '\0'
|
---|
| 2159 | && vbcppIsCIdentifierChar(ch))
|
---|
| 2160 | pszSrc++;
|
---|
| 2161 | size_t cchDefine = pszSrc - pszSrcSeq;
|
---|
| 2162 | uint32_t iArg;
|
---|
| 2163 | if ( VBCPP_BITMAP_IS_SET(pMacro->bmArgs, *pszSrcSeq)
|
---|
| 2164 | && (iArg = vbcppMacroLookupArg(pMacro, pszSrcSeq, cchDefine)) != UINT32_MAX)
|
---|
| 2165 | {
|
---|
| 2166 | /** @todo check out spaces here! */
|
---|
| 2167 | if (iArg < pMacro->cArgs)
|
---|
| 2168 | {
|
---|
| 2169 | Assert(iArg < pExp->cArgs);
|
---|
| 2170 | rcExit = vbcppStrBufAppend(pStrBuf, pExp->papszArgs[iArg]);
|
---|
| 2171 | if (*pExp->papszArgs[iArg] != '\0' && rcExit == RTEXITCODE_SUCCESS)
|
---|
| 2172 | rcExit = vbcppStrBufAppendCh(pStrBuf, ' ');
|
---|
| 2173 | }
|
---|
| 2174 | else
|
---|
| 2175 | {
|
---|
| 2176 | /* __VA_ARGS__ */
|
---|
| 2177 | if (iArg < pExp->cArgs)
|
---|
| 2178 | {
|
---|
| 2179 | for (;;)
|
---|
| 2180 | {
|
---|
| 2181 | rcExit = vbcppStrBufAppend(pStrBuf, pExp->papszArgs[iArg]);
|
---|
| 2182 | if (rcExit != RTEXITCODE_SUCCESS)
|
---|
| 2183 | break;
|
---|
| 2184 | iArg++;
|
---|
| 2185 | if (iArg >= pExp->cArgs)
|
---|
| 2186 | break;
|
---|
| 2187 | rcExit = vbcppStrBufAppendCh(pStrBuf, ',');
|
---|
| 2188 | if (rcExit != RTEXITCODE_SUCCESS)
|
---|
| 2189 | break;
|
---|
| 2190 | }
|
---|
| 2191 | }
|
---|
| 2192 | if (rcExit == RTEXITCODE_SUCCESS)
|
---|
| 2193 | rcExit = vbcppStrBufAppendCh(pStrBuf, ' ');
|
---|
| 2194 | }
|
---|
| 2195 | }
|
---|
| 2196 | /* Not an argument needing replacing. */
|
---|
| 2197 | else
|
---|
| 2198 | rcExit = vbcppStrBufAppendN(pStrBuf, pszSrcSeq, cchDefine);
|
---|
| 2199 | }
|
---|
| 2200 | else
|
---|
| 2201 | {
|
---|
| 2202 | rcExit = vbcppStrBufAppendCh(pStrBuf, ch);
|
---|
| 2203 | }
|
---|
| 2204 | }
|
---|
| 2205 |
|
---|
| 2206 | return rcExit;
|
---|
| 2207 | }
|
---|
| 2208 |
|
---|
| 2209 |
|
---|
| 2210 |
|
---|
| 2211 | /**
|
---|
| 2212 | * Expands the given macro.
|
---|
| 2213 | *
|
---|
| 2214 | * Caller already checked if a function macro should be expanded, i.e. whether
|
---|
| 2215 | * there is a parameter list.
|
---|
| 2216 | *
|
---|
| 2217 | * @returns RTEXITCODE_SUCCESS or RTEXITCODE_FAILURE + msg.
|
---|
| 2218 | * @param pThis The C preprocessor instance.
|
---|
| 2219 | * @param pExp The expansion context.
|
---|
| 2220 | * @param offMacro Offset into the expansion buffer of the macro
|
---|
| 2221 | * invocation.
|
---|
| 2222 | * @param pMacro The macro.
|
---|
[41303] | 2223 | * @param offParameters The start of the parameter list if applicable.
|
---|
| 2224 | * Ignored if not function macro. If the
|
---|
| 2225 | * parameter list starts at the current stream
|
---|
| 2226 | * position shall be at the end of the expansion
|
---|
| 2227 | * buffer.
|
---|
[41246] | 2228 | */
|
---|
[41297] | 2229 | static RTEXITCODE vbcppMacroExpandIt(PVBCPP pThis, PVBCPPMACROEXP pExp, size_t offMacro, PVBCPPMACRO pMacro,
|
---|
[41303] | 2230 | size_t offParameters)
|
---|
[41246] | 2231 | {
|
---|
| 2232 | RTEXITCODE rcExit;
|
---|
[41263] | 2233 | Assert(offMacro + pMacro->Core.cchString <= pExp->StrBuf.cchBuf);
|
---|
[41246] | 2234 | Assert(!pMacro->fExpanding);
|
---|
| 2235 |
|
---|
| 2236 | /*
|
---|
| 2237 | * Function macros are kind of difficult...
|
---|
| 2238 | */
|
---|
| 2239 | if (pMacro->fFunction)
|
---|
| 2240 | {
|
---|
[41303] | 2241 | rcExit = vbcppMacroExpandGatherParameters(pThis, pExp, &offParameters, pMacro->cArgs + pMacro->fVarArg);
|
---|
[41246] | 2242 | if (rcExit == RTEXITCODE_SUCCESS)
|
---|
| 2243 | {
|
---|
| 2244 | if (pExp->cArgs > pMacro->cArgs && !pMacro->fVarArg)
|
---|
| 2245 | rcExit = vbcppError(pThis, "Too many arguments to macro '%s' - found %u, expected %u",
|
---|
| 2246 | pMacro->Core.pszString, pExp->cArgs, pMacro->cArgs);
|
---|
| 2247 | else if (pExp->cArgs < pMacro->cArgs)
|
---|
| 2248 | rcExit = vbcppError(pThis, "Too few arguments to macro '%s' - found %u, expected %u",
|
---|
| 2249 | pMacro->Core.pszString, pExp->cArgs, pMacro->cArgs);
|
---|
| 2250 | }
|
---|
| 2251 | if (rcExit == RTEXITCODE_SUCCESS)
|
---|
| 2252 | {
|
---|
| 2253 | VBCPPSTRBUF ValueBuf;
|
---|
| 2254 | vbcppStrBufInit(&ValueBuf, pThis);
|
---|
| 2255 | rcExit = vbcppMacroExpandValueWithArguments(pThis, pExp, pMacro, &ValueBuf);
|
---|
| 2256 | if (rcExit == RTEXITCODE_SUCCESS)
|
---|
[41303] | 2257 | rcExit = vbcppMacroExpandReplace(pThis, pExp, offMacro, offParameters - offMacro,
|
---|
[41263] | 2258 | ValueBuf.pszBuf, ValueBuf.cchBuf);
|
---|
[41246] | 2259 | vbcppStrBufDelete(&ValueBuf);
|
---|
| 2260 | }
|
---|
| 2261 | }
|
---|
| 2262 | /*
|
---|
| 2263 | * Object-like macros are easy. :-)
|
---|
| 2264 | */
|
---|
| 2265 | else
|
---|
| 2266 | rcExit = vbcppMacroExpandReplace(pThis, pExp, offMacro, pMacro->Core.cchString, pMacro->szValue, pMacro->cchValue);
|
---|
| 2267 | if (rcExit == RTEXITCODE_SUCCESS)
|
---|
| 2268 | {
|
---|
[41301] | 2269 | #if 0 /* wrong */
|
---|
[41246] | 2270 | /*
|
---|
| 2271 | * Push the macro onto the stack.
|
---|
| 2272 | */
|
---|
| 2273 | pMacro->fExpanding = true;
|
---|
| 2274 | pMacro->pUpExpanding = pExp->pMacroStack;
|
---|
| 2275 | pExp->pMacroStack = pMacro;
|
---|
[41301] | 2276 | #endif
|
---|
[41246] | 2277 | }
|
---|
| 2278 |
|
---|
| 2279 | return rcExit;
|
---|
| 2280 | }
|
---|
| 2281 |
|
---|
| 2282 |
|
---|
| 2283 | /**
|
---|
[41263] | 2284 | * Looks for a left parenthesis in the macro expansion buffer and the input
|
---|
| 2285 | * stream.
|
---|
| 2286 | *
|
---|
| 2287 | * @retval true if found. The stream position at opening parenthesis.
|
---|
| 2288 | * @retval false if not found. The stream position is unchanged.
|
---|
| 2289 | *
|
---|
| 2290 | * @param pThis The C preprocessor instance.
|
---|
| 2291 | * @param pExp The expansion context.
|
---|
| 2292 | * @param poff The current offset in the expansion context.
|
---|
| 2293 | * Will be updated on success.
|
---|
| 2294 | *
|
---|
| 2295 | * @sa vbcppInputLookForLeftParenthesis
|
---|
| 2296 | */
|
---|
| 2297 | static bool vbcppMacroExpandLookForLeftParenthesis(PVBCPP pThis, PVBCPPMACROEXP pExp, size_t *poff)
|
---|
| 2298 | {
|
---|
| 2299 | /*
|
---|
| 2300 | * Search the buffer first. (No comments there.)
|
---|
| 2301 | */
|
---|
| 2302 | size_t off = *poff;
|
---|
| 2303 | while (off < pExp->StrBuf.cchBuf)
|
---|
| 2304 | {
|
---|
| 2305 | char ch = pExp->StrBuf.pszBuf[off];
|
---|
| 2306 | if (!RT_C_IS_SPACE(ch))
|
---|
| 2307 | {
|
---|
| 2308 | if (ch == '(')
|
---|
| 2309 | {
|
---|
| 2310 | *poff = off;
|
---|
| 2311 | return true;
|
---|
| 2312 | }
|
---|
| 2313 | return false;
|
---|
| 2314 | }
|
---|
| 2315 | off++;
|
---|
| 2316 | }
|
---|
| 2317 |
|
---|
| 2318 | /*
|
---|
| 2319 | * Reached the end of the buffer, continue searching in the stream.
|
---|
| 2320 | */
|
---|
| 2321 | PSCMSTREAM pStrmInput = pExp->pStrmInput;
|
---|
| 2322 | size_t offSaved = ScmStreamTell(pStrmInput);
|
---|
[62450] | 2323 | /*RTEXITCODE rcExit = */ vbcppProcessSkipWhiteEscapedEolAndComments(pThis, pStrmInput);
|
---|
[41263] | 2324 | unsigned ch = ScmStreamPeekCh(pStrmInput);
|
---|
| 2325 | if (ch == '(')
|
---|
| 2326 | {
|
---|
| 2327 | *poff = pExp->StrBuf.cchBuf;
|
---|
| 2328 | return true;
|
---|
| 2329 | }
|
---|
| 2330 |
|
---|
| 2331 | int rc = ScmStreamSeekAbsolute(pStrmInput, offSaved);
|
---|
| 2332 | AssertFatalRC(rc);
|
---|
| 2333 | return false;
|
---|
| 2334 | }
|
---|
| 2335 |
|
---|
| 2336 |
|
---|
| 2337 | /**
|
---|
| 2338 | * Implements the 'defined' unary operator for \#if and \#elif expressions.
|
---|
| 2339 | *
|
---|
| 2340 | * @returns RTEXITCODE_SUCCESS or RTEXITCODE_FAILURE + msg.
|
---|
| 2341 | * @param pThis The C preprocessor instance.
|
---|
| 2342 | * @param pExp The expansion context.
|
---|
| 2343 | * @param offStart The expansion buffer offset where the 'defined'
|
---|
| 2344 | * occurs.
|
---|
| 2345 | * @param poff Where to store the offset at which the re-scan
|
---|
| 2346 | * shall resume upon return.
|
---|
| 2347 | */
|
---|
| 2348 | static RTEXITCODE vbcppMacroExpandDefinedOperator(PVBCPP pThis, PVBCPPMACROEXP pExp, size_t offStart, size_t *poff)
|
---|
| 2349 | {
|
---|
| 2350 | Assert(!pExp->pStrmInput); /* offset usage below. */
|
---|
| 2351 |
|
---|
| 2352 | /*
|
---|
| 2353 | * Skip white space.
|
---|
| 2354 | */
|
---|
| 2355 | unsigned ch;
|
---|
| 2356 | while ((ch = vbcppMacroExpandGetCh(pExp, poff)) != ~(unsigned)0)
|
---|
| 2357 | if (!RT_C_IS_SPACE(ch))
|
---|
| 2358 | break;
|
---|
| 2359 | bool const fWithParenthesis = ch == '(';
|
---|
| 2360 | if (fWithParenthesis)
|
---|
| 2361 | while ((ch = vbcppMacroExpandGetCh(pExp, poff)) != ~(unsigned)0)
|
---|
| 2362 | if (!RT_C_IS_SPACE(ch))
|
---|
| 2363 | break;
|
---|
| 2364 |
|
---|
| 2365 | /*
|
---|
| 2366 | * Macro identifier.
|
---|
| 2367 | */
|
---|
| 2368 | if (!vbcppIsCIdentifierLeadChar(ch))
|
---|
| 2369 | return vbcppError(pThis, "Expected macro name after 'defined' operator");
|
---|
| 2370 |
|
---|
| 2371 | size_t const offDefine = *poff - 1;
|
---|
| 2372 | while ((ch = vbcppMacroExpandGetCh(pExp, poff)) != ~(unsigned)0)
|
---|
| 2373 | if (!vbcppIsCIdentifierChar(ch))
|
---|
| 2374 | break;
|
---|
[62002] | 2375 | size_t const cchDefine = *poff - offDefine - 1;
|
---|
[41263] | 2376 |
|
---|
| 2377 | /*
|
---|
| 2378 | * Check for closing parenthesis.
|
---|
| 2379 | */
|
---|
| 2380 | if (fWithParenthesis)
|
---|
| 2381 | {
|
---|
| 2382 | while (RT_C_IS_SPACE(ch))
|
---|
| 2383 | ch = vbcppMacroExpandGetCh(pExp, poff);
|
---|
| 2384 | if (ch != ')')
|
---|
| 2385 | return vbcppError(pThis, "Expected closing parenthesis after macro name");
|
---|
| 2386 | }
|
---|
| 2387 |
|
---|
| 2388 | /*
|
---|
| 2389 | * Do the job.
|
---|
| 2390 | */
|
---|
| 2391 | const char *pszResult = vbcppMacroExists(pThis, &pExp->StrBuf.pszBuf[offDefine], cchDefine)
|
---|
| 2392 | ? "1" : "0";
|
---|
| 2393 | RTEXITCODE rcExit = vbcppMacroExpandReplace(pThis, pExp, offStart, *poff - offStart, pszResult, 1);
|
---|
| 2394 | *poff = offStart + 1;
|
---|
| 2395 | return rcExit;
|
---|
| 2396 | }
|
---|
| 2397 |
|
---|
| 2398 |
|
---|
| 2399 | /**
|
---|
[41246] | 2400 | * Re-scan the expanded macro.
|
---|
| 2401 | *
|
---|
[41263] | 2402 | * @returns RTEXITCODE_SUCCESS or RTEXITCODE_FAILURE + msg.
|
---|
| 2403 | * @param pThis The C preprocessor instance.
|
---|
| 2404 | * @param pExp The expansion context.
|
---|
| 2405 | * @param enmMode The re-scan mode.
|
---|
| 2406 | * @param pcReplacements Where to return the number of replacements
|
---|
| 2407 | * performed. Optional.
|
---|
[100618] | 2408 | * @param pcDefinedUnknown Where to return the number of defined() checks
|
---|
| 2409 | * on unknown macros. Optional.
|
---|
[41246] | 2410 | */
|
---|
[100618] | 2411 | static RTEXITCODE vbcppMacroExpandReScan(PVBCPP pThis, PVBCPPMACROEXP pExp, VBCPPMACRORESCANMODE enmMode,
|
---|
| 2412 | size_t *pcReplacements, size_t *pcDefinedUnknown)
|
---|
[41246] | 2413 | {
|
---|
[100618] | 2414 | RTEXITCODE rcExit = RTEXITCODE_SUCCESS;
|
---|
| 2415 | size_t cReplacements = 0;
|
---|
| 2416 | size_t cDefinedUnknown = 0;
|
---|
| 2417 | size_t off = 0;
|
---|
[41263] | 2418 | unsigned ch;
|
---|
| 2419 | while ( off < pExp->StrBuf.cchBuf
|
---|
| 2420 | && (ch = vbcppMacroExpandGetCh(pExp, &off)) != ~(unsigned)0)
|
---|
| 2421 | {
|
---|
| 2422 | /*
|
---|
| 2423 | * String litteral or character constant.
|
---|
| 2424 | */
|
---|
| 2425 | if (ch == '\'' || ch == '"')
|
---|
| 2426 | {
|
---|
| 2427 | unsigned const chEndQuote = ch;
|
---|
| 2428 | while ( off < pExp->StrBuf.cchBuf
|
---|
| 2429 | && (ch = vbcppMacroExpandGetCh(pExp, &off)) != ~(unsigned)0)
|
---|
| 2430 | {
|
---|
| 2431 | if (ch == '\\')
|
---|
| 2432 | {
|
---|
| 2433 | ch = vbcppMacroExpandGetCh(pExp, &off);
|
---|
| 2434 | if (ch == ~(unsigned)0)
|
---|
| 2435 | break;
|
---|
| 2436 | }
|
---|
| 2437 | else if (ch == chEndQuote)
|
---|
| 2438 | break;
|
---|
| 2439 | }
|
---|
| 2440 | if (ch == ~(unsigned)0)
|
---|
| 2441 | return vbcppError(pThis, "Missing end quote (%c)", chEndQuote);
|
---|
| 2442 | }
|
---|
| 2443 | /*
|
---|
| 2444 | * Number constant.
|
---|
| 2445 | */
|
---|
| 2446 | else if ( RT_C_IS_DIGIT(ch)
|
---|
| 2447 | || ( ch == '.'
|
---|
| 2448 | && off + 1 < pExp->StrBuf.cchBuf
|
---|
| 2449 | && RT_C_IS_DIGIT(vbcppMacroExpandPeekCh(pExp, &off))
|
---|
| 2450 | )
|
---|
| 2451 | )
|
---|
| 2452 | {
|
---|
| 2453 | while ( off < pExp->StrBuf.cchBuf
|
---|
| 2454 | && (ch = vbcppMacroExpandPeekCh(pExp, &off)) != ~(unsigned)0
|
---|
| 2455 | && vbcppIsCIdentifierChar(ch) )
|
---|
| 2456 | vbcppMacroExpandGetCh(pExp, &off);
|
---|
| 2457 | }
|
---|
| 2458 | /*
|
---|
| 2459 | * Something that can be replaced?
|
---|
| 2460 | */
|
---|
| 2461 | else if (vbcppIsCIdentifierLeadChar(ch))
|
---|
| 2462 | {
|
---|
| 2463 | size_t offDefine = off - 1;
|
---|
| 2464 | while ( off < pExp->StrBuf.cchBuf
|
---|
| 2465 | && (ch = vbcppMacroExpandPeekCh(pExp, &off)) != ~(unsigned)0
|
---|
| 2466 | && vbcppIsCIdentifierChar(ch) )
|
---|
| 2467 | vbcppMacroExpandGetCh(pExp, &off);
|
---|
| 2468 | size_t cchDefine = off - offDefine;
|
---|
[41246] | 2469 |
|
---|
[41297] | 2470 | PVBCPPMACRO pMacro = vbcppMacroLookup(pThis, &pExp->StrBuf.pszBuf[offDefine], cchDefine);
|
---|
[41263] | 2471 | if ( pMacro
|
---|
| 2472 | && ( !pMacro->fFunction
|
---|
| 2473 | || vbcppMacroExpandLookForLeftParenthesis(pThis, pExp, &off)) )
|
---|
[41303] | 2474 | {
|
---|
[62594] | 2475 | cReplacements++;
|
---|
[41303] | 2476 | rcExit = vbcppMacroExpandIt(pThis, pExp, offDefine, pMacro, off);
|
---|
| 2477 | off = offDefine;
|
---|
| 2478 | }
|
---|
[41263] | 2479 | else
|
---|
| 2480 | {
|
---|
| 2481 | if ( !pMacro
|
---|
| 2482 | && enmMode == kMacroReScanMode_Expression
|
---|
| 2483 | && cchDefine == sizeof("defined") - 1
|
---|
| 2484 | && !strncmp(&pExp->StrBuf.pszBuf[offDefine], "defined", cchDefine))
|
---|
[62594] | 2485 | {
|
---|
| 2486 | cReplacements++;
|
---|
[100618] | 2487 | cDefinedUnknown++;
|
---|
[41263] | 2488 | rcExit = vbcppMacroExpandDefinedOperator(pThis, pExp, offDefine, &off);
|
---|
[62594] | 2489 | }
|
---|
[41263] | 2490 | else
|
---|
| 2491 | off = offDefine + cchDefine;
|
---|
| 2492 | }
|
---|
| 2493 | }
|
---|
| 2494 | else
|
---|
| 2495 | {
|
---|
| 2496 | Assert(RT_C_IS_SPACE(ch) || RT_C_IS_PUNCT(ch));
|
---|
| 2497 | Assert(ch != '\r' && ch != '\n');
|
---|
| 2498 | }
|
---|
| 2499 | }
|
---|
| 2500 |
|
---|
[62594] | 2501 | if (pcReplacements)
|
---|
| 2502 | *pcReplacements = cReplacements;
|
---|
[100618] | 2503 | if (pcDefinedUnknown)
|
---|
| 2504 | *pcDefinedUnknown = cDefinedUnknown;
|
---|
[41246] | 2505 | return rcExit;
|
---|
| 2506 | }
|
---|
| 2507 |
|
---|
| 2508 |
|
---|
| 2509 | /**
|
---|
| 2510 | * Cleans up the expansion context.
|
---|
| 2511 | *
|
---|
| 2512 | * This involves clearing VBCPPMACRO::fExpanding and VBCPPMACRO::pUpExpanding,
|
---|
| 2513 | * and freeing the memory resources associated with the expansion context.
|
---|
| 2514 | *
|
---|
| 2515 | * @param pExp The expansion context.
|
---|
| 2516 | */
|
---|
| 2517 | static void vbcppMacroExpandCleanup(PVBCPPMACROEXP pExp)
|
---|
| 2518 | {
|
---|
[41301] | 2519 | #if 0
|
---|
[41246] | 2520 | while (pExp->pMacroStack)
|
---|
| 2521 | {
|
---|
[41297] | 2522 | PVBCPPMACRO pMacro = pExp->pMacroStack;
|
---|
[41246] | 2523 | pExp->pMacroStack = pMacro->pUpExpanding;
|
---|
| 2524 |
|
---|
| 2525 | pMacro->fExpanding = false;
|
---|
| 2526 | pMacro->pUpExpanding = NULL;
|
---|
| 2527 | }
|
---|
[41301] | 2528 | #endif
|
---|
[41246] | 2529 |
|
---|
| 2530 | while (pExp->cArgs > 0)
|
---|
| 2531 | {
|
---|
| 2532 | RTMemFree(pExp->papszArgs[--pExp->cArgs]);
|
---|
| 2533 | pExp->papszArgs[pExp->cArgs] = NULL;
|
---|
| 2534 | }
|
---|
| 2535 |
|
---|
| 2536 | RTMemFree(pExp->papszArgs);
|
---|
| 2537 | pExp->papszArgs = NULL;
|
---|
| 2538 |
|
---|
[41263] | 2539 | vbcppStrBufDelete(&pExp->StrBuf);
|
---|
[41246] | 2540 | }
|
---|
| 2541 |
|
---|
| 2542 |
|
---|
| 2543 |
|
---|
| 2544 | /**
|
---|
[41204] | 2545 | * Frees a define.
|
---|
| 2546 | *
|
---|
| 2547 | * @returns VINF_SUCCESS (used when called by RTStrSpaceDestroy)
|
---|
[41297] | 2548 | * @param pStr Pointer to the VBCPPMACRO::Core member.
|
---|
[41204] | 2549 | * @param pvUser Unused.
|
---|
| 2550 | */
|
---|
[41226] | 2551 | static DECLCALLBACK(int) vbcppMacroFree(PRTSTRSPACECORE pStr, void *pvUser)
|
---|
[41204] | 2552 | {
|
---|
| 2553 | RTMemFree(pStr);
|
---|
| 2554 | NOREF(pvUser);
|
---|
| 2555 | return VINF_SUCCESS;
|
---|
[41186] | 2556 | }
|
---|
| 2557 |
|
---|
| 2558 |
|
---|
| 2559 | /**
|
---|
[41204] | 2560 | * Removes a define.
|
---|
[41186] | 2561 | *
|
---|
[41204] | 2562 | * @returns RTEXITCODE_SUCCESS or RTEXITCODE_FAILURE + msg.
|
---|
[41186] | 2563 | * @param pThis The C preprocessor instance.
|
---|
[41204] | 2564 | * @param pszDefine The define name, no argument list or anything.
|
---|
| 2565 | * @param cchDefine The length of the name. RTSTR_MAX is ok.
|
---|
| 2566 | * @param fExplicitUndef Explicit undefinition, that is, in a selective
|
---|
| 2567 | * preprocessing run it will evaluate to undefined.
|
---|
[41186] | 2568 | */
|
---|
[41226] | 2569 | static RTEXITCODE vbcppMacroUndef(PVBCPP pThis, const char *pszDefine, size_t cchDefine, bool fExplicitUndef)
|
---|
[41186] | 2570 | {
|
---|
[41204] | 2571 | PRTSTRSPACECORE pHit = RTStrSpaceGetN(&pThis->StrSpace, pszDefine, cchDefine);
|
---|
| 2572 | if (pHit)
|
---|
[41186] | 2573 | {
|
---|
[41204] | 2574 | RTStrSpaceRemove(&pThis->StrSpace, pHit->pszString);
|
---|
[41226] | 2575 | vbcppMacroFree(pHit, NULL);
|
---|
[41186] | 2576 | }
|
---|
[41204] | 2577 |
|
---|
| 2578 | if (fExplicitUndef)
|
---|
| 2579 | {
|
---|
| 2580 | if (cchDefine == RTSTR_MAX)
|
---|
| 2581 | cchDefine = strlen(pszDefine);
|
---|
| 2582 |
|
---|
| 2583 | PRTSTRSPACECORE pStr = (PRTSTRSPACECORE)RTMemAlloc(sizeof(*pStr) + cchDefine + 1);
|
---|
| 2584 | if (!pStr)
|
---|
| 2585 | return vbcppError(pThis, "out of memory");
|
---|
| 2586 | char *pszDst = (char *)(pStr + 1);
|
---|
| 2587 | pStr->pszString = pszDst;
|
---|
| 2588 | memcpy(pszDst, pszDefine, cchDefine);
|
---|
| 2589 | pszDst[cchDefine] = '\0';
|
---|
| 2590 | if (!RTStrSpaceInsert(&pThis->UndefStrSpace, pStr))
|
---|
| 2591 | RTMemFree(pStr);
|
---|
| 2592 | }
|
---|
| 2593 |
|
---|
| 2594 | return RTEXITCODE_SUCCESS;
|
---|
[41186] | 2595 | }
|
---|
| 2596 |
|
---|
| 2597 |
|
---|
| 2598 | /**
|
---|
[41204] | 2599 | * Inserts a define (rejecting and freeing it in some case).
|
---|
[41186] | 2600 | *
|
---|
[41204] | 2601 | * @returns RTEXITCODE_SUCCESS or RTEXITCODE_FAILURE + msg.
|
---|
| 2602 | * @param pThis The C preprocessor instance.
|
---|
[41226] | 2603 | * @param pMacro The define to insert.
|
---|
[41186] | 2604 | */
|
---|
[41297] | 2605 | static RTEXITCODE vbcppMacroInsert(PVBCPP pThis, PVBCPPMACRO pMacro)
|
---|
[41186] | 2606 | {
|
---|
[41204] | 2607 | /*
|
---|
[41209] | 2608 | * Reject illegal macro names.
|
---|
| 2609 | */
|
---|
[41226] | 2610 | if (!strcmp(pMacro->Core.pszString, "defined"))
|
---|
[41209] | 2611 | {
|
---|
[41226] | 2612 | RTEXITCODE rcExit = vbcppError(pThis, "Cannot use '%s' as a macro name", pMacro->Core.pszString);
|
---|
| 2613 | vbcppMacroFree(&pMacro->Core, NULL);
|
---|
[41209] | 2614 | return rcExit;
|
---|
| 2615 | }
|
---|
| 2616 |
|
---|
| 2617 | /*
|
---|
[41204] | 2618 | * Ignore in source-file defines when doing selective preprocessing.
|
---|
| 2619 | */
|
---|
| 2620 | if ( !pThis->fRespectSourceDefines
|
---|
[41226] | 2621 | && !pMacro->fCmdLine)
|
---|
[41186] | 2622 | {
|
---|
[41204] | 2623 | /* Ignore*/
|
---|
[41226] | 2624 | vbcppMacroFree(&pMacro->Core, NULL);
|
---|
[41204] | 2625 | return RTEXITCODE_SUCCESS;
|
---|
[41186] | 2626 | }
|
---|
[41204] | 2627 |
|
---|
| 2628 | /*
|
---|
| 2629 | * Insert it and update the lead character hint bitmap.
|
---|
| 2630 | */
|
---|
[41226] | 2631 | if (RTStrSpaceInsert(&pThis->StrSpace, &pMacro->Core))
|
---|
| 2632 | VBCPP_BITMAP_SET(pThis->bmDefined, *pMacro->Core.pszString);
|
---|
[41204] | 2633 | else
|
---|
| 2634 | {
|
---|
| 2635 | /*
|
---|
| 2636 | * Duplicate. When doing selective D preprocessing, let the command
|
---|
| 2637 | * line take precendece.
|
---|
| 2638 | */
|
---|
[41297] | 2639 | PVBCPPMACRO pOld = (PVBCPPMACRO)RTStrSpaceGet(&pThis->StrSpace, pMacro->Core.pszString); Assert(pOld);
|
---|
[41204] | 2640 | if ( pThis->fAllowRedefiningCmdLineDefines
|
---|
[41226] | 2641 | || pMacro->fCmdLine == pOld->fCmdLine)
|
---|
[41204] | 2642 | {
|
---|
[41226] | 2643 | if (pMacro->fCmdLine)
|
---|
| 2644 | RTMsgWarning("Redefining '%s'", pMacro->Core.pszString);
|
---|
[41204] | 2645 |
|
---|
| 2646 | RTStrSpaceRemove(&pThis->StrSpace, pOld->Core.pszString);
|
---|
[41226] | 2647 | vbcppMacroFree(&pOld->Core, NULL);
|
---|
[41204] | 2648 |
|
---|
[41226] | 2649 | bool fRc = RTStrSpaceInsert(&pThis->StrSpace, &pMacro->Core);
|
---|
[62452] | 2650 | Assert(fRc); NOREF(fRc);
|
---|
[41204] | 2651 | }
|
---|
| 2652 | else
|
---|
| 2653 | {
|
---|
[41226] | 2654 | RTMsgWarning("Ignoring redefinition of '%s'", pMacro->Core.pszString);
|
---|
| 2655 | vbcppMacroFree(&pMacro->Core, NULL);
|
---|
[41204] | 2656 | }
|
---|
| 2657 | }
|
---|
| 2658 |
|
---|
| 2659 | return RTEXITCODE_SUCCESS;
|
---|
[41186] | 2660 | }
|
---|
| 2661 |
|
---|
| 2662 |
|
---|
| 2663 | /**
|
---|
[41204] | 2664 | * Adds a define.
|
---|
[41186] | 2665 | *
|
---|
[41204] | 2666 | * @returns RTEXITCODE_SUCCESS or RTEXITCODE_FAILURE + msg.
|
---|
[41179] | 2667 | * @param pThis The C preprocessor instance.
|
---|
[41204] | 2668 | * @param pszDefine The define name, no parameter list.
|
---|
| 2669 | * @param cchDefine The length of the name.
|
---|
| 2670 | * @param pszParams The parameter list.
|
---|
| 2671 | * @param cchParams The length of the parameter list.
|
---|
| 2672 | * @param pszValue The value.
|
---|
| 2673 | * @param cchDefine The length of the value.
|
---|
| 2674 | * @param fCmdLine Set if originating on the command line.
|
---|
[41179] | 2675 | */
|
---|
[41226] | 2676 | static RTEXITCODE vbcppMacroAddFn(PVBCPP pThis, const char *pszDefine, size_t cchDefine,
|
---|
| 2677 | const char *pszParams, size_t cchParams,
|
---|
| 2678 | const char *pszValue, size_t cchValue,
|
---|
| 2679 | bool fCmdLine)
|
---|
[41204] | 2680 |
|
---|
[41179] | 2681 | {
|
---|
[41204] | 2682 | Assert(RTStrNLen(pszDefine, cchDefine) == cchDefine);
|
---|
| 2683 | Assert(RTStrNLen(pszParams, cchParams) == cchParams);
|
---|
| 2684 | Assert(RTStrNLen(pszValue, cchValue) == cchValue);
|
---|
| 2685 |
|
---|
[41186] | 2686 | /*
|
---|
[41204] | 2687 | * Determin the number of arguments and how much space their names
|
---|
| 2688 | * requires. Performing syntax validation while parsing.
|
---|
[41186] | 2689 | */
|
---|
[100618] | 2690 | bool fVariadic = false;
|
---|
| 2691 | size_t cchArgNames = 0;
|
---|
[41204] | 2692 | uint32_t cArgs = 0;
|
---|
| 2693 | for (size_t off = 0; off < cchParams; off++)
|
---|
[41186] | 2694 | {
|
---|
[41204] | 2695 | /* Skip blanks and maybe one comma. */
|
---|
| 2696 | bool fIgnoreComma = cArgs != 0;
|
---|
| 2697 | while (off < cchParams)
|
---|
[41186] | 2698 | {
|
---|
[100618] | 2699 | if ( !RT_C_IS_SPACE(pszParams[off])
|
---|
| 2700 | && ( pszParams[off] != '\\'
|
---|
| 2701 | || (pszParams[off + 1] != '\n' && pszParams[off + 1] != '\r')))
|
---|
[41186] | 2702 | {
|
---|
[41204] | 2703 | if (pszParams[off] != ',' || !fIgnoreComma)
|
---|
[41186] | 2704 | {
|
---|
[41204] | 2705 | if (vbcppIsCIdentifierLeadChar(pszParams[off]))
|
---|
| 2706 | break;
|
---|
[100618] | 2707 |
|
---|
| 2708 | /* Check for variadic macro argument, just parsing it for now. */
|
---|
| 2709 | if ( pszParams[off] == '.'
|
---|
| 2710 | && off + 3 <= cchParams
|
---|
| 2711 | && pszParams[off + 1] == '.'
|
---|
| 2712 | && pszParams[off + 2] == '.')
|
---|
| 2713 | {
|
---|
| 2714 | size_t const offSaved = off;
|
---|
| 2715 | off += 3;
|
---|
| 2716 | while (off < cchParams && RT_C_IS_SPACE(pszParams[off]))
|
---|
| 2717 | off++;
|
---|
| 2718 | if (off == cchParams)
|
---|
| 2719 | {
|
---|
| 2720 | cArgs++;
|
---|
| 2721 | cchArgNames += sizeof("...");
|
---|
| 2722 | fVariadic = true;
|
---|
| 2723 | break;
|
---|
| 2724 | }
|
---|
| 2725 | off = offSaved;
|
---|
| 2726 | }
|
---|
| 2727 | return vbcppErrorPos(pThis, &pszParams[off], "Unexpected character (%#x, off=%zu)", pszParams[off], off);
|
---|
[41186] | 2728 | }
|
---|
[41204] | 2729 | fIgnoreComma = false;
|
---|
[41186] | 2730 | }
|
---|
[41204] | 2731 | off++;
|
---|
| 2732 | }
|
---|
| 2733 | if (off >= cchParams)
|
---|
| 2734 | break;
|
---|
[41186] | 2735 |
|
---|
[41204] | 2736 | /* Found and argument. First character is already validated. */
|
---|
| 2737 | cArgs++;
|
---|
| 2738 | cchArgNames += 2;
|
---|
| 2739 | off++;
|
---|
| 2740 | while ( off < cchParams
|
---|
| 2741 | && vbcppIsCIdentifierChar(pszParams[off]))
|
---|
| 2742 | off++, cchArgNames++;
|
---|
| 2743 | }
|
---|
| 2744 |
|
---|
| 2745 | /*
|
---|
| 2746 | * Allocate a structure.
|
---|
| 2747 | */
|
---|
[73097] | 2748 | size_t cbDef = RT_UOFFSETOF_DYN(VBCPPMACRO, szValue[cchValue + 1 + cchDefine + 1 + cchArgNames])
|
---|
[41204] | 2749 | + sizeof(const char *) * cArgs;
|
---|
| 2750 | cbDef = RT_ALIGN_Z(cbDef, sizeof(const char *));
|
---|
[41297] | 2751 | PVBCPPMACRO pMacro = (PVBCPPMACRO)RTMemAlloc(cbDef);
|
---|
[41226] | 2752 | if (!pMacro)
|
---|
[41204] | 2753 | return RTMsgErrorExit(RTEXITCODE_FAILURE, "out of memory");
|
---|
| 2754 |
|
---|
[41226] | 2755 | char *pszDst = &pMacro->szValue[cchValue + 1];
|
---|
| 2756 | pMacro->Core.pszString = pszDst;
|
---|
[41204] | 2757 | memcpy(pszDst, pszDefine, cchDefine);
|
---|
| 2758 | pszDst += cchDefine;
|
---|
| 2759 | *pszDst++ = '\0';
|
---|
[41297] | 2760 | pMacro->fFunction = true;
|
---|
[100618] | 2761 | pMacro->fVarArg = fVariadic;
|
---|
[41297] | 2762 | pMacro->fCmdLine = fCmdLine;
|
---|
| 2763 | pMacro->fExpanding = false;
|
---|
| 2764 | pMacro->cArgs = cArgs;
|
---|
| 2765 | pMacro->papszArgs = (const char **)((uintptr_t)pMacro + cbDef - sizeof(const char *) * cArgs);
|
---|
[41226] | 2766 | VBCPP_BITMAP_EMPTY(pMacro->bmArgs);
|
---|
[41297] | 2767 | pMacro->cchValue = cchValue;
|
---|
[41226] | 2768 | memcpy(pMacro->szValue, pszValue, cchValue);
|
---|
| 2769 | pMacro->szValue[cchValue] = '\0';
|
---|
[41204] | 2770 |
|
---|
| 2771 | /*
|
---|
| 2772 | * Set up the arguments.
|
---|
| 2773 | */
|
---|
| 2774 | uint32_t iArg = 0;
|
---|
| 2775 | for (size_t off = 0; off < cchParams; off++)
|
---|
| 2776 | {
|
---|
| 2777 | /* Skip blanks and maybe one comma. */
|
---|
| 2778 | bool fIgnoreComma = cArgs != 0;
|
---|
| 2779 | while (off < cchParams)
|
---|
| 2780 | {
|
---|
[100618] | 2781 | if ( !RT_C_IS_SPACE(pszParams[off])
|
---|
| 2782 | && ( pszParams[off] != '\\'
|
---|
| 2783 | || (pszParams[off + 1] != '\n' && pszParams[off + 1] != '\r')))
|
---|
[41186] | 2784 | {
|
---|
[41204] | 2785 | if (pszParams[off] != ',' || !fIgnoreComma)
|
---|
| 2786 | break;
|
---|
| 2787 | fIgnoreComma = false;
|
---|
[41186] | 2788 | }
|
---|
[41204] | 2789 | off++;
|
---|
[41186] | 2790 | }
|
---|
[41204] | 2791 | if (off >= cchParams)
|
---|
| 2792 | break;
|
---|
| 2793 |
|
---|
| 2794 | /* Found and argument. First character is already validated. */
|
---|
[41226] | 2795 | pMacro->papszArgs[iArg] = pszDst;
|
---|
[100618] | 2796 | if (!fVariadic || iArg + 1 < cArgs)
|
---|
[41186] | 2797 | {
|
---|
[100618] | 2798 | VBCPP_BITMAP_SET(pMacro->bmArgs, pszParams[off]);
|
---|
| 2799 | do
|
---|
| 2800 | {
|
---|
| 2801 | *pszDst++ = pszParams[off++];
|
---|
| 2802 | } while ( off < cchParams
|
---|
| 2803 | && vbcppIsCIdentifierChar(pszParams[off]));
|
---|
| 2804 | }
|
---|
| 2805 | else
|
---|
| 2806 | {
|
---|
| 2807 | Assert(strncmp(&pszParams[off], "...", 3) == 0);
|
---|
| 2808 | VBCPP_BITMAP_SET(pMacro->bmArgs, '_'); /* __VA_ARGS__ */
|
---|
| 2809 | off += 3;
|
---|
| 2810 | *pszDst++ = '.';
|
---|
| 2811 | *pszDst++ = '.';
|
---|
| 2812 | *pszDst++ = '.';
|
---|
| 2813 | }
|
---|
[41204] | 2814 | *pszDst++ = '\0';
|
---|
| 2815 | iArg++;
|
---|
| 2816 | }
|
---|
[41226] | 2817 | Assert((uintptr_t)pszDst <= (uintptr_t)pMacro->papszArgs);
|
---|
[41186] | 2818 |
|
---|
[41226] | 2819 | return vbcppMacroInsert(pThis, pMacro);
|
---|
[41204] | 2820 | }
|
---|
[41186] | 2821 |
|
---|
| 2822 |
|
---|
[41204] | 2823 | /**
|
---|
| 2824 | * Adds a define.
|
---|
| 2825 | *
|
---|
| 2826 | * @returns RTEXITCODE_SUCCESS or RTEXITCODE_FAILURE + msg.
|
---|
| 2827 | * @param pThis The C preprocessor instance.
|
---|
| 2828 | * @param pszDefine The define name and optionally the argument
|
---|
| 2829 | * list.
|
---|
| 2830 | * @param cchDefine The length of the name. RTSTR_MAX is ok.
|
---|
| 2831 | * @param pszValue The value.
|
---|
| 2832 | * @param cchDefine The length of the value. RTSTR_MAX is ok.
|
---|
| 2833 | * @param fCmdLine Set if originating on the command line.
|
---|
| 2834 | */
|
---|
[41226] | 2835 | static RTEXITCODE vbcppMacroAdd(PVBCPP pThis, const char *pszDefine, size_t cchDefine,
|
---|
| 2836 | const char *pszValue, size_t cchValue, bool fCmdLine)
|
---|
[41204] | 2837 | {
|
---|
| 2838 | /*
|
---|
| 2839 | * We need the lengths. Trim the input.
|
---|
| 2840 | */
|
---|
| 2841 | if (cchDefine == RTSTR_MAX)
|
---|
| 2842 | cchDefine = strlen(pszDefine);
|
---|
| 2843 | while (cchDefine > 0 && RT_C_IS_SPACE(*pszDefine))
|
---|
| 2844 | pszDefine++, cchDefine--;
|
---|
| 2845 | while (cchDefine > 0 && RT_C_IS_SPACE(pszDefine[cchDefine - 1]))
|
---|
| 2846 | cchDefine--;
|
---|
| 2847 | if (!cchDefine)
|
---|
| 2848 | return vbcppErrorPos(pThis, pszDefine, "The define has no name");
|
---|
| 2849 |
|
---|
| 2850 | if (cchValue == RTSTR_MAX)
|
---|
| 2851 | cchValue = strlen(pszValue);
|
---|
| 2852 | while (cchValue > 0 && RT_C_IS_SPACE(*pszValue))
|
---|
| 2853 | pszValue++, cchValue--;
|
---|
| 2854 | while (cchValue > 0 && RT_C_IS_SPACE(pszValue[cchValue - 1]))
|
---|
| 2855 | cchValue--;
|
---|
| 2856 |
|
---|
| 2857 | /*
|
---|
| 2858 | * Arguments make the job a bit more annoying. Handle that elsewhere
|
---|
| 2859 | */
|
---|
| 2860 | const char *pszParams = (const char *)memchr(pszDefine, '(', cchDefine);
|
---|
| 2861 | if (pszParams)
|
---|
| 2862 | {
|
---|
| 2863 | size_t cchParams = pszDefine + cchDefine - pszParams;
|
---|
| 2864 | cchDefine -= cchParams;
|
---|
| 2865 | if (!vbcppValidateCIdentifier(pThis, pszDefine, cchDefine))
|
---|
| 2866 | return RTEXITCODE_FAILURE;
|
---|
| 2867 | if (pszParams[cchParams - 1] != ')')
|
---|
| 2868 | return vbcppErrorPos(pThis, pszParams + cchParams - 1, "Missing closing parenthesis");
|
---|
| 2869 | pszParams++;
|
---|
| 2870 | cchParams -= 2;
|
---|
[41226] | 2871 | return vbcppMacroAddFn(pThis, pszDefine, cchDefine, pszParams, cchParams, pszValue, cchValue, fCmdLine);
|
---|
[41186] | 2872 | }
|
---|
[41204] | 2873 |
|
---|
| 2874 | /*
|
---|
| 2875 | * Simple define, no arguments.
|
---|
| 2876 | */
|
---|
| 2877 | if (!vbcppValidateCIdentifier(pThis, pszDefine, cchDefine))
|
---|
| 2878 | return RTEXITCODE_FAILURE;
|
---|
| 2879 |
|
---|
[73097] | 2880 | PVBCPPMACRO pMacro = (PVBCPPMACRO)RTMemAlloc(RT_UOFFSETOF_DYN(VBCPPMACRO, szValue[cchValue + 1 + cchDefine + 1]));
|
---|
[41226] | 2881 | if (!pMacro)
|
---|
[41204] | 2882 | return RTMsgErrorExit(RTEXITCODE_FAILURE, "out of memory");
|
---|
| 2883 |
|
---|
[41226] | 2884 | pMacro->Core.pszString = &pMacro->szValue[cchValue + 1];
|
---|
| 2885 | memcpy((char *)pMacro->Core.pszString, pszDefine, cchDefine);
|
---|
| 2886 | ((char *)pMacro->Core.pszString)[cchDefine] = '\0';
|
---|
[41297] | 2887 | pMacro->fFunction = false;
|
---|
| 2888 | pMacro->fVarArg = false;
|
---|
| 2889 | pMacro->fCmdLine = fCmdLine;
|
---|
| 2890 | pMacro->fExpanding = false;
|
---|
| 2891 | pMacro->cArgs = 0;
|
---|
| 2892 | pMacro->papszArgs = NULL;
|
---|
[41226] | 2893 | VBCPP_BITMAP_EMPTY(pMacro->bmArgs);
|
---|
[41297] | 2894 | pMacro->cchValue = cchValue;
|
---|
[41226] | 2895 | memcpy(pMacro->szValue, pszValue, cchValue);
|
---|
| 2896 | pMacro->szValue[cchValue] = '\0';
|
---|
[41204] | 2897 |
|
---|
[41226] | 2898 | return vbcppMacroInsert(pThis, pMacro);
|
---|
[41186] | 2899 | }
|
---|
| 2900 |
|
---|
| 2901 |
|
---|
| 2902 | /**
|
---|
[41246] | 2903 | * Tries to convert a define into an inline D constant.
|
---|
| 2904 | *
|
---|
| 2905 | * @returns RTEXITCODE_SUCCESS or RTEXITCODE_FAILURE+msg.
|
---|
| 2906 | * @param pThis The C preprocessor instance.
|
---|
| 2907 | * @param pMacro The macro.
|
---|
| 2908 | */
|
---|
[41297] | 2909 | static RTEXITCODE vbcppMacroTryConvertToInlineD(PVBCPP pThis, PVBCPPMACRO pMacro)
|
---|
[41246] | 2910 | {
|
---|
| 2911 | AssertReturn(pMacro, vbcppError(pThis, "Internal error"));
|
---|
| 2912 | if (pMacro->fFunction)
|
---|
| 2913 | return RTEXITCODE_SUCCESS;
|
---|
| 2914 |
|
---|
| 2915 | /*
|
---|
| 2916 | * Do some simple macro resolving. (Mostly to make x86.h work.)
|
---|
| 2917 | */
|
---|
| 2918 | const char *pszDefine = pMacro->Core.pszString;
|
---|
| 2919 | const char *pszValue = pMacro->szValue;
|
---|
| 2920 | size_t cchValue = pMacro->cchValue;
|
---|
| 2921 |
|
---|
[41297] | 2922 | unsigned i = 0;
|
---|
| 2923 | PVBCPPMACRO pMacro2;
|
---|
[41246] | 2924 | while ( i < 10
|
---|
| 2925 | && cchValue > 0
|
---|
| 2926 | && vbcppIsCIdentifierLeadChar(*pszValue)
|
---|
| 2927 | && (pMacro2 = vbcppMacroLookup(pThis, pszValue, cchValue)) != NULL
|
---|
| 2928 | && !pMacro2->fFunction )
|
---|
| 2929 | {
|
---|
| 2930 | pszValue = pMacro2->szValue;
|
---|
| 2931 | cchValue = pMacro2->cchValue;
|
---|
| 2932 | i++;
|
---|
| 2933 | }
|
---|
| 2934 |
|
---|
| 2935 | if (!pMacro->cchValue)
|
---|
| 2936 | return RTEXITCODE_SUCCESS;
|
---|
| 2937 |
|
---|
| 2938 |
|
---|
| 2939 | /*
|
---|
| 2940 | * A lone value?
|
---|
| 2941 | */
|
---|
| 2942 | ssize_t cch = 0;
|
---|
| 2943 | uint64_t u64;
|
---|
| 2944 | char *pszNext;
|
---|
| 2945 | int rc = RTStrToUInt64Ex(pszValue, &pszNext, 0, &u64);
|
---|
| 2946 | if (RT_SUCCESS(rc))
|
---|
| 2947 | {
|
---|
| 2948 | if ( rc == VWRN_TRAILING_SPACES
|
---|
| 2949 | || rc == VWRN_NEGATIVE_UNSIGNED
|
---|
| 2950 | || rc == VWRN_NUMBER_TOO_BIG)
|
---|
| 2951 | return RTEXITCODE_SUCCESS;
|
---|
| 2952 | const char *pszType;
|
---|
| 2953 | if (rc == VWRN_TRAILING_CHARS)
|
---|
| 2954 | {
|
---|
| 2955 | if (!strcmp(pszNext, "u") || !strcmp(pszNext, "U"))
|
---|
| 2956 | pszType = "uint32_t";
|
---|
| 2957 | else if (!strcmp(pszNext, "ul") || !strcmp(pszNext, "UL"))
|
---|
| 2958 | pszType = "uintptr_t";
|
---|
| 2959 | else if (!strcmp(pszNext, "ull") || !strcmp(pszNext, "ULL"))
|
---|
| 2960 | pszType = "uint64_t";
|
---|
| 2961 | else
|
---|
| 2962 | pszType = NULL;
|
---|
| 2963 | }
|
---|
| 2964 | else if (u64 <= UINT8_MAX)
|
---|
| 2965 | pszType = "uint8_t";
|
---|
| 2966 | else if (u64 <= UINT16_MAX)
|
---|
| 2967 | pszType = "uint16_t";
|
---|
| 2968 | else if (u64 <= UINT32_MAX)
|
---|
| 2969 | pszType = "uint32_t";
|
---|
| 2970 | else
|
---|
| 2971 | pszType = "uint64_t";
|
---|
| 2972 | if (!pszType)
|
---|
| 2973 | return RTEXITCODE_SUCCESS;
|
---|
| 2974 | cch = ScmStreamPrintf(&pThis->StrmOutput, "inline %s %s = %.*s;\n",
|
---|
| 2975 | pszType, pszDefine, pszNext - pszValue, pszValue);
|
---|
| 2976 | }
|
---|
| 2977 | /*
|
---|
| 2978 | * A value wrapped in a constant macro?
|
---|
| 2979 | */
|
---|
[41249] | 2980 | else if ( (pszNext = (char *)strchr(pszValue, '(')) != NULL
|
---|
[41246] | 2981 | && pszValue[cchValue - 1] == ')' )
|
---|
| 2982 | {
|
---|
| 2983 | size_t cchPrefix = pszNext - pszValue;
|
---|
| 2984 | size_t cchInnerValue = cchValue - cchPrefix - 2;
|
---|
| 2985 | const char *pchInnerValue = &pszValue[cchPrefix + 1];
|
---|
| 2986 | while (cchInnerValue > 0 && RT_C_IS_SPACE(*pchInnerValue))
|
---|
| 2987 | cchInnerValue--, pchInnerValue++;
|
---|
| 2988 | while (cchInnerValue > 0 && RT_C_IS_SPACE(pchInnerValue[cchInnerValue - 1]))
|
---|
| 2989 | cchInnerValue--;
|
---|
| 2990 | if (!cchInnerValue || !RT_C_IS_XDIGIT(*pchInnerValue))
|
---|
| 2991 | return RTEXITCODE_SUCCESS;
|
---|
| 2992 |
|
---|
| 2993 | rc = RTStrToUInt64Ex(pchInnerValue, &pszNext, 0, &u64);
|
---|
| 2994 | if ( RT_FAILURE(rc)
|
---|
| 2995 | || rc == VWRN_TRAILING_SPACES
|
---|
| 2996 | || rc == VWRN_NEGATIVE_UNSIGNED
|
---|
| 2997 | || rc == VWRN_NUMBER_TOO_BIG)
|
---|
| 2998 | return RTEXITCODE_SUCCESS;
|
---|
| 2999 |
|
---|
| 3000 | const char *pszType;
|
---|
| 3001 | #define MY_MATCH_STR(a_sz) (sizeof(a_sz) - 1 == cchPrefix && !strncmp(pszValue, a_sz, sizeof(a_sz) - 1))
|
---|
| 3002 | if (MY_MATCH_STR("UINT8_C"))
|
---|
| 3003 | pszType = "uint8_t";
|
---|
| 3004 | else if (MY_MATCH_STR("UINT16_C"))
|
---|
| 3005 | pszType = "uint16_t";
|
---|
| 3006 | else if (MY_MATCH_STR("UINT32_C"))
|
---|
| 3007 | pszType = "uint32_t";
|
---|
| 3008 | else if (MY_MATCH_STR("UINT64_C"))
|
---|
| 3009 | pszType = "uint64_t";
|
---|
| 3010 | else
|
---|
| 3011 | pszType = NULL;
|
---|
| 3012 | if (pszType)
|
---|
| 3013 | cch = ScmStreamPrintf(&pThis->StrmOutput, "inline %s %s = %.*s;\n",
|
---|
| 3014 | pszType, pszDefine, cchInnerValue, pchInnerValue);
|
---|
| 3015 | else if (MY_MATCH_STR("RT_BIT") || MY_MATCH_STR("RT_BIT_32"))
|
---|
| 3016 | cch = ScmStreamPrintf(&pThis->StrmOutput, "inline uint32_t %s = 1U << %llu;\n",
|
---|
| 3017 | pszDefine, u64);
|
---|
| 3018 | else if (MY_MATCH_STR("RT_BIT_64"))
|
---|
| 3019 | cch = ScmStreamPrintf(&pThis->StrmOutput, "inline uint64_t %s = 1ULL << %llu;\n",
|
---|
| 3020 | pszDefine, u64);
|
---|
| 3021 | else
|
---|
| 3022 | return RTEXITCODE_SUCCESS;
|
---|
| 3023 | #undef MY_MATCH_STR
|
---|
| 3024 | }
|
---|
| 3025 | /* Dunno what this is... */
|
---|
| 3026 | else
|
---|
| 3027 | return RTEXITCODE_SUCCESS;
|
---|
| 3028 |
|
---|
| 3029 | /*
|
---|
| 3030 | * Check for output error and clear the output suppression indicator.
|
---|
| 3031 | */
|
---|
| 3032 | if (cch < 0)
|
---|
| 3033 | return vbcppError(pThis, "Output error");
|
---|
| 3034 |
|
---|
| 3035 | pThis->fJustDroppedLine = false;
|
---|
| 3036 | return RTEXITCODE_SUCCESS;
|
---|
| 3037 | }
|
---|
| 3038 |
|
---|
| 3039 |
|
---|
| 3040 |
|
---|
| 3041 | /**
|
---|
[41186] | 3042 | * Processes a abbreviated line number directive.
|
---|
| 3043 | *
|
---|
| 3044 | * @returns RTEXITCODE_SUCCESS or RTEXITCODE_FAILURE+msg.
|
---|
| 3045 | * @param pThis The C preprocessor instance.
|
---|
| 3046 | * @param pStrmInput The input stream.
|
---|
| 3047 | * @param offStart The stream position where the directive
|
---|
| 3048 | * started (for pass thru).
|
---|
| 3049 | */
|
---|
[41226] | 3050 | static RTEXITCODE vbcppDirectiveDefine(PVBCPP pThis, PSCMSTREAM pStrmInput, size_t offStart)
|
---|
[41186] | 3051 | {
|
---|
[62594] | 3052 | RT_NOREF_PV(offStart);
|
---|
| 3053 |
|
---|
[41195] | 3054 | /*
|
---|
| 3055 | * Parse it.
|
---|
| 3056 | */
|
---|
| 3057 | RTEXITCODE rcExit = vbcppProcessSkipWhiteEscapedEolAndComments(pThis, pStrmInput);
|
---|
| 3058 | if (rcExit == RTEXITCODE_SUCCESS)
|
---|
| 3059 | {
|
---|
| 3060 | size_t cchDefine;
|
---|
| 3061 | const char *pchDefine = ScmStreamCGetWord(pStrmInput, &cchDefine);
|
---|
| 3062 | if (pchDefine)
|
---|
| 3063 | {
|
---|
| 3064 | /* If it's a function style define, parse out the parameter list. */
|
---|
| 3065 | size_t cchParams = 0;
|
---|
| 3066 | const char *pchParams = NULL;
|
---|
| 3067 | unsigned ch = ScmStreamPeekCh(pStrmInput);
|
---|
| 3068 | if (ch == '(')
|
---|
| 3069 | {
|
---|
| 3070 | ScmStreamGetCh(pStrmInput);
|
---|
| 3071 | pchParams = ScmStreamGetCur(pStrmInput);
|
---|
| 3072 |
|
---|
| 3073 | unsigned chPrev = ch;
|
---|
| 3074 | while ((ch = ScmStreamPeekCh(pStrmInput)) != ~(unsigned)0)
|
---|
| 3075 | {
|
---|
| 3076 | if (ch == '\r' || ch == '\n')
|
---|
| 3077 | {
|
---|
| 3078 | if (chPrev != '\\')
|
---|
| 3079 | {
|
---|
| 3080 | rcExit = vbcppError(pThis, "Missing ')'");
|
---|
| 3081 | break;
|
---|
| 3082 | }
|
---|
| 3083 | ScmStreamSeekByLine(pStrmInput, ScmStreamTellLine(pStrmInput) + 1);
|
---|
| 3084 | }
|
---|
| 3085 | if (ch == ')')
|
---|
| 3086 | {
|
---|
| 3087 | cchParams = ScmStreamGetCur(pStrmInput) - pchParams;
|
---|
| 3088 | ScmStreamGetCh(pStrmInput);
|
---|
| 3089 | break;
|
---|
| 3090 | }
|
---|
[100618] | 3091 | chPrev = ch;
|
---|
[41195] | 3092 | ScmStreamGetCh(pStrmInput);
|
---|
| 3093 | }
|
---|
| 3094 | }
|
---|
| 3095 | /* The simple kind. */
|
---|
| 3096 | else if (!RT_C_IS_SPACE(ch) && ch != ~(unsigned)0)
|
---|
| 3097 | rcExit = vbcppError(pThis, "Expected whitespace after macro name");
|
---|
| 3098 |
|
---|
| 3099 | /* Parse out the value. */
|
---|
| 3100 | if (rcExit == RTEXITCODE_SUCCESS)
|
---|
| 3101 | rcExit = vbcppProcessSkipWhiteEscapedEolAndComments(pThis, pStrmInput);
|
---|
| 3102 | if (rcExit == RTEXITCODE_SUCCESS)
|
---|
| 3103 | {
|
---|
| 3104 | size_t offValue = ScmStreamTell(pStrmInput);
|
---|
| 3105 | const char *pchValue = ScmStreamGetCur(pStrmInput);
|
---|
| 3106 | unsigned chPrev = ch;
|
---|
| 3107 | while ((ch = ScmStreamPeekCh(pStrmInput)) != ~(unsigned)0)
|
---|
| 3108 | {
|
---|
| 3109 | if (ch == '\r' || ch == '\n')
|
---|
| 3110 | {
|
---|
| 3111 | if (chPrev != '\\')
|
---|
| 3112 | break;
|
---|
| 3113 | ScmStreamSeekByLine(pStrmInput, ScmStreamTellLine(pStrmInput) + 1);
|
---|
| 3114 | }
|
---|
[41209] | 3115 | chPrev = ScmStreamGetCh(pStrmInput);
|
---|
[41195] | 3116 | }
|
---|
| 3117 | size_t cchValue = ScmStreamGetCur(pStrmInput) - pchValue;
|
---|
| 3118 |
|
---|
| 3119 | /*
|
---|
| 3120 | * Execute.
|
---|
| 3121 | */
|
---|
| 3122 | if (pchParams)
|
---|
[41226] | 3123 | rcExit = vbcppMacroAddFn(pThis, pchDefine, cchDefine, pchParams, cchParams, pchValue, cchValue, false);
|
---|
[41195] | 3124 | else
|
---|
[41226] | 3125 | rcExit = vbcppMacroAdd(pThis, pchDefine, cchDefine, pchValue, cchValue, false);
|
---|
[41195] | 3126 |
|
---|
| 3127 | /*
|
---|
| 3128 | * Pass thru?
|
---|
| 3129 | */
|
---|
[41202] | 3130 | if ( rcExit == RTEXITCODE_SUCCESS
|
---|
| 3131 | && pThis->fPassThruDefines)
|
---|
[41195] | 3132 | {
|
---|
| 3133 | unsigned cchIndent = pThis->pCondStack ? pThis->pCondStack->iKeepLevel : 0;
|
---|
[41246] | 3134 | ssize_t cch;
|
---|
[41195] | 3135 | if (pchParams)
|
---|
| 3136 | cch = ScmStreamPrintf(&pThis->StrmOutput, "#%*sdefine %.*s(%.*s)",
|
---|
| 3137 | cchIndent, "", cchDefine, pchDefine, cchParams, pchParams);
|
---|
| 3138 | else
|
---|
| 3139 | cch = ScmStreamPrintf(&pThis->StrmOutput, "#%*sdefine %.*s",
|
---|
| 3140 | cchIndent, "", cchDefine, pchDefine);
|
---|
| 3141 | if (cch > 0)
|
---|
| 3142 | vbcppOutputComment(pThis, pStrmInput, offValue, cch, 1);
|
---|
| 3143 | else
|
---|
| 3144 | rcExit = vbcppError(pThis, "output error");
|
---|
| 3145 | }
|
---|
[41246] | 3146 | else if ( rcExit == RTEXITCODE_SUCCESS
|
---|
| 3147 | && pThis->enmMode == kVBCppMode_SelectiveD)
|
---|
| 3148 | rcExit = vbcppMacroTryConvertToInlineD(pThis, vbcppMacroLookup(pThis, pchDefine, cchDefine));
|
---|
| 3149 | else
|
---|
| 3150 | pThis->fJustDroppedLine = true;
|
---|
[41195] | 3151 | }
|
---|
| 3152 | }
|
---|
| 3153 | }
|
---|
| 3154 | return rcExit;
|
---|
[41186] | 3155 | }
|
---|
| 3156 |
|
---|
| 3157 |
|
---|
| 3158 | /**
|
---|
| 3159 | * Processes a abbreviated line number directive.
|
---|
| 3160 | *
|
---|
| 3161 | * @returns RTEXITCODE_SUCCESS or RTEXITCODE_FAILURE+msg.
|
---|
| 3162 | * @param pThis The C preprocessor instance.
|
---|
| 3163 | * @param pStrmInput The input stream.
|
---|
| 3164 | * @param offStart The stream position where the directive
|
---|
| 3165 | * started (for pass thru).
|
---|
| 3166 | */
|
---|
[41226] | 3167 | static RTEXITCODE vbcppDirectiveUndef(PVBCPP pThis, PSCMSTREAM pStrmInput, size_t offStart)
|
---|
[41186] | 3168 | {
|
---|
[62594] | 3169 | RT_NOREF_PV(offStart);
|
---|
| 3170 |
|
---|
[41246] | 3171 | /*
|
---|
| 3172 | * Parse it.
|
---|
| 3173 | */
|
---|
| 3174 | RTEXITCODE rcExit = vbcppProcessSkipWhiteEscapedEolAndComments(pThis, pStrmInput);
|
---|
| 3175 | if (rcExit == RTEXITCODE_SUCCESS)
|
---|
| 3176 | {
|
---|
| 3177 | size_t cchDefine;
|
---|
| 3178 | const char *pchDefine = ScmStreamCGetWord(pStrmInput, &cchDefine);
|
---|
| 3179 | if (pchDefine)
|
---|
| 3180 | {
|
---|
| 3181 | size_t offMaybeComment = vbcppProcessSkipWhite(pStrmInput);
|
---|
| 3182 | rcExit = vbcppProcessSkipWhiteEscapedEolAndCommentsCheckEol(pThis, pStrmInput);
|
---|
| 3183 | if (rcExit == RTEXITCODE_SUCCESS)
|
---|
| 3184 | {
|
---|
| 3185 | /*
|
---|
| 3186 | * Take action.
|
---|
| 3187 | */
|
---|
[41297] | 3188 | PVBCPPMACRO pMacro = vbcppMacroLookup(pThis, pchDefine, cchDefine);
|
---|
[41246] | 3189 | if ( pMacro
|
---|
| 3190 | && pThis->fRespectSourceDefines
|
---|
| 3191 | && ( !pMacro->fCmdLine
|
---|
| 3192 | || pThis->fAllowRedefiningCmdLineDefines ) )
|
---|
| 3193 | {
|
---|
| 3194 | RTStrSpaceRemove(&pThis->StrSpace, pMacro->Core.pszString);
|
---|
| 3195 | vbcppMacroFree(&pMacro->Core, NULL);
|
---|
| 3196 | }
|
---|
| 3197 |
|
---|
| 3198 | /*
|
---|
| 3199 | * Pass thru.
|
---|
| 3200 | */
|
---|
| 3201 | if ( rcExit == RTEXITCODE_SUCCESS
|
---|
| 3202 | && pThis->fPassThruDefines)
|
---|
| 3203 | {
|
---|
| 3204 | unsigned cchIndent = pThis->pCondStack ? pThis->pCondStack->iKeepLevel : 0;
|
---|
| 3205 | ssize_t cch = ScmStreamPrintf(&pThis->StrmOutput, "#%*sundef %.*s",
|
---|
| 3206 | cchIndent, "", cchDefine, pchDefine);
|
---|
| 3207 | if (cch > 0)
|
---|
| 3208 | vbcppOutputComment(pThis, pStrmInput, offMaybeComment, cch, 1);
|
---|
| 3209 | else
|
---|
| 3210 | rcExit = vbcppError(pThis, "output error");
|
---|
| 3211 | }
|
---|
| 3212 |
|
---|
| 3213 | }
|
---|
| 3214 | }
|
---|
| 3215 | else
|
---|
| 3216 | rcExit = vbcppError(pThis, "Malformed #ifndef");
|
---|
| 3217 | }
|
---|
| 3218 | return rcExit;
|
---|
| 3219 |
|
---|
[41186] | 3220 | }
|
---|
| 3221 |
|
---|
| 3222 |
|
---|
[41204] | 3223 |
|
---|
| 3224 |
|
---|
| 3225 |
|
---|
| 3226 | /*
|
---|
| 3227 | *
|
---|
| 3228 | *
|
---|
| 3229 | * C O N D I T I O N A L S
|
---|
| 3230 | * C O N D I T I O N A L S
|
---|
| 3231 | * C O N D I T I O N A L S
|
---|
| 3232 | * C O N D I T I O N A L S
|
---|
| 3233 | * C O N D I T I O N A L S
|
---|
| 3234 | *
|
---|
| 3235 | *
|
---|
| 3236 | */
|
---|
| 3237 |
|
---|
| 3238 |
|
---|
[41202] | 3239 | /**
|
---|
| 3240 | * Combines current stack result with the one being pushed.
|
---|
| 3241 | *
|
---|
| 3242 | * @returns Combined result.
|
---|
| 3243 | * @param enmEvalPush The result of the condition being pushed.
|
---|
| 3244 | * @param enmEvalStack The current stack result.
|
---|
| 3245 | */
|
---|
| 3246 | static VBCPPEVAL vbcppCondCombine(VBCPPEVAL enmEvalPush, VBCPPEVAL enmEvalStack)
|
---|
[41186] | 3247 | {
|
---|
[41202] | 3248 | if (enmEvalStack == kVBCppEval_False)
|
---|
[41186] | 3249 | return kVBCppEval_False;
|
---|
| 3250 | return enmEvalPush;
|
---|
| 3251 | }
|
---|
| 3252 |
|
---|
| 3253 |
|
---|
[41202] | 3254 | /**
|
---|
| 3255 | * Pushes an conditional onto the stack.
|
---|
| 3256 | *
|
---|
| 3257 | * @returns RTEXITCODE_SUCCESS or RTEXITCODE_FAILURE+msg.
|
---|
| 3258 | * @param pThis The C preprocessor instance.
|
---|
| 3259 | * @param pStrmInput The current input stream.
|
---|
| 3260 | * @param offStart Not currently used, using @a pchCondition and
|
---|
| 3261 | * @a cchCondition instead.
|
---|
| 3262 | * @param enmKind The kind of conditional.
|
---|
| 3263 | * @param enmResult The result of the evaluation.
|
---|
| 3264 | * @param pchCondition The raw condition.
|
---|
| 3265 | * @param cchCondition The length of @a pchCondition.
|
---|
| 3266 | */
|
---|
[41186] | 3267 | static RTEXITCODE vbcppCondPush(PVBCPP pThis, PSCMSTREAM pStrmInput, size_t offStart,
|
---|
| 3268 | VBCPPCONDKIND enmKind, VBCPPEVAL enmResult,
|
---|
| 3269 | const char *pchCondition, size_t cchCondition)
|
---|
| 3270 | {
|
---|
[62594] | 3271 | RT_NOREF_PV(offStart); RT_NOREF_PV(pStrmInput);
|
---|
| 3272 |
|
---|
| 3273 |
|
---|
[41186] | 3274 | if (pThis->cCondStackDepth >= _64K)
|
---|
| 3275 | return vbcppError(pThis, "Too many nested #if/#ifdef/#ifndef statements");
|
---|
| 3276 |
|
---|
| 3277 | /*
|
---|
| 3278 | * Allocate a new entry and push it.
|
---|
[41179] | 3279 | */
|
---|
[41186] | 3280 | PVBCPPCOND pCond = (PVBCPPCOND)RTMemAlloc(sizeof(*pCond));
|
---|
| 3281 | if (!pCond)
|
---|
| 3282 | return vbcppError(pThis, "out of memory");
|
---|
| 3283 |
|
---|
| 3284 | PVBCPPCOND pUp = pThis->pCondStack;
|
---|
| 3285 | pCond->enmKind = enmKind;
|
---|
| 3286 | pCond->enmResult = enmResult;
|
---|
| 3287 | pCond->enmStackResult = pUp ? vbcppCondCombine(enmResult, pUp->enmStackResult) : enmResult;
|
---|
| 3288 | pCond->fSeenElse = false;
|
---|
[41263] | 3289 | pCond->fElIfDecided = enmResult == kVBCppEval_True;
|
---|
[41186] | 3290 | pCond->iLevel = pThis->cCondStackDepth;
|
---|
[100618] | 3291 | pCond->iKeepLevel = (pUp ? pUp->iKeepLevel : 0) + (enmResult == kVBCppEval_Undecided);
|
---|
[41186] | 3292 | pCond->pchCond = pchCondition;
|
---|
| 3293 | pCond->cchCond = cchCondition;
|
---|
| 3294 |
|
---|
| 3295 | pCond->pUp = pThis->pCondStack;
|
---|
| 3296 | pThis->pCondStack = pCond;
|
---|
| 3297 | pThis->fIf0Mode = pCond->enmStackResult == kVBCppEval_False;
|
---|
| 3298 |
|
---|
| 3299 | /*
|
---|
| 3300 | * Do pass thru.
|
---|
| 3301 | */
|
---|
| 3302 | if ( !pThis->fIf0Mode
|
---|
| 3303 | && enmResult == kVBCppEval_Undecided)
|
---|
[41179] | 3304 | {
|
---|
[41186] | 3305 | /** @todo this is stripping comments of \#ifdef and \#ifndef atm. */
|
---|
| 3306 | const char *pszDirective;
|
---|
| 3307 | switch (enmKind)
|
---|
[41179] | 3308 | {
|
---|
[41186] | 3309 | case kVBCppCondKind_If: pszDirective = "if"; break;
|
---|
| 3310 | case kVBCppCondKind_IfDef: pszDirective = "ifdef"; break;
|
---|
| 3311 | case kVBCppCondKind_IfNDef: pszDirective = "ifndef"; break;
|
---|
| 3312 | case kVBCppCondKind_ElIf: pszDirective = "elif"; break;
|
---|
| 3313 | default: AssertFailedReturn(RTEXITCODE_FAILURE);
|
---|
| 3314 | }
|
---|
| 3315 | ssize_t cch = ScmStreamPrintf(&pThis->StrmOutput, "#%*s%s %.*s",
|
---|
| 3316 | pCond->iKeepLevel - 1, "", pszDirective, cchCondition, pchCondition);
|
---|
| 3317 | if (cch < 0)
|
---|
| 3318 | return vbcppError(pThis, "Output error %Rrc", (int)cch);
|
---|
| 3319 | }
|
---|
[41217] | 3320 | else
|
---|
| 3321 | pThis->fJustDroppedLine = true;
|
---|
[41186] | 3322 |
|
---|
| 3323 | return RTEXITCODE_SUCCESS;
|
---|
| 3324 | }
|
---|
| 3325 |
|
---|
| 3326 |
|
---|
| 3327 | /**
|
---|
[41263] | 3328 | * Recursively destroys the expression tree.
|
---|
| 3329 | *
|
---|
| 3330 | * @param pExpr The root of the expression tree to destroy.
|
---|
| 3331 | */
|
---|
| 3332 | static void vbcppExprDestoryTree(PVBCPPEXPR pExpr)
|
---|
[41209] | 3333 | {
|
---|
[41263] | 3334 | if (!pExpr)
|
---|
| 3335 | return;
|
---|
[41209] | 3336 |
|
---|
[41263] | 3337 | switch (pExpr->enmKind)
|
---|
| 3338 | {
|
---|
| 3339 | case kVBCppExprKind_Unary:
|
---|
| 3340 | vbcppExprDestoryTree(pExpr->u.Unary.pArg);
|
---|
| 3341 | break;
|
---|
| 3342 | case kVBCppExprKind_Binary:
|
---|
| 3343 | vbcppExprDestoryTree(pExpr->u.Binary.pLeft);
|
---|
| 3344 | vbcppExprDestoryTree(pExpr->u.Binary.pRight);
|
---|
| 3345 | break;
|
---|
| 3346 | case kVBCppExprKind_Ternary:
|
---|
| 3347 | vbcppExprDestoryTree(pExpr->u.Ternary.pExpr);
|
---|
[100555] | 3348 | vbcppExprDestoryTree(pExpr->u.Ternary.pTrue);
|
---|
[41263] | 3349 | vbcppExprDestoryTree(pExpr->u.Ternary.pFalse);
|
---|
| 3350 | break;
|
---|
| 3351 | case kVBCppExprKind_SignedValue:
|
---|
| 3352 | case kVBCppExprKind_UnsignedValue:
|
---|
| 3353 | break;
|
---|
[100618] | 3354 | case kVBCppExprKind_UndefMacroCall:
|
---|
| 3355 | pExpr->u.UndefMacroCall.pszName = NULL;
|
---|
| 3356 | for (size_t i = 0; i < pExpr->u.UndefMacroCall.cArgs; i++)
|
---|
| 3357 | vbcppExprDestoryTree(pExpr->u.UndefMacroCall.papArgs[i]);
|
---|
| 3358 | RTMemFree(pExpr->u.UndefMacroCall.papArgs);
|
---|
| 3359 | RTMemFree(pExpr->u.UndefMacroCall.pszName);
|
---|
| 3360 | break;
|
---|
[41263] | 3361 | default:
|
---|
| 3362 | AssertFailed();
|
---|
| 3363 | return;
|
---|
| 3364 | }
|
---|
| 3365 | RTMemFree(pExpr);
|
---|
[41209] | 3366 | }
|
---|
| 3367 |
|
---|
| 3368 |
|
---|
[41266] | 3369 | /**
|
---|
| 3370 | * Report error during expression parsing.
|
---|
| 3371 | *
|
---|
| 3372 | * @returns kExprRet_Error
|
---|
| 3373 | * @param pParser The parser instance.
|
---|
| 3374 | * @param pszMsg The error message.
|
---|
| 3375 | * @param ... Format arguments.
|
---|
| 3376 | */
|
---|
| 3377 | static VBCPPEXPRRET vbcppExprParseError(PVBCPPEXPRPARSER pParser, const char *pszMsg, ...)
|
---|
[41263] | 3378 | {
|
---|
| 3379 | va_list va;
|
---|
| 3380 | va_start(va, pszMsg);
|
---|
| 3381 | vbcppErrorV(pParser->pThis, pszMsg, va);
|
---|
| 3382 | va_end(va);
|
---|
| 3383 | return kExprRet_Error;
|
---|
| 3384 | }
|
---|
[41209] | 3385 |
|
---|
[41263] | 3386 |
|
---|
[41266] | 3387 | /**
|
---|
| 3388 | * Skip white space.
|
---|
| 3389 | *
|
---|
| 3390 | * @param pParser The parser instance.
|
---|
| 3391 | */
|
---|
[41263] | 3392 | static void vbcppExprParseSkipWhiteSpace(PVBCPPEXPRPARSER pParser)
|
---|
[41209] | 3393 | {
|
---|
[41263] | 3394 | while (RT_C_IS_SPACE(*pParser->pszCur))
|
---|
| 3395 | pParser->pszCur++;
|
---|
| 3396 | }
|
---|
| 3397 |
|
---|
| 3398 |
|
---|
[41266] | 3399 | /**
|
---|
| 3400 | * Allocate a new
|
---|
| 3401 | *
|
---|
| 3402 | * @returns Pointer to the node. NULL+msg on failure.
|
---|
| 3403 | * @param pParser The parser instance.
|
---|
| 3404 | */
|
---|
[41263] | 3405 | static PVBCPPEXPR vbcppExprParseAllocNode(PVBCPPEXPRPARSER pParser)
|
---|
| 3406 | {
|
---|
| 3407 | PVBCPPEXPR pExpr = (PVBCPPEXPR)RTMemAllocZ(sizeof(*pExpr));
|
---|
[41266] | 3408 | if (!pExpr)
|
---|
| 3409 | vbcppExprParseError(pParser, "out of memory (expression node)");
|
---|
[41263] | 3410 | return pExpr;
|
---|
| 3411 | }
|
---|
| 3412 |
|
---|
| 3413 |
|
---|
[41266] | 3414 | /**
|
---|
[100618] | 3415 | * Checks if we're currently in an call to an undefined macro.
|
---|
[41266] | 3416 | *
|
---|
[100618] | 3417 | * This will walk up the expression chain and check for a call node while also
|
---|
| 3418 | * taking parenthesis nodes into account.
|
---|
| 3419 | *
|
---|
| 3420 | * @returns true if we are, false if we aren't.
|
---|
| 3421 | * @param pParser The parser instance.
|
---|
| 3422 | */
|
---|
| 3423 | static bool vbcppExprParseIsInUndefCall(PVBCPPEXPRPARSER pParser)
|
---|
| 3424 | {
|
---|
| 3425 | PVBCPPEXPR pExpr = pParser->pCur;
|
---|
| 3426 | while (pExpr)
|
---|
| 3427 | {
|
---|
| 3428 | if (pExpr->enmKind == kVBCppExprKind_UndefMacroCall)
|
---|
| 3429 | return true;
|
---|
| 3430 | if ( pExpr->enmKind == kVBCppExprKind_Unary
|
---|
| 3431 | && pExpr->u.Unary.enmOperator == kVBCppUnaryOp_Parenthesis)
|
---|
| 3432 | break;
|
---|
| 3433 | pExpr = pExpr->pParent;
|
---|
| 3434 | }
|
---|
| 3435 | return false;
|
---|
| 3436 | }
|
---|
| 3437 |
|
---|
| 3438 |
|
---|
| 3439 | /**
|
---|
| 3440 | * Looks for right parentheses, comma and/or end of expression.
|
---|
| 3441 | *
|
---|
| 3442 | * (The comma is only if we're in the context of a undefined macro call.)
|
---|
| 3443 | *
|
---|
[41266] | 3444 | * @returns Expression status.
|
---|
| 3445 | * @retval kExprRet_Ok
|
---|
| 3446 | * @retval kExprRet_Error with msg.
|
---|
| 3447 | * @retval kExprRet_EndOfExpr
|
---|
| 3448 | * @param pParser The parser instance.
|
---|
| 3449 | */
|
---|
| 3450 | static VBCPPEXPRRET vbcppExprParseMaybeRParenOrEoe(PVBCPPEXPRPARSER pParser)
|
---|
[41263] | 3451 | {
|
---|
| 3452 | Assert(!pParser->ppCur);
|
---|
| 3453 | for (;;)
|
---|
[41259] | 3454 | {
|
---|
[41263] | 3455 | vbcppExprParseSkipWhiteSpace(pParser);
|
---|
[100618] | 3456 | char const ch = *pParser->pszCur;
|
---|
[41263] | 3457 | if (ch == '\0')
|
---|
[100618] | 3458 | {
|
---|
| 3459 | /* Unwind making sure we don't have any incomplete parentheses or
|
---|
| 3460 | incomplete call expressions on the stack. */
|
---|
| 3461 | PVBCPPEXPR pCur = pParser->pCur;
|
---|
| 3462 | Assert(pCur);
|
---|
| 3463 | for (;;)
|
---|
| 3464 | {
|
---|
| 3465 | if (!pCur->fComplete)
|
---|
| 3466 | {
|
---|
| 3467 | if ( pCur->enmKind == kVBCppExprKind_Unary
|
---|
| 3468 | && pCur->u.Unary.enmOperator == kVBCppUnaryOp_Parenthesis)
|
---|
| 3469 | return vbcppExprParseError(pParser, "Missing right parenthesis");
|
---|
| 3470 | if (pCur->enmKind == kVBCppExprKind_UndefMacroCall)
|
---|
| 3471 | return vbcppExprParseError(pParser, "Missing right parenthesis for undefined macro call");
|
---|
| 3472 | }
|
---|
| 3473 | if (pCur->pParent)
|
---|
| 3474 | pCur = pCur->pParent;
|
---|
| 3475 | else
|
---|
| 3476 | {
|
---|
| 3477 | pParser->pCur = pCur;
|
---|
| 3478 | pParser->ppCur = NULL;
|
---|
| 3479 | return kExprRet_EndOfExpr;
|
---|
| 3480 | }
|
---|
| 3481 | }
|
---|
| 3482 | }
|
---|
| 3483 |
|
---|
| 3484 | if (ch != ')' && (ch != ',' || !vbcppExprParseIsInUndefCall(pParser))) /** @todo just immediate? */
|
---|
[41263] | 3485 | break;
|
---|
| 3486 | pParser->pszCur++;
|
---|
| 3487 |
|
---|
| 3488 | PVBCPPEXPR pCur = pParser->pCur;
|
---|
| 3489 | while ( pCur
|
---|
[100618] | 3490 | && ( pCur->enmKind != kVBCppExprKind_UndefMacroCall
|
---|
| 3491 | || pCur->fComplete /*?*/)
|
---|
[41263] | 3492 | && ( pCur->enmKind != kVBCppExprKind_Unary
|
---|
[100618] | 3493 | || pCur->u.Unary.enmOperator != kVBCppUnaryOp_Parenthesis
|
---|
| 3494 | || pCur->fComplete))
|
---|
[41259] | 3495 | {
|
---|
[41263] | 3496 | switch (pCur->enmKind)
|
---|
| 3497 | {
|
---|
| 3498 | case kVBCppExprKind_SignedValue:
|
---|
| 3499 | case kVBCppExprKind_UnsignedValue:
|
---|
| 3500 | Assert(pCur->fComplete);
|
---|
| 3501 | break;
|
---|
| 3502 | case kVBCppExprKind_Unary:
|
---|
[41266] | 3503 | AssertReturn(pCur->u.Unary.pArg, vbcppExprParseError(pParser, "internal error"));
|
---|
[41263] | 3504 | pCur->fComplete = true;
|
---|
| 3505 | break;
|
---|
| 3506 | case kVBCppExprKind_Binary:
|
---|
[41266] | 3507 | AssertReturn(pCur->u.Binary.pLeft, vbcppExprParseError(pParser, "internal error"));
|
---|
| 3508 | AssertReturn(pCur->u.Binary.pRight, vbcppExprParseError(pParser, "internal error"));
|
---|
[41263] | 3509 | pCur->fComplete = true;
|
---|
| 3510 | break;
|
---|
| 3511 | case kVBCppExprKind_Ternary:
|
---|
| 3512 | #if 1 /** @todo Check out the ternary operator implementation. */
|
---|
[41266] | 3513 | return vbcppExprParseError(pParser, "The ternary operator is not implemented");
|
---|
[41263] | 3514 | #else
|
---|
| 3515 | Assert(pCur->u.Ternary.pExpr);
|
---|
| 3516 | if (!pCur->u.Ternary.pTrue)
|
---|
[41266] | 3517 | return vbcppExprParseError(pParser, "?!?!?");
|
---|
[41263] | 3518 | if (!pCur->u.Ternary.pFalse)
|
---|
[41266] | 3519 | return vbcppExprParseError(pParser, "?!?!?!?");
|
---|
[41263] | 3520 | pCur->fComplete = true;
|
---|
| 3521 | #endif
|
---|
| 3522 | break;
|
---|
[100618] | 3523 | case kVBCppExprKind_UndefMacroCall:
|
---|
| 3524 | break;
|
---|
[41263] | 3525 | default:
|
---|
[41266] | 3526 | return vbcppExprParseError(pParser, "Internal error (enmKind=%d)", pCur->enmKind);
|
---|
[41263] | 3527 | }
|
---|
| 3528 | pCur = pCur->pParent;
|
---|
| 3529 | }
|
---|
| 3530 | if (!pCur)
|
---|
[41266] | 3531 | return vbcppExprParseError(pParser, "Right parenthesis without a left one");
|
---|
[41263] | 3532 |
|
---|
[100618] | 3533 | /*
|
---|
| 3534 | * If we got down to an undefined macro call, we make it the current
|
---|
| 3535 | * parser expression and return EndOfExpr. The call expression is
|
---|
| 3536 | * completed if we hit a ')'.
|
---|
| 3537 | */
|
---|
| 3538 | if (pCur->enmKind == kVBCppExprKind_UndefMacroCall)
|
---|
[41263] | 3539 | {
|
---|
[100618] | 3540 | pCur->fComplete = ch == ')';
|
---|
| 3541 | pParser->pCur = pCur;
|
---|
| 3542 | pParser->ppCur = NULL;
|
---|
| 3543 | return kExprRet_EndOfExpr;
|
---|
[41263] | 3544 | }
|
---|
[100618] | 3545 |
|
---|
| 3546 | /*
|
---|
| 3547 | * Complete the parenthesis expression and make it current.
|
---|
| 3548 | */
|
---|
| 3549 | Assert( pCur->enmKind == kVBCppExprKind_Unary
|
---|
| 3550 | && pCur->u.Unary.enmOperator == kVBCppUnaryOp_Parenthesis);
|
---|
| 3551 | AssertReturn(pCur->u.Unary.pArg, vbcppExprParseError(pParser, "internal error"));
|
---|
| 3552 | pCur->fComplete = true;
|
---|
| 3553 | pParser->pCur = pCur;
|
---|
| 3554 | pParser->ppCur = NULL;
|
---|
[41263] | 3555 | }
|
---|
| 3556 |
|
---|
[41266] | 3557 | return kExprRet_Ok;
|
---|
| 3558 | }
|
---|
| 3559 |
|
---|
| 3560 |
|
---|
| 3561 | /**
|
---|
| 3562 | * Parses an binary operator.
|
---|
| 3563 | *
|
---|
| 3564 | * @returns Expression status.
|
---|
| 3565 | * @retval kExprRet_Ok
|
---|
| 3566 | * @retval kExprRet_Error with msg.
|
---|
| 3567 | * @param pParser The parser instance.
|
---|
| 3568 | */
|
---|
| 3569 | static VBCPPEXPRRET vbcppExprParseBinaryOperator(PVBCPPEXPRPARSER pParser)
|
---|
| 3570 | {
|
---|
[41263] | 3571 | /*
|
---|
| 3572 | * Binary or ternary operator should follow now.
|
---|
| 3573 | */
|
---|
| 3574 | VBCPPBINARYOP enmOp;
|
---|
[41266] | 3575 | char ch = *pParser->pszCur;
|
---|
[41263] | 3576 | switch (ch)
|
---|
| 3577 | {
|
---|
| 3578 | case '*':
|
---|
| 3579 | if (pParser->pszCur[1] == '=')
|
---|
[41266] | 3580 | return vbcppExprParseError(pParser, "The assignment by product operator is not valid in a preprocessor expression");
|
---|
[41263] | 3581 | enmOp = kVBCppBinary_Multiplication;
|
---|
| 3582 | break;
|
---|
| 3583 | case '/':
|
---|
| 3584 | if (pParser->pszCur[1] == '=')
|
---|
[41266] | 3585 | return vbcppExprParseError(pParser, "The assignment by quotient operator is not valid in a preprocessor expression");
|
---|
[41263] | 3586 | enmOp = kVBCppBinary_Division;
|
---|
| 3587 | break;
|
---|
| 3588 | case '%':
|
---|
| 3589 | if (pParser->pszCur[1] == '=')
|
---|
[41266] | 3590 | return vbcppExprParseError(pParser, "The assignment by remainder operator is not valid in a preprocessor expression");
|
---|
[41263] | 3591 | enmOp = kVBCppBinary_Modulo;
|
---|
| 3592 | break;
|
---|
| 3593 | case '+':
|
---|
| 3594 | if (pParser->pszCur[1] == '=')
|
---|
[41266] | 3595 | return vbcppExprParseError(pParser, "The assignment by sum operator is not valid in a preprocessor expression");
|
---|
[41263] | 3596 | enmOp = kVBCppBinary_Addition;
|
---|
| 3597 | break;
|
---|
| 3598 | case '-':
|
---|
| 3599 | if (pParser->pszCur[1] == '=')
|
---|
[41266] | 3600 | return vbcppExprParseError(pParser, "The assignment by difference operator is not valid in a preprocessor expression");
|
---|
[41263] | 3601 | enmOp = kVBCppBinary_Subtraction;
|
---|
| 3602 | break;
|
---|
| 3603 | case '<':
|
---|
| 3604 | enmOp = kVBCppBinary_LessThan;
|
---|
| 3605 | if (pParser->pszCur[1] == '=')
|
---|
| 3606 | {
|
---|
| 3607 | pParser->pszCur++;
|
---|
| 3608 | enmOp = kVBCppBinary_LessThanOrEqual;
|
---|
| 3609 | }
|
---|
| 3610 | else if (pParser->pszCur[1] == '<')
|
---|
| 3611 | {
|
---|
| 3612 | pParser->pszCur++;
|
---|
| 3613 | if (pParser->pszCur[1] == '=')
|
---|
[41266] | 3614 | return vbcppExprParseError(pParser, "The assignment by bitwise left shift operator is not valid in a preprocessor expression");
|
---|
[41263] | 3615 | enmOp = kVBCppBinary_LeftShift;
|
---|
| 3616 | }
|
---|
| 3617 | break;
|
---|
| 3618 | case '>':
|
---|
[62450] | 3619 | enmOp = kVBCppBinary_GreaterThan;
|
---|
[41263] | 3620 | if (pParser->pszCur[1] == '=')
|
---|
| 3621 | {
|
---|
| 3622 | pParser->pszCur++;
|
---|
| 3623 | enmOp = kVBCppBinary_GreaterThanOrEqual;
|
---|
| 3624 | }
|
---|
| 3625 | else if (pParser->pszCur[1] == '<')
|
---|
| 3626 | {
|
---|
| 3627 | pParser->pszCur++;
|
---|
| 3628 | if (pParser->pszCur[1] == '=')
|
---|
[41266] | 3629 | return vbcppExprParseError(pParser, "The assignment by bitwise right shift operator is not valid in a preprocessor expression");
|
---|
[41263] | 3630 | enmOp = kVBCppBinary_LeftShift;
|
---|
| 3631 | }
|
---|
| 3632 | break;
|
---|
| 3633 | case '=':
|
---|
| 3634 | if (pParser->pszCur[1] != '=')
|
---|
[41266] | 3635 | return vbcppExprParseError(pParser, "The assignment operator is not valid in a preprocessor expression");
|
---|
[41263] | 3636 | pParser->pszCur++;
|
---|
| 3637 | enmOp = kVBCppBinary_EqualTo;
|
---|
| 3638 | break;
|
---|
| 3639 |
|
---|
| 3640 | case '!':
|
---|
| 3641 | if (pParser->pszCur[1] != '=')
|
---|
[41266] | 3642 | return vbcppExprParseError(pParser, "Expected binary operator, found the unary operator logical NOT");
|
---|
[41263] | 3643 | pParser->pszCur++;
|
---|
| 3644 | enmOp = kVBCppBinary_NotEqualTo;
|
---|
| 3645 | break;
|
---|
| 3646 |
|
---|
| 3647 | case '&':
|
---|
| 3648 | if (pParser->pszCur[1] == '=')
|
---|
[41266] | 3649 | return vbcppExprParseError(pParser, "The assignment by bitwise AND operator is not valid in a preprocessor expression");
|
---|
[41263] | 3650 | if (pParser->pszCur[1] == '&')
|
---|
| 3651 | {
|
---|
| 3652 | pParser->pszCur++;
|
---|
| 3653 | enmOp = kVBCppBinary_LogicalAnd;
|
---|
| 3654 | }
|
---|
[41259] | 3655 | else
|
---|
[41263] | 3656 | enmOp = kVBCppBinary_BitwiseAnd;
|
---|
| 3657 | break;
|
---|
| 3658 | case '^':
|
---|
| 3659 | if (pParser->pszCur[1] == '=')
|
---|
[41266] | 3660 | return vbcppExprParseError(pParser, "The assignment by bitwise XOR operator is not valid in a preprocessor expression");
|
---|
[41263] | 3661 | enmOp = kVBCppBinary_BitwiseXor;
|
---|
| 3662 | break;
|
---|
| 3663 | case '|':
|
---|
| 3664 | if (pParser->pszCur[1] == '=')
|
---|
[41266] | 3665 | return vbcppExprParseError(pParser, "The assignment by bitwise AND operator is not valid in a preprocessor expression");
|
---|
[41263] | 3666 | if (pParser->pszCur[1] == '|')
|
---|
| 3667 | {
|
---|
| 3668 | pParser->pszCur++;
|
---|
| 3669 | enmOp = kVBCppBinary_LogicalOr;
|
---|
| 3670 | }
|
---|
| 3671 | else
|
---|
| 3672 | enmOp = kVBCppBinary_BitwiseOr;
|
---|
| 3673 | break;
|
---|
| 3674 | case '~':
|
---|
[41266] | 3675 | return vbcppExprParseError(pParser, "Expected binary operator, found the unary operator bitwise NOT");
|
---|
[41263] | 3676 |
|
---|
| 3677 | case ':':
|
---|
| 3678 | case '?':
|
---|
[41266] | 3679 | return vbcppExprParseError(pParser, "The ternary operator is not yet implemented");
|
---|
[41263] | 3680 |
|
---|
| 3681 | default:
|
---|
[41266] | 3682 | return vbcppExprParseError(pParser, "Expected binary operator, found '%.20s'", pParser->pszCur);
|
---|
[41263] | 3683 | }
|
---|
| 3684 | pParser->pszCur++;
|
---|
| 3685 |
|
---|
| 3686 | /*
|
---|
| 3687 | * Create a binary operator node.
|
---|
| 3688 | */
|
---|
| 3689 | PVBCPPEXPR pExpr = vbcppExprParseAllocNode(pParser);
|
---|
| 3690 | if (!pExpr)
|
---|
| 3691 | return kExprRet_Error;
|
---|
| 3692 | pExpr->fComplete = true;
|
---|
| 3693 | pExpr->enmKind = kVBCppExprKind_Binary;
|
---|
| 3694 | pExpr->u.Binary.enmOperator = enmOp;
|
---|
| 3695 | pExpr->u.Binary.pLeft = NULL;
|
---|
| 3696 | pExpr->u.Binary.pRight = NULL;
|
---|
| 3697 |
|
---|
| 3698 | /*
|
---|
| 3699 | * Back up the tree until we find our spot.
|
---|
| 3700 | */
|
---|
| 3701 | PVBCPPEXPR *ppPlace = NULL;
|
---|
[100618] | 3702 | PVBCPPEXPR pChild = pParser->pCur;
|
---|
| 3703 | PVBCPPEXPR pParent = pChild->pParent;
|
---|
[41263] | 3704 | while (pParent)
|
---|
| 3705 | {
|
---|
| 3706 | if (pParent->enmKind == kVBCppExprKind_Unary)
|
---|
| 3707 | {
|
---|
| 3708 | if (pParent->u.Unary.enmOperator == kVBCppUnaryOp_Parenthesis)
|
---|
| 3709 | {
|
---|
| 3710 | ppPlace = &pParent->u.Unary.pArg;
|
---|
| 3711 | break;
|
---|
| 3712 | }
|
---|
[41266] | 3713 | AssertReturn(pParent->u.Unary.pArg, vbcppExprParseError(pParser, "internal error"));
|
---|
[41263] | 3714 | pParent->fComplete = true;
|
---|
[41259] | 3715 | }
|
---|
[41263] | 3716 | else if (pParent->enmKind == kVBCppExprKind_Binary)
|
---|
| 3717 | {
|
---|
[41266] | 3718 | AssertReturn(pParent->u.Binary.pLeft, vbcppExprParseError(pParser, "internal error"));
|
---|
| 3719 | AssertReturn(pParent->u.Binary.pRight, vbcppExprParseError(pParser, "internal error"));
|
---|
[41263] | 3720 | if ((pParent->u.Binary.enmOperator & VBCPPOP_PRECEDENCE_MASK) >= (enmOp & VBCPPOP_PRECEDENCE_MASK))
|
---|
| 3721 | {
|
---|
[41266] | 3722 | AssertReturn(pChild, vbcppExprParseError(pParser, "internal error"));
|
---|
[41263] | 3723 |
|
---|
| 3724 | if (pParent->u.Binary.pRight == pChild)
|
---|
| 3725 | ppPlace = &pParent->u.Binary.pRight;
|
---|
| 3726 | else
|
---|
| 3727 | ppPlace = &pParent->u.Binary.pLeft;
|
---|
[41266] | 3728 | AssertReturn(*ppPlace == pChild, vbcppExprParseError(pParser, "internal error"));
|
---|
[41263] | 3729 | break;
|
---|
| 3730 | }
|
---|
| 3731 | pParent->fComplete = true;
|
---|
| 3732 | }
|
---|
| 3733 | else if (pParent->enmKind == kVBCppExprKind_Ternary)
|
---|
| 3734 | {
|
---|
[41266] | 3735 | return vbcppExprParseError(pParser, "The ternary operator is not implemented");
|
---|
[41263] | 3736 | }
|
---|
[100618] | 3737 | else if (pParent->enmKind == kVBCppExprKind_UndefMacroCall)
|
---|
| 3738 | {
|
---|
| 3739 | ppPlace = &pParent->u.UndefMacroCall.papArgs[pParent->u.UndefMacroCall.cArgs];
|
---|
| 3740 | break;
|
---|
| 3741 | }
|
---|
[41259] | 3742 | else
|
---|
[41263] | 3743 | AssertReturn( pParent->enmKind == kVBCppExprKind_SignedValue
|
---|
| 3744 | || pParent->enmKind == kVBCppExprKind_UnsignedValue,
|
---|
[41266] | 3745 | vbcppExprParseError(pParser, "internal error"));
|
---|
[41263] | 3746 |
|
---|
| 3747 | /* Up on level */
|
---|
| 3748 | pChild = pParent;
|
---|
| 3749 | pParent = pParent->pParent;
|
---|
[41259] | 3750 | }
|
---|
[41263] | 3751 |
|
---|
| 3752 | /*
|
---|
| 3753 | * Do the rotation.
|
---|
| 3754 | */
|
---|
| 3755 | Assert(pChild);
|
---|
| 3756 | Assert(pChild->pParent == pParent);
|
---|
| 3757 | pChild->pParent = pExpr;
|
---|
| 3758 |
|
---|
| 3759 | pExpr->u.Binary.pLeft = pChild;
|
---|
| 3760 | pExpr->pParent = pParent;
|
---|
| 3761 |
|
---|
| 3762 | if (!pParent)
|
---|
| 3763 | pParser->pRoot = pExpr;
|
---|
| 3764 | else
|
---|
| 3765 | *ppPlace = pExpr;
|
---|
| 3766 |
|
---|
| 3767 | pParser->ppCur = &pExpr->u.Binary.pRight;
|
---|
| 3768 | pParser->pCur = pExpr;
|
---|
| 3769 |
|
---|
| 3770 | return kExprRet_Ok;
|
---|
| 3771 | }
|
---|
| 3772 |
|
---|
| 3773 |
|
---|
[41266] | 3774 | /**
|
---|
| 3775 | * Deals with right paretheses or/and end of expression, looks for binary
|
---|
| 3776 | * operators.
|
---|
| 3777 | *
|
---|
| 3778 | * @returns Expression status.
|
---|
| 3779 | * @retval kExprRet_Ok if binary operator was found processed.
|
---|
| 3780 | * @retval kExprRet_Error with msg.
|
---|
| 3781 | * @retval kExprRet_EndOfExpr
|
---|
| 3782 | * @param pParser The parser instance.
|
---|
| 3783 | */
|
---|
| 3784 | static VBCPPEXPRRET vbcppExprParseBinaryOrEoeOrRparen(PVBCPPEXPRPARSER pParser)
|
---|
| 3785 | {
|
---|
| 3786 | VBCPPEXPRRET enmRet = vbcppExprParseMaybeRParenOrEoe(pParser);
|
---|
| 3787 | if (enmRet != kExprRet_Ok)
|
---|
| 3788 | return enmRet;
|
---|
| 3789 | return vbcppExprParseBinaryOperator(pParser);
|
---|
| 3790 | }
|
---|
| 3791 |
|
---|
| 3792 |
|
---|
| 3793 | /**
|
---|
[100618] | 3794 | * Worker for vbcppExprParseIdentifier that parses a call to an undefined macro
|
---|
| 3795 | * in selective mode.
|
---|
| 3796 | *
|
---|
| 3797 | * @returns Expression status.
|
---|
| 3798 | * @retval kExprRet_Ok if binary operator was found processed.
|
---|
| 3799 | * @retval kExprRet_Error with msg.
|
---|
| 3800 | * @retval kExprRet_EndOfExpr
|
---|
| 3801 | * @param pParser The parser instance.
|
---|
| 3802 | * @param pszMacro The start of the macro name.
|
---|
| 3803 | * @param cchMacro The length of the macro name.
|
---|
| 3804 | */
|
---|
| 3805 | static VBCPPEXPRRET vbcppExprParseUndefMacroCall(PVBCPPEXPRPARSER pParser, const char *pszMacro, size_t cchMacro)
|
---|
| 3806 | {
|
---|
| 3807 | /*
|
---|
| 3808 | * Treat it as a call to an undefined macro function.
|
---|
| 3809 | */
|
---|
| 3810 | /* Create a node. */
|
---|
| 3811 | PVBCPPEXPR const pExpr = vbcppExprParseAllocNode(pParser);
|
---|
| 3812 | if (!pExpr)
|
---|
| 3813 | return kExprRet_Error;
|
---|
| 3814 | pExpr->enmKind = kVBCppExprKind_UndefMacroCall;
|
---|
| 3815 | pExpr->fComplete = false;
|
---|
| 3816 | pExpr->u.UndefMacroCall.cArgs = 0;
|
---|
| 3817 | pExpr->u.UndefMacroCall.papArgs = NULL;
|
---|
| 3818 | pExpr->u.UndefMacroCall.pszName = RTStrDupN(pszMacro, cchMacro);
|
---|
| 3819 | AssertReturn(pExpr->u.UndefMacroCall.pszName, vbcppExprParseError(pParser, "out of memory"));
|
---|
| 3820 |
|
---|
| 3821 | /* Link it. */
|
---|
| 3822 | pExpr->pParent = pParser->pCur;
|
---|
| 3823 | pParser->pCur = pExpr;
|
---|
| 3824 | *pParser->ppCur = pExpr;
|
---|
| 3825 | pParser->ppCur = NULL;
|
---|
| 3826 |
|
---|
| 3827 | /*
|
---|
| 3828 | * Parse the argument list.
|
---|
| 3829 | */
|
---|
| 3830 | pParser->pszCur++;
|
---|
| 3831 | for (size_t iArg = 0 ; ; iArg++)
|
---|
| 3832 | {
|
---|
| 3833 | /*
|
---|
| 3834 | * Prepare the next argument expression pointer.
|
---|
| 3835 | */
|
---|
| 3836 | if (!(iArg % 16))
|
---|
| 3837 | {
|
---|
| 3838 | void *pvNew = RTMemRealloc(pExpr->u.UndefMacroCall.papArgs,
|
---|
| 3839 | sizeof(pExpr->u.UndefMacroCall.papArgs[0]) * (iArg + 16));
|
---|
| 3840 | AssertPtrReturn(pvNew, vbcppExprParseError(pParser, "out of memory"));
|
---|
| 3841 | pExpr->u.UndefMacroCall.papArgs = (PVBCPPEXPR *)pvNew;
|
---|
| 3842 | }
|
---|
| 3843 | pExpr->u.UndefMacroCall.papArgs[iArg] = NULL;
|
---|
| 3844 | pParser->ppCur = &pExpr->u.UndefMacroCall.papArgs[iArg];
|
---|
| 3845 |
|
---|
| 3846 | /*
|
---|
| 3847 | * Do the parsing.
|
---|
| 3848 | */
|
---|
| 3849 | for (;;)
|
---|
| 3850 | {
|
---|
| 3851 | /*
|
---|
| 3852 | * Eat unary operators until we hit a value or end of argument/call.
|
---|
| 3853 | */
|
---|
| 3854 | VBCPPEXPRRET enmRet;
|
---|
| 3855 | do
|
---|
| 3856 | enmRet = vbcppExprParseUnaryOrValue(pParser);
|
---|
| 3857 | while (enmRet == kExprRet_UnaryOperator);
|
---|
| 3858 | if (enmRet == kExprRet_EndOfExpr)
|
---|
| 3859 | break;
|
---|
| 3860 | if (enmRet == kExprRet_Error)
|
---|
| 3861 | return enmRet;
|
---|
| 3862 | AssertReturn(enmRet == kExprRet_Value, vbcppExprParseError(pParser, "Expected value (enmRet=%d)", enmRet));
|
---|
| 3863 |
|
---|
| 3864 | /*
|
---|
| 3865 | * Non-unary operator, right parenthesis or end of argument/call is up next.
|
---|
| 3866 | */
|
---|
| 3867 | enmRet = vbcppExprParseBinaryOrEoeOrRparen(pParser);
|
---|
| 3868 | if (enmRet == kExprRet_EndOfExpr)
|
---|
| 3869 | break;
|
---|
| 3870 | if (enmRet == kExprRet_Error)
|
---|
| 3871 | return enmRet;
|
---|
| 3872 | AssertReturn(enmRet == kExprRet_Ok, vbcppExprParseError(pParser, "Expected value (enmRet=%d)", enmRet));
|
---|
| 3873 | }
|
---|
| 3874 |
|
---|
| 3875 | /*
|
---|
| 3876 | * Append the argument and skip past the comma or right parenthesis.
|
---|
| 3877 | */
|
---|
| 3878 | if (pExpr->u.UndefMacroCall.papArgs[iArg] != NULL || !pExpr->fComplete)
|
---|
| 3879 | pExpr->u.UndefMacroCall.cArgs = iArg + 1;
|
---|
| 3880 |
|
---|
| 3881 | Assert(pParser->pCur == pExpr);
|
---|
| 3882 | if (pExpr->fComplete)
|
---|
| 3883 | break;
|
---|
| 3884 | }
|
---|
| 3885 |
|
---|
| 3886 | pParser->ppCur = NULL;
|
---|
| 3887 | return kExprRet_Value;
|
---|
| 3888 | }
|
---|
| 3889 |
|
---|
| 3890 |
|
---|
| 3891 | /**
|
---|
[41266] | 3892 | * Parses an identifier in the expression, replacing it by 0.
|
---|
| 3893 | *
|
---|
| 3894 | * All known identifiers has already been replaced by their macro values, so
|
---|
| 3895 | * what's left are unknown macros. These are replaced by 0.
|
---|
| 3896 | *
|
---|
| 3897 | * @returns Expression status.
|
---|
| 3898 | * @retval kExprRet_Value
|
---|
| 3899 | * @retval kExprRet_Error with msg.
|
---|
| 3900 | * @param pParser The parser instance.
|
---|
| 3901 | */
|
---|
[41263] | 3902 | static VBCPPEXPRRET vbcppExprParseIdentifier(PVBCPPEXPRPARSER pParser)
|
---|
| 3903 | {
|
---|
[41266] | 3904 | /** @todo don't increment if it's an actively undefined macro. Need to revise
|
---|
| 3905 | * the expression related code wrt selective preprocessing. */
|
---|
[41263] | 3906 | pParser->cUndefined++;
|
---|
| 3907 |
|
---|
| 3908 | /* Find the end. */
|
---|
| 3909 | const char *pszMacro = pParser->pszCur;
|
---|
| 3910 | const char *pszNext = pszMacro + 1;
|
---|
| 3911 | while (vbcppIsCIdentifierChar(*pszNext))
|
---|
| 3912 | pszNext++;
|
---|
[100618] | 3913 | size_t const cchMacro = pszNext - pszMacro;
|
---|
[41263] | 3914 |
|
---|
[100618] | 3915 | /* Skip spaces and check for parenthesis. */
|
---|
| 3916 | pParser->pszCur = pszNext;
|
---|
| 3917 | vbcppExprParseSkipWhiteSpace(pParser);
|
---|
| 3918 | if (*pParser->pszCur == '(')
|
---|
| 3919 | {
|
---|
| 3920 | if (pParser->pThis->enmMode == kVBCppMode_Selective)
|
---|
| 3921 | return vbcppExprParseUndefMacroCall(pParser, pszMacro, cchMacro);
|
---|
| 3922 | return vbcppExprParseError(pParser, "%sUnknown unary operator '%.*s'",
|
---|
| 3923 | pParser->pThis->enmMode != kVBCppMode_Standard ? "TODO selective: " : "",
|
---|
| 3924 | cchMacro, pszMacro);
|
---|
| 3925 | }
|
---|
| 3926 |
|
---|
[41263] | 3927 | /* Create a signed value node. */
|
---|
| 3928 | PVBCPPEXPR pExpr = vbcppExprParseAllocNode(pParser);
|
---|
| 3929 | if (!pExpr)
|
---|
| 3930 | return kExprRet_Error;
|
---|
| 3931 | pExpr->fComplete = true;
|
---|
| 3932 | pExpr->enmKind = kVBCppExprKind_UnsignedValue;
|
---|
| 3933 | pExpr->u.UnsignedValue.u64 = 0;
|
---|
| 3934 |
|
---|
| 3935 | /* Link it. */
|
---|
| 3936 | pExpr->pParent = pParser->pCur;
|
---|
| 3937 | pParser->pCur = pExpr;
|
---|
| 3938 | *pParser->ppCur = pExpr;
|
---|
| 3939 | pParser->ppCur = NULL;
|
---|
| 3940 |
|
---|
| 3941 | return kExprRet_Value;
|
---|
| 3942 | }
|
---|
| 3943 |
|
---|
| 3944 |
|
---|
[41266] | 3945 | /**
|
---|
| 3946 | * Parses an numeric constant in the expression.
|
---|
| 3947 | *
|
---|
| 3948 | * @returns Expression status.
|
---|
| 3949 | * @retval kExprRet_Value
|
---|
| 3950 | * @retval kExprRet_Error with msg.
|
---|
| 3951 | * @param pParser The parser instance.
|
---|
| 3952 | */
|
---|
[41263] | 3953 | static VBCPPEXPRRET vbcppExprParseNumber(PVBCPPEXPRPARSER pParser)
|
---|
| 3954 | {
|
---|
| 3955 | bool fSigned;
|
---|
| 3956 | char *pszNext;
|
---|
| 3957 | uint64_t u64;
|
---|
| 3958 | char ch = *pParser->pszCur++;
|
---|
| 3959 | char ch2 = *pParser->pszCur;
|
---|
| 3960 | if ( ch == '0'
|
---|
[103384] | 3961 | && (ch2 == 'x' || ch2 == 'X'))
|
---|
[41259] | 3962 | {
|
---|
[41263] | 3963 | ch2 = *++pParser->pszCur;
|
---|
| 3964 | if (!RT_C_IS_XDIGIT(ch2))
|
---|
[41266] | 3965 | return vbcppExprParseError(pParser, "Expected hex digit following '0x'");
|
---|
[41263] | 3966 | int rc = RTStrToUInt64Ex(pParser->pszCur, &pszNext, 16, &u64);
|
---|
| 3967 | if ( RT_FAILURE(rc)
|
---|
| 3968 | || rc == VWRN_NUMBER_TOO_BIG)
|
---|
[41266] | 3969 | return vbcppExprParseError(pParser, "Invalid hex value '%.20s...' (%Rrc)", pParser->pszCur, rc);
|
---|
[41263] | 3970 | fSigned = false;
|
---|
[41259] | 3971 | }
|
---|
[41263] | 3972 | else if (ch == '0')
|
---|
[41259] | 3973 | {
|
---|
[41263] | 3974 | int rc = RTStrToUInt64Ex(pParser->pszCur - 1, &pszNext, 8, &u64);
|
---|
| 3975 | if ( RT_FAILURE(rc)
|
---|
| 3976 | || rc == VWRN_NUMBER_TOO_BIG)
|
---|
[41266] | 3977 | return vbcppExprParseError(pParser, "Invalid octal value '%.20s...' (%Rrc)", pParser->pszCur, rc);
|
---|
[41263] | 3978 | fSigned = u64 > (uint64_t)INT64_MAX ? false : true;
|
---|
[41259] | 3979 | }
|
---|
[41263] | 3980 | else
|
---|
[41259] | 3981 | {
|
---|
[41263] | 3982 | int rc = RTStrToUInt64Ex(pParser->pszCur - 1, &pszNext, 10, &u64);
|
---|
| 3983 | if ( RT_FAILURE(rc)
|
---|
| 3984 | || rc == VWRN_NUMBER_TOO_BIG)
|
---|
[41266] | 3985 | return vbcppExprParseError(pParser, "Invalid decimal value '%.20s...' (%Rrc)", pParser->pszCur, rc);
|
---|
[41263] | 3986 | fSigned = u64 > (uint64_t)INT64_MAX ? false : true;
|
---|
| 3987 | }
|
---|
| 3988 |
|
---|
| 3989 | /* suffix. */
|
---|
| 3990 | if (vbcppIsCIdentifierLeadChar(*pszNext))
|
---|
| 3991 | {
|
---|
| 3992 | size_t cchSuffix = 1;
|
---|
| 3993 | while (vbcppIsCIdentifierLeadChar(pszNext[cchSuffix]))
|
---|
| 3994 | cchSuffix++;
|
---|
| 3995 |
|
---|
[100618] | 3996 | if (cchSuffix == 1 && (*pszNext == 'u' || *pszNext == 'U'))
|
---|
[41263] | 3997 | fSigned = false;
|
---|
[100618] | 3998 | else if ( cchSuffix == 1
|
---|
[41263] | 3999 | && (*pszNext == 'l' || *pszNext == 'L'))
|
---|
| 4000 | fSigned = true;
|
---|
[100618] | 4001 | else if ( cchSuffix == 2
|
---|
[41263] | 4002 | && (!strncmp(pszNext, "ul", 2) || !strncmp(pszNext, "UL", 2)))
|
---|
| 4003 | fSigned = false;
|
---|
[100618] | 4004 | else if ( cchSuffix == 2
|
---|
[41263] | 4005 | && (!strncmp(pszNext, "ll", 2) || !strncmp(pszNext, "LL", 2)))
|
---|
| 4006 | fSigned = true;
|
---|
[100618] | 4007 | else if ( cchSuffix == 3
|
---|
[41263] | 4008 | && (!strncmp(pszNext, "ull", 3) || !strncmp(pszNext, "ULL", 3)))
|
---|
| 4009 | fSigned = false;
|
---|
[41259] | 4010 | else
|
---|
[41266] | 4011 | return vbcppExprParseError(pParser, "Invalid number suffix '%.*s'", cchSuffix, pszNext);
|
---|
[41263] | 4012 |
|
---|
| 4013 | pszNext += cchSuffix;
|
---|
[41259] | 4014 | }
|
---|
[41263] | 4015 | pParser->pszCur = pszNext;
|
---|
| 4016 |
|
---|
| 4017 | /* Create a signed value node. */
|
---|
| 4018 | PVBCPPEXPR pExpr = vbcppExprParseAllocNode(pParser);
|
---|
| 4019 | if (!pExpr)
|
---|
| 4020 | return kExprRet_Error;
|
---|
| 4021 | pExpr->fComplete = true;
|
---|
| 4022 | if (fSigned)
|
---|
| 4023 | {
|
---|
| 4024 | pExpr->enmKind = kVBCppExprKind_SignedValue;
|
---|
| 4025 | pExpr->u.SignedValue.s64 = (int64_t)u64;
|
---|
| 4026 | }
|
---|
[41209] | 4027 | else
|
---|
[41263] | 4028 | {
|
---|
| 4029 | pExpr->enmKind = kVBCppExprKind_UnsignedValue;
|
---|
| 4030 | pExpr->u.UnsignedValue.u64 = u64;
|
---|
| 4031 | }
|
---|
| 4032 |
|
---|
| 4033 | /* Link it. */
|
---|
| 4034 | pExpr->pParent = pParser->pCur;
|
---|
| 4035 | pParser->pCur = pExpr;
|
---|
| 4036 | *pParser->ppCur = pExpr;
|
---|
| 4037 | pParser->ppCur = NULL;
|
---|
| 4038 |
|
---|
| 4039 | return kExprRet_Value;
|
---|
| 4040 | }
|
---|
| 4041 |
|
---|
| 4042 |
|
---|
[41266] | 4043 | /**
|
---|
| 4044 | * Parses an character constant in the expression.
|
---|
| 4045 | *
|
---|
| 4046 | * @returns Expression status.
|
---|
| 4047 | * @retval kExprRet_Value
|
---|
| 4048 | * @retval kExprRet_Error with msg.
|
---|
| 4049 | * @param pParser The parser instance.
|
---|
| 4050 | */
|
---|
[41263] | 4051 | static VBCPPEXPRRET vbcppExprParseCharacterConstant(PVBCPPEXPRPARSER pParser)
|
---|
| 4052 | {
|
---|
[62450] | 4053 | Assert(*pParser->pszCur == '\'');
|
---|
| 4054 | pParser->pszCur++;
|
---|
[41263] | 4055 | char ch2 = *pParser->pszCur++;
|
---|
| 4056 | if (ch2 == '\'')
|
---|
[41266] | 4057 | return vbcppExprParseError(pParser, "Empty character constant");
|
---|
[41263] | 4058 | int64_t s64;
|
---|
| 4059 | if (ch2 == '\\')
|
---|
| 4060 | {
|
---|
| 4061 | ch2 = *pParser->pszCur++;
|
---|
| 4062 | switch (ch2)
|
---|
| 4063 | {
|
---|
| 4064 | case '0': s64 = 0x00; break;
|
---|
| 4065 | case 'n': s64 = 0x0d; break;
|
---|
| 4066 | case 'r': s64 = 0x0a; break;
|
---|
| 4067 | case 't': s64 = 0x09; break;
|
---|
| 4068 | default:
|
---|
[41266] | 4069 | return vbcppExprParseError(pParser, "Escape character '%c' is not implemented", ch2);
|
---|
[41263] | 4070 | }
|
---|
| 4071 | }
|
---|
| 4072 | else
|
---|
| 4073 | s64 = ch2;
|
---|
| 4074 | if (*pParser->pszCur != '\'')
|
---|
[41266] | 4075 | return vbcppExprParseError(pParser, "Character constant contains more than one character");
|
---|
[41263] | 4076 |
|
---|
| 4077 | /* Create a signed value node. */
|
---|
| 4078 | PVBCPPEXPR pExpr = vbcppExprParseAllocNode(pParser);
|
---|
| 4079 | if (!pExpr)
|
---|
| 4080 | return kExprRet_Error;
|
---|
| 4081 | pExpr->fComplete = true;
|
---|
| 4082 | pExpr->enmKind = kVBCppExprKind_SignedValue;
|
---|
| 4083 | pExpr->u.SignedValue.s64 = s64;
|
---|
| 4084 |
|
---|
| 4085 | /* Link it. */
|
---|
| 4086 | pExpr->pParent = pParser->pCur;
|
---|
| 4087 | pParser->pCur = pExpr;
|
---|
| 4088 | *pParser->ppCur = pExpr;
|
---|
| 4089 | pParser->ppCur = NULL;
|
---|
| 4090 |
|
---|
| 4091 | return kExprRet_Value;
|
---|
| 4092 | }
|
---|
| 4093 |
|
---|
| 4094 |
|
---|
[41266] | 4095 | /**
|
---|
| 4096 | * Parses a unary operator or a value.
|
---|
| 4097 | *
|
---|
| 4098 | * @returns Expression status.
|
---|
| 4099 | * @retval kExprRet_Value if value was found and processed.
|
---|
| 4100 | * @retval kExprRet_UnaryOperator if an unary operator was found and processed.
|
---|
| 4101 | * @retval kExprRet_Error with msg.
|
---|
[100618] | 4102 | * @retval kExprRet_EndOfExpr if reached ',' or ')' if in an undefined call.
|
---|
[41266] | 4103 | * @param pParser The parser instance.
|
---|
| 4104 | */
|
---|
| 4105 | static VBCPPEXPRRET vbcppExprParseUnaryOrValue(PVBCPPEXPRPARSER pParser)
|
---|
[41263] | 4106 | {
|
---|
| 4107 | vbcppExprParseSkipWhiteSpace(pParser);
|
---|
| 4108 | char ch = *pParser->pszCur;
|
---|
| 4109 | if (ch == '\0')
|
---|
[41266] | 4110 | return vbcppExprParseError(pParser, "Premature end of expression");
|
---|
[41263] | 4111 |
|
---|
| 4112 | /*
|
---|
| 4113 | * Value?
|
---|
| 4114 | */
|
---|
| 4115 | if (ch == '\'')
|
---|
| 4116 | return vbcppExprParseCharacterConstant(pParser);
|
---|
| 4117 | if (RT_C_IS_DIGIT(ch))
|
---|
| 4118 | return vbcppExprParseNumber(pParser);
|
---|
| 4119 | if (ch == '"')
|
---|
[41266] | 4120 | return vbcppExprParseError(pParser, "String litteral");
|
---|
[41263] | 4121 | if (vbcppIsCIdentifierLeadChar(ch))
|
---|
| 4122 | return vbcppExprParseIdentifier(pParser);
|
---|
| 4123 |
|
---|
| 4124 | /*
|
---|
| 4125 | * Operator?
|
---|
| 4126 | */
|
---|
| 4127 | VBCPPUNARYOP enmOperator;
|
---|
| 4128 | if (ch == '+')
|
---|
| 4129 | {
|
---|
| 4130 | enmOperator = kVBCppUnaryOp_Pluss;
|
---|
| 4131 | if (pParser->pszCur[1] == '+')
|
---|
[41266] | 4132 | return vbcppExprParseError(pParser, "The prefix increment operator is not valid in a preprocessor expression");
|
---|
[41263] | 4133 | }
|
---|
| 4134 | else if (ch == '-')
|
---|
| 4135 | {
|
---|
| 4136 | enmOperator = kVBCppUnaryOp_Minus;
|
---|
| 4137 | if (pParser->pszCur[1] == '-')
|
---|
[41266] | 4138 | return vbcppExprParseError(pParser, "The prefix decrement operator is not valid in a preprocessor expression");
|
---|
[41263] | 4139 | }
|
---|
| 4140 | else if (ch == '!')
|
---|
| 4141 | enmOperator = kVBCppUnaryOp_LogicalNot;
|
---|
| 4142 | else if (ch == '~')
|
---|
| 4143 | enmOperator = kVBCppUnaryOp_BitwiseNot;
|
---|
| 4144 | else if (ch == '(')
|
---|
| 4145 | enmOperator = kVBCppUnaryOp_Parenthesis;
|
---|
[100618] | 4146 | else if ((ch == ',' || ch == ')') && pParser->pCur->enmKind == kVBCppExprKind_UndefMacroCall)
|
---|
| 4147 | {
|
---|
| 4148 | pParser->pszCur++;
|
---|
| 4149 | pParser->pCur->fComplete = ch == ')';
|
---|
| 4150 | return kExprRet_EndOfExpr;
|
---|
| 4151 | }
|
---|
[41263] | 4152 | else
|
---|
[100618] | 4153 | return vbcppExprParseError(pParser, "Unexpected token '%.*s'", 32, pParser->pszCur - 1);
|
---|
[41263] | 4154 | pParser->pszCur++;
|
---|
| 4155 |
|
---|
| 4156 | /* Create an operator node. */
|
---|
| 4157 | PVBCPPEXPR pExpr = vbcppExprParseAllocNode(pParser);
|
---|
| 4158 | if (!pExpr)
|
---|
| 4159 | return kExprRet_Error;
|
---|
| 4160 | pExpr->fComplete = false;
|
---|
| 4161 | pExpr->enmKind = kVBCppExprKind_Unary;
|
---|
| 4162 | pExpr->u.Unary.enmOperator = enmOperator;
|
---|
| 4163 | pExpr->u.Unary.pArg = NULL;
|
---|
| 4164 |
|
---|
| 4165 | /* Link it into the tree. */
|
---|
| 4166 | pExpr->pParent = pParser->pCur;
|
---|
| 4167 | pParser->pCur = pExpr;
|
---|
| 4168 | *pParser->ppCur = pExpr;
|
---|
| 4169 | pParser->ppCur = &pExpr->u.Unary.pArg;
|
---|
| 4170 |
|
---|
| 4171 | return kExprRet_UnaryOperator;
|
---|
| 4172 | }
|
---|
| 4173 |
|
---|
| 4174 |
|
---|
[41266] | 4175 | /**
|
---|
| 4176 | * Parses an expanded preprocessor expression.
|
---|
| 4177 | *
|
---|
| 4178 | * @returns RTEXITCODE_SUCCESS or RTEXITCODE_FAILURE+msg.
|
---|
| 4179 | * @param pThis The C preprocessor instance.
|
---|
| 4180 | * @param pszExpr The expression to parse.
|
---|
| 4181 | * @param cchExpr The length of the expression in case we need it.
|
---|
| 4182 | * @param ppExprTree Where to return the parse tree.
|
---|
| 4183 | * @param pcUndefined Where to return the number of unknown undefined
|
---|
| 4184 | * macros. Optional.
|
---|
| 4185 | */
|
---|
[41263] | 4186 | static RTEXITCODE vbcppExprParse(PVBCPP pThis, char *pszExpr, size_t cchExpr, PVBCPPEXPR *ppExprTree, size_t *pcUndefined)
|
---|
| 4187 | {
|
---|
| 4188 | RTEXITCODE rcExit = RTEXITCODE_FAILURE;
|
---|
[41266] | 4189 | NOREF(cchExpr);
|
---|
[41263] | 4190 |
|
---|
| 4191 | /*
|
---|
| 4192 | * Initialize the parser context structure.
|
---|
| 4193 | */
|
---|
| 4194 | VBCPPEXPRPARSER Parser;
|
---|
| 4195 | Parser.pszCur = pszExpr;
|
---|
| 4196 | Parser.pRoot = NULL;
|
---|
| 4197 | Parser.pCur = NULL;
|
---|
| 4198 | Parser.ppCur = &Parser.pRoot;
|
---|
| 4199 | Parser.pszExpr = pszExpr;
|
---|
| 4200 | Parser.cUndefined = 0;
|
---|
| 4201 | Parser.pThis = pThis;
|
---|
| 4202 |
|
---|
| 4203 | /*
|
---|
| 4204 | * Do the parsing.
|
---|
| 4205 | */
|
---|
| 4206 | VBCPPEXPRRET enmRet;
|
---|
| 4207 | for (;;)
|
---|
| 4208 | {
|
---|
| 4209 | /*
|
---|
| 4210 | * Eat unary operators until we hit a value.
|
---|
| 4211 | */
|
---|
| 4212 | do
|
---|
[41266] | 4213 | enmRet = vbcppExprParseUnaryOrValue(&Parser);
|
---|
[41263] | 4214 | while (enmRet == kExprRet_UnaryOperator);
|
---|
| 4215 | if (enmRet == kExprRet_Error)
|
---|
| 4216 | break;
|
---|
[41266] | 4217 | AssertBreakStmt(enmRet == kExprRet_Value, enmRet = vbcppExprParseError(&Parser, "Expected value (enmRet=%d)", enmRet));
|
---|
[41263] | 4218 |
|
---|
| 4219 | /*
|
---|
| 4220 | * Non-unary operator, right parenthesis or end of expression is up next.
|
---|
| 4221 | */
|
---|
[41266] | 4222 | enmRet = vbcppExprParseBinaryOrEoeOrRparen(&Parser);
|
---|
[41263] | 4223 | if (enmRet == kExprRet_Error)
|
---|
| 4224 | break;
|
---|
| 4225 | if (enmRet == kExprRet_EndOfExpr)
|
---|
| 4226 | {
|
---|
| 4227 | /** @todo check if there are any open parentheses. */
|
---|
| 4228 | rcExit = RTEXITCODE_SUCCESS;
|
---|
| 4229 | break;
|
---|
| 4230 | }
|
---|
[41266] | 4231 | AssertBreakStmt(enmRet == kExprRet_Ok, enmRet = vbcppExprParseError(&Parser, "Expected value (enmRet=%d)", enmRet));
|
---|
[41263] | 4232 | }
|
---|
| 4233 |
|
---|
| 4234 | if (rcExit != RTEXITCODE_SUCCESS)
|
---|
| 4235 | {
|
---|
| 4236 | vbcppExprDestoryTree(Parser.pRoot);
|
---|
| 4237 | return rcExit;
|
---|
| 4238 | }
|
---|
| 4239 |
|
---|
| 4240 | if (pcUndefined)
|
---|
| 4241 | *pcUndefined = Parser.cUndefined;
|
---|
| 4242 | *ppExprTree = Parser.pRoot;
|
---|
[41209] | 4243 | return rcExit;
|
---|
| 4244 | }
|
---|
| 4245 |
|
---|
| 4246 |
|
---|
[41266] | 4247 | /**
|
---|
| 4248 | * Checks if an expression value value is evaluates to @c true or @c false.
|
---|
| 4249 | *
|
---|
| 4250 | * @returns @c true or @c false.
|
---|
| 4251 | * @param pExpr The value expression.
|
---|
| 4252 | */
|
---|
[41263] | 4253 | static bool vbcppExprIsExprTrue(PVBCPPEXPR pExpr)
|
---|
| 4254 | {
|
---|
| 4255 | Assert(pExpr->enmKind == kVBCppExprKind_SignedValue || pExpr->enmKind == kVBCppExprKind_UnsignedValue);
|
---|
[41266] | 4256 |
|
---|
[41263] | 4257 | return pExpr->enmKind == kVBCppExprKind_SignedValue
|
---|
| 4258 | ? pExpr->u.SignedValue.s64 != 0
|
---|
| 4259 | : pExpr->u.UnsignedValue.u64 != 0;
|
---|
| 4260 | }
|
---|
| 4261 |
|
---|
| 4262 |
|
---|
[41266] | 4263 | /**
|
---|
| 4264 | * Evalutes a parse (sub-)tree.
|
---|
| 4265 | *
|
---|
| 4266 | * @returns RTEXITCODE_SUCCESS or RTEXITCODE_FAILURE+msg.
|
---|
| 4267 | * @param pThis The C preprocessor instance.
|
---|
| 4268 | * @param pRoot The root of the parse (sub-)tree.
|
---|
| 4269 | * @param pResult Where to store the result value.
|
---|
| 4270 | */
|
---|
[41263] | 4271 | static RTEXITCODE vbcppExprEvaluteTree(PVBCPP pThis, PVBCPPEXPR pRoot, PVBCPPEXPR pResult)
|
---|
| 4272 | {
|
---|
| 4273 | RTEXITCODE rcExit;
|
---|
| 4274 | switch (pRoot->enmKind)
|
---|
| 4275 | {
|
---|
| 4276 | case kVBCppExprKind_SignedValue:
|
---|
| 4277 | pResult->enmKind = kVBCppExprKind_SignedValue;
|
---|
| 4278 | pResult->u.SignedValue.s64 = pRoot->u.SignedValue.s64;
|
---|
| 4279 | return RTEXITCODE_SUCCESS;
|
---|
| 4280 |
|
---|
| 4281 | case kVBCppExprKind_UnsignedValue:
|
---|
| 4282 | pResult->enmKind = kVBCppExprKind_UnsignedValue;
|
---|
| 4283 | pResult->u.UnsignedValue.u64 = pRoot->u.UnsignedValue.u64;
|
---|
| 4284 | return RTEXITCODE_SUCCESS;
|
---|
| 4285 |
|
---|
| 4286 | case kVBCppExprKind_Unary:
|
---|
| 4287 | rcExit = vbcppExprEvaluteTree(pThis, pRoot->u.Unary.pArg, pResult);
|
---|
| 4288 | if (rcExit != RTEXITCODE_SUCCESS)
|
---|
| 4289 | return rcExit;
|
---|
| 4290 |
|
---|
| 4291 | /* Apply the unary operator to the value */
|
---|
| 4292 | switch (pRoot->u.Unary.enmOperator)
|
---|
| 4293 | {
|
---|
| 4294 | case kVBCppUnaryOp_Minus:
|
---|
| 4295 | if (pResult->enmKind == kVBCppExprKind_SignedValue)
|
---|
| 4296 | pResult->u.SignedValue.s64 = -pResult->u.SignedValue.s64;
|
---|
| 4297 | else
|
---|
| 4298 | pResult->u.UnsignedValue.u64 = (uint64_t)-(int64_t)pResult->u.UnsignedValue.u64;
|
---|
| 4299 | break;
|
---|
| 4300 |
|
---|
| 4301 | case kVBCppUnaryOp_LogicalNot:
|
---|
| 4302 | if (pResult->enmKind == kVBCppExprKind_SignedValue)
|
---|
| 4303 | pResult->u.SignedValue.s64 = !pResult->u.SignedValue.s64;
|
---|
| 4304 | else
|
---|
| 4305 | pResult->u.UnsignedValue.u64 = !pResult->u.UnsignedValue.u64;
|
---|
| 4306 | break;
|
---|
| 4307 |
|
---|
| 4308 | case kVBCppUnaryOp_BitwiseNot:
|
---|
| 4309 | if (pResult->enmKind == kVBCppExprKind_SignedValue)
|
---|
| 4310 | pResult->u.SignedValue.s64 = ~pResult->u.SignedValue.s64;
|
---|
| 4311 | else
|
---|
| 4312 | pResult->u.UnsignedValue.u64 = ~pResult->u.UnsignedValue.u64;
|
---|
| 4313 | break;
|
---|
| 4314 |
|
---|
| 4315 | case kVBCppUnaryOp_Pluss:
|
---|
| 4316 | case kVBCppUnaryOp_Parenthesis:
|
---|
| 4317 | /* do nothing. */
|
---|
| 4318 | break;
|
---|
| 4319 |
|
---|
| 4320 | default:
|
---|
| 4321 | return vbcppError(pThis, "Internal error: u.Unary.enmOperator=%d", pRoot->u.Unary.enmOperator);
|
---|
| 4322 | }
|
---|
| 4323 | return RTEXITCODE_SUCCESS;
|
---|
| 4324 |
|
---|
| 4325 | case kVBCppExprKind_Binary:
|
---|
| 4326 | {
|
---|
| 4327 | /* Always evalute the left side. */
|
---|
| 4328 | rcExit = vbcppExprEvaluteTree(pThis, pRoot->u.Binary.pLeft, pResult);
|
---|
| 4329 | if (rcExit != RTEXITCODE_SUCCESS)
|
---|
| 4330 | return rcExit;
|
---|
| 4331 |
|
---|
| 4332 | /* If logical AND or OR we can sometimes skip evaluting the right side. */
|
---|
| 4333 | if ( pRoot->u.Binary.enmOperator == kVBCppBinary_LogicalAnd
|
---|
| 4334 | && !vbcppExprIsExprTrue(pResult))
|
---|
| 4335 | return RTEXITCODE_SUCCESS;
|
---|
| 4336 |
|
---|
| 4337 | if ( pRoot->u.Binary.enmOperator == kVBCppBinary_LogicalOr
|
---|
| 4338 | && vbcppExprIsExprTrue(pResult))
|
---|
| 4339 | return RTEXITCODE_SUCCESS;
|
---|
| 4340 |
|
---|
| 4341 | /* Evalute the right side. */
|
---|
| 4342 | VBCPPEXPR Result2;
|
---|
[41266] | 4343 | rcExit = vbcppExprEvaluteTree(pThis, pRoot->u.Binary.pRight, &Result2);
|
---|
[41263] | 4344 | if (rcExit != RTEXITCODE_SUCCESS)
|
---|
| 4345 | return rcExit;
|
---|
| 4346 |
|
---|
| 4347 | /* If one of them is unsigned, promote the other to unsigned as well. */
|
---|
| 4348 | if ( pResult->enmKind == kVBCppExprKind_UnsignedValue
|
---|
| 4349 | && Result2.enmKind == kVBCppExprKind_SignedValue)
|
---|
| 4350 | {
|
---|
| 4351 | Result2.enmKind = kVBCppExprKind_UnsignedValue;
|
---|
| 4352 | Result2.u.UnsignedValue.u64 = Result2.u.SignedValue.s64;
|
---|
| 4353 | }
|
---|
| 4354 | else if ( pResult->enmKind == kVBCppExprKind_SignedValue
|
---|
| 4355 | && Result2.enmKind == kVBCppExprKind_UnsignedValue)
|
---|
| 4356 | {
|
---|
| 4357 | pResult->enmKind = kVBCppExprKind_UnsignedValue;
|
---|
| 4358 | pResult->u.UnsignedValue.u64 = pResult->u.SignedValue.s64;
|
---|
| 4359 | }
|
---|
| 4360 |
|
---|
| 4361 | /* Perform the operation. */
|
---|
| 4362 | if (pResult->enmKind == kVBCppExprKind_UnsignedValue)
|
---|
| 4363 | {
|
---|
| 4364 | switch (pRoot->u.Binary.enmOperator)
|
---|
| 4365 | {
|
---|
| 4366 | case kVBCppBinary_Multiplication:
|
---|
| 4367 | pResult->u.UnsignedValue.u64 *= Result2.u.UnsignedValue.u64;
|
---|
| 4368 | break;
|
---|
| 4369 | case kVBCppBinary_Division:
|
---|
| 4370 | if (!Result2.u.UnsignedValue.u64)
|
---|
| 4371 | return vbcppError(pThis, "Divide by zero");
|
---|
| 4372 | pResult->u.UnsignedValue.u64 /= Result2.u.UnsignedValue.u64;
|
---|
| 4373 | break;
|
---|
| 4374 | case kVBCppBinary_Modulo:
|
---|
| 4375 | if (!Result2.u.UnsignedValue.u64)
|
---|
| 4376 | return vbcppError(pThis, "Divide by zero");
|
---|
| 4377 | pResult->u.UnsignedValue.u64 %= Result2.u.UnsignedValue.u64;
|
---|
| 4378 | break;
|
---|
| 4379 | case kVBCppBinary_Addition:
|
---|
| 4380 | pResult->u.UnsignedValue.u64 += Result2.u.UnsignedValue.u64;
|
---|
| 4381 | break;
|
---|
| 4382 | case kVBCppBinary_Subtraction:
|
---|
| 4383 | pResult->u.UnsignedValue.u64 -= Result2.u.UnsignedValue.u64;
|
---|
| 4384 | break;
|
---|
| 4385 | case kVBCppBinary_LeftShift:
|
---|
| 4386 | pResult->u.UnsignedValue.u64 <<= Result2.u.UnsignedValue.u64;
|
---|
| 4387 | break;
|
---|
| 4388 | case kVBCppBinary_RightShift:
|
---|
| 4389 | pResult->u.UnsignedValue.u64 >>= Result2.u.UnsignedValue.u64;
|
---|
| 4390 | break;
|
---|
| 4391 | case kVBCppBinary_LessThan:
|
---|
| 4392 | pResult->u.UnsignedValue.u64 = pResult->u.UnsignedValue.u64 < Result2.u.UnsignedValue.u64;
|
---|
| 4393 | break;
|
---|
| 4394 | case kVBCppBinary_LessThanOrEqual:
|
---|
| 4395 | pResult->u.UnsignedValue.u64 = pResult->u.UnsignedValue.u64 <= Result2.u.UnsignedValue.u64;
|
---|
| 4396 | break;
|
---|
| 4397 | case kVBCppBinary_GreaterThan:
|
---|
| 4398 | pResult->u.UnsignedValue.u64 = pResult->u.UnsignedValue.u64 > Result2.u.UnsignedValue.u64;
|
---|
| 4399 | break;
|
---|
| 4400 | case kVBCppBinary_GreaterThanOrEqual:
|
---|
| 4401 | pResult->u.UnsignedValue.u64 = pResult->u.UnsignedValue.u64 >= Result2.u.UnsignedValue.u64;
|
---|
| 4402 | break;
|
---|
| 4403 | case kVBCppBinary_EqualTo:
|
---|
| 4404 | pResult->u.UnsignedValue.u64 = pResult->u.UnsignedValue.u64 == Result2.u.UnsignedValue.u64;
|
---|
| 4405 | break;
|
---|
| 4406 | case kVBCppBinary_NotEqualTo:
|
---|
| 4407 | pResult->u.UnsignedValue.u64 = pResult->u.UnsignedValue.u64 != Result2.u.UnsignedValue.u64;
|
---|
| 4408 | break;
|
---|
| 4409 | case kVBCppBinary_BitwiseAnd:
|
---|
| 4410 | pResult->u.UnsignedValue.u64 &= Result2.u.UnsignedValue.u64;
|
---|
| 4411 | break;
|
---|
| 4412 | case kVBCppBinary_BitwiseXor:
|
---|
| 4413 | pResult->u.UnsignedValue.u64 ^= Result2.u.UnsignedValue.u64;
|
---|
| 4414 | break;
|
---|
| 4415 | case kVBCppBinary_BitwiseOr:
|
---|
| 4416 | pResult->u.UnsignedValue.u64 |= Result2.u.UnsignedValue.u64;
|
---|
| 4417 | break;
|
---|
| 4418 | case kVBCppBinary_LogicalAnd:
|
---|
| 4419 | pResult->u.UnsignedValue.u64 = pResult->u.UnsignedValue.u64 && Result2.u.UnsignedValue.u64;
|
---|
| 4420 | break;
|
---|
| 4421 | case kVBCppBinary_LogicalOr:
|
---|
| 4422 | pResult->u.UnsignedValue.u64 = pResult->u.UnsignedValue.u64 || Result2.u.UnsignedValue.u64;
|
---|
| 4423 | break;
|
---|
| 4424 | default:
|
---|
| 4425 | return vbcppError(pThis, "Internal error: u.Binary.enmOperator=%d", pRoot->u.Binary.enmOperator);
|
---|
| 4426 | }
|
---|
| 4427 | }
|
---|
| 4428 | else
|
---|
| 4429 | {
|
---|
| 4430 | switch (pRoot->u.Binary.enmOperator)
|
---|
| 4431 | {
|
---|
| 4432 | case kVBCppBinary_Multiplication:
|
---|
| 4433 | pResult->u.SignedValue.s64 *= Result2.u.SignedValue.s64;
|
---|
| 4434 | break;
|
---|
| 4435 | case kVBCppBinary_Division:
|
---|
| 4436 | if (!Result2.u.SignedValue.s64)
|
---|
| 4437 | return vbcppError(pThis, "Divide by zero");
|
---|
| 4438 | pResult->u.SignedValue.s64 /= Result2.u.SignedValue.s64;
|
---|
| 4439 | break;
|
---|
| 4440 | case kVBCppBinary_Modulo:
|
---|
| 4441 | if (!Result2.u.SignedValue.s64)
|
---|
| 4442 | return vbcppError(pThis, "Divide by zero");
|
---|
| 4443 | pResult->u.SignedValue.s64 %= Result2.u.SignedValue.s64;
|
---|
| 4444 | break;
|
---|
| 4445 | case kVBCppBinary_Addition:
|
---|
| 4446 | pResult->u.SignedValue.s64 += Result2.u.SignedValue.s64;
|
---|
| 4447 | break;
|
---|
| 4448 | case kVBCppBinary_Subtraction:
|
---|
| 4449 | pResult->u.SignedValue.s64 -= Result2.u.SignedValue.s64;
|
---|
| 4450 | break;
|
---|
| 4451 | case kVBCppBinary_LeftShift:
|
---|
| 4452 | pResult->u.SignedValue.s64 <<= Result2.u.SignedValue.s64;
|
---|
| 4453 | break;
|
---|
| 4454 | case kVBCppBinary_RightShift:
|
---|
| 4455 | pResult->u.SignedValue.s64 >>= Result2.u.SignedValue.s64;
|
---|
| 4456 | break;
|
---|
| 4457 | case kVBCppBinary_LessThan:
|
---|
| 4458 | pResult->u.SignedValue.s64 = pResult->u.SignedValue.s64 < Result2.u.SignedValue.s64;
|
---|
| 4459 | break;
|
---|
| 4460 | case kVBCppBinary_LessThanOrEqual:
|
---|
| 4461 | pResult->u.SignedValue.s64 = pResult->u.SignedValue.s64 <= Result2.u.SignedValue.s64;
|
---|
| 4462 | break;
|
---|
| 4463 | case kVBCppBinary_GreaterThan:
|
---|
| 4464 | pResult->u.SignedValue.s64 = pResult->u.SignedValue.s64 > Result2.u.SignedValue.s64;
|
---|
| 4465 | break;
|
---|
| 4466 | case kVBCppBinary_GreaterThanOrEqual:
|
---|
| 4467 | pResult->u.SignedValue.s64 = pResult->u.SignedValue.s64 >= Result2.u.SignedValue.s64;
|
---|
| 4468 | break;
|
---|
| 4469 | case kVBCppBinary_EqualTo:
|
---|
| 4470 | pResult->u.SignedValue.s64 = pResult->u.SignedValue.s64 == Result2.u.SignedValue.s64;
|
---|
| 4471 | break;
|
---|
| 4472 | case kVBCppBinary_NotEqualTo:
|
---|
| 4473 | pResult->u.SignedValue.s64 = pResult->u.SignedValue.s64 != Result2.u.SignedValue.s64;
|
---|
| 4474 | break;
|
---|
| 4475 | case kVBCppBinary_BitwiseAnd:
|
---|
| 4476 | pResult->u.SignedValue.s64 &= Result2.u.SignedValue.s64;
|
---|
| 4477 | break;
|
---|
| 4478 | case kVBCppBinary_BitwiseXor:
|
---|
| 4479 | pResult->u.SignedValue.s64 ^= Result2.u.SignedValue.s64;
|
---|
| 4480 | break;
|
---|
| 4481 | case kVBCppBinary_BitwiseOr:
|
---|
| 4482 | pResult->u.SignedValue.s64 |= Result2.u.SignedValue.s64;
|
---|
| 4483 | break;
|
---|
| 4484 | case kVBCppBinary_LogicalAnd:
|
---|
| 4485 | pResult->u.SignedValue.s64 = pResult->u.SignedValue.s64 && Result2.u.SignedValue.s64;
|
---|
| 4486 | break;
|
---|
| 4487 | case kVBCppBinary_LogicalOr:
|
---|
| 4488 | pResult->u.SignedValue.s64 = pResult->u.SignedValue.s64 || Result2.u.SignedValue.s64;
|
---|
| 4489 | break;
|
---|
| 4490 | default:
|
---|
| 4491 | return vbcppError(pThis, "Internal error: u.Binary.enmOperator=%d", pRoot->u.Binary.enmOperator);
|
---|
| 4492 | }
|
---|
| 4493 | }
|
---|
| 4494 | return rcExit;
|
---|
| 4495 | }
|
---|
| 4496 |
|
---|
| 4497 | case kVBCppExprKind_Ternary:
|
---|
| 4498 | rcExit = vbcppExprEvaluteTree(pThis, pRoot->u.Ternary.pExpr, pResult);
|
---|
| 4499 | if (rcExit != RTEXITCODE_SUCCESS)
|
---|
| 4500 | return rcExit;
|
---|
| 4501 | if (vbcppExprIsExprTrue(pResult))
|
---|
| 4502 | return vbcppExprEvaluteTree(pThis, pRoot->u.Ternary.pTrue, pResult);
|
---|
| 4503 | return vbcppExprEvaluteTree(pThis, pRoot->u.Ternary.pFalse, pResult);
|
---|
| 4504 |
|
---|
| 4505 | default:
|
---|
| 4506 | return vbcppError(pThis, "Internal error: enmKind=%d", pRoot->enmKind);
|
---|
| 4507 | }
|
---|
| 4508 | }
|
---|
| 4509 |
|
---|
| 4510 |
|
---|
[41209] | 4511 | /**
|
---|
[41263] | 4512 | * Evalutes the expression.
|
---|
[41209] | 4513 | *
|
---|
| 4514 | * @returns RTEXITCODE_SUCCESS or RTEXITCODE_FAILURE+msg.
|
---|
| 4515 | * @param pThis The C preprocessor instance.
|
---|
[41263] | 4516 | * @param pszExpr The expression.
|
---|
| 4517 | * @param cchExpr The length of the expression.
|
---|
[100618] | 4518 | * @param cReplacements The number of replacements.
|
---|
| 4519 | * @param cDefinedUnknown The number of defined(UNKNOWN) cases. (Relevant
|
---|
| 4520 | * for selective modes.)
|
---|
[41263] | 4521 | * @param penmResult Where to store the result.
|
---|
[41209] | 4522 | */
|
---|
[100618] | 4523 | static RTEXITCODE vbcppExprEval(PVBCPP pThis, char *pszExpr, size_t cchExpr, size_t cReplacements, size_t cDefinedUnknown,
|
---|
| 4524 | VBCPPEVAL *penmResult)
|
---|
[41209] | 4525 | {
|
---|
[41266] | 4526 | Assert(strlen(pszExpr) == cchExpr);
|
---|
[62594] | 4527 | RT_NOREF_PV(cReplacements);
|
---|
| 4528 |
|
---|
[41263] | 4529 | size_t cUndefined;
|
---|
| 4530 | PVBCPPEXPR pExprTree;
|
---|
| 4531 | RTEXITCODE rcExit = vbcppExprParse(pThis, pszExpr, cchExpr, &pExprTree, &cUndefined);
|
---|
| 4532 | if (rcExit == RTEXITCODE_SUCCESS)
|
---|
[41209] | 4533 | {
|
---|
[100618] | 4534 | if ( (!cUndefined && !cDefinedUnknown)
|
---|
[41263] | 4535 | || pThis->enmMode == kVBCppMode_SelectiveD
|
---|
| 4536 | || pThis->enmMode == kVBCppMode_Standard)
|
---|
[41209] | 4537 | {
|
---|
[41263] | 4538 | VBCPPEXPR Result;
|
---|
| 4539 | rcExit = vbcppExprEvaluteTree(pThis, pExprTree, &Result);
|
---|
| 4540 | if (rcExit == RTEXITCODE_SUCCESS)
|
---|
[41209] | 4541 | {
|
---|
[41263] | 4542 | if (vbcppExprIsExprTrue(&Result))
|
---|
| 4543 | *penmResult = kVBCppEval_True;
|
---|
[41209] | 4544 | else
|
---|
[41263] | 4545 | *penmResult = kVBCppEval_False;
|
---|
| 4546 | }
|
---|
| 4547 | }
|
---|
| 4548 | else
|
---|
| 4549 | *penmResult = kVBCppEval_Undecided;
|
---|
| 4550 | }
|
---|
| 4551 | return rcExit;
|
---|
| 4552 | }
|
---|
[41209] | 4553 |
|
---|
| 4554 |
|
---|
[41263] | 4555 | static RTEXITCODE vbcppExtractSkipCommentLine(PVBCPP pThis, PSCMSTREAM pStrmInput)
|
---|
| 4556 | {
|
---|
[62594] | 4557 | RT_NOREF_PV(pThis);
|
---|
| 4558 |
|
---|
[41263] | 4559 | unsigned chPrev = ScmStreamGetCh(pStrmInput); Assert(chPrev == '/');
|
---|
| 4560 | unsigned ch;
|
---|
| 4561 | while ((ch = ScmStreamPeekCh(pStrmInput)) != ~(unsigned)0)
|
---|
| 4562 | {
|
---|
| 4563 | if (ch == '\r' || ch == '\n')
|
---|
| 4564 | {
|
---|
| 4565 | if (chPrev != '\\')
|
---|
| 4566 | break;
|
---|
| 4567 | ScmStreamSeekByLine(pStrmInput, ScmStreamTellLine(pStrmInput) + 1);
|
---|
| 4568 | chPrev = ch;
|
---|
[41209] | 4569 | }
|
---|
[41263] | 4570 | else
|
---|
| 4571 | {
|
---|
| 4572 | chPrev = ScmStreamGetCh(pStrmInput);
|
---|
| 4573 | Assert(chPrev == ch);
|
---|
| 4574 | }
|
---|
[41209] | 4575 | }
|
---|
[41263] | 4576 | return RTEXITCODE_SUCCESS;
|
---|
| 4577 | }
|
---|
[41209] | 4578 |
|
---|
[41263] | 4579 |
|
---|
| 4580 | static RTEXITCODE vbcppExtractSkipComment(PVBCPP pThis, PSCMSTREAM pStrmInput)
|
---|
| 4581 | {
|
---|
| 4582 | unsigned ch = ScmStreamGetCh(pStrmInput); Assert(ch == '*');
|
---|
| 4583 | while ((ch = ScmStreamGetCh(pStrmInput)) != ~(unsigned)0)
|
---|
| 4584 | {
|
---|
| 4585 | if (ch == '*')
|
---|
| 4586 | {
|
---|
| 4587 | ch = ScmStreamGetCh(pStrmInput);
|
---|
| 4588 | if (ch == '/')
|
---|
| 4589 | return RTEXITCODE_SUCCESS;
|
---|
| 4590 | }
|
---|
| 4591 | }
|
---|
| 4592 | return vbcppError(pThis, "Expected '*/'");
|
---|
[41209] | 4593 | }
|
---|
| 4594 |
|
---|
| 4595 |
|
---|
[41263] | 4596 | static RTEXITCODE vbcppExtractQuotedString(PVBCPP pThis, PSCMSTREAM pStrmInput, PVBCPPSTRBUF pStrBuf,
|
---|
| 4597 | char chOpen, char chClose)
|
---|
| 4598 | {
|
---|
| 4599 | unsigned ch = ScmStreamGetCh(pStrmInput);
|
---|
| 4600 | Assert(ch == (unsigned)chOpen);
|
---|
[41209] | 4601 |
|
---|
[41263] | 4602 | RTEXITCODE rcExit = vbcppStrBufAppendCh(pStrBuf, chOpen);
|
---|
| 4603 | if (rcExit != RTEXITCODE_SUCCESS)
|
---|
| 4604 | return rcExit;
|
---|
| 4605 |
|
---|
| 4606 | for (;;)
|
---|
| 4607 | {
|
---|
| 4608 | ch = ScmStreamGetCh(pStrmInput);
|
---|
| 4609 | if (ch == '\\')
|
---|
| 4610 | {
|
---|
| 4611 | ch = ScmStreamGetCh(pStrmInput);
|
---|
| 4612 | if (ch == ~(unsigned)0)
|
---|
| 4613 | break;
|
---|
| 4614 | rcExit = vbcppStrBufAppendCh(pStrBuf, '\\');
|
---|
| 4615 | if (rcExit == RTEXITCODE_SUCCESS)
|
---|
| 4616 | rcExit = vbcppStrBufAppendCh(pStrBuf, ch);
|
---|
| 4617 | if (rcExit != RTEXITCODE_SUCCESS)
|
---|
| 4618 | return rcExit;
|
---|
| 4619 | }
|
---|
| 4620 | else if (ch != ~(unsigned)0)
|
---|
| 4621 | {
|
---|
| 4622 | rcExit = vbcppStrBufAppendCh(pStrBuf, ch);
|
---|
| 4623 | if (rcExit != RTEXITCODE_SUCCESS)
|
---|
| 4624 | return rcExit;
|
---|
| 4625 | if (ch == (unsigned)chClose)
|
---|
| 4626 | return RTEXITCODE_SUCCESS;
|
---|
| 4627 | }
|
---|
| 4628 | else
|
---|
| 4629 | break;
|
---|
| 4630 | }
|
---|
| 4631 |
|
---|
| 4632 | return vbcppError(pThis, "File ended with an open character constant");
|
---|
| 4633 | }
|
---|
| 4634 |
|
---|
| 4635 |
|
---|
[41209] | 4636 | /**
|
---|
[41263] | 4637 | * Extracts a line from the stream, stripping it for comments and maybe
|
---|
| 4638 | * optimzing some of the whitespace.
|
---|
[41209] | 4639 | *
|
---|
| 4640 | * @returns RTEXITCODE_SUCCESS or RTEXITCODE_FAILURE+msg.
|
---|
| 4641 | * @param pThis The C preprocessor instance.
|
---|
| 4642 | * @param pStrmInput The input stream.
|
---|
[41263] | 4643 | * @param pStrBuf Where to store the extracted line. Caller must
|
---|
| 4644 | * initialize this prior to the call an delete it
|
---|
| 4645 | * after use (even on failure).
|
---|
[41209] | 4646 | * @param poffComment Where to note down the position of the final
|
---|
| 4647 | * comment. Optional.
|
---|
| 4648 | */
|
---|
[41263] | 4649 | static RTEXITCODE vbcppExtractDirectiveLine(PVBCPP pThis, PSCMSTREAM pStrmInput, PVBCPPSTRBUF pStrBuf, size_t *poffComment)
|
---|
[41209] | 4650 | {
|
---|
| 4651 | size_t offComment = ~(size_t)0;
|
---|
| 4652 | unsigned ch;
|
---|
| 4653 | while ((ch = ScmStreamPeekCh(pStrmInput)) != ~(unsigned)0)
|
---|
| 4654 | {
|
---|
[41263] | 4655 | RTEXITCODE rcExit;
|
---|
| 4656 | if (ch == '/')
|
---|
[41209] | 4657 | {
|
---|
[41263] | 4658 | /* Comment? */
|
---|
[62452] | 4659 | unsigned ch2 = ScmStreamGetCh(pStrmInput); Assert(ch == ch2); NOREF(ch2);
|
---|
[41263] | 4660 | ch = ScmStreamPeekCh(pStrmInput);
|
---|
| 4661 | if (ch == '*')
|
---|
[41209] | 4662 | {
|
---|
[41263] | 4663 | offComment = ScmStreamTell(pStrmInput) - 1;
|
---|
| 4664 | rcExit = vbcppExtractSkipComment(pThis, pStrmInput);
|
---|
[41209] | 4665 | }
|
---|
[41263] | 4666 | else if (ch == '/')
|
---|
[41209] | 4667 | {
|
---|
| 4668 | offComment = ScmStreamTell(pStrmInput) - 1;
|
---|
[41263] | 4669 | rcExit = vbcppExtractSkipCommentLine(pThis, pStrmInput);
|
---|
[41209] | 4670 | }
|
---|
[41263] | 4671 | else
|
---|
| 4672 | rcExit = vbcppStrBufAppendCh(pStrBuf, '/');
|
---|
| 4673 | }
|
---|
| 4674 | else if (ch == '\'')
|
---|
| 4675 | {
|
---|
| 4676 | offComment = ~(size_t)0;
|
---|
| 4677 | rcExit = vbcppExtractQuotedString(pThis, pStrmInput, pStrBuf, '\'', '\'');
|
---|
| 4678 | }
|
---|
| 4679 | else if (ch == '"')
|
---|
| 4680 | {
|
---|
| 4681 | offComment = ~(size_t)0;
|
---|
| 4682 | rcExit = vbcppExtractQuotedString(pThis, pStrmInput, pStrBuf, '"', '"');
|
---|
| 4683 | }
|
---|
| 4684 | else if (ch == '\r' || ch == '\n')
|
---|
| 4685 | break; /* done */
|
---|
[41266] | 4686 | else if ( RT_C_IS_SPACE(ch)
|
---|
| 4687 | && ( RT_C_IS_SPACE(vbcppStrBufLastCh(pStrBuf))
|
---|
| 4688 | || vbcppStrBufLastCh(pStrBuf) == '\0') )
|
---|
[41263] | 4689 | {
|
---|
| 4690 | unsigned ch2 = ScmStreamGetCh(pStrmInput);
|
---|
[62452] | 4691 | Assert(ch == ch2); NOREF(ch2);
|
---|
[41266] | 4692 | rcExit = RTEXITCODE_SUCCESS;
|
---|
[41263] | 4693 | }
|
---|
| 4694 | else
|
---|
| 4695 | {
|
---|
| 4696 | unsigned ch2 = ScmStreamGetCh(pStrmInput); Assert(ch == ch2);
|
---|
| 4697 |
|
---|
| 4698 | /* Escaped newline? */
|
---|
| 4699 | if ( ch == '\\'
|
---|
| 4700 | && ( (ch2 = ScmStreamPeekCh(pStrmInput)) == '\r'
|
---|
| 4701 | || ch2 == '\n'))
|
---|
[41209] | 4702 | {
|
---|
[41263] | 4703 | ScmStreamSeekByLine(pStrmInput, ScmStreamTellLine(pStrmInput) + 1);
|
---|
[41266] | 4704 | rcExit = RTEXITCODE_SUCCESS;
|
---|
[41209] | 4705 | }
|
---|
| 4706 | else
|
---|
| 4707 | {
|
---|
[41263] | 4708 | offComment = ~(size_t)0;
|
---|
| 4709 | rcExit = vbcppStrBufAppendCh(pStrBuf, ch);
|
---|
[41209] | 4710 | }
|
---|
| 4711 | }
|
---|
[41263] | 4712 | if (rcExit != RTEXITCODE_SUCCESS)
|
---|
| 4713 | return rcExit;
|
---|
[41209] | 4714 | }
|
---|
| 4715 |
|
---|
[41263] | 4716 | if (poffComment)
|
---|
| 4717 | *poffComment = offComment;
|
---|
| 4718 | return RTEXITCODE_SUCCESS;
|
---|
[41209] | 4719 | }
|
---|
| 4720 |
|
---|
| 4721 |
|
---|
| 4722 | /**
|
---|
[41186] | 4723 | * Processes a abbreviated line number directive.
|
---|
| 4724 | *
|
---|
| 4725 | * @returns RTEXITCODE_SUCCESS or RTEXITCODE_FAILURE+msg.
|
---|
| 4726 | * @param pThis The C preprocessor instance.
|
---|
| 4727 | * @param pStrmInput The input stream.
|
---|
| 4728 | * @param offStart The stream position where the directive
|
---|
| 4729 | * started (for pass thru).
|
---|
[41209] | 4730 | * @param enmKind The kind of directive we're processing.
|
---|
[41186] | 4731 | */
|
---|
[41226] | 4732 | static RTEXITCODE vbcppDirectiveIfOrElif(PVBCPP pThis, PSCMSTREAM pStrmInput, size_t offStart,
|
---|
[41263] | 4733 | VBCPPCONDKIND enmKind)
|
---|
[41186] | 4734 | {
|
---|
[41209] | 4735 | /*
|
---|
| 4736 | * Check for missing #if if #elif.
|
---|
| 4737 | */
|
---|
| 4738 | if ( enmKind == kVBCppCondKind_ElIf
|
---|
| 4739 | && !pThis->pCondStack )
|
---|
| 4740 | return vbcppError(pThis, "#elif without #if");
|
---|
| 4741 |
|
---|
| 4742 | /*
|
---|
[41263] | 4743 | * Extract the expression string.
|
---|
[41209] | 4744 | */
|
---|
[41263] | 4745 | const char *pchCondition = ScmStreamGetCur(pStrmInput);
|
---|
| 4746 | size_t offComment;
|
---|
| 4747 | VBCPPMACROEXP ExpCtx;
|
---|
[41301] | 4748 | #if 0
|
---|
[41263] | 4749 | ExpCtx.pMacroStack = NULL;
|
---|
[41301] | 4750 | #endif
|
---|
[41263] | 4751 | ExpCtx.pStrmInput = NULL;
|
---|
| 4752 | ExpCtx.papszArgs = NULL;
|
---|
| 4753 | ExpCtx.cArgs = 0;
|
---|
| 4754 | ExpCtx.cArgsAlloced = 0;
|
---|
| 4755 | vbcppStrBufInit(&ExpCtx.StrBuf, pThis);
|
---|
| 4756 | RTEXITCODE rcExit = vbcppExtractDirectiveLine(pThis, pStrmInput, &ExpCtx.StrBuf, &offComment);
|
---|
[41209] | 4757 | if (rcExit == RTEXITCODE_SUCCESS)
|
---|
| 4758 | {
|
---|
[100618] | 4759 | if (RT_C_IS_SPACE(*pchCondition))
|
---|
| 4760 | pchCondition++;
|
---|
[41209] | 4761 | size_t const cchCondition = ScmStreamGetCur(pStrmInput) - pchCondition;
|
---|
[41263] | 4762 |
|
---|
| 4763 | /*
|
---|
| 4764 | * Expand known macros in it.
|
---|
| 4765 | */
|
---|
[41209] | 4766 | size_t cReplacements;
|
---|
[100618] | 4767 | size_t cDefinedUnknown;
|
---|
| 4768 | rcExit = vbcppMacroExpandReScan(pThis, &ExpCtx, kMacroReScanMode_Expression, &cReplacements, &cDefinedUnknown);
|
---|
[41209] | 4769 | if (rcExit == RTEXITCODE_SUCCESS)
|
---|
| 4770 | {
|
---|
| 4771 | /*
|
---|
| 4772 | * Strip it and check that it's not empty.
|
---|
| 4773 | */
|
---|
[41263] | 4774 | char *pszExpr = ExpCtx.StrBuf.pszBuf;
|
---|
| 4775 | size_t cchExpr = ExpCtx.StrBuf.cchBuf;
|
---|
| 4776 | while (cchExpr > 0 && RT_C_IS_SPACE(*pszExpr))
|
---|
| 4777 | pszExpr++, cchExpr--;
|
---|
[41209] | 4778 |
|
---|
[41263] | 4779 | while (cchExpr > 0 && RT_C_IS_SPACE(pszExpr[cchExpr - 1]))
|
---|
| 4780 | {
|
---|
| 4781 | pszExpr[--cchExpr] = '\0';
|
---|
| 4782 | ExpCtx.StrBuf.cchBuf--;
|
---|
| 4783 | }
|
---|
[41209] | 4784 | if (cchExpr)
|
---|
| 4785 | {
|
---|
| 4786 | /*
|
---|
| 4787 | * Now, evalute the expression.
|
---|
| 4788 | */
|
---|
| 4789 | VBCPPEVAL enmResult;
|
---|
[100618] | 4790 | rcExit = vbcppExprEval(pThis, pszExpr, cchExpr, cReplacements, cDefinedUnknown, &enmResult);
|
---|
[41209] | 4791 | if (rcExit == RTEXITCODE_SUCCESS)
|
---|
| 4792 | {
|
---|
| 4793 | /*
|
---|
| 4794 | * Take action.
|
---|
| 4795 | */
|
---|
| 4796 | if (enmKind != kVBCppCondKind_ElIf)
|
---|
| 4797 | rcExit = vbcppCondPush(pThis, pStrmInput, offComment, enmKind, enmResult,
|
---|
| 4798 | pchCondition, cchCondition);
|
---|
| 4799 | else
|
---|
| 4800 | {
|
---|
| 4801 | PVBCPPCOND pCond = pThis->pCondStack;
|
---|
| 4802 | if ( pCond->enmResult != kVBCppEval_Undecided
|
---|
| 4803 | && ( !pCond->pUp
|
---|
| 4804 | || pCond->pUp->enmStackResult == kVBCppEval_True))
|
---|
| 4805 | {
|
---|
[41263] | 4806 | Assert(enmResult == kVBCppEval_True || enmResult == kVBCppEval_False);
|
---|
| 4807 | if ( pCond->enmResult == kVBCppEval_False
|
---|
| 4808 | && enmResult == kVBCppEval_True
|
---|
| 4809 | && !pCond->fElIfDecided)
|
---|
| 4810 | {
|
---|
| 4811 | pCond->enmStackResult = kVBCppEval_True;
|
---|
| 4812 | pCond->fElIfDecided = true;
|
---|
| 4813 | }
|
---|
| 4814 | else
|
---|
[41209] | 4815 | pCond->enmStackResult = kVBCppEval_False;
|
---|
| 4816 | pThis->fIf0Mode = pCond->enmStackResult == kVBCppEval_False;
|
---|
| 4817 | }
|
---|
[41263] | 4818 | pCond->enmKind = kVBCppCondKind_ElIf;
|
---|
[41209] | 4819 | pCond->enmResult = enmResult;
|
---|
| 4820 | pCond->pchCond = pchCondition;
|
---|
| 4821 | pCond->cchCond = cchCondition;
|
---|
| 4822 |
|
---|
| 4823 | /*
|
---|
| 4824 | * Do #elif pass thru.
|
---|
| 4825 | */
|
---|
| 4826 | if ( !pThis->fIf0Mode
|
---|
| 4827 | && pCond->enmResult == kVBCppEval_Undecided)
|
---|
| 4828 | {
|
---|
| 4829 | ssize_t cch = ScmStreamPrintf(&pThis->StrmOutput, "#%*selif", pCond->iKeepLevel - 1, "");
|
---|
| 4830 | if (cch > 0)
|
---|
[100618] | 4831 | rcExit = vbcppOutputComment(pThis, pStrmInput, offStart, cch, 1);
|
---|
[41209] | 4832 | else
|
---|
| 4833 | rcExit = vbcppError(pThis, "Output error %Rrc", (int)cch);
|
---|
| 4834 | }
|
---|
[41217] | 4835 | else
|
---|
| 4836 | pThis->fJustDroppedLine = true;
|
---|
[41209] | 4837 | }
|
---|
| 4838 | }
|
---|
| 4839 | }
|
---|
| 4840 | else
|
---|
| 4841 | rcExit = vbcppError(pThis, "Empty #if expression");
|
---|
| 4842 | }
|
---|
| 4843 | }
|
---|
[41263] | 4844 | vbcppMacroExpandCleanup(&ExpCtx);
|
---|
[41209] | 4845 | return rcExit;
|
---|
[41186] | 4846 | }
|
---|
| 4847 |
|
---|
| 4848 |
|
---|
| 4849 | /**
|
---|
| 4850 | * Processes a abbreviated line number directive.
|
---|
| 4851 | *
|
---|
| 4852 | * @returns RTEXITCODE_SUCCESS or RTEXITCODE_FAILURE+msg.
|
---|
| 4853 | * @param pThis The C preprocessor instance.
|
---|
| 4854 | * @param pStrmInput The input stream.
|
---|
| 4855 | * @param offStart The stream position where the directive
|
---|
| 4856 | * started (for pass thru).
|
---|
| 4857 | */
|
---|
[41226] | 4858 | static RTEXITCODE vbcppDirectiveIfDef(PVBCPP pThis, PSCMSTREAM pStrmInput, size_t offStart)
|
---|
[41186] | 4859 | {
|
---|
| 4860 | /*
|
---|
| 4861 | * Parse it.
|
---|
| 4862 | */
|
---|
| 4863 | RTEXITCODE rcExit = vbcppProcessSkipWhiteEscapedEolAndComments(pThis, pStrmInput);
|
---|
| 4864 | if (rcExit == RTEXITCODE_SUCCESS)
|
---|
| 4865 | {
|
---|
| 4866 | size_t cchDefine;
|
---|
| 4867 | const char *pchDefine = ScmStreamCGetWord(pStrmInput, &cchDefine);
|
---|
| 4868 | if (pchDefine)
|
---|
| 4869 | {
|
---|
| 4870 | rcExit = vbcppProcessSkipWhiteEscapedEolAndCommentsCheckEol(pThis, pStrmInput);
|
---|
| 4871 | if (rcExit == RTEXITCODE_SUCCESS)
|
---|
[41179] | 4872 | {
|
---|
[41186] | 4873 | /*
|
---|
| 4874 | * Evaluate it.
|
---|
| 4875 | */
|
---|
| 4876 | VBCPPEVAL enmEval;
|
---|
[41226] | 4877 | if (vbcppMacroExists(pThis, pchDefine, cchDefine))
|
---|
[41186] | 4878 | enmEval = kVBCppEval_True;
|
---|
[41209] | 4879 | else if ( !pThis->fUndecidedConditionals
|
---|
[41186] | 4880 | || RTStrSpaceGetN(&pThis->UndefStrSpace, pchDefine, cchDefine) != NULL)
|
---|
| 4881 | enmEval = kVBCppEval_False;
|
---|
| 4882 | else
|
---|
| 4883 | enmEval = kVBCppEval_Undecided;
|
---|
| 4884 | rcExit = vbcppCondPush(pThis, pStrmInput, offStart, kVBCppCondKind_IfDef, enmEval,
|
---|
| 4885 | pchDefine, cchDefine);
|
---|
[41179] | 4886 | }
|
---|
| 4887 | }
|
---|
[41186] | 4888 | else
|
---|
| 4889 | rcExit = vbcppError(pThis, "Malformed #ifdef");
|
---|
[41179] | 4890 | }
|
---|
[41186] | 4891 | return rcExit;
|
---|
[41179] | 4892 | }
|
---|
| 4893 |
|
---|
| 4894 |
|
---|
| 4895 | /**
|
---|
[41186] | 4896 | * Processes a abbreviated line number directive.
|
---|
| 4897 | *
|
---|
| 4898 | * @returns RTEXITCODE_SUCCESS or RTEXITCODE_FAILURE+msg.
|
---|
| 4899 | * @param pThis The C preprocessor instance.
|
---|
| 4900 | * @param pStrmInput The input stream.
|
---|
| 4901 | * @param offStart The stream position where the directive
|
---|
| 4902 | * started (for pass thru).
|
---|
| 4903 | */
|
---|
[41226] | 4904 | static RTEXITCODE vbcppDirectiveIfNDef(PVBCPP pThis, PSCMSTREAM pStrmInput, size_t offStart)
|
---|
[41186] | 4905 | {
|
---|
| 4906 | /*
|
---|
| 4907 | * Parse it.
|
---|
| 4908 | */
|
---|
| 4909 | RTEXITCODE rcExit = vbcppProcessSkipWhiteEscapedEolAndComments(pThis, pStrmInput);
|
---|
| 4910 | if (rcExit == RTEXITCODE_SUCCESS)
|
---|
| 4911 | {
|
---|
| 4912 | size_t cchDefine;
|
---|
| 4913 | const char *pchDefine = ScmStreamCGetWord(pStrmInput, &cchDefine);
|
---|
| 4914 | if (pchDefine)
|
---|
| 4915 | {
|
---|
| 4916 | rcExit = vbcppProcessSkipWhiteEscapedEolAndCommentsCheckEol(pThis, pStrmInput);
|
---|
| 4917 | if (rcExit == RTEXITCODE_SUCCESS)
|
---|
| 4918 | {
|
---|
| 4919 | /*
|
---|
| 4920 | * Evaluate it.
|
---|
| 4921 | */
|
---|
| 4922 | VBCPPEVAL enmEval;
|
---|
[41226] | 4923 | if (vbcppMacroExists(pThis, pchDefine, cchDefine))
|
---|
[41186] | 4924 | enmEval = kVBCppEval_False;
|
---|
[41209] | 4925 | else if ( !pThis->fUndecidedConditionals
|
---|
[41186] | 4926 | || RTStrSpaceGetN(&pThis->UndefStrSpace, pchDefine, cchDefine) != NULL)
|
---|
| 4927 | enmEval = kVBCppEval_True;
|
---|
| 4928 | else
|
---|
| 4929 | enmEval = kVBCppEval_Undecided;
|
---|
| 4930 | rcExit = vbcppCondPush(pThis, pStrmInput, offStart, kVBCppCondKind_IfNDef, enmEval,
|
---|
| 4931 | pchDefine, cchDefine);
|
---|
| 4932 | }
|
---|
| 4933 | }
|
---|
| 4934 | else
|
---|
[41195] | 4935 | rcExit = vbcppError(pThis, "Malformed #ifndef");
|
---|
[41186] | 4936 | }
|
---|
| 4937 | return rcExit;
|
---|
| 4938 | }
|
---|
| 4939 |
|
---|
| 4940 |
|
---|
| 4941 | /**
|
---|
| 4942 | * Processes a abbreviated line number directive.
|
---|
| 4943 | *
|
---|
| 4944 | * @returns RTEXITCODE_SUCCESS or RTEXITCODE_FAILURE+msg.
|
---|
| 4945 | * @param pThis The C preprocessor instance.
|
---|
| 4946 | * @param pStrmInput The input stream.
|
---|
| 4947 | * @param offStart The stream position where the directive
|
---|
| 4948 | * started (for pass thru).
|
---|
| 4949 | */
|
---|
[41226] | 4950 | static RTEXITCODE vbcppDirectiveElse(PVBCPP pThis, PSCMSTREAM pStrmInput, size_t offStart)
|
---|
[41186] | 4951 | {
|
---|
[41194] | 4952 | /*
|
---|
| 4953 | * Nothing to parse, just comment positions to find and note down.
|
---|
| 4954 | */
|
---|
| 4955 | offStart = vbcppProcessSkipWhite(pStrmInput);
|
---|
| 4956 | RTEXITCODE rcExit = vbcppProcessSkipWhiteEscapedEolAndCommentsCheckEol(pThis, pStrmInput);
|
---|
| 4957 | if (rcExit == RTEXITCODE_SUCCESS)
|
---|
| 4958 | {
|
---|
| 4959 | /*
|
---|
| 4960 | * Execute.
|
---|
| 4961 | */
|
---|
| 4962 | PVBCPPCOND pCond = pThis->pCondStack;
|
---|
| 4963 | if (pCond)
|
---|
| 4964 | {
|
---|
| 4965 | if (!pCond->fSeenElse)
|
---|
| 4966 | {
|
---|
| 4967 | pCond->fSeenElse = true;
|
---|
| 4968 | if ( pCond->enmResult != kVBCppEval_Undecided
|
---|
| 4969 | && ( !pCond->pUp
|
---|
| 4970 | || pCond->pUp->enmStackResult == kVBCppEval_True))
|
---|
| 4971 | {
|
---|
[41263] | 4972 | if ( pCond->enmResult == kVBCppEval_True
|
---|
| 4973 | || pCond->fElIfDecided)
|
---|
| 4974 |
|
---|
[41194] | 4975 | pCond->enmStackResult = kVBCppEval_False;
|
---|
| 4976 | else
|
---|
| 4977 | pCond->enmStackResult = kVBCppEval_True;
|
---|
| 4978 | pThis->fIf0Mode = pCond->enmStackResult == kVBCppEval_False;
|
---|
| 4979 | }
|
---|
| 4980 |
|
---|
| 4981 | /*
|
---|
| 4982 | * Do pass thru.
|
---|
| 4983 | */
|
---|
| 4984 | if ( !pThis->fIf0Mode
|
---|
| 4985 | && pCond->enmResult == kVBCppEval_Undecided)
|
---|
| 4986 | {
|
---|
| 4987 | ssize_t cch = ScmStreamPrintf(&pThis->StrmOutput, "#%*selse", pCond->iKeepLevel - 1, "");
|
---|
| 4988 | if (cch > 0)
|
---|
[41195] | 4989 | rcExit = vbcppOutputComment(pThis, pStrmInput, offStart, cch, 2);
|
---|
[41194] | 4990 | else
|
---|
| 4991 | rcExit = vbcppError(pThis, "Output error %Rrc", (int)cch);
|
---|
| 4992 | }
|
---|
[41217] | 4993 | else
|
---|
| 4994 | pThis->fJustDroppedLine = true;
|
---|
[41194] | 4995 | }
|
---|
| 4996 | else
|
---|
| 4997 | rcExit = vbcppError(pThis, "Double #else or/and missing #endif");
|
---|
| 4998 | }
|
---|
| 4999 | else
|
---|
| 5000 | rcExit = vbcppError(pThis, "#else without #if");
|
---|
| 5001 | }
|
---|
| 5002 | return rcExit;
|
---|
[41186] | 5003 | }
|
---|
| 5004 |
|
---|
| 5005 |
|
---|
| 5006 | /**
|
---|
| 5007 | * Processes a abbreviated line number directive.
|
---|
| 5008 | *
|
---|
| 5009 | * @returns RTEXITCODE_SUCCESS or RTEXITCODE_FAILURE+msg.
|
---|
| 5010 | * @param pThis The C preprocessor instance.
|
---|
| 5011 | * @param pStrmInput The input stream.
|
---|
| 5012 | * @param offStart The stream position where the directive
|
---|
| 5013 | * started (for pass thru).
|
---|
| 5014 | */
|
---|
[41226] | 5015 | static RTEXITCODE vbcppDirectiveEndif(PVBCPP pThis, PSCMSTREAM pStrmInput, size_t offStart)
|
---|
[41186] | 5016 | {
|
---|
[41194] | 5017 | /*
|
---|
| 5018 | * Nothing to parse, just comment positions to find and note down.
|
---|
| 5019 | */
|
---|
| 5020 | offStart = vbcppProcessSkipWhite(pStrmInput);
|
---|
| 5021 | RTEXITCODE rcExit = vbcppProcessSkipWhiteEscapedEolAndCommentsCheckEol(pThis, pStrmInput);
|
---|
| 5022 | if (rcExit == RTEXITCODE_SUCCESS)
|
---|
| 5023 | {
|
---|
| 5024 | /*
|
---|
| 5025 | * Execute.
|
---|
| 5026 | */
|
---|
| 5027 | PVBCPPCOND pCond = pThis->pCondStack;
|
---|
| 5028 | if (pCond)
|
---|
| 5029 | {
|
---|
| 5030 | pThis->pCondStack = pCond->pUp;
|
---|
[41217] | 5031 | pThis->fIf0Mode = pCond->pUp && pCond->pUp->enmStackResult == kVBCppEval_False;
|
---|
[41194] | 5032 |
|
---|
| 5033 | /*
|
---|
| 5034 | * Do pass thru.
|
---|
| 5035 | */
|
---|
| 5036 | if ( !pThis->fIf0Mode
|
---|
| 5037 | && pCond->enmResult == kVBCppEval_Undecided)
|
---|
| 5038 | {
|
---|
| 5039 | ssize_t cch = ScmStreamPrintf(&pThis->StrmOutput, "#%*sendif", pCond->iKeepLevel - 1, "");
|
---|
| 5040 | if (cch > 0)
|
---|
[41195] | 5041 | rcExit = vbcppOutputComment(pThis, pStrmInput, offStart, cch, 1);
|
---|
[41194] | 5042 | else
|
---|
| 5043 | rcExit = vbcppError(pThis, "Output error %Rrc", (int)cch);
|
---|
| 5044 | }
|
---|
[41217] | 5045 | else
|
---|
| 5046 | pThis->fJustDroppedLine = true;
|
---|
[41194] | 5047 | }
|
---|
| 5048 | else
|
---|
| 5049 | rcExit = vbcppError(pThis, "#endif without #if");
|
---|
| 5050 | }
|
---|
| 5051 | return rcExit;
|
---|
[41186] | 5052 | }
|
---|
| 5053 |
|
---|
| 5054 |
|
---|
[41204] | 5055 |
|
---|
| 5056 |
|
---|
| 5057 |
|
---|
| 5058 | /*
|
---|
| 5059 | *
|
---|
| 5060 | *
|
---|
| 5061 | * Misc Directives
|
---|
| 5062 | * Misc Directives
|
---|
| 5063 | * Misc Directives
|
---|
| 5064 | * Misc Directives
|
---|
| 5065 | *
|
---|
| 5066 | *
|
---|
| 5067 | */
|
---|
| 5068 |
|
---|
| 5069 |
|
---|
[41186] | 5070 | /**
|
---|
[41204] | 5071 | * Adds an include directory.
|
---|
| 5072 | *
|
---|
| 5073 | * @returns Program exit code, with error message on failure.
|
---|
| 5074 | * @param pThis The C preprocessor instance.
|
---|
| 5075 | * @param pszDir The directory to add.
|
---|
| 5076 | */
|
---|
| 5077 | static RTEXITCODE vbcppAddInclude(PVBCPP pThis, const char *pszDir)
|
---|
| 5078 | {
|
---|
| 5079 | uint32_t cIncludes = pThis->cIncludes;
|
---|
| 5080 | if (cIncludes >= _64K)
|
---|
| 5081 | return vbcppError(pThis, "Too many include directories");
|
---|
| 5082 |
|
---|
| 5083 | void *pv = RTMemRealloc(pThis->papszIncludes, (cIncludes + 1) * sizeof(char **));
|
---|
| 5084 | if (!pv)
|
---|
| 5085 | return vbcppError(pThis, "No memory for include directories");
|
---|
| 5086 | pThis->papszIncludes = (char **)pv;
|
---|
| 5087 |
|
---|
| 5088 | int rc = RTStrDupEx(&pThis->papszIncludes[cIncludes], pszDir);
|
---|
| 5089 | if (RT_FAILURE(rc))
|
---|
| 5090 | return vbcppError(pThis, "No string memory for include directories");
|
---|
| 5091 |
|
---|
| 5092 | pThis->cIncludes = cIncludes + 1;
|
---|
| 5093 | return RTEXITCODE_SUCCESS;
|
---|
| 5094 | }
|
---|
| 5095 |
|
---|
| 5096 |
|
---|
| 5097 | /**
|
---|
[41186] | 5098 | * Processes a abbreviated line number directive.
|
---|
| 5099 | *
|
---|
| 5100 | * @returns RTEXITCODE_SUCCESS or RTEXITCODE_FAILURE+msg.
|
---|
| 5101 | * @param pThis The C preprocessor instance.
|
---|
| 5102 | * @param pStrmInput The input stream.
|
---|
| 5103 | * @param offStart The stream position where the directive
|
---|
| 5104 | * started (for pass thru).
|
---|
| 5105 | */
|
---|
[41226] | 5106 | static RTEXITCODE vbcppDirectiveInclude(PVBCPP pThis, PSCMSTREAM pStrmInput, size_t offStart)
|
---|
[41204] | 5107 | {
|
---|
[62594] | 5108 | RT_NOREF_PV(offStart);
|
---|
| 5109 |
|
---|
[41204] | 5110 | /*
|
---|
| 5111 | * Parse it.
|
---|
| 5112 | */
|
---|
| 5113 | RTEXITCODE rcExit = vbcppProcessSkipWhiteEscapedEolAndComments(pThis, pStrmInput);
|
---|
| 5114 | if (rcExit == RTEXITCODE_SUCCESS)
|
---|
| 5115 | {
|
---|
| 5116 | size_t cchFileSpec = 0;
|
---|
| 5117 | const char *pchFileSpec = NULL;
|
---|
| 5118 | size_t cchFilename = 0;
|
---|
| 5119 | const char *pchFilename = NULL;
|
---|
| 5120 |
|
---|
| 5121 | unsigned ch = ScmStreamPeekCh(pStrmInput);
|
---|
| 5122 | unsigned chType = ch;
|
---|
| 5123 | if (ch == '"' || ch == '<')
|
---|
| 5124 | {
|
---|
| 5125 | ScmStreamGetCh(pStrmInput);
|
---|
| 5126 | pchFileSpec = pchFilename = ScmStreamGetCur(pStrmInput);
|
---|
| 5127 | unsigned chEnd = chType == '<' ? '>' : '"';
|
---|
| 5128 | while ( (ch = ScmStreamGetCh(pStrmInput)) != ~(unsigned)0
|
---|
| 5129 | && ch != chEnd)
|
---|
| 5130 | {
|
---|
| 5131 | if (ch == '\r' || ch == '\n')
|
---|
| 5132 | {
|
---|
| 5133 | rcExit = vbcppError(pThis, "Multi-line include file specfications are not supported");
|
---|
| 5134 | break;
|
---|
| 5135 | }
|
---|
| 5136 | }
|
---|
| 5137 |
|
---|
| 5138 | if (rcExit == RTEXITCODE_SUCCESS)
|
---|
| 5139 | {
|
---|
| 5140 | if (ch != ~(unsigned)0)
|
---|
| 5141 | cchFileSpec = cchFilename = ScmStreamGetCur(pStrmInput) - pchFilename - 1;
|
---|
| 5142 | else
|
---|
| 5143 | rcExit = vbcppError(pThis, "Expected '%c'", chType);
|
---|
| 5144 | }
|
---|
| 5145 | }
|
---|
| 5146 | else if (vbcppIsCIdentifierLeadChar(ch))
|
---|
| 5147 | {
|
---|
| 5148 | //pchFileSpec = ScmStreamCGetWord(pStrmInput, &cchFileSpec);
|
---|
| 5149 | rcExit = vbcppError(pThis, "Including via a define is not implemented yet");
|
---|
| 5150 | }
|
---|
| 5151 | else
|
---|
| 5152 | rcExit = vbcppError(pThis, "Malformed include directive");
|
---|
| 5153 |
|
---|
| 5154 | /*
|
---|
| 5155 | * Take down the location of the next non-white space, in case we need
|
---|
| 5156 | * to pass thru the directive further down. Then skip to the end of the
|
---|
| 5157 | * line.
|
---|
| 5158 | */
|
---|
| 5159 | size_t const offIncEnd = vbcppProcessSkipWhite(pStrmInput);
|
---|
| 5160 | if (rcExit == RTEXITCODE_SUCCESS)
|
---|
| 5161 | rcExit = vbcppProcessSkipWhiteEscapedEolAndCommentsCheckEol(pThis, pStrmInput);
|
---|
| 5162 |
|
---|
| 5163 | if (rcExit == RTEXITCODE_SUCCESS)
|
---|
| 5164 | {
|
---|
| 5165 | /*
|
---|
| 5166 | * Execute it.
|
---|
| 5167 | */
|
---|
| 5168 | if (pThis->enmIncludeAction == kVBCppIncludeAction_Include)
|
---|
| 5169 | {
|
---|
| 5170 | /** @todo Search for the include file and push it onto the input stack.
|
---|
| 5171 | * Not difficult, just unnecessary rigth now. */
|
---|
[100555] | 5172 | rcExit = vbcppError(pThis, "Sorry, includes are not yet implemented");
|
---|
[41204] | 5173 | }
|
---|
| 5174 | else if (pThis->enmIncludeAction == kVBCppIncludeAction_PassThru)
|
---|
| 5175 | {
|
---|
| 5176 | /* Pretty print the passthru. */
|
---|
| 5177 | unsigned cchIndent = pThis->pCondStack ? pThis->pCondStack->iKeepLevel : 0;
|
---|
[41246] | 5178 | ssize_t cch;
|
---|
[41204] | 5179 | if (chType == '<')
|
---|
| 5180 | cch = ScmStreamPrintf(&pThis->StrmOutput, "#%*sinclude <%.*s>",
|
---|
| 5181 | cchIndent, "", cchFileSpec, pchFileSpec);
|
---|
| 5182 | else if (chType == '"')
|
---|
| 5183 | cch = ScmStreamPrintf(&pThis->StrmOutput, "#%*sinclude \"%.*s\"",
|
---|
| 5184 | cchIndent, "", cchFileSpec, pchFileSpec);
|
---|
| 5185 | else
|
---|
| 5186 | cch = ScmStreamPrintf(&pThis->StrmOutput, "#%*sinclude %.*s",
|
---|
| 5187 | cchIndent, "", cchFileSpec, pchFileSpec);
|
---|
| 5188 | if (cch > 0)
|
---|
| 5189 | rcExit = vbcppOutputComment(pThis, pStrmInput, offIncEnd, cch, 1);
|
---|
| 5190 | else
|
---|
| 5191 | rcExit = vbcppError(pThis, "Output error %Rrc", (int)cch);
|
---|
| 5192 |
|
---|
| 5193 | }
|
---|
| 5194 | else
|
---|
[41217] | 5195 | {
|
---|
[41204] | 5196 | Assert(pThis->enmIncludeAction == kVBCppIncludeAction_Drop);
|
---|
[41217] | 5197 | pThis->fJustDroppedLine = true;
|
---|
| 5198 | }
|
---|
[41204] | 5199 | }
|
---|
| 5200 | }
|
---|
| 5201 | return rcExit;
|
---|
| 5202 | }
|
---|
| 5203 |
|
---|
| 5204 |
|
---|
| 5205 | /**
|
---|
| 5206 | * Processes a abbreviated line number directive.
|
---|
| 5207 | *
|
---|
| 5208 | * @returns RTEXITCODE_SUCCESS or RTEXITCODE_FAILURE+msg.
|
---|
| 5209 | * @param pThis The C preprocessor instance.
|
---|
| 5210 | * @param pStrmInput The input stream.
|
---|
| 5211 | * @param offStart The stream position where the directive
|
---|
| 5212 | * started (for pass thru).
|
---|
| 5213 | */
|
---|
[41226] | 5214 | static RTEXITCODE vbcppDirectivePragma(PVBCPP pThis, PSCMSTREAM pStrmInput, size_t offStart)
|
---|
[41186] | 5215 | {
|
---|
[62594] | 5216 | RT_NOREF_PV(offStart);
|
---|
| 5217 |
|
---|
[41217] | 5218 | /*
|
---|
| 5219 | * Parse out the first word.
|
---|
| 5220 | */
|
---|
| 5221 | RTEXITCODE rcExit = vbcppProcessSkipWhiteEscapedEolAndComments(pThis, pStrmInput);
|
---|
| 5222 | if (rcExit == RTEXITCODE_SUCCESS)
|
---|
| 5223 | {
|
---|
| 5224 | size_t cchPragma;
|
---|
| 5225 | const char *pchPragma = ScmStreamCGetWord(pStrmInput, &cchPragma);
|
---|
| 5226 | if (pchPragma)
|
---|
| 5227 | {
|
---|
| 5228 | size_t const off2nd = vbcppProcessSkipWhite(pStrmInput);
|
---|
| 5229 | size_t offComment;
|
---|
| 5230 | rcExit = vbcppInputSkipToEndOfDirectiveLine(pThis, pStrmInput, &offComment);
|
---|
| 5231 | if (rcExit == RTEXITCODE_SUCCESS)
|
---|
| 5232 | {
|
---|
| 5233 | /*
|
---|
| 5234 | * What to do about this
|
---|
| 5235 | */
|
---|
| 5236 | bool fPassThru = false;
|
---|
| 5237 | if ( cchPragma == 1
|
---|
| 5238 | && *pchPragma == 'D')
|
---|
| 5239 | fPassThru = pThis->fPassThruPragmaD;
|
---|
| 5240 | else if ( cchPragma == 3
|
---|
| 5241 | && !strncmp(pchPragma, "STD", 3))
|
---|
| 5242 | fPassThru = pThis->fPassThruPragmaSTD;
|
---|
| 5243 | else
|
---|
| 5244 | fPassThru = pThis->fPassThruPragmaOther;
|
---|
| 5245 | if (fPassThru)
|
---|
| 5246 | {
|
---|
| 5247 | unsigned cchIndent = pThis->pCondStack ? pThis->pCondStack->iKeepLevel : 0;
|
---|
[41246] | 5248 | ssize_t cch = ScmStreamPrintf(&pThis->StrmOutput, "#%*spragma %.*s",
|
---|
[41217] | 5249 | cchIndent, "", cchPragma, pchPragma);
|
---|
| 5250 | if (cch > 0)
|
---|
| 5251 | rcExit = vbcppOutputComment(pThis, pStrmInput, off2nd, cch, 1);
|
---|
| 5252 | else
|
---|
| 5253 | rcExit = vbcppError(pThis, "output error");
|
---|
| 5254 | }
|
---|
| 5255 | else
|
---|
| 5256 | pThis->fJustDroppedLine = true;
|
---|
| 5257 | }
|
---|
| 5258 | }
|
---|
| 5259 | else
|
---|
| 5260 | rcExit = vbcppError(pThis, "Malformed #pragma");
|
---|
| 5261 | }
|
---|
| 5262 |
|
---|
| 5263 | return rcExit;
|
---|
[41186] | 5264 | }
|
---|
| 5265 |
|
---|
| 5266 |
|
---|
| 5267 | /**
|
---|
[41226] | 5268 | * Processes an error directive.
|
---|
| 5269 | *
|
---|
| 5270 | * @returns RTEXITCODE_SUCCESS or RTEXITCODE_FAILURE+msg.
|
---|
| 5271 | * @param pThis The C preprocessor instance.
|
---|
| 5272 | * @param pStrmInput The input stream.
|
---|
| 5273 | * @param offStart The stream position where the directive
|
---|
| 5274 | * started (for pass thru).
|
---|
| 5275 | */
|
---|
| 5276 | static RTEXITCODE vbcppDirectiveError(PVBCPP pThis, PSCMSTREAM pStrmInput, size_t offStart)
|
---|
| 5277 | {
|
---|
[100618] | 5278 | RT_NOREF(offStart);
|
---|
| 5279 |
|
---|
| 5280 | /*
|
---|
| 5281 | * Parse out the message.
|
---|
| 5282 | */
|
---|
| 5283 | size_t const off1st = vbcppProcessSkipWhite(pStrmInput);
|
---|
| 5284 | size_t offComment;
|
---|
| 5285 | RTEXITCODE rcExit = vbcppInputSkipToEndOfDirectiveLine(pThis, pStrmInput, &offComment);
|
---|
| 5286 | if (rcExit == RTEXITCODE_SUCCESS)
|
---|
| 5287 | {
|
---|
| 5288 | /*
|
---|
| 5289 | * What to do about this
|
---|
| 5290 | */
|
---|
| 5291 | if (pThis->fPassThruError)
|
---|
| 5292 | {
|
---|
| 5293 | unsigned cchIndent = pThis->pCondStack ? pThis->pCondStack->iKeepLevel : 0;
|
---|
| 5294 | ssize_t cch = ScmStreamPrintf(&pThis->StrmOutput, "#%*serror", cchIndent, "");
|
---|
| 5295 | if (cch > 0)
|
---|
| 5296 | rcExit = vbcppOutputComment(pThis, pStrmInput, off1st, cch, 1);
|
---|
| 5297 | else
|
---|
| 5298 | rcExit = vbcppError(pThis, "output error");
|
---|
| 5299 | return RTEXITCODE_SUCCESS;
|
---|
| 5300 | }
|
---|
| 5301 | return vbcppError(pThis, "Hit an #error");
|
---|
| 5302 | }
|
---|
[62594] | 5303 | RT_NOREF_PV(offStart);
|
---|
[100618] | 5304 | vbcppError(pThis, "Malformed #error");
|
---|
[41226] | 5305 | return vbcppError(pThis, "Hit an #error");
|
---|
| 5306 | }
|
---|
| 5307 |
|
---|
| 5308 |
|
---|
| 5309 | /**
|
---|
[41186] | 5310 | * Processes a abbreviated line number directive.
|
---|
| 5311 | *
|
---|
| 5312 | * @returns RTEXITCODE_SUCCESS or RTEXITCODE_FAILURE+msg.
|
---|
| 5313 | * @param pThis The C preprocessor instance.
|
---|
| 5314 | * @param pStrmInput The input stream.
|
---|
| 5315 | * @param offStart The stream position where the directive
|
---|
| 5316 | * started (for pass thru).
|
---|
| 5317 | */
|
---|
[41226] | 5318 | static RTEXITCODE vbcppDirectiveLineNo(PVBCPP pThis, PSCMSTREAM pStrmInput, size_t offStart)
|
---|
[41186] | 5319 | {
|
---|
[62594] | 5320 | RT_NOREF_PV(offStart);
|
---|
| 5321 | RT_NOREF_PV(pStrmInput);
|
---|
[41194] | 5322 | return vbcppError(pThis, "Not implemented: %s", __FUNCTION__);
|
---|
[41186] | 5323 | }
|
---|
| 5324 |
|
---|
| 5325 |
|
---|
| 5326 | /**
|
---|
| 5327 | * Processes a abbreviated line number directive.
|
---|
| 5328 | *
|
---|
| 5329 | * @returns RTEXITCODE_SUCCESS or RTEXITCODE_FAILURE+msg.
|
---|
| 5330 | * @param pThis The C preprocessor instance.
|
---|
| 5331 | * @param pStrmInput The input stream.
|
---|
| 5332 | */
|
---|
[41226] | 5333 | static RTEXITCODE vbcppDirectiveLineNoShort(PVBCPP pThis, PSCMSTREAM pStrmInput)
|
---|
[41186] | 5334 | {
|
---|
[62594] | 5335 | RT_NOREF_PV(pStrmInput);
|
---|
[41194] | 5336 | return vbcppError(pThis, "Not implemented: %s", __FUNCTION__);
|
---|
[41186] | 5337 | }
|
---|
| 5338 |
|
---|
| 5339 |
|
---|
| 5340 | /**
|
---|
| 5341 | * Handles a preprocessor directive.
|
---|
| 5342 | *
|
---|
| 5343 | * @returns RTEXITCODE_SUCCESS or RTEXITCODE_FAILURE+msg.
|
---|
| 5344 | * @param pThis The C preprocessor instance.
|
---|
| 5345 | * @param pStrmInput The input stream.
|
---|
| 5346 | */
|
---|
| 5347 | static RTEXITCODE vbcppProcessDirective(PVBCPP pThis, PSCMSTREAM pStrmInput)
|
---|
| 5348 | {
|
---|
| 5349 | /*
|
---|
| 5350 | * Get the directive and do a string switch on it.
|
---|
| 5351 | */
|
---|
| 5352 | RTEXITCODE rcExit = vbcppProcessSkipWhiteEscapedEolAndComments(pThis, pStrmInput);
|
---|
| 5353 | if (rcExit != RTEXITCODE_SUCCESS)
|
---|
| 5354 | return rcExit;
|
---|
| 5355 | size_t cchDirective;
|
---|
| 5356 | const char *pchDirective = ScmStreamCGetWord(pStrmInput, &cchDirective);
|
---|
| 5357 | if (pchDirective)
|
---|
| 5358 | {
|
---|
| 5359 | size_t const offStart = ScmStreamTell(pStrmInput);
|
---|
[100618] | 5360 | #define IS_DIRECTIVE(a_sz) ( sizeof(a_sz) - 1 == cchDirective && memcmp(pchDirective, a_sz, sizeof(a_sz) - 1) == 0)
|
---|
[41186] | 5361 | if (IS_DIRECTIVE("if"))
|
---|
[41226] | 5362 | rcExit = vbcppDirectiveIfOrElif(pThis, pStrmInput, offStart, kVBCppCondKind_If);
|
---|
[41209] | 5363 | else if (IS_DIRECTIVE("elif"))
|
---|
[41226] | 5364 | rcExit = vbcppDirectiveIfOrElif(pThis, pStrmInput, offStart, kVBCppCondKind_ElIf);
|
---|
[41186] | 5365 | else if (IS_DIRECTIVE("ifdef"))
|
---|
[41226] | 5366 | rcExit = vbcppDirectiveIfDef(pThis, pStrmInput, offStart);
|
---|
[41186] | 5367 | else if (IS_DIRECTIVE("ifndef"))
|
---|
[41226] | 5368 | rcExit = vbcppDirectiveIfNDef(pThis, pStrmInput, offStart);
|
---|
[41186] | 5369 | else if (IS_DIRECTIVE("else"))
|
---|
[41226] | 5370 | rcExit = vbcppDirectiveElse(pThis, pStrmInput, offStart);
|
---|
[41186] | 5371 | else if (IS_DIRECTIVE("endif"))
|
---|
[41226] | 5372 | rcExit = vbcppDirectiveEndif(pThis, pStrmInput, offStart);
|
---|
[41186] | 5373 | else if (!pThis->fIf0Mode)
|
---|
| 5374 | {
|
---|
| 5375 | if (IS_DIRECTIVE("include"))
|
---|
[41226] | 5376 | rcExit = vbcppDirectiveInclude(pThis, pStrmInput, offStart);
|
---|
[41186] | 5377 | else if (IS_DIRECTIVE("define"))
|
---|
[41226] | 5378 | rcExit = vbcppDirectiveDefine(pThis, pStrmInput, offStart);
|
---|
[41186] | 5379 | else if (IS_DIRECTIVE("undef"))
|
---|
[41226] | 5380 | rcExit = vbcppDirectiveUndef(pThis, pStrmInput, offStart);
|
---|
[41186] | 5381 | else if (IS_DIRECTIVE("pragma"))
|
---|
[41226] | 5382 | rcExit = vbcppDirectivePragma(pThis, pStrmInput, offStart);
|
---|
| 5383 | else if (IS_DIRECTIVE("error"))
|
---|
| 5384 | rcExit = vbcppDirectiveError(pThis, pStrmInput, offStart);
|
---|
[41186] | 5385 | else if (IS_DIRECTIVE("line"))
|
---|
[41226] | 5386 | rcExit = vbcppDirectiveLineNo(pThis, pStrmInput, offStart);
|
---|
[41186] | 5387 | else
|
---|
| 5388 | rcExit = vbcppError(pThis, "Unknown preprocessor directive '#%.*s'", cchDirective, pchDirective);
|
---|
| 5389 | }
|
---|
| 5390 | #undef IS_DIRECTIVE
|
---|
| 5391 | }
|
---|
| 5392 | else if (!pThis->fIf0Mode)
|
---|
| 5393 | {
|
---|
| 5394 | /* Could it be a # <num> "file" directive? */
|
---|
| 5395 | unsigned ch = ScmStreamPeekCh(pStrmInput);
|
---|
| 5396 | if (RT_C_IS_DIGIT(ch))
|
---|
[41226] | 5397 | rcExit = vbcppDirectiveLineNoShort(pThis, pStrmInput);
|
---|
[41186] | 5398 | else
|
---|
| 5399 | rcExit = vbcppError(pThis, "Malformed preprocessor directive");
|
---|
| 5400 | }
|
---|
| 5401 | return rcExit;
|
---|
| 5402 | }
|
---|
| 5403 |
|
---|
| 5404 |
|
---|
[41204] | 5405 | /*
|
---|
[41186] | 5406 | *
|
---|
[41204] | 5407 | *
|
---|
| 5408 | * M a i n b o d y.
|
---|
| 5409 | * M a i n b o d y.
|
---|
| 5410 | * M a i n b o d y.
|
---|
| 5411 | * M a i n b o d y.
|
---|
| 5412 | * M a i n b o d y.
|
---|
| 5413 | *
|
---|
| 5414 | *
|
---|
[41179] | 5415 | */
|
---|
| 5416 |
|
---|
| 5417 |
|
---|
| 5418 | /**
|
---|
| 5419 | * Does the actually preprocessing of the input file.
|
---|
[41186] | 5420 | *
|
---|
[41179] | 5421 | * @returns Exit code.
|
---|
[41186] | 5422 | * @param pThis The C preprocessor instance.
|
---|
[41179] | 5423 | */
|
---|
[41186] | 5424 | static RTEXITCODE vbcppPreprocess(PVBCPP pThis)
|
---|
[41179] | 5425 | {
|
---|
[41186] | 5426 | RTEXITCODE rcExit = RTEXITCODE_SUCCESS;
|
---|
[41179] | 5427 |
|
---|
[41186] | 5428 | /*
|
---|
[41179] | 5429 | * Parse.
|
---|
[41186] | 5430 | */
|
---|
| 5431 | while (pThis->pInputStack)
|
---|
[41179] | 5432 | {
|
---|
[41186] | 5433 | pThis->fMaybePreprocessorLine = true;
|
---|
| 5434 |
|
---|
| 5435 | PSCMSTREAM pStrmInput = &pThis->pInputStack->StrmInput;
|
---|
| 5436 | unsigned ch;
|
---|
| 5437 | while ((ch = ScmStreamGetCh(pStrmInput)) != ~(unsigned)0)
|
---|
[41179] | 5438 | {
|
---|
[41186] | 5439 | if (ch == '/')
|
---|
| 5440 | {
|
---|
| 5441 | ch = ScmStreamPeekCh(pStrmInput);
|
---|
| 5442 | if (ch == '*')
|
---|
| 5443 | rcExit = vbcppProcessMultiLineComment(pThis, pStrmInput);
|
---|
| 5444 | else if (ch == '/')
|
---|
| 5445 | rcExit = vbcppProcessOneLineComment(pThis, pStrmInput);
|
---|
| 5446 | else
|
---|
| 5447 | {
|
---|
| 5448 | pThis->fMaybePreprocessorLine = false;
|
---|
| 5449 | if (!pThis->fIf0Mode)
|
---|
| 5450 | rcExit = vbcppOutputCh(pThis, '/');
|
---|
| 5451 | }
|
---|
| 5452 | }
|
---|
| 5453 | else if (ch == '#' && pThis->fMaybePreprocessorLine)
|
---|
| 5454 | {
|
---|
| 5455 | rcExit = vbcppProcessDirective(pThis, pStrmInput);
|
---|
| 5456 | pStrmInput = &pThis->pInputStack->StrmInput;
|
---|
| 5457 | }
|
---|
| 5458 | else if (ch == '\r' || ch == '\n')
|
---|
| 5459 | {
|
---|
[41217] | 5460 | if ( ( !pThis->fIf0Mode
|
---|
| 5461 | && !pThis->fJustDroppedLine)
|
---|
| 5462 | || !pThis->fRemoveDroppedLines
|
---|
| 5463 | || !ScmStreamIsAtStartOfLine(&pThis->StrmOutput))
|
---|
| 5464 | rcExit = vbcppOutputCh(pThis, ch);
|
---|
| 5465 | pThis->fJustDroppedLine = false;
|
---|
[41186] | 5466 | pThis->fMaybePreprocessorLine = true;
|
---|
| 5467 | }
|
---|
| 5468 | else if (RT_C_IS_SPACE(ch))
|
---|
| 5469 | {
|
---|
| 5470 | if (!pThis->fIf0Mode)
|
---|
| 5471 | rcExit = vbcppOutputCh(pThis, ch);
|
---|
| 5472 | }
|
---|
[41179] | 5473 | else
|
---|
| 5474 | {
|
---|
| 5475 | pThis->fMaybePreprocessorLine = false;
|
---|
[41186] | 5476 | if (!pThis->fIf0Mode)
|
---|
| 5477 | {
|
---|
| 5478 | if (ch == '"')
|
---|
[41226] | 5479 | rcExit = vbcppProcessStringLitteral(pThis, pStrmInput);
|
---|
[41186] | 5480 | else if (ch == '\'')
|
---|
[41226] | 5481 | rcExit = vbcppProcessCharacterConstant(pThis, pStrmInput);
|
---|
[41186] | 5482 | else if (vbcppIsCIdentifierLeadChar(ch))
|
---|
[62594] | 5483 | rcExit = vbcppProcessIdentifier(pThis, pStrmInput);
|
---|
[41226] | 5484 | else if (RT_C_IS_DIGIT(ch))
|
---|
| 5485 | rcExit = vbcppProcessNumber(pThis, pStrmInput, ch);
|
---|
[41186] | 5486 | else
|
---|
| 5487 | rcExit = vbcppOutputCh(pThis, ch);
|
---|
| 5488 | }
|
---|
[41179] | 5489 | }
|
---|
[41186] | 5490 | if (rcExit != RTEXITCODE_SUCCESS)
|
---|
| 5491 | break;
|
---|
[41179] | 5492 | }
|
---|
[41186] | 5493 |
|
---|
| 5494 | /*
|
---|
| 5495 | * Check for errors.
|
---|
| 5496 | */
|
---|
[41179] | 5497 | if (rcExit != RTEXITCODE_SUCCESS)
|
---|
| 5498 | break;
|
---|
[41186] | 5499 |
|
---|
| 5500 | /*
|
---|
| 5501 | * Pop the input stack.
|
---|
| 5502 | */
|
---|
| 5503 | PVBCPPINPUT pPopped = pThis->pInputStack;
|
---|
| 5504 | pThis->pInputStack = pPopped->pUp;
|
---|
| 5505 | RTMemFree(pPopped);
|
---|
[41179] | 5506 | }
|
---|
[41186] | 5507 |
|
---|
[41179] | 5508 | return rcExit;
|
---|
| 5509 | }
|
---|
| 5510 |
|
---|
| 5511 |
|
---|
| 5512 | /**
|
---|
[41204] | 5513 | * Opens the input and output streams.
|
---|
| 5514 | *
|
---|
| 5515 | * @returns Exit code.
|
---|
| 5516 | * @param pThis The C preprocessor instance.
|
---|
| 5517 | */
|
---|
| 5518 | static RTEXITCODE vbcppOpenStreams(PVBCPP pThis)
|
---|
| 5519 | {
|
---|
[100618] | 5520 | const char * const pszInput = pThis->pszInput ? pThis->pszInput : "stdin";
|
---|
| 5521 | size_t const cchName = strlen(pszInput);
|
---|
| 5522 | PVBCPPINPUT const pInput = (PVBCPPINPUT)RTMemAlloc(RT_UOFFSETOF_DYN(VBCPPINPUT, szName[cchName + 1]));
|
---|
[41204] | 5523 | if (!pInput)
|
---|
| 5524 | return vbcppError(pThis, "out of memory");
|
---|
| 5525 | pInput->pUp = pThis->pInputStack;
|
---|
| 5526 | pInput->pszSpecified = pInput->szName;
|
---|
[100618] | 5527 | memcpy(pInput->szName, pszInput, cchName + 1);
|
---|
[41204] | 5528 | pThis->pInputStack = pInput;
|
---|
[100618] | 5529 | int rc;
|
---|
| 5530 | if (pThis->pszInput)
|
---|
| 5531 | {
|
---|
| 5532 | rc = ScmStreamInitForReading(&pInput->StrmInput, pThis->pszInput);
|
---|
| 5533 | if (RT_FAILURE(rc))
|
---|
| 5534 | return vbcppError(pThis, "ScmStreamInitForReading returned %Rrc when opening and reading in input file (%s)",
|
---|
| 5535 | rc, pThis->pszInput);
|
---|
| 5536 | }
|
---|
| 5537 | else
|
---|
| 5538 | {
|
---|
| 5539 | rc = ScmStreamInitForReadingFromStdInput(&pInput->StrmInput);
|
---|
| 5540 | if (RT_FAILURE(rc))
|
---|
| 5541 | return vbcppError(pThis, "ScmStreamInitForReadingFromStdInput returned %Rrc", rc);
|
---|
[41204] | 5542 |
|
---|
[100618] | 5543 | }
|
---|
| 5544 |
|
---|
[41204] | 5545 | rc = ScmStreamInitForWriting(&pThis->StrmOutput, &pInput->StrmInput);
|
---|
| 5546 | if (RT_FAILURE(rc))
|
---|
| 5547 | return vbcppError(pThis, "ScmStreamInitForWriting returned %Rrc", rc);
|
---|
| 5548 |
|
---|
| 5549 | pThis->fStrmOutputValid = true;
|
---|
| 5550 | return RTEXITCODE_SUCCESS;
|
---|
| 5551 | }
|
---|
| 5552 |
|
---|
| 5553 |
|
---|
| 5554 | /**
|
---|
| 5555 | * Changes the preprocessing mode.
|
---|
| 5556 | *
|
---|
| 5557 | * @param pThis The C preprocessor instance.
|
---|
| 5558 | * @param enmMode The new mode.
|
---|
| 5559 | */
|
---|
| 5560 | static void vbcppSetMode(PVBCPP pThis, VBCPPMODE enmMode)
|
---|
| 5561 | {
|
---|
| 5562 | switch (enmMode)
|
---|
| 5563 | {
|
---|
| 5564 | case kVBCppMode_Standard:
|
---|
| 5565 | pThis->fKeepComments = false;
|
---|
| 5566 | pThis->fRespectSourceDefines = true;
|
---|
| 5567 | pThis->fAllowRedefiningCmdLineDefines = true;
|
---|
| 5568 | pThis->fPassThruDefines = false;
|
---|
| 5569 | pThis->fUndecidedConditionals = false;
|
---|
[41217] | 5570 | pThis->fPassThruPragmaD = false;
|
---|
| 5571 | pThis->fPassThruPragmaSTD = true;
|
---|
| 5572 | pThis->fPassThruPragmaOther = true;
|
---|
[100618] | 5573 | pThis->fPassThruError = false;
|
---|
[41217] | 5574 | pThis->fRemoveDroppedLines = false;
|
---|
[41204] | 5575 | pThis->fLineSplicing = true;
|
---|
| 5576 | pThis->enmIncludeAction = kVBCppIncludeAction_Include;
|
---|
| 5577 | break;
|
---|
| 5578 |
|
---|
| 5579 | case kVBCppMode_Selective:
|
---|
| 5580 | pThis->fKeepComments = true;
|
---|
| 5581 | pThis->fRespectSourceDefines = false;
|
---|
| 5582 | pThis->fAllowRedefiningCmdLineDefines = false;
|
---|
| 5583 | pThis->fPassThruDefines = true;
|
---|
| 5584 | pThis->fUndecidedConditionals = true;
|
---|
[41217] | 5585 | pThis->fPassThruPragmaD = true;
|
---|
| 5586 | pThis->fPassThruPragmaSTD = true;
|
---|
| 5587 | pThis->fPassThruPragmaOther = true;
|
---|
[100618] | 5588 | pThis->fPassThruError = true;
|
---|
[41217] | 5589 | pThis->fRemoveDroppedLines = true;
|
---|
[41204] | 5590 | pThis->fLineSplicing = false;
|
---|
| 5591 | pThis->enmIncludeAction = kVBCppIncludeAction_PassThru;
|
---|
| 5592 | break;
|
---|
| 5593 |
|
---|
| 5594 | case kVBCppMode_SelectiveD:
|
---|
| 5595 | pThis->fKeepComments = true;
|
---|
| 5596 | pThis->fRespectSourceDefines = true;
|
---|
| 5597 | pThis->fAllowRedefiningCmdLineDefines = false;
|
---|
| 5598 | pThis->fPassThruDefines = false;
|
---|
| 5599 | pThis->fUndecidedConditionals = false;
|
---|
[41217] | 5600 | pThis->fPassThruPragmaD = true;
|
---|
| 5601 | pThis->fPassThruPragmaSTD = false;
|
---|
| 5602 | pThis->fPassThruPragmaOther = false;
|
---|
[100618] | 5603 | pThis->fPassThruError = false;
|
---|
[41217] | 5604 | pThis->fRemoveDroppedLines = true;
|
---|
[41204] | 5605 | pThis->fLineSplicing = false;
|
---|
| 5606 | pThis->enmIncludeAction = kVBCppIncludeAction_Drop;
|
---|
| 5607 | break;
|
---|
| 5608 |
|
---|
| 5609 | default:
|
---|
| 5610 | AssertFailedReturnVoid();
|
---|
| 5611 | }
|
---|
| 5612 | pThis->enmMode = enmMode;
|
---|
| 5613 | }
|
---|
| 5614 |
|
---|
| 5615 |
|
---|
| 5616 | /**
|
---|
| 5617 | * Parses the command line options.
|
---|
| 5618 | *
|
---|
| 5619 | * @returns Program exit code. Exit on non-success or if *pfExit is set.
|
---|
| 5620 | * @param pThis The C preprocessor instance.
|
---|
| 5621 | * @param argc The argument count.
|
---|
| 5622 | * @param argv The argument vector.
|
---|
| 5623 | * @param pfExit Pointer to the exit indicator.
|
---|
| 5624 | */
|
---|
| 5625 | static RTEXITCODE vbcppParseOptions(PVBCPP pThis, int argc, char **argv, bool *pfExit)
|
---|
| 5626 | {
|
---|
| 5627 | RTEXITCODE rcExit;
|
---|
| 5628 |
|
---|
| 5629 | *pfExit = false;
|
---|
| 5630 |
|
---|
| 5631 | /*
|
---|
| 5632 | * Option config.
|
---|
| 5633 | */
|
---|
| 5634 | static RTGETOPTDEF const s_aOpts[] =
|
---|
| 5635 | {
|
---|
| 5636 | { "--define", 'D', RTGETOPT_REQ_STRING },
|
---|
| 5637 | { "--include-dir", 'I', RTGETOPT_REQ_STRING },
|
---|
| 5638 | { "--undefine", 'U', RTGETOPT_REQ_STRING },
|
---|
| 5639 | { "--keep-comments", 'C', RTGETOPT_REQ_NOTHING },
|
---|
| 5640 | { "--strip-comments", 'c', RTGETOPT_REQ_NOTHING },
|
---|
| 5641 | { "--D-strip", 'd', RTGETOPT_REQ_NOTHING },
|
---|
[100555] | 5642 | #define OPT_MODE 1000
|
---|
| 5643 | { "--mode", OPT_MODE, RTGETOPT_REQ_STRING },
|
---|
[41204] | 5644 | };
|
---|
| 5645 |
|
---|
| 5646 | RTGETOPTUNION ValueUnion;
|
---|
| 5647 | RTGETOPTSTATE GetOptState;
|
---|
| 5648 | int rc = RTGetOptInit(&GetOptState, argc, argv, &s_aOpts[0], RT_ELEMENTS(s_aOpts), 1, RTGETOPTINIT_FLAGS_OPTS_FIRST);
|
---|
| 5649 | AssertReleaseRCReturn(rc, RTEXITCODE_FAILURE);
|
---|
| 5650 |
|
---|
| 5651 | /*
|
---|
| 5652 | * Process the options.
|
---|
| 5653 | */
|
---|
| 5654 | while ((rc = RTGetOpt(&GetOptState, &ValueUnion)) != 0)
|
---|
| 5655 | {
|
---|
| 5656 | switch (rc)
|
---|
| 5657 | {
|
---|
| 5658 | case 'c':
|
---|
| 5659 | pThis->fKeepComments = false;
|
---|
| 5660 | break;
|
---|
| 5661 |
|
---|
| 5662 | case 'C':
|
---|
| 5663 | pThis->fKeepComments = false;
|
---|
| 5664 | break;
|
---|
| 5665 |
|
---|
| 5666 | case 'd':
|
---|
| 5667 | vbcppSetMode(pThis, kVBCppMode_SelectiveD);
|
---|
| 5668 | break;
|
---|
| 5669 |
|
---|
[100555] | 5670 | case OPT_MODE:
|
---|
| 5671 | if ( strcmp(ValueUnion.psz, "standard") == 0
|
---|
| 5672 | || strcmp(ValueUnion.psz, "std") == 0)
|
---|
| 5673 | vbcppSetMode(pThis, kVBCppMode_Standard);
|
---|
| 5674 | else if ( strcmp(ValueUnion.psz, "selective") == 0
|
---|
| 5675 | || strcmp(ValueUnion.psz, "sel") == 0)
|
---|
| 5676 | vbcppSetMode(pThis, kVBCppMode_Selective);
|
---|
| 5677 | else if ( strcmp(ValueUnion.psz, "selective-D") == 0
|
---|
| 5678 | || strcmp(ValueUnion.psz, "D-strip") == 0)
|
---|
| 5679 | vbcppSetMode(pThis, kVBCppMode_SelectiveD);
|
---|
| 5680 | else
|
---|
| 5681 | return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Unknown mode '%s'!", ValueUnion.psz);
|
---|
| 5682 | break;
|
---|
| 5683 |
|
---|
[41204] | 5684 | case 'D':
|
---|
| 5685 | {
|
---|
| 5686 | const char *pszEqual = strchr(ValueUnion.psz, '=');
|
---|
| 5687 | if (pszEqual)
|
---|
[41226] | 5688 | rcExit = vbcppMacroAdd(pThis, ValueUnion.psz, pszEqual - ValueUnion.psz, pszEqual + 1, RTSTR_MAX, true);
|
---|
[41204] | 5689 | else
|
---|
[41226] | 5690 | rcExit = vbcppMacroAdd(pThis, ValueUnion.psz, RTSTR_MAX, "1", 1, true);
|
---|
[41204] | 5691 | if (rcExit != RTEXITCODE_SUCCESS)
|
---|
| 5692 | return rcExit;
|
---|
| 5693 | break;
|
---|
| 5694 | }
|
---|
| 5695 |
|
---|
| 5696 | case 'I':
|
---|
| 5697 | rcExit = vbcppAddInclude(pThis, ValueUnion.psz);
|
---|
| 5698 | if (rcExit != RTEXITCODE_SUCCESS)
|
---|
| 5699 | return rcExit;
|
---|
| 5700 | break;
|
---|
| 5701 |
|
---|
| 5702 | case 'U':
|
---|
[41226] | 5703 | rcExit = vbcppMacroUndef(pThis, ValueUnion.psz, RTSTR_MAX, true);
|
---|
[41204] | 5704 | break;
|
---|
| 5705 |
|
---|
| 5706 | case 'h':
|
---|
[100555] | 5707 | RTPrintf("Usage: VBoxCPP [options] <input.c> [output.ii]\n"
|
---|
| 5708 | "\n"
|
---|
| 5709 | "Options:\n"
|
---|
| 5710 | " --mode={mode}\n"
|
---|
| 5711 | " Sets the processing mode and asscoiated defaults:\n"
|
---|
| 5712 | " - selective / sel: (default)\n"
|
---|
| 5713 | " Selectively applying the defines from the command line\n"
|
---|
| 5714 | " and preserving the rest.\n"
|
---|
| 5715 | " - selective-D / D-strip:\n"
|
---|
| 5716 | " Selectively applying the defines from the command line\n"
|
---|
| 5717 | " and removing things DTrace doesn't like.\n"
|
---|
| 5718 | " - standard / std:\n"
|
---|
| 5719 | " Standard C preprocesing. This is incomplete as, among other\n"
|
---|
| 5720 | " things, include processing has not yet been implemented.\n"
|
---|
| 5721 | " --D-strip\n"
|
---|
| 5722 | " Alias for --mode=selective-D\n"
|
---|
| 5723 | " --define={macro}[=val], -D{macro}[=val]\n"
|
---|
| 5724 | " Defines a macro.\n"
|
---|
| 5725 | " --undefine={macro}, -U{macro}\n"
|
---|
| 5726 | " Undefines a macro.\n"
|
---|
| 5727 | " --include-dir={dir}, -I{dir}\n"
|
---|
| 5728 | " Adds {dir} to the list of include directories that should\n"
|
---|
| 5729 | " be searched for header files."
|
---|
| 5730 | " --keep-comments, -C\n"
|
---|
| 5731 | " Keep comments unchanged in the output.\n"
|
---|
| 5732 | " --strip-comments, -c\n"
|
---|
| 5733 | " Strip comments in the output. (default)\n"
|
---|
| 5734 | "\n"
|
---|
| 5735 | "This is not a complete C preprocessor implementation (yet), as its use is\n"
|
---|
| 5736 | "mainly to selectively apply and eliminate defines and/or things are DTrace\n"
|
---|
| 5737 | "finds problematic. Among the missing features are:\n"
|
---|
| 5738 | " - Support for ternary expressions.\n"
|
---|
| 5739 | " - Including header files (in standard mode).\n"
|
---|
| 5740 | " - +++\n"
|
---|
| 5741 | );
|
---|
[41204] | 5742 | *pfExit = true;
|
---|
| 5743 | return RTEXITCODE_SUCCESS;
|
---|
| 5744 |
|
---|
| 5745 | case 'V':
|
---|
| 5746 | {
|
---|
| 5747 | /* The following is assuming that svn does it's job here. */
|
---|
| 5748 | static const char s_szRev[] = "$Revision: 103384 $";
|
---|
| 5749 | const char *psz = RTStrStripL(strchr(s_szRev, ' '));
|
---|
| 5750 | RTPrintf("r%.*s\n", strchr(psz, ' ') - psz, psz);
|
---|
| 5751 | *pfExit = true;
|
---|
| 5752 | return RTEXITCODE_SUCCESS;
|
---|
| 5753 | }
|
---|
| 5754 |
|
---|
| 5755 | case VINF_GETOPT_NOT_OPTION:
|
---|
| 5756 | if (!pThis->pszInput)
|
---|
| 5757 | pThis->pszInput = ValueUnion.psz;
|
---|
| 5758 | else if (!pThis->pszOutput)
|
---|
| 5759 | pThis->pszOutput = ValueUnion.psz;
|
---|
| 5760 | else
|
---|
| 5761 | return RTMsgErrorExit(RTEXITCODE_SYNTAX, "too many file arguments");
|
---|
| 5762 | break;
|
---|
| 5763 |
|
---|
| 5764 |
|
---|
| 5765 | /*
|
---|
| 5766 | * Errors and bugs.
|
---|
| 5767 | */
|
---|
| 5768 | default:
|
---|
| 5769 | return RTGetOptPrintError(rc, &ValueUnion);
|
---|
| 5770 | }
|
---|
| 5771 | }
|
---|
| 5772 |
|
---|
| 5773 | return RTEXITCODE_SUCCESS;
|
---|
| 5774 | }
|
---|
| 5775 |
|
---|
| 5776 |
|
---|
| 5777 | /**
|
---|
[41186] | 5778 | * Terminates the preprocessor.
|
---|
| 5779 | *
|
---|
| 5780 | * This may return failure if an error was delayed.
|
---|
| 5781 | *
|
---|
[41179] | 5782 | * @returns Exit code.
|
---|
| 5783 | * @param pThis The C preprocessor instance.
|
---|
| 5784 | */
|
---|
| 5785 | static RTEXITCODE vbcppTerm(PVBCPP pThis)
|
---|
| 5786 | {
|
---|
| 5787 | /*
|
---|
| 5788 | * Flush the output first.
|
---|
| 5789 | */
|
---|
| 5790 | if (pThis->fStrmOutputValid)
|
---|
| 5791 | {
|
---|
| 5792 | if (pThis->pszOutput)
|
---|
| 5793 | {
|
---|
| 5794 | int rc = ScmStreamWriteToFile(&pThis->StrmOutput, "%s", pThis->pszOutput);
|
---|
| 5795 | if (RT_FAILURE(rc))
|
---|
| 5796 | vbcppError(pThis, "ScmStreamWriteToFile failed with %Rrc when writing '%s'", rc, pThis->pszOutput);
|
---|
| 5797 | }
|
---|
| 5798 | else
|
---|
| 5799 | {
|
---|
| 5800 | int rc = ScmStreamWriteToStdOut(&pThis->StrmOutput);
|
---|
| 5801 | if (RT_FAILURE(rc))
|
---|
| 5802 | vbcppError(pThis, "ScmStreamWriteToStdOut failed with %Rrc", rc);
|
---|
| 5803 | }
|
---|
| 5804 | }
|
---|
| 5805 |
|
---|
| 5806 | /*
|
---|
| 5807 | * Cleanup.
|
---|
| 5808 | */
|
---|
[41186] | 5809 | while (pThis->pInputStack)
|
---|
| 5810 | {
|
---|
| 5811 | ScmStreamDelete(&pThis->pInputStack->StrmInput);
|
---|
| 5812 | void *pvFree = pThis->pInputStack;
|
---|
| 5813 | pThis->pInputStack = pThis->pInputStack->pUp;
|
---|
| 5814 | RTMemFree(pvFree);
|
---|
| 5815 | }
|
---|
| 5816 |
|
---|
[41179] | 5817 | ScmStreamDelete(&pThis->StrmOutput);
|
---|
| 5818 |
|
---|
[41226] | 5819 | RTStrSpaceDestroy(&pThis->StrSpace, vbcppMacroFree, NULL);
|
---|
[41179] | 5820 | pThis->StrSpace = NULL;
|
---|
| 5821 |
|
---|
| 5822 | uint32_t i = pThis->cIncludes;
|
---|
| 5823 | while (i-- > 0)
|
---|
| 5824 | RTStrFree(pThis->papszIncludes[i]);
|
---|
| 5825 | RTMemFree(pThis->papszIncludes);
|
---|
| 5826 | pThis->papszIncludes = NULL;
|
---|
| 5827 |
|
---|
| 5828 | return pThis->rcExit;
|
---|
| 5829 | }
|
---|
| 5830 |
|
---|
| 5831 |
|
---|
[41204] | 5832 | /**
|
---|
| 5833 | * Initializes the C preprocessor instance data.
|
---|
| 5834 | *
|
---|
| 5835 | * @param pThis The C preprocessor instance data.
|
---|
| 5836 | */
|
---|
| 5837 | static void vbcppInit(PVBCPP pThis)
|
---|
| 5838 | {
|
---|
| 5839 | vbcppSetMode(pThis, kVBCppMode_Selective);
|
---|
| 5840 | pThis->cIncludes = 0;
|
---|
| 5841 | pThis->papszIncludes = NULL;
|
---|
| 5842 | pThis->pszInput = NULL;
|
---|
| 5843 | pThis->pszOutput = NULL;
|
---|
| 5844 | pThis->StrSpace = NULL;
|
---|
| 5845 | pThis->UndefStrSpace = NULL;
|
---|
| 5846 | pThis->cCondStackDepth = 0;
|
---|
| 5847 | pThis->pCondStack = NULL;
|
---|
| 5848 | pThis->fIf0Mode = false;
|
---|
[41217] | 5849 | pThis->fJustDroppedLine = false;
|
---|
[41204] | 5850 | pThis->fMaybePreprocessorLine = true;
|
---|
| 5851 | VBCPP_BITMAP_EMPTY(pThis->bmDefined);
|
---|
| 5852 | pThis->cCondStackDepth = 0;
|
---|
| 5853 | pThis->pInputStack = NULL;
|
---|
| 5854 | RT_ZERO(pThis->StrmOutput);
|
---|
| 5855 | pThis->rcExit = RTEXITCODE_SUCCESS;
|
---|
| 5856 | pThis->fStrmOutputValid = false;
|
---|
| 5857 | }
|
---|
[41179] | 5858 |
|
---|
[41204] | 5859 |
|
---|
| 5860 |
|
---|
[41177] | 5861 | int main(int argc, char **argv)
|
---|
| 5862 | {
|
---|
| 5863 | int rc = RTR3InitExe(argc, &argv, 0);
|
---|
| 5864 | if (RT_FAILURE(rc))
|
---|
| 5865 | return RTMsgInitFailure(rc);
|
---|
| 5866 |
|
---|
[41179] | 5867 | /*
|
---|
| 5868 | * Do the job. The code says it all.
|
---|
[41177] | 5869 | */
|
---|
| 5870 | VBCPP This;
|
---|
| 5871 | vbcppInit(&This);
|
---|
| 5872 | bool fExit;
|
---|
| 5873 | RTEXITCODE rcExit = vbcppParseOptions(&This, argc, argv, &fExit);
|
---|
| 5874 | if (!fExit && rcExit == RTEXITCODE_SUCCESS)
|
---|
| 5875 | {
|
---|
[41179] | 5876 | rcExit = vbcppOpenStreams(&This);
|
---|
| 5877 | if (rcExit == RTEXITCODE_SUCCESS)
|
---|
[41186] | 5878 | rcExit = vbcppPreprocess(&This);
|
---|
[41177] | 5879 | }
|
---|
| 5880 |
|
---|
[41179] | 5881 | if (rcExit == RTEXITCODE_SUCCESS)
|
---|
| 5882 | rcExit = vbcppTerm(&This);
|
---|
| 5883 | else
|
---|
| 5884 | vbcppTerm(&This);
|
---|
[41177] | 5885 | return rcExit;
|
---|
| 5886 | }
|
---|
| 5887 |
|
---|