Merge pull request #2009 from bbbradsmith/ca65_feature_disable

ca65: allow .feature to both enable and disable
This commit is contained in:
Bob Andrews
2023-03-04 13:08:18 +01:00
committed by GitHub
9 changed files with 235 additions and 57 deletions

View File

@@ -2758,15 +2758,19 @@ See: <tt><ref id=".ASCIIZ" name=".ASCIIZ"></tt>,<tt><ref id=".CHARMAP" name=".CH
This directive may be used to enable one or more compatibility features This directive may be used to enable one or more compatibility features
of the assembler. While the use of <tt/.FEATURE/ should be avoided when of the assembler. While the use of <tt/.FEATURE/ should be avoided when
possible, it may be useful when porting sources written for other possible, it may be useful when porting sources written for other
assemblers. There is no way to switch a feature off, once you have assemblers. After the feature name an optional '+' or '-' may specify whether
enabled it, so using to enable or disable the feature (enable if omitted). Multiple features may be
enabled, separated by commas. Examples:
<tscreen><verb> <tscreen><verb>
.FEATURE xxx ; enable c_comments
.feature c_comments
.feature c_comments +
; enable force_range, disable underline_in_numbers, enable labels_without_colons
.feature force_range, underline_in_numbers -, labels_without_colons +
.feature force_range +, underline_in_numbers off, labels_without_colons on
</verb></tscreen> </verb></tscreen>
will enable the feature until end of assembly is reached.
The following features are available: The following features are available:
<descrip> <descrip>

View File

@@ -98,38 +98,30 @@ feature_t FindFeature (const StrBuf* Key)
feature_t SetFeature (const StrBuf* Key) void SetFeature (feature_t Feature, unsigned char On)
/* Find the feature and set the corresponding flag if the feature is known. /* Set the corresponding feature flag if Feature is valid.
** In any case, return the feature found. An invalid Key will return
** FEAT_UNKNOWN.
*/ */
{ {
/* Map the string to an enum value */
feature_t Feature = FindFeature (Key);
/* Set the flags */ /* Set the flags */
switch (Feature) { switch (Feature) {
case FEAT_DOLLAR_IS_PC: DollarIsPC = 1; break; case FEAT_DOLLAR_IS_PC: DollarIsPC = On; break;
case FEAT_LABELS_WITHOUT_COLONS: NoColonLabels = 1; break; case FEAT_LABELS_WITHOUT_COLONS: NoColonLabels = On; break;
case FEAT_LOOSE_STRING_TERM: LooseStringTerm = 1; break; case FEAT_LOOSE_STRING_TERM: LooseStringTerm = On; break;
case FEAT_LOOSE_CHAR_TERM: LooseCharTerm = 1; break; case FEAT_LOOSE_CHAR_TERM: LooseCharTerm = On; break;
case FEAT_AT_IN_IDENTIFIERS: AtInIdents = 1; break; case FEAT_AT_IN_IDENTIFIERS: AtInIdents = On; break;
case FEAT_DOLLAR_IN_IDENTIFIERS: DollarInIdents = 1; break; case FEAT_DOLLAR_IN_IDENTIFIERS: DollarInIdents = On; break;
case FEAT_LEADING_DOT_IN_IDENTIFIERS: LeadingDotInIdents= 1; break; case FEAT_LEADING_DOT_IN_IDENTIFIERS: LeadingDotInIdents= On; break;
case FEAT_ORG_PER_SEG: OrgPerSeg = 1; break; case FEAT_ORG_PER_SEG: OrgPerSeg = On; break;
case FEAT_PC_ASSIGNMENT: PCAssignment = 1; break; case FEAT_PC_ASSIGNMENT: PCAssignment = On; break;
case FEAT_MISSING_CHAR_TERM: MissingCharTerm = 1; break; case FEAT_MISSING_CHAR_TERM: MissingCharTerm = On; break;
case FEAT_UBIQUITOUS_IDENTS: UbiquitousIdents = 1; break; case FEAT_UBIQUITOUS_IDENTS: UbiquitousIdents = On; break;
case FEAT_C_COMMENTS: CComments = 1; break; case FEAT_C_COMMENTS: CComments = On; break;
case FEAT_FORCE_RANGE: ForceRange = 1; break; case FEAT_FORCE_RANGE: ForceRange = On; break;
case FEAT_UNDERLINE_IN_NUMBERS: UnderlineInNumbers= 1; break; case FEAT_UNDERLINE_IN_NUMBERS: UnderlineInNumbers= On; break;
case FEAT_ADDRSIZE: AddrSize = 1; break; case FEAT_ADDRSIZE: AddrSize = On; break;
case FEAT_BRACKET_AS_INDIRECT: BracketAsIndirect = 1; break; case FEAT_BRACKET_AS_INDIRECT: BracketAsIndirect = On; break;
case FEAT_STRING_ESCAPES: StringEscapes = 1; break; case FEAT_STRING_ESCAPES: StringEscapes = On; break;
case FEAT_LONG_JSR_JMP_RTS: LongJsrJmpRts = 1; break; case FEAT_LONG_JSR_JMP_RTS: LongJsrJmpRts = On; break;
default: /* Keep gcc silent */ break; default: break;
} }
/* Return the value found */
return Feature;
} }

View File

@@ -87,10 +87,8 @@ feature_t FindFeature (const StrBuf* Key);
** feature is invalid, return FEAT_UNKNOWN. ** feature is invalid, return FEAT_UNKNOWN.
*/ */
feature_t SetFeature (const StrBuf* Key); void SetFeature (feature_t Feature, unsigned char On);
/* Find the feature and set the corresponding flag if the feature is known. /* Set the corresponding feature flag if Feature is valid.
** In any case, return the feature found. An invalid Key will return
** FEAT_UNKNOWN.
*/ */

View File

@@ -489,12 +489,15 @@ static void OptDebugInfo (const char* Opt attribute ((unused)),
static void OptFeature (const char* Opt attribute ((unused)), const char* Arg) static void OptFeature (const char* Opt attribute ((unused)), const char* Arg)
/* Set an emulation feature */ /* Set an emulation feature */
{ {
/* Make a string buffer from Arg */ /* Make a string buffer from Arg and use it to find the feature. */
StrBuf Feature; StrBuf StrFeature;
feature_t Feature = FindFeature (SB_InitFromString (&StrFeature, Arg));
/* Set the feature, check for errors */ /* Enable the feature, check for errors */
if (SetFeature (SB_InitFromString (&Feature, Arg)) == FEAT_UNKNOWN) { if (Feature == FEAT_UNKNOWN) {
AbEnd ("Illegal emulation feature: '%s'", Arg); AbEnd ("Illegal emulation feature: '%s'", Arg);
} else {
SetFeature (Feature, 1);
} }
} }

View File

@@ -1023,7 +1023,10 @@ static void DoFatal (void)
static void DoFeature (void) static void DoFeature (void)
/* Switch the Feature option */ /* Switch the Feature option */
{ {
/* Allow a list of comma separated keywords */ feature_t Feature;
unsigned char On;
/* Allow a list of comma separated feature keywords with optional +/- or ON/OFF */
while (1) { while (1) {
/* We expect an identifier */ /* We expect an identifier */
@@ -1034,18 +1037,24 @@ static void DoFeature (void)
/* Make the string attribute lower case */ /* Make the string attribute lower case */
LocaseSVal (); LocaseSVal ();
Feature = FindFeature(&CurTok.SVal);
/* Set the feature and check for errors */ if (Feature == FEAT_UNKNOWN) {
if (SetFeature (&CurTok.SVal) == FEAT_UNKNOWN) {
/* Not found */ /* Not found */
ErrorSkip ("Invalid feature: '%m%p'", &CurTok.SVal); ErrorSkip ("Invalid feature: '%m%p'", &CurTok.SVal);
return; return;
} else { }
/* Skip the keyword */ NextTok ();
NextTok ();
/* Optional +/- or ON/OFF */
On = 1;
if (CurTok.Tok != TOK_COMMA && !TokIsSep (CurTok.Tok)) {
SetBoolOption(&On);
} }
/* Allow more than one keyword */ /* Apply feature setting. */
SetFeature (Feature, On);
/* Allow more than one feature separated by commas. */
if (CurTok.Tok == TOK_COMMA) { if (CurTok.Tok == TOK_COMMA) {
NextTok (); NextTok ();
} else { } else {

View File

@@ -0,0 +1,8 @@
; test of long-rts promotion
.p816
.feature long_jsr_jmp_rts
.smart +
.proc farproc : far
rts ; should be $6B (RTL) and not $60 (RTS)
.endproc

View File

@@ -6,22 +6,38 @@ The name of a test is everything in the form <test>.s.
The following reference files can be added: The following reference files can be added:
- <test>.bin-ref: - ref/<test>.bin-ref:
This is a reference for the resulting binary. This is a reference for the resulting binary.
The binary as binary tested against this file. The binary as binary tested against this file.
If they are not equal, the test fails. If they are not equal, the test fails.
- <test>.list-ref - ref/<test>.list-ref
This is a reference for the resulting listing output This is a reference for the resulting listing output
This file *must* have the first line of the listing removed, as that This file *must* have the first line of the listing removed, as that
contains a ca65 version string, and almost always this will be changed! contains a ca65 version string, and almost always this will be changed!
- ref/<test>.err-ref
This is a reference for the resulting ca65 stdout (>) output.
- ref/<test>.err2-ref
This is a reference for the resulting ca65 stderr (2>) output.
- ref/<test>.ld65err-ref
This is a reference for the resutling ld65 stdout (>) output.
- ref/<test>.ld65err2-ref
This is a reference for the resulting ld65 stderr (2>) output.
The following control files can be added to control the tests.
These files are empty (contents ignored), and only the filename is used:
- control/<test>.err
Test is expected to produce an error.
- control/<test>.no-ld65
Skip the ld65 step.
Note that the resulting .bin file is generated twice: Once with no listing Note that the resulting .bin file is generated twice: Once with no listing
file, and once with listing file. This way, one can find out if the listing file, and once with listing file. This way, one can find out if the listing
file generation changes anything with the resulting binary output. file generation changes anything with the resulting binary output.
TODO:
- add the possibility to test for specific error output that are to be
expected

View File

@@ -0,0 +1 @@
k

147
test/asm/val/feature.s Normal file
View File

@@ -0,0 +1,147 @@
; a simple test of every .feature
.export _main
.segment "ZEROPAGE"
zplabel:
.segment "CODE"
abslabel:
; exit with 0
_main:
; if any feature needs a runtime test,
; it can be added here.
lda #0
tax
rts
.feature addrsize +
.assert .addrsize(zplabel) = 1, error, ".addrsize 1 expected for ZEROPAGE"
.assert .addrsize(abslabel) = 2, error, ".addrsize 2 expected for absolute"
.feature addrsize -
.feature at_in_identifiers on
ident@with@at:
rts
.feature at_in_identifiers off
.feature bracket_as_indirect
lda [$82],y
.feature bracket_as_indirect-
.feature c_comments
lda zplabel /* comment */
/* comment */
/* multiline
** comment
*/
.feature c_comments -
.feature dollar_in_identifiers
ident$with$dollar:
rts
.feature dollar_in_identifiers -
.feature dollar_is_pc
.assert $ = *, error, "dollar_is_pc failure"
.feature dollar_is_pc -
.feature force_range
lda #-1
.feature force_range -
.feature labels_without_colons
labelwithoutcolon
jmp labelwithoutcolon
.feature labels_without_colons -
.feature leading_dot_in_identifiers
.identifierwithdot:
rts
.feature leading_dot_in_identifiers -
.feature long_jsr_jmp_rts
.p816
; long addresses require alternate instruction names JSL, JML without this feature
jsr $123456
jmp $123456
; smart + far + long_jsr_jmp_rts will promote rts to rtl
.smart +
.proc long_rts : far
rts ; should become RTL ($6B) instead of RTS ($60)
; the emitted opcode is not verified by this test,
; see test/asm/listing/108-long-rts
.endproc
.smart -
.p02
.feature long_jsr_jmp_rts -
.feature loose_char_term
.byte 'a'
.byte "a"
.feature loose_char_term -
.feature loose_string_term
.asciiz "string"
.asciiz 'string'
.feature loose_string_term -
.feature missing_char_term
lda #'a
.feature missing_char_term -
.feature org_per_seg
.segment "RODATA"
.org $5678
.assert * = $5678, error, "org_per_seg failed"
.segment "CODE"
.org $9ABC
.assert * = $9ABC, error, "org_per_seg failed"
.segment "RODATA"
.assert * = $5678, error, "org_per_seg failed"
.reloc
.segment "CODE"
.assert * = $9ABC, error, "org_per_seg failed"
.reloc
.feature org_per_seg -
.feature pc_assignment
* = $1234
.assert * = $1234, error, "pc_assignment failed"
.reloc
.feature pc_assignment -
.feature string_escapes
.asciiz "quote:\""
.feature string_escapes -
.feature ubiquitous_idents
.macro bit
brk
.endmacro
bit
.feature ubiquitous_idents -
.feature underline_in_numbers
.byte %10_10_10_10
.feature underline_in_numbers -