1
0
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:
mrdudz 2022-11-05 20:43:47 +01:00
commit 4a8c13fd93
106 changed files with 4156 additions and 1797 deletions

View File

@ -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
View 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

View File

@ -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 :)

View File

@ -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

View File

@ -414,6 +414,7 @@ TARGETS := \
define TARGET_recipe
@echo making samples for: $(T)
@$(MAKE) -j2 SYS:=$(T)
@$(MAKE) --no-print-directory clean SYS:=$(T)

View File

@ -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 */

View File

@ -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) {

View File

@ -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);

View File

@ -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)));

View File

@ -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 */

View File

@ -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;
}
}

View File

@ -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);

View File

@ -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 */
/*****************************************************************************/

View File

@ -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) */

View File

@ -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 */

View File

@ -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);

View File

@ -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);
}

View File

@ -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

View File

@ -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;

View File

@ -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 */

View File

@ -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 */

View File

@ -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;
}
}

View File

@ -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);

View File

@ -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);

View File

@ -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 */

View File

@ -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;
}
}

View File

@ -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. */

View File

@ -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;

View File

@ -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);
}

File diff suppressed because it is too large Load Diff

View File

@ -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 */

View 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");
}
}

View File

@ -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 */

View File

@ -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 */

View File

@ -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);
}

View File

@ -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 */

View File

@ -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 */

View File

@ -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);

View File

@ -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);

View File

@ -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

View File

@ -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;

View File

@ -372,6 +372,14 @@ Again:
return;
}
/* Decimal number offset? */
if (C == '+') {
NextChar ();
InfoIVal = GetDecimalToken ();
InfoTok = INFOTOK_OFFSET_INTCON;
return;
}
/* Other characters */
switch (C) {

View File

@ -48,6 +48,7 @@
typedef enum token_t {
INFOTOK_NONE,
INFOTOK_INTCON,
INFOTOK_OFFSET_INTCON,
INFOTOK_STRCON,
INFOTOK_CHARCON,
INFOTOK_IDENT,

View File

@ -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 */
{

View File

@ -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 */

View File

@ -761,6 +761,7 @@ TARGETS := \
define TARGET_recipe
@echo making targettest for: $(T)
@$(MAKE) -j2 SYS:=$(T)
@$(MAKE) --no-print-directory clean SYS:=$(T)

View File

@ -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)

View File

@ -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
View 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
View 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;
}

View File

@ -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."

View File

@ -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

View File

@ -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))

View 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 */
}

View 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

View 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;
}

View 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

View File

@ -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 */

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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>

View File

@ -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;
}

View File

@ -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

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View 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
View 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;
}

View 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;
}

View File

@ -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;
}

View File

@ -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();

View 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;
}

View 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;
}

View File

@ -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();

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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