Merge branch 'cc65:master' into kim1
This commit is contained in:
@@ -1298,7 +1298,7 @@ static void EmitCode (EffAddr* A)
|
||||
break;
|
||||
|
||||
case 2:
|
||||
if (CPU == CPU_65816 && (A->AddrModeBit & (AM65_ABS | AM65_ABS_X | AM65_ABS_Y))) {
|
||||
if (CPU == CPU_65816 && (A->AddrModeBit & (AM65_ABS | AM65_ABS_X | AM65_ABS_Y | AM65_ABS_X_IND))) {
|
||||
/* This is a 16 bit mode that uses an address. If in 65816,
|
||||
** mode, force this address into 16 bit range to allow
|
||||
** addressing inside a 64K segment.
|
||||
|
||||
@@ -489,23 +489,6 @@ void MacDef (unsigned Style)
|
||||
** the .LOCAL command is detected and removed, at this time.
|
||||
*/
|
||||
while (1) {
|
||||
/* Check for include */
|
||||
if (CurTok.Tok == TOK_INCLUDE && Style == MAC_STYLE_CLASSIC) {
|
||||
/* Include another file */
|
||||
NextTok ();
|
||||
/* Name must follow */
|
||||
if (CurTok.Tok != TOK_STRCON) {
|
||||
ErrorSkip ("String constant expected");
|
||||
} else {
|
||||
SB_Terminate (&CurTok.SVal);
|
||||
if (NewInputFile (SB_GetConstBuf (&CurTok.SVal)) == 0) {
|
||||
/* Error opening the file, skip remainder of line */
|
||||
SkipUntilSep ();
|
||||
}
|
||||
}
|
||||
NextTok ();
|
||||
}
|
||||
|
||||
/* Check for end of macro */
|
||||
if (Style == MAC_STYLE_CLASSIC) {
|
||||
/* In classic macros, only .endmacro is allowed */
|
||||
|
||||
@@ -103,6 +103,7 @@
|
||||
<ClInclude Include="cc65\macrotab.h" />
|
||||
<ClInclude Include="cc65\opcodes.h" />
|
||||
<ClInclude Include="cc65\output.h" />
|
||||
<ClInclude Include="cc65\ppexpr.h" />
|
||||
<ClInclude Include="cc65\pragma.h" />
|
||||
<ClInclude Include="cc65\preproc.h" />
|
||||
<ClInclude Include="cc65\reginfo.h" />
|
||||
@@ -182,6 +183,7 @@
|
||||
<ClCompile Include="cc65\main.c" />
|
||||
<ClCompile Include="cc65\opcodes.c" />
|
||||
<ClCompile Include="cc65\output.c" />
|
||||
<ClCompile Include="cc65\ppexpr.c" />
|
||||
<ClCompile Include="cc65\pragma.c" />
|
||||
<ClCompile Include="cc65\preproc.c" />
|
||||
<ClCompile Include="cc65\reginfo.c" />
|
||||
|
||||
@@ -49,21 +49,6 @@
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Data */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
/* Map a generator function and its attributes to a token */
|
||||
typedef struct GenDesc {
|
||||
token_t Tok; /* Token to map to */
|
||||
unsigned Flags; /* Flags for generator function */
|
||||
void (*Func) (unsigned, unsigned long); /* Generator func */
|
||||
} GenDesc;
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Code */
|
||||
/*****************************************************************************/
|
||||
@@ -605,6 +590,12 @@ void OpAssign (const GenDesc* Gen, ExprDesc* Expr, const char* Op)
|
||||
/* Normal straight 'op=' */
|
||||
OpAssignArithmetic (Gen, Expr, Op);
|
||||
}
|
||||
|
||||
/* Expression has had side effects */
|
||||
Expr->Flags |= E_SIDE_EFFECTS;
|
||||
|
||||
/* Propagate viral flags */
|
||||
ED_PropagateFrom (Expr, &Expr2);
|
||||
}
|
||||
|
||||
|
||||
@@ -725,4 +716,10 @@ void OpAddSubAssign (const GenDesc* Gen, ExprDesc *Expr, const char* Op)
|
||||
|
||||
/* Expression is an rvalue in the primary now */
|
||||
ED_FinalizeRValLoad (Expr);
|
||||
|
||||
/* Expression has had side effects */
|
||||
Expr->Flags |= E_SIDE_EFFECTS;
|
||||
|
||||
/* Propagate viral flags */
|
||||
ED_PropagateFrom (Expr, &Expr2);
|
||||
}
|
||||
|
||||
@@ -1797,7 +1797,6 @@ void CE_GenRegInfo (CodeEntry* E, RegContents* InputRegs)
|
||||
}
|
||||
} else if (strcmp (E->Arg, "tosaslax") == 0) {
|
||||
if (RegValIsKnown (In->RegA) && (In->RegA & 0x0F) >= 8) {
|
||||
printf ("Hey!\n");
|
||||
Out->RegA = 0;
|
||||
}
|
||||
} else if (strcmp (E->Arg, "tosorax") == 0) {
|
||||
|
||||
@@ -461,7 +461,8 @@ void g_importstartup (void)
|
||||
|
||||
|
||||
void g_importmainargs (void)
|
||||
/* Forced import of a special symbol that handles arguments to main */
|
||||
/* Forced import of a special symbol that handles arguments to main. This will
|
||||
happen only when the compiler sees a main function that takes arguments. */
|
||||
{
|
||||
AddTextLine ("\t.forceimport\tinitmainargs");
|
||||
}
|
||||
@@ -4920,5 +4921,25 @@ void g_switch (Collection* Nodes, unsigned DefaultLabel, unsigned Depth)
|
||||
void g_asmcode (struct StrBuf* B)
|
||||
/* Output one line of assembler code. */
|
||||
{
|
||||
AddCodeLine ("%.*s", (int) SB_GetLen (B), SB_GetConstBuf (B));
|
||||
int len = (int) SB_GetLen(B);
|
||||
const char *buf = SB_GetConstBuf(B);
|
||||
|
||||
/* remove whitespace at end of line */
|
||||
/* NOTE: This masks problems in ParseInsn(), which in some cases seems to
|
||||
rely on no whitespace being present at the end of a line in generated
|
||||
code (see issue #1252). However, it generally seems to be a good
|
||||
idea to remove trailing whitespace from (inline) assembly, so we
|
||||
do it anyway. */
|
||||
while (len) {
|
||||
switch (buf[len - 1]) {
|
||||
case '\n':
|
||||
case ' ':
|
||||
case '\t':
|
||||
--len;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
AddCodeLine ("%.*s", len, buf);
|
||||
}
|
||||
|
||||
@@ -82,8 +82,11 @@ static void Parse (void)
|
||||
SymEntry* Entry;
|
||||
FuncDesc* FuncDef = 0;
|
||||
|
||||
/* Go... */
|
||||
NextToken ();
|
||||
/* Initialization for deferred operations */
|
||||
InitDeferredOps ();
|
||||
|
||||
/* Fill up the next token with a bogus semicolon and start the tokenizer */
|
||||
NextTok.Tok = TOK_SEMI;
|
||||
NextToken ();
|
||||
|
||||
/* Parse until end of input */
|
||||
@@ -207,7 +210,7 @@ static void Parse (void)
|
||||
/* Allow initialization */
|
||||
if (CurTok.Tok == TOK_ASSIGN) {
|
||||
|
||||
/* This is a definition */
|
||||
/* This is a definition with storage */
|
||||
if (SymIsDef (Entry)) {
|
||||
Error ("Global variable '%s' has already been defined",
|
||||
Entry->Name);
|
||||
@@ -218,14 +221,16 @@ static void Parse (void)
|
||||
** void types in ISO modes.
|
||||
*/
|
||||
if (Size == 0) {
|
||||
if (!IsTypeVoid (Decl.Type)) {
|
||||
if (!IsEmptiableObjectType (Decl.Type)) {
|
||||
if (!IsTypeArray (Decl.Type)) {
|
||||
/* Size is unknown and not an array */
|
||||
Error ("Variable '%s' has unknown size", Decl.Ident);
|
||||
Error ("Cannot initialize variable '%s' of unknown size", Decl.Ident);
|
||||
}
|
||||
} else if (IS_Get (&Standard) != STD_CC65) {
|
||||
/* We cannot declare variables of type void */
|
||||
Error ("Illegal type for variable '%s'", Decl.Ident);
|
||||
Error ("Illegal type '%s' for variable '%s'",
|
||||
GetFullTypeName (Decl.Type),
|
||||
Decl.Ident);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -249,16 +254,26 @@ static void Parse (void)
|
||||
ParseInit (Entry->Type);
|
||||
} else {
|
||||
|
||||
/* This is a declaration */
|
||||
if (IsTypeVoid (Decl.Type)) {
|
||||
/* We cannot declare variables of type void */
|
||||
Error ("Illegal type for variable '%s'", Decl.Ident);
|
||||
Entry->Flags &= ~(SC_STORAGE | SC_DEF);
|
||||
} else if (Size == 0 && SymIsDef (Entry)) {
|
||||
} else if (Size == 0 && SymIsDef (Entry) && !IsEmptiableObjectType (Decl.Type)) {
|
||||
/* Size is unknown. Is it an array? */
|
||||
if (!IsTypeArray (Decl.Type)) {
|
||||
Error ("Variable '%s' has unknown size", Decl.Ident);
|
||||
}
|
||||
} else {
|
||||
/* Check for enum forward declaration.
|
||||
** Warn about it when extensions are not allowed.
|
||||
*/
|
||||
if (Size == 0 && IsTypeEnum (Decl.Type)) {
|
||||
if (IS_Get (&Standard) != STD_CC65) {
|
||||
Warning ("ISO C forbids forward references to 'enum' types");
|
||||
}
|
||||
}
|
||||
|
||||
/* A global (including static) uninitialized variable is
|
||||
** only a tentative definition. For example, this is valid:
|
||||
** int i;
|
||||
@@ -285,17 +300,9 @@ static void Parse (void)
|
||||
}
|
||||
|
||||
/* Make the symbol zeropage according to the segment address size */
|
||||
if ((Entry->Flags & SC_EXTERN) != 0) {
|
||||
if ((Entry->Flags & SC_STATIC) != 0) {
|
||||
if (GetSegAddrSize (GetSegName (CS->CurDSeg)) == ADDR_SIZE_ZP) {
|
||||
Entry->Flags |= SC_ZEROPAGE;
|
||||
/* Check for enum forward declaration.
|
||||
** Warn about it when extensions are not allowed.
|
||||
*/
|
||||
if (Size == 0 && IsTypeEnum (Decl.Type)) {
|
||||
if (IS_Get (&Standard) != STD_CC65) {
|
||||
Warning ("ISO C forbids forward references to 'enum' types");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -334,6 +341,9 @@ static void Parse (void)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/* Done with deferred operations */
|
||||
DoneDeferredOps ();
|
||||
}
|
||||
|
||||
|
||||
@@ -386,6 +396,11 @@ void Compile (const char* FileName)
|
||||
DefineNumericMacro ("__EAGERLY_INLINE_FUNCS__", 1);
|
||||
}
|
||||
|
||||
/* Placeholders for __FILE__, __LINE__ and __COUNTER__ macros */
|
||||
DefineTextMacro ("__FILE__", "");
|
||||
DefineTextMacro ("__LINE__", "");
|
||||
DefineTextMacro ("__COUNTER__", "");
|
||||
|
||||
/* __TIME__ and __DATE__ macros */
|
||||
Time = time (0);
|
||||
TM = localtime (&Time);
|
||||
@@ -399,7 +414,13 @@ void Compile (const char* FileName)
|
||||
/* DefineNumericMacro ("__STDC__", 1); <- not now */
|
||||
DefineNumericMacro ("__STDC_HOSTED__", 1);
|
||||
|
||||
InitDeferredOps ();
|
||||
/* Stuff unsupported */
|
||||
if (IS_Get (&Standard) > STD_C99) {
|
||||
DefineNumericMacro ("__STDC_NO_ATOMICS__", 1);
|
||||
DefineNumericMacro ("__STDC_NO_COMPLEX__", 1);
|
||||
DefineNumericMacro ("__STDC_NO_THREADS__", 1);
|
||||
DefineNumericMacro ("__STDC_NO_VLA__", 1);
|
||||
}
|
||||
|
||||
/* Create the base lexical level */
|
||||
EnterGlobalLevel ();
|
||||
@@ -419,6 +440,9 @@ void Compile (const char* FileName)
|
||||
/* Generate the code generator preamble */
|
||||
g_preamble ();
|
||||
|
||||
/* Init preprocessor */
|
||||
InitPreprocess ();
|
||||
|
||||
/* Open the input file */
|
||||
OpenMainFile (FileName);
|
||||
|
||||
@@ -429,10 +453,8 @@ void Compile (const char* FileName)
|
||||
OpenOutputFile ();
|
||||
|
||||
/* Preprocess each line and write it to the output file */
|
||||
while (NextLine ()) {
|
||||
Preprocess ();
|
||||
WriteOutput ("%.*s\n", (int) SB_GetLen (Line), SB_GetConstBuf (Line));
|
||||
}
|
||||
while (PreprocessNextLine ())
|
||||
{ /* Nothing */ }
|
||||
|
||||
/* Close the output file */
|
||||
CloseOutputFile ();
|
||||
@@ -490,9 +512,11 @@ void Compile (const char* FileName)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
DoneDeferredOps ();
|
||||
/* Done with preprocessor */
|
||||
DonePreprocess ();
|
||||
|
||||
if (Debug) {
|
||||
PrintMacroStats (stdout);
|
||||
|
||||
@@ -805,7 +805,11 @@ unsigned CheckedSizeOf (const Type* T)
|
||||
{
|
||||
unsigned Size = SizeOf (T);
|
||||
if (Size == 0) {
|
||||
Error ("Size of type '%s' is unknown", GetFullTypeName (T));
|
||||
if (HasUnknownSize (T + 1)) {
|
||||
Error ("Size of type '%s' is unknown", GetFullTypeName (T));
|
||||
} else {
|
||||
Error ("Size of type '%s' is 0", GetFullTypeName (T));
|
||||
}
|
||||
Size = SIZEOF_CHAR; /* Don't return zero */
|
||||
}
|
||||
return Size;
|
||||
@@ -821,7 +825,11 @@ unsigned CheckedPSizeOf (const Type* T)
|
||||
{
|
||||
unsigned Size = PSizeOf (T);
|
||||
if (Size == 0) {
|
||||
Error ("Size of type '%s' is unknown", GetFullTypeName (T + 1));
|
||||
if (HasUnknownSize (T + 1)) {
|
||||
Error ("Pointer to type '%s' of unknown size", GetFullTypeName (T + 1));
|
||||
} else {
|
||||
Error ("Pointer to type '%s' of 0 size", GetFullTypeName (T + 1));
|
||||
}
|
||||
Size = SIZEOF_CHAR; /* Don't return zero */
|
||||
}
|
||||
return Size;
|
||||
@@ -999,6 +1007,25 @@ const Type* PtrConversion (const Type* T)
|
||||
|
||||
|
||||
|
||||
const Type* StdConversion (const Type* T)
|
||||
/* If the type is a function, convert it to pointer to function. If the
|
||||
** expression is an array, convert it to pointer to first element. If the
|
||||
** type is an integer, do integeral promotion. Otherwise return T.
|
||||
*/
|
||||
{
|
||||
if (IsTypeFunc (T)) {
|
||||
return AddressOf (T);
|
||||
} else if (IsTypeArray (T)) {
|
||||
return AddressOf (GetElementType (T));
|
||||
} else if (IsClassInt (T)) {
|
||||
return IntPromotion (T);
|
||||
} else {
|
||||
return T;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
const Type* IntPromotion (const Type* T)
|
||||
/* Apply the integer promotions to T and return the result. The returned type
|
||||
** string may be T if there is no need to change it.
|
||||
|
||||
@@ -368,6 +368,12 @@ const Type* PtrConversion (const Type* T);
|
||||
** return T.
|
||||
*/
|
||||
|
||||
const Type* StdConversion (const Type* T);
|
||||
/* If the type is a function, convert it to pointer to function. If the
|
||||
** expression is an array, convert it to pointer to first element. If the
|
||||
** type is an integer, do integeral promotion. Otherwise return T.
|
||||
*/
|
||||
|
||||
const Type* IntPromotion (const Type* T);
|
||||
/* Apply the integer promotions to T and return the result. The returned type
|
||||
** string may be T if there is no need to change it.
|
||||
|
||||
279
src/cc65/expr.c
279
src/cc65/expr.c
@@ -48,13 +48,6 @@
|
||||
|
||||
|
||||
|
||||
/* Map a generator function and its attributes to a token */
|
||||
typedef struct GenDesc {
|
||||
token_t Tok; /* Token to map to */
|
||||
unsigned Flags; /* Flags for generator function */
|
||||
void (*Func) (unsigned, unsigned long); /* Generator func */
|
||||
} GenDesc;
|
||||
|
||||
/* Descriptors for the operations */
|
||||
static GenDesc GenPASGN = { TOK_PLUS_ASSIGN, GEN_NOPUSH, g_add };
|
||||
static GenDesc GenSASGN = { TOK_MINUS_ASSIGN, GEN_NOPUSH, g_sub };
|
||||
@@ -243,7 +236,7 @@ static const GenDesc* FindGen (token_t Tok, const GenDesc* Table)
|
||||
/* Find a token in a generator table */
|
||||
{
|
||||
while (Table->Tok != TOK_INVALID) {
|
||||
if (Table->Tok == Tok) {
|
||||
if ((token_t)Table->Tok == Tok) {
|
||||
return Table;
|
||||
}
|
||||
++Table;
|
||||
@@ -311,13 +304,9 @@ void PushAddr (const ExprDesc* Expr)
|
||||
|
||||
|
||||
static void WarnConstCompareResult (const ExprDesc* Expr)
|
||||
/* If the result of a comparison is constant, this is suspicious when not in
|
||||
** preprocessor mode.
|
||||
*/
|
||||
/* If the result of a comparison is constant, this is suspicious */
|
||||
{
|
||||
if (!Preprocessing &&
|
||||
!ED_NeedsConst (Expr) &&
|
||||
IS_Get (&WarnConstComparison) != 0) {
|
||||
if (!ED_NeedsConst (Expr) && IS_Get (&WarnConstComparison) != 0) {
|
||||
Warning ("Result of comparison is always %s", Expr->IVal != 0 ? "true" : "false");
|
||||
}
|
||||
}
|
||||
@@ -649,6 +638,9 @@ void DoDeferred (unsigned Flags, ExprDesc* Expr)
|
||||
/* Sufficient to pop the processor flags */
|
||||
AddCodeLine ("plp");
|
||||
}
|
||||
|
||||
/* Expression has had side effects */
|
||||
Expr->Flags |= E_SIDE_EFFECTS;
|
||||
}
|
||||
|
||||
|
||||
@@ -772,9 +764,10 @@ static unsigned FunctionArgList (FuncDesc* Func, int IsFastcall, ExprDesc* ED)
|
||||
} else {
|
||||
|
||||
/* No prototype available. Convert array to "pointer to first
|
||||
** element", and function to "pointer to function".
|
||||
** element", function to "pointer to function" and do integral
|
||||
** promotion if necessary.
|
||||
*/
|
||||
Expr.Type = PtrConversion (Expr.Type);
|
||||
TypeConversion (&Expr, StdConversion (Expr.Type));
|
||||
|
||||
}
|
||||
|
||||
@@ -822,6 +815,9 @@ static unsigned FunctionArgList (FuncDesc* Func, int IsFastcall, ExprDesc* ED)
|
||||
}
|
||||
}
|
||||
|
||||
/* Propagate viral flags */
|
||||
ED_PropagateFrom (ED, &Expr);
|
||||
|
||||
/* Check for end of argument list */
|
||||
if (CurTok.Tok != TOK_COMMA) {
|
||||
break;
|
||||
@@ -1064,6 +1060,9 @@ static void FunctionCall (ExprDesc* Expr)
|
||||
}
|
||||
|
||||
Expr->Type = ReturnType;
|
||||
|
||||
/* We assume all function calls had side effects */
|
||||
Expr->Flags |= E_SIDE_EFFECTS;
|
||||
}
|
||||
|
||||
|
||||
@@ -1072,58 +1071,19 @@ static void Primary (ExprDesc* E)
|
||||
/* This is the lowest level of the expression parser. */
|
||||
{
|
||||
SymEntry* Sym;
|
||||
|
||||
/* Character and integer constants. */
|
||||
if (CurTok.Tok == TOK_ICONST || CurTok.Tok == TOK_CCONST) {
|
||||
E->IVal = CurTok.IVal;
|
||||
E->Flags |= E_LOC_NONE | E_RTYPE_RVAL;
|
||||
E->Type = CurTok.Type;
|
||||
NextToken ();
|
||||
return;
|
||||
}
|
||||
|
||||
/* Floating point constant */
|
||||
if (CurTok.Tok == TOK_FCONST) {
|
||||
E->V.FVal = CurTok.FVal;
|
||||
E->Flags |= E_LOC_NONE | E_RTYPE_RVAL;
|
||||
E->Type = CurTok.Type;
|
||||
NextToken ();
|
||||
return;
|
||||
}
|
||||
|
||||
/* Process parenthesized subexpression by calling the whole parser
|
||||
** recursively.
|
||||
*/
|
||||
if (CurTok.Tok == TOK_LPAREN) {
|
||||
NextToken ();
|
||||
hie0 (E);
|
||||
ConsumeRParen ();
|
||||
return;
|
||||
}
|
||||
|
||||
/* If we run into an identifier in preprocessing mode, we assume that this
|
||||
** is an undefined macro and replace it by a constant value of zero.
|
||||
*/
|
||||
if (Preprocessing && CurTok.Tok == TOK_IDENT) {
|
||||
NextToken ();
|
||||
ED_MakeConstAbsInt (E, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
/* All others may only be used if the expression evaluation is not called
|
||||
** recursively by the preprocessor.
|
||||
*/
|
||||
if (Preprocessing) {
|
||||
/* Illegal expression in PP mode */
|
||||
Error ("Preprocessor expression expected");
|
||||
ED_MakeConstAbsInt (E, 1);
|
||||
return;
|
||||
}
|
||||
|
||||
unsigned Flags = E->Flags & E_MASK_KEEP_MAKE;
|
||||
|
||||
switch (CurTok.Tok) {
|
||||
|
||||
case TOK_LPAREN:
|
||||
/* Process parenthesized subexpression by calling the whole parser
|
||||
** recursively.
|
||||
*/
|
||||
NextToken ();
|
||||
hie0 (E);
|
||||
ConsumeRParen ();
|
||||
break;
|
||||
|
||||
case TOK_BOOL_AND:
|
||||
/* A computed goto label address */
|
||||
if (IS_Get (&Standard) >= STD_CC65) {
|
||||
@@ -1133,7 +1093,7 @@ static void Primary (ExprDesc* E)
|
||||
/* output its label */
|
||||
E->Flags = E_RTYPE_RVAL | E_LOC_CODE | E_ADDRESS_OF;
|
||||
E->Name = Entry->V.L.Label;
|
||||
E->Type = NewPointerTo (type_void);
|
||||
E->Type = type_void_p;
|
||||
NextToken ();
|
||||
} else {
|
||||
Error ("Computed gotos are a C extension, not supported with this --standard");
|
||||
@@ -1157,9 +1117,9 @@ static void Primary (ExprDesc* E)
|
||||
/* Cannot use type symbols */
|
||||
Error ("Variable identifier expected");
|
||||
/* Assume an int type to make E valid */
|
||||
E->Flags |= E_LOC_STACK | E_RTYPE_LVAL;
|
||||
E->Type = type_int;
|
||||
return;
|
||||
E->Flags = E_LOC_STACK | E_RTYPE_LVAL;
|
||||
E->Type = type_int;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Mark the symbol as referenced */
|
||||
@@ -1172,11 +1132,7 @@ static void Primary (ExprDesc* E)
|
||||
if ((Sym->Flags & SC_CONST) == SC_CONST) {
|
||||
/* Enum or some other numeric constant */
|
||||
E->Flags = E_LOC_NONE | E_RTYPE_RVAL;
|
||||
E->IVal = Sym->V.ConstVal;
|
||||
} else if ((Sym->Flags & SC_FUNC) == SC_FUNC) {
|
||||
/* Function */
|
||||
E->Flags = E_LOC_GLOBAL | E_RTYPE_LVAL;
|
||||
E->Name = (uintptr_t) Sym->Name;
|
||||
E->IVal = Sym->V.ConstVal;
|
||||
} else if ((Sym->Flags & SC_AUTO) == SC_AUTO) {
|
||||
/* Local variable. If this is a parameter for a variadic
|
||||
** function, we have to add some address calculations, and the
|
||||
@@ -1191,6 +1147,10 @@ static void Primary (ExprDesc* E)
|
||||
E->Flags = E_LOC_STACK | E_RTYPE_LVAL;
|
||||
E->IVal = Sym->V.Offs;
|
||||
}
|
||||
} else if ((Sym->Flags & SC_FUNC) == SC_FUNC) {
|
||||
/* Function */
|
||||
E->Flags = E_LOC_GLOBAL | E_RTYPE_LVAL;
|
||||
E->Name = (uintptr_t) Sym->Name;
|
||||
} else if ((Sym->Flags & SC_REGISTER) == SC_REGISTER) {
|
||||
/* Register variable, zero page based */
|
||||
E->Flags = E_LOC_REGISTER | E_RTYPE_LVAL;
|
||||
@@ -1199,10 +1159,10 @@ static void Primary (ExprDesc* E)
|
||||
/* Static variable */
|
||||
if (Sym->Flags & (SC_EXTERN | SC_STORAGE | SC_DECL)) {
|
||||
E->Flags = E_LOC_GLOBAL | E_RTYPE_LVAL;
|
||||
E->Name = (uintptr_t) Sym->Name;
|
||||
E->Name = (uintptr_t) Sym->Name;
|
||||
} else {
|
||||
E->Flags = E_LOC_STATIC | E_RTYPE_LVAL;
|
||||
E->Name = Sym->V.L.Label;
|
||||
E->Name = Sym->V.L.Label;
|
||||
}
|
||||
} else {
|
||||
/* Local static variable */
|
||||
@@ -1248,7 +1208,7 @@ static void Primary (ExprDesc* E)
|
||||
/* Undeclared Variable */
|
||||
Sym = AddLocalSym (Ident, type_int, SC_AUTO | SC_REF, 0);
|
||||
E->Flags = E_LOC_STACK | E_RTYPE_LVAL;
|
||||
E->Type = type_int;
|
||||
E->Type = type_int;
|
||||
Error ("Undefined symbol: '%s'", Ident);
|
||||
}
|
||||
|
||||
@@ -1260,6 +1220,8 @@ static void Primary (ExprDesc* E)
|
||||
/* String literal */
|
||||
if ((Flags & E_EVAL_UNEVAL) != E_EVAL_UNEVAL) {
|
||||
E->V.LVal = UseLiteral (CurTok.SVal);
|
||||
/* Translate into target charset */
|
||||
TranslateLiteral (E->V.LVal);
|
||||
} else {
|
||||
E->V.LVal = CurTok.SVal;
|
||||
}
|
||||
@@ -1270,10 +1232,28 @@ static void Primary (ExprDesc* E)
|
||||
NextToken ();
|
||||
break;
|
||||
|
||||
case TOK_ICONST:
|
||||
case TOK_CCONST:
|
||||
case TOK_WCCONST:
|
||||
/* Character and integer constants */
|
||||
E->IVal = CurTok.IVal;
|
||||
E->Flags = E_LOC_NONE | E_RTYPE_RVAL;
|
||||
E->Type = CurTok.Type;
|
||||
NextToken ();
|
||||
break;
|
||||
|
||||
case TOK_FCONST:
|
||||
/* Floating point constant */
|
||||
E->V.FVal = CurTok.FVal;
|
||||
E->Flags = E_LOC_NONE | E_RTYPE_RVAL;
|
||||
E->Type = CurTok.Type;
|
||||
NextToken ();
|
||||
break;
|
||||
|
||||
case TOK_ASM:
|
||||
/* ASM statement */
|
||||
AsmStatement ();
|
||||
E->Flags = E_RTYPE_RVAL | E_EVAL_MAYBE_UNUSED;
|
||||
E->Flags = E_RTYPE_RVAL | E_EVAL_MAYBE_UNUSED | E_SIDE_EFFECTS;
|
||||
E->Type = type_void;
|
||||
break;
|
||||
|
||||
@@ -1658,6 +1638,9 @@ static void PreInc (ExprDesc* Expr)
|
||||
|
||||
/* Result is an expression, no reference */
|
||||
ED_FinalizeRValLoad (Expr);
|
||||
|
||||
/* Expression has had side effects */
|
||||
Expr->Flags |= E_SIDE_EFFECTS;
|
||||
}
|
||||
|
||||
|
||||
@@ -1685,6 +1668,9 @@ static void PreDec (ExprDesc* Expr)
|
||||
|
||||
/* Result is an expression, no reference */
|
||||
ED_FinalizeRValLoad (Expr);
|
||||
|
||||
/* Expression has had side effects */
|
||||
Expr->Flags |= E_SIDE_EFFECTS;
|
||||
}
|
||||
|
||||
|
||||
@@ -1721,6 +1707,9 @@ static void PostInc (ExprDesc* Expr)
|
||||
LoadExpr (CF_NONE, Expr);
|
||||
AddCodeLine ("inc %s", ED_GetLabelName (Expr, 0));
|
||||
|
||||
/* Expression has had side effects */
|
||||
Expr->Flags |= E_SIDE_EFFECTS;
|
||||
|
||||
} else {
|
||||
|
||||
if (ED_IsLocPrimaryOrExpr (Expr)) {
|
||||
@@ -1728,6 +1717,9 @@ static void PostInc (ExprDesc* Expr)
|
||||
/* Do the increment */
|
||||
DoInc (Expr, OA_NEED_OLD);
|
||||
|
||||
/* Expression has had side effects */
|
||||
Expr->Flags |= E_SIDE_EFFECTS;
|
||||
|
||||
} else {
|
||||
|
||||
/* Defer the increment until after the value of this expression is used */
|
||||
@@ -1771,6 +1763,9 @@ static void PostDec (ExprDesc* Expr)
|
||||
LoadExpr (CF_NONE, Expr);
|
||||
AddCodeLine ("dec %s", ED_GetLabelName (Expr, 0));
|
||||
|
||||
/* Expression has had side effects */
|
||||
Expr->Flags |= E_SIDE_EFFECTS;
|
||||
|
||||
} else {
|
||||
|
||||
if (ED_IsLocPrimaryOrExpr (Expr)) {
|
||||
@@ -1778,6 +1773,9 @@ static void PostDec (ExprDesc* Expr)
|
||||
/* Do the decrement */
|
||||
DoDec (Expr, OA_NEED_OLD);
|
||||
|
||||
/* Expression has had side effects */
|
||||
Expr->Flags |= E_SIDE_EFFECTS;
|
||||
|
||||
} else {
|
||||
|
||||
/* Defer the decrement until after the value of this expression is used */
|
||||
@@ -1952,7 +1950,7 @@ void hie10 (ExprDesc* Expr)
|
||||
/* The & operator yields an rvalue address */
|
||||
ED_AddrExpr (Expr);
|
||||
}
|
||||
Expr->Type = NewPointerTo (Expr->Type);
|
||||
Expr->Type = AddressOf (Expr->Type);
|
||||
break;
|
||||
|
||||
case TOK_SIZEOF:
|
||||
@@ -2238,6 +2236,9 @@ static void hie_internal (const GenDesc* Ops, /* List of generators */
|
||||
/* We have an rvalue in the primary now */
|
||||
ED_FinalizeRValLoad (Expr);
|
||||
}
|
||||
|
||||
/* Propagate viral flags */
|
||||
ED_PropagateFrom (Expr, &Expr2);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2271,9 +2272,9 @@ static void hie_compare (const GenDesc* Ops, /* List of generators */
|
||||
Tok = CurTok.Tok;
|
||||
NextToken ();
|
||||
|
||||
/* If lhs is a function, convert it to pointer to function */
|
||||
/* If lhs is a function, convert it to the address of the function */
|
||||
if (IsTypeFunc (Expr->Type)) {
|
||||
Expr->Type = NewPointerTo (Expr->Type);
|
||||
Expr->Type = AddressOf (Expr->Type);
|
||||
}
|
||||
|
||||
/* Get the lhs on stack */
|
||||
@@ -2293,9 +2294,9 @@ static void hie_compare (const GenDesc* Ops, /* List of generators */
|
||||
/* Get the right hand side */
|
||||
MarkedExprWithCheck (hienext, &Expr2);
|
||||
|
||||
/* If rhs is a function, convert it to pointer to function */
|
||||
/* If rhs is a function, convert it to the address of the function */
|
||||
if (IsTypeFunc (Expr2.Type)) {
|
||||
Expr2.Type = NewPointerTo (Expr2.Type);
|
||||
Expr2.Type = AddressOf (Expr2.Type);
|
||||
}
|
||||
|
||||
/* Check for a numeric constant expression */
|
||||
@@ -2340,7 +2341,7 @@ static void hie_compare (const GenDesc* Ops, /* List of generators */
|
||||
} else if (IsClassPtr (Expr->Type)) {
|
||||
if (IsClassPtr (Expr2.Type)) {
|
||||
/* Pointers are allowed in comparison */
|
||||
if (TypeCmp (Expr->Type, Expr2.Type).C < TC_STRICT_COMPATIBLE) {
|
||||
if (TypeCmp (Expr->Type, Expr2.Type).C < TC_VOID_PTR) {
|
||||
/* Warn about distinct pointer types */
|
||||
TypeCompatibilityDiagnostic (PtrConversion (Expr->Type), PtrConversion (Expr2.Type), 0,
|
||||
"Distinct pointer types comparing '%s' with '%s'");
|
||||
@@ -2659,6 +2660,9 @@ static void hie_compare (const GenDesc* Ops, /* List of generators */
|
||||
|
||||
/* Result type is always boolean */
|
||||
Done: Expr->Type = type_bool;
|
||||
|
||||
/* Propagate viral flags */
|
||||
ED_PropagateFrom (Expr, &Expr2);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3069,12 +3073,15 @@ static void parseadd (ExprDesc* Expr, int DoArrayRef)
|
||||
Error ("Invalid operands for binary operator '+'");
|
||||
} else {
|
||||
/* Array and function types must be converted to pointer types */
|
||||
Expr->Type = PtrConversion (Expr->Type);
|
||||
Expr->Type = StdConversion (Expr->Type);
|
||||
}
|
||||
}
|
||||
|
||||
/* Condition code not set */
|
||||
ED_MarkAsUntested (Expr);
|
||||
|
||||
/* Propagate viral flags */
|
||||
ED_PropagateFrom (Expr, &Expr2);
|
||||
}
|
||||
|
||||
|
||||
@@ -3348,10 +3355,13 @@ static void parsesub (ExprDesc* Expr)
|
||||
}
|
||||
|
||||
/* Result type is either a pointer or an integer */
|
||||
Expr->Type = PtrConversion (Expr->Type);
|
||||
Expr->Type = StdConversion (Expr->Type);
|
||||
|
||||
/* Condition code not set */
|
||||
ED_MarkAsUntested (Expr);
|
||||
|
||||
/* Propagate viral flags */
|
||||
ED_PropagateFrom (Expr, &Expr2);
|
||||
}
|
||||
|
||||
|
||||
@@ -3441,48 +3451,6 @@ static void hie2 (ExprDesc* Expr)
|
||||
|
||||
|
||||
|
||||
static void hieAndPP (ExprDesc* Expr)
|
||||
/* Process "exp && exp" in preprocessor mode (that is, when the parser is
|
||||
** called recursively from the preprocessor.
|
||||
*/
|
||||
{
|
||||
*Expr = NoCodeConstAbsIntExpr (hie2);
|
||||
while (CurTok.Tok == TOK_BOOL_AND) {
|
||||
|
||||
/* Skip the && */
|
||||
NextToken ();
|
||||
|
||||
/* Get rhs */
|
||||
ExprDesc Expr2 = NoCodeConstAbsIntExpr (hie2);
|
||||
|
||||
/* Combine the two */
|
||||
Expr->IVal = (Expr->IVal && Expr2.IVal);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void hieOrPP (ExprDesc *Expr)
|
||||
/* Process "exp || exp" in preprocessor mode (that is, when the parser is
|
||||
** called recursively from the preprocessor.
|
||||
*/
|
||||
{
|
||||
*Expr = NoCodeConstAbsIntExpr (hieAndPP);
|
||||
while (CurTok.Tok == TOK_BOOL_OR) {
|
||||
|
||||
/* Skip the && */
|
||||
NextToken ();
|
||||
|
||||
/* Get rhs */
|
||||
ExprDesc Expr2 = NoCodeConstAbsIntExpr (hieAndPP);
|
||||
|
||||
/* Combine the two */
|
||||
Expr->IVal = (Expr->IVal || Expr2.IVal);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int hieAnd (ExprDesc* Expr, unsigned* TrueLab, int* TrueLabAllocated)
|
||||
/* Process "exp && exp". This should only be called within hieOr.
|
||||
** Return true if logic AND does occur.
|
||||
@@ -3603,6 +3571,12 @@ static int hieAnd (ExprDesc* Expr, unsigned* TrueLab, int* TrueLabAllocated)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Propagate viral flags */
|
||||
if ((Expr->Flags & E_EVAL_UNEVAL) != E_EVAL_UNEVAL) {
|
||||
ED_PropagateFrom (Expr, &Expr2);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* Last expression */
|
||||
@@ -3768,6 +3742,11 @@ static void hieOr (ExprDesc *Expr)
|
||||
}
|
||||
}
|
||||
|
||||
/* Propagate viral flags */
|
||||
if ((Expr->Flags & E_EVAL_UNEVAL) != E_EVAL_UNEVAL) {
|
||||
ED_PropagateFrom (Expr, &Expr2);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* Convert to bool */
|
||||
@@ -3821,11 +3800,7 @@ static void hieQuest (ExprDesc* Expr)
|
||||
Type* ResultType; /* Type of result */
|
||||
|
||||
/* Call the lower level eval routine */
|
||||
if (Preprocessing) {
|
||||
ExprWithCheck (hieOrPP, Expr);
|
||||
} else {
|
||||
ExprWithCheck (hieOr, Expr);
|
||||
}
|
||||
ExprWithCheck (hieOr, Expr);
|
||||
|
||||
/* Check if it's a ternary expression */
|
||||
if (CurTok.Tok == TOK_QUEST) {
|
||||
@@ -4059,6 +4034,14 @@ static void hieQuest (ExprDesc* Expr)
|
||||
|
||||
/* Setup the target expression */
|
||||
Expr->Type = ResultType;
|
||||
|
||||
/* Propagate viral flags */
|
||||
if ((Expr2.Flags & E_EVAL_UNEVAL) != E_EVAL_UNEVAL) {
|
||||
ED_PropagateFrom (Expr, &Expr2);
|
||||
}
|
||||
if ((Expr3.Flags & E_EVAL_UNEVAL) != E_EVAL_UNEVAL) {
|
||||
ED_PropagateFrom (Expr, &Expr3);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4136,26 +4119,39 @@ void hie0 (ExprDesc *Expr)
|
||||
/* Append deferred inc/dec at sequence point */
|
||||
DoDeferred (SQP_KEEP_NONE, Expr);
|
||||
|
||||
/* If the expression didn't generate code or isn't cast to type void,
|
||||
** emit a warning.
|
||||
/* If the expression has no observable effect and isn't cast to type
|
||||
** void, emit a warning and remove useless code if any.
|
||||
*/
|
||||
GetCodePos (&End);
|
||||
if (!ED_MayHaveNoEffect (Expr) &&
|
||||
CodeRangeIsEmpty (&Start, &End) &&
|
||||
IS_Get (&WarnNoEffect) &&
|
||||
PrevErrorCount == ErrorCount) {
|
||||
Warning ("Expression result unused");
|
||||
if (CodeRangeIsEmpty (&Start, &End) ||
|
||||
(Expr->Flags & E_SIDE_EFFECTS) == 0) {
|
||||
|
||||
if (!ED_MayHaveNoEffect (Expr) &&
|
||||
IS_Get (&WarnNoEffect) &&
|
||||
PrevErrorCount == ErrorCount) {
|
||||
Warning ("Left-hand operand of comma expression has no effect");
|
||||
}
|
||||
|
||||
/* Remove code with no effect */
|
||||
RemoveCode (&Start);
|
||||
}
|
||||
|
||||
PrevErrorCount = ErrorCount;
|
||||
|
||||
/* Remember the current code position */
|
||||
GetCodePos (&Start);
|
||||
|
||||
/* Keep viral flags propagated from subexpressions */
|
||||
Flags |= Expr->Flags & E_MASK_VIRAL;
|
||||
|
||||
/* Reset the expression */
|
||||
ED_Init (Expr);
|
||||
Expr->Flags = Flags;
|
||||
Expr->Flags = Flags & ~E_MASK_VIRAL;
|
||||
NextToken ();
|
||||
hie1 (Expr);
|
||||
|
||||
/* Propagate viral flags */
|
||||
Expr->Flags |= Flags & E_MASK_VIRAL;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4217,7 +4213,8 @@ ExprDesc NoCodeConstExpr (void (*Func) (ExprDesc*))
|
||||
if (!ED_IsConst (&Expr) || !ED_CodeRangeIsEmpty (&Expr)) {
|
||||
Error ("Constant expression expected");
|
||||
/* To avoid any compiler errors, make the expression a valid const */
|
||||
ED_MakeConstAbsInt (&Expr, 1);
|
||||
Expr.Flags &= E_MASK_RTYPE | E_MASK_KEEP_RESULT;
|
||||
Expr.Flags |= E_LOC_NONE;
|
||||
}
|
||||
|
||||
/* Return by value */
|
||||
|
||||
@@ -26,13 +26,20 @@
|
||||
#define SQP_KEEP_NONE 0x00
|
||||
#define SQP_KEEP_TEST 0x01U
|
||||
#define SQP_KEEP_EAX 0x02U
|
||||
#define SQP_KEEP_EXPR 0x03U /* SQP_KEEP_TEST | SQP_KEEP_EAX */
|
||||
#define SQP_KEEP_EXPR 0x03U /* SQP_KEEP_TEST | SQP_KEEP_EAX */
|
||||
|
||||
/* Generator attributes */
|
||||
#define GEN_NOPUSH 0x01 /* Don't push lhs */
|
||||
#define GEN_COMM 0x02 /* Operator is commutative */
|
||||
#define GEN_NOFUNC 0x04 /* Not allowed for function pointers */
|
||||
|
||||
/* Map a generator function and its attributes to a token */
|
||||
typedef struct GenDesc {
|
||||
long Tok; /* Token to map to */
|
||||
unsigned Flags; /* Flags for generator function */
|
||||
void (*Func) (unsigned, unsigned long); /* Generator func */
|
||||
} GenDesc;
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
@@ -125,6 +125,7 @@ enum {
|
||||
E_LOADED = 0x1000, /* Expression is loaded in primary */
|
||||
E_CC_SET = 0x2000, /* Condition codes are set */
|
||||
E_HAVE_MARKS = 0x4000, /* Code marks are valid */
|
||||
E_SIDE_EFFECTS = 0x8000, /* Expression has had side effects */
|
||||
|
||||
/* Optimization hints */
|
||||
E_MASK_NEED = 0x030000,
|
||||
@@ -181,6 +182,9 @@ enum {
|
||||
/* Expression result must be known to the compiler and generate no code to load */
|
||||
E_EVAL_C_CONST = E_EVAL_COMPILER_KNOWN | E_EVAL_NO_CODE,
|
||||
|
||||
/* Flags to combine from subexpressions */
|
||||
E_MASK_VIRAL = E_SIDE_EFFECTS,
|
||||
|
||||
/* Flags to keep in subexpressions of most operations other than ternary */
|
||||
E_MASK_KEEP_SUBEXPR = E_MASK_EVAL,
|
||||
|
||||
@@ -467,6 +471,16 @@ INLINE int ED_MayHaveNoEffect (const ExprDesc* Expr)
|
||||
# define ED_MayHaveNoEffect(Expr) (((Expr)->Flags & E_EVAL_MAYBE_UNUSED) == E_EVAL_MAYBE_UNUSED)
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_INLINE)
|
||||
INLINE void ED_PropagateFrom (ExprDesc* Expr, const ExprDesc* SubExpr)
|
||||
/* Propagate viral flags from subexpression */
|
||||
{
|
||||
Expr->Flags |= SubExpr->Flags & E_MASK_VIRAL;
|
||||
}
|
||||
#else
|
||||
# define ED_PropagateFrom(Expr, SubExpr) (void)((Expr)->Flags |= (SubExpr)->Flags & E_MASK_VIRAL)
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_INLINE)
|
||||
INLINE int ED_IsLocPrimaryOrExpr (const ExprDesc* Expr)
|
||||
/* Return true if the expression is E_LOC_PRIMARY or E_LOC_EXPR */
|
||||
|
||||
169
src/cc65/input.c
169
src/cc65/input.c
@@ -54,6 +54,7 @@
|
||||
#include "input.h"
|
||||
#include "lineinfo.h"
|
||||
#include "output.h"
|
||||
#include "preproc.h"
|
||||
|
||||
|
||||
|
||||
@@ -91,6 +92,9 @@ struct AFile {
|
||||
FILE* F; /* Input file stream */
|
||||
IFile* Input; /* Points to corresponding IFile */
|
||||
int SearchPath; /* True if we've added a path for this file */
|
||||
char* PName; /* Presumed name of the file */
|
||||
PPIfStack IfStack; /* PP #if stack */
|
||||
int MissingNL; /* Last input line was missing a newline */
|
||||
};
|
||||
|
||||
/* List of all input files */
|
||||
@@ -102,6 +106,9 @@ static Collection AFiles = STATIC_COLLECTION_INITIALIZER;
|
||||
/* Input stack used when preprocessing. */
|
||||
static Collection InputStack = STATIC_COLLECTION_INITIALIZER;
|
||||
|
||||
/* Counter for the __COUNTER__ macro */
|
||||
static unsigned MainFileCounter;
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
@@ -156,6 +163,9 @@ static AFile* NewAFile (IFile* IF, FILE* F)
|
||||
AF->Line = 0;
|
||||
AF->F = F;
|
||||
AF->Input = IF;
|
||||
AF->PName = 0;
|
||||
AF->IfStack.Index = -1;
|
||||
AF->MissingNL = 0;
|
||||
|
||||
/* Increment the usage counter of the corresponding IFile. If this
|
||||
** is the first use, set the file data and output debug info if
|
||||
@@ -204,6 +214,9 @@ static AFile* NewAFile (IFile* IF, FILE* F)
|
||||
static void FreeAFile (AFile* AF)
|
||||
/* Free an AFile structure */
|
||||
{
|
||||
if (AF->PName != 0) {
|
||||
xfree (AF->PName);
|
||||
}
|
||||
xfree (AF);
|
||||
}
|
||||
|
||||
@@ -257,6 +270,12 @@ void OpenMainFile (const char* Name)
|
||||
/* Allocate a new AFile structure for the file */
|
||||
MainFile = NewAFile (IF, F);
|
||||
|
||||
/* Use this file with PP */
|
||||
SetPPIfStack (&MainFile->IfStack);
|
||||
|
||||
/* Begin PP for this file */
|
||||
PreprocessBegin ();
|
||||
|
||||
/* Allocate the input line buffer */
|
||||
Line = NewStrBuf ();
|
||||
|
||||
@@ -264,6 +283,9 @@ void OpenMainFile (const char* Name)
|
||||
** the main file before the first line is read.
|
||||
*/
|
||||
UpdateLineInfo (MainFile->Input, MainFile->Line, Line);
|
||||
|
||||
/* Initialize the __COUNTER__ counter */
|
||||
MainFileCounter = 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -274,6 +296,7 @@ void OpenIncludeFile (const char* Name, InputType IT)
|
||||
char* N;
|
||||
FILE* F;
|
||||
IFile* IF;
|
||||
AFile* AF;
|
||||
|
||||
/* Check for the maximum include nesting */
|
||||
if (CollCount (&AFiles) > MAX_INC_NESTING) {
|
||||
@@ -311,12 +334,18 @@ void OpenIncludeFile (const char* Name, InputType IT)
|
||||
Print (stdout, 1, "Opened include file '%s'\n", IF->Name);
|
||||
|
||||
/* Allocate a new AFile structure */
|
||||
(void) NewAFile (IF, F);
|
||||
AF = NewAFile (IF, F);
|
||||
|
||||
/* Use this file with PP */
|
||||
SetPPIfStack (&AF->IfStack);
|
||||
|
||||
/* Begin PP for this file */
|
||||
PreprocessBegin ();
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void CloseIncludeFile (void)
|
||||
void CloseIncludeFile (void)
|
||||
/* Close an include file and switch to the higher level file. Set Input to
|
||||
** NULL if this was the main file.
|
||||
*/
|
||||
@@ -329,14 +358,18 @@ static void CloseIncludeFile (void)
|
||||
/* Must have an input file when called */
|
||||
PRECONDITION (AFileCount > 0);
|
||||
|
||||
/* End preprocessor in this file */
|
||||
PreprocessEnd ();
|
||||
|
||||
/* Get the current active input file */
|
||||
Input = (AFile*) CollLast (&AFiles);
|
||||
Input = CollLast (&AFiles);
|
||||
|
||||
/* Close the current input file (we're just reading so no error check) */
|
||||
fclose (Input->F);
|
||||
|
||||
/* Delete the last active file from the active file collection */
|
||||
CollDelete (&AFiles, AFileCount-1);
|
||||
--AFileCount;
|
||||
CollDelete (&AFiles, AFileCount);
|
||||
|
||||
/* If we had added an extra search path for this AFile, remove it */
|
||||
if (Input->SearchPath) {
|
||||
@@ -345,6 +378,12 @@ static void CloseIncludeFile (void)
|
||||
|
||||
/* Delete the active file structure */
|
||||
FreeAFile (Input);
|
||||
|
||||
/* Use previous file with PP if it is not the main file */
|
||||
if (AFileCount > 0) {
|
||||
Input = CollLast (&AFiles);
|
||||
SetPPIfStack (&Input->IfStack);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -436,47 +475,49 @@ StrBuf* InitLine (StrBuf* Buf)
|
||||
|
||||
|
||||
int NextLine (void)
|
||||
/* Get a line from the current input. Returns 0 on end of file. */
|
||||
/* Get a line from the current input. Returns 0 on end of file with no new
|
||||
** input bytes.
|
||||
*/
|
||||
{
|
||||
int C;
|
||||
AFile* Input;
|
||||
|
||||
/* Clear the current line */
|
||||
ClearLine ();
|
||||
SB_Clear (Line);
|
||||
|
||||
/* If there is no file open, bail out, otherwise get the current input file */
|
||||
if (CollCount (&AFiles) == 0) {
|
||||
/* Must have an input file when called */
|
||||
if (CollCount(&AFiles) == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Get the current input file */
|
||||
Input = CollLast (&AFiles);
|
||||
|
||||
/* Read characters until we have one complete line */
|
||||
while (1) {
|
||||
|
||||
/* Read the next character */
|
||||
int C = fgetc (Input->F);
|
||||
C = fgetc (Input->F);
|
||||
|
||||
/* Check for EOF */
|
||||
if (C == EOF) {
|
||||
|
||||
/* Accept files without a newline at the end */
|
||||
if (SB_NotEmpty (Line)) {
|
||||
if (!Input->MissingNL || SB_NotEmpty (Line)) {
|
||||
|
||||
/* Accept files without a newline at the end */
|
||||
++Input->Line;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Leave the current file */
|
||||
CloseIncludeFile ();
|
||||
/* Assume no new line */
|
||||
Input->MissingNL = 1;
|
||||
|
||||
/* If there is no file open, bail out, otherwise get the
|
||||
** previous input file and start over.
|
||||
*/
|
||||
if (CollCount (&AFiles) == 0) {
|
||||
return 0;
|
||||
}
|
||||
Input = CollLast (&AFiles);
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Assume no new line */
|
||||
Input->MissingNL = 1;
|
||||
|
||||
/* Check for end of line */
|
||||
if (C == '\n') {
|
||||
|
||||
@@ -497,6 +538,7 @@ int NextLine (void)
|
||||
if (SB_LookAtLast (Line) == '\\') {
|
||||
Line->Buf[Line->Len-1] = '\n';
|
||||
} else {
|
||||
Input->MissingNL = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -517,6 +559,38 @@ int NextLine (void)
|
||||
/* Create line information for this line */
|
||||
UpdateLineInfo (Input->Input, Input->Line, Line);
|
||||
|
||||
/* Done */
|
||||
return C != EOF || SB_NotEmpty (Line);
|
||||
}
|
||||
|
||||
|
||||
|
||||
int PreprocessNextLine (void)
|
||||
/* Get a line from opened input files and do preprocess. Returns 0 on end of
|
||||
** main file.
|
||||
*/
|
||||
{
|
||||
while (NextLine() == 0) {
|
||||
|
||||
/* If there is no input file open, bail out. Otherwise get the previous
|
||||
** input file and start over.
|
||||
*/
|
||||
if (CollCount (&AFiles) == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Leave the current file */
|
||||
CloseIncludeFile ();
|
||||
}
|
||||
|
||||
/* Do preprocess anyways */
|
||||
Preprocess ();
|
||||
|
||||
/* Write it to the output file if in preprocess-only mode */
|
||||
if (PreprocessOnly) {
|
||||
WriteOutput ("%.*s\n", (int) SB_GetLen (Line), SB_GetConstBuf (Line));
|
||||
}
|
||||
|
||||
/* Done */
|
||||
return 1;
|
||||
}
|
||||
@@ -536,17 +610,11 @@ const char* GetCurrentFile (void)
|
||||
{
|
||||
unsigned AFileCount = CollCount (&AFiles);
|
||||
if (AFileCount > 0) {
|
||||
const AFile* AF = (const AFile*) CollAt (&AFiles, AFileCount-1);
|
||||
return AF->Input->Name;
|
||||
const AFile* AF = CollLast (&AFiles);
|
||||
return AF->PName == 0 ? AF->Input->Name : AF->PName;
|
||||
} else {
|
||||
/* No open file. Use the main file if we have one. */
|
||||
unsigned IFileCount = CollCount (&IFiles);
|
||||
if (IFileCount > 0) {
|
||||
const IFile* IF = (const IFile*) CollAt (&IFiles, 0);
|
||||
return IF->Name;
|
||||
} else {
|
||||
return "(outside file scope)";
|
||||
}
|
||||
/* No open file */
|
||||
return "(outside file scope)";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -557,7 +625,7 @@ unsigned GetCurrentLine (void)
|
||||
{
|
||||
unsigned AFileCount = CollCount (&AFiles);
|
||||
if (AFileCount > 0) {
|
||||
const AFile* AF = (const AFile*) CollAt (&AFiles, AFileCount-1);
|
||||
const AFile* AF = CollLast (&AFiles);
|
||||
return AF->Line;
|
||||
} else {
|
||||
/* No open file */
|
||||
@@ -567,6 +635,43 @@ unsigned GetCurrentLine (void)
|
||||
|
||||
|
||||
|
||||
void SetCurrentLine (unsigned LineNum)
|
||||
/* Set the line number in the current input file */
|
||||
{
|
||||
unsigned AFileCount = CollCount (&AFiles);
|
||||
if (AFileCount > 0) {
|
||||
AFile* AF = CollLast (&AFiles);
|
||||
AF->Line = LineNum;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void SetCurrentFilename (const char* Name)
|
||||
/* Set the presumed name of the current input file */
|
||||
{
|
||||
unsigned AFileCount = CollCount (&AFiles);
|
||||
if (AFileCount > 0) {
|
||||
size_t Len = strlen (Name);
|
||||
AFile* AF = CollLast (&AFiles);
|
||||
if (AF->PName != 0) {
|
||||
xfree (AF->PName);
|
||||
}
|
||||
AF->PName = xmalloc (Len + 1);
|
||||
memcpy (AF->PName, Name, Len + 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
unsigned GetCurrentCounter (void)
|
||||
/* Return the counter number in the current input file */
|
||||
{
|
||||
return MainFileCounter++;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void WriteEscaped (FILE* F, const char* Name)
|
||||
/* Write a file name to a dependency file escaping spaces */
|
||||
{
|
||||
|
||||
@@ -46,7 +46,7 @@
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* data */
|
||||
/* Data */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
@@ -84,6 +84,11 @@ void OpenMainFile (const char* Name);
|
||||
void OpenIncludeFile (const char* Name, InputType IT);
|
||||
/* Open an include file and insert it into the tables. */
|
||||
|
||||
void CloseIncludeFile (void);
|
||||
/* Close an include file and switch to the higher level file. Set Input to
|
||||
** NULL if this was the main file.
|
||||
*/
|
||||
|
||||
void NextChar (void);
|
||||
/* Read the next character from the input stream and make CurC and NextC
|
||||
** valid. If end of line is reached, both are set to NUL, no more lines
|
||||
@@ -99,7 +104,14 @@ StrBuf* InitLine (StrBuf* Buf);
|
||||
*/
|
||||
|
||||
int NextLine (void);
|
||||
/* Get a line from the current input. Returns 0 on end of file. */
|
||||
/* Get a line from the current input. Returns 0 on end of file with no new
|
||||
** input bytes.
|
||||
*/
|
||||
|
||||
int PreprocessNextLine (void);
|
||||
/* Get a line from opened input files and do preprocess. Returns 0 on end of
|
||||
** main file.
|
||||
*/
|
||||
|
||||
const char* GetInputFile (const struct IFile* IF);
|
||||
/* Return a filename from an IFile struct */
|
||||
@@ -110,6 +122,15 @@ const char* GetCurrentFile (void);
|
||||
unsigned GetCurrentLine (void);
|
||||
/* Return the line number in the current input file */
|
||||
|
||||
void SetCurrentLine (unsigned LineNum);
|
||||
/* Set the line number in the current input file */
|
||||
|
||||
void SetCurrentFilename (const char* Name);
|
||||
/* Set the presumed name of the current input file */
|
||||
|
||||
unsigned GetCurrentCounter (void);
|
||||
/* Return the counter number in the current input file */
|
||||
|
||||
void CreateDependencies (void);
|
||||
/* Create dependency files requested by the user */
|
||||
|
||||
|
||||
@@ -126,9 +126,6 @@ static void FreeLiteral (Literal* L)
|
||||
static void OutputLiteral (Literal* L)
|
||||
/* Output one literal to the currently active data segment */
|
||||
{
|
||||
/* Translate the literal into the target charset */
|
||||
TranslateLiteral (L);
|
||||
|
||||
/* Define the label for the literal */
|
||||
g_defliterallabel (L->Label);
|
||||
|
||||
@@ -387,9 +384,6 @@ static void OutputReadOnlyLiterals (Collection* Literals)
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Translate the literal into the target charset */
|
||||
TranslateLiteral (L);
|
||||
|
||||
/* Check if this literal is part of another one. Since the literals
|
||||
** are sorted by size (larger ones first), it can only be part of a
|
||||
** literal with a smaller index.
|
||||
|
||||
@@ -277,4 +277,8 @@ void LoadExpr (unsigned Flags, struct ExprDesc* Expr)
|
||||
}
|
||||
}
|
||||
|
||||
if (ED_IsLVal (Expr) && IsQualVolatile (Expr->Type)) {
|
||||
/* Expression has had side effects */
|
||||
Expr->Flags |= E_SIDE_EFFECTS;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -174,8 +174,8 @@ static void ParseRegisterDecl (Declaration* Decl, int Reg)
|
||||
Sym->Flags |= SC_REF;
|
||||
}
|
||||
|
||||
/* Cannot allocate a variable of zero size */
|
||||
if (Size == 0) {
|
||||
/* Cannot allocate a variable of unknown size */
|
||||
if (HasUnknownSize (Sym->Type)) {
|
||||
if (IsTypeArray (Decl->Type)) {
|
||||
Error ("Array '%s' has unknown size", Decl->Ident);
|
||||
} else {
|
||||
@@ -370,8 +370,8 @@ static void ParseAutoDecl (Declaration* Decl)
|
||||
}
|
||||
}
|
||||
|
||||
/* Cannot allocate a variable of zero size */
|
||||
if (Size == 0) {
|
||||
/* Cannot allocate an incomplete variable */
|
||||
if (HasUnknownSize (Sym->Type)) {
|
||||
if (IsTypeArray (Decl->Type)) {
|
||||
Error ("Array '%s' has unknown size", Decl->Ident);
|
||||
} else {
|
||||
@@ -428,8 +428,8 @@ static void ParseStaticDecl (Declaration* Decl)
|
||||
|
||||
}
|
||||
|
||||
/* Cannot allocate a variable of zero size */
|
||||
if (Size == 0) {
|
||||
/* Cannot allocate an incomplete variable */
|
||||
if (HasUnknownSize (Sym->Type)) {
|
||||
if (IsTypeArray (Decl->Type)) {
|
||||
Error ("Array '%s' has unknown size", Decl->Ident);
|
||||
} else {
|
||||
|
||||
@@ -42,6 +42,7 @@
|
||||
|
||||
/* cc65 */
|
||||
#include "error.h"
|
||||
#include "preproc.h"
|
||||
#include "macrotab.h"
|
||||
|
||||
|
||||
@@ -56,6 +57,9 @@
|
||||
#define MACRO_TAB_SIZE 211
|
||||
static Macro* MacroTab[MACRO_TAB_SIZE];
|
||||
|
||||
/* The undefined macros list head */
|
||||
static Macro* UndefinedMacrosListHead;
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
@@ -108,6 +112,29 @@ void FreeMacro (Macro* M)
|
||||
|
||||
|
||||
|
||||
Macro* CloneMacro (const Macro* M)
|
||||
/* Clone a macro definition. The function is not insert the macro into the
|
||||
** macro table, thus the cloned instance cannot be freed with UndefineMacro.
|
||||
** Use FreeMacro for that.
|
||||
*/
|
||||
{
|
||||
Macro* New = NewMacro (M->Name);
|
||||
unsigned I;
|
||||
|
||||
for (I = 0; I < CollCount (&M->FormalArgs); ++I) {
|
||||
/* Copy the argument */
|
||||
const char* Arg = CollAtUnchecked (&M->FormalArgs, I);
|
||||
CollAppend (&New->FormalArgs, xstrdup (Arg));
|
||||
}
|
||||
New->ArgCount = M->ArgCount;
|
||||
New->Variadic = M->Variadic;
|
||||
SB_Copy (&New->Replacement, &M->Replacement);
|
||||
|
||||
return New;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void DefineNumericMacro (const char* Name, long Val)
|
||||
/* Define a macro for a numeric constant */
|
||||
{
|
||||
@@ -150,10 +177,11 @@ void InsertMacro (Macro* M)
|
||||
|
||||
|
||||
|
||||
int UndefineMacro (const char* Name)
|
||||
/* Search for the macro with the given name and remove it from the macro
|
||||
** table if it exists. Return 1 if a macro was found and deleted, return
|
||||
** 0 otherwise.
|
||||
Macro* UndefineMacro (const char* Name)
|
||||
/* Search for the macro with the given name, if it exists, remove it from
|
||||
** the defined macro table and insert it to a list for pending deletion.
|
||||
** Return the macro if it was found and removed, return 0 otherwise.
|
||||
** To safely free the removed macro, use FreeUndefinedMacros().
|
||||
*/
|
||||
{
|
||||
/* Get the hash value of the macro name */
|
||||
@@ -173,11 +201,12 @@ int UndefineMacro (const char* Name)
|
||||
L->Next = M->Next;
|
||||
}
|
||||
|
||||
/* Delete the macro */
|
||||
FreeMacro (M);
|
||||
/* Add this macro to pending deletion list */
|
||||
M->Next = UndefinedMacrosListHead;
|
||||
UndefinedMacrosListHead = M;
|
||||
|
||||
/* Done */
|
||||
return 1;
|
||||
return M;
|
||||
}
|
||||
|
||||
/* Next macro */
|
||||
@@ -191,6 +220,23 @@ int UndefineMacro (const char* Name)
|
||||
|
||||
|
||||
|
||||
void FreeUndefinedMacros (void)
|
||||
/* Free all undefined macros */
|
||||
{
|
||||
Macro* Next;
|
||||
|
||||
while (UndefinedMacrosListHead != 0) {
|
||||
Next = UndefinedMacrosListHead->Next;
|
||||
|
||||
/* Delete the macro */
|
||||
FreeMacro (UndefinedMacrosListHead);
|
||||
|
||||
UndefinedMacrosListHead = Next;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
Macro* FindMacro (const char* Name)
|
||||
/* Find a macro with the given name. Return the macro definition or NULL */
|
||||
{
|
||||
@@ -201,6 +247,10 @@ Macro* FindMacro (const char* Name)
|
||||
Macro* M = MacroTab[Hash];
|
||||
while (M) {
|
||||
if (strcmp (M->Name, Name) == 0) {
|
||||
/* Check for some special macro names */
|
||||
if (Name[0] == '_') {
|
||||
HandleSpecialMacro (M, Name);
|
||||
}
|
||||
/* Found it */
|
||||
return M;
|
||||
}
|
||||
@@ -245,7 +295,7 @@ void AddMacroArg (Macro* M, const char* Arg)
|
||||
for (I = 0; I < CollCount (&M->FormalArgs); ++I) {
|
||||
if (strcmp (CollAtUnchecked (&M->FormalArgs, I), Arg) == 0) {
|
||||
/* Found */
|
||||
Error ("Duplicate macro parameter: '%s'", Arg);
|
||||
PPError ("Duplicate macro parameter: '%s'", Arg);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -82,6 +82,12 @@ void FreeMacro (Macro* M);
|
||||
** table, use UndefineMacro for that.
|
||||
*/
|
||||
|
||||
Macro* CloneMacro (const Macro* M);
|
||||
/* Clone a macro definition. The function is not insert the macro into the
|
||||
** macro table, thus the cloned instance cannot be freed with UndefineMacro.
|
||||
** Use FreeMacro for that.
|
||||
*/
|
||||
|
||||
void DefineNumericMacro (const char* Name, long Val);
|
||||
/* Define a macro for a numeric constant */
|
||||
|
||||
@@ -91,12 +97,16 @@ void DefineTextMacro (const char* Name, const char* Val);
|
||||
void InsertMacro (Macro* M);
|
||||
/* Insert the given macro into the macro table. */
|
||||
|
||||
int UndefineMacro (const char* Name);
|
||||
/* Search for the macro with the given name and remove it from the macro
|
||||
** table if it exists. Return 1 if a macro was found and deleted, return
|
||||
** 0 otherwise.
|
||||
Macro* UndefineMacro (const char* Name);
|
||||
/* Search for the macro with the given name, if it exists, remove it from
|
||||
** the defined macro table and insert it to a list for pending deletion.
|
||||
** Return the macro if it was found and removed, return 0 otherwise.
|
||||
** To safely free the removed macro, use FreeUndefinedMacros().
|
||||
*/
|
||||
|
||||
void FreeUndefinedMacros (void);
|
||||
/* Free all undefined macros */
|
||||
|
||||
Macro* FindMacro (const char* Name);
|
||||
/* Find a macro with the given name. Return the macro definition or NULL */
|
||||
|
||||
|
||||
878
src/cc65/ppexpr.c
Normal file
878
src/cc65/ppexpr.c
Normal file
@@ -0,0 +1,878 @@
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* ppexpr.h */
|
||||
/* */
|
||||
/* Expressions for C preprocessor */
|
||||
/* */
|
||||
/* */
|
||||
/* */
|
||||
/* (C) 2022 The cc65 Authors */
|
||||
/* */
|
||||
/* */
|
||||
/* This software is provided 'as-is', without any expressed or implied */
|
||||
/* warranty. In no event will the authors be held liable for any damages */
|
||||
/* arising from the use of this software. */
|
||||
/* */
|
||||
/* Permission is granted to anyone to use this software for any purpose, */
|
||||
/* including commercial applications, and to alter it and redistribute it */
|
||||
/* freely, subject to the following restrictions: */
|
||||
/* */
|
||||
/* 1. The origin of this software must not be misrepresented; you must not */
|
||||
/* claim that you wrote the original software. If you use this software */
|
||||
/* in a product, an acknowledgment in the product documentation would be */
|
||||
/* appreciated but is not required. */
|
||||
/* 2. Altered source versions must be plainly marked as such, and must not */
|
||||
/* be misrepresented as being the original software. */
|
||||
/* 3. This notice may not be removed or altered from any source */
|
||||
/* distribution. */
|
||||
/* */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
/* cc65 */
|
||||
#include "error.h"
|
||||
#include "scanner.h"
|
||||
#include "ppexpr.h"
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Data */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
/* PP expression parser status */
|
||||
static int PPEvaluationEnabled = 0;
|
||||
static int PPEvaluationFailed = 0;
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Forwards */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
static void PPhie0 (PPExpr* Expr);
|
||||
static void PPhie1 (PPExpr* Expr);
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Helper functions */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
static token_t PPFindTok (token_t Tok, const token_t* Table)
|
||||
/* Find a token in a generator table */
|
||||
{
|
||||
while (*Table != TOK_INVALID) {
|
||||
if (*Table == Tok) {
|
||||
return Tok;
|
||||
}
|
||||
++Table;
|
||||
}
|
||||
return TOK_INVALID;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void PPExprInit (PPExpr* Expr)
|
||||
/* Initialize the expression */
|
||||
{
|
||||
Expr->IVal = 0;
|
||||
Expr->Flags = PPEXPR_NONE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void PPErrorSkipLine (void)
|
||||
/* Set the expression parser error flag, skip the remain tokens till the end
|
||||
** of the line, clear the current and the next tokens.
|
||||
*/
|
||||
{
|
||||
PPEvaluationFailed = 1;
|
||||
SkipTokens (0, 0);
|
||||
CurTok.Tok = TOK_CEOF;
|
||||
NextTok.Tok = TOK_CEOF;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Code */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
static void PPhiePrimary (PPExpr* Expr)
|
||||
/* This is the lowest level of the PP expression parser */
|
||||
{
|
||||
switch (CurTok.Tok) {
|
||||
case TOK_ICONST:
|
||||
case TOK_CCONST:
|
||||
case TOK_WCCONST:
|
||||
/* Character and integer constants */
|
||||
Expr->IVal = CurTok.IVal;
|
||||
/* According to the C standard, all signed types act as intmax_t
|
||||
** and all unsigned types act as uintmax_t.
|
||||
*/
|
||||
if (IsSignUnsigned (CurTok.Type)) {
|
||||
Expr->Flags |= PPEXPR_UNSIGNED;
|
||||
}
|
||||
NextToken ();
|
||||
break;
|
||||
|
||||
case TOK_FCONST:
|
||||
/* Floating point constant */
|
||||
PPError ("Floating constant in preprocessor expression");
|
||||
Expr->IVal = 0;
|
||||
NextToken ();
|
||||
break;
|
||||
|
||||
case TOK_LPAREN:
|
||||
/* Parse parenthesized subexpression by calling the whole parser
|
||||
** recursively.
|
||||
*/
|
||||
NextToken ();
|
||||
PPhie0 (Expr);
|
||||
ConsumeRParen ();
|
||||
break;
|
||||
|
||||
case TOK_IDENT:
|
||||
/* Assume that this identifier is an undefined macro and replace
|
||||
** it by a constant value of zero.
|
||||
*/
|
||||
NextToken ();
|
||||
Expr->Flags |= PPEXPR_UNDEFINED;
|
||||
Expr->IVal = 0;
|
||||
break;
|
||||
|
||||
case TOK_CEOF:
|
||||
/* Error recovery */
|
||||
break;
|
||||
|
||||
default:
|
||||
/* Illegal expression in PP mode */
|
||||
PPError ("Preprocessor expression expected");
|
||||
PPErrorSkipLine ();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void PPhie11 (PPExpr* Expr)
|
||||
/* Handle compound types (structs and arrays) etc which are invalid in PP */
|
||||
{
|
||||
/* Evaluate the lhs */
|
||||
PPhiePrimary (Expr);
|
||||
|
||||
/* Check for a rhs */
|
||||
while (CurTok.Tok == TOK_INC || CurTok.Tok == TOK_DEC ||
|
||||
CurTok.Tok == TOK_LBRACK || CurTok.Tok == TOK_LPAREN ||
|
||||
CurTok.Tok == TOK_DOT || CurTok.Tok == TOK_PTR_REF) {
|
||||
|
||||
switch (CurTok.Tok) {
|
||||
|
||||
case TOK_LBRACK:
|
||||
PPError ("Token \".\" is not valid in preprocessor expressions");
|
||||
PPErrorSkipLine ();
|
||||
break;
|
||||
|
||||
case TOK_LPAREN:
|
||||
/* Function call syntax is not recognized in preprocessor
|
||||
** expressions.
|
||||
*/
|
||||
PPError ("Missing binary operator before token \"(\"");
|
||||
PPErrorSkipLine ();
|
||||
break;
|
||||
|
||||
case TOK_DOT:
|
||||
PPError ("Token \".\" is not valid in preprocessor expressions");
|
||||
PPErrorSkipLine ();
|
||||
break;
|
||||
|
||||
case TOK_PTR_REF:
|
||||
PPError ("Token \"->\" is not valid in preprocessor expressions");
|
||||
PPErrorSkipLine ();
|
||||
break;
|
||||
|
||||
case TOK_INC:
|
||||
PPError ("Token \"++\" is not valid in preprocessor expressions");
|
||||
PPErrorSkipLine ();
|
||||
break;
|
||||
|
||||
case TOK_DEC:
|
||||
PPError ("Token \"--\" is not valid in preprocessor expressions");
|
||||
PPErrorSkipLine ();
|
||||
break;
|
||||
|
||||
default:
|
||||
Internal ("Invalid token in PPhie11: %d", CurTok.Tok);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/* Check for excessive expressions */
|
||||
if (!TokIsPunc (&CurTok)) {
|
||||
PPError ("Missing binary operator");
|
||||
PPErrorSkipLine ();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void PPhie10 (PPExpr* Expr)
|
||||
/* Handle prefixing unary operators */
|
||||
{
|
||||
switch (CurTok.Tok) {
|
||||
|
||||
case TOK_INC:
|
||||
PPError ("Token \"++\" is not valid in preprocessor expressions");
|
||||
PPErrorSkipLine ();
|
||||
break;
|
||||
|
||||
case TOK_DEC:
|
||||
PPError ("Token \"--\" is not valid in preprocessor expressions");
|
||||
PPErrorSkipLine ();
|
||||
break;
|
||||
|
||||
case TOK_PLUS:
|
||||
NextToken ();
|
||||
PPhie10 (Expr);
|
||||
Expr->IVal = +Expr->IVal;
|
||||
break;
|
||||
|
||||
case TOK_MINUS:
|
||||
NextToken ();
|
||||
PPhie10 (Expr);
|
||||
Expr->IVal = -Expr->IVal;
|
||||
break;
|
||||
|
||||
case TOK_COMP:
|
||||
NextToken ();
|
||||
PPhie10 (Expr);
|
||||
Expr->IVal = ~Expr->IVal;
|
||||
break;
|
||||
|
||||
case TOK_BOOL_NOT:
|
||||
NextToken ();
|
||||
PPhie10 (Expr);
|
||||
Expr->IVal = !Expr->IVal;
|
||||
break;
|
||||
|
||||
case TOK_CEOF:
|
||||
/* Error recovery */
|
||||
break;
|
||||
|
||||
case TOK_STAR:
|
||||
case TOK_AND:
|
||||
case TOK_SIZEOF:
|
||||
default:
|
||||
/* Type cast, sizeof, *, &, are not recognized in preprocessor
|
||||
** expressions. So everything is treated as as expression here.
|
||||
*/
|
||||
PPhie11 (Expr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void PPhie_internal (const token_t* Ops, /* List of generators */
|
||||
PPExpr* Expr,
|
||||
void (*hienext) (PPExpr*))
|
||||
/* Helper function */
|
||||
{
|
||||
token_t Tok;
|
||||
|
||||
hienext (Expr);
|
||||
|
||||
while ((Tok = PPFindTok (CurTok.Tok, Ops)) != 0) {
|
||||
|
||||
PPExpr Rhs;
|
||||
PPExprInit (&Rhs);
|
||||
|
||||
/* Remember the operator token, then skip it */
|
||||
NextToken ();
|
||||
|
||||
/* Get the right hand side */
|
||||
hienext (&Rhs);
|
||||
|
||||
if (PPEvaluationEnabled && !PPEvaluationFailed) {
|
||||
|
||||
/* If either side is unsigned, the result is unsigned */
|
||||
Expr->Flags |= Rhs.Flags & PPEXPR_UNSIGNED;
|
||||
|
||||
/* Handle the op differently for signed and unsigned integers */
|
||||
if ((Expr->Flags & PPEXPR_UNSIGNED) == 0) {
|
||||
|
||||
/* Evaluate the result for signed operands */
|
||||
signed long Val1 = Expr->IVal;
|
||||
signed long Val2 = Rhs.IVal;
|
||||
switch (Tok) {
|
||||
case TOK_OR:
|
||||
Expr->IVal = (Val1 | Val2);
|
||||
break;
|
||||
case TOK_XOR:
|
||||
Expr->IVal = (Val1 ^ Val2);
|
||||
break;
|
||||
case TOK_AND:
|
||||
Expr->IVal = (Val1 & Val2);
|
||||
break;
|
||||
case TOK_PLUS:
|
||||
Expr->IVal = (Val1 + Val2);
|
||||
break;
|
||||
case TOK_MINUS:
|
||||
Expr->IVal = (Val1 - Val2);
|
||||
break;
|
||||
case TOK_MUL:
|
||||
Expr->IVal = (Val1 * Val2);
|
||||
break;
|
||||
case TOK_DIV:
|
||||
if (Val2 == 0) {
|
||||
PPError ("Division by zero");
|
||||
Expr->IVal = 0;
|
||||
} else {
|
||||
Expr->IVal = (Val1 / Val2);
|
||||
}
|
||||
break;
|
||||
case TOK_MOD:
|
||||
if (Val2 == 0) {
|
||||
PPError ("Modulo operation with zero");
|
||||
Expr->IVal = 0;
|
||||
} else {
|
||||
Expr->IVal = (Val1 % Val2);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
Internal ("PPhie_internal: got token 0x%X\n", Tok);
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
/* Evaluate the result for unsigned operands */
|
||||
unsigned long Val1 = Expr->IVal;
|
||||
unsigned long Val2 = Rhs.IVal;
|
||||
switch (Tok) {
|
||||
case TOK_OR:
|
||||
Expr->IVal = (Val1 | Val2);
|
||||
break;
|
||||
case TOK_XOR:
|
||||
Expr->IVal = (Val1 ^ Val2);
|
||||
break;
|
||||
case TOK_AND:
|
||||
Expr->IVal = (Val1 & Val2);
|
||||
break;
|
||||
case TOK_PLUS:
|
||||
Expr->IVal = (Val1 + Val2);
|
||||
break;
|
||||
case TOK_MINUS:
|
||||
Expr->IVal = (Val1 - Val2);
|
||||
break;
|
||||
case TOK_MUL:
|
||||
Expr->IVal = (Val1 * Val2);
|
||||
break;
|
||||
case TOK_DIV:
|
||||
if (Val2 == 0) {
|
||||
PPError ("Division by zero");
|
||||
Expr->IVal = 0;
|
||||
} else {
|
||||
Expr->IVal = (Val1 / Val2);
|
||||
}
|
||||
break;
|
||||
case TOK_MOD:
|
||||
if (Val2 == 0) {
|
||||
PPError ("Modulo operation with zero");
|
||||
Expr->IVal = 0;
|
||||
} else {
|
||||
Expr->IVal = (Val1 % Val2);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
Internal ("PPhie_internal: got token 0x%X\n", Tok);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void PPhie_compare (const token_t* Ops, /* List of generators */
|
||||
PPExpr* Expr,
|
||||
void (*hienext) (PPExpr*))
|
||||
/* Helper function for the compare operators */
|
||||
{
|
||||
token_t Tok;
|
||||
|
||||
hienext (Expr);
|
||||
|
||||
while ((Tok = PPFindTok (CurTok.Tok, Ops)) != 0) {
|
||||
|
||||
PPExpr Rhs;
|
||||
|
||||
PPExprInit (&Rhs);
|
||||
|
||||
/* Skip the operator token */
|
||||
NextToken ();
|
||||
|
||||
/* Get the right hand side */
|
||||
hienext (&Rhs);
|
||||
|
||||
if (PPEvaluationEnabled && !PPEvaluationFailed) {
|
||||
|
||||
/* If either side is unsigned, the comparison is unsigned */
|
||||
Expr->Flags |= Rhs.Flags & PPEXPR_UNSIGNED;
|
||||
|
||||
/* Determine if this is a signed or unsigned compare */
|
||||
if ((Expr->Flags & PPEXPR_UNSIGNED) == 0) {
|
||||
|
||||
/* Evaluate the result for signed operands */
|
||||
signed long Val1 = Expr->IVal;
|
||||
signed long Val2 = Rhs.IVal;
|
||||
switch (Tok) {
|
||||
case TOK_EQ: Expr->IVal = (Val1 == Val2); break;
|
||||
case TOK_NE: Expr->IVal = (Val1 != Val2); break;
|
||||
case TOK_LT: Expr->IVal = (Val1 < Val2); break;
|
||||
case TOK_LE: Expr->IVal = (Val1 <= Val2); break;
|
||||
case TOK_GE: Expr->IVal = (Val1 >= Val2); break;
|
||||
case TOK_GT: Expr->IVal = (Val1 > Val2); break;
|
||||
default: Internal ("PPhie_compare: got token 0x%X\n", Tok);
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
/* Evaluate the result for unsigned operands */
|
||||
unsigned long Val1 = Expr->IVal;
|
||||
unsigned long Val2 = Rhs.IVal;
|
||||
switch (Tok) {
|
||||
case TOK_EQ: Expr->IVal = (Val1 == Val2); break;
|
||||
case TOK_NE: Expr->IVal = (Val1 != Val2); break;
|
||||
case TOK_LT: Expr->IVal = (Val1 < Val2); break;
|
||||
case TOK_LE: Expr->IVal = (Val1 <= Val2); break;
|
||||
case TOK_GE: Expr->IVal = (Val1 >= Val2); break;
|
||||
case TOK_GT: Expr->IVal = (Val1 > Val2); break;
|
||||
default: Internal ("PPhie_compare: got token 0x%X\n", Tok);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* The result is signed */
|
||||
Expr->Flags &= ~PPEXPR_UNSIGNED;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void PPhie9 (PPExpr* Expr)
|
||||
/* Handle "*", "/" and "%" operators */
|
||||
{
|
||||
static const token_t PPhie9_ops[] = {
|
||||
TOK_STAR,
|
||||
TOK_DIV,
|
||||
TOK_MOD,
|
||||
TOK_INVALID
|
||||
};
|
||||
|
||||
PPhie_internal (PPhie9_ops, Expr, PPhie10);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void PPhie8 (PPExpr* Expr)
|
||||
/* Handle "+" and "-" binary operators */
|
||||
{
|
||||
static const token_t PPhie8_ops[] = {
|
||||
TOK_PLUS,
|
||||
TOK_MINUS,
|
||||
TOK_INVALID
|
||||
};
|
||||
|
||||
PPhie_internal (PPhie8_ops, Expr, PPhie9);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void PPhie7 (PPExpr* Expr)
|
||||
/* Handle the "<<" and ">>" shift operators */
|
||||
{
|
||||
/* Evaluate the lhs */
|
||||
PPhie8 (Expr);
|
||||
|
||||
while (CurTok.Tok == TOK_SHL || CurTok.Tok == TOK_SHR) {
|
||||
|
||||
token_t Op; /* The operator token */
|
||||
PPExpr Rhs;
|
||||
PPExprInit (&Rhs);
|
||||
|
||||
/* Remember the operator, then skip its token */
|
||||
Op = CurTok.Tok;
|
||||
NextToken ();
|
||||
|
||||
/* Get the right hand side */
|
||||
PPhie8 (&Rhs);
|
||||
|
||||
/* Evaluate */
|
||||
if (PPEvaluationEnabled && !PPEvaluationFailed) {
|
||||
/* To shift by a negative value is equivalent to shift to the
|
||||
** opposite direction.
|
||||
*/
|
||||
if ((Rhs.Flags & PPEXPR_UNSIGNED) != 0 && Rhs.IVal > (long)LONG_BITS) {
|
||||
Rhs.IVal = (long)LONG_BITS;
|
||||
}
|
||||
if (Op == TOK_SHR) {
|
||||
Rhs.IVal = -Rhs.IVal;
|
||||
}
|
||||
|
||||
/* Evaluate the result */
|
||||
if ((Expr->Flags & PPEXPR_UNSIGNED) != 0) {
|
||||
if (Rhs.IVal >= (long)LONG_BITS) {
|
||||
/* For now we use (unsigned) long types for integer constants */
|
||||
PPWarning ("Integer overflow in preprocessor expression");
|
||||
Expr->IVal = 0;
|
||||
} else if (Rhs.IVal > 0) {
|
||||
Expr->IVal <<= Rhs.IVal;
|
||||
} else if (Rhs.IVal < -(long)LONG_BITS) {
|
||||
Expr->IVal = 0;
|
||||
} else if (Rhs.IVal < 0) {
|
||||
Expr->IVal = (unsigned long)Expr->IVal >> -Rhs.IVal;
|
||||
}
|
||||
} else {
|
||||
if (Rhs.IVal >= (long)(LONG_BITS - 1)) {
|
||||
/* For now we use (unsigned) long types for integer constants */
|
||||
PPWarning ("Integer overflow in preprocessor expression");
|
||||
Expr->IVal = 0;
|
||||
} else if (Rhs.IVal > 0) {
|
||||
Expr->IVal <<= Rhs.IVal;
|
||||
} else if (Rhs.IVal < -(long)LONG_BITS) {
|
||||
Expr->IVal = -1;
|
||||
} else if (Rhs.IVal < 0) {
|
||||
Expr->IVal >>= Expr->IVal >> -Rhs.IVal;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void PPhie6 (PPExpr* Expr)
|
||||
/* Handle greater-than type relational operators */
|
||||
{
|
||||
static const token_t PPhie6_ops [] = {
|
||||
TOK_LT,
|
||||
TOK_LE,
|
||||
TOK_GE,
|
||||
TOK_GT,
|
||||
TOK_INVALID
|
||||
};
|
||||
|
||||
PPhie_compare (PPhie6_ops, Expr, PPhie7);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void PPhie5 (PPExpr* Expr)
|
||||
/* Handle "==" and "!=" relational operators */
|
||||
{
|
||||
static const token_t PPhie5_ops[] = {
|
||||
TOK_EQ,
|
||||
TOK_NE,
|
||||
TOK_INVALID
|
||||
};
|
||||
|
||||
PPhie_compare (PPhie5_ops, Expr, PPhie6);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void PPhie4 (PPExpr* Expr)
|
||||
/* Handle the bitwise AND "&" operator */
|
||||
{
|
||||
static const token_t PPhie4_ops[] = {
|
||||
TOK_AND,
|
||||
TOK_INVALID
|
||||
};
|
||||
|
||||
PPhie_internal (PPhie4_ops, Expr, PPhie5);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void PPhie3 (PPExpr* Expr)
|
||||
/* Handle the bitwise exclusive OR "^" operator */
|
||||
{
|
||||
static const token_t PPhie3_ops[] = {
|
||||
TOK_XOR,
|
||||
TOK_INVALID
|
||||
};
|
||||
|
||||
PPhie_internal (PPhie3_ops, Expr, PPhie4);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void PPhie2 (PPExpr* Expr)
|
||||
/* Handle the bitwise OR "|" operator */
|
||||
{
|
||||
static const token_t PPhie2_ops[] = {
|
||||
TOK_OR,
|
||||
TOK_INVALID
|
||||
};
|
||||
|
||||
PPhie_internal (PPhie2_ops, Expr, PPhie3);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void PPhieAnd (PPExpr* Expr)
|
||||
/* Handle the logical AND "expr1 && expr2" operator */
|
||||
{
|
||||
/* Get one operand */
|
||||
PPhie2 (Expr);
|
||||
|
||||
if (CurTok.Tok == TOK_BOOL_AND) {
|
||||
|
||||
int PPEvaluationEnabledPrev = PPEvaluationEnabled;
|
||||
PPExpr One;
|
||||
|
||||
/* Do logical and */
|
||||
Expr->IVal = (Expr->IVal != 0);
|
||||
if (Expr->IVal == 0) {
|
||||
PPEvaluationEnabled = 0;
|
||||
}
|
||||
|
||||
/* While there are more expressions */
|
||||
while (CurTok.Tok == TOK_BOOL_AND) {
|
||||
/* Skip the && */
|
||||
NextToken ();
|
||||
|
||||
/* Get one operand */
|
||||
PPExprInit (&One);
|
||||
PPhie2 (&One);
|
||||
|
||||
/* Evaluate */
|
||||
if (PPEvaluationEnabled) {
|
||||
if (One.IVal == 0) {
|
||||
/* Skip evaluating remaining */
|
||||
PPEvaluationEnabled = 0;
|
||||
/* The value of the result will be false */
|
||||
Expr->IVal = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Restore evaluation as before */
|
||||
PPEvaluationEnabled = PPEvaluationEnabledPrev;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void PPhieOr (PPExpr* Expr)
|
||||
/* Handle the logical OR "||" operator */
|
||||
{
|
||||
/* Call the next level parser */
|
||||
PPhieAnd (Expr);
|
||||
|
||||
if (CurTok.Tok == TOK_BOOL_OR) {
|
||||
|
||||
int PPEvaluationEnabledPrev = PPEvaluationEnabled;
|
||||
PPExpr One;
|
||||
|
||||
/* Do logical or */
|
||||
Expr->IVal = (Expr->IVal != 0);
|
||||
if (Expr->IVal != 0) {
|
||||
PPEvaluationEnabled = 0;
|
||||
}
|
||||
|
||||
/* While there are more expressions */
|
||||
while (CurTok.Tok == TOK_BOOL_OR) {
|
||||
/* Skip the || */
|
||||
NextToken ();
|
||||
|
||||
/* Get rhs subexpression */
|
||||
PPExprInit (&One);
|
||||
PPhieAnd (&One);
|
||||
|
||||
/* Evaluate */
|
||||
if (PPEvaluationEnabled) {
|
||||
if (One.IVal != 0) {
|
||||
/* Skip evaluating remaining */
|
||||
PPEvaluationEnabled = 0;
|
||||
/* The value of the result will be true */
|
||||
Expr->IVal = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Restore evaluation as before */
|
||||
PPEvaluationEnabled = PPEvaluationEnabledPrev;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void PPhieQuest (PPExpr* Expr)
|
||||
/* Handle the ternary "expr1 ? expr2 : expr3 " operator */
|
||||
{
|
||||
/* Call the lower level eval routine */
|
||||
PPhieOr (Expr);
|
||||
|
||||
/* Check if it's a ternary expression */
|
||||
if (CurTok.Tok == TOK_QUEST) {
|
||||
int PPEvaluationEnabledPrev = PPEvaluationEnabled;
|
||||
PPExpr Expr2; /* Expression 2 */
|
||||
PPExpr Expr3; /* Expression 3 */
|
||||
|
||||
/* Skip the question mark */
|
||||
NextToken ();
|
||||
|
||||
/* Disable evaluation for Expr2 if the condition is false */
|
||||
if (Expr->IVal == 0) {
|
||||
PPEvaluationEnabled = 0;
|
||||
}
|
||||
|
||||
/* Parse second expression */
|
||||
PPExprInit (&Expr2);
|
||||
PPhie0 (&Expr2);
|
||||
|
||||
/* Skip the colon */
|
||||
ConsumeColon ();
|
||||
|
||||
/* Disable evaluation for Expr3 if the condition is true */
|
||||
if (Expr->IVal != 0) {
|
||||
PPEvaluationEnabled = 0;
|
||||
}
|
||||
|
||||
/* Parse third expression */
|
||||
PPExprInit (&Expr3);
|
||||
PPhie1 (&Expr3);
|
||||
|
||||
/* Set the result */
|
||||
Expr->IVal = Expr->IVal ? Expr2.IVal != 0 : Expr3.IVal != 0;
|
||||
|
||||
/* Restore evaluation as before */
|
||||
PPEvaluationEnabled = PPEvaluationEnabledPrev;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void PPhie1 (PPExpr* Expr)
|
||||
/* Handle first level of expression hierarchy */
|
||||
{
|
||||
PPhieQuest (Expr);
|
||||
|
||||
if (!PPEvaluationEnabled) {
|
||||
/* Skip evaluation */
|
||||
return;
|
||||
}
|
||||
|
||||
switch (CurTok.Tok) {
|
||||
|
||||
case TOK_ASSIGN:
|
||||
PPError ("Token \"=\" is not valid in preprocessor expressions");
|
||||
PPErrorSkipLine ();
|
||||
break;
|
||||
|
||||
case TOK_PLUS_ASSIGN:
|
||||
PPError ("Token \"+=\" is not valid in preprocessor expressions");
|
||||
PPErrorSkipLine ();
|
||||
break;
|
||||
|
||||
case TOK_MINUS_ASSIGN:
|
||||
PPError ("Token \"-=\" is not valid in preprocessor expressions");
|
||||
PPErrorSkipLine ();
|
||||
break;
|
||||
|
||||
case TOK_MUL_ASSIGN:
|
||||
PPError ("Token \"*=\" is not valid in preprocessor expressions");
|
||||
PPErrorSkipLine ();
|
||||
break;
|
||||
|
||||
case TOK_DIV_ASSIGN:
|
||||
PPError ("Token \"/=\" is not valid in preprocessor expressions");
|
||||
PPErrorSkipLine ();
|
||||
break;
|
||||
|
||||
case TOK_MOD_ASSIGN:
|
||||
PPError ("Token \"%%=\" is not valid in preprocessor expressions");
|
||||
PPErrorSkipLine ();
|
||||
break;
|
||||
|
||||
case TOK_SHL_ASSIGN:
|
||||
PPError ("Token \"<<=\" is not valid in preprocessor expressions");
|
||||
PPErrorSkipLine ();
|
||||
break;
|
||||
|
||||
case TOK_SHR_ASSIGN:
|
||||
PPError ("Token \">>=\" is not valid in preprocessor expressions");
|
||||
PPErrorSkipLine ();
|
||||
break;
|
||||
|
||||
case TOK_AND_ASSIGN:
|
||||
PPError ("Token \"&=\" is not valid in preprocessor expressions");
|
||||
PPErrorSkipLine ();
|
||||
break;
|
||||
|
||||
case TOK_OR_ASSIGN:
|
||||
PPError ("Token \"|=\" is not valid in preprocessor expressions");
|
||||
PPErrorSkipLine ();
|
||||
break;
|
||||
|
||||
case TOK_XOR_ASSIGN:
|
||||
PPError ("Token \"^=\" is not valid in preprocessor expressions");
|
||||
PPErrorSkipLine ();
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void PPhie0 (PPExpr* Expr)
|
||||
/* Handle the comma "," operator */
|
||||
{
|
||||
PPhie1 (Expr);
|
||||
|
||||
while (CurTok.Tok == TOK_COMMA) {
|
||||
/* Skip the comma */
|
||||
NextToken ();
|
||||
/* Reset the expression */
|
||||
PPExprInit (Expr);
|
||||
/* Use the next operand as the value instead */
|
||||
PPhie1 (Expr);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void ParsePPExprInLine (PPExpr* Expr)
|
||||
/* Parse a line for PP expression */
|
||||
{
|
||||
/* Initialize the parser status */
|
||||
PPEvaluationFailed = 0;
|
||||
PPEvaluationEnabled = 1;
|
||||
PPParserRunning = 1;
|
||||
|
||||
/* Parse */
|
||||
PPExprInit (Expr);
|
||||
PPhie0 (Expr);
|
||||
|
||||
/* If the evaluation fails, the result is always zero */
|
||||
if (PPEvaluationFailed) {
|
||||
Expr->IVal = 0;
|
||||
PPEvaluationFailed = 0;
|
||||
}
|
||||
|
||||
/* Restore parser status */
|
||||
PPParserRunning = 0;
|
||||
}
|
||||
76
src/cc65/ppexpr.h
Normal file
76
src/cc65/ppexpr.h
Normal file
@@ -0,0 +1,76 @@
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* ppexpr.h */
|
||||
/* */
|
||||
/* Expressions for C preprocessor */
|
||||
/* */
|
||||
/* */
|
||||
/* */
|
||||
/* (C) 2022 The cc65 Authors */
|
||||
/* */
|
||||
/* */
|
||||
/* This software is provided 'as-is', without any expressed or implied */
|
||||
/* warranty. In no event will the authors be held liable for any damages */
|
||||
/* arising from the use of this software. */
|
||||
/* */
|
||||
/* Permission is granted to anyone to use this software for any purpose, */
|
||||
/* including commercial applications, and to alter it and redistribute it */
|
||||
/* freely, subject to the following restrictions: */
|
||||
/* */
|
||||
/* 1. The origin of this software must not be misrepresented; you must not */
|
||||
/* claim that you wrote the original software. If you use this software */
|
||||
/* in a product, an acknowledgment in the product documentation would be */
|
||||
/* appreciated but is not required. */
|
||||
/* 2. Altered source versions must be plainly marked as such, and must not */
|
||||
/* be misrepresented as being the original software. */
|
||||
/* 3. This notice may not be removed or altered from any source */
|
||||
/* distribution. */
|
||||
/* */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
#ifndef PPEXPR_H
|
||||
#define PPEXPR_H
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Data */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
/* PPExpr data struct */
|
||||
typedef struct PPExpr PPExpr;
|
||||
struct PPExpr
|
||||
{
|
||||
long IVal;
|
||||
unsigned Flags;
|
||||
};
|
||||
|
||||
/* PPExpr initializers */
|
||||
#define AUTO_PPEXPR_INITIALIZER { 0, 0 }
|
||||
#define STATIC_PPEXPR_INITIALIZER { 0, 0 }
|
||||
|
||||
/* PPExpr flags */
|
||||
#define PPEXPR_NONE 0U
|
||||
#define PPEXPR_UNSIGNED 1U
|
||||
#define PPEXPR_UNDEFINED 2U
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Code */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
void ParsePPExprInLine (PPExpr* Expr);
|
||||
/* Parse a line for PP expression */
|
||||
|
||||
|
||||
|
||||
/* End of ppexpr.h */
|
||||
|
||||
#endif
|
||||
1362
src/cc65/preproc.c
1362
src/cc65/preproc.c
File diff suppressed because it is too large
Load Diff
@@ -39,18 +39,35 @@
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* data */
|
||||
/* Forwards */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
/* Set when the preprocessor calls NoCodeConstExpr() recursively */
|
||||
extern unsigned char Preprocessing;
|
||||
typedef struct Macro Macro;
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* code */
|
||||
/* Data */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
/* Maximum #if depth per file */
|
||||
#define MAX_PP_IFS 256
|
||||
|
||||
/* Data struct used for per-file-directive handling */
|
||||
typedef struct PPIfStack PPIfStack;
|
||||
struct PPIfStack {
|
||||
unsigned char Stack[MAX_PP_IFS];
|
||||
int Index;
|
||||
};
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Code */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
@@ -58,6 +75,24 @@ extern unsigned char Preprocessing;
|
||||
void Preprocess (void);
|
||||
/* Preprocess a line */
|
||||
|
||||
void SetPPIfStack (PPIfStack* Stack);
|
||||
/* Specify which PP #if stack to use */
|
||||
|
||||
void PreprocessBegin (void);
|
||||
/* Initialize preprocessor with current file */
|
||||
|
||||
void PreprocessEnd (void);
|
||||
/* Preprocessor done with current file */
|
||||
|
||||
void InitPreprocess (void);
|
||||
/* Init preprocessor */
|
||||
|
||||
void DonePreprocess (void);
|
||||
/* Done with preprocessor */
|
||||
|
||||
void HandleSpecialMacro (Macro* M, const char* Name);
|
||||
/* Handle special "magic" macros that may change */
|
||||
|
||||
|
||||
|
||||
/* End of preproc.h */
|
||||
|
||||
@@ -69,6 +69,7 @@
|
||||
|
||||
Token CurTok; /* The current token */
|
||||
Token NextTok; /* The next token */
|
||||
int PPParserRunning; /* Is tokenizer used by the preprocessor */
|
||||
|
||||
|
||||
|
||||
@@ -188,10 +189,12 @@ static int SkipWhite (void)
|
||||
{
|
||||
while (1) {
|
||||
while (CurC == '\0') {
|
||||
if (NextLine () == 0) {
|
||||
/* If reading next line fails or is disabled with directives, bail
|
||||
** out.
|
||||
*/
|
||||
if (PPParserRunning || PreprocessNextLine () == 0) {
|
||||
return 0;
|
||||
}
|
||||
Preprocess ();
|
||||
}
|
||||
if (IsSpace (CurC)) {
|
||||
NextChar ();
|
||||
@@ -245,6 +248,45 @@ int IsSym (char* S)
|
||||
|
||||
|
||||
|
||||
int IsPPNumber (int Cur, int Next)
|
||||
/* Return 1 if the two successive characters indicate a pp-number, otherwise
|
||||
** return 0.
|
||||
*/
|
||||
{
|
||||
return Cur != '.' ? IsDigit (Cur) : IsDigit (Next);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void CopyPPNumber (StrBuf* Target)
|
||||
/* Copy a pp-number from the input to Target */
|
||||
{
|
||||
int Std;
|
||||
|
||||
if (!IsPPNumber (CurC, NextC)) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* P-exp is only valid in C99 and later */
|
||||
Std = IS_Get (&Standard);
|
||||
while (IsIdent (CurC) || IsDigit (CurC) || CurC == '.') {
|
||||
SB_AppendChar (Target, CurC);
|
||||
if (NextC == '+' || NextC == '-') {
|
||||
if (CurC == 'e' || CurC == 'E' ||
|
||||
(Std >= STD_C99 && (CurC == 'p' || CurC == 'P'))) {
|
||||
SB_AppendChar (Target, NextC);
|
||||
NextChar ();
|
||||
} else {
|
||||
NextChar ();
|
||||
break;
|
||||
}
|
||||
}
|
||||
NextChar ();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void UnknownChar (char C)
|
||||
/* Error message for unknown character */
|
||||
{
|
||||
@@ -370,6 +412,15 @@ static void CharConst (void)
|
||||
{
|
||||
int C;
|
||||
|
||||
if (CurC == 'L') {
|
||||
/* Wide character constant */
|
||||
NextTok.Tok = TOK_WCCONST;
|
||||
NextChar ();
|
||||
} else {
|
||||
/* Narrow character constant */
|
||||
NextTok.Tok = TOK_CCONST;
|
||||
}
|
||||
|
||||
/* Skip the quote */
|
||||
NextChar ();
|
||||
|
||||
@@ -384,9 +435,6 @@ static void CharConst (void)
|
||||
NextChar ();
|
||||
}
|
||||
|
||||
/* Setup values and attributes */
|
||||
NextTok.Tok = TOK_CCONST;
|
||||
|
||||
/* Translate into target charset */
|
||||
NextTok.IVal = SignExtendChar (TgtTranslateChar (C));
|
||||
|
||||
@@ -457,76 +505,77 @@ static void StringConst (void)
|
||||
static void NumericConst (void)
|
||||
/* Parse a numeric constant */
|
||||
{
|
||||
unsigned Base; /* Temporary number base */
|
||||
unsigned Prefix; /* Base according to prefix */
|
||||
StrBuf S = STATIC_STRBUF_INITIALIZER;
|
||||
unsigned Base; /* Temporary number base according to prefix */
|
||||
unsigned Index;
|
||||
StrBuf Src = AUTO_STRBUF_INITIALIZER;
|
||||
int IsFloat;
|
||||
char C;
|
||||
unsigned DigitVal;
|
||||
unsigned long IVal; /* Value */
|
||||
|
||||
/* Get the pp-number first, then parse on it */
|
||||
CopyPPNumber (&Src);
|
||||
SB_Terminate (&Src);
|
||||
SB_Reset (&Src);
|
||||
|
||||
/* Check for a leading hex, octal or binary prefix and determine the
|
||||
** possible integer types.
|
||||
*/
|
||||
if (CurC == '0') {
|
||||
if (SB_Peek (&Src) == '0') {
|
||||
/* Gobble 0 and examine next char */
|
||||
NextChar ();
|
||||
if (toupper (CurC) == 'X') {
|
||||
Base = Prefix = 16;
|
||||
NextChar (); /* gobble "x" */
|
||||
} else if (toupper (CurC) == 'B' && IS_Get (&Standard) >= STD_CC65) {
|
||||
Base = Prefix = 2;
|
||||
NextChar (); /* gobble 'b' */
|
||||
SB_Skip (&Src);
|
||||
if (toupper (SB_Peek (&Src)) == 'X' &&
|
||||
IsXDigit (SB_LookAt (&Src, SB_GetIndex (&Src) + 1))) {
|
||||
Base = 16;
|
||||
SB_Skip (&Src); /* gobble "x" */
|
||||
} else if (toupper (SB_Peek (&Src)) == 'B' &&
|
||||
IS_Get (&Standard) >= STD_CC65 &&
|
||||
IsDigit (SB_LookAt (&Src, SB_GetIndex (&Src) + 1))) {
|
||||
Base = 2;
|
||||
SB_Skip (&Src); /* gobble 'b' */
|
||||
} else {
|
||||
Base = 10; /* Assume 10 for now - see below */
|
||||
Prefix = 8; /* Actual prefix says octal */
|
||||
}
|
||||
} else {
|
||||
Base = Prefix = 10;
|
||||
Base = 10;
|
||||
}
|
||||
|
||||
/* Because floating point numbers don't have octal prefixes (a number
|
||||
** with a leading zero is decimal), we first have to read the number
|
||||
** before converting it, so we can determine if it's a float or an
|
||||
** integer.
|
||||
/* Because floating point numbers don't have octal prefixes (a number with
|
||||
** a leading zero is decimal), we first have to read the number before
|
||||
** converting it, so we can determine if it's a float or an integer.
|
||||
*/
|
||||
while (IsXDigit (CurC) && HexVal (CurC) < Base) {
|
||||
SB_AppendChar (&S, CurC);
|
||||
NextChar ();
|
||||
Index = SB_GetIndex (&Src);
|
||||
while ((C = SB_Peek (&Src)) != '\0' && (Base <= 10 ? IsDigit (C) : IsXDigit (C))) {
|
||||
SB_Skip (&Src);
|
||||
}
|
||||
SB_Terminate (&S);
|
||||
|
||||
/* The following character tells us if we have an integer or floating
|
||||
** point constant. Note: Hexadecimal floating point constants aren't
|
||||
** supported in C89.
|
||||
*/
|
||||
IsFloat = (CurC == '.' ||
|
||||
(Base == 10 && toupper (CurC) == 'E') ||
|
||||
(Base == 16 && toupper (CurC) == 'P' && IS_Get (&Standard) >= STD_C99));
|
||||
IsFloat = (C == '.' ||
|
||||
(Base == 10 && toupper (C) == 'E') ||
|
||||
(Base == 16 && toupper (C) == 'P' && IS_Get (&Standard) >= STD_C99));
|
||||
|
||||
/* If we don't have a floating point type, an octal prefix results in an
|
||||
** octal base.
|
||||
*/
|
||||
if (!IsFloat && Prefix == 8) {
|
||||
/* An octal prefix for an integer type results in an octal base */
|
||||
if (!IsFloat && Base == 10 && SB_LookAt (&Src, 0) == '0') {
|
||||
Base = 8;
|
||||
}
|
||||
|
||||
/* Since we do now know the correct base, convert the remembered input
|
||||
** into a number.
|
||||
*/
|
||||
SB_Reset (&S);
|
||||
/* Since we now know the correct base, convert the input into a number */
|
||||
SB_SetIndex (&Src, Index);
|
||||
IVal = 0;
|
||||
while ((C = SB_Get (&S)) != '\0') {
|
||||
while ((C = SB_Peek (&Src)) != '\0' && (Base <= 10 ? IsDigit (C) : IsXDigit (C))) {
|
||||
DigitVal = HexVal (C);
|
||||
if (DigitVal >= Base) {
|
||||
Error ("Numeric constant contains digits beyond the radix");
|
||||
Error ("Invalid digit \"%c\" beyond radix %u constant", C, Base);
|
||||
SB_Clear (&Src);
|
||||
break;
|
||||
}
|
||||
IVal = (IVal * Base) + DigitVal;
|
||||
SB_Skip (&Src);
|
||||
}
|
||||
|
||||
/* We don't need the string buffer any longer */
|
||||
SB_Done (&S);
|
||||
|
||||
/* Distinguish between integer and floating point constants */
|
||||
if (!IsFloat) {
|
||||
|
||||
@@ -537,27 +586,32 @@ static void NumericConst (void)
|
||||
** possible to convert the data to unsigned long even if the IT_ULONG
|
||||
** flag were not set, but we are not doing that.
|
||||
*/
|
||||
if (toupper (CurC) == 'U') {
|
||||
if (toupper (SB_Peek (&Src)) == 'U') {
|
||||
/* Unsigned type */
|
||||
NextChar ();
|
||||
if (toupper (CurC) != 'L') {
|
||||
SB_Skip (&Src);
|
||||
if (toupper (SB_Peek (&Src)) != 'L') {
|
||||
Types = IT_UINT | IT_ULONG;
|
||||
} else {
|
||||
NextChar ();
|
||||
SB_Skip (&Src);
|
||||
Types = IT_ULONG;
|
||||
}
|
||||
} else if (toupper (CurC) == 'L') {
|
||||
} else if (toupper (SB_Peek (&Src)) == 'L') {
|
||||
/* Long type */
|
||||
NextChar ();
|
||||
if (toupper (CurC) != 'U') {
|
||||
SB_Skip (&Src);
|
||||
if (toupper (SB_Peek (&Src)) != 'U') {
|
||||
Types = IT_LONG | IT_ULONG;
|
||||
WarnTypes = IT_ULONG;
|
||||
} else {
|
||||
NextChar ();
|
||||
SB_Skip (&Src);
|
||||
Types = IT_ULONG;
|
||||
}
|
||||
} else {
|
||||
if (Prefix == 10) {
|
||||
if (SB_Peek (&Src) != '\0') {
|
||||
Error ("Invalid suffix \"%s\" on integer constant",
|
||||
SB_GetConstBuf (&Src) + SB_GetIndex (&Src));
|
||||
}
|
||||
|
||||
if (Base == 10) {
|
||||
/* Decimal constants are of any type but uint */
|
||||
Types = IT_INT | IT_LONG | IT_ULONG;
|
||||
WarnTypes = IT_LONG | IT_ULONG;
|
||||
@@ -621,16 +675,16 @@ static void NumericConst (void)
|
||||
Double FVal = FP_D_FromInt (IVal); /* Convert to double */
|
||||
|
||||
/* Check for a fractional part and read it */
|
||||
if (CurC == '.') {
|
||||
if (SB_Peek (&Src) == '.') {
|
||||
|
||||
Double Scale;
|
||||
|
||||
/* Skip the dot */
|
||||
NextChar ();
|
||||
SB_Skip (&Src);
|
||||
|
||||
/* Read fractional digits */
|
||||
Scale = FP_D_Make (1.0);
|
||||
while (IsXDigit (CurC) && (DigitVal = HexVal (CurC)) < Base) {
|
||||
while (IsXDigit (SB_Peek (&Src)) && (DigitVal = HexVal (SB_Peek (&Src))) < Base) {
|
||||
/* Get the value of this digit */
|
||||
Double FracVal = FP_D_Div (FP_D_FromInt (DigitVal * Base), Scale);
|
||||
/* Add it to the float value */
|
||||
@@ -638,25 +692,25 @@ static void NumericConst (void)
|
||||
/* Scale base */
|
||||
Scale = FP_D_Mul (Scale, FP_D_FromInt (DigitVal));
|
||||
/* Skip the digit */
|
||||
NextChar ();
|
||||
SB_Skip (&Src);
|
||||
}
|
||||
}
|
||||
|
||||
/* Check for an exponent and read it */
|
||||
if ((Base == 16 && toupper (CurC) == 'F') ||
|
||||
(Base == 10 && toupper (CurC) == 'E')) {
|
||||
if ((Base == 16 && toupper (SB_Peek (&Src)) == 'P') ||
|
||||
(Base == 10 && toupper (SB_Peek (&Src)) == 'E')) {
|
||||
|
||||
unsigned Digits;
|
||||
unsigned Exp;
|
||||
|
||||
/* Skip the exponent notifier */
|
||||
NextChar ();
|
||||
SB_Skip (&Src);
|
||||
|
||||
/* Read an optional sign */
|
||||
if (CurC == '-') {
|
||||
NextChar ();
|
||||
} else if (CurC == '+') {
|
||||
NextChar ();
|
||||
if (SB_Peek (&Src) == '-') {
|
||||
SB_Skip (&Src);
|
||||
} else if (SB_Peek (&Src) == '+') {
|
||||
SB_Skip (&Src);
|
||||
}
|
||||
|
||||
/* Read exponent digits. Since we support only 32 bit floats
|
||||
@@ -667,11 +721,11 @@ static void NumericConst (void)
|
||||
*/
|
||||
Digits = 0;
|
||||
Exp = 0;
|
||||
while (IsDigit (CurC)) {
|
||||
while (IsDigit (SB_Peek (&Src))) {
|
||||
if (++Digits <= 3) {
|
||||
Exp = Exp * 10 + HexVal (CurC);
|
||||
Exp = Exp * 10 + HexVal (SB_Peek (&Src));
|
||||
}
|
||||
NextChar ();
|
||||
SB_Skip (&Src);
|
||||
}
|
||||
|
||||
/* Check for errors: We must have exponent digits, and not more
|
||||
@@ -690,10 +744,14 @@ static void NumericConst (void)
|
||||
}
|
||||
|
||||
/* Check for a suffix and determine the type of the constant */
|
||||
if (toupper (CurC) == 'F') {
|
||||
NextChar ();
|
||||
if (toupper (SB_Peek (&Src)) == 'F') {
|
||||
SB_Skip (&Src);
|
||||
NextTok.Type = type_float;
|
||||
} else {
|
||||
if (SB_Peek (&Src) != '\0') {
|
||||
Error ("Invalid suffix \"%s\" on floating constant",
|
||||
SB_GetConstBuf (&Src) + SB_GetIndex (&Src));
|
||||
}
|
||||
NextTok.Type = type_double;
|
||||
}
|
||||
|
||||
@@ -702,6 +760,9 @@ static void NumericConst (void)
|
||||
NextTok.Tok = TOK_FCONST;
|
||||
|
||||
}
|
||||
|
||||
/* We don't need the string buffer any longer */
|
||||
SB_Done (&Src);
|
||||
}
|
||||
|
||||
|
||||
@@ -743,39 +804,38 @@ void NextToken (void)
|
||||
}
|
||||
|
||||
/* Determine the next token from the lookahead */
|
||||
if (IsDigit (CurC) || (CurC == '.' && IsDigit (NextC))) {
|
||||
if (IsPPNumber (CurC, NextC)) {
|
||||
/* A number */
|
||||
NumericConst ();
|
||||
return;
|
||||
}
|
||||
|
||||
/* Check for wide character literals */
|
||||
if (CurC == 'L' && NextC == '\"') {
|
||||
StringConst ();
|
||||
return;
|
||||
/* Check for wide character constants and literals */
|
||||
if (CurC == 'L') {
|
||||
if (NextC == '\"') {
|
||||
StringConst ();
|
||||
return;
|
||||
} else if (NextC == '\'') {
|
||||
CharConst ();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check for keywords and identifiers */
|
||||
if (IsSym (token)) {
|
||||
|
||||
/* Check for a keyword */
|
||||
if ((NextTok.Tok = FindKey (token)) != TOK_IDENT) {
|
||||
/* Reserved word found */
|
||||
return;
|
||||
if (!PPParserRunning) {
|
||||
/* Check for a keyword */
|
||||
if ((NextTok.Tok = FindKey (token)) != TOK_IDENT) {
|
||||
/* Reserved word found */
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* No reserved word, check for special symbols */
|
||||
if (token[0] == '_' && token[1] == '_') {
|
||||
/* Special symbols */
|
||||
if (strcmp (token+2, "FILE__") == 0) {
|
||||
NextTok.SVal = AddLiteral (GetCurrentFile());
|
||||
NextTok.Tok = TOK_SCONST;
|
||||
return;
|
||||
} else if (strcmp (token+2, "LINE__") == 0) {
|
||||
NextTok.Tok = TOK_ICONST;
|
||||
NextTok.IVal = GetCurrentLine();
|
||||
NextTok.Type = type_int;
|
||||
return;
|
||||
} else if (strcmp (token+2, "func__") == 0) {
|
||||
if (strcmp (token+2, "func__") == 0) {
|
||||
/* __func__ is only defined in functions */
|
||||
if (CurrentFunc) {
|
||||
NextTok.SVal = AddLiteral (F_GetFuncName (CurrentFunc));
|
||||
@@ -1011,6 +1071,15 @@ void NextToken (void)
|
||||
SetTok (TOK_COMP);
|
||||
break;
|
||||
|
||||
case '#':
|
||||
NextChar ();
|
||||
if (CurC == '#') {
|
||||
SetTok (TOK_DOUBLE_HASH);
|
||||
} else {
|
||||
NextTok.Tok = TOK_HASH;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
UnknownChar (CurC);
|
||||
|
||||
|
||||
@@ -79,6 +79,10 @@ typedef enum token_t {
|
||||
TOK_FASTCALL,
|
||||
TOK_CDECL,
|
||||
|
||||
/* Address sizes */
|
||||
TOK_FAR,
|
||||
TOK_NEAR,
|
||||
|
||||
/* Tokens denoting types */
|
||||
TOK_FIRST_TYPE,
|
||||
TOK_ENUM = TOK_FIRST_TYPE,
|
||||
@@ -95,94 +99,101 @@ typedef enum token_t {
|
||||
TOK_VOID,
|
||||
TOK_LAST_TYPE = TOK_VOID,
|
||||
|
||||
/* Control statements */
|
||||
/* Selection statements */
|
||||
TOK_IF,
|
||||
TOK_ELSE,
|
||||
TOK_SWITCH,
|
||||
|
||||
/* Iteration statements */
|
||||
TOK_WHILE,
|
||||
TOK_DO,
|
||||
TOK_FOR,
|
||||
TOK_GOTO,
|
||||
TOK_IF,
|
||||
TOK_RETURN,
|
||||
TOK_SWITCH,
|
||||
TOK_WHILE,
|
||||
|
||||
TOK_ASM,
|
||||
/* Jump statements */
|
||||
TOK_GOTO,
|
||||
TOK_CONTINUE,
|
||||
TOK_BREAK,
|
||||
TOK_RETURN,
|
||||
|
||||
/* Labels */
|
||||
TOK_CASE,
|
||||
TOK_DEFAULT,
|
||||
TOK_BREAK,
|
||||
TOK_CONTINUE,
|
||||
TOK_ELSE,
|
||||
TOK_ELLIPSIS,
|
||||
|
||||
/* Misc. */
|
||||
TOK_ATTRIBUTE,
|
||||
TOK_PRAGMA,
|
||||
TOK_STATIC_ASSERT,
|
||||
TOK_ASM,
|
||||
TOK_SIZEOF,
|
||||
|
||||
TOK_IDENT,
|
||||
TOK_SEMI,
|
||||
|
||||
/* Primary operators */
|
||||
TOK_LBRACK,
|
||||
/* Punctuators */
|
||||
TOK_FIRST_PUNC,
|
||||
TOK_LBRACK = TOK_FIRST_PUNC,
|
||||
TOK_RBRACK,
|
||||
TOK_LPAREN,
|
||||
TOK_RPAREN,
|
||||
TOK_LCURLY,
|
||||
TOK_RCURLY,
|
||||
TOK_DOT,
|
||||
TOK_PTR_REF,
|
||||
|
||||
TOK_LCURLY,
|
||||
TOK_RBRACK,
|
||||
TOK_COMP,
|
||||
TOK_INC,
|
||||
TOK_PLUS_ASSIGN,
|
||||
TOK_PLUS,
|
||||
TOK_COMMA,
|
||||
TOK_DEC,
|
||||
TOK_MINUS_ASSIGN,
|
||||
TOK_RCURLY,
|
||||
TOK_MINUS,
|
||||
TOK_MUL_ASSIGN,
|
||||
TOK_ADDR,
|
||||
TOK_AND = TOK_ADDR, /* Alias */
|
||||
TOK_STAR,
|
||||
TOK_MUL = TOK_STAR, /* Alias */
|
||||
TOK_DIV_ASSIGN,
|
||||
TOK_DIV,
|
||||
TOK_BOOL_AND,
|
||||
TOK_AND_ASSIGN,
|
||||
TOK_AND,
|
||||
TOK_NE,
|
||||
TOK_PLUS,
|
||||
TOK_MINUS,
|
||||
TOK_COMP,
|
||||
TOK_BOOL_NOT,
|
||||
TOK_BOOL_OR,
|
||||
TOK_OR_ASSIGN,
|
||||
TOK_OR,
|
||||
TOK_EQ,
|
||||
TOK_ASSIGN,
|
||||
|
||||
/* Inequalities */
|
||||
TOK_LE,
|
||||
TOK_LT,
|
||||
TOK_GE,
|
||||
TOK_GT,
|
||||
|
||||
TOK_SHL_ASSIGN,
|
||||
TOK_SHL,
|
||||
TOK_SHR_ASSIGN,
|
||||
TOK_SHR,
|
||||
TOK_XOR_ASSIGN,
|
||||
TOK_XOR,
|
||||
TOK_MOD_ASSIGN,
|
||||
TOK_DIV,
|
||||
TOK_MOD,
|
||||
TOK_SHL,
|
||||
TOK_SHR,
|
||||
TOK_LT,
|
||||
TOK_GT,
|
||||
TOK_LE,
|
||||
TOK_GE,
|
||||
TOK_EQ,
|
||||
TOK_NE,
|
||||
TOK_XOR,
|
||||
TOK_OR,
|
||||
TOK_BOOL_AND,
|
||||
TOK_BOOL_OR,
|
||||
TOK_QUEST,
|
||||
TOK_COLON,
|
||||
TOK_RPAREN,
|
||||
TOK_SCONST,
|
||||
TOK_SEMI,
|
||||
TOK_ELLIPSIS,
|
||||
TOK_ASSIGN,
|
||||
TOK_MUL_ASSIGN,
|
||||
TOK_DIV_ASSIGN,
|
||||
TOK_MOD_ASSIGN,
|
||||
TOK_PLUS_ASSIGN,
|
||||
TOK_MINUS_ASSIGN,
|
||||
TOK_SHL_ASSIGN,
|
||||
TOK_SHR_ASSIGN,
|
||||
TOK_AND_ASSIGN,
|
||||
TOK_XOR_ASSIGN,
|
||||
TOK_OR_ASSIGN,
|
||||
TOK_COMMA,
|
||||
TOK_HASH,
|
||||
TOK_HASH_HASH,
|
||||
TOK_DOUBLE_HASH = TOK_HASH_HASH, /* Alias */
|
||||
TOK_LAST_PUNC = TOK_DOUBLE_HASH,
|
||||
|
||||
/* Primary expressions */
|
||||
TOK_ICONST,
|
||||
TOK_CCONST,
|
||||
TOK_WCCONST,
|
||||
TOK_FCONST,
|
||||
TOK_SCONST,
|
||||
TOK_WCSCONST,
|
||||
|
||||
TOK_ATTRIBUTE,
|
||||
TOK_STATIC_ASSERT,
|
||||
TOK_FAR,
|
||||
TOK_NEAR,
|
||||
TOK_IDENT,
|
||||
TOK_A,
|
||||
TOK_X,
|
||||
TOK_Y,
|
||||
TOK_AX,
|
||||
TOK_EAX,
|
||||
|
||||
TOK_PRAGMA
|
||||
TOK_EAX
|
||||
} token_t;
|
||||
|
||||
|
||||
@@ -210,6 +221,7 @@ struct Token {
|
||||
|
||||
extern Token CurTok; /* The current token */
|
||||
extern Token NextTok; /* The next token */
|
||||
extern int PPParserRunning; /* Is tokenizer used by the preprocessor */
|
||||
|
||||
|
||||
|
||||
@@ -219,6 +231,17 @@ extern Token NextTok; /* The next token */
|
||||
|
||||
|
||||
|
||||
#if defined(HAVE_INLINE)
|
||||
INLINE int TokIsPunc (const Token* T)
|
||||
/* Return true if the token is a punctuator */
|
||||
{
|
||||
return (T->Tok >= TOK_FIRST_PUNC && T->Tok <= TOK_LAST_PUNC);
|
||||
}
|
||||
#else
|
||||
# define TokIsPunc(T) \
|
||||
((T)->Tok >= TOK_FIRST_PUNC && (T)->Tok <= TOK_LAST_PUNC)
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_INLINE)
|
||||
INLINE int TokIsStorageClass (const Token* T)
|
||||
/* Return true if the token is a storage class specifier */
|
||||
@@ -262,6 +285,14 @@ void SymName (char* S);
|
||||
int IsSym (char* S);
|
||||
/* If a symbol follows, read it and return 1, otherwise return 0 */
|
||||
|
||||
int IsPPNumber (int Cur, int Next);
|
||||
/* Return 1 if the two successive characters indicate a pp-number, otherwise
|
||||
** return 0.
|
||||
*/
|
||||
|
||||
void CopyPPNumber (StrBuf* Target);
|
||||
/* Copy a pp-number from the input to Target */
|
||||
|
||||
void NextToken (void);
|
||||
/* Get next token from input stream */
|
||||
|
||||
|
||||
@@ -237,5 +237,8 @@ MakeRVal:
|
||||
|
||||
/* Set the type of the result */
|
||||
Expr->Type = ResultType;
|
||||
|
||||
/* Propagate from subexpressions */
|
||||
Expr->Flags |= Expr2.Flags & E_MASK_VIRAL;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -185,6 +185,9 @@ static void ParseArg (ArgDesc* Arg, const Type* Type, ExprDesc* Expr)
|
||||
|
||||
/* Use the type of the argument for the push */
|
||||
Arg->Flags |= TypeOf (Arg->Expr.Type);
|
||||
|
||||
/* Propagate from subexpressions */
|
||||
Expr->Flags |= Arg->Expr.Flags & E_MASK_VIRAL;
|
||||
}
|
||||
|
||||
|
||||
@@ -1365,6 +1368,9 @@ static void StdFunc_strlen (FuncDesc* F attribute ((unused)), ExprDesc* Expr)
|
||||
ExitPoint:
|
||||
/* We expect the closing brace */
|
||||
ConsumeRParen ();
|
||||
|
||||
/* Propagate from subexpressions */
|
||||
Expr->Flags |= Arg.Flags & E_MASK_VIRAL;
|
||||
}
|
||||
|
||||
|
||||
@@ -1405,4 +1411,7 @@ void HandleStdFunc (int Index, FuncDesc* F, ExprDesc* lval)
|
||||
|
||||
/* Call the handler function */
|
||||
D->Handler (F, lval);
|
||||
|
||||
/* We assume all function calls had side effects */
|
||||
lval->Flags |= E_SIDE_EFFECTS;
|
||||
}
|
||||
|
||||
@@ -609,17 +609,23 @@ static void Statement (int* PendingToken)
|
||||
Expr.Flags |= E_NEED_NONE;
|
||||
Expression0 (&Expr);
|
||||
|
||||
/* If the statement didn't generate code, and is not of type
|
||||
** void, emit a warning.
|
||||
/* If the statement has no observable effect and isn't cast to type
|
||||
** void, emit a warning and remove useless code if any.
|
||||
*/
|
||||
GetCodePos (&End);
|
||||
if (!ED_YetToLoad (&Expr) &&
|
||||
!ED_MayHaveNoEffect (&Expr) &&
|
||||
CodeRangeIsEmpty (&Start, &End) &&
|
||||
IS_Get (&WarnNoEffect) &&
|
||||
PrevErrorCount == ErrorCount) {
|
||||
Warning ("Expression result unused");
|
||||
if (CodeRangeIsEmpty (&Start, &End) ||
|
||||
(Expr.Flags & E_SIDE_EFFECTS) == 0) {
|
||||
|
||||
if (!ED_MayHaveNoEffect (&Expr) &&
|
||||
IS_Get (&WarnNoEffect) &&
|
||||
PrevErrorCount == ErrorCount) {
|
||||
Warning ("Statement has no effect");
|
||||
}
|
||||
|
||||
/* Remove code with no effect */
|
||||
RemoveCode (&Start);
|
||||
}
|
||||
|
||||
CheckSemi (PendingToken);
|
||||
}
|
||||
|
||||
|
||||
@@ -206,7 +206,7 @@ void SwitchStatement (void)
|
||||
|
||||
|
||||
void CaseLabel (void)
|
||||
/* Handle a case sabel */
|
||||
/* Handle a case label */
|
||||
{
|
||||
ExprDesc CaseExpr; /* Case label expression */
|
||||
long Val; /* Case label value */
|
||||
|
||||
@@ -728,6 +728,7 @@ static int HandleSymRedefinition (SymEntry* Entry, const Type* T, unsigned Flags
|
||||
/* New type must be compatible with the composite prototype */
|
||||
if (IsDistinctRedef (E_Type, T, TC_EQUAL, TCF_MASK_QUAL)) {
|
||||
Error ("Conflicting function types for '%s'", Entry->Name);
|
||||
TypeCompatibilityDiagnostic (T, E_Type, 0, "'%s' vs '%s'");
|
||||
Entry = 0;
|
||||
} else {
|
||||
/* Refine the existing composite prototype with this new
|
||||
|
||||
@@ -143,10 +143,10 @@ static void DoConversion (ExprDesc* Expr, const Type* NewType)
|
||||
|
||||
/* Do the integer constant <-> absolute address conversion if necessary */
|
||||
if (IsClassPtr (NewType)) {
|
||||
Expr->Flags &= ~E_LOC_NONE;
|
||||
Expr->Flags &= ~E_MASK_LOC;
|
||||
Expr->Flags |= E_LOC_ABS | E_ADDRESS_OF;
|
||||
} else if (IsClassInt (NewType)) {
|
||||
Expr->Flags &= ~(E_LOC_ABS | E_ADDRESS_OF);
|
||||
Expr->Flags &= ~(E_MASK_LOC | E_ADDRESS_OF);
|
||||
Expr->Flags |= E_LOC_NONE;
|
||||
}
|
||||
|
||||
|
||||
@@ -776,14 +776,20 @@ static void PrintUnresolved (ExpCheckFunc F, void* Data)
|
||||
Import* Imp = E->ImpList;
|
||||
const char* name = GetString (E->Name);
|
||||
while (Imp) {
|
||||
unsigned J;
|
||||
for (J = 0; J < CollCount (&Imp->RefLines); ++J) {
|
||||
const LineInfo* LI = CollConstAt (&Imp->RefLines, J);
|
||||
fprintf (stderr,
|
||||
"%s:%u: Error: Unresolved external '%s'\n",
|
||||
GetSourceName (LI),
|
||||
GetSourceLine (LI),
|
||||
name);
|
||||
unsigned J, count = CollCount (&Imp->RefLines);
|
||||
/* The count is 0 when the import was not added by an input file,
|
||||
but by the compiler itself. */
|
||||
if (count == 0) {
|
||||
fprintf (stderr, "Error: Unresolved external '%s'\n", name);
|
||||
} else {
|
||||
for (J = 0; J < count; ++J) {
|
||||
const LineInfo* LI = CollConstAt (&Imp->RefLines, J);
|
||||
fprintf (stderr,
|
||||
"%s:%u: Error: Unresolved external '%s'\n",
|
||||
GetSourceName (LI),
|
||||
GetSourceLine (LI),
|
||||
name);
|
||||
}
|
||||
}
|
||||
Imp = Imp->Next;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user