mirror of
https://github.com/cc65/cc65.git
synced 2024-06-09 06:29:38 +00:00
Merge branch 'master' into fptest
This commit is contained in:
commit
4a8c13fd93
22
.github/checks/Makefile
vendored
22
.github/checks/Makefile
vendored
|
@ -1,7 +1,23 @@
|
|||
|
||||
.PHONY: checkstyle tabs lastline spaces noexec
|
||||
ifneq ($(shell echo),)
|
||||
CMD_EXE = 1
|
||||
endif
|
||||
|
||||
checkstyle: tabs lastline spaces noexec
|
||||
ifdef CMD_EXE
|
||||
|
||||
.PHONY: checkstyle
|
||||
|
||||
checkstyle:
|
||||
$(info INFO: style checks require bash.)
|
||||
|
||||
else
|
||||
|
||||
.PHONY: checkstyle lineendings tabs lastline spaces noexec
|
||||
|
||||
checkstyle: lineendings tabs lastline spaces noexec
|
||||
|
||||
lineendings: lineendings.sh
|
||||
@./lineendings.sh
|
||||
|
||||
tabs: tabs.sh
|
||||
@./tabs.sh
|
||||
|
@ -14,3 +30,5 @@ spaces: spaces.sh
|
|||
|
||||
noexec: noexec.sh
|
||||
@./noexec.sh
|
||||
|
||||
endif
|
||||
|
|
18
.github/checks/lineendings.sh
vendored
Executable file
18
.github/checks/lineendings.sh
vendored
Executable file
|
@ -0,0 +1,18 @@
|
|||
#! /bin/bash
|
||||
OLDCWD=`pwd`
|
||||
SCRIPT_PATH=`dirname $0`
|
||||
CHECK_PATH=.
|
||||
|
||||
cd $SCRIPT_PATH/../../
|
||||
|
||||
FILES=`find $CHECK_PATH -type f \( -name \*.inc -o -name Makefile -o -name \*.cfg -o -name \*.\[chs\] -o -name \*.mac -o -name \*.asm -o -name \*.sgml \) -print | grep -v "libwrk/" | grep -v "testwrk/" | xargs grep -IUl $'\r'`
|
||||
|
||||
cd $OLDCWD
|
||||
|
||||
if [ x"$FILES"x != xx ]; then
|
||||
echo "error: found CR in the following files:" >&2
|
||||
for n in $FILES; do
|
||||
echo $n >&2
|
||||
done
|
||||
exit -1
|
||||
fi
|
|
@ -8,11 +8,16 @@ This document contains all kinds of information that you should know if you want
|
|||
|
||||
* You must obey these rules when contributing new code or documentation to cc65. We are well aware that not all existing code may respect all rules outlined here - but this is no reason for you not to respect them.
|
||||
* One commit/patch/PR per issue. Do not mix several things unless they are very closely related.
|
||||
* Sometimes when you make a PR, it may break completely unrelated tests. However, any PR is expected to merge cleanly with no failures. That means in practise that you are expected to fix/update the failing tests if required - for example this might be needed if you make changes to the compiler that changes the format of error- or warning messages. In that case you might have to update some reference files in the testbench. Obviously still check if that is actually the right thing to do ;)
|
||||
|
||||
# Codestyle rules
|
||||
|
||||
## All Sources
|
||||
|
||||
### Line endings
|
||||
|
||||
All files must only contain Unix style 'LF' line endings. Please configure your editors accordingly.
|
||||
|
||||
### TABs and spaces
|
||||
|
||||
This is an ongoing controversial topic - everyone knows that. However, the following is how we do it :)
|
||||
|
|
|
@ -461,7 +461,8 @@ following attributes are recognized:
|
|||
<tag><tt>END</tt></tag>
|
||||
This gives the end address of the range. The end address is inclusive, that
|
||||
means, it is part of the range. Of course, it may not be smaller than the
|
||||
start address.
|
||||
start address. Optionally, the end may be given as a decimal offset instead
|
||||
of an absolute address, "+3", to specify it as a size.
|
||||
|
||||
<tag><tt>NAME</tt></tag>
|
||||
This is a convenience attribute. It takes a string argument and will cause
|
||||
|
|
|
@ -414,6 +414,7 @@ TARGETS := \
|
|||
|
||||
define TARGET_recipe
|
||||
|
||||
@echo making samples for: $(T)
|
||||
@$(MAKE) -j2 SYS:=$(T)
|
||||
@$(MAKE) --no-print-directory clean SYS:=$(T)
|
||||
|
||||
|
|
|
@ -43,6 +43,7 @@
|
|||
|
||||
/* common */
|
||||
#include "addrsize.h"
|
||||
#include "attrib.h"
|
||||
#include "check.h"
|
||||
#include "cpu.h"
|
||||
#include "shift.h"
|
||||
|
@ -4896,7 +4897,7 @@ void g_initstatic (unsigned InitLabel, unsigned VarLabel, unsigned Size)
|
|||
|
||||
|
||||
|
||||
void g_testbitfield (unsigned Flags, unsigned BitOffs, unsigned BitWidth)
|
||||
void g_testbitfield (ATTR_UNUSED(unsigned Flags), unsigned BitOffs, unsigned BitWidth)
|
||||
/* Test bit-field in primary. */
|
||||
{
|
||||
/* Since the end is inclusive and cannot be negative here, we subtract 1 from the sum */
|
||||
|
|
|
@ -399,10 +399,7 @@ static CodeEntry* ParseInsn (CodeSeg* S, LineInfo* LI, const char* L)
|
|||
|
||||
default:
|
||||
/* Absolute, maybe indexed */
|
||||
L = ReadToken (L, ", ", Arg, sizeof (Arg));
|
||||
if (*L == ' ') {
|
||||
L = SkipSpace (L+1);
|
||||
}
|
||||
L = ReadToken (L, ",", Arg, sizeof (Arg));
|
||||
if (*L == '\0') {
|
||||
/* Absolute, zeropage or branch */
|
||||
if ((OPC->Info & OF_BRA) != 0) {
|
||||
|
|
|
@ -79,7 +79,7 @@ static void Parse (void)
|
|||
/* Top level parser routine. */
|
||||
{
|
||||
int comma;
|
||||
SymEntry* Entry;
|
||||
SymEntry* Sym;
|
||||
FuncDesc* FuncDef = 0;
|
||||
|
||||
/* Initialization for deferred operations */
|
||||
|
@ -123,7 +123,7 @@ static void Parse (void)
|
|||
}
|
||||
|
||||
/* Read variable defs and functions */
|
||||
ParseDeclSpec (&Spec, SC_EXTERN | SC_STATIC, T_INT);
|
||||
ParseDeclSpec (&Spec, TS_DEFAULT_TYPE_INT, SC_EXTERN | SC_STATIC);
|
||||
|
||||
/* Don't accept illegal storage classes */
|
||||
if ((Spec.StorageClass & SC_TYPEMASK) == 0) {
|
||||
|
@ -142,7 +142,7 @@ static void Parse (void)
|
|||
}
|
||||
|
||||
/* Read declarations for this type */
|
||||
Entry = 0;
|
||||
Sym = 0;
|
||||
comma = 0;
|
||||
while (1) {
|
||||
|
||||
|
@ -196,10 +196,10 @@ static void Parse (void)
|
|||
}
|
||||
|
||||
/* Add an entry to the symbol table */
|
||||
Entry = AddGlobalSym (Decl.Ident, Decl.Type, Decl.StorageClass);
|
||||
Sym = AddGlobalSym (Decl.Ident, Decl.Type, Decl.StorageClass);
|
||||
|
||||
/* Add declaration attributes */
|
||||
SymUseAttr (Entry, &Decl);
|
||||
SymUseAttr (Sym, &Decl);
|
||||
|
||||
/* Reserve storage for the variable if we need to */
|
||||
if (Decl.StorageClass & SC_STORAGE) {
|
||||
|
@ -211,11 +211,11 @@ static void Parse (void)
|
|||
if (CurTok.Tok == TOK_ASSIGN) {
|
||||
|
||||
/* This is a definition with storage */
|
||||
if (SymIsDef (Entry)) {
|
||||
if (SymIsDef (Sym)) {
|
||||
Error ("Global variable '%s' has already been defined",
|
||||
Entry->Name);
|
||||
Sym->Name);
|
||||
}
|
||||
Entry->Flags |= SC_DEF;
|
||||
Sym->Flags |= SC_DEF;
|
||||
|
||||
/* We cannot initialize types of unknown size, or
|
||||
** void types in ISO modes.
|
||||
|
@ -245,21 +245,21 @@ static void Parse (void)
|
|||
}
|
||||
|
||||
/* Define a label */
|
||||
g_defgloblabel (Entry->Name);
|
||||
g_defgloblabel (Sym->Name);
|
||||
|
||||
/* Skip the '=' */
|
||||
NextToken ();
|
||||
|
||||
/* Parse the initialization */
|
||||
ParseInit (Entry->Type);
|
||||
ParseInit (Sym->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) && !IsEmptiableObjectType (Decl.Type)) {
|
||||
Sym->Flags &= ~(SC_STORAGE | SC_DEF);
|
||||
} else if (Size == 0 && SymIsDef (Sym) && !IsEmptiableObjectType (Decl.Type)) {
|
||||
/* Size is unknown. Is it an array? */
|
||||
if (!IsTypeArray (Decl.Type)) {
|
||||
Error ("Variable '%s' has unknown size", Decl.Ident);
|
||||
|
@ -286,11 +286,11 @@ static void Parse (void)
|
|||
*/
|
||||
const char* bssName = GetSegName (SEG_BSS);
|
||||
|
||||
if (Entry->V.BssName && strcmp (Entry->V.BssName, bssName) != 0) {
|
||||
if (Sym->V.BssName && strcmp (Sym->V.BssName, bssName) != 0) {
|
||||
Error ("Global variable '%s' already was defined in the '%s' segment.",
|
||||
Entry->Name, Entry->V.BssName);
|
||||
Sym->Name, Sym->V.BssName);
|
||||
}
|
||||
Entry->V.BssName = xstrdup (bssName);
|
||||
Sym->V.BssName = xstrdup (bssName);
|
||||
|
||||
/* This is to make the automatical zeropage setting of the symbol
|
||||
** work right.
|
||||
|
@ -300,9 +300,9 @@ static void Parse (void)
|
|||
}
|
||||
|
||||
/* Make the symbol zeropage according to the segment address size */
|
||||
if ((Entry->Flags & SC_STATIC) != 0) {
|
||||
if ((Sym->Flags & SC_STATIC) != 0) {
|
||||
if (GetSegAddrSize (GetSegName (CS->CurDSeg)) == ADDR_SIZE_ZP) {
|
||||
Entry->Flags |= SC_ZEROPAGE;
|
||||
Sym->Flags |= SC_ZEROPAGE;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -318,7 +318,7 @@ static void Parse (void)
|
|||
}
|
||||
|
||||
/* Function declaration? */
|
||||
if (Entry && IsTypeFunc (Entry->Type)) {
|
||||
if (Sym && IsTypeFunc (Sym->Type)) {
|
||||
|
||||
/* Function */
|
||||
if (!comma) {
|
||||
|
@ -327,7 +327,7 @@ static void Parse (void)
|
|||
NextToken ();
|
||||
} else {
|
||||
/* Parse the function body */
|
||||
NewFunc (Entry, FuncDef);
|
||||
NewFunc (Sym, FuncDef);
|
||||
|
||||
/* Make sure we aren't omitting any work */
|
||||
CheckDeferredOpAllDone ();
|
||||
|
@ -478,8 +478,9 @@ void Compile (const char* FileName)
|
|||
for (Entry = GetGlobalSymTab ()->SymHead; Entry; Entry = Entry->NextSym) {
|
||||
if ((Entry->Flags & (SC_STORAGE | SC_DEF | SC_STATIC)) == (SC_STORAGE | SC_STATIC)) {
|
||||
/* Assembly definition of uninitialized global variable */
|
||||
SymEntry* Sym = GetSymType (Entry->Type);
|
||||
SymEntry* TagSym = GetESUTagSym (Entry->Type);
|
||||
unsigned Size = SizeOf (Entry->Type);
|
||||
|
||||
if (Size == 0 && IsTypeArray (Entry->Type)) {
|
||||
if (GetElementCount (Entry->Type) == UNSPECIFIED) {
|
||||
/* Assume array size of 1 */
|
||||
|
@ -488,11 +489,11 @@ void Compile (const char* FileName)
|
|||
Warning ("Incomplete array '%s[]' assumed to have one element", Entry->Name);
|
||||
}
|
||||
|
||||
Sym = GetSymType (GetElementType (Entry->Type));
|
||||
TagSym = GetESUTagSym (GetElementType (Entry->Type));
|
||||
}
|
||||
|
||||
/* For non-ESU types, Size != 0 */
|
||||
if (Size != 0 || (Sym != 0 && SymIsDef (Sym))) {
|
||||
if (Size != 0 || (TagSym != 0 && SymIsDef (TagSym))) {
|
||||
/* Set the segment name only when it changes */
|
||||
if (strcmp (GetSegName (SEG_BSS), Entry->V.BssName) != 0) {
|
||||
SetSegName (SEG_BSS, Entry->V.BssName);
|
||||
|
|
|
@ -48,6 +48,7 @@
|
|||
#include "fp.h"
|
||||
#include "funcdesc.h"
|
||||
#include "global.h"
|
||||
#include "ident.h"
|
||||
#include "symtab.h"
|
||||
|
||||
|
||||
|
@ -86,6 +87,83 @@ const Type type_c_void_p[] = { TYPE(T_PTR), TYPE(T_C_VOID), TYPE(T_END) };
|
|||
|
||||
|
||||
|
||||
const char* GetBasicTypeName (const Type* T)
|
||||
/* Return a const name string of the basic type.
|
||||
** Return "type" for unknown basic types.
|
||||
*/
|
||||
{
|
||||
switch (GetRawType (T)) {
|
||||
case T_TYPE_ENUM: return "enum";
|
||||
case T_TYPE_BITFIELD: return "bit-field";
|
||||
case T_TYPE_FLOAT: return "float";
|
||||
case T_TYPE_DOUBLE: return "double";
|
||||
case T_TYPE_VOID: return "void";
|
||||
case T_TYPE_STRUCT: return "struct";
|
||||
case T_TYPE_UNION: return "union";
|
||||
case T_TYPE_ARRAY: return "array";
|
||||
case T_TYPE_PTR: return "pointer";
|
||||
case T_TYPE_FUNC: return "function";
|
||||
case T_TYPE_NONE: /* FALLTHROUGH */
|
||||
default: break;
|
||||
}
|
||||
if (IsClassInt (T)) {
|
||||
if (IsRawSignSigned (T)) {
|
||||
switch (GetRawType (T)) {
|
||||
case T_TYPE_CHAR: return "signed char";
|
||||
case T_TYPE_SHORT: return "short";
|
||||
case T_TYPE_INT: return "int";
|
||||
case T_TYPE_LONG: return "long";
|
||||
case T_TYPE_LONGLONG: return "long long";
|
||||
default:
|
||||
return "signed integer";
|
||||
}
|
||||
} else if (IsRawSignUnsigned (T)) {
|
||||
switch (GetRawType (T)) {
|
||||
case T_TYPE_CHAR: return "unsigned char";
|
||||
case T_TYPE_SHORT: return "unsigned short";
|
||||
case T_TYPE_INT: return "unsigned int";
|
||||
case T_TYPE_LONG: return "unsigned long";
|
||||
case T_TYPE_LONGLONG: return "unsigned long long";
|
||||
default:
|
||||
return "unsigned integer";
|
||||
}
|
||||
} else {
|
||||
switch (GetRawType (T)) {
|
||||
case T_TYPE_CHAR: return "char";
|
||||
case T_TYPE_SHORT: return "short";
|
||||
case T_TYPE_INT: return "int";
|
||||
case T_TYPE_LONG: return "long";
|
||||
case T_TYPE_LONGLONG: return "long long";
|
||||
default:
|
||||
return "integer";
|
||||
}
|
||||
}
|
||||
}
|
||||
return "type";
|
||||
}
|
||||
|
||||
|
||||
|
||||
static const char* GetTagSymName (const Type* T)
|
||||
/* Return a name string of the type or the symbol name if it is an ESU type.
|
||||
** Note: This may use a static buffer that could be overwritten by other calls.
|
||||
*/
|
||||
{
|
||||
static char TypeName [IDENTSIZE + 16];
|
||||
SymEntry* TagSym;
|
||||
|
||||
TagSym = GetESUTagSym (T);
|
||||
if (TagSym == 0) {
|
||||
return GetBasicTypeName (T);
|
||||
}
|
||||
sprintf (TypeName, "%s %s", GetBasicTypeName (T),
|
||||
TagSym->Name[0] != '\0' ? TagSym->Name : "<unknown>");
|
||||
|
||||
return TypeName;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static struct StrBuf* GetFullTypeNameWestEast (struct StrBuf* West, struct StrBuf* East, const Type* T)
|
||||
/* Return the name string of the given type split into a western part and an
|
||||
** eastern part.
|
||||
|
@ -208,7 +286,7 @@ static struct StrBuf* GetFullTypeNameWestEast (struct StrBuf* West, struct StrBu
|
|||
}
|
||||
|
||||
if (!IsTypeBitField (T)) {
|
||||
SB_AppendStr (&Buf, GetSymTypeName (T));
|
||||
SB_AppendStr (&Buf, GetTagSymName (T));
|
||||
} else {
|
||||
SB_AppendStr (&Buf, GetBasicTypeName (T + 1));
|
||||
}
|
||||
|
@ -228,63 +306,6 @@ static struct StrBuf* GetFullTypeNameWestEast (struct StrBuf* West, struct StrBu
|
|||
|
||||
|
||||
|
||||
const char* GetBasicTypeName (const Type* T)
|
||||
/* Return a const name string of the basic type.
|
||||
** Return "type" for unknown basic types.
|
||||
*/
|
||||
{
|
||||
switch (GetRawType (T)) {
|
||||
case T_TYPE_ENUM: return "enum";
|
||||
case T_TYPE_BITFIELD: return "bit-field";
|
||||
case T_TYPE_FLOAT: return "float";
|
||||
case T_TYPE_DOUBLE: return "double";
|
||||
case T_TYPE_VOID: return "void";
|
||||
case T_TYPE_STRUCT: return "struct";
|
||||
case T_TYPE_UNION: return "union";
|
||||
case T_TYPE_ARRAY: return "array";
|
||||
case T_TYPE_PTR: return "pointer";
|
||||
case T_TYPE_FUNC: return "function";
|
||||
case T_TYPE_NONE: /* FALLTHROUGH */
|
||||
default: break;
|
||||
}
|
||||
if (IsClassInt (T)) {
|
||||
if (IsRawSignSigned (T)) {
|
||||
switch (GetRawType (T)) {
|
||||
case T_TYPE_CHAR: return "signed char";
|
||||
case T_TYPE_SHORT: return "short";
|
||||
case T_TYPE_INT: return "int";
|
||||
case T_TYPE_LONG: return "long";
|
||||
case T_TYPE_LONGLONG: return "long long";
|
||||
default:
|
||||
return "signed integer";
|
||||
}
|
||||
} else if (IsRawSignUnsigned (T)) {
|
||||
switch (GetRawType (T)) {
|
||||
case T_TYPE_CHAR: return "unsigned char";
|
||||
case T_TYPE_SHORT: return "unsigned short";
|
||||
case T_TYPE_INT: return "unsigned int";
|
||||
case T_TYPE_LONG: return "unsigned long";
|
||||
case T_TYPE_LONGLONG: return "unsigned long long";
|
||||
default:
|
||||
return "unsigned integer";
|
||||
}
|
||||
} else {
|
||||
switch (GetRawType (T)) {
|
||||
case T_TYPE_CHAR: return "char";
|
||||
case T_TYPE_SHORT: return "short";
|
||||
case T_TYPE_INT: return "int";
|
||||
case T_TYPE_LONG: return "long";
|
||||
case T_TYPE_LONGLONG: return "long long";
|
||||
default:
|
||||
return "integer";
|
||||
}
|
||||
}
|
||||
}
|
||||
return "type";
|
||||
}
|
||||
|
||||
|
||||
|
||||
const char* GetFullTypeName (const Type* T)
|
||||
/* Return the full name string of the given type */
|
||||
{
|
||||
|
@ -1320,9 +1341,9 @@ int IsESUType (const Type* T)
|
|||
int IsIncompleteESUType (const Type* T)
|
||||
/* Return true if this is an incomplete ESU type */
|
||||
{
|
||||
SymEntry* Sym = GetSymType (T);
|
||||
SymEntry* TagSym = GetESUTagSym (T);
|
||||
|
||||
return Sym != 0 && !SymIsDef (Sym);
|
||||
return TagSym != 0 && !SymIsDef (TagSym);
|
||||
}
|
||||
|
||||
|
||||
|
@ -1499,20 +1520,21 @@ const Type* GetBaseElementType (const Type* T)
|
|||
|
||||
|
||||
|
||||
struct SymEntry* GetESUSymEntry (const Type* T)
|
||||
/* Return a SymEntry pointer from an enum/struct/union type */
|
||||
struct SymEntry* GetESUTagSym (const Type* T)
|
||||
/* Get the tag symbol entry of the enum/struct/union type.
|
||||
** Return 0 if it is not an enum/struct/union.
|
||||
*/
|
||||
{
|
||||
/* Only enums, structs or unions have a SymEntry attribute */
|
||||
CHECK (IsClassStruct (T) || IsTypeEnum (T));
|
||||
|
||||
/* Return the attribute */
|
||||
return T->A.S;
|
||||
if ((IsClassStruct (T) || IsTypeEnum (T))) {
|
||||
return T->A.S;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void SetESUSymEntry (Type* T, struct SymEntry* S)
|
||||
/* Set the SymEntry pointer for an enum/struct/union type */
|
||||
void SetESUTagSym (Type* T, struct SymEntry* S)
|
||||
/* Set the tag symbol entry of the enum/struct/union type */
|
||||
{
|
||||
/* Only enums, structs or unions have a SymEntry attribute */
|
||||
CHECK (IsClassStruct (T) || IsTypeEnum (T));
|
||||
|
@ -1583,7 +1605,7 @@ void PrintFuncSig (FILE* F, const char* Name, const Type* T)
|
|||
if (SymIsRegVar (Param)) {
|
||||
SB_AppendStr (&ParamList, "register ");
|
||||
}
|
||||
if (!HasAnonName (Param)) {
|
||||
if (!SymHasAnonName (Param)) {
|
||||
SB_AppendStr (&Buf, Param->Name);
|
||||
}
|
||||
SB_AppendStr (&ParamList, SB_GetConstBuf (GetFullTypeNameBuf (&Buf, Param->Type)));
|
||||
|
|
|
@ -943,11 +943,13 @@ const Type* GetBaseElementType (const Type* T);
|
|||
** the element type that is not an array.
|
||||
*/
|
||||
|
||||
struct SymEntry* GetESUSymEntry (const Type* T) attribute ((const));
|
||||
/* Return a SymEntry pointer from an enum/struct/union type */
|
||||
struct SymEntry* GetESUTagSym (const Type* T) attribute ((const));
|
||||
/* Get the tag symbol entry of the enum/struct/union type.
|
||||
** Return 0 if it is not an enum/struct/union.
|
||||
*/
|
||||
|
||||
void SetESUSymEntry (Type* T, struct SymEntry* S);
|
||||
/* Set the SymEntry pointer for an enum/struct/union type */
|
||||
void SetESUTagSym (Type* T, struct SymEntry* S);
|
||||
/* Set the tag symbol entry of the enum/struct/union type */
|
||||
|
||||
TypeCode AddrSizeQualifier (unsigned AddrSize);
|
||||
/* Return T_QUAL_NEAR or T_QUAL_FAR depending on the address size */
|
||||
|
|
|
@ -72,8 +72,7 @@
|
|||
|
||||
|
||||
|
||||
static void ParseTypeSpec (DeclSpec* D, long Default, TypeCode Qualifiers,
|
||||
int* SignednessSpecified);
|
||||
static void ParseTypeSpec (DeclSpec* D, typespec_t TSFlags, int* SignednessSpecified);
|
||||
/* Parse a type specifier */
|
||||
|
||||
|
||||
|
@ -84,6 +83,75 @@ static void ParseTypeSpec (DeclSpec* D, long Default, TypeCode Qualifiers,
|
|||
|
||||
|
||||
|
||||
static unsigned ParseOneStorageClass (void)
|
||||
/* Parse and return a storage class specifier */
|
||||
{
|
||||
unsigned StorageClass = 0;
|
||||
|
||||
/* Check the storage class given */
|
||||
switch (CurTok.Tok) {
|
||||
|
||||
case TOK_EXTERN:
|
||||
StorageClass = SC_EXTERN | SC_STATIC;
|
||||
NextToken ();
|
||||
break;
|
||||
|
||||
case TOK_STATIC:
|
||||
StorageClass = SC_STATIC;
|
||||
NextToken ();
|
||||
break;
|
||||
|
||||
case TOK_REGISTER:
|
||||
StorageClass = SC_REGISTER | SC_STATIC;
|
||||
NextToken ();
|
||||
break;
|
||||
|
||||
case TOK_AUTO:
|
||||
StorageClass = SC_AUTO;
|
||||
NextToken ();
|
||||
break;
|
||||
|
||||
case TOK_TYPEDEF:
|
||||
StorageClass = SC_TYPEDEF;
|
||||
NextToken ();
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return StorageClass;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int ParseStorageClass (DeclSpec* D)
|
||||
/* Parse storage class specifiers. Return true if a specifier is read even if
|
||||
** it was duplicated or disallowed. */
|
||||
{
|
||||
/* Check the storage class given */
|
||||
unsigned StorageClass = ParseOneStorageClass ();
|
||||
|
||||
if (StorageClass == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
while (StorageClass != 0) {
|
||||
if (D->StorageClass == 0) {
|
||||
D->StorageClass = StorageClass;
|
||||
} else if (D->StorageClass == StorageClass) {
|
||||
Warning ("Duplicate storage class specifier");
|
||||
} else {
|
||||
Error ("Conflicting storage class specifier");
|
||||
}
|
||||
StorageClass = ParseOneStorageClass ();
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void DuplicateQualifier (const char* Name)
|
||||
/* Print an error message */
|
||||
{
|
||||
|
@ -92,9 +160,9 @@ static void DuplicateQualifier (const char* Name)
|
|||
|
||||
|
||||
|
||||
static TypeCode OptionalQualifiers (TypeCode Allowed)
|
||||
static TypeCode OptionalQualifiers (TypeCode Qualifiers, TypeCode Allowed)
|
||||
/* Read type qualifiers if we have any. Allowed specifies the allowed
|
||||
** qualifiers.
|
||||
** qualifiers. Return any read qualifiers even if they caused errors.
|
||||
*/
|
||||
{
|
||||
/* We start without any qualifiers */
|
||||
|
@ -107,7 +175,7 @@ static TypeCode OptionalQualifiers (TypeCode Allowed)
|
|||
|
||||
case TOK_CONST:
|
||||
if (Allowed & T_QUAL_CONST) {
|
||||
if (Q & T_QUAL_CONST) {
|
||||
if (Qualifiers & T_QUAL_CONST) {
|
||||
DuplicateQualifier ("const");
|
||||
}
|
||||
Q |= T_QUAL_CONST;
|
||||
|
@ -118,7 +186,7 @@ static TypeCode OptionalQualifiers (TypeCode Allowed)
|
|||
|
||||
case TOK_VOLATILE:
|
||||
if (Allowed & T_QUAL_VOLATILE) {
|
||||
if (Q & T_QUAL_VOLATILE) {
|
||||
if (Qualifiers & T_QUAL_VOLATILE) {
|
||||
DuplicateQualifier ("volatile");
|
||||
}
|
||||
Q |= T_QUAL_VOLATILE;
|
||||
|
@ -129,7 +197,7 @@ static TypeCode OptionalQualifiers (TypeCode Allowed)
|
|||
|
||||
case TOK_RESTRICT:
|
||||
if (Allowed & T_QUAL_RESTRICT) {
|
||||
if (Q & T_QUAL_RESTRICT) {
|
||||
if (Qualifiers & T_QUAL_RESTRICT) {
|
||||
DuplicateQualifier ("restrict");
|
||||
}
|
||||
Q |= T_QUAL_RESTRICT;
|
||||
|
@ -140,7 +208,7 @@ static TypeCode OptionalQualifiers (TypeCode Allowed)
|
|||
|
||||
case TOK_NEAR:
|
||||
if (Allowed & T_QUAL_NEAR) {
|
||||
if (Q & T_QUAL_NEAR) {
|
||||
if (Qualifiers & T_QUAL_NEAR) {
|
||||
DuplicateQualifier ("near");
|
||||
}
|
||||
Q |= T_QUAL_NEAR;
|
||||
|
@ -151,7 +219,7 @@ static TypeCode OptionalQualifiers (TypeCode Allowed)
|
|||
|
||||
case TOK_FAR:
|
||||
if (Allowed & T_QUAL_FAR) {
|
||||
if (Q & T_QUAL_FAR) {
|
||||
if (Qualifiers & T_QUAL_FAR) {
|
||||
DuplicateQualifier ("far");
|
||||
}
|
||||
Q |= T_QUAL_FAR;
|
||||
|
@ -162,7 +230,7 @@ static TypeCode OptionalQualifiers (TypeCode Allowed)
|
|||
|
||||
case TOK_FASTCALL:
|
||||
if (Allowed & T_QUAL_FASTCALL) {
|
||||
if (Q & T_QUAL_FASTCALL) {
|
||||
if (Qualifiers & T_QUAL_FASTCALL) {
|
||||
DuplicateQualifier ("fastcall");
|
||||
}
|
||||
Q |= T_QUAL_FASTCALL;
|
||||
|
@ -173,7 +241,7 @@ static TypeCode OptionalQualifiers (TypeCode Allowed)
|
|||
|
||||
case TOK_CDECL:
|
||||
if (Allowed & T_QUAL_CDECL) {
|
||||
if (Q & T_QUAL_CDECL) {
|
||||
if (Qualifiers & T_QUAL_CDECL) {
|
||||
DuplicateQualifier ("cdecl");
|
||||
}
|
||||
Q |= T_QUAL_CDECL;
|
||||
|
@ -187,13 +255,16 @@ static TypeCode OptionalQualifiers (TypeCode Allowed)
|
|||
|
||||
}
|
||||
|
||||
/* Combine with newly read qualifiers */
|
||||
Qualifiers |= Q;
|
||||
|
||||
/* Skip the token */
|
||||
NextToken ();
|
||||
}
|
||||
|
||||
Done:
|
||||
/* We cannot have more than one address size far qualifier */
|
||||
switch (Q & T_QUAL_ADDRSIZE) {
|
||||
switch (Qualifiers & T_QUAL_ADDRSIZE) {
|
||||
|
||||
case T_QUAL_NONE:
|
||||
case T_QUAL_NEAR:
|
||||
|
@ -202,11 +273,11 @@ Done:
|
|||
|
||||
default:
|
||||
Error ("Cannot specify more than one address size qualifier");
|
||||
Q &= ~T_QUAL_ADDRSIZE;
|
||||
Qualifiers &= ~T_QUAL_ADDRSIZE;
|
||||
}
|
||||
|
||||
/* We cannot have more than one calling convention specifier */
|
||||
switch (Q & T_QUAL_CCONV) {
|
||||
switch (Qualifiers & T_QUAL_CCONV) {
|
||||
|
||||
case T_QUAL_NONE:
|
||||
case T_QUAL_FASTCALL:
|
||||
|
@ -215,15 +286,41 @@ Done:
|
|||
|
||||
default:
|
||||
Error ("Cannot specify more than one calling convention qualifier");
|
||||
Q &= ~T_QUAL_CCONV;
|
||||
Qualifiers &= ~T_QUAL_CCONV;
|
||||
}
|
||||
|
||||
/* Return the qualifiers read */
|
||||
/* Return any qualifiers just read */
|
||||
return Q;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void OptionalSpecifiers (DeclSpec* Spec, TypeCode* Qualifiers, typespec_t TSFlags)
|
||||
/* Read storage specifiers and/or type qualifiers if we have any. Storage class
|
||||
** specifiers require the corresponding typespec_t flag set to be allowed, and
|
||||
** only const and volatile type qualifiers are allowed under any circumstance.
|
||||
** Read storage class specifiers are output in *Spec and type qualifiers are
|
||||
** output in *Qualifiers with error checking.
|
||||
*/
|
||||
{
|
||||
TypeCode Q = T_QUAL_NONE;
|
||||
int Continue;
|
||||
|
||||
do {
|
||||
/* There may be type qualifiers *before* any storage class specifiers */
|
||||
Q = OptionalQualifiers (*Qualifiers, T_QUAL_CONST | T_QUAL_VOLATILE);
|
||||
*Qualifiers |= Q;
|
||||
|
||||
/* Parse storage class specifiers anyway then check */
|
||||
Continue = ParseStorageClass (Spec);
|
||||
if (Continue && (TSFlags & (TS_STORAGE_CLASS_SPEC | TS_FUNCTION_SPEC)) == 0) {
|
||||
Error ("Unexpected storage class specified");
|
||||
}
|
||||
} while (Continue || Q != T_QUAL_NONE);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void OptionalInt (void)
|
||||
/* Eat an optional "int" token */
|
||||
{
|
||||
|
@ -396,48 +493,6 @@ static void FixQualifiers (Type* DataType)
|
|||
|
||||
|
||||
|
||||
static unsigned ParseOneStorageClass (void)
|
||||
/* Parse and return a storage class */
|
||||
{
|
||||
unsigned StorageClass = 0;
|
||||
|
||||
/* Check the storage class given */
|
||||
switch (CurTok.Tok) {
|
||||
|
||||
case TOK_EXTERN:
|
||||
StorageClass = SC_EXTERN | SC_STATIC;
|
||||
NextToken ();
|
||||
break;
|
||||
|
||||
case TOK_STATIC:
|
||||
StorageClass = SC_STATIC;
|
||||
NextToken ();
|
||||
break;
|
||||
|
||||
case TOK_REGISTER:
|
||||
StorageClass = SC_REGISTER | SC_STATIC;
|
||||
NextToken ();
|
||||
break;
|
||||
|
||||
case TOK_AUTO:
|
||||
StorageClass = SC_AUTO;
|
||||
NextToken ();
|
||||
break;
|
||||
|
||||
case TOK_TYPEDEF:
|
||||
StorageClass = SC_TYPEDEF;
|
||||
NextToken ();
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return StorageClass;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void CheckArrayElementType (Type* DataType)
|
||||
/* Check if data type consists of arrays of incomplete element types */
|
||||
{
|
||||
|
@ -469,51 +524,24 @@ static void CheckArrayElementType (Type* DataType)
|
|||
|
||||
|
||||
|
||||
static void ParseStorageClass (DeclSpec* D, unsigned DefStorage)
|
||||
/* Parse a storage class */
|
||||
{
|
||||
/* Assume we're using an explicit storage class */
|
||||
D->Flags &= ~DS_DEF_STORAGE;
|
||||
|
||||
/* Check the storage class given */
|
||||
D->StorageClass = ParseOneStorageClass ();
|
||||
if (D->StorageClass == 0) {
|
||||
/* No storage class given, use default */
|
||||
D->Flags |= DS_DEF_STORAGE;
|
||||
D->StorageClass = DefStorage;
|
||||
} else {
|
||||
unsigned StorageClass = ParseOneStorageClass ();
|
||||
while (StorageClass != 0) {
|
||||
if (D->StorageClass == StorageClass) {
|
||||
Warning ("Duplicate storage class specifier");
|
||||
} else {
|
||||
Error ("Conflicting storage class specifier");
|
||||
}
|
||||
StorageClass = ParseOneStorageClass ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static SymEntry* ESUForwardDecl (const char* Name, unsigned Flags, unsigned* DSFlags)
|
||||
/* Handle an enum, struct or union forward decl */
|
||||
{
|
||||
/* Try to find an enum/struct/union with the given name. If there is none,
|
||||
** insert a forward declaration into the current lexical level.
|
||||
*/
|
||||
SymEntry* Entry = FindTagSym (Name);
|
||||
if (Entry == 0) {
|
||||
SymEntry* TagEntry = FindTagSym (Name);
|
||||
if (TagEntry == 0) {
|
||||
if ((Flags & SC_ESUTYPEMASK) != SC_ENUM) {
|
||||
Entry = AddStructSym (Name, Flags, 0, 0, DSFlags);
|
||||
TagEntry = AddStructSym (Name, Flags, 0, 0, DSFlags);
|
||||
} else {
|
||||
Entry = AddEnumSym (Name, Flags, 0, 0, DSFlags);
|
||||
TagEntry = AddEnumSym (Name, Flags, 0, 0, DSFlags);
|
||||
}
|
||||
} else if ((Entry->Flags & SC_TYPEMASK) != (Flags & SC_ESUTYPEMASK)) {
|
||||
} else if ((TagEntry->Flags & SC_TYPEMASK) != (Flags & SC_ESUTYPEMASK)) {
|
||||
/* Already defined, but not the same type class */
|
||||
Error ("Symbol '%s' is already different kind", Name);
|
||||
}
|
||||
return Entry;
|
||||
return TagEntry;
|
||||
}
|
||||
|
||||
|
||||
|
@ -611,20 +639,20 @@ static SymEntry* ParseEnumDecl (const char* Name, unsigned* DSFlags)
|
|||
|
||||
} else {
|
||||
|
||||
/* Defaulted with the same signedness as the previous member's */
|
||||
/* Defaulted with the same signedness as the previous member's */
|
||||
IsSigned = IsSignSigned (MemberType) &&
|
||||
(unsigned long)EnumVal != GetIntegerTypeMax (MemberType);
|
||||
|
||||
/* Enumerate. Signed integer overflow is UB but unsigned integers
|
||||
** are guaranteed to wrap around.
|
||||
*/
|
||||
EnumVal = (long)((unsigned long)EnumVal + 1UL);
|
||||
/* Enumerate by adding one to the previous value */
|
||||
EnumVal = (long)(((unsigned long)EnumVal + 1UL) & 0xFFFFFFFFUL);
|
||||
|
||||
if (UnqualifiedType (MemberType->C) == T_ULONG && EnumVal == 0) {
|
||||
/* Warn on 'unsigned long' overflow in enumeration */
|
||||
Warning ("Enumerator '%s' overflows the range of '%s'",
|
||||
Ident,
|
||||
GetBasicTypeName (type_ulong));
|
||||
/* Error since the new value cannot be represented in the
|
||||
** largest unsigned integer type supported by cc65 for enum.
|
||||
*/
|
||||
Error ("Enumerator '%s' overflows the range of '%s'",
|
||||
Ident,
|
||||
GetBasicTypeName (type_ulong));
|
||||
}
|
||||
|
||||
IsIncremented = 1;
|
||||
|
@ -657,11 +685,12 @@ static SymEntry* ParseEnumDecl (const char* Name, unsigned* DSFlags)
|
|||
/* Warn if the incremented value exceeds the range of the previous
|
||||
** type.
|
||||
*/
|
||||
if (IsIncremented &&
|
||||
EnumVal >= 0 &&
|
||||
if (PrevErrorCount == ErrorCount &&
|
||||
IsIncremented &&
|
||||
(!IsSigned || EnumVal >= 0) &&
|
||||
NewType->C != UnqualifiedType (MemberType->C)) {
|
||||
/* The possible overflow here can only be when EnumVal > 0 */
|
||||
Warning ("Enumerator '%s' (value = %lu) is of type '%s'",
|
||||
Warning ("Enumerator '%s' (value = %lu) implies type '%s'",
|
||||
Ident,
|
||||
(unsigned long)EnumVal,
|
||||
GetBasicTypeName (NewType));
|
||||
|
@ -809,15 +838,13 @@ static unsigned AliasAnonStructFields (const Declaration* D, SymEntry* Anon)
|
|||
*/
|
||||
{
|
||||
unsigned Count = 0;
|
||||
SymEntry* Field;
|
||||
SymEntry* Alias;
|
||||
|
||||
/* Get the pointer to the symbol table entry of the anon struct */
|
||||
SymEntry* Entry = GetESUSymEntry (D->Type);
|
||||
|
||||
/* Get the symbol table containing the fields. If it is empty, there has
|
||||
** been an error before, so bail out.
|
||||
*/
|
||||
SymTable* Tab = Entry->V.S.SymTab;
|
||||
SymTable* Tab = GetESUTagSym (D->Type)->V.S.SymTab;
|
||||
if (Tab == 0) {
|
||||
/* Incomplete definition - has been flagged before */
|
||||
return 0;
|
||||
|
@ -826,24 +853,24 @@ static unsigned AliasAnonStructFields (const Declaration* D, SymEntry* Anon)
|
|||
/* Get a pointer to the list of symbols. Then walk the list adding copies
|
||||
** of the embedded struct to the current level.
|
||||
*/
|
||||
Entry = Tab->SymHead;
|
||||
while (Entry) {
|
||||
Field = Tab->SymHead;
|
||||
while (Field) {
|
||||
|
||||
/* Enter an alias of this symbol */
|
||||
if (!IsAnonName (Entry->Name)) {
|
||||
Alias = AddLocalSym (Entry->Name, Entry->Type, SC_STRUCTFIELD|SC_ALIAS, 0);
|
||||
Alias->V.A.Field = Entry;
|
||||
Alias->V.A.Offs = Anon->V.Offs + Entry->V.Offs;
|
||||
if (!IsAnonName (Field->Name)) {
|
||||
Alias = AddLocalSym (Field->Name, Field->Type, SC_STRUCTFIELD|SC_ALIAS, 0);
|
||||
Alias->V.A.Field = Field;
|
||||
Alias->V.A.Offs = Anon->V.Offs + Field->V.Offs;
|
||||
++Count;
|
||||
}
|
||||
|
||||
/* Currently, there can not be any attributes, but if there will be
|
||||
** some in the future, we want to know this.
|
||||
*/
|
||||
CHECK (Entry->Attr == 0);
|
||||
CHECK (Field->Attr == 0);
|
||||
|
||||
/* Next entry */
|
||||
Entry = Entry->NextSym;
|
||||
Field = Field->NextSym;
|
||||
}
|
||||
|
||||
/* Return the count of created aliases */
|
||||
|
@ -861,7 +888,7 @@ static SymEntry* ParseUnionDecl (const char* Name, unsigned* DSFlags)
|
|||
int FieldWidth; /* Width in bits, -1 if not a bit-field */
|
||||
SymTable* FieldTab;
|
||||
SymEntry* UnionTagEntry;
|
||||
SymEntry* Entry;
|
||||
SymEntry* Field;
|
||||
unsigned Flags = 0;
|
||||
unsigned PrevErrorCount = ErrorCount;
|
||||
|
||||
|
@ -883,14 +910,21 @@ static SymEntry* ParseUnionDecl (const char* Name, unsigned* DSFlags)
|
|||
EnterStructLevel ();
|
||||
|
||||
/* Parse union fields */
|
||||
UnionSize = 0;
|
||||
UnionSize = 0;
|
||||
while (CurTok.Tok != TOK_RCURLY) {
|
||||
|
||||
/* Get the type of the entry */
|
||||
DeclSpec Spec;
|
||||
int SignednessSpecified = 0;
|
||||
|
||||
/* Check for a _Static_assert */
|
||||
if (CurTok.Tok == TOK_STATIC_ASSERT) {
|
||||
ParseStaticAssert ();
|
||||
continue;
|
||||
}
|
||||
|
||||
InitDeclSpec (&Spec);
|
||||
ParseTypeSpec (&Spec, -1, T_QUAL_NONE, &SignednessSpecified);
|
||||
ParseTypeSpec (&Spec, TS_DEFAULT_TYPE_NONE, &SignednessSpecified);
|
||||
|
||||
/* Read fields with this type */
|
||||
while (1) {
|
||||
|
@ -945,17 +979,17 @@ static SymEntry* ParseUnionDecl (const char* Name, unsigned* DSFlags)
|
|||
AddBitField (Decl.Ident, Decl.Type, 0, 0, FieldWidth,
|
||||
SignednessSpecified);
|
||||
} else if (Decl.Ident[0] != '\0') {
|
||||
Entry = AddLocalSym (Decl.Ident, Decl.Type, SC_STRUCTFIELD, 0);
|
||||
Field = AddLocalSym (Decl.Ident, Decl.Type, SC_STRUCTFIELD, 0);
|
||||
if (IsAnonName (Decl.Ident)) {
|
||||
Entry->V.A.ANumber = UnionTagEntry->V.S.ACount++;
|
||||
AliasAnonStructFields (&Decl, Entry);
|
||||
Field->V.A.ANumber = UnionTagEntry->V.S.ACount++;
|
||||
AliasAnonStructFields (&Decl, Field);
|
||||
}
|
||||
|
||||
/* Check if the field itself has a flexible array member */
|
||||
if (IsClassStruct (Decl.Type)) {
|
||||
SymEntry* Sym = GetSymType (Decl.Type);
|
||||
if (Sym && SymHasFlexibleArrayMember (Sym)) {
|
||||
Entry->Flags |= SC_HAVEFAM;
|
||||
SymEntry* TagEntry = GetESUTagSym (Decl.Type);
|
||||
if (TagEntry && SymHasFlexibleArrayMember (TagEntry)) {
|
||||
Field->Flags |= SC_HAVEFAM;
|
||||
Flags |= SC_HAVEFAM;
|
||||
}
|
||||
}
|
||||
|
@ -1002,7 +1036,7 @@ static SymEntry* ParseStructDecl (const char* Name, unsigned* DSFlags)
|
|||
int FieldWidth; /* Width in bits, -1 if not a bit-field */
|
||||
SymTable* FieldTab;
|
||||
SymEntry* StructTagEntry;
|
||||
SymEntry* Entry;
|
||||
SymEntry* Field;
|
||||
unsigned Flags = 0;
|
||||
unsigned PrevErrorCount = ErrorCount;
|
||||
|
||||
|
@ -1031,6 +1065,7 @@ static SymEntry* ParseStructDecl (const char* Name, unsigned* DSFlags)
|
|||
|
||||
/* Get the type of the entry */
|
||||
DeclSpec Spec;
|
||||
int SignednessSpecified = 0;
|
||||
|
||||
/* Check for a _Static_assert */
|
||||
if (CurTok.Tok == TOK_STATIC_ASSERT) {
|
||||
|
@ -1038,9 +1073,8 @@ static SymEntry* ParseStructDecl (const char* Name, unsigned* DSFlags)
|
|||
continue;
|
||||
}
|
||||
|
||||
int SignednessSpecified = 0;
|
||||
InitDeclSpec (&Spec);
|
||||
ParseTypeSpec (&Spec, -1, T_QUAL_NONE, &SignednessSpecified);
|
||||
ParseTypeSpec (&Spec, TS_DEFAULT_TYPE_NONE, &SignednessSpecified);
|
||||
|
||||
/* Read fields with this type */
|
||||
while (1) {
|
||||
|
@ -1147,17 +1181,17 @@ static SymEntry* ParseStructDecl (const char* Name, unsigned* DSFlags)
|
|||
StructSize += BitOffs / CHAR_BITS;
|
||||
BitOffs %= CHAR_BITS;
|
||||
} else if (Decl.Ident[0] != '\0') {
|
||||
Entry = AddLocalSym (Decl.Ident, Decl.Type, SC_STRUCTFIELD, StructSize);
|
||||
Field = AddLocalSym (Decl.Ident, Decl.Type, SC_STRUCTFIELD, StructSize);
|
||||
if (IsAnonName (Decl.Ident)) {
|
||||
Entry->V.A.ANumber = StructTagEntry->V.S.ACount++;
|
||||
AliasAnonStructFields (&Decl, Entry);
|
||||
Field->V.A.ANumber = StructTagEntry->V.S.ACount++;
|
||||
AliasAnonStructFields (&Decl, Field);
|
||||
}
|
||||
|
||||
/* Check if the field itself has a flexible array member */
|
||||
if (IsClassStruct (Decl.Type)) {
|
||||
SymEntry* Sym = GetSymType (Decl.Type);
|
||||
if (Sym && SymHasFlexibleArrayMember (Sym)) {
|
||||
Entry->Flags |= SC_HAVEFAM;
|
||||
SymEntry* TagEntry = GetESUTagSym (Decl.Type);
|
||||
if (TagEntry && SymHasFlexibleArrayMember (TagEntry)) {
|
||||
Field->Flags |= SC_HAVEFAM;
|
||||
Flags |= SC_HAVEFAM;
|
||||
}
|
||||
}
|
||||
|
@ -1206,15 +1240,15 @@ NextMember: if (CurTok.Tok != TOK_COMMA) {
|
|||
|
||||
|
||||
|
||||
static void ParseTypeSpec (DeclSpec* D, long Default, TypeCode Qualifiers,
|
||||
int* SignednessSpecified)
|
||||
static void ParseTypeSpec (DeclSpec* D, typespec_t TSFlags, int* SignednessSpecified)
|
||||
/* Parse a type specifier. Store whether one of "signed" or "unsigned" was
|
||||
** specified, so bit-fields of unspecified signedness can be treated as
|
||||
** unsigned; without special handling, it would be treated as signed.
|
||||
*/
|
||||
{
|
||||
ident Ident;
|
||||
SymEntry* Entry;
|
||||
SymEntry* TagEntry;
|
||||
TypeCode Qualifiers = T_QUAL_NONE;
|
||||
|
||||
if (SignednessSpecified != NULL) {
|
||||
*SignednessSpecified = 0;
|
||||
|
@ -1223,8 +1257,8 @@ static void ParseTypeSpec (DeclSpec* D, long Default, TypeCode Qualifiers,
|
|||
/* Assume we have an explicit type */
|
||||
D->Flags &= ~DS_DEF_TYPE;
|
||||
|
||||
/* Read type qualifiers if we have any */
|
||||
Qualifiers |= OptionalQualifiers (T_QUAL_CONST | T_QUAL_VOLATILE);
|
||||
/* Read storage specifiers and/or type qualifiers if we have any */
|
||||
OptionalSpecifiers (D, &Qualifiers, TSFlags);
|
||||
|
||||
/* Look at the data type */
|
||||
switch (CurTok.Tok) {
|
||||
|
@ -1384,10 +1418,10 @@ static void ParseTypeSpec (DeclSpec* D, long Default, TypeCode Qualifiers,
|
|||
/* Remember we have an extra type decl */
|
||||
D->Flags |= DS_EXTRA_TYPE;
|
||||
/* Declare the union in the current scope */
|
||||
Entry = ParseUnionDecl (Ident, &D->Flags);
|
||||
TagEntry = ParseUnionDecl (Ident, &D->Flags);
|
||||
/* Encode the union entry into the type */
|
||||
D->Type[0].C = T_UNION;
|
||||
SetESUSymEntry (D->Type, Entry);
|
||||
SetESUTagSym (D->Type, TagEntry);
|
||||
D->Type[1].C = T_END;
|
||||
break;
|
||||
|
||||
|
@ -1403,10 +1437,10 @@ static void ParseTypeSpec (DeclSpec* D, long Default, TypeCode Qualifiers,
|
|||
/* Remember we have an extra type decl */
|
||||
D->Flags |= DS_EXTRA_TYPE;
|
||||
/* Declare the struct in the current scope */
|
||||
Entry = ParseStructDecl (Ident, &D->Flags);
|
||||
TagEntry = ParseStructDecl (Ident, &D->Flags);
|
||||
/* Encode the struct entry into the type */
|
||||
D->Type[0].C = T_STRUCT;
|
||||
SetESUSymEntry (D->Type, Entry);
|
||||
SetESUTagSym (D->Type, TagEntry);
|
||||
D->Type[1].C = T_END;
|
||||
break;
|
||||
|
||||
|
@ -1426,10 +1460,10 @@ static void ParseTypeSpec (DeclSpec* D, long Default, TypeCode Qualifiers,
|
|||
/* Remember we have an extra type decl */
|
||||
D->Flags |= DS_EXTRA_TYPE;
|
||||
/* Parse the enum decl */
|
||||
Entry = ParseEnumDecl (Ident, &D->Flags);
|
||||
TagEntry = ParseEnumDecl (Ident, &D->Flags);
|
||||
/* Encode the enum entry into the type */
|
||||
D->Type[0].C |= T_ENUM;
|
||||
SetESUSymEntry (D->Type, Entry);
|
||||
SetESUTagSym (D->Type, TagEntry);
|
||||
D->Type[1].C = T_END;
|
||||
/* The signedness of enums is determined by the type, so say this is specified to avoid
|
||||
** the int -> unsigned int handling for plain int bit-fields in AddBitField.
|
||||
|
@ -1442,11 +1476,11 @@ static void ParseTypeSpec (DeclSpec* D, long Default, TypeCode Qualifiers,
|
|||
case TOK_IDENT:
|
||||
/* This could be a label */
|
||||
if (NextTok.Tok != TOK_COLON || GetLexicalLevel () == LEX_LEVEL_STRUCT) {
|
||||
Entry = FindSym (CurTok.Ident);
|
||||
if (Entry && SymIsTypeDef (Entry)) {
|
||||
TagEntry = FindSym (CurTok.Ident);
|
||||
if (TagEntry && SymIsTypeDef (TagEntry)) {
|
||||
/* It's a typedef */
|
||||
NextToken ();
|
||||
TypeCopy (D->Type, Entry->Type);
|
||||
TypeCopy (D->Type, TagEntry->Type);
|
||||
/* If it's a typedef, we should actually use whether the signedness was
|
||||
** specified on the typedef, but that information has been lost. Treat the
|
||||
** signedness as being specified to work around the ICE in #1267.
|
||||
|
@ -1471,20 +1505,21 @@ static void ParseTypeSpec (DeclSpec* D, long Default, TypeCode Qualifiers,
|
|||
/* FALL THROUGH */
|
||||
|
||||
default:
|
||||
if (Default < 0) {
|
||||
if ((TSFlags & TS_MASK_DEFAULT_TYPE) != TS_DEFAULT_TYPE_INT) {
|
||||
Error ("Type expected");
|
||||
D->Type[0].C = T_INT;
|
||||
D->Type[1].C = T_END;
|
||||
} else {
|
||||
D->Flags |= DS_DEF_TYPE;
|
||||
D->Type[0].C = (TypeCode) Default;
|
||||
D->Type[0].C = T_INT;
|
||||
D->Type[1].C = T_END;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* There may also be qualifiers *after* the initial type */
|
||||
D->Type[0].C |= (Qualifiers | OptionalQualifiers (T_QUAL_CONST | T_QUAL_VOLATILE));
|
||||
/* There may also be specifiers/qualifiers *after* the initial type */
|
||||
OptionalSpecifiers (D, &Qualifiers, TSFlags);
|
||||
D->Type[0].C |= Qualifiers;
|
||||
}
|
||||
|
||||
|
||||
|
@ -1564,7 +1599,7 @@ static void ParseOldStyleParamList (FuncDesc* F)
|
|||
DeclSpec Spec;
|
||||
|
||||
/* Read the declaration specifier */
|
||||
ParseDeclSpec (&Spec, SC_AUTO, T_INT);
|
||||
ParseDeclSpec (&Spec, TS_DEFAULT_TYPE_NONE, SC_AUTO);
|
||||
|
||||
/* We accept only auto and register as storage class specifiers, but
|
||||
** we ignore all this, since we use auto anyway.
|
||||
|
@ -1591,19 +1626,19 @@ static void ParseOldStyleParamList (FuncDesc* F)
|
|||
if (Decl.Ident[0] != '\0') {
|
||||
|
||||
/* We have a name given. Search for the symbol */
|
||||
SymEntry* Sym = FindLocalSym (Decl.Ident);
|
||||
if (Sym) {
|
||||
SymEntry* Param = FindLocalSym (Decl.Ident);
|
||||
if (Param) {
|
||||
/* Check if we already changed the type for this
|
||||
** parameter
|
||||
*/
|
||||
if (Sym->Flags & SC_DEFTYPE) {
|
||||
if (Param->Flags & SC_DEFTYPE) {
|
||||
/* Found it, change the default type to the one given */
|
||||
ChangeSymType (Sym, ParamTypeCvt (Decl.Type));
|
||||
SymChangeType (Param, ParamTypeCvt (Decl.Type));
|
||||
/* Reset the "default type" flag */
|
||||
Sym->Flags &= ~SC_DEFTYPE;
|
||||
Param->Flags &= ~SC_DEFTYPE;
|
||||
} else {
|
||||
/* Type has already been changed */
|
||||
Error ("Redefinition for parameter '%s'", Sym->Name);
|
||||
Error ("Redefinition for parameter '%s'", Param->Name);
|
||||
}
|
||||
} else {
|
||||
Error ("Unknown identifier: '%s'", Decl.Ident);
|
||||
|
@ -1633,7 +1668,7 @@ static void ParseAnsiParamList (FuncDesc* F)
|
|||
|
||||
DeclSpec Spec;
|
||||
Declaration Decl;
|
||||
SymEntry* Sym;
|
||||
SymEntry* Param;
|
||||
|
||||
/* Allow an ellipsis as last parameter */
|
||||
if (CurTok.Tok == TOK_ELLIPSIS) {
|
||||
|
@ -1643,7 +1678,7 @@ static void ParseAnsiParamList (FuncDesc* F)
|
|||
}
|
||||
|
||||
/* Read the declaration specifier */
|
||||
ParseDeclSpec (&Spec, SC_AUTO, T_INT);
|
||||
ParseDeclSpec (&Spec, TS_DEFAULT_TYPE_NONE, SC_AUTO);
|
||||
|
||||
/* We accept only auto and register as storage class specifiers */
|
||||
if ((Spec.StorageClass & SC_AUTO) == SC_AUTO) {
|
||||
|
@ -1681,10 +1716,10 @@ static void ParseAnsiParamList (FuncDesc* F)
|
|||
ParseAttribute (&Decl);
|
||||
|
||||
/* Create a symbol table entry */
|
||||
Sym = AddLocalSym (Decl.Ident, ParamTypeCvt (Decl.Type), Decl.StorageClass, 0);
|
||||
Param = AddLocalSym (Decl.Ident, ParamTypeCvt (Decl.Type), Decl.StorageClass, 0);
|
||||
|
||||
/* Add attributes if we have any */
|
||||
SymUseAttr (Sym, &Decl);
|
||||
SymUseAttr (Param, &Decl);
|
||||
|
||||
/* If the parameter is a struct or union, emit a warning */
|
||||
if (IsClassStruct (Decl.Type)) {
|
||||
|
@ -1791,7 +1826,7 @@ static void Declarator (const DeclSpec* Spec, Declaration* D, declmode_t Mode)
|
|||
** qualifier later will be transfered to the function itself. If it's a
|
||||
** pointer to something else, it will be flagged as an error.
|
||||
*/
|
||||
TypeCode Qualifiers = OptionalQualifiers (T_QUAL_ADDRSIZE | T_QUAL_CCONV);
|
||||
TypeCode Qualifiers = OptionalQualifiers (T_QUAL_NONE, T_QUAL_ADDRSIZE | T_QUAL_CCONV);
|
||||
|
||||
/* Pointer to something */
|
||||
if (CurTok.Tok == TOK_STAR) {
|
||||
|
@ -1800,7 +1835,7 @@ static void Declarator (const DeclSpec* Spec, Declaration* D, declmode_t Mode)
|
|||
NextToken ();
|
||||
|
||||
/* Allow const, restrict, and volatile qualifiers */
|
||||
Qualifiers |= OptionalQualifiers (T_QUAL_CVR);
|
||||
Qualifiers |= OptionalQualifiers (Qualifiers, T_QUAL_CVR);
|
||||
|
||||
/* Parse the type that the pointer points to */
|
||||
Declarator (Spec, D, Mode);
|
||||
|
@ -1945,7 +1980,7 @@ Type* ParseType (Type* T)
|
|||
|
||||
/* Get a type without a default */
|
||||
InitDeclSpec (&Spec);
|
||||
ParseTypeSpec (&Spec, -1, T_QUAL_NONE, NULL);
|
||||
ParseTypeSpec (&Spec, TS_DEFAULT_TYPE_NONE, NULL);
|
||||
|
||||
/* Parse additional declarators */
|
||||
ParseDecl (&Spec, &Decl, DM_NO_IDENT);
|
||||
|
@ -2070,22 +2105,23 @@ void ParseDecl (const DeclSpec* Spec, Declaration* D, declmode_t Mode)
|
|||
|
||||
|
||||
|
||||
void ParseDeclSpec (DeclSpec* D, unsigned DefStorage, long DefType)
|
||||
void ParseDeclSpec (DeclSpec* D, typespec_t TSFlags, unsigned DefStorage)
|
||||
/* Parse a declaration specification */
|
||||
{
|
||||
TypeCode Qualifiers;
|
||||
|
||||
/* Initialize the DeclSpec struct */
|
||||
InitDeclSpec (D);
|
||||
|
||||
/* There may be qualifiers *before* the storage class specifier */
|
||||
Qualifiers = OptionalQualifiers (T_QUAL_CONST | T_QUAL_VOLATILE);
|
||||
/* Assume we're using an explicit storage class */
|
||||
D->Flags &= ~DS_DEF_STORAGE;
|
||||
|
||||
/* Now get the storage class specifier for this declaration */
|
||||
ParseStorageClass (D, DefStorage);
|
||||
/* Parse the type specifiers */
|
||||
ParseTypeSpec (D, TSFlags | TS_STORAGE_CLASS_SPEC | TS_FUNCTION_SPEC, NULL);
|
||||
|
||||
/* Parse the type specifiers passing any initial type qualifiers */
|
||||
ParseTypeSpec (D, DefType, Qualifiers, NULL);
|
||||
/* If no explicit storage class is given, use the default */
|
||||
if (D->StorageClass == 0) {
|
||||
D->Flags |= DS_DEF_STORAGE;
|
||||
D->StorageClass = DefStorage;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -53,6 +53,22 @@
|
|||
|
||||
|
||||
|
||||
/* Type specifier parser flags */
|
||||
typedef enum typespec_t typespec_t;
|
||||
enum typespec_t {
|
||||
TS_NONE = 0x00,
|
||||
|
||||
/* Default type */
|
||||
TS_MASK_DEFAULT_TYPE = 0x03,
|
||||
TS_DEFAULT_TYPE_NONE = 0x00, /* No default type */
|
||||
TS_DEFAULT_TYPE_INT = 0x01, /* Good old int */
|
||||
TS_DEFAULT_TYPE_AUTO = 0x02, /* C23 type inference with auto */
|
||||
|
||||
/* Whether to allow certain kinds of specifiers */
|
||||
TS_STORAGE_CLASS_SPEC = 0x04, /* Allow storage storage class specifiers */
|
||||
TS_FUNCTION_SPEC = 0x08, /* Allow function specifiers */
|
||||
};
|
||||
|
||||
/* Masks for the Flags field in DeclSpec */
|
||||
#define DS_DEF_STORAGE 0x0001U /* Default storage class used */
|
||||
#define DS_DEF_TYPE 0x0002U /* Default type used */
|
||||
|
@ -105,7 +121,7 @@ Type* ParseType (Type* Type);
|
|||
void ParseDecl (const DeclSpec* Spec, Declaration* D, declmode_t Mode);
|
||||
/* Parse a variable, type or function declaration */
|
||||
|
||||
void ParseDeclSpec (DeclSpec* D, unsigned DefStorage, long DefType);
|
||||
void ParseDeclSpec (DeclSpec* D, typespec_t TSFlags, unsigned DefStorage);
|
||||
/* Parse a declaration specification */
|
||||
|
||||
void CheckEmptyDecl (const DeclSpec* D);
|
||||
|
|
123
src/cc65/error.c
123
src/cc65/error.c
|
@ -108,6 +108,36 @@ Collection DiagnosticStrBufs;
|
|||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Helpers */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
static const char* GetDiagnosticFileName (void)
|
||||
/* Get the source file name where the diagnostic info refers to */
|
||||
{
|
||||
if (CurTok.LI) {
|
||||
return GetInputName (CurTok.LI);
|
||||
} else {
|
||||
return GetCurrentFilename ();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static unsigned GetDiagnosticLineNum (void)
|
||||
/* Get the source line number where the diagnostic info refers to */
|
||||
{
|
||||
if (CurTok.LI) {
|
||||
return GetInputLine (CurTok.LI);
|
||||
} else {
|
||||
return GetCurrentLineNum ();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Handling of fatal errors */
|
||||
/*****************************************************************************/
|
||||
|
@ -119,17 +149,7 @@ void Fatal (const char* Format, ...)
|
|||
{
|
||||
va_list ap;
|
||||
|
||||
const char* FileName;
|
||||
unsigned LineNum;
|
||||
if (CurTok.LI) {
|
||||
FileName = GetInputName (CurTok.LI);
|
||||
LineNum = GetInputLine (CurTok.LI);
|
||||
} else {
|
||||
FileName = GetCurrentFile ();
|
||||
LineNum = GetCurrentLine ();
|
||||
}
|
||||
|
||||
fprintf (stderr, "%s:%u: Fatal: ", FileName, LineNum);
|
||||
fprintf (stderr, "%s:%u: Fatal: ", GetDiagnosticFileName (), GetDiagnosticLineNum ());
|
||||
|
||||
va_start (ap, Format);
|
||||
vfprintf (stderr, Format, ap);
|
||||
|
@ -145,22 +165,12 @@ void Fatal (const char* Format, ...)
|
|||
|
||||
|
||||
void Internal (const char* Format, ...)
|
||||
/* Print a message about an internal compiler error and die. */
|
||||
/* Print a message about an internal compiler error and die */
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
const char* FileName;
|
||||
unsigned LineNum;
|
||||
if (CurTok.LI) {
|
||||
FileName = GetInputName (CurTok.LI);
|
||||
LineNum = GetInputLine (CurTok.LI);
|
||||
} else {
|
||||
FileName = GetCurrentFile ();
|
||||
LineNum = GetCurrentLine ();
|
||||
}
|
||||
|
||||
fprintf (stderr, "%s:%u: Internal compiler error:\n",
|
||||
FileName, LineNum);
|
||||
GetDiagnosticFileName (), GetDiagnosticLineNum ());
|
||||
|
||||
va_start (ap, Format);
|
||||
vfprintf (stderr, Format, ap);
|
||||
|
@ -184,7 +194,7 @@ void Internal (const char* Format, ...)
|
|||
|
||||
|
||||
static void IntError (const char* Filename, unsigned LineNo, const char* Msg, va_list ap)
|
||||
/* Print an error message - internal function*/
|
||||
/* Print an error message - internal function */
|
||||
{
|
||||
fprintf (stderr, "%s:%u: Error: ", Filename, LineNo);
|
||||
vfprintf (stderr, Msg, ap);
|
||||
|
@ -206,7 +216,7 @@ void Error (const char* Format, ...)
|
|||
{
|
||||
va_list ap;
|
||||
va_start (ap, Format);
|
||||
IntError (GetInputName (CurTok.LI), GetInputLine (CurTok.LI), Format, ap);
|
||||
IntError (GetDiagnosticFileName (), GetDiagnosticLineNum (), Format, ap);
|
||||
va_end (ap);
|
||||
}
|
||||
|
||||
|
@ -224,11 +234,11 @@ void LIError (const LineInfo* LI, const char* Format, ...)
|
|||
|
||||
|
||||
void PPError (const char* Format, ...)
|
||||
/* Print an error message. For use within the preprocessor. */
|
||||
/* Print an error message. For use within the preprocessor */
|
||||
{
|
||||
va_list ap;
|
||||
va_start (ap, Format);
|
||||
IntError (GetCurrentFile(), GetCurrentLine(), Format, ap);
|
||||
IntError (GetCurrentFilename(), GetCurrentLineNum(), Format, ap);
|
||||
va_end (ap);
|
||||
}
|
||||
|
||||
|
@ -241,7 +251,7 @@ void PPError (const char* Format, ...)
|
|||
|
||||
|
||||
static void IntWarning (const char* Filename, unsigned LineNo, const char* Msg, va_list ap)
|
||||
/* Print warning message - internal function. */
|
||||
/* Print a warning message - internal function */
|
||||
{
|
||||
if (IS_Get (&WarningsAreErrors)) {
|
||||
|
||||
|
@ -265,11 +275,11 @@ static void IntWarning (const char* Filename, unsigned LineNo, const char* Msg,
|
|||
|
||||
|
||||
void Warning (const char* Format, ...)
|
||||
/* Print warning message. */
|
||||
/* Print a warning message */
|
||||
{
|
||||
va_list ap;
|
||||
va_start (ap, Format);
|
||||
IntWarning (GetInputName (CurTok.LI), GetInputLine (CurTok.LI), Format, ap);
|
||||
IntWarning (GetDiagnosticFileName (), GetDiagnosticLineNum (), Format, ap);
|
||||
va_end (ap);
|
||||
}
|
||||
|
||||
|
@ -287,11 +297,11 @@ void LIWarning (const LineInfo* LI, const char* Format, ...)
|
|||
|
||||
|
||||
void PPWarning (const char* Format, ...)
|
||||
/* Print warning message. For use within the preprocessor. */
|
||||
/* Print a warning message. For use within the preprocessor */
|
||||
{
|
||||
va_list ap;
|
||||
va_start (ap, Format);
|
||||
IntWarning (GetCurrentFile(), GetCurrentLine(), Format, ap);
|
||||
IntWarning (GetCurrentFilename(), GetCurrentLineNum(), Format, ap);
|
||||
va_end (ap);
|
||||
}
|
||||
|
||||
|
@ -326,6 +336,55 @@ void ListWarnings (FILE* F)
|
|||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Handling of other infos */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
static void IntNote (const char* Filename, unsigned LineNo, const char* Msg, va_list ap)
|
||||
/* Print a note message - internal function */
|
||||
{
|
||||
fprintf (stderr, "%s:%u: Note: ", Filename, LineNo);
|
||||
vfprintf (stderr, Msg, ap);
|
||||
fprintf (stderr, "\n");
|
||||
}
|
||||
|
||||
|
||||
|
||||
void Note (const char* Format, ...)
|
||||
/* Print a note message */
|
||||
{
|
||||
va_list ap;
|
||||
va_start (ap, Format);
|
||||
IntNote (GetDiagnosticFileName (), GetDiagnosticLineNum (), Format, ap);
|
||||
va_end (ap);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void LINote (const LineInfo* LI, const char* Format, ...)
|
||||
/* Print a note message with the line info given explicitly */
|
||||
{
|
||||
va_list ap;
|
||||
va_start (ap, Format);
|
||||
IntNote (GetInputName (LI), GetInputLine (LI), Format, ap);
|
||||
va_end (ap);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void PPNote (const char* Format, ...)
|
||||
/* Print a note message. For use within the preprocessor */
|
||||
{
|
||||
va_list ap;
|
||||
va_start (ap, Format);
|
||||
IntNote (GetCurrentFilename(), GetCurrentLineNum(), Format, ap);
|
||||
va_end (ap);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Code */
|
||||
/*****************************************************************************/
|
||||
|
|
|
@ -92,7 +92,7 @@ void Fatal (const char* Format, ...) attribute ((noreturn, format (printf, 1, 2)
|
|||
/* Print a message about a fatal error and die */
|
||||
|
||||
void Internal (const char* Format, ...) attribute ((noreturn, format (printf, 1, 2)));
|
||||
/* Print a message about an internal compiler error and die. */
|
||||
/* Print a message about an internal compiler error and die */
|
||||
|
||||
void Error (const char* Format, ...) attribute ((format (printf, 1, 2)));
|
||||
/* Print an error message */
|
||||
|
@ -101,16 +101,16 @@ void LIError (const LineInfo* LI, const char* Format, ...) attribute ((format (p
|
|||
/* Print an error message with the line info given explicitly */
|
||||
|
||||
void PPError (const char* Format, ...) attribute ((format (printf, 1, 2)));
|
||||
/* Print an error message. For use within the preprocessor. */
|
||||
/* Print an error message. For use within the preprocessor */
|
||||
|
||||
void Warning (const char* Format, ...) attribute ((format (printf, 1, 2)));
|
||||
/* Print warning message. */
|
||||
/* Print a warning message */
|
||||
|
||||
void LIWarning (const LineInfo* LI, const char* Format, ...) attribute ((format (printf, 2, 3)));
|
||||
/* Print a warning message with the line info given explicitly */
|
||||
|
||||
void PPWarning (const char* Format, ...) attribute ((format (printf, 1, 2)));
|
||||
/* Print warning message. For use within the preprocessor. */
|
||||
/* Print a warning message. For use within the preprocessor */
|
||||
|
||||
IntStack* FindWarning (const char* Name);
|
||||
/* Search for a warning in the WarnMap table and return a pointer to the
|
||||
|
@ -120,6 +120,15 @@ IntStack* FindWarning (const char* Name);
|
|||
void ListWarnings (FILE* F);
|
||||
/* Print a list of warning types/names to the given file */
|
||||
|
||||
void Note (const char* Format, ...) attribute ((format (printf, 1, 2)));
|
||||
/* Print a note message */
|
||||
|
||||
void LINote (const LineInfo* LI, const char* Format, ...) attribute ((format (printf, 2, 3)));
|
||||
/* Print a note message with the line info given explicitly */
|
||||
|
||||
void PPNote (const char* Format, ...) attribute ((format (printf, 1, 2)));
|
||||
/* Print a note message. For use within the preprocessor */
|
||||
|
||||
void ErrorReport (void);
|
||||
/* Report errors (called at end of compile) */
|
||||
|
||||
|
|
|
@ -199,12 +199,15 @@ static unsigned typeadjust (ExprDesc* lhs, const ExprDesc* rhs, int NoPush)
|
|||
|
||||
|
||||
|
||||
void LimitExprValue (ExprDesc* Expr)
|
||||
void LimitExprValue (ExprDesc* Expr, int WarnOverflow)
|
||||
/* Limit the constant value of the expression to the range of its type */
|
||||
{
|
||||
switch (GetUnderlyingTypeCode (Expr->Type)) {
|
||||
case T_INT:
|
||||
case T_SHORT:
|
||||
if (WarnOverflow && ((Expr->IVal < -0x8000) || (Expr->IVal > 0x7FFF))) {
|
||||
Warning ("Signed integer constant overflow");
|
||||
}
|
||||
Expr->IVal = (int16_t)Expr->IVal;
|
||||
break;
|
||||
|
||||
|
@ -224,6 +227,9 @@ void LimitExprValue (ExprDesc* Expr)
|
|||
break;
|
||||
|
||||
case T_SCHAR:
|
||||
if (WarnOverflow && ((Expr->IVal < -0x80) || (Expr->IVal > 0x7F))) {
|
||||
Warning ("Signed character constant overflow");
|
||||
}
|
||||
Expr->IVal = (int8_t)Expr->IVal;
|
||||
break;
|
||||
|
||||
|
@ -286,11 +292,10 @@ static unsigned ExprCheckedSizeOf (const Type* T)
|
|||
/* Specially checked SizeOf() used in 'sizeof' expressions */
|
||||
{
|
||||
unsigned Size = SizeOf (T);
|
||||
SymEntry* Sym;
|
||||
|
||||
if (Size == 0) {
|
||||
Sym = GetSymType (T);
|
||||
if (Sym == 0 || !SymIsDef (Sym)) {
|
||||
SymEntry* TagSym = GetESUTagSym (T);
|
||||
if (TagSym == 0 || !SymIsDef (TagSym)) {
|
||||
Error ("Cannot apply 'sizeof' to incomplete type '%s'", GetFullTypeName (T));
|
||||
}
|
||||
}
|
||||
|
@ -1308,7 +1313,7 @@ static void Primary (ExprDesc* E)
|
|||
/* Let's see if this is a C99-style declaration */
|
||||
DeclSpec Spec;
|
||||
InitDeclSpec (&Spec);
|
||||
ParseDeclSpec (&Spec, -1, T_QUAL_NONE);
|
||||
ParseDeclSpec (&Spec, TS_DEFAULT_TYPE_INT, SC_AUTO);
|
||||
|
||||
if (Spec.Type->C != T_END) {
|
||||
|
||||
|
@ -1848,7 +1853,7 @@ static void UnaryOp (ExprDesc* Expr)
|
|||
}
|
||||
|
||||
/* Limit the calculated value to the range of its type */
|
||||
LimitExprValue (Expr);
|
||||
LimitExprValue (Expr, 1);
|
||||
|
||||
} else {
|
||||
unsigned Flags;
|
||||
|
@ -2260,7 +2265,7 @@ LOG(("hie_internal Expr->Type:%s Expr2->Type:%s\n",
|
|||
}
|
||||
|
||||
/* Limit the calculated value to the range of its type */
|
||||
LimitExprValue (Expr);
|
||||
LimitExprValue (Expr, 1);
|
||||
|
||||
} else if (lconst && (Gen->Flags & GEN_COMM) && !rconst) {
|
||||
/* If the LHS constant is an int that fits into an unsigned char, change the
|
||||
|
@ -2904,7 +2909,7 @@ static void parseadd (ExprDesc* Expr, int DoArrayRef)
|
|||
Expr->Type = rhst;
|
||||
} else {
|
||||
/* Limit the calculated value to the range of its type */
|
||||
LimitExprValue (Expr);
|
||||
LimitExprValue (Expr, 1);
|
||||
}
|
||||
|
||||
/* The result is always an rvalue */
|
||||
|
@ -3402,7 +3407,7 @@ static void parsesub (ExprDesc* Expr)
|
|||
/* Just adjust the result type */
|
||||
Expr->Type = ArithmeticConvert (Expr->Type, Expr2.Type);
|
||||
/* And limit the calculated value to the range of it */
|
||||
LimitExprValue (Expr);
|
||||
LimitExprValue (Expr, 1);
|
||||
}
|
||||
/* The result is always an rvalue */
|
||||
ED_MarkExprAsRVal (Expr);
|
||||
|
@ -4017,9 +4022,9 @@ static void hieQuest (ExprDesc* Expr)
|
|||
|
||||
ED_FinalizeRValLoad (&Expr2);
|
||||
} else {
|
||||
/* Constant boolean subexpression could still have deferred inc/
|
||||
** dec operations, so just flush their side-effects at this
|
||||
** sequence point.
|
||||
/* Constant subexpression could still have deferred inc/dec
|
||||
** operations, so just flush their side-effects at this sequence
|
||||
** point.
|
||||
*/
|
||||
DoDeferred (SQP_KEEP_NONE, &Expr2);
|
||||
}
|
||||
|
@ -4055,7 +4060,7 @@ static void hieQuest (ExprDesc* Expr)
|
|||
/* Parse third expression. Remember for later if it is a NULL pointer
|
||||
** expression, then load it into the primary.
|
||||
*/
|
||||
ExprWithCheck (hie1, &Expr3);
|
||||
ExprWithCheck (hieQuest, &Expr3);
|
||||
Expr3IsNULL = ED_IsNullPtr (&Expr3);
|
||||
if (!IsTypeVoid (Expr3.Type) &&
|
||||
ED_YetToLoad (&Expr3) &&
|
||||
|
@ -4068,9 +4073,9 @@ static void hieQuest (ExprDesc* Expr)
|
|||
|
||||
ED_FinalizeRValLoad (&Expr3);
|
||||
} else {
|
||||
/* Constant boolean subexpression could still have deferred inc/
|
||||
** dec operations, so just flush their side-effects at this
|
||||
** sequence point.
|
||||
/* Constant subexpression could still have deferred inc/dec
|
||||
** operations, so just flush their side-effects at this sequence
|
||||
** point.
|
||||
*/
|
||||
DoDeferred (SQP_KEEP_NONE, &Expr3);
|
||||
}
|
||||
|
@ -4184,6 +4189,8 @@ static void hieQuest (ExprDesc* Expr)
|
|||
} else {
|
||||
*Expr = Expr3;
|
||||
}
|
||||
/* The result expression is always an rvalue */
|
||||
ED_MarkExprAsRVal (Expr);
|
||||
}
|
||||
|
||||
/* Setup the target expression */
|
||||
|
|
|
@ -59,7 +59,7 @@ void MarkedExprWithCheck (void (*Func) (ExprDesc*), ExprDesc* Expr);
|
|||
** generated code.
|
||||
*/
|
||||
|
||||
void LimitExprValue (ExprDesc* Expr);
|
||||
void LimitExprValue (ExprDesc* Expr, int WarnOverflow);
|
||||
/* Limit the constant value of the expression to the range of its type */
|
||||
|
||||
void PushAddr (const ExprDesc* Expr);
|
||||
|
|
|
@ -67,75 +67,9 @@ ExprDesc* ED_Init (ExprDesc* Expr)
|
|||
|
||||
|
||||
|
||||
#if !defined(HAVE_INLINE)
|
||||
int ED_IsLocQuasiConst (const ExprDesc* Expr)
|
||||
/* Return true if the expression is a constant location of some sort or on the
|
||||
** stack.
|
||||
*/
|
||||
{
|
||||
return ED_IsLocConst (Expr) || ED_IsLocStack (Expr);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#if !defined(HAVE_INLINE)
|
||||
int ED_IsLocPrimaryOrExpr (const ExprDesc* Expr)
|
||||
/* Return true if the expression is E_LOC_PRIMARY or E_LOC_EXPR */
|
||||
{
|
||||
return ED_IsLocPrimary (Expr) || ED_IsLocExpr (Expr);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#if !defined(HAVE_INLINE)
|
||||
int ED_IsIndExpr (const ExprDesc* Expr)
|
||||
/* Check if the expression is a reference to its value */
|
||||
{
|
||||
return (Expr->Flags & E_ADDRESS_OF) == 0 &&
|
||||
!ED_IsLocNone (Expr) && !ED_IsLocPrimary (Expr);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
int ED_YetToLoad (const ExprDesc* Expr)
|
||||
/* Check if the expression needs to be loaded somehow. */
|
||||
{
|
||||
return ED_NeedsPrimary (Expr) ||
|
||||
ED_YetToTest (Expr) ||
|
||||
(ED_IsLVal (Expr) && IsQualVolatile (Expr->Type));
|
||||
}
|
||||
|
||||
|
||||
|
||||
void ED_MarkForUneval (ExprDesc* Expr)
|
||||
/* Mark the expression as not to be evaluated */
|
||||
{
|
||||
Expr->Flags = (Expr->Flags & ~E_MASK_EVAL) | E_EVAL_UNEVAL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void ED_SetCodeRange (ExprDesc* Expr, const CodeMark* Start, const CodeMark* End)
|
||||
/* Set the code range for this expression */
|
||||
{
|
||||
Expr->Flags |= E_HAVE_MARKS;
|
||||
Expr->Start = *Start;
|
||||
Expr->End = *End;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int ED_CodeRangeIsEmpty (const ExprDesc* Expr)
|
||||
/* Return true if no code was output for this expression */
|
||||
{
|
||||
/* We must have code marks */
|
||||
PRECONDITION (Expr->Flags & E_HAVE_MARKS);
|
||||
|
||||
return CodeRangeIsEmpty (&Expr->Start, &Expr->End);
|
||||
}
|
||||
/*****************************************************************************/
|
||||
/* Info Extraction */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
|
@ -215,6 +149,190 @@ int ED_GetStackOffs (const ExprDesc* Expr, int Offs)
|
|||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Predicates */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
#if !defined(HAVE_INLINE)
|
||||
int ED_IsLocQuasiConst (const ExprDesc* Expr)
|
||||
/* Return true if the expression is a constant location of some sort or on the
|
||||
** stack.
|
||||
*/
|
||||
{
|
||||
return ED_IsLocConst (Expr) || ED_IsLocStack (Expr);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#if !defined(HAVE_INLINE)
|
||||
int ED_IsLocPrimaryOrExpr (const ExprDesc* Expr)
|
||||
/* Return true if the expression is E_LOC_PRIMARY or E_LOC_EXPR */
|
||||
{
|
||||
return ED_IsLocPrimary (Expr) || ED_IsLocExpr (Expr);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#if !defined(HAVE_INLINE)
|
||||
int ED_IsIndExpr (const ExprDesc* Expr)
|
||||
/* Check if the expression is a reference to its value */
|
||||
{
|
||||
return (Expr->Flags & E_ADDRESS_OF) == 0 &&
|
||||
!ED_IsLocNone (Expr) && !ED_IsLocPrimary (Expr);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
int ED_YetToLoad (const ExprDesc* Expr)
|
||||
/* Check if the expression needs to be loaded somehow. */
|
||||
{
|
||||
return ED_NeedsPrimary (Expr) ||
|
||||
ED_YetToTest (Expr) ||
|
||||
(ED_IsLVal (Expr) && IsQualVolatile (Expr->Type));
|
||||
}
|
||||
|
||||
|
||||
|
||||
#if !defined(HAVE_INLINE)
|
||||
int ED_IsAbs (const ExprDesc* Expr)
|
||||
/* Return true if the expression denotes a numeric value or address. */
|
||||
{
|
||||
return (Expr->Flags & (E_MASK_LOC)) == (E_LOC_NONE) ||
|
||||
(Expr->Flags & (E_MASK_LOC|E_ADDRESS_OF)) == (E_LOC_ABS|E_ADDRESS_OF);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#if !defined(HAVE_INLINE)
|
||||
int ED_IsConstAbs (const ExprDesc* Expr)
|
||||
/* Return true if the expression denotes a constant absolute value. This can be
|
||||
** a numeric constant, cast to any type.
|
||||
*/
|
||||
{
|
||||
return ED_IsRVal (Expr) && ED_IsAbs (Expr);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
int ED_IsConstAbsInt (const ExprDesc* Expr)
|
||||
/* Return true if the expression is a constant (numeric) integer. */
|
||||
{
|
||||
return ED_IsConstAbs (Expr) && IsClassInt (Expr->Type);
|
||||
}
|
||||
|
||||
|
||||
|
||||
int ED_IsConstBool (const ExprDesc* Expr)
|
||||
/* Return true if the expression can be constantly evaluated as a boolean. */
|
||||
{
|
||||
return ED_IsConstAbsInt (Expr) || ED_IsAddrExpr (Expr);
|
||||
}
|
||||
|
||||
|
||||
|
||||
int ED_IsConstTrue (const ExprDesc* Expr)
|
||||
/* Return true if the constant expression can be evaluated as boolean true at
|
||||
** compile time.
|
||||
*/
|
||||
{
|
||||
/* Non-zero arithmetics and objects addresses are boolean true */
|
||||
return (ED_IsConstAbsInt (Expr) && Expr->IVal != 0) ||
|
||||
(ED_IsAddrExpr (Expr));
|
||||
}
|
||||
|
||||
|
||||
|
||||
int ED_IsConstFalse (const ExprDesc* Expr)
|
||||
/* Return true if the constant expression can be evaluated as boolean false at
|
||||
** compile time.
|
||||
*/
|
||||
{
|
||||
/* Zero arithmetics and null pointers are boolean false */
|
||||
return (ED_IsConstAbsInt (Expr) && Expr->IVal == 0) ||
|
||||
ED_IsNullPtr (Expr);
|
||||
}
|
||||
|
||||
|
||||
|
||||
int ED_IsConst (const ExprDesc* Expr)
|
||||
/* Return true if the expression denotes a constant of some sort. This can be a
|
||||
** numeric constant, the address of a global variable (maybe with offset) or
|
||||
** similar.
|
||||
*/
|
||||
{
|
||||
return (Expr->Flags & E_MASK_LOC) == E_LOC_NONE || ED_IsConstAddr (Expr);
|
||||
}
|
||||
|
||||
|
||||
|
||||
int ED_IsQuasiConst (const ExprDesc* Expr)
|
||||
/* Return true if the expression denotes a quasi-constant of some sort. This
|
||||
** can be a numeric constant, a constant address or a stack variable address.
|
||||
*/
|
||||
{
|
||||
return (Expr->Flags & E_MASK_LOC) == E_LOC_NONE || ED_IsQuasiConstAddr (Expr);
|
||||
}
|
||||
|
||||
|
||||
|
||||
int ED_IsConstAddr (const ExprDesc* Expr)
|
||||
/* Return true if the expression denotes a constant address of some sort. This
|
||||
** can be the address of a global variable (maybe with offset) or similar.
|
||||
*/
|
||||
{
|
||||
return ED_IsAddrExpr (Expr) && ED_IsLocConst (Expr);
|
||||
}
|
||||
|
||||
|
||||
|
||||
int ED_IsQuasiConstAddr (const ExprDesc* Expr)
|
||||
/* Return true if the expression denotes a quasi-constant address of some sort.
|
||||
** This can be a constant address or a stack variable address.
|
||||
*/
|
||||
{
|
||||
return ED_IsAddrExpr (Expr) && ED_IsLocQuasiConst (Expr);
|
||||
}
|
||||
|
||||
|
||||
|
||||
int ED_IsNullPtr (const ExprDesc* Expr)
|
||||
/* Return true if the given expression is a NULL pointer constant */
|
||||
{
|
||||
return (Expr->Flags & (E_MASK_LOC|E_MASK_RTYPE)) ==
|
||||
(E_LOC_NONE|E_RTYPE_RVAL) &&
|
||||
Expr->IVal == 0 &&
|
||||
IsClassInt (Expr->Type);
|
||||
}
|
||||
|
||||
|
||||
|
||||
int ED_IsBool (const ExprDesc* Expr)
|
||||
/* Return true if the expression can be treated as a boolean, that is, it can
|
||||
** be an operand to a compare operation.
|
||||
*/
|
||||
{
|
||||
/* Either ints, floats, or pointers can be used in a boolean context */
|
||||
return IsClassInt (Expr->Type) ||
|
||||
IsClassFloat (Expr->Type) ||
|
||||
IsClassPtr (Expr->Type) ||
|
||||
IsClassFunc (Expr->Type);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Manipulation */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
ExprDesc* ED_MakeConstAbs (ExprDesc* Expr, long Value, const Type* Type)
|
||||
/* Replace Expr with an absolute const with the given value and type */
|
||||
{
|
||||
|
@ -331,7 +449,7 @@ ExprDesc* ED_IndExpr (ExprDesc* Expr)
|
|||
** original address. We simply mark this as E_LOC_EXPR so that
|
||||
** some info about the original location can be retained.
|
||||
** If it's really meant to dereference a "pointer value", it
|
||||
** should be done in two steps where the pointervalue should
|
||||
** should be done in two steps where the pointer value should
|
||||
** be the manually loaded first before a call into this, and
|
||||
** the offset should be manually cleared somewhere outside.
|
||||
*/
|
||||
|
@ -345,131 +463,27 @@ ExprDesc* ED_IndExpr (ExprDesc* Expr)
|
|||
|
||||
|
||||
|
||||
#if !defined(HAVE_INLINE)
|
||||
int ED_IsAbs (const ExprDesc* Expr)
|
||||
/* Return true if the expression denotes a numeric value or address. */
|
||||
void ED_MarkForUneval (ExprDesc* Expr)
|
||||
/* Mark the expression as not to be evaluated */
|
||||
{
|
||||
return (Expr->Flags & (E_MASK_LOC)) == (E_LOC_NONE) ||
|
||||
(Expr->Flags & (E_MASK_LOC|E_ADDRESS_OF)) == (E_LOC_ABS|E_ADDRESS_OF);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#if !defined(HAVE_INLINE)
|
||||
int ED_IsConstAbs (const ExprDesc* Expr)
|
||||
/* Return true if the expression denotes a constant absolute value. This can be
|
||||
** a numeric constant, cast to any type.
|
||||
*/
|
||||
{
|
||||
return ED_IsRVal (Expr) && ED_IsAbs (Expr);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
int ED_IsConstAbsInt (const ExprDesc* Expr)
|
||||
/* Return true if the expression is a constant (numeric) integer. */
|
||||
{
|
||||
return ED_IsConstAbs (Expr) && IsClassInt (Expr->Type);
|
||||
Expr->Flags = (Expr->Flags & ~E_MASK_EVAL) | E_EVAL_UNEVAL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int ED_IsConstBool (const ExprDesc* Expr)
|
||||
/* Return true if the expression can be constantly evaluated as a boolean. */
|
||||
const Type* ReplaceType (ExprDesc* Expr, const Type* NewType)
|
||||
/* Replace the type of Expr by a copy of Newtype and return the old type string */
|
||||
{
|
||||
return ED_IsConstAbsInt (Expr) || ED_IsAddrExpr (Expr);
|
||||
const Type* OldType = Expr->Type;
|
||||
Expr->Type = TypeDup (NewType);
|
||||
return OldType;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int ED_IsConstTrue (const ExprDesc* Expr)
|
||||
/* Return true if the constant expression can be evaluated as boolean true at
|
||||
** compile time.
|
||||
*/
|
||||
{
|
||||
/* Non-zero arithmetics and objects addresses are boolean true */
|
||||
return (ED_IsConstAbsInt (Expr) && Expr->IVal != 0) ||
|
||||
(ED_IsAddrExpr (Expr));
|
||||
}
|
||||
|
||||
|
||||
|
||||
int ED_IsConstFalse (const ExprDesc* Expr)
|
||||
/* Return true if the constant expression can be evaluated as boolean false at
|
||||
** compile time.
|
||||
*/
|
||||
{
|
||||
/* Zero arithmetics and null pointers are boolean false */
|
||||
return (ED_IsConstAbsInt (Expr) && Expr->IVal == 0) ||
|
||||
ED_IsNullPtr (Expr);
|
||||
}
|
||||
|
||||
|
||||
|
||||
int ED_IsConst (const ExprDesc* Expr)
|
||||
/* Return true if the expression denotes a constant of some sort. This can be a
|
||||
** numeric constant, the address of a global variable (maybe with offset) or
|
||||
** similar.
|
||||
*/
|
||||
{
|
||||
return (Expr->Flags & E_MASK_LOC) == E_LOC_NONE || ED_IsConstAddr (Expr);
|
||||
}
|
||||
|
||||
|
||||
|
||||
int ED_IsQuasiConst (const ExprDesc* Expr)
|
||||
/* Return true if the expression denotes a quasi-constant of some sort. This
|
||||
** can be a numeric constant, a constant address or a stack variable address.
|
||||
*/
|
||||
{
|
||||
return (Expr->Flags & E_MASK_LOC) == E_LOC_NONE || ED_IsQuasiConstAddr (Expr);
|
||||
}
|
||||
|
||||
|
||||
int ED_IsConstAddr (const ExprDesc* Expr)
|
||||
/* Return true if the expression denotes a constant address of some sort. This
|
||||
** can be the address of a global variable (maybe with offset) or similar.
|
||||
*/
|
||||
{
|
||||
return ED_IsAddrExpr (Expr) && ED_IsLocConst (Expr);
|
||||
}
|
||||
|
||||
|
||||
|
||||
int ED_IsQuasiConstAddr (const ExprDesc* Expr)
|
||||
/* Return true if the expression denotes a quasi-constant address of some sort.
|
||||
** This can be a constant address or a stack variable address.
|
||||
*/
|
||||
{
|
||||
return ED_IsAddrExpr (Expr) && ED_IsLocQuasiConst (Expr);
|
||||
}
|
||||
|
||||
|
||||
|
||||
int ED_IsNullPtr (const ExprDesc* Expr)
|
||||
/* Return true if the given expression is a NULL pointer constant */
|
||||
{
|
||||
return (Expr->Flags & (E_MASK_LOC|E_MASK_RTYPE)) ==
|
||||
(E_LOC_NONE|E_RTYPE_RVAL) &&
|
||||
Expr->IVal == 0 &&
|
||||
IsClassInt (Expr->Type);
|
||||
}
|
||||
|
||||
|
||||
|
||||
int ED_IsBool (const ExprDesc* Expr)
|
||||
/* Return true if the expression can be treated as a boolean, that is, it can
|
||||
** be an operand to a compare operation.
|
||||
*/
|
||||
{
|
||||
/* Either ints, floats, or pointers can be used in a boolean context */
|
||||
return IsClassInt (Expr->Type) ||
|
||||
IsClassFloat (Expr->Type) ||
|
||||
IsClassPtr (Expr->Type) ||
|
||||
IsClassFunc (Expr->Type);
|
||||
}
|
||||
/*****************************************************************************/
|
||||
/* Other Helpers */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
|
@ -577,10 +591,21 @@ void PrintExprDesc (FILE* F, ExprDesc* E)
|
|||
|
||||
|
||||
|
||||
const Type* ReplaceType (ExprDesc* Expr, const Type* NewType)
|
||||
/* Replace the type of Expr by a copy of Newtype and return the old type string */
|
||||
void ED_SetCodeRange (ExprDesc* Expr, const CodeMark* Start, const CodeMark* End)
|
||||
/* Set the code range for this expression */
|
||||
{
|
||||
const Type* OldType = Expr->Type;
|
||||
Expr->Type = TypeDup (NewType);
|
||||
return OldType;
|
||||
Expr->Flags |= E_HAVE_MARKS;
|
||||
Expr->Start = *Start;
|
||||
Expr->End = *End;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int ED_CodeRangeIsEmpty (const ExprDesc* Expr)
|
||||
/* Return true if no code was output for this expression */
|
||||
{
|
||||
/* We must have code marks */
|
||||
PRECONDITION (Expr->Flags & E_HAVE_MARKS);
|
||||
|
||||
return CodeRangeIsEmpty (&Expr->Start, &Expr->End);
|
||||
}
|
||||
|
|
|
@ -227,6 +227,14 @@ struct ExprDesc {
|
|||
ExprDesc* ED_Init (ExprDesc* Expr);
|
||||
/* Initialize an ExprDesc */
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Info Extraction */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
#if defined(HAVE_INLINE)
|
||||
INLINE int ED_GetLoc (const ExprDesc* Expr)
|
||||
/* Return the location flags from the expression */
|
||||
|
@ -237,6 +245,35 @@ INLINE int ED_GetLoc (const ExprDesc* Expr)
|
|||
# define ED_GetLoc(Expr) ((Expr)->Flags & E_MASK_LOC)
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_INLINE)
|
||||
INLINE int ED_GetNeeds (const ExprDesc* Expr)
|
||||
/* Get flags about what the expression needs. */
|
||||
{
|
||||
return (Expr->Flags & E_MASK_NEED);
|
||||
}
|
||||
#else
|
||||
# define ED_GetNeeds(Expr) ((Expr)->Flags & E_MASK_NEED)
|
||||
#endif
|
||||
|
||||
const char* ED_GetLabelName (const ExprDesc* Expr, long Offs);
|
||||
/* Return the assembler label name of the given expression. Beware: This
|
||||
** function may use a static buffer, so the name may get "lost" on the second
|
||||
** call to the function.
|
||||
*/
|
||||
|
||||
int ED_GetStackOffs (const ExprDesc* Expr, int Offs);
|
||||
/* Get the stack offset of an address on the stack in Expr taking into account
|
||||
** an additional offset in Offs.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Predicates */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
#if defined(HAVE_INLINE)
|
||||
INLINE int ED_IsLocNone (const ExprDesc* Expr)
|
||||
/* Return true if the expression is an absolute value */
|
||||
|
@ -279,7 +316,7 @@ INLINE int ED_IsLocStack (const ExprDesc* Expr)
|
|||
|
||||
#if defined(HAVE_INLINE)
|
||||
INLINE int ED_IsLocPrimary (const ExprDesc* Expr)
|
||||
/* Return true if the expression is an expression in the register pseudo variable */
|
||||
/* Return true if the expression is an expression in the primary */
|
||||
{
|
||||
return (Expr->Flags & E_MASK_LOC) == E_LOC_PRIMARY;
|
||||
}
|
||||
|
@ -289,7 +326,7 @@ INLINE int ED_IsLocPrimary (const ExprDesc* Expr)
|
|||
|
||||
#if defined(HAVE_INLINE)
|
||||
INLINE int ED_IsLocExpr (const ExprDesc* Expr)
|
||||
/* Return true if the expression is an expression in the primary */
|
||||
/* Return true if the expression is an expression referenced in the primary */
|
||||
{
|
||||
return (Expr->Flags & E_MASK_LOC) == E_LOC_EXPR;
|
||||
}
|
||||
|
@ -333,33 +370,14 @@ int ED_IsLocQuasiConst (const ExprDesc* Expr);
|
|||
#endif
|
||||
|
||||
#if defined(HAVE_INLINE)
|
||||
INLINE void ED_RequireTest (ExprDesc* Expr)
|
||||
/* Mark the expression for a test. */
|
||||
INLINE int ED_IsLocPrimaryOrExpr (const ExprDesc* Expr)
|
||||
/* Return true if the expression is E_LOC_PRIMARY or E_LOC_EXPR */
|
||||
{
|
||||
Expr->Flags |= E_NEED_TEST;
|
||||
return ED_IsLocPrimary (Expr) || ED_IsLocExpr (Expr);
|
||||
}
|
||||
#else
|
||||
# define ED_RequireTest(Expr) do { (Expr)->Flags |= E_NEED_TEST; } while (0)
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_INLINE)
|
||||
INLINE void ED_RequireNoTest (ExprDesc* Expr)
|
||||
/* Mark the expression not for a test. */
|
||||
{
|
||||
Expr->Flags &= ~E_NEED_TEST;
|
||||
}
|
||||
#else
|
||||
# define ED_RequireNoTest(Expr) do { (Expr)->Flags &= ~E_NEED_TEST; } while (0)
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_INLINE)
|
||||
INLINE int ED_GetNeeds (const ExprDesc* Expr)
|
||||
/* Get flags about what the expression needs. */
|
||||
{
|
||||
return (Expr->Flags & E_MASK_NEED);
|
||||
}
|
||||
#else
|
||||
# define ED_GetNeeds(Expr) ((Expr)->Flags & E_MASK_NEED)
|
||||
int ED_IsLocPrimaryOrExpr (const ExprDesc* Expr);
|
||||
/* Return true if the expression is E_LOC_PRIMARY or E_LOC_EXPR */
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_INLINE)
|
||||
|
@ -382,27 +400,6 @@ INLINE int ED_NeedsTest (const ExprDesc* Expr)
|
|||
# define ED_NeedsTest(Expr) (((Expr)->Flags & E_NEED_TEST) != 0)
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_INLINE)
|
||||
INLINE int ED_YetToTest (const ExprDesc* Expr)
|
||||
/* Check if the expression needs to be tested but not yet. */
|
||||
{
|
||||
return ((Expr)->Flags & (E_NEED_TEST | E_CC_SET)) == E_NEED_TEST;
|
||||
}
|
||||
#else
|
||||
# define ED_YetToTest(Expr) (((Expr)->Flags & (E_NEED_TEST | E_CC_SET)) == E_NEED_TEST)
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_INLINE)
|
||||
INLINE void ED_TestDone (ExprDesc* Expr)
|
||||
/* Mark the expression as tested and condition codes set. */
|
||||
{
|
||||
Expr->Flags |= E_CC_SET;
|
||||
}
|
||||
#else
|
||||
# define ED_TestDone(Expr) \
|
||||
do { (Expr)->Flags |= E_CC_SET; } while (0)
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_INLINE)
|
||||
INLINE int ED_IsTested (const ExprDesc* Expr)
|
||||
/* Check if the expression has set the condition codes. */
|
||||
|
@ -414,13 +411,13 @@ INLINE int ED_IsTested (const ExprDesc* Expr)
|
|||
#endif
|
||||
|
||||
#if defined(HAVE_INLINE)
|
||||
INLINE void ED_MarkAsUntested (ExprDesc* Expr)
|
||||
/* Mark the expression as not tested (condition codes not set). */
|
||||
INLINE int ED_YetToTest (const ExprDesc* Expr)
|
||||
/* Check if the expression needs to be tested but not yet. */
|
||||
{
|
||||
Expr->Flags &= ~E_CC_SET;
|
||||
return ((Expr)->Flags & (E_NEED_TEST | E_CC_SET)) == E_NEED_TEST;
|
||||
}
|
||||
#else
|
||||
# define ED_MarkAsUntested(Expr) do { (Expr)->Flags &= ~E_CC_SET; } while (0)
|
||||
# define ED_YetToTest(Expr) (((Expr)->Flags & (E_NEED_TEST | E_CC_SET)) == E_NEED_TEST)
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_INLINE)
|
||||
|
@ -448,9 +445,6 @@ INLINE int ED_NeedsConst (const ExprDesc* Expr)
|
|||
# define ED_NeedsConst(Expr) (((Expr)->Flags & E_EVAL_IMMUTABLE_RESULT) == E_EVAL_IMMUTABLE_RESULT)
|
||||
#endif
|
||||
|
||||
void ED_MarkForUneval (ExprDesc* Expr);
|
||||
/* Mark the expression as not to be evaluated */
|
||||
|
||||
#if defined(HAVE_INLINE)
|
||||
INLINE int ED_IsUneval (const ExprDesc* Expr)
|
||||
/* Check if the expression is not to be evaluated */
|
||||
|
@ -471,27 +465,6 @@ 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 */
|
||||
{
|
||||
return ED_IsLocPrimary (Expr) || ED_IsLocExpr (Expr);
|
||||
}
|
||||
#else
|
||||
int ED_IsLocPrimaryOrExpr (const ExprDesc* Expr);
|
||||
/* Return true if the expression is E_LOC_PRIMARY or E_LOC_EXPR */
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_INLINE)
|
||||
INLINE int ED_IsAddrExpr (const ExprDesc* Expr)
|
||||
/* Check if the expression is taken address of instead of its value.
|
||||
|
@ -515,35 +488,6 @@ int ED_IsIndExpr (const ExprDesc* Expr);
|
|||
/* Check if the expression is a reference to its value */
|
||||
#endif
|
||||
|
||||
void ED_SetCodeRange (ExprDesc* Expr, const CodeMark* Start, const CodeMark* End);
|
||||
/* Set the code range for this expression */
|
||||
|
||||
int ED_CodeRangeIsEmpty (const ExprDesc* Expr);
|
||||
/* Return true if no code was output for this expression */
|
||||
|
||||
const char* ED_GetLabelName (const ExprDesc* Expr, long Offs);
|
||||
/* Return the assembler label name of the given expression. Beware: This
|
||||
** function may use a static buffer, so the name may get "lost" on the second
|
||||
** call to the function.
|
||||
*/
|
||||
|
||||
int ED_GetStackOffs (const ExprDesc* Expr, int Offs);
|
||||
/* Get the stack offset of an address on the stack in Expr taking into account
|
||||
** an additional offset in Offs.
|
||||
*/
|
||||
|
||||
ExprDesc* ED_MakeConstAbs (ExprDesc* Expr, long Value, const Type* Type);
|
||||
/* Replace Expr with an absolute const with the given value and type */
|
||||
|
||||
ExprDesc* ED_MakeConstAbsInt (ExprDesc* Expr, long Value);
|
||||
/* Replace Expr with an constant integer with the given value */
|
||||
|
||||
ExprDesc* ED_MakeConstBool (ExprDesc* Expr, long Value);
|
||||
/* Replace Expr with a constant boolean expression with the given value */
|
||||
|
||||
ExprDesc* ED_FinalizeRValLoad (ExprDesc* Expr);
|
||||
/* Finalize the result of LoadExpr to be an rvalue in the primary register */
|
||||
|
||||
#if defined(HAVE_INLINE)
|
||||
INLINE int ED_IsLVal (const ExprDesc* Expr)
|
||||
/* Return true if the expression is a reference */
|
||||
|
@ -564,40 +508,6 @@ INLINE int ED_IsRVal (const ExprDesc* Expr)
|
|||
# define ED_IsRVal(Expr) (((Expr)->Flags & E_MASK_RTYPE) == E_RTYPE_RVAL)
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_INLINE)
|
||||
INLINE void ED_MarkExprAsLVal (ExprDesc* Expr)
|
||||
/* Mark the expression as an lvalue.
|
||||
** HINT: Consider using ED_IndExpr instead of this, unless you know what
|
||||
** consequence there will be, as there are both a big part in the code
|
||||
** assuming rvalue = const and a big part assuming rvalue = address.
|
||||
*/
|
||||
{
|
||||
Expr->Flags |= E_RTYPE_LVAL;
|
||||
}
|
||||
#else
|
||||
# define ED_MarkExprAsLVal(Expr) do { (Expr)->Flags |= E_RTYPE_LVAL; } while (0)
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_INLINE)
|
||||
INLINE void ED_MarkExprAsRVal (ExprDesc* Expr)
|
||||
/* Mark the expression as an rvalue.
|
||||
** HINT: Consider using ED_AddrExpr instead of this, unless you know what
|
||||
** consequence there will be, as there are both a big part in the code
|
||||
** assuming rvalue = const and a big part assuming rvalue = address.
|
||||
*/
|
||||
{
|
||||
Expr->Flags &= ~E_RTYPE_LVAL;
|
||||
}
|
||||
#else
|
||||
# define ED_MarkExprAsRVal(Expr) do { (Expr)->Flags &= ~E_RTYPE_LVAL; } while (0)
|
||||
#endif
|
||||
|
||||
ExprDesc* ED_AddrExpr (ExprDesc* Expr);
|
||||
/* Take address of Expr */
|
||||
|
||||
ExprDesc* ED_IndExpr (ExprDesc* Expr);
|
||||
/* Dereference Expr */
|
||||
|
||||
#if defined(HAVE_INLINE)
|
||||
INLINE int ED_IsAbs (const ExprDesc* Expr)
|
||||
/* Return true if the expression denotes a numeric value or address. */
|
||||
|
@ -670,14 +580,136 @@ int ED_IsBool (const ExprDesc* Expr);
|
|||
** be an operand to a compare operation with 0/NULL.
|
||||
*/
|
||||
|
||||
void PrintExprDesc (FILE* F, ExprDesc* Expr);
|
||||
/* Print an ExprDesc */
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Manipulation */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
ExprDesc* ED_MakeConstAbs (ExprDesc* Expr, long Value, const Type* Type);
|
||||
/* Replace Expr with an absolute const with the given value and type */
|
||||
|
||||
ExprDesc* ED_MakeConstAbsInt (ExprDesc* Expr, long Value);
|
||||
/* Replace Expr with an constant integer with the given value */
|
||||
|
||||
ExprDesc* ED_MakeConstBool (ExprDesc* Expr, long Value);
|
||||
/* Replace Expr with a constant boolean expression with the given value */
|
||||
|
||||
ExprDesc* ED_FinalizeRValLoad (ExprDesc* Expr);
|
||||
/* Finalize the result of LoadExpr to be an rvalue in the primary register */
|
||||
|
||||
#if defined(HAVE_INLINE)
|
||||
INLINE void ED_MarkExprAsLVal (ExprDesc* Expr)
|
||||
/* Mark the expression as an lvalue.
|
||||
** HINT: Consider using ED_IndExpr instead of this, unless you know what
|
||||
** consequence there will be, as there are both a big part in the code
|
||||
** assuming rvalue = const and a big part assuming rvalue = address.
|
||||
*/
|
||||
{
|
||||
Expr->Flags |= E_RTYPE_LVAL;
|
||||
}
|
||||
#else
|
||||
# define ED_MarkExprAsLVal(Expr) do { (Expr)->Flags |= E_RTYPE_LVAL; } while (0)
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_INLINE)
|
||||
INLINE void ED_MarkExprAsRVal (ExprDesc* Expr)
|
||||
/* Mark the expression as an rvalue.
|
||||
** HINT: Consider using ED_AddrExpr instead of this, unless you know what
|
||||
** consequence there will be, as there are both a big part in the code
|
||||
** assuming rvalue = const and a big part assuming rvalue = address.
|
||||
*/
|
||||
{
|
||||
Expr->Flags &= ~E_RTYPE_LVAL;
|
||||
}
|
||||
#else
|
||||
# define ED_MarkExprAsRVal(Expr) do { (Expr)->Flags &= ~E_RTYPE_LVAL; } while (0)
|
||||
#endif
|
||||
|
||||
ExprDesc* ED_AddrExpr (ExprDesc* Expr);
|
||||
/* Take address of Expr */
|
||||
|
||||
ExprDesc* ED_IndExpr (ExprDesc* Expr);
|
||||
/* Dereference Expr */
|
||||
|
||||
#if defined(HAVE_INLINE)
|
||||
INLINE void ED_RequireTest (ExprDesc* Expr)
|
||||
/* Mark the expression for a test. */
|
||||
{
|
||||
Expr->Flags |= E_NEED_TEST;
|
||||
}
|
||||
#else
|
||||
# define ED_RequireTest(Expr) do { (Expr)->Flags |= E_NEED_TEST; } while (0)
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_INLINE)
|
||||
INLINE void ED_RequireNoTest (ExprDesc* Expr)
|
||||
/* Mark the expression not for a test. */
|
||||
{
|
||||
Expr->Flags &= ~E_NEED_TEST;
|
||||
}
|
||||
#else
|
||||
# define ED_RequireNoTest(Expr) do { (Expr)->Flags &= ~E_NEED_TEST; } while (0)
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_INLINE)
|
||||
INLINE void ED_TestDone (ExprDesc* Expr)
|
||||
/* Mark the expression as tested and condition codes set. */
|
||||
{
|
||||
Expr->Flags |= E_CC_SET;
|
||||
}
|
||||
#else
|
||||
# define ED_TestDone(Expr) \
|
||||
do { (Expr)->Flags |= E_CC_SET; } while (0)
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_INLINE)
|
||||
INLINE void ED_MarkAsUntested (ExprDesc* Expr)
|
||||
/* Mark the expression as not tested (condition codes not set). */
|
||||
{
|
||||
Expr->Flags &= ~E_CC_SET;
|
||||
}
|
||||
#else
|
||||
# define ED_MarkAsUntested(Expr) do { (Expr)->Flags &= ~E_CC_SET; } while (0)
|
||||
#endif
|
||||
|
||||
void ED_MarkForUneval (ExprDesc* Expr);
|
||||
/* Mark the expression as not to be evaluated */
|
||||
|
||||
#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
|
||||
|
||||
const Type* ReplaceType (ExprDesc* Expr, const Type* NewType);
|
||||
/* Replace the type of Expr by a copy of Newtype and return the old type string */
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Other Helpers */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
void PrintExprDesc (FILE* F, ExprDesc* Expr);
|
||||
/* Print an ExprDesc */
|
||||
|
||||
void ED_SetCodeRange (ExprDesc* Expr, const CodeMark* Start, const CodeMark* End);
|
||||
/* Set the code range for this expression */
|
||||
|
||||
int ED_CodeRangeIsEmpty (const ExprDesc* Expr);
|
||||
/* Return true if no code was output for this expression */
|
||||
|
||||
|
||||
|
||||
/* End of exprdesc.h */
|
||||
|
||||
#endif
|
||||
|
|
|
@ -613,7 +613,7 @@ void NewFunc (SymEntry* Func, FuncDesc* D)
|
|||
/* Could we allocate a register? */
|
||||
if (Reg < 0) {
|
||||
/* No register available: Convert parameter to auto */
|
||||
CvtRegVarToAuto (Param);
|
||||
SymCvtRegVarToAuto (Param);
|
||||
} else {
|
||||
/* Remember the register offset */
|
||||
Param->V.R.RegOffs = Reg;
|
||||
|
|
|
@ -49,6 +49,7 @@ unsigned char DebugInfo = 0; /* Add debug info to the obj */
|
|||
unsigned char PreprocessOnly = 0; /* Just preprocess the input */
|
||||
unsigned char DebugOptOutput = 0; /* Output debug stuff */
|
||||
unsigned RegisterSpace = 6; /* Space available for register vars */
|
||||
unsigned AllowNewComments = 0; /* Allow new style comments in C89 mode */
|
||||
|
||||
/* Stackable options */
|
||||
IntStack WritableStrings = INTSTACK(0); /* Literal strings are r/w */
|
||||
|
|
|
@ -57,6 +57,7 @@ extern unsigned char DebugInfo; /* Add debug info to the obj */
|
|||
extern unsigned char PreprocessOnly; /* Just preprocess the input */
|
||||
extern unsigned char DebugOptOutput; /* Output debug stuff */
|
||||
extern unsigned RegisterSpace; /* Space available for register vars */
|
||||
extern unsigned AllowNewComments; /* Allow new style comments in C89 mode */
|
||||
|
||||
/* Stackable options */
|
||||
extern IntStack WritableStrings; /* Literal strings are r/w */
|
||||
|
|
|
@ -459,7 +459,7 @@ static unsigned ParseArrayInit (Type* T, int* Braces, int AllowFlexibleMembers)
|
|||
static unsigned ParseStructInit (Type* T, int* Braces, int AllowFlexibleMembers)
|
||||
/* Parse initialization of a struct or union. Return the number of data bytes. */
|
||||
{
|
||||
SymEntry* Sym;
|
||||
SymEntry* TagSym;
|
||||
SymTable* Tab;
|
||||
StructInitData SI;
|
||||
int HasCurly = 0;
|
||||
|
@ -474,15 +474,15 @@ static unsigned ParseStructInit (Type* T, int* Braces, int AllowFlexibleMembers)
|
|||
}
|
||||
|
||||
/* Get a pointer to the struct entry from the type */
|
||||
Sym = GetESUSymEntry (T);
|
||||
TagSym = GetESUTagSym (T);
|
||||
|
||||
/* Get the size of the struct from the symbol table entry */
|
||||
SI.Size = Sym->V.S.Size;
|
||||
SI.Size = TagSym->V.S.Size;
|
||||
|
||||
/* Check if this struct definition has a field table. If it doesn't, it
|
||||
** is an incomplete definition.
|
||||
*/
|
||||
Tab = Sym->V.S.SymTab;
|
||||
Tab = TagSym->V.S.SymTab;
|
||||
if (Tab == 0) {
|
||||
Error ("Cannot initialize variables with incomplete type");
|
||||
/* Try error recovery */
|
||||
|
@ -492,7 +492,7 @@ static unsigned ParseStructInit (Type* T, int* Braces, int AllowFlexibleMembers)
|
|||
}
|
||||
|
||||
/* Get a pointer to the list of symbols */
|
||||
Sym = Tab->SymHead;
|
||||
TagSym = Tab->SymHead;
|
||||
|
||||
/* Initialize fields */
|
||||
SI.Offs = 0;
|
||||
|
@ -501,7 +501,7 @@ static unsigned ParseStructInit (Type* T, int* Braces, int AllowFlexibleMembers)
|
|||
while (CurTok.Tok != TOK_RCURLY) {
|
||||
|
||||
/* Check for excess elements */
|
||||
if (Sym == 0) {
|
||||
if (TagSym == 0) {
|
||||
/* Is there just one trailing comma before a closing curly? */
|
||||
if (NextTok.Tok == TOK_RCURLY && CurTok.Tok == TOK_COMMA) {
|
||||
/* Skip comma and exit scope */
|
||||
|
@ -517,7 +517,7 @@ static unsigned ParseStructInit (Type* T, int* Braces, int AllowFlexibleMembers)
|
|||
}
|
||||
|
||||
/* Check for special members that don't consume the initializer */
|
||||
if ((Sym->Flags & SC_ALIAS) == SC_ALIAS) {
|
||||
if ((TagSym->Flags & SC_ALIAS) == SC_ALIAS) {
|
||||
/* Just skip */
|
||||
goto NextMember;
|
||||
}
|
||||
|
@ -525,13 +525,13 @@ static unsigned ParseStructInit (Type* T, int* Braces, int AllowFlexibleMembers)
|
|||
/* This may be an anonymous bit-field, in which case it doesn't
|
||||
** have an initializer.
|
||||
*/
|
||||
if (SymIsBitField (Sym) && (IsAnonName (Sym->Name))) {
|
||||
if (SymIsBitField (TagSym) && (IsAnonName (TagSym->Name))) {
|
||||
/* Account for the data and output it if we have at least a full
|
||||
** byte. We may have more if there was storage unit overlap, for
|
||||
** example two consecutive 7 bit fields. Those would be packed
|
||||
** into 2 bytes.
|
||||
*/
|
||||
SI.ValBits += Sym->Type->A.B.Width;
|
||||
SI.ValBits += TagSym->Type->A.B.Width;
|
||||
CHECK (SI.ValBits <= CHAR_BIT * sizeof(SI.BitVal));
|
||||
/* TODO: Generalize this so any type can be used. */
|
||||
CHECK (SI.ValBits <= LONG_BITS);
|
||||
|
@ -548,7 +548,7 @@ static unsigned ParseStructInit (Type* T, int* Braces, int AllowFlexibleMembers)
|
|||
SkipComma = 0;
|
||||
}
|
||||
|
||||
if (SymIsBitField (Sym)) {
|
||||
if (SymIsBitField (TagSym)) {
|
||||
|
||||
/* Parse initialization of one field. Bit-fields need a special
|
||||
** handling.
|
||||
|
@ -559,14 +559,14 @@ static unsigned ParseStructInit (Type* T, int* Braces, int AllowFlexibleMembers)
|
|||
unsigned Shift;
|
||||
|
||||
/* Calculate the bitmask from the bit-field data */
|
||||
unsigned long Mask = shl_l (1UL, Sym->Type->A.B.Width) - 1UL;
|
||||
unsigned long Mask = shl_l (1UL, TagSym->Type->A.B.Width) - 1UL;
|
||||
|
||||
/* Safety ... */
|
||||
CHECK (Sym->V.Offs * CHAR_BITS + Sym->Type->A.B.Offs ==
|
||||
CHECK (TagSym->V.Offs * CHAR_BITS + TagSym->Type->A.B.Offs ==
|
||||
SI.Offs * CHAR_BITS + SI.ValBits);
|
||||
|
||||
/* Read the data, check for a constant integer, do a range check */
|
||||
Field = ParseScalarInitInternal (IntPromotion (Sym->Type));
|
||||
Field = ParseScalarInitInternal (IntPromotion (TagSym->Type));
|
||||
if (!ED_IsConstAbsInt (&Field)) {
|
||||
Error ("Constant initializer expected");
|
||||
ED_MakeConstAbsInt (&Field, 1);
|
||||
|
@ -576,19 +576,19 @@ static unsigned ParseStructInit (Type* T, int* Braces, int AllowFlexibleMembers)
|
|||
** any useful bits.
|
||||
*/
|
||||
Val = (unsigned long) Field.IVal & Mask;
|
||||
if (IsSignUnsigned (Sym->Type)) {
|
||||
if (IsSignUnsigned (TagSym->Type)) {
|
||||
if (Field.IVal < 0 || (unsigned long) Field.IVal != Val) {
|
||||
Warning (IsSignUnsigned (Field.Type) ?
|
||||
"Implicit truncation from '%s' to '%s : %u' in bit-field initializer"
|
||||
" changes value from %lu to %lu" :
|
||||
"Implicit truncation from '%s' to '%s : %u' in bit-field initializer"
|
||||
" changes value from %ld to %lu",
|
||||
GetFullTypeName (Field.Type), GetFullTypeName (Sym->Type),
|
||||
Sym->Type->A.B.Width, Field.IVal, Val);
|
||||
GetFullTypeName (Field.Type), GetFullTypeName (TagSym->Type),
|
||||
TagSym->Type->A.B.Width, Field.IVal, Val);
|
||||
}
|
||||
} else {
|
||||
/* Sign extend back to full width of host long. */
|
||||
unsigned ShiftBits = sizeof (long) * CHAR_BIT - Sym->Type->A.B.Width;
|
||||
unsigned ShiftBits = sizeof (long) * CHAR_BIT - TagSym->Type->A.B.Width;
|
||||
long RestoredVal = asr_l (asl_l (Val, ShiftBits), ShiftBits);
|
||||
if (Field.IVal != RestoredVal) {
|
||||
Warning (IsSignUnsigned (Field.Type) ?
|
||||
|
@ -596,17 +596,17 @@ static unsigned ParseStructInit (Type* T, int* Braces, int AllowFlexibleMembers)
|
|||
" changes value from %lu to %ld" :
|
||||
"Implicit truncation from '%s' to '%s : %u' in bit-field initializer"
|
||||
" changes value from %ld to %ld",
|
||||
GetFullTypeName (Field.Type), GetFullTypeName (Sym->Type),
|
||||
Sym->Type->A.B.Width, Field.IVal, RestoredVal);
|
||||
GetFullTypeName (Field.Type), GetFullTypeName (TagSym->Type),
|
||||
TagSym->Type->A.B.Width, Field.IVal, RestoredVal);
|
||||
}
|
||||
}
|
||||
|
||||
/* Add the value to the currently stored bit-field value */
|
||||
Shift = (Sym->V.Offs - SI.Offs) * CHAR_BITS + Sym->Type->A.B.Offs;
|
||||
Shift = (TagSym->V.Offs - SI.Offs) * CHAR_BITS + TagSym->Type->A.B.Offs;
|
||||
SI.BitVal |= (Val << Shift);
|
||||
|
||||
/* Account for the data and output any full bytes we have. */
|
||||
SI.ValBits += Sym->Type->A.B.Width;
|
||||
SI.ValBits += TagSym->Type->A.B.Width;
|
||||
/* Make sure unsigned is big enough to hold the value, 32 bits.
|
||||
** This cannot be more than 32 bits because a 16-bit or 32-bit
|
||||
** bit-field will always be byte-aligned with padding before it
|
||||
|
@ -631,7 +631,7 @@ static unsigned ParseStructInit (Type* T, int* Braces, int AllowFlexibleMembers)
|
|||
/* Flexible array members may only be initialized if they are
|
||||
** the last field (or part of the last struct field).
|
||||
*/
|
||||
SI.Offs += ParseInitInternal (Sym->Type, Braces, AllowFlexibleMembers && Sym->NextSym == 0);
|
||||
SI.Offs += ParseInitInternal (TagSym->Type, Braces, AllowFlexibleMembers && TagSym->NextSym == 0);
|
||||
}
|
||||
|
||||
/* More initializers? */
|
||||
|
@ -646,10 +646,10 @@ NextMember:
|
|||
/* Next member. For unions, only the first one can be initialized */
|
||||
if (IsTypeUnion (T)) {
|
||||
/* Union */
|
||||
Sym = 0;
|
||||
TagSym = 0;
|
||||
} else {
|
||||
/* Struct */
|
||||
Sym = Sym->NextSym;
|
||||
TagSym = TagSym->NextSym;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
148
src/cc65/input.c
148
src/cc65/input.c
|
@ -67,6 +67,9 @@
|
|||
/* The current input line */
|
||||
StrBuf* Line;
|
||||
|
||||
/* The input line to reuse as the next line */
|
||||
static StrBuf* CurReusedLine;
|
||||
|
||||
/* Current and next input character */
|
||||
char CurC = '\0';
|
||||
char NextC = '\0';
|
||||
|
@ -103,8 +106,8 @@ static Collection IFiles = STATIC_COLLECTION_INITIALIZER;
|
|||
/* List of all active files */
|
||||
static Collection AFiles = STATIC_COLLECTION_INITIALIZER;
|
||||
|
||||
/* Input stack used when preprocessing. */
|
||||
static Collection InputStack = STATIC_COLLECTION_INITIALIZER;
|
||||
/* Input stack used when preprocessing */
|
||||
static Collection* CurrentInputStack;
|
||||
|
||||
/* Counter for the __COUNTER__ macro */
|
||||
static unsigned MainFileCounter;
|
||||
|
@ -394,34 +397,19 @@ static void GetInputChar (void)
|
|||
** are read by this function.
|
||||
*/
|
||||
{
|
||||
/* Drop all pushed fragments that don't have data left */
|
||||
while (SB_GetIndex (Line) >= SB_GetLen (Line)) {
|
||||
/* Cannot read more from this line, check next line on stack if any */
|
||||
if (CollCount (&InputStack) == 0) {
|
||||
/* This is THE line */
|
||||
break;
|
||||
}
|
||||
FreeStrBuf (Line);
|
||||
Line = CollPop (&InputStack);
|
||||
/* Get the next-next character from the line */
|
||||
if (SB_GetIndex (Line) + 1 < SB_GetLen (Line)) {
|
||||
/* CurC and NextC come from this fragment */
|
||||
CurC = SB_AtUnchecked (Line, SB_GetIndex (Line));
|
||||
NextC = SB_AtUnchecked (Line, SB_GetIndex (Line) + 1);
|
||||
} else {
|
||||
/* NextC is '\0' by default */
|
||||
NextC = '\0';
|
||||
|
||||
/* Get CurC from the line */
|
||||
CurC = SB_LookAt (Line, SB_GetIndex (Line));
|
||||
}
|
||||
|
||||
/* Now get the next characters from the line */
|
||||
if (SB_GetIndex (Line) >= SB_GetLen (Line)) {
|
||||
CurC = NextC = '\0';
|
||||
} else {
|
||||
CurC = SB_AtUnchecked (Line, SB_GetIndex (Line));
|
||||
if (SB_GetIndex (Line) + 1 < SB_GetLen (Line)) {
|
||||
/* NextC comes from this fragment */
|
||||
NextC = SB_AtUnchecked (Line, SB_GetIndex (Line) + 1);
|
||||
} else {
|
||||
/* NextC comes from next fragment */
|
||||
if (CollCount (&InputStack) > 0) {
|
||||
NextC = ' ';
|
||||
} else {
|
||||
NextC = '\0';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -441,17 +429,41 @@ void NextChar (void)
|
|||
|
||||
|
||||
|
||||
Collection* UseInputStack (Collection* InputStack)
|
||||
/* Use the provided input stack for incoming input. Return the previously used
|
||||
** InputStack.
|
||||
*/
|
||||
{
|
||||
Collection* OldInputStack = CurrentInputStack;
|
||||
|
||||
CurrentInputStack = InputStack;
|
||||
return OldInputStack;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void PushLine (StrBuf* L)
|
||||
/* Save the current input line and use a new one */
|
||||
{
|
||||
PRECONDITION (CurrentInputStack != 0);
|
||||
CollAppend (CurrentInputStack, Line);
|
||||
Line = L;
|
||||
GetInputChar ();
|
||||
}
|
||||
|
||||
|
||||
|
||||
void ReuseInputLine (void)
|
||||
/* Save and reuse the current line as the next line */
|
||||
{
|
||||
CurReusedLine = Line;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void ClearLine (void)
|
||||
/* Clear the current input line */
|
||||
{
|
||||
unsigned I;
|
||||
|
||||
/* Remove all pushed fragments from the input stack */
|
||||
for (I = 0; I < CollCount (&InputStack); ++I) {
|
||||
FreeStrBuf (CollAtUnchecked (&InputStack, I));
|
||||
}
|
||||
CollDeleteAll (&InputStack);
|
||||
|
||||
/* Clear the contents of Line */
|
||||
SB_Clear (Line);
|
||||
CurC = '\0';
|
||||
|
@ -482,12 +494,47 @@ int NextLine (void)
|
|||
int C;
|
||||
AFile* Input;
|
||||
|
||||
/* Clear the current line */
|
||||
ClearLine ();
|
||||
SB_Clear (Line);
|
||||
/* Overwrite the next input line with the pushed line if there is one */
|
||||
if (CurReusedLine != 0) {
|
||||
/* Use data move to resolve the issue that Line may be impersistent */
|
||||
if (Line != CurReusedLine) {
|
||||
SB_Move (Line, CurReusedLine);
|
||||
}
|
||||
/* Continue with this Line */
|
||||
InitLine (Line);
|
||||
CurReusedLine = 0;
|
||||
|
||||
/* Must have an input file when called */
|
||||
if (CollCount(&AFiles) == 0) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* If there are pushed input lines, read from them */
|
||||
if (CurrentInputStack != 0 && CollCount (CurrentInputStack) > 0) {
|
||||
/* Drop all pushed fragments that have no data left until one can be
|
||||
** used as input.
|
||||
*/
|
||||
do {
|
||||
/* Use data move to resolve the issue that Line may be impersistent */
|
||||
if (Line != CollLast (CurrentInputStack)) {
|
||||
SB_Move (Line, CollPop (CurrentInputStack));
|
||||
} else {
|
||||
CollPop (CurrentInputStack);
|
||||
}
|
||||
} while (CollCount (CurrentInputStack) > 0 &&
|
||||
SB_GetIndex (Line) >= SB_GetLen (Line));
|
||||
|
||||
if (SB_GetIndex (Line) < SB_GetLen (Line)) {
|
||||
InitLine (Line);
|
||||
|
||||
/* Successive */
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Otherwise, clear the current line */
|
||||
ClearLine ();
|
||||
|
||||
/* Must have an input file when going on */
|
||||
if (CollCount (&AFiles) == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -531,15 +578,16 @@ int NextLine (void)
|
|||
SB_Drop (Line, 1);
|
||||
}
|
||||
|
||||
/* If we don't have a line continuation character at the end,
|
||||
** we're done with this line. Otherwise replace the character
|
||||
** by a newline and continue reading.
|
||||
/* If we don't have a line continuation character at the end, we
|
||||
** are done with this line. Otherwise just skip the character and
|
||||
** continue reading.
|
||||
*/
|
||||
if (SB_LookAtLast (Line) == '\\') {
|
||||
Line->Buf[Line->Len-1] = '\n';
|
||||
} else {
|
||||
if (SB_LookAtLast (Line) != '\\') {
|
||||
Input->MissingNL = 0;
|
||||
break;
|
||||
} else {
|
||||
SB_Drop (Line, 1);
|
||||
ContinueLine ();
|
||||
}
|
||||
|
||||
} else if (C != '\0') { /* Ignore embedded NULs */
|
||||
|
@ -605,7 +653,7 @@ const char* GetInputFile (const struct IFile* IF)
|
|||
|
||||
|
||||
|
||||
const char* GetCurrentFile (void)
|
||||
const char* GetCurrentFilename (void)
|
||||
/* Return the name of the current input file */
|
||||
{
|
||||
unsigned AFileCount = CollCount (&AFiles);
|
||||
|
@ -620,7 +668,7 @@ const char* GetCurrentFile (void)
|
|||
|
||||
|
||||
|
||||
unsigned GetCurrentLine (void)
|
||||
unsigned GetCurrentLineNum (void)
|
||||
/* Return the line number in the current input file */
|
||||
{
|
||||
unsigned AFileCount = CollCount (&AFiles);
|
||||
|
@ -635,7 +683,7 @@ unsigned GetCurrentLine (void)
|
|||
|
||||
|
||||
|
||||
void SetCurrentLine (unsigned LineNum)
|
||||
void SetCurrentLineNum (unsigned LineNum)
|
||||
/* Set the line number in the current input file */
|
||||
{
|
||||
unsigned AFileCount = CollCount (&AFiles);
|
||||
|
|
|
@ -41,6 +41,7 @@
|
|||
#include <stdio.h>
|
||||
|
||||
/* common */
|
||||
#include "coll.h"
|
||||
#include "strbuf.h"
|
||||
|
||||
|
||||
|
@ -95,6 +96,17 @@ void NextChar (void);
|
|||
** are read by this function.
|
||||
*/
|
||||
|
||||
Collection* UseInputStack (Collection* InputStack);
|
||||
/* Use the provided input stack for incoming input. Return the previously used
|
||||
** InputStack.
|
||||
*/
|
||||
|
||||
void PushLine (StrBuf* L);
|
||||
/* Save the current input line and use a new one */
|
||||
|
||||
void ReuseInputLine (void);
|
||||
/* Save and reuse the current line as the next line */
|
||||
|
||||
void ClearLine (void);
|
||||
/* Clear the current input line */
|
||||
|
||||
|
@ -116,13 +128,13 @@ int PreprocessNextLine (void);
|
|||
const char* GetInputFile (const struct IFile* IF);
|
||||
/* Return a filename from an IFile struct */
|
||||
|
||||
const char* GetCurrentFile (void);
|
||||
const char* GetCurrentFilename (void);
|
||||
/* Return the name of the current input file */
|
||||
|
||||
unsigned GetCurrentLine (void);
|
||||
unsigned GetCurrentLineNum (void);
|
||||
/* Return the line number in the current input file */
|
||||
|
||||
void SetCurrentLine (unsigned LineNum);
|
||||
void SetCurrentLineNum (unsigned LineNum);
|
||||
/* Set the line number in the current input file */
|
||||
|
||||
void SetCurrentFilename (const char* Name);
|
||||
|
|
|
@ -308,7 +308,7 @@ static void ParseAutoDecl (Declaration* Decl)
|
|||
** We abuse the Collection somewhat by using it to store line
|
||||
** numbers.
|
||||
*/
|
||||
CollReplace (&CurrentFunc->LocalsBlockStack, (void *)(size_t)GetCurrentLine (),
|
||||
CollReplace (&CurrentFunc->LocalsBlockStack, (void *)(size_t)GetCurrentLineNum (),
|
||||
CollCount (&CurrentFunc->LocalsBlockStack) - 1);
|
||||
|
||||
} else {
|
||||
|
@ -486,8 +486,8 @@ static void ParseOneDecl (const DeclSpec* Spec)
|
|||
/* The default storage class could be wrong. Just clear them */
|
||||
Decl.StorageClass &= ~SC_STORAGEMASK;
|
||||
|
||||
/* This is always a declaration */
|
||||
Decl.StorageClass |= SC_DECL;
|
||||
/* This is always an extern declaration */
|
||||
Decl.StorageClass |= SC_DECL | SC_EXTERN;
|
||||
}
|
||||
|
||||
/* If we don't have a name, this was flagged as an error earlier.
|
||||
|
@ -545,7 +545,9 @@ static void ParseOneDecl (const DeclSpec* Spec)
|
|||
|
||||
if ((Decl.StorageClass & SC_EXTERN) == SC_EXTERN ||
|
||||
(Decl.StorageClass & SC_FUNC) == SC_FUNC) {
|
||||
/* Add the global symbol to the local symbol table */
|
||||
/* Add the global symbol to both of the global and local symbol
|
||||
** tables.
|
||||
*/
|
||||
AddGlobalSym (Decl.Ident, Decl.Type, Decl.StorageClass);
|
||||
} else {
|
||||
/* Add the local symbol to the local symbol table */
|
||||
|
@ -587,7 +589,7 @@ void DeclareLocals (void)
|
|||
continue;
|
||||
}
|
||||
|
||||
ParseDeclSpec (&Spec, SC_AUTO, T_INT);
|
||||
ParseDeclSpec (&Spec, TS_DEFAULT_TYPE_INT, SC_AUTO);
|
||||
if ((Spec.Flags & DS_DEF_STORAGE) != 0 && /* No storage spec */
|
||||
(Spec.Flags & DS_DEF_TYPE) != 0 && /* No type given */
|
||||
GetQualifier (Spec.Type) == T_QUAL_NONE) { /* No type qualifier */
|
||||
|
|
|
@ -74,19 +74,17 @@ Macro* NewMacro (const char* Name)
|
|||
*/
|
||||
{
|
||||
/* Get the length of the macro name */
|
||||
unsigned Len = strlen(Name);
|
||||
unsigned Len = strlen (Name);
|
||||
|
||||
/* Allocate the structure */
|
||||
Macro* M = (Macro*) xmalloc (sizeof(Macro) + Len);
|
||||
|
||||
/* Initialize the data */
|
||||
M->Next = 0;
|
||||
M->Expanding = 0;
|
||||
M->ArgCount = -1; /* Flag: Not a function like macro */
|
||||
M->MaxArgs = 0;
|
||||
InitCollection (&M->FormalArgs);
|
||||
M->Next = 0;
|
||||
M->ParamCount = -1; /* Flag: Not a function-like macro */
|
||||
InitCollection (&M->Params);
|
||||
SB_Init (&M->Replacement);
|
||||
M->Variadic = 0;
|
||||
M->Variadic = 0;
|
||||
memcpy (M->Name, Name, Len+1);
|
||||
|
||||
/* Return the new macro */
|
||||
|
@ -102,10 +100,10 @@ void FreeMacro (Macro* M)
|
|||
{
|
||||
unsigned I;
|
||||
|
||||
for (I = 0; I < CollCount (&M->FormalArgs); ++I) {
|
||||
xfree (CollAtUnchecked (&M->FormalArgs, I));
|
||||
for (I = 0; I < CollCount (&M->Params); ++I) {
|
||||
xfree (CollAtUnchecked (&M->Params, I));
|
||||
}
|
||||
DoneCollection (&M->FormalArgs);
|
||||
DoneCollection (&M->Params);
|
||||
SB_Done (&M->Replacement);
|
||||
xfree (M);
|
||||
}
|
||||
|
@ -121,12 +119,12 @@ Macro* CloneMacro (const Macro* M)
|
|||
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));
|
||||
for (I = 0; I < CollCount (&M->Params); ++I) {
|
||||
/* Copy the parameter */
|
||||
const char* Param = CollAtUnchecked (&M->Params, I);
|
||||
CollAppend (&New->Params, xstrdup (Param));
|
||||
}
|
||||
New->ArgCount = M->ArgCount;
|
||||
New->ParamCount = M->ParamCount;
|
||||
New->Variadic = M->Variadic;
|
||||
SB_Copy (&New->Replacement, &M->Replacement);
|
||||
|
||||
|
@ -265,14 +263,14 @@ Macro* FindMacro (const char* Name)
|
|||
|
||||
|
||||
|
||||
int FindMacroArg (Macro* M, const char* Arg)
|
||||
/* Search for a formal macro argument. If found, return the index of the
|
||||
** argument. If the argument was not found, return -1.
|
||||
int FindMacroParam (const Macro* M, const char* Param)
|
||||
/* Search for a macro parameter. If found, return the index of the parameter.
|
||||
** If the parameter was not found, return -1.
|
||||
*/
|
||||
{
|
||||
unsigned I;
|
||||
for (I = 0; I < CollCount (&M->FormalArgs); ++I) {
|
||||
if (strcmp (CollAtUnchecked (&M->FormalArgs, I), Arg) == 0) {
|
||||
for (I = 0; I < CollCount (&M->Params); ++I) {
|
||||
if (strcmp (CollAtUnchecked (&M->Params, I), Param) == 0) {
|
||||
/* Found */
|
||||
return I;
|
||||
}
|
||||
|
@ -284,25 +282,25 @@ int FindMacroArg (Macro* M, const char* Arg)
|
|||
|
||||
|
||||
|
||||
void AddMacroArg (Macro* M, const char* Arg)
|
||||
/* Add a formal macro argument. */
|
||||
void AddMacroParam (Macro* M, const char* Param)
|
||||
/* Add a macro parameter. */
|
||||
{
|
||||
/* Check if we have a duplicate macro argument, but add it anyway.
|
||||
** Beware: Don't use FindMacroArg here, since the actual argument array
|
||||
/* Check if we have a duplicate macro parameter, but add it anyway.
|
||||
** Beware: Don't use FindMacroParam here, since the actual argument array
|
||||
** may not be initialized.
|
||||
*/
|
||||
unsigned I;
|
||||
for (I = 0; I < CollCount (&M->FormalArgs); ++I) {
|
||||
if (strcmp (CollAtUnchecked (&M->FormalArgs, I), Arg) == 0) {
|
||||
for (I = 0; I < CollCount (&M->Params); ++I) {
|
||||
if (strcmp (CollAtUnchecked (&M->Params, I), Param) == 0) {
|
||||
/* Found */
|
||||
PPError ("Duplicate macro parameter: '%s'", Arg);
|
||||
PPError ("Duplicate macro parameter: '%s'", Param);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Add the new argument */
|
||||
CollAppend (&M->FormalArgs, xstrdup (Arg));
|
||||
++M->ArgCount;
|
||||
/* Add the new parameter */
|
||||
CollAppend (&M->Params, xstrdup (Param));
|
||||
++M->ParamCount;
|
||||
}
|
||||
|
||||
|
||||
|
@ -313,14 +311,14 @@ int MacroCmp (const Macro* M1, const Macro* M2)
|
|||
int I;
|
||||
|
||||
/* Argument count must be identical */
|
||||
if (M1->ArgCount != M2->ArgCount) {
|
||||
if (M1->ParamCount != M2->ParamCount) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Compare the arguments */
|
||||
for (I = 0; I < M1->ArgCount; ++I) {
|
||||
if (strcmp (CollConstAt (&M1->FormalArgs, I),
|
||||
CollConstAt (&M2->FormalArgs, I)) != 0) {
|
||||
/* Compare the parameters */
|
||||
for (I = 0; I < M1->ParamCount; ++I) {
|
||||
if (strcmp (CollConstAt (&M1->Params, I),
|
||||
CollConstAt (&M2->Params, I)) != 0) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -55,10 +55,8 @@
|
|||
typedef struct Macro Macro;
|
||||
struct Macro {
|
||||
Macro* Next; /* Next macro with same hash value */
|
||||
int Expanding; /* Are we currently expanding this macro? */
|
||||
int ArgCount; /* Number of parameters, -1 = no parens */
|
||||
unsigned MaxArgs; /* Size of formal argument list */
|
||||
Collection FormalArgs; /* Formal argument list (char*) */
|
||||
int ParamCount; /* Number of parameters, -1 = no parens */
|
||||
Collection Params; /* Parameter list (char*) */
|
||||
StrBuf Replacement; /* Replacement text */
|
||||
unsigned char Variadic; /* C99 variadic macro */
|
||||
char Name[1]; /* Name, dynamically allocated */
|
||||
|
@ -120,13 +118,13 @@ INLINE int IsMacro (const char* Name)
|
|||
# define IsMacro(Name) (FindMacro (Name) != 0)
|
||||
#endif
|
||||
|
||||
int FindMacroArg (Macro* M, const char* Arg);
|
||||
/* Search for a formal macro argument. If found, return the index of the
|
||||
** argument. If the argument was not found, return -1.
|
||||
int FindMacroParam (const Macro* M, const char* Param);
|
||||
/* Search for a macro parameter. If found, return the index of the parameter.
|
||||
** If the parameter was not found, return -1.
|
||||
*/
|
||||
|
||||
void AddMacroArg (Macro* M, const char* Arg);
|
||||
/* Add a formal macro argument. */
|
||||
void AddMacroParam (Macro* M, const char* Param);
|
||||
/* Add a macro parameter. */
|
||||
|
||||
int MacroCmp (const Macro* M1, const Macro* M2);
|
||||
/* Compare two macros and return zero if both are identical. */
|
||||
|
|
|
@ -752,7 +752,7 @@ static void PPhieQuest (PPExpr* Expr)
|
|||
|
||||
/* Parse third expression */
|
||||
PPExprInit (&Expr3);
|
||||
PPhie1 (&Expr3);
|
||||
PPhieQuest (&Expr3);
|
||||
|
||||
/* Set the result */
|
||||
Expr->IVal = Expr->IVal ? Expr2.IVal != 0 : Expr3.IVal != 0;
|
||||
|
|
|
@ -784,7 +784,7 @@ static void IntPragma (StrBuf* B, IntStack* Stack, long Low, long High)
|
|||
|
||||
static void MakeMessage (const char* Message)
|
||||
{
|
||||
fprintf (stderr, "%s:%u: Note: %s\n", GetInputName (CurTok.LI), GetInputLine (CurTok.LI), Message);
|
||||
Note ("%s", Message);
|
||||
}
|
||||
|
||||
|
||||
|
|
2259
src/cc65/preproc.c
2259
src/cc65/preproc.c
File diff suppressed because it is too large
Load Diff
|
@ -36,17 +36,7 @@
|
|||
#ifndef PREPROC_H
|
||||
#define PREPROC_H
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Forwards */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
typedef struct Macro Macro;
|
||||
|
||||
|
||||
#include "macrotab.h"
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Data */
|
||||
|
@ -78,6 +68,9 @@ void Preprocess (void);
|
|||
void SetPPIfStack (PPIfStack* Stack);
|
||||
/* Specify which PP #if stack to use */
|
||||
|
||||
void ContinueLine (void);
|
||||
/* Continue the current line ended with a '\\' */
|
||||
|
||||
void PreprocessBegin (void);
|
||||
/* Initialize preprocessor with current file */
|
||||
|
||||
|
|
|
@ -241,10 +241,20 @@ void SymName (char* S)
|
|||
|
||||
|
||||
|
||||
int IsWideQuoted (char First, char Second)
|
||||
/* Return 1 if the two successive characters indicate a wide string literal or
|
||||
** a wide char constant, otherwise return 0.
|
||||
*/
|
||||
{
|
||||
return First == 'L' && IsQuote(Second);
|
||||
}
|
||||
|
||||
|
||||
|
||||
int IsSym (char* S)
|
||||
/* If a symbol follows, read it and return 1, otherwise return 0 */
|
||||
{
|
||||
if (IsIdent (CurC)) {
|
||||
if (IsIdent (CurC) && !IsWideQuoted (CurC, NextC)) {
|
||||
SymName (S);
|
||||
return 1;
|
||||
} else {
|
||||
|
@ -639,7 +649,7 @@ static void NumericConst (void)
|
|||
if (IVal <= 0xFFFF &&
|
||||
(Types & IT_UINT) == 0 &&
|
||||
(WarnTypes & IT_LONG) != 0) {
|
||||
Warning ("Integer constant is long");
|
||||
Warning ("Integer constant implies signed long");
|
||||
}
|
||||
}
|
||||
if (IVal > 0xFFFF) {
|
||||
|
@ -656,7 +666,7 @@ static void NumericConst (void)
|
|||
** a preceding unary op or when it is used in constant calculation.
|
||||
*/
|
||||
if (WarnTypes & IT_ULONG) {
|
||||
Warning ("Integer constant is unsigned long");
|
||||
Warning ("Integer constant implies unsigned long");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -282,6 +282,11 @@ void SymName (char* S);
|
|||
** least of size MAX_IDENTLEN+1.
|
||||
*/
|
||||
|
||||
int IsWideQuoted (char First, char Second);
|
||||
/* Return 1 if the two successive characters indicate a wide string literal or
|
||||
** a wide char constant, otherwise return 0.
|
||||
*/
|
||||
|
||||
int IsSym (char* S);
|
||||
/* If a symbol follows, read it and return 1, otherwise return 0 */
|
||||
|
||||
|
|
|
@ -173,7 +173,7 @@ void ShiftExpr (struct ExprDesc* Expr)
|
|||
}
|
||||
|
||||
/* Limit the calculated value to the range of its type */
|
||||
LimitExprValue (Expr);
|
||||
LimitExprValue (Expr, 1);
|
||||
}
|
||||
|
||||
/* Result is already got, remove the generated code */
|
||||
|
|
|
@ -40,6 +40,7 @@
|
|||
|
||||
/* cc65 */
|
||||
#include "anonname.h"
|
||||
#include "asmlabel.h"
|
||||
#include "declare.h"
|
||||
#include "error.h"
|
||||
#include "symentry.h"
|
||||
|
@ -65,13 +66,12 @@ SymEntry* NewSymEntry (const char* Name, unsigned Flags)
|
|||
E->NextHash = 0;
|
||||
E->PrevSym = 0;
|
||||
E->NextSym = 0;
|
||||
E->Link = 0;
|
||||
E->Owner = 0;
|
||||
E->Flags = Flags;
|
||||
E->Type = 0;
|
||||
E->Attr = 0;
|
||||
E->AsmName = 0;
|
||||
E->V.BssName = 0;
|
||||
memset (&E->V, 0, sizeof (E->V));
|
||||
memcpy (E->Name, Name, Len+1);
|
||||
|
||||
/* Return the new entry */
|
||||
|
@ -250,7 +250,9 @@ void SymUseAttr (SymEntry* Sym, struct Declaration* D)
|
|||
|
||||
|
||||
void SymSetAsmName (SymEntry* Sym)
|
||||
/* Set the assembler name for an external symbol from the name of the symbol */
|
||||
/* Set the assembler name for an external symbol from the name of the symbol.
|
||||
** The symbol must have no assembler name set yet.
|
||||
*/
|
||||
{
|
||||
unsigned Len;
|
||||
|
||||
|
@ -266,7 +268,7 @@ void SymSetAsmName (SymEntry* Sym)
|
|||
|
||||
|
||||
|
||||
void CvtRegVarToAuto (SymEntry* Sym)
|
||||
void SymCvtRegVarToAuto (SymEntry* Sym)
|
||||
/* Convert a register variable to an auto variable */
|
||||
{
|
||||
/* Change the storage class */
|
||||
|
@ -278,59 +280,26 @@ void CvtRegVarToAuto (SymEntry* Sym)
|
|||
|
||||
|
||||
|
||||
SymEntry* GetSymType (const Type* T)
|
||||
/* Get the symbol entry of the enum/struct/union type
|
||||
** Return 0 if it is not an enum/struct/union.
|
||||
*/
|
||||
{
|
||||
if ((IsClassStruct (T) || IsTypeEnum (T))) {
|
||||
return T->A.S;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
const char* GetSymTypeName (const Type* T)
|
||||
/* Return a name string of the type or the symbol name if it is an ESU type.
|
||||
** Note: This may use a static buffer that could be overwritten by other calls.
|
||||
*/
|
||||
{
|
||||
static char TypeName [IDENTSIZE + 16];
|
||||
SymEntry* Sym;
|
||||
|
||||
Sym = GetSymType (T);
|
||||
if (Sym == 0) {
|
||||
return GetBasicTypeName (T);
|
||||
}
|
||||
sprintf (TypeName, "%s %s", GetBasicTypeName (T),
|
||||
Sym->Name[0] != '\0' ? Sym->Name : "<unknown>");
|
||||
|
||||
return TypeName;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void ChangeSymType (SymEntry* Entry, const Type* T)
|
||||
void SymChangeType (SymEntry* Sym, const Type* T)
|
||||
/* Change the type of the given symbol */
|
||||
{
|
||||
TypeFree (Entry->Type);
|
||||
Entry->Type = TypeDup (T);
|
||||
TypeFree (Sym->Type);
|
||||
Sym->Type = TypeDup (T);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void ChangeAsmName (SymEntry* Entry, const char* NewAsmName)
|
||||
void SymChangeAsmName (SymEntry* Sym, const char* NewAsmName)
|
||||
/* Change the assembler name of the symbol */
|
||||
{
|
||||
xfree (Entry->AsmName);
|
||||
Entry->AsmName = xstrdup (NewAsmName);
|
||||
xfree (Sym->AsmName);
|
||||
Sym->AsmName = xstrdup (NewAsmName);
|
||||
}
|
||||
|
||||
|
||||
|
||||
int HasAnonName (const SymEntry* Entry)
|
||||
int SymHasAnonName (const SymEntry* Sym)
|
||||
/* Return true if the symbol entry has an anonymous name */
|
||||
{
|
||||
return IsAnonName (Entry->Name);
|
||||
return IsAnonName (Sym->Name);
|
||||
}
|
||||
|
|
|
@ -105,8 +105,8 @@ struct CodeEntry;
|
|||
#define SC_SPADJUSTMENT 0x400000U
|
||||
#define SC_GOTO_IND 0x800000U /* Indirect goto */
|
||||
|
||||
#define SC_ALIAS 0x01000000U /* Alias of anonymous field */
|
||||
#define SC_FICTITIOUS 0x02000000U /* Symbol is fictitious */
|
||||
#define SC_ALIAS 0x01000000U /* Alias of global or anonymous field */
|
||||
#define SC_FICTITIOUS 0x02000000U /* Symbol is fictitious (for error recovery) */
|
||||
#define SC_HAVEFAM 0x04000000U /* Type has a Flexible Array Member */
|
||||
|
||||
|
||||
|
@ -128,7 +128,6 @@ struct SymEntry {
|
|||
SymEntry* NextHash; /* Next entry in hash list */
|
||||
SymEntry* PrevSym; /* Previous symbol in dl list */
|
||||
SymEntry* NextSym; /* Next symbol double linked list */
|
||||
SymEntry* Link; /* General purpose single linked list */
|
||||
struct SymTable* Owner; /* Symbol table the symbol is in */
|
||||
unsigned Flags; /* Symbol flags */
|
||||
Type* Type; /* Symbol type */
|
||||
|
@ -138,27 +137,9 @@ struct SymEntry {
|
|||
/* Data that differs for the different symbol types */
|
||||
union {
|
||||
|
||||
/* Offset for locals or struct members */
|
||||
/* Offset for locals */
|
||||
int Offs;
|
||||
|
||||
/* Data for anonymous struct or union members */
|
||||
struct {
|
||||
int Offs; /* Byte offset into struct */
|
||||
unsigned ANumber; /* Numeric ID */
|
||||
SymEntry* Field; /* The real field aliased */
|
||||
} A;
|
||||
|
||||
|
||||
/* Label name for static symbols */
|
||||
struct {
|
||||
unsigned Label;
|
||||
Collection *DefsOrRefs;
|
||||
struct CodeEntry *IndJumpFrom;
|
||||
} L;
|
||||
|
||||
/* Value of SP adjustment needed after forward 'goto' */
|
||||
unsigned short SPAdjustment;
|
||||
|
||||
/* Register bank offset and offset of the saved copy on stack for
|
||||
** register variables.
|
||||
*/
|
||||
|
@ -167,32 +148,50 @@ struct SymEntry {
|
|||
int SaveOffs;
|
||||
} R;
|
||||
|
||||
/* Value for constants (including enums) */
|
||||
/* Segment name for tentantive global definitions */
|
||||
const char* BssName;
|
||||
|
||||
/* Value for integer constants (including enumerators) */
|
||||
long ConstVal;
|
||||
|
||||
/* Data for structs/unions */
|
||||
struct {
|
||||
struct SymTable* SymTab; /* Member symbol table */
|
||||
unsigned Size; /* Size of the union/struct */
|
||||
unsigned ACount; /* Count of anonymous fields */
|
||||
} S;
|
||||
|
||||
/* Data for enums */
|
||||
struct {
|
||||
struct SymTable* SymTab; /* Member symbol table */
|
||||
const Type* Type; /* Underlying type */
|
||||
} E;
|
||||
|
||||
/* Data for functions */
|
||||
struct {
|
||||
struct Segments* Seg; /* Segments for this function */
|
||||
struct LiteralPool* LitPool; /* Literal pool for this function */
|
||||
} F;
|
||||
|
||||
/* Segment name for tentantive global definitions */
|
||||
const char* BssName;
|
||||
/* Label name for static symbols */
|
||||
struct {
|
||||
unsigned Label;
|
||||
Collection *DefsOrRefs;
|
||||
struct CodeEntry *IndJumpFrom;
|
||||
} L;
|
||||
|
||||
/* Value of SP adjustment needed after forward 'goto' */
|
||||
unsigned short SPAdjustment;
|
||||
|
||||
/* Data for anonymous struct or union members */
|
||||
struct {
|
||||
int Offs; /* Byte offset into struct */
|
||||
unsigned ANumber; /* Numeric ID */
|
||||
SymEntry* Field; /* The real field aliased */
|
||||
} A;
|
||||
|
||||
/* Data for structs/unions tags */
|
||||
struct {
|
||||
struct SymTable* SymTab; /* Member symbol table */
|
||||
unsigned Size; /* Size of the union/struct */
|
||||
unsigned ACount; /* Count of anonymous fields */
|
||||
} S;
|
||||
|
||||
/* Data for enums tags */
|
||||
struct {
|
||||
struct SymTable* SymTab; /* Member symbol table */
|
||||
const Type* Type; /* Underlying type */
|
||||
} E;
|
||||
|
||||
} V;
|
||||
char Name[1]; /* Name, dynamically allocated */
|
||||
char Name[1]; /* Name, dynamically allocated */
|
||||
};
|
||||
|
||||
|
||||
|
@ -303,28 +302,20 @@ void SymUseAttr (SymEntry* Sym, struct Declaration* D);
|
|||
/* Use the attributes from the declaration for this symbol */
|
||||
|
||||
void SymSetAsmName (SymEntry* Sym);
|
||||
/* Set the assembler name for an external symbol from the name of the symbol */
|
||||
/* Set the assembler name for an external symbol from the name of the symbol.
|
||||
** The symbol must have no assembler name set yet.
|
||||
*/
|
||||
|
||||
void CvtRegVarToAuto (SymEntry* Sym);
|
||||
void SymCvtRegVarToAuto (SymEntry* Sym);
|
||||
/* Convert a register variable to an auto variable */
|
||||
|
||||
SymEntry* GetSymType (const Type* T);
|
||||
/* Get the symbol entry of the enum/struct/union type
|
||||
** Return 0 if it is not an enum/struct/union.
|
||||
*/
|
||||
|
||||
const char* GetSymTypeName (const Type* T);
|
||||
/* Return a name string of the type or the symbol name if it is an ESU type.
|
||||
** Note: This may use a static buffer that could be overwritten by other calls.
|
||||
*/
|
||||
|
||||
void ChangeSymType (SymEntry* Entry, const Type* T);
|
||||
void SymChangeType (SymEntry* Sym, const Type* T);
|
||||
/* Change the type of the given symbol */
|
||||
|
||||
void ChangeAsmName (SymEntry* Entry, const char* NewAsmName);
|
||||
void SymChangeAsmName (SymEntry* Sym, const char* NewAsmName);
|
||||
/* Change the assembler name of the symbol */
|
||||
|
||||
int HasAnonName (const SymEntry* Entry);
|
||||
int SymHasAnonName (const SymEntry* Sym);
|
||||
/* Return true if the symbol entry has an anonymous name */
|
||||
|
||||
|
||||
|
|
|
@ -567,6 +567,11 @@ static SymEntry* FindSymInTree (const SymTable* Tab, const char* Name)
|
|||
/* Try to find the symbol in this table */
|
||||
SymEntry* E = FindSymInTable (Tab, Name, Hash);
|
||||
|
||||
while (E != 0 && (E->Flags & SC_ALIAS) == SC_ALIAS) {
|
||||
/* Get the aliased entry */
|
||||
E = E->V.A.Field;
|
||||
}
|
||||
|
||||
/* Bail out if we found it */
|
||||
if (E != 0) {
|
||||
return E;
|
||||
|
@ -620,8 +625,8 @@ SymEntry FindStructField (const Type* T, const char* Name)
|
|||
** value, or an empty entry struct if the field is not found.
|
||||
*/
|
||||
{
|
||||
SymEntry* Entry = 0;
|
||||
SymEntry Field;
|
||||
SymEntry* Field = 0;
|
||||
SymEntry Res;
|
||||
int Offs = 0;
|
||||
|
||||
/* The given type may actually be a pointer to struct/union */
|
||||
|
@ -632,35 +637,35 @@ SymEntry FindStructField (const Type* T, const char* Name)
|
|||
/* Only structs/unions have struct/union fields... */
|
||||
if (IsClassStruct (T)) {
|
||||
|
||||
/* Get a pointer to the struct/union type */
|
||||
const SymEntry* Struct = GetESUSymEntry (T);
|
||||
CHECK (Struct != 0);
|
||||
/* Get a pointer to the struct/union tag */
|
||||
const SymEntry* TagSym = GetESUTagSym (T);
|
||||
CHECK (TagSym != 0);
|
||||
|
||||
/* Now search in the struct/union symbol table. Beware: The table may
|
||||
** not exist.
|
||||
*/
|
||||
if (Struct->V.S.SymTab) {
|
||||
Entry = FindSymInTable (Struct->V.S.SymTab, Name, HashStr (Name));
|
||||
if (TagSym->V.S.SymTab) {
|
||||
Field = FindSymInTable (TagSym->V.S.SymTab, Name, HashStr (Name));
|
||||
|
||||
if (Entry != 0) {
|
||||
Offs = Entry->V.Offs;
|
||||
if (Field != 0) {
|
||||
Offs = Field->V.Offs;
|
||||
}
|
||||
|
||||
while (Entry != 0 && (Entry->Flags & SC_ALIAS) == SC_ALIAS) {
|
||||
while (Field != 0 && (Field->Flags & SC_ALIAS) == SC_ALIAS) {
|
||||
/* Get the real field */
|
||||
Entry = Entry->V.A.Field;
|
||||
Field = Field->V.A.Field;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (Entry != 0) {
|
||||
Field = *Entry;
|
||||
Field.V.Offs = Offs;
|
||||
if (Field != 0) {
|
||||
Res = *Field;
|
||||
Res.V.Offs = Offs;
|
||||
} else {
|
||||
memset (&Field, 0, sizeof(SymEntry));
|
||||
memset (&Res, 0, sizeof(SymEntry));
|
||||
}
|
||||
|
||||
return Field;
|
||||
return Res;
|
||||
}
|
||||
|
||||
|
||||
|
@ -684,15 +689,15 @@ static int IsDistinctRedef (const Type* lhst, const Type* rhst, typecmpcode_t Co
|
|||
}
|
||||
|
||||
|
||||
static int HandleSymRedefinition (SymEntry* Entry, const Type* T, unsigned Flags)
|
||||
static int HandleSymRedefinition (SymEntry* Sym, const Type* T, unsigned Flags)
|
||||
/* Check and handle redefinition of existing symbols.
|
||||
** Complete array sizes and function descriptors as well.
|
||||
** Return true if there *is* an error.
|
||||
*/
|
||||
{
|
||||
/* Get the type info of the existing symbol */
|
||||
Type* E_Type = Entry->Type;
|
||||
unsigned E_SCType = Entry->Flags & SC_TYPEMASK;
|
||||
Type* E_Type = Sym->Type;
|
||||
unsigned E_SCType = Sym->Flags & SC_TYPEMASK;
|
||||
unsigned SCType = Flags & SC_TYPEMASK;
|
||||
|
||||
/* Some symbols may be redeclared if certain requirements are met */
|
||||
|
@ -701,15 +706,16 @@ static int HandleSymRedefinition (SymEntry* Entry, const Type* T, unsigned Flags
|
|||
/* Existing typedefs cannot be redeclared as anything different */
|
||||
if (SCType == SC_TYPEDEF) {
|
||||
if (IsDistinctRedef (E_Type, T, TC_IDENTICAL, TCF_MASK_QUAL)) {
|
||||
Error ("Conflicting types for typedef '%s'", Entry->Name);
|
||||
Entry = 0;
|
||||
Error ("Conflicting types for typedef '%s'", Sym->Name);
|
||||
Note ("'%s' vs '%s'", GetFullTypeName (T), GetFullTypeName (E_Type));
|
||||
Sym = 0;
|
||||
}
|
||||
} else {
|
||||
Error ("Redefinition of typedef '%s' as different kind of symbol", Entry->Name);
|
||||
Entry = 0;
|
||||
Error ("Redefinition of typedef '%s' as different kind of symbol", Sym->Name);
|
||||
Sym = 0;
|
||||
}
|
||||
|
||||
} else if ((Entry->Flags & SC_FUNC) == SC_FUNC) {
|
||||
} else if ((Sym->Flags & SC_FUNC) == SC_FUNC) {
|
||||
|
||||
/* In case of a function, use the new type descriptor, since it
|
||||
** contains pointers to the new symbol tables that are needed if
|
||||
|
@ -720,27 +726,27 @@ static int HandleSymRedefinition (SymEntry* Entry, const Type* T, unsigned Flags
|
|||
if (IsTypeFunc (T)) {
|
||||
|
||||
/* Check for duplicate function definitions */
|
||||
if (SymIsDef (Entry) && (Flags & SC_DEF) == SC_DEF) {
|
||||
if (SymIsDef (Sym) && (Flags & SC_DEF) == SC_DEF) {
|
||||
Error ("Body for function '%s' has already been defined",
|
||||
Entry->Name);
|
||||
Entry = 0;
|
||||
Sym->Name);
|
||||
Sym = 0;
|
||||
} else {
|
||||
/* 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;
|
||||
Error ("Conflicting function types for '%s'", Sym->Name);
|
||||
Note ("'%s' vs '%s'", GetFullTypeName (T), GetFullTypeName (E_Type));
|
||||
Sym = 0;
|
||||
} else {
|
||||
/* Refine the existing composite prototype with this new
|
||||
** one.
|
||||
*/
|
||||
RefineFuncDesc (Entry->Type, T);
|
||||
RefineFuncDesc (Sym->Type, T);
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
Error ("Redefinition of function '%s' as different kind of symbol", Entry->Name);
|
||||
Entry = 0;
|
||||
Error ("Redefinition of function '%s' as different kind of symbol", Sym->Name);
|
||||
Sym = 0;
|
||||
}
|
||||
|
||||
} else {
|
||||
|
@ -759,8 +765,9 @@ static int HandleSymRedefinition (SymEntry* Entry, const Type* T, unsigned Flags
|
|||
if ((Size != UNSPECIFIED && ESize != UNSPECIFIED && Size != ESize) ||
|
||||
IsDistinctRedef (E_Type + 1, T + 1, TC_IDENTICAL, TCF_MASK_QUAL)) {
|
||||
/* Conflicting element types */
|
||||
Error ("Conflicting array types for '%s[]'", Entry->Name);
|
||||
Entry = 0;
|
||||
Error ("Conflicting array types for '%s[]'", Sym->Name);
|
||||
Note ("'%s' vs '%s'", GetFullTypeName (T), GetFullTypeName (E_Type));
|
||||
Sym = 0;
|
||||
} else {
|
||||
/* Check if we have a size in the existing definition */
|
||||
if (ESize == UNSPECIFIED) {
|
||||
|
@ -773,24 +780,25 @@ static int HandleSymRedefinition (SymEntry* Entry, const Type* T, unsigned Flags
|
|||
|
||||
/* New type must be equivalent */
|
||||
if (SCType != E_SCType) {
|
||||
Error ("Redefinition of '%s' as different kind of symbol", Entry->Name);
|
||||
Entry = 0;
|
||||
Error ("Redefinition of '%s' as different kind of symbol", Sym->Name);
|
||||
Sym = 0;
|
||||
} else if (IsDistinctRedef (E_Type, T, TC_EQUAL, TCF_MASK_QUAL)) {
|
||||
Error ("Conflicting types for '%s'", Entry->Name);
|
||||
Entry = 0;
|
||||
Error ("Conflicting types for '%s'", Sym->Name);
|
||||
Note ("'%s' vs '%s'", GetFullTypeName (T), GetFullTypeName (E_Type));
|
||||
Sym = 0;
|
||||
} else if (E_SCType == SC_ENUMERATOR) {
|
||||
/* Enumerators aren't allowed to be redeclared at all, even if
|
||||
** all occurences are identical. The current code logic won't
|
||||
** get here, but let's just do it.
|
||||
*/
|
||||
Error ("Redeclaration of enumerator constant '%s'", Entry->Name);
|
||||
Entry = 0;
|
||||
Error ("Redeclaration of enumerator constant '%s'", Sym->Name);
|
||||
Sym = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Return if there are any errors */
|
||||
return Entry == 0;
|
||||
return Sym == 0;
|
||||
}
|
||||
|
||||
|
||||
|
@ -824,38 +832,38 @@ static void AddSymEntry (SymTable* T, SymEntry* S)
|
|||
|
||||
|
||||
SymEntry* AddEnumSym (const char* Name, unsigned Flags, const Type* Type, SymTable* Tab, unsigned* DSFlags)
|
||||
/* Add an enum entry and return it */
|
||||
/* Add an enum tag entry and return it */
|
||||
{
|
||||
SymTable* CurTagTab = TagTab;
|
||||
SymEntry* Entry;
|
||||
SymEntry* TagEntry;
|
||||
|
||||
if ((Flags & SC_FICTITIOUS) == 0) {
|
||||
/* Do we have an entry with this name already? */
|
||||
Entry = FindSymInTable (CurTagTab, Name, HashStr (Name));
|
||||
TagEntry = FindSymInTable (CurTagTab, Name, HashStr (Name));
|
||||
} else {
|
||||
/* Add a fictitious symbol in the fail-safe table */
|
||||
Entry = 0;
|
||||
TagEntry = 0;
|
||||
CurTagTab = FailSafeTab;
|
||||
}
|
||||
|
||||
if (Entry) {
|
||||
if (TagEntry) {
|
||||
|
||||
/* We do have an entry. This may be a forward, so check it. */
|
||||
if ((Entry->Flags & SC_TYPEMASK) != SC_ENUM) {
|
||||
if ((TagEntry->Flags & SC_TYPEMASK) != SC_ENUM) {
|
||||
/* Existing symbol is not an enum */
|
||||
Error ("Symbol '%s' is already different kind", Name);
|
||||
Entry = 0;
|
||||
TagEntry = 0;
|
||||
} else if (Type != 0) {
|
||||
/* Define the struct size if the underlying type is given. */
|
||||
if (Entry->V.E.Type != 0) {
|
||||
if (TagEntry->V.E.Type != 0) {
|
||||
/* Both are definitions. */
|
||||
Error ("Multiple definition for 'enum %s'", Name);
|
||||
Entry = 0;
|
||||
TagEntry = 0;
|
||||
} else {
|
||||
Entry->V.E.SymTab = Tab;
|
||||
Entry->V.E.Type = Type;
|
||||
Entry->Flags &= ~SC_DECL;
|
||||
Entry->Flags |= SC_DEF;
|
||||
TagEntry->V.E.SymTab = Tab;
|
||||
TagEntry->V.E.Type = Type;
|
||||
TagEntry->Flags &= ~SC_DECL;
|
||||
TagEntry->Flags |= SC_DEF;
|
||||
|
||||
/* Remember this is the first definition of this type */
|
||||
if (DSFlags != 0) {
|
||||
|
@ -864,83 +872,83 @@ SymEntry* AddEnumSym (const char* Name, unsigned Flags, const Type* Type, SymTab
|
|||
}
|
||||
}
|
||||
|
||||
if (Entry == 0) {
|
||||
if (TagEntry == 0) {
|
||||
/* Use the fail-safe table for fictitious symbols */
|
||||
CurTagTab = FailSafeTab;
|
||||
}
|
||||
}
|
||||
|
||||
if (Entry == 0) {
|
||||
if (TagEntry == 0) {
|
||||
|
||||
/* Create a new entry */
|
||||
Entry = NewSymEntry (Name, SC_ENUM);
|
||||
TagEntry = NewSymEntry (Name, SC_ENUM);
|
||||
|
||||
/* Set the enum type data */
|
||||
Entry->V.E.SymTab = Tab;
|
||||
Entry->V.E.Type = Type;
|
||||
TagEntry->V.E.SymTab = Tab;
|
||||
TagEntry->V.E.Type = Type;
|
||||
|
||||
if (Type != 0) {
|
||||
Entry->Flags |= SC_DEF;
|
||||
TagEntry->Flags |= SC_DEF;
|
||||
}
|
||||
|
||||
/* Remember this is the first definition of this type */
|
||||
if (CurTagTab != FailSafeTab && DSFlags != 0) {
|
||||
if ((Entry->Flags & SC_DEF) != 0) {
|
||||
if ((TagEntry->Flags & SC_DEF) != 0) {
|
||||
*DSFlags |= DS_NEW_TYPE_DEF;
|
||||
}
|
||||
*DSFlags |= DS_NEW_TYPE_DECL;
|
||||
}
|
||||
|
||||
/* Add it to the current table */
|
||||
AddSymEntry (CurTagTab, Entry);
|
||||
AddSymEntry (CurTagTab, TagEntry);
|
||||
}
|
||||
|
||||
/* Return the entry */
|
||||
return Entry;
|
||||
return TagEntry;
|
||||
}
|
||||
|
||||
|
||||
|
||||
SymEntry* AddStructSym (const char* Name, unsigned Flags, unsigned Size, SymTable* Tab, unsigned* DSFlags)
|
||||
/* Add a struct/union entry and return it */
|
||||
/* Add a struct/union tag entry and return it */
|
||||
{
|
||||
SymTable* CurTagTab = TagTab;
|
||||
SymEntry* Entry;
|
||||
unsigned Type = (Flags & SC_TYPEMASK);
|
||||
SymEntry* TagEntry;
|
||||
unsigned SCType = (Flags & SC_TYPEMASK);
|
||||
|
||||
/* Type must be struct or union */
|
||||
PRECONDITION (Type == SC_STRUCT || Type == SC_UNION);
|
||||
/* SCType must be struct or union */
|
||||
PRECONDITION (SCType == SC_STRUCT || SCType == SC_UNION);
|
||||
|
||||
if ((Flags & SC_FICTITIOUS) == 0) {
|
||||
/* Do we have an entry with this name already? */
|
||||
Entry = FindSymInTable (CurTagTab, Name, HashStr (Name));
|
||||
TagEntry = FindSymInTable (CurTagTab, Name, HashStr (Name));
|
||||
} else {
|
||||
/* Add a fictitious symbol in the fail-safe table */
|
||||
Entry = 0;
|
||||
TagEntry = 0;
|
||||
CurTagTab = FailSafeTab;
|
||||
}
|
||||
|
||||
if (Entry) {
|
||||
if (TagEntry) {
|
||||
|
||||
/* We do have an entry. This may be a forward, so check it. */
|
||||
if ((Entry->Flags & SC_TYPEMASK) != Type) {
|
||||
if ((TagEntry->Flags & SC_TYPEMASK) != SCType) {
|
||||
/* Existing symbol is not a struct */
|
||||
Error ("Symbol '%s' is already different kind", Name);
|
||||
Entry = 0;
|
||||
} else if ((Entry->Flags & Flags & SC_DEF) == SC_DEF) {
|
||||
TagEntry = 0;
|
||||
} else if ((TagEntry->Flags & Flags & SC_DEF) == SC_DEF) {
|
||||
/* Both structs are definitions. */
|
||||
if (Type == SC_STRUCT) {
|
||||
if (SCType == SC_STRUCT) {
|
||||
Error ("Multiple definition for 'struct %s'", Name);
|
||||
} else {
|
||||
Error ("Multiple definition for 'union %s'", Name);
|
||||
}
|
||||
Entry = 0;
|
||||
TagEntry = 0;
|
||||
} else {
|
||||
/* Define the struct size if it is a definition */
|
||||
if ((Flags & SC_DEF) == SC_DEF) {
|
||||
Entry->Flags = Flags;
|
||||
Entry->V.S.SymTab = Tab;
|
||||
Entry->V.S.Size = Size;
|
||||
TagEntry->Flags = Flags;
|
||||
TagEntry->V.S.SymTab = Tab;
|
||||
TagEntry->V.S.Size = Size;
|
||||
|
||||
/* Remember this is the first definition of this type */
|
||||
if (DSFlags != 0) {
|
||||
|
@ -949,35 +957,35 @@ SymEntry* AddStructSym (const char* Name, unsigned Flags, unsigned Size, SymTabl
|
|||
}
|
||||
}
|
||||
|
||||
if (Entry == 0) {
|
||||
if (TagEntry == 0) {
|
||||
/* Use the fail-safe table for fictitious symbols */
|
||||
CurTagTab = FailSafeTab;
|
||||
}
|
||||
}
|
||||
|
||||
if (Entry == 0) {
|
||||
if (TagEntry == 0) {
|
||||
|
||||
/* Create a new entry */
|
||||
Entry = NewSymEntry (Name, Flags);
|
||||
TagEntry = NewSymEntry (Name, Flags);
|
||||
|
||||
/* Set the struct data */
|
||||
Entry->V.S.SymTab = Tab;
|
||||
Entry->V.S.Size = Size;
|
||||
TagEntry->V.S.SymTab = Tab;
|
||||
TagEntry->V.S.Size = Size;
|
||||
|
||||
/* Remember this is the first definition of this type */
|
||||
if (CurTagTab != FailSafeTab && DSFlags != 0) {
|
||||
if ((Entry->Flags & SC_DEF) != 0) {
|
||||
if ((TagEntry->Flags & SC_DEF) != 0) {
|
||||
*DSFlags |= DS_NEW_TYPE_DEF;
|
||||
}
|
||||
*DSFlags |= DS_NEW_TYPE_DECL;
|
||||
}
|
||||
|
||||
/* Add it to the current tag table */
|
||||
AddSymEntry (CurTagTab, Entry);
|
||||
AddSymEntry (CurTagTab, TagEntry);
|
||||
}
|
||||
|
||||
/* Return the entry */
|
||||
return Entry;
|
||||
return TagEntry;
|
||||
}
|
||||
|
||||
|
||||
|
@ -1068,7 +1076,7 @@ DefOrRef* AddDefOrRef (SymEntry* E, unsigned Flags)
|
|||
|
||||
DOR = xmalloc (sizeof (DefOrRef));
|
||||
CollAppend (E->V.L.DefsOrRefs, DOR);
|
||||
DOR->Line = GetCurrentLine ();
|
||||
DOR->Line = GetCurrentLineNum ();
|
||||
DOR->LocalsBlockId = (size_t)CollLast (&CurrentFunc->LocalsBlockStack);
|
||||
DOR->Flags = Flags;
|
||||
DOR->StackPtr = StackPtr;
|
||||
|
@ -1136,7 +1144,7 @@ SymEntry* AddLabelSym (const char* Name, unsigned Flags)
|
|||
(size_t)CollAt (AIC, DOR->Depth - 1) != DOR->LocalsBlockId)) {
|
||||
Warning ("Goto at line %d to label %s jumps into a block with "
|
||||
"initialization of an object that has automatic storage duration",
|
||||
GetCurrentLine (), Name);
|
||||
GetCurrentLineNum (), Name);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1279,6 +1287,11 @@ SymEntry* AddLocalSym (const char* Name, const Type* T, unsigned Flags, int Offs
|
|||
/* Generate the assembler name from the data label number */
|
||||
Entry->V.L.Label = Offs;
|
||||
Entry->AsmName = xstrdup (LocalDataLabelName (Entry->V.L.Label));
|
||||
} else if ((Flags & SC_ALIAS) == SC_ALIAS) {
|
||||
/* Just clear the info */
|
||||
Entry->V.A.Field = 0;
|
||||
Entry->V.A.ANumber = 0;
|
||||
Entry->V.A.Offs = 0;
|
||||
} else {
|
||||
Internal ("Invalid flags in AddLocalSym: %04X", Flags);
|
||||
}
|
||||
|
@ -1296,13 +1309,26 @@ SymEntry* AddLocalSym (const char* Name, const Type* T, unsigned Flags, int Offs
|
|||
SymEntry* AddGlobalSym (const char* Name, const Type* T, unsigned Flags)
|
||||
/* Add an external or global symbol to the symbol table and return the entry */
|
||||
{
|
||||
/* Start from the local symbol table */
|
||||
SymTable* Tab = SymTab;
|
||||
/* Add the new declaration to the global symbol table if no errors */
|
||||
SymTable* Tab = SymTab0;
|
||||
|
||||
/* Only search this name in the local and global symbol tables */
|
||||
SymEntry* Entry = 0;
|
||||
SymEntry* Alias = 0;
|
||||
|
||||
if (SymTab != SymTab0) {
|
||||
Alias = Entry = FindLocalSym (Name);
|
||||
while (Entry && (Entry->Flags & SC_ALIAS) == SC_ALIAS) {
|
||||
/* Get the aliased entry */
|
||||
Entry = Entry->V.A.Field;
|
||||
}
|
||||
}
|
||||
|
||||
if (Entry == 0) {
|
||||
Entry = FindGlobalSym (Name);
|
||||
}
|
||||
|
||||
/* Do we have an entry with this name already? */
|
||||
SymEntry* Entry = FindSymInTree (Tab, Name);
|
||||
if (Entry) {
|
||||
|
||||
/* We have a symbol with this name already */
|
||||
if (HandleSymRedefinition (Entry, T, Flags)) {
|
||||
Entry = 0;
|
||||
|
@ -1317,7 +1343,7 @@ SymEntry* AddGlobalSym (const char* Name, const Type* T, unsigned Flags)
|
|||
** declaration if both declarations are global, otherwise give an
|
||||
** error.
|
||||
*/
|
||||
if (Tab == SymTab0 &&
|
||||
if (SymTab == SymTab0 &&
|
||||
(Flags & SC_EXTERN) == 0 &&
|
||||
(Entry->Flags & SC_EXTERN) != 0) {
|
||||
Warning ("Static declaration of '%s' follows non-static declaration", Name);
|
||||
|
@ -1353,12 +1379,9 @@ SymEntry* AddGlobalSym (const char* Name, const Type* T, unsigned Flags)
|
|||
/* Use the fail-safe table for fictitious symbols */
|
||||
Tab = FailSafeTab;
|
||||
}
|
||||
|
||||
} else if ((Flags & (SC_EXTERN | SC_FUNC)) != 0) {
|
||||
/* Add the new declaration to the global symbol table instead */
|
||||
Tab = SymTab0;
|
||||
}
|
||||
if (Entry == 0 || Entry->Owner != Tab) {
|
||||
|
||||
if (Entry == 0) {
|
||||
|
||||
/* Create a new entry */
|
||||
Entry = NewSymEntry (Name, Flags);
|
||||
|
@ -1376,6 +1399,13 @@ SymEntry* AddGlobalSym (const char* Name, const Type* T, unsigned Flags)
|
|||
|
||||
/* Add the entry to the symbol table */
|
||||
AddSymEntry (Tab, Entry);
|
||||
|
||||
}
|
||||
|
||||
/* Add an alias of the global symbol to the local symbol table */
|
||||
if (Tab == SymTab0 && SymTab != SymTab0 && Entry->Owner != SymTab && Alias == 0) {
|
||||
Alias = AddLocalSym (Name, T, SC_ALIAS, 0);
|
||||
Alias->V.A.Field = Entry;
|
||||
}
|
||||
|
||||
/* Return the entry */
|
||||
|
|
|
@ -169,10 +169,10 @@ unsigned short FindSPAdjustment (const char* Name);
|
|||
|
||||
|
||||
SymEntry* AddEnumSym (const char* Name, unsigned Flags, const Type* Type, SymTable* Tab, unsigned* DSFlags);
|
||||
/* Add an enum entry and return it */
|
||||
/* Add an enum tag entry and return it */
|
||||
|
||||
SymEntry* AddStructSym (const char* Name, unsigned Flags, unsigned Size, SymTable* Tab, unsigned* DSFlags);
|
||||
/* Add a struct/union entry and return it */
|
||||
/* Add a struct/union tag entry and return it */
|
||||
|
||||
SymEntry* AddBitField (const char* Name, const Type* Type, unsigned Offs,
|
||||
unsigned BitOffs, unsigned BitWidth, int SignednessSpecified);
|
||||
|
|
|
@ -303,8 +303,8 @@ static void DoCompare (const Type* lhs, const Type* rhs, typecmp_t* Result)
|
|||
if ((IsTypeEnum (lhs) || IsTypeEnum (rhs))) {
|
||||
|
||||
/* Compare the tag types */
|
||||
Sym1 = IsTypeEnum (lhs) ? GetESUSymEntry (lhs) : 0;
|
||||
Sym2 = IsTypeEnum (rhs) ? GetESUSymEntry (rhs) : 0;
|
||||
Sym1 = IsTypeEnum (lhs) ? GetESUTagSym (lhs) : 0;
|
||||
Sym2 = IsTypeEnum (rhs) ? GetESUTagSym (rhs) : 0;
|
||||
|
||||
if (Sym1 != Sym2) {
|
||||
if (Sym1 == 0 || Sym2 == 0) {
|
||||
|
@ -420,8 +420,8 @@ static void DoCompare (const Type* lhs, const Type* rhs, typecmp_t* Result)
|
|||
case T_TYPE_STRUCT:
|
||||
case T_TYPE_UNION:
|
||||
/* Compare the tag types */
|
||||
Sym1 = GetESUSymEntry (lhs);
|
||||
Sym2 = GetESUSymEntry (rhs);
|
||||
Sym1 = GetESUTagSym (lhs);
|
||||
Sym2 = GetESUTagSym (rhs);
|
||||
|
||||
CHECK (Sym1 != 0 || Sym2 != 0);
|
||||
|
||||
|
|
|
@ -44,14 +44,20 @@
|
|||
|
||||
|
||||
|
||||
#if defined(__GNUC__)
|
||||
# define attribute(a) __attribute__(a)
|
||||
#ifdef __clang__
|
||||
# define attribute(a) __attribute__(a)
|
||||
# define ATTR_UNUSED(x)
|
||||
# define ATTR_NORETURN __attribute__((analyzer_noreturn))
|
||||
#elif defined(__GNUC__)
|
||||
# define attribute(a) __attribute__(a)
|
||||
# define ATTR_UNUSED(x) __attribute__((__unused__)) x
|
||||
# define ATTR_NORETURN __attribute__((noreturn))
|
||||
#else
|
||||
# define attribute(a)
|
||||
# define ATTR_UNUSED(x)
|
||||
# define ATTR_NORETURN
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/* End of attrib.h */
|
||||
|
||||
#endif
|
||||
|
|
|
@ -592,9 +592,19 @@ static void RangeSection (void)
|
|||
case INFOTOK_END:
|
||||
AddAttr ("END", &Attributes, tEnd);
|
||||
InfoNextTok ();
|
||||
InfoAssureInt ();
|
||||
InfoRangeCheck (0x0000, 0xFFFF);
|
||||
End = InfoIVal;
|
||||
|
||||
if (InfoTok == INFOTOK_OFFSET_INTCON) {
|
||||
InfoRangeCheck (0x0000, 0xFFFF);
|
||||
if (!(Attributes & tStart))
|
||||
InfoError ("When using End with an offset, Start must be specified before");
|
||||
End = Start + InfoIVal - 1;
|
||||
if (End > 0xFFFF)
|
||||
InfoError ("Range error");
|
||||
} else {
|
||||
InfoAssureInt ();
|
||||
InfoRangeCheck (0x0000, 0xFFFF);
|
||||
End = InfoIVal;
|
||||
}
|
||||
InfoNextTok ();
|
||||
break;
|
||||
|
||||
|
|
|
@ -372,6 +372,14 @@ Again:
|
|||
return;
|
||||
}
|
||||
|
||||
/* Decimal number offset? */
|
||||
if (C == '+') {
|
||||
NextChar ();
|
||||
InfoIVal = GetDecimalToken ();
|
||||
InfoTok = INFOTOK_OFFSET_INTCON;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Other characters */
|
||||
switch (C) {
|
||||
|
||||
|
|
|
@ -48,6 +48,7 @@
|
|||
typedef enum token_t {
|
||||
INFOTOK_NONE,
|
||||
INFOTOK_INTCON,
|
||||
INFOTOK_OFFSET_INTCON,
|
||||
INFOTOK_STRCON,
|
||||
INFOTOK_CHARCON,
|
||||
INFOTOK_IDENT,
|
||||
|
|
|
@ -46,7 +46,7 @@
|
|||
|
||||
|
||||
/* THE memory */
|
||||
static unsigned char Mem[0x10000];
|
||||
unsigned char Mem[0x10000];
|
||||
|
||||
|
||||
|
||||
|
@ -73,14 +73,6 @@ void MemWriteWord (unsigned Addr, unsigned Val)
|
|||
|
||||
|
||||
|
||||
unsigned char MemReadByte (unsigned Addr)
|
||||
/* Read a byte from a memory location */
|
||||
{
|
||||
return Mem[Addr];
|
||||
}
|
||||
|
||||
|
||||
|
||||
unsigned MemReadWord (unsigned Addr)
|
||||
/* Read a word from a memory location */
|
||||
{
|
||||
|
|
|
@ -36,7 +36,9 @@
|
|||
#ifndef MEMORY_H
|
||||
#define MEMORY_H
|
||||
|
||||
#include "inline.h"
|
||||
|
||||
extern unsigned char Mem[0x10000];
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Code */
|
||||
|
@ -50,8 +52,15 @@ void MemWriteByte (unsigned Addr, unsigned char Val);
|
|||
void MemWriteWord (unsigned Addr, unsigned Val);
|
||||
/* Write a word to a memory location */
|
||||
|
||||
unsigned char MemReadByte (unsigned Addr);
|
||||
#if defined(HAVE_INLINE)
|
||||
INLINE unsigned char MemReadByte (unsigned Addr)
|
||||
/* Read a byte from a memory location */
|
||||
{
|
||||
return Mem[Addr];
|
||||
}
|
||||
#else
|
||||
#define MemReadByte(Addr) Mem[Addr]
|
||||
#endif
|
||||
|
||||
unsigned MemReadWord (unsigned Addr);
|
||||
/* Read a word from a memory location */
|
||||
|
|
|
@ -761,6 +761,7 @@ TARGETS := \
|
|||
|
||||
define TARGET_recipe
|
||||
|
||||
@echo making targettest for: $(T)
|
||||
@$(MAKE) -j2 SYS:=$(T)
|
||||
@$(MAKE) --no-print-directory clean SYS:=$(T)
|
||||
|
||||
|
|
|
@ -73,4 +73,7 @@ endif
|
|||
dd if=$< bs=8K count=${COUNT} >> $@
|
||||
|
||||
clean:
|
||||
@$(DEL) conio.o conio.??? 2>$(NULLDEV)
|
||||
@$(DEL) conio.o 2>$(NULLDEV)
|
||||
@$(DEL) conio.pce 2>$(NULLDEV)
|
||||
@$(DEL) conio.bin 2>$(NULLDEV)
|
||||
@$(DEL) conio.map 2>$(NULLDEV)
|
||||
|
|
|
@ -5,25 +5,33 @@ ifneq ($(shell echo),)
|
|||
endif
|
||||
|
||||
ifdef CMD_EXE
|
||||
S = $(subst /,\,/)
|
||||
EXE = .exe
|
||||
MKDIR = mkdir $(subst /,\,$1)
|
||||
RMDIR = -rmdir /q /s $(subst /,\,$1)
|
||||
ERRDIR = 2>&1
|
||||
TRUE = exit 0
|
||||
CAT = type $(subst /,\,$1)
|
||||
else
|
||||
S = /
|
||||
EXE =
|
||||
MKDIR = mkdir -p $1
|
||||
RMDIR = $(RM) -r $1
|
||||
ERRDIR = 2>&1
|
||||
TRUE = true
|
||||
CAT = cat
|
||||
endif
|
||||
|
||||
ifdef QUIET
|
||||
# .SILENT:
|
||||
endif
|
||||
|
||||
CA65 := $(if $(wildcard ../../../bin/ca65*),../../../bin/ca65,ca65)
|
||||
LD65 := $(if $(wildcard ../../../bin/ld65*),../../../bin/ld65,ld65)
|
||||
CA65 := $(if $(wildcard ../../../bin/ca65*),..$S..$S..$Sbin$Sca65,ca65)
|
||||
LD65 := $(if $(wildcard ../../../bin/ld65*),..$S..$S..$Sbin$Sld65,ld65)
|
||||
|
||||
WORKDIR = ../../../testwrk/asm/listing
|
||||
|
||||
ISEQUAL = ../../../testwrk/isequal$(EXE)
|
||||
ISEQUAL = ..$S..$S..$Stestwrk$Sisequal$(EXE)
|
||||
|
||||
CC = gcc
|
||||
CFLAGS = -O2
|
||||
|
@ -50,14 +58,14 @@ $(WORKDIR)/$1.bin: $1.s $(ISEQUAL)
|
|||
|
||||
# compile without generating listing
|
||||
ifeq ($(wildcard control/$1.err),)
|
||||
$(CA65) -t none -o $$(@:.bin=.o) $$< > $$(@:.bin=.err) 2>&1
|
||||
$(CA65) -t none -o $$(@:.bin=.o) $$< > $$(@:.bin=.err) $(ERRDIR)
|
||||
ifeq ($(wildcard control/$1.no-ld65),)
|
||||
$(LD65) -t none -o $$@ $$(@:.bin=.o) none.lib > $$(@:.bin=.ld65-err) 2>&1
|
||||
$(LD65) -t none -o $$@ $$(@:.bin=.o) none.lib > $$(@:.bin=.ld65-err) $(ERRDIR)
|
||||
endif
|
||||
else
|
||||
$(CA65) -t none -o $$(@:.bin=.o) $$< > $$(@:.bin=.err) 2>&1 || true
|
||||
$(CA65) -t none -o $$(@:.bin=.o) $$< > $$(@:.bin=.err) $(ERRDIR) || $(TRUE)
|
||||
ifeq ($(wildcard control/$1.no-ld65),)
|
||||
$(LD65) -t none -o $$@ $$(@:.bin=.o) none.lib > $$(@:.bin=.ld65-err) 2>&1 || true
|
||||
$(LD65) -t none -o $$@ $$(@:.bin=.o) none.lib > $$(@:.bin=.ld65-err) $(ERRDIR) || $(TRUE)
|
||||
endif
|
||||
endif
|
||||
|
||||
|
@ -71,14 +79,15 @@ ifneq ($(wildcard ref/$1.bin-ref),)
|
|||
$(ISEQUAL) --binary ref/$1.bin-ref $$@
|
||||
endif
|
||||
|
||||
# rem $(indfo $(CAT) $(subst /,$$S,$$$(@:.bin=.ld65-err)))
|
||||
|
||||
ifneq ($(wildcard ref/$1.ld65err-ref),)
|
||||
@echo cat $$(@:.bin=.ld65-err)
|
||||
cat $$(@:.bin=.ld65-err)
|
||||
@echo
|
||||
@echo
|
||||
@echo $(CAT) $$(@:.bin=.ld65-err)
|
||||
# FIXME: somehow this refuses to work in cmd.exe
|
||||
ifndef CMD_EXE
|
||||
$(call CAT,$$(@:.bin=.ld65-err))
|
||||
-diff -u ref/$1.ld65err-ref $$(@:.bin=.ld65-err)
|
||||
@echo
|
||||
@echo
|
||||
endif
|
||||
$(ISEQUAL) --wildcards ref/$1.ld65err-ref $$(@:.bin=.ld65-err)
|
||||
else
|
||||
ifneq ($(wildcard $(WORKDIR)/$1.ld65-err),)
|
||||
|
@ -88,14 +97,14 @@ endif
|
|||
|
||||
# compile with listing file
|
||||
ifeq ($(wildcard control/$1.err),)
|
||||
$(CA65) -t none -l $$(@:.bin=.list-lst) -o $$(@:.bin=.list-o) $$< > $$(@:.bin=.list-err) 2>&1
|
||||
$(CA65) -t none -l $$(@:.bin=.list-lst) -o $$(@:.bin=.list-o) $$< > $$(@:.bin=.list-err) $(ERRDIR)
|
||||
ifeq ($(wildcard control/$1.no-ld65),)
|
||||
$(LD65) -t none -o $$(@:.bin=.list-bin) $$(@:.bin=.list-o) none.lib > $$(@:.bin=.list-ld65-err) 2>&1
|
||||
$(LD65) -t none -o $$(@:.bin=.list-bin) $$(@:.bin=.list-o) none.lib > $$(@:.bin=.list-ld65-err) $(ERRDIR)
|
||||
endif
|
||||
else
|
||||
$(CA65) -t none -l $$(@:.bin=.list-lst) -o $$(@:.bin=.list-o) $$< > $$(@:.bin=.list-err) 2>&1 || true
|
||||
$(CA65) -t none -l $$(@:.bin=.list-lst) -o $$(@:.bin=.list-o) $$< > $$(@:.bin=.list-err) $(ERRDIR) || $(TRUE)
|
||||
ifeq ($(wildcard control/$1.no-ld65),)
|
||||
$(LD65) -t none -o $$(@:.bin=.list-bin) $$(@:.bin=.list-o) none.lib > $$(@:.bin=.list-ld65-err) 2>&1 || true
|
||||
$(LD65) -t none -o $$(@:.bin=.list-bin) $$(@:.bin=.list-o) none.lib > $$(@:.bin=.list-ld65-err) $(ERRDIR) || $(TRUE)
|
||||
endif
|
||||
endif
|
||||
|
||||
|
|
9
test/err/bug1890.c
Normal file
9
test/err/bug1890.c
Normal file
|
@ -0,0 +1,9 @@
|
|||
/* bug #1890 - Overflow in enumerator value is not detected */
|
||||
|
||||
#include <limits.h>
|
||||
enum { a = ULONG_MAX, b } c = b;
|
||||
|
||||
int main(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
8
test/err/bug1893.c
Normal file
8
test/err/bug1893.c
Normal file
|
@ -0,0 +1,8 @@
|
|||
/* bug #1893 - Compiler accepts a ternary expression where it shouldn't */
|
||||
|
||||
int main(void)
|
||||
{
|
||||
int a, b, c;
|
||||
a == 1? b : c = 3;
|
||||
return 0;
|
||||
}
|
|
@ -58,6 +58,12 @@ $(ISEQUAL): ../isequal.c | $(WORKDIR)
|
|||
|
||||
define PRG_template
|
||||
|
||||
# should compile, but gives an error
|
||||
$(WORKDIR)/int-static-1888.$1.$2.prg: int-static-1888.c | $(WORKDIR)
|
||||
@echo "FIXME: " $$@ "currently does not compile."
|
||||
$(if $(QUIET),echo misc/int-static-1888.$1.$2.prg)
|
||||
$(NOT) $(CC65) -t sim$2 -$1 -o $$@ $$< $(NULLERR)
|
||||
|
||||
# should compile, but gives an error
|
||||
$(WORKDIR)/bug1768.$1.$2.prg: bug1768.c | $(WORKDIR)
|
||||
@echo "FIXME: " $$@ "currently does not compile."
|
||||
|
|
|
@ -20,6 +20,28 @@ compiler is working as expected (when the tests behave as described):
|
|||
library.
|
||||
|
||||
/ref - These tests produce output that must be compared with reference output.
|
||||
Normally the reference output is produced by compiling the program on the
|
||||
host (using gcc mostly) and then running them on the host. Tests should
|
||||
be tweaked to produce the same output as on the host in the cases where
|
||||
it would be different.
|
||||
|
||||
The Makefile also handles some special cases (add the tests to the
|
||||
respective list in the makefile):
|
||||
|
||||
- Sometimes we want to check the warnings produced by the compiler. In
|
||||
that case use the CUSTOMSOURCES list. Whatever output the compiler writes
|
||||
to stderr will be compared against the matching .cref file. There is an
|
||||
example in custom-reference.c/.cref
|
||||
|
||||
- Sometimes we want to check what kind of output the compiler produces
|
||||
for a file that does not compile. In that case use the ERRORSOURCES list.
|
||||
There is an example in custom-reference-error.c/.cref
|
||||
|
||||
Warning: please understand that comparing the compiler output against
|
||||
a reference produces a moving target, ie the tests may break randomly
|
||||
at any time when the compiler output changes for whatever reason. So
|
||||
only ever use this as a last resort when something can not be tested by
|
||||
other means.
|
||||
|
||||
/err - contains tests that MUST NOT compile
|
||||
|
||||
|
|
|
@ -11,12 +11,14 @@ ifdef CMD_EXE
|
|||
NULLDEV = nul:
|
||||
MKDIR = mkdir $(subst /,\,$1)
|
||||
RMDIR = -rmdir /s /q $(subst /,\,$1)
|
||||
CP=copy
|
||||
else
|
||||
S = /
|
||||
EXE =
|
||||
NULLDEV = /dev/null
|
||||
MKDIR = mkdir -p $1
|
||||
RMDIR = $(RM) -r $1
|
||||
CP=cp
|
||||
endif
|
||||
|
||||
ifdef QUIET
|
||||
|
@ -42,24 +44,47 @@ CFLAGS = -O2 -Wall -W -Wextra -funsigned-char -fwrapv -fno-strict-overflow
|
|||
|
||||
.PHONY: all clean
|
||||
|
||||
SOURCES := $(wildcard *.c)
|
||||
# list of sources that produces warnings that we want to check. a .cref file
|
||||
# containing the exact output is required.
|
||||
CUSTOMSOURCES = \
|
||||
custom-reference.c
|
||||
|
||||
# list of sources that produce a compiler error. a .cref files containing the
|
||||
# exact error output is required
|
||||
ERRORSOURCES = \
|
||||
custom-reference-error.c
|
||||
|
||||
SOURCES := $(filter-out $(CUSTOMSOURCES) $(ERRORSOURCES),$(wildcard *.c))
|
||||
|
||||
REFS = $(SOURCES:%.c=$(WORKDIR)/%.ref)
|
||||
CUSTOMREFS = $(CUSTOMSOURCES:%.c=$(WORKDIR)/%.cref) $(ERRORSOURCES:%.c=$(WORKDIR)/%.cref)
|
||||
|
||||
TESTS = $(foreach option,$(OPTIONS),$(SOURCES:%.c=$(WORKDIR)/%.$(option).6502.prg))
|
||||
TESTS += $(foreach option,$(OPTIONS),$(SOURCES:%.c=$(WORKDIR)/%.$(option).65c02.prg))
|
||||
|
||||
all: $(REFS) $(TESTS)
|
||||
CUSTOMTESTS = $(foreach option,$(OPTIONS),$(CUSTOMSOURCES:%.c=$(WORKDIR)/%.$(option).6502.custom.prg))
|
||||
CUSTOMTESTS += $(foreach option,$(OPTIONS),$(CUSTOMSOURCES:%.c=$(WORKDIR)/%.$(option).65c02.custom.prg))
|
||||
|
||||
ERRORTESTS = $(foreach option,$(OPTIONS),$(ERRORSOURCES:%.c=$(WORKDIR)/%.$(option).6502.error.prg))
|
||||
ERRORTESTS += $(foreach option,$(OPTIONS),$(ERRORSOURCES:%.c=$(WORKDIR)/%.$(option).65c02.error.prg))
|
||||
|
||||
all: $(CUSTOMREFS) $(REFS) $(TESTS) $(CUSTOMTESTS) $(ERRORTESTS)
|
||||
|
||||
$(WORKDIR):
|
||||
$(call MKDIR,$(WORKDIR))
|
||||
|
||||
$(ISEQUAL): ../isequal.c | $(WORKDIR)
|
||||
$(CC) $(CFLAGS) -o $@ $<
|
||||
|
||||
$(WORKDIR)/%.cref: %.cref | $(WORKDIR)
|
||||
$(if $(QUIET),echo ref/$*.cref)
|
||||
$(CP) $*.cref $@
|
||||
|
||||
$(WORKDIR)/%.ref: %.c | $(WORKDIR)
|
||||
$(if $(QUIET),echo ref/$*.host)
|
||||
$(CC) $(CFLAGS) -o $(WORKDIR)/$*.host $< $(NULLERR)
|
||||
$(WORKDIR)$S$*.host > $@
|
||||
|
||||
$(ISEQUAL): ../isequal.c | $(WORKDIR)
|
||||
$(CC) $(CFLAGS) -o $@ $<
|
||||
|
||||
# "yaccdbg.c" includes "yacc.c".
|
||||
# yaccdbg's built files must depend on both of them.
|
||||
#
|
||||
|
@ -78,8 +103,43 @@ $(WORKDIR)/%.$1.$2.prg: %.c $(WORKDIR)/%.ref $(ISEQUAL)
|
|||
|
||||
endef # PRG_template
|
||||
|
||||
# extra template for the case when compilation works, but we still want to
|
||||
# compare the warning output with our custom reference
|
||||
define PRG_custom_template
|
||||
|
||||
$(WORKDIR)/%.$1.$2.custom.prg: %.c $(WORKDIR)/%.ref %.c $(WORKDIR)/%.cref $(ISEQUAL)
|
||||
$(if $(QUIET),echo cref/$$*.$1.$2.custom.prg)
|
||||
-$(CC65) -t sim$2 $$(CC65FLAGS) -$1 -o $$(@:.custom.prg=.s) $$< 2> $(WORKDIR)/$$*.$1.$2.cout
|
||||
$(CA65) -t sim$2 -o $$(@:.custom.prg=.o) $$(@:.custom.prg=.s) $(NULLERR)
|
||||
$(LD65) -t sim$2 -o $$@ $$(@:.custom.prg=.o) sim$2.lib $(NULLERR)
|
||||
$(SIM65) $(SIM65FLAGS) $$@ > $(WORKDIR)/$$*.$1.$2.out
|
||||
$(ISEQUAL) $(WORKDIR)/$$*.$1.$2.cout $(WORKDIR)/$$*.cref
|
||||
$(ISEQUAL) $(WORKDIR)/$$*.$1.$2.out $(WORKDIR)/$$*.ref
|
||||
|
||||
endef # PRG_error_template
|
||||
|
||||
# extra template for the case when compilation fails, but we still want to
|
||||
# compare the error output with our custom reference
|
||||
define PRG_error_template
|
||||
|
||||
$(WORKDIR)/%.$1.$2.error.prg: %.c $(WORKDIR)/%.cref $(ISEQUAL)
|
||||
$(if $(QUIET),echo cref/$$*.$1.$2.error.prg)
|
||||
-$(CC65) -t sim$2 $$(CC65FLAGS) -$1 -o $$(@:.error.prg=.s) $$< 2> $(WORKDIR)/$$*.$1.$2.cout
|
||||
# $(CA65) -t sim$2 -o $$(@:.error.prg=.o) $$(@:.error.prg=.s) $(NULLERR)
|
||||
# $(LD65) -t sim$2 -o $$@ $$(@:.error.prg=.o) sim$2.lib $(NULLERR)
|
||||
# $(SIM65) $(SIM65FLAGS) $$@ > $(WORKDIR)/$$*.$1.$2.out
|
||||
$(ISEQUAL) $(WORKDIR)/$$*.$1.$2.cout $(WORKDIR)/$$*.cref
|
||||
|
||||
endef # PRG_error_template
|
||||
|
||||
$(foreach option,$(OPTIONS),$(eval $(call PRG_template,$(option),6502)))
|
||||
$(foreach option,$(OPTIONS),$(eval $(call PRG_template,$(option),65c02)))
|
||||
|
||||
$(foreach option,$(OPTIONS),$(eval $(call PRG_custom_template,$(option),6502)))
|
||||
$(foreach option,$(OPTIONS),$(eval $(call PRG_custom_template,$(option),65c02)))
|
||||
|
||||
$(foreach option,$(OPTIONS),$(eval $(call PRG_error_template,$(option),6502)))
|
||||
$(foreach option,$(OPTIONS),$(eval $(call PRG_error_template,$(option),65c02)))
|
||||
|
||||
clean:
|
||||
@$(call RMDIR,$(WORKDIR))
|
||||
|
|
21
test/ref/custom-reference-error.c
Normal file
21
test/ref/custom-reference-error.c
Normal file
|
@ -0,0 +1,21 @@
|
|||
|
||||
/*
|
||||
this is an example (not actually a regression test) that shows how to
|
||||
make a check that compares the compiler (error-) output with a provided
|
||||
reference.
|
||||
|
||||
to produce a reference file, first make sure your program "works" as intended,
|
||||
then "make" in this directory once and copy the produced compiler output to
|
||||
the reference:
|
||||
|
||||
$ cp ../../testwrk/ref/custom-reference-error.g.6502.out custom-reference-error.cref
|
||||
|
||||
and then "make" again to confirm
|
||||
*/
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
printf("%02x", 0x42);
|
||||
n = 0; /* produce an error */
|
||||
/* another error */
|
||||
}
|
5
test/ref/custom-reference-error.cref
Normal file
5
test/ref/custom-reference-error.cref
Normal file
|
@ -0,0 +1,5 @@
|
|||
custom-reference-error.c:18: Error: Call to undeclared function 'printf'
|
||||
custom-reference-error.c:19: Error: Undefined symbol: 'n'
|
||||
custom-reference-error.c:21: Warning: Control reaches end of non-void function [-Wreturn-type]
|
||||
custom-reference-error.c:21: Warning: Parameter 'argc' is never used
|
||||
custom-reference-error.c:21: Warning: Parameter 'argv' is never used
|
24
test/ref/custom-reference.c
Normal file
24
test/ref/custom-reference.c
Normal file
|
@ -0,0 +1,24 @@
|
|||
|
||||
/*
|
||||
this is an example (not actually a regression test) that shows how to
|
||||
make a check that compares the compiler (error-) output with a provided
|
||||
reference.
|
||||
|
||||
to produce a reference file, first make sure your program "works" as intended,
|
||||
then "make" in this directory once and copy the produced compiler output to
|
||||
the reference:
|
||||
|
||||
$ cp ../../testwrk/ref/custom-reference.g.6502.out custom-reference.cref
|
||||
|
||||
and then "make" again to confirm
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
printf("%02x", 0x42);
|
||||
/* produce a warning */
|
||||
return 0;
|
||||
}
|
2
test/ref/custom-reference.cref
Normal file
2
test/ref/custom-reference.cref
Normal file
|
@ -0,0 +1,2 @@
|
|||
custom-reference.c:24: Warning: Parameter 'argc' is never used
|
||||
custom-reference.c:24: Warning: Parameter 'argv' is never used
|
|
@ -564,9 +564,9 @@ int main (void)
|
|||
|
||||
/* Output the result */
|
||||
if (Failures) {
|
||||
printf ("%u tests, %u failures\n", Tests, Failures);
|
||||
printf ("sprintf-test: %u tests, %u failures\n", Tests, Failures);
|
||||
} else {
|
||||
printf ("%u tests: Ok\n", Tests);
|
||||
printf ("sprintf-test: %u tests: Ok\n", Tests);
|
||||
}
|
||||
|
||||
/* Wait for a key so we can read the result */
|
||||
|
|
|
@ -1,41 +1,41 @@
|
|||
/* Bug #1408: Signed char type comparisons with unsigned numeric constants */
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
static int failures = 0;
|
||||
static signed char x = -1;
|
||||
|
||||
int main(void)
|
||||
{
|
||||
if (!(x > -2u)) {
|
||||
printf("x > -2u should be true\n");
|
||||
++failures;
|
||||
}
|
||||
if (!(x > 0u)) {
|
||||
printf("x > 0u should be true\n");
|
||||
++failures;
|
||||
}
|
||||
if (!(x > 255u)) {
|
||||
printf("x > 255u should be true\n");
|
||||
++failures;
|
||||
}
|
||||
|
||||
if (!(-2u < x)) {
|
||||
printf("-2u < x should be true\n");
|
||||
++failures;
|
||||
}
|
||||
if (!(0u < x)) {
|
||||
printf("0u < x should be true\n");
|
||||
++failures;
|
||||
}
|
||||
if (!(255u < x)) {
|
||||
printf("255u < x should be true\n");
|
||||
++failures;
|
||||
}
|
||||
|
||||
if (failures != 0) {
|
||||
printf("Failures: %d\n", failures);
|
||||
}
|
||||
|
||||
return failures;
|
||||
}
|
||||
/* Bug #1408: Signed char type comparisons with unsigned numeric constants */
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
static int failures = 0;
|
||||
static signed char x = -1;
|
||||
|
||||
int main(void)
|
||||
{
|
||||
if (!(x > -2u)) {
|
||||
printf("x > -2u should be true\n");
|
||||
++failures;
|
||||
}
|
||||
if (!(x > 0u)) {
|
||||
printf("x > 0u should be true\n");
|
||||
++failures;
|
||||
}
|
||||
if (!(x > 255u)) {
|
||||
printf("x > 255u should be true\n");
|
||||
++failures;
|
||||
}
|
||||
|
||||
if (!(-2u < x)) {
|
||||
printf("-2u < x should be true\n");
|
||||
++failures;
|
||||
}
|
||||
if (!(0u < x)) {
|
||||
printf("0u < x should be true\n");
|
||||
++failures;
|
||||
}
|
||||
if (!(255u < x)) {
|
||||
printf("255u < x should be true\n");
|
||||
++failures;
|
||||
}
|
||||
|
||||
if (failures != 0) {
|
||||
printf("Failures: %d\n", failures);
|
||||
}
|
||||
|
||||
return failures;
|
||||
}
|
||||
|
|
|
@ -1,39 +1,39 @@
|
|||
/* Bug #1451 - local struct field access via the address of the struct */
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
typedef struct {
|
||||
int a;
|
||||
int b;
|
||||
} S;
|
||||
|
||||
int failures = 0;
|
||||
|
||||
int main(void)
|
||||
{
|
||||
S a = {2, 5};
|
||||
S b = {1, 4};
|
||||
S m[1] = {{6, 3}};
|
||||
S *p = &a;
|
||||
|
||||
(&a)->a += b.a;
|
||||
p->b += b.b;
|
||||
m->a += b.a;
|
||||
|
||||
if ((&a)->a != 3) {
|
||||
++failures;
|
||||
printf("Expected 3, got %d\n", (&a)->a);
|
||||
}
|
||||
|
||||
if (p->b != 9) {
|
||||
++failures;
|
||||
printf("Expected 9, got %d\n", p->b);
|
||||
}
|
||||
|
||||
if (m->a != 7) {
|
||||
++failures;
|
||||
printf("Expected 7, got %d\n", m->a);
|
||||
}
|
||||
|
||||
return failures;
|
||||
}
|
||||
/* Bug #1451 - local struct field access via the address of the struct */
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
typedef struct {
|
||||
int a;
|
||||
int b;
|
||||
} S;
|
||||
|
||||
int failures = 0;
|
||||
|
||||
int main(void)
|
||||
{
|
||||
S a = {2, 5};
|
||||
S b = {1, 4};
|
||||
S m[1] = {{6, 3}};
|
||||
S *p = &a;
|
||||
|
||||
(&a)->a += b.a;
|
||||
p->b += b.b;
|
||||
m->a += b.a;
|
||||
|
||||
if ((&a)->a != 3) {
|
||||
++failures;
|
||||
printf("Expected 3, got %d\n", (&a)->a);
|
||||
}
|
||||
|
||||
if (p->b != 9) {
|
||||
++failures;
|
||||
printf("Expected 9, got %d\n", p->b);
|
||||
}
|
||||
|
||||
if (m->a != 7) {
|
||||
++failures;
|
||||
printf("Expected 7, got %d\n", m->a);
|
||||
}
|
||||
|
||||
return failures;
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
|
||||
/* issue #1462 - Bit-fields are still broken */
|
||||
/* More tests on "op= expression result value" that a naive fix might fail with */
|
||||
/* When (un-)signedness involves with integral promotion */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <limits.h>
|
|
@ -1,12 +1,12 @@
|
|||
/* bug #1643, macro expansion in #include */
|
||||
|
||||
#define MKSTR(a) MKSTR_IMPL(a)
|
||||
#define MKSTR_IMPL(a) #a
|
||||
#define BUG1643_H bug1643.h
|
||||
|
||||
#include MKSTR(BUG1643_H)
|
||||
|
||||
int main(void)
|
||||
{
|
||||
return BUG1643_RESULT;
|
||||
}
|
||||
/* bug #1643, macro expansion in #include */
|
||||
|
||||
#define MKSTR(a) MKSTR_IMPL(a)
|
||||
#define MKSTR_IMPL(a) #a
|
||||
#define BUG1643_H bug1643.h
|
||||
|
||||
#include MKSTR(BUG1643_H)
|
||||
|
||||
int main(void)
|
||||
{
|
||||
return BUG1643_RESULT;
|
||||
}
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
/* bug #1643, macro expansion in #include */
|
||||
|
||||
#define STDIO_H <stdio.h>
|
||||
#include STDIO_H
|
||||
|
||||
#ifdef string
|
||||
#undef string
|
||||
#endif
|
||||
|
||||
#define string 0!%^&*/_=
|
||||
#include <string.h>
|
||||
|
||||
#define BUG1643_RESULT 0
|
||||
/* bug #1643, macro expansion in #include */
|
||||
|
||||
#define STDIO_H <stdio.h>
|
||||
#include STDIO_H
|
||||
|
||||
#ifdef string
|
||||
#undef string
|
||||
#endif
|
||||
|
||||
#define string 0!%^&*/_=
|
||||
#include <string.h>
|
||||
|
||||
#define BUG1643_RESULT 0
|
||||
|
|
|
@ -1,30 +1,30 @@
|
|||
/* OptCmp1 messed up with labels */
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
static int failures = 0;
|
||||
static unsigned int z = 0xFF23;
|
||||
|
||||
int main(void)
|
||||
{
|
||||
register unsigned int x = 0x200;
|
||||
register unsigned int y = 0;
|
||||
|
||||
do {
|
||||
++y;
|
||||
} while (--x);
|
||||
if (y != 0x200) {
|
||||
printf("y should be 0x200, not 0x%X.\n", y);
|
||||
++failures;;
|
||||
}
|
||||
|
||||
if ((z -= 0x23)) {
|
||||
/* Passed -- non-zero z looks like non-zero. */
|
||||
} else {
|
||||
/* Failed -- only the low byte of z was tested. */
|
||||
printf("Test thinks non-zero z is zero.\n");
|
||||
++failures;
|
||||
}
|
||||
|
||||
return failures;
|
||||
}
|
||||
/* OptCmp1 messed up with labels */
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
static int failures = 0;
|
||||
static unsigned int z = 0xFF23;
|
||||
|
||||
int main(void)
|
||||
{
|
||||
register unsigned int x = 0x200;
|
||||
register unsigned int y = 0;
|
||||
|
||||
do {
|
||||
++y;
|
||||
} while (--x);
|
||||
if (y != 0x200) {
|
||||
printf("y should be 0x200, not 0x%X.\n", y);
|
||||
++failures;;
|
||||
}
|
||||
|
||||
if ((z -= 0x23)) {
|
||||
/* Passed -- non-zero z looks like non-zero. */
|
||||
} else {
|
||||
/* Failed -- only the low byte of z was tested. */
|
||||
printf("Test thinks non-zero z is zero.\n");
|
||||
++failures;
|
||||
}
|
||||
|
||||
return failures;
|
||||
}
|
||||
|
|
|
@ -1,25 +1,25 @@
|
|||
/* Bug #1822 - Redefined macros failed to be all undefined with a single #undef */
|
||||
|
||||
#undef F
|
||||
#undef F
|
||||
|
||||
#define F 1
|
||||
#define F 1
|
||||
|
||||
#undef F
|
||||
#if defined F
|
||||
#error #undef F fails!
|
||||
#endif
|
||||
|
||||
#define F 0
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
int main(void)
|
||||
{
|
||||
if (F != 0)
|
||||
{
|
||||
printf("failed: F = %d\n", F);
|
||||
}
|
||||
return F;
|
||||
}
|
||||
/* Bug #1822 - Redefined macros failed to be all undefined with a single #undef */
|
||||
|
||||
#undef F
|
||||
#undef F
|
||||
|
||||
#define F 1
|
||||
#define F 1
|
||||
|
||||
#undef F
|
||||
#if defined F
|
||||
#error #undef F fails!
|
||||
#endif
|
||||
|
||||
#define F 0
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
int main(void)
|
||||
{
|
||||
if (F != 0)
|
||||
{
|
||||
printf("failed: F = %d\n", F);
|
||||
}
|
||||
return F;
|
||||
}
|
||||
|
|
|
@ -1,35 +1,35 @@
|
|||
/* Bug 1838 - function parameters declared as function types rather than function pointers */
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
static int failures = 0;
|
||||
|
||||
typedef int fn_t(int);
|
||||
|
||||
int main(void)
|
||||
{
|
||||
void foo(fn_t*);
|
||||
fn_t bar;
|
||||
|
||||
foo(bar);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void foo(int func(int))
|
||||
{
|
||||
int n = func(42);
|
||||
|
||||
if (n != 12) {
|
||||
printf("n = %d, expected: 12\n", n);
|
||||
++failures;
|
||||
}
|
||||
}
|
||||
|
||||
int bar(int a)
|
||||
{
|
||||
if (a != 42) {
|
||||
printf("a = %d, expected: 42\n", a);
|
||||
++failures;
|
||||
}
|
||||
return 12;
|
||||
}
|
||||
/* Bug 1838 - function parameters declared as function types rather than function pointers */
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
static int failures = 0;
|
||||
|
||||
typedef int fn_t(int);
|
||||
|
||||
int main(void)
|
||||
{
|
||||
void foo(fn_t*);
|
||||
fn_t bar;
|
||||
|
||||
foo(bar);
|
||||
return failures;
|
||||
}
|
||||
|
||||
void foo(int func(int))
|
||||
{
|
||||
int n = func(42);
|
||||
|
||||
if (n != 12) {
|
||||
printf("n = %d, expected: 12\n", n);
|
||||
++failures;
|
||||
}
|
||||
}
|
||||
|
||||
int bar(int a)
|
||||
{
|
||||
if (a != 42) {
|
||||
printf("a = %d, expected: 42\n", a);
|
||||
++failures;
|
||||
}
|
||||
return 12;
|
||||
}
|
||||
|
|
|
@ -1,46 +1,46 @@
|
|||
/* Bug #1847 - struct field access */
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
struct TestStruct {
|
||||
char a;
|
||||
char b;
|
||||
char c;
|
||||
};
|
||||
|
||||
struct TestStruct s0[2] = { {0xFF, 0, 0xFF}, {0, 0x42, 0xFF} };
|
||||
struct TestStruct* s0Ptr = s0;
|
||||
|
||||
#define TEST_READ_SUB(X, E) \
|
||||
if ((X) != (E)) { \
|
||||
printf(#X ": 0x%X, expected: 0x%X\n", (X), (E)); \
|
||||
++failures; \
|
||||
}
|
||||
|
||||
#define TEST_READ(S, I, F, E) \
|
||||
TEST_READ_SUB(S[I].F, E) \
|
||||
TEST_READ_SUB((&S[I])->F, E) \
|
||||
TEST_READ_SUB((&S[I])[0].F, E) \
|
||||
TEST_READ_SUB(S##Ptr[I].F, E) \
|
||||
TEST_READ_SUB((&S##Ptr[I])->F, E) \
|
||||
TEST_READ_SUB((&(S##Ptr[I]))[0].F, E) \
|
||||
TEST_READ_SUB((&(*S##Ptr))[I].F, E) \
|
||||
TEST_READ_SUB((&(*S##Ptr)+I)->F, E) \
|
||||
TEST_READ_SUB((S##Ptr+I)->F, E) \
|
||||
TEST_READ_SUB((S##Ptr+I)[0].F, E)
|
||||
|
||||
static unsigned failures = 0;
|
||||
|
||||
int main(void) {
|
||||
struct TestStruct s1[2] = { {0xFF, 0, 0xFF}, {0, 42, 0xFF} };
|
||||
struct TestStruct* s1Ptr = s1;
|
||||
|
||||
TEST_READ(s0, 1, b, 0x42)
|
||||
TEST_READ(s1, 1, b, 42)
|
||||
|
||||
if (failures > 0) {
|
||||
printf("Failures: %u\n", failures);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
/* Bug #1847 - struct field access */
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
struct TestStruct {
|
||||
char a;
|
||||
char b;
|
||||
char c;
|
||||
};
|
||||
|
||||
struct TestStruct s0[2] = { {0xFF, 0, 0xFF}, {0, 0x42, 0xFF} };
|
||||
struct TestStruct* s0Ptr = s0;
|
||||
|
||||
#define TEST_READ_SUB(X, E) \
|
||||
if ((X) != (E)) { \
|
||||
printf(#X ": 0x%X, expected: 0x%X\n", (X), (E)); \
|
||||
++failures; \
|
||||
}
|
||||
|
||||
#define TEST_READ(S, I, F, E) \
|
||||
TEST_READ_SUB(S[I].F, E) \
|
||||
TEST_READ_SUB((&S[I])->F, E) \
|
||||
TEST_READ_SUB((&S[I])[0].F, E) \
|
||||
TEST_READ_SUB(S##Ptr[I].F, E) \
|
||||
TEST_READ_SUB((&S##Ptr[I])->F, E) \
|
||||
TEST_READ_SUB((&(S##Ptr[I]))[0].F, E) \
|
||||
TEST_READ_SUB((&(*S##Ptr))[I].F, E) \
|
||||
TEST_READ_SUB((&(*S##Ptr)+I)->F, E) \
|
||||
TEST_READ_SUB((S##Ptr+I)->F, E) \
|
||||
TEST_READ_SUB((S##Ptr+I)[0].F, E)
|
||||
|
||||
static unsigned failures = 0;
|
||||
|
||||
int main(void) {
|
||||
struct TestStruct s1[2] = { {0xFF, 0, 0xFF}, {0, 42, 0xFF} };
|
||||
struct TestStruct* s1Ptr = s1;
|
||||
|
||||
TEST_READ(s0, 1, b, 0x42)
|
||||
TEST_READ(s1, 1, b, 42)
|
||||
|
||||
if (failures > 0) {
|
||||
printf("Failures: %u\n", failures);
|
||||
}
|
||||
|
||||
return failures;
|
||||
}
|
||||
|
|
21
test/val/bug1853-inline-asm.c
Normal file
21
test/val/bug1853-inline-asm.c
Normal file
|
@ -0,0 +1,21 @@
|
|||
|
||||
/* #1853 - Regression on inline assembly expression evaluation */
|
||||
|
||||
int main(void)
|
||||
{
|
||||
/*
|
||||
compiles with e.g. Git 2f4e2a3 to the expected
|
||||
|
||||
lda 1
|
||||
lda 1 + 1
|
||||
rts
|
||||
|
||||
However, with the current HEAD, it compiles to
|
||||
|
||||
lda 1
|
||||
lda
|
||||
*/
|
||||
__asm__("lda 1");
|
||||
__asm__("lda 1 + 1");
|
||||
return 0;
|
||||
}
|
19
test/val/bug1891.c
Normal file
19
test/val/bug1891.c
Normal file
|
@ -0,0 +1,19 @@
|
|||
/* bug #1891 - backslash/newline sequence in string constants is treated wrong */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
const char* a = "hello \
|
||||
world";
|
||||
const char* b = \
|
||||
"hello world";
|
||||
|
||||
int main(void)
|
||||
{
|
||||
if (strcmp(a, b) != 0) {
|
||||
printf("a:\n%s\n", a);
|
||||
printf("b:\n%s\n", b);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
160
test/val/const-side-effect.c
Normal file
160
test/val/const-side-effect.c
Normal file
|
@ -0,0 +1,160 @@
|
|||
/* Check code generation for constant operands with side-effects */
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
static int failures = 0;
|
||||
|
||||
#define TEST(X, Y, L) \
|
||||
if (x != X || y != Y) { \
|
||||
printf("Failed: " L "\nExpected: x = " #X ", y = " #Y ", got: x = %d, y = %d\n\n", x, y); \
|
||||
++failures; \
|
||||
}
|
||||
|
||||
#define TEST_LINE_UNARY(OP, RH, ID) \
|
||||
"x = " #OP "(set(&y, " #ID "), " #RH ")"
|
||||
|
||||
#define TEST_UNARY(OP, RH, RS, ID) \
|
||||
x = -!(RS), y = -!(RS); \
|
||||
x = OP (set(&y, ID), RH); \
|
||||
TEST(RS, ID, TEST_LINE_UNARY(OP, RH, ID))
|
||||
|
||||
#define TEST_LINE_RHS_EFFECT(LH, OP, RH, ID) \
|
||||
"x = " #LH " " #OP " (set(&y, " #ID "), " #RH ")"
|
||||
|
||||
#define TEST_LINE_LHS_EFFECT(LH, OP, RH, ID) \
|
||||
"y = (set(&x, " #ID "), " #LH ") " #OP " " #RH
|
||||
|
||||
#define TEST_BINARY(LH, OP, RH, RS, ID) \
|
||||
x = -!(RS), y = -!(RS); \
|
||||
x = LH OP (set(&y, ID), RH); \
|
||||
TEST(RS, ID, TEST_LINE_RHS_EFFECT(LH, OP, RH, ID)) \
|
||||
y = -!(RS), x = -!(RS); \
|
||||
y = (set(&x, ID), LH) OP RH; \
|
||||
TEST(ID, RS, TEST_LINE_LHS_EFFECT(LH, OP, RH, ID)) \
|
||||
y = -!(RS); \
|
||||
x = (set(&x, LH), x) OP (set(&y, ID), RH); \
|
||||
TEST(RS, ID, TEST_LINE_RHS_EFFECT((set(&x, LH), x), OP, RH, ID)) \
|
||||
x = -!(RS); \
|
||||
y = (set(&x, ID), LH) OP (set(&y, RH), y); \
|
||||
TEST(ID, RS, TEST_LINE_LHS_EFFECT(LH, OP, (set(&y, RH), y), ID))
|
||||
|
||||
#define TEST_LINE_RHS_EFFECT_WITH_CAST(LT, LH, OP, RT, RH, ID) \
|
||||
"x = (" #LT ")" #LH " " #OP " (" #RT ")(set(&y, " #ID "), " #RH ")"
|
||||
|
||||
#define TEST_LINE_LHS_EFFECT_WITH_CAST(LT, LH, OP, RT, RH, ID) \
|
||||
"y = (" #LT ")(set(&x, " #ID "), " #LH ") " #OP " (" #RT ")" #RH
|
||||
|
||||
#define TEST_BINARY_WITH_CAST(LT, LH, OP, RT, RH, RS, ID) \
|
||||
x = -!(RS), y = -!(RS); \
|
||||
x = (LT)LH OP (RT)(set(&y, ID), RH); \
|
||||
TEST(RS, ID, TEST_LINE_RHS_EFFECT_WITH_CAST(LT, LH, OP, RT, RH, ID)) \
|
||||
y = -!(RS), x = -!(RS); \
|
||||
y = (LT)(set(&x, ID), LH) OP (RT)RH; \
|
||||
TEST(ID, RS, TEST_LINE_LHS_EFFECT_WITH_CAST(LT, LH, OP, RT, RH, ID)) \
|
||||
y = -!(RS); \
|
||||
x = (LT)(set(&x, LH), x) OP (RT)(set(&y, ID), RH); \
|
||||
TEST(RS, ID, TEST_LINE_RHS_EFFECT_WITH_CAST(LT, (set(&x, LH), x), OP, RT, RH, ID)) \
|
||||
x = -!(RS); \
|
||||
y = (LT)(set(&x, ID), LH) OP (RT)(set(&y, RH), y); \
|
||||
TEST(ID, RS, TEST_LINE_LHS_EFFECT_WITH_CAST(LT, LH, OP, RT, (set(&y, RH), y), ID))
|
||||
|
||||
void set(int *p, int q)
|
||||
{
|
||||
*p = q;
|
||||
}
|
||||
|
||||
int twice(int a)
|
||||
{
|
||||
return a * 2;
|
||||
}
|
||||
|
||||
int (*twicep)(int) = twice;
|
||||
|
||||
void test_unary(void)
|
||||
{
|
||||
int x, y;
|
||||
|
||||
TEST_UNARY(+, 42, 42, 1);
|
||||
TEST_UNARY(-, -42, 42, 2);
|
||||
TEST_UNARY(~, ~42, 42, 3);
|
||||
TEST_UNARY(!, 42, 0, 4);
|
||||
}
|
||||
|
||||
void test_binary_arithmetic(void)
|
||||
{
|
||||
int x, y;
|
||||
|
||||
TEST_BINARY(41, +, 1, 42, 1)
|
||||
TEST_BINARY(42, +, 0, 42, 1)
|
||||
|
||||
TEST_BINARY(43, -, 1, 42, 2)
|
||||
TEST_BINARY(42, -, 0, 42, 2)
|
||||
|
||||
TEST_BINARY(6, *, 7, 42, 3)
|
||||
TEST_BINARY(42, *, 1, 42, 3)
|
||||
TEST_BINARY(-42, *, -1, 42, 3)
|
||||
|
||||
TEST_BINARY(126, /, 3, 42, 4)
|
||||
TEST_BINARY(42, /, 1, 42, 4)
|
||||
TEST_BINARY(-42, /, -1, 42, 4)
|
||||
|
||||
TEST_BINARY(85, %, 43, 42, 5)
|
||||
TEST_BINARY(10794, %, 256, 42, 5)
|
||||
|
||||
TEST_BINARY(84, >>, 1, 42, 6)
|
||||
TEST_BINARY(42, >>, 0, 42, 6)
|
||||
TEST_BINARY(10752, >>, 8, 42, 6)
|
||||
TEST_BINARY(21504, >>, 9, 42, 6)
|
||||
|
||||
TEST_BINARY(21, <<, 1, 42, 7)
|
||||
TEST_BINARY(42, <<, 0, 42, 7)
|
||||
TEST_BINARY(42, <<, 8, 10752, 7)
|
||||
|
||||
TEST_BINARY(59, &, 238, 42, 8)
|
||||
TEST_BINARY(42, &, 0, 0, 8)
|
||||
TEST_BINARY(42, &, -1, 42, 8)
|
||||
|
||||
TEST_BINARY(34, |, 10, 42, 9)
|
||||
TEST_BINARY(42, |, 0, 42, 9)
|
||||
TEST_BINARY(34, |, -1, -1, 9)
|
||||
|
||||
TEST_BINARY(59, ^, 17, 42, 10)
|
||||
TEST_BINARY(42, ^, 0, 42, 10)
|
||||
TEST_BINARY(~42, ^, -1, 42, 10)
|
||||
}
|
||||
|
||||
void test_binary_comparison(void)
|
||||
{
|
||||
int x, y;
|
||||
|
||||
TEST_BINARY(42, ==, 42, 1, 11)
|
||||
|
||||
TEST_BINARY(42, !=, 43, 1, 12)
|
||||
TEST_BINARY_WITH_CAST(signed char, 42, !=, long, 65536L, 1, 12)
|
||||
TEST_BINARY_WITH_CAST(long, 65536L, !=, signed char, 42, 1, 12)
|
||||
|
||||
TEST_BINARY(42, >, 41, 1, 13)
|
||||
TEST_BINARY_WITH_CAST(int, 0, >, unsigned, 42, 0, 13)
|
||||
|
||||
TEST_BINARY(42, <, 43, 1, 14)
|
||||
TEST_BINARY_WITH_CAST(unsigned, 42, <, int, 0, 0, 14)
|
||||
|
||||
TEST_BINARY(42, >=, 0, 1, 15)
|
||||
TEST_BINARY_WITH_CAST(unsigned, 42, >=, int, 0, 1, 15)
|
||||
|
||||
TEST_BINARY(42, <=, 43, 1, 16)
|
||||
TEST_BINARY_WITH_CAST(int, 0, <=, unsigned, 42, 1, 16)
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
test_unary();
|
||||
test_binary_arithmetic();
|
||||
test_binary_comparison();
|
||||
|
||||
if (failures != 0) {
|
||||
printf("Failures: %d\n", failures);
|
||||
}
|
||||
|
||||
return failures;
|
||||
}
|
|
@ -1,60 +1,60 @@
|
|||
/* Tests for predefined macro __COUNTER__ */
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
static int failures = 0;
|
||||
|
||||
#if __COUNTER__ /* 0 */
|
||||
# error __COUNTER__ should begin at 0!
|
||||
#elif __COUNTER__ == 1 /* 1 */
|
||||
# define CONCAT(a,b) CONCAT_impl_(a,b)
|
||||
# define CONCAT_impl_(a,b) a##b
|
||||
#endif
|
||||
|
||||
#line 42 "What is the answer?"
|
||||
int CONCAT(ident,__COUNTER__)[0+__LINE__] = {__LINE__}, CONCAT(ident,__COUNTER__)[0+__LINE__] = {__LINE__}; /* 2,3 */
|
||||
|
||||
#if __COUNTER__ == 4 ? 1 || __COUNTER__ : 0 && __COUNTER__ /* 4,5,6 */
|
||||
_Static_assert(__COUNTER__ == 7, "__COUNTER__ should be 7 here!"); /* 7 */
|
||||
# define GET_COUNTER() __COUNTER__
|
||||
# define GET_LINE() __LINE__
|
||||
# warning __COUNTER__ in #warning is just output as text and will never increase!
|
||||
#else
|
||||
# if __COUNTER__ + __COUNTER__ + __COUNTER__ /* Skipped as a whole and not incrementing */
|
||||
# endif
|
||||
# error __COUNTER__ is skipped along with the whole #error line and will never increase anyways! */
|
||||
#endif
|
||||
|
||||
#include "counter.h"
|
||||
#include "counter.h"
|
||||
|
||||
_Static_assert(GET_COUNTER() == 10, "__COUNTER__ should be 10 here!"); /* 10 */
|
||||
|
||||
int main(void)
|
||||
{
|
||||
if (ident2[0] != 42) {
|
||||
printf("Expected ident2[0]: %s, got: %s\n", 42, ident2[0]);
|
||||
++failures;
|
||||
}
|
||||
|
||||
if (ident3[0] != 42) {
|
||||
printf("Expected ident3[0]: %s, got: %s\n", 42, ident3[0]);
|
||||
++failures;
|
||||
}
|
||||
|
||||
if (ident8 != 8) {
|
||||
printf("Expected ident8: %s, got: %s\n", 8, ident8);
|
||||
++failures;
|
||||
}
|
||||
|
||||
if (ident9 != 9) {
|
||||
printf("Expected ident9: %s, got: %s\n", 9, ident9);
|
||||
++failures;
|
||||
}
|
||||
|
||||
if (failures != 0) {
|
||||
printf("Failures: %d\n", failures);
|
||||
}
|
||||
|
||||
return failures;
|
||||
}
|
||||
/* Tests for predefined macro __COUNTER__ */
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
static int failures = 0;
|
||||
|
||||
#if __COUNTER__ /* 0 */
|
||||
# error __COUNTER__ should begin at 0!
|
||||
#elif __COUNTER__ == 1 /* 1 */
|
||||
# define CONCAT(a,b) CONCAT_impl_(a,b)
|
||||
# define CONCAT_impl_(a,b) a##b
|
||||
#endif
|
||||
|
||||
#line 42 "What is the answer?"
|
||||
int CONCAT(ident,__COUNTER__)[0+__LINE__] = {__LINE__}, CONCAT(ident,__COUNTER__)[0+__LINE__] = {__LINE__}; /* 2,3 */
|
||||
|
||||
#if __COUNTER__ == 4 ? 1 || __COUNTER__ : 0 && __COUNTER__ /* 4,5,6 */
|
||||
_Static_assert(__COUNTER__ == 7, "__COUNTER__ should be 7 here!"); /* 7 */
|
||||
# define GET_COUNTER() __COUNTER__
|
||||
# define GET_LINE() __LINE__
|
||||
# warning __COUNTER__ in #warning is just output as text and will never increase!
|
||||
#else
|
||||
# if __COUNTER__ + __COUNTER__ + __COUNTER__ /* Skipped as a whole and not incrementing */
|
||||
# endif
|
||||
# error __COUNTER__ is skipped along with the whole #error line and will never increase anyways! */
|
||||
#endif
|
||||
|
||||
#include "counter.h"
|
||||
#include "counter.h"
|
||||
|
||||
_Static_assert(GET_COUNTER() == 10, "__COUNTER__ should be 10 here!"); /* 10 */
|
||||
|
||||
int main(void)
|
||||
{
|
||||
if (ident2[0] != 42) {
|
||||
printf("Expected ident2[0]: %s, got: %s\n", 42, ident2[0]);
|
||||
++failures;
|
||||
}
|
||||
|
||||
if (ident3[0] != 42) {
|
||||
printf("Expected ident3[0]: %s, got: %s\n", 42, ident3[0]);
|
||||
++failures;
|
||||
}
|
||||
|
||||
if (ident8 != 8) {
|
||||
printf("Expected ident8: %s, got: %s\n", 8, ident8);
|
||||
++failures;
|
||||
}
|
||||
|
||||
if (ident9 != 9) {
|
||||
printf("Expected ident9: %s, got: %s\n", 9, ident9);
|
||||
++failures;
|
||||
}
|
||||
|
||||
if (failures != 0) {
|
||||
printf("Failures: %d\n", failures);
|
||||
}
|
||||
|
||||
return failures;
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* Tests for predefined macro __COUNTER__ */
|
||||
|
||||
#line GET_COUNTER() /* 1st: 8; 2nd: 9 */
|
||||
int CONCAT(ident,GET_LINE()) = GET_LINE();
|
||||
/* Tests for predefined macro __COUNTER__ */
|
||||
|
||||
#line GET_COUNTER() /* 1st: 8; 2nd: 9 */
|
||||
int CONCAT(ident,GET_LINE()) = GET_LINE();
|
||||
|
|
31
test/val/decl-extern-shadow.c
Normal file
31
test/val/decl-extern-shadow.c
Normal file
|
@ -0,0 +1,31 @@
|
|||
/* Test for shadowing and linkage of file-scope "static" and block-scope "extern" declarations */
|
||||
|
||||
static int g(int x); /* Generated functions with internal linkage are not always kept in cc65 */
|
||||
|
||||
int main(void)
|
||||
{
|
||||
char f = 'f'; /* Shadows global "int f(void)" (if any) */
|
||||
char c = 'c'; /* Shadows global "int c" (if any) */
|
||||
{
|
||||
void* f = 0; /* Shadows local "char f" */
|
||||
void* c = 0; /* Shadows local "char c" */
|
||||
{
|
||||
int f(void); /* Shadows local "char f" and "void* f" */
|
||||
extern int g(int); /* Shadows global "int g(int x)" */
|
||||
extern int c; /* Shadows local "char c" and "void* c" */
|
||||
return f() ^ g(c); /* Link to global "int g(int x)" */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int c = 42;
|
||||
|
||||
int f(void)
|
||||
{
|
||||
return 42;
|
||||
}
|
||||
|
||||
int g(int x)
|
||||
{
|
||||
return x;
|
||||
}
|
19
test/val/decl-mixed-specifiers.c
Normal file
19
test/val/decl-mixed-specifiers.c
Normal file
|
@ -0,0 +1,19 @@
|
|||
/* bug 1888 - cc65 fails with storage class specifiers after type specifiers */
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
int const typedef volatile x_type, * const volatile y_type;
|
||||
|
||||
int static failures = 0;
|
||||
|
||||
int extern main(void);
|
||||
|
||||
int main(void)
|
||||
{
|
||||
volatile static x_type const x = 42, * const volatile y[] = { 1 ? &x : (y_type)0 };
|
||||
if (**y != 42) {
|
||||
++failures;
|
||||
printf("y = %d, Expected: 42\n", **y);
|
||||
}
|
||||
return failures;
|
||||
}
|
|
@ -26,15 +26,17 @@ void done()
|
|||
|
||||
void m1(void)
|
||||
{
|
||||
c1 = c1*5; /* char = char * lit */
|
||||
c1 = c1*5; /* char = char * lit */
|
||||
c2 = c1*c3; /* char = char * char */
|
||||
|
||||
c2 = c1 *c3; /* char = char * char */
|
||||
|
||||
uc1= uc1*5; /* uchar = uchar * lit *
|
||||
uc2=uc1*uc3; /* uchar = uchar * uchar */
|
||||
uc1 = uc1*3; /* uchar = uchar * lit */
|
||||
uc2 = uc1*uc3; /* uchar = uchar * uchar */
|
||||
|
||||
if(c2 != 25)
|
||||
failures++;
|
||||
|
||||
if(uc2 != 36)
|
||||
failures++;
|
||||
}
|
||||
|
||||
void m2(unsigned char uc)
|
||||
|
@ -96,6 +98,9 @@ int main(void)
|
|||
c1 = 1;
|
||||
c3 = 5;
|
||||
|
||||
uc1 = 2;
|
||||
uc3 = 6;
|
||||
|
||||
m1();
|
||||
|
||||
uc1 = 0x10;
|
||||
|
@ -107,7 +112,7 @@ int main(void)
|
|||
|
||||
ui3 = ui1*ui2; /* uint = uint * unit */
|
||||
|
||||
/*m3(TESTLIT);*/
|
||||
m3(TESTLIT);
|
||||
|
||||
success = failures;
|
||||
done();
|
||||
|
|
|
@ -1,33 +1,33 @@
|
|||
|
||||
/* Test for result types of certain unary operations */
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
signed char x;
|
||||
struct S {
|
||||
unsigned char a : 3;
|
||||
unsigned int b : 3;
|
||||
} s;
|
||||
|
||||
int main(void)
|
||||
{
|
||||
_Static_assert(sizeof (++x) == sizeof (char), "++x result should not have promoted type");
|
||||
_Static_assert(sizeof (--x) == sizeof (char), "--x result should not have promoted type");
|
||||
_Static_assert(sizeof (x++) == sizeof (char), "x++ result should not have promoted type");
|
||||
_Static_assert(sizeof (x--) == sizeof (char), "x-- result should not have promoted type");
|
||||
_Static_assert(sizeof (x=0) == sizeof (char), "x=0 result should not have promoted type");
|
||||
|
||||
_Static_assert(sizeof (+x) == sizeof (int), "+x result should have promoted type");
|
||||
_Static_assert(sizeof (-x) == sizeof (int), "-x result should have promoted type");
|
||||
_Static_assert(sizeof (~x) == sizeof (int), "~x result should have promoted type");
|
||||
|
||||
_Static_assert(sizeof (+s.a) == sizeof (int), "+s.a result should have promoted type");
|
||||
_Static_assert(sizeof (-s.a) == sizeof (int), "-s.a result should have promoted type");
|
||||
_Static_assert(sizeof (~s.a) == sizeof (int), "~s.a result should have promoted type");
|
||||
|
||||
_Static_assert(sizeof (+s.b) == sizeof (int), "+s.b result should have promoted type");
|
||||
_Static_assert(sizeof (-s.b) == sizeof (int), "-s.b result should have promoted type");
|
||||
_Static_assert(sizeof (~s.b) == sizeof (int), "~s.b result should have promoted type");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Test for result types of certain unary operations */
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
signed char x;
|
||||
struct S {
|
||||
unsigned char a : 3;
|
||||
unsigned int b : 3;
|
||||
} s;
|
||||
|
||||
int main(void)
|
||||
{
|
||||
_Static_assert(sizeof (++x) == sizeof (char), "++x result should not have promoted type");
|
||||
_Static_assert(sizeof (--x) == sizeof (char), "--x result should not have promoted type");
|
||||
_Static_assert(sizeof (x++) == sizeof (char), "x++ result should not have promoted type");
|
||||
_Static_assert(sizeof (x--) == sizeof (char), "x-- result should not have promoted type");
|
||||
_Static_assert(sizeof (x=0) == sizeof (char), "x=0 result should not have promoted type");
|
||||
|
||||
_Static_assert(sizeof (+x) == sizeof (int), "+x result should have promoted type");
|
||||
_Static_assert(sizeof (-x) == sizeof (int), "-x result should have promoted type");
|
||||
_Static_assert(sizeof (~x) == sizeof (int), "~x result should have promoted type");
|
||||
|
||||
_Static_assert(sizeof (+s.a) == sizeof (int), "+s.a result should have promoted type");
|
||||
_Static_assert(sizeof (-s.a) == sizeof (int), "-s.a result should have promoted type");
|
||||
_Static_assert(sizeof (~s.a) == sizeof (int), "~s.a result should have promoted type");
|
||||
|
||||
_Static_assert(sizeof (+s.b) == sizeof (int), "+s.b result should have promoted type");
|
||||
_Static_assert(sizeof (-s.b) == sizeof (int), "-s.b result should have promoted type");
|
||||
_Static_assert(sizeof (~s.b) == sizeof (int), "~s.b result should have promoted type");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
/* Test for PR #1833 fixes */
|
||||
|
||||
#define char 1
|
||||
|
||||
#if char && !int && L'A' - L'B' == 'A' - 'B' && L'A' == 'A'
|
||||
#else
|
||||
#error
|
||||
#endif
|
||||
|
||||
int main(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
/* Test for PR #1833 fixes */
|
||||
|
||||
#define char 1
|
||||
|
||||
#if char && !int && L'A' - L'B' == 'A' - 'B' && L'A' == 'A'
|
||||
#else
|
||||
#error
|
||||
#endif
|
||||
|
||||
int main(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -65,6 +65,13 @@ struct S {
|
|||
int b;
|
||||
};
|
||||
|
||||
/* _Static_assert can also appear in unions. */
|
||||
union U {
|
||||
int a;
|
||||
_Static_assert (1, "1 should still be true.");
|
||||
int b;
|
||||
};
|
||||
|
||||
|
||||
int main (void)
|
||||
{
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user