35 #include "precompiled.h"
42 #define MAX_MACRO_ARGS 16
81 if (new_alloc != Allocated)
83 Allocated = new_alloc;
84 Buffer = (
char *)realloc (Buffer, Allocated);
92 char *newstr = (
char *)malloc (Allocated);
93 memcpy (newstr, String,
Length);
107 while (isspace (String [i]))
111 if (String [i] ==
'0')
113 if (
Length > i + 1 && String [i + 1] ==
'x')
121 long c = long (String [i]);
126 if (c >=
'a' && c <=
'z')
134 c -= (
'A' -
'9' - 1);
139 val = (val * base) + c;
144 if (!isspace (String [i]))
154 int len = snprintf (tmp,
sizeof (tmp),
"%ld", iValue);
162 static const char newlines [8] =
163 {
'\n',
'\n',
'\n',
'\n',
'\n',
'\n',
'\n',
'\n' };
167 Append (newlines, 8);
171 Append (newlines, iCount);
176 if (Type == TK_EOS || Type == TK_ERROR)
179 const char *s = String;
184 const char *n = (
const char *)memchr (s,
'\n', l);
206 for (i = 0; i < iNumArgs; i++)
207 cpp.
Define (Args [i].String, Args [i].Length,
210 for (; i < NumArgs; i++)
211 cpp.
Define (Args [i].String, Args [i].Length,
"", 0);
219 for (
int j = NumArgs - 1; j >= 0; j--)
220 cpp.
Undef (Args [j].String, Args [j].Length);
230 const char *iToken,
size_t iTokenLen)
234 LOGERROR(L
"Preprocessor error: line %d: %hs: '%.*hs'\n",
235 iLine, iError,
int (iTokenLen), iToken);
237 LOGERROR(L
"Preprocessor error: line %d: %hs\n", iLine, iError);
271 const char *begin =
Source;
275 if (c ==
'\n' || (c ==
'\r' && *
Source ==
'\n'))
283 else if (isspace (c))
293 else if (isdigit (c))
307 else if (c ==
'_' || isalnum (c))
317 else if (c ==
'"' || c ==
'\'')
336 else if (c ==
'/' && *
Source ==
'/')
344 else if (c ==
'/' && *
Source ==
'*')
360 else if (c ==
'#' &&
BOL)
386 else if (c ==
'<' && (*
Source ==
'<' || *
Source ==
'='))
388 else if (c ==
'!' && *
Source ==
'=')
390 else if (c ==
'=' && *
Source ==
'=')
392 else if ((c ==
'|' || c ==
'&' || c ==
'^') && *
Source == c)
401 if (cur->Name == iToken)
438 snprintf (tmp,
sizeof (tmp),
"Macro `%.*s' passed %d arguments, but takes just %d",
441 Error (old_line, tmp);
475 Token &oResult,
int iLine,
int iOpPriority)
493 if (strchr (
"+-!~", oResult.
String [0]))
495 char uop = oResult.
String [0];
498 if (!
GetValue (oResult, val, iLine))
500 snprintf (tmp,
sizeof (tmp),
"Unary '%c' not applicable", uop);
501 Error (iLine, tmp, &oResult);
512 else if (oResult.
String [0] ==
'(')
519 Error (iLine,
"Unclosed parenthesis in #if expression");
547 case '|': prio = 4;
break;
548 case '^': prio = 5;
break;
549 case '&': prio = 6;
break;
551 case '>': prio = 8;
break;
553 case '-': prio = 10;
break;
556 case '%': prio = 11;
break;
561 case '|':
if (op.
String [1] ==
'|') prio = 2;
break;
562 case '&':
if (op.
String [1] ==
'&') prio = 3;
break;
563 case '=':
if (op.
String [1] ==
'=') prio = 7;
break;
564 case '!':
if (op.
String [1] ==
'=') prio = 7;
break;
568 else if (op.
String [1] ==
'<')
574 else if (op.
String [1] ==
'>')
581 Error (iLine,
"Expecting operator, got", &op);
585 if (iOpPriority >= prio)
591 if (!
GetValue (oResult, vlop, iLine))
593 snprintf (tmp,
sizeof (tmp),
"Left operand of '%.*s' is not a number",
595 Error (iLine, tmp, &oResult);
600 snprintf (tmp,
sizeof (tmp),
"Right operand of '%.*s' is not a number",
602 Error (iLine, tmp, &rop);
636 case '^': oResult.
SetValue (vlop ^ vrop);
break;
637 case '!': oResult.
SetValue (vlop != vrop);
break;
638 case '=': oResult.
SetValue (vlop == vrop);
break;
639 case '+': oResult.
SetValue (vlop + vrop);
break;
640 case '-': oResult.
SetValue (vlop - vrop);
break;
641 case '*': oResult.
SetValue (vlop * vrop);
break;
646 Error (iLine,
"Division by zero");
663 const Token *vt = &iToken;
670 Error (iLine,
"Trying to evaluate an empty expression");
689 Error (iLine,
"Garbage after expression", &t);
710 bool rc =
GetValue (x, oValue, iLine);
723 Error (iLine,
"Not a numeric expression", vt);
729 Error (iLine,
"Unexpected token", vt);
752 (oArg.
String [0] ==
',' ||
766 unsigned int len = oArg.
Length;
773 Error (
Line,
"Unfinished list of arguments");
777 if (t.
String [0] ==
',' ||
837 Error (
Line,
"Too many arguments to macro");
846 Error (
Line,
"Unfinished list of arguments");
866 oArgs =
new Token [nargs];
867 for (
int i = 0; i < nargs; i++)
868 oArgs [i] = args [i];
880 Error (iLine,
"Macro name expected after #define");
927 Error (iLine,
"Expecting a macro name after #undef, got", &t);
942 Error (iLine,
"Warning: Ignoring garbage after directive", &t);
951 Error (iLine,
"Too many embedded #if directives");
961 Error (iLine,
"Expecting a macro name after #ifdef, got", &t);
977 Error (iLine,
"Warning: Ignoring garbage after directive", &t);
986 iParent->
Error (iParent->
Line,
"The defined() function takes exactly one argument");
990 const char *v = iParent->
IsDefined (iArgs [0]) ?
"1" :
"0";
1005 bool rc =
GetValue (iBody, val, iLine);
1009 defined.
Next = NULL;
1025 Error (iLine,
"#else without #if");
1033 Error (iLine,
"Warning: Ignoring garbage after #else", &iBody);
1043 Error (iLine,
"#endif without #if");
1048 Error (iLine,
"Warning: Ignoring garbage after #endif", &iBody);
1056 const char *directive = iToken.
String + 1;
1057 int dirlen = iToken.
Length - 1;
1058 while (dirlen && isspace (*directive))
1059 dirlen--, directive++;
1061 int old_line =
Line;
1112 #define IS_DIRECTIVE(s) \
1113 ((dirlen == sizeof (s) - 1) && (strncmp (directive, s, sizeof (s) - 1) == 0))
1140 Error (iLine,
"Unsupported preprocessor directive #elif");
1160 const char *iMacroValue,
size_t iMacroValueLen)
1179 Define (iMacroName, strlen(iMacroName), iMacroValue, strlen(iMacroValue));
1184 Define (iMacroName, strlen(iMacroName), iMacroValue);
1193 if ((*cur)->Name == name)
1196 (*cur)->
Next = NULL;
1202 cur = &(*cur)->
Next;
1218 int empty_lines = 0;
1221 bool old_output_enabled =
true;
1222 bool output_enabled =
true;
1223 int output_disabled_line = 0;
1227 int old_line =
Line;
1257 if (output_enabled != old_output_enabled)
1260 output.
AppendNL (old_line - output_disabled_line);
1262 output_disabled_line = old_line;
1263 old_output_enabled = output_enabled;
1297 Error (
Line,
"Unclosed #if at end of source");
char * Buffer
A memory-allocated string.
const char * Source
The current source text input.
void Define(const char *iMacroName, size_t iMacroNameLen, const char *iMacroValue, size_t iMacroValueLen)
Define a macro without parameters.
void Append(const char *iString, size_t iLength)
Append a string to this token.
int NumArgs
Number of arguments.
Token Expand(int iNumArgs, Token *iArgs, Macro *iMacros)
Expand the macro value (will not work for functions)
void Error(int iLine, const char *iError, const Token *iToken=NULL)
Call the error handler.
bool Undef(const char *iMacroName, size_t iMacroNameLen)
Undefine a macro.
CPreprocessor()
Create an empty preprocessor object.
size_t Length
Token length in bytes.
bool HandleDefine(Token &iBody, int iLine)
Handle a #define directive.
Token Parse(const Token &iSource)
Parse the input string and return a token containing the whole output.
const char * String
A pointer somewhere into the input buffer.
bool HandleIf(Token &iBody, int iLine)
Handle an #if directive.
bool HandleEndIf(Token &iBody, int iLine)
Handle an #endif directive.
Token * Args
The names of the arguments.
bool BOL
True if we are at beginning of line.
Token GetToken(bool iExpand)
Stateless tokenizer: Parse the input text and return the next token.
#define ENSURE(expr)
ensure the expression <expr> evaluates to non-zero.
Token GetArguments(int &oNumArgs, Token *&oArgs, bool iExpand)
Get all the arguments of a macro: '(' arg1 { ',' arg2 { ',' ...
virtual ~CPreprocessor()
Destroy the preprocessor object.
Token GetArgument(Token &oArg, bool iExpand)
Get a single function argument until next ',' or ')'.
Token HandleDirective(Token &iToken, int iLine)
Handle a preprocessor directive.
Macro * Next
Next macro in chained list.
size_t Allocated
True if string was allocated (and must be freed)
int CountNL()
Count number of newlines in this token.
bool HandleElse(Token &iBody, int iLine)
Handle an #else directive.
const char * SourceEnd
The end of the source text.
static ErrorHandlerFunc ErrorHandler
A pointer to the preprocessor's error handler.
bool GetValue(long &oValue) const
Get the numeric value of the token.
Macro * IsDefined(const Token &iToken)
Check if a macro is defined, and if so, return it.
Token Value
The macro value.
Token ExpandMacro(const Token &iToken)
Expand the given macro, if it exists.
Token(* ExpandFunc)(CPreprocessor *iParent, int iNumArgs, Token *iArgs)
A pointer to function implementation (if macro is really a func)
bool HandleIfDef(Token &iBody, int iLine)
Handle an #ifdef directive.
unsigned EnableOutput
A stack of 32 booleans packed into one value :)
bool Expanding
true if macro expansion is in progress
This is a simplistic C/C++-like preprocessor.
static float Length(const SVec3 v)
static void DefaultError(void *iData, int iLine, const char *iError, const char *iToken, size_t iTokenLen)
void AppendNL(int iCount)
Append given number of newlines to this token.
Token GetExpression(Token &oResult, int iLine, int iOpPriority=0)
Parse an expression, compute it and return the result.
Token Body
Unparsed macro body (keeps the whole raw unparsed macro body)
static size_t ClosestPow2(size_t x)
Return closest power of two not smaller than given number.
Macro * MacroList
The list of macros defined so far.
static Token ExpandDefined(CPreprocessor *iParent, int iNumArgs, Token *iArgs)
The implementation of the defined() preprocessor function.
bool GetValue(const Token &iToken, long &oValue, int iLine)
Get the numeric value of a token.
void * ErrorData
User-specific storage, passed to Error()
void(* ErrorHandlerFunc)(void *iData, int iLine, const char *iError, const char *iToken, size_t iTokenLen)
An error handler function type.
bool HandleUnDef(Token &iBody, int iLine)
Undefine a previously defined macro.
int Line
Current line number.
void SetValue(long iValue)
Set the numeric value of the token.