1
0
mirror of https://github.com/cc65/cc65.git synced 2024-06-15 02:29:32 +00:00

Merge branch 'master' into underscores

This commit is contained in:
mrdudz 2022-11-19 17:11:11 +01:00
commit d6c37a757d
167 changed files with 6142 additions and 2906 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

@ -19,7 +19,7 @@ jobs:
- shell: bash
run: git config --global core.autocrlf input
- name: Checkout Source
uses: actions/checkout@v2
uses: actions/checkout@v3
- name: Do some simple style checks
shell: bash
@ -57,7 +57,7 @@ jobs:
run: git config --global core.autocrlf input
- name: Checkout Source
uses: actions/checkout@v2
uses: actions/checkout@v3
- name: Add msbuild to PATH
uses: microsoft/setup-msbuild@v1.1

View File

@ -18,7 +18,7 @@ jobs:
run: git config --global core.autocrlf input
- name: Checkout Source
uses: actions/checkout@v2
uses: actions/checkout@v3
- name: Add msbuild to PATH
uses: microsoft/setup-msbuild@v1.1
@ -44,7 +44,7 @@ jobs:
- shell: bash
run: git config --global core.autocrlf input
- name: Checkout Source
uses: actions/checkout@v2
uses: actions/checkout@v3
- name: Do some simple style checks
shell: bash
@ -97,7 +97,7 @@ jobs:
path: cc65-snapshot-win64.zip
- name: Get the online documents repo.
uses: actions/checkout@v2
uses: actions/checkout@v3
with:
repository: cc65/doc
path: doc.git

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

@ -57,7 +57,9 @@
;----------------------------------------------------------------------------
; I/O definitions
ACIA = $C088
Offset = $8F ; Move 6502 false read out of I/O to page $BF
ACIA = $C088-Offset
ACIA_DATA = ACIA+0 ; Data register
ACIA_STATUS = ACIA+1 ; Status register
ACIA_CMD = ACIA+2 ; Command register
@ -197,6 +199,7 @@ SER_OPEN:
asl
asl
asl
adc Offset ; Assume carry to be clear
tax
; Check if the handshake setting is valid

View File

@ -29,6 +29,6 @@ _tgi_unload:
jmp _mod_free ; Free the driver
no_driver:
lda #<TGI_ERR_NO_DRIVER
lda #TGI_ERR_NO_DRIVER
sta _tgi_error
rts

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

@ -1298,7 +1298,7 @@ static void EmitCode (EffAddr* A)
break;
case 2:
if (CPU == CPU_65816 && (A->AddrModeBit & (AM65_ABS | AM65_ABS_X | AM65_ABS_Y))) {
if (CPU == CPU_65816 && (A->AddrModeBit & (AM65_ABS | AM65_ABS_X | AM65_ABS_Y | AM65_ABS_X_IND))) {
/* This is a 16 bit mode that uses an address. If in 65816,
** mode, force this address into 16 bit range to allow
** addressing inside a 64K segment.

View File

@ -315,12 +315,41 @@ static void OpAssignBitField (const GenDesc* Gen, ExprDesc* Expr, const char* Op
} else if (Gen->Func == g_sub) {
g_dec (Flags | CF_CONST, Expr2.IVal);
} else {
if (Expr2.IVal == 0) {
/* Check for div by zero/mod by zero */
if (Gen->Func == g_div) {
Error ("Division by zero");
} else if (Gen->Func == g_mod) {
Error ("Modulo operation with zero");
if (!ED_IsUneval (Expr)) {
if (Expr2.IVal == 0) {
/* Check for div by zero/mod by zero */
if (Gen->Func == g_div) {
Warning ("Division by zero");
} else if (Gen->Func == g_mod) {
Warning ("Modulo operation with zero");
}
} else if (Gen->Func == g_asl || Gen->Func == g_asr) {
const Type* CalType = IntPromotion (Expr->Type);
unsigned ExprBits = BitSizeOf (CalType);
/* If the shift count is greater than or equal to the width of the
** promoted left operand, the behaviour is undefined according to
** the standard.
*/
if (Expr2.IVal < 0) {
Warning ("Negative shift count %ld treated as %u for %s",
Expr2.IVal,
(unsigned)Expr2.IVal & (ExprBits - 1),
GetBasicTypeName (CalType));
} else if (Expr2.IVal >= (long)ExprBits) {
Warning ("Shift count %ld >= width of %s treated as %u",
Expr2.IVal,
GetBasicTypeName (CalType),
(unsigned)Expr2.IVal & (ExprBits - 1));
}
/* Here we simply "wrap" the shift count around the width */
Expr2.IVal &= ExprBits - 1;
/* Additional check for bit-fields */
if (Expr2.IVal >= (long)Expr->Type->A.B.Width) {
Warning ("Shift count %ld >= width of bit-field", Expr2.IVal);
}
}
}
@ -495,12 +524,42 @@ static void OpAssignArithmetic (const GenDesc* Gen, ExprDesc* Expr, const char*
} else if (Gen->Func == g_sub) {
g_dec (Flags | CF_CONST, Expr2.IVal);
} else {
if (Expr2.IVal == 0) {
/* Check for div by zero/mod by zero */
if (Gen->Func == g_div) {
Error ("Division by zero");
} else if (Gen->Func == g_mod) {
Error ("Modulo operation with zero");
if (!ED_IsUneval (Expr)) {
if (Expr2.IVal == 0 && !ED_IsUneval (Expr)) {
/* Check for div by zero/mod by zero */
if (Gen->Func == g_div) {
Warning ("Division by zero");
} else if (Gen->Func == g_mod) {
Warning ("Modulo operation with zero");
}
} else if (Gen->Func == g_asl || Gen->Func == g_asr) {
const Type* CalType = IntPromotion (Expr->Type);
unsigned ExprBits = BitSizeOf (CalType);
/* If the shift count is greater than or equal to the width of the
** promoted left operand, the behaviour is undefined according to
** the standard.
*/
if (Expr2.IVal < 0) {
Warning ("Negative shift count %ld treated as %u for %s",
Expr2.IVal,
(unsigned)Expr2.IVal & (ExprBits - 1),
GetBasicTypeName (CalType));
} else if (Expr2.IVal >= (long)ExprBits) {
Warning ("Shift count %ld >= width of %s treated as %u",
Expr2.IVal,
GetBasicTypeName (CalType),
(unsigned)Expr2.IVal & (ExprBits - 1));
}
/* Here we simply "wrap" the shift count around the width */
Expr2.IVal &= ExprBits - 1;
/* Additional check for bit width */
if (Expr2.IVal >= (long)BitSizeOf (Expr->Type)) {
Warning ("Shift count %ld >= width of %s",
Expr2.IVal, GetBasicTypeName (Expr->Type));
}
}
}
Gen->Func (Flags | CF_CONST, Expr2.IVal);

View File

@ -41,6 +41,7 @@
/* common */
#include "addrsize.h"
#include "attrib.h"
#include "check.h"
#include "cpu.h"
#include "shift.h"
@ -64,7 +65,16 @@
#include "util.h"
#include "codegen.h"
/* This is a terrible hack that tries to combat the ever reoccuring issue with
Mingw and PRIXPTR - the macro should have been defined like this for us in
the first place.
NOTE: "I64u" works in the github actions now, so if your local mingw64 fails,
you probably have to update.
*/
#if defined(__MINGW64__)
#undef PRIXPTR
#define PRIXPTR "I64u"
#endif
/*****************************************************************************/
/* Helpers */
@ -1282,34 +1292,49 @@ void g_tosint (unsigned flags)
static void g_regchar (unsigned Flags)
/* Make sure, the value in the primary register is in the range of char. Truncate if necessary */
static void g_regchar (unsigned to)
/* Treat the value in the primary register as a char with specified signedness
** and convert it to an int (whose representation is irrelevent of signedness).
*/
{
unsigned L;
AddCodeLine ("ldx #$00");
if ((Flags & CF_UNSIGNED) == 0) {
/* Sign extend */
L = GetLocalLabel();
AddCodeLine ("cmp #$80");
AddCodeLine ("bcc %s", LocalLabelName (L));
AddCodeLine ("dex");
g_defcodelabel (L);
}
/* Since char is the smallest type supported here, we never need any info
** about the original type to "promote from it". However, we have to make
** sure the entire AX contains the correct char value as an int, since we
** will almost always use the char value as an int in AX directly in code
** generation (unless CF_FORCECHAR is specified). That is to say, we don't
** need the original "from" flags for the first conversion to char, but do
** need the original "to" flags as the new "from" flags for the conversion
** to int.
*/
g_regint (to | CF_FORCECHAR);
}
void g_regint (unsigned Flags)
/* Make sure, the value in the primary register an int. Convert if necessary */
void g_regint (unsigned from)
/* Convert the value in the primary register to an int (whose representation
** is irrelevent of signedness).
*/
{
switch (Flags & CF_TYPEMASK) {
switch (from & CF_TYPEMASK) {
case CF_CHAR:
if (Flags & CF_FORCECHAR) {
/* Conversion is from char */
g_regchar (Flags);
/* If the original value was forced to use only A, it must be
** extended from char to fill AX. Otherwise nothing to do here
** since AX would already have the correct int value.
*/
if (from & CF_FORCECHAR) {
AddCodeLine ("ldx #$00");
if ((from & CF_UNSIGNED) == 0) {
/* Sign extend */
unsigned L = GetLocalLabel();
AddCodeLine ("cmp #$80");
AddCodeLine ("bcc %s", LocalLabelName (L));
AddCodeLine ("dex");
g_defcodelabel (L);
}
break;
}
/* FALLTHROUGH */
@ -1318,21 +1343,27 @@ void g_regint (unsigned Flags)
break;
default:
typeerror (Flags);
typeerror (from);
}
}
void g_reglong (unsigned Flags)
/* Make sure, the value in the primary register a long. Convert if necessary */
void g_reglong (unsigned from)
/* Convert the value in the primary register to a long (whose representation
** is irrelevent of signedness).
*/
{
switch (Flags & CF_TYPEMASK) {
switch (from & CF_TYPEMASK) {
case CF_CHAR:
if (Flags & CF_FORCECHAR) {
/* If the original value was forced to use only A, it must be
** extended from char to long. Otherwise AX would already have
** the correct int value to be extened to long.
*/
if (from & CF_FORCECHAR) {
/* Conversion is from char */
if (Flags & CF_UNSIGNED) {
if (from & CF_UNSIGNED) {
if (IS_Get (&CodeSizeFactor) >= 200) {
AddCodeLine ("ldx #$00");
AddCodeLine ("stx sreg");
@ -1342,18 +1373,19 @@ void g_reglong (unsigned Flags)
}
} else {
if (IS_Get (&CodeSizeFactor) >= 366) {
g_regchar (Flags);
g_regint (from);
AddCodeLine ("stx sreg");
AddCodeLine ("stx sreg+1");
} else {
AddCodeLine ("jsr along");
}
}
break;
}
/* FALLTHROUGH */
case CF_INT:
if (Flags & CF_UNSIGNED) {
if (from & CF_UNSIGNED) {
if (IS_Get (&CodeSizeFactor) >= 200) {
AddCodeLine ("ldy #$00");
AddCodeLine ("sty sreg");
@ -1370,7 +1402,7 @@ void g_reglong (unsigned Flags)
break;
default:
typeerror (Flags);
typeerror (from);
}
}
@ -1507,48 +1539,49 @@ unsigned g_typeadjust (unsigned lhs, unsigned rhs)
unsigned g_typecast (unsigned lhs, unsigned rhs)
/* Cast the value in the primary register to the operand size that is flagged
** by the lhs value. Return the result value.
unsigned g_typecast (unsigned to, unsigned from)
/* Cast the value in the primary register to the specified operand size and
** signedness. Return the result flags.
*/
{
/* Check if a conversion is needed */
if ((rhs & CF_CONST) == 0) {
switch (lhs & CF_TYPEMASK) {
if ((from & CF_CONST) == 0) {
switch (to & CF_TYPEMASK) {
case CF_LONG:
/* We must promote the primary register to long */
g_reglong (rhs);
/* We must promote the primary register to long in EAX */
g_reglong (from);
break;
case CF_INT:
/* We must promote the primary register to int */
g_regint (rhs);
/* We must promote the primary register to int in AX */
g_regint (from);
break;
case CF_CHAR:
/* We must truncate the primary register to char */
g_regchar (lhs);
/* We must truncate the primary register to char and then
** sign-extend it to signed int in AX.
*/
g_regchar (to);
break;
default:
typeerror (lhs);
/* Since we are switching on "to", report an error on it */
typeerror (to);
}
}
/* Do not need any other action. If the left type is int, and the primary
/* Do not need any other action. If the "to" type is int, and the primary
** register is long, it will be automagically truncated. If the right hand
** side is const, it is not located in the primary register and handled by
** the expression parser code.
*/
/* Result is const if the right hand side was const */
lhs |= (rhs & CF_CONST);
to |= (from & CF_CONST);
/* The resulting type is that of the left hand side (that's why you called
** this function :-)
*/
return lhs;
/* The resulting type is "to" (that's why you called this function :-) */
return to;
}
@ -4561,7 +4594,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

@ -208,11 +208,15 @@ void g_toslong (unsigned flags);
void g_tosint (unsigned flags);
/* Make sure, the value on TOS is an int. Convert if necessary */
void g_regint (unsigned Flags);
/* Make sure, the value in the primary register an int. Convert if necessary */
void g_regint (unsigned from);
/* Convert the value in the primary register to an int (whose representation
** is irrelevent of signedness).
*/
void g_reglong (unsigned Flags);
/* Make sure, the value in the primary register a long. Convert if necessary */
void g_reglong (unsigned from);
/* Convert the value in the primary register to a long (whose representation
** is irrelevent of signedness).
*/
unsigned g_typeadjust (unsigned lhs, unsigned rhs);
/* Adjust the integer operands before doing a binary operation. lhs is a flags
@ -220,9 +224,9 @@ unsigned g_typeadjust (unsigned lhs, unsigned rhs);
** in (e)ax. The return value is the flags value for the resulting type.
*/
unsigned g_typecast (unsigned lhs, unsigned rhs);
/* Cast the value in the primary register to the operand size that is flagged
** by the lhs value. Return the result value.
unsigned g_typecast (unsigned to, unsigned from);
/* Cast the value in the primary register to the specified operand size and
** signedness. Return the result flags.
*/
void g_scale (unsigned flags, long val);

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,11 +142,11 @@ static void Parse (void)
}
/* Read declarations for this type */
Entry = 0;
Sym = 0;
comma = 0;
while (1) {
Declaration Decl;
Declarator Decl;
/* Read the next declaration */
ParseDecl (&Spec, &Decl, DM_NEED_IDENT);
@ -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);

File diff suppressed because it is too large Load Diff

View File

@ -239,23 +239,6 @@ extern const Type type_c_void_p[];
const char* GetBasicTypeName (const Type* T);
/* Return a const name string of the basic type.
** Return "type" for unknown basic types.
*/
const char* GetFullTypeName (const Type* T);
/* Return the full name string of the given type */
struct StrBuf* GetFullTypeNameBuf (struct StrBuf* S, const Type* T);
/* Return the full name string of the given type */
int GetQualifierTypeCodeNameBuf (struct StrBuf* S, TypeCode Qual, TypeCode IgnoredQual);
/* Return the names of the qualifiers of the type.
** Qualifiers to be ignored can be specified with the IgnoredQual flags.
** Return the count of added qualifier names.
*/
unsigned TypeLen (const Type* T);
/* Return the length of the type string */
@ -273,17 +256,26 @@ Type* TypeAlloc (unsigned Len);
void TypeFree (Type* T);
/* Free a type string */
#if defined(HAVE_INLINE)
INLINE void CopyTypeAttr (const Type* Src, Type* Dest)
/* Copy attribute data from Src to Dest */
{
Dest->A = Src->A;
}
#else
# define CopyTypeAttr(Src, Dest) ((Dest)->A = (Src)->A)
#endif
/*****************************************************************************/
/* Type info extraction */
/*****************************************************************************/
int SignExtendChar (int C);
/* Do correct sign extension of a character */
Type* GetCharArrayType (unsigned Len);
/* Return the type for a char array of the given length */
Type* GetImplicitFuncType (void);
/* Return a type string for an inplicitly declared function */
const Type* GetStructReplacementType (const Type* SType);
/* Get a replacement type for passing a struct/union in the primary register */
/* Do correct sign extension of a character to an int */
long GetIntegerTypeMin (const Type* Type);
/* Get the smallest possible value of the integer type.
@ -295,9 +287,51 @@ unsigned long GetIntegerTypeMax (const Type* Type);
** The type must have a known size.
*/
unsigned BitSizeOf (const Type* T);
/* Return the size (in bit-width) of a data type */
unsigned SizeOf (const Type* T);
/* Compute size (in bytes) of object represented by type array */
unsigned PSizeOf (const Type* T);
/* Compute size (in bytes) of pointee object */
unsigned CheckedBitSizeOf (const Type* T);
/* Return the size (in bit-width) of a data type. If the size is zero, emit an
** error and return some valid size instead (so the rest of the compiler
** doesn't have to work with invalid sizes).
*/
unsigned CheckedSizeOf (const Type* T);
/* Return the size (in bytes) of a data type. If the size is zero, emit an
** error and return some valid size instead (so the rest of the compiler
** doesn't have to work with invalid sizes).
*/
unsigned CheckedPSizeOf (const Type* T);
/* Return the size (in bytes) of a data type that is pointed to by a pointer.
** If the size is zero, emit an error and return some valid size instead (so
** the rest of the compiler doesn't have to work with invalid sizes).
*/
#if defined(HAVE_INLINE)
INLINE TypeCode GetQualifier (const Type* T)
/* Get the qualifier from the given type string */
{
return (T->C & T_MASK_QUAL);
}
#else
# define GetQualifier(T) ((T)->C & T_MASK_QUAL)
#endif
TypeCode GetUnderlyingTypeCode (const Type* Type);
/* Get the type code of the unqualified underlying type of TCode.
** Return TCode if it is not scalar.
*/
#if defined(HAVE_INLINE)
INLINE TypeCode UnqualifiedType (TypeCode T)
/* Return the unqalified type code */
/* Return the unqualified type code */
{
return (T & ~T_MASK_QUAL);
}
@ -305,39 +339,94 @@ INLINE TypeCode UnqualifiedType (TypeCode T)
# define UnqualifiedType(T) ((T) & ~T_MASK_QUAL)
#endif
const Type* GetUnderlyingType (const Type* Type);
/* Get the underlying type of an enum or other integer class type */
#if defined(HAVE_INLINE)
INLINE TypeCode GetClass (const Type* T)
/* Get the class of a type string */
{
return (T->C & T_MASK_CLASS);
}
#else
# define GetClass(T) ((T)->C & T_MASK_CLASS)
#endif
TypeCode GetUnderlyingTypeCode (const Type* Type);
/* Get the type code of the unqualified underlying type of TCode.
** Return TCode if it is not scalar.
#if defined(HAVE_INLINE)
INLINE TypeCode GetSignedness (const Type* T)
/* Get the signedness of a type */
{
return (GetUnderlyingTypeCode (T) & T_MASK_SIGN);
}
#else
# define GetSignedness(T) (GetUnderlyingTypeCode (T) & T_MASK_SIGN)
#endif
#if defined(HAVE_INLINE)
INLINE TypeCode GetSizeModifier (const Type* T)
/* Get the size modifier of a type */
{
return (GetUnderlyingTypeCode (T) & T_MASK_SIZE);
}
#else
# define GetSizeModifier(T) (GetUnderlyingTypeCode (T) & T_MASK_SIZE)
#endif
#if defined(HAVE_INLINE)
INLINE TypeCode GetRawType (const Type* T)
/* Get the raw type */
{
return (T->C & T_MASK_TYPE);
}
#else
# define GetRawType(T) ((T)->C & T_MASK_TYPE)
#endif
#if defined(HAVE_INLINE)
INLINE TypeCode GetRawSignedness (const Type* T)
/* Get the raw signedness of a type */
{
return ((T)->C & T_MASK_SIGN);
}
#else
# define GetRawSignedness(T) ((T)->C & T_MASK_SIGN)
#endif
#if defined(HAVE_INLINE)
INLINE TypeCode GetRawSizeModifier (const Type* T)
/* Get the size modifier of a raw type */
{
return (T->C & T_MASK_SIZE);
}
#else
# define GetRawSizeModifier(T) ((T)->C & T_MASK_SIZE)
#endif
/*****************************************************************************/
/* Type manipulation */
/*****************************************************************************/
Type* GetImplicitFuncType (void);
/* Return a type string for an implicitly declared function */
Type* GetCharArrayType (unsigned Len);
/* Return the type for a char array of the given length */
Type* NewPointerTo (const Type* T);
/* Return a type string that is "pointer to T". The type string is allocated
** on the heap and may be freed after use.
*/
const Type* GetBitFieldChunkType (const Type* Type);
/* Get the type needed to operate on the byte chunk containing the bit-field */
unsigned SizeOf (const Type* T);
/* Compute size of object represented by type array. */
unsigned PSizeOf (const Type* T);
/* Compute size of pointer object. */
unsigned CheckedSizeOf (const Type* T);
/* Return the size of a data type. If the size is zero, emit an error and
** return some valid size instead (so the rest of the compiler doesn't have
** to work with invalid sizes).
*/
unsigned CheckedPSizeOf (const Type* T);
/* Return the size of a data type that is pointed to by a pointer. If the
** size is zero, emit an error and return some valid size instead (so the
** rest of the compiler doesn't have to work with invalid sizes).
Type* NewBitFieldType (const Type* T, unsigned BitOffs, unsigned BitWidth);
/* Return a type string that is "T : BitWidth" aligned on BitOffs. The type
** string is allocated on the heap and may be freed after use.
*/
unsigned TypeOf (const Type* T);
/* Get the code generator base type of the object */
unsigned FuncTypeOf (const Type* T);
/* Get the code generator flag for calling the function */
const Type* AddressOf (const Type* T);
/* Return a type string that is "address of T". The type string is allocated
** on the heap and may be freed after use.
*/
const Type* Indirect (const Type* T);
/* Do one indirection for the given type, that is, return the type where the
@ -349,16 +438,6 @@ Type* IndirectModifiable (Type* T);
** given type points to.
*/
Type* NewPointerTo (const Type* T);
/* Return a type string that is "pointer to T". The type string is allocated
** on the heap and may be freed after use.
*/
const Type* AddressOf (const Type* T);
/* Return a type string that is "address of T". The type string is allocated
** on the heap and may be freed after use.
*/
Type* ArrayToPtr (const Type* T);
/* Convert an array to a pointer to it's first element */
@ -388,20 +467,22 @@ const Type* SignedType (const Type* T);
const Type* UnsignedType (const Type* T);
/* Get unsigned counterpart of the integral type */
Type* NewBitFieldType (const Type* T, unsigned BitOffs, unsigned BitWidth);
/* Return a type string that is "T : BitWidth" aligned on BitOffs. The type
** string is allocated on the heap and may be freed after use.
*/
const Type* GetUnderlyingType (const Type* Type);
/* Get the underlying type of an enum or other integer class type */
const Type* GetStructReplacementType (const Type* SType);
/* Get a replacement type for passing a struct/union in the primary register */
const Type* GetBitFieldChunkType (const Type* Type);
/* Get the type needed to operate on the byte chunk containing the bit-field */
/*****************************************************************************/
/* Type Predicates */
/*****************************************************************************/
#if defined(HAVE_INLINE)
INLINE TypeCode GetRawType (const Type* T)
/* Get the raw type */
{
return (T->C & T_MASK_TYPE);
}
#else
# define GetRawType(T) ((T)->C & T_MASK_TYPE)
#endif
#if defined(HAVE_INLINE)
INLINE int IsTypeChar (const Type* T)
@ -420,7 +501,7 @@ INLINE int IsTypeShort (const Type* T)
return (GetRawType (GetUnderlyingType (T)) == T_TYPE_SHORT);
}
#else
# define IsTypeShort(T) (GetRawType (GetUnderlyingType (T)) == T_TYPE_SHORT)
# define IsTypeShort(T) (GetRawType (GetUnderlyingType (T)) == T_TYPE_SHORT)
#endif
#if defined(HAVE_INLINE)
@ -585,7 +666,7 @@ INLINE int IsTypeUnion (const Type* T)
return (GetRawType (T) == T_TYPE_UNION);
}
#else
# define IsTypeUnion(T) (GetRawType (T) == T_TYPE_UNION)
# define IsTypeUnion(T) (GetRawType (T) == T_TYPE_UNION)
#endif
#if defined(HAVE_INLINE)
@ -628,16 +709,6 @@ INLINE int IsTypeFuncPtr (const Type* T)
# define IsTypeFuncPtr(T) (IsTypePtr (T) && IsTypeFunc (T+1))
#endif
#if defined(HAVE_INLINE)
INLINE TypeCode GetClass (const Type* T)
/* Get the class of a type string */
{
return (T->C & T_MASK_CLASS);
}
#else
# define GetClass(T) ((T)->C & T_MASK_CLASS)
#endif
#if defined(HAVE_INLINE)
INLINE int IsClassInt (const Type* T)
/* Return true if this is an integer type */
@ -727,25 +798,8 @@ int IsEmptiableObjectType (const Type* T);
int HasUnknownSize (const Type* T);
/* Return true if this is an incomplete ESU type or an array of unknown size */
#if defined(HAVE_INLINE)
INLINE TypeCode GetRawSignedness (const Type* T)
/* Get the raw signedness of a type */
{
return ((T)->C & T_MASK_SIGN);
}
#else
# define GetRawSignedness(T) ((T)->C & T_MASK_SIGN)
#endif
#if defined(HAVE_INLINE)
INLINE TypeCode GetSignedness (const Type* T)
/* Get the signedness of a type */
{
return (GetUnderlyingTypeCode (T) & T_MASK_SIGN);
}
#else
# define GetSignedness(T) (GetUnderlyingTypeCode (T) & T_MASK_SIGN)
#endif
int TypeHasAttr (const Type* T);
/* Return true if the given type has attribute data */
#if defined(HAVE_INLINE)
INLINE int IsRawSignUnsigned (const Type* T)
@ -787,35 +841,13 @@ INLINE int IsSignSigned (const Type* T)
# define IsSignSigned(T) (GetSignedness (T) == T_SIGN_SIGNED)
#endif
#if defined(HAVE_INLINE)
INLINE TypeCode GetRawSizeModifier (const Type* T)
/* Get the size modifier of a raw type */
{
return (T->C & T_MASK_SIZE);
}
#else
# define GetRawSizeModifier(T) ((T)->C & T_MASK_SIZE)
#endif
#if defined(HAVE_INLINE)
INLINE TypeCode GetSizeModifier (const Type* T)
/* Get the size modifier of a type */
{
return (GetUnderlyingTypeCode (T) & T_MASK_SIZE);
}
#else
# define GetSizeModifier(T) (GetUnderlyingTypeCode (T) & T_MASK_SIZE)
#endif
#if defined(HAVE_INLINE)
INLINE TypeCode GetQualifier (const Type* T)
/* Get the qualifier from the given type string */
{
return (T->C & T_MASK_QUAL);
}
#else
# define GetQualifier(T) ((T)->C & T_MASK_QUAL)
#endif
/*****************************************************************************/
/* Qualifier helpers */
/*****************************************************************************/
#if defined(HAVE_INLINE)
INLINE int IsQualConst (const Type* T)
@ -897,6 +929,37 @@ INLINE int IsQualCConv (const Type* T)
# define IsQualCConv(T) (((T)->C & T_QUAL_CCONV) != 0)
#endif
TypeCode AddrSizeQualifier (unsigned AddrSize);
/* Return T_QUAL_NEAR or T_QUAL_FAR depending on the address size */
#if defined(HAVE_INLINE)
INLINE TypeCode CodeAddrSizeQualifier (void)
/* Return T_QUAL_NEAR or T_QUAL_FAR depending on the code address size */
{
return AddrSizeQualifier (CodeAddrSize);
}
#else
# define CodeAddrSizeQualifier() (AddrSizeQualifier (CodeAddrSize))
#endif
#if defined(HAVE_INLINE)
INLINE TypeCode DataAddrSizeQualifier (void)
/* Return T_QUAL_NEAR or T_QUAL_FAR depending on the data address size */
{
return AddrSizeQualifier (DataAddrSize);
}
#else
# define DataAddrSizeQualifier() (AddrSizeQualifier (DataAddrSize))
#endif
/*****************************************************************************/
/* Function type helpers */
/*****************************************************************************/
int IsVariadicFunc (const Type* T) attribute ((const));
/* Return true if this is a function type or pointer to function type with
** variable parameter list.
@ -924,6 +987,14 @@ Type* GetFuncReturnModifiable (Type* T) attribute ((const));
const FuncDesc* GetFuncDefinitionDesc (const Type* T) attribute ((const));
/* Get the function descriptor of the function definition */
/*****************************************************************************/
/* Array type helpers */
/*****************************************************************************/
long GetElementCount (const Type* T);
/* Get the element count of the array specified in T (which must be of
** array type).
@ -943,47 +1014,46 @@ 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 */
void SetESUSymEntry (Type* T, struct SymEntry* S);
/* Set the SymEntry pointer for an enum/struct/union type */
TypeCode AddrSizeQualifier (unsigned AddrSize);
/* Return T_QUAL_NEAR or T_QUAL_FAR depending on the address size */
/*****************************************************************************/
/* ESU types helpers */
/*****************************************************************************/
#if defined(HAVE_INLINE)
INLINE TypeCode CodeAddrSizeQualifier (void)
/* Return T_QUAL_NEAR or T_QUAL_FAR depending on the code address size */
{
return AddrSizeQualifier (CodeAddrSize);
}
#else
# define CodeAddrSizeQualifier() (AddrSizeQualifier (CodeAddrSize))
#endif
#if defined(HAVE_INLINE)
INLINE TypeCode DataAddrSizeQualifier (void)
/* Return T_QUAL_NEAR or T_QUAL_FAR depending on the data address size */
{
return AddrSizeQualifier (DataAddrSize);
}
#else
# define DataAddrSizeQualifier() (AddrSizeQualifier (DataAddrSize))
#endif
int TypeHasAttr (const Type* T);
/* Return true if the given type has attribute data */
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.
*/
#if defined(HAVE_INLINE)
INLINE void CopyTypeAttr (const Type* Src, Type* Dest)
/* Copy attribute data from Src to Dest */
{
Dest->A = Src->A;
}
#else
# define CopyTypeAttr(Src, Dest) ((Dest)->A = (Src)->A)
#endif
void SetESUTagSym (Type* T, struct SymEntry* S);
/* Set the tag symbol entry of the enum/struct/union type */
/*****************************************************************************/
/* Helpers */
/*****************************************************************************/
const char* GetBasicTypeName (const Type* T);
/* Return a const name string of the basic type.
** Return "type" for unknown basic types.
*/
const char* GetFullTypeName (const Type* T);
/* Return the full name string of the given type */
struct StrBuf* GetFullTypeNameBuf (struct StrBuf* S, const Type* T);
/* Return the full name string of the given type */
int GetQualifierTypeCodeNameBuf (struct StrBuf* S, TypeCode Qual, TypeCode IgnoredQual);
/* Return the names of the qualifiers of the type.
** Qualifiers to be ignored can be specified with the IgnoredQual flags.
** Return the count of added qualifier names.
*/
void PrintType (FILE* F, const Type* T);
/* Print fulle name of the type */

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 */
{
@ -259,8 +356,8 @@ void InitDeclSpec (DeclSpec* D)
static void InitDeclaration (Declaration* D)
/* Initialize the Declaration struct for use */
static void InitDeclarator (Declarator* D)
/* Initialize the Declarator struct for use */
{
D->Ident[0] = '\0';
D->Type[0].C = T_END;
@ -270,7 +367,7 @@ static void InitDeclaration (Declaration* D)
static void NeedTypeSpace (Declaration* D, unsigned Count)
static void NeedTypeSpace (Declarator* D, unsigned Count)
/* Check if there is enough space for Count type specifiers within D */
{
if (D->Index + Count >= MAXTYPELEN) {
@ -284,8 +381,8 @@ static void NeedTypeSpace (Declaration* D, unsigned Count)
static void AddTypeToDeclaration (Declaration* D, TypeCode T)
/* Add a type specifier to the type of a declaration */
static void AddTypeCodeToDeclarator (Declarator* D, TypeCode T)
/* Add a type specifier to the type of a declarator */
{
NeedTypeSpace (D, 1);
D->Type[D->Index++].C = T;
@ -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 */
static SymEntry* ForwardESU (const char* Name, unsigned Flags, unsigned* DSFlags)
/* Handle an enum, struct or union forward declaration */
{
/* 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;
}
@ -556,8 +584,8 @@ static const Type* GetEnumeratorType (long Min, unsigned long Max, int Signed)
static SymEntry* ParseEnumDecl (const char* Name, unsigned* DSFlags)
/* Process an enum declaration */
static SymEntry* ParseEnumSpec (const char* Name, unsigned* DSFlags)
/* Process an enum specifier */
{
SymTable* FieldTab;
long EnumVal;
@ -574,7 +602,7 @@ static SymEntry* ParseEnumDecl (const char* Name, unsigned* DSFlags)
if (CurTok.Tok != TOK_LCURLY) {
/* Just a forward definition */
return ESUForwardDecl (Name, SC_ENUM, DSFlags);
return ForwardESU (Name, SC_ENUM, DSFlags);
}
/* Add a forward declaration for the enum tag in the current lexical level */
@ -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));
@ -725,7 +754,7 @@ static SymEntry* ParseEnumDecl (const char* Name, unsigned* DSFlags)
static int ParseFieldWidth (Declaration* D)
static int ParseFieldWidth (Declarator* D)
/* Parse an optional field width. Returns -1 if no field width is specified,
** otherwise the width of the field.
*/
@ -803,21 +832,19 @@ static unsigned PadWithBitField (unsigned StructSize, unsigned BitOffs)
static unsigned AliasAnonStructFields (const Declaration* D, SymEntry* Anon)
static unsigned AliasAnonStructFields (const Declarator* D, SymEntry* Anon)
/* Create alias fields from an anon union/struct in the current lexical level.
** The function returns the count of created aliases.
*/
{
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 */
@ -852,8 +879,8 @@ static unsigned AliasAnonStructFields (const Declaration* D, SymEntry* Anon)
static SymEntry* ParseUnionDecl (const char* Name, unsigned* DSFlags)
/* Parse a union declaration. */
static SymEntry* ParseUnionSpec (const char* Name, unsigned* DSFlags)
/* Parse a union specifier */
{
unsigned UnionSize;
@ -861,14 +888,14 @@ 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;
if (CurTok.Tok != TOK_LCURLY) {
/* Just a forward declaration */
return ESUForwardDecl (Name, SC_UNION, DSFlags);
return ForwardESU (Name, SC_UNION, DSFlags);
}
/* Add a forward declaration for the union tag in the current lexical level */
@ -883,19 +910,26 @@ 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) {
Declaration Decl;
Declarator Decl;
/* Get type and name of the struct field */
ParseDecl (&Spec, &Decl, DM_ACCEPT_IDENT);
@ -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;
}
}
@ -992,8 +1026,8 @@ NextMember: if (CurTok.Tok != TOK_COMMA) {
static SymEntry* ParseStructDecl (const char* Name, unsigned* DSFlags)
/* Parse a struct declaration. */
static SymEntry* ParseStructSpec (const char* Name, unsigned* DSFlags)
/* Parse a struct specifier */
{
unsigned StructSize;
@ -1002,14 +1036,14 @@ 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;
if (CurTok.Tok != TOK_LCURLY) {
/* Just a forward declaration */
return ESUForwardDecl (Name, SC_STRUCT, DSFlags);
return ForwardESU (Name, SC_STRUCT, DSFlags);
}
/* Add a forward declaration for the struct tag in the current lexical level */
@ -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,14 +1073,13 @@ 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) {
Declaration Decl;
Declarator Decl;
/* If we had a flexible array member before, no other fields can
** follow.
@ -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 = ParseUnionSpec (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 = ParseStructSpec (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;
@ -1419,17 +1453,16 @@ static void ParseTypeSpec (DeclSpec* D, long Default, TypeCode Qualifiers,
} else {
if (CurTok.Tok != TOK_LCURLY) {
Error ("Identifier expected");
} else {
AnonName (Ident, "enum");
}
AnonName (Ident, "enum");
}
/* Remember we have an extra type decl */
D->Flags |= DS_EXTRA_TYPE;
/* Parse the enum decl */
Entry = ParseEnumDecl (Ident, &D->Flags);
TagEntry = ParseEnumSpec (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 +1475,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 +1504,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 +1598,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.
@ -1577,7 +1611,7 @@ static void ParseOldStyleParamList (FuncDesc* F)
/* Parse a comma separated variable list */
while (1) {
Declaration Decl;
Declarator Decl;
/* Read the parameter */
ParseDecl (&Spec, &Decl, DM_NEED_IDENT);
@ -1591,19 +1625,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);
@ -1632,8 +1666,8 @@ static void ParseAnsiParamList (FuncDesc* F)
while (CurTok.Tok != TOK_RPAREN) {
DeclSpec Spec;
Declaration Decl;
SymEntry* Sym;
Declarator Decl;
SymEntry* Param;
/* Allow an ellipsis as last parameter */
if (CurTok.Tok == TOK_ELLIPSIS) {
@ -1643,7 +1677,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 +1715,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)) {
@ -1713,7 +1747,7 @@ static void ParseAnsiParamList (FuncDesc* F)
static FuncDesc* ParseFuncDecl (void)
/* Parse the argument list of a function. */
/* Parse the argument list of a function with the enclosing parentheses */
{
SymEntry* Sym;
SymEntry* WrappedCall;
@ -1725,6 +1759,9 @@ static FuncDesc* ParseFuncDecl (void)
/* Enter a new lexical level */
EnterFunctionLevel ();
/* Skip the opening paren */
NextToken ();
/* Check for several special parameter lists */
if (CurTok.Tok == TOK_RPAREN) {
/* Parameter list is empty (K&R-style) */
@ -1782,16 +1819,16 @@ static FuncDesc* ParseFuncDecl (void)
static void Declarator (const DeclSpec* Spec, Declaration* D, declmode_t Mode)
/* Recursively process declarators. Build a type array in reverse order. */
static void DirectDecl (const DeclSpec* Spec, Declarator* D, declmode_t Mode)
/* Recursively process direct declarators. Build a type array in reverse order. */
{
/* Read optional function or pointer qualifiers. They modify the
** identifier or token to the right. For convenience, we allow a calling
** convention also for pointers here. If it's a pointer-to-function, the
** qualifier later will be transfered to the function itself. If it's a
** pointer to something else, it will be flagged as an error.
/* Read optional function or pointer qualifiers that modify the identifier
** or token to the right. For convenience, we allow a calling convention
** also for pointers here. If it's a pointer-to-function, the 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,19 +1837,19 @@ 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);
DirectDecl (Spec, D, Mode);
/* Add the type */
AddTypeToDeclaration (D, T_PTR | Qualifiers);
AddTypeCodeToDeclarator (D, T_PTR | Qualifiers);
return;
}
if (CurTok.Tok == TOK_LPAREN) {
NextToken ();
Declarator (Spec, D, Mode);
DirectDecl (Spec, D, Mode);
ConsumeRParen ();
} else {
/* Things depend on Mode now:
@ -1832,7 +1869,13 @@ static void Declarator (const DeclSpec* Spec, Declaration* D, declmode_t Mode)
NextToken ();
} else {
if (Mode == DM_NEED_IDENT) {
/* Some fix point tokens that are used for error recovery */
static const token_t TokenList[] = { TOK_COMMA, TOK_SEMI };
Error ("Identifier expected");
/* Try some smart error recovery */
SkipTokens (TokenList, sizeof(TokenList) / sizeof(TokenList[0]));
}
D->Ident[0] = '\0';
}
@ -1841,14 +1884,11 @@ static void Declarator (const DeclSpec* Spec, Declaration* D, declmode_t Mode)
while (CurTok.Tok == TOK_LBRACK || CurTok.Tok == TOK_LPAREN) {
if (CurTok.Tok == TOK_LPAREN) {
/* Function declaration */
/* Function declarator */
FuncDesc* F;
SymEntry* PrevEntry;
/* Skip the opening paren */
NextToken ();
/* Parse the function declaration */
/* Parse the function declarator */
F = ParseFuncDecl ();
/* We cannot specify fastcall for variadic functions */
@ -1877,7 +1917,7 @@ static void Declarator (const DeclSpec* Spec, Declaration* D, declmode_t Mode)
Qualifiers = T_QUAL_NONE;
} else {
/* Array declaration. */
/* Array declarator */
long Size = UNSPECIFIED;
/* We cannot have any qualifiers for an array */
@ -1941,11 +1981,11 @@ Type* ParseType (Type* T)
/* Parse a complete type specification */
{
DeclSpec Spec;
Declaration Decl;
Declarator Decl;
/* 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);
@ -1959,19 +1999,19 @@ Type* ParseType (Type* T)
void ParseDecl (const DeclSpec* Spec, Declaration* D, declmode_t Mode)
/* Parse a variable, type or function declaration */
void ParseDecl (const DeclSpec* Spec, Declarator* D, declmode_t Mode)
/* Parse a variable, type or function declarator */
{
/* Used to check if we have any errors during parsing this */
unsigned PrevErrorCount = ErrorCount;
/* Initialize the Declaration struct */
InitDeclaration (D);
/* Initialize the Declarator struct */
InitDeclarator (D);
/* Get additional declarators and the identifier */
Declarator (Spec, D, Mode);
/* Get additional derivation of the declarator and the identifier */
DirectDecl (Spec, D, Mode);
/* Add the base type. */
/* Add the base type */
NeedTypeSpace (D, TypeLen (Spec->Type) + 1); /* Bounds check */
TypeCopy (D->Type + D->Index, Spec->Type);
@ -1989,7 +2029,7 @@ void ParseDecl (const DeclSpec* Spec, Declaration* D, declmode_t Mode)
D->StorageClass |= SC_FUNC;
}
/* Parse attributes for this declaration */
/* Parse attributes for this declarator */
ParseAttribute (D);
/* Check several things for function or function pointer types */
@ -2070,22 +2110,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 */
@ -70,8 +86,8 @@ struct DeclSpec {
};
/* Result of ParseDecl */
typedef struct Declaration Declaration;
struct Declaration {
typedef struct Declarator Declarator;
struct Declarator {
unsigned StorageClass; /* A set of SC_xxx flags */
Type Type[MAXTYPELEN]; /* The type */
ident Ident; /* The identifier, if any*/
@ -102,10 +118,10 @@ void InitDeclSpec (DeclSpec* D);
Type* ParseType (Type* Type);
/* Parse a complete type specification */
void ParseDecl (const DeclSpec* Spec, Declaration* D, declmode_t Mode);
/* Parse a variable, type or function declaration */
void ParseDecl (const DeclSpec* Spec, Declarator* D, declmode_t Mode);
/* Parse a variable, type or function declarator */
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

@ -2,7 +2,7 @@
/* */
/* declattr.c */
/* */
/* Declaration attributes */
/* Declarator attributes */
/* */
/* */
/* */
@ -55,8 +55,8 @@
/* Forwards for attribute handlers */
static void NoReturnAttr (Declaration* D);
static void UnusedAttr (Declaration* D);
static void NoReturnAttr (Declarator* D);
static void UnusedAttr (Declarator* D);
@ -64,7 +64,7 @@ static void UnusedAttr (Declaration* D);
typedef struct AttrDesc AttrDesc;
struct AttrDesc {
const char Name[15];
void (*Handler) (Declaration*);
void (*Handler) (Declarator*);
};
static const AttrDesc AttrTable [] = {
{ "__noreturn__", NoReturnAttr },
@ -141,8 +141,8 @@ static void ErrorSkip (void)
static void AddAttr (Declaration* D, DeclAttr* A)
/* Add an attribute to a declaration */
static void AddAttr (Declarator* D, DeclAttr* A)
/* Add an attribute to a declarator */
{
/* Allocate the list if necessary, the add the attribute */
if (D->Attributes == 0) {
@ -159,7 +159,7 @@ static void AddAttr (Declaration* D, DeclAttr* A)
static void NoReturnAttr (Declaration* D)
static void NoReturnAttr (Declarator* D)
/* Parse the "noreturn" attribute */
{
/* Add the noreturn attribute */
@ -168,7 +168,7 @@ static void NoReturnAttr (Declaration* D)
static void UnusedAttr (Declaration* D)
static void UnusedAttr (Declarator* D)
/* Parse the "unused" attribute */
{
/* Add the noreturn attribute */
@ -177,7 +177,7 @@ static void UnusedAttr (Declaration* D)
void ParseAttribute (Declaration* D)
void ParseAttribute (Declarator* D)
/* Parse an additional __attribute__ modifier */
{
/* Do we have an attribute? */

View File

@ -2,7 +2,7 @@
/* */
/* declattr.h */
/* */
/* Declaration attributes */
/* Declarator attributes */
/* */
/* */
/* */
@ -45,7 +45,7 @@
/* Forward */
struct Declaration;
struct Declarator;
/* Supported attribute types */
typedef enum {
@ -67,7 +67,7 @@ struct DeclAttr {
void ParseAttribute (struct Declaration* D);
void ParseAttribute (struct Declarator* D);
/* Parse an additional __attribute__ modifier */

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

@ -103,6 +103,100 @@ unsigned GlobalModeFlags (const ExprDesc* Expr)
static unsigned TypeOfBySize (unsigned Size)
/* Get the code generator replacement type of the object by its size */
{
unsigned NewType;
/* If the size is less than or equal to that of a a long, we will copy
** the struct using the primary register, otherwise we use memcpy.
*/
switch (Size) {
case 1: NewType = CF_CHAR; break;
case 2: NewType = CF_INT; break;
case 3: /* FALLTHROUGH */
case 4: NewType = CF_LONG; break;
default: NewType = CF_NONE; break;
}
return NewType;
}
unsigned TypeOf (const Type* T)
/* Get the code generator base type of the object */
{
unsigned NewType;
switch (GetUnderlyingTypeCode (T)) {
case T_SCHAR:
return CF_CHAR;
case T_UCHAR:
return CF_CHAR | CF_UNSIGNED;
case T_SHORT:
case T_INT:
return CF_INT;
case T_USHORT:
case T_UINT:
case T_PTR:
case T_ARRAY:
return CF_INT | CF_UNSIGNED;
case T_LONG:
return CF_LONG;
case T_ULONG:
return CF_LONG | CF_UNSIGNED;
case T_FLOAT:
case T_DOUBLE:
/* These two are identical in the backend */
return CF_FLOAT;
case T_FUNC:
/* Treat this as a function pointer */
return CF_INT | CF_UNSIGNED;
case T_STRUCT:
case T_UNION:
NewType = TypeOfBySize (SizeOf (T));
if (NewType != CF_NONE) {
return NewType;
}
/* Address of ... */
return CF_INT | CF_UNSIGNED;
case T_VOID:
case T_ENUM:
/* Incomplete enum type */
Error ("Incomplete type '%s'", GetFullTypeName (T));
return CF_INT;
default:
Error ("Illegal type %04lX", T->C);
return CF_INT;
}
}
unsigned FuncTypeOf (const Type* T)
/* Get the code generator flag for calling the function */
{
if (GetUnderlyingTypeCode (T) == T_FUNC) {
return (T->A.F->Flags & FD_VARIADIC) ? 0 : CF_FIXARGC;
} else {
Error ("Illegal function type %04lX", T->C);
return 0;
}
}
void ExprWithCheck (void (*Func) (ExprDesc*), ExprDesc* Expr)
/* Call an expression function with checks. */
{
@ -193,12 +287,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;
@ -218,6 +315,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;
@ -274,11 +374,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));
}
}
@ -1296,13 +1395,13 @@ 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) {
Error ("Mixed declarations and code are not supported in cc65");
while (CurTok.Tok != TOK_SEMI) {
Declaration Decl;
Declarator Decl;
/* Parse one declaration */
ParseDecl (&Spec, &Decl, DM_ACCEPT_IDENT);
@ -1822,7 +1921,7 @@ static void UnaryOp (ExprDesc* Expr)
Expr->Type = IntPromotion (Expr->Type);
/* Limit the calculated value to the range of its type */
LimitExprValue (Expr);
LimitExprValue (Expr, 1);
} else {
unsigned Flags;
@ -2078,6 +2177,10 @@ static void hie_internal (const GenDesc* Ops, /* List of generators */
/* Check for const operands */
if (lconst && rconst) {
/* Evaluate the result for operands */
unsigned long Val1 = Expr->IVal;
unsigned long Val2 = Expr2.IVal;
/* Both operands are constant, remove the generated code */
RemoveCode (&Mark1);
@ -2085,84 +2188,55 @@ static void hie_internal (const GenDesc* Ops, /* List of generators */
Expr->Type = ArithmeticConvert (Expr->Type, Expr2.Type);
/* Handle the op differently for signed and unsigned types */
if (IsSignSigned (Expr->Type)) {
/* Evaluate the result for signed operands */
signed long Val1 = Expr->IVal;
signed long Val2 = Expr2.IVal;
switch (Tok) {
case TOK_OR:
Expr->IVal = (Val1 | Val2);
break;
case TOK_XOR:
Expr->IVal = (Val1 ^ Val2);
break;
case TOK_AND:
Expr->IVal = (Val1 & Val2);
break;
case TOK_STAR:
Expr->IVal = (Val1 * Val2);
break;
case TOK_DIV:
if (Val2 == 0) {
Error ("Division by zero");
Expr->IVal = 0x7FFFFFFF;
switch (Tok) {
case TOK_OR:
Expr->IVal = (Val1 | Val2);
break;
case TOK_XOR:
Expr->IVal = (Val1 ^ Val2);
break;
case TOK_AND:
Expr->IVal = (Val1 & Val2);
break;
case TOK_STAR:
Expr->IVal = (Val1 * Val2);
break;
case TOK_DIV:
if (Val2 == 0) {
if (!ED_IsUneval (Expr)) {
Warning ("Division by zero");
}
Expr->IVal = 0xFFFFFFFF;
} else {
/* Handle signed and unsigned operands differently */
if (IsSignSigned (Expr->Type)) {
Expr->IVal = ((long)Val1 / (long)Val2);
} else {
Expr->IVal = (Val1 / Val2);
}
break;
case TOK_MOD:
if (Val2 == 0) {
Error ("Modulo operation with zero");
Expr->IVal = 0;
}
break;
case TOK_MOD:
if (Val2 == 0) {
if (!ED_IsUneval (Expr)) {
Warning ("Modulo operation with zero");
}
Expr->IVal = 0;
} else {
/* Handle signed and unsigned operands differently */
if (IsSignSigned (Expr->Type)) {
Expr->IVal = ((long)Val1 % (long)Val2);
} else {
Expr->IVal = (Val1 % Val2);
}
break;
default:
Internal ("hie_internal: got token 0x%X\n", Tok);
}
} else {
/* Evaluate the result for unsigned operands */
unsigned long Val1 = Expr->IVal;
unsigned long Val2 = Expr2.IVal;
switch (Tok) {
case TOK_OR:
Expr->IVal = (Val1 | Val2);
break;
case TOK_XOR:
Expr->IVal = (Val1 ^ Val2);
break;
case TOK_AND:
Expr->IVal = (Val1 & Val2);
break;
case TOK_STAR:
Expr->IVal = (Val1 * Val2);
break;
case TOK_DIV:
if (Val2 == 0) {
Error ("Division by zero");
Expr->IVal = 0xFFFFFFFF;
} else {
Expr->IVal = (Val1 / Val2);
}
break;
case TOK_MOD:
if (Val2 == 0) {
Error ("Modulo operation with zero");
Expr->IVal = 0;
} else {
Expr->IVal = (Val1 % Val2);
}
break;
default:
Internal ("hie_internal: got token 0x%X\n", Tok);
}
}
break;
default:
Internal ("hie_internal: got token 0x%X\n", Tok);
}
/* 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
@ -2215,10 +2289,12 @@ static void hie_internal (const GenDesc* Ops, /* List of generators */
/* Second value is constant - check for div */
type |= CF_CONST;
rtype |= CF_CONST;
if (Tok == TOK_DIV && Expr2.IVal == 0) {
Error ("Division by zero");
} else if (Tok == TOK_MOD && Expr2.IVal == 0) {
Error ("Modulo operation with zero");
if (Expr2.IVal == 0 && !ED_IsUneval (Expr)) {
if (Tok == TOK_DIV) {
Warning ("Division by zero");
} else if (Tok == TOK_MOD) {
Warning ("Modulo operation with zero");
}
}
if ((Gen->Flags & GEN_NOPUSH) != 0) {
RemoveCode (&Mark2);
@ -2789,7 +2865,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 */
@ -3260,7 +3336,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);
@ -3814,17 +3890,6 @@ static void hieQuest (ExprDesc* Expr)
ED_Init (&Expr3);
Expr3.Flags = Flags;
NextToken ();
/* Convert non-integer constant to boolean constant, so that we may just
** check it in the same way.
*/
if (ED_IsConstTrue (Expr)) {
ED_MakeConstBool (Expr, 1);
} else if (ED_IsConstFalse (Expr)) {
ED_MakeConstBool (Expr, 0);
}
if (!ConstantCond) {
/* Condition codes not set, request a test */
ED_RequireTest (Expr);
@ -3836,6 +3901,15 @@ static void hieQuest (ExprDesc* Expr)
FalseLab = GetLocalLabel ();
g_falsejump (CF_NONE, FalseLab);
} else {
/* Convert non-integer constant to boolean constant, so that we
** may just check it in an easier way later.
*/
if (ED_IsConstTrue (Expr)) {
ED_MakeConstBool (Expr, 1);
} else if (ED_IsConstFalse (Expr)) {
ED_MakeConstBool (Expr, 0);
}
/* Constant boolean subexpression could still have deferred inc/dec
** operations, so just flush their side-effects at this sequence point.
*/
@ -3844,9 +3918,18 @@ static void hieQuest (ExprDesc* Expr)
if (Expr->IVal == 0) {
/* Remember the current code position */
GetCodePos (&SkippedBranch);
/* Expr2 is unevaluated when the condition is false */
Expr2.Flags |= E_EVAL_UNEVAL;
} else {
/* Expr3 is unevaluated when the condition is true */
Expr3.Flags |= E_EVAL_UNEVAL;
}
}
/* Skip the question mark */
NextToken ();
/* Parse second expression. Remember for later if it is a NULL pointer
** expression, then load it into the primary.
*/
@ -3863,9 +3946,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);
}
@ -3878,30 +3961,26 @@ static void hieQuest (ExprDesc* Expr)
/* Jump around the evaluation of the third expression */
TrueLab = GetLocalLabel ();
ConsumeColon ();
g_jump (TrueLab);
/* Jump here if the first expression was false */
g_defcodelabel (FalseLab);
} else {
if (Expr->IVal == 0) {
/* Expr2 is unevaluated when the condition is false */
Expr2.Flags |= E_EVAL_UNEVAL;
/* Remove the load code of Expr2 */
RemoveCode (&SkippedBranch);
} else {
/* Remember the current code position */
GetCodePos (&SkippedBranch);
}
ConsumeColon();
}
ConsumeColon ();
/* 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) &&
@ -3914,18 +3993,15 @@ 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);
}
Expr3.Type = PtrConversion (Expr3.Type);
if (ConstantCond && Expr->IVal != 0) {
/* Expr3 is unevaluated when the condition is true */
Expr3.Flags |= E_EVAL_UNEVAL;
/* Remove the load code of Expr3 */
RemoveCode (&SkippedBranch);
}
@ -4030,6 +4106,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

@ -51,6 +51,12 @@ typedef struct GenDesc {
unsigned GlobalModeFlags (const ExprDesc* Expr);
/* Return the addressing mode flags for the given expression */
unsigned TypeOf (const Type* T);
/* Get the code generator base type of the object */
unsigned FuncTypeOf (const Type* T);
/* Get the code generator flag for calling the function */
void ExprWithCheck (void (*Func) (ExprDesc*), ExprDesc* Expr);
/* Call an expression function with checks. */
@ -59,7 +65,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,74 +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);
}
#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 */
/*****************************************************************************/
@ -214,132 +149,51 @@ int ED_GetStackOffs (const ExprDesc* Expr, int Offs)
ExprDesc* ED_MakeConstAbs (ExprDesc* Expr, long Value, const Type* Type)
/* Replace Expr with an absolute const with the given value and type */
/*****************************************************************************/
/* 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.
*/
{
Expr->Type = Type;
Expr->Flags = E_LOC_NONE | E_RTYPE_RVAL | (Expr->Flags & E_MASK_KEEP_MAKE);
Expr->Name = 0;
Expr->Sym = 0;
Expr->IVal = Value;
memset (&Expr->V, 0, sizeof (Expr->V));
return Expr;
return ED_IsLocConst (Expr) || ED_IsLocStack (Expr);
}
#endif
ExprDesc* ED_MakeConstAbsInt (ExprDesc* Expr, long Value)
/* Replace Expr with a constant integer expression with the given value */
#if !defined(HAVE_INLINE)
int ED_IsLocPrimaryOrExpr (const ExprDesc* Expr)
/* Return true if the expression is E_LOC_PRIMARY or E_LOC_EXPR */
{
Expr->Type = type_int;
Expr->Flags = E_LOC_NONE | E_RTYPE_RVAL | (Expr->Flags & E_MASK_KEEP_MAKE);
Expr->Name = 0;
Expr->Sym = 0;
Expr->IVal = Value;
memset (&Expr->V, 0, sizeof (Expr->V));
return Expr;
return ED_IsLocPrimary (Expr) || ED_IsLocExpr (Expr);
}
#endif
ExprDesc* ED_MakeConstBool (ExprDesc* Expr, long Value)
/* Replace Expr with a constant boolean expression with the given value */
#if !defined(HAVE_INLINE)
int ED_IsIndExpr (const ExprDesc* Expr)
/* Check if the expression is a reference to its value */
{
Expr->Sym = 0;
Expr->Type = type_bool;
Expr->Flags = E_LOC_NONE | E_RTYPE_RVAL | (Expr->Flags & E_MASK_KEEP_MAKE);
Expr->Name = 0;
Expr->IVal = Value;
memset (&Expr->V, 0, sizeof (Expr->V));
return Expr;
return (Expr->Flags & E_ADDRESS_OF) == 0 &&
!ED_IsLocNone (Expr) && !ED_IsLocPrimary (Expr);
}
#endif
ExprDesc* ED_FinalizeRValLoad (ExprDesc* Expr)
/* Finalize the result of LoadExpr to be an rvalue in the primary register */
int ED_YetToLoad (const ExprDesc* Expr)
/* Check if the expression needs to be loaded somehow. */
{
Expr->Flags &= ~(E_MASK_LOC | E_MASK_RTYPE | E_ADDRESS_OF);
Expr->Flags &= ~E_CC_SET;
Expr->Flags |= (E_LOC_PRIMARY | E_RTYPE_RVAL);
Expr->Sym = 0;
Expr->Name = 0;
Expr->IVal = 0; /* No offset */
memset (&Expr->V, 0, sizeof (Expr->V));
return Expr;
}
ExprDesc* ED_AddrExpr (ExprDesc* Expr)
/* Take address of Expr. The result is always an rvalue */
{
switch (Expr->Flags & E_MASK_LOC) {
case E_LOC_NONE:
Error ("Cannot get the address of a numeric constant");
break;
case E_LOC_EXPR:
Expr->Flags &= ~(E_MASK_LOC | E_MASK_RTYPE);
Expr->Flags |= E_ADDRESS_OF | E_LOC_PRIMARY | E_RTYPE_RVAL;
break;
default:
if ((Expr->Flags & E_ADDRESS_OF) == 0) {
Expr->Flags &= ~E_MASK_RTYPE;
Expr->Flags |= E_ADDRESS_OF | E_RTYPE_RVAL;
} else {
/* Due to the way we handle arrays, this may happen if we take
** the address of a pointer to an array element.
*/
if (!IsTypePtr (Expr->Type)) {
Error ("Cannot get the address of an address");
}
Expr->Flags &= ~E_MASK_RTYPE;
Expr->Flags |= E_RTYPE_RVAL;
}
break;
}
return Expr;
}
ExprDesc* ED_IndExpr (ExprDesc* Expr)
/* Dereference Expr */
{
switch (Expr->Flags & E_MASK_LOC) {
case E_LOC_NONE:
Expr->Flags &= ~(E_MASK_LOC | E_MASK_RTYPE);
Expr->Flags |= E_LOC_ABS | E_RTYPE_LVAL;
break;
case E_LOC_PRIMARY:
Expr->Flags &= ~(E_MASK_LOC | E_MASK_RTYPE);
Expr->Flags |= E_LOC_EXPR | E_RTYPE_LVAL;
break;
default:
if ((Expr->Flags & E_ADDRESS_OF) != 0) {
Expr->Flags &= ~(E_MASK_RTYPE | E_ADDRESS_OF);
Expr->Flags |= E_RTYPE_LVAL;
} else {
/* Due to the limitation of LoadExpr, this may happen after we
** have loaded the value from a referenced address, in which
** case the content in the primary no longer refers to the
** 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
** be the manually loaded first before a call into this, and
** the offset should be manually cleared somewhere outside.
*/
Expr->Flags &= ~(E_MASK_LOC | E_MASK_RTYPE);
Expr->Flags |= E_LOC_EXPR | E_RTYPE_LVAL;
}
break;
}
return Expr;
return ED_NeedsPrimary (Expr) ||
ED_YetToTest (Expr) ||
(ED_IsLVal (Expr) && IsQualVolatile (Expr->Type));
}
@ -427,6 +281,7 @@ int ED_IsQuasiConst (const ExprDesc* 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.
@ -472,6 +327,166 @@ int ED_IsBool (const ExprDesc* Expr)
/*****************************************************************************/
/* Manipulation */
/*****************************************************************************/
ExprDesc* ED_MakeConstAbs (ExprDesc* Expr, long Value, const Type* Type)
/* Replace Expr with an absolute const with the given value and type */
{
Expr->Type = Type;
Expr->Flags = E_LOC_NONE | E_RTYPE_RVAL | (Expr->Flags & E_MASK_KEEP_MAKE);
Expr->Name = 0;
Expr->Sym = 0;
Expr->IVal = Value;
memset (&Expr->V, 0, sizeof (Expr->V));
return Expr;
}
ExprDesc* ED_MakeConstAbsInt (ExprDesc* Expr, long Value)
/* Replace Expr with a constant integer expression with the given value */
{
Expr->Type = type_int;
Expr->Flags = E_LOC_NONE | E_RTYPE_RVAL | (Expr->Flags & E_MASK_KEEP_MAKE);
Expr->Name = 0;
Expr->Sym = 0;
Expr->IVal = Value;
memset (&Expr->V, 0, sizeof (Expr->V));
return Expr;
}
ExprDesc* ED_MakeConstBool (ExprDesc* Expr, long Value)
/* Replace Expr with a constant boolean expression with the given value */
{
Expr->Sym = 0;
Expr->Type = type_bool;
Expr->Flags = E_LOC_NONE | E_RTYPE_RVAL | (Expr->Flags & E_MASK_KEEP_MAKE);
Expr->Name = 0;
Expr->IVal = Value;
memset (&Expr->V, 0, sizeof (Expr->V));
return Expr;
}
ExprDesc* ED_FinalizeRValLoad (ExprDesc* Expr)
/* Finalize the result of LoadExpr to be an rvalue in the primary register */
{
Expr->Flags &= ~(E_MASK_LOC | E_MASK_RTYPE | E_ADDRESS_OF);
Expr->Flags &= ~E_CC_SET;
Expr->Flags |= (E_LOC_PRIMARY | E_RTYPE_RVAL);
Expr->Sym = 0;
Expr->Name = 0;
Expr->IVal = 0; /* No offset */
memset (&Expr->V, 0, sizeof (Expr->V));
return Expr;
}
ExprDesc* ED_AddrExpr (ExprDesc* Expr)
/* Take address of Expr. The result is always an rvalue */
{
switch (Expr->Flags & E_MASK_LOC) {
case E_LOC_NONE:
Error ("Cannot get the address of a numeric constant");
break;
case E_LOC_EXPR:
Expr->Flags &= ~(E_MASK_LOC | E_MASK_RTYPE);
Expr->Flags |= E_LOC_PRIMARY | E_RTYPE_RVAL;
break;
default:
if ((Expr->Flags & E_ADDRESS_OF) == 0) {
Expr->Flags &= ~E_MASK_RTYPE;
Expr->Flags |= E_ADDRESS_OF | E_RTYPE_RVAL;
} else {
/* Due to the way we handle arrays, this may happen if we take
** the address of a pointer to an array element.
*/
if (!IsTypePtr (Expr->Type)) {
Error ("Cannot get the address of an address");
}
Expr->Flags &= ~E_MASK_RTYPE;
Expr->Flags |= E_RTYPE_RVAL;
}
break;
}
return Expr;
}
ExprDesc* ED_IndExpr (ExprDesc* Expr)
/* Dereference Expr */
{
switch (Expr->Flags & E_MASK_LOC) {
case E_LOC_NONE:
Expr->Flags &= ~(E_MASK_LOC | E_MASK_RTYPE);
Expr->Flags |= E_LOC_ABS | E_RTYPE_LVAL;
break;
case E_LOC_PRIMARY:
Expr->Flags &= ~(E_MASK_LOC | E_MASK_RTYPE);
Expr->Flags |= E_LOC_EXPR | E_RTYPE_LVAL;
break;
default:
if ((Expr->Flags & E_ADDRESS_OF) != 0) {
Expr->Flags &= ~(E_MASK_RTYPE | E_ADDRESS_OF);
Expr->Flags |= E_RTYPE_LVAL;
} else {
/* Due to the limitation of LoadExpr, this may happen after we
** have loaded the value from a referenced address, in which
** case the content in the primary no longer refers to the
** 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 pointer value should
** be the manually loaded first before a call into this, and
** the offset should be manually cleared somewhere outside.
*/
Expr->Flags &= ~(E_MASK_LOC | E_MASK_RTYPE);
Expr->Flags |= E_LOC_EXPR | E_RTYPE_LVAL;
}
break;
}
return Expr;
}
void ED_MarkForUneval (ExprDesc* Expr)
/* Mark the expression as not to be evaluated */
{
Expr->Flags = (Expr->Flags & ~E_MASK_EVAL) | E_EVAL_UNEVAL;
}
const Type* ReplaceType (ExprDesc* Expr, const Type* NewType)
/* Replace the type of Expr by a copy of Newtype and return the old type string */
{
const Type* OldType = Expr->Type;
Expr->Type = TypeDup (NewType);
return OldType;
}
/*****************************************************************************/
/* Other Helpers */
/*****************************************************************************/
void PrintExprDesc (FILE* F, ExprDesc* E)
/* Print an ExprDesc */
{
@ -576,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.
@ -507,42 +480,14 @@ INLINE int ED_IsAddrExpr (const ExprDesc* Expr)
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);
return (Expr->Flags & E_ADDRESS_OF) == 0 &&
!ED_IsLocNone (Expr) && !ED_IsLocPrimary (Expr);
}
#else
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 */
@ -563,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. */
@ -669,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

@ -42,6 +42,7 @@
#include "asmlabel.h"
#include "codegen.h"
#include "error.h"
#include "expr.h"
#include "funcdesc.h"
#include "global.h"
#include "litpool.h"
@ -613,7 +614,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

@ -437,7 +437,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;
@ -452,15 +452,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 */
@ -470,7 +470,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;
@ -479,7 +479,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 */
@ -495,7 +495,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;
}
@ -503,13 +503,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);
@ -526,7 +526,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.
@ -537,14 +537,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);
@ -554,19 +554,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) ?
@ -574,17 +574,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
@ -602,14 +602,14 @@ static unsigned ParseStructInit (Type* T, int* Braces, int AllowFlexibleMembers)
/* Standard member. We should never have stuff from a
** bit-field left because an anonymous member was added
** for padding by ParseStructDecl.
** for padding by ParseStructSpec.
*/
CHECK (SI.ValBits == 0);
/* 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? */
@ -624,10 +624,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

@ -36,6 +36,7 @@
/* cc65 */
#include "codegen.h"
#include "error.h"
#include "expr.h"
#include "exprdesc.h"
#include "global.h"
#include "loadexpr.h"
@ -92,7 +93,6 @@ static void LoadAddress (unsigned Flags, ExprDesc* Expr)
g_leasp (Expr->IVal);
break;
case E_LOC_PRIMARY:
case E_LOC_EXPR:
if (Expr->IVal != 0) {
/* We have an expression in the primary plus a constant

View File

@ -97,8 +97,8 @@ static void AllocStorage (unsigned DataLabel, void (*UseSeg) (), unsigned Size)
static void ParseRegisterDecl (Declaration* Decl, int Reg)
/* Parse the declaration of a register variable. Reg is the offset of the
static void ParseRegisterDecl (Declarator* Decl, int Reg)
/* Parse the declarator of a register variable. Reg is the offset of the
** variable in the register bank.
*/
{
@ -186,8 +186,8 @@ static void ParseRegisterDecl (Declaration* Decl, int Reg)
static void ParseAutoDecl (Declaration* Decl)
/* Parse the declaration of an auto variable. */
static void ParseAutoDecl (Declarator* Decl)
/* Parse the declarator of an auto variable. */
{
unsigned Flags;
SymEntry* Sym;
@ -287,7 +287,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 {
@ -382,8 +382,8 @@ static void ParseAutoDecl (Declaration* Decl)
static void ParseStaticDecl (Declaration* Decl)
/* Parse the declaration of a static variable. */
static void ParseStaticDecl (Declarator* Decl)
/* Parse the declarator of a static variable. */
{
unsigned Size;
@ -441,12 +441,12 @@ static void ParseStaticDecl (Declaration* Decl)
static void ParseOneDecl (const DeclSpec* Spec)
/* Parse one variable declaration */
/* Parse one variable declarator. */
{
Declaration Decl; /* Declaration data structure */
Declarator Decl; /* Declarator data structure */
/* Read the declaration */
/* Read the declarator */
ParseDecl (Spec, &Decl, DM_NEED_IDENT);
/* Check if there are any non-extern storage classes set for function
@ -465,8 +465,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.
@ -524,7 +524,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 */
@ -566,7 +568,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

@ -305,97 +305,60 @@ static void PPhie_internal (const token_t* Ops, /* List of generators */
if (PPEvaluationEnabled && !PPEvaluationFailed) {
/* Evaluate the result for operands */
unsigned long Val1 = Expr->IVal;
unsigned long Val2 = Rhs.IVal;
/* If either side is unsigned, the result is unsigned */
Expr->Flags |= Rhs.Flags & PPEXPR_UNSIGNED;
/* Handle the op differently for signed and unsigned integers */
if ((Expr->Flags & PPEXPR_UNSIGNED) == 0) {
/* Evaluate the result for signed operands */
signed long Val1 = Expr->IVal;
signed long Val2 = Rhs.IVal;
switch (Tok) {
case TOK_OR:
Expr->IVal = (Val1 | Val2);
break;
case TOK_XOR:
Expr->IVal = (Val1 ^ Val2);
break;
case TOK_AND:
Expr->IVal = (Val1 & Val2);
break;
case TOK_PLUS:
Expr->IVal = (Val1 + Val2);
break;
case TOK_MINUS:
Expr->IVal = (Val1 - Val2);
break;
case TOK_MUL:
Expr->IVal = (Val1 * Val2);
break;
case TOK_DIV:
if (Val2 == 0) {
PPError ("Division by zero");
Expr->IVal = 0;
switch (Tok) {
case TOK_OR:
Expr->IVal = (Val1 | Val2);
break;
case TOK_XOR:
Expr->IVal = (Val1 ^ Val2);
break;
case TOK_AND:
Expr->IVal = (Val1 & Val2);
break;
case TOK_PLUS:
Expr->IVal = (Val1 + Val2);
break;
case TOK_MINUS:
Expr->IVal = (Val1 - Val2);
break;
case TOK_MUL:
Expr->IVal = (Val1 * Val2);
break;
case TOK_DIV:
if (Val2 == 0) {
PPError ("Division by zero");
Expr->IVal = 0;
} else {
/* Handle signed and unsigned operands differently */
if ((Expr->Flags & PPEXPR_UNSIGNED) == 0) {
Expr->IVal = ((long)Val1 / (long)Val2);
} else {
Expr->IVal = (Val1 / Val2);
}
break;
case TOK_MOD:
if (Val2 == 0) {
PPError ("Modulo operation with zero");
Expr->IVal = 0;
}
break;
case TOK_MOD:
if (Val2 == 0) {
PPError ("Modulo operation with zero");
Expr->IVal = 0;
} else {
/* Handle signed and unsigned operands differently */
if ((Expr->Flags & PPEXPR_UNSIGNED) == 0) {
Expr->IVal = ((long)Val1 % (long)Val2);
} else {
Expr->IVal = (Val1 % Val2);
}
break;
default:
Internal ("PPhie_internal: got token 0x%X\n", Tok);
}
} else {
/* Evaluate the result for unsigned operands */
unsigned long Val1 = Expr->IVal;
unsigned long Val2 = Rhs.IVal;
switch (Tok) {
case TOK_OR:
Expr->IVal = (Val1 | Val2);
break;
case TOK_XOR:
Expr->IVal = (Val1 ^ Val2);
break;
case TOK_AND:
Expr->IVal = (Val1 & Val2);
break;
case TOK_PLUS:
Expr->IVal = (Val1 + Val2);
break;
case TOK_MINUS:
Expr->IVal = (Val1 - Val2);
break;
case TOK_MUL:
Expr->IVal = (Val1 * Val2);
break;
case TOK_DIV:
if (Val2 == 0) {
PPError ("Division by zero");
Expr->IVal = 0;
} else {
Expr->IVal = (Val1 / Val2);
}
break;
case TOK_MOD:
if (Val2 == 0) {
PPError ("Modulo operation with zero");
Expr->IVal = 0;
} else {
Expr->IVal = (Val1 % Val2);
}
break;
default:
Internal ("PPhie_internal: got token 0x%X\n", Tok);
}
}
break;
default:
Internal ("PPhie_internal: got token 0x%X\n", Tok);
}
}
}
@ -519,12 +482,21 @@ static void PPhie7 (PPExpr* Expr)
/* Evaluate */
if (PPEvaluationEnabled && !PPEvaluationFailed) {
/* To shift by a negative value is equivalent to shift to the
** opposite direction.
*/
if ((Rhs.Flags & PPEXPR_UNSIGNED) != 0 && Rhs.IVal > (long)LONG_BITS) {
/* For now we use 32-bit integer types for PP integer constants */
if ((Rhs.Flags & PPEXPR_UNSIGNED) != 0) {
if ((unsigned long)Rhs.IVal > LONG_BITS) {
Rhs.IVal = (long)LONG_BITS;
}
} else if (Rhs.IVal > (long)LONG_BITS) {
Rhs.IVal = (long)LONG_BITS;
} else if (Rhs.IVal < -(long)LONG_BITS) {
Rhs.IVal = -(long)LONG_BITS;
}
/* Positive count for left-shift and negative for right-shift. So
** to shift by a count is equivalent to shift to the opposite
** direction by the negated count.
*/
if (Op == TOK_SHR) {
Rhs.IVal = -Rhs.IVal;
}
@ -532,27 +504,26 @@ static void PPhie7 (PPExpr* Expr)
/* Evaluate the result */
if ((Expr->Flags & PPEXPR_UNSIGNED) != 0) {
if (Rhs.IVal >= (long)LONG_BITS) {
/* For now we use (unsigned) long types for integer constants */
PPWarning ("Integer overflow in preprocessor expression");
Expr->IVal = 0;
} else if (Rhs.IVal > 0) {
Expr->IVal <<= Rhs.IVal;
} else if (Rhs.IVal < -(long)LONG_BITS) {
} else if (Rhs.IVal <= -(long)LONG_BITS) {
Expr->IVal = 0;
} else if (Rhs.IVal < 0) {
Expr->IVal = (unsigned long)Expr->IVal >> -Rhs.IVal;
}
} else {
/* -1 for sign bit */
if (Rhs.IVal >= (long)(LONG_BITS - 1)) {
/* For now we use (unsigned) long types for integer constants */
PPWarning ("Integer overflow in preprocessor expression");
Expr->IVal = 0;
} else if (Rhs.IVal > 0) {
Expr->IVal <<= Rhs.IVal;
} else if (Rhs.IVal < -(long)LONG_BITS) {
Expr->IVal = -1;
} else if (Rhs.IVal <= -(long)LONG_BITS) {
Expr->IVal = Expr->IVal >= 0 ? 0 : -1;
} else if (Rhs.IVal < 0) {
Expr->IVal >>= Expr->IVal >> -Rhs.IVal;
Expr->IVal = (long)Expr->IVal >> -Rhs.IVal;
}
}
}
@ -752,7 +723,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

@ -235,10 +235,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 {
@ -633,7 +643,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) {
@ -650,7 +660,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

@ -139,20 +139,34 @@ void ShiftExpr (struct ExprDesc* Expr)
/* Remove the code that pushes the rhs onto the stack. */
RemoveCode (&Mark2);
/* If the shift count is greater or equal than the bit count of
** the operand, the behaviour is undefined according to the
** standard.
/* If the shift count is greater than or equal to the width of the
** promoted left operand, the behaviour is undefined according to
** the standard.
*/
if (Expr2.IVal < 0) {
if (!ED_IsUneval (Expr)) {
if (Expr2.IVal < 0) {
Warning ("Negative shift count %ld treated as %u for %s",
Expr2.IVal,
(unsigned)Expr2.IVal & (ExprBits - 1),
GetBasicTypeName (ResultType));
} else if (Expr2.IVal >= (long) ExprBits) {
Warning ("Shift count %ld >= width of %s treated as %u",
Expr2.IVal,
GetBasicTypeName (ResultType),
(unsigned)Expr2.IVal & (ExprBits - 1));
}
}
Warning ("Shift count '%ld' is negative", Expr2.IVal);
Expr2.IVal &= ExprBits - 1;
} else if (Expr2.IVal >= (long) ExprBits) {
Warning ("Shift count '%ld' >= width of type", Expr2.IVal);
Expr2.IVal &= ExprBits - 1;
/* Here we simply "wrap" the shift count around the width */
Expr2.IVal &= ExprBits - 1;
/* Additional check for bit-fields */
if (IsTypeBitField (Expr->Type) &&
Tok == TOK_SHR &&
Expr2.IVal >= (long) Expr->Type->A.B.Width) {
if (!ED_IsUneval (Expr)) {
Warning ("Right-shift count %ld >= width of bit-field", Expr2.IVal);
}
}
/* If the shift count is zero, nothing happens. If the left hand
@ -173,7 +187,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 */
@ -230,8 +230,8 @@ const DeclAttr* SymGetAttr (const SymEntry* Sym, DeclAttrType AttrType)
void SymUseAttr (SymEntry* Sym, struct Declaration* D)
/* Use the attributes from the declaration for this symbol */
void SymUseAttr (SymEntry* Sym, struct Declarator* D)
/* Use the attributes from the declarator for this symbol */
{
/* We cannot specify attributes twice */
if ((Sym->Flags & SC_HAVEATTR) != 0) {
@ -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 */
};
@ -299,32 +298,24 @@ INLINE int SymHasAttr (const SymEntry* Sym, DeclAttrType A)
# define SymHasAttr(Sym, A) (SymGetAttr (Sym, A) != 0)
#endif
void SymUseAttr (SymEntry* Sym, struct Declaration* D);
/* Use the attributes from the declaration for this symbol */
void SymUseAttr (SymEntry* Sym, struct Declarator* D);
/* Use the attributes from the declarator 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

@ -266,18 +266,6 @@ static void DoCompare (const Type* lhs, const Type* rhs, typecmp_t* Result)
LeftType = (GetUnderlyingTypeCode (lhs) & T_MASK_TYPE);
RightType = (GetUnderlyingTypeCode (rhs) & T_MASK_TYPE);
/* If one side is a pointer and the other side is an array, both are
** compatible.
*/
if (LeftType == T_TYPE_PTR && RightType == T_TYPE_ARRAY) {
RightType = T_TYPE_PTR;
SetResult (Result, TC_PTR_DECAY);
}
if (LeftType == T_TYPE_ARRAY && RightType == T_TYPE_PTR) {
LeftType = T_TYPE_PTR;
SetResult (Result, TC_STRICT_COMPATIBLE);
}
/* Bit-fields are considered compatible if they have the same
** signedness, bit-offset and bit-width.
*/
@ -287,12 +275,27 @@ static void DoCompare (const Type* lhs, const Type* rhs, typecmp_t* Result)
lhs->A.B.Offs != rhs->A.B.Offs ||
lhs->A.B.Width != rhs->A.B.Width) {
SetResult (Result, TC_INCOMPATIBLE);
return;
}
if (LeftType != RightType) {
SetResult (Result, TC_STRICT_COMPATIBLE);
}
}
/* If one side is a pointer and the other side is an array, both are
** compatible.
*/
if (Result->Indirections == 0) {
if (LeftType == T_TYPE_PTR && RightType == T_TYPE_ARRAY) {
RightType = T_TYPE_PTR;
SetResult (Result, TC_PTR_DECAY);
}
if (LeftType == T_TYPE_ARRAY && RightType == T_TYPE_PTR) {
LeftType = T_TYPE_PTR;
SetResult (Result, TC_STRICT_COMPATIBLE);
}
}
/* If the underlying types are not identical, the types are incompatible */
if (LeftType != RightType) {
SetResult (Result, TC_INCOMPATIBLE);
@ -303,8 +306,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 +423,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) __attribute__((__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) 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,31 @@ ifneq ($(shell echo),)
endif
ifdef CMD_EXE
S = $(subst /,\,/)
EXE = .exe
MKDIR = mkdir $(subst /,\,$1)
RMDIR = -rmdir /q /s $(subst /,\,$1)
TRUE = exit 0
CAT = type $(subst /,\,$1)
else
S = /
EXE =
MKDIR = mkdir -p $1
RMDIR = $(RM) -r $1
TRUE = true
CAT = cat $1
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 +56,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) 2> $$(@:.bin=.err2)
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) 2> $$(@:.bin=.ld65-err2)
endif
else
$(CA65) -t none -o $$(@:.bin=.o) $$< > $$(@:.bin=.err) 2>&1 || true
$(CA65) -t none -o $$(@:.bin=.o) $$< > $$(@:.bin=.err) 2> $$(@:.bin=.err2) || $(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) 2> $$(@:.bin=.ld65-err2) || $(TRUE)
endif
endif
@ -67,18 +73,25 @@ else
$(ISEQUAL) --empty $$(@:.bin=.err)
endif
ifneq ($(wildcard ref/$1.err2-ref),)
$(ISEQUAL) ref/$1.err2-ref $$(@:.bin=.err2)
else
$(ISEQUAL) --empty $$(@:.bin=.err2)
endif
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),)
@ -86,16 +99,30 @@ ifneq ($(wildcard $(WORKDIR)/$1.ld65-err),)
endif
endif
ifneq ($(wildcard ref/$1.ld65err2-ref),)
@echo $(CAT) $$(@:.bin=.ld65-err2)
# FIXME: somehow this refuses to work in cmd.exe
ifndef CMD_EXE
$(call CAT,$$(@:.bin=.ld65-err2))
-diff -u ref/$1.ld65err2-ref $$(@:.bin=.ld65-err2)
endif
$(ISEQUAL) --wildcards ref/$1.ld65err2-ref $$(@:.bin=.ld65-err2)
else
ifneq ($(wildcard $(WORKDIR)/$1.ld65-err2),)
$(ISEQUAL) --empty $$(@:.bin=.ld65-err2)
endif
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) 2> $$(@:.bin=.list-err2)
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) 2> $$(@:.bin=.list-ld65-err2)
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) 2> $$(@:.bin=.list-err2) || $(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) 2> $$(@:.bin=.list-ld65-err2) || $(TRUE)
endif
endif
@ -113,10 +140,26 @@ ifneq ($(wildcard $(WORKDIR)/$1.list-ld65-err),)
endif
endif
ifneq ($(wildcard ref/$1.err2-ref),)
$(ISEQUAL) ref/$1.err2-ref $$(@:.bin=.list-err2)
else
$(ISEQUAL) --empty $$(@:.bin=.list-err2)
endif
ifneq ($(wildcard ref/$1.ld65err2-ref),)
$(ISEQUAL) --wildcards ref/$1.ld65err2-ref $$(@:.bin=.list-ld65-err2)
else
ifneq ($(wildcard $(WORKDIR)/$1.list-ld65-err2),)
$(ISEQUAL) --empty $$(@:.bin=.list-ld65-err2)
endif
endif
# check if the result bin is the same as without listing file
ifeq ($(wildcard control/$1.err),)
ifeq ($(wildcard control/$1.err2),)
$(ISEQUAL) $$@ $$(@:.bin=.list-bin)
endif
endif
ifneq ($(wildcard ref/$1.list-ref),)
# we have a reference file, compare that, too

View File

@ -1,15 +1,6 @@
.paramcount = 3
.paramcount = 5
010-paramcount.s:18: Warning: User warning: r1 is blank!
010-paramcount.s:14: Note: Macro was defined here
010-paramcount.s:8: Note: Macro was defined here
.paramcount = 3
.paramcount = 5
010-paramcount.s:19: Warning: User warning: r1 is blank!
010-paramcount.s:14: Note: Macro was defined here
010-paramcount.s:8: Note: Macro was defined here
.paramcount = 1
.paramcount = 5
010-paramcount.s:20: Warning: User warning: r1 is blank!
010-paramcount.s:14: Note: Macro was defined here
010-paramcount.s:8: Note: Macro was defined here

View File

@ -0,0 +1,9 @@
010-paramcount.s:18: Warning: User warning: r1 is blank!
010-paramcount.s:14: Note: Macro was defined here
010-paramcount.s:8: Note: Macro was defined here
010-paramcount.s:19: Warning: User warning: r1 is blank!
010-paramcount.s:14: Note: Macro was defined here
010-paramcount.s:8: Note: Macro was defined here
010-paramcount.s:20: Warning: User warning: r1 is blank!
010-paramcount.s:14: Note: Macro was defined here
010-paramcount.s:8: Note: Macro was defined here

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

@ -0,0 +1,5 @@
/* Bug #1895 - missing diagnostics on incompatible pointer/array types */
#define DO_TEST_1_SUB_1_A
#include "bug1895-common.h"

View File

@ -0,0 +1,5 @@
/* Bug #1895 - missing diagnostics on incompatible pointer/array types */
#define DO_TEST_1_SUB_1_B
#include "bug1895-common.h"

View File

@ -0,0 +1,5 @@
/* Bug #1895 - missing diagnostics on incompatible pointer/array types */
#define DO_TEST_1_SUB_2_A
#include "bug1895-common.h"

View File

@ -0,0 +1,5 @@
/* Bug #1895 - missing diagnostics on incompatible pointer/array types */
#define DO_TEST_1_SUB_2_B
#include "bug1895-common.h"

View File

@ -0,0 +1,5 @@
/* Bug #1895 - missing diagnostics on incompatible pointer/array types */
#define DO_TEST_1_SUB_4_A
#include "bug1895-common.h"

View File

@ -0,0 +1,5 @@
/* Bug #1895 - missing diagnostics on incompatible pointer/array types */
#define DO_TEST_1_SUB_4_B
#include "bug1895-common.h"

View File

@ -0,0 +1,5 @@
/* Bug #1895 - missing diagnostics on incompatible pointer/array types */
#define DO_TEST_1_SUB_5_A
#include "bug1895-common.h"

View File

@ -0,0 +1,5 @@
/* Bug #1895 - missing diagnostics on incompatible pointer/array types */
#define DO_TEST_1_SUB_5_B
#include "bug1895-common.h"

196
test/err/bug1895-common.h Normal file
View File

@ -0,0 +1,196 @@
/* Bug #1895 - missing diagnostics on incompatible pointer/array types
Test of incompatible pointer/array types in assignment ans conditional
expressions, as well as function prototypes.
In each source file, define a single macro and include this file to perform
a coresponding test individually.
https://github.com/cc65/cc65/issues/1895
*/
/* Test 1 suite */
#ifdef DO_TEST_1_SUB_1_A
#define TEST_1_SUB_1_A CMP_TYPES_1
#else
#define TEST_1_SUB_1_A BLANK
#endif
#ifdef DO_TEST_1_SUB_1_B
#define TEST_1_SUB_1_B CMP_TYPES_1
#else
#define TEST_1_SUB_1_B BLANK
#endif
#ifdef DO_TEST_1_SUB_2_A
#define TEST_1_SUB_2_A CMP_TYPES_1
#else
#define TEST_1_SUB_2_A BLANK
#endif
#ifdef DO_TEST_1_SUB_2_B
#define TEST_1_SUB_2_B CMP_TYPES_1
#else
#define TEST_1_SUB_2_B BLANK
#endif
#ifdef DO_TEST_1_SUB_4_A
#define TEST_1_SUB_4_A CMP_TYPES_1
#else
#define TEST_1_SUB_4_A BLANK
#endif
#ifdef DO_TEST_1_SUB_4_B
#define TEST_1_SUB_4_B CMP_TYPES_1
#else
#define TEST_1_SUB_4_B BLANK
#endif
#ifdef DO_TEST_1_SUB_5_A
#define TEST_1_SUB_5_A CMP_TYPES_1
#else
#define TEST_1_SUB_5_A BLANK
#endif
#ifdef DO_TEST_1_SUB_5_B
#define TEST_1_SUB_5_B CMP_TYPES_1
#else
#define TEST_1_SUB_5_B BLANK
#endif
/* Test 2 suite */
#ifdef DO_TEST_2_SUB_1
#define TEST_2_SUB_1 CMP_TYPES_2
#else
#define TEST_2_SUB_1 BLANK
#endif
#ifdef DO_TEST_2_SUB_2
#define TEST_2_SUB_2 CMP_TYPES_2
#else
#define TEST_2_SUB_2 BLANK
#endif
#ifdef DO_TEST_2_SUB_3
#define TEST_2_SUB_3 CMP_TYPES_2
#else
#define TEST_2_SUB_3 BLANK
#endif
#ifdef DO_TEST_2_SUB_4
#define TEST_2_SUB_4 CMP_TYPES_2
#else
#define TEST_2_SUB_4 BLANK
#endif
#ifdef DO_TEST_2_SUB_5
#define TEST_2_SUB_5 CMP_TYPES_2
#else
#define TEST_2_SUB_5 BLANK
#endif
/* Test 3 suite */
#ifdef DO_TEST_3_SUB_1
#define TEST_3_SUB_1 CMP_TYPES_3
#else
#define TEST_3_SUB_1 BLANK
#endif
#ifdef DO_TEST_3_SUB_2
#define TEST_3_SUB_2 CMP_TYPES_3
#else
#define TEST_3_SUB_2 BLANK
#endif
#ifdef DO_TEST_3_SUB_3
#define TEST_3_SUB_3 CMP_TYPES_3
#else
#define TEST_3_SUB_3 BLANK
#endif
#ifdef DO_TEST_3_SUB_4
#define TEST_3_SUB_4 CMP_TYPES_3
#else
#define TEST_3_SUB_4 BLANK
#endif
#ifdef DO_TEST_3_SUB_5
#define TEST_3_SUB_5 CMP_TYPES_3
#else
#define TEST_3_SUB_5 BLANK
#endif
/* Implementation */
#define CONCAT(a, b) CONCAT_impl_(a, b)
#define CONCAT_impl_(a, b) a##b
#define BLANK(...)
#define DECL_FUNCS(A, B)\
void CONCAT(foo_,__LINE__)(A); void CONCAT(foo_,__LINE__)(B);
/* Test with assignment */
#define CMP_TYPES_1(A, B)\
do {\
A p; B q;\
_Pragma("warn(error, on)")\
p = q;\
_Pragma("warn(error, off)")\
} while (0)
/* Test with conditional expression */
#define CMP_TYPES_2(A, B)\
do {\
A p; B q;\
_Pragma("warn(error, on)")\
v = v ? p : q;\
_Pragma("warn(error, off)")\
} while (0)
/* Test with function prototype */
#define CMP_TYPES_3(A, B)\
do {\
DECL_FUNCS(A,B);\
} while (0)
static void *v;
typedef int (*p1)[3]; /* pointer to array */
typedef int **q1; /* pointer to pointer */
typedef int (**p2)[3]; /* pointer to pointer to array */
typedef int ***q2; /* pointer to pointer to pointer */
typedef int p3[1][3]; /* array of array */
typedef int *q3[1]; /* array of pointer */
typedef int const **p4; /* pointer to pointer to const */
typedef int **q4; /* pointer to pointer to non-const */
typedef int (*p5)(int (*)(p3)); /* pointer to function taking pointer to function taking pointer to array */
typedef int (*q5)(int (*)(q3)); /* pointer to function taking pointer to function taking pointer to pointer */
int main(void)
{
/* Warnings */
TEST_1_SUB_1_A(p1, q1);
TEST_1_SUB_1_B(q1, p1);
TEST_1_SUB_2_A(p2, q2);
TEST_1_SUB_2_B(q2, p2);
/* TEST_1_SUB_3_A(p3, q3); */
/* TEST_1_SUB_3_B(q3, p3); */
TEST_1_SUB_4_A(p4, q4);
TEST_1_SUB_4_B(q4, p4);
TEST_1_SUB_5_A(p5, q5);
TEST_1_SUB_5_B(q5, p5);
/* GCC and clang give warnings while cc65 gives errors */
TEST_2_SUB_1(p1, q1);
TEST_2_SUB_2(p2, q2);
TEST_2_SUB_3(p3, q3);
TEST_2_SUB_4(p4, q4);
TEST_2_SUB_5(p5, q5);
/* Errors */
TEST_3_SUB_1(p1, q1);
TEST_3_SUB_2(p2, q2);
TEST_3_SUB_3(p3, q3);
TEST_3_SUB_4(p4, q4);
TEST_3_SUB_5(p5, q5);
return 0;
}

5
test/err/bug1895-cond1.c Normal file
View File

@ -0,0 +1,5 @@
/* Bug #1895 - missing diagnostics on incompatible pointer/array types */
#define DO_TEST_2_SUB_1
#include "bug1895-common.h"

5
test/err/bug1895-cond2.c Normal file
View File

@ -0,0 +1,5 @@
/* Bug #1895 - missing diagnostics on incompatible pointer/array types */
#define DO_TEST_2_SUB_2
#include "bug1895-common.h"

5
test/err/bug1895-cond3.c Normal file
View File

@ -0,0 +1,5 @@
/* Bug #1895 - missing diagnostics on incompatible pointer/array types */
#define DO_TEST_2_SUB_3
#include "bug1895-common.h"

5
test/err/bug1895-cond4.c Normal file
View File

@ -0,0 +1,5 @@
/* Bug #1895 - missing diagnostics on incompatible pointer/array types */
#define DO_TEST_2_SUB_4
#include "bug1895-common.h"

5
test/err/bug1895-cond5.c Normal file
View File

@ -0,0 +1,5 @@
/* Bug #1895 - missing diagnostics on incompatible pointer/array types */
#define DO_TEST_2_SUB_5
#include "bug1895-common.h"

Some files were not shown because too many files have changed in this diff Show More