mirror of
https://github.com/cc65/cc65.git
synced 2025-04-08 19:38:55 +00:00
Merge branch 'master' into underscores
This commit is contained in:
commit
d6c37a757d
22
.github/checks/Makefile
vendored
22
.github/checks/Makefile
vendored
@ -1,7 +1,23 @@
|
||||
|
||||
.PHONY: checkstyle tabs lastline spaces noexec
|
||||
ifneq ($(shell echo),)
|
||||
CMD_EXE = 1
|
||||
endif
|
||||
|
||||
checkstyle: tabs lastline spaces noexec
|
||||
ifdef CMD_EXE
|
||||
|
||||
.PHONY: checkstyle
|
||||
|
||||
checkstyle:
|
||||
$(info INFO: style checks require bash.)
|
||||
|
||||
else
|
||||
|
||||
.PHONY: checkstyle lineendings tabs lastline spaces noexec
|
||||
|
||||
checkstyle: lineendings tabs lastline spaces noexec
|
||||
|
||||
lineendings: lineendings.sh
|
||||
@./lineendings.sh
|
||||
|
||||
tabs: tabs.sh
|
||||
@./tabs.sh
|
||||
@ -14,3 +30,5 @@ spaces: spaces.sh
|
||||
|
||||
noexec: noexec.sh
|
||||
@./noexec.sh
|
||||
|
||||
endif
|
||||
|
18
.github/checks/lineendings.sh
vendored
Executable file
18
.github/checks/lineendings.sh
vendored
Executable file
@ -0,0 +1,18 @@
|
||||
#! /bin/bash
|
||||
OLDCWD=`pwd`
|
||||
SCRIPT_PATH=`dirname $0`
|
||||
CHECK_PATH=.
|
||||
|
||||
cd $SCRIPT_PATH/../../
|
||||
|
||||
FILES=`find $CHECK_PATH -type f \( -name \*.inc -o -name Makefile -o -name \*.cfg -o -name \*.\[chs\] -o -name \*.mac -o -name \*.asm -o -name \*.sgml \) -print | grep -v "libwrk/" | grep -v "testwrk/" | xargs grep -IUl $'\r'`
|
||||
|
||||
cd $OLDCWD
|
||||
|
||||
if [ x"$FILES"x != xx ]; then
|
||||
echo "error: found CR in the following files:" >&2
|
||||
for n in $FILES; do
|
||||
echo $n >&2
|
||||
done
|
||||
exit -1
|
||||
fi
|
4
.github/workflows/build-on-pull-request.yml
vendored
4
.github/workflows/build-on-pull-request.yml
vendored
@ -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
|
||||
|
@ -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
|
||||
|
@ -8,11 +8,16 @@ This document contains all kinds of information that you should know if you want
|
||||
|
||||
* You must obey these rules when contributing new code or documentation to cc65. We are well aware that not all existing code may respect all rules outlined here - but this is no reason for you not to respect them.
|
||||
* One commit/patch/PR per issue. Do not mix several things unless they are very closely related.
|
||||
* Sometimes when you make a PR, it may break completely unrelated tests. However, any PR is expected to merge cleanly with no failures. That means in practise that you are expected to fix/update the failing tests if required - for example this might be needed if you make changes to the compiler that changes the format of error- or warning messages. In that case you might have to update some reference files in the testbench. Obviously still check if that is actually the right thing to do ;)
|
||||
|
||||
# Codestyle rules
|
||||
|
||||
## All Sources
|
||||
|
||||
### Line endings
|
||||
|
||||
All files must only contain Unix style 'LF' line endings. Please configure your editors accordingly.
|
||||
|
||||
### TABs and spaces
|
||||
|
||||
This is an ongoing controversial topic - everyone knows that. However, the following is how we do it :)
|
||||
|
@ -461,7 +461,8 @@ following attributes are recognized:
|
||||
<tag><tt>END</tt></tag>
|
||||
This gives the end address of the range. The end address is inclusive, that
|
||||
means, it is part of the range. Of course, it may not be smaller than the
|
||||
start address.
|
||||
start address. Optionally, the end may be given as a decimal offset instead
|
||||
of an absolute address, "+3", to specify it as a size.
|
||||
|
||||
<tag><tt>NAME</tt></tag>
|
||||
This is a convenience attribute. It takes a string argument and will cause
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -414,6 +414,7 @@ TARGETS := \
|
||||
|
||||
define TARGET_recipe
|
||||
|
||||
@echo making samples for: $(T)
|
||||
@$(MAKE) -j2 SYS:=$(T)
|
||||
@$(MAKE) --no-print-directory clean SYS:=$(T)
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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);
|
||||
|
@ -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 */
|
||||
|
@ -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);
|
||||
|
@ -399,10 +399,7 @@ static CodeEntry* ParseInsn (CodeSeg* S, LineInfo* LI, const char* L)
|
||||
|
||||
default:
|
||||
/* Absolute, maybe indexed */
|
||||
L = ReadToken (L, ", ", Arg, sizeof (Arg));
|
||||
if (*L == ' ') {
|
||||
L = SkipSpace (L+1);
|
||||
}
|
||||
L = ReadToken (L, ",", Arg, sizeof (Arg));
|
||||
if (*L == '\0') {
|
||||
/* Absolute, zeropage or branch */
|
||||
if ((OPC->Info & OF_BRA) != 0) {
|
||||
|
@ -79,7 +79,7 @@ static void Parse (void)
|
||||
/* Top level parser routine. */
|
||||
{
|
||||
int comma;
|
||||
SymEntry* Entry;
|
||||
SymEntry* Sym;
|
||||
FuncDesc* FuncDef = 0;
|
||||
|
||||
/* Initialization for deferred operations */
|
||||
@ -123,7 +123,7 @@ static void Parse (void)
|
||||
}
|
||||
|
||||
/* Read variable defs and functions */
|
||||
ParseDeclSpec (&Spec, SC_EXTERN | SC_STATIC, T_INT);
|
||||
ParseDeclSpec (&Spec, TS_DEFAULT_TYPE_INT, SC_EXTERN | SC_STATIC);
|
||||
|
||||
/* Don't accept illegal storage classes */
|
||||
if ((Spec.StorageClass & SC_TYPEMASK) == 0) {
|
||||
@ -142,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);
|
||||
|
1348
src/cc65/datatype.c
1348
src/cc65/datatype.c
File diff suppressed because it is too large
Load Diff
@ -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 */
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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? */
|
||||
|
@ -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 */
|
||||
|
||||
|
||||
|
123
src/cc65/error.c
123
src/cc65/error.c
@ -108,6 +108,36 @@ Collection DiagnosticStrBufs;
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Helpers */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
static const char* GetDiagnosticFileName (void)
|
||||
/* Get the source file name where the diagnostic info refers to */
|
||||
{
|
||||
if (CurTok.LI) {
|
||||
return GetInputName (CurTok.LI);
|
||||
} else {
|
||||
return GetCurrentFilename ();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static unsigned GetDiagnosticLineNum (void)
|
||||
/* Get the source line number where the diagnostic info refers to */
|
||||
{
|
||||
if (CurTok.LI) {
|
||||
return GetInputLine (CurTok.LI);
|
||||
} else {
|
||||
return GetCurrentLineNum ();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Handling of fatal errors */
|
||||
/*****************************************************************************/
|
||||
@ -119,17 +149,7 @@ void Fatal (const char* Format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
const char* FileName;
|
||||
unsigned LineNum;
|
||||
if (CurTok.LI) {
|
||||
FileName = GetInputName (CurTok.LI);
|
||||
LineNum = GetInputLine (CurTok.LI);
|
||||
} else {
|
||||
FileName = GetCurrentFile ();
|
||||
LineNum = GetCurrentLine ();
|
||||
}
|
||||
|
||||
fprintf (stderr, "%s:%u: Fatal: ", FileName, LineNum);
|
||||
fprintf (stderr, "%s:%u: Fatal: ", GetDiagnosticFileName (), GetDiagnosticLineNum ());
|
||||
|
||||
va_start (ap, Format);
|
||||
vfprintf (stderr, Format, ap);
|
||||
@ -145,22 +165,12 @@ void Fatal (const char* Format, ...)
|
||||
|
||||
|
||||
void Internal (const char* Format, ...)
|
||||
/* Print a message about an internal compiler error and die. */
|
||||
/* Print a message about an internal compiler error and die */
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
const char* FileName;
|
||||
unsigned LineNum;
|
||||
if (CurTok.LI) {
|
||||
FileName = GetInputName (CurTok.LI);
|
||||
LineNum = GetInputLine (CurTok.LI);
|
||||
} else {
|
||||
FileName = GetCurrentFile ();
|
||||
LineNum = GetCurrentLine ();
|
||||
}
|
||||
|
||||
fprintf (stderr, "%s:%u: Internal compiler error:\n",
|
||||
FileName, LineNum);
|
||||
GetDiagnosticFileName (), GetDiagnosticLineNum ());
|
||||
|
||||
va_start (ap, Format);
|
||||
vfprintf (stderr, Format, ap);
|
||||
@ -184,7 +194,7 @@ void Internal (const char* Format, ...)
|
||||
|
||||
|
||||
static void IntError (const char* Filename, unsigned LineNo, const char* Msg, va_list ap)
|
||||
/* Print an error message - internal function*/
|
||||
/* Print an error message - internal function */
|
||||
{
|
||||
fprintf (stderr, "%s:%u: Error: ", Filename, LineNo);
|
||||
vfprintf (stderr, Msg, ap);
|
||||
@ -206,7 +216,7 @@ void Error (const char* Format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start (ap, Format);
|
||||
IntError (GetInputName (CurTok.LI), GetInputLine (CurTok.LI), Format, ap);
|
||||
IntError (GetDiagnosticFileName (), GetDiagnosticLineNum (), Format, ap);
|
||||
va_end (ap);
|
||||
}
|
||||
|
||||
@ -224,11 +234,11 @@ void LIError (const LineInfo* LI, const char* Format, ...)
|
||||
|
||||
|
||||
void PPError (const char* Format, ...)
|
||||
/* Print an error message. For use within the preprocessor. */
|
||||
/* Print an error message. For use within the preprocessor */
|
||||
{
|
||||
va_list ap;
|
||||
va_start (ap, Format);
|
||||
IntError (GetCurrentFile(), GetCurrentLine(), Format, ap);
|
||||
IntError (GetCurrentFilename(), GetCurrentLineNum(), Format, ap);
|
||||
va_end (ap);
|
||||
}
|
||||
|
||||
@ -241,7 +251,7 @@ void PPError (const char* Format, ...)
|
||||
|
||||
|
||||
static void IntWarning (const char* Filename, unsigned LineNo, const char* Msg, va_list ap)
|
||||
/* Print warning message - internal function. */
|
||||
/* Print a warning message - internal function */
|
||||
{
|
||||
if (IS_Get (&WarningsAreErrors)) {
|
||||
|
||||
@ -265,11 +275,11 @@ static void IntWarning (const char* Filename, unsigned LineNo, const char* Msg,
|
||||
|
||||
|
||||
void Warning (const char* Format, ...)
|
||||
/* Print warning message. */
|
||||
/* Print a warning message */
|
||||
{
|
||||
va_list ap;
|
||||
va_start (ap, Format);
|
||||
IntWarning (GetInputName (CurTok.LI), GetInputLine (CurTok.LI), Format, ap);
|
||||
IntWarning (GetDiagnosticFileName (), GetDiagnosticLineNum (), Format, ap);
|
||||
va_end (ap);
|
||||
}
|
||||
|
||||
@ -287,11 +297,11 @@ void LIWarning (const LineInfo* LI, const char* Format, ...)
|
||||
|
||||
|
||||
void PPWarning (const char* Format, ...)
|
||||
/* Print warning message. For use within the preprocessor. */
|
||||
/* Print a warning message. For use within the preprocessor */
|
||||
{
|
||||
va_list ap;
|
||||
va_start (ap, Format);
|
||||
IntWarning (GetCurrentFile(), GetCurrentLine(), Format, ap);
|
||||
IntWarning (GetCurrentFilename(), GetCurrentLineNum(), Format, ap);
|
||||
va_end (ap);
|
||||
}
|
||||
|
||||
@ -326,6 +336,55 @@ void ListWarnings (FILE* F)
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Handling of other infos */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
static void IntNote (const char* Filename, unsigned LineNo, const char* Msg, va_list ap)
|
||||
/* Print a note message - internal function */
|
||||
{
|
||||
fprintf (stderr, "%s:%u: Note: ", Filename, LineNo);
|
||||
vfprintf (stderr, Msg, ap);
|
||||
fprintf (stderr, "\n");
|
||||
}
|
||||
|
||||
|
||||
|
||||
void Note (const char* Format, ...)
|
||||
/* Print a note message */
|
||||
{
|
||||
va_list ap;
|
||||
va_start (ap, Format);
|
||||
IntNote (GetDiagnosticFileName (), GetDiagnosticLineNum (), Format, ap);
|
||||
va_end (ap);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void LINote (const LineInfo* LI, const char* Format, ...)
|
||||
/* Print a note message with the line info given explicitly */
|
||||
{
|
||||
va_list ap;
|
||||
va_start (ap, Format);
|
||||
IntNote (GetInputName (LI), GetInputLine (LI), Format, ap);
|
||||
va_end (ap);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void PPNote (const char* Format, ...)
|
||||
/* Print a note message. For use within the preprocessor */
|
||||
{
|
||||
va_list ap;
|
||||
va_start (ap, Format);
|
||||
IntNote (GetCurrentFilename(), GetCurrentLineNum(), Format, ap);
|
||||
va_end (ap);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Code */
|
||||
/*****************************************************************************/
|
||||
|
@ -92,7 +92,7 @@ void Fatal (const char* Format, ...) attribute ((noreturn, format (printf, 1, 2)
|
||||
/* Print a message about a fatal error and die */
|
||||
|
||||
void Internal (const char* Format, ...) attribute ((noreturn, format (printf, 1, 2)));
|
||||
/* Print a message about an internal compiler error and die. */
|
||||
/* Print a message about an internal compiler error and die */
|
||||
|
||||
void Error (const char* Format, ...) attribute ((format (printf, 1, 2)));
|
||||
/* Print an error message */
|
||||
@ -101,16 +101,16 @@ void LIError (const LineInfo* LI, const char* Format, ...) attribute ((format (p
|
||||
/* Print an error message with the line info given explicitly */
|
||||
|
||||
void PPError (const char* Format, ...) attribute ((format (printf, 1, 2)));
|
||||
/* Print an error message. For use within the preprocessor. */
|
||||
/* Print an error message. For use within the preprocessor */
|
||||
|
||||
void Warning (const char* Format, ...) attribute ((format (printf, 1, 2)));
|
||||
/* Print warning message. */
|
||||
/* Print a warning message */
|
||||
|
||||
void LIWarning (const LineInfo* LI, const char* Format, ...) attribute ((format (printf, 2, 3)));
|
||||
/* Print a warning message with the line info given explicitly */
|
||||
|
||||
void PPWarning (const char* Format, ...) attribute ((format (printf, 1, 2)));
|
||||
/* Print warning message. For use within the preprocessor. */
|
||||
/* Print a warning message. For use within the preprocessor */
|
||||
|
||||
IntStack* FindWarning (const char* Name);
|
||||
/* Search for a warning in the WarnMap table and return a pointer to the
|
||||
@ -120,6 +120,15 @@ IntStack* FindWarning (const char* Name);
|
||||
void ListWarnings (FILE* F);
|
||||
/* Print a list of warning types/names to the given file */
|
||||
|
||||
void Note (const char* Format, ...) attribute ((format (printf, 1, 2)));
|
||||
/* Print a note message */
|
||||
|
||||
void LINote (const LineInfo* LI, const char* Format, ...) attribute ((format (printf, 2, 3)));
|
||||
/* Print a note message with the line info given explicitly */
|
||||
|
||||
void PPNote (const char* Format, ...) attribute ((format (printf, 1, 2)));
|
||||
/* Print a note message. For use within the preprocessor */
|
||||
|
||||
void ErrorReport (void);
|
||||
/* Report errors (called at end of compile) */
|
||||
|
||||
|
296
src/cc65/expr.c
296
src/cc65/expr.c
@ -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 */
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -49,6 +49,7 @@ unsigned char DebugInfo = 0; /* Add debug info to the obj */
|
||||
unsigned char PreprocessOnly = 0; /* Just preprocess the input */
|
||||
unsigned char DebugOptOutput = 0; /* Output debug stuff */
|
||||
unsigned RegisterSpace = 6; /* Space available for register vars */
|
||||
unsigned AllowNewComments = 0; /* Allow new style comments in C89 mode */
|
||||
|
||||
/* Stackable options */
|
||||
IntStack WritableStrings = INTSTACK(0); /* Literal strings are r/w */
|
||||
|
@ -57,6 +57,7 @@ extern unsigned char DebugInfo; /* Add debug info to the obj */
|
||||
extern unsigned char PreprocessOnly; /* Just preprocess the input */
|
||||
extern unsigned char DebugOptOutput; /* Output debug stuff */
|
||||
extern unsigned RegisterSpace; /* Space available for register vars */
|
||||
extern unsigned AllowNewComments; /* Allow new style comments in C89 mode */
|
||||
|
||||
/* Stackable options */
|
||||
extern IntStack WritableStrings; /* Literal strings are r/w */
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
148
src/cc65/input.c
148
src/cc65/input.c
@ -67,6 +67,9 @@
|
||||
/* The current input line */
|
||||
StrBuf* Line;
|
||||
|
||||
/* The input line to reuse as the next line */
|
||||
static StrBuf* CurReusedLine;
|
||||
|
||||
/* Current and next input character */
|
||||
char CurC = '\0';
|
||||
char NextC = '\0';
|
||||
@ -103,8 +106,8 @@ static Collection IFiles = STATIC_COLLECTION_INITIALIZER;
|
||||
/* List of all active files */
|
||||
static Collection AFiles = STATIC_COLLECTION_INITIALIZER;
|
||||
|
||||
/* Input stack used when preprocessing. */
|
||||
static Collection InputStack = STATIC_COLLECTION_INITIALIZER;
|
||||
/* Input stack used when preprocessing */
|
||||
static Collection* CurrentInputStack;
|
||||
|
||||
/* Counter for the __COUNTER__ macro */
|
||||
static unsigned MainFileCounter;
|
||||
@ -394,34 +397,19 @@ static void GetInputChar (void)
|
||||
** are read by this function.
|
||||
*/
|
||||
{
|
||||
/* Drop all pushed fragments that don't have data left */
|
||||
while (SB_GetIndex (Line) >= SB_GetLen (Line)) {
|
||||
/* Cannot read more from this line, check next line on stack if any */
|
||||
if (CollCount (&InputStack) == 0) {
|
||||
/* This is THE line */
|
||||
break;
|
||||
}
|
||||
FreeStrBuf (Line);
|
||||
Line = CollPop (&InputStack);
|
||||
/* Get the next-next character from the line */
|
||||
if (SB_GetIndex (Line) + 1 < SB_GetLen (Line)) {
|
||||
/* CurC and NextC come from this fragment */
|
||||
CurC = SB_AtUnchecked (Line, SB_GetIndex (Line));
|
||||
NextC = SB_AtUnchecked (Line, SB_GetIndex (Line) + 1);
|
||||
} else {
|
||||
/* NextC is '\0' by default */
|
||||
NextC = '\0';
|
||||
|
||||
/* Get CurC from the line */
|
||||
CurC = SB_LookAt (Line, SB_GetIndex (Line));
|
||||
}
|
||||
|
||||
/* Now get the next characters from the line */
|
||||
if (SB_GetIndex (Line) >= SB_GetLen (Line)) {
|
||||
CurC = NextC = '\0';
|
||||
} else {
|
||||
CurC = SB_AtUnchecked (Line, SB_GetIndex (Line));
|
||||
if (SB_GetIndex (Line) + 1 < SB_GetLen (Line)) {
|
||||
/* NextC comes from this fragment */
|
||||
NextC = SB_AtUnchecked (Line, SB_GetIndex (Line) + 1);
|
||||
} else {
|
||||
/* NextC comes from next fragment */
|
||||
if (CollCount (&InputStack) > 0) {
|
||||
NextC = ' ';
|
||||
} else {
|
||||
NextC = '\0';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -441,17 +429,41 @@ void NextChar (void)
|
||||
|
||||
|
||||
|
||||
Collection* UseInputStack (Collection* InputStack)
|
||||
/* Use the provided input stack for incoming input. Return the previously used
|
||||
** InputStack.
|
||||
*/
|
||||
{
|
||||
Collection* OldInputStack = CurrentInputStack;
|
||||
|
||||
CurrentInputStack = InputStack;
|
||||
return OldInputStack;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void PushLine (StrBuf* L)
|
||||
/* Save the current input line and use a new one */
|
||||
{
|
||||
PRECONDITION (CurrentInputStack != 0);
|
||||
CollAppend (CurrentInputStack, Line);
|
||||
Line = L;
|
||||
GetInputChar ();
|
||||
}
|
||||
|
||||
|
||||
|
||||
void ReuseInputLine (void)
|
||||
/* Save and reuse the current line as the next line */
|
||||
{
|
||||
CurReusedLine = Line;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void ClearLine (void)
|
||||
/* Clear the current input line */
|
||||
{
|
||||
unsigned I;
|
||||
|
||||
/* Remove all pushed fragments from the input stack */
|
||||
for (I = 0; I < CollCount (&InputStack); ++I) {
|
||||
FreeStrBuf (CollAtUnchecked (&InputStack, I));
|
||||
}
|
||||
CollDeleteAll (&InputStack);
|
||||
|
||||
/* Clear the contents of Line */
|
||||
SB_Clear (Line);
|
||||
CurC = '\0';
|
||||
@ -482,12 +494,47 @@ int NextLine (void)
|
||||
int C;
|
||||
AFile* Input;
|
||||
|
||||
/* Clear the current line */
|
||||
ClearLine ();
|
||||
SB_Clear (Line);
|
||||
/* Overwrite the next input line with the pushed line if there is one */
|
||||
if (CurReusedLine != 0) {
|
||||
/* Use data move to resolve the issue that Line may be impersistent */
|
||||
if (Line != CurReusedLine) {
|
||||
SB_Move (Line, CurReusedLine);
|
||||
}
|
||||
/* Continue with this Line */
|
||||
InitLine (Line);
|
||||
CurReusedLine = 0;
|
||||
|
||||
/* Must have an input file when called */
|
||||
if (CollCount(&AFiles) == 0) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* If there are pushed input lines, read from them */
|
||||
if (CurrentInputStack != 0 && CollCount (CurrentInputStack) > 0) {
|
||||
/* Drop all pushed fragments that have no data left until one can be
|
||||
** used as input.
|
||||
*/
|
||||
do {
|
||||
/* Use data move to resolve the issue that Line may be impersistent */
|
||||
if (Line != CollLast (CurrentInputStack)) {
|
||||
SB_Move (Line, CollPop (CurrentInputStack));
|
||||
} else {
|
||||
CollPop (CurrentInputStack);
|
||||
}
|
||||
} while (CollCount (CurrentInputStack) > 0 &&
|
||||
SB_GetIndex (Line) >= SB_GetLen (Line));
|
||||
|
||||
if (SB_GetIndex (Line) < SB_GetLen (Line)) {
|
||||
InitLine (Line);
|
||||
|
||||
/* Successive */
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Otherwise, clear the current line */
|
||||
ClearLine ();
|
||||
|
||||
/* Must have an input file when going on */
|
||||
if (CollCount (&AFiles) == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -531,15 +578,16 @@ int NextLine (void)
|
||||
SB_Drop (Line, 1);
|
||||
}
|
||||
|
||||
/* If we don't have a line continuation character at the end,
|
||||
** we're done with this line. Otherwise replace the character
|
||||
** by a newline and continue reading.
|
||||
/* If we don't have a line continuation character at the end, we
|
||||
** are done with this line. Otherwise just skip the character and
|
||||
** continue reading.
|
||||
*/
|
||||
if (SB_LookAtLast (Line) == '\\') {
|
||||
Line->Buf[Line->Len-1] = '\n';
|
||||
} else {
|
||||
if (SB_LookAtLast (Line) != '\\') {
|
||||
Input->MissingNL = 0;
|
||||
break;
|
||||
} else {
|
||||
SB_Drop (Line, 1);
|
||||
ContinueLine ();
|
||||
}
|
||||
|
||||
} else if (C != '\0') { /* Ignore embedded NULs */
|
||||
@ -605,7 +653,7 @@ const char* GetInputFile (const struct IFile* IF)
|
||||
|
||||
|
||||
|
||||
const char* GetCurrentFile (void)
|
||||
const char* GetCurrentFilename (void)
|
||||
/* Return the name of the current input file */
|
||||
{
|
||||
unsigned AFileCount = CollCount (&AFiles);
|
||||
@ -620,7 +668,7 @@ const char* GetCurrentFile (void)
|
||||
|
||||
|
||||
|
||||
unsigned GetCurrentLine (void)
|
||||
unsigned GetCurrentLineNum (void)
|
||||
/* Return the line number in the current input file */
|
||||
{
|
||||
unsigned AFileCount = CollCount (&AFiles);
|
||||
@ -635,7 +683,7 @@ unsigned GetCurrentLine (void)
|
||||
|
||||
|
||||
|
||||
void SetCurrentLine (unsigned LineNum)
|
||||
void SetCurrentLineNum (unsigned LineNum)
|
||||
/* Set the line number in the current input file */
|
||||
{
|
||||
unsigned AFileCount = CollCount (&AFiles);
|
||||
|
@ -41,6 +41,7 @@
|
||||
#include <stdio.h>
|
||||
|
||||
/* common */
|
||||
#include "coll.h"
|
||||
#include "strbuf.h"
|
||||
|
||||
|
||||
@ -95,6 +96,17 @@ void NextChar (void);
|
||||
** are read by this function.
|
||||
*/
|
||||
|
||||
Collection* UseInputStack (Collection* InputStack);
|
||||
/* Use the provided input stack for incoming input. Return the previously used
|
||||
** InputStack.
|
||||
*/
|
||||
|
||||
void PushLine (StrBuf* L);
|
||||
/* Save the current input line and use a new one */
|
||||
|
||||
void ReuseInputLine (void);
|
||||
/* Save and reuse the current line as the next line */
|
||||
|
||||
void ClearLine (void);
|
||||
/* Clear the current input line */
|
||||
|
||||
@ -116,13 +128,13 @@ int PreprocessNextLine (void);
|
||||
const char* GetInputFile (const struct IFile* IF);
|
||||
/* Return a filename from an IFile struct */
|
||||
|
||||
const char* GetCurrentFile (void);
|
||||
const char* GetCurrentFilename (void);
|
||||
/* Return the name of the current input file */
|
||||
|
||||
unsigned GetCurrentLine (void);
|
||||
unsigned GetCurrentLineNum (void);
|
||||
/* Return the line number in the current input file */
|
||||
|
||||
void SetCurrentLine (unsigned LineNum);
|
||||
void SetCurrentLineNum (unsigned LineNum);
|
||||
/* Set the line number in the current input file */
|
||||
|
||||
void SetCurrentFilename (const char* Name);
|
||||
|
@ -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
|
||||
|
@ -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 */
|
||||
|
@ -74,19 +74,17 @@ Macro* NewMacro (const char* Name)
|
||||
*/
|
||||
{
|
||||
/* Get the length of the macro name */
|
||||
unsigned Len = strlen(Name);
|
||||
unsigned Len = strlen (Name);
|
||||
|
||||
/* Allocate the structure */
|
||||
Macro* M = (Macro*) xmalloc (sizeof(Macro) + Len);
|
||||
|
||||
/* Initialize the data */
|
||||
M->Next = 0;
|
||||
M->Expanding = 0;
|
||||
M->ArgCount = -1; /* Flag: Not a function like macro */
|
||||
M->MaxArgs = 0;
|
||||
InitCollection (&M->FormalArgs);
|
||||
M->Next = 0;
|
||||
M->ParamCount = -1; /* Flag: Not a function-like macro */
|
||||
InitCollection (&M->Params);
|
||||
SB_Init (&M->Replacement);
|
||||
M->Variadic = 0;
|
||||
M->Variadic = 0;
|
||||
memcpy (M->Name, Name, Len+1);
|
||||
|
||||
/* Return the new macro */
|
||||
@ -102,10 +100,10 @@ void FreeMacro (Macro* M)
|
||||
{
|
||||
unsigned I;
|
||||
|
||||
for (I = 0; I < CollCount (&M->FormalArgs); ++I) {
|
||||
xfree (CollAtUnchecked (&M->FormalArgs, I));
|
||||
for (I = 0; I < CollCount (&M->Params); ++I) {
|
||||
xfree (CollAtUnchecked (&M->Params, I));
|
||||
}
|
||||
DoneCollection (&M->FormalArgs);
|
||||
DoneCollection (&M->Params);
|
||||
SB_Done (&M->Replacement);
|
||||
xfree (M);
|
||||
}
|
||||
@ -121,12 +119,12 @@ Macro* CloneMacro (const Macro* M)
|
||||
Macro* New = NewMacro (M->Name);
|
||||
unsigned I;
|
||||
|
||||
for (I = 0; I < CollCount (&M->FormalArgs); ++I) {
|
||||
/* Copy the argument */
|
||||
const char* Arg = CollAtUnchecked (&M->FormalArgs, I);
|
||||
CollAppend (&New->FormalArgs, xstrdup (Arg));
|
||||
for (I = 0; I < CollCount (&M->Params); ++I) {
|
||||
/* Copy the parameter */
|
||||
const char* Param = CollAtUnchecked (&M->Params, I);
|
||||
CollAppend (&New->Params, xstrdup (Param));
|
||||
}
|
||||
New->ArgCount = M->ArgCount;
|
||||
New->ParamCount = M->ParamCount;
|
||||
New->Variadic = M->Variadic;
|
||||
SB_Copy (&New->Replacement, &M->Replacement);
|
||||
|
||||
@ -265,14 +263,14 @@ Macro* FindMacro (const char* Name)
|
||||
|
||||
|
||||
|
||||
int FindMacroArg (Macro* M, const char* Arg)
|
||||
/* Search for a formal macro argument. If found, return the index of the
|
||||
** argument. If the argument was not found, return -1.
|
||||
int FindMacroParam (const Macro* M, const char* Param)
|
||||
/* Search for a macro parameter. If found, return the index of the parameter.
|
||||
** If the parameter was not found, return -1.
|
||||
*/
|
||||
{
|
||||
unsigned I;
|
||||
for (I = 0; I < CollCount (&M->FormalArgs); ++I) {
|
||||
if (strcmp (CollAtUnchecked (&M->FormalArgs, I), Arg) == 0) {
|
||||
for (I = 0; I < CollCount (&M->Params); ++I) {
|
||||
if (strcmp (CollAtUnchecked (&M->Params, I), Param) == 0) {
|
||||
/* Found */
|
||||
return I;
|
||||
}
|
||||
@ -284,25 +282,25 @@ int FindMacroArg (Macro* M, const char* Arg)
|
||||
|
||||
|
||||
|
||||
void AddMacroArg (Macro* M, const char* Arg)
|
||||
/* Add a formal macro argument. */
|
||||
void AddMacroParam (Macro* M, const char* Param)
|
||||
/* Add a macro parameter. */
|
||||
{
|
||||
/* Check if we have a duplicate macro argument, but add it anyway.
|
||||
** Beware: Don't use FindMacroArg here, since the actual argument array
|
||||
/* Check if we have a duplicate macro parameter, but add it anyway.
|
||||
** Beware: Don't use FindMacroParam here, since the actual argument array
|
||||
** may not be initialized.
|
||||
*/
|
||||
unsigned I;
|
||||
for (I = 0; I < CollCount (&M->FormalArgs); ++I) {
|
||||
if (strcmp (CollAtUnchecked (&M->FormalArgs, I), Arg) == 0) {
|
||||
for (I = 0; I < CollCount (&M->Params); ++I) {
|
||||
if (strcmp (CollAtUnchecked (&M->Params, I), Param) == 0) {
|
||||
/* Found */
|
||||
PPError ("Duplicate macro parameter: '%s'", Arg);
|
||||
PPError ("Duplicate macro parameter: '%s'", Param);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Add the new argument */
|
||||
CollAppend (&M->FormalArgs, xstrdup (Arg));
|
||||
++M->ArgCount;
|
||||
/* Add the new parameter */
|
||||
CollAppend (&M->Params, xstrdup (Param));
|
||||
++M->ParamCount;
|
||||
}
|
||||
|
||||
|
||||
@ -313,14 +311,14 @@ int MacroCmp (const Macro* M1, const Macro* M2)
|
||||
int I;
|
||||
|
||||
/* Argument count must be identical */
|
||||
if (M1->ArgCount != M2->ArgCount) {
|
||||
if (M1->ParamCount != M2->ParamCount) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Compare the arguments */
|
||||
for (I = 0; I < M1->ArgCount; ++I) {
|
||||
if (strcmp (CollConstAt (&M1->FormalArgs, I),
|
||||
CollConstAt (&M2->FormalArgs, I)) != 0) {
|
||||
/* Compare the parameters */
|
||||
for (I = 0; I < M1->ParamCount; ++I) {
|
||||
if (strcmp (CollConstAt (&M1->Params, I),
|
||||
CollConstAt (&M2->Params, I)) != 0) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
@ -55,10 +55,8 @@
|
||||
typedef struct Macro Macro;
|
||||
struct Macro {
|
||||
Macro* Next; /* Next macro with same hash value */
|
||||
int Expanding; /* Are we currently expanding this macro? */
|
||||
int ArgCount; /* Number of parameters, -1 = no parens */
|
||||
unsigned MaxArgs; /* Size of formal argument list */
|
||||
Collection FormalArgs; /* Formal argument list (char*) */
|
||||
int ParamCount; /* Number of parameters, -1 = no parens */
|
||||
Collection Params; /* Parameter list (char*) */
|
||||
StrBuf Replacement; /* Replacement text */
|
||||
unsigned char Variadic; /* C99 variadic macro */
|
||||
char Name[1]; /* Name, dynamically allocated */
|
||||
@ -120,13 +118,13 @@ INLINE int IsMacro (const char* Name)
|
||||
# define IsMacro(Name) (FindMacro (Name) != 0)
|
||||
#endif
|
||||
|
||||
int FindMacroArg (Macro* M, const char* Arg);
|
||||
/* Search for a formal macro argument. If found, return the index of the
|
||||
** argument. If the argument was not found, return -1.
|
||||
int FindMacroParam (const Macro* M, const char* Param);
|
||||
/* Search for a macro parameter. If found, return the index of the parameter.
|
||||
** If the parameter was not found, return -1.
|
||||
*/
|
||||
|
||||
void AddMacroArg (Macro* M, const char* Arg);
|
||||
/* Add a formal macro argument. */
|
||||
void AddMacroParam (Macro* M, const char* Param);
|
||||
/* Add a macro parameter. */
|
||||
|
||||
int MacroCmp (const Macro* M1, const Macro* M2);
|
||||
/* Compare two macros and return zero if both are identical. */
|
||||
|
@ -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;
|
||||
|
@ -784,7 +784,7 @@ static void IntPragma (StrBuf* B, IntStack* Stack, long Low, long High)
|
||||
|
||||
static void MakeMessage (const char* Message)
|
||||
{
|
||||
fprintf (stderr, "%s:%u: Note: %s\n", GetInputName (CurTok.LI), GetInputLine (CurTok.LI), Message);
|
||||
Note ("%s", Message);
|
||||
}
|
||||
|
||||
|
||||
|
2259
src/cc65/preproc.c
2259
src/cc65/preproc.c
File diff suppressed because it is too large
Load Diff
@ -36,17 +36,7 @@
|
||||
#ifndef PREPROC_H
|
||||
#define PREPROC_H
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Forwards */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
typedef struct Macro Macro;
|
||||
|
||||
|
||||
#include "macrotab.h"
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Data */
|
||||
@ -78,6 +68,9 @@ void Preprocess (void);
|
||||
void SetPPIfStack (PPIfStack* Stack);
|
||||
/* Specify which PP #if stack to use */
|
||||
|
||||
void ContinueLine (void);
|
||||
/* Continue the current line ended with a '\\' */
|
||||
|
||||
void PreprocessBegin (void);
|
||||
/* Initialize preprocessor with current file */
|
||||
|
||||
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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 */
|
||||
|
||||
|
@ -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 */
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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 */
|
||||
|
||||
|
||||
|
@ -567,6 +567,11 @@ static SymEntry* FindSymInTree (const SymTable* Tab, const char* Name)
|
||||
/* Try to find the symbol in this table */
|
||||
SymEntry* E = FindSymInTable (Tab, Name, Hash);
|
||||
|
||||
while (E != 0 && (E->Flags & SC_ALIAS) == SC_ALIAS) {
|
||||
/* Get the aliased entry */
|
||||
E = E->V.A.Field;
|
||||
}
|
||||
|
||||
/* Bail out if we found it */
|
||||
if (E != 0) {
|
||||
return E;
|
||||
@ -620,8 +625,8 @@ SymEntry FindStructField (const Type* T, const char* Name)
|
||||
** value, or an empty entry struct if the field is not found.
|
||||
*/
|
||||
{
|
||||
SymEntry* Entry = 0;
|
||||
SymEntry Field;
|
||||
SymEntry* Field = 0;
|
||||
SymEntry Res;
|
||||
int Offs = 0;
|
||||
|
||||
/* The given type may actually be a pointer to struct/union */
|
||||
@ -632,35 +637,35 @@ SymEntry FindStructField (const Type* T, const char* Name)
|
||||
/* Only structs/unions have struct/union fields... */
|
||||
if (IsClassStruct (T)) {
|
||||
|
||||
/* Get a pointer to the struct/union type */
|
||||
const SymEntry* Struct = GetESUSymEntry (T);
|
||||
CHECK (Struct != 0);
|
||||
/* Get a pointer to the struct/union tag */
|
||||
const SymEntry* TagSym = GetESUTagSym (T);
|
||||
CHECK (TagSym != 0);
|
||||
|
||||
/* Now search in the struct/union symbol table. Beware: The table may
|
||||
** not exist.
|
||||
*/
|
||||
if (Struct->V.S.SymTab) {
|
||||
Entry = FindSymInTable (Struct->V.S.SymTab, Name, HashStr (Name));
|
||||
if (TagSym->V.S.SymTab) {
|
||||
Field = FindSymInTable (TagSym->V.S.SymTab, Name, HashStr (Name));
|
||||
|
||||
if (Entry != 0) {
|
||||
Offs = Entry->V.Offs;
|
||||
if (Field != 0) {
|
||||
Offs = Field->V.Offs;
|
||||
}
|
||||
|
||||
while (Entry != 0 && (Entry->Flags & SC_ALIAS) == SC_ALIAS) {
|
||||
while (Field != 0 && (Field->Flags & SC_ALIAS) == SC_ALIAS) {
|
||||
/* Get the real field */
|
||||
Entry = Entry->V.A.Field;
|
||||
Field = Field->V.A.Field;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (Entry != 0) {
|
||||
Field = *Entry;
|
||||
Field.V.Offs = Offs;
|
||||
if (Field != 0) {
|
||||
Res = *Field;
|
||||
Res.V.Offs = Offs;
|
||||
} else {
|
||||
memset (&Field, 0, sizeof(SymEntry));
|
||||
memset (&Res, 0, sizeof(SymEntry));
|
||||
}
|
||||
|
||||
return Field;
|
||||
return Res;
|
||||
}
|
||||
|
||||
|
||||
@ -684,15 +689,15 @@ static int IsDistinctRedef (const Type* lhst, const Type* rhst, typecmpcode_t Co
|
||||
}
|
||||
|
||||
|
||||
static int HandleSymRedefinition (SymEntry* Entry, const Type* T, unsigned Flags)
|
||||
static int HandleSymRedefinition (SymEntry* Sym, const Type* T, unsigned Flags)
|
||||
/* Check and handle redefinition of existing symbols.
|
||||
** Complete array sizes and function descriptors as well.
|
||||
** Return true if there *is* an error.
|
||||
*/
|
||||
{
|
||||
/* Get the type info of the existing symbol */
|
||||
Type* E_Type = Entry->Type;
|
||||
unsigned E_SCType = Entry->Flags & SC_TYPEMASK;
|
||||
Type* E_Type = Sym->Type;
|
||||
unsigned E_SCType = Sym->Flags & SC_TYPEMASK;
|
||||
unsigned SCType = Flags & SC_TYPEMASK;
|
||||
|
||||
/* Some symbols may be redeclared if certain requirements are met */
|
||||
@ -701,15 +706,16 @@ static int HandleSymRedefinition (SymEntry* Entry, const Type* T, unsigned Flags
|
||||
/* Existing typedefs cannot be redeclared as anything different */
|
||||
if (SCType == SC_TYPEDEF) {
|
||||
if (IsDistinctRedef (E_Type, T, TC_IDENTICAL, TCF_MASK_QUAL)) {
|
||||
Error ("Conflicting types for typedef '%s'", Entry->Name);
|
||||
Entry = 0;
|
||||
Error ("Conflicting types for typedef '%s'", Sym->Name);
|
||||
Note ("'%s' vs '%s'", GetFullTypeName (T), GetFullTypeName (E_Type));
|
||||
Sym = 0;
|
||||
}
|
||||
} else {
|
||||
Error ("Redefinition of typedef '%s' as different kind of symbol", Entry->Name);
|
||||
Entry = 0;
|
||||
Error ("Redefinition of typedef '%s' as different kind of symbol", Sym->Name);
|
||||
Sym = 0;
|
||||
}
|
||||
|
||||
} else if ((Entry->Flags & SC_FUNC) == SC_FUNC) {
|
||||
} else if ((Sym->Flags & SC_FUNC) == SC_FUNC) {
|
||||
|
||||
/* In case of a function, use the new type descriptor, since it
|
||||
** contains pointers to the new symbol tables that are needed if
|
||||
@ -720,27 +726,27 @@ static int HandleSymRedefinition (SymEntry* Entry, const Type* T, unsigned Flags
|
||||
if (IsTypeFunc (T)) {
|
||||
|
||||
/* Check for duplicate function definitions */
|
||||
if (SymIsDef (Entry) && (Flags & SC_DEF) == SC_DEF) {
|
||||
if (SymIsDef (Sym) && (Flags & SC_DEF) == SC_DEF) {
|
||||
Error ("Body for function '%s' has already been defined",
|
||||
Entry->Name);
|
||||
Entry = 0;
|
||||
Sym->Name);
|
||||
Sym = 0;
|
||||
} else {
|
||||
/* New type must be compatible with the composite prototype */
|
||||
if (IsDistinctRedef (E_Type, T, TC_EQUAL, TCF_MASK_QUAL)) {
|
||||
Error ("Conflicting function types for '%s'", Entry->Name);
|
||||
TypeCompatibilityDiagnostic (T, E_Type, 0, "'%s' vs '%s'");
|
||||
Entry = 0;
|
||||
Error ("Conflicting function types for '%s'", Sym->Name);
|
||||
Note ("'%s' vs '%s'", GetFullTypeName (T), GetFullTypeName (E_Type));
|
||||
Sym = 0;
|
||||
} else {
|
||||
/* Refine the existing composite prototype with this new
|
||||
** one.
|
||||
*/
|
||||
RefineFuncDesc (Entry->Type, T);
|
||||
RefineFuncDesc (Sym->Type, T);
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
Error ("Redefinition of function '%s' as different kind of symbol", Entry->Name);
|
||||
Entry = 0;
|
||||
Error ("Redefinition of function '%s' as different kind of symbol", Sym->Name);
|
||||
Sym = 0;
|
||||
}
|
||||
|
||||
} else {
|
||||
@ -759,8 +765,9 @@ static int HandleSymRedefinition (SymEntry* Entry, const Type* T, unsigned Flags
|
||||
if ((Size != UNSPECIFIED && ESize != UNSPECIFIED && Size != ESize) ||
|
||||
IsDistinctRedef (E_Type + 1, T + 1, TC_IDENTICAL, TCF_MASK_QUAL)) {
|
||||
/* Conflicting element types */
|
||||
Error ("Conflicting array types for '%s[]'", Entry->Name);
|
||||
Entry = 0;
|
||||
Error ("Conflicting array types for '%s[]'", Sym->Name);
|
||||
Note ("'%s' vs '%s'", GetFullTypeName (T), GetFullTypeName (E_Type));
|
||||
Sym = 0;
|
||||
} else {
|
||||
/* Check if we have a size in the existing definition */
|
||||
if (ESize == UNSPECIFIED) {
|
||||
@ -773,24 +780,25 @@ static int HandleSymRedefinition (SymEntry* Entry, const Type* T, unsigned Flags
|
||||
|
||||
/* New type must be equivalent */
|
||||
if (SCType != E_SCType) {
|
||||
Error ("Redefinition of '%s' as different kind of symbol", Entry->Name);
|
||||
Entry = 0;
|
||||
Error ("Redefinition of '%s' as different kind of symbol", Sym->Name);
|
||||
Sym = 0;
|
||||
} else if (IsDistinctRedef (E_Type, T, TC_EQUAL, TCF_MASK_QUAL)) {
|
||||
Error ("Conflicting types for '%s'", Entry->Name);
|
||||
Entry = 0;
|
||||
Error ("Conflicting types for '%s'", Sym->Name);
|
||||
Note ("'%s' vs '%s'", GetFullTypeName (T), GetFullTypeName (E_Type));
|
||||
Sym = 0;
|
||||
} else if (E_SCType == SC_ENUMERATOR) {
|
||||
/* Enumerators aren't allowed to be redeclared at all, even if
|
||||
** all occurences are identical. The current code logic won't
|
||||
** get here, but let's just do it.
|
||||
*/
|
||||
Error ("Redeclaration of enumerator constant '%s'", Entry->Name);
|
||||
Entry = 0;
|
||||
Error ("Redeclaration of enumerator constant '%s'", Sym->Name);
|
||||
Sym = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Return if there are any errors */
|
||||
return Entry == 0;
|
||||
return Sym == 0;
|
||||
}
|
||||
|
||||
|
||||
@ -824,38 +832,38 @@ static void AddSymEntry (SymTable* T, SymEntry* S)
|
||||
|
||||
|
||||
SymEntry* AddEnumSym (const char* Name, unsigned Flags, const Type* Type, SymTable* Tab, unsigned* DSFlags)
|
||||
/* Add an enum entry and return it */
|
||||
/* Add an enum tag entry and return it */
|
||||
{
|
||||
SymTable* CurTagTab = TagTab;
|
||||
SymEntry* Entry;
|
||||
SymEntry* TagEntry;
|
||||
|
||||
if ((Flags & SC_FICTITIOUS) == 0) {
|
||||
/* Do we have an entry with this name already? */
|
||||
Entry = FindSymInTable (CurTagTab, Name, HashStr (Name));
|
||||
TagEntry = FindSymInTable (CurTagTab, Name, HashStr (Name));
|
||||
} else {
|
||||
/* Add a fictitious symbol in the fail-safe table */
|
||||
Entry = 0;
|
||||
TagEntry = 0;
|
||||
CurTagTab = FailSafeTab;
|
||||
}
|
||||
|
||||
if (Entry) {
|
||||
if (TagEntry) {
|
||||
|
||||
/* We do have an entry. This may be a forward, so check it. */
|
||||
if ((Entry->Flags & SC_TYPEMASK) != SC_ENUM) {
|
||||
if ((TagEntry->Flags & SC_TYPEMASK) != SC_ENUM) {
|
||||
/* Existing symbol is not an enum */
|
||||
Error ("Symbol '%s' is already different kind", Name);
|
||||
Entry = 0;
|
||||
TagEntry = 0;
|
||||
} else if (Type != 0) {
|
||||
/* Define the struct size if the underlying type is given. */
|
||||
if (Entry->V.E.Type != 0) {
|
||||
if (TagEntry->V.E.Type != 0) {
|
||||
/* Both are definitions. */
|
||||
Error ("Multiple definition for 'enum %s'", Name);
|
||||
Entry = 0;
|
||||
TagEntry = 0;
|
||||
} else {
|
||||
Entry->V.E.SymTab = Tab;
|
||||
Entry->V.E.Type = Type;
|
||||
Entry->Flags &= ~SC_DECL;
|
||||
Entry->Flags |= SC_DEF;
|
||||
TagEntry->V.E.SymTab = Tab;
|
||||
TagEntry->V.E.Type = Type;
|
||||
TagEntry->Flags &= ~SC_DECL;
|
||||
TagEntry->Flags |= SC_DEF;
|
||||
|
||||
/* Remember this is the first definition of this type */
|
||||
if (DSFlags != 0) {
|
||||
@ -864,83 +872,83 @@ SymEntry* AddEnumSym (const char* Name, unsigned Flags, const Type* Type, SymTab
|
||||
}
|
||||
}
|
||||
|
||||
if (Entry == 0) {
|
||||
if (TagEntry == 0) {
|
||||
/* Use the fail-safe table for fictitious symbols */
|
||||
CurTagTab = FailSafeTab;
|
||||
}
|
||||
}
|
||||
|
||||
if (Entry == 0) {
|
||||
if (TagEntry == 0) {
|
||||
|
||||
/* Create a new entry */
|
||||
Entry = NewSymEntry (Name, SC_ENUM);
|
||||
TagEntry = NewSymEntry (Name, SC_ENUM);
|
||||
|
||||
/* Set the enum type data */
|
||||
Entry->V.E.SymTab = Tab;
|
||||
Entry->V.E.Type = Type;
|
||||
TagEntry->V.E.SymTab = Tab;
|
||||
TagEntry->V.E.Type = Type;
|
||||
|
||||
if (Type != 0) {
|
||||
Entry->Flags |= SC_DEF;
|
||||
TagEntry->Flags |= SC_DEF;
|
||||
}
|
||||
|
||||
/* Remember this is the first definition of this type */
|
||||
if (CurTagTab != FailSafeTab && DSFlags != 0) {
|
||||
if ((Entry->Flags & SC_DEF) != 0) {
|
||||
if ((TagEntry->Flags & SC_DEF) != 0) {
|
||||
*DSFlags |= DS_NEW_TYPE_DEF;
|
||||
}
|
||||
*DSFlags |= DS_NEW_TYPE_DECL;
|
||||
}
|
||||
|
||||
/* Add it to the current table */
|
||||
AddSymEntry (CurTagTab, Entry);
|
||||
AddSymEntry (CurTagTab, TagEntry);
|
||||
}
|
||||
|
||||
/* Return the entry */
|
||||
return Entry;
|
||||
return TagEntry;
|
||||
}
|
||||
|
||||
|
||||
|
||||
SymEntry* AddStructSym (const char* Name, unsigned Flags, unsigned Size, SymTable* Tab, unsigned* DSFlags)
|
||||
/* Add a struct/union entry and return it */
|
||||
/* Add a struct/union tag entry and return it */
|
||||
{
|
||||
SymTable* CurTagTab = TagTab;
|
||||
SymEntry* Entry;
|
||||
unsigned Type = (Flags & SC_TYPEMASK);
|
||||
SymEntry* TagEntry;
|
||||
unsigned SCType = (Flags & SC_TYPEMASK);
|
||||
|
||||
/* Type must be struct or union */
|
||||
PRECONDITION (Type == SC_STRUCT || Type == SC_UNION);
|
||||
/* SCType must be struct or union */
|
||||
PRECONDITION (SCType == SC_STRUCT || SCType == SC_UNION);
|
||||
|
||||
if ((Flags & SC_FICTITIOUS) == 0) {
|
||||
/* Do we have an entry with this name already? */
|
||||
Entry = FindSymInTable (CurTagTab, Name, HashStr (Name));
|
||||
TagEntry = FindSymInTable (CurTagTab, Name, HashStr (Name));
|
||||
} else {
|
||||
/* Add a fictitious symbol in the fail-safe table */
|
||||
Entry = 0;
|
||||
TagEntry = 0;
|
||||
CurTagTab = FailSafeTab;
|
||||
}
|
||||
|
||||
if (Entry) {
|
||||
if (TagEntry) {
|
||||
|
||||
/* We do have an entry. This may be a forward, so check it. */
|
||||
if ((Entry->Flags & SC_TYPEMASK) != Type) {
|
||||
if ((TagEntry->Flags & SC_TYPEMASK) != SCType) {
|
||||
/* Existing symbol is not a struct */
|
||||
Error ("Symbol '%s' is already different kind", Name);
|
||||
Entry = 0;
|
||||
} else if ((Entry->Flags & Flags & SC_DEF) == SC_DEF) {
|
||||
TagEntry = 0;
|
||||
} else if ((TagEntry->Flags & Flags & SC_DEF) == SC_DEF) {
|
||||
/* Both structs are definitions. */
|
||||
if (Type == SC_STRUCT) {
|
||||
if (SCType == SC_STRUCT) {
|
||||
Error ("Multiple definition for 'struct %s'", Name);
|
||||
} else {
|
||||
Error ("Multiple definition for 'union %s'", Name);
|
||||
}
|
||||
Entry = 0;
|
||||
TagEntry = 0;
|
||||
} else {
|
||||
/* Define the struct size if it is a definition */
|
||||
if ((Flags & SC_DEF) == SC_DEF) {
|
||||
Entry->Flags = Flags;
|
||||
Entry->V.S.SymTab = Tab;
|
||||
Entry->V.S.Size = Size;
|
||||
TagEntry->Flags = Flags;
|
||||
TagEntry->V.S.SymTab = Tab;
|
||||
TagEntry->V.S.Size = Size;
|
||||
|
||||
/* Remember this is the first definition of this type */
|
||||
if (DSFlags != 0) {
|
||||
@ -949,35 +957,35 @@ SymEntry* AddStructSym (const char* Name, unsigned Flags, unsigned Size, SymTabl
|
||||
}
|
||||
}
|
||||
|
||||
if (Entry == 0) {
|
||||
if (TagEntry == 0) {
|
||||
/* Use the fail-safe table for fictitious symbols */
|
||||
CurTagTab = FailSafeTab;
|
||||
}
|
||||
}
|
||||
|
||||
if (Entry == 0) {
|
||||
if (TagEntry == 0) {
|
||||
|
||||
/* Create a new entry */
|
||||
Entry = NewSymEntry (Name, Flags);
|
||||
TagEntry = NewSymEntry (Name, Flags);
|
||||
|
||||
/* Set the struct data */
|
||||
Entry->V.S.SymTab = Tab;
|
||||
Entry->V.S.Size = Size;
|
||||
TagEntry->V.S.SymTab = Tab;
|
||||
TagEntry->V.S.Size = Size;
|
||||
|
||||
/* Remember this is the first definition of this type */
|
||||
if (CurTagTab != FailSafeTab && DSFlags != 0) {
|
||||
if ((Entry->Flags & SC_DEF) != 0) {
|
||||
if ((TagEntry->Flags & SC_DEF) != 0) {
|
||||
*DSFlags |= DS_NEW_TYPE_DEF;
|
||||
}
|
||||
*DSFlags |= DS_NEW_TYPE_DECL;
|
||||
}
|
||||
|
||||
/* Add it to the current tag table */
|
||||
AddSymEntry (CurTagTab, Entry);
|
||||
AddSymEntry (CurTagTab, TagEntry);
|
||||
}
|
||||
|
||||
/* Return the entry */
|
||||
return Entry;
|
||||
return TagEntry;
|
||||
}
|
||||
|
||||
|
||||
@ -1068,7 +1076,7 @@ DefOrRef* AddDefOrRef (SymEntry* E, unsigned Flags)
|
||||
|
||||
DOR = xmalloc (sizeof (DefOrRef));
|
||||
CollAppend (E->V.L.DefsOrRefs, DOR);
|
||||
DOR->Line = GetCurrentLine ();
|
||||
DOR->Line = GetCurrentLineNum ();
|
||||
DOR->LocalsBlockId = (size_t)CollLast (&CurrentFunc->LocalsBlockStack);
|
||||
DOR->Flags = Flags;
|
||||
DOR->StackPtr = StackPtr;
|
||||
@ -1136,7 +1144,7 @@ SymEntry* AddLabelSym (const char* Name, unsigned Flags)
|
||||
(size_t)CollAt (AIC, DOR->Depth - 1) != DOR->LocalsBlockId)) {
|
||||
Warning ("Goto at line %d to label %s jumps into a block with "
|
||||
"initialization of an object that has automatic storage duration",
|
||||
GetCurrentLine (), Name);
|
||||
GetCurrentLineNum (), Name);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1279,6 +1287,11 @@ SymEntry* AddLocalSym (const char* Name, const Type* T, unsigned Flags, int Offs
|
||||
/* Generate the assembler name from the data label number */
|
||||
Entry->V.L.Label = Offs;
|
||||
Entry->AsmName = xstrdup (LocalDataLabelName (Entry->V.L.Label));
|
||||
} else if ((Flags & SC_ALIAS) == SC_ALIAS) {
|
||||
/* Just clear the info */
|
||||
Entry->V.A.Field = 0;
|
||||
Entry->V.A.ANumber = 0;
|
||||
Entry->V.A.Offs = 0;
|
||||
} else {
|
||||
Internal ("Invalid flags in AddLocalSym: %04X", Flags);
|
||||
}
|
||||
@ -1296,13 +1309,26 @@ SymEntry* AddLocalSym (const char* Name, const Type* T, unsigned Flags, int Offs
|
||||
SymEntry* AddGlobalSym (const char* Name, const Type* T, unsigned Flags)
|
||||
/* Add an external or global symbol to the symbol table and return the entry */
|
||||
{
|
||||
/* Start from the local symbol table */
|
||||
SymTable* Tab = SymTab;
|
||||
/* Add the new declaration to the global symbol table if no errors */
|
||||
SymTable* Tab = SymTab0;
|
||||
|
||||
/* Only search this name in the local and global symbol tables */
|
||||
SymEntry* Entry = 0;
|
||||
SymEntry* Alias = 0;
|
||||
|
||||
if (SymTab != SymTab0) {
|
||||
Alias = Entry = FindLocalSym (Name);
|
||||
while (Entry && (Entry->Flags & SC_ALIAS) == SC_ALIAS) {
|
||||
/* Get the aliased entry */
|
||||
Entry = Entry->V.A.Field;
|
||||
}
|
||||
}
|
||||
|
||||
if (Entry == 0) {
|
||||
Entry = FindGlobalSym (Name);
|
||||
}
|
||||
|
||||
/* Do we have an entry with this name already? */
|
||||
SymEntry* Entry = FindSymInTree (Tab, Name);
|
||||
if (Entry) {
|
||||
|
||||
/* We have a symbol with this name already */
|
||||
if (HandleSymRedefinition (Entry, T, Flags)) {
|
||||
Entry = 0;
|
||||
@ -1317,7 +1343,7 @@ SymEntry* AddGlobalSym (const char* Name, const Type* T, unsigned Flags)
|
||||
** declaration if both declarations are global, otherwise give an
|
||||
** error.
|
||||
*/
|
||||
if (Tab == SymTab0 &&
|
||||
if (SymTab == SymTab0 &&
|
||||
(Flags & SC_EXTERN) == 0 &&
|
||||
(Entry->Flags & SC_EXTERN) != 0) {
|
||||
Warning ("Static declaration of '%s' follows non-static declaration", Name);
|
||||
@ -1353,12 +1379,9 @@ SymEntry* AddGlobalSym (const char* Name, const Type* T, unsigned Flags)
|
||||
/* Use the fail-safe table for fictitious symbols */
|
||||
Tab = FailSafeTab;
|
||||
}
|
||||
|
||||
} else if ((Flags & (SC_EXTERN | SC_FUNC)) != 0) {
|
||||
/* Add the new declaration to the global symbol table instead */
|
||||
Tab = SymTab0;
|
||||
}
|
||||
if (Entry == 0 || Entry->Owner != Tab) {
|
||||
|
||||
if (Entry == 0) {
|
||||
|
||||
/* Create a new entry */
|
||||
Entry = NewSymEntry (Name, Flags);
|
||||
@ -1376,6 +1399,13 @@ SymEntry* AddGlobalSym (const char* Name, const Type* T, unsigned Flags)
|
||||
|
||||
/* Add the entry to the symbol table */
|
||||
AddSymEntry (Tab, Entry);
|
||||
|
||||
}
|
||||
|
||||
/* Add an alias of the global symbol to the local symbol table */
|
||||
if (Tab == SymTab0 && SymTab != SymTab0 && Entry->Owner != SymTab && Alias == 0) {
|
||||
Alias = AddLocalSym (Name, T, SC_ALIAS, 0);
|
||||
Alias->V.A.Field = Entry;
|
||||
}
|
||||
|
||||
/* Return the entry */
|
||||
|
@ -169,10 +169,10 @@ unsigned short FindSPAdjustment (const char* Name);
|
||||
|
||||
|
||||
SymEntry* AddEnumSym (const char* Name, unsigned Flags, const Type* Type, SymTable* Tab, unsigned* DSFlags);
|
||||
/* Add an enum entry and return it */
|
||||
/* Add an enum tag entry and return it */
|
||||
|
||||
SymEntry* AddStructSym (const char* Name, unsigned Flags, unsigned Size, SymTable* Tab, unsigned* DSFlags);
|
||||
/* Add a struct/union entry and return it */
|
||||
/* Add a struct/union tag entry and return it */
|
||||
|
||||
SymEntry* AddBitField (const char* Name, const Type* Type, unsigned Offs,
|
||||
unsigned BitOffs, unsigned BitWidth, int SignednessSpecified);
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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
|
||||
|
@ -592,9 +592,19 @@ static void RangeSection (void)
|
||||
case INFOTOK_END:
|
||||
AddAttr ("END", &Attributes, tEnd);
|
||||
InfoNextTok ();
|
||||
InfoAssureInt ();
|
||||
InfoRangeCheck (0x0000, 0xFFFF);
|
||||
End = InfoIVal;
|
||||
|
||||
if (InfoTok == INFOTOK_OFFSET_INTCON) {
|
||||
InfoRangeCheck (0x0000, 0xFFFF);
|
||||
if (!(Attributes & tStart))
|
||||
InfoError ("When using End with an offset, Start must be specified before");
|
||||
End = Start + InfoIVal - 1;
|
||||
if (End > 0xFFFF)
|
||||
InfoError ("Range error");
|
||||
} else {
|
||||
InfoAssureInt ();
|
||||
InfoRangeCheck (0x0000, 0xFFFF);
|
||||
End = InfoIVal;
|
||||
}
|
||||
InfoNextTok ();
|
||||
break;
|
||||
|
||||
|
@ -372,6 +372,14 @@ Again:
|
||||
return;
|
||||
}
|
||||
|
||||
/* Decimal number offset? */
|
||||
if (C == '+') {
|
||||
NextChar ();
|
||||
InfoIVal = GetDecimalToken ();
|
||||
InfoTok = INFOTOK_OFFSET_INTCON;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Other characters */
|
||||
switch (C) {
|
||||
|
||||
|
@ -48,6 +48,7 @@
|
||||
typedef enum token_t {
|
||||
INFOTOK_NONE,
|
||||
INFOTOK_INTCON,
|
||||
INFOTOK_OFFSET_INTCON,
|
||||
INFOTOK_STRCON,
|
||||
INFOTOK_CHARCON,
|
||||
INFOTOK_IDENT,
|
||||
|
@ -46,7 +46,7 @@
|
||||
|
||||
|
||||
/* THE memory */
|
||||
static unsigned char Mem[0x10000];
|
||||
unsigned char Mem[0x10000];
|
||||
|
||||
|
||||
|
||||
@ -73,14 +73,6 @@ void MemWriteWord (unsigned Addr, unsigned Val)
|
||||
|
||||
|
||||
|
||||
unsigned char MemReadByte (unsigned Addr)
|
||||
/* Read a byte from a memory location */
|
||||
{
|
||||
return Mem[Addr];
|
||||
}
|
||||
|
||||
|
||||
|
||||
unsigned MemReadWord (unsigned Addr)
|
||||
/* Read a word from a memory location */
|
||||
{
|
||||
|
@ -36,7 +36,9 @@
|
||||
#ifndef MEMORY_H
|
||||
#define MEMORY_H
|
||||
|
||||
#include "inline.h"
|
||||
|
||||
extern unsigned char Mem[0x10000];
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Code */
|
||||
@ -50,8 +52,15 @@ void MemWriteByte (unsigned Addr, unsigned char Val);
|
||||
void MemWriteWord (unsigned Addr, unsigned Val);
|
||||
/* Write a word to a memory location */
|
||||
|
||||
unsigned char MemReadByte (unsigned Addr);
|
||||
#if defined(HAVE_INLINE)
|
||||
INLINE unsigned char MemReadByte (unsigned Addr)
|
||||
/* Read a byte from a memory location */
|
||||
{
|
||||
return Mem[Addr];
|
||||
}
|
||||
#else
|
||||
#define MemReadByte(Addr) Mem[Addr]
|
||||
#endif
|
||||
|
||||
unsigned MemReadWord (unsigned Addr);
|
||||
/* Read a word from a memory location */
|
||||
|
@ -761,6 +761,7 @@ TARGETS := \
|
||||
|
||||
define TARGET_recipe
|
||||
|
||||
@echo making targettest for: $(T)
|
||||
@$(MAKE) -j2 SYS:=$(T)
|
||||
@$(MAKE) --no-print-directory clean SYS:=$(T)
|
||||
|
||||
|
@ -73,4 +73,7 @@ endif
|
||||
dd if=$< bs=8K count=${COUNT} >> $@
|
||||
|
||||
clean:
|
||||
@$(DEL) conio.o conio.??? 2>$(NULLDEV)
|
||||
@$(DEL) conio.o 2>$(NULLDEV)
|
||||
@$(DEL) conio.pce 2>$(NULLDEV)
|
||||
@$(DEL) conio.bin 2>$(NULLDEV)
|
||||
@$(DEL) conio.map 2>$(NULLDEV)
|
||||
|
@ -5,25 +5,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
|
||||
|
@ -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
|
||||
|
9
test/asm/listing/ref/010-paramcount.err2-ref
Normal file
9
test/asm/listing/ref/010-paramcount.err2-ref
Normal 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
9
test/err/bug1890.c
Normal file
@ -0,0 +1,9 @@
|
||||
/* bug #1890 - Overflow in enumerator value is not detected */
|
||||
|
||||
#include <limits.h>
|
||||
enum { a = ULONG_MAX, b } c = b;
|
||||
|
||||
int main(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
8
test/err/bug1893.c
Normal file
8
test/err/bug1893.c
Normal file
@ -0,0 +1,8 @@
|
||||
/* bug #1893 - Compiler accepts a ternary expression where it shouldn't */
|
||||
|
||||
int main(void)
|
||||
{
|
||||
int a, b, c;
|
||||
a == 1? b : c = 3;
|
||||
return 0;
|
||||
}
|
5
test/err/bug1895-assign1a.c
Normal file
5
test/err/bug1895-assign1a.c
Normal 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"
|
5
test/err/bug1895-assign1b.c
Normal file
5
test/err/bug1895-assign1b.c
Normal 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"
|
5
test/err/bug1895-assign2a.c
Normal file
5
test/err/bug1895-assign2a.c
Normal 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"
|
5
test/err/bug1895-assign2b.c
Normal file
5
test/err/bug1895-assign2b.c
Normal 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"
|
5
test/err/bug1895-assign4a.c
Normal file
5
test/err/bug1895-assign4a.c
Normal 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"
|
5
test/err/bug1895-assign4b.c
Normal file
5
test/err/bug1895-assign4b.c
Normal 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"
|
5
test/err/bug1895-assign5a.c
Normal file
5
test/err/bug1895-assign5a.c
Normal 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"
|
5
test/err/bug1895-assign5b.c
Normal file
5
test/err/bug1895-assign5b.c
Normal 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
196
test/err/bug1895-common.h
Normal 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
5
test/err/bug1895-cond1.c
Normal 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
5
test/err/bug1895-cond2.c
Normal 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
5
test/err/bug1895-cond3.c
Normal 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
5
test/err/bug1895-cond4.c
Normal 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
5
test/err/bug1895-cond5.c
Normal 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
Loading…
x
Reference in New Issue
Block a user