mirror of
https://github.com/cc65/cc65.git
synced 2024-09-28 10:55:43 +00:00
Merge remote-tracking branch 'upstream/master' into fptest
# Conflicts: # src/cc65/scanner.c
This commit is contained in:
commit
034d414d00
@ -24,6 +24,10 @@ 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```.
|
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
|
||||||
|
|
||||||
|
* 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.
|
||||||
|
|
||||||
### misc
|
### misc
|
||||||
|
|
||||||
* 80 characters is the desired maximum width of files. But, it isn't a "strong" rule; sometimes, you will want to type longer lines, in order to keep the parts of expressions or comments together on the same line.
|
* 80 characters is the desired maximum width of files. But, it isn't a "strong" rule; sometimes, you will want to type longer lines, in order to keep the parts of expressions or comments together on the same line.
|
||||||
@ -159,6 +163,13 @@ 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
|
* 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
|
||||||
|
|
||||||
|
The first step is implementing the datatype "float" as IEEE488 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/
|
||||||
|
|
||||||
## Test suite
|
## Test suite
|
||||||
|
|
||||||
* specific tests to check the optimizer (rather than the codegenerator) are needed.
|
* specific tests to check the optimizer (rather than the codegenerator) are needed.
|
||||||
|
@ -538,11 +538,11 @@ NMIVec := $0318
|
|||||||
; YM2151 audio chip
|
; YM2151 audio chip
|
||||||
.struct YM2151
|
.struct YM2151
|
||||||
.org $9F40
|
.org $9F40
|
||||||
.union
|
|
||||||
STATUS .byte
|
|
||||||
ADDR .byte
|
ADDR .byte
|
||||||
.endunion
|
.union
|
||||||
DATA .byte
|
DATA .byte
|
||||||
|
STATUS .byte
|
||||||
|
.endunion
|
||||||
.endstruct
|
.endstruct
|
||||||
|
|
||||||
; X16 Emulator device
|
; X16 Emulator device
|
||||||
|
@ -442,19 +442,7 @@ package delivers the same feature.</em>
|
|||||||
You can switch back to the ATASCII mapping by including
|
You can switch back to the ATASCII mapping by including
|
||||||
"<tt/atari_atascii_charmap.h/".
|
"<tt/atari_atascii_charmap.h/".
|
||||||
|
|
||||||
A final note: Since cc65 has currently some difficulties with string merging
|
Example:
|
||||||
under different mappings, defining remapped strings works only flawlessly
|
|
||||||
with static array initialization:
|
|
||||||
|
|
||||||
<tscreen><verb>
|
|
||||||
#include <atari_screen_charmap.h>
|
|
||||||
char pcScreenMappingString[] = "Hello Atari!";
|
|
||||||
|
|
||||||
#include <atari_atascii_charmap.h>
|
|
||||||
char pcAtasciiMappingString[] = "Hello Atari!";
|
|
||||||
</verb></tscreen>
|
|
||||||
|
|
||||||
delivers correct results, while
|
|
||||||
|
|
||||||
<tscreen><verb>
|
<tscreen><verb>
|
||||||
#include <atari_screen_charmap.h>
|
#include <atari_screen_charmap.h>
|
||||||
@ -464,8 +452,6 @@ char* pcScreenMappingString = "Hello Atari!";
|
|||||||
char* pcAtasciiMappingString = "Hello Atari!";
|
char* pcAtasciiMappingString = "Hello Atari!";
|
||||||
</verb></tscreen>
|
</verb></tscreen>
|
||||||
|
|
||||||
does not.
|
|
||||||
|
|
||||||
<sect1>Keyboard codes<p>
|
<sect1>Keyboard codes<p>
|
||||||
|
|
||||||
For direct keyboard scanning in conjunction with e.g. the OS location "CH" (764/$2FC),
|
For direct keyboard scanning in conjunction with e.g. the OS location "CH" (764/$2FC),
|
||||||
|
@ -1202,17 +1202,34 @@ The compiler defines several macros at startup:
|
|||||||
|
|
||||||
This macro is defined if the target is the Commodore Plus/4 (-t plus4).
|
This macro is defined if the target is the Commodore Plus/4 (-t plus4).
|
||||||
|
|
||||||
<tag><tt>__STDC_HOSTED__</tt></tag>
|
|
||||||
|
|
||||||
This macro is expands to the integer constant 1.
|
|
||||||
|
|
||||||
<tag><tt>__SIM6502__</tt></tag>
|
<tag><tt>__SIM6502__</tt></tag>
|
||||||
|
|
||||||
This macro is defined if the target is sim65 in 6502 mode (-t sim6502).
|
This macro is defined if the target is sim65 in 6502 mode (-t sim6502).
|
||||||
|
|
||||||
<tag><tt>__SIM65C02__</tt></tag>
|
<tag><tt>__SIM65C02__</tt></tag>
|
||||||
|
|
||||||
This macro is defined if the target is sim65 in 65C02 mode (-t sim65c02).
|
This macro is defined if the target is sim65 in 65C02 mode (-t sim65c02).
|
||||||
|
|
||||||
|
<tag><tt>__STDC_HOSTED__</tt></tag>
|
||||||
|
|
||||||
|
This macro expands to the integer constant 1.
|
||||||
|
|
||||||
|
<tag><tt>__STDC_NO_ATOMICS__</tt></tag>
|
||||||
|
|
||||||
|
This macro expands to the integer constant 1 if the language standard is cc65 (--standard cc65).
|
||||||
|
|
||||||
|
<tag><tt>__STDC_NO_COMPLEX__</tt></tag>
|
||||||
|
|
||||||
|
This macro expands to the integer constant 1 if the language standard is cc65 (--standard cc65).
|
||||||
|
|
||||||
|
<tag><tt>__STDC_NO_THREADS__</tt></tag>
|
||||||
|
|
||||||
|
This macro expands to the integer constant 1 if the language standard is cc65 (--standard cc65).
|
||||||
|
|
||||||
|
<tag><tt>__STDC_NO_VLA__</tt></tag>
|
||||||
|
|
||||||
|
This macro expands to the integer constant 1 if the language standard is cc65 (--standard cc65).
|
||||||
|
|
||||||
<tag><tt>__SUPERVISION__</tt></tag>
|
<tag><tt>__SUPERVISION__</tt></tag>
|
||||||
|
|
||||||
This macro is defined if the target is the Supervision (-t supervision).
|
This macro is defined if the target is the Supervision (-t supervision).
|
||||||
|
@ -145,6 +145,7 @@ extern void c64_ram_emd[];
|
|||||||
extern void c64_ramcart_emd[];
|
extern void c64_ramcart_emd[];
|
||||||
extern void c64_reu_emd[];
|
extern void c64_reu_emd[];
|
||||||
extern void c64_vdc_emd[];
|
extern void c64_vdc_emd[];
|
||||||
|
extern void c64_rrr_emd[];
|
||||||
extern void dtv_himem_emd[];
|
extern void dtv_himem_emd[];
|
||||||
extern void c64_hitjoy_joy[];
|
extern void c64_hitjoy_joy[];
|
||||||
extern void c64_numpad_joy[];
|
extern void c64_numpad_joy[];
|
||||||
|
@ -285,11 +285,11 @@ struct __vera {
|
|||||||
|
|
||||||
/* Audio chip */
|
/* Audio chip */
|
||||||
struct __ym2151 {
|
struct __ym2151 {
|
||||||
|
unsigned char reg; /* Register number for data */
|
||||||
union {
|
union {
|
||||||
unsigned char reg; /* Register number for data */
|
unsigned char data;
|
||||||
unsigned char status; /* Busy flag */
|
unsigned char status; /* Busy flag */
|
||||||
};
|
};
|
||||||
unsigned char data;
|
|
||||||
};
|
};
|
||||||
#define YM2151 (*(volatile struct __ym2151 *)0x9F40)
|
#define YM2151 (*(volatile struct __ym2151 *)0x9F40)
|
||||||
|
|
||||||
|
@ -54,7 +54,7 @@ typedef unsigned size_t;
|
|||||||
|
|
||||||
/* NULL pointer */
|
/* NULL pointer */
|
||||||
#ifndef _HAVE_NULL
|
#ifndef _HAVE_NULL
|
||||||
#define NULL 0
|
#define NULL ((void *) 0)
|
||||||
#define _HAVE_NULL
|
#define _HAVE_NULL
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
363
libsrc/c64/emd/c64-rrr.s
Normal file
363
libsrc/c64/emd/c64-rrr.s
Normal file
@ -0,0 +1,363 @@
|
|||||||
|
;
|
||||||
|
; Extended Memory Driver for the Action Replay/Retro Replay RAM
|
||||||
|
;
|
||||||
|
; original Version 1.0 by Johannes Braun 2006-08-22 <hannenz@freenet.de>
|
||||||
|
; ------------------------------------------------------------------------
|
||||||
|
|
||||||
|
.include "zeropage.inc"
|
||||||
|
|
||||||
|
.include "em-kernel.inc"
|
||||||
|
.include "em-error.inc"
|
||||||
|
|
||||||
|
.macpack generic
|
||||||
|
.macpack module
|
||||||
|
|
||||||
|
; ------------------------------------------------------------------------
|
||||||
|
|
||||||
|
c64_ram = ptr1 ; use some more expressive identifiers...
|
||||||
|
rr_ram = ptr2
|
||||||
|
len = ptr3
|
||||||
|
aux = ptr4
|
||||||
|
temp = tmp1
|
||||||
|
|
||||||
|
Lo_Mem = $0100 ; location of Lo_Code (must be below $1000 or above $e000)
|
||||||
|
|
||||||
|
RRMODE_OFF = $02
|
||||||
|
RRMODE_CART_RAM = $23
|
||||||
|
|
||||||
|
; ------------------------------------------------------------------------
|
||||||
|
; Header. Includes jump table
|
||||||
|
|
||||||
|
module_header _c64_rrr_emd
|
||||||
|
|
||||||
|
; Driver signature
|
||||||
|
|
||||||
|
.byte $65, $6d, $64 ; "emd"
|
||||||
|
.byte EMD_API_VERSION ; EM API version number
|
||||||
|
|
||||||
|
; Library reference
|
||||||
|
|
||||||
|
.addr $0000
|
||||||
|
|
||||||
|
; Jump table
|
||||||
|
|
||||||
|
.addr INSTALL
|
||||||
|
.addr UNINSTALL
|
||||||
|
.addr PAGECOUNT
|
||||||
|
.addr MAP
|
||||||
|
.addr USE
|
||||||
|
.addr COMMIT
|
||||||
|
.addr COPYFROM
|
||||||
|
.addr COPYTO
|
||||||
|
|
||||||
|
; ------------------------------------------------------------------------
|
||||||
|
; Data.
|
||||||
|
|
||||||
|
.bss
|
||||||
|
window: .res 256 ; the memory window (256 bytes)
|
||||||
|
pagecount: .res 1 ; Number of available pages
|
||||||
|
|
||||||
|
.rodata
|
||||||
|
dummy:
|
||||||
|
.word window ; a "pseudo"-em_copy_struct, used by em_map/ em_commit
|
||||||
|
.byte 0 ; to pass over to COPYTO/COPYFROM
|
||||||
|
curpage:
|
||||||
|
.byte $ff ; just this byte is changed according to the desired page
|
||||||
|
.byte 0
|
||||||
|
.word 256
|
||||||
|
|
||||||
|
.code
|
||||||
|
|
||||||
|
;----------------------------------------------------------------------------------------
|
||||||
|
;unsigned char __fastcall__ em_install(void *driver);
|
||||||
|
;returns an error code
|
||||||
|
;----------------------------------------------------------------------------------------
|
||||||
|
INSTALL:
|
||||||
|
ldx #c2-c1
|
||||||
|
: lda c1,x
|
||||||
|
sta Lo_Mem,x
|
||||||
|
dex
|
||||||
|
bpl :-
|
||||||
|
;ldx #$ff
|
||||||
|
stx curpage ; invalidate current page
|
||||||
|
|
||||||
|
ldy #RRMODE_OFF
|
||||||
|
sei
|
||||||
|
jmp Lo_Mem+8 ; jump to the code below
|
||||||
|
|
||||||
|
; copied to Lo_Mem
|
||||||
|
c1:
|
||||||
|
|
||||||
|
;detectmodes:
|
||||||
|
.byte RRMODE_CART_RAM | $00
|
||||||
|
.byte RRMODE_CART_RAM | $08
|
||||||
|
.byte RRMODE_CART_RAM | $10
|
||||||
|
.byte RRMODE_CART_RAM | $18
|
||||||
|
.byte RRMODE_CART_RAM | $80
|
||||||
|
.byte RRMODE_CART_RAM | $88
|
||||||
|
.byte RRMODE_CART_RAM | $90
|
||||||
|
.byte RRMODE_CART_RAM | $98
|
||||||
|
|
||||||
|
; first save c64 memory
|
||||||
|
lda $8888
|
||||||
|
pha
|
||||||
|
|
||||||
|
; tag c64 memory
|
||||||
|
lda #$00
|
||||||
|
sta $8888
|
||||||
|
|
||||||
|
ldx #$07
|
||||||
|
:
|
||||||
|
; try accessing rr-ram
|
||||||
|
;lda detectmodes, x
|
||||||
|
lda Lo_Mem, x
|
||||||
|
sta $de00
|
||||||
|
|
||||||
|
; tag (hopefully) rr memory
|
||||||
|
txa
|
||||||
|
ora #$80
|
||||||
|
sta $8888
|
||||||
|
|
||||||
|
dex
|
||||||
|
bpl :-
|
||||||
|
|
||||||
|
;ldy #RRMODE_OFF
|
||||||
|
sty $de00
|
||||||
|
|
||||||
|
; now if C64 memory is $80, there is no AR/RR
|
||||||
|
; if C64 memory is $00, there is a AR/RR.
|
||||||
|
|
||||||
|
lda $8888
|
||||||
|
beq detectpages
|
||||||
|
|
||||||
|
lda #0
|
||||||
|
beq hasnopages
|
||||||
|
|
||||||
|
detectpages:
|
||||||
|
; we can now read the highest available bank nr from the highest bank :)
|
||||||
|
|
||||||
|
lda #RRMODE_CART_RAM | $98
|
||||||
|
sta $de00
|
||||||
|
|
||||||
|
ldx $8888
|
||||||
|
inx
|
||||||
|
txa
|
||||||
|
|
||||||
|
; 8k = 32 pages
|
||||||
|
asl
|
||||||
|
asl
|
||||||
|
asl
|
||||||
|
asl
|
||||||
|
asl
|
||||||
|
|
||||||
|
hasnopages:
|
||||||
|
|
||||||
|
;ldy #RRMODE_OFF
|
||||||
|
sty $de00 ; c64 ram again
|
||||||
|
|
||||||
|
sta pagecount
|
||||||
|
|
||||||
|
; restore c64 memory
|
||||||
|
pla
|
||||||
|
sta $8888
|
||||||
|
|
||||||
|
cli
|
||||||
|
|
||||||
|
ldx pagecount
|
||||||
|
beq no
|
||||||
|
|
||||||
|
; no error
|
||||||
|
lda #0
|
||||||
|
tax
|
||||||
|
rts
|
||||||
|
|
||||||
|
no:
|
||||||
|
lda #4 ; return #4: error code for "device not present"
|
||||||
|
rts
|
||||||
|
c2:
|
||||||
|
|
||||||
|
;----------------------------------------------------------------------------------------
|
||||||
|
;void em_uninstall(void);
|
||||||
|
;----------------------------------------------------------------------------------------
|
||||||
|
UNINSTALL:
|
||||||
|
return_null:
|
||||||
|
lda #$00
|
||||||
|
tax
|
||||||
|
rts
|
||||||
|
|
||||||
|
;----------------------------------------------------------------------------------------
|
||||||
|
;unsigned __fastcall__ em_pagecount(void);
|
||||||
|
;----------------------------------------------------------------------------------------
|
||||||
|
PAGECOUNT:
|
||||||
|
lda pagecount ; always return 32kb (128 pages)
|
||||||
|
ldx #$00
|
||||||
|
rts
|
||||||
|
|
||||||
|
;----------------------------------------------------------------------------------------
|
||||||
|
;void* __fastcall__ em_use(unsigned page);
|
||||||
|
;----------------------------------------------------------------------------------------
|
||||||
|
USE:
|
||||||
|
cmp #$80 ; valid page?
|
||||||
|
bcs return_null ; no, return NULL pointer
|
||||||
|
sta curpage ; set to current page
|
||||||
|
return_win:
|
||||||
|
lda #<window ; return pointer to window
|
||||||
|
ldx #>window
|
||||||
|
return: rts
|
||||||
|
|
||||||
|
;----------------------------------------------------------------------------------------
|
||||||
|
;void* __fastcall__ em_map(unsigned page);
|
||||||
|
;----------------------------------------------------------------------------------------
|
||||||
|
MAP:
|
||||||
|
cmp pagecount
|
||||||
|
bcs return_null
|
||||||
|
sta curpage
|
||||||
|
lda #<dummy ; load .A/.X with adress of data for COPYFROM-call (which expects the
|
||||||
|
ldx #>dummy ; adress in .A/.X)
|
||||||
|
jsr COPYFROM
|
||||||
|
bcs return_win ; function returns pointer to window (returns always with carry set!)
|
||||||
|
|
||||||
|
;----------------------------------------------------------------------------------------
|
||||||
|
;void __fastcall__ em_commit(void);
|
||||||
|
;----------------------------------------------------------------------------------------
|
||||||
|
COMMIT:
|
||||||
|
lda curpage
|
||||||
|
cmp pagecount
|
||||||
|
bcs return
|
||||||
|
lda #<dummy ; load .A/.X with adress of data for COPYTO-call (which expects the
|
||||||
|
ldx #>dummy ; adress in .A/.X)
|
||||||
|
|
||||||
|
;----------------------------------------------------------------------------------------
|
||||||
|
;void __fastcall__ em_copyto (struct em_copy *copy_data);
|
||||||
|
;----------------------------------------------------------------------------------------
|
||||||
|
COPYTO:
|
||||||
|
jsr get_struct_data ;read the parameters passed in the em_struct pointed to by .A/.X upon call
|
||||||
|
|
||||||
|
;copy the main copyto routine into Lo_Mem
|
||||||
|
|
||||||
|
ldy #Lo_Code1_End - Lo_Code1
|
||||||
|
: lda Lo_Code1-1,y
|
||||||
|
sta Lo_Mem-1,y
|
||||||
|
dey
|
||||||
|
bne :-
|
||||||
|
COMMON:
|
||||||
|
sei
|
||||||
|
jmp Lo_Mem
|
||||||
|
|
||||||
|
;this part will be executed in Lo_Mem (!) by COPYFROM
|
||||||
|
|
||||||
|
Lo_Code2:
|
||||||
|
; copy byte rr -> c64
|
||||||
|
stx $de00 ;map in rr-ram
|
||||||
|
lda (rr_ram),y ;get byte from rr-ram
|
||||||
|
sty $de00 ;RR-ROM will be mapped to $8000-$a000 but write access will go to c64-ram anyway!!
|
||||||
|
sta (c64_ram),y ;and write to c64-ram
|
||||||
|
nop ;pad to same size as Lo_Code1
|
||||||
|
nop
|
||||||
|
Lo_Code2_End:
|
||||||
|
|
||||||
|
|
||||||
|
;this part will be executed in Lo_Mem (!) by COPYTO
|
||||||
|
|
||||||
|
Lo_Code1:
|
||||||
|
; copy byte c64 -> rr
|
||||||
|
lda (c64_ram),y ;read 1 byte from c64-ram
|
||||||
|
stx $de00 ;map in rr-ram
|
||||||
|
sta (rr_ram),y ;write byte to rr-ram
|
||||||
|
lda #$02 ;map in c64-ram again
|
||||||
|
sta $de00
|
||||||
|
;12 bytes
|
||||||
|
|
||||||
|
;this part is common for both COPYFROM/COPYTO and executed in Lo_Mem, too
|
||||||
|
|
||||||
|
Lo_Code_Common:
|
||||||
|
inc c64_ram ;increase pointers
|
||||||
|
bne :+
|
||||||
|
inc c64_ram+1
|
||||||
|
: inc rr_ram
|
||||||
|
bne @skip
|
||||||
|
inc rr_ram+1
|
||||||
|
lda rr_ram+1
|
||||||
|
cmp #$a0 ;wrap around 16k boundary in rr-ram window ($8000-$a000)
|
||||||
|
bne @skip
|
||||||
|
|
||||||
|
lda #$80 ;reset pointer to $8000
|
||||||
|
sta rr_ram+1
|
||||||
|
txa ;adjust value in .X to map in next 16k-bank in rr-ram
|
||||||
|
adc #7 ;carry is set because of former CMP, so it adds 8
|
||||||
|
tax
|
||||||
|
;27 bytes
|
||||||
|
@skip: lda c64_ram
|
||||||
|
cmp len
|
||||||
|
lda c64_ram+1
|
||||||
|
sbc len+1
|
||||||
|
bcc Lo_Code1
|
||||||
|
lda #2 ;CHANGE to LDA #0 if driver is called from ROM
|
||||||
|
sta $de00
|
||||||
|
cli
|
||||||
|
rts ;17 bytes = 56 bytes Lo_Code ($38)
|
||||||
|
Lo_Code1_End:
|
||||||
|
;----------------------------------------------------------------------------------------
|
||||||
|
;void __fastcall__ em_copyfrom(struct em_copy *copy_data);
|
||||||
|
;copy from extended memory into linear memory
|
||||||
|
;----------------------------------------------------------------------------------------
|
||||||
|
COPYFROM:
|
||||||
|
jsr get_struct_data
|
||||||
|
|
||||||
|
ldy #Lo_Code2_End - Lo_Code2 ;copy routine into Lo_Mem
|
||||||
|
: lda Lo_Code2-1,y
|
||||||
|
sta Lo_Mem-1,y
|
||||||
|
dey
|
||||||
|
bne :-
|
||||||
|
ldy #Lo_Code1_End-Lo_Code_Common
|
||||||
|
: lda Lo_Code_Common-1,y
|
||||||
|
sta Lo_Mem+11,y
|
||||||
|
dey
|
||||||
|
bne :-
|
||||||
|
beq COMMON ;and execute...
|
||||||
|
;----------------------------------------------------------------------------------------
|
||||||
|
;read the struct data located at (.A/.X)
|
||||||
|
;and setup parameters for stash/ fetch operation
|
||||||
|
;----------------------------------------------------------------------------------------
|
||||||
|
get_struct_data:
|
||||||
|
|
||||||
|
;read and process the values from the em_copy struct passed to as parameters rameter to the
|
||||||
|
;functions em_copyto and em_copyfrom
|
||||||
|
|
||||||
|
sta aux ;store adress of struct (passed in .A/.X) into a zp pointer
|
||||||
|
stx aux+1
|
||||||
|
ldy #0 ;index 0
|
||||||
|
|
||||||
|
lda (aux),y ;read c64-adress lo
|
||||||
|
sta c64_ram
|
||||||
|
iny
|
||||||
|
lda (aux),y ;read c64-adress hi
|
||||||
|
sta c64_ram+1 ;(c64_ram) --> points to c64-adress space
|
||||||
|
iny
|
||||||
|
lda (aux),y ;read rr-adress lo
|
||||||
|
sta rr_ram
|
||||||
|
iny
|
||||||
|
lda (aux),y ;rr-adress hi
|
||||||
|
pha ;remember
|
||||||
|
and #$1f
|
||||||
|
ora #$80 ;adjust into 16k-window ($8000-$a000)
|
||||||
|
sta rr_ram+1
|
||||||
|
pla ;re-get hi byte of rr-adress
|
||||||
|
and #$60 ;isolate bits 5 and 6
|
||||||
|
lsr
|
||||||
|
lsr ;shift into bits 3 and 4
|
||||||
|
ora #$23 ;set bit 5 (select ram) and 1+2 (game/exrom setting for ULTIMAX-mode)
|
||||||
|
tax ;.X has now the value to write into $de00 to acess rr-ram at desired 16k-bank
|
||||||
|
iny
|
||||||
|
iny ;skip unused byte
|
||||||
|
lda (aux),y ;read length lo-byte
|
||||||
|
clc
|
||||||
|
adc c64_ram ;add to c64-addres
|
||||||
|
sta len
|
||||||
|
iny
|
||||||
|
lda (aux),y ;length hi-byte
|
||||||
|
adc c64_ram+1
|
||||||
|
sta len+1 ;tmp2: length, tmp3 contains end adress of transfer in c64-ram.
|
||||||
|
rts
|
||||||
|
;55 bytes
|
||||||
|
|
@ -11,6 +11,7 @@
|
|||||||
;
|
;
|
||||||
|
|
||||||
.export _isascii
|
.export _isascii
|
||||||
|
.import return0
|
||||||
|
|
||||||
_isascii:
|
_isascii:
|
||||||
asl a ; high-bit to carry
|
asl a ; high-bit to carry
|
||||||
@ -19,6 +20,4 @@ _isascii:
|
|||||||
adc #$FF ; calculate return value based on carry
|
adc #$FF ; calculate return value based on carry
|
||||||
rts
|
rts
|
||||||
|
|
||||||
@L1: lda #$00 ; return false
|
@L1: jmp return0 ; return false
|
||||||
tax
|
|
||||||
rts
|
|
||||||
|
@ -5,17 +5,20 @@
|
|||||||
; /* Wait for the start of the next video field. */
|
; /* Wait for the start of the next video field. */
|
||||||
;
|
;
|
||||||
; VERA's vertical sync causes IRQs which increment the jiffy timer.
|
; VERA's vertical sync causes IRQs which increment the jiffy timer.
|
||||||
|
;
|
||||||
|
; Updated by ZeroByteOrg to use Kernal API RDTIM to retreive the TIMER variable
|
||||||
;
|
;
|
||||||
|
|
||||||
.export _waitvsync
|
.export _waitvsync
|
||||||
|
.importzp tmp1
|
||||||
|
.import RDTIM
|
||||||
|
|
||||||
.include "cx16.inc"
|
.proc _waitvsync: near
|
||||||
|
jsr RDTIM
|
||||||
_waitvsync:
|
sta tmp1
|
||||||
ldx RAM_BANK ; (TIMER is in RAM bank 0)
|
keep_waiting:
|
||||||
stz RAM_BANK
|
jsr RDTIM
|
||||||
lda TIMER + 2
|
cmp tmp1
|
||||||
: cmp TIMER + 2
|
beq keep_waiting
|
||||||
beq :- ; Wait for next jiffy
|
rts
|
||||||
stx RAM_BANK
|
.endproc
|
||||||
rts
|
|
||||||
|
@ -1063,7 +1063,7 @@ static char StackHandler (void)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case 'a':
|
case 'a':
|
||||||
#ifdef CH_CURS_UP:
|
#ifdef CH_CURS_UP
|
||||||
case CH_CURS_UP:
|
case CH_CURS_UP:
|
||||||
#endif
|
#endif
|
||||||
--StackAddr;
|
--StackAddr;
|
||||||
|
@ -489,23 +489,6 @@ void MacDef (unsigned Style)
|
|||||||
** the .LOCAL command is detected and removed, at this time.
|
** the .LOCAL command is detected and removed, at this time.
|
||||||
*/
|
*/
|
||||||
while (1) {
|
while (1) {
|
||||||
/* Check for include */
|
|
||||||
if (CurTok.Tok == TOK_INCLUDE && Style == MAC_STYLE_CLASSIC) {
|
|
||||||
/* Include another file */
|
|
||||||
NextTok ();
|
|
||||||
/* Name must follow */
|
|
||||||
if (CurTok.Tok != TOK_STRCON) {
|
|
||||||
ErrorSkip ("String constant expected");
|
|
||||||
} else {
|
|
||||||
SB_Terminate (&CurTok.SVal);
|
|
||||||
if (NewInputFile (SB_GetConstBuf (&CurTok.SVal)) == 0) {
|
|
||||||
/* Error opening the file, skip remainder of line */
|
|
||||||
SkipUntilSep ();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
NextTok ();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Check for end of macro */
|
/* Check for end of macro */
|
||||||
if (Style == MAC_STYLE_CLASSIC) {
|
if (Style == MAC_STYLE_CLASSIC) {
|
||||||
/* In classic macros, only .endmacro is allowed */
|
/* In classic macros, only .endmacro is allowed */
|
||||||
|
@ -103,6 +103,7 @@
|
|||||||
<ClInclude Include="cc65\macrotab.h" />
|
<ClInclude Include="cc65\macrotab.h" />
|
||||||
<ClInclude Include="cc65\opcodes.h" />
|
<ClInclude Include="cc65\opcodes.h" />
|
||||||
<ClInclude Include="cc65\output.h" />
|
<ClInclude Include="cc65\output.h" />
|
||||||
|
<ClInclude Include="cc65\ppexpr.h" />
|
||||||
<ClInclude Include="cc65\pragma.h" />
|
<ClInclude Include="cc65\pragma.h" />
|
||||||
<ClInclude Include="cc65\preproc.h" />
|
<ClInclude Include="cc65\preproc.h" />
|
||||||
<ClInclude Include="cc65\reginfo.h" />
|
<ClInclude Include="cc65\reginfo.h" />
|
||||||
@ -182,6 +183,7 @@
|
|||||||
<ClCompile Include="cc65\main.c" />
|
<ClCompile Include="cc65\main.c" />
|
||||||
<ClCompile Include="cc65\opcodes.c" />
|
<ClCompile Include="cc65\opcodes.c" />
|
||||||
<ClCompile Include="cc65\output.c" />
|
<ClCompile Include="cc65\output.c" />
|
||||||
|
<ClCompile Include="cc65\ppexpr.c" />
|
||||||
<ClCompile Include="cc65\pragma.c" />
|
<ClCompile Include="cc65\pragma.c" />
|
||||||
<ClCompile Include="cc65\preproc.c" />
|
<ClCompile Include="cc65\preproc.c" />
|
||||||
<ClCompile Include="cc65\reginfo.c" />
|
<ClCompile Include="cc65\reginfo.c" />
|
||||||
|
@ -1797,7 +1797,6 @@ void CE_GenRegInfo (CodeEntry* E, RegContents* InputRegs)
|
|||||||
}
|
}
|
||||||
} else if (strcmp (E->Arg, "tosaslax") == 0) {
|
} else if (strcmp (E->Arg, "tosaslax") == 0) {
|
||||||
if (RegValIsKnown (In->RegA) && (In->RegA & 0x0F) >= 8) {
|
if (RegValIsKnown (In->RegA) && (In->RegA & 0x0F) >= 8) {
|
||||||
printf ("Hey!\n");
|
|
||||||
Out->RegA = 0;
|
Out->RegA = 0;
|
||||||
}
|
}
|
||||||
} else if (strcmp (E->Arg, "tosorax") == 0) {
|
} else if (strcmp (E->Arg, "tosorax") == 0) {
|
||||||
|
@ -82,8 +82,11 @@ static void Parse (void)
|
|||||||
SymEntry* Entry;
|
SymEntry* Entry;
|
||||||
FuncDesc* FuncDef = 0;
|
FuncDesc* FuncDef = 0;
|
||||||
|
|
||||||
/* Go... */
|
/* Initialization for deferred operations */
|
||||||
NextToken ();
|
InitDeferredOps ();
|
||||||
|
|
||||||
|
/* Fill up the next token with a bogus semicolon and start the tokenizer */
|
||||||
|
NextTok.Tok = TOK_SEMI;
|
||||||
NextToken ();
|
NextToken ();
|
||||||
|
|
||||||
/* Parse until end of input */
|
/* Parse until end of input */
|
||||||
@ -207,7 +210,7 @@ static void Parse (void)
|
|||||||
/* Allow initialization */
|
/* Allow initialization */
|
||||||
if (CurTok.Tok == TOK_ASSIGN) {
|
if (CurTok.Tok == TOK_ASSIGN) {
|
||||||
|
|
||||||
/* This is a definition */
|
/* This is a definition with storage */
|
||||||
if (SymIsDef (Entry)) {
|
if (SymIsDef (Entry)) {
|
||||||
Error ("Global variable '%s' has already been defined",
|
Error ("Global variable '%s' has already been defined",
|
||||||
Entry->Name);
|
Entry->Name);
|
||||||
@ -251,6 +254,7 @@ static void Parse (void)
|
|||||||
ParseInit (Entry->Type);
|
ParseInit (Entry->Type);
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
|
/* This is a declaration */
|
||||||
if (IsTypeVoid (Decl.Type)) {
|
if (IsTypeVoid (Decl.Type)) {
|
||||||
/* We cannot declare variables of type void */
|
/* We cannot declare variables of type void */
|
||||||
Error ("Illegal type for variable '%s'", Decl.Ident);
|
Error ("Illegal type for variable '%s'", Decl.Ident);
|
||||||
@ -261,6 +265,15 @@ static void Parse (void)
|
|||||||
Error ("Variable '%s' has unknown size", Decl.Ident);
|
Error ("Variable '%s' has unknown size", Decl.Ident);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
/* Check for enum forward declaration.
|
||||||
|
** Warn about it when extensions are not allowed.
|
||||||
|
*/
|
||||||
|
if (Size == 0 && IsTypeEnum (Decl.Type)) {
|
||||||
|
if (IS_Get (&Standard) != STD_CC65) {
|
||||||
|
Warning ("ISO C forbids forward references to 'enum' types");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* A global (including static) uninitialized variable is
|
/* A global (including static) uninitialized variable is
|
||||||
** only a tentative definition. For example, this is valid:
|
** only a tentative definition. For example, this is valid:
|
||||||
** int i;
|
** int i;
|
||||||
@ -287,17 +300,9 @@ static void Parse (void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Make the symbol zeropage according to the segment address size */
|
/* Make the symbol zeropage according to the segment address size */
|
||||||
if ((Entry->Flags & SC_EXTERN) != 0) {
|
if ((Entry->Flags & SC_STATIC) != 0) {
|
||||||
if (GetSegAddrSize (GetSegName (CS->CurDSeg)) == ADDR_SIZE_ZP) {
|
if (GetSegAddrSize (GetSegName (CS->CurDSeg)) == ADDR_SIZE_ZP) {
|
||||||
Entry->Flags |= SC_ZEROPAGE;
|
Entry->Flags |= SC_ZEROPAGE;
|
||||||
/* Check for enum forward declaration.
|
|
||||||
** Warn about it when extensions are not allowed.
|
|
||||||
*/
|
|
||||||
if (Size == 0 && IsTypeEnum (Decl.Type)) {
|
|
||||||
if (IS_Get (&Standard) != STD_CC65) {
|
|
||||||
Warning ("ISO C forbids forward references to 'enum' types");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -336,6 +341,9 @@ static void Parse (void)
|
|||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Done with deferred operations */
|
||||||
|
DoneDeferredOps ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -401,7 +409,13 @@ void Compile (const char* FileName)
|
|||||||
/* DefineNumericMacro ("__STDC__", 1); <- not now */
|
/* DefineNumericMacro ("__STDC__", 1); <- not now */
|
||||||
DefineNumericMacro ("__STDC_HOSTED__", 1);
|
DefineNumericMacro ("__STDC_HOSTED__", 1);
|
||||||
|
|
||||||
InitDeferredOps ();
|
/* Stuff unsupported */
|
||||||
|
if (IS_Get (&Standard) > STD_C99) {
|
||||||
|
DefineNumericMacro ("__STDC_NO_ATOMICS__", 1);
|
||||||
|
DefineNumericMacro ("__STDC_NO_COMPLEX__", 1);
|
||||||
|
DefineNumericMacro ("__STDC_NO_THREADS__", 1);
|
||||||
|
DefineNumericMacro ("__STDC_NO_VLA__", 1);
|
||||||
|
}
|
||||||
|
|
||||||
/* Create the base lexical level */
|
/* Create the base lexical level */
|
||||||
EnterGlobalLevel ();
|
EnterGlobalLevel ();
|
||||||
@ -421,6 +435,9 @@ void Compile (const char* FileName)
|
|||||||
/* Generate the code generator preamble */
|
/* Generate the code generator preamble */
|
||||||
g_preamble ();
|
g_preamble ();
|
||||||
|
|
||||||
|
/* Init preprocessor */
|
||||||
|
InitPreprocess ();
|
||||||
|
|
||||||
/* Open the input file */
|
/* Open the input file */
|
||||||
OpenMainFile (FileName);
|
OpenMainFile (FileName);
|
||||||
|
|
||||||
@ -431,10 +448,8 @@ void Compile (const char* FileName)
|
|||||||
OpenOutputFile ();
|
OpenOutputFile ();
|
||||||
|
|
||||||
/* Preprocess each line and write it to the output file */
|
/* Preprocess each line and write it to the output file */
|
||||||
while (NextLine ()) {
|
while (PreprocessNextLine ())
|
||||||
Preprocess ();
|
{ /* Nothing */ }
|
||||||
WriteOutput ("%.*s\n", (int) SB_GetLen (Line), SB_GetConstBuf (Line));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Close the output file */
|
/* Close the output file */
|
||||||
CloseOutputFile ();
|
CloseOutputFile ();
|
||||||
@ -492,9 +507,11 @@ void Compile (const char* FileName)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DoneDeferredOps ();
|
/* Done with preprocessor */
|
||||||
|
DonePreprocess ();
|
||||||
|
|
||||||
if (Debug) {
|
if (Debug) {
|
||||||
PrintMacroStats (stdout);
|
PrintMacroStats (stdout);
|
||||||
|
151
src/cc65/expr.c
151
src/cc65/expr.c
@ -316,13 +316,9 @@ void PushAddr (const ExprDesc* Expr)
|
|||||||
|
|
||||||
|
|
||||||
static void WarnConstCompareResult (const ExprDesc* Expr)
|
static void WarnConstCompareResult (const ExprDesc* Expr)
|
||||||
/* If the result of a comparison is constant, this is suspicious when not in
|
/* If the result of a comparison is constant, this is suspicious */
|
||||||
** preprocessor mode.
|
|
||||||
*/
|
|
||||||
{
|
{
|
||||||
if (!Preprocessing &&
|
if (!ED_NeedsConst (Expr) && IS_Get (&WarnConstComparison) != 0) {
|
||||||
!ED_NeedsConst (Expr) &&
|
|
||||||
IS_Get (&WarnConstComparison) != 0) {
|
|
||||||
Warning ("Result of comparison is always %s", Expr->IVal != 0 ? "true" : "false");
|
Warning ("Result of comparison is always %s", Expr->IVal != 0 ? "true" : "false");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1087,58 +1083,19 @@ static void Primary (ExprDesc* E)
|
|||||||
/* This is the lowest level of the expression parser. */
|
/* This is the lowest level of the expression parser. */
|
||||||
{
|
{
|
||||||
SymEntry* Sym;
|
SymEntry* Sym;
|
||||||
|
|
||||||
/* Character and integer constants. */
|
|
||||||
if (CurTok.Tok == TOK_ICONST || CurTok.Tok == TOK_CCONST) {
|
|
||||||
E->IVal = CurTok.IVal;
|
|
||||||
E->Flags |= E_LOC_NONE | E_RTYPE_RVAL;
|
|
||||||
E->Type = CurTok.Type;
|
|
||||||
NextToken ();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Floating point constant */
|
|
||||||
if (CurTok.Tok == TOK_FCONST) {
|
|
||||||
E->V.FVal = CurTok.FVal;
|
|
||||||
E->Flags |= E_LOC_NONE | E_RTYPE_RVAL;
|
|
||||||
E->Type = CurTok.Type;
|
|
||||||
NextToken ();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Process parenthesized subexpression by calling the whole parser
|
|
||||||
** recursively.
|
|
||||||
*/
|
|
||||||
if (CurTok.Tok == TOK_LPAREN) {
|
|
||||||
NextToken ();
|
|
||||||
hie0 (E);
|
|
||||||
ConsumeRParen ();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If we run into an identifier in preprocessing mode, we assume that this
|
|
||||||
** is an undefined macro and replace it by a constant value of zero.
|
|
||||||
*/
|
|
||||||
if (Preprocessing && CurTok.Tok == TOK_IDENT) {
|
|
||||||
NextToken ();
|
|
||||||
ED_MakeConstAbsInt (E, 0);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* All others may only be used if the expression evaluation is not called
|
|
||||||
** recursively by the preprocessor.
|
|
||||||
*/
|
|
||||||
if (Preprocessing) {
|
|
||||||
/* Illegal expression in PP mode */
|
|
||||||
Error ("Preprocessor expression expected");
|
|
||||||
ED_MakeConstAbsInt (E, 1);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned Flags = E->Flags & E_MASK_KEEP_MAKE;
|
unsigned Flags = E->Flags & E_MASK_KEEP_MAKE;
|
||||||
|
|
||||||
switch (CurTok.Tok) {
|
switch (CurTok.Tok) {
|
||||||
|
|
||||||
|
case TOK_LPAREN:
|
||||||
|
/* Process parenthesized subexpression by calling the whole parser
|
||||||
|
** recursively.
|
||||||
|
*/
|
||||||
|
NextToken ();
|
||||||
|
hie0 (E);
|
||||||
|
ConsumeRParen ();
|
||||||
|
break;
|
||||||
|
|
||||||
case TOK_BOOL_AND:
|
case TOK_BOOL_AND:
|
||||||
/* A computed goto label address */
|
/* A computed goto label address */
|
||||||
if (IS_Get (&Standard) >= STD_CC65) {
|
if (IS_Get (&Standard) >= STD_CC65) {
|
||||||
@ -1172,9 +1129,9 @@ static void Primary (ExprDesc* E)
|
|||||||
/* Cannot use type symbols */
|
/* Cannot use type symbols */
|
||||||
Error ("Variable identifier expected");
|
Error ("Variable identifier expected");
|
||||||
/* Assume an int type to make E valid */
|
/* Assume an int type to make E valid */
|
||||||
E->Flags |= E_LOC_STACK | E_RTYPE_LVAL;
|
E->Flags = E_LOC_STACK | E_RTYPE_LVAL;
|
||||||
E->Type = type_int;
|
E->Type = type_int;
|
||||||
return;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Mark the symbol as referenced */
|
/* Mark the symbol as referenced */
|
||||||
@ -1187,11 +1144,11 @@ static void Primary (ExprDesc* E)
|
|||||||
if ((Sym->Flags & SC_CONST) == SC_CONST) {
|
if ((Sym->Flags & SC_CONST) == SC_CONST) {
|
||||||
/* Enum or some other numeric constant */
|
/* Enum or some other numeric constant */
|
||||||
E->Flags = E_LOC_NONE | E_RTYPE_RVAL;
|
E->Flags = E_LOC_NONE | E_RTYPE_RVAL;
|
||||||
E->IVal = Sym->V.ConstVal;
|
E->IVal = Sym->V.ConstVal;
|
||||||
} else if ((Sym->Flags & SC_FUNC) == SC_FUNC) {
|
} else if ((Sym->Flags & SC_FUNC) == SC_FUNC) {
|
||||||
/* Function */
|
/* Function */
|
||||||
E->Flags = E_LOC_GLOBAL | E_RTYPE_LVAL;
|
E->Flags = E_LOC_GLOBAL | E_RTYPE_LVAL;
|
||||||
E->Name = (uintptr_t) Sym->Name;
|
E->Name = (uintptr_t) Sym->Name;
|
||||||
} else if ((Sym->Flags & SC_AUTO) == SC_AUTO) {
|
} else if ((Sym->Flags & SC_AUTO) == SC_AUTO) {
|
||||||
/* Local variable. If this is a parameter for a variadic
|
/* Local variable. If this is a parameter for a variadic
|
||||||
** function, we have to add some address calculations, and the
|
** function, we have to add some address calculations, and the
|
||||||
@ -1214,10 +1171,10 @@ static void Primary (ExprDesc* E)
|
|||||||
/* Static variable */
|
/* Static variable */
|
||||||
if (Sym->Flags & (SC_EXTERN | SC_STORAGE | SC_DECL)) {
|
if (Sym->Flags & (SC_EXTERN | SC_STORAGE | SC_DECL)) {
|
||||||
E->Flags = E_LOC_GLOBAL | E_RTYPE_LVAL;
|
E->Flags = E_LOC_GLOBAL | E_RTYPE_LVAL;
|
||||||
E->Name = (uintptr_t) Sym->Name;
|
E->Name = (uintptr_t) Sym->Name;
|
||||||
} else {
|
} else {
|
||||||
E->Flags = E_LOC_STATIC | E_RTYPE_LVAL;
|
E->Flags = E_LOC_STATIC | E_RTYPE_LVAL;
|
||||||
E->Name = Sym->V.L.Label;
|
E->Name = Sym->V.L.Label;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* Local static variable */
|
/* Local static variable */
|
||||||
@ -1263,7 +1220,7 @@ static void Primary (ExprDesc* E)
|
|||||||
/* Undeclared Variable */
|
/* Undeclared Variable */
|
||||||
Sym = AddLocalSym (Ident, type_int, SC_AUTO | SC_REF, 0);
|
Sym = AddLocalSym (Ident, type_int, SC_AUTO | SC_REF, 0);
|
||||||
E->Flags = E_LOC_STACK | E_RTYPE_LVAL;
|
E->Flags = E_LOC_STACK | E_RTYPE_LVAL;
|
||||||
E->Type = type_int;
|
E->Type = type_int;
|
||||||
Error ("Undefined symbol: '%s'", Ident);
|
Error ("Undefined symbol: '%s'", Ident);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1275,6 +1232,8 @@ static void Primary (ExprDesc* E)
|
|||||||
/* String literal */
|
/* String literal */
|
||||||
if ((Flags & E_EVAL_UNEVAL) != E_EVAL_UNEVAL) {
|
if ((Flags & E_EVAL_UNEVAL) != E_EVAL_UNEVAL) {
|
||||||
E->V.LVal = UseLiteral (CurTok.SVal);
|
E->V.LVal = UseLiteral (CurTok.SVal);
|
||||||
|
/* Translate into target charset */
|
||||||
|
TranslateLiteral (E->V.LVal);
|
||||||
} else {
|
} else {
|
||||||
E->V.LVal = CurTok.SVal;
|
E->V.LVal = CurTok.SVal;
|
||||||
}
|
}
|
||||||
@ -1285,6 +1244,24 @@ static void Primary (ExprDesc* E)
|
|||||||
NextToken ();
|
NextToken ();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case TOK_ICONST:
|
||||||
|
case TOK_CCONST:
|
||||||
|
case TOK_WCCONST:
|
||||||
|
/* Character and integer constants */
|
||||||
|
E->IVal = CurTok.IVal;
|
||||||
|
E->Flags = E_LOC_NONE | E_RTYPE_RVAL;
|
||||||
|
E->Type = CurTok.Type;
|
||||||
|
NextToken ();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TOK_FCONST:
|
||||||
|
/* Floating point constant */
|
||||||
|
E->V.FVal = CurTok.FVal;
|
||||||
|
E->Flags = E_LOC_NONE | E_RTYPE_RVAL;
|
||||||
|
E->Type = CurTok.Type;
|
||||||
|
NextToken ();
|
||||||
|
break;
|
||||||
|
|
||||||
case TOK_ASM:
|
case TOK_ASM:
|
||||||
/* ASM statement */
|
/* ASM statement */
|
||||||
AsmStatement ();
|
AsmStatement ();
|
||||||
@ -2462,7 +2439,7 @@ static void hie_compare (const GenDesc* Ops, /* List of generators */
|
|||||||
} else if (IsClassPtr (Expr->Type)) {
|
} else if (IsClassPtr (Expr->Type)) {
|
||||||
if (IsClassPtr (Expr2.Type)) {
|
if (IsClassPtr (Expr2.Type)) {
|
||||||
/* Pointers are allowed in comparison */
|
/* Pointers are allowed in comparison */
|
||||||
if (TypeCmp (Expr->Type, Expr2.Type).C < TC_STRICT_COMPATIBLE) {
|
if (TypeCmp (Expr->Type, Expr2.Type).C < TC_VOID_PTR) {
|
||||||
/* Warn about distinct pointer types */
|
/* Warn about distinct pointer types */
|
||||||
TypeCompatibilityDiagnostic (PtrConversion (Expr->Type), PtrConversion (Expr2.Type), 0,
|
TypeCompatibilityDiagnostic (PtrConversion (Expr->Type), PtrConversion (Expr2.Type), 0,
|
||||||
"Distinct pointer types comparing '%s' with '%s'");
|
"Distinct pointer types comparing '%s' with '%s'");
|
||||||
@ -3628,48 +3605,6 @@ static void hie2 (ExprDesc* Expr)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
static void hieAndPP (ExprDesc* Expr)
|
|
||||||
/* Process "exp && exp" in preprocessor mode (that is, when the parser is
|
|
||||||
** called recursively from the preprocessor.
|
|
||||||
*/
|
|
||||||
{
|
|
||||||
*Expr = NoCodeConstAbsIntExpr (hie2);
|
|
||||||
while (CurTok.Tok == TOK_BOOL_AND) {
|
|
||||||
|
|
||||||
/* Skip the && */
|
|
||||||
NextToken ();
|
|
||||||
|
|
||||||
/* Get rhs */
|
|
||||||
ExprDesc Expr2 = NoCodeConstAbsIntExpr (hie2);
|
|
||||||
|
|
||||||
/* Combine the two */
|
|
||||||
Expr->IVal = (Expr->IVal && Expr2.IVal);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static void hieOrPP (ExprDesc *Expr)
|
|
||||||
/* Process "exp || exp" in preprocessor mode (that is, when the parser is
|
|
||||||
** called recursively from the preprocessor.
|
|
||||||
*/
|
|
||||||
{
|
|
||||||
*Expr = NoCodeConstAbsIntExpr (hieAndPP);
|
|
||||||
while (CurTok.Tok == TOK_BOOL_OR) {
|
|
||||||
|
|
||||||
/* Skip the && */
|
|
||||||
NextToken ();
|
|
||||||
|
|
||||||
/* Get rhs */
|
|
||||||
ExprDesc Expr2 = NoCodeConstAbsIntExpr (hieAndPP);
|
|
||||||
|
|
||||||
/* Combine the two */
|
|
||||||
Expr->IVal = (Expr->IVal || Expr2.IVal);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static int hieAnd (ExprDesc* Expr, unsigned* TrueLab, int* TrueLabAllocated)
|
static int hieAnd (ExprDesc* Expr, unsigned* TrueLab, int* TrueLabAllocated)
|
||||||
/* Process "exp && exp". This should only be called within hieOr.
|
/* Process "exp && exp". This should only be called within hieOr.
|
||||||
** Return true if logic AND does occur.
|
** Return true if logic AND does occur.
|
||||||
@ -4019,11 +3954,7 @@ static void hieQuest (ExprDesc* Expr)
|
|||||||
Type* ResultType; /* Type of result */
|
Type* ResultType; /* Type of result */
|
||||||
|
|
||||||
/* Call the lower level eval routine */
|
/* Call the lower level eval routine */
|
||||||
if (Preprocessing) {
|
ExprWithCheck (hieOr, Expr);
|
||||||
ExprWithCheck (hieOrPP, Expr);
|
|
||||||
} else {
|
|
||||||
ExprWithCheck (hieOr, Expr);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Check if it's a ternary expression */
|
/* Check if it's a ternary expression */
|
||||||
if (CurTok.Tok == TOK_QUEST) {
|
if (CurTok.Tok == TOK_QUEST) {
|
||||||
|
115
src/cc65/input.c
115
src/cc65/input.c
@ -54,6 +54,7 @@
|
|||||||
#include "input.h"
|
#include "input.h"
|
||||||
#include "lineinfo.h"
|
#include "lineinfo.h"
|
||||||
#include "output.h"
|
#include "output.h"
|
||||||
|
#include "preproc.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -91,6 +92,8 @@ struct AFile {
|
|||||||
FILE* F; /* Input file stream */
|
FILE* F; /* Input file stream */
|
||||||
IFile* Input; /* Points to corresponding IFile */
|
IFile* Input; /* Points to corresponding IFile */
|
||||||
int SearchPath; /* True if we've added a path for this file */
|
int SearchPath; /* True if we've added a path for this file */
|
||||||
|
PPIfStack IfStack; /* PP #if stack */
|
||||||
|
int MissingNL; /* Last input line was missing a newline */
|
||||||
};
|
};
|
||||||
|
|
||||||
/* List of all input files */
|
/* List of all input files */
|
||||||
@ -156,6 +159,8 @@ static AFile* NewAFile (IFile* IF, FILE* F)
|
|||||||
AF->Line = 0;
|
AF->Line = 0;
|
||||||
AF->F = F;
|
AF->F = F;
|
||||||
AF->Input = IF;
|
AF->Input = IF;
|
||||||
|
AF->IfStack.Index = -1;
|
||||||
|
AF->MissingNL = 0;
|
||||||
|
|
||||||
/* Increment the usage counter of the corresponding IFile. If this
|
/* Increment the usage counter of the corresponding IFile. If this
|
||||||
** is the first use, set the file data and output debug info if
|
** is the first use, set the file data and output debug info if
|
||||||
@ -257,6 +262,12 @@ void OpenMainFile (const char* Name)
|
|||||||
/* Allocate a new AFile structure for the file */
|
/* Allocate a new AFile structure for the file */
|
||||||
MainFile = NewAFile (IF, F);
|
MainFile = NewAFile (IF, F);
|
||||||
|
|
||||||
|
/* Use this file with PP */
|
||||||
|
SetPPIfStack (&MainFile->IfStack);
|
||||||
|
|
||||||
|
/* Begin PP for this file */
|
||||||
|
PreprocessBegin ();
|
||||||
|
|
||||||
/* Allocate the input line buffer */
|
/* Allocate the input line buffer */
|
||||||
Line = NewStrBuf ();
|
Line = NewStrBuf ();
|
||||||
|
|
||||||
@ -274,6 +285,7 @@ void OpenIncludeFile (const char* Name, InputType IT)
|
|||||||
char* N;
|
char* N;
|
||||||
FILE* F;
|
FILE* F;
|
||||||
IFile* IF;
|
IFile* IF;
|
||||||
|
AFile* AF;
|
||||||
|
|
||||||
/* Check for the maximum include nesting */
|
/* Check for the maximum include nesting */
|
||||||
if (CollCount (&AFiles) > MAX_INC_NESTING) {
|
if (CollCount (&AFiles) > MAX_INC_NESTING) {
|
||||||
@ -311,12 +323,18 @@ void OpenIncludeFile (const char* Name, InputType IT)
|
|||||||
Print (stdout, 1, "Opened include file '%s'\n", IF->Name);
|
Print (stdout, 1, "Opened include file '%s'\n", IF->Name);
|
||||||
|
|
||||||
/* Allocate a new AFile structure */
|
/* Allocate a new AFile structure */
|
||||||
(void) NewAFile (IF, F);
|
AF = NewAFile (IF, F);
|
||||||
|
|
||||||
|
/* Use this file with PP */
|
||||||
|
SetPPIfStack (&AF->IfStack);
|
||||||
|
|
||||||
|
/* Begin PP for this file */
|
||||||
|
PreprocessBegin ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static void CloseIncludeFile (void)
|
void CloseIncludeFile (void)
|
||||||
/* Close an include file and switch to the higher level file. Set Input to
|
/* Close an include file and switch to the higher level file. Set Input to
|
||||||
** NULL if this was the main file.
|
** NULL if this was the main file.
|
||||||
*/
|
*/
|
||||||
@ -329,14 +347,18 @@ static void CloseIncludeFile (void)
|
|||||||
/* Must have an input file when called */
|
/* Must have an input file when called */
|
||||||
PRECONDITION (AFileCount > 0);
|
PRECONDITION (AFileCount > 0);
|
||||||
|
|
||||||
|
/* End preprocessor in this file */
|
||||||
|
PreprocessEnd ();
|
||||||
|
|
||||||
/* Get the current active input file */
|
/* Get the current active input file */
|
||||||
Input = (AFile*) CollLast (&AFiles);
|
Input = CollLast (&AFiles);
|
||||||
|
|
||||||
/* Close the current input file (we're just reading so no error check) */
|
/* Close the current input file (we're just reading so no error check) */
|
||||||
fclose (Input->F);
|
fclose (Input->F);
|
||||||
|
|
||||||
/* Delete the last active file from the active file collection */
|
/* Delete the last active file from the active file collection */
|
||||||
CollDelete (&AFiles, AFileCount-1);
|
--AFileCount;
|
||||||
|
CollDelete (&AFiles, AFileCount);
|
||||||
|
|
||||||
/* If we had added an extra search path for this AFile, remove it */
|
/* If we had added an extra search path for this AFile, remove it */
|
||||||
if (Input->SearchPath) {
|
if (Input->SearchPath) {
|
||||||
@ -345,6 +367,12 @@ static void CloseIncludeFile (void)
|
|||||||
|
|
||||||
/* Delete the active file structure */
|
/* Delete the active file structure */
|
||||||
FreeAFile (Input);
|
FreeAFile (Input);
|
||||||
|
|
||||||
|
/* Use previous file with PP if it is not the main file */
|
||||||
|
if (AFileCount > 0) {
|
||||||
|
Input = CollLast (&AFiles);
|
||||||
|
SetPPIfStack (&Input->IfStack);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -436,47 +464,49 @@ StrBuf* InitLine (StrBuf* Buf)
|
|||||||
|
|
||||||
|
|
||||||
int NextLine (void)
|
int NextLine (void)
|
||||||
/* Get a line from the current input. Returns 0 on end of file. */
|
/* Get a line from the current input. Returns 0 on end of file with no new
|
||||||
|
** input bytes.
|
||||||
|
*/
|
||||||
{
|
{
|
||||||
|
int C;
|
||||||
AFile* Input;
|
AFile* Input;
|
||||||
|
|
||||||
/* Clear the current line */
|
/* Clear the current line */
|
||||||
ClearLine ();
|
ClearLine ();
|
||||||
|
SB_Clear (Line);
|
||||||
|
|
||||||
/* If there is no file open, bail out, otherwise get the current input file */
|
/* Must have an input file when called */
|
||||||
if (CollCount (&AFiles) == 0) {
|
if (CollCount(&AFiles) == 0) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Get the current input file */
|
||||||
Input = CollLast (&AFiles);
|
Input = CollLast (&AFiles);
|
||||||
|
|
||||||
/* Read characters until we have one complete line */
|
/* Read characters until we have one complete line */
|
||||||
while (1) {
|
while (1) {
|
||||||
|
|
||||||
/* Read the next character */
|
/* Read the next character */
|
||||||
int C = fgetc (Input->F);
|
C = fgetc (Input->F);
|
||||||
|
|
||||||
/* Check for EOF */
|
/* Check for EOF */
|
||||||
if (C == EOF) {
|
if (C == EOF) {
|
||||||
|
|
||||||
/* Accept files without a newline at the end */
|
if (!Input->MissingNL || SB_NotEmpty (Line)) {
|
||||||
if (SB_NotEmpty (Line)) {
|
|
||||||
|
/* Accept files without a newline at the end */
|
||||||
++Input->Line;
|
++Input->Line;
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Leave the current file */
|
/* Assume no new line */
|
||||||
CloseIncludeFile ();
|
Input->MissingNL = 1;
|
||||||
|
|
||||||
/* If there is no file open, bail out, otherwise get the
|
|
||||||
** previous input file and start over.
|
|
||||||
*/
|
|
||||||
if (CollCount (&AFiles) == 0) {
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
Input = CollLast (&AFiles);
|
break;
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Assume no new line */
|
||||||
|
Input->MissingNL = 1;
|
||||||
|
|
||||||
/* Check for end of line */
|
/* Check for end of line */
|
||||||
if (C == '\n') {
|
if (C == '\n') {
|
||||||
|
|
||||||
@ -497,6 +527,7 @@ int NextLine (void)
|
|||||||
if (SB_LookAtLast (Line) == '\\') {
|
if (SB_LookAtLast (Line) == '\\') {
|
||||||
Line->Buf[Line->Len-1] = '\n';
|
Line->Buf[Line->Len-1] = '\n';
|
||||||
} else {
|
} else {
|
||||||
|
Input->MissingNL = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -517,6 +548,38 @@ int NextLine (void)
|
|||||||
/* Create line information for this line */
|
/* Create line information for this line */
|
||||||
UpdateLineInfo (Input->Input, Input->Line, Line);
|
UpdateLineInfo (Input->Input, Input->Line, Line);
|
||||||
|
|
||||||
|
/* Done */
|
||||||
|
return C != EOF || SB_NotEmpty (Line);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int PreprocessNextLine (void)
|
||||||
|
/* Get a line from opened input files and do preprocess. Returns 0 on end of
|
||||||
|
** main file.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
while (NextLine() == 0) {
|
||||||
|
|
||||||
|
/* If there is no input file open, bail out. Otherwise get the previous
|
||||||
|
** input file and start over.
|
||||||
|
*/
|
||||||
|
if (CollCount (&AFiles) == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Leave the current file */
|
||||||
|
CloseIncludeFile ();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Do preprocess anyways */
|
||||||
|
Preprocess ();
|
||||||
|
|
||||||
|
/* Write it to the output file if in preprocess-only mode */
|
||||||
|
if (PreprocessOnly) {
|
||||||
|
WriteOutput ("%.*s\n", (int) SB_GetLen (Line), SB_GetConstBuf (Line));
|
||||||
|
}
|
||||||
|
|
||||||
/* Done */
|
/* Done */
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@ -539,14 +602,8 @@ const char* GetCurrentFile (void)
|
|||||||
const AFile* AF = (const AFile*) CollAt (&AFiles, AFileCount-1);
|
const AFile* AF = (const AFile*) CollAt (&AFiles, AFileCount-1);
|
||||||
return AF->Input->Name;
|
return AF->Input->Name;
|
||||||
} else {
|
} else {
|
||||||
/* No open file. Use the main file if we have one. */
|
/* No open file */
|
||||||
unsigned IFileCount = CollCount (&IFiles);
|
return "(outside file scope)";
|
||||||
if (IFileCount > 0) {
|
|
||||||
const IFile* IF = (const IFile*) CollAt (&IFiles, 0);
|
|
||||||
return IF->Name;
|
|
||||||
} else {
|
|
||||||
return "(outside file scope)";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -46,7 +46,7 @@
|
|||||||
|
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
/* data */
|
/* Data */
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
@ -84,6 +84,11 @@ void OpenMainFile (const char* Name);
|
|||||||
void OpenIncludeFile (const char* Name, InputType IT);
|
void OpenIncludeFile (const char* Name, InputType IT);
|
||||||
/* Open an include file and insert it into the tables. */
|
/* Open an include file and insert it into the tables. */
|
||||||
|
|
||||||
|
void CloseIncludeFile (void);
|
||||||
|
/* Close an include file and switch to the higher level file. Set Input to
|
||||||
|
** NULL if this was the main file.
|
||||||
|
*/
|
||||||
|
|
||||||
void NextChar (void);
|
void NextChar (void);
|
||||||
/* Read the next character from the input stream and make CurC and NextC
|
/* Read the next character from the input stream and make CurC and NextC
|
||||||
** valid. If end of line is reached, both are set to NUL, no more lines
|
** valid. If end of line is reached, both are set to NUL, no more lines
|
||||||
@ -99,7 +104,14 @@ StrBuf* InitLine (StrBuf* Buf);
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
int NextLine (void);
|
int NextLine (void);
|
||||||
/* Get a line from the current input. Returns 0 on end of file. */
|
/* Get a line from the current input. Returns 0 on end of file with no new
|
||||||
|
** input bytes.
|
||||||
|
*/
|
||||||
|
|
||||||
|
int PreprocessNextLine (void);
|
||||||
|
/* Get a line from opened input files and do preprocess. Returns 0 on end of
|
||||||
|
** main file.
|
||||||
|
*/
|
||||||
|
|
||||||
const char* GetInputFile (const struct IFile* IF);
|
const char* GetInputFile (const struct IFile* IF);
|
||||||
/* Return a filename from an IFile struct */
|
/* Return a filename from an IFile struct */
|
||||||
|
@ -126,9 +126,6 @@ static void FreeLiteral (Literal* L)
|
|||||||
static void OutputLiteral (Literal* L)
|
static void OutputLiteral (Literal* L)
|
||||||
/* Output one literal to the currently active data segment */
|
/* Output one literal to the currently active data segment */
|
||||||
{
|
{
|
||||||
/* Translate the literal into the target charset */
|
|
||||||
TranslateLiteral (L);
|
|
||||||
|
|
||||||
/* Define the label for the literal */
|
/* Define the label for the literal */
|
||||||
g_defliterallabel (L->Label);
|
g_defliterallabel (L->Label);
|
||||||
|
|
||||||
@ -387,9 +384,6 @@ static void OutputReadOnlyLiterals (Collection* Literals)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Translate the literal into the target charset */
|
|
||||||
TranslateLiteral (L);
|
|
||||||
|
|
||||||
/* Check if this literal is part of another one. Since the literals
|
/* Check if this literal is part of another one. Since the literals
|
||||||
** are sorted by size (larger ones first), it can only be part of a
|
** are sorted by size (larger ones first), it can only be part of a
|
||||||
** literal with a smaller index.
|
** literal with a smaller index.
|
||||||
|
@ -56,6 +56,9 @@
|
|||||||
#define MACRO_TAB_SIZE 211
|
#define MACRO_TAB_SIZE 211
|
||||||
static Macro* MacroTab[MACRO_TAB_SIZE];
|
static Macro* MacroTab[MACRO_TAB_SIZE];
|
||||||
|
|
||||||
|
/* The undefined macros list head */
|
||||||
|
static Macro* UndefinedMacrosListHead;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
@ -108,6 +111,29 @@ void FreeMacro (Macro* M)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Macro* CloneMacro (const Macro* M)
|
||||||
|
/* Clone a macro definition. The function is not insert the macro into the
|
||||||
|
** macro table, thus the cloned instance cannot be freed with UndefineMacro.
|
||||||
|
** Use FreeMacro for that.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
New->ArgCount = M->ArgCount;
|
||||||
|
New->Variadic = M->Variadic;
|
||||||
|
SB_Copy (&New->Replacement, &M->Replacement);
|
||||||
|
|
||||||
|
return New;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void DefineNumericMacro (const char* Name, long Val)
|
void DefineNumericMacro (const char* Name, long Val)
|
||||||
/* Define a macro for a numeric constant */
|
/* Define a macro for a numeric constant */
|
||||||
{
|
{
|
||||||
@ -150,10 +176,11 @@ void InsertMacro (Macro* M)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
int UndefineMacro (const char* Name)
|
Macro* UndefineMacro (const char* Name)
|
||||||
/* Search for the macro with the given name and remove it from the macro
|
/* Search for the macro with the given name, if it exists, remove it from
|
||||||
** table if it exists. Return 1 if a macro was found and deleted, return
|
** the defined macro table and insert it to a list for pending deletion.
|
||||||
** 0 otherwise.
|
** Return the macro if it was found and removed, return 0 otherwise.
|
||||||
|
** To safely free the removed macro, use FreeUndefinedMacros().
|
||||||
*/
|
*/
|
||||||
{
|
{
|
||||||
/* Get the hash value of the macro name */
|
/* Get the hash value of the macro name */
|
||||||
@ -173,11 +200,12 @@ int UndefineMacro (const char* Name)
|
|||||||
L->Next = M->Next;
|
L->Next = M->Next;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Delete the macro */
|
/* Add this macro to pending deletion list */
|
||||||
FreeMacro (M);
|
M->Next = UndefinedMacrosListHead;
|
||||||
|
UndefinedMacrosListHead = M;
|
||||||
|
|
||||||
/* Done */
|
/* Done */
|
||||||
return 1;
|
return M;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Next macro */
|
/* Next macro */
|
||||||
@ -191,6 +219,23 @@ int UndefineMacro (const char* Name)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void FreeUndefinedMacros (void)
|
||||||
|
/* Free all undefined macros */
|
||||||
|
{
|
||||||
|
Macro* Next;
|
||||||
|
|
||||||
|
while (UndefinedMacrosListHead != 0) {
|
||||||
|
Next = UndefinedMacrosListHead->Next;
|
||||||
|
|
||||||
|
/* Delete the macro */
|
||||||
|
FreeMacro (UndefinedMacrosListHead);
|
||||||
|
|
||||||
|
UndefinedMacrosListHead = Next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Macro* FindMacro (const char* Name)
|
Macro* FindMacro (const char* Name)
|
||||||
/* Find a macro with the given name. Return the macro definition or NULL */
|
/* Find a macro with the given name. Return the macro definition or NULL */
|
||||||
{
|
{
|
||||||
|
@ -82,6 +82,12 @@ void FreeMacro (Macro* M);
|
|||||||
** table, use UndefineMacro for that.
|
** table, use UndefineMacro for that.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
Macro* CloneMacro (const Macro* M);
|
||||||
|
/* Clone a macro definition. The function is not insert the macro into the
|
||||||
|
** macro table, thus the cloned instance cannot be freed with UndefineMacro.
|
||||||
|
** Use FreeMacro for that.
|
||||||
|
*/
|
||||||
|
|
||||||
void DefineNumericMacro (const char* Name, long Val);
|
void DefineNumericMacro (const char* Name, long Val);
|
||||||
/* Define a macro for a numeric constant */
|
/* Define a macro for a numeric constant */
|
||||||
|
|
||||||
@ -91,12 +97,16 @@ void DefineTextMacro (const char* Name, const char* Val);
|
|||||||
void InsertMacro (Macro* M);
|
void InsertMacro (Macro* M);
|
||||||
/* Insert the given macro into the macro table. */
|
/* Insert the given macro into the macro table. */
|
||||||
|
|
||||||
int UndefineMacro (const char* Name);
|
Macro* UndefineMacro (const char* Name);
|
||||||
/* Search for the macro with the given name and remove it from the macro
|
/* Search for the macro with the given name, if it exists, remove it from
|
||||||
** table if it exists. Return 1 if a macro was found and deleted, return
|
** the defined macro table and insert it to a list for pending deletion.
|
||||||
** 0 otherwise.
|
** Return the macro if it was found and removed, return 0 otherwise.
|
||||||
|
** To safely free the removed macro, use FreeUndefinedMacros().
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
void FreeUndefinedMacros (void);
|
||||||
|
/* Free all undefined macros */
|
||||||
|
|
||||||
Macro* FindMacro (const char* Name);
|
Macro* FindMacro (const char* Name);
|
||||||
/* Find a macro with the given name. Return the macro definition or NULL */
|
/* Find a macro with the given name. Return the macro definition or NULL */
|
||||||
|
|
||||||
|
878
src/cc65/ppexpr.c
Normal file
878
src/cc65/ppexpr.c
Normal file
@ -0,0 +1,878 @@
|
|||||||
|
/*****************************************************************************/
|
||||||
|
/* */
|
||||||
|
/* ppexpr.h */
|
||||||
|
/* */
|
||||||
|
/* Expressions for C preprocessor */
|
||||||
|
/* */
|
||||||
|
/* */
|
||||||
|
/* */
|
||||||
|
/* (C) 2022 The cc65 Authors */
|
||||||
|
/* */
|
||||||
|
/* */
|
||||||
|
/* This software is provided 'as-is', without any expressed 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. */
|
||||||
|
/* */
|
||||||
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* cc65 */
|
||||||
|
#include "error.h"
|
||||||
|
#include "scanner.h"
|
||||||
|
#include "ppexpr.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/* Data */
|
||||||
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* PP expression parser status */
|
||||||
|
static int PPEvaluationEnabled = 0;
|
||||||
|
static int PPEvaluationFailed = 0;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/* Forwards */
|
||||||
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static void PPhie0 (PPExpr* Expr);
|
||||||
|
static void PPhie1 (PPExpr* Expr);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/* Helper functions */
|
||||||
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static token_t PPFindTok (token_t Tok, const token_t* Table)
|
||||||
|
/* Find a token in a generator table */
|
||||||
|
{
|
||||||
|
while (*Table != TOK_INVALID) {
|
||||||
|
if (*Table == Tok) {
|
||||||
|
return Tok;
|
||||||
|
}
|
||||||
|
++Table;
|
||||||
|
}
|
||||||
|
return TOK_INVALID;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static void PPExprInit (PPExpr* Expr)
|
||||||
|
/* Initialize the expression */
|
||||||
|
{
|
||||||
|
Expr->IVal = 0;
|
||||||
|
Expr->Flags = PPEXPR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static void PPErrorSkipLine (void)
|
||||||
|
/* Set the expression parser error flag, skip the remain tokens till the end
|
||||||
|
** of the line, clear the current and the next tokens.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
PPEvaluationFailed = 1;
|
||||||
|
SkipTokens (0, 0);
|
||||||
|
CurTok.Tok = TOK_CEOF;
|
||||||
|
NextTok.Tok = TOK_CEOF;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/* Code */
|
||||||
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static void PPhiePrimary (PPExpr* Expr)
|
||||||
|
/* This is the lowest level of the PP expression parser */
|
||||||
|
{
|
||||||
|
switch (CurTok.Tok) {
|
||||||
|
case TOK_ICONST:
|
||||||
|
case TOK_CCONST:
|
||||||
|
case TOK_WCCONST:
|
||||||
|
/* Character and integer constants */
|
||||||
|
Expr->IVal = CurTok.IVal;
|
||||||
|
/* According to the C standard, all signed types act as intmax_t
|
||||||
|
** and all unsigned types act as uintmax_t.
|
||||||
|
*/
|
||||||
|
if (IsSignUnsigned (CurTok.Type)) {
|
||||||
|
Expr->Flags |= PPEXPR_UNSIGNED;
|
||||||
|
}
|
||||||
|
NextToken ();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TOK_FCONST:
|
||||||
|
/* Floating point constant */
|
||||||
|
PPError ("Floating constant in preprocessor expression");
|
||||||
|
Expr->IVal = 0;
|
||||||
|
NextToken ();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TOK_LPAREN:
|
||||||
|
/* Parse parenthesized subexpression by calling the whole parser
|
||||||
|
** recursively.
|
||||||
|
*/
|
||||||
|
NextToken ();
|
||||||
|
PPhie0 (Expr);
|
||||||
|
ConsumeRParen ();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TOK_IDENT:
|
||||||
|
/* Assume that this identifier is an undefined macro and replace
|
||||||
|
** it by a constant value of zero.
|
||||||
|
*/
|
||||||
|
NextToken ();
|
||||||
|
Expr->Flags |= PPEXPR_UNDEFINED;
|
||||||
|
Expr->IVal = 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TOK_CEOF:
|
||||||
|
/* Error recovery */
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
/* Illegal expression in PP mode */
|
||||||
|
PPError ("Preprocessor expression expected");
|
||||||
|
PPErrorSkipLine ();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static void PPhie11 (PPExpr* Expr)
|
||||||
|
/* Handle compound types (structs and arrays) etc which are invalid in PP */
|
||||||
|
{
|
||||||
|
/* Evaluate the lhs */
|
||||||
|
PPhiePrimary (Expr);
|
||||||
|
|
||||||
|
/* Check for a rhs */
|
||||||
|
while (CurTok.Tok == TOK_INC || CurTok.Tok == TOK_DEC ||
|
||||||
|
CurTok.Tok == TOK_LBRACK || CurTok.Tok == TOK_LPAREN ||
|
||||||
|
CurTok.Tok == TOK_DOT || CurTok.Tok == TOK_PTR_REF) {
|
||||||
|
|
||||||
|
switch (CurTok.Tok) {
|
||||||
|
|
||||||
|
case TOK_LBRACK:
|
||||||
|
PPError ("Token \".\" is not valid in preprocessor expressions");
|
||||||
|
PPErrorSkipLine ();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TOK_LPAREN:
|
||||||
|
/* Function call syntax is not recognized in preprocessor
|
||||||
|
** expressions.
|
||||||
|
*/
|
||||||
|
PPError ("Missing binary operator before token \"(\"");
|
||||||
|
PPErrorSkipLine ();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TOK_DOT:
|
||||||
|
PPError ("Token \".\" is not valid in preprocessor expressions");
|
||||||
|
PPErrorSkipLine ();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TOK_PTR_REF:
|
||||||
|
PPError ("Token \"->\" is not valid in preprocessor expressions");
|
||||||
|
PPErrorSkipLine ();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TOK_INC:
|
||||||
|
PPError ("Token \"++\" is not valid in preprocessor expressions");
|
||||||
|
PPErrorSkipLine ();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TOK_DEC:
|
||||||
|
PPError ("Token \"--\" is not valid in preprocessor expressions");
|
||||||
|
PPErrorSkipLine ();
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
Internal ("Invalid token in PPhie11: %d", CurTok.Tok);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check for excessive expressions */
|
||||||
|
if (!TokIsPunc (&CurTok)) {
|
||||||
|
PPError ("Missing binary operator");
|
||||||
|
PPErrorSkipLine ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void PPhie10 (PPExpr* Expr)
|
||||||
|
/* Handle prefixing unary operators */
|
||||||
|
{
|
||||||
|
switch (CurTok.Tok) {
|
||||||
|
|
||||||
|
case TOK_INC:
|
||||||
|
PPError ("Token \"++\" is not valid in preprocessor expressions");
|
||||||
|
PPErrorSkipLine ();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TOK_DEC:
|
||||||
|
PPError ("Token \"--\" is not valid in preprocessor expressions");
|
||||||
|
PPErrorSkipLine ();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TOK_PLUS:
|
||||||
|
NextToken ();
|
||||||
|
PPhie10 (Expr);
|
||||||
|
Expr->IVal = +Expr->IVal;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TOK_MINUS:
|
||||||
|
NextToken ();
|
||||||
|
PPhie10 (Expr);
|
||||||
|
Expr->IVal = -Expr->IVal;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TOK_COMP:
|
||||||
|
NextToken ();
|
||||||
|
PPhie10 (Expr);
|
||||||
|
Expr->IVal = ~Expr->IVal;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TOK_BOOL_NOT:
|
||||||
|
NextToken ();
|
||||||
|
PPhie10 (Expr);
|
||||||
|
Expr->IVal = !Expr->IVal;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TOK_CEOF:
|
||||||
|
/* Error recovery */
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TOK_STAR:
|
||||||
|
case TOK_AND:
|
||||||
|
case TOK_SIZEOF:
|
||||||
|
default:
|
||||||
|
/* Type cast, sizeof, *, &, are not recognized in preprocessor
|
||||||
|
** expressions. So everything is treated as as expression here.
|
||||||
|
*/
|
||||||
|
PPhie11 (Expr);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static void PPhie_internal (const token_t* Ops, /* List of generators */
|
||||||
|
PPExpr* Expr,
|
||||||
|
void (*hienext) (PPExpr*))
|
||||||
|
/* Helper function */
|
||||||
|
{
|
||||||
|
token_t Tok;
|
||||||
|
|
||||||
|
hienext (Expr);
|
||||||
|
|
||||||
|
while ((Tok = PPFindTok (CurTok.Tok, Ops)) != 0) {
|
||||||
|
|
||||||
|
PPExpr Rhs;
|
||||||
|
PPExprInit (&Rhs);
|
||||||
|
|
||||||
|
/* Remember the operator token, then skip it */
|
||||||
|
NextToken ();
|
||||||
|
|
||||||
|
/* Get the right hand side */
|
||||||
|
hienext (&Rhs);
|
||||||
|
|
||||||
|
if (PPEvaluationEnabled && !PPEvaluationFailed) {
|
||||||
|
|
||||||
|
/* 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;
|
||||||
|
} 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
} 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static void PPhie_compare (const token_t* Ops, /* List of generators */
|
||||||
|
PPExpr* Expr,
|
||||||
|
void (*hienext) (PPExpr*))
|
||||||
|
/* Helper function for the compare operators */
|
||||||
|
{
|
||||||
|
token_t Tok;
|
||||||
|
|
||||||
|
hienext (Expr);
|
||||||
|
|
||||||
|
while ((Tok = PPFindTok (CurTok.Tok, Ops)) != 0) {
|
||||||
|
|
||||||
|
PPExpr Rhs;
|
||||||
|
|
||||||
|
PPExprInit (&Rhs);
|
||||||
|
|
||||||
|
/* Skip the operator token */
|
||||||
|
NextToken ();
|
||||||
|
|
||||||
|
/* Get the right hand side */
|
||||||
|
hienext (&Rhs);
|
||||||
|
|
||||||
|
if (PPEvaluationEnabled && !PPEvaluationFailed) {
|
||||||
|
|
||||||
|
/* If either side is unsigned, the comparison is unsigned */
|
||||||
|
Expr->Flags |= Rhs.Flags & PPEXPR_UNSIGNED;
|
||||||
|
|
||||||
|
/* Determine if this is a signed or unsigned compare */
|
||||||
|
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_EQ: Expr->IVal = (Val1 == Val2); break;
|
||||||
|
case TOK_NE: Expr->IVal = (Val1 != Val2); break;
|
||||||
|
case TOK_LT: Expr->IVal = (Val1 < Val2); break;
|
||||||
|
case TOK_LE: Expr->IVal = (Val1 <= Val2); break;
|
||||||
|
case TOK_GE: Expr->IVal = (Val1 >= Val2); break;
|
||||||
|
case TOK_GT: Expr->IVal = (Val1 > Val2); break;
|
||||||
|
default: Internal ("PPhie_compare: 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_EQ: Expr->IVal = (Val1 == Val2); break;
|
||||||
|
case TOK_NE: Expr->IVal = (Val1 != Val2); break;
|
||||||
|
case TOK_LT: Expr->IVal = (Val1 < Val2); break;
|
||||||
|
case TOK_LE: Expr->IVal = (Val1 <= Val2); break;
|
||||||
|
case TOK_GE: Expr->IVal = (Val1 >= Val2); break;
|
||||||
|
case TOK_GT: Expr->IVal = (Val1 > Val2); break;
|
||||||
|
default: Internal ("PPhie_compare: got token 0x%X\n", Tok);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The result is signed */
|
||||||
|
Expr->Flags &= ~PPEXPR_UNSIGNED;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static void PPhie9 (PPExpr* Expr)
|
||||||
|
/* Handle "*", "/" and "%" operators */
|
||||||
|
{
|
||||||
|
static const token_t PPhie9_ops[] = {
|
||||||
|
TOK_STAR,
|
||||||
|
TOK_DIV,
|
||||||
|
TOK_MOD,
|
||||||
|
TOK_INVALID
|
||||||
|
};
|
||||||
|
|
||||||
|
PPhie_internal (PPhie9_ops, Expr, PPhie10);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static void PPhie8 (PPExpr* Expr)
|
||||||
|
/* Handle "+" and "-" binary operators */
|
||||||
|
{
|
||||||
|
static const token_t PPhie8_ops[] = {
|
||||||
|
TOK_PLUS,
|
||||||
|
TOK_MINUS,
|
||||||
|
TOK_INVALID
|
||||||
|
};
|
||||||
|
|
||||||
|
PPhie_internal (PPhie8_ops, Expr, PPhie9);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static void PPhie7 (PPExpr* Expr)
|
||||||
|
/* Handle the "<<" and ">>" shift operators */
|
||||||
|
{
|
||||||
|
/* Evaluate the lhs */
|
||||||
|
PPhie8 (Expr);
|
||||||
|
|
||||||
|
while (CurTok.Tok == TOK_SHL || CurTok.Tok == TOK_SHR) {
|
||||||
|
|
||||||
|
token_t Op; /* The operator token */
|
||||||
|
PPExpr Rhs;
|
||||||
|
PPExprInit (&Rhs);
|
||||||
|
|
||||||
|
/* Remember the operator, then skip its token */
|
||||||
|
Op = CurTok.Tok;
|
||||||
|
NextToken ();
|
||||||
|
|
||||||
|
/* Get the right hand side */
|
||||||
|
PPhie8 (&Rhs);
|
||||||
|
|
||||||
|
/* 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) {
|
||||||
|
Rhs.IVal = (long)LONG_BITS;
|
||||||
|
}
|
||||||
|
if (Op == TOK_SHR) {
|
||||||
|
Rhs.IVal = -Rhs.IVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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) {
|
||||||
|
Expr->IVal = 0;
|
||||||
|
} else if (Rhs.IVal < 0) {
|
||||||
|
Expr->IVal = (unsigned long)Expr->IVal >> -Rhs.IVal;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
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 < 0) {
|
||||||
|
Expr->IVal >>= Expr->IVal >> -Rhs.IVal;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static void PPhie6 (PPExpr* Expr)
|
||||||
|
/* Handle greater-than type relational operators */
|
||||||
|
{
|
||||||
|
static const token_t PPhie6_ops [] = {
|
||||||
|
TOK_LT,
|
||||||
|
TOK_LE,
|
||||||
|
TOK_GE,
|
||||||
|
TOK_GT,
|
||||||
|
TOK_INVALID
|
||||||
|
};
|
||||||
|
|
||||||
|
PPhie_compare (PPhie6_ops, Expr, PPhie7);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static void PPhie5 (PPExpr* Expr)
|
||||||
|
/* Handle "==" and "!=" relational operators */
|
||||||
|
{
|
||||||
|
static const token_t PPhie5_ops[] = {
|
||||||
|
TOK_EQ,
|
||||||
|
TOK_NE,
|
||||||
|
TOK_INVALID
|
||||||
|
};
|
||||||
|
|
||||||
|
PPhie_compare (PPhie5_ops, Expr, PPhie6);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static void PPhie4 (PPExpr* Expr)
|
||||||
|
/* Handle the bitwise AND "&" operator */
|
||||||
|
{
|
||||||
|
static const token_t PPhie4_ops[] = {
|
||||||
|
TOK_AND,
|
||||||
|
TOK_INVALID
|
||||||
|
};
|
||||||
|
|
||||||
|
PPhie_internal (PPhie4_ops, Expr, PPhie5);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static void PPhie3 (PPExpr* Expr)
|
||||||
|
/* Handle the bitwise exclusive OR "^" operator */
|
||||||
|
{
|
||||||
|
static const token_t PPhie3_ops[] = {
|
||||||
|
TOK_XOR,
|
||||||
|
TOK_INVALID
|
||||||
|
};
|
||||||
|
|
||||||
|
PPhie_internal (PPhie3_ops, Expr, PPhie4);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static void PPhie2 (PPExpr* Expr)
|
||||||
|
/* Handle the bitwise OR "|" operator */
|
||||||
|
{
|
||||||
|
static const token_t PPhie2_ops[] = {
|
||||||
|
TOK_OR,
|
||||||
|
TOK_INVALID
|
||||||
|
};
|
||||||
|
|
||||||
|
PPhie_internal (PPhie2_ops, Expr, PPhie3);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static void PPhieAnd (PPExpr* Expr)
|
||||||
|
/* Handle the logical AND "expr1 && expr2" operator */
|
||||||
|
{
|
||||||
|
/* Get one operand */
|
||||||
|
PPhie2 (Expr);
|
||||||
|
|
||||||
|
if (CurTok.Tok == TOK_BOOL_AND) {
|
||||||
|
|
||||||
|
int PPEvaluationEnabledPrev = PPEvaluationEnabled;
|
||||||
|
PPExpr One;
|
||||||
|
|
||||||
|
/* Do logical and */
|
||||||
|
Expr->IVal = (Expr->IVal != 0);
|
||||||
|
if (Expr->IVal == 0) {
|
||||||
|
PPEvaluationEnabled = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* While there are more expressions */
|
||||||
|
while (CurTok.Tok == TOK_BOOL_AND) {
|
||||||
|
/* Skip the && */
|
||||||
|
NextToken ();
|
||||||
|
|
||||||
|
/* Get one operand */
|
||||||
|
PPExprInit (&One);
|
||||||
|
PPhie2 (&One);
|
||||||
|
|
||||||
|
/* Evaluate */
|
||||||
|
if (PPEvaluationEnabled) {
|
||||||
|
if (One.IVal == 0) {
|
||||||
|
/* Skip evaluating remaining */
|
||||||
|
PPEvaluationEnabled = 0;
|
||||||
|
/* The value of the result will be false */
|
||||||
|
Expr->IVal = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Restore evaluation as before */
|
||||||
|
PPEvaluationEnabled = PPEvaluationEnabledPrev;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static void PPhieOr (PPExpr* Expr)
|
||||||
|
/* Handle the logical OR "||" operator */
|
||||||
|
{
|
||||||
|
/* Call the next level parser */
|
||||||
|
PPhieAnd (Expr);
|
||||||
|
|
||||||
|
if (CurTok.Tok == TOK_BOOL_OR) {
|
||||||
|
|
||||||
|
int PPEvaluationEnabledPrev = PPEvaluationEnabled;
|
||||||
|
PPExpr One;
|
||||||
|
|
||||||
|
/* Do logical or */
|
||||||
|
Expr->IVal = (Expr->IVal != 0);
|
||||||
|
if (Expr->IVal != 0) {
|
||||||
|
PPEvaluationEnabled = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* While there are more expressions */
|
||||||
|
while (CurTok.Tok == TOK_BOOL_OR) {
|
||||||
|
/* Skip the || */
|
||||||
|
NextToken ();
|
||||||
|
|
||||||
|
/* Get rhs subexpression */
|
||||||
|
PPExprInit (&One);
|
||||||
|
PPhieAnd (&One);
|
||||||
|
|
||||||
|
/* Evaluate */
|
||||||
|
if (PPEvaluationEnabled) {
|
||||||
|
if (One.IVal != 0) {
|
||||||
|
/* Skip evaluating remaining */
|
||||||
|
PPEvaluationEnabled = 0;
|
||||||
|
/* The value of the result will be true */
|
||||||
|
Expr->IVal = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Restore evaluation as before */
|
||||||
|
PPEvaluationEnabled = PPEvaluationEnabledPrev;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static void PPhieQuest (PPExpr* Expr)
|
||||||
|
/* Handle the ternary "expr1 ? expr2 : expr3 " operator */
|
||||||
|
{
|
||||||
|
/* Call the lower level eval routine */
|
||||||
|
PPhieOr (Expr);
|
||||||
|
|
||||||
|
/* Check if it's a ternary expression */
|
||||||
|
if (CurTok.Tok == TOK_QUEST) {
|
||||||
|
int PPEvaluationEnabledPrev = PPEvaluationEnabled;
|
||||||
|
PPExpr Expr2; /* Expression 2 */
|
||||||
|
PPExpr Expr3; /* Expression 3 */
|
||||||
|
|
||||||
|
/* Skip the question mark */
|
||||||
|
NextToken ();
|
||||||
|
|
||||||
|
/* Disable evaluation for Expr2 if the condition is false */
|
||||||
|
if (Expr->IVal == 0) {
|
||||||
|
PPEvaluationEnabled = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Parse second expression */
|
||||||
|
PPExprInit (&Expr2);
|
||||||
|
PPhie0 (&Expr2);
|
||||||
|
|
||||||
|
/* Skip the colon */
|
||||||
|
ConsumeColon ();
|
||||||
|
|
||||||
|
/* Disable evaluation for Expr3 if the condition is true */
|
||||||
|
if (Expr->IVal != 0) {
|
||||||
|
PPEvaluationEnabled = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Parse third expression */
|
||||||
|
PPExprInit (&Expr3);
|
||||||
|
PPhie1 (&Expr3);
|
||||||
|
|
||||||
|
/* Set the result */
|
||||||
|
Expr->IVal = Expr->IVal ? Expr2.IVal != 0 : Expr3.IVal != 0;
|
||||||
|
|
||||||
|
/* Restore evaluation as before */
|
||||||
|
PPEvaluationEnabled = PPEvaluationEnabledPrev;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static void PPhie1 (PPExpr* Expr)
|
||||||
|
/* Handle first level of expression hierarchy */
|
||||||
|
{
|
||||||
|
PPhieQuest (Expr);
|
||||||
|
|
||||||
|
if (!PPEvaluationEnabled) {
|
||||||
|
/* Skip evaluation */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (CurTok.Tok) {
|
||||||
|
|
||||||
|
case TOK_ASSIGN:
|
||||||
|
PPError ("Token \"=\" is not valid in preprocessor expressions");
|
||||||
|
PPErrorSkipLine ();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TOK_PLUS_ASSIGN:
|
||||||
|
PPError ("Token \"+=\" is not valid in preprocessor expressions");
|
||||||
|
PPErrorSkipLine ();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TOK_MINUS_ASSIGN:
|
||||||
|
PPError ("Token \"-=\" is not valid in preprocessor expressions");
|
||||||
|
PPErrorSkipLine ();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TOK_MUL_ASSIGN:
|
||||||
|
PPError ("Token \"*=\" is not valid in preprocessor expressions");
|
||||||
|
PPErrorSkipLine ();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TOK_DIV_ASSIGN:
|
||||||
|
PPError ("Token \"/=\" is not valid in preprocessor expressions");
|
||||||
|
PPErrorSkipLine ();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TOK_MOD_ASSIGN:
|
||||||
|
PPError ("Token \"%%=\" is not valid in preprocessor expressions");
|
||||||
|
PPErrorSkipLine ();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TOK_SHL_ASSIGN:
|
||||||
|
PPError ("Token \"<<=\" is not valid in preprocessor expressions");
|
||||||
|
PPErrorSkipLine ();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TOK_SHR_ASSIGN:
|
||||||
|
PPError ("Token \">>=\" is not valid in preprocessor expressions");
|
||||||
|
PPErrorSkipLine ();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TOK_AND_ASSIGN:
|
||||||
|
PPError ("Token \"&=\" is not valid in preprocessor expressions");
|
||||||
|
PPErrorSkipLine ();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TOK_OR_ASSIGN:
|
||||||
|
PPError ("Token \"|=\" is not valid in preprocessor expressions");
|
||||||
|
PPErrorSkipLine ();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TOK_XOR_ASSIGN:
|
||||||
|
PPError ("Token \"^=\" is not valid in preprocessor expressions");
|
||||||
|
PPErrorSkipLine ();
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static void PPhie0 (PPExpr* Expr)
|
||||||
|
/* Handle the comma "," operator */
|
||||||
|
{
|
||||||
|
PPhie1 (Expr);
|
||||||
|
|
||||||
|
while (CurTok.Tok == TOK_COMMA) {
|
||||||
|
/* Skip the comma */
|
||||||
|
NextToken ();
|
||||||
|
/* Reset the expression */
|
||||||
|
PPExprInit (Expr);
|
||||||
|
/* Use the next operand as the value instead */
|
||||||
|
PPhie1 (Expr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void ParsePPExprInLine (PPExpr* Expr)
|
||||||
|
/* Parse a line for PP expression */
|
||||||
|
{
|
||||||
|
/* Initialize the parser status */
|
||||||
|
PPEvaluationFailed = 0;
|
||||||
|
PPEvaluationEnabled = 1;
|
||||||
|
PPParserRunning = 1;
|
||||||
|
|
||||||
|
/* Parse */
|
||||||
|
PPExprInit (Expr);
|
||||||
|
PPhie0 (Expr);
|
||||||
|
|
||||||
|
/* If the evaluation fails, the result is always zero */
|
||||||
|
if (PPEvaluationFailed) {
|
||||||
|
Expr->IVal = 0;
|
||||||
|
PPEvaluationFailed = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Restore parser status */
|
||||||
|
PPParserRunning = 0;
|
||||||
|
}
|
76
src/cc65/ppexpr.h
Normal file
76
src/cc65/ppexpr.h
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
/*****************************************************************************/
|
||||||
|
/* */
|
||||||
|
/* ppexpr.h */
|
||||||
|
/* */
|
||||||
|
/* Expressions for C preprocessor */
|
||||||
|
/* */
|
||||||
|
/* */
|
||||||
|
/* */
|
||||||
|
/* (C) 2022 The cc65 Authors */
|
||||||
|
/* */
|
||||||
|
/* */
|
||||||
|
/* This software is provided 'as-is', without any expressed 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. */
|
||||||
|
/* */
|
||||||
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef PPEXPR_H
|
||||||
|
#define PPEXPR_H
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/* Data */
|
||||||
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* PPExpr data struct */
|
||||||
|
typedef struct PPExpr PPExpr;
|
||||||
|
struct PPExpr
|
||||||
|
{
|
||||||
|
long IVal;
|
||||||
|
unsigned Flags;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* PPExpr initializers */
|
||||||
|
#define AUTO_PPEXPR_INITIALIZER { 0, 0 }
|
||||||
|
#define STATIC_PPEXPR_INITIALIZER { 0, 0 }
|
||||||
|
|
||||||
|
/* PPExpr flags */
|
||||||
|
#define PPEXPR_NONE 0U
|
||||||
|
#define PPEXPR_UNSIGNED 1U
|
||||||
|
#define PPEXPR_UNDEFINED 2U
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/* Code */
|
||||||
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void ParsePPExprInLine (PPExpr* Expr);
|
||||||
|
/* Parse a line for PP expression */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* End of ppexpr.h */
|
||||||
|
|
||||||
|
#endif
|
1107
src/cc65/preproc.c
1107
src/cc65/preproc.c
File diff suppressed because it is too large
Load Diff
@ -39,18 +39,25 @@
|
|||||||
|
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
/* data */
|
/* Data */
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* Set when the preprocessor calls NoCodeConstExpr() recursively */
|
/* Maximum #if depth per file */
|
||||||
extern unsigned char Preprocessing;
|
#define MAX_PP_IFS 256
|
||||||
|
|
||||||
|
/* Data struct used for per-file-directive handling */
|
||||||
|
typedef struct PPIfStack PPIfStack;
|
||||||
|
struct PPIfStack {
|
||||||
|
unsigned char Stack[MAX_PP_IFS];
|
||||||
|
int Index;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
/* code */
|
/* Code */
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
@ -58,6 +65,21 @@ extern unsigned char Preprocessing;
|
|||||||
void Preprocess (void);
|
void Preprocess (void);
|
||||||
/* Preprocess a line */
|
/* Preprocess a line */
|
||||||
|
|
||||||
|
void SetPPIfStack (PPIfStack* Stack);
|
||||||
|
/* Specify which PP #if stack to use */
|
||||||
|
|
||||||
|
void PreprocessBegin (void);
|
||||||
|
/* Initialize preprocessor with current file */
|
||||||
|
|
||||||
|
void PreprocessEnd (void);
|
||||||
|
/* Preprocessor done with current file */
|
||||||
|
|
||||||
|
void InitPreprocess (void);
|
||||||
|
/* Init preprocessor */
|
||||||
|
|
||||||
|
void DonePreprocess (void);
|
||||||
|
/* Done with preprocessor */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* End of preproc.h */
|
/* End of preproc.h */
|
||||||
|
@ -75,6 +75,7 @@
|
|||||||
|
|
||||||
Token CurTok; /* The current token */
|
Token CurTok; /* The current token */
|
||||||
Token NextTok; /* The next token */
|
Token NextTok; /* The next token */
|
||||||
|
int PPParserRunning; /* Is tokenizer used by the preprocessor */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -194,10 +195,12 @@ static int SkipWhite (void)
|
|||||||
{
|
{
|
||||||
while (1) {
|
while (1) {
|
||||||
while (CurC == '\0') {
|
while (CurC == '\0') {
|
||||||
if (NextLine () == 0) {
|
/* If reading next line fails or is disabled with directives, bail
|
||||||
|
** out.
|
||||||
|
*/
|
||||||
|
if (PPParserRunning || PreprocessNextLine () == 0) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
Preprocess ();
|
|
||||||
}
|
}
|
||||||
if (IsSpace (CurC)) {
|
if (IsSpace (CurC)) {
|
||||||
NextChar ();
|
NextChar ();
|
||||||
@ -251,6 +254,45 @@ int IsSym (char* S)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int IsPPNumber (int Cur, int Next)
|
||||||
|
/* Return 1 if the two successive characters indicate a pp-number, otherwise
|
||||||
|
** return 0.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
return Cur != '.' ? IsDigit (Cur) : IsDigit (Next);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void CopyPPNumber (StrBuf* Target)
|
||||||
|
/* Copy a pp-number from the input to Target */
|
||||||
|
{
|
||||||
|
int Std;
|
||||||
|
|
||||||
|
if (!IsPPNumber (CurC, NextC)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* P-exp is only valid in C99 and later */
|
||||||
|
Std = IS_Get (&Standard);
|
||||||
|
while (IsIdent (CurC) || IsDigit (CurC) || CurC == '.') {
|
||||||
|
SB_AppendChar (Target, CurC);
|
||||||
|
if (NextC == '+' || NextC == '-') {
|
||||||
|
if (CurC == 'e' || CurC == 'E' ||
|
||||||
|
(Std >= STD_C99 && (CurC == 'p' || CurC == 'P'))) {
|
||||||
|
SB_AppendChar (Target, NextC);
|
||||||
|
NextChar ();
|
||||||
|
} else {
|
||||||
|
NextChar ();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
NextChar ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static void UnknownChar (char C)
|
static void UnknownChar (char C)
|
||||||
/* Error message for unknown character */
|
/* Error message for unknown character */
|
||||||
{
|
{
|
||||||
@ -376,6 +418,15 @@ static void CharConst (void)
|
|||||||
{
|
{
|
||||||
int C;
|
int C;
|
||||||
|
|
||||||
|
if (CurC == 'L') {
|
||||||
|
/* Wide character constant */
|
||||||
|
NextTok.Tok = TOK_WCCONST;
|
||||||
|
NextChar ();
|
||||||
|
} else {
|
||||||
|
/* Narrow character constant */
|
||||||
|
NextTok.Tok = TOK_CCONST;
|
||||||
|
}
|
||||||
|
|
||||||
/* Skip the quote */
|
/* Skip the quote */
|
||||||
NextChar ();
|
NextChar ();
|
||||||
|
|
||||||
@ -390,9 +441,6 @@ static void CharConst (void)
|
|||||||
NextChar ();
|
NextChar ();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Setup values and attributes */
|
|
||||||
NextTok.Tok = TOK_CCONST;
|
|
||||||
|
|
||||||
/* Translate into target charset */
|
/* Translate into target charset */
|
||||||
NextTok.IVal = SignExtendChar (TgtTranslateChar (C));
|
NextTok.IVal = SignExtendChar (TgtTranslateChar (C));
|
||||||
|
|
||||||
@ -463,76 +511,77 @@ static void StringConst (void)
|
|||||||
static void NumericConst (void)
|
static void NumericConst (void)
|
||||||
/* Parse a numeric constant */
|
/* Parse a numeric constant */
|
||||||
{
|
{
|
||||||
unsigned Base; /* Temporary number base */
|
unsigned Base; /* Temporary number base according to prefix */
|
||||||
unsigned Prefix; /* Base according to prefix */
|
unsigned Index;
|
||||||
StrBuf S = STATIC_STRBUF_INITIALIZER;
|
StrBuf Src = AUTO_STRBUF_INITIALIZER;
|
||||||
int IsFloat;
|
int IsFloat;
|
||||||
char C;
|
char C;
|
||||||
unsigned DigitVal;
|
unsigned DigitVal;
|
||||||
unsigned long IVal; /* Value */
|
unsigned long IVal; /* Value */
|
||||||
|
|
||||||
|
/* Get the pp-number first, then parse on it */
|
||||||
|
CopyPPNumber (&Src);
|
||||||
|
SB_Terminate (&Src);
|
||||||
|
SB_Reset (&Src);
|
||||||
|
|
||||||
/* Check for a leading hex, octal or binary prefix and determine the
|
/* Check for a leading hex, octal or binary prefix and determine the
|
||||||
** possible integer types.
|
** possible integer types.
|
||||||
*/
|
*/
|
||||||
if (CurC == '0') {
|
if (SB_Peek (&Src) == '0') {
|
||||||
/* Gobble 0 and examine next char */
|
/* Gobble 0 and examine next char */
|
||||||
NextChar ();
|
SB_Skip (&Src);
|
||||||
if (toupper (CurC) == 'X') {
|
if (toupper (SB_Peek (&Src)) == 'X' &&
|
||||||
Base = Prefix = 16;
|
IsXDigit (SB_LookAt (&Src, SB_GetIndex (&Src) + 1))) {
|
||||||
NextChar (); /* gobble "x" */
|
Base = 16;
|
||||||
} else if (toupper (CurC) == 'B' && IS_Get (&Standard) >= STD_CC65) {
|
SB_Skip (&Src); /* gobble "x" */
|
||||||
Base = Prefix = 2;
|
} else if (toupper (SB_Peek (&Src)) == 'B' &&
|
||||||
NextChar (); /* gobble 'b' */
|
IS_Get (&Standard) >= STD_CC65 &&
|
||||||
|
IsDigit (SB_LookAt (&Src, SB_GetIndex (&Src) + 1))) {
|
||||||
|
Base = 2;
|
||||||
|
SB_Skip (&Src); /* gobble 'b' */
|
||||||
} else {
|
} else {
|
||||||
Base = 10; /* Assume 10 for now - see below */
|
Base = 10; /* Assume 10 for now - see below */
|
||||||
Prefix = 8; /* Actual prefix says octal */
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Base = Prefix = 10;
|
Base = 10;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Because floating point numbers don't have octal prefixes (a number
|
/* Because floating point numbers don't have octal prefixes (a number with
|
||||||
** with a leading zero is decimal), we first have to read the number
|
** a leading zero is decimal), we first have to read the number before
|
||||||
** before converting it, so we can determine if it's a float or an
|
** converting it, so we can determine if it's a float or an integer.
|
||||||
** integer.
|
|
||||||
*/
|
*/
|
||||||
while (IsXDigit (CurC) && HexVal (CurC) < Base) {
|
Index = SB_GetIndex (&Src);
|
||||||
SB_AppendChar (&S, CurC);
|
while ((C = SB_Peek (&Src)) != '\0' && (Base <= 10 ? IsDigit (C) : IsXDigit (C))) {
|
||||||
NextChar ();
|
SB_Skip (&Src);
|
||||||
}
|
}
|
||||||
SB_Terminate (&S);
|
|
||||||
|
|
||||||
/* The following character tells us if we have an integer or floating
|
/* The following character tells us if we have an integer or floating
|
||||||
** point constant. Note: Hexadecimal floating point constants aren't
|
** point constant. Note: Hexadecimal floating point constants aren't
|
||||||
** supported in C89.
|
** supported in C89.
|
||||||
*/
|
*/
|
||||||
IsFloat = (CurC == '.' ||
|
IsFloat = (C == '.' ||
|
||||||
(Base == 10 && toupper (CurC) == 'E') ||
|
(Base == 10 && toupper (C) == 'E') ||
|
||||||
(Base == 16 && toupper (CurC) == 'P' && IS_Get (&Standard) >= STD_C99));
|
(Base == 16 && toupper (C) == 'P' && IS_Get (&Standard) >= STD_C99));
|
||||||
|
|
||||||
/* If we don't have a floating point type, an octal prefix results in an
|
/* An octal prefix for an integer type results in an octal base */
|
||||||
** octal base.
|
if (!IsFloat && Base == 10 && SB_LookAt (&Src, 0) == '0') {
|
||||||
*/
|
|
||||||
if (!IsFloat && Prefix == 8) {
|
|
||||||
Base = 8;
|
Base = 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Since we do now know the correct base, convert the remembered input
|
/* Since we now know the correct base, convert the input into a number */
|
||||||
** into a number.
|
SB_SetIndex (&Src, Index);
|
||||||
*/
|
|
||||||
SB_Reset (&S);
|
|
||||||
IVal = 0;
|
IVal = 0;
|
||||||
while ((C = SB_Get (&S)) != '\0') {
|
while ((C = SB_Peek (&Src)) != '\0' && (Base <= 10 ? IsDigit (C) : IsXDigit (C))) {
|
||||||
DigitVal = HexVal (C);
|
DigitVal = HexVal (C);
|
||||||
if (DigitVal >= Base) {
|
if (DigitVal >= Base) {
|
||||||
Error ("Numeric constant contains digits beyond the radix");
|
Error ("Invalid digit \"%c\" beyond radix %u constant", C, Base);
|
||||||
|
SB_Clear (&Src);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
IVal = (IVal * Base) + DigitVal;
|
IVal = (IVal * Base) + DigitVal;
|
||||||
|
SB_Skip (&Src);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* We don't need the string buffer any longer */
|
|
||||||
SB_Done (&S);
|
|
||||||
|
|
||||||
/* Distinguish between integer and floating point constants */
|
/* Distinguish between integer and floating point constants */
|
||||||
if (!IsFloat) {
|
if (!IsFloat) {
|
||||||
|
|
||||||
@ -543,27 +592,32 @@ static void NumericConst (void)
|
|||||||
** possible to convert the data to unsigned long even if the IT_ULONG
|
** possible to convert the data to unsigned long even if the IT_ULONG
|
||||||
** flag were not set, but we are not doing that.
|
** flag were not set, but we are not doing that.
|
||||||
*/
|
*/
|
||||||
if (toupper (CurC) == 'U') {
|
if (toupper (SB_Peek (&Src)) == 'U') {
|
||||||
/* Unsigned type */
|
/* Unsigned type */
|
||||||
NextChar ();
|
SB_Skip (&Src);
|
||||||
if (toupper (CurC) != 'L') {
|
if (toupper (SB_Peek (&Src)) != 'L') {
|
||||||
Types = IT_UINT | IT_ULONG;
|
Types = IT_UINT | IT_ULONG;
|
||||||
} else {
|
} else {
|
||||||
NextChar ();
|
SB_Skip (&Src);
|
||||||
Types = IT_ULONG;
|
Types = IT_ULONG;
|
||||||
}
|
}
|
||||||
} else if (toupper (CurC) == 'L') {
|
} else if (toupper (SB_Peek (&Src)) == 'L') {
|
||||||
/* Long type */
|
/* Long type */
|
||||||
NextChar ();
|
SB_Skip (&Src);
|
||||||
if (toupper (CurC) != 'U') {
|
if (toupper (SB_Peek (&Src)) != 'U') {
|
||||||
Types = IT_LONG | IT_ULONG;
|
Types = IT_LONG | IT_ULONG;
|
||||||
WarnTypes = IT_ULONG;
|
WarnTypes = IT_ULONG;
|
||||||
} else {
|
} else {
|
||||||
NextChar ();
|
SB_Skip (&Src);
|
||||||
Types = IT_ULONG;
|
Types = IT_ULONG;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (Prefix == 10) {
|
if (SB_Peek (&Src) != '\0') {
|
||||||
|
Error ("Invalid suffix \"%s\" on integer constant",
|
||||||
|
SB_GetConstBuf (&Src) + SB_GetIndex (&Src));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Base == 10) {
|
||||||
/* Decimal constants are of any type but uint */
|
/* Decimal constants are of any type but uint */
|
||||||
Types = IT_INT | IT_LONG | IT_ULONG;
|
Types = IT_INT | IT_LONG | IT_ULONG;
|
||||||
WarnTypes = IT_LONG | IT_ULONG;
|
WarnTypes = IT_LONG | IT_ULONG;
|
||||||
@ -629,16 +683,16 @@ static void NumericConst (void)
|
|||||||
LOG(("NumericConst start IVal:%ld FVal: %f\n", IVal, FVal.V));
|
LOG(("NumericConst start IVal:%ld FVal: %f\n", IVal, FVal.V));
|
||||||
|
|
||||||
/* Check for a fractional part and read it */
|
/* Check for a fractional part and read it */
|
||||||
if (CurC == '.') {
|
if (SB_Peek (&Src) == '.') {
|
||||||
|
|
||||||
Double Scale;
|
Double Scale;
|
||||||
|
|
||||||
/* Skip the dot */
|
/* Skip the dot */
|
||||||
NextChar ();
|
SB_Skip (&Src);
|
||||||
|
|
||||||
/* Read fractional digits */
|
/* Read fractional digits */
|
||||||
Scale = FP_D_Make (10.0);
|
Scale = FP_D_Make (10.0);
|
||||||
while (IsXDigit (CurC) && (DigitVal = HexVal (CurC)) < Base) {
|
while (IsXDigit (SB_Peek (&Src)) && (DigitVal = HexVal (SB_Peek (&Src))) < Base) {
|
||||||
/* Get the value of this digit */
|
/* Get the value of this digit */
|
||||||
Double FracVal = FP_D_FromInt(0);
|
Double FracVal = FP_D_FromInt(0);
|
||||||
if (DigitVal != 0) {
|
if (DigitVal != 0) {
|
||||||
@ -649,25 +703,25 @@ static void NumericConst (void)
|
|||||||
/* Scale base */
|
/* Scale base */
|
||||||
Scale = FP_D_Mul (Scale, FP_D_FromInt (Base));
|
Scale = FP_D_Mul (Scale, FP_D_FromInt (Base));
|
||||||
/* Skip the digit */
|
/* Skip the digit */
|
||||||
NextChar ();
|
SB_Skip (&Src);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check for an exponent and read it */
|
/* Check for an exponent and read it */
|
||||||
if ((Base == 16 && toupper (CurC) == 'F') ||
|
if ((Base == 16 && toupper (SB_Peek (&Src)) == 'P') ||
|
||||||
(Base == 10 && toupper (CurC) == 'E')) {
|
(Base == 10 && toupper (SB_Peek (&Src)) == 'E')) {
|
||||||
|
|
||||||
unsigned Digits;
|
unsigned Digits;
|
||||||
unsigned Exp;
|
unsigned Exp;
|
||||||
|
|
||||||
/* Skip the exponent notifier */
|
/* Skip the exponent notifier */
|
||||||
NextChar ();
|
SB_Skip (&Src);
|
||||||
|
|
||||||
/* Read an optional sign */
|
/* Read an optional sign */
|
||||||
if (CurC == '-') {
|
if (SB_Peek (&Src) == '-') {
|
||||||
NextChar ();
|
SB_Skip (&Src);
|
||||||
} else if (CurC == '+') {
|
} else if (SB_Peek (&Src) == '+') {
|
||||||
NextChar ();
|
SB_Skip (&Src);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Read exponent digits. Since we support only 32 bit floats
|
/* Read exponent digits. Since we support only 32 bit floats
|
||||||
@ -678,11 +732,11 @@ static void NumericConst (void)
|
|||||||
*/
|
*/
|
||||||
Digits = 0;
|
Digits = 0;
|
||||||
Exp = 0;
|
Exp = 0;
|
||||||
while (IsDigit (CurC)) {
|
while (IsDigit (SB_Peek (&Src))) {
|
||||||
if (++Digits <= 3) {
|
if (++Digits <= 3) {
|
||||||
Exp = Exp * 10 + HexVal (CurC);
|
Exp = Exp * 10 + HexVal (SB_Peek (&Src));
|
||||||
}
|
}
|
||||||
NextChar ();
|
SB_Skip (&Src);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check for errors: We must have exponent digits, and not more
|
/* Check for errors: We must have exponent digits, and not more
|
||||||
@ -703,10 +757,14 @@ static void NumericConst (void)
|
|||||||
LOG(("NumericConst end FVal: %f\n", FVal.V));
|
LOG(("NumericConst end FVal: %f\n", FVal.V));
|
||||||
|
|
||||||
/* Check for a suffix and determine the type of the constant */
|
/* Check for a suffix and determine the type of the constant */
|
||||||
if (toupper (CurC) == 'F') {
|
if (toupper (SB_Peek (&Src)) == 'F') {
|
||||||
NextChar ();
|
SB_Skip (&Src);
|
||||||
NextTok.Type = type_float;
|
NextTok.Type = type_float;
|
||||||
} else {
|
} else {
|
||||||
|
if (SB_Peek (&Src) != '\0') {
|
||||||
|
Error ("Invalid suffix \"%s\" on floating constant",
|
||||||
|
SB_GetConstBuf (&Src) + SB_GetIndex (&Src));
|
||||||
|
}
|
||||||
NextTok.Type = type_double;
|
NextTok.Type = type_double;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -716,6 +774,8 @@ static void NumericConst (void)
|
|||||||
|
|
||||||
}
|
}
|
||||||
LOG(("NumericConst exit IsFloat:%d IVal: %ld FVal: %f\n", IsFloat, NextTok.IVal, NextTok.FVal.V));
|
LOG(("NumericConst exit IsFloat:%d IVal: %ld FVal: %f\n", IsFloat, NextTok.IVal, NextTok.FVal.V));
|
||||||
|
/* We don't need the string buffer any longer */
|
||||||
|
SB_Done (&Src);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -757,26 +817,34 @@ void NextToken (void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Determine the next token from the lookahead */
|
/* Determine the next token from the lookahead */
|
||||||
if (IsDigit (CurC) || (CurC == '.' && IsDigit (NextC))) {
|
if (IsPPNumber (CurC, NextC)) {
|
||||||
/* A number */
|
/* A number */
|
||||||
NumericConst ();
|
NumericConst ();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check for wide character literals */
|
/* Check for wide character constants and literals */
|
||||||
if (CurC == 'L' && NextC == '\"') {
|
if (CurC == 'L') {
|
||||||
StringConst ();
|
if (NextC == '\"') {
|
||||||
return;
|
StringConst ();
|
||||||
|
return;
|
||||||
|
} else if (NextC == '\'') {
|
||||||
|
CharConst ();
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check for keywords and identifiers */
|
/* Check for keywords and identifiers */
|
||||||
if (IsSym (token)) {
|
if (IsSym (token)) {
|
||||||
|
|
||||||
/* Check for a keyword */
|
if (!PPParserRunning) {
|
||||||
if ((NextTok.Tok = FindKey (token)) != TOK_IDENT) {
|
/* Check for a keyword */
|
||||||
/* Reserved word found */
|
if ((NextTok.Tok = FindKey (token)) != TOK_IDENT) {
|
||||||
return;
|
/* Reserved word found */
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* No reserved word, check for special symbols */
|
/* No reserved word, check for special symbols */
|
||||||
if (token[0] == '_' && token[1] == '_') {
|
if (token[0] == '_' && token[1] == '_') {
|
||||||
/* Special symbols */
|
/* Special symbols */
|
||||||
@ -1025,6 +1093,15 @@ void NextToken (void)
|
|||||||
SetTok (TOK_COMP);
|
SetTok (TOK_COMP);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case '#':
|
||||||
|
NextChar ();
|
||||||
|
if (CurC == '#') {
|
||||||
|
SetTok (TOK_DOUBLE_HASH);
|
||||||
|
} else {
|
||||||
|
NextTok.Tok = TOK_HASH;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
UnknownChar (CurC);
|
UnknownChar (CurC);
|
||||||
|
|
||||||
|
@ -79,6 +79,10 @@ typedef enum token_t {
|
|||||||
TOK_FASTCALL,
|
TOK_FASTCALL,
|
||||||
TOK_CDECL,
|
TOK_CDECL,
|
||||||
|
|
||||||
|
/* Address sizes */
|
||||||
|
TOK_FAR,
|
||||||
|
TOK_NEAR,
|
||||||
|
|
||||||
/* Tokens denoting types */
|
/* Tokens denoting types */
|
||||||
TOK_FIRST_TYPE,
|
TOK_FIRST_TYPE,
|
||||||
TOK_ENUM = TOK_FIRST_TYPE,
|
TOK_ENUM = TOK_FIRST_TYPE,
|
||||||
@ -95,94 +99,101 @@ typedef enum token_t {
|
|||||||
TOK_VOID,
|
TOK_VOID,
|
||||||
TOK_LAST_TYPE = TOK_VOID,
|
TOK_LAST_TYPE = TOK_VOID,
|
||||||
|
|
||||||
/* Control statements */
|
/* Selection statements */
|
||||||
|
TOK_IF,
|
||||||
|
TOK_ELSE,
|
||||||
|
TOK_SWITCH,
|
||||||
|
|
||||||
|
/* Iteration statements */
|
||||||
|
TOK_WHILE,
|
||||||
TOK_DO,
|
TOK_DO,
|
||||||
TOK_FOR,
|
TOK_FOR,
|
||||||
TOK_GOTO,
|
|
||||||
TOK_IF,
|
|
||||||
TOK_RETURN,
|
|
||||||
TOK_SWITCH,
|
|
||||||
TOK_WHILE,
|
|
||||||
|
|
||||||
TOK_ASM,
|
/* Jump statements */
|
||||||
|
TOK_GOTO,
|
||||||
|
TOK_CONTINUE,
|
||||||
|
TOK_BREAK,
|
||||||
|
TOK_RETURN,
|
||||||
|
|
||||||
|
/* Labels */
|
||||||
TOK_CASE,
|
TOK_CASE,
|
||||||
TOK_DEFAULT,
|
TOK_DEFAULT,
|
||||||
TOK_BREAK,
|
|
||||||
TOK_CONTINUE,
|
/* Misc. */
|
||||||
TOK_ELSE,
|
TOK_ATTRIBUTE,
|
||||||
TOK_ELLIPSIS,
|
TOK_PRAGMA,
|
||||||
|
TOK_STATIC_ASSERT,
|
||||||
|
TOK_ASM,
|
||||||
TOK_SIZEOF,
|
TOK_SIZEOF,
|
||||||
|
|
||||||
TOK_IDENT,
|
/* Punctuators */
|
||||||
TOK_SEMI,
|
TOK_FIRST_PUNC,
|
||||||
|
TOK_LBRACK = TOK_FIRST_PUNC,
|
||||||
/* Primary operators */
|
TOK_RBRACK,
|
||||||
TOK_LBRACK,
|
|
||||||
TOK_LPAREN,
|
TOK_LPAREN,
|
||||||
|
TOK_RPAREN,
|
||||||
|
TOK_LCURLY,
|
||||||
|
TOK_RCURLY,
|
||||||
TOK_DOT,
|
TOK_DOT,
|
||||||
TOK_PTR_REF,
|
TOK_PTR_REF,
|
||||||
|
|
||||||
TOK_LCURLY,
|
|
||||||
TOK_RBRACK,
|
|
||||||
TOK_COMP,
|
|
||||||
TOK_INC,
|
TOK_INC,
|
||||||
TOK_PLUS_ASSIGN,
|
|
||||||
TOK_PLUS,
|
|
||||||
TOK_COMMA,
|
|
||||||
TOK_DEC,
|
TOK_DEC,
|
||||||
TOK_MINUS_ASSIGN,
|
TOK_ADDR,
|
||||||
TOK_RCURLY,
|
TOK_AND = TOK_ADDR, /* Alias */
|
||||||
TOK_MINUS,
|
|
||||||
TOK_MUL_ASSIGN,
|
|
||||||
TOK_STAR,
|
TOK_STAR,
|
||||||
TOK_MUL = TOK_STAR, /* Alias */
|
TOK_MUL = TOK_STAR, /* Alias */
|
||||||
TOK_DIV_ASSIGN,
|
TOK_PLUS,
|
||||||
TOK_DIV,
|
TOK_MINUS,
|
||||||
TOK_BOOL_AND,
|
TOK_COMP,
|
||||||
TOK_AND_ASSIGN,
|
|
||||||
TOK_AND,
|
|
||||||
TOK_NE,
|
|
||||||
TOK_BOOL_NOT,
|
TOK_BOOL_NOT,
|
||||||
TOK_BOOL_OR,
|
TOK_DIV,
|
||||||
TOK_OR_ASSIGN,
|
|
||||||
TOK_OR,
|
|
||||||
TOK_EQ,
|
|
||||||
TOK_ASSIGN,
|
|
||||||
|
|
||||||
/* Inequalities */
|
|
||||||
TOK_LE,
|
|
||||||
TOK_LT,
|
|
||||||
TOK_GE,
|
|
||||||
TOK_GT,
|
|
||||||
|
|
||||||
TOK_SHL_ASSIGN,
|
|
||||||
TOK_SHL,
|
|
||||||
TOK_SHR_ASSIGN,
|
|
||||||
TOK_SHR,
|
|
||||||
TOK_XOR_ASSIGN,
|
|
||||||
TOK_XOR,
|
|
||||||
TOK_MOD_ASSIGN,
|
|
||||||
TOK_MOD,
|
TOK_MOD,
|
||||||
|
TOK_SHL,
|
||||||
|
TOK_SHR,
|
||||||
|
TOK_LT,
|
||||||
|
TOK_GT,
|
||||||
|
TOK_LE,
|
||||||
|
TOK_GE,
|
||||||
|
TOK_EQ,
|
||||||
|
TOK_NE,
|
||||||
|
TOK_XOR,
|
||||||
|
TOK_OR,
|
||||||
|
TOK_BOOL_AND,
|
||||||
|
TOK_BOOL_OR,
|
||||||
TOK_QUEST,
|
TOK_QUEST,
|
||||||
TOK_COLON,
|
TOK_COLON,
|
||||||
TOK_RPAREN,
|
TOK_SEMI,
|
||||||
TOK_SCONST,
|
TOK_ELLIPSIS,
|
||||||
|
TOK_ASSIGN,
|
||||||
|
TOK_MUL_ASSIGN,
|
||||||
|
TOK_DIV_ASSIGN,
|
||||||
|
TOK_MOD_ASSIGN,
|
||||||
|
TOK_PLUS_ASSIGN,
|
||||||
|
TOK_MINUS_ASSIGN,
|
||||||
|
TOK_SHL_ASSIGN,
|
||||||
|
TOK_SHR_ASSIGN,
|
||||||
|
TOK_AND_ASSIGN,
|
||||||
|
TOK_XOR_ASSIGN,
|
||||||
|
TOK_OR_ASSIGN,
|
||||||
|
TOK_COMMA,
|
||||||
|
TOK_HASH,
|
||||||
|
TOK_HASH_HASH,
|
||||||
|
TOK_DOUBLE_HASH = TOK_HASH_HASH, /* Alias */
|
||||||
|
TOK_LAST_PUNC = TOK_DOUBLE_HASH,
|
||||||
|
|
||||||
|
/* Primary expressions */
|
||||||
TOK_ICONST,
|
TOK_ICONST,
|
||||||
TOK_CCONST,
|
TOK_CCONST,
|
||||||
|
TOK_WCCONST,
|
||||||
TOK_FCONST,
|
TOK_FCONST,
|
||||||
|
TOK_SCONST,
|
||||||
TOK_WCSCONST,
|
TOK_WCSCONST,
|
||||||
|
TOK_IDENT,
|
||||||
TOK_ATTRIBUTE,
|
|
||||||
TOK_STATIC_ASSERT,
|
|
||||||
TOK_FAR,
|
|
||||||
TOK_NEAR,
|
|
||||||
TOK_A,
|
TOK_A,
|
||||||
TOK_X,
|
TOK_X,
|
||||||
TOK_Y,
|
TOK_Y,
|
||||||
TOK_AX,
|
TOK_AX,
|
||||||
TOK_EAX,
|
TOK_EAX
|
||||||
|
|
||||||
TOK_PRAGMA
|
|
||||||
} token_t;
|
} token_t;
|
||||||
|
|
||||||
|
|
||||||
@ -210,6 +221,7 @@ struct Token {
|
|||||||
|
|
||||||
extern Token CurTok; /* The current token */
|
extern Token CurTok; /* The current token */
|
||||||
extern Token NextTok; /* The next token */
|
extern Token NextTok; /* The next token */
|
||||||
|
extern int PPParserRunning; /* Is tokenizer used by the preprocessor */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -219,6 +231,17 @@ extern Token NextTok; /* The next token */
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(HAVE_INLINE)
|
||||||
|
INLINE int TokIsPunc (const Token* T)
|
||||||
|
/* Return true if the token is a punctuator */
|
||||||
|
{
|
||||||
|
return (T->Tok >= TOK_FIRST_PUNC && T->Tok <= TOK_LAST_PUNC);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
# define TokIsPunc(T) \
|
||||||
|
((T)->Tok >= TOK_FIRST_PUNC && (T)->Tok <= TOK_LAST_PUNC)
|
||||||
|
#endif
|
||||||
|
|
||||||
#if defined(HAVE_INLINE)
|
#if defined(HAVE_INLINE)
|
||||||
INLINE int TokIsStorageClass (const Token* T)
|
INLINE int TokIsStorageClass (const Token* T)
|
||||||
/* Return true if the token is a storage class specifier */
|
/* Return true if the token is a storage class specifier */
|
||||||
@ -262,6 +285,14 @@ void SymName (char* S);
|
|||||||
int IsSym (char* S);
|
int IsSym (char* S);
|
||||||
/* If a symbol follows, read it and return 1, otherwise return 0 */
|
/* If a symbol follows, read it and return 1, otherwise return 0 */
|
||||||
|
|
||||||
|
int IsPPNumber (int Cur, int Next);
|
||||||
|
/* Return 1 if the two successive characters indicate a pp-number, otherwise
|
||||||
|
** return 0.
|
||||||
|
*/
|
||||||
|
|
||||||
|
void CopyPPNumber (StrBuf* Target);
|
||||||
|
/* Copy a pp-number from the input to Target */
|
||||||
|
|
||||||
void NextToken (void);
|
void NextToken (void);
|
||||||
/* Get next token from input stream */
|
/* Get next token from input stream */
|
||||||
|
|
||||||
|
@ -808,6 +808,11 @@ testcode.d64: testcode
|
|||||||
$(foreach file,$(EXELIST_$(SYS)),$(D64_WRITE_PRG_recipe))
|
$(foreach file,$(EXELIST_$(SYS)),$(D64_WRITE_PRG_recipe))
|
||||||
# $(foreach file,$(EMD) $(MOU) $(TGI),$(D64_WRITE_SEQ_recipe))
|
# $(foreach file,$(EMD) $(MOU) $(TGI),$(D64_WRITE_SEQ_recipe))
|
||||||
|
|
||||||
|
testcode.d81: testcode
|
||||||
|
@$(C1541) -format testcode,AA d81 $@ >$(NULLDEV)
|
||||||
|
$(foreach file,$(EXELIST_$(SYS)),$(D64_WRITE_PRG_recipe))
|
||||||
|
$(foreach file,$(EMD) $(MOU) $(TGI),$(D64_WRITE_SEQ_recipe))
|
||||||
|
|
||||||
# --------------------------------------------------------------------------
|
# --------------------------------------------------------------------------
|
||||||
# Rule to make an Apple II disk with all testcode. Needs the AppleCommander
|
# Rule to make an Apple II disk with all testcode. Needs the AppleCommander
|
||||||
# program, available at https://applecommander.github.io/, and a template disk
|
# program, available at https://applecommander.github.io/, and a template disk
|
||||||
|
@ -2,6 +2,10 @@
|
|||||||
# var. to build for another target system.
|
# var. to build for another target system.
|
||||||
SYS ?= c64
|
SYS ?= c64
|
||||||
|
|
||||||
|
# This one comes with the VICE emulator.
|
||||||
|
# See http://vice-emu.sourceforge.net/
|
||||||
|
C1541 ?= c1541
|
||||||
|
|
||||||
# Just the usual way to find out if we're
|
# Just the usual way to find out if we're
|
||||||
# using cmd.exe to execute make rules.
|
# using cmd.exe to execute make rules.
|
||||||
ifneq ($(shell echo),)
|
ifneq ($(shell echo),)
|
||||||
@ -32,11 +36,20 @@ endif
|
|||||||
|
|
||||||
EXELIST_c64 = \
|
EXELIST_c64 = \
|
||||||
petscii.prg \
|
petscii.prg \
|
||||||
cbmdir-test.prg
|
cbmdir-test.prg \
|
||||||
|
cbmread.prg
|
||||||
|
|
||||||
|
EXTRALIST_c64 = \
|
||||||
|
read-0 \
|
||||||
|
read-1 \
|
||||||
|
read-8
|
||||||
|
|
||||||
EXELIST_vic20 = \
|
EXELIST_vic20 = \
|
||||||
cbmdir-test.prg
|
cbmdir-test.prg
|
||||||
|
|
||||||
|
DISK_c64 = testcode.d64
|
||||||
|
DISK_vic20 = testcode.d64
|
||||||
|
|
||||||
ifneq ($(EXELIST_$(SYS)),)
|
ifneq ($(EXELIST_$(SYS)),)
|
||||||
testcode: $(EXELIST_$(SYS))
|
testcode: $(EXELIST_$(SYS))
|
||||||
else
|
else
|
||||||
@ -66,5 +79,38 @@ else
|
|||||||
$(CL) -t $(SYS) -Oris -o $@ $<
|
$(CL) -t $(SYS) -Oris -o $@ $<
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
cbmread.prg: cbmread.c
|
||||||
|
ifeq ($(SYS),vic20)
|
||||||
|
$(CL) -t $(SYS) -C vic20-32k.cfg -Oris -o $@ $<
|
||||||
|
else
|
||||||
|
$(CL) -t $(SYS) -Oris -o $@ $<
|
||||||
|
endif
|
||||||
|
|
||||||
|
# --------------------------------------------------------------------------
|
||||||
|
# Rule to make a CBM disk with all testcode. Needs the c1541 program that comes
|
||||||
|
# with the VICE emulator.
|
||||||
|
|
||||||
|
define D64_WRITE_PRG_recipe
|
||||||
|
|
||||||
|
$(C1541) -attach $@ -write "$(subst ?,$(SPACE),$(file))" "$(subst ?,$(SPACE),$(subst .prg,,$(notdir $(file))))",p >$(NULLDEV)
|
||||||
|
|
||||||
|
endef # D64_WRITE_PRG_recipe
|
||||||
|
|
||||||
|
define D64_WRITE_SEQ_recipe
|
||||||
|
|
||||||
|
$(C1541) -attach $@ -write "$(subst ?,$(SPACE),$(file))" $(notdir $(file)),s >$(NULLDEV)
|
||||||
|
|
||||||
|
endef # D64_WRITE_SEQ_recipe
|
||||||
|
|
||||||
|
disk: $(DISK_$(SYS))
|
||||||
|
|
||||||
|
testcode.d64: testcode
|
||||||
|
@$(C1541) -format "testcode,00" d64 $@ >$(NULLDEV)
|
||||||
|
$(foreach file,$(EXELIST_$(SYS)),$(D64_WRITE_PRG_recipe))
|
||||||
|
$(foreach file,$(EXTRALIST_$(SYS)),$(D64_WRITE_SEQ_recipe))
|
||||||
|
# $(foreach file,$(EMD) $(MOU) $(TGI),$(D64_WRITE_SEQ_recipe))
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
@$(DEL) *.lbl petscii.prg cbmdir-test.prg 2>$(NULLDEV)
|
@$(DEL) *.lbl petscii.prg cbmdir-test.prg 2>$(NULLDEV)
|
||||||
|
@$(DEL) $(DISK_c64)
|
||||||
|
@$(DEL) $(DISK_vic20)
|
||||||
|
82
targettest/cbm/cbmread.c
Normal file
82
targettest/cbm/cbmread.c
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
#include <cbm.h>
|
||||||
|
|
||||||
|
int res = 0;
|
||||||
|
int tests = 0;
|
||||||
|
|
||||||
|
#define LFN 8
|
||||||
|
|
||||||
|
#define MAXREADSIZE 256
|
||||||
|
|
||||||
|
static char data[MAXREADSIZE];
|
||||||
|
|
||||||
|
void test1 (char * what, char * filename, int len1, int len2, int rlen1, int rlen2)
|
||||||
|
{
|
||||||
|
int rlen;
|
||||||
|
unsigned char err;
|
||||||
|
|
||||||
|
printf ("1:%s (%d bytes)..." , what, rlen1);
|
||||||
|
|
||||||
|
err = cbm_open (LFN, 8, 8, filename);
|
||||||
|
if (err != 0) {
|
||||||
|
printf ("\nError: could not open file.\n");
|
||||||
|
goto test1exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
rlen = cbm_read (LFN, data, rlen1);
|
||||||
|
if (rlen == -1) {
|
||||||
|
printf ("\ncbm_read error (%d)\n", _oserror);
|
||||||
|
res++;
|
||||||
|
goto test1exit;
|
||||||
|
}
|
||||||
|
if (rlen != len1) {
|
||||||
|
printf ("\nError: 1st read returned %d instead of %d\n", rlen, len1);
|
||||||
|
res++;
|
||||||
|
goto test1exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf (" OK\n");
|
||||||
|
|
||||||
|
printf ("2:%s (%d bytes)..." , what, rlen2);
|
||||||
|
|
||||||
|
rlen = cbm_read (LFN, data, rlen2);
|
||||||
|
if (rlen == -1) {
|
||||||
|
printf ("\ncbm_read error (%d)\n", _oserror);
|
||||||
|
res++;
|
||||||
|
goto test1exit;
|
||||||
|
}
|
||||||
|
if (rlen != len2) {
|
||||||
|
printf ("\nError: 2nd read returned %d instead of %d\n", rlen, len2);
|
||||||
|
res++;
|
||||||
|
goto test1exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf (" OK\n");
|
||||||
|
|
||||||
|
test1exit:
|
||||||
|
cbm_close (LFN);
|
||||||
|
tests++;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
test1 ("Read empty file", "read-0", 0, 0, 0, 0);
|
||||||
|
test1 ("Read empty file", "read-0", 0, 0, 1, 1);
|
||||||
|
test1 ("Read empty file", "read-0", 0, 0, 8, 8);
|
||||||
|
|
||||||
|
test1 ("Read 1 byte file", "read-1", 0, 0, 0, 0);
|
||||||
|
test1 ("Read 1 byte file", "read-1", 1, 0, 1, 1);
|
||||||
|
test1 ("Read 1 byte file", "read-1", 1, 0, 8, 8);
|
||||||
|
|
||||||
|
test1 ("Read 8 byte file", "read-8", 0, 0, 0, 0);
|
||||||
|
test1 ("Read 8 byte file", "read-8", 1, 1, 1, 1);
|
||||||
|
test1 ("Read 8 byte file", "read-8", 4, 4, 4, 4);
|
||||||
|
test1 ("Read 8 byte file", "read-8", 8, 0, 8, 8);
|
||||||
|
test1 ("Read 8 byte file", "read-8", 8, 0,10, 1);
|
||||||
|
|
||||||
|
printf ("%d/%d Tests failed.\n", res, tests);
|
||||||
|
return res;
|
||||||
|
}
|
0
targettest/cbm/read-0
Normal file
0
targettest/cbm/read-0
Normal file
1
targettest/cbm/read-1
Normal file
1
targettest/cbm/read-1
Normal file
@ -0,0 +1 @@
|
|||||||
|
B
|
1
targettest/cbm/read-8
Normal file
1
targettest/cbm/read-8
Normal file
@ -0,0 +1 @@
|
|||||||
|
GЊЛЬн
|
@ -96,6 +96,7 @@ static emd_test_t drivers[] = {
|
|||||||
{ '8', "C64DTV himem", "dtv-himem.emd" },
|
{ '8', "C64DTV himem", "dtv-himem.emd" },
|
||||||
{ '9', "65816 extra banks", "c64-65816.emd" },
|
{ '9', "65816 extra banks", "c64-65816.emd" },
|
||||||
{ 'k', "Kerberos", "c64-kerberos.emd" },
|
{ 'k', "Kerberos", "c64-kerberos.emd" },
|
||||||
|
{ 'r', "Retro Replay RAM", "c64-rrr.emd" },
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(__C128__)
|
#if defined(__C128__)
|
||||||
|
16
test/asm/listing/001-macro-simple-listing.s
Normal file
16
test/asm/listing/001-macro-simple-listing.s
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
; 2022-01-17 Spiro Trikaliotis
|
||||||
|
|
||||||
|
.macro TESTER
|
||||||
|
lda #2
|
||||||
|
.endmacro
|
||||||
|
|
||||||
|
test:
|
||||||
|
ldx #0
|
||||||
|
TESTER
|
||||||
|
ldx #15
|
||||||
|
TESTER
|
||||||
|
inx
|
||||||
|
TESTER
|
||||||
|
TESTER
|
||||||
|
dex
|
||||||
|
rts
|
16
test/asm/listing/002-macro-param-listing.s
Normal file
16
test/asm/listing/002-macro-param-listing.s
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
; 2022-01-17 Spiro Trikaliotis
|
||||||
|
|
||||||
|
.macro TESTER val
|
||||||
|
lda #val
|
||||||
|
.endmacro
|
||||||
|
|
||||||
|
test:
|
||||||
|
ldx #0
|
||||||
|
TESTER 1
|
||||||
|
ldx #15
|
||||||
|
TESTER 2
|
||||||
|
inx
|
||||||
|
TESTER 3
|
||||||
|
TESTER 4
|
||||||
|
dex
|
||||||
|
rts
|
14
test/asm/listing/020-asciiz.s
Normal file
14
test/asm/listing/020-asciiz.s
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
; 2022-06-15 Spiro Trikaliotis
|
||||||
|
|
||||||
|
|
||||||
|
; upper case pseudo-op
|
||||||
|
.ASCIIZ ""
|
||||||
|
.ASCIIZ "Hello World"
|
||||||
|
.ASCIIZ "Hello ","World"
|
||||||
|
.ASCIIZ "Hello ","World"," ","I"," ","am"," ","testing"
|
||||||
|
|
||||||
|
; lower case pseudo-op
|
||||||
|
.asciiz ""
|
||||||
|
.asciiz "Hello World"
|
||||||
|
.asciiz "Hello ","World"
|
||||||
|
.asciiz "Hello ","World"," ","I"," ","am"," ","testing"
|
81
test/asm/listing/030-assert-success.s
Normal file
81
test/asm/listing/030-assert-success.s
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
; 2022-06-15 Spiro Trikaliotis
|
||||||
|
|
||||||
|
.ASSERT * = $0000, warning, "Code not at $0000"
|
||||||
|
.assert * = $0000, warning, "Code not at $0000"
|
||||||
|
|
||||||
|
.ASSERT * = $0001, warning, "Code not at $0001"
|
||||||
|
.assert * = $0001, warning, "Code not at $0001"
|
||||||
|
|
||||||
|
.ASSERT * = $1000, warning, "Code not at $1000"
|
||||||
|
.assert * = $1000, warning, "Code not at $1000"
|
||||||
|
|
||||||
|
.ASSERT * = $1001, warning, "Code not at $1001"
|
||||||
|
.assert * = $1001, warning, "Code not at $1001"
|
||||||
|
|
||||||
|
.ASSERT * = $8000, warning, "Code not at $8000"
|
||||||
|
.assert * = $8000, warning, "Code not at $8000"
|
||||||
|
|
||||||
|
.ASSERT * = $8001, warning, "Code not at $8001"
|
||||||
|
.assert * = $8001, warning, "Code not at $8001"
|
||||||
|
|
||||||
|
nop
|
||||||
|
|
||||||
|
.ASSERT * = $0000, warning, "Code not at $0000"
|
||||||
|
.assert * = $0000, warning, "Code not at $0000"
|
||||||
|
|
||||||
|
.ASSERT * = $0001, warning, "Code not at $0001"
|
||||||
|
.assert * = $0001, warning, "Code not at $0001"
|
||||||
|
|
||||||
|
.ASSERT * = $1000, warning, "Code not at $1000"
|
||||||
|
.assert * = $1000, warning, "Code not at $1000"
|
||||||
|
|
||||||
|
.ASSERT * = $1001, warning, "Code not at $1001"
|
||||||
|
.assert * = $1001, warning, "Code not at $1001"
|
||||||
|
|
||||||
|
.ASSERT * = $8000, warning, "Code not at $8000"
|
||||||
|
.assert * = $8000, warning, "Code not at $8000"
|
||||||
|
|
||||||
|
.ASSERT * = $8001, warning, "Code not at $8001"
|
||||||
|
.assert * = $8001, warning, "Code not at $8001"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.org $8000
|
||||||
|
|
||||||
|
.ASSERT * = $0000, warning, "Code not at $0000"
|
||||||
|
.assert * = $0000, warning, "Code not at $0000"
|
||||||
|
|
||||||
|
.ASSERT * = $0001, warning, "Code not at $0001"
|
||||||
|
.assert * = $0001, warning, "Code not at $0001"
|
||||||
|
|
||||||
|
.ASSERT * = $1000, warning, "Code not at $1000"
|
||||||
|
.assert * = $1000, warning, "Code not at $1000"
|
||||||
|
|
||||||
|
.ASSERT * = $1001, warning, "Code not at $1001"
|
||||||
|
.assert * = $1001, warning, "Code not at $1001"
|
||||||
|
|
||||||
|
.ASSERT * = $8000, warning, "Code not at $8000"
|
||||||
|
.assert * = $8000, warning, "Code not at $8000"
|
||||||
|
|
||||||
|
.ASSERT * = $8001, warning, "Code not at $8001"
|
||||||
|
.assert * = $8001, warning, "Code not at $8001"
|
||||||
|
|
||||||
|
nop
|
||||||
|
|
||||||
|
.ASSERT * = $0000, warning, "Code not at $0000"
|
||||||
|
.assert * = $0000, warning, "Code not at $0000"
|
||||||
|
|
||||||
|
.ASSERT * = $0001, warning, "Code not at $0001"
|
||||||
|
.assert * = $0001, warning, "Code not at $0001"
|
||||||
|
|
||||||
|
.ASSERT * = $1000, warning, "Code not at $1000"
|
||||||
|
.assert * = $1000, warning, "Code not at $1000"
|
||||||
|
|
||||||
|
.ASSERT * = $1001, warning, "Code not at $1001"
|
||||||
|
.assert * = $1001, warning, "Code not at $1001"
|
||||||
|
|
||||||
|
.ASSERT * = $8000, warning, "Code not at $8000"
|
||||||
|
.assert * = $8000, warning, "Code not at $8000"
|
||||||
|
|
||||||
|
.ASSERT * = $8001, warning, "Code not at $8001"
|
||||||
|
.assert * = $8001, warning, "Code not at $8001"
|
28
test/asm/listing/031-assert-error.s
Normal file
28
test/asm/listing/031-assert-error.s
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
; 2022-06-15 Spiro Trikaliotis
|
||||||
|
|
||||||
|
.ASSERT * = $0000, error, "Code not at $0000"
|
||||||
|
.assert * = $0000, error, "Code not at $0000"
|
||||||
|
|
||||||
|
.ASSERT * = $0001, error, "Code not at $0001"
|
||||||
|
.assert * = $0001, error, "Code not at $0001"
|
||||||
|
|
||||||
|
.ASSERT * = $1000, error, "Code not at $1000"
|
||||||
|
.assert * = $1000, error, "Code not at $1000"
|
||||||
|
|
||||||
|
.ASSERT * = $1001, error, "Code not at $1001"
|
||||||
|
.assert * = $1001, error, "Code not at $1001"
|
||||||
|
|
||||||
|
.ASSERT * = $8000, error, "Code not at $8000"
|
||||||
|
.assert * = $8000, error, "Code not at $8000"
|
||||||
|
|
||||||
|
.ASSERT * = $8001, error, "Code not at $8001"
|
||||||
|
.assert * = $8001, error, "Code not at $8001"
|
||||||
|
|
||||||
|
|
||||||
|
.org $8000
|
||||||
|
|
||||||
|
.ASSERT * = $8000, error, "Code not at $8000"
|
||||||
|
.assert * = $8000, error, "Code not at $8000"
|
||||||
|
|
||||||
|
.ASSERT * = $8001, error, "Code not at $8001"
|
||||||
|
.assert * = $8001, error, "Code not at $8001"
|
8
test/asm/listing/032-assert-error2.s
Normal file
8
test/asm/listing/032-assert-error2.s
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
; 2022-06-18 Spiro Trikaliotis
|
||||||
|
|
||||||
|
.ASSERT * = $0000, error, "Code not at $0000"
|
||||||
|
.ASSERT * = $0001, error, "Code not at $0001"
|
||||||
|
.ASSERT * = $1000, error, "Code not at $1000"
|
||||||
|
.ASSERT * = $1001, error, "Code not at $1001"
|
||||||
|
.ASSERT * = $8000, error, "Code not at $8000"
|
||||||
|
.ASSERT * = $8001, error, "Code not at $8001"
|
3
test/asm/listing/032-assert-error3.s
Normal file
3
test/asm/listing/032-assert-error3.s
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
; 2022-06-20 Spiro Trikaliotis
|
||||||
|
|
||||||
|
.assert * = $0000, error, "Code not at $0000"
|
3
test/asm/listing/032-assert-error4.s
Normal file
3
test/asm/listing/032-assert-error4.s
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
; 2022-06-20 Spiro Trikaliotis
|
||||||
|
|
||||||
|
.assert * = $0001, error, "Code not at $0001"
|
3
test/asm/listing/032-assert-error5.s
Normal file
3
test/asm/listing/032-assert-error5.s
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
; 2022-06-20 Spiro Trikaliotis
|
||||||
|
|
||||||
|
.assert * = $1000, error, "Code not at $1000"
|
3
test/asm/listing/032-assert-error6.s
Normal file
3
test/asm/listing/032-assert-error6.s
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
; 2022-06-20 Spiro Trikaliotis
|
||||||
|
|
||||||
|
.assert * = $1001, error, "Code not at $1001"
|
3
test/asm/listing/032-assert-error7.s
Normal file
3
test/asm/listing/032-assert-error7.s
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
; 2022-06-20 Spiro Trikaliotis
|
||||||
|
|
||||||
|
.assert * = $8000, error, "Code not at $8000"
|
3
test/asm/listing/032-assert-error8.s
Normal file
3
test/asm/listing/032-assert-error8.s
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
; 2022-06-20 Spiro Trikaliotis
|
||||||
|
|
||||||
|
.assert * = $8001, error, "Code not at $8001"
|
81
test/asm/listing/033-assert-ldwarning-success.s
Normal file
81
test/asm/listing/033-assert-ldwarning-success.s
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
; 2022-06-15 Spiro Trikaliotis
|
||||||
|
|
||||||
|
.ASSERT * = $0000, ldwarning, "Code not at $0000"
|
||||||
|
.assert * = $0000, ldwarning, "Code not at $0000"
|
||||||
|
|
||||||
|
.ASSERT * = $0001, ldwarning, "Code not at $0001"
|
||||||
|
.assert * = $0001, ldwarning, "Code not at $0001"
|
||||||
|
|
||||||
|
.ASSERT * = $1000, ldwarning, "Code not at $1000"
|
||||||
|
.assert * = $1000, ldwarning, "Code not at $1000"
|
||||||
|
|
||||||
|
.ASSERT * = $1001, ldwarning, "Code not at $1001"
|
||||||
|
.assert * = $1001, ldwarning, "Code not at $1001"
|
||||||
|
|
||||||
|
.ASSERT * = $8000, ldwarning, "Code not at $8000"
|
||||||
|
.assert * = $8000, ldwarning, "Code not at $8000"
|
||||||
|
|
||||||
|
.ASSERT * = $8001, ldwarning, "Code not at $8001"
|
||||||
|
.assert * = $8001, ldwarning, "Code not at $8001"
|
||||||
|
|
||||||
|
nop
|
||||||
|
|
||||||
|
.ASSERT * = $0000, ldwarning, "Code not at $0000"
|
||||||
|
.assert * = $0000, ldwarning, "Code not at $0000"
|
||||||
|
|
||||||
|
.ASSERT * = $0001, ldwarning, "Code not at $0001"
|
||||||
|
.assert * = $0001, ldwarning, "Code not at $0001"
|
||||||
|
|
||||||
|
.ASSERT * = $1000, ldwarning, "Code not at $1000"
|
||||||
|
.assert * = $1000, ldwarning, "Code not at $1000"
|
||||||
|
|
||||||
|
.ASSERT * = $1001, ldwarning, "Code not at $1001"
|
||||||
|
.assert * = $1001, ldwarning, "Code not at $1001"
|
||||||
|
|
||||||
|
.ASSERT * = $8000, ldwarning, "Code not at $8000"
|
||||||
|
.assert * = $8000, ldwarning, "Code not at $8000"
|
||||||
|
|
||||||
|
.ASSERT * = $8001, ldwarning, "Code not at $8001"
|
||||||
|
.assert * = $8001, ldwarning, "Code not at $8001"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.org $8000
|
||||||
|
|
||||||
|
.ASSERT * = $0000, ldwarning, "Code not at $0000"
|
||||||
|
.assert * = $0000, ldwarning, "Code not at $0000"
|
||||||
|
|
||||||
|
.ASSERT * = $0001, ldwarning, "Code not at $0001"
|
||||||
|
.assert * = $0001, ldwarning, "Code not at $0001"
|
||||||
|
|
||||||
|
.ASSERT * = $1000, ldwarning, "Code not at $1000"
|
||||||
|
.assert * = $1000, ldwarning, "Code not at $1000"
|
||||||
|
|
||||||
|
.ASSERT * = $1001, ldwarning, "Code not at $1001"
|
||||||
|
.assert * = $1001, ldwarning, "Code not at $1001"
|
||||||
|
|
||||||
|
.ASSERT * = $8000, ldwarning, "Code not at $8000"
|
||||||
|
.assert * = $8000, ldwarning, "Code not at $8000"
|
||||||
|
|
||||||
|
.ASSERT * = $8001, ldwarning, "Code not at $8001"
|
||||||
|
.assert * = $8001, ldwarning, "Code not at $8001"
|
||||||
|
|
||||||
|
nop
|
||||||
|
|
||||||
|
.ASSERT * = $0000, ldwarning, "Code not at $0000"
|
||||||
|
.assert * = $0000, ldwarning, "Code not at $0000"
|
||||||
|
|
||||||
|
.ASSERT * = $0001, ldwarning, "Code not at $0001"
|
||||||
|
.assert * = $0001, ldwarning, "Code not at $0001"
|
||||||
|
|
||||||
|
.ASSERT * = $1000, ldwarning, "Code not at $1000"
|
||||||
|
.assert * = $1000, ldwarning, "Code not at $1000"
|
||||||
|
|
||||||
|
.ASSERT * = $1001, ldwarning, "Code not at $1001"
|
||||||
|
.assert * = $1001, ldwarning, "Code not at $1001"
|
||||||
|
|
||||||
|
.ASSERT * = $8000, ldwarning, "Code not at $8000"
|
||||||
|
.assert * = $8000, ldwarning, "Code not at $8000"
|
||||||
|
|
||||||
|
.ASSERT * = $8001, ldwarning, "Code not at $8001"
|
||||||
|
.assert * = $8001, ldwarning, "Code not at $8001"
|
28
test/asm/listing/034-assert-lderror1.s
Normal file
28
test/asm/listing/034-assert-lderror1.s
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
; 2022-06-15 Spiro Trikaliotis
|
||||||
|
|
||||||
|
.ASSERT * = $0000, error, "Code not at $0000"
|
||||||
|
.assert * = $0000, error, "Code not at $0000"
|
||||||
|
|
||||||
|
.ASSERT * = $0001, error, "Code not at $0001"
|
||||||
|
.assert * = $0001, error, "Code not at $0001"
|
||||||
|
|
||||||
|
.ASSERT * = $1000, error, "Code not at $1000"
|
||||||
|
.assert * = $1000, error, "Code not at $1000"
|
||||||
|
|
||||||
|
.ASSERT * = $1001, error, "Code not at $1001"
|
||||||
|
.assert * = $1001, error, "Code not at $1001"
|
||||||
|
|
||||||
|
.ASSERT * = $8000, error, "Code not at $8000"
|
||||||
|
.assert * = $8000, error, "Code not at $8000"
|
||||||
|
|
||||||
|
.ASSERT * = $8001, error, "Code not at $8001"
|
||||||
|
.assert * = $8001, error, "Code not at $8001"
|
||||||
|
|
||||||
|
|
||||||
|
.org $8000
|
||||||
|
|
||||||
|
.ASSERT * = $8000, error, "Code not at $8000"
|
||||||
|
.assert * = $8000, error, "Code not at $8000"
|
||||||
|
|
||||||
|
.ASSERT * = $8001, error, "Code not at $8001"
|
||||||
|
.assert * = $8001, error, "Code not at $8001"
|
8
test/asm/listing/034-assert-lderror2.s
Normal file
8
test/asm/listing/034-assert-lderror2.s
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
; 2022-06-18 Spiro Trikaliotis
|
||||||
|
|
||||||
|
.ASSERT * = $0000, lderror, "Code not at $0000"
|
||||||
|
.ASSERT * = $0001, lderror, "Code not at $0001"
|
||||||
|
.ASSERT * = $1000, lderror, "Code not at $1000"
|
||||||
|
.ASSERT * = $1001, lderror, "Code not at $1001"
|
||||||
|
.ASSERT * = $8000, lderror, "Code not at $8000"
|
||||||
|
.ASSERT * = $8001, lderror, "Code not at $8001"
|
3
test/asm/listing/034-assert-lderror3.s
Normal file
3
test/asm/listing/034-assert-lderror3.s
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
; 2022-06-20 Spiro Trikaliotis
|
||||||
|
|
||||||
|
.assert * = $0000, lderror, "Code not at $0000"
|
3
test/asm/listing/034-assert-lderror4.s
Normal file
3
test/asm/listing/034-assert-lderror4.s
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
; 2022-06-20 Spiro Trikaliotis
|
||||||
|
|
||||||
|
.assert * = $0001, lderror, "Code not at $0001"
|
3
test/asm/listing/034-assert-lderror5.s
Normal file
3
test/asm/listing/034-assert-lderror5.s
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
; 2022-06-20 Spiro Trikaliotis
|
||||||
|
|
||||||
|
.assert * = $1000, lderror, "Code not at $1000"
|
3
test/asm/listing/034-assert-lderror6.s
Normal file
3
test/asm/listing/034-assert-lderror6.s
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
; 2022-06-20 Spiro Trikaliotis
|
||||||
|
|
||||||
|
.assert * = $1001, lderror, "Code not at $1001"
|
3
test/asm/listing/034-assert-lderror7.s
Normal file
3
test/asm/listing/034-assert-lderror7.s
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
; 2022-06-20 Spiro Trikaliotis
|
||||||
|
|
||||||
|
.assert * = $8000, lderror, "Code not at $8000"
|
3
test/asm/listing/034-assert-lderror8.s
Normal file
3
test/asm/listing/034-assert-lderror8.s
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
; 2022-06-20 Spiro Trikaliotis
|
||||||
|
|
||||||
|
.assert * = $8001, lderror, "Code not at $8001"
|
20
test/asm/listing/040-align.s
Normal file
20
test/asm/listing/040-align.s
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
; 2022-06-20 Spiro Trikaliotis
|
||||||
|
|
||||||
|
.byte 0
|
||||||
|
|
||||||
|
.align 4
|
||||||
|
.byte 4
|
||||||
|
.word 12
|
||||||
|
.word 18
|
||||||
|
|
||||||
|
.align 1
|
||||||
|
.byte 1
|
||||||
|
|
||||||
|
.align 8
|
||||||
|
.byte 8
|
||||||
|
|
||||||
|
.align 8
|
||||||
|
.byte 8
|
||||||
|
|
||||||
|
.align 128
|
||||||
|
.byte 128
|
10
test/asm/listing/050-case-off-2.s
Normal file
10
test/asm/listing/050-case-off-2.s
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
; 2022-06-20 Spiro Trikaliotis
|
||||||
|
|
||||||
|
.case -
|
||||||
|
|
||||||
|
CamelCase:
|
||||||
|
lda #0
|
||||||
|
|
||||||
|
Test:
|
||||||
|
beq CamelCase
|
||||||
|
bne camelcase
|
10
test/asm/listing/050-case-off-3.s
Normal file
10
test/asm/listing/050-case-off-3.s
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
; 2022-06-20 Spiro Trikaliotis
|
||||||
|
|
||||||
|
.case off
|
||||||
|
|
||||||
|
CamelCase:
|
||||||
|
lda #0
|
||||||
|
|
||||||
|
Test:
|
||||||
|
beq CamelCase
|
||||||
|
bne camelcase
|
10
test/asm/listing/050-case-off-4.s
Normal file
10
test/asm/listing/050-case-off-4.s
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
; 2022-06-20 Spiro Trikaliotis
|
||||||
|
|
||||||
|
.CASE OFF
|
||||||
|
|
||||||
|
CamelCase:
|
||||||
|
lda #0
|
||||||
|
|
||||||
|
Test:
|
||||||
|
beq CamelCase
|
||||||
|
bne camelcase
|
10
test/asm/listing/050-case-on-1.s
Normal file
10
test/asm/listing/050-case-on-1.s
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
; 2022-06-20 Spiro Trikaliotis
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
CamelCase:
|
||||||
|
lda #0
|
||||||
|
|
||||||
|
Test:
|
||||||
|
beq CamelCase
|
||||||
|
bne camelcase
|
10
test/asm/listing/050-case-on-2.s
Normal file
10
test/asm/listing/050-case-on-2.s
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
; 2022-06-20 Spiro Trikaliotis
|
||||||
|
|
||||||
|
.case +
|
||||||
|
|
||||||
|
CamelCase:
|
||||||
|
lda #0
|
||||||
|
|
||||||
|
Test:
|
||||||
|
beq CamelCase
|
||||||
|
bne camelcase
|
10
test/asm/listing/050-case-on-3.s
Normal file
10
test/asm/listing/050-case-on-3.s
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
; 2022-06-20 Spiro Trikaliotis
|
||||||
|
|
||||||
|
.case on
|
||||||
|
|
||||||
|
CamelCase:
|
||||||
|
lda #0
|
||||||
|
|
||||||
|
Test:
|
||||||
|
beq CamelCase
|
||||||
|
bne camelcase
|
10
test/asm/listing/050-case-on-4.s
Normal file
10
test/asm/listing/050-case-on-4.s
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
; 2022-06-20 Spiro Trikaliotis
|
||||||
|
|
||||||
|
.CASE ON
|
||||||
|
|
||||||
|
CamelCase:
|
||||||
|
lda #0
|
||||||
|
|
||||||
|
Test:
|
||||||
|
beq CamelCase
|
||||||
|
bne camelcase
|
10
test/asm/listing/050-case-on-5.s
Normal file
10
test/asm/listing/050-case-on-5.s
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
; 2022-06-20 Spiro Trikaliotis
|
||||||
|
|
||||||
|
.case
|
||||||
|
|
||||||
|
CamelCase:
|
||||||
|
lda #0
|
||||||
|
|
||||||
|
Test:
|
||||||
|
beq CamelCase
|
||||||
|
bne camelcase
|
3526
test/asm/listing/100-byte.s
Normal file
3526
test/asm/listing/100-byte.s
Normal file
File diff suppressed because it is too large
Load Diff
3526
test/asm/listing/101-byt.s
Normal file
3526
test/asm/listing/101-byt.s
Normal file
File diff suppressed because it is too large
Load Diff
6076
test/asm/listing/102-word.s
Normal file
6076
test/asm/listing/102-word.s
Normal file
File diff suppressed because it is too large
Load Diff
6076
test/asm/listing/103-dbyt.s
Normal file
6076
test/asm/listing/103-dbyt.s
Normal file
File diff suppressed because it is too large
Load Diff
4874
test/asm/listing/104-dword.s
Normal file
4874
test/asm/listing/104-dword.s
Normal file
File diff suppressed because it is too large
Load Diff
6717
test/asm/listing/105-faraddr.s
Normal file
6717
test/asm/listing/105-faraddr.s
Normal file
File diff suppressed because it is too large
Load Diff
6076
test/asm/listing/106-hibytes.s
Normal file
6076
test/asm/listing/106-hibytes.s
Normal file
File diff suppressed because it is too large
Load Diff
6076
test/asm/listing/107-lobytes.s
Normal file
6076
test/asm/listing/107-lobytes.s
Normal file
File diff suppressed because it is too large
Load Diff
@ -15,7 +15,7 @@ else
|
|||||||
endif
|
endif
|
||||||
|
|
||||||
ifdef QUIET
|
ifdef QUIET
|
||||||
.SILENT:
|
# .SILENT:
|
||||||
endif
|
endif
|
||||||
|
|
||||||
CA65 := $(if $(wildcard ../../../bin/ca65*),../../../bin/ca65,ca65)
|
CA65 := $(if $(wildcard ../../../bin/ca65*),../../../bin/ca65,ca65)
|
||||||
@ -49,33 +49,82 @@ $(WORKDIR)/$1.bin: $1.s $(ISEQUAL)
|
|||||||
$(if $(QUIET),echo asm/$1.bin)
|
$(if $(QUIET),echo asm/$1.bin)
|
||||||
|
|
||||||
# compile without generating listing
|
# compile without generating listing
|
||||||
$(CA65) -t none -o $$(@:.bin=.o) $$<
|
ifeq ($(wildcard control/$1.err),)
|
||||||
$(LD65) -t none -o $$@ $$(@:.bin=.o) none.lib
|
$(CA65) -t none -o $$(@:.bin=.o) $$< > $$(@:.bin=.err) 2>&1
|
||||||
|
ifeq ($(wildcard control/$1.no-ld65),)
|
||||||
ifneq ($(wildcard $1.bin-ref),)
|
$(LD65) -t none -o $$@ $$(@:.bin=.o) none.lib > $$(@:.bin=.ld65-err) 2>&1
|
||||||
$(ISEQUAL) $1.bin-ref $$@
|
endif
|
||||||
|
else
|
||||||
|
$(CA65) -t none -o $$(@:.bin=.o) $$< > $$(@:.bin=.err) 2>&1 || true
|
||||||
|
ifeq ($(wildcard control/$1.no-ld65),)
|
||||||
|
$(LD65) -t none -o $$@ $$(@:.bin=.o) none.lib > $$(@:.bin=.ld65-err) 2>&1 || true
|
||||||
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
$(CA65) -t none -l $$(@:.bin=.list.orig) -o $$(@:.bin=.list-o) $$<
|
ifneq ($(wildcard ref/$1.err-ref),)
|
||||||
$(LD65) -t none -o $$(@:.bin=.list-bin) $$(@:.bin=.list-o) none.lib
|
$(ISEQUAL) ref/$1.err-ref $$(@:.bin=.err)
|
||||||
|
else
|
||||||
|
$(ISEQUAL) --empty $$(@:.bin=.err)
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifneq ($(wildcard ref/$1.bin-ref),)
|
||||||
|
$(ISEQUAL) --binary ref/$1.bin-ref $$@
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifneq ($(wildcard ref/$1.ld65err-ref),)
|
||||||
|
@echo cat $$(@:.bin=.ld65-err)
|
||||||
|
cat $$(@:.bin=.ld65-err)
|
||||||
|
@echo
|
||||||
|
@echo
|
||||||
|
-diff -u ref/$1.ld65err-ref $$(@:.bin=.ld65-err)
|
||||||
|
@echo
|
||||||
|
@echo
|
||||||
|
$(ISEQUAL) --wildcards ref/$1.ld65err-ref $$(@:.bin=.ld65-err)
|
||||||
|
else
|
||||||
|
ifneq ($(wildcard $(WORKDIR)/$1.ld65-err),)
|
||||||
|
$(ISEQUAL) --empty $$(@:.bin=.ld65-err)
|
||||||
|
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
|
||||||
|
ifeq ($(wildcard control/$1.no-ld65),)
|
||||||
|
$(LD65) -t none -o $$(@:.bin=.list-bin) $$(@:.bin=.list-o) none.lib > $$(@:.bin=.list-ld65-err) 2>&1
|
||||||
|
endif
|
||||||
|
else
|
||||||
|
$(CA65) -t none -l $$(@:.bin=.list-lst) -o $$(@:.bin=.list-o) $$< > $$(@:.bin=.list-err) 2>&1 || 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
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifneq ($(wildcard ref/$1.err-ref),)
|
||||||
|
$(ISEQUAL) ref/$1.err-ref $$(@:.bin=.list-err)
|
||||||
|
else
|
||||||
|
$(ISEQUAL) --empty $$(@:.bin=.list-err)
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifneq ($(wildcard ref/$1.ld65err-ref),)
|
||||||
|
$(ISEQUAL) --wildcards ref/$1.ld65err-ref $$(@:.bin=.list-ld65-err)
|
||||||
|
else
|
||||||
|
ifneq ($(wildcard $(WORKDIR)/$1.list-ld65-err),)
|
||||||
|
$(ISEQUAL) --empty $$(@:.bin=.list-ld65-err)
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
# check if the result bin is the same as without listing file
|
# check if the result bin is the same as without listing file
|
||||||
|
ifeq ($(wildcard control/$1.err),)
|
||||||
$(ISEQUAL) $$@ $$(@:.bin=.list-bin)
|
$(ISEQUAL) $$@ $$(@:.bin=.list-bin)
|
||||||
|
endif
|
||||||
|
|
||||||
ifneq ($(wildcard $1.list-ref),)
|
ifneq ($(wildcard ref/$1.list-ref),)
|
||||||
# we have a reference file, compare that, too
|
# we have a reference file, compare that, too
|
||||||
|
|
||||||
# remove first line which contains a version number
|
# remove first line which contains a version number
|
||||||
tail -n +2 $$(@:.bin=.lst.orig) > $$(@:.bin=.lst)
|
$(ISEQUAL) --skip=1 ref/$1.list-ref $$(@:.bin=.list-lst)
|
||||||
$(ISEQUAL) $1.list-ref $$(@:.bin=.lst)
|
|
||||||
endif
|
endif
|
||||||
|
|
||||||
# $(CA65) -t none -f -l $$(@:.bin=.flist.orig) -o $$(@:.bin=.flist-o) $$<
|
|
||||||
# $(LD65) -t none -o $$(@:.bin=.flist-bin) $$(@:.bin=.flist-o) none.lib
|
|
||||||
|
|
||||||
# # check if the result bin is the same as without listing file
|
|
||||||
# $(ISEQUAL) $$@ $$(@:.bin=.flist-bin)
|
|
||||||
|
|
||||||
endef # LISTING_template
|
endef # LISTING_template
|
||||||
|
|
||||||
|
|
||||||
|
0
test/asm/listing/control/031-assert-error.err
Normal file
0
test/asm/listing/control/031-assert-error.err
Normal file
0
test/asm/listing/control/031-assert-error.no-ld65
Normal file
0
test/asm/listing/control/031-assert-error.no-ld65
Normal file
0
test/asm/listing/control/032-assert-error2.err
Normal file
0
test/asm/listing/control/032-assert-error2.err
Normal file
0
test/asm/listing/control/032-assert-error3.err
Normal file
0
test/asm/listing/control/032-assert-error3.err
Normal file
0
test/asm/listing/control/032-assert-error4.err
Normal file
0
test/asm/listing/control/032-assert-error4.err
Normal file
0
test/asm/listing/control/032-assert-error6.err
Normal file
0
test/asm/listing/control/032-assert-error6.err
Normal file
0
test/asm/listing/control/032-assert-error7.err
Normal file
0
test/asm/listing/control/032-assert-error7.err
Normal file
0
test/asm/listing/control/032-assert-error8.err
Normal file
0
test/asm/listing/control/032-assert-error8.err
Normal file
0
test/asm/listing/control/034-assert-lderror1.err
Normal file
0
test/asm/listing/control/034-assert-lderror1.err
Normal file
0
test/asm/listing/control/034-assert-lderror2.err
Normal file
0
test/asm/listing/control/034-assert-lderror2.err
Normal file
0
test/asm/listing/control/034-assert-lderror3.err
Normal file
0
test/asm/listing/control/034-assert-lderror3.err
Normal file
0
test/asm/listing/control/034-assert-lderror4.err
Normal file
0
test/asm/listing/control/034-assert-lderror4.err
Normal file
0
test/asm/listing/control/034-assert-lderror6.err
Normal file
0
test/asm/listing/control/034-assert-lderror6.err
Normal file
0
test/asm/listing/control/034-assert-lderror7.err
Normal file
0
test/asm/listing/control/034-assert-lderror7.err
Normal file
0
test/asm/listing/control/034-assert-lderror8.err
Normal file
0
test/asm/listing/control/034-assert-lderror8.err
Normal file
0
test/asm/listing/control/050-case-on-1.err
Normal file
0
test/asm/listing/control/050-case-on-1.err
Normal file
0
test/asm/listing/control/050-case-on-1.no-ld65
Normal file
0
test/asm/listing/control/050-case-on-1.no-ld65
Normal file
0
test/asm/listing/control/050-case-on-2.err
Normal file
0
test/asm/listing/control/050-case-on-2.err
Normal file
0
test/asm/listing/control/050-case-on-2.no-ld65
Normal file
0
test/asm/listing/control/050-case-on-2.no-ld65
Normal file
0
test/asm/listing/control/050-case-on-3.err
Normal file
0
test/asm/listing/control/050-case-on-3.err
Normal file
0
test/asm/listing/control/050-case-on-3.no-ld65
Normal file
0
test/asm/listing/control/050-case-on-3.no-ld65
Normal file
0
test/asm/listing/control/050-case-on-4.err
Normal file
0
test/asm/listing/control/050-case-on-4.err
Normal file
0
test/asm/listing/control/050-case-on-4.no-ld65
Normal file
0
test/asm/listing/control/050-case-on-4.no-ld65
Normal file
0
test/asm/listing/control/050-case-on-5.err
Normal file
0
test/asm/listing/control/050-case-on-5.err
Normal file
0
test/asm/listing/control/050-case-on-5.no-ld65
Normal file
0
test/asm/listing/control/050-case-on-5.no-ld65
Normal file
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user