From 8fd469b81fd84ea552dd91a29ac93f0c4a099391 Mon Sep 17 00:00:00 2001 From: Andy McFadden Date: Wed, 14 Aug 2019 17:25:40 -0700 Subject: [PATCH] Correctly handle delimiters in character operands We weren't checking to see if character operands matched their delimiters, so bad code like "LDA #'''" was being generated. There wasn't a test for this in 2006-operand-formats, so the test has been updated with single and double quotes in low and high ASCII. --- Asm65/Formatter.cs | 58 ++++++------------ SourceGen/SGTestData/2006-operand-formats | Bin 125 -> 133 bytes .../SGTestData/2006-operand-formats.dis65 | 50 +++++++++------ .../Expected/2006-operand-formats_64tass.S | 6 +- .../Expected/2006-operand-formats_Merlin32.S | 4 ++ .../Expected/2006-operand-formats_acme.S | 6 +- .../Expected/2006-operand-formats_cc65.S | 4 ++ .../Expected/2006-operand-formats_cc65.cfg | 2 +- .../SGTestData/Source/2006-operand-formats.S | 4 ++ 9 files changed, 73 insertions(+), 61 deletions(-) diff --git a/Asm65/Formatter.cs b/Asm65/Formatter.cs index 5aba27f..dab5172 100644 --- a/Asm65/Formatter.cs +++ b/Asm65/Formatter.cs @@ -119,10 +119,9 @@ namespace Asm65 { public char OpenDelim { get; private set; } public char CloseDelim { get; private set; } public string Suffix { get; private set; } + public string FormatStr { get; private set; } - public DelimiterDef(char delim) { - OpenDelim = CloseDelim = delim; - Prefix = Suffix = string.Empty; + public DelimiterDef(char delim) : this(string.Empty, delim, delim, string.Empty) { } public DelimiterDef(string prefix, char openDelim, char closeDelim, string suffix) { Debug.Assert(prefix != null); @@ -131,6 +130,15 @@ namespace Asm65 { OpenDelim = openDelim; CloseDelim = closeDelim; Suffix = suffix; + + // Generate format string. + StringBuilder sb = new StringBuilder(); + sb.Append(Prefix); + sb.Append(OpenDelim); + sb.Append("{0}"); + sb.Append(CloseDelim); + sb.Append(Suffix); + FormatStr = sb.ToString(); } public override string ToString() { return Prefix + OpenDelim + '#' + CloseDelim + Suffix; @@ -291,13 +299,6 @@ namespace Asm65 { private string mAddrFormatNoBank; private string mAddrFormatWithBank; - // Character data delimiter format strings, processed from the delimiter patterns. - private string mCharDelimAsciiFmt; - private string mCharDelimHighAsciiFmt; - private string mCharDelimC64PetsciiFmt; - private string mCharDelimC64ScreenCodeFmt; - - // Generated opcode strings. The index is the bitwise OR of the opcode value and // the disambiguation value. In most cases this just helps us avoid calling // ToUpper incessantly. @@ -431,24 +432,6 @@ namespace Asm65 { Debug.WriteLine("NOTE: char delimiters not set"); chrDelim = DelimiterSet.GetDefaultCharDelimiters(); } - mCharDelimAsciiFmt = - DelimiterDefToFormat(chrDelim.Get(CharEncoding.Encoding.Ascii)); - mCharDelimHighAsciiFmt = - DelimiterDefToFormat(chrDelim.Get(CharEncoding.Encoding.HighAscii)); - mCharDelimC64PetsciiFmt = - DelimiterDefToFormat(chrDelim.Get(CharEncoding.Encoding.C64Petscii)); - mCharDelimC64ScreenCodeFmt = - DelimiterDefToFormat(chrDelim.Get(CharEncoding.Encoding.C64ScreenCode)); - } - - private string DelimiterDefToFormat(DelimiterDef def) { - StringBuilder sb = new StringBuilder(); - sb.Append(def.Prefix); - sb.Append(def.OpenDelim); - sb.Append("{0}"); - sb.Append(def.CloseDelim); - sb.Append(def.Suffix); - return sb.ToString(); } /// @@ -544,37 +527,36 @@ namespace Asm65 { return FormatHexValue(value, 2); } - string fmt; + DelimiterDef delimDef = mFormatConfig.mCharDelimiters.Get(enc); + string fmt = delimDef.FormatStr; + Debug.Assert(fmt != null); + CharEncoding.Convert conv; switch (enc) { case CharEncoding.Encoding.Ascii: - fmt = mCharDelimAsciiFmt; conv = CharEncoding.ConvertAscii; break; case CharEncoding.Encoding.HighAscii: - fmt = mCharDelimHighAsciiFmt; conv = CharEncoding.ConvertHighAscii; break; case CharEncoding.Encoding.C64Petscii: - fmt = mCharDelimC64PetsciiFmt; conv = CharEncoding.ConvertC64Petscii; break; case CharEncoding.Encoding.C64ScreenCode: - fmt = mCharDelimC64ScreenCodeFmt; conv = CharEncoding.ConvertC64ScreenCode; break; default: return FormatHexValue(value, 2); } - if (string.IsNullOrEmpty(fmt)) { - return FormatHexValue(value, 2); - } char ch = conv((byte)value); - if (ch == CharEncoding.UNPRINTABLE_CHAR) { + if (ch == CharEncoding.UNPRINTABLE_CHAR || ch == delimDef.OpenDelim || + ch == delimDef.CloseDelim) { + // We might be able to do better with delimiter clashes, e.g. '\'', but + // that's assembler-specific. return FormatHexValue(value, 2); } else { - // possible optimization: replace fmt with a prefix/suffix pair, and just concat + // Possible optimization: replace fmt with a prefix/suffix pair, and just concat return string.Format(fmt, ch); } } diff --git a/SourceGen/SGTestData/2006-operand-formats b/SourceGen/SGTestData/2006-operand-formats index 79ba9453f713405066eec3caf9bf6b39762038c8..ff2319e7c481960f3a60bfa1c853c422a533e47c 100644 GIT binary patch delta 36 qcmbmkm1Y_06_+U3;?N53PJz? diff --git a/SourceGen/SGTestData/2006-operand-formats.dis65 b/SourceGen/SGTestData/2006-operand-formats.dis65 index 3e23962..144d3d3 100644 --- a/SourceGen/SGTestData/2006-operand-formats.dis65 +++ b/SourceGen/SGTestData/2006-operand-formats.dis65 @@ -1,6 +1,6 @@ ### 6502bench SourceGen dis65 v1.0 ### { -"_ContentVersion":1,"FileDataLength":125,"FileDataCrc32":611887040,"ProjectProps":{ +"_ContentVersion":1,"FileDataLength":133,"FileDataCrc32":-811370049,"ProjectProps":{ "CpuName":"65816","IncludeUndocumentedInstr":false,"EntryFlags":33489103,"AnalysisParams":{ "AnalyzeUncategorizedData":true,"MinCharsForString":4,"SeekNearbyTargets":true}, "PlatformSymbolFileIdentifiers":[],"ExtensionScriptFileIdentifiers":[],"ProjectSyms":{ @@ -19,8 +19,8 @@ "UserLabels":{ "63":{ "Label":"skipdata","Value":4159,"Source":"User","Type":"LocalOrGlobalAddr"}, -"104":{ -"Label":"more_ascii","Value":4200,"Source":"User","Type":"LocalOrGlobalAddr"}}, +"112":{ +"Label":"more_ascii","Value":4208,"Source":"User","Type":"LocalOrGlobalAddr"}}, "OperandFormats":{ "4":{ "Length":2,"Format":"NumericLE","SubFormat":"Hex","SymbolRef":null}, @@ -93,33 +93,43 @@ "92":{ "Length":2,"Format":"NumericLE","SubFormat":"Ascii","SymbolRef":null}, "94":{ -"Length":3,"Format":"NumericLE","SubFormat":"Ascii","SymbolRef":null}, -"97":{ -"Length":3,"Format":"NumericLE","SubFormat":"Ascii","SymbolRef":null}, -"104":{ -"Length":1,"Format":"NumericLE","SubFormat":"Ascii","SymbolRef":null}, -"105":{ -"Length":1,"Format":"NumericLE","SubFormat":"Ascii","SymbolRef":null}, -"106":{ "Length":2,"Format":"NumericLE","SubFormat":"Ascii","SymbolRef":null}, -"109":{ -"Length":2,"Format":"NumericLE","SubFormat":"Address","SymbolRef":null}, -"111":{ -"Length":3,"Format":"NumericLE","SubFormat":"Address","SymbolRef":null}, +"96":{ +"Length":2,"Format":"NumericLE","SubFormat":"Ascii","SymbolRef":null}, +"98":{ +"Length":2,"Format":"NumericLE","SubFormat":"Ascii","SymbolRef":null}, +"100":{ +"Length":2,"Format":"NumericLE","SubFormat":"Ascii","SymbolRef":null}, +"102":{ +"Length":3,"Format":"NumericLE","SubFormat":"Ascii","SymbolRef":null}, +"105":{ +"Length":3,"Format":"NumericLE","SubFormat":"Ascii","SymbolRef":null}, +"108":{ +"Length":3,"Format":"NumericLE","SubFormat":"Ascii","SymbolRef":null}, +"112":{ +"Length":1,"Format":"NumericLE","SubFormat":"Ascii","SymbolRef":null}, +"113":{ +"Length":1,"Format":"NumericLE","SubFormat":"Ascii","SymbolRef":null}, "114":{ +"Length":2,"Format":"NumericLE","SubFormat":"Ascii","SymbolRef":null}, +"117":{ +"Length":2,"Format":"NumericLE","SubFormat":"Address","SymbolRef":null}, +"119":{ +"Length":3,"Format":"NumericLE","SubFormat":"Address","SymbolRef":null}, +"122":{ "Length":2,"Format":"NumericBE","SubFormat":"Address","SymbolRef":null}, -"116":{ +"124":{ "Length":1,"Format":"NumericLE","SubFormat":"Symbol","SymbolRef":{ "Label":"more_ascii","Part":"Low"}}, -"117":{ +"125":{ "Length":1,"Format":"NumericLE","SubFormat":"Symbol","SymbolRef":{ "Label":"more_ascii","Part":"High"}}, -"118":{ +"126":{ "Length":2,"Format":"NumericLE","SubFormat":"Symbol","SymbolRef":{ "Label":"more_ascii","Part":"Low"}}, -"120":{ +"128":{ "Length":3,"Format":"NumericLE","SubFormat":"Symbol","SymbolRef":{ "Label":"more_ascii","Part":"Low"}}, -"123":{ +"131":{ "Length":2,"Format":"NumericBE","SubFormat":"Symbol","SymbolRef":{ "Label":"more_ascii","Part":"Low"}}}} diff --git a/SourceGen/SGTestData/Expected/2006-operand-formats_64tass.S b/SourceGen/SGTestData/Expected/2006-operand-formats_64tass.S index 32692af..b9ad953 100644 --- a/SourceGen/SGTestData/Expected/2006-operand-formats_64tass.S +++ b/SourceGen/SGTestData/Expected/2006-operand-formats_64tass.S @@ -36,11 +36,15 @@ skipdata lda #'h' lda @l'h' lda #$1f lda #' ' + lda #'"' + lda #$27 lda #'~' lda #$7f lda #$80 lda #$9f lda #' ' | $80 + lda #'"' | $80 + lda #$a7 lda #'~' | $80 lda #$ff rep #'0' @@ -62,4 +66,4 @@ more_ascii .byte 'h' .byte >more_ascii .word more_ascii .long more_ascii - .byte $10,$68 + .byte $10,$70 diff --git a/SourceGen/SGTestData/Expected/2006-operand-formats_Merlin32.S b/SourceGen/SGTestData/Expected/2006-operand-formats_Merlin32.S index de1e087..0badf05 100644 --- a/SourceGen/SGTestData/Expected/2006-operand-formats_Merlin32.S +++ b/SourceGen/SGTestData/Expected/2006-operand-formats_Merlin32.S @@ -33,11 +33,15 @@ skipdata lda #'h' ldal 'h' lda #$1f lda #' ' + lda #'"' + lda #$27 lda #'~' lda #$7f lda #$80 lda #$9f lda #" " + lda #$a2 + lda #"'" lda #"~" lda #$ff rep #'0' diff --git a/SourceGen/SGTestData/Expected/2006-operand-formats_acme.S b/SourceGen/SGTestData/Expected/2006-operand-formats_acme.S index dce937a..59edf2f 100644 --- a/SourceGen/SGTestData/Expected/2006-operand-formats_acme.S +++ b/SourceGen/SGTestData/Expected/2006-operand-formats_acme.S @@ -36,11 +36,15 @@ skipdata lda #'h' lda+3 'h' lda #$1f lda #' ' + lda #'"' + lda #$27 lda #'~' lda #$7f lda #$80 lda #$9f lda #' ' | $80 + lda #'"' | $80 + lda #$a7 lda #'~' | $80 lda #$ff rep #'0' @@ -62,4 +66,4 @@ more_ascii !byte 'h' !byte >more_ascii !word more_ascii !24 more_ascii - !byte $10,$68 + !byte $10,$70 diff --git a/SourceGen/SGTestData/Expected/2006-operand-formats_cc65.S b/SourceGen/SGTestData/Expected/2006-operand-formats_cc65.S index 67c811c..eb34fd4 100644 --- a/SourceGen/SGTestData/Expected/2006-operand-formats_cc65.S +++ b/SourceGen/SGTestData/Expected/2006-operand-formats_cc65.S @@ -37,11 +37,15 @@ skipdata: lda #'h' lda f:'h' lda #$1f lda #' ' + lda #'"' + lda #$27 lda #'~' lda #$7f lda #$80 lda #$9f lda #' ' | $80 + lda #'"' | $80 + lda #$a7 lda #'~' | $80 lda #$ff rep #'0' diff --git a/SourceGen/SGTestData/Expected/2006-operand-formats_cc65.cfg b/SourceGen/SGTestData/Expected/2006-operand-formats_cc65.cfg index cb230fa..b689faf 100644 --- a/SourceGen/SGTestData/Expected/2006-operand-formats_cc65.cfg +++ b/SourceGen/SGTestData/Expected/2006-operand-formats_cc65.cfg @@ -1,7 +1,7 @@ # 6502bench SourceGen generated linker script for 2006-operand-formats MEMORY { MAIN: file=%O, start=%S, size=65536; -# MEM000: file=%O, start=$1000, size=125; +# MEM000: file=%O, start=$1000, size=133; } SEGMENTS { CODE: load=MAIN, type=rw; diff --git a/SourceGen/SGTestData/Source/2006-operand-formats.S b/SourceGen/SGTestData/Source/2006-operand-formats.S index dd4f8aa..9a027bd 100644 --- a/SourceGen/SGTestData/Source/2006-operand-formats.S +++ b/SourceGen/SGTestData/Source/2006-operand-formats.S @@ -43,11 +43,15 @@ lda #$1f lda #$20 + lda #$22 + lda #$27 lda #$7e lda #$7f lda #$80 lda #$9f lda #$a0 + lda #$a2 + lda #$a7 lda #$fe lda #$ff