Merge branch 'cc65:master' into master

This commit is contained in:
rumbledethumps
2025-10-16 16:21:09 -07:00
committed by GitHub
44 changed files with 375 additions and 33 deletions

View File

@@ -16,7 +16,7 @@ have in mind is not how we'd expect it to be - talking to us
before you start might save you a lot of work in those cases. before you start might save you a lot of work in those cases.
(''Note:'' The word "must" indicates a requirement. The word (''Note:'' The word "must" indicates a requirement. The word
"should" indicates a recomendation.) "should" indicates a recommendation.)
*this is work in progress and is constantly updated - if in *this is work in progress and is constantly updated - if in
doubt, please ask* doubt, please ask*
@@ -54,7 +54,7 @@ This is an ongoing controversial topic - everyone knows
that. However, the following is how we do it :) that. However, the following is how we do it :)
* TAB characters must be expanded to spaces. * TAB characters must be expanded to spaces.
* 4 spaces per indention level (rather than 8) are * 4 spaces per indentation level (rather than 8) are
preferred, especially if there are many different levels. preferred, especially if there are many different levels.
* No extra spaces at the end of lines. * No extra spaces at the end of lines.
* All text files must end with new-line characters. Don't * All text files must end with new-line characters. Don't
@@ -262,9 +262,9 @@ conform with the C standard. That means:
.assert RETURN_VALUE = 0 .assert RETURN_VALUE = 0
tax tax
; Sometimes jumping to 'return 0' could save a byte: ; Sometimes jumping to 'return0' could save a byte:
.assert RETURN_VALUE = 0 .assert RETURN_VALUE = 0
jmp return 0 jmp return0
~~~ ~~~
* Functions, that are intended for a platform's system * Functions, that are intended for a platform's system
@@ -300,7 +300,7 @@ conform with the C standard. That means:
is on emulators or eg flash cartridges, the process of is on emulators or eg flash cartridges, the process of
converting them to something that can be used with these converting them to something that can be used with these
should be documented in the user manual. should be documented in the user manual.
* Generally every function should live in a seperate source * Generally every function should live in a separate source
file - unless the functions are so closely related that file - unless the functions are so closely related that
splitting makes no sense. splitting makes no sense.
* Source files should not contain commented out code - if * Source files should not contain commented out code - if
@@ -342,7 +342,7 @@ to the github actions - those may rely on bash and/or linux tools.
## Compiler ## Compiler
* We need a way that makes it possible to feed arbitrary * We need a way that makes it possible to feed arbitrary
assembler code into the optimzer, so we can have proper assembler code into the optimizer, so we can have proper
tests for it. tests for it.
### Floating point support ### Floating point support

View File

@@ -1319,6 +1319,11 @@ if you want to access the "other" symbol <tt/bar/, you would have to write:
.endscope .endscope
</verb></tscreen> </verb></tscreen>
The above example also shows that to search a scope that is not yet defined in
the code above the usage, you should use the namespace token (<tt/::/) and
specify the full scope name, to allow the assembler to create the scope at the
correct place.
<sect>Address sizes and memory models<label id="address-sizes"><p> <sect>Address sizes and memory models<label id="address-sizes"><p>

View File

@@ -81,13 +81,13 @@ L1: .repeat 2 ; Unroll this a bit to make it faster
; Set the remaining bytes if any ; Set the remaining bytes if any
L2: ldy ptr3 ; Get the low byte of n L2: ldy ptr3 ; Get the low byte of n
beq leave ; something to set? No -> leave beq @leave ; something to set? No -> leave
L3: dey @L3: dey
sta (ptr1),y ; set bytes in low sta (ptr1),y ; set bytes in low
sta (ptr2),y ; and high section sta (ptr2),y ; and high section
bne L3 ; flags still up to date from dey! bne @L3 ; flags still up to date from dey!
leave: @leave:
jmp popax ; Pop ptr and return as result jmp popax ; Pop ptr and return as result

View File

@@ -27,21 +27,21 @@ _strcspn:
loadChar: loadChar:
ldy #0 ldy #0
lda (ptr1),y ; get next char from s1 lda (ptr1),y ; get next char from s1
beq leave ; handly byte of s1 beq @leave ; handly byte of s1
advance: @advance:
inc ptr1 ; advance string position to test inc ptr1 ; advance string position to test
bne check bne @check
inc ptr1+1 inc ptr1+1
dey ; correct next iny (faster/shorter than bne...) dey ; correct next iny (faster/shorter than bne...)
checkNext: @checkNext:
iny iny
check: cpy tmp1 ; compare with length of test character string @check: cpy tmp1 ; compare with length of test character string
beq endOfTestChars beq endOfTestChars
cmp (ptr4),y ; found matching char? cmp (ptr4),y ; found matching char?
bne checkNext bne @checkNext
leave: txa ; restore position of finding @leave: txa ; restore position of finding
ldx tmp2 ; and return ldx tmp2 ; and return
rts rts

View File

@@ -27,26 +27,26 @@ _strspn:
loadChar: loadChar:
ldy #0 ldy #0
lda (ptr1),y ; get next char from s1 lda (ptr1),y ; get next char from s1
beq leave ; handly byte of s1 beq @leave ; handly byte of s1
advance: @advance:
inc ptr1 ; advance string position to test inc ptr1 ; advance string position to test
bne check bne @check
inc ptr1+1 inc ptr1+1
dey ; correct next iny (faster/shorter than bne...) dey ; correct next iny (faster/shorter than bne...)
checkNext: @checkNext:
iny iny
check: cpy tmp1 ; compare with length of test character string @check: cpy tmp1 ; compare with length of test character string
beq leave beq @leave
cmp (ptr4),y ; found matching char? cmp (ptr4),y ; found matching char?
bne checkNext bne @checkNext
foundTestChar: @foundTestChar:
inx inx
bne loadChar bne loadChar
inc tmp2 inc tmp2
bne loadChar ; like bra... bne loadChar ; like bra...
leave: txa ; restore position of finding @leave: txa ; restore position of finding
ldx tmp2 ; and return ldx tmp2 ; and return
rts rts

View File

@@ -646,10 +646,14 @@ static void StudySymbol (ExprNode* Expr, ExprDesc* D)
** about the address size, check higher lexical levels for a symbol ** about the address size, check higher lexical levels for a symbol
** with the same name and use its address size if we find such a ** with the same name and use its address size if we find such a
** symbol which is defined. ** symbol which is defined.
**
** Only do the search if the symbol is not in the current scope,
** assume scoped symbols can't be resolved in a different scope.
*/ */
AddrSize = GetSymAddrSize (Sym); AddrSize = GetSymAddrSize (Sym);
Parent = GetSymParentScope (Sym); Parent = GetSymParentScope (Sym);
if (AddrSize == ADDR_SIZE_DEFAULT && Parent != 0) { if (AddrSize == ADDR_SIZE_DEFAULT && Parent != 0 &&
Sym->Sym.Tab == CurrentScope) {
SymEntry* H = SymFindAny (Parent, GetSymName (Sym)); SymEntry* H = SymFindAny (Parent, GetSymName (Sym));
if (H) { if (H) {
AddrSize = GetSymAddrSize (H); AddrSize = GetSymAddrSize (H);

View File

@@ -94,10 +94,14 @@ SymTable* ParseScopedIdent (StrBuf* Name, StrBuf* FullName)
*/ */
Scope = SymFindAnyScope (CurrentScope, Name); Scope = SymFindAnyScope (CurrentScope, Name);
if (Scope == 0) { if (Scope == 0) {
/* Scope not found */ /* Scope not found, create a new scope here */
SB_Terminate (FullName); Scope = SymFindScope (CurrentScope, Name, SYM_ALLOC_NEW);
Error ("No such scope: `%m%p'", FullName); if (Scope == 0) {
return 0; SB_Terminate (FullName);
/* Scope not found */
Error ("Can't create scope: `%m%p'", FullName);
return 0;
}
} }
} else { } else {
@@ -136,10 +140,10 @@ SymTable* ParseScopedIdent (StrBuf* Name, StrBuf* FullName)
SB_Append (FullName, Name); SB_Append (FullName, Name);
/* Search for the child scope */ /* Search for the child scope */
Scope = SymFindScope (Scope, Name, SYM_FIND_EXISTING); Scope = SymFindScope (Scope, Name, SYM_ALLOC_NEW);
if (Scope == 0) { if (Scope == 0) {
/* Scope not found */ /* Scope not found */
Error ("No such scope: `%m%p'", FullName); Error ("Can't create scope: `%m%p'", FullName);
return 0; return 0;
} }

View File

@@ -218,6 +218,8 @@ void SymEnterLevel (const StrBuf* ScopeName, unsigned char Type,
if (CurrentScope->Flags & ST_DEFINED) { if (CurrentScope->Flags & ST_DEFINED) {
Error ("Duplicate scope `%m%p'", ScopeName); Error ("Duplicate scope `%m%p'", ScopeName);
} }
/* Open the scope as we are entering it */
CurrentScope->Flags &= ~ST_CLOSED;
} else { } else {
CurrentScope = RootScope = NewSymTable (0, ScopeName); CurrentScope = RootScope = NewSymTable (0, ScopeName);
@@ -294,6 +296,8 @@ SymTable* SymFindScope (SymTable* Parent, const StrBuf* Name, SymFindAction Acti
/* Create a new scope if requested and we didn't find one */ /* Create a new scope if requested and we didn't find one */
if (*T == 0 && (Action & SYM_ALLOC_NEW) != 0) { if (*T == 0 && (Action & SYM_ALLOC_NEW) != 0) {
*T = NewSymTable (Parent, Name); *T = NewSymTable (Parent, Name);
/* Close the created scope, will be reopened if needed */
(*T)->Flags |= ST_CLOSED;
} }
/* Return the scope */ /* Return the scope */

View File

@@ -0,0 +1,16 @@
.org $800
symbol1 := * ; ::symbol1
.addr symbol1 ; ::symbol1
.scope scope1
symbol1 := * ; ::scope1::symbol1
.addr symbol1 ; ::scope1::symbol1
.addr ::symbol1 ; ::symbol1
.endscope
.addr symbol1 ; ::symbol1
.addr scope1::symbol1 ; ::scope1::symbol

View File

@@ -0,0 +1,7 @@
.scope outer
foo = 2
.scope inner
lda #foo
foo = 3
.endscope
.endscope

View File

@@ -0,0 +1,7 @@
.scope outer
foo = $1234
.scope inner
lda foo,x
foo = $12
.endscope
.endscope

View File

@@ -0,0 +1,7 @@
.scope outer
foo = $12
.scope inner
lda foo,x
foo = $1234
.endscope
.endscope

View File

@@ -0,0 +1,7 @@
.scope outer
foo = $12
.scope inner
lda a:foo,x
foo = $1234
.endscope
.endscope

View File

@@ -0,0 +1,6 @@
bar = 3
.scope foo
bar = 2
lda #::bar ; Access the global bar (which is 3)
.endscope

View File

@@ -0,0 +1,10 @@
.scope foo
bar = 3
.endscope
.scope outer
lda #foo::bar ; Will load 3, not 2!
.scope foo
bar = 2
.endscope
.endscope

View File

@@ -0,0 +1,18 @@
.scope foo
.scope outer
.scope inner
bar = 1
.endscope
.endscope
.scope another
.scope nested
lda #outer::inner::bar ; 1
.endscope
.endscope
.endscope
.scope outer
.scope inner
bar = 2
.endscope
.endscope

View File

@@ -0,0 +1,18 @@
.scope foo
.scope outer
.scope inner
bar = 1
.endscope
.endscope
.scope another
.scope nested
lda #::outer::inner::bar ; 2
.endscope
.endscope
.endscope
.scope outer
.scope inner
bar = 2
.endscope
.endscope

View File

@@ -0,0 +1,16 @@
.org $2000
.proc s1
symbol := $1
stx s1::s2::symbol
stx s2_symbol
.scope s2
symbol: .byte 0
.endscope
s2_symbol := s2::symbol
.endproc

View File

@@ -0,0 +1,17 @@
.org $800
.scope main
.proc foo
;; should all be the same
lda params__bar
lda params::bar
lda foo::params::bar
.proc params
bar: .byte 0
.endproc
params__bar := params::bar
.endproc
.endscope

View File

@@ -0,0 +1,16 @@
;;; Regression test to ensure that newly inferred scopes are closed.
.scope foo
start:
;; Since `bar` is not a known scope at this point, it is
;; inferred to be `::foo::bar`, and since `::foo::bar::start`
;; does not exist this will produce an error. Importantly,
;; it does not resolve to `::foo::start` which would be
;; incorrect.
jmp bar::start
.endscope
.scope bar
start:
rts
.endscope

Binary file not shown.

View File

@@ -0,0 +1,21 @@
ca65 Vx.xx - Git XXXXXXXXX
Main file : 300-scopes-basic.s
Current file: 300-scopes-basic.s
000000r 1
000000r 1 .org $800
000800 1
000800 1 symbol1 := * ; ::symbol1
000800 1 00 08 .addr symbol1 ; ::symbol1
000802 1
000802 1
000802 1 .scope scope1
000802 1 symbol1 := * ; ::scope1::symbol1
000802 1
000802 1 02 08 .addr symbol1 ; ::scope1::symbol1
000804 1 00 08 .addr ::symbol1 ; ::symbol1
000806 1 .endscope
000806 1
000806 1 00 08 .addr symbol1 ; ::symbol1
000808 1 02 08 .addr scope1::symbol1 ; ::scope1::symbol
000808 1

View File

@@ -0,0 +1 @@
<EFBFBD>

View File

@@ -0,0 +1,12 @@
ca65 Vx.xx - Git XXXXXXXXX
Main file : 301-nested-scopes.s
Current file: 301-nested-scopes.s
000000r 1 .scope outer
000000r 1 foo = 2
000000r 1 .scope inner
000000r 1 A9 03 lda #foo
000002r 1 foo = 3
000002r 1 .endscope
000002r 1 .endscope
000002r 1

Binary file not shown.

View File

@@ -0,0 +1,12 @@
ca65 Vx.xx - Git XXXXXXXXX
Main file : 302-scope-redefined.s
Current file: 302-scope-redefined.s
000000r 1 .scope outer
000000r 1 foo = $1234
000000r 1 .scope inner
000000r 1 BD 12 00 lda foo,x
000003r 1 foo = $12
000003r 1 .endscope
000003r 1 .endscope
000003r 1

View File

@@ -0,0 +1 @@
303-change-addressing-mode-error.s:4: Error: Range error (4660 not in [0..255])

View File

@@ -0,0 +1 @@
<EFBFBD>4

View File

@@ -0,0 +1,12 @@
ca65 Vx.xx - Git XXXXXXXXX
Main file : 304-fix-addressing-mode-error.s
Current file: 304-fix-addressing-mode-error.s
000000r 1 .scope outer
000000r 1 foo = $12
000000r 1 .scope inner
000000r 1 BD 34 12 lda a:foo,x
000003r 1 foo = $1234
000003r 1 .endscope
000003r 1 .endscope
000003r 1

View File

@@ -0,0 +1 @@
<EFBFBD>

View File

@@ -0,0 +1,11 @@
ca65 Vx.xx - Git XXXXXXXXX
Main file : 305-explicit-scope-reference.s
Current file: 305-explicit-scope-reference.s
000000r 1 bar = 3
000000r 1
000000r 1 .scope foo
000000r 1 bar = 2
000000r 1 A9 03 lda #::bar ; Access the global bar (which is 3)
000002r 1 .endscope
000002r 1

View File

@@ -0,0 +1 @@
<EFBFBD>

View File

@@ -0,0 +1,15 @@
ca65 Vx.xx - Git XXXXXXXXX
Main file : 306-scope-use-before-definition.s
Current file: 306-scope-use-before-definition.s
000000r 1 .scope foo
000000r 1 bar = 3
000000r 1 .endscope
000000r 1
000000r 1 .scope outer
000000r 1 A9 03 lda #foo::bar ; Will load 3, not 2!
000002r 1 .scope foo
000002r 1 bar = 2
000002r 1 .endscope
000002r 1 .endscope
000002r 1

View File

@@ -0,0 +1 @@
<EFBFBD>

View File

@@ -0,0 +1,23 @@
ca65 Vx.xx - Git XXXXXXXXX
Main file : 307-scope-chains.s
Current file: 307-scope-chains.s
000000r 1 .scope foo
000000r 1 .scope outer
000000r 1 .scope inner
000000r 1 bar = 1
000000r 1 .endscope
000000r 1 .endscope
000000r 1 .scope another
000000r 1 .scope nested
000000r 1 A9 01 lda #outer::inner::bar ; 1
000002r 1 .endscope
000002r 1 .endscope
000002r 1 .endscope
000002r 1
000002r 1 .scope outer
000002r 1 .scope inner
000002r 1 bar = 2
000002r 1 .endscope
000002r 1 .endscope
000002r 1

View File

@@ -0,0 +1 @@
<EFBFBD>

View File

@@ -0,0 +1,23 @@
ca65 Vx.xx - Git XXXXXXXXX
Main file : 308-global-scope-anchoring.s
Current file: 308-global-scope-anchoring.s
000000r 1 .scope foo
000000r 1 .scope outer
000000r 1 .scope inner
000000r 1 bar = 1
000000r 1 .endscope
000000r 1 .endscope
000000r 1 .scope another
000000r 1 .scope nested
000000r 1 A9 02 lda #::outer::inner::bar ; 2
000002r 1 .endscope
000002r 1 .endscope
000002r 1 .endscope
000002r 1
000002r 1 .scope outer
000002r 1 .scope inner
000002r 1 bar = 2
000002r 1 .endscope
000002r 1 .endscope
000002r 1

View File

@@ -0,0 +1,21 @@
ca65 Vx.xx - Git XXXXXXXXX
Main file : 309-namespace-path-vs-addressing-mode.s
Current file: 309-namespace-path-vs-addressing-mode.s
000000r 1 .org $2000
002000 1
002000 1 .proc s1
002000 1
002000 1 symbol := $1
002000 1
002000 1 8E 06 20 stx s1::s2::symbol
002003 1 8E 06 20 stx s2_symbol
002006 1
002006 1 .scope s2
002006 1 00 symbol: .byte 0
002007 1 .endscope
002007 1
002007 1 s2_symbol := s2::symbol
002007 1
002007 1 .endproc
002007 1

View File

@@ -0,0 +1,22 @@
ca65 Vx.xx - Git XXXXXXXXX
Main file : 310-create-in-current-scope.s
Current file: 310-create-in-current-scope.s
000000r 1 .org $800
000800 1
000800 1 .scope main
000800 1 .proc foo
000800 1
000800 1 ;; should all be the same
000800 1 AD 09 08 lda params__bar
000803 1 AD 09 08 lda params::bar
000806 1 AD 09 08 lda foo::params::bar
000809 1
000809 1 .proc params
000809 1 00 bar: .byte 0
00080A 1 .endproc
00080A 1 params__bar := params::bar
00080A 1
00080A 1 .endproc
00080A 1 .endscope
00080A 1

View File

@@ -0,0 +1 @@
311-close-new-scopes-error.s:10: Error: Symbol 'start' is undefined