diff --git a/.github/checks/Makefile b/.github/checks/Makefile index 18cc153d4..93eeddd19 100644 --- a/.github/checks/Makefile +++ b/.github/checks/Makefile @@ -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 diff --git a/.github/checks/lineendings.sh b/.github/checks/lineendings.sh new file mode 100755 index 000000000..5b445522f --- /dev/null +++ b/.github/checks/lineendings.sh @@ -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 diff --git a/.github/workflows/build-on-pull-request.yml b/.github/workflows/build-on-pull-request.yml index 0ba0c6a1f..05d6a4a39 100644 --- a/.github/workflows/build-on-pull-request.yml +++ b/.github/workflows/build-on-pull-request.yml @@ -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 diff --git a/.github/workflows/snapshot-on-push-master.yml b/.github/workflows/snapshot-on-push-master.yml index 769d778d5..e8be4400e 100644 --- a/.github/workflows/snapshot-on-push-master.yml +++ b/.github/workflows/snapshot-on-push-master.yml @@ -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 diff --git a/Contributing.md b/Contributing.md index ab1e73508..74e6ead17 100644 --- a/Contributing.md +++ b/Contributing.md @@ -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 :) @@ -24,9 +29,22 @@ This is an ongoing controversial topic - everyone knows that. However, the follo The (bash) scripts used to check the above rules can be found in ```.github/check```. You can also run all checks using ```make check```. -### identifiers and symbol names +### Identifiers and Symbol names -* any symbols that are exported from source files and/or appear in header files should not be in the "_symbol" form in C, or "__symbol" form in assembly. This way we evade the problem that "_symbol" may or may not be reserved by that standard. +The C Standard defines certain identifiers and symbol names, which we can not use +in our code. Since it is not always obvious which parts of the library code will +actually end up in a linked program, the following applies to ALL of the library. + +Any non standard identifier/symbol/function that is exported from source files, +or appears in header files: + +* must not be in the "_symbol" form in C, or "__symbol" form in assembly. +* must start with (at least) two (C Code) or three (assembly code) underscores, unless the symbol appears in a non standard header file. + +This is likely more than the standard dictates us to do - but it is certainly +standard compliant - and easy to remember. + +Also see the discussion in https://github.com/cc65/cc65/issues/1796 ### misc @@ -163,12 +181,97 @@ The only exception to the above are actions that are exclusive to the github act * the printf family of function does not completely implement all printf modifiers and does not behave as expected in some cases - all this should be documented in detail -## Floating point support +## Compiler -The first step is implementing the datatype "float" as IEEE488 floats. Help welcomed! +* We need a way that makes it possible to feed arbitrary assembler code into the optimzer, so we can have proper tests for it + +### Floating point support + +The first step is implementing the datatype "float" as IEEE 754 floats. Help welcomed! * WIP compiler/library changes are here: https://github.com/cc65/cc65/pull/1777 -* free software library with testbench is here: http://www.jhauser.us/arithmetic/ + +## Library + +### name clashes in the library + +see "Identifiers and Symbol names" above - not all identifiers have been checked +and renamed yet. The following is a list of those that still might need to be +fixed: + +``` +common + +__argc libsrc/runtime/callmain.s libsrc/cbm610/mainargs.s libsrc/cx16/mainargs.s libsrc/plus4/mainargs.s libsrc/lynx/mainargs.s libsrc/c16/mainargs.s libsrc/geos-common/system/mainargs.s libsrc/sim6502/mainargs.s libsrc/c128/mainargs.s libsrc/vic20/mainargs.s libsrc/nes/mainargs.s libsrc/atari/getargs.s libsrc/apple2/mainargs.s libsrc/cbm510/mainargs.s libsrc/telestrat/mainargs.s libsrc/c64/mainargs.s libsrc/pet/mainargs.s libsrc/atmos/mainargs.s +__argv libsrc/runtime/callmain.s libsrc/cbm610/mainargs.s libsrc/cx16/mainargs.s libsrc/plus4/mainargs.s libsrc/lynx/mainargs.s libsrc/c16/mainargs.s libsrc/geos-common/system/mainargs.s libsrc/sim6502/mainargs.s libsrc/c128/mainargs.s libsrc/vic20/mainargs.s libsrc/nes/mainargs.s libsrc/atari/getargs.s libsrc/apple2/mainargs.s libsrc/cbm510/mainargs.s libsrc/telestrat/mainargs.s libsrc/c64/mainargs.s libsrc/pet/mainargs.s libsrc/atmos/mainargs.s +__cos libsrc/common/sincos.s +__ctypeidx libsrc/common/ctype.s libsrc/common/ctypemask.s libsrc/geos-common/system/ctype.s libsrc/atari/ctype.s libsrc/cbm/ctype.s libsrc/atmos/ctype.s asminc/ctype_common.inc +__cwd libsrc/common/getcwd.s libsrc/common/_cwd.s libsrc/atari/initcwd.s libsrc/apple2/initcwd.s libsrc/apple2/initcwd.s libsrc/telestrat/initcwd.s libsrc/cbm/initcwd.s +__cwd_buf_size libsrc/common/_cwd.s +__envcount libsrc/common/searchenv.s libsrc/common/_environ.s libsrc/common/putenv.s libsrc/common/getenv.s +__environ libsrc/common/searchenv.s libsrc/common/_environ.s libsrc/common/putenv.s libsrc/common/getenv.s +__envsize libsrc/common/_environ.s libsrc/common/putenv.s +__fdesc libsrc/common/_fdesc.s libsrc/common/fopen.s +__filetab libsrc/common/_fdesc.s libsrc/common/_file.s asminc/_file.inc +__fopen libsrc/common/fopen.s libsrc/common/_fopen.s +__printf libsrc/common/vsnprintf.s libsrc/common/_printf.s libsrc/common/vfprintf.s libsrc/conio/vcprintf.s libsrc/pce/_printf.s +__scanf libsrc/common/_scanf.inc libsrc/common/vsscanf.s libsrc/conio/vcscanf.s +__sin libsrc/common/sincos.s +__sys libsrc/common/_sys.s libsrc/apple2/_sys.s +__sys_oserrlist libsrc/common/stroserr.s libsrc/geos-common/system/oserrlist.s libsrc/atari/oserrlist.s libsrc/apple2/oserrlist.s libsrc/cbm/oserrlist.s libsrc/atmos/oserrlist.s +__syschdir libsrc/common/chdir.s libsrc/atari/syschdir.s libsrc/apple2/syschdir.s libsrc/telestrat/syschdir.s libsrc/cbm/syschdir.s +__sysmkdir libsrc/common/mkdir.s libsrc/atari/sysmkdir.s libsrc/apple2/sysmkdir.s libsrc/telestrat/sysmkdir.s +__sysremove libsrc/common/remove.s libsrc/geos-common/file/sysremove.s libsrc/atari/sysremove.s libsrc/atari/sysrmdir.s libsrc/apple2/sysremove.s libsrc/apple2/sysrmdir.s libsrc/telestrat/sysremove.s libsrc/cbm/sysremove.s +__sysrename libsrc/common/rename.s libsrc/geos-common/file/sysrename.s libsrc/atari/sysrename.s libsrc/apple2/sysrename.s libsrc/cbm/sysrename.s +__sysrmdir libsrc/common/rmdir.s libsrc/atari/sysrmdir.s libsrc/apple2/sysrmdir.s +__sysuname libsrc/common/uname.s libsrc/cbm610/sysuname.s libsrc/cx16/sysuname.s libsrc/plus4/sysuname.s libsrc/lynx/sysuname.s libsrc/c16/sysuname.s libsrc/geos-common/system/sysuname.s libsrc/c128/sysuname.s libsrc/creativision/sysuname.s libsrc/vic20/sysuname.s libsrc/nes/sysuname.s libsrc/atari/sysuname.s libsrc/apple2/sysuname.s libsrc/cbm510/sysuname.s libsrc/telestrat/sysuname.s libsrc/c64/sysuname.s libsrc/pet/sysuname.s libsrc/atari5200/sysuname.s libsrc/atmos/sysuname.s + +apple2 + +__auxtype libsrc/apple2/open.s +__datetime libsrc/apple2/open.s +__dos_type libsrc/apple2/dioopen.s libsrc/apple2/curdevice.s libsrc/apple2/mainargs.s libsrc/apple2/settime.s libsrc/apple2/getdevice.s libsrc/apple2/dosdetect.s libsrc/apple2/irq.s libsrc/apple2/open.s libsrc/apple2/mli.s libsrc/apple2/getres.s +__filetype libsrc/apple2/open.s libsrc/apple2/exehdr.s + + +atari + +__defdev libsrc/atari/posixdirent.s libsrc/atari/ucase_fn.s libsrc/atari/getdefdev.s +__dos_type libsrc/atari/getargs.s libsrc/atari/exec.s libsrc/atari/settime.s libsrc/atari/syschdir.s libsrc/atari/dosdetect.s libsrc/atari/is_cmdline_dos.s libsrc/atari/sysrmdir.s libsrc/atari/gettime.s libsrc/atari/lseek.s libsrc/atari/getres.s libsrc/atari/getdefdev.s +__do_oserror libsrc/atari/posixdirent.s libsrc/atari/do_oserr.s libsrc/atari/serref.s libsrc/atari/read.s libsrc/atari/write.s libsrc/atari/close.s +__getcolor libsrc/atari/setcolor.s +__getdefdev libsrc/atari/getdefdev.s +__graphics libsrc/atari/graphics.s +__inviocb libsrc/atari/serref.s libsrc/atari/ser/atrrdev.s libsrc/atari/inviocb.s libsrc/atari/read.s libsrc/atari/write.s libsrc/atari/lseek.s libsrc/atari/close.s +__is_cmdline_dos libsrc/atari/is_cmdline_dos.s libsrc/atari/doesclrscr.s +__rest_vecs libsrc/atari/savevec.s +__rwsetup libsrc/atari/rwcommon.s libsrc/atari/read.s libsrc/atari/write.s +__save_vecs libsrc/atari/savevec.s +__scroll libsrc/atari/scroll.s +__setcolor libsrc/atari/setcolor.s +__setcolor_low libsrc/atari/setcolor.s +__sio_call libsrc/atari/diowritev.s libsrc/atari/diopncls.s libsrc/atari/siocall.s libsrc/atari/diowrite.s libsrc/atari/dioread.s + + +cbm + +__cbm_filetype libsrc/cbm/cbm_filetype.s asminc/cbm_filetype.in +__dirread libsrc/cbm/dir.inc libsrc/cbm/dir.s +__dirread1 libsrc/cbm/dir.inc libsrc/cbm/dir.s + + +lynx + +__iodat libsrc/lynx/lynx-cart.s libsrc/lynx/bootldr.s libsrc/lynx/extzp.s libsrc/lynx/crt0.s libsrc/lynx/extzp.inc +__iodir libsrc/lynx/extzp.s libsrc/lynx/crt0.s libsrc/lynx/extzp.inc +__sprsys libsrc/lynx/tgi/lynx-160-102-16.s libsrc/lynx/extzp.s libsrc/lynx/crt0.s libsrc/lynx/extzp.inc +__viddma libsrc/lynx/tgi/lynx-160-102-16.s libsrc/lynx/extzp.s libsrc/lynx/crt0.s libsrc/lynx/extzp.inc + + +pce + +__nmi libsrc/pce/irq.s libsrc/pce/crt0.s +``` ## Test suite diff --git a/asminc/_heap.inc b/asminc/_heap.inc index a7d6acea2..1bf80ac82 100644 --- a/asminc/_heap.inc +++ b/asminc/_heap.inc @@ -28,8 +28,8 @@ HEAP_MIN_BLOCKSIZE = .sizeof (freeblock) ; Minimum size of an allocated block HEAP_ADMIN_SPACE = .sizeof (usedblock) ; Additional space for used bock ; Variables -.global __heaporg -.global __heapptr -.global __heapend -.global __heapfirst -.global __heaplast +.global ___heaporg +.global ___heapptr +.global ___heapend +.global ___heapfirst +.global ___heaplast diff --git a/asminc/errno.inc b/asminc/errno.inc index 1efe88cda..2e876c7ac 100644 --- a/asminc/errno.inc +++ b/asminc/errno.inc @@ -4,10 +4,10 @@ ; Variables and functions - .global __errno, __oserror - .global __osmaperrno - .global __seterrno - .global __directerrno, __mappederrno + .global ___errno, ___oserror + .global ___osmaperrno + .global ___seterrno + .global ___directerrno, ___mappederrno ; Error codes, must match the values in the C headers .enum diff --git a/asminc/signal.inc b/asminc/signal.inc index ebde07e42..597cad413 100644 --- a/asminc/signal.inc +++ b/asminc/signal.inc @@ -49,8 +49,8 @@ SIGCOUNT = 6 ; Number of signals .global sigtable ; Function declarations -.global __sig_ign -.global __sig_dfl +.global ___sig_ign +.global ___sig_dfl .global _signal .global _raise diff --git a/doc/da65.sgml b/doc/da65.sgml index bf074a667..185dbe0e6 100644 --- a/doc/da65.sgml +++ b/doc/da65.sgml @@ -461,7 +461,8 @@ following attributes are recognized: END 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. NAME This is a convenience attribute. It takes a string argument and will cause diff --git a/include/_heap.h b/include/_heap.h index c054cfa34..62a7f4bed 100644 --- a/include/_heap.h +++ b/include/_heap.h @@ -37,13 +37,20 @@ struct freeblock { /* Variables that describe the heap */ -extern unsigned* _heaporg; /* Bottom of heap */ -extern unsigned* _heapptr; /* Current top */ -extern unsigned* _heapend; /* Upper limit */ -extern struct freeblock* _heapfirst; /* First free block in list */ -extern struct freeblock* _heaplast; /* Last free block in list */ - +extern unsigned* __heaporg; /* Bottom of heap */ +extern unsigned* __heapptr; /* Current top */ +extern unsigned* __heapend; /* Upper limit */ +extern struct freeblock* __heapfirst; /* First free block in list */ +extern struct freeblock* __heaplast; /* Last free block in list */ +#if __CC65_STD__ == __CC65_STD_CC65__ +/* define old name with one underscore for backwards compatibility */ +#define _heaporg __heaporg +#define _heapptr __heapptr +#define _heapend __heapend +#define _heapfirst __heapfirst +#define _heaplast __heaplast +#endif /* End of _heap.h */ diff --git a/include/apple2.h b/include/apple2.h index cb15cab97..9f644bc97 100644 --- a/include/apple2.h +++ b/include/apple2.h @@ -171,7 +171,7 @@ extern struct { extern void a2_auxmem_emd[]; extern void a2_stdjoy_joy[]; /* Referred to by joy_static_stddrv[] */ extern void a2_stdmou_mou[]; /* Referred to by mouse_static_stddrv[] */ -extern void a2_ssc_ser[]; +extern void a2_ssc_ser[]; /* Referred to by ser_static_stddrv[] */ extern void a2_hi_tgi[]; /* Referred to by tgi_static_stddrv[] */ extern void a2_lo_tgi[]; #endif diff --git a/include/apple2enh.h b/include/apple2enh.h index 58e0b397f..bfe5cdb18 100644 --- a/include/apple2enh.h +++ b/include/apple2enh.h @@ -99,7 +99,7 @@ extern void a2e_auxmem_emd[]; extern void a2e_stdjoy_joy[]; /* Referred to by joy_static_stddrv[] */ extern void a2e_stdmou_mou[]; /* Referred to by mouse_static_stddrv[] */ -extern void a2e_ssc_ser[]; +extern void a2e_ssc_ser[]; /* Referred to by ser_static_stddrv[] */ extern void a2e_hi_tgi[]; /* Referred to by tgi_static_stddrv[] */ extern void a2e_lo_tgi[]; diff --git a/include/assert.h b/include/assert.h index a4dcd5d7f..ca8d4acc1 100644 --- a/include/assert.h +++ b/include/assert.h @@ -42,8 +42,8 @@ #ifdef NDEBUG # define assert(expr) #else -extern void __fastcall__ _afailed (const char*, unsigned); -# define assert(expr) ((expr)? (void)0 : _afailed(__FILE__, __LINE__)) +extern void __fastcall__ __afailed (const char*, unsigned); +# define assert(expr) ((expr)? (void)0 : __afailed(__FILE__, __LINE__)) #endif /* TODO: Guard with #if __CC65_STD__ >= __CC65_STD_C11__ if there diff --git a/include/atari.h b/include/atari.h index 781ee7a80..deae8fdf5 100644 --- a/include/atari.h +++ b/include/atari.h @@ -261,7 +261,7 @@ extern void atrst_mou[]; /* referred to by mouse_static_stddrv[] extern void atrami_mou[]; extern void atrtrk_mou[]; extern void atrtt_mou[]; -extern void atrrdev_ser[]; +extern void atrrdev_ser[]; /* referred to by ser_static_stddrv[] */ extern void atr3_tgi[]; extern void atr4_tgi[]; extern void atr5_tgi[]; @@ -286,7 +286,7 @@ extern void atrxst_mou[]; /* referred to by mouse_static_stddrv[] extern void atrxami_mou[]; extern void atrxtrk_mou[]; extern void atrxtt_mou[]; -extern void atrxrdev_ser[]; +extern void atrxrdev_ser[]; /* referred to by ser_static_stddrv[] */ extern void atrx3_tgi[]; extern void atrx4_tgi[]; extern void atrx5_tgi[]; diff --git a/include/atmos.h b/include/atmos.h index 227c387aa..38d423c46 100644 --- a/include/atmos.h +++ b/include/atmos.h @@ -133,7 +133,7 @@ /* The addresses of the static drivers */ extern void atmos_pase_joy[]; /* Referred to by joy_static_stddrv[] */ extern void atmos_ijk_joy[]; -extern void atmos_acia_ser[]; +extern void atmos_acia_ser[]; /* Referred to by ser_static_stddrv[] */ extern void atmos_228_200_3_tgi[]; extern void atmos_240_200_2_tgi[]; /* Referred to by tgi_static_stddrv[] */ diff --git a/include/c128.h b/include/c128.h index ee1dce99e..5a34904e0 100644 --- a/include/c128.h +++ b/include/c128.h @@ -140,7 +140,7 @@ extern void c128_1351_mou[]; /* Referred to by mouse_static_stddrv[] */ extern void c128_joy_mou[]; extern void c128_inkwell_mou[]; extern void c128_pot_mou[]; -extern void c128_swlink_ser[]; +extern void c128_swlink_ser[]; /* Referred to by ser_static_stddrv[] */ extern void c128_hi_tgi[]; extern void c128_vdc_tgi[]; /* Referred to by tgi_static_stddrv[] */ extern void c128_vdc2_tgi[]; diff --git a/include/c64.h b/include/c64.h index 13d252dcb..ffac801ef 100644 --- a/include/c64.h +++ b/include/c64.h @@ -155,7 +155,7 @@ extern void c64_1351_mou[]; /* Referred to by mouse_static_stddrv[] extern void c64_joy_mou[]; extern void c64_inkwell_mou[]; extern void c64_pot_mou[]; -extern void c64_swlink_ser[]; +extern void c64_swlink_ser[]; /* Referred to by ser_static_stddrv[] */ extern void c64_hi_tgi[]; /* Referred to by tgi_static_stddrv[] */ diff --git a/include/cbm.h b/include/cbm.h index cceb76b1b..0679b2d65 100644 --- a/include/cbm.h +++ b/include/cbm.h @@ -225,7 +225,7 @@ void cbm_k_untlk (void); -/* The cbm_* I/O functions below set _oserror (see errno.h), +/* The cbm_* I/O functions below set __oserror (see errno.h), ** in case of an error. ** ** error-code BASIC error @@ -251,7 +251,7 @@ unsigned int __fastcall__ cbm_load (const char* name, unsigned char device, void ** address of the file if "data" is the null pointer (like load"name",8,1 ** in BASIC). ** Returns number of bytes that were loaded if loading was successful; -** otherwise 0, "_oserror" contains an error-code, then (see table above). +** otherwise 0, "__oserror" contains an error-code, then (see table above). */ unsigned char __fastcall__ cbm_save (const char* name, unsigned char device, @@ -274,7 +274,7 @@ void __fastcall__ cbm_close (unsigned char lfn); int __fastcall__ cbm_read (unsigned char lfn, void* buffer, unsigned int size); /* Reads up to "size" bytes from a file into "buffer". ** Returns the number of actually-read bytes, 0 if there are no bytes left. -** -1 in case of an error; then, _oserror contains an error-code (see table +** -1 in case of an error; then, __oserror contains an error-code (see table ** above). (Remember: 0 means end-of-file; -1 means error.) */ @@ -282,7 +282,7 @@ int __fastcall__ cbm_write (unsigned char lfn, const void* buffer, unsigned int size); /* Writes up to "size" bytes from "buffer" to a file. ** Returns the number of actually-written bytes, or -1 in case of an error; -** _oserror contains an error-code, then (see above table). +** __oserror contains an error-code, then (see above table). */ unsigned char cbm_opendir (unsigned char lfn, unsigned char device, ...); diff --git a/include/cbm510.h b/include/cbm510.h index 20b334ed9..8ebbdf3c1 100644 --- a/include/cbm510.h +++ b/include/cbm510.h @@ -128,7 +128,7 @@ extern void cbm510_inkwl_mou[]; extern void cbm510_joy_mou[]; /* Referred to by mouse_static_stddrv[] */ extern void cbm510_ram_emd[]; extern void cbm510_std_joy[]; /* Referred to by joy_static_stddrv[] */ -extern void cbm510_std_ser[]; +extern void cbm510_std_ser[]; /* Referred to by ser_static_stddrv[] */ diff --git a/include/cbm610.h b/include/cbm610.h index de7aa50f8..64beab9e6 100644 --- a/include/cbm610.h +++ b/include/cbm610.h @@ -105,7 +105,7 @@ /* The addresses of the static drivers */ extern void cbm610_ram_emd[]; -extern void cbm610_std_ser[]; +extern void cbm610_std_ser[]; /* Referred to by ser_static_stddrv[] */ diff --git a/include/dio.h b/include/dio.h index 4201728cc..2521a90ff 100644 --- a/include/dio.h +++ b/include/dio.h @@ -35,9 +35,9 @@ -/* Please note: All functions in this file will set _oserror *and* return its -** value. The only exception is dio_open, which will return NULL, but _oserror -** will be set. All function will also set _oserror in case of successful +/* Please note: All functions in this file will set __oserror *and* return its +** value. The only exception is dio_open, which will return NULL, but __oserror +** will be set. All function will also set __oserror in case of successful ** execution, effectively clearing it. */ diff --git a/include/errno.h b/include/errno.h index 92d304938..8f329e3cc 100644 --- a/include/errno.h +++ b/include/errno.h @@ -45,12 +45,17 @@ /* Operating system specific error code */ -extern unsigned char _oserror; +extern unsigned char __oserror; -extern int _errno; +#if __CC65_STD__ >= __CC65_STD_CC65__ +/* define the name with just one underscore for backwards compatibility */ +#define _oserror __oserror +#endif + +extern int __errno; /* System errors go here */ -#define errno _errno +#define errno __errno /* errno must be a macro */ @@ -83,27 +88,45 @@ extern int _errno; -int __fastcall__ _osmaperrno (unsigned char oserror); -/* Map an operating system specific error code (for example from _oserror) +int __fastcall__ __osmaperrno (unsigned char oserror); +/* Map an operating system specific error code (for example from __oserror) ** into one of the E... codes above. It is user callable. */ -unsigned char __fastcall__ _seterrno (unsigned char code); +#if __CC65_STD__ >= __CC65_STD_CC65__ +/* define the name with just one underscore for backwards compatibility */ +#define _osmaperrno __osmaperrno +#endif + +unsigned char __fastcall__ __seterrno (unsigned char code); /* Set errno to a specific error code and return zero. Used by the library */ -int __fastcall__ _directerrno (unsigned char code); -/* Set errno to a specific error code, clear _oserror and return -1. Used +#if __CC65_STD__ >= __CC65_STD_CC65__ +/* define the name with just one underscore for backwards compatibility */ +#define _seterrno __seterrno +#endif + +int __fastcall__ __directerrno (unsigned char code); +/* Set errno to a specific error code, clear __oserror and return -1. Used ** by the library. */ -int __fastcall__ _mappederrno (unsigned char code); -/* Set _oserror to the given platform specific error code. If it is a real +#if __CC65_STD__ >= __CC65_STD_CC65__ +/* define the name with just one underscore for backwards compatibility */ +#define _directerrno __directerrno +#endif + +int __fastcall__ __mappederrno (unsigned char code); +/* Set __oserror to the given platform specific error code. If it is a real ** error code (not zero) set errno to the corresponding system error code ** and return -1. Otherwise return zero. ** Used by the library. */ - +#if __CC65_STD__ >= __CC65_STD_CC65__ +/* define the name with just one underscore for backwards compatibility */ +#define _mappederrno __mappederrno +#endif /* End of errno.h */ #endif diff --git a/include/lynx.h b/include/lynx.h index 1b4828a72..41dc5acb3 100644 --- a/include/lynx.h +++ b/include/lynx.h @@ -115,7 +115,7 @@ /* The addresses of the static drivers */ extern void lynx_stdjoy_joy[]; /* Referred to by joy_static_stddrv[] */ -extern void lynx_comlynx_ser[]; +extern void lynx_comlynx_ser[]; /* Referred to by ser_static_stddrv[] */ extern void lynx_160_102_16_tgi[]; /* Referred to by tgi_static_stddrv[] */ diff --git a/include/osic1p.h b/include/osic1p.h index d6ab5fee1..479d9fd52 100644 --- a/include/osic1p.h +++ b/include/osic1p.h @@ -36,6 +36,24 @@ # error "This module may only be used when compiling for the Challenger 1P!" #endif +/* Colors are not functional, display is black and white only. */ +#define COLOR_BLACK 0x00 +#define COLOR_WHITE 0x01 + +#define CH_ULCORNER 0xCC +#define CH_URCORNER 0xCD +#define CH_LLCORNER 0xCB +#define CH_LRCORNER 0xCE +#define CH_TTEE 0xD9 +#define CH_BTEE 0xD7 +#define CH_LTEE 0xD8 +#define CH_RTEE 0xDA +#define CH_CROSS 0xDB +#define CH_HLINE 0x94 +#define CH_VLINE 0x95 + +#define CH_ENTER 0x0D + /* The following #defines will cause the matching functions calls in conio.h ** to be overlaid by macros with the same names, saving the function call ** overhead. @@ -43,5 +61,6 @@ #define _textcolor(color) COLOR_WHITE #define _bgcolor(color) COLOR_BLACK #define _bordercolor(color) COLOR_BLACK +#define _cpeekcolor(color) COLOR_WHITE #endif diff --git a/include/plus4.h b/include/plus4.h index 325ba7d89..7730938e8 100644 --- a/include/plus4.h +++ b/include/plus4.h @@ -56,7 +56,7 @@ /* The addresses of the static drivers */ extern void plus4_stdjoy_joy[]; /* Referred to by joy_static_stddrv[] */ -extern void plus4_stdser_ser[]; +extern void plus4_stdser_ser[]; /* Referred to by ser_static_stddrv[] */ diff --git a/include/serial.h b/include/serial.h index 35d7b8f66..0510cd219 100644 --- a/include/serial.h +++ b/include/serial.h @@ -123,6 +123,13 @@ struct ser_params { unsigned char handshake; /* Type of handshake to use */ }; +/* The name of the standard serial driver for a platform */ +extern const char ser_stddrv[]; + +/* The address of the static standard serial driver for a platform */ +extern const void ser_static_stddrv[]; + + /*****************************************************************************/ /* Code */ diff --git a/include/setjmp.h b/include/setjmp.h index 460829e38..5fac25634 100644 --- a/include/setjmp.h +++ b/include/setjmp.h @@ -42,8 +42,8 @@ typedef char jmp_buf [5]; -int __fastcall__ _setjmp (jmp_buf buf); -#define setjmp _setjmp /* ISO insists on a macro */ +int __fastcall__ __setjmp (jmp_buf buf); +#define setjmp __setjmp /* ISO insists on a macro */ void __fastcall__ longjmp (jmp_buf buf, int retval) __attribute__((noreturn)); diff --git a/include/signal.h b/include/signal.h index 0d5f6ad09..d67cebf7c 100644 --- a/include/signal.h +++ b/include/signal.h @@ -45,12 +45,12 @@ typedef unsigned char sig_atomic_t; typedef void __fastcall__ (*__sigfunc) (int); /* Functions that implement SIG_IGN and SIG_DFL */ -void __fastcall__ _sig_ign (int); -void __fastcall__ _sig_dfl (int); +void __fastcall__ __sig_ign (int); +void __fastcall__ __sig_dfl (int); /* Standard signal handling functions */ -#define SIG_DFL _sig_dfl -#define SIG_IGN _sig_ign +#define SIG_DFL __sig_dfl +#define SIG_IGN __sig_ign #define SIG_ERR ((__sigfunc) 0x0000) /* Signal numbers */ diff --git a/include/stdio.h b/include/stdio.h index 84a991a98..858dd5059 100644 --- a/include/stdio.h +++ b/include/stdio.h @@ -147,7 +147,11 @@ int __fastcall__ vfscanf (FILE* f, const char* format, __va_list ap); FILE* __fastcall__ fdopen (int fd, const char* mode); /* Unix */ int __fastcall__ fileno (FILE* f); /* Unix */ #endif -void __fastcall__ _poserror (const char* msg); /* cc65 */ +void __fastcall__ __poserror (const char* msg); /* cc65 */ +#if __CC65_STD__ == __CC65_STD_CC65__ +/* define old name with one underscore for backwards compatibility */ +#define _poserror __poserror +#endif /* Masking macros for some functions */ #define getc(f) fgetc (f) /* ANSI */ diff --git a/include/stdlib.h b/include/stdlib.h index 99151317f..4e7ffbd6a 100644 --- a/include/stdlib.h +++ b/include/stdlib.h @@ -92,24 +92,44 @@ int __fastcall__ posix_memalign (void** memptr, size_t alignment, size_t size); */ #endif -void __fastcall__ _heapadd (void* mem, size_t size); +void __fastcall__ __heapadd (void* mem, size_t size); /* Add a block to the heap */ +#if __CC65_STD__ == __CC65_STD_CC65__ +/* define old name with one underscore for backwards compatibility */ +#define _heapadd __heapadd +#endif -size_t __fastcall__ _heapblocksize (const void* block); +size_t __fastcall__ __heapblocksize (const void* block); /* Return the size of an allocated block */ +#if __CC65_STD__ == __CC65_STD_CC65__ +/* define old name with one underscore for backwards compatibility */ +#define _heapblocksize __heapblocksize +#endif -size_t _heapmemavail (void); +size_t __heapmemavail (void); /* Return the total free heap space */ +#if __CC65_STD__ == __CC65_STD_CC65__ +/* define old name with one underscore for backwards compatibility */ +#define _heapmemavail __heapmemavail +#endif -size_t _heapmaxavail (void); +size_t __heapmaxavail (void); /* Return the size of the largest free block on the heap */ +#if __CC65_STD__ == __CC65_STD_CC65__ +/* define old name with one underscore for backwards compatibility */ +#define _heapmaxavail __heapmaxavail +#endif /* Random numbers */ #define RAND_MAX 0x7FFF int rand (void); void __fastcall__ srand (unsigned seed); -void _randomize (void); /* Non-standard */ +void __randomize (void); /* Non-standard */ +#if __CC65_STD__ == __CC65_STD_CC65__ +/* define old name with one underscore for backwards compatibility */ +#define _randomize __randomize +#endif /* Other standard stuff */ void abort (void) __attribute__ ((noreturn)); @@ -130,7 +150,11 @@ unsigned long __fastcall__ strtoul (const char* nptr, char** endptr, int base); int __fastcall__ system (const char* s); /* Non-ANSI functions */ -void __fastcall__ _swap (void* p, void* q, size_t size); +void __fastcall__ __swap (void* p, void* q, size_t size); +#if __CC65_STD__ == __CC65_STD_CC65__ +/* define old name with one underscore for backwards compatibility */ +#define _swap __swap +#endif #if __CC65_STD__ == __CC65_STD_CC65__ char* __fastcall__ itoa (int val, char* buf, int radix); char* __fastcall__ utoa (unsigned val, char* buf, int radix); diff --git a/include/string.h b/include/string.h index 1bd83b385..854359dad 100644 --- a/include/string.h +++ b/include/string.h @@ -74,7 +74,7 @@ void* __fastcall__ memset (void* s, int c, size_t count); /* The following is an internal function, the compiler will replace memset ** with it if the fill value is zero. Never use this one directly! */ -void* __fastcall__ _bzero (void* ptr, size_t n); +void* __fastcall__ __bzero (void* ptr, size_t n); /* Non standard: */ #if __CC65_STD__ == __CC65_STD_CC65__ @@ -92,8 +92,12 @@ char* __fastcall__ strupper (char* s); char* __fastcall__ strqtok (char* s1, const char* s2); #endif -const char* __fastcall__ _stroserror (unsigned char errcode); +const char* __fastcall__ __stroserror (unsigned char errcode); /* Map an operating system error number to an error message. */ +#if __CC65_STD__ == __CC65_STD_CC65__ +/* define old name with one underscore for backwards compatibility */ +#define _stroserror __stroserror +#endif /* End of string.h */ diff --git a/include/time.h b/include/time.h index 99bb1c8e3..642d68c4e 100644 --- a/include/time.h +++ b/include/time.h @@ -89,8 +89,8 @@ struct tm { # define CLOCKS_PER_SEC 10 #elif defined(__ATARI__) || defined (__LYNX__) /* Read the clock rate at runtime */ -clock_t _clocks_per_sec (void); -# define CLOCKS_PER_SEC _clocks_per_sec() +clock_t __clocks_per_sec (void); +# define CLOCKS_PER_SEC __clocks_per_sec() #endif #define CLOCK_REALTIME 0 diff --git a/libsrc/apple2/close.s b/libsrc/apple2/close.s index cef42b6f8..0002d081d 100644 --- a/libsrc/apple2/close.s +++ b/libsrc/apple2/close.s @@ -33,8 +33,8 @@ zerofd: lda #$00 ; Return success lda #$00 - ; Set __oserror -oserr: jmp __mappederrno + ; Set ___oserror +oserr: jmp ___mappederrno ; Set __errno -errno: jmp __directerrno +errno: jmp ___directerrno diff --git a/libsrc/apple2/devicedir.s b/libsrc/apple2/devicedir.s index 79f4c60de..21cabf59e 100644 --- a/libsrc/apple2/devicedir.s +++ b/libsrc/apple2/devicedir.s @@ -45,9 +45,9 @@ _getdevicedir: ; Handle errors erange: lda #buf sta ICBAH,x ; set buffer address diff --git a/libsrc/atari/getres.s b/libsrc/atari/getres.s index f2e4874f9..9716040d8 100644 --- a/libsrc/atari/getres.s +++ b/libsrc/atari/getres.s @@ -41,7 +41,7 @@ _clock_getres: enosys: lda #ENOSYS ; Set __errno - jmp __directerrno + jmp ___directerrno ;---------------------------------------------------------------------------- ; timespec struct with tv_sec set to 1 second diff --git a/libsrc/atari/gettime.s b/libsrc/atari/gettime.s index 093d34843..df6e24021 100644 --- a/libsrc/atari/gettime.s +++ b/libsrc/atari/gettime.s @@ -105,7 +105,7 @@ errexit:jsr incsp3 ; Preserves A ; set __errno - jmp __directerrno + jmp ___directerrno ; ------- diff --git a/libsrc/atari/graphics.s b/libsrc/atari/graphics.s index ab26ed0da..1f7844c39 100644 --- a/libsrc/atari/graphics.s +++ b/libsrc/atari/graphics.s @@ -10,7 +10,7 @@ .export __graphics .import findfreeiocb - .import __oserror + .import ___oserror .import fddecusage .import clriocb .import fdtoiocb @@ -45,7 +45,7 @@ parmok: jsr findfreeiocb beq iocbok ; we found one lda #EINVAL @@ -94,7 +94,7 @@ doopen: txa lda tmp2 ; get fd ldx #0 - stx __oserror + stx ___oserror rts cioerr: sty tmp3 ; remember error code @@ -103,6 +103,6 @@ cioerr: sty tmp3 ; remember error code jsr CIOV ; close IOCB again since open failed jsr fddecusage ; and decrement usage counter of fd lda tmp3 ; put error code into A - jmp __mappederrno + jmp ___mappederrno .endproc ; __graphics diff --git a/libsrc/atari/inviocb.s b/libsrc/atari/inviocb.s index c1c27ee03..2ceb385b1 100644 --- a/libsrc/atari/inviocb.s +++ b/libsrc/atari/inviocb.s @@ -7,4 +7,4 @@ __inviocb: lda #(charsperline * screenrows) lda #<(charsperline * screenrows) - jmp __bzero + jmp ___bzero .endproc diff --git a/libsrc/atari7800/mono_clrscr.s b/libsrc/atari7800/mono_clrscr.s index 19f1fdfd6..f6f6735cb 100644 --- a/libsrc/atari7800/mono_clrscr.s +++ b/libsrc/atari7800/mono_clrscr.s @@ -4,7 +4,7 @@ .export _mono_clrscr .import _mono_screen - .import pushax, __bzero + .import pushax, ___bzero .include "extzp.inc" .code @@ -16,7 +16,7 @@ jsr pushax ldx #>(mono_charsperline * screenrows) lda #<(mono_charsperline * screenrows) - jmp __bzero + jmp ___bzero .endproc diff --git a/libsrc/atmos/oserror.s b/libsrc/atmos/oserror.s index 37c9bd7fc..2e902afdf 100644 --- a/libsrc/atmos/oserror.s +++ b/libsrc/atmos/oserror.s @@ -1,14 +1,14 @@ ; ; Stefan Haubenthal, 2011-04-18 ; -; int __fastcall__ _osmaperrno (unsigned char oserror); +; int __fastcall__ __osmaperrno (unsigned char oserror); ; /* Map a system specific error into a system independent code */ ; .include "errno.inc" - .export __osmaperrno + .export ___osmaperrno -.proc __osmaperrno +.proc ___osmaperrno lda #EUNKNOWN diff --git a/libsrc/atmos/ser_stat_stddrv.s b/libsrc/atmos/ser_stat_stddrv.s new file mode 100644 index 000000000..2b4373695 --- /dev/null +++ b/libsrc/atmos/ser_stat_stddrv.s @@ -0,0 +1,14 @@ +; +; Address of the static standard serial driver +; +; Oliver Schmidt, 2022-12-22 +; +; const void ser_static_stddrv[]; +; + + .export _ser_static_stddrv + .import _atmos_acia_ser + +.rodata + +_ser_static_stddrv := _atmos_acia_ser diff --git a/libsrc/atmos/ser_stddrv.s b/libsrc/atmos/ser_stddrv.s new file mode 100644 index 000000000..71e33115a --- /dev/null +++ b/libsrc/atmos/ser_stddrv.s @@ -0,0 +1,13 @@ +; +; Name of the standard serial driver +; +; Oliver Schmidt, 2022-12-22 +; +; const char ser_stddrv[]; +; + + .export _ser_stddrv + +.rodata + +_ser_stddrv: .asciiz "atmos-acia.ser" diff --git a/libsrc/c128/randomize.s b/libsrc/c128/randomize.s index ae63184a4..2b7754e86 100644 --- a/libsrc/c128/randomize.s +++ b/libsrc/c128/randomize.s @@ -2,16 +2,16 @@ ; 2002-11-05, Ullrich von Bassewitz ; 2015-09-11, Greg King ; -; void _randomize (void); +; void __randomize (void); ; /* Initialize the random number generator */ ; - .export __randomize + .export ___randomize .import _srand .include "c128.inc" -__randomize: +___randomize: ldx VIC_HLINE ; Use VIC rasterline as high byte lda TIME+2 ; Use 60HZ clock as low byte jmp _srand ; Initialize generator diff --git a/libsrc/c128/ser_stat_stddrv.s b/libsrc/c128/ser_stat_stddrv.s new file mode 100644 index 000000000..8b0732703 --- /dev/null +++ b/libsrc/c128/ser_stat_stddrv.s @@ -0,0 +1,14 @@ +; +; Address of the static standard serial driver +; +; Oliver Schmidt, 2022-12-22 +; +; const void ser_static_stddrv[]; +; + + .export _ser_static_stddrv + .import _c128_swlink_ser + +.rodata + +_ser_static_stddrv := _c128_swlink_ser diff --git a/libsrc/c128/ser_stddrv.s b/libsrc/c128/ser_stddrv.s new file mode 100644 index 000000000..63f73cadd --- /dev/null +++ b/libsrc/c128/ser_stddrv.s @@ -0,0 +1,13 @@ +; +; Name of the standard serial driver +; +; Oliver Schmidt, 2022-12-22 +; +; const char ser_stddrv[]; +; + + .export _ser_stddrv + +.rodata + +_ser_stddrv: .asciiz "c128_swlink.ser" diff --git a/libsrc/c16/randomize.s b/libsrc/c16/randomize.s index 796ad118b..0d1ccaf03 100644 --- a/libsrc/c16/randomize.s +++ b/libsrc/c16/randomize.s @@ -2,16 +2,16 @@ ; 2002-11-05, Ullrich von Bassewitz ; 2015-09-11, Greg King ; -; void _randomize (void); +; void __randomize (void); ; /* Initialize the random number generator */ ; - .export __randomize + .export ___randomize .import _srand .include "plus4.inc" -__randomize: +___randomize: ldx TED_VLINELO ; Use TED rasterline as high byte lda TIME+2 ; Use 60HZ clock as low byte jmp _srand ; Initialize generator diff --git a/libsrc/c64/randomize.s b/libsrc/c64/randomize.s index a875203af..da32dfc28 100644 --- a/libsrc/c64/randomize.s +++ b/libsrc/c64/randomize.s @@ -2,16 +2,16 @@ ; 2002-11-05, Ullrich von Bassewitz ; 2015-09-11, Greg King ; -; void _randomize (void); +; void __randomize (void); ; /* Initialize the random number generator */ ; - .export __randomize + .export ___randomize .import _srand .include "c64.inc" -__randomize: +___randomize: ldx VIC_HLINE ; Use VIC rasterline as high byte lda TIME+2 ; Use 60HZ clock as low byte jmp _srand ; Initialize generator diff --git a/libsrc/c64/ser_stat_stddrv.s b/libsrc/c64/ser_stat_stddrv.s new file mode 100644 index 000000000..327abbe5f --- /dev/null +++ b/libsrc/c64/ser_stat_stddrv.s @@ -0,0 +1,14 @@ +; +; Address of the static standard serial driver +; +; Oliver Schmidt, 2022-12-22 +; +; const void ser_static_stddrv[]; +; + + .export _ser_static_stddrv + .import _c64_swlink_ser + +.rodata + +_ser_static_stddrv := _c64_swlink_ser diff --git a/libsrc/c64/ser_stddrv.s b/libsrc/c64/ser_stddrv.s new file mode 100644 index 000000000..5b00b7642 --- /dev/null +++ b/libsrc/c64/ser_stddrv.s @@ -0,0 +1,13 @@ +; +; Name of the standard serial driver +; +; Oliver Schmidt, 2022-12-22 +; +; const char ser_stddrv[]; +; + + .export _ser_stddrv + +.rodata + +_ser_stddrv: .asciiz "c64_swlink.ser" diff --git a/libsrc/cbm/c_load.s b/libsrc/cbm/c_load.s index d81430a03..7f2a054bd 100644 --- a/libsrc/cbm/c_load.s +++ b/libsrc/cbm/c_load.s @@ -7,7 +7,7 @@ .include "cbm.inc" .export _cbm_k_load - .import __oserror + .import ___oserror .import popa .importzp ptr1 @@ -19,7 +19,7 @@ _cbm_k_load: ldy ptr1+1 jsr LOAD bcc @Ok - sta __oserror + sta ___oserror ldx ptr1 ldy ptr1+1 @Ok: txa diff --git a/libsrc/cbm/cbm_open.s b/libsrc/cbm/cbm_open.s index db4179db8..c7590af2a 100644 --- a/libsrc/cbm/cbm_open.s +++ b/libsrc/cbm/cbm_open.s @@ -15,7 +15,7 @@ ; { ; cbm_k_setlfs(lfn, device, sec_addr); ; cbm_k_setnam(name); -; return _oserror = cbm_k_open(); +; return __oserror = cbm_k_open(); ; } ; @@ -23,7 +23,7 @@ .import popa .import _cbm_k_setlfs, _cbm_k_setnam, _cbm_k_open - .import __oserror + .import ___oserror _cbm_open: jsr _cbm_k_setnam @@ -32,5 +32,5 @@ _cbm_open: jsr _cbm_k_setlfs ; Call SETLFS, pop all args jsr _cbm_k_open - sta __oserror + sta ___oserror rts diff --git a/libsrc/cbm/cbm_read.s b/libsrc/cbm/cbm_read.s index 29e0e1f19..8a9939eca 100644 --- a/libsrc/cbm/cbm_read.s +++ b/libsrc/cbm/cbm_read.s @@ -6,7 +6,7 @@ ; int __fastcall__ cbm_read (unsigned char lfn, void* buffer, unsigned int size) ; /* Reads up to "size" bytes from a file to "buffer". ; ** Returns the number of actually read bytes, 0 if there are no bytes left -; ** (EOF) or -1 in case of an error. _oserror contains an errorcode then (see +; ** (EOF) or -1 in case of an error. __oserror contains an errorcode then (see ; ** table below). ; */ ; { @@ -14,7 +14,7 @@ ; static unsigned char tmp; ; ; /* if we can't change to the inputchannel #lfn then return an error */ -; if (_oserror = cbm_k_chkin(lfn)) return -1; +; if (__oserror = cbm_k_chkin(lfn)) return -1; ; ; bytesread = 0; ; @@ -41,7 +41,7 @@ .export _cbm_read .importzp ptr1, ptr2, ptr3, tmp1 .import popax, popa - .import __oserror + .import ___oserror _cbm_read: @@ -106,7 +106,7 @@ _cbm_read: ; CHKIN failed -@E1: sta __oserror +@E1: sta ___oserror lda #$FF tax rts ; return -1 diff --git a/libsrc/cbm/cbm_write.s b/libsrc/cbm/cbm_write.s index 5ac07209c..18c6f4684 100644 --- a/libsrc/cbm/cbm_write.s +++ b/libsrc/cbm/cbm_write.s @@ -9,7 +9,7 @@ ; static unsigned int byteswritten; ; ; /* if we can't change to the outputchannel #lfn then return an error */ -; if (_oserror = cbm_k_ckout(lfn)) return -1; +; if (__oserror = cbm_k_ckout(lfn)) return -1; ; ; byteswritten = 0; ; @@ -18,7 +18,7 @@ ; } ; ; if (cbm_k_readst()) { -; _oserror = 5; /* device not present */ +; __oserror = 5; /* device not present */ ; byteswritten = -1; ; } ; @@ -33,7 +33,7 @@ .export _cbm_write .importzp ptr1, ptr2, ptr3 .import popax, popa - .import __oserror + .import ___oserror _cbm_write: @@ -87,7 +87,7 @@ _cbm_write: ; Error entry, error code is in A -@E2: sta __oserror +@E2: sta ___oserror lda #$FF tax rts ; return -1 diff --git a/libsrc/cbm/close.s b/libsrc/cbm/close.s index 7fc600e87..d805e37cc 100644 --- a/libsrc/cbm/close.s +++ b/libsrc/cbm/close.s @@ -54,12 +54,12 @@ ldx unittab,y jsr closecmdchannel ; Close the disk command channel pla ; Get the error code from the disk - jmp __mappederrno ; Set _oserror and _errno, return 0/-1 + jmp ___mappederrno ; Set __oserror and _errno, return 0/-1 ; Error entry: The given file descriptor is not valid or not open invalidfd: lda #EBADF - jmp __directerrno ; Set _errno, clear _oserror, return -1 + jmp ___directerrno ; Set _errno, clear __oserror, return -1 .endproc diff --git a/libsrc/cbm/devicedir.s b/libsrc/cbm/devicedir.s index 3a4e6d774..1f2b2166c 100644 --- a/libsrc/cbm/devicedir.s +++ b/libsrc/cbm/devicedir.s @@ -32,7 +32,7 @@ jsr popa jsr diskinit beq size - jsr __mappederrno + jsr ___mappederrno bne fail ; Branch always ; Check for sufficient buf size @@ -43,7 +43,7 @@ size: lda ptr3+1 cmp #3 bcs okay ; Buf >= 3 lda # -void __fastcall__ _afailed (char* file, unsigned line) +void __fastcall__ __afailed (char* file, unsigned line) { raise (SIGABRT); fprintf (stderr, "ASSERTION FAILED IN %s:%u\n", file, line); diff --git a/libsrc/common/_directerrno.s b/libsrc/common/_directerrno.s index 794247148..20060bdd7 100644 --- a/libsrc/common/_directerrno.s +++ b/libsrc/common/_directerrno.s @@ -10,14 +10,14 @@ .macpack cpu ; ---------------------------------------------------------------------------- -; int __fastcall__ _directerrno (unsigned char code); -; /* Set errno to a specific error code, clear _oserror, and return -1. Used +; int __fastcall__ __directerrno (unsigned char code); +; /* Set errno to a specific error code, clear __oserror, and return -1. Used ; ** by the library. ; */ -__directerrno: - jsr __seterrno ; Set errno (returns with .A = 0) - sta __oserror ; Clear __oserror +___directerrno: + jsr ___seterrno ; Set errno (returns with .A = 0) + sta ___oserror ; Clear ___oserror .if (.cpu .bitand CPU_ISET_65SC02) dec a .else diff --git a/libsrc/common/_fopen.s b/libsrc/common/_fopen.s index 29f1c4cd9..17a1ec19b 100644 --- a/libsrc/common/_fopen.s +++ b/libsrc/common/_fopen.s @@ -69,7 +69,7 @@ invmode: lda #EINVAL - jsr __seterrno ; Set __errno, returns zero in A + jsr ___seterrno ; Set __errno, returns zero in A tax ; a/x = 0 jmp incsp4 @@ -91,7 +91,7 @@ modeok: ldy #$00 bne openok cmp #$FF bne openok - jmp return0 ; Failure, errno/_oserror already set + jmp return0 ; Failure, errno/__oserror already set ; Open call succeeded diff --git a/libsrc/common/_heap.s b/libsrc/common/_heap.s index 4ec8c80cd..eb680fa20 100644 --- a/libsrc/common/_heap.s +++ b/libsrc/common/_heap.s @@ -13,15 +13,15 @@ .data -__heaporg: +___heaporg: .word __BSS_RUN__+__BSS_SIZE__ ; Linker calculates this symbol -__heapptr: +___heapptr: .word __BSS_RUN__+__BSS_SIZE__ ; Dito -__heapend: +___heapend: .word __BSS_RUN__+__BSS_SIZE__ -__heapfirst: +___heapfirst: .word 0 -__heaplast: +___heaplast: .word 0 @@ -33,10 +33,10 @@ initheap: sec lda sp sbc #<__STACKSIZE__ - sta __heapend + sta ___heapend lda sp+1 sbc #>__STACKSIZE__ - sta __heapend+1 + sta ___heapend+1 rts diff --git a/libsrc/common/_heapadd.s b/libsrc/common/_heapadd.s index 14080cb5e..7695a732d 100644 --- a/libsrc/common/_heapadd.s +++ b/libsrc/common/_heapadd.s @@ -10,7 +10,7 @@ .importzp ptr1, ptr2 .import popax .import heapadd - .export __heapadd + .export ___heapadd .include "_heap.inc" @@ -19,7 +19,7 @@ ;----------------------------------------------------------------------------- ; Code -__heapadd: +___heapadd: sta ptr1 ; Store size in ptr1 stx ptr1+1 jsr popax ; Get the block pointer diff --git a/libsrc/common/_heapblocksize.s b/libsrc/common/_heapblocksize.s index db33f594c..e9b0cdad9 100644 --- a/libsrc/common/_heapblocksize.s +++ b/libsrc/common/_heapblocksize.s @@ -7,7 +7,7 @@ ; .importzp ptr1, ptr2 - .export __heapblocksize + .export ___heapblocksize .include "_heap.inc" @@ -17,7 +17,7 @@ ;----------------------------------------------------------------------------- ; Code -__heapblocksize: +___heapblocksize: ; Below the user data is a pointer that points to the start of the real ; (raw) memory block. The first word of this block is the size. To access diff --git a/libsrc/common/_heapmaxavail.s b/libsrc/common/_heapmaxavail.s index 19ae18b8d..b4e72f2d4 100644 --- a/libsrc/common/_heapmaxavail.s +++ b/libsrc/common/_heapmaxavail.s @@ -8,7 +8,7 @@ ; .importzp ptr1, ptr2 - .export __heapmaxavail + .export ___heapmaxavail .include "_heap.inc" @@ -17,22 +17,22 @@ ;----------------------------------------------------------------------------- ; Code -__heapmaxavail: +___heapmaxavail: ; size_t Size = (_heapend - _heapptr) * sizeof (*_heapend); - lda __heapend - sub __heapptr + lda ___heapend + sub ___heapptr sta ptr2 - lda __heapend+1 - sbc __heapptr+1 + lda ___heapend+1 + sbc ___heapptr+1 sta ptr2+1 ; struct freeblock* F = _heapfirst; - lda __heapfirst + lda ___heapfirst sta ptr1 - lda __heapfirst+1 + lda ___heapfirst+1 @L1: sta ptr1+1 ; while (F) { diff --git a/libsrc/common/_heapmemavail.s b/libsrc/common/_heapmemavail.s index 69aa75f8a..14ecc853a 100644 --- a/libsrc/common/_heapmemavail.s +++ b/libsrc/common/_heapmemavail.s @@ -8,7 +8,7 @@ ; .importzp ptr1, ptr2 - .export __heapmemavail + .export ___heapmemavail .include "_heap.inc" @@ -17,7 +17,7 @@ ;----------------------------------------------------------------------------- ; Code -__heapmemavail: +___heapmemavail: ; size_t Size = 0; @@ -27,9 +27,9 @@ __heapmemavail: ; struct freeblock* F = _heapfirst; - lda __heapfirst + lda ___heapfirst sta ptr1 - lda __heapfirst+1 + lda ___heapfirst+1 @L1: sta ptr1+1 ; while (F) { @@ -61,17 +61,17 @@ __heapmemavail: ; return Size + (_heapend - _heapptr) * sizeof (*_heapend); @L2: lda ptr2 - add __heapend + add ___heapend sta ptr2 lda ptr2+1 - adc __heapend+1 + adc ___heapend+1 tax lda ptr2 - sub __heapptr + sub ___heapptr sta ptr2 txa - sbc __heapptr+1 + sbc ___heapptr+1 tax lda ptr2 diff --git a/libsrc/common/_mappederrno.s b/libsrc/common/_mappederrno.s index 33f654c29..83565b723 100644 --- a/libsrc/common/_mappederrno.s +++ b/libsrc/common/_mappederrno.s @@ -11,19 +11,19 @@ .macpack cpu ; ---------------------------------------------------------------------------- -; int __fastcall__ _mappederrno (unsigned char code); -; /* Set _oserror to the given platform-specific error code. If it is a real +; int __fastcall__ __mappederrno (unsigned char code); +; /* Set __oserror to the given platform-specific error code. If it is a real ; ** error code (not zero), set errno to the corresponding system error code, ; ** and return -1. Otherwise, return zero. ; ** Used by the library. ; */ -__mappederrno: - sta __oserror ; Store the error code +___mappederrno: + sta ___oserror ; Store the error code tax ; Did we have an error? bze ok ; Branch if no - jsr __osmaperrno ; Map OS error into errno code - jsr __seterrno ; Save in errno (returns with .A = 0) + jsr ___osmaperrno ; Map OS error into errno code + jsr ___seterrno ; Save in errno (returns with .A = 0) .if (.cpu .bitand CPU_ISET_65SC02) dec a .else diff --git a/libsrc/common/_oserror.s b/libsrc/common/_oserror.s index 256d89658..bd8e40711 100644 --- a/libsrc/common/_oserror.s +++ b/libsrc/common/_oserror.s @@ -1,14 +1,14 @@ ; ; Ullrich von Bassewitz, 16.05.2000 ; -; extern unsigned char _oserror; +; extern unsigned char __oserror; ; /* Operating system specific errors from the low level functions */ - .export __oserror + .export ___oserror .bss -__oserror: +___oserror: .res 1 diff --git a/libsrc/common/_poserror.c b/libsrc/common/_poserror.c index 2777fee98..a2a67dd3e 100644 --- a/libsrc/common/_poserror.c +++ b/libsrc/common/_poserror.c @@ -39,10 +39,10 @@ -void __fastcall__ _poserror (const char* msg) +void __fastcall__ __poserror (const char* msg) { /* Fetch the message that corresponds to _oserror */ - const char* errormsg = _stroserror (_oserror); + const char* errormsg = __stroserror (_oserror); /* Different output depending on msg */ if (msg) { diff --git a/libsrc/common/_seterrno.s b/libsrc/common/_seterrno.s index 79021143a..4344a3302 100644 --- a/libsrc/common/_seterrno.s +++ b/libsrc/common/_seterrno.s @@ -1,7 +1,7 @@ ; ; Ullrich von Bassewitz, 2004-05-13 ; -; __seterrno: Will set __errno to the value in A and return zero in A. Other +; ___seterrno: Will set ___errno to the value in A and return zero in A. Other ; registers aren't changed. The function is C callable, but ; currently only called from asm code. ; @@ -10,11 +10,11 @@ .code -.proc __seterrno +.proc ___seterrno - sta __errno + sta ___errno lda #0 - sta __errno+1 + sta ___errno+1 rts .endproc diff --git a/libsrc/common/_swap.s b/libsrc/common/_swap.s index 9ad771de1..ba3e5922d 100644 --- a/libsrc/common/_swap.s +++ b/libsrc/common/_swap.s @@ -1,15 +1,15 @@ ; ; Ullrich von Bassewitz, 1998-12-09, 2004-11-30 ; -; void __fastcall__ _swap (void* p, void* q, size_t size); +; void __fastcall__ __swap (void* p, void* q, size_t size); ; - .export __swap + .export ___swap .import popax, popptr1 .importzp ptr1, ptr2, ptr3 -__swap: eor #$FF +___swap: eor #$FF sta ptr3 txa eor #$FF diff --git a/libsrc/common/atexit.s b/libsrc/common/atexit.s index 6edfd4a5d..47a1dfd4d 100644 --- a/libsrc/common/atexit.s +++ b/libsrc/common/atexit.s @@ -38,7 +38,7 @@ ; Error, no space left @Error: lda #ENOSPC ; No space left - jsr __seterrno + jsr ___seterrno ldx #$FF ; Return -1 txa rts diff --git a/libsrc/common/calloc.s b/libsrc/common/calloc.s index 6e3e1bd3f..4cb701146 100644 --- a/libsrc/common/calloc.s +++ b/libsrc/common/calloc.s @@ -7,7 +7,7 @@ ; .export _calloc - .import _malloc, __bzero + .import _malloc, ___bzero .import tosumulax, pushax @@ -48,7 +48,7 @@ ClearBlock: jsr pushax ; ptr lda Size ldx Size+1 ; Size - jmp __bzero + jmp ___bzero .endproc diff --git a/libsrc/common/chdir.s b/libsrc/common/chdir.s index 3e638cb04..1f10a6804 100644 --- a/libsrc/common/chdir.s +++ b/libsrc/common/chdir.s @@ -7,7 +7,7 @@ .export _chdir .import __syschdir - .import __mappederrno + .import ___mappederrno ;-------------------------------------------------------------------------- @@ -17,7 +17,7 @@ .proc _chdir jsr __syschdir ; Call the machine specific function - jmp __mappederrno ; Store into _oserror, set errno, return 0/-1 + jmp ___mappederrno ; Store into __oserror, set errno, return 0/-1 .endproc diff --git a/libsrc/common/errno.s b/libsrc/common/errno.s index f448c3c14..43bbe3fb0 100644 --- a/libsrc/common/errno.s +++ b/libsrc/common/errno.s @@ -2,7 +2,7 @@ ; 2003-08-12, Ullrich von Bassewitz ; 2015-09-24, Greg King ; -; extern int _errno; +; extern int __errno; ; /* Library errors go here. */ ; @@ -10,5 +10,5 @@ .bss -__errno: +___errno: .word 0 diff --git a/libsrc/common/fclose.s b/libsrc/common/fclose.s index 5365d70da..2368bf9f6 100644 --- a/libsrc/common/fclose.s +++ b/libsrc/common/fclose.s @@ -31,7 +31,7 @@ ; File is not open lda #EINVAL - jsr __seterrno + jsr ___seterrno lda #$FF ; Return -1 tax rts diff --git a/libsrc/common/fmisc.s b/libsrc/common/fmisc.s index 156a80dbc..90b48e8a6 100644 --- a/libsrc/common/fmisc.s +++ b/libsrc/common/fmisc.s @@ -78,7 +78,7 @@ err: rts ; If the file is not valid, fileno must set errno and return -1 error: lda #prev field lda (ptr1),y sta ptr2+1 ; Remember f->prev in ptr2 - sta __heaplast+1 + sta ___heaplast+1 dey lda (ptr1),y sta ptr2 ; Remember f->prev in ptr2 - sta __heaplast - ora __heaplast+1 ; -> prev == 0? + sta ___heaplast + ora ___heaplast+1 ; -> prev == 0? bne @L8 ; Jump if free list not empty ; Free list is now empty (A = 0) - sta __heapfirst - sta __heapfirst+1 + sta ___heapfirst + sta ___heapfirst+1 ; Done @@ -283,9 +283,9 @@ _free: sta ptr2 ; Check if the free list is empty, storing _hfirst into ptr3 for later heapadd: - lda __heapfirst + lda ___heapfirst sta ptr3 - lda __heapfirst+1 + lda ___heapfirst+1 sta ptr3+1 ora ptr3 bne SearchFreeList @@ -301,10 +301,10 @@ heapadd: lda ptr2 ldx ptr2+1 - sta __heapfirst - stx __heapfirst+1 ; _heapfirst = f; - sta __heaplast - stx __heaplast+1 ; _heaplast = f; + sta ___heapfirst + stx ___heapfirst+1 ; _heapfirst = f; + sta ___heaplast + stx ___heaplast+1 ; _heaplast = f; rts ; Done @@ -351,9 +351,9 @@ SearchFreeList: sta (ptr2),y ; Clear low byte of f->next lda ptr2 ; _heaplast = f; - sta __heaplast + sta ___heaplast lda ptr2+1 - sta __heaplast+1 + sta ___heaplast+1 ; Since we have checked the case that the freelist is empty before, if the ; right pointer is NULL, the left *cannot* be NULL here. So skip the @@ -414,9 +414,9 @@ CheckRightMerge: ; f->next is zero, this is now the last block @L1: lda ptr2 ; _heaplast = f; - sta __heaplast + sta ___heaplast lda ptr2+1 - sta __heaplast+1 + sta ___heaplast+1 jmp CheckLeftMerge ; No right merge, just set the link. @@ -451,9 +451,9 @@ CheckLeftMerge: sta (ptr2),y lda ptr2 ; _heapfirst = f; - sta __heapfirst + sta ___heapfirst lda ptr2+1 - sta __heapfirst+1 + sta ___heapfirst+1 rts ; Done @@ -510,9 +510,9 @@ CheckLeftMerge2: ; This is now the last block, do _heaplast = left @L1: lda ptr4 - sta __heaplast + sta ___heaplast lda ptr4+1 - sta __heaplast+1 + sta ___heaplast+1 rts ; Done ; No merge of the left block, just set the link. Y points to size+1 if diff --git a/libsrc/common/fwrite.s b/libsrc/common/fwrite.s index b0fa7ec42..861feb120 100644 --- a/libsrc/common/fwrite.s +++ b/libsrc/common/fwrite.s @@ -39,7 +39,7 @@ ; File not open @L1: lda #EBADF - jsr __seterrno ; Returns with A = 0 + jsr ___seterrno ; Returns with A = 0 tax ; A = X = 0 jmp incsp6 diff --git a/libsrc/common/getcwd.s b/libsrc/common/getcwd.s index 9b856ea7c..5fc0bbf0a 100644 --- a/libsrc/common/getcwd.s +++ b/libsrc/common/getcwd.s @@ -51,7 +51,7 @@ loop: dec ptr2 overflow: lda #next @L1: lda (ptr2),y ; Load high byte of f->next - sta __heapfirst+1 + sta ___heapfirst+1 dey ; Points to next lda (ptr2),y ; Load low byte of f->next - sta __heapfirst + sta ___heapfirst ; Check f->next. Y points always to next if we come here @@ -275,10 +275,10 @@ BlockFound: ; Do _hlast = f->prev @L3: lda (ptr2),y ; Load low byte of f->prev - sta __heaplast + sta ___heaplast iny ; Points to prev+1 lda (ptr2),y ; Load high byte of f->prev - sta __heaplast+1 + sta ___heaplast+1 jmp RetUserPtr ; Done ; We must slice the block found. Cut off space from the upper end, so we diff --git a/libsrc/common/memset.s b/libsrc/common/memset.s index a57a90e5c..be78fc30d 100644 --- a/libsrc/common/memset.s +++ b/libsrc/common/memset.s @@ -1,6 +1,6 @@ ; ; void* __fastcall__ memset (void* ptr, int c, size_t n); -; void* __fastcall__ _bzero (void* ptr, size_t n); +; void* __fastcall__ __bzero (void* ptr, size_t n); ; void __fastcall__ bzero (void* ptr, size_t n); ; ; Ullrich von Bassewitz, 29.05.1998 @@ -8,19 +8,19 @@ ; Christian Krueger, 12.09.2009, slightly improved 12.01.2011 ; ; NOTE: bzero will return it's first argument as memset does. It is no problem -; to declare the return value as void, since it may be ignored. _bzero -; (note the leading underscore) is declared with the proper return type, -; because the compiler will replace memset by _bzero if the fill value +; to declare the return value as void, since it may be ignored. __bzero +; (note the leading underscores) is declared with the proper return type, +; because the compiler will replace memset by __bzero if the fill value ; is zero, and the optimizer looks at the return type to see if the value ; in a/x is of any use. ; - .export _memset, _bzero, __bzero + .export _memset, _bzero, ___bzero .import popax .importzp sp, ptr1, ptr2, ptr3 _bzero: -__bzero: +___bzero: sta ptr3 stx ptr3+1 ; Save n ldx #0 ; Fill with zeros diff --git a/libsrc/common/mkdir.s b/libsrc/common/mkdir.s index 1144983aa..1a5c7551f 100644 --- a/libsrc/common/mkdir.s +++ b/libsrc/common/mkdir.s @@ -7,7 +7,7 @@ .export _mkdir .import __sysmkdir - .import __mappederrno + .import ___mappederrno ;-------------------------------------------------------------------------- @@ -15,6 +15,6 @@ .proc _mkdir jsr __sysmkdir ; Call the machine specific function - jmp __mappederrno ; Store into _oserror, set errno, return 0/-1 + jmp ___mappederrno ; Store into __oserror, set errno, return 0/-1 .endproc diff --git a/libsrc/common/perror.c b/libsrc/common/perror.c index ddc015c1e..9b0dac7de 100644 --- a/libsrc/common/perror.c +++ b/libsrc/common/perror.c @@ -42,7 +42,7 @@ void __fastcall__ perror (const char* msg) { /* Fetch the message that corresponds to errno */ - const char* errormsg = strerror (_errno); + const char* errormsg = strerror (__errno); /* Different output depending on msg */ if (msg) { diff --git a/libsrc/common/putenv.s b/libsrc/common/putenv.s index c68d20a32..5febcc71e 100644 --- a/libsrc/common/putenv.s +++ b/libsrc/common/putenv.s @@ -169,7 +169,7 @@ addentry: ; Error entries nomem: lda #ENOMEM -error: jsr __seterrno +error: jsr ___seterrno lda #$FF ; Return -1 tax rts diff --git a/libsrc/common/qsort.c b/libsrc/common/qsort.c index 991db3ba1..913165814 100644 --- a/libsrc/common/qsort.c +++ b/libsrc/common/qsort.c @@ -32,13 +32,13 @@ static void QuickSort (register unsigned char* Base, int Lo, int Hi, J -= Size; } if (I <= J) { - _swap (Base + I, Base + J, Size); + __swap (Base + I, Base + J, Size); I += Size; J -= Size; } } if (J != Lo) { - _swap (Base + J, Base + Lo, Size); + __swap (Base + J, Base + Lo, Size); } if (((unsigned) J) * 2 > (Hi + Lo)) { QuickSort (Base, J + Size, Hi, Size, Compare); diff --git a/libsrc/common/raise.s b/libsrc/common/raise.s index 07898ef90..205bbd471 100644 --- a/libsrc/common/raise.s +++ b/libsrc/common/raise.s @@ -33,9 +33,9 @@ _raise: ; introduce race conditions, but it's the simplest way to satisfy the ; standard). - lda #<__sig_dfl + lda #<___sig_dfl sta sigtable,x - lda #>__sig_dfl + lda #>___sig_dfl sta sigtable+1,x ; Restore the signal number and call the function diff --git a/libsrc/common/realloc.c b/libsrc/common/realloc.c index c47dbbb98..eeb1eeea5 100644 --- a/libsrc/common/realloc.c +++ b/libsrc/common/realloc.c @@ -74,12 +74,12 @@ void* __fastcall__ realloc (void* block, register size_t size) oldsize = b->size; /* Is the block at the current heap top? */ - if (((unsigned) b) + oldsize == ((unsigned) _heapptr)) { + if (((unsigned) b) + oldsize == ((unsigned) __heapptr)) { /* Check if we've enough memory at the heap top */ - newhptr = ((unsigned) _heapptr) - oldsize + size; - if (newhptr <= ((unsigned) _heapend)) { + newhptr = ((unsigned) __heapptr) - oldsize + size; + if (newhptr <= ((unsigned) __heapend)) { /* Ok, there's space enough */ - _heapptr = (unsigned*) newhptr; + __heapptr = (unsigned*) newhptr; b->size = size; b->start = b; return block; diff --git a/libsrc/common/remove.s b/libsrc/common/remove.s index e66f047ef..1b8515870 100644 --- a/libsrc/common/remove.s +++ b/libsrc/common/remove.s @@ -7,7 +7,7 @@ .export _remove .import __sysremove - .import __mappederrno + .import ___mappederrno ;-------------------------------------------------------------------------- @@ -15,7 +15,7 @@ .proc _remove jsr __sysremove ; Call the machine specific function - jmp __mappederrno ; Store into _oserror, set errno, return 0/-1 + jmp ___mappederrno ; Store into __oserror, set errno, return 0/-1 .endproc diff --git a/libsrc/common/rename.s b/libsrc/common/rename.s index 0fbffa426..122ae1501 100644 --- a/libsrc/common/rename.s +++ b/libsrc/common/rename.s @@ -7,7 +7,7 @@ .export _rename .import __sysrename - .import __mappederrno + .import ___mappederrno ;-------------------------------------------------------------------------- @@ -15,7 +15,7 @@ .proc _rename jsr __sysrename ; Call the machine specific function - jmp __mappederrno ; Store into _oserror, set errno, return 0/-1 + jmp ___mappederrno ; Store into __oserror, set errno, return 0/-1 .endproc diff --git a/libsrc/common/rmdir.s b/libsrc/common/rmdir.s index 84ae9a54c..ea0780387 100644 --- a/libsrc/common/rmdir.s +++ b/libsrc/common/rmdir.s @@ -7,7 +7,7 @@ .export _rmdir .import __sysrmdir - .import __mappederrno + .import ___mappederrno ;-------------------------------------------------------------------------- @@ -15,6 +15,6 @@ .proc _rmdir jsr __sysrmdir ; Call the machine specific function - jmp __mappederrno ; Store into _oserror, set errno, return 0/-1 + jmp ___mappederrno ; Store into __oserror, set errno, return 0/-1 .endproc diff --git a/libsrc/common/setjmp.s b/libsrc/common/setjmp.s index a763ac3ec..886853368 100644 --- a/libsrc/common/setjmp.s +++ b/libsrc/common/setjmp.s @@ -2,15 +2,15 @@ ; 1998-06-06, Ullrich von Bassewitz ; 2015-09-11, Greg King ; -; int __fastcall__ setjmp (jmp_buf buf); +; int __fastcall__ __setjmp (jmp_buf buf); ; - .export __setjmp + .export ___setjmp .import return0 .importzp sp, ptr1 -__setjmp: +___setjmp: sta ptr1 ; Save buf stx ptr1+1 ldy #0 diff --git a/libsrc/common/signal.s b/libsrc/common/signal.s index 333072801..65d0316b4 100644 --- a/libsrc/common/signal.s +++ b/libsrc/common/signal.s @@ -54,15 +54,15 @@ _signal: pla tax pla -__sig_ign: +___sig_ign: rts ; Error entry: We use our knowledge that SIG_ERR is zero here to save a byte invalidsig: lda #EINVAL ; = 0 - sta __errno+1 + sta ___errno+1 ; lda #$00 ; A contains zero: "Unknown error" ; Load the pointer to the error message and return diff --git a/libsrc/common/stroserr.s b/libsrc/common/stroserr.s index 25ca30daf..ae8e117f1 100644 --- a/libsrc/common/stroserr.s +++ b/libsrc/common/stroserr.s @@ -1,11 +1,11 @@ ; ; Ullrich von Bassewitz, 17.07.2002 ; -; const char* __fastcall__ _stroserror (unsigned char errcode); +; const char* __fastcall__ __stroserror (unsigned char errcode); ; /* Map an operating system error number to an error message. */ ; - .export __stroserror + .export ___stroserror .import __sys_oserrlist .importzp ptr1, tmp1 @@ -21,7 +21,7 @@ ; and terminated by an entry with length zero that is returned if the ; error code could not be found. -__stroserror: +___stroserror: sta tmp1 ; Save the error code ldy #<__sys_oserrlist diff --git a/libsrc/common/uname.s b/libsrc/common/uname.s index 3c1b0840f..3f2a8ff14 100644 --- a/libsrc/common/uname.s +++ b/libsrc/common/uname.s @@ -7,7 +7,7 @@ .export _uname .import __sysuname - .import __mappederrno + .import ___mappederrno ;-------------------------------------------------------------------------- @@ -15,7 +15,7 @@ .proc _uname jsr __sysuname ; Call the machine specific function - jmp __mappederrno ; Store into _oserror, set errno, return 0/-1 + jmp ___mappederrno ; Store into __oserror, set errno, return 0/-1 .endproc diff --git a/libsrc/common/ungetc.s b/libsrc/common/ungetc.s index 88595068c..7e8c1f94f 100644 --- a/libsrc/common/ungetc.s +++ b/libsrc/common/ungetc.s @@ -62,7 +62,7 @@ ; File is not open or the character is invalid error: lda #EINVAL - jsr __seterrno + jsr ___seterrno lda #$FF ; Return -1 tax rts diff --git a/libsrc/common/vsnprintf.s b/libsrc/common/vsnprintf.s index 228e531d0..048a756c3 100644 --- a/libsrc/common/vsnprintf.s +++ b/libsrc/common/vsnprintf.s @@ -140,7 +140,7 @@ L0: ldy #EINVAL pla ; Drop ap pla tya - jsr __directerrno ; Return -1 + jsr ___directerrno ; Return -1 jmp incsp6 ; Drop parameters diff --git a/libsrc/cx16/randomize.s b/libsrc/cx16/randomize.s index 3d965c82a..49051e012 100644 --- a/libsrc/cx16/randomize.s +++ b/libsrc/cx16/randomize.s @@ -1,14 +1,14 @@ ; ; 2020-05-02, Greg King ; -; void _randomize (void); +; void __randomize (void); ; /* Initialize the random number generator */ ; - .export __randomize + .export ___randomize .import ENTROPY_GET, _srand -__randomize: +___randomize: jsr ENTROPY_GET jmp _srand ; Initialize generator diff --git a/libsrc/geos-cbm/disk/dio_cts.s b/libsrc/geos-cbm/disk/dio_cts.s index 478181b69..81b189f65 100644 --- a/libsrc/geos-cbm/disk/dio_cts.s +++ b/libsrc/geos-cbm/disk/dio_cts.s @@ -10,7 +10,7 @@ .export _dio_phys_to_log .export sectab_1541_l, sectab_1541_h ; for log_to_phys - .import popax,__oserror + .import popax,___oserror .importzp ptr1,ptr2,ptr3,tmp1,tmp2,tmp3,tmp4 .include "dio.inc" @@ -82,7 +82,7 @@ dio_ctsend: ldx #0 txa ret: - sta __oserror + sta ___oserror rts ; return success ; errors diff --git a/libsrc/geos-cbm/disk/dio_openclose.s b/libsrc/geos-cbm/disk/dio_openclose.s index 327503017..953aed318 100644 --- a/libsrc/geos-cbm/disk/dio_openclose.s +++ b/libsrc/geos-cbm/disk/dio_openclose.s @@ -11,7 +11,7 @@ ; dio_close does nothing special .export _dio_open, _dio_close - .import __oserror, _OpenDisk + .import ___oserror, _OpenDisk .importzp ptr1, tmp1 .include "dio.inc" @@ -69,7 +69,7 @@ _dio_open: _inv_drive: lda #DEV_NOT_FOUND - sta __oserror + sta ___oserror lda #0 tax rts @@ -80,6 +80,6 @@ _dio_close: lda #0 ldy #sst_flag sta (ptr1),y - sta __oserror ; success + sta ___oserror ; success tax rts ; return no error diff --git a/libsrc/geos-cbm/disk/dio_qcount.s b/libsrc/geos-cbm/disk/dio_qcount.s index 5f10ac247..b5d380825 100644 --- a/libsrc/geos-cbm/disk/dio_qcount.s +++ b/libsrc/geos-cbm/disk/dio_qcount.s @@ -5,11 +5,11 @@ ; .export _dio_query_sectcount - .import __oserror + .import ___oserror _dio_query_sectcount: lda #0 - sta __oserror + sta ___oserror lda #<683 ldx #>683 rts diff --git a/libsrc/geos-cbm/disk/dio_qsize.s b/libsrc/geos-cbm/disk/dio_qsize.s index bf9178035..14c8a460a 100644 --- a/libsrc/geos-cbm/disk/dio_qsize.s +++ b/libsrc/geos-cbm/disk/dio_qsize.s @@ -5,10 +5,10 @@ ; .export _dio_query_sectsize - .import __oserror + .import ___oserror _dio_query_sectsize: lda #<256 ldx #>256 - sta __oserror + sta ___oserror rts diff --git a/libsrc/geos-cbm/disk/dio_read.s b/libsrc/geos-cbm/disk/dio_read.s index ac19f9afa..4c9297e65 100644 --- a/libsrc/geos-cbm/disk/dio_read.s +++ b/libsrc/geos-cbm/disk/dio_read.s @@ -8,7 +8,7 @@ ; .export _dio_read - .import dio_params, __oserror + .import dio_params, ___oserror .include "geossym.inc" .include "jumptab.inc" @@ -18,6 +18,6 @@ _dio_read: tay bne err jsr ReadBlock - stx __oserror + stx ___oserror txa err: rts diff --git a/libsrc/geos-cbm/disk/dio_stc.s b/libsrc/geos-cbm/disk/dio_stc.s index 469df93ca..3c3c9108f 100644 --- a/libsrc/geos-cbm/disk/dio_stc.s +++ b/libsrc/geos-cbm/disk/dio_stc.s @@ -9,7 +9,7 @@ .export _dio_log_to_phys .importzp ptr1,ptr2,ptr3,tmp1,tmp2 - .import popax,__oserror + .import popax,___oserror .import sectab_1541_l, sectab_1541_h .include "dio.inc" @@ -78,7 +78,7 @@ dio_stcend: ldx #0 txa _ret: - sta __oserror + sta ___oserror rts ; return success ; errors diff --git a/libsrc/geos-cbm/disk/dio_writev.s b/libsrc/geos-cbm/disk/dio_writev.s index 9b36ed096..962d7e77f 100644 --- a/libsrc/geos-cbm/disk/dio_writev.s +++ b/libsrc/geos-cbm/disk/dio_writev.s @@ -8,7 +8,7 @@ ; .export _dio_write_verify - .import dio_params, __oserror + .import dio_params, ___oserror .include "geossym.inc" .include "jumptab.inc" @@ -18,6 +18,6 @@ _dio_write_verify: tay bne err jsr VerWriteBlock - stx __oserror + stx ___oserror txa err: rts diff --git a/libsrc/geos-common/common/_afailed.c b/libsrc/geos-common/common/_afailed.c index 97727d605..acc437fb0 100644 --- a/libsrc/geos-common/common/_afailed.c +++ b/libsrc/geos-common/common/_afailed.c @@ -8,7 +8,7 @@ #include #include -void _afailed (char* file, unsigned line) +void __afailed (char* file, unsigned line) { ExitTurbo(); diff --git a/libsrc/geos-common/common/_poserror.c b/libsrc/geos-common/common/_poserror.c index eeb3f368e..b47f0a7d9 100644 --- a/libsrc/geos-common/common/_poserror.c +++ b/libsrc/geos-common/common/_poserror.c @@ -9,9 +9,9 @@ #include #include -void __fastcall__ _poserror (const char* msg) +void __fastcall__ __poserror (const char* msg) { - const char *errmsg = _stroserror(_oserror); + const char *errmsg = __stroserror(_oserror); ExitTurbo(); if (msg && *msg) { diff --git a/libsrc/geos-common/common/memset.s b/libsrc/geos-common/common/memset.s index 2cb6732d1..82b7f4a87 100644 --- a/libsrc/geos-common/common/memset.s +++ b/libsrc/geos-common/common/memset.s @@ -1,14 +1,14 @@ ; ; void* memset (void* ptr, int c, size_t n); -; void* _bzero (void* ptr, size_t n); +; void* __bzero (void* ptr, size_t n); ; void bzero (void* ptr, size_t n); ; ; Maciej 'YTM/Elysium' Witkowiak, 20.08.2003 ; - .export _memset, _bzero, __bzero + .export _memset, _bzero, ___bzero .import _ClearRam, _FillRam _bzero = _ClearRam -__bzero = _ClearRam +___bzero = _ClearRam _memset = _FillRam diff --git a/libsrc/geos-common/disk/calcblksfree.s b/libsrc/geos-common/disk/calcblksfree.s index 7e1bb4f52..fec6d6690 100644 --- a/libsrc/geos-common/disk/calcblksfree.s +++ b/libsrc/geos-common/disk/calcblksfree.s @@ -5,7 +5,7 @@ ; int CalcBlksFree (void); - .import __oserror + .import ___oserror .export _CalcBlksFree .include "jumptab.inc" @@ -18,7 +18,7 @@ _CalcBlksFree: sta r5L stx r5H jsr CalcBlksFree - stx __oserror + stx ___oserror lda r4L ldx r4H rts diff --git a/libsrc/geos-common/disk/getptrcurdknm.s b/libsrc/geos-common/disk/getptrcurdknm.s index d92e5d91e..9112c9f99 100644 --- a/libsrc/geos-common/disk/getptrcurdknm.s +++ b/libsrc/geos-common/disk/getptrcurdknm.s @@ -7,7 +7,7 @@ ; (fills curName[17] with current disk's name) .importzp ptr4, ptr3 - .import __oserror + .import ___oserror .export _GetPtrCurDkNm .include "jumptab.inc" @@ -34,5 +34,5 @@ namelp: lda (ptr4),y bne namelp fin: lda #0 sta (ptr3),y - stx __oserror + stx ___oserror rts diff --git a/libsrc/geos-common/disk/setnextfree.s b/libsrc/geos-common/disk/setnextfree.s index b24f16f6f..2d43c1e36 100644 --- a/libsrc/geos-common/disk/setnextfree.s +++ b/libsrc/geos-common/disk/setnextfree.s @@ -5,7 +5,7 @@ ; struct tr_se SetNextFree (struct tr_se *startTS); - .import __oserror + .import ___oserror .import gettrse .export _SetNextFree @@ -18,7 +18,7 @@ _SetNextFree: sta r3L stx r3H jsr SetNextFree - stx __oserror + stx ___oserror lda r3L ldx r3H rts diff --git a/libsrc/geos-common/drivers/fio_module.s b/libsrc/geos-common/drivers/fio_module.s index 1314fc4c5..affbf6ecc 100644 --- a/libsrc/geos-common/drivers/fio_module.s +++ b/libsrc/geos-common/drivers/fio_module.s @@ -14,7 +14,7 @@ FILEDES = 3 ; first free to use file descriptor .importzp ptr1, ptr2, ptr3, tmp1 .import addysp, popax, popptr1 - .import __oserror + .import ___oserror .import _FindFile, _ReadByte .export _open, _close, _read @@ -65,8 +65,8 @@ _open: stx f_offset stx f_offset+1 lda #0 ; clear errors - sta __oserror - jsr __seterrno + sta ___oserror + jsr ___seterrno lda #FILEDES ; return fd sta filedesc rts @@ -75,14 +75,14 @@ _open: .byte $2c ; skip @alreadyopen: lda #EMFILE ; too many opened files (there can be only one) - jmp __directerrno ; set errno, clear oserror, return -1 + jmp ___directerrno ; set errno, clear oserror, return -1 @oserror: - jmp __mappederrno ; set platform error code, return -1 + jmp ___mappederrno ; set platform error code, return -1 _close: lda #0 - sta __oserror - jsr __seterrno ; clear errors + sta ___oserror + jsr ___seterrno ; clear errors lda #0 ; clear fd sta filedesc tax @@ -92,7 +92,7 @@ _read: ; a/x - number of bytes ; popax - buffer ptr ; popax - fd, must be == to the above one - ; return -1+__oserror or number of bytes read + ; return -1+___oserror or number of bytes read inx stx ptr1+1 @@ -111,14 +111,14 @@ _read: @filenotopen: lda #EBADF - jmp __directerrno ; Sets _errno, clears _oserror, returns -1 + jmp ___directerrno ; Sets _errno, clears __oserror, returns -1 @fileok: lda #0 sta ptr3 sta ptr3+1 ; put 0 into ptr3 (number of bytes read) - sta __oserror ; clear error flags - jsr __seterrno + sta ___oserror ; clear error flags + jsr ___seterrno lda f_track ; restore stuff for ReadByte ldx f_sector @@ -147,11 +147,11 @@ _read: bne @L2 inc ptr3+1 -@L2: lda __oserror ; was there error ? +@L2: lda ___oserror ; was there error ? beq @L3 cmp #BFR_OVERFLOW ; EOF? beq @done ; yes, we're done - jmp __mappederrno ; no, we're screwed + jmp ___mappederrno ; no, we're screwed @L3: dec ptr1 ; decrement the count bne @L0 diff --git a/libsrc/geos-common/file/get1stdirentry.s b/libsrc/geos-common/file/get1stdirentry.s index f0ad59388..2217718ea 100644 --- a/libsrc/geos-common/file/get1stdirentry.s +++ b/libsrc/geos-common/file/get1stdirentry.s @@ -5,7 +5,7 @@ ; struct filehandle* Get1stDirEntry (void); - .import __oserror, return0 + .import ___oserror, return0 .export _Get1stDirEntry .include "diskdrv.inc" @@ -13,7 +13,7 @@ _Get1stDirEntry: jsr Get1stDirEntry - stx __oserror + stx ___oserror txa bne L1 ; jump if disk error lda r5L diff --git a/libsrc/geos-common/file/getnxtdirentry.s b/libsrc/geos-common/file/getnxtdirentry.s index e8ccbf3a2..0f74a0ed8 100644 --- a/libsrc/geos-common/file/getnxtdirentry.s +++ b/libsrc/geos-common/file/getnxtdirentry.s @@ -5,7 +5,7 @@ ; struct filehandle* GetNxtDirEntry (void); - .import __oserror, return0 + .import ___oserror, return0 .export _GetNxtDirEntry .include "diskdrv.inc" @@ -13,7 +13,7 @@ _GetNxtDirEntry: jsr GetNxtDirEntry - stx __oserror + stx ___oserror txa bne L1 ; jump if disk error tya diff --git a/libsrc/geos-common/file/readbyte.s b/libsrc/geos-common/file/readbyte.s index 9a24e68df..90616a426 100644 --- a/libsrc/geos-common/file/readbyte.s +++ b/libsrc/geos-common/file/readbyte.s @@ -5,13 +5,13 @@ ; char ReadByte (void); - .import __oserror + .import ___oserror .export _ReadByte .include "jumptab.inc" _ReadByte: jsr ReadByte - stx __oserror + stx ___oserror ldx #0 rts diff --git a/libsrc/geos-common/system/oserror.s b/libsrc/geos-common/system/oserror.s index f0915fd5b..fa45f3e14 100644 --- a/libsrc/geos-common/system/oserror.s +++ b/libsrc/geos-common/system/oserror.s @@ -3,16 +3,16 @@ ; GEOS port: Maciej 'YTM/Elysium' Witkowiak ; 2.7.2001 ; -; int __fastcall__ _osmaperrno (unsigned char oserror); +; int __fastcall__ __osmaperrno (unsigned char oserror); ; /* Map a system specific error into a system independent code */ ; - .export __osmaperrno + .export ___osmaperrno .include "errno.inc" .include "const.inc" -__osmaperrno: +___osmaperrno: ldx #ErrTabSize @L1: cmp ErrTab-2,x ; Search for the error code beq @L2 ; Jump if found diff --git a/libsrc/geos-common/system/randomize.s b/libsrc/geos-common/system/randomize.s index 67c217d80..d8f821356 100644 --- a/libsrc/geos-common/system/randomize.s +++ b/libsrc/geos-common/system/randomize.s @@ -1,16 +1,16 @@ ; ; Ullrich von Bassewitz, 05.11.2002 ; -; void _randomize (void); +; void __randomize (void); ; /* Initialize the random number generator */ ; - .export __randomize + .export ___randomize .import _srand .include "geossym.inc" -__randomize: +___randomize: lda random ; get random value from internal generator ldx random+1 jmp _srand ; and use it as seed diff --git a/libsrc/geos-common/system/setoserror.s b/libsrc/geos-common/system/setoserror.s index adc6ad017..6fb89e96e 100644 --- a/libsrc/geos-common/system/setoserror.s +++ b/libsrc/geos-common/system/setoserror.s @@ -5,10 +5,10 @@ ; .export setoserror - .import __oserror + .import ___oserror setoserror: - stx __oserror + stx ___oserror txa ldx #0 ; X is cleared (high byte for promoting char to int) tay ; Y register is used just to save flags state diff --git a/libsrc/lynx/clock.s b/libsrc/lynx/clock.s index e29799df6..d881e5a67 100644 --- a/libsrc/lynx/clock.s +++ b/libsrc/lynx/clock.s @@ -3,13 +3,13 @@ ; 2012-02-06, Greg King ; ; clock_t clock (void); -; clock_t _clocks_per_sec (void); +; clock_t __clocks_per_sec (void); ; ; clocks_per_sec()'s test-values are based on the numbers in "set_tv.s". ; If you change the numbers there, then change them here, too. ; - .export _clock, __clocks_per_sec, clock_count + .export _clock, ___clocks_per_sec, clock_count .interruptor update_clock, 2 ; (low priority) .constructor init_clock @@ -38,7 +38,7 @@ ;----------------------------------------------------------------------------- ; Return the number of clock ticks in one second. ; -__clocks_per_sec: +___clocks_per_sec: ldx #$00 ; >50, >60, >75 ldy PBKUP lda #<75 diff --git a/libsrc/lynx/open.s b/libsrc/lynx/open.s index c48b8eb95..032f55a99 100644 --- a/libsrc/lynx/open.s +++ b/libsrc/lynx/open.s @@ -66,7 +66,7 @@ parmok: jsr popax beq flagsok jsr popax lda #EINVAL - jmp __directerrno + jmp ___directerrno flagsok: jsr popax @@ -74,7 +74,7 @@ flagsok: jsr _openn ldx #$00 lda #$01 - stx __oserror + stx ___oserror rts .endproc diff --git a/libsrc/lynx/oserror.s b/libsrc/lynx/oserror.s index 5570a3bb7..b2ccbf4f0 100644 --- a/libsrc/lynx/oserror.s +++ b/libsrc/lynx/oserror.s @@ -1,7 +1,7 @@ ; ; Karri Kaksonen, 2010 ; -; int __fastcall__ _osmaperrno (unsigned char oserror); +; int __fastcall__ __osmaperrno (unsigned char oserror); ; /* Map a system specific error into a system independent code */ ; @@ -9,6 +9,6 @@ .code -__osmaperrno: +___osmaperrno: rts diff --git a/libsrc/lynx/ser_stat_stddrv.s b/libsrc/lynx/ser_stat_stddrv.s new file mode 100644 index 000000000..37f481c47 --- /dev/null +++ b/libsrc/lynx/ser_stat_stddrv.s @@ -0,0 +1,14 @@ +; +; Address of the static standard serial driver +; +; Oliver Schmidt, 2022-12-22 +; +; const void ser_static_stddrv[]; +; + + .export _ser_static_stddrv + .import _lynx_comlynx_ser + +.rodata + +_ser_static_stddrv := _lynx_comlynx_ser diff --git a/libsrc/nes/randomize.s b/libsrc/nes/randomize.s index 8df4fb88a..a146fef1b 100644 --- a/libsrc/nes/randomize.s +++ b/libsrc/nes/randomize.s @@ -1,16 +1,16 @@ ; ; Ullrich von Bassewitz, 2003-05-02 ; -; void _randomize (void); +; void __randomize (void); ; /* Initialize the random number generator */ ; - .export __randomize + .export ___randomize .import _srand .include "nes.inc" -__randomize: +___randomize: ldx tickcount ; Use tick clock lda tickcount+1 jmp _srand ; Initialize generator diff --git a/libsrc/osic1p/oserror.s b/libsrc/osic1p/oserror.s index 073691a06..380c5ebb9 100644 --- a/libsrc/osic1p/oserror.s +++ b/libsrc/osic1p/oserror.s @@ -4,14 +4,14 @@ ; original by ; Stefan Haubenthal, 2011-04-18 ; -; int __fastcall__ _osmaperrno (unsigned char oserror); +; int __fastcall__ __osmaperrno (unsigned char oserror); ; /* Map a system specific error into a system independent code */ ; .include "errno.inc" - .export __osmaperrno + .export ___osmaperrno -.proc __osmaperrno +.proc ___osmaperrno lda #EUNKNOWN diff --git a/libsrc/pce/memset.s b/libsrc/pce/memset.s index 45a78d533..1148e00c8 100644 --- a/libsrc/pce/memset.s +++ b/libsrc/pce/memset.s @@ -6,21 +6,21 @@ ; 1998-05-29, Ullrich von Bassewitz ; 2015-11-06, Greg King ; -; void* __fastcall__ _bzero (void* ptr, size_t n); +; void* __fastcall__ __bzero (void* ptr, size_t n); ; void __fastcall__ bzero (void* ptr, size_t n); ; void* __fastcall__ memset (void* ptr, int c, size_t n); ; ; NOTE: bzero() will return its first argument, as memset() does. It is no ; problem to declare the return value as void, because it can be ignored. -; _bzero() (note the leading underscore) is declared with the proper -; return type because the compiler will replace memset() by _bzero() if +; __bzero() (note the leading underscores) is declared with the proper +; return type because the compiler will replace memset() by __bzero() if ; the fill value is zero; and, the optimizer looks at the return type ; to see if the value in .XA is of any use. ; ; NOTE: This function uses entry points from "pce/memcpy.s"! ; - .export __bzero, _bzero, _memset + .export ___bzero, _bzero, _memset .import memcpy_getparams, memcpy_increment .import pushax, popax @@ -30,7 +30,7 @@ ; ---------------------------------------------------------------------- -__bzero: +___bzero: _bzero: pha cla ; fill with zeros jsr pushax ; (high byte isn't important) diff --git a/libsrc/pet/randomize.s b/libsrc/pet/randomize.s index 44bf4c38e..a173cf076 100644 --- a/libsrc/pet/randomize.s +++ b/libsrc/pet/randomize.s @@ -2,16 +2,16 @@ ; 2002-11-05, Ullrich von Bassewitz ; 2015-09-11, Greg King ; -; void _randomize (void); +; void __randomize (void); ; /* Initialize the random number generator */ ; - .export __randomize + .export ___randomize .import _srand .include "pet.inc" -__randomize: +___randomize: ldx TIME+2 lda TIME+1 ; Use 60HZ clock jmp _srand ; Initialize generator diff --git a/libsrc/plus4/randomize.s b/libsrc/plus4/randomize.s index 796ad118b..0d1ccaf03 100644 --- a/libsrc/plus4/randomize.s +++ b/libsrc/plus4/randomize.s @@ -2,16 +2,16 @@ ; 2002-11-05, Ullrich von Bassewitz ; 2015-09-11, Greg King ; -; void _randomize (void); +; void __randomize (void); ; /* Initialize the random number generator */ ; - .export __randomize + .export ___randomize .import _srand .include "plus4.inc" -__randomize: +___randomize: ldx TED_VLINELO ; Use TED rasterline as high byte lda TIME+2 ; Use 60HZ clock as low byte jmp _srand ; Initialize generator diff --git a/libsrc/plus4/ser_stat_stddrv.s b/libsrc/plus4/ser_stat_stddrv.s new file mode 100644 index 000000000..f35b09232 --- /dev/null +++ b/libsrc/plus4/ser_stat_stddrv.s @@ -0,0 +1,14 @@ +; +; Address of the static standard serial driver +; +; Oliver Schmidt, 2022-12-22 +; +; const void ser_static_stddrv[]; +; + + .export _ser_static_stddrv + .import _plus4_stdser_ser + +.rodata + +_ser_static_stddrv := _plus4_stdser_ser diff --git a/libsrc/plus4/ser_stddrv.s b/libsrc/plus4/ser_stddrv.s new file mode 100644 index 000000000..f308d5f40 --- /dev/null +++ b/libsrc/plus4/ser_stddrv.s @@ -0,0 +1,13 @@ +; +; Name of the standard serial driver +; +; Oliver Schmidt, 2022-12-22 +; +; const char ser_stddrv[]; +; + + .export _ser_stddrv + +.rodata + +_ser_stddrv: .asciiz "plus4-stdser.ser" diff --git a/libsrc/telestrat/oserror.s b/libsrc/telestrat/oserror.s index e3b9e619a..8fe255656 100644 --- a/libsrc/telestrat/oserror.s +++ b/libsrc/telestrat/oserror.s @@ -1,14 +1,14 @@ ; ; Jede, 2017-10-27 ; -; int __fastcall__ _osmaperrno (unsigned char oserror); +; int __fastcall__ __osmaperrno (unsigned char oserror); ; /* Map a system specific error into a system independent code */ ; .include "errno.inc" - .export __osmaperrno + .export ___osmaperrno -.proc __osmaperrno +.proc ___osmaperrno lda #EUNKNOWN diff --git a/libsrc/vic20/randomize.s b/libsrc/vic20/randomize.s index 69cf07bb3..ac2c09a7d 100644 --- a/libsrc/vic20/randomize.s +++ b/libsrc/vic20/randomize.s @@ -2,16 +2,16 @@ ; 2002-11-05, Ullrich von Bassewitz ; 2015-09-11, Greg King ; -; void _randomize (void); +; void __randomize (void); ; /* Initialize the random number generator */ ; - .export __randomize + .export ___randomize .import _srand .include "vic20.inc" -__randomize: +___randomize: lda VIC_LINES ; Get overflow bit asl a ; Shift bit 7 into carry lda VIC_HLINE ; Get bit 1-8 of rasterline diff --git a/samples/Makefile b/samples/Makefile index cec4bed89..0e5292306 100644 --- a/samples/Makefile +++ b/samples/Makefile @@ -171,6 +171,7 @@ EXELIST_apple2 = \ multdemo \ ovrldemo \ sieve \ + terminal \ tinyshell \ tgidemo @@ -186,6 +187,7 @@ EXELIST_atari = \ multdemo \ ovrldemo \ sieve \ + terminal \ tinyshell \ tgidemo @@ -203,6 +205,7 @@ EXELIST_atmos = \ hello \ mandelbrot \ sieve \ + terminal \ tgidemo EXELIST_bbc = \ @@ -219,6 +222,7 @@ EXELIST_c64 = \ multdemo \ ovrldemo \ sieve \ + terminal \ tinyshell \ tgidemo @@ -231,6 +235,7 @@ EXELIST_c128 = \ mandelbrot \ mousedemo \ sieve \ + terminal \ tinyshell \ tgidemo @@ -247,6 +252,7 @@ EXELIST_cbm510 = \ gunzip65 \ hello \ mousedemo \ + terminal \ tinyshell \ sieve @@ -255,6 +261,7 @@ EXELIST_cbm610 = \ checkversion \ gunzip65 \ hello \ + terminal \ tinyshell \ sieve @@ -314,6 +321,7 @@ EXELIST_plus4 = \ enumdevdir \ gunzip65 \ hello \ + terminal \ tinyshell \ sieve @@ -418,6 +426,7 @@ TARGETS := \ define TARGET_recipe +@echo making samples for: $(T) @$(MAKE) -j2 SYS:=$(T) @$(MAKE) --no-print-directory clean SYS:=$(T) diff --git a/samples/terminal.c b/samples/terminal.c new file mode 100644 index 000000000..51973f7a3 --- /dev/null +++ b/samples/terminal.c @@ -0,0 +1,76 @@ +/* +** Minimalistic terminal program. +** +** Makes use of the serial drivers. +** +** 2022-12-23, Oliver Schmidt (ol.sc@web.de) +** +*/ + + + +#include +#include +#include +#include +#include + + +static void check (const char* msg, unsigned char err) +{ + if (err == SER_ERR_OK) { + return; + } + + printf ("%s:0x%02x\n", msg, err); + if (doesclrscrafterexit ()) { + cgetc (); + } + exit (1); +} + + +void main (void) +{ + const struct ser_params par = { + SER_BAUD_9600, + SER_BITS_8, + SER_STOP_1, + SER_PAR_NONE, + SER_HS_HW + }; + + check ("ser_install", ser_install (ser_static_stddrv)); + + check ("ser_open", ser_open (&par)); + + atexit ((void (*)) ser_close); + + printf ("Serial Port: 9600-8-1-N RTS/CTS\n" + "Simple Term: Press ESC for exit\n"); + + while (1) + { + char chr; + + if (kbhit ()) + { + chr = cgetc (); + + if (chr == CH_ESC) { + putchar ('\n'); + return; + } + + if (ser_put (chr) == SER_ERR_OK) { + putchar (chr); + } else { + putchar ('\a'); + } + } + + if (ser_get (&chr) == SER_ERR_OK) { + putchar (chr); + } + } +} diff --git a/src/cc65/assignment.c b/src/cc65/assignment.c index 9834ae5d1..54ab28d4e 100644 --- a/src/cc65/assignment.c +++ b/src/cc65/assignment.c @@ -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); diff --git a/src/cc65/codegen.c b/src/cc65/codegen.c index e521fff73..480cc32ea 100644 --- a/src/cc65/codegen.c +++ b/src/cc65/codegen.c @@ -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: "I64x" works in the github actions now, so if your local mingw64 fails, + you probably have to update. +*/ +#if defined(__MINGW64__) +#undef PRIXPTR +#define PRIXPTR "I64x" +#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 */ diff --git a/src/cc65/codegen.h b/src/cc65/codegen.h index cb62d78bd..8e04b45e4 100644 --- a/src/cc65/codegen.h +++ b/src/cc65/codegen.h @@ -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); diff --git a/src/cc65/codeopt.c b/src/cc65/codeopt.c index 440b10751..208ada134 100644 --- a/src/cc65/codeopt.c +++ b/src/cc65/codeopt.c @@ -850,6 +850,10 @@ static unsigned RunOptGroup7 (CodeSeg* S) C += RunOptFunc (S, &DOptJumpCascades, 1); C += RunOptFunc (S, &DOptBranchDist2, 1); + /* Adjust branch distances again, since the previous step may change code + between branches */ + C += RunOptFunc (S, &DOptBranchDist, 3); + Changes += C; /* If we had changes, we must run dead code elimination again, ** since the changes may have introduced dead code. diff --git a/src/cc65/compile.c b/src/cc65/compile.c index 11dcbced0..73380f3df 100644 --- a/src/cc65/compile.c +++ b/src/cc65/compile.c @@ -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); diff --git a/src/cc65/coptstop.c b/src/cc65/coptstop.c index 08f6c820e..4d0151c55 100644 --- a/src/cc65/coptstop.c +++ b/src/cc65/coptstop.c @@ -1329,7 +1329,7 @@ static unsigned Opt_a_tosult (StackOpData* D) /* The first column of these two tables must be sorted in lexical order */ static const OptFuncDesc FuncTable[] = { - { "__bzero", Opt___bzero, REG_NONE, OP_X_ZERO | OP_A_KNOWN }, + { "___bzero", Opt___bzero, REG_NONE, OP_X_ZERO | OP_A_KNOWN }, { "staspidx", Opt_staspidx, REG_NONE, OP_NONE }, { "staxspidx", Opt_staxspidx, REG_AX, OP_NONE }, { "tosaddax", Opt_tosaddax, REG_NONE, OP_NONE }, diff --git a/src/cc65/datatype.c b/src/cc65/datatype.c index 6d9afa403..023aefaf7 100644 --- a/src/cc65/datatype.c +++ b/src/cc65/datatype.c @@ -48,6 +48,7 @@ #include "fp.h" #include "funcdesc.h" #include "global.h" +#include "ident.h" #include "symtab.h" @@ -86,297 +87,6 @@ const Type type_c_void_p[] = { TYPE(T_PTR), TYPE(T_C_VOID), TYPE(T_END) }; -static struct StrBuf* GetFullTypeNameWestEast (struct StrBuf* West, struct StrBuf* East, const Type* T) -/* Return the name string of the given type split into a western part and an -** eastern part. -*/ -{ - struct StrBuf Buf = AUTO_STRBUF_INITIALIZER; - - if (IsTypeArray (T)) { - - long Count = GetElementCount (T); - if (!SB_IsEmpty (East)) { - if (Count > 0) { - SB_Printf (&Buf, "[%ld]", Count); - } else { - SB_Printf (&Buf, "[]"); - } - SB_Append (East, &Buf); - SB_Terminate (East); - - } else { - if (Count > 0) { - SB_Printf (East, "[%ld]", Count); - } else { - SB_Printf (East, "[]"); - } - - if (!SB_IsEmpty (West)) { - /* Add parentheses to West */ - SB_Printf (&Buf, "(%s)", SB_GetConstBuf (West)); - SB_Copy (West, &Buf); - SB_Terminate (West); - } - } - - /* Get element type */ - GetFullTypeNameWestEast (West, East, T + 1); - - } else if (IsTypeFunc (T)) { - - FuncDesc* D = GetFuncDesc (T); - struct StrBuf ParamList = AUTO_STRBUF_INITIALIZER; - - /* First argument */ - SymEntry* Param = D->SymTab->SymHead; - unsigned I; - for (I = 0; I < D->ParamCount; ++I) { - CHECK (Param != 0 && (Param->Flags & SC_PARAM) != 0); - if (I > 0) { - SB_AppendStr (&ParamList, ", "); - } - SB_AppendStr (&ParamList, SB_GetConstBuf (GetFullTypeNameBuf (&Buf, Param->Type))); - SB_Clear (&Buf); - /* Next argument */ - Param = Param->NextSym; - } - if ((D->Flags & FD_VARIADIC) == 0) { - if (D->ParamCount == 0 && (D->Flags & FD_EMPTY) == 0) { - SB_AppendStr (&ParamList, "void"); - } - } else { - if (D->ParamCount > 0) { - SB_AppendStr (&ParamList, ", ..."); - } else { - SB_AppendStr (&ParamList, "..."); - } - } - SB_Terminate (&ParamList); - - /* Join the existing West and East together */ - if (!SB_IsEmpty (East)) { - SB_Append (West, East); - SB_Terminate (West); - SB_Clear (East); - } - - if (SB_IsEmpty (West)) { - /* Just use the param list */ - SB_Printf (West, "(%s)", SB_GetConstBuf (&ParamList)); - } else { - /* Append the param list to the existing West */ - SB_Printf (&Buf, "(%s)(%s)", SB_GetConstBuf (West), SB_GetConstBuf (&ParamList)); - SB_Printf (West, "%s", SB_GetConstBuf (&Buf)); - } - SB_Done (&ParamList); - - /* Return type */ - GetFullTypeNameWestEast (West, East, T + 1); - - } else if (IsTypePtr (T)) { - - int QualCount = 0; - - SB_Printf (&Buf, "*"); - - /* Add qualifiers */ - if ((GetQualifier (T) & ~T_QUAL_NEAR) != T_QUAL_NONE) { - QualCount = GetQualifierTypeCodeNameBuf (&Buf, T->C, T_QUAL_NEAR); - } - - if (!SB_IsEmpty (West)) { - if (QualCount > 0) { - SB_AppendChar (&Buf, ' '); - } - SB_Append (&Buf, West); - } - - SB_Copy (West, &Buf); - SB_Terminate (West); - - /* Get indirection type */ - GetFullTypeNameWestEast (West, East, T + 1); - - } else { - - /* Add qualifiers */ - if ((GetQualifier (T) & ~T_QUAL_NEAR) != 0) { - if (GetQualifierTypeCodeNameBuf (&Buf, T->C, T_QUAL_NEAR) > 0) { - SB_AppendChar (&Buf, ' '); - } - } - - if (!IsTypeBitField (T)) { - SB_AppendStr (&Buf, GetSymTypeName (T)); - } else { - SB_AppendStr (&Buf, GetBasicTypeName (T + 1)); - } - - if (!SB_IsEmpty (West)) { - SB_AppendChar (&Buf, ' '); - SB_Append (&Buf, West); - } - - SB_Copy (West, &Buf); - SB_Terminate (West); - } - - SB_Done (&Buf); - return West; -} - - - -const char* GetBasicTypeName (const Type* T) -/* Return a const name string of the basic type. -** Return "type" for unknown basic types. -*/ -{ - switch (GetRawType (T)) { - case T_TYPE_ENUM: return "enum"; - case T_TYPE_BITFIELD: return "bit-field"; - case T_TYPE_FLOAT: return "float"; - case T_TYPE_DOUBLE: return "double"; - case T_TYPE_VOID: return "void"; - case T_TYPE_STRUCT: return "struct"; - case T_TYPE_UNION: return "union"; - case T_TYPE_ARRAY: return "array"; - case T_TYPE_PTR: return "pointer"; - case T_TYPE_FUNC: return "function"; - case T_TYPE_NONE: /* FALLTHROUGH */ - default: break; - } - if (IsClassInt (T)) { - if (IsRawSignSigned (T)) { - switch (GetRawType (T)) { - case T_TYPE_CHAR: return "signed char"; - case T_TYPE_SHORT: return "short"; - case T_TYPE_INT: return "int"; - case T_TYPE_LONG: return "long"; - case T_TYPE_LONGLONG: return "long long"; - default: - return "signed integer"; - } - } else if (IsRawSignUnsigned (T)) { - switch (GetRawType (T)) { - case T_TYPE_CHAR: return "unsigned char"; - case T_TYPE_SHORT: return "unsigned short"; - case T_TYPE_INT: return "unsigned int"; - case T_TYPE_LONG: return "unsigned long"; - case T_TYPE_LONGLONG: return "unsigned long long"; - default: - return "unsigned integer"; - } - } else { - switch (GetRawType (T)) { - case T_TYPE_CHAR: return "char"; - case T_TYPE_SHORT: return "short"; - case T_TYPE_INT: return "int"; - case T_TYPE_LONG: return "long"; - case T_TYPE_LONGLONG: return "long long"; - default: - return "integer"; - } - } - } - return "type"; -} - - - -const char* GetFullTypeName (const Type* T) -/* Return the full name string of the given type */ -{ - struct StrBuf* Buf = NewDiagnosticStrBuf (); - GetFullTypeNameBuf (Buf, T); - - return SB_GetConstBuf (Buf); -} - - - -struct StrBuf* GetFullTypeNameBuf (struct StrBuf* S, const Type* T) -/* Return the full name string of the given type */ -{ - struct StrBuf East = AUTO_STRBUF_INITIALIZER; - GetFullTypeNameWestEast (S, &East, T); - - /* Join West and East */ - SB_Append (S, &East); - SB_Terminate (S); - SB_Done (&East); - - return S; -} - - - -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. -*/ -{ - int Count = 0; - - Qual &= T_MASK_QUAL & ~IgnoredQual; - if (Qual & T_QUAL_CONST) { - if (!SB_IsEmpty (S)) { - SB_AppendChar (S, ' '); - } - SB_AppendStr (S, "const"); - ++Count; - } - if (Qual & T_QUAL_VOLATILE) { - if (Count > 0) { - SB_AppendChar (S, ' '); - } - SB_AppendStr (S, "volatile"); - ++Count; - } - if (Qual & T_QUAL_RESTRICT) { - if (Count > 0) { - SB_AppendChar (S, ' '); - } - SB_AppendStr (S, "restrict"); - ++Count; - } - if (Qual & T_QUAL_NEAR) { - if (Count > 0) { - SB_AppendChar (S, ' '); - } - SB_AppendStr (S, "__near__"); - ++Count; - } - if (Qual & T_QUAL_FAR) { - SB_AppendStr (S, "__far__"); - ++Count; - } - if (Qual & T_QUAL_FASTCALL) { - if (Count > 0) { - SB_AppendChar (S, ' '); - } - SB_AppendStr (S, "__fastcall__"); - ++Count; - } - if (Qual & T_QUAL_CDECL) { - if (Count > 0) { - SB_AppendChar (S, ' '); - } - SB_AppendStr (S, "__cdecl__"); - ++Count; - } - - if (Count > 0) { - SB_Terminate (S); - } - - return Count; -} - - - unsigned TypeLen (const Type* T) /* Return the length of the type string */ { @@ -433,6 +143,12 @@ void TypeFree (Type* T) +/*****************************************************************************/ +/* Type info extraction */ +/*****************************************************************************/ + + + int SignExtendChar (int C) /* Do correct sign extension of a character */ { @@ -445,70 +161,6 @@ int SignExtendChar (int C) -Type* GetCharArrayType (unsigned Len) -/* Return the type for a char array of the given length */ -{ - /* Allocate memory for the type string */ - Type* T = TypeAlloc (3); /* array/char/terminator */ - - /* Fill the type string */ - T[0].C = T_ARRAY; - T[0].A.L = Len; /* Array length is in the L attribute */ - T[1].C = T_CHAR; - T[2].C = T_END; - - /* Return the new type */ - return T; -} - - - -Type* GetImplicitFuncType (void) -/* Return a type string for an inplicitly declared function */ -{ - /* Get a new function descriptor */ - FuncDesc* F = NewFuncDesc (); - - /* Allocate memory for the type string */ - Type* T = TypeAlloc (3); /* func/returns int/terminator */ - - /* Prepare the function descriptor */ - F->Flags = FD_EMPTY; - F->SymTab = &EmptySymTab; - F->TagTab = &EmptySymTab; - - /* Fill the type string */ - T[0].C = T_FUNC | CodeAddrSizeQualifier (); - T[0].A.F = F; - T[1].C = T_INT; - T[2].C = T_END; - - /* Return the new type */ - return T; -} - - - -const Type* GetStructReplacementType (const Type* SType) -/* Get a replacement type for passing a struct/union in the primary register */ -{ - const Type* NewType; - /* If the size is less than or equal to that of a long, we will copy the - ** struct using the primary register, otherwise we will use memcpy. - */ - switch (SizeOf (SType)) { - case 1: NewType = type_uchar; break; - case 2: NewType = type_uint; break; - case 3: /* FALLTHROUGH */ - case 4: NewType = type_ulong; break; - default: NewType = SType; break; - } - - return NewType; -} - - - long GetIntegerTypeMin (const Type* Type) /* Get the smallest possible value of the integer type. ** The type must have a known size. @@ -551,169 +203,16 @@ unsigned long GetIntegerTypeMax (const Type* Type) -static unsigned GetBitFieldMinimalTypeSize (unsigned BitWidth) -/* Return the size of the smallest integer type that may have BitWidth bits */ +unsigned BitSizeOf (const Type* T) +/* Return the size (in bit-width) of a data type */ { - /* Since all integer types supported in cc65 for bit-fields have sizes that - ** are powers of 2, we can just use this bit-twiddling trick. - */ - unsigned V = (int)(BitWidth - 1U) / (int)CHAR_BITS; - V |= V >> 1; - V |= V >> 2; - V |= V >> 4; - V |= V >> 8; - V |= V >> 16; - - /* Return the result size */ - return V + 1U; -} - - -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; -} - - - -const Type* GetUnderlyingType (const Type* Type) -/* Get the underlying type of an enum or other integer class type */ -{ - if (IsISOChar (Type)) { - return IS_Get (&SignedChars) ? type_schar : type_uchar; - } else if (IsTypeEnum (Type)) { - /* This should not happen, but just in case */ - if (Type->A.S == 0) { - Internal ("Enum tag type error in GetUnderlyingTypeCode"); - } - - /* If incomplete enum type is used, just return its raw type */ - if (Type->A.S->V.E.Type != 0) { - return Type->A.S->V.E.Type; - } - } else if (IsTypeBitField (Type)) { - /* We consider the smallest type that can represent all values of the - ** bit-field, instead of the type used in the declaration, the truly - ** underlying of the bit-field. - */ - switch (GetBitFieldMinimalTypeSize (Type->A.B.Width)) { - case SIZEOF_CHAR: Type = IsSignSigned (Type) ? type_schar : type_uchar; break; - case SIZEOF_INT: Type = IsSignSigned (Type) ? type_int : type_uint; break; - case SIZEOF_LONG: Type = IsSignSigned (Type) ? type_long : type_ulong; break; - default: Type = IsSignSigned (Type) ? type_int : type_uint; break; - } - } - - return Type; -} - - - -TypeCode GetUnderlyingTypeCode (const Type* Type) -/* Get the type code of the unqualified underlying type of TCode. -** Return UnqualifiedType (TCode) if TCode is not scalar. -*/ -{ - TypeCode Underlying = UnqualifiedType (Type->C); - - if (IsISOChar (Type)) { - - return IS_Get (&SignedChars) ? T_SCHAR : T_UCHAR; - - } else if (IsTypeEnum (Type)) { - TypeCode TCode; - - /* This should not happen, but just in case */ - if (Type->A.S == 0) { - Internal ("Enum tag type error in GetUnderlyingTypeCode"); - } - - /* Inspect the underlying type of the enum */ - if (Type->A.S->V.E.Type == 0) { - /* Incomplete enum type is used */ - return Underlying; - } - TCode = UnqualifiedType (Type->A.S->V.E.Type->C); - - /* Replace the type code with integer */ - Underlying = (TCode & ~T_MASK_TYPE); - switch (TCode & T_MASK_SIZE) { - case T_SIZE_INT: Underlying |= T_TYPE_INT; break; - case T_SIZE_LONG: Underlying |= T_TYPE_LONG; break; - case T_SIZE_SHORT: Underlying |= T_TYPE_SHORT; break; - case T_SIZE_CHAR: Underlying |= T_TYPE_CHAR; break; - case T_SIZE_LONGLONG: Underlying |= T_TYPE_LONGLONG; break; - default: Underlying |= T_TYPE_INT; break; - } - } else if (IsTypeBitField (Type)) { - /* We consider the smallest type that can represent all values of the - ** bit-field, instead of the type used in the declaration, the truly - ** underlying of the bit-field. - */ - switch (GetBitFieldMinimalTypeSize (Type->A.B.Width)) { - case SIZEOF_CHAR: Underlying = T_CHAR; break; - case SIZEOF_INT: Underlying = T_INT; break; - case SIZEOF_LONG: Underlying = T_LONG; break; - case SIZEOF_LONGLONG: Underlying = T_LONGLONG; break; - default: Underlying = T_INT; break; - } - Underlying &= ~T_MASK_SIGN; - Underlying |= Type->C & T_MASK_SIGN; - } - - return Underlying; -} - - - -const Type* GetBitFieldChunkType (const Type* Type) -/* Get the type needed to operate on the byte chunk containing the bit-field */ -{ - unsigned ChunkSize; - if ((Type->A.B.Width - 1U) / CHAR_BITS == - (Type->A.B.Offs + Type->A.B.Width - 1U) / CHAR_BITS) { - /* T bit-field fits within its underlying type */ - return GetUnderlyingType (Type); - } - - ChunkSize = GetBitFieldMinimalTypeSize (Type->A.B.Offs + Type->A.B.Width); - if (ChunkSize < SizeOf (Type + 1)) { - /* The end of the bit-field is offset by some bits so that it requires - ** more bytes to be accessed as a whole than its underlying type does. - ** Note: In cc65 the bit offset is always less than CHAR_BITS. - */ - switch (ChunkSize) { - case SIZEOF_CHAR: return IsSignSigned (Type) ? type_schar : type_uchar; - case SIZEOF_INT: return IsSignSigned (Type) ? type_int : type_uint; - case SIZEOF_LONG: return IsSignSigned (Type) ? type_long : type_ulong; - default: return IsSignSigned (Type) ? type_int : type_uint; - } - } - - /* We can always use the declarartion integer type as the chunk type. - ** Note: A bit-field will not occupy bits located in bytes more than that - ** of its declaration type in cc65. So this is OK. - */ - return Type + 1; + return IsTypeBitField (T) ? T->A.B.Width : CHAR_BITS * SizeOf (T); } unsigned SizeOf (const Type* T) -/* Compute size of object represented by type array. */ +/* Compute size (in bytes) of object represented by type array */ { switch (GetUnderlyingTypeCode (T)) { @@ -786,7 +285,7 @@ unsigned SizeOf (const Type* T) unsigned PSizeOf (const Type* T) -/* Compute size of pointer object. */ +/* Compute size (in bytes) of pointee object */ { /* We are expecting a pointer expression */ CHECK (IsClassPtr (T)); @@ -797,10 +296,21 @@ unsigned PSizeOf (const Type* T) +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). +*/ +{ + return IsTypeBitField (T) ? T->A.B.Width : CHAR_BITS * CheckedSizeOf (T); +} + + + 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). +/* 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 Size = SizeOf (T); @@ -818,9 +328,9 @@ unsigned CheckedSizeOf (const Type* T) 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). +/* 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). */ { unsigned Size = PSizeOf (T); @@ -837,76 +347,201 @@ unsigned CheckedPSizeOf (const Type* T) -unsigned TypeOf (const Type* T) -/* Get the code generator base type of the object */ +static unsigned GetBitFieldMinimalTypeSize (unsigned BitWidth) +/* Return the size of the smallest integer type that may have BitWidth bits */ { - unsigned NewType; + /* Since all integer types supported in cc65 for bit-fields have sizes that + ** are powers of 2, we can just use this bit-twiddling trick. + */ + unsigned V = (int)(BitWidth - 1U) / (int)CHAR_BITS; + V |= V >> 1; + V |= V >> 2; + V |= V >> 4; + V |= V >> 8; + V |= V >> 16; - 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; - } + /* Return the result size */ + return V + 1U; } -unsigned FuncTypeOf (const Type* T) -/* Get the code generator flag for calling the function */ +TypeCode GetUnderlyingTypeCode (const Type* Type) +/* Get the type code of the unqualified underlying type of TCode. +** Return UnqualTypeCode (Type) if Type is not scalar. +*/ { - 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; + TypeCode Underlying = UnqualifiedType (Type->C); + + if (IsISOChar (Type)) { + + return IS_Get (&SignedChars) ? T_SCHAR : T_UCHAR; + + } else if (IsTypeEnum (Type)) { + TypeCode TCode; + + /* This should not happen, but just in case */ + if (Type->A.S == 0) { + Internal ("Enum tag type error in GetUnderlyingTypeCode"); + } + + /* Inspect the underlying type of the enum */ + if (Type->A.S->V.E.Type == 0) { + /* Incomplete enum type is used */ + return Underlying; + } + TCode = UnqualifiedType (Type->A.S->V.E.Type->C); + + /* Replace the type code with integer */ + Underlying = (TCode & ~T_MASK_TYPE); + switch (TCode & T_MASK_SIZE) { + case T_SIZE_INT: Underlying |= T_TYPE_INT; break; + case T_SIZE_LONG: Underlying |= T_TYPE_LONG; break; + case T_SIZE_SHORT: Underlying |= T_TYPE_SHORT; break; + case T_SIZE_CHAR: Underlying |= T_TYPE_CHAR; break; + case T_SIZE_LONGLONG: Underlying |= T_TYPE_LONGLONG; break; + default: Underlying |= T_TYPE_INT; break; + } + } else if (IsTypeBitField (Type)) { + /* We consider the smallest type that can represent all values of the + ** bit-field, instead of the type used in the declaration, the truly + ** underlying of the bit-field. + */ + switch (GetBitFieldMinimalTypeSize (Type->A.B.Width)) { + case SIZEOF_CHAR: Underlying = T_CHAR; break; + case SIZEOF_INT: Underlying = T_INT; break; + case SIZEOF_LONG: Underlying = T_LONG; break; + case SIZEOF_LONGLONG: Underlying = T_LONGLONG; break; + default: Underlying = T_INT; break; + } + Underlying &= ~T_MASK_SIGN; + Underlying |= Type->C & T_MASK_SIGN; } + + return Underlying; +} + + + +/*****************************************************************************/ +/* Type manipulation */ +/*****************************************************************************/ + + + +Type* GetImplicitFuncType (void) +/* Return a type string for an implicitly declared function */ +{ + /* Get a new function descriptor */ + FuncDesc* F = NewFuncDesc (); + + /* Allocate memory for the type string */ + Type* T = TypeAlloc (3); /* func/returns int/terminator */ + + /* Prepare the function descriptor */ + F->Flags = FD_EMPTY; + F->SymTab = &EmptySymTab; + F->TagTab = &EmptySymTab; + + /* Fill the type string */ + T[0].C = T_FUNC | CodeAddrSizeQualifier (); + T[0].A.F = F; + T[1].C = T_INT; + T[2].C = T_END; + + /* Return the new type */ + return T; +} + + + +Type* GetCharArrayType (unsigned Len) +/* Return the type for a char array of the given length */ +{ + /* Allocate memory for the type string */ + Type* T = TypeAlloc (3); /* array/char/terminator */ + + /* Fill the type string */ + T[0].C = T_ARRAY; + T[0].A.L = Len; /* Array length is in the L attribute */ + T[1].C = T_CHAR; + T[2].C = T_END; + + /* Return the new type */ + return T; +} + + + +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. +*/ +{ + /* Get the size of the type string including the terminator */ + unsigned Size = TypeLen (T) + 1; + + /* Allocate the new type string */ + Type* P = TypeAlloc (Size + 1); + + /* Create the return type... */ + P[0].C = T_PTR | (T[0].C & T_QUAL_ADDRSIZE); + memcpy (P+1, T, Size * sizeof (Type)); + + /* ...and return it */ + return P; +} + + + +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. +*/ +{ + Type* P; + + /* The type specifier must be integeral */ + CHECK (IsClassInt (T)); + + /* Allocate the new type string */ + P = TypeAlloc (3); + + /* Create the return type... */ + P[0].C = IsSignSigned (T) ? T_SBITFIELD : T_UBITFIELD; + P[0].C |= (T[0].C & T_QUAL_ADDRSIZE); + P[0].A.B.Offs = BitOffs; + P[0].A.B.Width = BitWidth; + + /* Get the declaration type */ + memcpy (&P[1], GetUnderlyingType (T), sizeof (P[1])); + + /* Get done... */ + P[2].C = T_END; + + /* ...and return it */ + return P; +} + + + +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. +*/ +{ + /* Get the size of the type string including the terminator */ + unsigned Size = TypeLen (T) + 1; + + /* Allocate the new type string */ + Type* P = TypeAlloc (Size + 1); + + /* Create the return type... */ + P[0].C = T_PTR | (T[0].C & T_QUAL_ADDRSIZE) | T_QUAL_CONST; + memcpy (P+1, T, Size * sizeof (Type)); + + /* ...and return it */ + return P; } @@ -939,48 +574,6 @@ Type* IndirectModifiable (Type* T) -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. -*/ -{ - /* Get the size of the type string including the terminator */ - unsigned Size = TypeLen (T) + 1; - - /* Allocate the new type string */ - Type* P = TypeAlloc (Size + 1); - - /* Create the return type... */ - P[0].C = T_PTR | (T[0].C & T_QUAL_ADDRSIZE); - memcpy (P+1, T, Size * sizeof (Type)); - - /* ...and return it */ - return P; -} - - - -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. -*/ -{ - /* Get the size of the type string including the terminator */ - unsigned Size = TypeLen (T) + 1; - - /* Allocate the new type string */ - Type* P = TypeAlloc (Size + 1); - - /* Create the return type... */ - P[0].C = T_PTR | (T[0].C & T_QUAL_ADDRSIZE) | T_QUAL_CONST; - memcpy (P+1, T, Size * sizeof (Type)); - - /* ...and return it */ - return P; -} - - - Type* ArrayToPtr (const Type* T) /* Convert an array to a pointer to it's first element */ { @@ -1181,37 +774,98 @@ const Type* UnsignedType (const Type* T) -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 */ { - Type* P; + if (IsISOChar (Type)) { + return IS_Get (&SignedChars) ? type_schar : type_uchar; + } else if (IsTypeEnum (Type)) { + /* This should not happen, but just in case */ + if (Type->A.S == 0) { + Internal ("Enum tag type error in GetUnderlyingTypeCode"); + } - /* The type specifier must be integeral */ - CHECK (IsClassInt (T)); + /* If incomplete enum type is used, just return its raw type */ + if (Type->A.S->V.E.Type != 0) { + return Type->A.S->V.E.Type; + } + } else if (IsTypeBitField (Type)) { + /* We consider the smallest type that can represent all values of the + ** bit-field, instead of the type used in the declaration, the truly + ** underlying of the bit-field. + */ + switch (GetBitFieldMinimalTypeSize (Type->A.B.Width)) { + case SIZEOF_CHAR: Type = IsSignSigned (Type) ? type_schar : type_uchar; break; + case SIZEOF_INT: Type = IsSignSigned (Type) ? type_int : type_uint; break; + case SIZEOF_LONG: Type = IsSignSigned (Type) ? type_long : type_ulong; break; + default: Type = IsSignSigned (Type) ? type_int : type_uint; break; + } + } - /* Allocate the new type string */ - P = TypeAlloc (3); - - /* Create the return type... */ - P[0].C = IsSignSigned (T) ? T_SBITFIELD : T_UBITFIELD; - P[0].C |= (T[0].C & T_QUAL_ADDRSIZE); - P[0].A.B.Offs = BitOffs; - P[0].A.B.Width = BitWidth; - - /* Get the declaration type */ - memcpy (&P[1], GetUnderlyingType (T), sizeof (P[1])); - - /* Get done... */ - P[2].C = T_END; - - /* ...and return it */ - return P; + return Type; } +const Type* GetStructReplacementType (const Type* SType) +/* Get a replacement type for passing a struct/union in the primary register */ +{ + const Type* NewType; + /* If the size is less than or equal to that of a long, we will copy the + ** struct using the primary register, otherwise we will use memcpy. + */ + switch (SizeOf (SType)) { + case 1: NewType = type_uchar; break; + case 2: NewType = type_uint; break; + case 3: /* FALLTHROUGH */ + case 4: NewType = type_ulong; break; + default: NewType = SType; break; + } + + return NewType; +} + + + +const Type* GetBitFieldChunkType (const Type* Type) +/* Get the type needed to operate on the byte chunk containing the bit-field */ +{ + unsigned ChunkSize; + if ((Type->A.B.Width - 1U) / CHAR_BITS == + (Type->A.B.Offs + Type->A.B.Width - 1U) / CHAR_BITS) { + /* T bit-field fits within its underlying type */ + return GetUnderlyingType (Type); + } + + ChunkSize = GetBitFieldMinimalTypeSize (Type->A.B.Offs + Type->A.B.Width); + if (ChunkSize < SizeOf (Type + 1)) { + /* The end of the bit-field is offset by some bits so that it requires + ** more bytes to be accessed as a whole than its underlying type does. + ** Note: In cc65 the bit offset is always less than CHAR_BITS. + */ + switch (ChunkSize) { + case SIZEOF_CHAR: return IsSignSigned (Type) ? type_schar : type_uchar; + case SIZEOF_INT: return IsSignSigned (Type) ? type_int : type_uint; + case SIZEOF_LONG: return IsSignSigned (Type) ? type_long : type_ulong; + default: return IsSignSigned (Type) ? type_int : type_uint; + } + } + + /* We can always use the declarartion integer type as the chunk type. + ** Note: A bit-field will not occupy bits located in bytes more than that + ** of its declaration type in cc65. So this is OK. + */ + return Type + 1; +} + + + +/*****************************************************************************/ +/* Type Predicates */ +/*****************************************************************************/ + + + int IsTypeFragBitField (const Type* T) /* Return true if this is a bit-field that shares byte space with other fields */ { @@ -1307,9 +961,9 @@ int IsESUType (const Type* T) int IsIncompleteESUType (const Type* T) /* Return true if this is an incomplete ESU type */ { - SymEntry* Sym = GetSymType (T); + SymEntry* TagSym = GetESUTagSym (T); - return Sym != 0 && !SymIsDef (Sym); + return TagSym != 0 && !SymIsDef (TagSym); } @@ -1333,6 +987,46 @@ int HasUnknownSize (const Type* T) +int TypeHasAttr (const Type* T) +/* Return true if the given type has attribute data */ +{ + return IsClassStruct (T) || IsTypeArray (T) || IsClassFunc (T); +} + + + +/*****************************************************************************/ +/* Qualifier helpers */ +/*****************************************************************************/ + + + +TypeCode AddrSizeQualifier (unsigned AddrSize) +/* Return T_QUAL_NEAR or T_QUAL_FAR depending on the address size */ +{ + switch (AddrSize) { + + case ADDR_SIZE_ABS: + return T_QUAL_NEAR; + + case ADDR_SIZE_FAR: + return T_QUAL_FAR; + + default: + Error ("Invalid address size"); + return T_QUAL_NEAR; + + } +} + + + +/*****************************************************************************/ +/* Function type helpers */ +/*****************************************************************************/ + + + int IsVariadicFunc (const Type* T) /* Return true if this is a function type or pointer to function type with ** variable parameter list. @@ -1441,6 +1135,12 @@ const FuncDesc* GetFuncDefinitionDesc (const Type* T) +/*****************************************************************************/ +/* Array type helpers */ +/*****************************************************************************/ + + + long GetElementCount (const Type* T) /* Get the element count of the array specified in T (which must be of ** array type). @@ -1486,20 +1186,27 @@ const Type* GetBaseElementType (const Type* T) -struct SymEntry* GetESUSymEntry (const Type* T) -/* Return a SymEntry pointer from an enum/struct/union type */ -{ - /* Only enums, structs or unions have a SymEntry attribute */ - CHECK (IsClassStruct (T) || IsTypeEnum (T)); +/*****************************************************************************/ +/* ESU types helpers */ +/*****************************************************************************/ - /* Return the attribute */ - return T->A.S; + + +struct SymEntry* GetESUTagSym (const Type* T) +/* Get the tag symbol entry of the enum/struct/union type. +** Return 0 if it is not an enum/struct/union. +*/ +{ + if ((IsClassStruct (T) || IsTypeEnum (T))) { + return T->A.S; + } + return 0; } -void SetESUSymEntry (Type* T, struct SymEntry* S) -/* Set the SymEntry pointer for an enum/struct/union type */ +void SetESUTagSym (Type* T, struct SymEntry* S) +/* Set the tag symbol entry of the enum/struct/union type */ { /* Only enums, structs or unions have a SymEntry attribute */ CHECK (IsClassStruct (T) || IsTypeEnum (T)); @@ -1510,30 +1217,319 @@ void SetESUSymEntry (Type* T, struct SymEntry* S) -TypeCode AddrSizeQualifier (unsigned AddrSize) -/* Return T_QUAL_NEAR or T_QUAL_FAR depending on the address size */ +/*****************************************************************************/ +/* Helpers */ +/*****************************************************************************/ + + + +const char* GetBasicTypeName (const Type* T) +/* Return a const name string of the basic type. +** Return "type" for unknown basic types. +*/ { - switch (AddrSize) { - - case ADDR_SIZE_ABS: - return T_QUAL_NEAR; - - case ADDR_SIZE_FAR: - return T_QUAL_FAR; - - default: - Error ("Invalid address size"); - return T_QUAL_NEAR; - + switch (GetRawType (T)) { + case T_TYPE_ENUM: return "enum"; + case T_TYPE_BITFIELD: return "bit-field"; + case T_TYPE_FLOAT: return "float"; + case T_TYPE_DOUBLE: return "double"; + case T_TYPE_VOID: return "void"; + case T_TYPE_STRUCT: return "struct"; + case T_TYPE_UNION: return "union"; + case T_TYPE_ARRAY: return "array"; + case T_TYPE_PTR: return "pointer"; + case T_TYPE_FUNC: return "function"; + case T_TYPE_NONE: /* FALLTHROUGH */ + default: break; } + if (IsClassInt (T)) { + if (IsRawSignSigned (T)) { + switch (GetRawType (T)) { + case T_TYPE_CHAR: return "signed char"; + case T_TYPE_SHORT: return "short"; + case T_TYPE_INT: return "int"; + case T_TYPE_LONG: return "long"; + case T_TYPE_LONGLONG: return "long long"; + default: + return "signed integer"; + } + } else if (IsRawSignUnsigned (T)) { + switch (GetRawType (T)) { + case T_TYPE_CHAR: return "unsigned char"; + case T_TYPE_SHORT: return "unsigned short"; + case T_TYPE_INT: return "unsigned int"; + case T_TYPE_LONG: return "unsigned long"; + case T_TYPE_LONGLONG: return "unsigned long long"; + default: + return "unsigned integer"; + } + } else { + switch (GetRawType (T)) { + case T_TYPE_CHAR: return "char"; + case T_TYPE_SHORT: return "short"; + case T_TYPE_INT: return "int"; + case T_TYPE_LONG: return "long"; + case T_TYPE_LONGLONG: return "long long"; + default: + return "integer"; + } + } + } + return "type"; } -int TypeHasAttr (const Type* T) -/* Return true if the given type has attribute data */ +static const char* GetTagSymName (const Type* T) +/* Return a name string of the type or the symbol name if it is an ESU type. +** Note: This may use a static buffer that could be overwritten by other calls. +*/ { - return IsClassStruct (T) || IsTypeArray (T) || IsClassFunc (T); + static char TypeName [IDENTSIZE + 16]; + SymEntry* Sym; + + Sym = GetESUTagSym (T); + if (Sym == 0) { + return GetBasicTypeName (T); + } + sprintf (TypeName, "%s %s", GetBasicTypeName (T), + Sym->Name[0] != '\0' ? Sym->Name : ""); + + return TypeName; +} + + + +const char* GetFullTypeName (const Type* T) +/* Return the full name string of the given type */ +{ + struct StrBuf* Buf = NewDiagnosticStrBuf (); + GetFullTypeNameBuf (Buf, T); + + return SB_GetConstBuf (Buf); +} + + + +static struct StrBuf* GetFullTypeNameWestEast (struct StrBuf* West, struct StrBuf* East, const Type* T) +/* Return the name string of the given type split into a western part and an +** eastern part. +*/ +{ + struct StrBuf Buf = AUTO_STRBUF_INITIALIZER; + + if (IsTypeArray (T)) { + + long Count = GetElementCount (T); + if (!SB_IsEmpty (East)) { + if (Count > 0) { + SB_Printf (&Buf, "[%ld]", Count); + } else { + SB_Printf (&Buf, "[]"); + } + SB_Append (East, &Buf); + SB_Terminate (East); + + } else { + if (Count > 0) { + SB_Printf (East, "[%ld]", Count); + } else { + SB_Printf (East, "[]"); + } + + if (!SB_IsEmpty (West)) { + /* Add parentheses to West */ + SB_Printf (&Buf, "(%s)", SB_GetConstBuf (West)); + SB_Copy (West, &Buf); + SB_Terminate (West); + } + } + + /* Get element type */ + GetFullTypeNameWestEast (West, East, T + 1); + + } else if (IsTypeFunc (T)) { + + FuncDesc* D = GetFuncDesc (T); + struct StrBuf ParamList = AUTO_STRBUF_INITIALIZER; + + /* First argument */ + SymEntry* Param = D->SymTab->SymHead; + unsigned I; + for (I = 0; I < D->ParamCount; ++I) { + CHECK (Param != 0 && (Param->Flags & SC_PARAM) != 0); + if (I > 0) { + SB_AppendStr (&ParamList, ", "); + } + SB_AppendStr (&ParamList, SB_GetConstBuf (GetFullTypeNameBuf (&Buf, Param->Type))); + SB_Clear (&Buf); + /* Next argument */ + Param = Param->NextSym; + } + if ((D->Flags & FD_VARIADIC) == 0) { + if (D->ParamCount == 0 && (D->Flags & FD_EMPTY) == 0) { + SB_AppendStr (&ParamList, "void"); + } + } else { + if (D->ParamCount > 0) { + SB_AppendStr (&ParamList, ", ..."); + } else { + SB_AppendStr (&ParamList, "..."); + } + } + SB_Terminate (&ParamList); + + /* Join the existing West and East together */ + if (!SB_IsEmpty (East)) { + SB_Append (West, East); + SB_Terminate (West); + SB_Clear (East); + } + + if (SB_IsEmpty (West)) { + /* Just use the param list */ + SB_Printf (West, "(%s)", SB_GetConstBuf (&ParamList)); + } else { + /* Append the param list to the existing West */ + SB_Printf (&Buf, "(%s)(%s)", SB_GetConstBuf (West), SB_GetConstBuf (&ParamList)); + SB_Printf (West, "%s", SB_GetConstBuf (&Buf)); + } + SB_Done (&ParamList); + + /* Return type */ + GetFullTypeNameWestEast (West, East, T + 1); + + } else if (IsTypePtr (T)) { + + int QualCount = 0; + + SB_Printf (&Buf, "*"); + + /* Add qualifiers */ + if ((GetQualifier (T) & ~T_QUAL_NEAR) != T_QUAL_NONE) { + QualCount = GetQualifierTypeCodeNameBuf (&Buf, T->C, T_QUAL_NEAR); + } + + if (!SB_IsEmpty (West)) { + if (QualCount > 0) { + SB_AppendChar (&Buf, ' '); + } + SB_Append (&Buf, West); + } + + SB_Copy (West, &Buf); + SB_Terminate (West); + + /* Get indirection type */ + GetFullTypeNameWestEast (West, East, T + 1); + + } else { + + /* Add qualifiers */ + if ((GetQualifier (T) & ~T_QUAL_NEAR) != 0) { + if (GetQualifierTypeCodeNameBuf (&Buf, T->C, T_QUAL_NEAR) > 0) { + SB_AppendChar (&Buf, ' '); + } + } + + if (!IsTypeBitField (T)) { + SB_AppendStr (&Buf, GetTagSymName (T)); + } else { + SB_AppendStr (&Buf, GetBasicTypeName (T + 1)); + } + + if (!SB_IsEmpty (West)) { + SB_AppendChar (&Buf, ' '); + SB_Append (&Buf, West); + } + + SB_Copy (West, &Buf); + SB_Terminate (West); + } + + SB_Done (&Buf); + return West; +} + + + +struct StrBuf* GetFullTypeNameBuf (struct StrBuf* S, const Type* T) +/* Return the full name string of the given type */ +{ + struct StrBuf East = AUTO_STRBUF_INITIALIZER; + GetFullTypeNameWestEast (S, &East, T); + + /* Join West and East */ + SB_Append (S, &East); + SB_Terminate (S); + SB_Done (&East); + + return S; +} + + + +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. +*/ +{ + int Count = 0; + + Qual &= T_MASK_QUAL & ~IgnoredQual; + if (Qual & T_QUAL_CONST) { + if (!SB_IsEmpty (S)) { + SB_AppendChar (S, ' '); + } + SB_AppendStr (S, "const"); + ++Count; + } + if (Qual & T_QUAL_VOLATILE) { + if (Count > 0) { + SB_AppendChar (S, ' '); + } + SB_AppendStr (S, "volatile"); + ++Count; + } + if (Qual & T_QUAL_RESTRICT) { + if (Count > 0) { + SB_AppendChar (S, ' '); + } + SB_AppendStr (S, "restrict"); + ++Count; + } + if (Qual & T_QUAL_NEAR) { + if (Count > 0) { + SB_AppendChar (S, ' '); + } + SB_AppendStr (S, "__near__"); + ++Count; + } + if (Qual & T_QUAL_FAR) { + SB_AppendStr (S, "__far__"); + ++Count; + } + if (Qual & T_QUAL_FASTCALL) { + if (Count > 0) { + SB_AppendChar (S, ' '); + } + SB_AppendStr (S, "__fastcall__"); + ++Count; + } + if (Qual & T_QUAL_CDECL) { + if (Count > 0) { + SB_AppendChar (S, ' '); + } + SB_AppendStr (S, "__cdecl__"); + ++Count; + } + + if (Count > 0) { + SB_Terminate (S); + } + + return Count; } @@ -1570,7 +1566,7 @@ void PrintFuncSig (FILE* F, const char* Name, const Type* T) if (SymIsRegVar (Param)) { SB_AppendStr (&ParamList, "register "); } - if (!HasAnonName (Param)) { + if (!SymHasAnonName (Param)) { SB_AppendStr (&Buf, Param->Name); } SB_AppendStr (&ParamList, SB_GetConstBuf (GetFullTypeNameBuf (&Buf, Param->Type))); diff --git a/src/cc65/datatype.h b/src/cc65/datatype.h index e8ba7b6c0..4a20422fb 100644 --- a/src/cc65/datatype.h +++ b/src/cc65/datatype.h @@ -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 */ diff --git a/src/cc65/declare.c b/src/cc65/declare.c index 7cc7444b6..459ffa103 100644 --- a/src/cc65/declare.c +++ b/src/cc65/declare.c @@ -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; + } } diff --git a/src/cc65/declare.h b/src/cc65/declare.h index 2b8b36f1c..ee9e1fc63 100644 --- a/src/cc65/declare.h +++ b/src/cc65/declare.h @@ -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); diff --git a/src/cc65/declattr.c b/src/cc65/declattr.c index 37048e69b..eec89552e 100644 --- a/src/cc65/declattr.c +++ b/src/cc65/declattr.c @@ -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? */ diff --git a/src/cc65/declattr.h b/src/cc65/declattr.h index 63669cee7..930cd71ff 100644 --- a/src/cc65/declattr.h +++ b/src/cc65/declattr.h @@ -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 */ diff --git a/src/cc65/error.c b/src/cc65/error.c index f0e023969..3f36d9e97 100644 --- a/src/cc65/error.c +++ b/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 */ /*****************************************************************************/ diff --git a/src/cc65/error.h b/src/cc65/error.h index c4420c434..7fcb03467 100644 --- a/src/cc65/error.h +++ b/src/cc65/error.h @@ -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) */ diff --git a/src/cc65/expr.c b/src/cc65/expr.c index afb5e1960..78a4c516a 100644 --- a/src/cc65/expr.c +++ b/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 */ diff --git a/src/cc65/expr.h b/src/cc65/expr.h index abdf8ab0d..5644fb82d 100644 --- a/src/cc65/expr.h +++ b/src/cc65/expr.h @@ -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); diff --git a/src/cc65/exprdesc.c b/src/cc65/exprdesc.c index 3d7b7c384..5924ab6cf 100644 --- a/src/cc65/exprdesc.c +++ b/src/cc65/exprdesc.c @@ -67,75 +67,9 @@ ExprDesc* ED_Init (ExprDesc* Expr) -#if !defined(HAVE_INLINE) -int ED_IsLocQuasiConst (const ExprDesc* Expr) -/* Return true if the expression is a constant location of some sort or on the -** stack. -*/ -{ - return ED_IsLocConst (Expr) || ED_IsLocStack (Expr); -} -#endif - - - -#if !defined(HAVE_INLINE) -int ED_IsLocPrimaryOrExpr (const ExprDesc* Expr) -/* Return true if the expression is E_LOC_PRIMARY or E_LOC_EXPR */ -{ - return ED_IsLocPrimary (Expr) || ED_IsLocExpr (Expr); -} -#endif - - - -#if !defined(HAVE_INLINE) -int ED_IsIndExpr (const ExprDesc* Expr) -/* Check if the expression is a reference to its value */ -{ - return (Expr->Flags & E_ADDRESS_OF) == 0 && - !ED_IsLocNone (Expr) && !ED_IsLocPrimary (Expr); -} -#endif - - - -int ED_YetToLoad (const ExprDesc* Expr) -/* Check if the expression needs to be loaded somehow. */ -{ - return ED_NeedsPrimary (Expr) || - ED_YetToTest (Expr) || - (ED_IsLVal (Expr) && IsQualVolatile (Expr->Type)); -} - - - -void ED_MarkForUneval (ExprDesc* Expr) -/* Mark the expression as not to be evaluated */ -{ - Expr->Flags = (Expr->Flags & ~E_MASK_EVAL) | E_EVAL_UNEVAL; -} - - - -void ED_SetCodeRange (ExprDesc* Expr, const CodeMark* Start, const CodeMark* End) -/* Set the code range for this expression */ -{ - Expr->Flags |= E_HAVE_MARKS; - Expr->Start = *Start; - Expr->End = *End; -} - - - -int ED_CodeRangeIsEmpty (const ExprDesc* Expr) -/* Return true if no code was output for this expression */ -{ - /* We must have code marks */ - PRECONDITION (Expr->Flags & E_HAVE_MARKS); - - return CodeRangeIsEmpty (&Expr->Start, &Expr->End); -} +/*****************************************************************************/ +/* Info Extraction */ +/*****************************************************************************/ @@ -215,6 +149,190 @@ int ED_GetStackOffs (const ExprDesc* Expr, int Offs) +/*****************************************************************************/ +/* Predicates */ +/*****************************************************************************/ + + + +#if !defined(HAVE_INLINE) +int ED_IsLocQuasiConst (const ExprDesc* Expr) +/* Return true if the expression is a constant location of some sort or on the +** stack. +*/ +{ + return ED_IsLocConst (Expr) || ED_IsLocStack (Expr); +} +#endif + + + +#if !defined(HAVE_INLINE) +int ED_IsLocPrimaryOrExpr (const ExprDesc* Expr) +/* Return true if the expression is E_LOC_PRIMARY or E_LOC_EXPR */ +{ + return ED_IsLocPrimary (Expr) || ED_IsLocExpr (Expr); +} +#endif + + + +#if !defined(HAVE_INLINE) +int ED_IsIndExpr (const ExprDesc* Expr) +/* Check if the expression is a reference to its value */ +{ + return (Expr->Flags & E_ADDRESS_OF) == 0 && + !ED_IsLocNone (Expr) && !ED_IsLocPrimary (Expr); +} +#endif + + + +int ED_YetToLoad (const ExprDesc* Expr) +/* Check if the expression needs to be loaded somehow. */ +{ + return ED_NeedsPrimary (Expr) || + ED_YetToTest (Expr) || + (ED_IsLVal (Expr) && IsQualVolatile (Expr->Type)); +} + + + +#if !defined(HAVE_INLINE) +int ED_IsAbs (const ExprDesc* Expr) +/* Return true if the expression denotes a numeric value or address. */ +{ + return (Expr->Flags & (E_MASK_LOC)) == (E_LOC_NONE) || + (Expr->Flags & (E_MASK_LOC|E_ADDRESS_OF)) == (E_LOC_ABS|E_ADDRESS_OF); +} +#endif + + + +#if !defined(HAVE_INLINE) +int ED_IsConstAbs (const ExprDesc* Expr) +/* Return true if the expression denotes a constant absolute value. This can be +** a numeric constant, cast to any type. +*/ +{ + return ED_IsRVal (Expr) && ED_IsAbs (Expr); +} +#endif + + + +int ED_IsConstAbsInt (const ExprDesc* Expr) +/* Return true if the expression is a constant (numeric) integer. */ +{ + return ED_IsConstAbs (Expr) && IsClassInt (Expr->Type); +} + + + +int ED_IsConstBool (const ExprDesc* Expr) +/* Return true if the expression can be constantly evaluated as a boolean. */ +{ + return ED_IsConstAbsInt (Expr) || ED_IsAddrExpr (Expr); +} + + + +int ED_IsConstTrue (const ExprDesc* Expr) +/* Return true if the constant expression can be evaluated as boolean true at +** compile time. +*/ +{ + /* Non-zero arithmetics and objects addresses are boolean true */ + return (ED_IsConstAbsInt (Expr) && Expr->IVal != 0) || + (ED_IsAddrExpr (Expr)); +} + + + +int ED_IsConstFalse (const ExprDesc* Expr) +/* Return true if the constant expression can be evaluated as boolean false at +** compile time. +*/ +{ + /* Zero arithmetics and null pointers are boolean false */ + return (ED_IsConstAbsInt (Expr) && Expr->IVal == 0) || + ED_IsNullPtr (Expr); +} + + + +int ED_IsConst (const ExprDesc* Expr) +/* Return true if the expression denotes a constant of some sort. This can be a +** numeric constant, the address of a global variable (maybe with offset) or +** similar. +*/ +{ + return (Expr->Flags & E_MASK_LOC) == E_LOC_NONE || ED_IsConstAddr (Expr); +} + + + +int ED_IsQuasiConst (const ExprDesc* Expr) +/* Return true if the expression denotes a quasi-constant of some sort. This +** can be a numeric constant, a constant address or a stack variable address. +*/ +{ + return (Expr->Flags & E_MASK_LOC) == E_LOC_NONE || ED_IsQuasiConstAddr (Expr); +} + + + +int ED_IsConstAddr (const ExprDesc* Expr) +/* Return true if the expression denotes a constant address of some sort. This +** can be the address of a global variable (maybe with offset) or similar. +*/ +{ + return ED_IsAddrExpr (Expr) && ED_IsLocConst (Expr); +} + + + +int ED_IsQuasiConstAddr (const ExprDesc* Expr) +/* Return true if the expression denotes a quasi-constant address of some sort. +** This can be a constant address or a stack variable address. +*/ +{ + return ED_IsAddrExpr (Expr) && ED_IsLocQuasiConst (Expr); +} + + + +int ED_IsNullPtr (const ExprDesc* Expr) +/* Return true if the given expression is a NULL pointer constant */ +{ + return (Expr->Flags & (E_MASK_LOC|E_MASK_RTYPE)) == + (E_LOC_NONE|E_RTYPE_RVAL) && + Expr->IVal == 0 && + IsClassInt (Expr->Type); +} + + + +int ED_IsBool (const ExprDesc* Expr) +/* Return true if the expression can be treated as a boolean, that is, it can +** be an operand to a compare operation. +*/ +{ + /* Either ints, floats, or pointers can be used in a boolean context */ + return IsClassInt (Expr->Type) || + IsClassFloat (Expr->Type) || + IsClassPtr (Expr->Type) || + IsClassFunc (Expr->Type); +} + + + +/*****************************************************************************/ +/* Manipulation */ +/*****************************************************************************/ + + + ExprDesc* ED_MakeConstAbs (ExprDesc* Expr, long Value, const Type* Type) /* Replace Expr with an absolute const with the given value and type */ { @@ -331,7 +449,7 @@ ExprDesc* ED_IndExpr (ExprDesc* Expr) ** original address. We simply mark this as E_LOC_EXPR so that ** some info about the original location can be retained. ** If it's really meant to dereference a "pointer value", it - ** should be done in two steps where the pointervalue should + ** should be done in two steps where the pointer value should ** be the manually loaded first before a call into this, and ** the offset should be manually cleared somewhere outside. */ @@ -345,131 +463,27 @@ ExprDesc* ED_IndExpr (ExprDesc* Expr) -#if !defined(HAVE_INLINE) -int ED_IsAbs (const ExprDesc* Expr) -/* Return true if the expression denotes a numeric value or address. */ +void ED_MarkForUneval (ExprDesc* Expr) +/* Mark the expression as not to be evaluated */ { - return (Expr->Flags & (E_MASK_LOC)) == (E_LOC_NONE) || - (Expr->Flags & (E_MASK_LOC|E_ADDRESS_OF)) == (E_LOC_ABS|E_ADDRESS_OF); -} -#endif - - - -#if !defined(HAVE_INLINE) -int ED_IsConstAbs (const ExprDesc* Expr) -/* Return true if the expression denotes a constant absolute value. This can be -** a numeric constant, cast to any type. -*/ -{ - return ED_IsRVal (Expr) && ED_IsAbs (Expr); -} -#endif - - - -int ED_IsConstAbsInt (const ExprDesc* Expr) -/* Return true if the expression is a constant (numeric) integer. */ -{ - return ED_IsConstAbs (Expr) && IsClassInt (Expr->Type); + Expr->Flags = (Expr->Flags & ~E_MASK_EVAL) | E_EVAL_UNEVAL; } -int ED_IsConstBool (const ExprDesc* Expr) -/* Return true if the expression can be constantly evaluated as a boolean. */ +const Type* ReplaceType (ExprDesc* Expr, const Type* NewType) +/* Replace the type of Expr by a copy of Newtype and return the old type string */ { - return ED_IsConstAbsInt (Expr) || ED_IsAddrExpr (Expr); + const Type* OldType = Expr->Type; + Expr->Type = TypeDup (NewType); + return OldType; } -int ED_IsConstTrue (const ExprDesc* Expr) -/* Return true if the constant expression can be evaluated as boolean true at -** compile time. -*/ -{ - /* Non-zero arithmetics and objects addresses are boolean true */ - return (ED_IsConstAbsInt (Expr) && Expr->IVal != 0) || - (ED_IsAddrExpr (Expr)); -} - - - -int ED_IsConstFalse (const ExprDesc* Expr) -/* Return true if the constant expression can be evaluated as boolean false at -** compile time. -*/ -{ - /* Zero arithmetics and null pointers are boolean false */ - return (ED_IsConstAbsInt (Expr) && Expr->IVal == 0) || - ED_IsNullPtr (Expr); -} - - - -int ED_IsConst (const ExprDesc* Expr) -/* Return true if the expression denotes a constant of some sort. This can be a -** numeric constant, the address of a global variable (maybe with offset) or -** similar. -*/ -{ - return (Expr->Flags & E_MASK_LOC) == E_LOC_NONE || ED_IsConstAddr (Expr); -} - - - -int ED_IsQuasiConst (const ExprDesc* Expr) -/* Return true if the expression denotes a quasi-constant of some sort. This -** can be a numeric constant, a constant address or a stack variable address. -*/ -{ - return (Expr->Flags & E_MASK_LOC) == E_LOC_NONE || ED_IsQuasiConstAddr (Expr); -} - - -int ED_IsConstAddr (const ExprDesc* Expr) -/* Return true if the expression denotes a constant address of some sort. This -** can be the address of a global variable (maybe with offset) or similar. -*/ -{ - return ED_IsAddrExpr (Expr) && ED_IsLocConst (Expr); -} - - - -int ED_IsQuasiConstAddr (const ExprDesc* Expr) -/* Return true if the expression denotes a quasi-constant address of some sort. -** This can be a constant address or a stack variable address. -*/ -{ - return ED_IsAddrExpr (Expr) && ED_IsLocQuasiConst (Expr); -} - - - -int ED_IsNullPtr (const ExprDesc* Expr) -/* Return true if the given expression is a NULL pointer constant */ -{ - return (Expr->Flags & (E_MASK_LOC|E_MASK_RTYPE)) == - (E_LOC_NONE|E_RTYPE_RVAL) && - Expr->IVal == 0 && - IsClassInt (Expr->Type); -} - - - -int ED_IsBool (const ExprDesc* Expr) -/* Return true if the expression can be treated as a boolean, that is, it can -** be an operand to a compare operation. -*/ -{ - /* Either ints, floats, or pointers can be used in a boolean context */ - return IsClassInt (Expr->Type) || - IsClassFloat (Expr->Type) || - IsClassPtr (Expr->Type) || - IsClassFunc (Expr->Type); -} +/*****************************************************************************/ +/* Other Helpers */ +/*****************************************************************************/ @@ -577,10 +591,21 @@ void PrintExprDesc (FILE* F, ExprDesc* E) -const Type* ReplaceType (ExprDesc* Expr, const Type* NewType) -/* Replace the type of Expr by a copy of Newtype and return the old type string */ +void ED_SetCodeRange (ExprDesc* Expr, const CodeMark* Start, const CodeMark* End) +/* Set the code range for this expression */ { - const Type* OldType = Expr->Type; - Expr->Type = TypeDup (NewType); - return OldType; + Expr->Flags |= E_HAVE_MARKS; + Expr->Start = *Start; + Expr->End = *End; +} + + + +int ED_CodeRangeIsEmpty (const ExprDesc* Expr) +/* Return true if no code was output for this expression */ +{ + /* We must have code marks */ + PRECONDITION (Expr->Flags & E_HAVE_MARKS); + + return CodeRangeIsEmpty (&Expr->Start, &Expr->End); } diff --git a/src/cc65/exprdesc.h b/src/cc65/exprdesc.h index f1f121cc4..2ef8b617f 100644 --- a/src/cc65/exprdesc.h +++ b/src/cc65/exprdesc.h @@ -227,6 +227,14 @@ struct ExprDesc { ExprDesc* ED_Init (ExprDesc* Expr); /* Initialize an ExprDesc */ + + +/*****************************************************************************/ +/* Info Extraction */ +/*****************************************************************************/ + + + #if defined(HAVE_INLINE) INLINE int ED_GetLoc (const ExprDesc* Expr) /* Return the location flags from the expression */ @@ -237,6 +245,35 @@ INLINE int ED_GetLoc (const ExprDesc* Expr) # define ED_GetLoc(Expr) ((Expr)->Flags & E_MASK_LOC) #endif +#if defined(HAVE_INLINE) +INLINE int ED_GetNeeds (const ExprDesc* Expr) +/* Get flags about what the expression needs. */ +{ + return (Expr->Flags & E_MASK_NEED); +} +#else +# define ED_GetNeeds(Expr) ((Expr)->Flags & E_MASK_NEED) +#endif + +const char* ED_GetLabelName (const ExprDesc* Expr, long Offs); +/* Return the assembler label name of the given expression. Beware: This +** function may use a static buffer, so the name may get "lost" on the second +** call to the function. +*/ + +int ED_GetStackOffs (const ExprDesc* Expr, int Offs); +/* Get the stack offset of an address on the stack in Expr taking into account +** an additional offset in Offs. +*/ + + + +/*****************************************************************************/ +/* Predicates */ +/*****************************************************************************/ + + + #if defined(HAVE_INLINE) INLINE int ED_IsLocNone (const ExprDesc* Expr) /* Return true if the expression is an absolute value */ @@ -279,7 +316,7 @@ INLINE int ED_IsLocStack (const ExprDesc* Expr) #if defined(HAVE_INLINE) INLINE int ED_IsLocPrimary (const ExprDesc* Expr) -/* Return true if the expression is an expression in the register pseudo variable */ +/* Return true if the expression is an expression in the primary */ { return (Expr->Flags & E_MASK_LOC) == E_LOC_PRIMARY; } @@ -289,7 +326,7 @@ INLINE int ED_IsLocPrimary (const ExprDesc* Expr) #if defined(HAVE_INLINE) INLINE int ED_IsLocExpr (const ExprDesc* Expr) -/* Return true if the expression is an expression in the primary */ +/* Return true if the expression is an expression referenced in the primary */ { return (Expr->Flags & E_MASK_LOC) == E_LOC_EXPR; } @@ -333,33 +370,14 @@ int ED_IsLocQuasiConst (const ExprDesc* Expr); #endif #if defined(HAVE_INLINE) -INLINE void ED_RequireTest (ExprDesc* Expr) -/* Mark the expression for a test. */ +INLINE int ED_IsLocPrimaryOrExpr (const ExprDesc* Expr) +/* Return true if the expression is E_LOC_PRIMARY or E_LOC_EXPR */ { - Expr->Flags |= E_NEED_TEST; + return ED_IsLocPrimary (Expr) || ED_IsLocExpr (Expr); } #else -# define ED_RequireTest(Expr) do { (Expr)->Flags |= E_NEED_TEST; } while (0) -#endif - -#if defined(HAVE_INLINE) -INLINE void ED_RequireNoTest (ExprDesc* Expr) -/* Mark the expression not for a test. */ -{ - Expr->Flags &= ~E_NEED_TEST; -} -#else -# define ED_RequireNoTest(Expr) do { (Expr)->Flags &= ~E_NEED_TEST; } while (0) -#endif - -#if defined(HAVE_INLINE) -INLINE int ED_GetNeeds (const ExprDesc* Expr) -/* Get flags about what the expression needs. */ -{ - return (Expr->Flags & E_MASK_NEED); -} -#else -# define ED_GetNeeds(Expr) ((Expr)->Flags & E_MASK_NEED) +int ED_IsLocPrimaryOrExpr (const ExprDesc* Expr); +/* Return true if the expression is E_LOC_PRIMARY or E_LOC_EXPR */ #endif #if defined(HAVE_INLINE) @@ -382,27 +400,6 @@ INLINE int ED_NeedsTest (const ExprDesc* Expr) # define ED_NeedsTest(Expr) (((Expr)->Flags & E_NEED_TEST) != 0) #endif -#if defined(HAVE_INLINE) -INLINE int ED_YetToTest (const ExprDesc* Expr) -/* Check if the expression needs to be tested but not yet. */ -{ - return ((Expr)->Flags & (E_NEED_TEST | E_CC_SET)) == E_NEED_TEST; -} -#else -# define ED_YetToTest(Expr) (((Expr)->Flags & (E_NEED_TEST | E_CC_SET)) == E_NEED_TEST) -#endif - -#if defined(HAVE_INLINE) -INLINE void ED_TestDone (ExprDesc* Expr) -/* Mark the expression as tested and condition codes set. */ -{ - Expr->Flags |= E_CC_SET; -} -#else -# define ED_TestDone(Expr) \ - do { (Expr)->Flags |= E_CC_SET; } while (0) -#endif - #if defined(HAVE_INLINE) INLINE int ED_IsTested (const ExprDesc* Expr) /* Check if the expression has set the condition codes. */ @@ -414,13 +411,13 @@ INLINE int ED_IsTested (const ExprDesc* Expr) #endif #if defined(HAVE_INLINE) -INLINE void ED_MarkAsUntested (ExprDesc* Expr) -/* Mark the expression as not tested (condition codes not set). */ +INLINE int ED_YetToTest (const ExprDesc* Expr) +/* Check if the expression needs to be tested but not yet. */ { - Expr->Flags &= ~E_CC_SET; + return ((Expr)->Flags & (E_NEED_TEST | E_CC_SET)) == E_NEED_TEST; } #else -# define ED_MarkAsUntested(Expr) do { (Expr)->Flags &= ~E_CC_SET; } while (0) +# define ED_YetToTest(Expr) (((Expr)->Flags & (E_NEED_TEST | E_CC_SET)) == E_NEED_TEST) #endif #if defined(HAVE_INLINE) @@ -448,9 +445,6 @@ INLINE int ED_NeedsConst (const ExprDesc* Expr) # define ED_NeedsConst(Expr) (((Expr)->Flags & E_EVAL_IMMUTABLE_RESULT) == E_EVAL_IMMUTABLE_RESULT) #endif -void ED_MarkForUneval (ExprDesc* Expr); -/* Mark the expression as not to be evaluated */ - #if defined(HAVE_INLINE) INLINE int ED_IsUneval (const ExprDesc* Expr) /* Check if the expression is not to be evaluated */ @@ -471,27 +465,6 @@ INLINE int ED_MayHaveNoEffect (const ExprDesc* Expr) # define ED_MayHaveNoEffect(Expr) (((Expr)->Flags & E_EVAL_MAYBE_UNUSED) == E_EVAL_MAYBE_UNUSED) #endif -#if defined(HAVE_INLINE) -INLINE void ED_PropagateFrom (ExprDesc* Expr, const ExprDesc* SubExpr) -/* Propagate viral flags from subexpression */ -{ - Expr->Flags |= SubExpr->Flags & E_MASK_VIRAL; -} -#else -# define ED_PropagateFrom(Expr, SubExpr) (void)((Expr)->Flags |= (SubExpr)->Flags & E_MASK_VIRAL) -#endif - -#if defined(HAVE_INLINE) -INLINE int ED_IsLocPrimaryOrExpr (const ExprDesc* Expr) -/* Return true if the expression is E_LOC_PRIMARY or E_LOC_EXPR */ -{ - return ED_IsLocPrimary (Expr) || ED_IsLocExpr (Expr); -} -#else -int ED_IsLocPrimaryOrExpr (const ExprDesc* Expr); -/* Return true if the expression is E_LOC_PRIMARY or E_LOC_EXPR */ -#endif - #if defined(HAVE_INLINE) INLINE int ED_IsAddrExpr (const ExprDesc* Expr) /* Check if the expression is taken address of instead of its value. @@ -515,35 +488,6 @@ int ED_IsIndExpr (const ExprDesc* Expr); /* Check if the expression is a reference to its value */ #endif -void ED_SetCodeRange (ExprDesc* Expr, const CodeMark* Start, const CodeMark* End); -/* Set the code range for this expression */ - -int ED_CodeRangeIsEmpty (const ExprDesc* Expr); -/* Return true if no code was output for this expression */ - -const char* ED_GetLabelName (const ExprDesc* Expr, long Offs); -/* Return the assembler label name of the given expression. Beware: This -** function may use a static buffer, so the name may get "lost" on the second -** call to the function. -*/ - -int ED_GetStackOffs (const ExprDesc* Expr, int Offs); -/* Get the stack offset of an address on the stack in Expr taking into account -** an additional offset in Offs. -*/ - -ExprDesc* ED_MakeConstAbs (ExprDesc* Expr, long Value, const Type* Type); -/* Replace Expr with an absolute const with the given value and type */ - -ExprDesc* ED_MakeConstAbsInt (ExprDesc* Expr, long Value); -/* Replace Expr with an constant integer with the given value */ - -ExprDesc* ED_MakeConstBool (ExprDesc* Expr, long Value); -/* Replace Expr with a constant boolean expression with the given value */ - -ExprDesc* ED_FinalizeRValLoad (ExprDesc* Expr); -/* Finalize the result of LoadExpr to be an rvalue in the primary register */ - #if defined(HAVE_INLINE) INLINE int ED_IsLVal (const ExprDesc* Expr) /* Return true if the expression is a reference */ @@ -564,40 +508,6 @@ INLINE int ED_IsRVal (const ExprDesc* Expr) # define ED_IsRVal(Expr) (((Expr)->Flags & E_MASK_RTYPE) == E_RTYPE_RVAL) #endif -#if defined(HAVE_INLINE) -INLINE void ED_MarkExprAsLVal (ExprDesc* Expr) -/* Mark the expression as an lvalue. -** HINT: Consider using ED_IndExpr instead of this, unless you know what -** consequence there will be, as there are both a big part in the code -** assuming rvalue = const and a big part assuming rvalue = address. -*/ -{ - Expr->Flags |= E_RTYPE_LVAL; -} -#else -# define ED_MarkExprAsLVal(Expr) do { (Expr)->Flags |= E_RTYPE_LVAL; } while (0) -#endif - -#if defined(HAVE_INLINE) -INLINE void ED_MarkExprAsRVal (ExprDesc* Expr) -/* Mark the expression as an rvalue. -** HINT: Consider using ED_AddrExpr instead of this, unless you know what -** consequence there will be, as there are both a big part in the code -** assuming rvalue = const and a big part assuming rvalue = address. -*/ -{ - Expr->Flags &= ~E_RTYPE_LVAL; -} -#else -# define ED_MarkExprAsRVal(Expr) do { (Expr)->Flags &= ~E_RTYPE_LVAL; } while (0) -#endif - -ExprDesc* ED_AddrExpr (ExprDesc* Expr); -/* Take address of Expr */ - -ExprDesc* ED_IndExpr (ExprDesc* Expr); -/* Dereference Expr */ - #if defined(HAVE_INLINE) INLINE int ED_IsAbs (const ExprDesc* Expr) /* Return true if the expression denotes a numeric value or address. */ @@ -670,14 +580,136 @@ int ED_IsBool (const ExprDesc* Expr); ** be an operand to a compare operation with 0/NULL. */ -void PrintExprDesc (FILE* F, ExprDesc* Expr); -/* Print an ExprDesc */ + + +/*****************************************************************************/ +/* Manipulation */ +/*****************************************************************************/ + + + +ExprDesc* ED_MakeConstAbs (ExprDesc* Expr, long Value, const Type* Type); +/* Replace Expr with an absolute const with the given value and type */ + +ExprDesc* ED_MakeConstAbsInt (ExprDesc* Expr, long Value); +/* Replace Expr with an constant integer with the given value */ + +ExprDesc* ED_MakeConstBool (ExprDesc* Expr, long Value); +/* Replace Expr with a constant boolean expression with the given value */ + +ExprDesc* ED_FinalizeRValLoad (ExprDesc* Expr); +/* Finalize the result of LoadExpr to be an rvalue in the primary register */ + +#if defined(HAVE_INLINE) +INLINE void ED_MarkExprAsLVal (ExprDesc* Expr) +/* Mark the expression as an lvalue. +** HINT: Consider using ED_IndExpr instead of this, unless you know what +** consequence there will be, as there are both a big part in the code +** assuming rvalue = const and a big part assuming rvalue = address. +*/ +{ + Expr->Flags |= E_RTYPE_LVAL; +} +#else +# define ED_MarkExprAsLVal(Expr) do { (Expr)->Flags |= E_RTYPE_LVAL; } while (0) +#endif + +#if defined(HAVE_INLINE) +INLINE void ED_MarkExprAsRVal (ExprDesc* Expr) +/* Mark the expression as an rvalue. +** HINT: Consider using ED_AddrExpr instead of this, unless you know what +** consequence there will be, as there are both a big part in the code +** assuming rvalue = const and a big part assuming rvalue = address. +*/ +{ + Expr->Flags &= ~E_RTYPE_LVAL; +} +#else +# define ED_MarkExprAsRVal(Expr) do { (Expr)->Flags &= ~E_RTYPE_LVAL; } while (0) +#endif + +ExprDesc* ED_AddrExpr (ExprDesc* Expr); +/* Take address of Expr */ + +ExprDesc* ED_IndExpr (ExprDesc* Expr); +/* Dereference Expr */ + +#if defined(HAVE_INLINE) +INLINE void ED_RequireTest (ExprDesc* Expr) +/* Mark the expression for a test. */ +{ + Expr->Flags |= E_NEED_TEST; +} +#else +# define ED_RequireTest(Expr) do { (Expr)->Flags |= E_NEED_TEST; } while (0) +#endif + +#if defined(HAVE_INLINE) +INLINE void ED_RequireNoTest (ExprDesc* Expr) +/* Mark the expression not for a test. */ +{ + Expr->Flags &= ~E_NEED_TEST; +} +#else +# define ED_RequireNoTest(Expr) do { (Expr)->Flags &= ~E_NEED_TEST; } while (0) +#endif + +#if defined(HAVE_INLINE) +INLINE void ED_TestDone (ExprDesc* Expr) +/* Mark the expression as tested and condition codes set. */ +{ + Expr->Flags |= E_CC_SET; +} +#else +# define ED_TestDone(Expr) \ + do { (Expr)->Flags |= E_CC_SET; } while (0) +#endif + +#if defined(HAVE_INLINE) +INLINE void ED_MarkAsUntested (ExprDesc* Expr) +/* Mark the expression as not tested (condition codes not set). */ +{ + Expr->Flags &= ~E_CC_SET; +} +#else +# define ED_MarkAsUntested(Expr) do { (Expr)->Flags &= ~E_CC_SET; } while (0) +#endif + +void ED_MarkForUneval (ExprDesc* Expr); +/* Mark the expression as not to be evaluated */ + +#if defined(HAVE_INLINE) +INLINE void ED_PropagateFrom (ExprDesc* Expr, const ExprDesc* SubExpr) +/* Propagate viral flags from subexpression */ +{ + Expr->Flags |= SubExpr->Flags & E_MASK_VIRAL; +} +#else +# define ED_PropagateFrom(Expr, SubExpr) (void)((Expr)->Flags |= (SubExpr)->Flags & E_MASK_VIRAL) +#endif const Type* ReplaceType (ExprDesc* Expr, const Type* NewType); /* Replace the type of Expr by a copy of Newtype and return the old type string */ +/*****************************************************************************/ +/* Other Helpers */ +/*****************************************************************************/ + + + +void PrintExprDesc (FILE* F, ExprDesc* Expr); +/* Print an ExprDesc */ + +void ED_SetCodeRange (ExprDesc* Expr, const CodeMark* Start, const CodeMark* End); +/* Set the code range for this expression */ + +int ED_CodeRangeIsEmpty (const ExprDesc* Expr); +/* Return true if no code was output for this expression */ + + + /* End of exprdesc.h */ #endif diff --git a/src/cc65/function.c b/src/cc65/function.c index 452181af9..737b068a3 100644 --- a/src/cc65/function.c +++ b/src/cc65/function.c @@ -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; diff --git a/src/cc65/global.c b/src/cc65/global.c index 8b9838dc5..b2c3ef0a0 100644 --- a/src/cc65/global.c +++ b/src/cc65/global.c @@ -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 */ diff --git a/src/cc65/global.h b/src/cc65/global.h index 266035346..ba7105130 100644 --- a/src/cc65/global.h +++ b/src/cc65/global.h @@ -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 */ diff --git a/src/cc65/initdata.c b/src/cc65/initdata.c index 99dacdca9..2b151e59e 100644 --- a/src/cc65/initdata.c +++ b/src/cc65/initdata.c @@ -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; } } diff --git a/src/cc65/input.c b/src/cc65/input.c index 0e8fc3276..89c471687 100644 --- a/src/cc65/input.c +++ b/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); diff --git a/src/cc65/input.h b/src/cc65/input.h index fb24bbaa8..9457bdf9b 100644 --- a/src/cc65/input.h +++ b/src/cc65/input.h @@ -41,6 +41,7 @@ #include /* 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); diff --git a/src/cc65/loadexpr.c b/src/cc65/loadexpr.c index ccd694e35..c5ac43f78 100644 --- a/src/cc65/loadexpr.c +++ b/src/cc65/loadexpr.c @@ -36,6 +36,7 @@ /* cc65 */ #include "codegen.h" #include "error.h" +#include "expr.h" #include "exprdesc.h" #include "global.h" #include "loadexpr.h" diff --git a/src/cc65/locals.c b/src/cc65/locals.c index ad36bded0..68ac00e62 100644 --- a/src/cc65/locals.c +++ b/src/cc65/locals.c @@ -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 */ diff --git a/src/cc65/macrotab.c b/src/cc65/macrotab.c index 0e80cd638..3bfae0811 100644 --- a/src/cc65/macrotab.c +++ b/src/cc65/macrotab.c @@ -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; } } diff --git a/src/cc65/macrotab.h b/src/cc65/macrotab.h index 6a09d7281..52b812b2f 100644 --- a/src/cc65/macrotab.h +++ b/src/cc65/macrotab.h @@ -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. */ diff --git a/src/cc65/ppexpr.c b/src/cc65/ppexpr.c index dd129ced9..8d8c0b65d 100644 --- a/src/cc65/ppexpr.c +++ b/src/cc65/ppexpr.c @@ -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; diff --git a/src/cc65/pragma.c b/src/cc65/pragma.c index b0478ce2a..83ed362c8 100644 --- a/src/cc65/pragma.c +++ b/src/cc65/pragma.c @@ -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); } diff --git a/src/cc65/preproc.c b/src/cc65/preproc.c index 020df011a..0a9b94bf2 100644 --- a/src/cc65/preproc.c +++ b/src/cc65/preproc.c @@ -74,11 +74,20 @@ #define MSM_IN_DIRECTIVE 0x02U /* In PP directives scan */ #define MSM_IN_ARG_LIST 0x04U /* In macro argument scan */ #define MSM_IN_ARG_EXPANSION 0x08U /* In expansion on arguments */ -#define MSM_OP_DEFINED 0x10U /* Handle the defined operator */ -#define MSM_OP_HAS_INCLUDE 0x20U /* Handle the __has_include operator */ -#define MSM_OP_HAS_C_ATTRIBUTE 0x40U /* Handle the __has_c_attribute operator */ +#define MSM_OP_DEFINED 0x10U /* Handle the "defined" operator */ +#define MSM_OP_HAS_INCLUDE 0x20U /* Handle the "__has_include" operator */ +#define MSM_OP_HAS_C_ATTRIBUTE 0x40U /* Handle the "__has_c_attribute" operator */ #define MSM_TOK_HEADER 0x80U /* Support header tokens */ +/* Macro expansion state flags */ +#define MES_NONE 0x00U /* Nothing */ +#define MES_FIRST_TOKEN 0x01U /* Mark for detecting pp-token count in the sequence */ +#define MES_MULTIPLE_TOKEN 0x02U /* Multiple pp-tokens are detected in the sequence */ +#define MES_BEGIN_WITH_IDENT 0x04U /* The first pp-token of the sequence is an identifier */ +#define MES_HAS_REPLACEMENT 0x10U /* Macro argument has cached replacement result */ +#define MES_NO_VA_COMMA 0x20U /* Variadic macro called w/o the ',' in front of variable argument */ +#define MES_ERROR 0x80U /* Error has occurred in macro expansion */ + /* Management data for #if */ #define IFCOND_NONE 0x00U #define IFCOND_SKIP 0x01U @@ -88,20 +97,52 @@ /* Current PP if stack */ static PPIfStack* PPStack; +/* Struct for rescan */ +typedef struct RescanInputStack RescanInputStack; +struct RescanInputStack { + Collection Lines; + Collection LastTokLens; + StrBuf* PrevTok; +}; + +/* Input backup for rescan */ +static RescanInputStack* CurRescanStack; + /* Intermediate input buffers */ static StrBuf* PLine; /* Buffer for macro expansion */ static StrBuf* MLine; /* Buffer for macro expansion in #pragma */ static StrBuf* OLine; /* Buffer for #pragma output */ /* Newlines to be added to preprocessed text */ -static int PendingNewLines; +static unsigned PendingNewLines; +static unsigned ContinuedLines; static int FileChanged; /* Structure used when expanding macros */ typedef struct MacroExp MacroExp; struct MacroExp { - Collection ActualArgs; /* Actual arguments */ - StrBuf Replacement; /* Replacement with arguments substituted */ + Collection Args; /* Actual arguments (for function-like) */ + Collection HideSets; /* Macros hidden from expansion */ + StrBuf Tokens; /* Originally read sequence */ + unsigned IdentCount; /* Count of identifiers in the pp-token sequence */ + unsigned Flags; /* Macro argument flags */ + MacroExp* Replaced; /* Macro-replaced version of this pp-token sequence */ + unsigned FirstTokLen; /* Length of the first pp-token */ + unsigned LastTokLen; /* Length of the last pp-token */ +}; + +typedef struct HideRange HideRange; +struct HideRange +{ + HideRange* Next; + unsigned Start; + unsigned End; +}; + +typedef struct HiddenMacro HiddenMacro; +struct HiddenMacro { + const Macro* M; + HideRange* HS; }; @@ -125,8 +166,26 @@ static void PreprocessDirective (StrBuf* Source, StrBuf* Target, unsigned ModeFl static int ParseDirectives (unsigned ModeFlags); /* Handle directives. Return 1 if any whitespace or newlines are parsed. */ -static void MacroReplacement (StrBuf* Source, StrBuf* Target, unsigned ModeFlags); -/* Scan for and perform macro replacement */ +static unsigned ReplaceMacros (StrBuf* Source, StrBuf* Target, MacroExp* E, unsigned ModeFlags); +/* Scan for and perform macro replacement. Return the count of identifiers and +** right parentheses in the replacement result. +*/ + +static MacroExp* InitMacroExp (MacroExp* E); +/* Initialize a MacroExp structure */ + +static void DoneMacroExp (MacroExp* E); +/* Cleanup after use of a MacroExp structure */ + +static int CheckPastePPTok (StrBuf* Target, unsigned TokLen, char Next); +/* Return 1 if the last pp-tokens from Source could be concatenated with any +** characters from Appended to form a new valid one. +*/ + +static void LazyCheckNextPPTok (const StrBuf* Prev, unsigned LastTokLen); +/* Memorize the previous pp-token(s) to later check for potential pp-token +** concatenation. +*/ @@ -201,17 +260,451 @@ static ppdirective_t FindPPDirectiveType (const char* Ident) +/*****************************************************************************/ +/* MacroExp helpers */ +/*****************************************************************************/ + + + +static HideRange* NewHideRange (unsigned Start, unsigned Len) +/* Create a hide range */ +{ + HideRange* HS = xmalloc (sizeof (HideRange)); + + HS->Next = 0; + HS->Start = Start; + HS->End = Start + Len; + + return HS; +} + + + +static void FreeHideRange (HideRange* HS) +/* Free a hide range */ +{ + xfree (HS); +} + + + +static HiddenMacro* NewHiddenMacro (const Macro* M) +/* Create a new struct for the hidden macro */ +{ + HiddenMacro* MHS = xmalloc (sizeof (HiddenMacro)); + + MHS->M = M; + MHS->HS = 0; + + return MHS; +} + + + +static void FreeHiddenMacro (HiddenMacro* MHS) +/* Free the struct and all ranges of the hidden macro */ +{ + HideRange* This; + HideRange* Next; + + if (MHS == 0) { + return; + } + + for (This = MHS->HS; This != 0; This = Next) { + Next = This->Next; + FreeHideRange (This); + } + + xfree (MHS); +} + + + /*****************************************************************************/ /* struct MacroExp */ /*****************************************************************************/ +static HiddenMacro* ME_FindHiddenMacro (const MacroExp* E, const Macro* M) +/* Find the macro hide set */ +{ + unsigned I; + + for (I = 0; I < CollCount (&E->HideSets); ++I) { + HiddenMacro* MHS = CollAtUnchecked (&E->HideSets, I); + if (MHS->M == M) { + return MHS; + } + } + + return 0; +} + + + +static void ME_HideMacro (unsigned Idx, unsigned Count, MacroExp* E, const Macro* M) +/* Hide the macro from the Idx'th identifier */ +{ + if (Count > 0) { + /* Find the macro hideset */ + HiddenMacro* MHS = ME_FindHiddenMacro (E, M); + HideRange** This; + + /* New hidden section */ + HideRange* NewHS = NewHideRange (Idx, Count); + + /* New macro to hide */ + if (MHS == 0) { + MHS = NewHiddenMacro (M); + CollAppend (&E->HideSets, MHS); + } + This = &MHS->HS; + + if (*This == 0) { + *This = NewHS; + } else { + /* Insert */ + while (1) { + if (*This == 0 || NewHS->Start <= (*This)->Start) { + /* Insert before */ + NewHS->Next = *This; + *This = NewHS; + break; + } else if (NewHS->Start <= (*This)->End) { + /* Insert after */ + NewHS->Next = (*This)->Next; + (*This)->Next = NewHS; + break; + } + /* Advance */ + This = &(*This)->Next; + } + + /* Merge */ + while (*This != 0) { + HideRange* Next = (*This)->Next; + + if (Next != 0 && (*This)->End >= Next->Start) { + /* Expand this to the next */ + if ((*This)->End < Next->End) { + (*This)->End = Next->End; + } + + /* Remove next */ + (*This)->Next = Next->Next; + FreeHideRange (Next); + + /* Advance */ + This = &(*This)->Next; + } else { + /* No more */ + break; + } + } + } + } +} + + + +static int ME_CanExpand (unsigned Idx, const MacroExp* E, const Macro* M) +/* Return 1 if the macro can be expanded with the Idx'th identifier */ +{ + if (E != 0) { + /* Find the macro hideset */ + HiddenMacro* MHS = ME_FindHiddenMacro (E, M); + if (MHS != 0) { + /* Check if the macro is hidden from this identifier */ + HideRange* HS = MHS->HS; + while (HS != 0) { + /* If the macro name overlaps with the range where the macro is hidden, + ** the macro cannot be expanded. + */ + if (Idx >= HS->Start && Idx < HS->End) { + return 0; + } + HS = HS->Next; + } + } + } + + return 1; +} + + + +static void ME_OffsetHideSets (unsigned Idx, unsigned Offs, MacroExp* E) +/* Adjust all macro hide set ranges for the macro expansion when the identifier +** at Idx is replaced with a count of Offs + 1 (if Offs > 0) of identifiers. +*/ +{ + if (Offs != 0) { + unsigned I; + + for (I = 0; I < CollCount (&E->HideSets); ++I) { + HiddenMacro* MHS = CollAtUnchecked (&E->HideSets, I); + HideRange* This; + + for (This = MHS->HS; This != 0; This = This->Next) { + if (Idx < This->Start) { + This->Start += Offs; + This->End += Offs; + } else if (Idx < This->End) { + This->End += Offs; + } + } + } + } +} + + + +static void ME_RemoveToken (unsigned Idx, unsigned Count, MacroExp* E) +/* Remove the Idx'th identifier token from tracking and offset all hidden +** ranges accordingly. +*/ +{ + unsigned I; + + for (I = 0; I < CollCount (&E->HideSets); ++I) { + HiddenMacro* MHS = CollAtUnchecked (&E->HideSets, I); + HideRange* This; + HideRange** Prev; + + for (Prev = &MHS->HS, This = *Prev; This != 0; This = *Prev) { + if (Idx < This->Start) { + if (This->Start - Idx >= Count) { + This->Start -= Count; + This->End -= Count; + } else { + if (This->End - Idx > Count) { + This->Start = Idx; + This->End -= Count; + } else { + /* Remove */ + (*Prev) = This->Next; + FreeHideRange (This); + continue; + } + } + } else if (Idx < This->End) { + if (This->End - Idx > Count) { + This->End -= Count; + } else { + This->End = Idx; + } + + if (This->End == This->Start) { + /* Remove */ + (*Prev) = This->Next; + FreeHideRange (This); + continue; + } + } + + Prev = &This->Next; + } + } +} + + + +static void ME_HandleSemiNestedMacro (unsigned NameIdx, unsigned LastIdx, MacroExp* E) +/* Unhide the macro name from all hidesets if it was expanded with an unhidden +** right parenthesis. This is unspecified but allowed behavior according to +** ISO/IEC 9899:2018, 6.10.3.4ff. +*/ +{ + unsigned I; + + for (I = 0; I < CollCount (&E->HideSets); ++I) { + HiddenMacro* MHS = CollAtUnchecked (&E->HideSets, I); + HideRange* This; + HideRange** Prev; + + for (Prev = &MHS->HS, This = *Prev; This != 0; This = *Prev) { + if (NameIdx < This->End) { + if (NameIdx >= This->Start && LastIdx >= This->End) { + This->End = NameIdx; + if (This->End == This->Start) { + /* Remove */ + (*Prev) = This->Next; + FreeHideRange (This); + continue; + } + } + Prev = &This->Next; + } else { + break; + } + } + } +} + + + +static void ME_AddArgHideSets (unsigned Idx, const MacroExp* A, MacroExp* Parent) +/* Propagate the macro hide sets of the substituted argument starting as the +** Idx'th identifier of the result. +*/ +{ + unsigned I; + + /* Move the hide set generated with in the argument as it will be freed later */ + for (I = 0; I < CollCount (&A->HideSets); ++I) { + HiddenMacro* MHS = CollAtUnchecked (&A->HideSets, I); + HideRange* HS; + + for (HS = MHS->HS; HS != 0; HS = HS->Next) { + ME_HideMacro (Idx + HS->Start, HS->End - HS->Start, Parent, MHS->M); + } + } +} + + + +static void ME_DoneHideSets (MacroExp* E) +/* Free all of hidden macros for the macro expansion */ +{ + unsigned I; + + for (I = 0; I < CollCount (&E->HideSets); ++I) { + HiddenMacro* MHS = CollAtUnchecked (&E->HideSets, I); + FreeHiddenMacro (MHS); + } + DoneCollection (&E->HideSets); +} + + + +static void ME_SetTokLens (MacroExp* E, unsigned TokLen) +/* Set token lengths and flags for macro expansion struct */ +{ + E->LastTokLen = TokLen; + if ((E->Flags & MES_FIRST_TOKEN) != 0) { + E->Flags &= ~MES_FIRST_TOKEN; + E->FirstTokLen = E->LastTokLen; + } else { + E->Flags |= MES_MULTIPLE_TOKEN; + } +} + + + +static MacroExp* ME_MakeReplaced (MacroExp* A) +/* Make a replaced version of the argument */ +{ + /* Replace the parameter with actual argument tokens */ + if ((A->Flags & MES_HAS_REPLACEMENT) == 0) { + A->Replaced = xmalloc (sizeof (MacroExp)); + + InitMacroExp (A->Replaced); + SB_Reset (&A->Tokens); + + /* Propagate the hide sets */ + ME_AddArgHideSets (0, A, A->Replaced); + + /* Do macro expansion on the argument */ + A->Replaced->IdentCount = ReplaceMacros (&A->Tokens, + &A->Replaced->Tokens, + A->Replaced, + MSM_IN_ARG_EXPANSION); + + A->Flags |= MES_HAS_REPLACEMENT; + } + + return A->Replaced != 0 ? A->Replaced : A; +} + + + +static MacroExp* ME_GetOriginalArg (const MacroExp* E, unsigned Index) +/* Return an actual macro argument with the given index */ +{ + return CollAt (&E->Args, Index); +} + + + +static MacroExp* ME_GetReplacedArg (const MacroExp* E, unsigned Index) +/* Return a replaced macro argument with the given index */ +{ + return ME_MakeReplaced (CollAt (&E->Args, Index)); +} + + + +static MacroExp* ME_AppendArg (MacroExp* E, MacroExp* Arg) +/* Add a copy of Arg to the list of actual macro arguments. +** NOTE: This function will clear the token sequence of Arg! +*/ +{ + MacroExp* A = xmalloc (sizeof (MacroExp)); + + /* Initialize our MacroExp structure */ + InitMacroExp (A); + + /* Copy info about the original strings */ + A->IdentCount = Arg->IdentCount; + A->Flags = Arg->Flags; + A->FirstTokLen = Arg->FirstTokLen; + A->LastTokLen = Arg->LastTokLen; + + /* Move the contents of Arg to A */ + SB_Move (&A->Tokens, &Arg->Tokens); + + /* Add A to the list of actual arguments */ + CollAppend (&E->Args, A); + + return A; +} + + + +static void ME_ClearArgs (MacroExp* E) +/* Clear all read arguments for macro expansion */ +{ + unsigned I; + + /* Delete the list with actual arguments */ + for (I = 0; I < CollCount (&E->Args); ++I) { + MacroExp* A = CollAtUnchecked (&E->Args, I); + + /* Destroy the macro expansion structure and then free memory allocated + ** for it. + */ + DoneMacroExp (A); + xfree (A); + } + + DoneCollection (&E->Args); + InitCollection (&E->Args); +} + + + +static int ME_IsNextArgVariadic (const MacroExp* E, const Macro* M) +/* Return true if the next actual argument we will add is a variadic one */ +{ + return (M->Variadic && + M->ParamCount == (int) CollCount (&E->Args) + 1); +} + + + static MacroExp* InitMacroExp (MacroExp* E) /* Initialize a MacroExp structure */ { - InitCollection (&E->ActualArgs); - SB_Init (&E->Replacement); + InitCollection (&E->Args); + InitCollection (&E->HideSets); + SB_Init (&E->Tokens); + E->IdentCount = 0; + E->Flags = MES_FIRST_TOKEN; + E->Replaced = 0; + E->FirstTokLen = 0; + E->LastTokLen = 0; return E; } @@ -220,48 +713,70 @@ static MacroExp* InitMacroExp (MacroExp* E) static void DoneMacroExp (MacroExp* E) /* Cleanup after use of a MacroExp structure */ { - unsigned I; - - /* Delete the list with actual arguments */ - for (I = 0; I < CollCount (&E->ActualArgs); ++I) { - FreeStrBuf (CollAtUnchecked (&E->ActualArgs, I)); + ME_ClearArgs (E); + ME_DoneHideSets (E); + SB_Done (&E->Tokens); + if (E->Replaced != 0) { + DoneMacroExp (E->Replaced); } - DoneCollection (&E->ActualArgs); - SB_Done (&E->Replacement); } -static void ME_AppendActual (MacroExp* E, StrBuf* Arg) -/* Add a copy of Arg to the list of actual macro arguments. -** NOTE: This function will clear Arg! -*/ +/*****************************************************************************/ +/* Rescan input stack */ +/*****************************************************************************/ + + + +static void PushRescanLine (RescanInputStack* RIS, StrBuf* L, unsigned LastTokLen) +/* Push an input line to the rescan input stack */ { - /* Create a new string buffer */ - StrBuf* A = NewStrBuf (); - - /* Move the contents of Arg to A */ - SB_Move (A, Arg); - - /* Add A to the actual arguments */ - CollAppend (&E->ActualArgs, A); + CollAppend (&RIS->Lines, L); + /* Abuse the pointer to store an unsigned */ + CollAppend (&RIS->LastTokLens, (void*)(uintptr_t)LastTokLen); } -static StrBuf* ME_GetActual (MacroExp* E, unsigned Index) -/* Return an actual macro argument with the given index */ +static void PopRescanLine (void) +/* Pop and free a rescan input line if it reaches the end */ { - return CollAt (&E->ActualArgs, Index); + if (CurC == '\0' && CollCount (&CurRescanStack->Lines) > 1) { + FreeStrBuf (CollPop (&CurRescanStack->Lines)); + InitLine (CollLast (&CurRescanStack->Lines)); + CollPop (&CurRescanStack->LastTokLens); + } } -static int ME_ArgIsVariadic (const MacroExp* E, const Macro* M) -/* Return true if the next actual argument we will add is a variadic one */ +static void InitRescanInputStack (RescanInputStack* RIS) +/* Init a RescanInputStack struct */ { - return (M->Variadic && - M->ArgCount == (int) CollCount (&E->ActualArgs) + 1); + InitCollection (&RIS->Lines); + InitCollection (&RIS->LastTokLens); + RIS->PrevTok = 0; +} + + + +static void DoneRescanInputStack (RescanInputStack* RIS) +/* Free a RescanInputStack struct. RIS must be non-NULL. */ +{ + /* Free pushed input lines */ + while (CollCount (&RIS->Lines) > 1) { + FreeStrBuf (CollPop (&RIS->Lines)); + } + /* Switch back to the old input stack */ + InitLine (CollPop (&RIS->Lines)); + + /* Free any remaining pp-tokens used for concatenation check */ + FreeStrBuf (RIS->PrevTok); + + /* Done */ + DoneCollection (&RIS->Lines); + DoneCollection (&RIS->LastTokLens); } @@ -292,21 +807,42 @@ static int MacName (char* Ident) +static void CheckForBadIdent (const char* Ident, int Std, const Macro* M) +/* Check for and warning on problematic identifiers */ +{ + if (Std >= STD_C99 && + (M == 0 || !M->Variadic) && + strcmp (Ident, "__VA_ARGS__") == 0) { + /* __VA_ARGS__ cannot be used as a macro parameter name in post-C89 + ** mode. + */ + PPWarning ("__VA_ARGS__ can only appear in the expansion of a C99 variadic macro"); + } +} + + + static void AddPreLine (StrBuf* Str) /* Add newlines to the string buffer */ { + /* No need to prettify the non-exist output */ if (!PreprocessOnly) { PendingNewLines = 0; + ContinuedLines = 0; return; } + /* We'll adjust the line number later if necessary */ + PendingNewLines += ContinuedLines; + if (FileChanged || PendingNewLines > 6) { /* Output #line directives as source info */ StrBuf Comment = AUTO_STRBUF_INITIALIZER; if (SB_NotEmpty (Str) && SB_LookAtLast (Str) != '\n') { SB_AppendChar (Str, '\n'); } - SB_Printf (&Comment, "#line %u \"%s\"\n", GetCurrentLine (), GetCurrentFile ()); + SB_Printf (&Comment, "#line %u \"%s\"\n", + GetCurrentLineNum () - ContinuedLines, GetCurrentFilename ()); SB_Append (Str, &Comment); } else { /* Output new lines */ @@ -317,6 +853,7 @@ static void AddPreLine (StrBuf* Str) } FileChanged = 0; PendingNewLines = 0; + ContinuedLines = 0; } @@ -364,12 +901,12 @@ static void Stringize (StrBuf* Source, StrBuf* Target) static void OldStyleComment (void) -/* Remove an old style C comment from line. */ +/* Remove an old style C comment from line */ { /* Remember the current line number, so we can output better error ** messages if the comment is not terminated in the current file. */ - unsigned StartingLine = GetCurrentLine (); + unsigned StartingLine = GetCurrentLineNum (); /* Skip the start of comment chars */ NextChar (); @@ -383,6 +920,7 @@ static void OldStyleComment (void) StartingLine); return; } + ++PendingNewLines; } else { if (CurC == '/' && NextC == '*') { PPWarning ("'/*' found inside a comment"); @@ -399,11 +937,13 @@ static void OldStyleComment (void) static void NewStyleComment (void) -/* Remove a new style C comment from line. */ +/* Remove a new style C comment from line */ { /* Diagnose if this is unsupported */ - if (IS_Get (&Standard) < STD_C99) { + if (IS_Get (&Standard) < STD_C99 && !AllowNewComments) { PPError ("C++ style comments are not allowed in C89"); + PPNote ("(this will be reported only once per input file)"); + AllowNewComments = 1; } /* Beware: Because line continuation chars are handled when reading @@ -431,6 +971,8 @@ static int SkipWhitespace (int SkipLines) { int Skipped = 0; int NewLine = 0; + + /* Rescanning */ while (1) { if (IsSpace (CurC)) { NextChar (); @@ -441,14 +983,51 @@ static int SkipWhitespace (int SkipLines) } else if (CurC == '/' && NextC == '/') { NewStyleComment (); Skipped = 1; - } else if (CurC == '\0' && SkipLines) { - /* End of line, read next */ - if (NextLine () != 0) { - ++PendingNewLines; - NewLine = 1; - Skipped = 0; + } else if (CurC == '\0') { + /* End of line */ + if (CurRescanStack != 0 && + CollCount (&CurRescanStack->Lines) > 1 && + Line == CollLast (&CurRescanStack->Lines)) { + + unsigned LastTokLen = (unsigned)(uintptr_t)CollLast (&CurRescanStack->LastTokLens); + + /* Check for potentially merged tokens */ + if (Skipped == 0 && LastTokLen != 0) { + /* Get the following input */ + StrBuf* Next = CollAtUnchecked (&CurRescanStack->Lines, + CollCount (&CurRescanStack->Lines) - 2); + char C = SB_Peek (Next); + + /* We cannot check right now if the next pp-token may be a + ** macro. + */ + if (IsIdent (C)) { + /* Memorize the previous pp-token and check it later */ + LazyCheckNextPPTok (Line, LastTokLen); + } else if (C != '\0' && !IsSpace (C)) { + /* If the two adjacent pp-tokens could be put together + ** to form a new one, we have to separate them with an + ** additional space. + */ + Skipped = CheckPastePPTok (Line, LastTokLen, SB_Peek (Next)); + } + + } + + /* switch back to previous input */ + PopRescanLine (); + + } else if (SkipLines) { + /* Read next line */ + if (NextLine () != 0) { + ++PendingNewLines; + NewLine = 1; + Skipped = 0; + } else { + /* End of input */ + break; + } } else { - /* End of input */ break; } } else { @@ -456,6 +1035,7 @@ static int SkipWhitespace (int SkipLines) break; } } + return Skipped != 0 ? Skipped : -(NewLine != 0); } @@ -490,11 +1070,28 @@ static void CopyHeaderNameToken (StrBuf* Target) +static int IsQuotedString (void) +/* Retrun 1 if the incoming characters indicate a string literal or character +** constant, otherwise return 0. +*/ +{ + return IsQuote (CurC) || IsWideQuoted (CurC, NextC); +} + + + static void CopyQuotedString (StrBuf* Target) /* Copy a single or double quoted string from the input to Target. */ { /* Remember the quote character, copy it to the target buffer and skip it */ - char Quote = CurC; + char Quote; + + if (CurC == 'L') { + SB_AppendChar (Target, CurC); + NextChar (); + } + + Quote = CurC; SB_AppendChar (Target, CurC); NextChar (); @@ -521,6 +1118,384 @@ static void CopyQuotedString (StrBuf* Target) +static int GetPunc (char* S) +/* Parse a punctuator token. Return 1 and store the parsed token string into S +** on success, otherwise just return 0. +*/ +{ + char C; + switch (CurC) { + + case '[': + case ']': + case '(': + case ')': + case '{': + case '}': + case '~': + case '?': + case ':': + case ';': + case ',': + /* C */ + *S++ = CurC; + NextChar (); + break; + + case '=': + case '#': + /* C or CC */ + C = *S++ = CurC; + NextChar (); + if (CurC == C) { + *S++ = C; + NextChar (); + } + break; + + case '*': + case '/': + case '%': + case '^': + case '!': + /* C or C= */ + *S++ = CurC; + NextChar (); + if (CurC == '=') { + *S++ = CurC; + NextChar (); + } + break; + + case '+': + case '&': + case '|': + /* C, CC or C= */ + C = *S++ = CurC; + NextChar (); + if (CurC == C || CurC == '=') { + *S++ = CurC; + NextChar (); + } + break; + + case '<': + case '>': + /* C, CC, C= or CC= */ + C = *S++ = CurC; + NextChar (); + if (CurC == C) { + *S++ = CurC; + if (NextC == '=') { + *S++ = NextC; + NextChar (); + } + NextChar (); + } else if (CurC == '=') { + *S++ = CurC; + NextChar (); + } + break; + + case '-': + /* C, CC, C= or C> */ + *S++ = CurC; + NextChar (); + switch (CurC) { + case '-': + case '=': + case '>': + *S++ = CurC; + NextChar (); + break; + default: + break; + } + break; + + case '.': + /* C or CCC */ + *S++ = CurC; + NextChar (); + if (CurC == '.' && NextC == '.') { + *S++ = CurC; + *S++ = NextC; + NextChar (); + NextChar (); + } + break; + + default: + return 0; + + } + + *S = '\0'; + return 1; +} + + + +static int CheckPastePPTok (StrBuf* Source, unsigned TokLen, char Next) +/* Return 1 if the last pp-tokens from Source could be concatenated with any +** characters from Appended to form a new valid one. +*/ +{ + char C; + unsigned NewTokLen; + StrBuf* OldSource; + StrBuf Src = AUTO_STRBUF_INITIALIZER; + StrBuf Buf = AUTO_STRBUF_INITIALIZER; + + if (TokLen == 0 || IsBlank (SB_LookAtLast (Source))) { + return 0; + } + + PRECONDITION (SB_GetLen (Source) >= TokLen); + + /* Special casing "..", "/ /" and "/ *" that are not pp-tokens but still + ** need be separated. + */ + C = SB_LookAt (Source, SB_GetLen (Source) - TokLen); + if ((C == '.' && Next == '.') || (C == '/' && (Next == '/' || Next == '*'))) { + return 1; + } + + SB_CopyBuf (&Src, SB_GetConstBuf (Source) + SB_GetLen (Source) - TokLen, TokLen); + SB_AppendChar (&Src, Next); + + SB_Reset (&Src); + OldSource = InitLine (&Src); + + if (IsPPNumber (CurC, NextC)) { + /* PP-number */ + CopyPPNumber (&Buf); + } else if (IsQuotedString ()) { + /* Quoted string */ + CopyQuotedString (&Buf); + } else { + ident Ident; + if (GetPunc (Ident)) { + /* Punctuator */ + SB_CopyStr (&Buf, Ident); + } else if (IsSym (Ident)) { + /* Identifier */ + SB_CopyStr (&Buf, Ident); + } + } + + NewTokLen = SB_GetLen (&Buf); + + SB_Done (&Buf); + SB_Done (&Src); + + /* Restore old source */ + InitLine (OldSource); + + /* Return if concatenation succeeded */ + return NewTokLen != TokLen; +} + + + +static int TryPastePPTok (StrBuf* Target, + StrBuf* Appended, + unsigned FirstTokLen, + unsigned SecondTokLen) +/* Paste the whole appened pp-token sequence onto the end of the target +** pp-token sequence. Diagnose if it fails to form a valid pp-token with the +** two pp-tokens pasted together. Return 1 if succeeds. +*/ +{ + unsigned TokLen; + StrBuf* OldSource; + StrBuf Src = AUTO_STRBUF_INITIALIZER; + StrBuf Buf = AUTO_STRBUF_INITIALIZER; + + if (FirstTokLen == 0 || SecondTokLen == 0) { + SB_Append (Target, Appended); + return 1; + } + + /* Since we need to concatenate the token sequences, remove the + ** last whitespace that was added to target, since it must come + ** from the input. + */ + if (IsBlank (SB_LookAtLast (Target))) { + SB_Drop (Target, 1); + } + + PRECONDITION (SB_GetLen (Target) >= FirstTokLen && + SB_GetLen (Appended) >= SecondTokLen); + + /* Special casing "..", "/ /" and "/ *" */ + if (FirstTokLen == 1) { + char C = SB_LookAt (Target, SB_GetLen (Target) - FirstTokLen); + char N = SB_LookAt (Appended, 0); + /* Avoid forming a comment introducer or an ellipsis. Note that an + ** ellipsis pp-token cannot be formed with macros anyway. + */ + if ((C == '.' && N == '.') || (C == '/' && (N == '/' || N == '*'))) { + SB_AppendChar (Target, ' '); + SB_Append (Target, Appended); + PPWarning ("Pasting formed \"%c%c\", an invalid preprocessing token", C, N); + + return 0; + } + } + + SB_CopyBuf (&Src, SB_GetConstBuf (Target) + SB_GetLen (Target) - FirstTokLen, FirstTokLen); + if (SecondTokLen == SB_GetLen (Appended) || IsSpace (SB_LookAt (Appended, SecondTokLen))) { + SB_AppendBuf (&Src, SB_GetConstBuf (Appended), SecondTokLen); + } else { + SB_AppendBuf (&Src, SB_GetConstBuf (Appended), SecondTokLen + 1); + } + + SB_Reset (&Src); + OldSource = InitLine (&Src); + + if (IsPPNumber (CurC, NextC)) { + /* PP-number */ + CopyPPNumber (&Buf); + } else if (IsQuotedString ()) { + /* Quoted string */ + CopyQuotedString (&Buf); + } else { + ident Ident; + if (GetPunc (Ident)) { + /* Punctuator */ + SB_CopyStr (&Buf, Ident); + } else if (IsSym (Ident)) { + /* Identifier */ + SB_CopyStr (&Buf, Ident); + } else { + /* Unknown */ + } + } + + TokLen = SB_GetLen (&Buf); + if (TokLen < FirstTokLen + SecondTokLen) { + /* The pasting doesn't form a valid pp-token */ + while (SB_GetLen (&Buf) < FirstTokLen + SecondTokLen) { + SB_AppendChar (&Buf, CurC); + NextChar (); + } + SB_Terminate (&Buf); + PPWarning ("Pasting formed \"%s\", an invalid preprocessing token", + SB_GetConstBuf (&Buf)); + + /* Add a space between the tokens to avoid problems in rescanning */ + if (TokLen > FirstTokLen) { + SB_AppendChar (Target, ' '); + } + /* Append all remaining tokens */ + SB_Append (Target, Appended); + + /* No concatenation */ + TokLen = FirstTokLen; + } else { + /* Add a space after the merged token if necessary */ + SB_AppendBuf (Target, SB_GetConstBuf (Appended), SecondTokLen); + if (TokLen > FirstTokLen + SecondTokLen) { + SB_AppendChar (Target, ' '); + } + /* Append all remaining tokens */ + SB_AppendBuf (Target, + SB_GetConstBuf (Appended) + SecondTokLen, + SB_GetLen (Appended) - SecondTokLen); + } + + SB_Done (&Buf); + SB_Done (&Src); + + /* Restore old source */ + InitLine (OldSource); + + /* Return if concatenation succeeded */ + return TokLen != FirstTokLen; +} + + + +static void SeparatePPTok (StrBuf* Target, char Next) +/* Add a space to target if the previous pp-token could be concatenated with +** the following character. +*/ +{ + if (CurRescanStack->PrevTok != 0) { + unsigned Len = SB_GetLen (CurRescanStack->PrevTok) - SB_GetIndex (CurRescanStack->PrevTok); + + /* Check for pp-token pasting */ + if (CheckPastePPTok (CurRescanStack->PrevTok, Len, Next)) { + SB_AppendChar (Target, ' '); + } + FreeStrBuf (CurRescanStack->PrevTok); + CurRescanStack->PrevTok = 0; + } +} + + + +static void LazyCheckNextPPTok (const StrBuf* Prev, unsigned LastTokLen) +/* Memorize the previous pp-token(s) to later check for potential pp-token +** concatenation. +*/ +{ + char C; + int CheckEllipsis = 0; + unsigned NewIndex = SB_GetLen (Prev) - LastTokLen; + + PRECONDITION (SB_GetLen (Prev) >= LastTokLen); + + /* Check for some special cases */ + C = SB_AtUnchecked (Prev, NewIndex); + + /* We may exclude certain punctuators for speedups. As newer C standards + ** could add more punctuators such as "[[", "]]", "::" and so on, this + ** check might need changes accordingly. + */ + if (C == '[' || C == ']' || C == '(' || C == ')' || + C == '{' || C == '}' || C == '~' || C == '?' || + C == ':' || C == ';' || C == ',') { + /* These punctuators cannot be concatenated */ + return; + } + + /* Special check for .. */ + if (NewIndex > 0 && + C == '.' && + SB_AtUnchecked (Prev, NewIndex - 1) == '.') { + /* Save the preceding '.' as well */ + CheckEllipsis = 1; + } + + if (CurRescanStack->PrevTok != 0) { + unsigned OldIndex = SB_GetIndex (CurRescanStack->PrevTok); + unsigned OldLen = SB_GetLen (CurRescanStack->PrevTok) - OldIndex; + unsigned NewLen = SB_GetLen (Prev) - NewIndex; + if (OldLen == NewLen && + strncmp (SB_GetConstBuf (CurRescanStack->PrevTok) + OldIndex - CheckEllipsis, + SB_GetConstBuf (Prev) + NewIndex - CheckEllipsis, + OldLen + CheckEllipsis) == 0) { + /* Same pp-token, keep using the old one */ + } else { + /* Logic error */ + SB_Terminate (CurRescanStack->PrevTok); + Internal ("Unchecked pp-token concatenation: \"%s\"", + SB_GetConstBuf (CurRescanStack->PrevTok) + SB_GetIndex (CurRescanStack->PrevTok)); + } + } else { + /* Memorize the current line */ + CurRescanStack->PrevTok = NewStrBuf (); + SB_CopyBuf (CurRescanStack->PrevTok, + SB_GetConstBuf (Prev) + NewIndex - CheckEllipsis, + LastTokLen + CheckEllipsis); + SB_Reset (CurRescanStack->PrevTok); + } +} + + + static int CheckExtraTokens (const char* Name) /* Check for extra tokens at the end of the directive. Return 1 if there are ** extra tokens, otherwise 0. @@ -542,317 +1517,629 @@ static int CheckExtraTokens (const char* Name) -static void ReadMacroArgs (MacroExp* E, const Macro* M, int MultiLine) -/* Identify the arguments to a macro call as-is */ +static unsigned ReadMacroArgs (unsigned NameIdx, MacroExp* E, const Macro* M, int MultiLine) +/* Identify the arguments to a macro call as-is. Return the total count of +** identifiers and right parentheses in the read argument list. +*/ { - int MissingParen = 0; - unsigned Parens; /* Number of open parenthesis */ - StrBuf Arg = AUTO_STRBUF_INITIALIZER; + unsigned Idx = 0; + unsigned CountInArg = 0; + unsigned Parens = 0; /* Number of open parenthesis */ + ident Ident; + MacroExp Arg; + + InitMacroExp (&Arg); /* Eat the left paren */ NextChar (); /* Read the actual macro arguments */ - Parens = 0; while (1) { /* Squeeze runs of blanks within an arg */ - int OldPendingNewLines = PendingNewLines; + unsigned OldPendingNewLines = PendingNewLines; int Skipped = SkipWhitespace (MultiLine); - if (MultiLine && CurC == '#') { - int Newlines = 0; - while (CurC == '#') { + /* Directives can only be found in an argument list that spans + ** multiple lines. + */ + if (MultiLine && OldPendingNewLines < PendingNewLines && CurC == '#') { + unsigned Newlines = 0; + + while (OldPendingNewLines < PendingNewLines && CurC == '#') { Newlines += PendingNewLines - OldPendingNewLines; PendingNewLines = OldPendingNewLines; OldPendingNewLines = 0; Skipped = ParseDirectives (MSM_IN_ARG_LIST) || Skipped; - Skipped = SkipWhitespace (MultiLine) || Skipped; } PendingNewLines += Newlines; } - if (Skipped && SB_NotEmpty (&Arg)) { - SB_AppendChar (&Arg, ' '); + + /* Append a space as a separator */ + if (Skipped && SB_NotEmpty (&Arg.Tokens)) { + SB_AppendChar (&Arg.Tokens, ' '); + Skipped = 1; + } else { + Skipped = 0; } - if (CurC == '(') { - /* Nested parenthesis */ - SB_AppendChar (&Arg, CurC); - NextChar (); - ++Parens; + /* Finish reading the current argument if we are not inside nested + ** parentheses or a variadic macro argument. + */ + if (Parens == 0 && + ((CurC == ',' && !ME_IsNextArgVariadic (E, M)) || CurC == ')')) { - } else if (IsQuote (CurC)) { - - /* Quoted string - just copy */ - CopyQuotedString (&Arg); - - } else if (CurC == ',' || CurC == ')') { - - if (Parens) { - /* Comma or right paren inside nested parenthesis */ - if (CurC == ')') { - --Parens; - } - SB_AppendChar (&Arg, CurC); - NextChar (); - } else if (CurC == ',' && ME_ArgIsVariadic (E, M)) { - /* It's a comma, but we're inside a variadic macro argument, so - ** just copy it and proceed. - */ - SB_AppendChar (&Arg, CurC); - NextChar (); - } else { - /* End of actual argument. Remove whitespace from the end. */ - while (IsSpace (SB_LookAtLast (&Arg))) { - SB_Drop (&Arg, 1); - } - - /* If this is not the single empty argument for a macro with - ** an empty argument list, remember it. - */ - if (CurC != ')' || SB_NotEmpty (&Arg) || M->ArgCount > 0) { - ME_AppendActual (E, &Arg); - } - - /* Check for end of macro param list */ - if (CurC == ')') { - NextChar (); - break; - } - - /* Start the next param */ - NextChar (); - SB_Clear (&Arg); + /* End of actual argument. Remove whitespace from the end. */ + while (IsBlank (SB_LookAtLast (&Arg.Tokens))) { + SB_Drop (&Arg.Tokens, 1); } + + /* If this is not the single empty argument for a macro with an + ** empty argument list, remember it. + */ + if (CurC != ')' || + CollCount (&E->Args) > 0 || + SB_NotEmpty (&Arg.Tokens) || + M->ParamCount > 0) { + MacroExp* A = ME_AppendArg (E, &Arg); + unsigned I; + + /* Copy the hide sets from the argument list */ + for (I = 0; I < CollCount (&E->HideSets); ++I) { + HiddenMacro* MHS = CollAtUnchecked (&E->HideSets, I); + HideRange* HS; + + for (HS = MHS->HS; HS != 0; HS = HS->Next) { + /* Get the correct hide range */ + unsigned Start = NameIdx + 1 + Idx; + unsigned Len; + if (HS->Start < Start) { + if (HS->End > Start) { + Len = HS->End - Start; + } else { + /* Out of the range */ + continue; + } + Start = 0; + } else { + Len = HS->End - HS->Start; + Start = HS->Start - Start; + } + if (Start + Len > Idx + CountInArg) { + if (Idx + CountInArg > Start) { + Len = Idx + CountInArg - Start; + } else { + /* Out of the range */ + break; + } + } + ME_HideMacro (Start, Len, A, MHS->M); + } + } + + /* More argument info */ + A->IdentCount = CountInArg; + } + + Idx += CountInArg; + + /* Check for end of macro param list */ + if (CurC == ')') { + /* Count right parens */ + ++Idx; + NextChar (); + break; + } + + /* Start the next param */ + NextChar (); + DoneMacroExp (&Arg); + InitMacroExp (&Arg); + CountInArg = 0; + + continue; + } else if (CurC == '\0') { + /* End of input inside macro argument list */ PPError ("Unterminated argument list invoking macro '%s'", M->Name); - MissingParen = 1; + Parens = -1; ClearLine (); + E->Flags |= MES_ERROR; + Idx = 0; break; + } else { - /* Just copy the character */ - SB_AppendChar (&Arg, CurC); - NextChar (); + unsigned LastLen = SB_GetLen (&Arg.Tokens); + + if (IsSym (Ident)) { + /* Just copy the identifier */ + SB_AppendStr (&Arg.Tokens, Ident); + + /* Count identifiers */ + ++CountInArg; + + /* Used for concatentation check */ + if ((Arg.Flags & MES_FIRST_TOKEN) != 0) { + Arg.Flags |= MES_BEGIN_WITH_IDENT; + } + } else if (IsPPNumber (CurC, NextC)) { + /* Copy a pp-number */ + CopyPPNumber (&Arg.Tokens); + } else if (IsQuotedString ()) { + /* Quoted string - just copy */ + CopyQuotedString (&Arg.Tokens); + } else if (GetPunc (Ident)) { + /* Check nested parentheses */ + if (Ident[0] == '(') { + /* Opening nested parenthesis */ + ++Parens; + } else if (Ident[0] == ')') { + /* Closing nested parenthesis */ + --Parens; + + /* Count right parens */ + ++CountInArg; + } + /* Just copy the punctuator */ + SB_AppendStr (&Arg.Tokens, Ident); + } else { + /* Just copy the character */ + SB_AppendChar (&Arg.Tokens, CurC); + NextChar (); + + /* But don't count it */ + ++LastLen; + } + + /* Used for concatentation check */ + ME_SetTokLens (&Arg, SB_GetLen (&Arg.Tokens) - LastLen - Skipped); } } /* Compare formal and actual argument count */ - if (CollCount (&E->ActualArgs) != (unsigned) M->ArgCount) { - - if (!MissingParen) { - /* Argument count mismatch */ - PPError ("Macro argument count mismatch"); + if (CollCount (&E->Args) < (unsigned) M->ParamCount) { + /* Check further only when the parentheses are paired */ + if (Parens == 0) { + /* Specially casing variable argument */ + if (M->Variadic && + M->ParamCount > 0 && + CollCount (&E->Args) + 1 == (unsigned) M->ParamCount) { + /* The variable argument is left out entirely */ + E->Flags |= MES_NO_VA_COMMA; + if (IS_Get (&Standard) < STD_CC65) { + PPWarning ("ISO C does not permit leaving out the comma before the variable argument"); + } + } else { + /* Too few argument */ + PPError ("Macro \"%s\" passed only %u arguments, but requires %u", + M->Name, CollCount (&E->Args), (unsigned) M->ParamCount); + } } /* Be sure to make enough empty arguments available */ - SB_Clear (&Arg); - while (CollCount (&E->ActualArgs) < (unsigned) M->ArgCount) { - ME_AppendActual (E, &Arg); + DoneMacroExp (&Arg); + InitMacroExp (&Arg); + Arg.Flags |= MES_HAS_REPLACEMENT; + while (CollCount (&E->Args) < (unsigned) M->ParamCount) { + ME_AppendArg (E, &Arg); } + } else if (Parens == 0 && CollCount (&E->Args) > (unsigned) M->ParamCount) { + /* Too many arguments */ + PPError ("Macro \"%s\" passed %u arguments, but takes just %u", + M->Name, CollCount (&E->Args), (unsigned) M->ParamCount); } - /* Deallocate string buf resources */ - SB_Done (&Arg); + /* Deallocate argument resources */ + DoneMacroExp (&Arg); + + /* Return the total count of identifiers and right parentheses in the + ** argument list. + */ + return Idx; } -static void SubstMacroArgs (MacroExp* E, Macro* M) -/* Argument substitution according to ISO/IEC 9899:1999 (E), 6.10.3.1ff */ +static unsigned SubstMacroArgs (unsigned NameIdx, StrBuf* Target, MacroExp* E, Macro* M, unsigned* IdentCount) +/* Argument substitution according to ISO/IEC 9899:1999 (E), 6.10.3.1ff. +** Return the length of the last pp-token in the result and output the count +** of identifiers and right parentheses in the result to *IdentCount. +*/ { + unsigned Idx = NameIdx; ident Ident; - int ArgIdx; + unsigned TokLen = 0; + int ParamIdx; StrBuf* OldSource; - StrBuf* Arg; - int HaveSpace; + int HaveSpace = 0; + StrBuf Buf = AUTO_STRBUF_INITIALIZER; /* Temporary buffer */ + /* Remember the current input stack and disable it for now */ + Collection* OldInputStack = UseInputStack (0); + + /* Remember the current input and switch to the macro replacement */ + unsigned OldIndex = SB_GetIndex (&M->Replacement); - /* Remember the current input and switch to the macro replacement. */ - int OldIndex = SB_GetIndex (&M->Replacement); SB_Reset (&M->Replacement); OldSource = InitLine (&M->Replacement); - /* Argument handling loop */ + /* If the macro expansion replaces an function-like macro with an argument + ** list containing a right parenthesis outside the hidesets of previously + ** replaced macros, stop those hidesets from this replacement. This is not + ** required by the standard but just to match up with other major C + ** compilers. + */ + ME_HandleSemiNestedMacro (NameIdx, NameIdx + *IdentCount, E); + + /* Substitution loop */ while (CurC != '\0') { + int NeedPaste = 0; /* If we have an identifier, check if it's a macro */ if (IsSym (Ident)) { - /* Check if it's a macro argument */ - if ((ArgIdx = FindMacroArg (M, Ident)) >= 0) { + /* Remember and skip any following whitespace */ + HaveSpace = SkipWhitespace (0); - /* A macro argument. Get the corresponding actual argument. */ - Arg = ME_GetActual (E, ArgIdx); - - /* Copy any following whitespace */ - HaveSpace = SkipWhitespace (0); + /* Check if it's a macro parameter */ + if ((ParamIdx = FindMacroParam (M, Ident)) >= 0) { /* If a ## operator follows, we have to insert the actual - ** argument as is, otherwise it must be macro replaced. + ** argument as-is, otherwise it must be macro-replaced. */ if (CurC == '#' && NextC == '#') { - /* ### Add placemarker if necessary */ - SB_Append (&E->Replacement, Arg); + /* Get the corresponding actual argument */ + const MacroExp* A = ME_GetOriginalArg (E, ParamIdx); + + /* Separate with a white space if necessary */ + if (CheckPastePPTok (Target, TokLen, SB_Peek (&A->Tokens))) { + SB_AppendChar (Target, ' '); + } + + /* For now we need no placemarkers */ + SB_Append (Target, &A->Tokens); + + /* Adjust tracking */ + ME_OffsetHideSets (Idx, A->IdentCount, E); + Idx += A->IdentCount; + + /* This will be used for concatenation */ + TokLen = A->LastTokLen; } else { - /* Replace the formal argument by a macro replaced copy - ** of the actual. - */ - SB_Reset (Arg); - MacroReplacement (Arg, &E->Replacement, 0); + /* Get the corresponding macro-replaced argument */ + const MacroExp* A = ME_GetReplacedArg (E, ParamIdx); - /* If we skipped whitespace before, re-add it now */ - if (HaveSpace) { - SB_AppendChar (&E->Replacement, ' '); + /* Separate with a white space if necessary */ + if (CheckPastePPTok (Target, TokLen, SB_Peek (&A->Tokens))) { + SB_AppendChar (Target, ' '); } - } + /* Append the replaced string */ + SB_Append (Target, &A->Tokens); + + /* Insert the range of identifiers to parent preceding this argument */ + ME_OffsetHideSets (Idx, A->IdentCount, E); + + /* Add hide range */ + ME_AddArgHideSets (Idx, A, E); + + /* Adjust tracking */ + Idx += A->IdentCount; + + /* May be used for later pp-token merge check */ + TokLen = A->LastTokLen; + } } else { /* An identifier, keep it */ - SB_AppendStr (&E->Replacement, Ident); + SB_AppendStr (Target, Ident); + /* Adjust tracking */ + ME_OffsetHideSets (Idx, 1, E); + ++Idx; + + /* May be used for later concatenation */ + TokLen = strlen (Ident); } + /* Special casing for 'L' prefixing '#' */ + if (TokLen == 1 && SB_LookAtLast (Target) == 'L' && CurC == '#') { + HaveSpace = 1; + } + + /* Squeeze and add the skipped whitespace back for consistency */ + if (HaveSpace && !IsBlank (SB_LookAtLast (Target))) { + SB_AppendChar (Target, ' '); + } + + /* Done with this substituted argument */ + continue; + } else if (CurC == '#' && NextC == '#') { - /* ## operator. */ + /* ## operator */ NextChar (); NextChar (); SkipWhitespace (0); - /* Since we need to concatenate the token sequences, remove - ** any whitespace that was added to target, since it must come - ** from the input. - */ - while (IsSpace (SB_LookAtLast (&E->Replacement))) { - SB_Drop (&E->Replacement, 1); - } - /* If the next token is an identifier which is a macro argument, - ** replace it, otherwise do nothing. + ** replace it, otherwise just add it. */ if (IsSym (Ident)) { + unsigned NewCount = 1; - /* Check if it's a macro argument */ - if ((ArgIdx = FindMacroArg (M, Ident)) >= 0) { + /* Check if it's a macro parameter */ + if ((ParamIdx = FindMacroParam (M, Ident)) >= 0) { - /* Get the corresponding actual argument and add it. */ - SB_Append (&E->Replacement, ME_GetActual (E, ArgIdx)); + /* Get the corresponding actual argument */ + MacroExp* A = ME_GetOriginalArg (E, ParamIdx); + + /* Insert the range of identifiers to parent preceding this argument */ + ME_OffsetHideSets (Idx, A->IdentCount, E); + + /* Add hide range */ + ME_AddArgHideSets (Idx, A, E); + + /* Adjust tracking */ + NewCount = A->IdentCount; + + /* If the preceding pp-token is not a placemarker and is + ** concatenated to with an identifier, the count of tracked + ** identifiers is then one less. + */ + if (TryPastePPTok (Target, &A->Tokens, TokLen, A->FirstTokLen)) { + if (TokLen > 0 && (A->Flags & MES_BEGIN_WITH_IDENT) != 0) { + --NewCount; + ME_RemoveToken (Idx, 1, E); + } + if ((A->Flags & MES_MULTIPLE_TOKEN) == 0) { + TokLen += A->FirstTokLen; + } else { + TokLen = A->LastTokLen; + } + } else { + TokLen = A->LastTokLen; + } } else { - /* Just an ordinary identifier - add as is */ - SB_AppendStr (&E->Replacement, Ident); + unsigned Len; + + /* Just an ordinary identifier - add as-is */ + SB_CopyStr (&Buf, Ident); + + /* If the preceding pp-token is not a placemarker and is + ** concatenated to with an identifier, the count of tracked + ** identifiers is then one less. + */ + Len = SB_GetLen (&Buf); + if (TryPastePPTok (Target, &Buf, TokLen, Len)) { + if (TokLen > 0) { + --NewCount; + } + TokLen += Len; + } else { + TokLen = Len; + } + + /* Adjust tracking */ + ME_OffsetHideSets (Idx, NewCount, E); } + + /* Adjust tracking */ + Idx += NewCount; + + /* Keep the whitespace for consistency */ + HaveSpace = SkipWhitespace (0); + if (HaveSpace && !IsBlank (SB_LookAtLast (Target))) { + SB_AppendChar (Target, ' '); + } + + /* Done with this concatenated identifier */ + continue; } - } else if (CurC == '#' && M->ArgCount >= 0) { - - /* A # operator within a macro expansion of a function like - ** macro. Read the following identifier and check if it's a - ** macro parameter. - */ - NextChar (); - SkipWhitespace (0); - if (!IsSym (Ident) || (ArgIdx = FindMacroArg (M, Ident)) < 0) { - PPError ("'#' is not followed by a macro parameter"); - } else { - /* Make a valid string from Replacement */ - Arg = ME_GetActual (E, ArgIdx); - SB_Reset (Arg); - Stringize (Arg, &E->Replacement); + if (CurC != '\0') { + /* Non-identifiers may still be pasted together */ + NeedPaste = 1; } - } else if (IsQuote (CurC)) { - CopyQuotedString (&E->Replacement); - } else { - SB_AppendChar (&E->Replacement, CurC); - NextChar (); } + + /* Use the temporary buffer */ + SB_Clear (&Buf); + if (IsPPNumber (CurC, NextC)) { + CopyPPNumber (&Buf); + } else if (IsQuotedString ()) { + CopyQuotedString (&Buf); + } else { + if (CurC == '#' && M->ParamCount >= 0) { + /* A # operator within a macro expansion of a function-like + ** macro. Read the following identifier and check if it's a + ** macro parameter. + */ + NextChar (); + SkipWhitespace (0); + if (!IsSym (Ident) || (ParamIdx = FindMacroParam (M, Ident)) < 0) { + /* Should not happen, but still */ + Internal ("'#' is not followed by a macro parameter"); + } else { + /* Make a valid string from Replacement */ + MacroExp* A = ME_GetOriginalArg (E, ParamIdx); + SB_Reset (&A->Tokens); + Stringize (&A->Tokens, &Buf); + } + } else if (GetPunc (Ident)) { + /* Count right parens. This is OK since they cannot be pasted + ** to form different punctuators with others. + */ + if (Ident[0] == ')') { + /* Adjust tracking */ + ME_OffsetHideSets (Idx, 1, E); + ++Idx; + } + SB_AppendStr (&Buf, Ident); + } else if (CurC != '\0') { + SB_AppendChar (&Buf, CurC); + NextChar (); + } + } + + /* Squeeze any whitespace for consistency. Especially, comments must + ** be consumed before fed to the punctuator parser, or their leading + ** '/' characters would be parsed wrongly as division operators. + */ + HaveSpace = SkipWhitespace (0); + + if (NeedPaste) { + unsigned Len = SB_GetLen (&Buf); + + /* Concatenate pp-tokens */ + if (TryPastePPTok (Target, &Buf, TokLen, Len)) { + TokLen += Len; + } else { + TokLen = Len; + } + } else { + /* Just append the token */ + SB_Append (Target, &Buf); + TokLen = SB_GetLen (&Buf); + } + + if (HaveSpace && !IsBlank (SB_LookAtLast (Target))) { + SB_AppendChar (Target, ' '); + } + } -#if 0 - /* Remove whitespace from the end of the line */ - while (IsSpace (SB_LookAtLast (&E->Replacement))) { - SB_Drop (&E->Replacement, 1); - } -#endif + /* Done with the temporary buffer */ + SB_Done (&Buf); + + /* Remove the macro name itself together with the arguments (if any) */ + ME_RemoveToken (Idx, 1 + *IdentCount, E); + + /* Hide this macro for the whole result of this expansion */ + ME_HideMacro (NameIdx, Idx - NameIdx, E, M); /* Switch back the input */ + UseInputStack (OldInputStack); InitLine (OldSource); SB_SetIndex (&M->Replacement, OldIndex); + + /* Set the count of identifiers and right parentheses in the result */ + *IdentCount = Idx - NameIdx; + + /* Return the length of the last pp-token */ + return TokLen; } -static void ExpandMacro (StrBuf* Target, Macro* M, int MultiLine) -/* Expand a macro into Target */ +static unsigned ExpandMacro (unsigned Idx, StrBuf* Target, MacroExp* E, Macro* M, int MultiLine) +/* Expand a macro into Target. Return the length of the last pp-token in the +** result of the expansion. +*/ { - MacroExp E; + unsigned Count = 0; /* Count of identifiers and right parentheses */ + unsigned Len = 0; /* Length of the last pp-token in the result */ -#if 0 + /* Disable previous pp-token spacing checking */ + StrBuf* PrevTok = CurRescanStack->PrevTok; + CurRescanStack->PrevTok = 0; + +#if DEV_CC65_DEBUG static unsigned V = 0; - printf ("Expanding %s(%u)\n", M->Name, ++V); + printf ("Expanding (%u) %s\n", ++V, M->Name); #endif - /* Initialize our MacroExp structure */ - InitMacroExp (&E); - /* Check if this is a function like macro */ - if (M->ArgCount >= 0) { - + if (M->ParamCount >= 0) { /* Read the actual macro arguments (with the enclosing parentheses) */ - ReadMacroArgs (&E, M, MultiLine); - + Count = ReadMacroArgs (Idx, E, M, MultiLine); } - /* Replace macro arguments handling the # and ## operators */ - SubstMacroArgs (&E, M); + if ((E->Flags & MES_ERROR) == 0) { + /* Replace macro parameters with arguments handling the # and ## operators */ + Len = SubstMacroArgs (Idx, Target, E, M, &Count); + } else { + SB_CopyStr (Target, M->Name); + } - /* Forbide repeated expansion of the same macro in use */ - M->Expanding = 1; - MacroReplacement (&E.Replacement, Target, 0); - M->Expanding = 0; + if (CollCount (&E->Args) > 0) { + /* Clear all arguments */ + ME_ClearArgs (E); + } -#if 0 - printf ("Done with %s(%u)\n", E.M->Name, V--); +#if DEV_CC65_DEBUG + printf ("Expanded (%u) %s to %d ident(s) at %u: %s\n", + V--, M->Name, Count, Idx, SB_GetConstBuf (Target)); #endif - /* Free memory allocated for the macro expansion structure */ - DoneMacroExp (&E); + /* Reenable previous pp-token concatenation checking */ + FreeStrBuf (CurRescanStack->PrevTok); + CurRescanStack->PrevTok = PrevTok; + + /* Return the length of the last pp-token in the expansion result */ + return Len; } -static void MacroReplacement (StrBuf* Source, StrBuf* Target, unsigned ModeFlags) -/* Scan for and perform macro replacement */ +static unsigned ReplaceMacros (StrBuf* Source, StrBuf* Target, MacroExp* E, unsigned ModeFlags) +/* Scan for and perform macro replacement. Return the count of identifiers and +** right parentheses in the replacement result. +*/ { - ident Ident; + unsigned Count = 0; + StrBuf* TmpTarget = NewStrBuf (); /* Remember the current input and switch to Source */ - StrBuf* OldSource = InitLine (Source); + StrBuf* OldSource = InitLine (Source); + RescanInputStack RescanStack; + RescanInputStack* OldRescanStack = CurRescanStack; + + InitRescanInputStack (&RescanStack); + PushRescanLine (&RescanStack, Line, 0); + CurRescanStack = &RescanStack; /* Loop substituting macros */ while (CurC != '\0') { + int Skipped = 0; + ident Ident; + /* If we have an identifier, check if it's a macro */ if (IsSym (Ident)) { + /* Check for bad identifier names */ + if ((ModeFlags & (MSM_MULTILINE | MSM_IN_DIRECTIVE | MSM_IN_ARG_LIST)) != 0 && + (CollCount (&CurRescanStack->Lines) == 1 || CurC == '\0')) { + CheckForBadIdent (Ident, IS_Get (&Standard), 0); + } + if ((ModeFlags & MSM_OP_DEFINED) != 0 && strcmp (Ident, "defined") == 0) { /* Handle the "defined" operator */ int HaveParen = 0; + /* Eat the "defined" operator */ + ME_RemoveToken (Count, 1, E); + SkipWhitespace (0); if (CurC == '(') { HaveParen = 1; NextChar (); SkipWhitespace (0); } + + /* Add a space to separate the result if necessary */ + SeparatePPTok (Target, '0'); + if (IsSym (Ident)) { /* Eat the identifier */ + ME_RemoveToken (Count, 1, E); SB_AppendChar (Target, IsMacro (Ident) ? '1' : '0'); if (HaveParen) { SkipWhitespace (0); @@ -860,6 +2147,8 @@ static void MacroReplacement (StrBuf* Source, StrBuf* Target, unsigned ModeFlags PPError ("')' expected"); ClearLine (); } else { + /* Eat the right parenthesis */ + ME_RemoveToken (Count, 1, E); NextChar (); } } @@ -869,83 +2158,289 @@ static void MacroReplacement (StrBuf* Source, StrBuf* Target, unsigned ModeFlags SB_AppendChar (Target, '0'); } } else { - /* Check if it's an expandable macro */ Macro* M = FindMacro (Ident); - if (M != 0 && !M->Expanding) { + + /* Check if it's an expandable macro */ + if (M != 0 && ME_CanExpand (Count, E, M)) { + int MultiLine = (ModeFlags & MSM_MULTILINE) != 0; + unsigned LastTokLen; + /* Check if this is a function-like macro */ - if (M->ArgCount >= 0) { - int MultiLine = (ModeFlags & MSM_MULTILINE) != 0; - int Whitespace = SkipWhitespace (MultiLine); + if (M->ParamCount >= 0) { + int HaveSpace = SkipWhitespace (MultiLine) > 0; + + /* A function-like macro name without an immediately + ** following argument list is not subject to expansion. + */ if (CurC != '(') { - /* Function-like macro without an argument list is not replaced */ + /* No expansion */ + ++Count; + + /* Add a space to separate the macro name if necessary */ + SeparatePPTok (Target, M->Name[0]); SB_AppendStr (Target, M->Name); - if (Whitespace > 0) { + + /* Keep tracking pp-token lengths */ + if ((ModeFlags & MSM_IN_ARG_EXPANSION) != 0) { + /* Used for concatentation check */ + if ((E->Flags & MES_FIRST_TOKEN) != 0) { + E->Flags |= MES_BEGIN_WITH_IDENT; + } + ME_SetTokLens (E, strlen (M->Name)); + } + + /* Since we have already got on hold of the next + ** line, we have to reuse it as the next line + ** instead of reading a new line from the source. + */ + if (PendingNewLines > 0 && MultiLine) { + unsigned I = SB_GetIndex (Line); + + /* There is no way a function-like macro call + ** detection could span multiple lines within + ** the range of another just expanded macro. + */ + CHECK (CollCount (&CurRescanStack->Lines) == 1); + + /* Revert one newline */ + --PendingNewLines; + + /* Align indention */ + while (I > 0) { + --I; + if (SB_GetBuf (Line)[I] == '\n') { + ++I; + break; + } + SB_GetBuf (Line)[I] = ' '; + } + + /* Set start index */ + SB_SetIndex (Line, I); + + /* Add newlines */ + AddPreLine (Target); + + /* Reuse this line as the next line */ + ReuseInputLine (); + + /* Quit this loop */ + break; + } + + /* Append back the whitespace */ + if (HaveSpace) { SB_AppendChar (Target, ' '); } - /* Directives can only be found in an argument list - ** that spans multiple lines. - */ - if (MultiLine) { - if (CurC == '#') { - /* If we were going to support #pragma in - ** macro argument list, it would be output - ** to OLine. - */ - if (OLine == 0) { - OLine = Target; - ParseDirectives (ModeFlags); - OLine = 0; - } else { - ParseDirectives (ModeFlags); - } - } - /* Add the source info to preprocessor output if needed */ - AddPreLine (Target); - } - } else { - /* Function-like macro */ - if (OLine == 0) { - OLine = Target; - ExpandMacro (Target, M, MultiLine); - OLine = 0; - } else { - ExpandMacro (Target, M, MultiLine); - } + /* Loop */ + goto Loop; } - } else { - /* Object-like macro */ - ExpandMacro (Target, M, 0); } - } else { - /* An identifier, keep it */ - SB_AppendStr (Target, Ident); + + /* Either an object-like or function-like macro */ + MultiLine = MultiLine && M->ParamCount >= 0; + + /* If we were going to support #pragma in macro argument + ** list, it would be output to OLine. + */ + if (MultiLine && OLine == 0) { + OLine = TmpTarget; + LastTokLen = ExpandMacro (Count, TmpTarget, E, M, MultiLine); + OLine = 0; + } else { + LastTokLen = ExpandMacro (Count, TmpTarget, E, M, MultiLine); + } + + /* Check for errors in expansion */ + if ((E->Flags & MES_ERROR) != 0) { + break; + } + + /* Pop the current line if it is at the end */ + PopRescanLine (); + + if (SB_GetLen (TmpTarget) > 0) { + /* Start rescanning from the temporary result */ + SB_Reset (TmpTarget); + InitLine (TmpTarget); + PushRescanLine (CurRescanStack, TmpTarget, LastTokLen); + + /* Add a space before a '#' at the beginning of the line */ + if (CurC == '#' && + NextC != '#' && + (SB_IsEmpty (Target) || SB_LookAtLast (Target) == '\n')) { + SB_AppendChar (Target, ' '); + } + + /* Switch the buffers */ + TmpTarget = NewStrBuf (); + } else if (PendingNewLines > 0 && MultiLine) { + /* Cancel remaining check for pp-tokens separation + ** if there is since ther have been newlines that + ** can always separate them. + */ + if (CurRescanStack->PrevTok != 0) { + FreeStrBuf (CurRescanStack->PrevTok); + CurRescanStack->PrevTok = 0; + } + + /* Squeeze whitespace */ + SkipWhitespace (0); + + /* Add indention to preprocessor output if needed */ + if (CurC != '\0' && CollCount (&CurRescanStack->Lines) == 1) { + /* Add newlines */ + AddPreLine (Target); + + /* Align indention */ + AppendIndent (Target, SB_GetIndex (Line)); + } + } + + /* Since we are rescanning, we needn't add the + ** count of just replaced identifiers right now. + */ + continue; + } + + /* An unexpandable identifier. Keep it. */ + ++Count; + + /* Add a space to separate the macro name if necessary */ + SeparatePPTok (Target, Ident[0]); + SB_AppendStr (Target, Ident); + + /* Keep tracking pp-token lengths */ + if ((ModeFlags & MSM_IN_ARG_EXPANSION) != 0) { + /* Used for concatentation check */ + if ((E->Flags & MES_FIRST_TOKEN) != 0) { + E->Flags |= MES_BEGIN_WITH_IDENT; + } + ME_SetTokLens (E, strlen (Ident)); } } } else { + unsigned LastLen; + + /* Add a space to separate the macro name if necessary */ + SeparatePPTok (Target, CurC); + + LastLen = SB_GetLen (Target); + if ((ModeFlags & MSM_TOK_HEADER) != 0 && (CurC == '<' || CurC == '\"')) { CopyHeaderNameToken (Target); - } else if (IsQuote (CurC)) { + } else if (IsPPNumber (CurC, NextC)) { + CopyPPNumber (Target); + } else if (IsQuotedString ()) { CopyQuotedString (Target); } else { - int Whitespace = SkipWhitespace (0); - if (Whitespace) { - SB_AppendChar (Target, ' '); + /* We want to squeeze whitespace until the end of the current + ** input line, so we have to deal with such cases specially. + */ + if (CollCount (&CurRescanStack->Lines) > 1) { + RescanInputStack* RIS = CurRescanStack; + + /* Temporarily disable input popping */ + CurRescanStack = 0; + Skipped = SkipWhitespace (0); + CurRescanStack = RIS; + + if (CurC == '\0') { + /* Now we are at the end of the input line */ + goto Loop; + } } else { - SB_AppendChar (Target, CurC); - NextChar (); + Skipped = SkipWhitespace (0); + } + + /* Punctuators must be checked after whitespace since comments + ** introducers may be misinterpreted as division operators. + */ + if (!Skipped) { + if (GetPunc (Ident)) { + if (Ident[0] == ')') { + /* Count right parens */ + ++Count; + } + SB_AppendStr (Target, Ident); + + /* If an identifier follows immediately, it could be a macro + ** expanded later that occasionally need a space to separate. + */ + if (IsIdent (CurC)) { + /* Memorize the previous pp-token and check it later */ + LazyCheckNextPPTok (Target, strlen (Ident)); + } + } else { + SB_AppendChar (Target, CurC); + NextChar (); + + /* Don't count this character */ + ++LastLen; + } } } + + /* Keep tracking pp-token lengths */ + if ((ModeFlags & MSM_IN_ARG_EXPANSION) != 0) { + ME_SetTokLens (E, SB_GetLen (Target) - LastLen); + } + } + +Loop: + /* Switch back to the previous input stream if we have finished + ** rescanning the current one. + */ + if (CurC == '\0' && CollCount (&CurRescanStack->Lines) > 1) { + /* Check for rescan sequence end and pp-token pasting */ + Skipped = SkipWhitespace (0) || Skipped; + + /* Add indention to preprocessor output if needed */ + if (CurC != '\0' && + PendingNewLines > 0 && + (ModeFlags & MSM_MULTILINE) != 0 && + CollCount (&CurRescanStack->Lines) == 1) { + /* Add newlines */ + AddPreLine (Target); + + /* Align indention */ + AppendIndent (Target, SB_GetIndex (Line)); + Skipped = 0; + } + } + + /* Append a space if there hasn't been one */ + if (Skipped && !IsSpace (SB_LookAtLast (Target))) { + SB_AppendChar (Target, ' '); } } + /* Append the remaining result */ + SB_Append (Target, TmpTarget); + + /* Done with the temporary buffer */ + SB_Done (TmpTarget); + /* Drop whitespace at the end */ if (IsBlank (SB_LookAtLast (Target))) { SB_Drop (Target, 1); } + /* Sanity check */ + if ((E->Flags & MES_ERROR) == 0) { + CHECK (CollCount (&CurRescanStack->Lines) == 1); + } + + /* Done with the current input stack */ + DoneRescanInputStack (CurRescanStack); + CurRescanStack = OldRescanStack; + /* Switch back the input */ InitLine (OldSource); + + /* Return the count of identifiers and right parentheses */ + return Count; } @@ -956,41 +2451,137 @@ static void MacroReplacement (StrBuf* Source, StrBuf* Target, unsigned ModeFlags +static int ParseMacroReplacement (StrBuf* Source, Macro* M) +/* Check correctness of macro definition while squeezing old and new style +** comments and other non-newline whitespace sequences. Return 1 on success +** or 0 on failure. +*/ +{ + /* Switch to the new input source */ + StrBuf* OldSource = InitLine (Source); + int HasWhiteSpace = 0; + unsigned Len; + ident Ident; + int Std = IS_Get (&Standard); + + /* Skip whitespace before the macro replacement */ + SkipWhitespace (0); + + /* Check for ## at start */ + if (CurC == '#' && NextC == '#') { + /* Diagnose and bail out */ + PPError ("'##' cannot appear at start of macro expansion"); + goto Error_Handler; + } + + /* Loop removing ws and comments */ + while (CurC != '\0') { + if (HasWhiteSpace) { + SB_AppendChar (&M->Replacement, ' '); + } else if (IsQuotedString ()) { + CopyQuotedString (&M->Replacement); + } else if (IsSym (Ident)) { + CheckForBadIdent (Ident, Std, M); + SB_AppendStr (&M->Replacement, Ident); + } else { + if (M->ParamCount >= 0 && GetPunc (Ident)) { + Len = strlen (Ident); + /* Check for # */ + if (Len == 1 && Ident[0] == '#') { + HasWhiteSpace = SkipWhitespace (0); + + /* Check next pp-token */ + if (!IsSym (Ident) || FindMacroParam (M, Ident) < 0) { + PPError ("'#' is not followed by a macro parameter"); + goto Error_Handler; + } + + /* Make the replacement */ + SB_AppendChar (&M->Replacement, '#'); + if (HasWhiteSpace) { + SB_AppendChar (&M->Replacement, ' '); + } + SB_AppendStr (&M->Replacement, Ident); + } else { + SB_AppendBuf (&M->Replacement, Ident, Len); + } + } else { + SB_AppendChar (&M->Replacement, CurC); + NextChar (); + } + } + + HasWhiteSpace = SkipWhitespace (0); + } + + /* Check for ## at end */ + Len = SB_GetLen (&M->Replacement); + if (Len >= 2) { + if (SB_LookAt (&M->Replacement, Len - 1) == '#' && + SB_LookAt (&M->Replacement, Len - 2) == '#') { + /* Diagnose and bail out */ + PPError ("'##' cannot appear at end of macro expansion"); + goto Error_Handler; + } + } + + /* Terminate the new input line */ + SB_Terminate (&M->Replacement); + + /* Switch back to the old source */ + InitLine (OldSource); + + /* Success */ + return 1; + +Error_Handler: + + /* Switch back to the old source */ + InitLine (OldSource); + + /* Failure */ + return 0; +} + + + static void DoDefine (void) /* Process #define directive */ { ident Ident; - Macro* M; + Macro* M = 0; Macro* Existing; - int C89; - unsigned Len; + int Std; /* Read the macro name */ SkipWhitespace (0); if (!MacName (Ident)) { - return; + goto Error_Handler; } - /* Remember if we're in C89 mode */ - C89 = (IS_Get (&Standard) == STD_C89); + /* Remember the language standard we are in */ + Std = IS_Get (&Standard); /* Check for forbidden macro names */ if (strcmp (Ident, "defined") == 0) { PPError ("'%s' cannot be used as a macro name", Ident); - return; + goto Error_Handler; } + /* Check for and warn on special identifiers */ + CheckForBadIdent (Ident, Std, 0); + /* Create a new macro definition */ M = NewMacro (Ident); - /* Check if this is a function like macro */ + /* Check if this is a function-like macro */ if (CurC == '(') { /* Skip the left paren */ NextChar (); - /* Set the marker that this is a function like macro */ - M->ArgCount = 0; + /* Set the marker that this is a function-like macro */ + M->ParamCount = 0; /* Read the formal parameter list */ while (1) { @@ -1004,42 +2595,37 @@ static void DoDefine (void) /* The next token must be either an identifier, or - if not in ** C89 mode - the ellipsis. */ - if (!C89 && CurC == '.') { + if (Std >= STD_C99 && CurC == '.') { /* Ellipsis */ NextChar (); if (CurC != '.' || NextC != '.') { PPError ("'...' expected"); - ClearLine (); - FreeMacro (M); - return; + goto Error_Handler; } NextChar (); NextChar (); /* Remember that the macro is variadic and use __VA_ARGS__ as - ** the argument name. + ** the parameter name. */ - AddMacroArg (M, "__VA_ARGS__"); + AddMacroParam (M, "__VA_ARGS__"); M->Variadic = 1; } else { - /* Must be macro argument name */ + /* Must be macro parameter name */ if (MacName (Ident) == 0) { - return; + goto Error_Handler; } - /* __VA_ARGS__ is only allowed in post-C89 mode */ - if (!C89 && strcmp (Ident, "__VA_ARGS__") == 0) { - PPWarning ("'__VA_ARGS__' can only appear in the expansion " - "of a C99 variadic macro"); - } + /* Check for and warn on special identifiers */ + CheckForBadIdent (Ident, Std, 0); - /* Add the macro argument */ - AddMacroArg (M, Ident); + /* Add the macro parameter */ + AddMacroParam (M, Ident); } /* If we had an ellipsis, or the next char is not a comma, we've - ** reached the end of the macro argument list. + ** reached the end of the macro parameter list. */ SkipWhitespace (0); if (M->Variadic || CurC != ',') { @@ -1051,47 +2637,22 @@ static void DoDefine (void) /* Check for a right paren and eat it if we find one */ if (CurC != ')') { PPError ("')' expected for macro definition"); - ClearLine (); - FreeMacro (M); - return; + goto Error_Handler; } NextChar (); } - /* Skip whitespace before the macro replacement */ - SkipWhitespace (0); - /* Remove whitespace and comments from the line, store the preprocessed ** line into the macro replacement buffer. */ - TranslationPhase3 (Line, &M->Replacement); - - /* Remove whitespace from the end of the line */ - while (IsSpace (SB_LookAtLast (&M->Replacement))) { - SB_Drop (&M->Replacement, 1); + if (ParseMacroReplacement (Line, M) == 0) { + goto Error_Handler; } + #if 0 printf ("%s: <%.*s>\n", M->Name, SB_GetLen (&M->Replacement), SB_GetConstBuf (&M->Replacement)); #endif - /* Check for ## at start or end */ - Len = SB_GetLen (&M->Replacement); - if (Len >= 2) { - if (SB_LookAt (&M->Replacement, 0) == '#' && - SB_LookAt (&M->Replacement, 1) == '#') { - /* Diagnose and bail out */ - PPError ("'##' cannot appear at start of macro expansion"); - FreeMacro (M); - return; - } else if (SB_LookAt (&M->Replacement, Len - 1) == '#' && - SB_LookAt (&M->Replacement, Len - 2) == '#') { - /* Diagnose and bail out */ - PPError ("'##' cannot appear at end of macro expansion"); - FreeMacro (M); - return; - } - } - /* Get an existing macro definition with this name */ Existing = FindMacro (M->Name); @@ -1108,6 +2669,18 @@ static void DoDefine (void) /* Insert the new macro into the macro table */ InsertMacro (M); + + /* Success */ + return; + +Error_Handler: + + /* Cleanup */ + ClearLine (); + + if (M != 0) { + FreeMacro (M); + } } @@ -1220,6 +2793,7 @@ static int DoIfDef (int skip, int flag) SkipWhitespace (0); if (MacName (Ident)) { + CheckForBadIdent (Ident, IS_Get (&Standard), 0); Value = IsMacro (Ident); /* Check for extra tokens */ CheckExtraTokens (flag ? "ifdef" : "ifndef"); @@ -1379,7 +2953,7 @@ static void DoLine (void) /* #line actually sets the line number of the next line */ if (LineNum > 0) { - SetCurrentLine (LineNum - 1); + SetCurrentLineNum (LineNum - 1); /* Check for extra tokens at the end */ CheckExtraTokens ("line"); } @@ -1426,6 +3000,7 @@ static void DoUndef (void) SkipWhitespace (0); if (MacName (Ident)) { + CheckForBadIdent (Ident, IS_Get (&Standard), 0); UndefineMacro (Ident); } /* Check for extra tokens */ @@ -1582,6 +3157,7 @@ static int ParseDirectives (unsigned ModeFlags) if (!PPSkip) { if ((ModeFlags & MSM_IN_ARG_LIST) == 0) { DoPragma (); + return Whitespace; } else { PPError ("Embedded #pragma directive within macro arguments is unsupported"); } @@ -1624,7 +3200,7 @@ static int ParseDirectives (unsigned ModeFlags) Whitespace = SkipWhitespace (0) || Whitespace; } - return Whitespace != 0; + return Whitespace; } @@ -1640,11 +3216,11 @@ void HandleSpecialMacro (Macro* M, const char* Name) SB_Printf (&M->Replacement, "%u", GetCurrentCounter ()); } else if (strcmp (Name, "__LINE__") == 0) { /* Replace __LINE__ with the current line number */ - SB_Printf (&M->Replacement, "%u", GetCurrentLine ()); + SB_Printf (&M->Replacement, "%u", GetCurrentLineNum ()); } else if (strcmp (Name, "__FILE__") == 0) { /* Replace __FILE__ with the current filename */ StrBuf B = AUTO_STRBUF_INITIALIZER; - SB_InitFromString (&B, GetCurrentFile ()); + SB_InitFromString (&B, GetCurrentFilename ()); SB_Clear (&M->Replacement); Stringize (&B, &M->Replacement); SB_Done (&B); @@ -1688,7 +3264,7 @@ static void TranslationPhase3 (StrBuf* Source, StrBuf* Target) } if (HasWhiteSpace) { SB_AppendChar (Target, ' '); - } else if (IsQuote (CurC)) { + } else if (IsQuotedString ()) { CopyQuotedString (Target); } else { SB_AppendChar (Target, CurC); @@ -1710,16 +3286,12 @@ static void PreprocessDirective (StrBuf* Source, StrBuf* Target, unsigned ModeFl ** whitespace and comments, then do macro replacement. */ { - int OldIndex = SB_GetIndex (Source); MacroExp E; SkipWhitespace (0); InitMacroExp (&E); - MacroReplacement (Source, Target, ModeFlags | MSM_IN_DIRECTIVE); + ReplaceMacros (Source, Target, &E, ModeFlags | MSM_IN_DIRECTIVE); DoneMacroExp (&E); - - /* Restore the source input index */ - SB_SetIndex (Source, OldIndex); } @@ -1727,6 +3299,8 @@ static void PreprocessDirective (StrBuf* Source, StrBuf* Target, unsigned ModeFl void Preprocess (void) /* Preprocess lines count of which is affected by directives */ { + MacroExp E; + SB_Clear (PLine); /* Add the source info to preprocessor output if needed */ @@ -1741,10 +3315,14 @@ void Preprocess (void) AddPreLine (PLine); /* Add leading whitespace to prettify preprocessor output */ - AppendIndent (PLine, SB_GetIndex (Line)); + if (CurC != '\0') { + AppendIndent (PLine, SB_GetIndex (Line)); + } /* Expand macros if any */ - MacroReplacement (Line, PLine, MSM_MULTILINE); + InitMacroExp (&E); + ReplaceMacros (Line, PLine, &E, MSM_MULTILINE); + DoneMacroExp (&E); /* Add the source info to preprocessor output if needed */ AddPreLine (PLine); @@ -1754,7 +3332,7 @@ void Preprocess (void) PLine = InitLine (PLine); if (Verbosity > 1 && SB_NotEmpty (Line)) { - printf ("%s:%u: %.*s\n", GetCurrentFile (), GetCurrentLine (), + printf ("%s:%u: %.*s\n", GetCurrentFilename (), GetCurrentLineNum (), (int) SB_GetLen (Line), SB_GetConstBuf (Line)); } @@ -1792,6 +3370,14 @@ void SetPPIfStack (PPIfStack* Stack) +void ContinueLine (void) +/* Continue the current line ended with a '\\' */ +{ + ++ContinuedLines; +} + + + void PreprocessBegin (void) /* Initialize preprocessor with current file */ { @@ -1800,6 +3386,9 @@ void PreprocessBegin (void) /* Remember to update source file location in preprocess-only mode */ FileChanged = 1; + + /* Enable diagnostics on new style comments in C89 mode */ + AllowNewComments = 0; } diff --git a/src/cc65/preproc.h b/src/cc65/preproc.h index a4619e545..e2a1b073c 100644 --- a/src/cc65/preproc.h +++ b/src/cc65/preproc.h @@ -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 */ diff --git a/src/cc65/scanner.c b/src/cc65/scanner.c index 09dd8fef8..36fd1301b 100644 --- a/src/cc65/scanner.c +++ b/src/cc65/scanner.c @@ -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"); } } diff --git a/src/cc65/scanner.h b/src/cc65/scanner.h index 7a67b10ed..338ad6a65 100644 --- a/src/cc65/scanner.h +++ b/src/cc65/scanner.h @@ -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 */ diff --git a/src/cc65/shiftexpr.c b/src/cc65/shiftexpr.c index eb879a475..b8fb70434 100644 --- a/src/cc65/shiftexpr.c +++ b/src/cc65/shiftexpr.c @@ -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 */ diff --git a/src/cc65/stdfunc.c b/src/cc65/stdfunc.c index 5ed5ce671..fc19ce7f0 100644 --- a/src/cc65/stdfunc.c +++ b/src/cc65/stdfunc.c @@ -604,7 +604,7 @@ static void StdFunc_memset (FuncDesc* F attribute ((unused)), ExprDesc* Expr) DoDeferred (SQP_KEEP_EAX, &Arg3.Expr); /* Emit the actual function call. This will also cleanup the stack. */ - g_call (CF_FIXARGC, MemSet? Func_memset : Func__bzero, ParamSize); + g_call (CF_FIXARGC, MemSet? Func_memset : Func___bzero, ParamSize); if (ED_IsConstAbsInt (&Arg3.Expr) && Arg3.Expr.IVal == 0) { diff --git a/src/cc65/stdnames.c b/src/cc65/stdnames.c index 687b53894..cdecd61a1 100644 --- a/src/cc65/stdnames.c +++ b/src/cc65/stdnames.c @@ -44,9 +44,9 @@ -const char Func__bzero[] = "_bzero"; /* Asm name of "_bzero" */ -const char Func_memcpy[] = "memcpy"; /* Asm name of "memcpy" */ -const char Func_memset[] = "memset"; /* Asm name of "memset" */ -const char Func_strcmp[] = "strcmp"; /* Asm name of "strcmp" */ -const char Func_strcpy[] = "strcpy"; /* Asm name of "strcpy" */ -const char Func_strlen[] = "strlen"; /* Asm name of "strlen" */ +const char Func___bzero[] = "__bzero"; /* C name of "__bzero" */ +const char Func_memcpy[] = "memcpy"; /* C name of "memcpy" */ +const char Func_memset[] = "memset"; /* C name of "memset" */ +const char Func_strcmp[] = "strcmp"; /* C name of "strcmp" */ +const char Func_strcpy[] = "strcpy"; /* C name of "strcpy" */ +const char Func_strlen[] = "strlen"; /* C name of "strlen" */ diff --git a/src/cc65/stdnames.h b/src/cc65/stdnames.h index dcb323924..e6497e4c3 100644 --- a/src/cc65/stdnames.h +++ b/src/cc65/stdnames.h @@ -44,12 +44,12 @@ -extern const char Func__bzero[]; /* Asm name of "_bzero" */ -extern const char Func_memcpy[]; /* Asm name of "memcpy" */ -extern const char Func_memset[]; /* Asm name of "memset" */ -extern const char Func_strcmp[]; /* Asm name of "strcmp" */ -extern const char Func_strcpy[]; /* Asm name of "strcpy" */ -extern const char Func_strlen[]; /* Asm name of "strlen" */ +extern const char Func___bzero[]; /* C name of "__bzero" */ +extern const char Func_memcpy[]; /* C name of "memcpy" */ +extern const char Func_memset[]; /* C name of "memset" */ +extern const char Func_strcmp[]; /* C name of "strcmp" */ +extern const char Func_strcpy[]; /* C name of "strcpy" */ +extern const char Func_strlen[]; /* C name of "strlen" */ diff --git a/src/cc65/symentry.c b/src/cc65/symentry.c index cc790c931..30ebe7dd8 100644 --- a/src/cc65/symentry.c +++ b/src/cc65/symentry.c @@ -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 : ""); - - 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); } diff --git a/src/cc65/symentry.h b/src/cc65/symentry.h index bcf586510..5ebd30a75 100644 --- a/src/cc65/symentry.h +++ b/src/cc65/symentry.h @@ -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 */ diff --git a/src/cc65/symtab.c b/src/cc65/symtab.c index aa4a9a44a..961f36046 100644 --- a/src/cc65/symtab.c +++ b/src/cc65/symtab.c @@ -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 */ diff --git a/src/cc65/symtab.h b/src/cc65/symtab.h index 1df61a822..b711fe606 100644 --- a/src/cc65/symtab.h +++ b/src/cc65/symtab.h @@ -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); diff --git a/src/cc65/typecmp.c b/src/cc65/typecmp.c index 6052f4a84..1a108159f 100644 --- a/src/cc65/typecmp.c +++ b/src/cc65/typecmp.c @@ -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); diff --git a/src/common/attrib.h b/src/common/attrib.h index 07e08b2df..3cdacb9d5 100644 --- a/src/common/attrib.h +++ b/src/common/attrib.h @@ -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 diff --git a/src/common/xsprintf.c b/src/common/xsprintf.c index a3fbc676b..556e4f359 100644 --- a/src/common/xsprintf.c +++ b/src/common/xsprintf.c @@ -486,6 +486,18 @@ int xvsnprintf (char* Buf, size_t Size, const char* Format, va_list ap) } break; + /* support the MSVC specific I64 for long long */ + case 'I': + F = *Format++; + if (F == '6') { + F = *Format++; + if (F == '4') { + F = *Format++; + P.LengthMod = lmLongLong; + } + } + break; + case 'l': F = *Format++; if (F == 'l') { diff --git a/src/da65/infofile.c b/src/da65/infofile.c index 6db82cb36..48a95c9b0 100644 --- a/src/da65/infofile.c +++ b/src/da65/infofile.c @@ -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; diff --git a/src/da65/scanner.c b/src/da65/scanner.c index 33fb3a826..d0301c08a 100644 --- a/src/da65/scanner.c +++ b/src/da65/scanner.c @@ -372,6 +372,14 @@ Again: return; } + /* Decimal number offset? */ + if (C == '+') { + NextChar (); + InfoIVal = GetDecimalToken (); + InfoTok = INFOTOK_OFFSET_INTCON; + return; + } + /* Other characters */ switch (C) { diff --git a/src/da65/scanner.h b/src/da65/scanner.h index d4e38177b..63d3273f6 100644 --- a/src/da65/scanner.h +++ b/src/da65/scanner.h @@ -48,6 +48,7 @@ typedef enum token_t { INFOTOK_NONE, INFOTOK_INTCON, + INFOTOK_OFFSET_INTCON, INFOTOK_STRCON, INFOTOK_CHARCON, INFOTOK_IDENT, diff --git a/src/sim65/memory.c b/src/sim65/memory.c index 11f0be55a..68e7bb93b 100644 --- a/src/sim65/memory.c +++ b/src/sim65/memory.c @@ -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 */ { diff --git a/src/sim65/memory.h b/src/sim65/memory.h index 41cc800d3..cef786aaa 100644 --- a/src/sim65/memory.h +++ b/src/sim65/memory.h @@ -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 */ diff --git a/targettest/Makefile b/targettest/Makefile index 5e693bf9d..7bcbc95f0 100644 --- a/targettest/Makefile +++ b/targettest/Makefile @@ -762,6 +762,7 @@ TARGETS := \ define TARGET_recipe +@echo making targettest for: $(T) @$(MAKE) -j2 SYS:=$(T) @$(MAKE) --no-print-directory clean SYS:=$(T) diff --git a/targettest/conio.c b/targettest/conio.c index 49434595b..efe82d7c6 100644 --- a/targettest/conio.c +++ b/targettest/conio.c @@ -130,9 +130,11 @@ void main(void) case CH_ENTER: clrscr(); return; +#ifdef CH_CURS_LEFT case CH_CURS_LEFT: inpos = (inpos - 1) % 8; break; +#endif case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': (void)textcolor(i - '0'); @@ -164,7 +166,9 @@ void main(void) default: cputc(i); /* fallthrough */ +#ifdef CH_CURS_RIGHT case CH_CURS_RIGHT: +#endif inpos = (inpos + 1) % 8; } #endif diff --git a/targettest/pce/Makefile b/targettest/pce/Makefile index f757c3062..89abca6b6 100644 --- a/targettest/pce/Makefile +++ b/targettest/pce/Makefile @@ -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) diff --git a/test/asm/listing/Makefile b/test/asm/listing/Makefile index d3dc21409..3c4c404af 100644 --- a/test/asm/listing/Makefile +++ b/test/asm/listing/Makefile @@ -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 diff --git a/test/asm/listing/ref/010-paramcount.err-ref b/test/asm/listing/ref/010-paramcount.err-ref index a66162eb5..baf73f50f 100644 --- a/test/asm/listing/ref/010-paramcount.err-ref +++ b/test/asm/listing/ref/010-paramcount.err-ref @@ -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 diff --git a/test/asm/listing/ref/010-paramcount.err2-ref b/test/asm/listing/ref/010-paramcount.err2-ref new file mode 100644 index 000000000..304c9de61 --- /dev/null +++ b/test/asm/listing/ref/010-paramcount.err2-ref @@ -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 diff --git a/test/asm/listing/ref/030-assert-success.err-ref b/test/asm/listing/ref/030-assert-success.err2-ref similarity index 100% rename from test/asm/listing/ref/030-assert-success.err-ref rename to test/asm/listing/ref/030-assert-success.err2-ref diff --git a/test/asm/listing/ref/030-assert-success.ld65err-ref b/test/asm/listing/ref/030-assert-success.ld65err2-ref similarity index 100% rename from test/asm/listing/ref/030-assert-success.ld65err-ref rename to test/asm/listing/ref/030-assert-success.ld65err2-ref diff --git a/test/asm/listing/ref/031-assert-error.err-ref b/test/asm/listing/ref/031-assert-error.err2-ref similarity index 100% rename from test/asm/listing/ref/031-assert-error.err-ref rename to test/asm/listing/ref/031-assert-error.err2-ref diff --git a/test/asm/listing/ref/032-assert-error2.ld65err-ref b/test/asm/listing/ref/032-assert-error2.ld65err2-ref similarity index 100% rename from test/asm/listing/ref/032-assert-error2.ld65err-ref rename to test/asm/listing/ref/032-assert-error2.ld65err2-ref diff --git a/test/asm/listing/ref/032-assert-error3.ld65err-ref b/test/asm/listing/ref/032-assert-error3.ld65err2-ref similarity index 100% rename from test/asm/listing/ref/032-assert-error3.ld65err-ref rename to test/asm/listing/ref/032-assert-error3.ld65err2-ref diff --git a/test/asm/listing/ref/032-assert-error4.ld65err-ref b/test/asm/listing/ref/032-assert-error4.ld65err2-ref similarity index 100% rename from test/asm/listing/ref/032-assert-error4.ld65err-ref rename to test/asm/listing/ref/032-assert-error4.ld65err2-ref diff --git a/test/asm/listing/ref/032-assert-error5.ld65err-ref b/test/asm/listing/ref/032-assert-error5.ld65err2-ref similarity index 100% rename from test/asm/listing/ref/032-assert-error5.ld65err-ref rename to test/asm/listing/ref/032-assert-error5.ld65err2-ref diff --git a/test/asm/listing/ref/032-assert-error6.ld65err-ref b/test/asm/listing/ref/032-assert-error6.ld65err2-ref similarity index 100% rename from test/asm/listing/ref/032-assert-error6.ld65err-ref rename to test/asm/listing/ref/032-assert-error6.ld65err2-ref diff --git a/test/asm/listing/ref/032-assert-error7.ld65err-ref b/test/asm/listing/ref/032-assert-error7.ld65err2-ref similarity index 100% rename from test/asm/listing/ref/032-assert-error7.ld65err-ref rename to test/asm/listing/ref/032-assert-error7.ld65err2-ref diff --git a/test/asm/listing/ref/032-assert-error8.ld65err-ref b/test/asm/listing/ref/032-assert-error8.ld65err2-ref similarity index 100% rename from test/asm/listing/ref/032-assert-error8.ld65err-ref rename to test/asm/listing/ref/032-assert-error8.ld65err2-ref diff --git a/test/asm/listing/ref/033-assert-ldwarning-success.ld65err-ref b/test/asm/listing/ref/033-assert-ldwarning-success.ld65err2-ref similarity index 100% rename from test/asm/listing/ref/033-assert-ldwarning-success.ld65err-ref rename to test/asm/listing/ref/033-assert-ldwarning-success.ld65err2-ref diff --git a/test/asm/listing/ref/034-assert-lderror1.err-ref b/test/asm/listing/ref/034-assert-lderror1.err2-ref similarity index 100% rename from test/asm/listing/ref/034-assert-lderror1.err-ref rename to test/asm/listing/ref/034-assert-lderror1.err2-ref diff --git a/test/asm/listing/ref/034-assert-lderror2.ld65err-ref b/test/asm/listing/ref/034-assert-lderror2.ld65err2-ref similarity index 100% rename from test/asm/listing/ref/034-assert-lderror2.ld65err-ref rename to test/asm/listing/ref/034-assert-lderror2.ld65err2-ref diff --git a/test/asm/listing/ref/034-assert-lderror3.ld65err-ref b/test/asm/listing/ref/034-assert-lderror3.ld65err2-ref similarity index 100% rename from test/asm/listing/ref/034-assert-lderror3.ld65err-ref rename to test/asm/listing/ref/034-assert-lderror3.ld65err2-ref diff --git a/test/asm/listing/ref/034-assert-lderror4.ld65err-ref b/test/asm/listing/ref/034-assert-lderror4.ld65err2-ref similarity index 100% rename from test/asm/listing/ref/034-assert-lderror4.ld65err-ref rename to test/asm/listing/ref/034-assert-lderror4.ld65err2-ref diff --git a/test/asm/listing/ref/034-assert-lderror6.ld65err-ref b/test/asm/listing/ref/034-assert-lderror6.ld65err2-ref similarity index 100% rename from test/asm/listing/ref/034-assert-lderror6.ld65err-ref rename to test/asm/listing/ref/034-assert-lderror6.ld65err2-ref diff --git a/test/asm/listing/ref/034-assert-lderror7.ld65err-ref b/test/asm/listing/ref/034-assert-lderror7.ld65err2-ref similarity index 100% rename from test/asm/listing/ref/034-assert-lderror7.ld65err-ref rename to test/asm/listing/ref/034-assert-lderror7.ld65err2-ref diff --git a/test/asm/listing/ref/034-assert-lderror8.ld65err-ref b/test/asm/listing/ref/034-assert-lderror8.ld65err2-ref similarity index 100% rename from test/asm/listing/ref/034-assert-lderror8.ld65err-ref rename to test/asm/listing/ref/034-assert-lderror8.ld65err2-ref diff --git a/test/asm/listing/ref/040-align.ld65err-ref b/test/asm/listing/ref/040-align.ld65err2-ref similarity index 100% rename from test/asm/listing/ref/040-align.ld65err-ref rename to test/asm/listing/ref/040-align.ld65err2-ref diff --git a/test/asm/listing/ref/050-case-on-1.err-ref b/test/asm/listing/ref/050-case-on-1.err2-ref similarity index 100% rename from test/asm/listing/ref/050-case-on-1.err-ref rename to test/asm/listing/ref/050-case-on-1.err2-ref diff --git a/test/asm/listing/ref/050-case-on-2.err-ref b/test/asm/listing/ref/050-case-on-2.err2-ref similarity index 100% rename from test/asm/listing/ref/050-case-on-2.err-ref rename to test/asm/listing/ref/050-case-on-2.err2-ref diff --git a/test/asm/listing/ref/050-case-on-3.err-ref b/test/asm/listing/ref/050-case-on-3.err2-ref similarity index 100% rename from test/asm/listing/ref/050-case-on-3.err-ref rename to test/asm/listing/ref/050-case-on-3.err2-ref diff --git a/test/asm/listing/ref/050-case-on-4.err-ref b/test/asm/listing/ref/050-case-on-4.err2-ref similarity index 100% rename from test/asm/listing/ref/050-case-on-4.err-ref rename to test/asm/listing/ref/050-case-on-4.err2-ref diff --git a/test/asm/listing/ref/050-case-on-5.err-ref b/test/asm/listing/ref/050-case-on-5.err2-ref similarity index 100% rename from test/asm/listing/ref/050-case-on-5.err-ref rename to test/asm/listing/ref/050-case-on-5.err2-ref diff --git a/test/err/bug1890.c b/test/err/bug1890.c new file mode 100644 index 000000000..15d857cdb --- /dev/null +++ b/test/err/bug1890.c @@ -0,0 +1,9 @@ +/* bug #1890 - Overflow in enumerator value is not detected */ + +#include +enum { a = ULONG_MAX, b } c = b; + +int main(void) +{ + return 0; +} diff --git a/test/err/bug1893.c b/test/err/bug1893.c new file mode 100644 index 000000000..455256179 --- /dev/null +++ b/test/err/bug1893.c @@ -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; +} diff --git a/test/err/bug1895-assign1a.c b/test/err/bug1895-assign1a.c new file mode 100644 index 000000000..223964104 --- /dev/null +++ b/test/err/bug1895-assign1a.c @@ -0,0 +1,5 @@ +/* Bug #1895 - missing diagnostics on incompatible pointer/array types */ + +#define DO_TEST_1_SUB_1_A + +#include "bug1895-common.h" diff --git a/test/err/bug1895-assign1b.c b/test/err/bug1895-assign1b.c new file mode 100644 index 000000000..cccc0a318 --- /dev/null +++ b/test/err/bug1895-assign1b.c @@ -0,0 +1,5 @@ +/* Bug #1895 - missing diagnostics on incompatible pointer/array types */ + +#define DO_TEST_1_SUB_1_B + +#include "bug1895-common.h" diff --git a/test/err/bug1895-assign2a.c b/test/err/bug1895-assign2a.c new file mode 100644 index 000000000..512b658a9 --- /dev/null +++ b/test/err/bug1895-assign2a.c @@ -0,0 +1,5 @@ +/* Bug #1895 - missing diagnostics on incompatible pointer/array types */ + +#define DO_TEST_1_SUB_2_A + +#include "bug1895-common.h" diff --git a/test/err/bug1895-assign2b.c b/test/err/bug1895-assign2b.c new file mode 100644 index 000000000..d07191206 --- /dev/null +++ b/test/err/bug1895-assign2b.c @@ -0,0 +1,5 @@ +/* Bug #1895 - missing diagnostics on incompatible pointer/array types */ + +#define DO_TEST_1_SUB_2_B + +#include "bug1895-common.h" diff --git a/test/err/bug1895-assign4a.c b/test/err/bug1895-assign4a.c new file mode 100644 index 000000000..c2a6f25de --- /dev/null +++ b/test/err/bug1895-assign4a.c @@ -0,0 +1,5 @@ +/* Bug #1895 - missing diagnostics on incompatible pointer/array types */ + +#define DO_TEST_1_SUB_4_A + +#include "bug1895-common.h" diff --git a/test/err/bug1895-assign4b.c b/test/err/bug1895-assign4b.c new file mode 100644 index 000000000..740e10b04 --- /dev/null +++ b/test/err/bug1895-assign4b.c @@ -0,0 +1,5 @@ +/* Bug #1895 - missing diagnostics on incompatible pointer/array types */ + +#define DO_TEST_1_SUB_4_B + +#include "bug1895-common.h" diff --git a/test/err/bug1895-assign5a.c b/test/err/bug1895-assign5a.c new file mode 100644 index 000000000..fed4e07d9 --- /dev/null +++ b/test/err/bug1895-assign5a.c @@ -0,0 +1,5 @@ +/* Bug #1895 - missing diagnostics on incompatible pointer/array types */ + +#define DO_TEST_1_SUB_5_A + +#include "bug1895-common.h" diff --git a/test/err/bug1895-assign5b.c b/test/err/bug1895-assign5b.c new file mode 100644 index 000000000..ed8498e34 --- /dev/null +++ b/test/err/bug1895-assign5b.c @@ -0,0 +1,5 @@ +/* Bug #1895 - missing diagnostics on incompatible pointer/array types */ + +#define DO_TEST_1_SUB_5_B + +#include "bug1895-common.h" diff --git a/test/err/bug1895-common.h b/test/err/bug1895-common.h new file mode 100644 index 000000000..03f02e2de --- /dev/null +++ b/test/err/bug1895-common.h @@ -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; +} diff --git a/test/err/bug1895-cond1.c b/test/err/bug1895-cond1.c new file mode 100644 index 000000000..ac6a301c9 --- /dev/null +++ b/test/err/bug1895-cond1.c @@ -0,0 +1,5 @@ +/* Bug #1895 - missing diagnostics on incompatible pointer/array types */ + +#define DO_TEST_2_SUB_1 + +#include "bug1895-common.h" diff --git a/test/err/bug1895-cond2.c b/test/err/bug1895-cond2.c new file mode 100644 index 000000000..81b8b2912 --- /dev/null +++ b/test/err/bug1895-cond2.c @@ -0,0 +1,5 @@ +/* Bug #1895 - missing diagnostics on incompatible pointer/array types */ + +#define DO_TEST_2_SUB_2 + +#include "bug1895-common.h" diff --git a/test/err/bug1895-cond3.c b/test/err/bug1895-cond3.c new file mode 100644 index 000000000..f1571acbf --- /dev/null +++ b/test/err/bug1895-cond3.c @@ -0,0 +1,5 @@ +/* Bug #1895 - missing diagnostics on incompatible pointer/array types */ + +#define DO_TEST_2_SUB_3 + +#include "bug1895-common.h" diff --git a/test/err/bug1895-cond4.c b/test/err/bug1895-cond4.c new file mode 100644 index 000000000..e7ef77964 --- /dev/null +++ b/test/err/bug1895-cond4.c @@ -0,0 +1,5 @@ +/* Bug #1895 - missing diagnostics on incompatible pointer/array types */ + +#define DO_TEST_2_SUB_4 + +#include "bug1895-common.h" diff --git a/test/err/bug1895-cond5.c b/test/err/bug1895-cond5.c new file mode 100644 index 000000000..1625c599b --- /dev/null +++ b/test/err/bug1895-cond5.c @@ -0,0 +1,5 @@ +/* Bug #1895 - missing diagnostics on incompatible pointer/array types */ + +#define DO_TEST_2_SUB_5 + +#include "bug1895-common.h" diff --git a/test/err/bug1895-prototype1.c b/test/err/bug1895-prototype1.c new file mode 100644 index 000000000..30331e757 --- /dev/null +++ b/test/err/bug1895-prototype1.c @@ -0,0 +1,5 @@ +/* Bug #1895 - missing diagnostics on incompatible pointer/array types */ + +#define DO_TEST_3_SUB_1 + +#include "bug1895-common.h" diff --git a/test/err/bug1895-prototype2.c b/test/err/bug1895-prototype2.c new file mode 100644 index 000000000..c8fe213f4 --- /dev/null +++ b/test/err/bug1895-prototype2.c @@ -0,0 +1,5 @@ +/* Bug #1895 - missing diagnostics on incompatible pointer/array types */ + +#define DO_TEST_3_SUB_2 + +#include "bug1895-common.h" diff --git a/test/err/bug1895-prototype3.c b/test/err/bug1895-prototype3.c new file mode 100644 index 000000000..f7d2b79e4 --- /dev/null +++ b/test/err/bug1895-prototype3.c @@ -0,0 +1,5 @@ +/* Bug #1895 - missing diagnostics on incompatible pointer/array types */ + +#define DO_TEST_3_SUB_3 + +#include "bug1895-common.h" diff --git a/test/err/bug1895-prototype4.c b/test/err/bug1895-prototype4.c new file mode 100644 index 000000000..3d0fe2c05 --- /dev/null +++ b/test/err/bug1895-prototype4.c @@ -0,0 +1,5 @@ +/* Bug #1895 - missing diagnostics on incompatible pointer/array types */ + +#define DO_TEST_3_SUB_4 + +#include "bug1895-common.h" diff --git a/test/err/bug1895-prototype5.c b/test/err/bug1895-prototype5.c new file mode 100644 index 000000000..ba9b997c9 --- /dev/null +++ b/test/err/bug1895-prototype5.c @@ -0,0 +1,5 @@ +/* Bug #1895 - missing diagnostics on incompatible pointer/array types */ + +#define DO_TEST_3_SUB_5 + +#include "bug1895-common.h" diff --git a/test/misc/Makefile b/test/misc/Makefile index e77d37b29..d0b8979b0 100644 --- a/test/misc/Makefile +++ b/test/misc/Makefile @@ -59,9 +59,9 @@ $(ISEQUAL): ../isequal.c | $(WORKDIR) define PRG_template # should compile, but gives an error -$(WORKDIR)/bug1768.$1.$2.prg: bug1768.c | $(WORKDIR) +$(WORKDIR)/int-static-1888.$1.$2.prg: int-static-1888.c | $(WORKDIR) @echo "FIXME: " $$@ "currently does not compile." - $(if $(QUIET),echo misc/bug1768.$1.$2.prg) + $(if $(QUIET),echo misc/int-static-1888.$1.$2.prg) $(NOT) $(CC65) -t sim$2 -$1 -o $$@ $$< $(NULLERR) # should compile, but gives an error @@ -132,6 +132,14 @@ $(WORKDIR)/bug1265.$1.$2.prg: bug1265.c | $(WORKDIR) $(LD65) -t sim$2 -o $$@ $$(@:.prg=.o) sim$2.lib $(NULLERR) $(SIM65) $(SIM65FLAGS) $$@ $(NULLOUT) $(NULLERR) +# this one requires -Werror +$(WORKDIR)/bug1768.$1.$2.prg: bug1768.c | $(WORKDIR) + $(if $(QUIET),echo misc/bug1768.$1.$2.prg) + $(CC65) -Werror -t sim$2 -$1 -o $$(@:.prg=.s) $$< $(NULLERR) + $(CA65) -t sim$2 -o $$(@:.prg=.o) $$(@:.prg=.s) $(NULLERR) + $(LD65) -t sim$2 -o $$@ $$(@:.prg=.o) sim$2.lib $(NULLERR) + $(SIM65) $(SIM65FLAGS) $$@ $(NULLOUT) $(NULLERR) + # should compile, but then hangs in an endless loop $(WORKDIR)/endless.$1.$2.prg: endless.c | $(WORKDIR) $(if $(QUIET),echo misc/endless.$1.$2.prg) diff --git a/test/misc/bug1768.c b/test/misc/bug1768.c index 916aa64bc..35cee1049 100644 --- a/test/misc/bug1768.c +++ b/test/misc/bug1768.c @@ -1,14 +1,147 @@ +/* + Copyright 2021-2022, The cc65 Authors -#include + This software is provided "as-is", without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. -int a = 1 || (8 / 0); -int b = 0 && (8 % 0); -int c = 1 ? 42 : (0 % 0); -int d = 1 || a / 0; -int e = 0 && b % 0; -int f = 1 ? 42 : (a %= 0, b /= 0); + Permission is granted to anyone to use this software for any purpose, + including commercial applications; and, to alter it and redistribute it + freely, subject to the following restrictions: + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated, but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ + +/* + Test of operations in unevaluated context resulted from 'sizeof' and + short-circuited code-paths in AND, OR and conditional operations. + + See also: + https://github.com/cc65/cc65/issues/1768#issuecomment-1175221466 +*/ + +#include + +static int failures; + +#define TEST(EXPR)\ + {\ + int acc = 0;\ + acc += sizeof((EXPR), 0);\ + acc += (0 && (EXPR));\ + acc += (1 || (EXPR));\ + acc += (0 ? (EXPR) : 0);\ + acc += (1 ? 0 : (EXPR));\ + if (acc == 0) {\ + printf("acc = %d\n", acc);\ + ++failures;\ + }\ + } + +/* Division by zero/modulo with zero */ +void test_1(void) +{ + int i; + int j; + TEST((i / 0) | (j % 0)) +} + +/* Division by zero/modulo with zero */ +void test_2(void) +{ + int i; + int j; + TEST((i /= 0) | (j %= 0)) +} + +/* Shift by too wide counts */ +void test_3(void) +{ + int i; + int j; + TEST((i << 32) | (j >> 32)) +} + +/* Shift by too wide counts */ +void test_4(void) +{ + int i; + int j; + TEST((i <<= 32) | (j >>= 32)) +} + +/* Shift by negative counts */ +void test_5(void) +{ + int i; + int j; + TEST((i << -1) | (j >> -1)) +} + +/* Shift by negative counts */ +void test_6(void) +{ + int i; + int j; + TEST((i <<= -1) | (j >>= -1)) +} + +/* Shift bit-fields */ +void test_7(void) +{ + struct S { + long i : 24; /* Will be promoted to 32-bit integer in calculation */ + long j : 8; /* Will be promoted to 16-bit integer in calculation */ + } s; + long k; + + s.i = 1; + printf("%u\n", sizeof(s.i << 24)); + s.i = 2; + k = s.i << 16; + if (k != 0x00020000L) { + printf("k = %ld, expected: %ld\n", k, 0x00020000L); + } + TEST(s.j >> 16) +} + +/* Shift bit-fields */ +void test_8(void) +{ + struct S { + long i : 24; /* Will be promoted to 32-bit integer in calculation */ + long j : 8; /* Will be promoted to 16-bit integer in calculation */ + } s; + long k; + + s.i = 3; + printf("%u\n", sizeof(s.i << 24)); + s.i = 4; + k = s.i <<= 16; + if (k != 0x00040000L) { + printf("k = %ld, expected: %ld\n", k, 0x00040000L); + } + TEST(s.j >>= 8) +} + +/* Do all tests */ int main(void) { - return EXIT_SUCCESS; + test_1(); + test_2(); + test_3(); + test_4(); + test_5(); + test_6(); + test_7(); + test_8(); + + printf("Failures: %d\n", failures); + return failures; } diff --git a/test/readme.txt b/test/readme.txt index dd87ea9df..41d19aee3 100644 --- a/test/readme.txt +++ b/test/readme.txt @@ -20,6 +20,28 @@ compiler is working as expected (when the tests behave as described): library. /ref - These tests produce output that must be compared with reference output. + Normally the reference output is produced by compiling the program on the + host (using gcc mostly) and then running them on the host. Tests should + be tweaked to produce the same output as on the host in the cases where + it would be different. + + The Makefile also handles some special cases (add the tests to the + respective list in the makefile): + + - Sometimes we want to check the warnings produced by the compiler. In + that case use the CUSTOMSOURCES list. Whatever output the compiler writes + to stderr will be compared against the matching .cref file. There is an + example in custom-reference.c/.cref + + - Sometimes we want to check what kind of output the compiler produces + for a file that does not compile. In that case use the ERRORSOURCES list. + There is an example in custom-reference-error.c/.cref + + Warning: please understand that comparing the compiler output against + a reference produces a moving target, ie the tests may break randomly + at any time when the compiler output changes for whatever reason. So + only ever use this as a last resort when something can not be tested by + other means. /err - contains tests that MUST NOT compile diff --git a/test/ref/Makefile b/test/ref/Makefile index d9c9817ee..abd3e9bc0 100644 --- a/test/ref/Makefile +++ b/test/ref/Makefile @@ -11,12 +11,14 @@ ifdef CMD_EXE NULLDEV = nul: MKDIR = mkdir $(subst /,\,$1) RMDIR = -rmdir /s /q $(subst /,\,$1) + COPY = copy $(subst /,\,$1) $(subst /,\,$2) else S = / EXE = NULLDEV = /dev/null MKDIR = mkdir -p $1 RMDIR = $(RM) -r $1 + COPY = cp $1 $2 endif ifdef QUIET @@ -42,24 +44,48 @@ CFLAGS = -O2 -Wall -W -Wextra -funsigned-char -fwrapv -fno-strict-overflow .PHONY: all clean -SOURCES := $(wildcard *.c) +# list of sources that produces warnings that we want to check. a .cref file +# containing the exact output is required. +CUSTOMSOURCES = \ + custom-reference.c + +# list of sources that produce a compiler error. a .cref files containing the +# exact error output is required +ERRORSOURCES = \ + custom-reference-error.c \ + bug1889-missing-identifier.c + +SOURCES := $(filter-out $(CUSTOMSOURCES) $(ERRORSOURCES),$(wildcard *.c)) + REFS = $(SOURCES:%.c=$(WORKDIR)/%.ref) +CUSTOMREFS = $(CUSTOMSOURCES:%.c=$(WORKDIR)/%.cref) $(ERRORSOURCES:%.c=$(WORKDIR)/%.cref) + TESTS = $(foreach option,$(OPTIONS),$(SOURCES:%.c=$(WORKDIR)/%.$(option).6502.prg)) TESTS += $(foreach option,$(OPTIONS),$(SOURCES:%.c=$(WORKDIR)/%.$(option).65c02.prg)) -all: $(REFS) $(TESTS) +CUSTOMTESTS = $(foreach option,$(OPTIONS),$(CUSTOMSOURCES:%.c=$(WORKDIR)/%.$(option).6502.custom.prg)) +CUSTOMTESTS += $(foreach option,$(OPTIONS),$(CUSTOMSOURCES:%.c=$(WORKDIR)/%.$(option).65c02.custom.prg)) + +ERRORTESTS = $(foreach option,$(OPTIONS),$(ERRORSOURCES:%.c=$(WORKDIR)/%.$(option).6502.error.prg)) +ERRORTESTS += $(foreach option,$(OPTIONS),$(ERRORSOURCES:%.c=$(WORKDIR)/%.$(option).65c02.error.prg)) + +all: $(CUSTOMREFS) $(REFS) $(TESTS) $(CUSTOMTESTS) $(ERRORTESTS) $(WORKDIR): $(call MKDIR,$(WORKDIR)) +$(ISEQUAL): ../isequal.c | $(WORKDIR) + $(CC) $(CFLAGS) -o $@ $< + +$(WORKDIR)/%.cref: %.cref | $(WORKDIR) + $(if $(QUIET),echo ref/$*.cref) + $(call COPY,$*.cref,$@) + $(WORKDIR)/%.ref: %.c | $(WORKDIR) $(if $(QUIET),echo ref/$*.host) $(CC) $(CFLAGS) -o $(WORKDIR)/$*.host $< $(NULLERR) $(WORKDIR)$S$*.host > $@ -$(ISEQUAL): ../isequal.c | $(WORKDIR) - $(CC) $(CFLAGS) -o $@ $< - # "yaccdbg.c" includes "yacc.c". # yaccdbg's built files must depend on both of them. # @@ -78,8 +104,43 @@ $(WORKDIR)/%.$1.$2.prg: %.c $(WORKDIR)/%.ref $(ISEQUAL) endef # PRG_template +# extra template for the case when compilation works, but we still want to +# compare the warning output with our custom reference +define PRG_custom_template + +$(WORKDIR)/%.$1.$2.custom.prg: %.c $(WORKDIR)/%.ref %.c $(WORKDIR)/%.cref $(ISEQUAL) + $(if $(QUIET),echo cref/$$*.$1.$2.custom.prg) + -$(CC65) -t sim$2 $$(CC65FLAGS) -$1 -o $$(@:.custom.prg=.s) $$< 2> $(WORKDIR)/$$*.$1.$2.cout + $(CA65) -t sim$2 -o $$(@:.custom.prg=.o) $$(@:.custom.prg=.s) $(NULLERR) + $(LD65) -t sim$2 -o $$@ $$(@:.custom.prg=.o) sim$2.lib $(NULLERR) + $(SIM65) $(SIM65FLAGS) $$@ > $(WORKDIR)/$$*.$1.$2.out + $(ISEQUAL) $(WORKDIR)/$$*.$1.$2.cout $(WORKDIR)/$$*.cref + $(ISEQUAL) $(WORKDIR)/$$*.$1.$2.out $(WORKDIR)/$$*.ref + +endef # PRG_error_template + +# extra template for the case when compilation fails, but we still want to +# compare the error output with our custom reference +define PRG_error_template + +$(WORKDIR)/%.$1.$2.error.prg: %.c $(WORKDIR)/%.cref $(ISEQUAL) + $(if $(QUIET),echo cref/$$*.$1.$2.error.prg) + -$(CC65) -t sim$2 $$(CC65FLAGS) -$1 -o $$(@:.error.prg=.s) $$< 2> $(WORKDIR)/$$*.$1.$2.cout +# $(CA65) -t sim$2 -o $$(@:.error.prg=.o) $$(@:.error.prg=.s) $(NULLERR) +# $(LD65) -t sim$2 -o $$@ $$(@:.error.prg=.o) sim$2.lib $(NULLERR) +# $(SIM65) $(SIM65FLAGS) $$@ > $(WORKDIR)/$$*.$1.$2.out + $(ISEQUAL) $(WORKDIR)/$$*.$1.$2.cout $(WORKDIR)/$$*.cref + +endef # PRG_error_template + $(foreach option,$(OPTIONS),$(eval $(call PRG_template,$(option),6502))) $(foreach option,$(OPTIONS),$(eval $(call PRG_template,$(option),65c02))) +$(foreach option,$(OPTIONS),$(eval $(call PRG_custom_template,$(option),6502))) +$(foreach option,$(OPTIONS),$(eval $(call PRG_custom_template,$(option),65c02))) + +$(foreach option,$(OPTIONS),$(eval $(call PRG_error_template,$(option),6502))) +$(foreach option,$(OPTIONS),$(eval $(call PRG_error_template,$(option),65c02))) + clean: @$(call RMDIR,$(WORKDIR)) diff --git a/test/ref/bug1889-missing-identifier.c b/test/ref/bug1889-missing-identifier.c new file mode 100644 index 000000000..d9cf4aa52 --- /dev/null +++ b/test/ref/bug1889-missing-identifier.c @@ -0,0 +1,9 @@ +/* bug 1889 - endless errors due to failure in recovery from missing identifier */ + +int enum { a } x; +inline enum { b }; + +int main(void) +{ + return 0; +} diff --git a/test/ref/bug1889-missing-identifier.cref b/test/ref/bug1889-missing-identifier.cref new file mode 100644 index 000000000..cd3f76849 --- /dev/null +++ b/test/ref/bug1889-missing-identifier.cref @@ -0,0 +1,3 @@ +bug1889-missing-identifier.c:3: Error: Identifier expected +bug1889-missing-identifier.c:4: Error: Identifier expected +bug1889-missing-identifier.c:4: Warning: Implicit 'int' is an obsolete feature diff --git a/test/ref/custom-reference-error.c b/test/ref/custom-reference-error.c new file mode 100644 index 000000000..c86a8b9e9 --- /dev/null +++ b/test/ref/custom-reference-error.c @@ -0,0 +1,21 @@ + +/* + this is an example (not actually a regression test) that shows how to + make a check that compares the compiler (error-) output with a provided + reference. + + to produce a reference file, first make sure your program "works" as intended, + then "make" in this directory once and copy the produced compiler output to + the reference: + + $ cp ../../testwrk/ref/custom-reference-error.g.6502.out custom-reference-error.cref + + and then "make" again to confirm +*/ + +int main(int argc, char* argv[]) +{ + printf("%02x", 0x42); + n = 0; /* produce an error */ + /* another error */ +} diff --git a/test/ref/custom-reference-error.cref b/test/ref/custom-reference-error.cref new file mode 100644 index 000000000..fa584f307 --- /dev/null +++ b/test/ref/custom-reference-error.cref @@ -0,0 +1,5 @@ +custom-reference-error.c:18: Error: Call to undeclared function 'printf' +custom-reference-error.c:19: Error: Undefined symbol: 'n' +custom-reference-error.c:21: Warning: Control reaches end of non-void function [-Wreturn-type] +custom-reference-error.c:21: Warning: Parameter 'argc' is never used +custom-reference-error.c:21: Warning: Parameter 'argv' is never used diff --git a/test/ref/custom-reference.c b/test/ref/custom-reference.c new file mode 100644 index 000000000..5d9c356df --- /dev/null +++ b/test/ref/custom-reference.c @@ -0,0 +1,24 @@ + +/* + this is an example (not actually a regression test) that shows how to + make a check that compares the compiler (error-) output with a provided + reference. + + to produce a reference file, first make sure your program "works" as intended, + then "make" in this directory once and copy the produced compiler output to + the reference: + + $ cp ../../testwrk/ref/custom-reference.g.6502.out custom-reference.cref + + and then "make" again to confirm +*/ + +#include +#include + +int main(int argc, char* argv[]) +{ + printf("%02x", 0x42); + /* produce a warning */ + return 0; +} diff --git a/test/ref/custom-reference.cref b/test/ref/custom-reference.cref new file mode 100644 index 000000000..4dba6009b --- /dev/null +++ b/test/ref/custom-reference.cref @@ -0,0 +1,2 @@ +custom-reference.c:24: Warning: Parameter 'argc' is never used +custom-reference.c:24: Warning: Parameter 'argv' is never used diff --git a/test/todo/sprintf-test.c b/test/todo/sprintf-test.c index bd5de44b4..ea50f418a 100644 --- a/test/todo/sprintf-test.c +++ b/test/todo/sprintf-test.c @@ -564,9 +564,9 @@ int main (void) /* Output the result */ if (Failures) { - printf ("%u tests, %u failures\n", Tests, Failures); + printf ("sprintf-test: %u tests, %u failures\n", Tests, Failures); } else { - printf ("%u tests: Ok\n", Tests); + printf ("sprintf-test: %u tests: Ok\n", Tests); } /* Wait for a key so we can read the result */ diff --git a/test/val/assign-use1.c b/test/val/assign-shift-use1.c similarity index 100% rename from test/val/assign-use1.c rename to test/val/assign-shift-use1.c diff --git a/test/val/fields.c b/test/val/bitfield-1.c similarity index 100% rename from test/val/fields.c rename to test/val/bitfield-1.c diff --git a/test/val/char-bitfield.c b/test/val/bitfield-char-1.c similarity index 100% rename from test/val/char-bitfield.c rename to test/val/bitfield-char-1.c diff --git a/test/val/call1.c b/test/val/boolean-call1.c similarity index 100% rename from test/val/call1.c rename to test/val/boolean-call1.c diff --git a/test/val/bug1408.c b/test/val/bug1408.c index 8ecc1be68..137899315 100644 --- a/test/val/bug1408.c +++ b/test/val/bug1408.c @@ -1,41 +1,41 @@ -/* Bug #1408: Signed char type comparisons with unsigned numeric constants */ - -#include - -static int failures = 0; -static signed char x = -1; - -int main(void) -{ - if (!(x > -2u)) { - printf("x > -2u should be true\n"); - ++failures; - } - if (!(x > 0u)) { - printf("x > 0u should be true\n"); - ++failures; - } - if (!(x > 255u)) { - printf("x > 255u should be true\n"); - ++failures; - } - - if (!(-2u < x)) { - printf("-2u < x should be true\n"); - ++failures; - } - if (!(0u < x)) { - printf("0u < x should be true\n"); - ++failures; - } - if (!(255u < x)) { - printf("255u < x should be true\n"); - ++failures; - } - - if (failures != 0) { - printf("Failures: %d\n", failures); - } - - return failures; -} +/* Bug #1408: Signed char type comparisons with unsigned numeric constants */ + +#include + +static int failures = 0; +static signed char x = -1; + +int main(void) +{ + if (!(x > -2u)) { + printf("x > -2u should be true\n"); + ++failures; + } + if (!(x > 0u)) { + printf("x > 0u should be true\n"); + ++failures; + } + if (!(x > 255u)) { + printf("x > 255u should be true\n"); + ++failures; + } + + if (!(-2u < x)) { + printf("-2u < x should be true\n"); + ++failures; + } + if (!(0u < x)) { + printf("0u < x should be true\n"); + ++failures; + } + if (!(255u < x)) { + printf("255u < x should be true\n"); + ++failures; + } + + if (failures != 0) { + printf("Failures: %d\n", failures); + } + + return failures; +} diff --git a/test/val/bug1451-struct-ptr-to-local.c b/test/val/bug1451-struct-ptr-to-local.c index f9cca2561..2148e034d 100644 --- a/test/val/bug1451-struct-ptr-to-local.c +++ b/test/val/bug1451-struct-ptr-to-local.c @@ -1,39 +1,39 @@ -/* Bug #1451 - local struct field access via the address of the struct */ - -#include - -typedef struct { - int a; - int b; -} S; - -int failures = 0; - -int main(void) -{ - S a = {2, 5}; - S b = {1, 4}; - S m[1] = {{6, 3}}; - S *p = &a; - - (&a)->a += b.a; - p->b += b.b; - m->a += b.a; - - if ((&a)->a != 3) { - ++failures; - printf("Expected 3, got %d\n", (&a)->a); - } - - if (p->b != 9) { - ++failures; - printf("Expected 9, got %d\n", p->b); - } - - if (m->a != 7) { - ++failures; - printf("Expected 7, got %d\n", m->a); - } - - return failures; -} +/* Bug #1451 - local struct field access via the address of the struct */ + +#include + +typedef struct { + int a; + int b; +} S; + +int failures = 0; + +int main(void) +{ + S a = {2, 5}; + S b = {1, 4}; + S m[1] = {{6, 3}}; + S *p = &a; + + (&a)->a += b.a; + p->b += b.b; + m->a += b.a; + + if ((&a)->a != 3) { + ++failures; + printf("Expected 3, got %d\n", (&a)->a); + } + + if (p->b != 9) { + ++failures; + printf("Expected 9, got %d\n", p->b); + } + + if (m->a != 7) { + ++failures; + printf("Expected 7, got %d\n", m->a); + } + + return failures; +} diff --git a/test/val/bug1462-biefield-assign-4.c b/test/val/bug1462-biefield-assign-4.c index f811ddbd6..e607dbd25 100644 --- a/test/val/bug1462-biefield-assign-4.c +++ b/test/val/bug1462-biefield-assign-4.c @@ -1,6 +1,6 @@ /* issue #1462 - Bit-fields are still broken */ -/* More tests on "op= expression result value" that a naive fix might fail with */ +/* When (un-)signedness involves with integral promotion */ #include #include diff --git a/test/val/bug1643.c b/test/val/bug1643.c index eba733511..c6237b7fb 100644 --- a/test/val/bug1643.c +++ b/test/val/bug1643.c @@ -1,12 +1,12 @@ -/* bug #1643, macro expansion in #include */ - -#define MKSTR(a) MKSTR_IMPL(a) -#define MKSTR_IMPL(a) #a -#define BUG1643_H bug1643.h - -#include MKSTR(BUG1643_H) - -int main(void) -{ - return BUG1643_RESULT; -} +/* bug #1643, macro expansion in #include */ + +#define MKSTR(a) MKSTR_IMPL(a) +#define MKSTR_IMPL(a) #a +#define BUG1643_H bug1643.h + +#include MKSTR(BUG1643_H) + +int main(void) +{ + return BUG1643_RESULT; +} diff --git a/test/val/bug1643.h b/test/val/bug1643.h index fe0423688..068263436 100644 --- a/test/val/bug1643.h +++ b/test/val/bug1643.h @@ -1,13 +1,13 @@ -/* bug #1643, macro expansion in #include */ - -#define STDIO_H -#include STDIO_H - -#ifdef string -#undef string -#endif - -#define string 0!%^&*/_= -#include - -#define BUG1643_RESULT 0 +/* bug #1643, macro expansion in #include */ + +#define STDIO_H +#include STDIO_H + +#ifdef string +#undef string +#endif + +#define string 0!%^&*/_= +#include + +#define BUG1643_RESULT 0 diff --git a/test/val/bug1690.c b/test/val/bug1690.c index 499dc6b35..78c0cda41 100644 --- a/test/val/bug1690.c +++ b/test/val/bug1690.c @@ -1,30 +1,30 @@ -/* OptCmp1 messed up with labels */ - -#include - -static int failures = 0; -static unsigned int z = 0xFF23; - -int main(void) -{ - register unsigned int x = 0x200; - register unsigned int y = 0; - - do { - ++y; - } while (--x); - if (y != 0x200) { - printf("y should be 0x200, not 0x%X.\n", y); - ++failures;; - } - - if ((z -= 0x23)) { - /* Passed -- non-zero z looks like non-zero. */ - } else { - /* Failed -- only the low byte of z was tested. */ - printf("Test thinks non-zero z is zero.\n"); - ++failures; - } - - return failures; -} +/* OptCmp1 messed up with labels */ + +#include + +static int failures = 0; +static unsigned int z = 0xFF23; + +int main(void) +{ + register unsigned int x = 0x200; + register unsigned int y = 0; + + do { + ++y; + } while (--x); + if (y != 0x200) { + printf("y should be 0x200, not 0x%X.\n", y); + ++failures;; + } + + if ((z -= 0x23)) { + /* Passed -- non-zero z looks like non-zero. */ + } else { + /* Failed -- only the low byte of z was tested. */ + printf("Test thinks non-zero z is zero.\n"); + ++failures; + } + + return failures; +} diff --git a/test/val/bug1822-pptest.c b/test/val/bug1822-pptest.c index eb4d23391..133d69f6b 100644 --- a/test/val/bug1822-pptest.c +++ b/test/val/bug1822-pptest.c @@ -1,25 +1,25 @@ -/* Bug #1822 - Redefined macros failed to be all undefined with a single #undef */ - -#undef F -#undef F - -#define F 1 -#define F 1 - -#undef F -#if defined F -#error #undef F fails! -#endif - -#define F 0 - -#include - -int main(void) -{ - if (F != 0) - { - printf("failed: F = %d\n", F); - } - return F; -} +/* Bug #1822 - Redefined macros failed to be all undefined with a single #undef */ + +#undef F +#undef F + +#define F 1 +#define F 1 + +#undef F +#if defined F +#error #undef F fails! +#endif + +#define F 0 + +#include + +int main(void) +{ + if (F != 0) + { + printf("failed: F = %d\n", F); + } + return F; +} diff --git a/test/val/bug1838.c b/test/val/bug1838.c index ea2d39a81..38becf5e9 100644 --- a/test/val/bug1838.c +++ b/test/val/bug1838.c @@ -1,35 +1,35 @@ -/* Bug 1838 - function parameters declared as function types rather than function pointers */ - -#include - -static int failures = 0; - -typedef int fn_t(int); - -int main(void) -{ - void foo(fn_t*); - fn_t bar; - - foo(bar); - return failures; -} - -void foo(int func(int)) -{ - int n = func(42); - - if (n != 12) { - printf("n = %d, expected: 12\n", n); - ++failures; - } -} - -int bar(int a) -{ - if (a != 42) { - printf("a = %d, expected: 42\n", a); - ++failures; - } - return 12; -} +/* Bug 1838 - function parameters declared as function types rather than function pointers */ + +#include + +static int failures = 0; + +typedef int fn_t(int); + +int main(void) +{ + void foo(fn_t*); + fn_t bar; + + foo(bar); + return failures; +} + +void foo(int func(int)) +{ + int n = func(42); + + if (n != 12) { + printf("n = %d, expected: 12\n", n); + ++failures; + } +} + +int bar(int a) +{ + if (a != 42) { + printf("a = %d, expected: 42\n", a); + ++failures; + } + return 12; +} diff --git a/test/val/bug1847-struct-field-access.c b/test/val/bug1847-struct-field-access.c index 71575636f..f7e19e40b 100644 --- a/test/val/bug1847-struct-field-access.c +++ b/test/val/bug1847-struct-field-access.c @@ -1,46 +1,46 @@ -/* Bug #1847 - struct field access */ - -#include - -struct TestStruct { - char a; - char b; - char c; -}; - -struct TestStruct s0[2] = { {0xFF, 0, 0xFF}, {0, 0x42, 0xFF} }; -struct TestStruct* s0Ptr = s0; - -#define TEST_READ_SUB(X, E) \ - if ((X) != (E)) { \ - printf(#X ": 0x%X, expected: 0x%X\n", (X), (E)); \ - ++failures; \ - } - -#define TEST_READ(S, I, F, E) \ - TEST_READ_SUB(S[I].F, E) \ - TEST_READ_SUB((&S[I])->F, E) \ - TEST_READ_SUB((&S[I])[0].F, E) \ - TEST_READ_SUB(S##Ptr[I].F, E) \ - TEST_READ_SUB((&S##Ptr[I])->F, E) \ - TEST_READ_SUB((&(S##Ptr[I]))[0].F, E) \ - TEST_READ_SUB((&(*S##Ptr))[I].F, E) \ - TEST_READ_SUB((&(*S##Ptr)+I)->F, E) \ - TEST_READ_SUB((S##Ptr+I)->F, E) \ - TEST_READ_SUB((S##Ptr+I)[0].F, E) - -static unsigned failures = 0; - -int main(void) { - struct TestStruct s1[2] = { {0xFF, 0, 0xFF}, {0, 42, 0xFF} }; - struct TestStruct* s1Ptr = s1; - - TEST_READ(s0, 1, b, 0x42) - TEST_READ(s1, 1, b, 42) - - if (failures > 0) { - printf("Failures: %u\n", failures); - } - - return failures; -} +/* Bug #1847 - struct field access */ + +#include + +struct TestStruct { + char a; + char b; + char c; +}; + +struct TestStruct s0[2] = { {0xFF, 0, 0xFF}, {0, 0x42, 0xFF} }; +struct TestStruct* s0Ptr = s0; + +#define TEST_READ_SUB(X, E) \ + if ((X) != (E)) { \ + printf(#X ": 0x%X, expected: 0x%X\n", (X), (E)); \ + ++failures; \ + } + +#define TEST_READ(S, I, F, E) \ + TEST_READ_SUB(S[I].F, E) \ + TEST_READ_SUB((&S[I])->F, E) \ + TEST_READ_SUB((&S[I])[0].F, E) \ + TEST_READ_SUB(S##Ptr[I].F, E) \ + TEST_READ_SUB((&S##Ptr[I])->F, E) \ + TEST_READ_SUB((&(S##Ptr[I]))[0].F, E) \ + TEST_READ_SUB((&(*S##Ptr))[I].F, E) \ + TEST_READ_SUB((&(*S##Ptr)+I)->F, E) \ + TEST_READ_SUB((S##Ptr+I)->F, E) \ + TEST_READ_SUB((S##Ptr+I)[0].F, E) + +static unsigned failures = 0; + +int main(void) { + struct TestStruct s1[2] = { {0xFF, 0, 0xFF}, {0, 42, 0xFF} }; + struct TestStruct* s1Ptr = s1; + + TEST_READ(s0, 1, b, 0x42) + TEST_READ(s1, 1, b, 42) + + if (failures > 0) { + printf("Failures: %u\n", failures); + } + + return failures; +} diff --git a/test/val/bug1891.c b/test/val/bug1891.c new file mode 100644 index 000000000..0373ba46d --- /dev/null +++ b/test/val/bug1891.c @@ -0,0 +1,19 @@ +/* bug #1891 - backslash/newline sequence in string constants is treated wrong */ + +#include +#include + +const char* a = "hello \ +world"; +const char* b = \ +"hello world"; + +int main(void) +{ + if (strcmp(a, b) != 0) { + printf("a:\n%s\n", a); + printf("b:\n%s\n", b); + return 1; + } + return 0; +} diff --git a/test/val/bug1933.c b/test/val/bug1933.c new file mode 100644 index 000000000..4715f38fe --- /dev/null +++ b/test/val/bug1933.c @@ -0,0 +1,9 @@ + +/* bug #1933 - wrong printf specifier breaks data lines */ + +unsigned char info_signature[3] = {3, 21, 63 | 0x80}; + +int main(void) +{ + return 0; +} diff --git a/test/val/bug1936.c b/test/val/bug1936.c new file mode 100644 index 000000000..e97231797 --- /dev/null +++ b/test/val/bug1936.c @@ -0,0 +1,88 @@ + +/* bug #1936 - Compiler produces broken Assembly (129 operand for bne) */ + +#include + +static uint8_t item_counter; + + +static uint8_t freeze; +static uint8_t powerUp; + +static uint8_t wall_appeared; +static uint8_t freeze_locked; +static uint8_t zombie_locked; + + +struct ItemStruct +{ + uint8_t _active; + void(*_effect)(void); +} ; +typedef struct ItemStruct Item; + +static Item freezeItem; +static Item powerUpItem; +static Item wallItem; +static Item zombieItem; + + +static Item extraPointsItem[1]; + + +uint8_t find_inactive(Item* itemArray) +{ +} + + +void drop_item(register Item *item, uint8_t max_counter) +{ +} + + +void handle_item_drop(void) +{ + { + if(item_counter==1) + { + if(!powerUpItem._active) + { + drop_item(&powerUpItem,35); + } + } + else if((!freeze_locked)&&(!freeze)) + { + if(!freezeItem._active) + { + drop_item(&freezeItem,45); + } + } + else if(!wall_appeared&&(powerUp>=9)) + { + if(!wallItem._active) + { + drop_item(&wallItem,35); + } + } + else if(!zombie_locked && !zombieItem._active) + { + drop_item(&zombieItem,50); + } + else + { + uint8_t index; + + index = find_inactive(extraPointsItem); + if(index!=1) // REMARK: compilation does not fail with 0 + { + drop_item(&extraPointsItem[index],90); + } + } + } +} + +int main(void) +{ + return 0; +} + diff --git a/test/val/bzero.c b/test/val/bzero.c new file mode 100644 index 000000000..4e7ed6ac1 --- /dev/null +++ b/test/val/bzero.c @@ -0,0 +1,51 @@ + +// test if memset and bzero work as expected after optimizations + +#include + +char s1[10] = { 1,2,3,4,5,6,7,8,9,10 }; +char r1[10] = { 0,0,0,0,0,6,7,8,9,10 }; + +char s2[10] = { 1,2,3,4,5,6,7,8,9,10 }; +char r2[10] = { 0,0,0,0,0,0,7,8,9,10 }; + +char s3[10] = { 1,2,3,4,5,6,7,8,9,10 }; +char r3[10] = { 0,0,0,0,0,0,0,8,9,10 }; + +char *p1, *p2, *p3; + +int res = 0; + +int main(void) +{ + /* regular bzero */ + bzero(s1, 5); + p1 = __AX__; /* this works because bzero jumps into memset */ + /* this gets converted to __bzero */ + p2 = memset(s2, 0, 6); + /* call internal __bzero (we should not do this in real code) */ + p3 = __bzero(s3, 7); + + /* check the results */ + if (memcmp(s1, r1, 10) != 0) { + res++; + } + if (memcmp(s2, r2, 10) != 0) { + res++; + } + if (memcmp(s3, r3, 10) != 0) { + res++; + } + + if (p1 != s1) { + res++; + } + if (p2 != s2) { + res++; + } + if (p3 != s3) { + res++; + } + + return res; +} diff --git a/test/val/bool3.c b/test/val/compare-bool3.c similarity index 100% rename from test/val/bool3.c rename to test/val/compare-bool3.c diff --git a/test/val/const-side-effect.c b/test/val/const-side-effect.c index 7c2f074f2..cebc6f099 100644 --- a/test/val/const-side-effect.c +++ b/test/val/const-side-effect.c @@ -1,160 +1,160 @@ -/* Check code generation for constant operands with side-effects */ - -#include - -static int failures = 0; - -#define TEST(X, Y, L) \ - if (x != X || y != Y) { \ - printf("Failed: " L "\nExpected: x = " #X ", y = " #Y ", got: x = %d, y = %d\n\n", x, y); \ - ++failures; \ - } - -#define TEST_LINE_UNARY(OP, RH, ID) \ - "x = " #OP "(set(&y, " #ID "), " #RH ")" - -#define TEST_UNARY(OP, RH, RS, ID) \ - x = -!(RS), y = -!(RS); \ - x = OP (set(&y, ID), RH); \ - TEST(RS, ID, TEST_LINE_UNARY(OP, RH, ID)) - -#define TEST_LINE_RHS_EFFECT(LH, OP, RH, ID) \ - "x = " #LH " " #OP " (set(&y, " #ID "), " #RH ")" - -#define TEST_LINE_LHS_EFFECT(LH, OP, RH, ID) \ - "y = (set(&x, " #ID "), " #LH ") " #OP " " #RH - -#define TEST_BINARY(LH, OP, RH, RS, ID) \ - x = -!(RS), y = -!(RS); \ - x = LH OP (set(&y, ID), RH); \ - TEST(RS, ID, TEST_LINE_RHS_EFFECT(LH, OP, RH, ID)) \ - y = -!(RS), x = -!(RS); \ - y = (set(&x, ID), LH) OP RH; \ - TEST(ID, RS, TEST_LINE_LHS_EFFECT(LH, OP, RH, ID)) \ - y = -!(RS); \ - x = (set(&x, LH), x) OP (set(&y, ID), RH); \ - TEST(RS, ID, TEST_LINE_RHS_EFFECT((set(&x, LH), x), OP, RH, ID)) \ - x = -!(RS); \ - y = (set(&x, ID), LH) OP (set(&y, RH), y); \ - TEST(ID, RS, TEST_LINE_LHS_EFFECT(LH, OP, (set(&y, RH), y), ID)) - -#define TEST_LINE_RHS_EFFECT_WITH_CAST(LT, LH, OP, RT, RH, ID) \ - "x = (" #LT ")" #LH " " #OP " (" #RT ")(set(&y, " #ID "), " #RH ")" - -#define TEST_LINE_LHS_EFFECT_WITH_CAST(LT, LH, OP, RT, RH, ID) \ - "y = (" #LT ")(set(&x, " #ID "), " #LH ") " #OP " (" #RT ")" #RH - -#define TEST_BINARY_WITH_CAST(LT, LH, OP, RT, RH, RS, ID) \ - x = -!(RS), y = -!(RS); \ - x = (LT)LH OP (RT)(set(&y, ID), RH); \ - TEST(RS, ID, TEST_LINE_RHS_EFFECT_WITH_CAST(LT, LH, OP, RT, RH, ID)) \ - y = -!(RS), x = -!(RS); \ - y = (LT)(set(&x, ID), LH) OP (RT)RH; \ - TEST(ID, RS, TEST_LINE_LHS_EFFECT_WITH_CAST(LT, LH, OP, RT, RH, ID)) \ - y = -!(RS); \ - x = (LT)(set(&x, LH), x) OP (RT)(set(&y, ID), RH); \ - TEST(RS, ID, TEST_LINE_RHS_EFFECT_WITH_CAST(LT, (set(&x, LH), x), OP, RT, RH, ID)) \ - x = -!(RS); \ - y = (LT)(set(&x, ID), LH) OP (RT)(set(&y, RH), y); \ - TEST(ID, RS, TEST_LINE_LHS_EFFECT_WITH_CAST(LT, LH, OP, RT, (set(&y, RH), y), ID)) - -void set(int *p, int q) -{ - *p = q; -} - -int twice(int a) -{ - return a * 2; -} - -int (*twicep)(int) = twice; - -void test_unary(void) -{ - int x, y; - - TEST_UNARY(+, 42, 42, 1); - TEST_UNARY(-, -42, 42, 2); - TEST_UNARY(~, ~42, 42, 3); - TEST_UNARY(!, 42, 0, 4); -} - -void test_binary_arithmetic(void) -{ - int x, y; - - TEST_BINARY(41, +, 1, 42, 1) - TEST_BINARY(42, +, 0, 42, 1) - - TEST_BINARY(43, -, 1, 42, 2) - TEST_BINARY(42, -, 0, 42, 2) - - TEST_BINARY(6, *, 7, 42, 3) - TEST_BINARY(42, *, 1, 42, 3) - TEST_BINARY(-42, *, -1, 42, 3) - - TEST_BINARY(126, /, 3, 42, 4) - TEST_BINARY(42, /, 1, 42, 4) - TEST_BINARY(-42, /, -1, 42, 4) - - TEST_BINARY(85, %, 43, 42, 5) - TEST_BINARY(10794, %, 256, 42, 5) - - TEST_BINARY(84, >>, 1, 42, 6) - TEST_BINARY(42, >>, 0, 42, 6) - TEST_BINARY(10752, >>, 8, 42, 6) - TEST_BINARY(21504, >>, 9, 42, 6) - - TEST_BINARY(21, <<, 1, 42, 7) - TEST_BINARY(42, <<, 0, 42, 7) - TEST_BINARY(42, <<, 8, 10752, 7) - - TEST_BINARY(59, &, 238, 42, 8) - TEST_BINARY(42, &, 0, 0, 8) - TEST_BINARY(42, &, -1, 42, 8) - - TEST_BINARY(34, |, 10, 42, 9) - TEST_BINARY(42, |, 0, 42, 9) - TEST_BINARY(34, |, -1, -1, 9) - - TEST_BINARY(59, ^, 17, 42, 10) - TEST_BINARY(42, ^, 0, 42, 10) - TEST_BINARY(~42, ^, -1, 42, 10) -} - -void test_binary_comparison(void) -{ - int x, y; - - TEST_BINARY(42, ==, 42, 1, 11) - - TEST_BINARY(42, !=, 43, 1, 12) - TEST_BINARY_WITH_CAST(signed char, 42, !=, long, 65536L, 1, 12) - TEST_BINARY_WITH_CAST(long, 65536L, !=, signed char, 42, 1, 12) - - TEST_BINARY(42, >, 41, 1, 13) - TEST_BINARY_WITH_CAST(int, 0, >, unsigned, 42, 0, 13) - - TEST_BINARY(42, <, 43, 1, 14) - TEST_BINARY_WITH_CAST(unsigned, 42, <, int, 0, 0, 14) - - TEST_BINARY(42, >=, 0, 1, 15) - TEST_BINARY_WITH_CAST(unsigned, 42, >=, int, 0, 1, 15) - - TEST_BINARY(42, <=, 43, 1, 16) - TEST_BINARY_WITH_CAST(int, 0, <=, unsigned, 42, 1, 16) -} - -int main(void) -{ - test_unary(); - test_binary_arithmetic(); - test_binary_comparison(); - - if (failures != 0) { - printf("Failures: %d\n", failures); - } - - return failures; -} +/* Check code generation for constant operands with side-effects */ + +#include + +static int failures = 0; + +#define TEST(X, Y, L) \ + if (x != X || y != Y) { \ + printf("Failed: " L "\nExpected: x = " #X ", y = " #Y ", got: x = %d, y = %d\n\n", x, y); \ + ++failures; \ + } + +#define TEST_LINE_UNARY(OP, RH, ID) \ + "x = " #OP "(set(&y, " #ID "), " #RH ")" + +#define TEST_UNARY(OP, RH, RS, ID) \ + x = -!(RS), y = -!(RS); \ + x = OP (set(&y, ID), RH); \ + TEST(RS, ID, TEST_LINE_UNARY(OP, RH, ID)) + +#define TEST_LINE_RHS_EFFECT(LH, OP, RH, ID) \ + "x = " #LH " " #OP " (set(&y, " #ID "), " #RH ")" + +#define TEST_LINE_LHS_EFFECT(LH, OP, RH, ID) \ + "y = (set(&x, " #ID "), " #LH ") " #OP " " #RH + +#define TEST_BINARY(LH, OP, RH, RS, ID) \ + x = -!(RS), y = -!(RS); \ + x = LH OP (set(&y, ID), RH); \ + TEST(RS, ID, TEST_LINE_RHS_EFFECT(LH, OP, RH, ID)) \ + y = -!(RS), x = -!(RS); \ + y = (set(&x, ID), LH) OP RH; \ + TEST(ID, RS, TEST_LINE_LHS_EFFECT(LH, OP, RH, ID)) \ + y = -!(RS); \ + x = (set(&x, LH), x) OP (set(&y, ID), RH); \ + TEST(RS, ID, TEST_LINE_RHS_EFFECT((set(&x, LH), x), OP, RH, ID)) \ + x = -!(RS); \ + y = (set(&x, ID), LH) OP (set(&y, RH), y); \ + TEST(ID, RS, TEST_LINE_LHS_EFFECT(LH, OP, (set(&y, RH), y), ID)) + +#define TEST_LINE_RHS_EFFECT_WITH_CAST(LT, LH, OP, RT, RH, ID) \ + "x = (" #LT ")" #LH " " #OP " (" #RT ")(set(&y, " #ID "), " #RH ")" + +#define TEST_LINE_LHS_EFFECT_WITH_CAST(LT, LH, OP, RT, RH, ID) \ + "y = (" #LT ")(set(&x, " #ID "), " #LH ") " #OP " (" #RT ")" #RH + +#define TEST_BINARY_WITH_CAST(LT, LH, OP, RT, RH, RS, ID) \ + x = -!(RS), y = -!(RS); \ + x = (LT)LH OP (RT)(set(&y, ID), RH); \ + TEST(RS, ID, TEST_LINE_RHS_EFFECT_WITH_CAST(LT, LH, OP, RT, RH, ID)) \ + y = -!(RS), x = -!(RS); \ + y = (LT)(set(&x, ID), LH) OP (RT)RH; \ + TEST(ID, RS, TEST_LINE_LHS_EFFECT_WITH_CAST(LT, LH, OP, RT, RH, ID)) \ + y = -!(RS); \ + x = (LT)(set(&x, LH), x) OP (RT)(set(&y, ID), RH); \ + TEST(RS, ID, TEST_LINE_RHS_EFFECT_WITH_CAST(LT, (set(&x, LH), x), OP, RT, RH, ID)) \ + x = -!(RS); \ + y = (LT)(set(&x, ID), LH) OP (RT)(set(&y, RH), y); \ + TEST(ID, RS, TEST_LINE_LHS_EFFECT_WITH_CAST(LT, LH, OP, RT, (set(&y, RH), y), ID)) + +void set(int *p, int q) +{ + *p = q; +} + +int twice(int a) +{ + return a * 2; +} + +int (*twicep)(int) = twice; + +void test_unary(void) +{ + int x, y; + + TEST_UNARY(+, 42, 42, 1); + TEST_UNARY(-, -42, 42, 2); + TEST_UNARY(~, ~42, 42, 3); + TEST_UNARY(!, 42, 0, 4); +} + +void test_binary_arithmetic(void) +{ + int x, y; + + TEST_BINARY(41, +, 1, 42, 1) + TEST_BINARY(42, +, 0, 42, 1) + + TEST_BINARY(43, -, 1, 42, 2) + TEST_BINARY(42, -, 0, 42, 2) + + TEST_BINARY(6, *, 7, 42, 3) + TEST_BINARY(42, *, 1, 42, 3) + TEST_BINARY(-42, *, -1, 42, 3) + + TEST_BINARY(126, /, 3, 42, 4) + TEST_BINARY(42, /, 1, 42, 4) + TEST_BINARY(-42, /, -1, 42, 4) + + TEST_BINARY(85, %, 43, 42, 5) + TEST_BINARY(10794, %, 256, 42, 5) + + TEST_BINARY(84, >>, 1, 42, 6) + TEST_BINARY(42, >>, 0, 42, 6) + TEST_BINARY(10752, >>, 8, 42, 6) + TEST_BINARY(21504, >>, 9, 42, 6) + + TEST_BINARY(21, <<, 1, 42, 7) + TEST_BINARY(42, <<, 0, 42, 7) + TEST_BINARY(42, <<, 8, 10752, 7) + + TEST_BINARY(59, &, 238, 42, 8) + TEST_BINARY(42, &, 0, 0, 8) + TEST_BINARY(42, &, -1, 42, 8) + + TEST_BINARY(34, |, 10, 42, 9) + TEST_BINARY(42, |, 0, 42, 9) + TEST_BINARY(34, |, -1, -1, 9) + + TEST_BINARY(59, ^, 17, 42, 10) + TEST_BINARY(42, ^, 0, 42, 10) + TEST_BINARY(~42, ^, -1, 42, 10) +} + +void test_binary_comparison(void) +{ + int x, y; + + TEST_BINARY(42, ==, 42, 1, 11) + + TEST_BINARY(42, !=, 43, 1, 12) + TEST_BINARY_WITH_CAST(signed char, 42, !=, long, 65536L, 1, 12) + TEST_BINARY_WITH_CAST(long, 65536L, !=, signed char, 42, 1, 12) + + TEST_BINARY(42, >, 41, 1, 13) + TEST_BINARY_WITH_CAST(int, 0, >, unsigned, 42, 0, 13) + + TEST_BINARY(42, <, 43, 1, 14) + TEST_BINARY_WITH_CAST(unsigned, 42, <, int, 0, 0, 14) + + TEST_BINARY(42, >=, 0, 1, 15) + TEST_BINARY_WITH_CAST(unsigned, 42, >=, int, 0, 1, 15) + + TEST_BINARY(42, <=, 43, 1, 16) + TEST_BINARY_WITH_CAST(int, 0, <=, unsigned, 42, 1, 16) +} + +int main(void) +{ + test_unary(); + test_binary_arithmetic(); + test_binary_comparison(); + + if (failures != 0) { + printf("Failures: %d\n", failures); + } + + return failures; +} diff --git a/test/val/counter.c b/test/val/counter.c index 4efa18359..1867b1a66 100644 --- a/test/val/counter.c +++ b/test/val/counter.c @@ -1,60 +1,60 @@ -/* Tests for predefined macro __COUNTER__ */ - -#include - -static int failures = 0; - -#if __COUNTER__ /* 0 */ -# error __COUNTER__ should begin at 0! -#elif __COUNTER__ == 1 /* 1 */ -# define CONCAT(a,b) CONCAT_impl_(a,b) -# define CONCAT_impl_(a,b) a##b -#endif - -#line 42 "What is the answer?" -int CONCAT(ident,__COUNTER__)[0+__LINE__] = {__LINE__}, CONCAT(ident,__COUNTER__)[0+__LINE__] = {__LINE__}; /* 2,3 */ - -#if __COUNTER__ == 4 ? 1 || __COUNTER__ : 0 && __COUNTER__ /* 4,5,6 */ -_Static_assert(__COUNTER__ == 7, "__COUNTER__ should be 7 here!"); /* 7 */ -# define GET_COUNTER() __COUNTER__ -# define GET_LINE() __LINE__ -# warning __COUNTER__ in #warning is just output as text and will never increase! -#else -# if __COUNTER__ + __COUNTER__ + __COUNTER__ /* Skipped as a whole and not incrementing */ -# endif -# error __COUNTER__ is skipped along with the whole #error line and will never increase anyways! */ -#endif - -#include "counter.h" -#include "counter.h" - -_Static_assert(GET_COUNTER() == 10, "__COUNTER__ should be 10 here!"); /* 10 */ - -int main(void) -{ - if (ident2[0] != 42) { - printf("Expected ident2[0]: %s, got: %s\n", 42, ident2[0]); - ++failures; - } - - if (ident3[0] != 42) { - printf("Expected ident3[0]: %s, got: %s\n", 42, ident3[0]); - ++failures; - } - - if (ident8 != 8) { - printf("Expected ident8: %s, got: %s\n", 8, ident8); - ++failures; - } - - if (ident9 != 9) { - printf("Expected ident9: %s, got: %s\n", 9, ident9); - ++failures; - } - - if (failures != 0) { - printf("Failures: %d\n", failures); - } - - return failures; -} +/* Tests for predefined macro __COUNTER__ */ + +#include + +static int failures = 0; + +#if __COUNTER__ /* 0 */ +# error __COUNTER__ should begin at 0! +#elif __COUNTER__ == 1 /* 1 */ +# define CONCAT(a,b) CONCAT_impl_(a,b) +# define CONCAT_impl_(a,b) a##b +#endif + +#line 42 "What is the answer?" +int CONCAT(ident,__COUNTER__)[0+__LINE__] = {__LINE__}, CONCAT(ident,__COUNTER__)[0+__LINE__] = {__LINE__}; /* 2,3 */ + +#if __COUNTER__ == 4 ? 1 || __COUNTER__ : 0 && __COUNTER__ /* 4,5,6 */ +_Static_assert(__COUNTER__ == 7, "__COUNTER__ should be 7 here!"); /* 7 */ +# define GET_COUNTER() __COUNTER__ +# define GET_LINE() __LINE__ +# warning __COUNTER__ in #warning is just output as text and will never increase! +#else +# if __COUNTER__ + __COUNTER__ + __COUNTER__ /* Skipped as a whole and not incrementing */ +# endif +# error __COUNTER__ is skipped along with the whole #error line and will never increase anyways! */ +#endif + +#include "counter.h" +#include "counter.h" + +_Static_assert(GET_COUNTER() == 10, "__COUNTER__ should be 10 here!"); /* 10 */ + +int main(void) +{ + if (ident2[0] != 42) { + printf("Expected ident2[0]: %s, got: %s\n", 42, ident2[0]); + ++failures; + } + + if (ident3[0] != 42) { + printf("Expected ident3[0]: %s, got: %s\n", 42, ident3[0]); + ++failures; + } + + if (ident8 != 8) { + printf("Expected ident8: %s, got: %s\n", 8, ident8); + ++failures; + } + + if (ident9 != 9) { + printf("Expected ident9: %s, got: %s\n", 9, ident9); + ++failures; + } + + if (failures != 0) { + printf("Failures: %d\n", failures); + } + + return failures; +} diff --git a/test/val/counter.h b/test/val/counter.h index b6b5a98e2..b97cbf54d 100644 --- a/test/val/counter.h +++ b/test/val/counter.h @@ -1,4 +1,4 @@ -/* Tests for predefined macro __COUNTER__ */ - -#line GET_COUNTER() /* 1st: 8; 2nd: 9 */ -int CONCAT(ident,GET_LINE()) = GET_LINE(); +/* Tests for predefined macro __COUNTER__ */ + +#line GET_COUNTER() /* 1st: 8; 2nd: 9 */ +int CONCAT(ident,GET_LINE()) = GET_LINE(); diff --git a/test/val/decl-extern-shadow.c b/test/val/decl-extern-shadow.c new file mode 100644 index 000000000..6df3c9d50 --- /dev/null +++ b/test/val/decl-extern-shadow.c @@ -0,0 +1,31 @@ +/* Test for shadowing and linkage of file-scope "static" and block-scope "extern" declarations */ + +static int g(int x); /* Generated functions with internal linkage are not always kept in cc65 */ + +int main(void) +{ + char f = 'f'; /* Shadows global "int f(void)" (if any) */ + char c = 'c'; /* Shadows global "int c" (if any) */ + { + void* f = 0; /* Shadows local "char f" */ + void* c = 0; /* Shadows local "char c" */ + { + int f(void); /* Shadows local "char f" and "void* f" */ + extern int g(int); /* Shadows global "int g(int x)" */ + extern int c; /* Shadows local "char c" and "void* c" */ + return f() ^ g(c); /* Link to global "int g(int x)" */ + } + } +} + +int c = 42; + +int f(void) +{ + return 42; +} + +int g(int x) +{ + return x; +} diff --git a/test/val/decl-mixed-specifiers.c b/test/val/decl-mixed-specifiers.c new file mode 100644 index 000000000..a0fb1596b --- /dev/null +++ b/test/val/decl-mixed-specifiers.c @@ -0,0 +1,19 @@ +/* bug 1888 - cc65 fails with storage class specifiers after type specifiers */ + +#include + +int const typedef volatile x_type, * const volatile y_type; + +int static failures = 0; + +int extern main(void); + +int main(void) +{ + volatile static x_type const x = 42, * const volatile y[] = { 1 ? &x : (y_type)0 }; + if (**y != 42) { + ++failures; + printf("y = %d, Expected: 42\n", **y); + } + return failures; +} diff --git a/test/val/static-1.c b/test/val/decl-static-extern.c similarity index 100% rename from test/val/static-1.c rename to test/val/decl-static-extern.c diff --git a/test/val/static-fwd-decl.c b/test/val/decl-static-fwd.c similarity index 100% rename from test/val/static-fwd-decl.c rename to test/val/decl-static-fwd.c diff --git a/test/val/nestfor.c b/test/val/for-nested.c similarity index 100% rename from test/val/nestfor.c rename to test/val/for-nested.c diff --git a/test/val/opsize.c b/test/val/opsize.c index 20c7f0511..8ec49e8a8 100644 --- a/test/val/opsize.c +++ b/test/val/opsize.c @@ -1,33 +1,33 @@ - -/* Test for result types of certain unary operations */ - -#include - -signed char x; -struct S { - unsigned char a : 3; - unsigned int b : 3; -} s; - -int main(void) -{ - _Static_assert(sizeof (++x) == sizeof (char), "++x result should not have promoted type"); - _Static_assert(sizeof (--x) == sizeof (char), "--x result should not have promoted type"); - _Static_assert(sizeof (x++) == sizeof (char), "x++ result should not have promoted type"); - _Static_assert(sizeof (x--) == sizeof (char), "x-- result should not have promoted type"); - _Static_assert(sizeof (x=0) == sizeof (char), "x=0 result should not have promoted type"); - - _Static_assert(sizeof (+x) == sizeof (int), "+x result should have promoted type"); - _Static_assert(sizeof (-x) == sizeof (int), "-x result should have promoted type"); - _Static_assert(sizeof (~x) == sizeof (int), "~x result should have promoted type"); - - _Static_assert(sizeof (+s.a) == sizeof (int), "+s.a result should have promoted type"); - _Static_assert(sizeof (-s.a) == sizeof (int), "-s.a result should have promoted type"); - _Static_assert(sizeof (~s.a) == sizeof (int), "~s.a result should have promoted type"); - - _Static_assert(sizeof (+s.b) == sizeof (int), "+s.b result should have promoted type"); - _Static_assert(sizeof (-s.b) == sizeof (int), "-s.b result should have promoted type"); - _Static_assert(sizeof (~s.b) == sizeof (int), "~s.b result should have promoted type"); - - return 0; -} + +/* Test for result types of certain unary operations */ + +#include + +signed char x; +struct S { + unsigned char a : 3; + unsigned int b : 3; +} s; + +int main(void) +{ + _Static_assert(sizeof (++x) == sizeof (char), "++x result should not have promoted type"); + _Static_assert(sizeof (--x) == sizeof (char), "--x result should not have promoted type"); + _Static_assert(sizeof (x++) == sizeof (char), "x++ result should not have promoted type"); + _Static_assert(sizeof (x--) == sizeof (char), "x-- result should not have promoted type"); + _Static_assert(sizeof (x=0) == sizeof (char), "x=0 result should not have promoted type"); + + _Static_assert(sizeof (+x) == sizeof (int), "+x result should have promoted type"); + _Static_assert(sizeof (-x) == sizeof (int), "-x result should have promoted type"); + _Static_assert(sizeof (~x) == sizeof (int), "~x result should have promoted type"); + + _Static_assert(sizeof (+s.a) == sizeof (int), "+s.a result should have promoted type"); + _Static_assert(sizeof (-s.a) == sizeof (int), "-s.a result should have promoted type"); + _Static_assert(sizeof (~s.a) == sizeof (int), "~s.a result should have promoted type"); + + _Static_assert(sizeof (+s.b) == sizeof (int), "+s.b result should have promoted type"); + _Static_assert(sizeof (-s.b) == sizeof (int), "-s.b result should have promoted type"); + _Static_assert(sizeof (~s.b) == sizeof (int), "~s.b result should have promoted type"); + + return 0; +} diff --git a/test/val/ppshift.c b/test/val/ppshift.c new file mode 100644 index 000000000..466b15926 --- /dev/null +++ b/test/val/ppshift.c @@ -0,0 +1,120 @@ +/* + Test of bitwise-shift in preprocessor expressions. + + Note: Keep in mind that integer constants are always 32-bit in PP for cc65. +*/ + +/* Signed lhs */ +#if 1 << 16 != 0x00010000 +#error 1 << 16 != 0x00010000 +#endif + +#if 0x00010000 << -16 != 1 +#error 0x00010000 << -16 != 1 +#endif + +#if 0x10000 >> 16 != 1 +#error 0x10000 >> 16 != 1 +#endif + +#if 1 >> -16 != 0x10000 +#error 1 >> -16 != 0x10000 +#endif + +#if 1 << 32 != 0 +#error 1 << 32 != 0 +#endif + +#if 1 << -32 != 0 +#error 1 << -32 != 0 +#endif + +#if 1 >> 32 != 0 +#error 1 >> 32 != 0 +#endif + +#if 1 >> -32 != 0 +#error 1 >> -32 != 0 +#endif + +#if -1 << 32 != 0 +#error -1 << 32 != 0 +#endif + +#if -1 << -32 != -1 +#error -1 << -32 != -1 +#endif + +#if -1 >> 32 != -1 +#error -1 >> 32 != -1 +#endif + +#if -1 >> -32 != 0 +#error -1 >> -32 != 0 +#endif + +/* NOTE: 2147483648 is an UNSIGNED integer! */ +#if -1 << 2147483648 != 0 +#error -1 << 2147483648 != 0 +#endif + +/* NOTE: -2147483648 is also an UNSIGNED integer! */ +#if -1 << -2147483648 != 0 +#error -1 << -2147483648 != 0 +#endif + +#if -1 << (-2147483647 - 1) != -1 +#error -1 << (-2147483647 - 1) != -1 +#endif + +/* NOTE: 2147483648 is an UNSIGNED integer! */ +#if -1 >> 2147483648 != -1 +#error -1 >> 2147483648 != -1 +#endif + +/* NOTE: -2147483648 is also an UNSIGNED integer! */ +#if -1 >> -2147483648 != -1 +#error -1 >> -2147483648 != 0 +#endif + +#if -1 >> (-2147483647 - 1) != 0 +#error -1 >> (-2147483647 - 1) != 0 +#endif + +/* Unsigned lhs */ +#if 1U << 16 != 0x00010000 +#error 1U << 16 != 0x00010000 +#endif + +#if 0x80000000U << -16 != 0x8000 +#error 0x80000000U << -16 != 0x8000 +#endif + +#if 0x80000000U >> 16 != 0x8000 +#error 0x80000000U >> 16 != 0x8000 +#endif + +#if 1U >> -16 != 0x10000 +#error 1U >> -16 != 0x10000 +#endif + +#if -1U << 32 != 0 +#error -1U << 32 != 0 +#endif + +#if -1U << -32 != 0 +#error -1U << -32 != 0 +#endif + +#if -1U >> 32 != 0 +#error -1U >> 32 != 0 +#endif + +#if -1U >> -32 != 0 +#error -1U >> -32 != 0 +#endif + +int main(void) +{ + return 0; +} diff --git a/test/val/pr1833.c b/test/val/pr1833.c index bdc820811..177069eb4 100644 --- a/test/val/pr1833.c +++ b/test/val/pr1833.c @@ -1,13 +1,13 @@ -/* Test for PR #1833 fixes */ - -#define char 1 - -#if char && !int && L'A' - L'B' == 'A' - 'B' && L'A' == 'A' -#else -#error -#endif - -int main(void) -{ - return 0; -} +/* Test for PR #1833 fixes */ + +#define char 1 + +#if char && !int && L'A' - L'B' == 'A' - 'B' && L'A' == 'A' +#else +#error +#endif + +int main(void) +{ + return 0; +} diff --git a/test/val/staticassert.c b/test/val/staticassert.c index e43eeec8d..3338f7a4a 100644 --- a/test/val/staticassert.c +++ b/test/val/staticassert.c @@ -65,6 +65,13 @@ struct S { int b; }; +/* _Static_assert can also appear in unions. */ +union U { + int a; + _Static_assert (1, "1 should still be true."); + int b; +}; + int main (void) { diff --git a/test/val/casttochar.c b/test/val/type-cast-to-char.c similarity index 100% rename from test/val/casttochar.c rename to test/val/type-cast-to-char.c diff --git a/test/val/char-promote.c b/test/val/type-char-promote.c similarity index 100% rename from test/val/char-promote.c rename to test/val/type-char-promote.c diff --git a/test/val/uneval.c b/test/val/uneval.c index 50e00973a..fe42cc592 100644 --- a/test/val/uneval.c +++ b/test/val/uneval.c @@ -1,46 +1,46 @@ -/* - Copyright 2021, The cc65 Authors - - This software is provided "as-is", without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications; and, to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated, but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. -*/ - -/* - Test of deferred operations in unevaluated context resulted from 'sizeof' and - short-circuited code-paths in AND, OR and tenary operations. - - https://github.com/cc65/cc65/issues/1406 -*/ - -#include - -int main(void) -{ - int i = 0; - int j = 0; - - sizeof(i++ | j--); - 0 && (i++ | j--); - 1 || (i++ | j--); - 0 ? i++ | j-- : 0; - 1 ? 0 : i++ | j--; - - if (i != 0 || j != 0) { - printf("i = %d, j = %d\n", i, j); - printf("Failures: %d\n", i - j); - } - return i - j; -} +/* + Copyright 2021, The cc65 Authors + + This software is provided "as-is", without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications; and, to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated, but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ + +/* + Test of deferred operations in unevaluated context resulted from 'sizeof' and + short-circuited code-paths in AND, OR and tenary operations. + + https://github.com/cc65/cc65/issues/1406 +*/ + +#include + +int main(void) +{ + int i = 0; + int j = 0; + + sizeof(i++ | j--); + 0 && (i++ | j--); + 1 || (i++ | j--); + 0 ? i++ | j-- : 0; + 1 ? 0 : i++ | j--; + + if (i != 0 || j != 0) { + printf("i = %d, j = %d\n", i, j); + printf("Failures: %d\n", i - j); + } + return i - j; +} diff --git a/util/atari/Makefile b/util/atari/Makefile index db4226f69..e53c837aa 100644 --- a/util/atari/Makefile +++ b/util/atari/Makefile @@ -5,6 +5,16 @@ ifdef CROSS_COMPILE $(info CC: $(CC)) endif +ifneq ($(shell echo),) + CMD_EXE = 1 +endif + +ifdef CMD_EXE + DEL = -del /f +else + DEL = $(RM) +endif + CFLAGS += -O3 -Wall -Wextra -Wno-char-subscripts $(USER_CFLAGS) .PHONY: mostlyclean clean @@ -15,6 +25,6 @@ ataricvt: ataricvt.c $(CC) $(CFLAGS) -o ataricvt ataricvt.c mostlyclean clean: - $(RM) ataricvt + $(DEL) ataricvt install zip: diff --git a/util/gamate/Makefile b/util/gamate/Makefile index db2a1f059..54fa74191 100644 --- a/util/gamate/Makefile +++ b/util/gamate/Makefile @@ -5,6 +5,16 @@ ifdef CROSS_COMPILE $(info CC: $(CC)) endif +ifneq ($(shell echo),) + CMD_EXE = 1 +endif + +ifdef CMD_EXE + DEL = -del /f +else + DEL = $(RM) +endif + CFLAGS += -O3 -Wall -Wextra -Wno-char-subscripts $(USER_CFLAGS) .PHONY: mostlyclean clean @@ -15,6 +25,6 @@ gamate-fixcart: gamate-fixcart.c $(CC) $(CFLAGS) -o gamate-fixcart gamate-fixcart.c mostlyclean clean: - $(RM) gamate-fixcart + $(DEL) gamate-fixcart install zip: diff --git a/util/zlib/Makefile b/util/zlib/Makefile index 3770e1f3c..f276ddaf2 100644 --- a/util/zlib/Makefile +++ b/util/zlib/Makefile @@ -5,21 +5,33 @@ ifdef CROSS_COMPILE $(info CC: $(CC)) endif +ifneq ($(shell echo),) + CMD_EXE = 1 +endif + +ifdef CMD_EXE + DEL = -del /f +else + DEL = $(RM) +endif + CFLAGS += -O3 -Wall -Wextra -Wno-char-subscripts $(USER_CFLAGS) .PHONY: mostlyclean clean -zlib: warning +zlib: +#zlib: warning #zlib: deflater warning: - @echo "deflater needs zlib installed, use 'make deflater' to build" + @echo "util/zlib/deflater is no longer built by default" + @echo "use 'make deflater' to build if you need it" + @echo "note that you need zlib installed first" deflater: deflater.c $(CC) $(CFLAGS) -o deflater deflater.c -lz mostlyclean clean: - $(RM) deflater - -install zip: + $(DEL) deflater +install zip: diff --git a/util/zlib/readme.txt b/util/zlib/readme.txt new file mode 100644 index 000000000..90e15871c --- /dev/null +++ b/util/zlib/readme.txt @@ -0,0 +1,2 @@ +Deflater program in this directory is not built by default +Use 'make deflater' to build. Note that you need zlib installed first