Added regression tests that check cc65's handling of void variables.
<title>cc65 Users Guide
<author><url url="mailto:uz@cc65.org" name="Ullrich von Bassewitz">,<newline>
<url url="mailto:gregdk@users.sf.net" name="Greg King">
-<date>2016-06-11
+<date>2017-02-27
<abstract>
cc65 is a C compiler for 6502 targets. It supports several 6502 based home
string.
<p>
-<item> cc65 allows the initialization of <tt/void/ variables. This may be
- used to create variable structures that are more compatible with
- interfaces written for assembler languages. Here is an example:
+<item> cc65 allows the initialization of <tt/void/ variables. This may be
+ used to create arbitrary structures that are more compatible with
+ interfaces written for assembler languages. Here is an example:
- <tscreen><verb>
- void GCmd = { (char)3, (unsigned)0x2000, (unsigned)0x3000 };
- </verb></tscreen>
+ <tscreen><verb>
+ void GCmd = { (char)3, (unsigned)0x2000, (unsigned)0x3000 };
+ </verb></tscreen>
- This will be translated as follows:
+ That will be translated as follows:
- <tscreen><verb>
- _GCmd:
- .byte 3
- .word $2000
- .word $3000
- </verb></tscreen>
+ <tscreen><verb>
+ _GCmd:
+ .byte 3
+ .word $2000
+ .word $3000
+ </verb></tscreen>
- Since the variable is of type <tt/void/ you may not use it as is.
- However, taking the address of the variable results in a <tt/void*/
- which may be passed to any function expecting a pointer.
+ Since the variable is of type <tt/void/, you may not use it as-is.
+ However, taking the address of the variable results in a <tt/void*/
+ which may be passed to any function expecting a pointer. Also, the
+ <tt/sizeof/ operator will give the length of the initializer:
- See the <url url="geos.html" name="GEOS library document"> for examples
- on how to use this feature.
- <p>
+ <tscreen><verb>
+ GLen = sizeof GCmd;
+ </verb></tscreen>
+
+ will assign the value 5 to <tt/GLen/.
+
+ See the <url url="geos.html" name="GEOS library document"> for examples
+ on how to use that feature.
+ <p>
<item> cc65 implements flexible array struct members as defined in the C99 ISO
standard. As an extension, these fields may be initialized. There are
switch (UnqualifiedType (T->C)) {
case T_VOID:
- return 0; /* Assume voids have size zero */
+ /* A void variable is a cc65 extension.
+ ** Get its size (in bytes).
+ */
+ return T->A.U;
/* Beware: There's a chance that this triggers problems in other parts
of the compiler. The solution is to fix the callers, because calling
/* Array with unspecified size */
return 0;
} else {
- return T->A.L * SizeOf (T + 1);
+ return T->A.U * SizeOf (T + 1);
}
default:
case TOK_VOID:
NextToken ();
D->Type[0].C = T_VOID;
+ D->Type[0].A.U = 0;
D->Type[1].C = T_END;
break;
-static unsigned ParseVoidInit (void)
+static unsigned ParseVoidInit (Type* T)
/* Parse an initialization of a void variable (special cc65 extension).
** Return the number of bytes initialized.
*/
/* Closing brace */
ConsumeRCurly ();
+ /* Number of bytes determined by initializer */
+ T->A.U = Size;
+
/* Return the number of bytes initialized */
return Size;
}
case T_VOID:
if (IS_Get (&Standard) == STD_CC65) {
- /* Special cc65 extension in non ANSI mode */
- return ParseVoidInit ();
+ /* Special cc65 extension in non-ANSI mode */
+ return ParseVoidInit (T);
}
/* FALLTHROUGH */
--- /dev/null
+/*
+ !!DESCRIPTION!! Uninitialized void variables
+ !!ORIGIN!! cc65 regression tests
+ !!LICENCE!! Public Domain
+ !!AUTHOR!! Greg King
+*/
+
+void test;
+const void list;
--- /dev/null
+/*
+ !!DESCRIPTION!! Size of void cast
+ !!ORIGIN!! cc65 regression tests
+ !!LICENCE!! Public Domain
+ !!AUTHOR!! Greg King
+*/
+
+unsigned test (void)
+{
+ return sizeof ((void)12345);
+}
--- /dev/null
+/*
+ !!DESCRIPTION!! Getting the size of a void-type variable (cc65 extension)
+ !!ORIGIN!! cc65 regression tests
+ !!LICENCE!! Public Domain
+ !!AUTHOR!! Greg King
+*/
+
+static const void list1 = {
+ (char)1,
+ (char)2,
+ (char)3,
+ (char)4,
+ (char)5,
+ (char)6,
+ (char)7,
+ (char)8,
+ (char)9,
+ (char)0
+};
+
+static void list2 = {
+ 1,
+ 2,
+ 3,
+ 4,
+ 5,
+ 6,
+ 7,
+ 8,
+ 9,
+ 0
+};
+
+void list3 = {
+ (char)1,
+ (char)2,
+ (char)3,
+ (char)4,
+ &list1,
+ (char)6,
+ (char)7,
+ (char)8,
+ (char)9,
+ &list2
+};
+
+/* We know that the expression is constant; don't tell us. */
+
+#pragma warn (const-comparison, off)
+
+int main (void)
+{
+ return sizeof list1 != 10
+ || sizeof list2 != 20
+ || sizeof list3 != 12;
+}
/*
-** testprogram for ANTIC instructions as defined in "_antic.h"
+** test program for ANTIC instructions as defined in "_antic.h"
**
** 23-Feb-2017, Christian Krueger
*/
#include <conio.h>
#include <atari.h>
-#include <peekpoke.h>
-#include <string.h>
-// code is only for testing purposes, as screen and display list are not aligned
+// code is only for testing purposes, as screen and display list are not aligned,
// and jumps not set!
unsigned char DummyScreen[400];
void DisplayList = {
- DL_BLK1,
- DL_BLK2,
- DL_BLK3,
- DL_BLK4,
- DL_BLK5,
- DL_BLK6,
- DL_BLK7,
- DL_DLI(DL_BLK8),
- DL_LMS(DL_CHR40x8x1),
- DummyScreen,
- DL_HSCROL(DL_CHR40x10x1),
- DL_VSCROL(DL_CHR40x8x4),
- DL_CHR40x16x4,
- DL_LMS(DL_HSCROL(DL_VSCROL(DL_DLI(DL_CHR20x8x2)))),
- DummyScreen+120,
- DL_CHR20x16x2,
- DL_MAP40x8x4,
- DL_MAP80x4x2,
- DL_MAP80x4x4,
- DL_MAP160x2x2,
- DL_MAP160x1x2,
- DL_MAP160x2x4,
- DL_MAP160x1x4,
- DL_MAP320x1x1,
- DL_JVB,
- DL_JMP
+ DL_BLK1,
+ DL_BLK2,
+ DL_BLK3,
+ DL_BLK4,
+ DL_BLK5,
+ DL_BLK6,
+ DL_BLK7,
+ DL_DLI(DL_BLK8),
+ DL_LMS(DL_CHR40x8x1),
+ DummyScreen,
+ DL_HSCROL(DL_CHR40x10x1),
+ DL_VSCROL(DL_CHR40x8x4),
+ DL_CHR40x16x4,
+ DL_LMS(DL_HSCROL(DL_VSCROL(DL_DLI(DL_CHR20x8x2)))),
+ DummyScreen+120,
+ DL_CHR20x16x2,
+ DL_MAP40x8x4,
+ DL_MAP80x4x2,
+ DL_MAP80x4x4,
+ DL_MAP160x2x2,
+ DL_MAP160x1x2,
+ DL_MAP160x2x4,
+ DL_MAP160x1x4,
+ DL_MAP320x1x1,
+ DL_JVB,
+ DL_JMP
};
-unsigned char dlend = 0;
+/* We know that the sizeof expression is constant; don't tell us. */
+
+#pragma warn (const-comparison, off)
int
main(void)
{
- // unfortunately "sizeof()" doesn't work with void data
- // (Error: Size of data type is unknown)
- // so we trick with the addresses at front and end...
-
- int returnValue = (((unsigned int)&dlend-(unsigned int)&DisplayList) != 28); // assure only one byte per instruction!
+ int returnValue = (sizeof DisplayList != 28); // assure only one byte per instruction!
clrscr();
if (returnValue)
return returnValue;
}
-