Skip to content

Instantly share code, notes, and snippets.

@Movax12
Last active October 9, 2022 15:21
Show Gist options
  • Save Movax12/b11687f218f38952ecf2dcb98c1756b0 to your computer and use it in GitHub Desktop.
Save Movax12/b11687f218f38952ecf2dcb98c1756b0 to your computer and use it in GitHub Desktop.
; --------------------------------------------------------------------------------------------
; https://mit-license.org/
; Copyright © 2022 Julian Terrell [email protected]
;
; Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
; documentation files (the “Software”), to deal in the Software without restriction, including without limitation
; the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
; and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above
; copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
;
; THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
; TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
; THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
; CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
; DEALINGS IN THE SOFTWARE.
; --------------------------------------------------------------------------------------------
; File: anonLabels.h
;
; Implementation of GNU assembler numbered local labels using CA65 macros.
;
; Known limitations:
; - Cheap local labels will not work when interleaved with these labels.
; - These labels may not work when interleaved with changes in scope.
; - Cannot jump forward to the next numbered label on the same line as a similarly numbered label, ie:
; L:1 bcc F 1 ; will branch to itself, and not the next L:1 label
; - Cannot jump back to the same numbered label on the same line as a similarly numbered label, ie:
; L:1 bcc B 1 ; will not work as the label is not yet properly defined.
; - Cannot use L, F, B as macro names or identifiers.
; - Instructions/macros on the same line as an 'L' label definition are limited to one additional parameter, ie:
; This will work:
; L:0 lda foo, x
; This will NOT work:
; L:0 myMacro foo, bar, #$02
; This will work:
; L:0 {myMacro foo, bar, #$02}
; Define the label on its own line to avoid this issue.
;
; User options:
; Max labels available, uncomment or define this before including this file:
; ::GAS_ANON_LABELS_MAX = 10
;
; Usage:
; These macros are indented to provide the functionality described here:
; https://sourceware.org/binutils/docs/as/Symbol-Names.html
;
; Example usage:
; L:1
; branch F 1
; L:2 branch B 1
; L:1 branch F 2
; L:2 branch B 1
;
; Which is the equivalent of:
; label_1: branch label_3
; label_2: branch label_1
; label_3: branch label_4
; label_4: branch label_3
; Labels made with the 'L' macro are assembled as:
; Number:
; This is the number supplied to the macro that is used in label definition. If the label is 'L:55' then the number is '55'.
; C_B
; This character string is included to reduce the chance you do not accidentally invent a symbol of the same name.
; Count:
; Each time a label with the same number is used the count for that label number will be increased. This count will be part of the label
; to ensure each numbered label is unique. The first definition of 'L:0' gets the number '1'. The 15th definition of 'L:0'
; gets the number '15', and so on. Likewise the first definition of 'L:1' gets the number '1' and its 15th definition gets '15' as well.
; Example: the first L:1 may be named L1C_B1, and the 9th L:3 may be named L3C_B9.
; --------------------------------------------------------------------------------------------
.ifndef ::GAS_ANON_LABELS
::GAS_ANON_LABELS = 1
; max labels available, change or define this before including this file:
.ifndef ::GAS_ANON_LABELS_MAX
::GAS_ANON_LABELS_MAX = 10
.endif
; define an array, CA65 style:
.define ANON_LABEL_COUNT_FOR_VALUE(c) ::.ident(.sprintf("LABEL_COUNT_FOR_%02X", c))
; init array:
.repeat ::GAS_ANON_LABELS_MAX, c
ANON_LABEL_COUNT_FOR_VALUE {c} .set 1
.endrepeat
; macro for label definitions, does a basic syntax check:
.macro L value, p0
.if (!.xmatch({.left(1,{value})}, {:}))
.error "`:` followed by a constant expected."
.endif
.local thisValue
thisValue = .mid(1, 1, {value}) ; second token
.if thisValue > ::GAS_ANON_LABELS_MAX - 1
.error .sprintf("Max label value is %d. Set GAS_ANON_LABELS_MAX to a higher value.", ::GAS_ANON_LABELS_MAX - 1)
.exitmacro
.endif
.ident( .sprintf("L%dC_B%d", thisValue, ANON_LABEL_COUNT_FOR_VALUE {thisValue})):
; anything else on the line with the label? If so, output the tokens
.if (.tcount({value}) > 2)
.if .paramcount > 1
.mid( 2, .tcount({value}) - 2, {value}) , p0 ; allow indexed to work
.else
.mid( 2, .tcount({value}) - 2, {value})
.endif
.endif
ANON_LABEL_COUNT_FOR_VALUE {thisValue} .set ANON_LABEL_COUNT_FOR_VALUE {thisValue} + 1
.endmacro
; forward or backward references. Error checking not possible
.define F(value) .ident( .sprintf("L%dC_B%d", .right(1,value), ANON_LABEL_COUNT_FOR_VALUE {.right(1,value)} ))
.define B(value) .ident( .sprintf("L%dC_B%d", .right(1,value), ANON_LABEL_COUNT_FOR_VALUE {.right(1,value)} - 1 ))
.endif
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment