mirror of
https://github.com/fadden/6502bench.git
synced 2024-11-25 14:34:27 +00:00
Label rework, part 3
Added serialization of non-unique labels to project files. The address labels are stored without the non-unique tag, because we can get that from the file offset. (If we stored it, we'd need to extract the value and verify that it matches the offset.) Operand weak references are symbolic, and so do include the tag string. We weren't validating symbol labels before. Now we are. This also adds a "NonU" filter to the Symbols window so the labels can be shown or hidden as desired. Also, added source for a first pass at a regression test.
This commit is contained in:
parent
be65f280a3
commit
8273631917
@ -77,6 +77,7 @@ namespace SourceGen {
|
||||
|
||||
// Symbol-list window options.
|
||||
public const string SYMWIN_SHOW_USER = "symwin-show-user";
|
||||
public const string SYMWIN_SHOW_NON_UNIQUE = "symwin-show-non-unique";
|
||||
public const string SYMWIN_SHOW_AUTO = "symwin-show-auto";
|
||||
public const string SYMWIN_SHOW_PROJECT = "symwin-show-project";
|
||||
public const string SYMWIN_SHOW_PLATFORM = "symwin-show-platform";
|
||||
|
@ -308,11 +308,12 @@ namespace SourceGen {
|
||||
// actually used is expected to do something reasonable by default.
|
||||
|
||||
settings.SetBool(AppSettings.SYMWIN_SHOW_USER, true);
|
||||
settings.SetBool(AppSettings.SYMWIN_SHOW_NON_UNIQUE, false);
|
||||
settings.SetBool(AppSettings.SYMWIN_SHOW_PROJECT, true);
|
||||
settings.SetBool(AppSettings.SYMWIN_SHOW_PLATFORM, false);
|
||||
settings.SetBool(AppSettings.SYMWIN_SHOW_AUTO, false);
|
||||
settings.SetBool(AppSettings.SYMWIN_SHOW_CONST, true);
|
||||
settings.SetBool(AppSettings.SYMWIN_SHOW_ADDR, true);
|
||||
settings.SetBool(AppSettings.SYMWIN_SHOW_CONST, true);
|
||||
settings.SetBool(AppSettings.SYMWIN_SORT_ASCENDING, true);
|
||||
settings.SetInt(AppSettings.SYMWIN_SORT_COL, (int)Symbol.SymbolSortField.Name);
|
||||
|
||||
@ -502,6 +503,8 @@ namespace SourceGen {
|
||||
// Configure the Symbols window.
|
||||
mMainWin.SymFilterUserLabels =
|
||||
settings.GetBool(AppSettings.SYMWIN_SHOW_USER, false);
|
||||
mMainWin.SymFilterNonUniqueLabels =
|
||||
settings.GetBool(AppSettings.SYMWIN_SHOW_NON_UNIQUE, false);
|
||||
mMainWin.SymFilterAutoLabels =
|
||||
settings.GetBool(AppSettings.SYMWIN_SHOW_AUTO, false);
|
||||
mMainWin.SymFilterProjectSymbols =
|
||||
|
@ -279,7 +279,7 @@ namespace SourceGen {
|
||||
|
||||
public SerSymbol() { }
|
||||
public SerSymbol(Symbol sym) {
|
||||
Label = sym.Label;
|
||||
Label = sym.LabelForSerialization; // use bare label here
|
||||
Value = sym.Value;
|
||||
Source = sym.SymbolSource.ToString();
|
||||
Type = sym.SymbolType.ToString();
|
||||
@ -308,7 +308,7 @@ namespace SourceGen {
|
||||
|
||||
public SerWeakSymbolRef() { }
|
||||
public SerWeakSymbolRef(WeakSymbolRef weakSym) {
|
||||
Label = weakSym.Label;
|
||||
Label = weakSym.Label; // retain non-unique tag in weak refs
|
||||
Part = weakSym.ValuePart.ToString();
|
||||
}
|
||||
}
|
||||
@ -642,7 +642,7 @@ namespace SourceGen {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!CreateSymbol(kvp.Value, report, out Symbol newSym)) {
|
||||
if (!CreateSymbol(kvp.Value, intKey, report, out Symbol newSym)) {
|
||||
continue;
|
||||
}
|
||||
if (newSym.SymbolSource != Symbol.Source.User) {
|
||||
@ -656,13 +656,15 @@ namespace SourceGen {
|
||||
// Check for duplicate labels. We only want to compare label strings, so we
|
||||
// can't test UserLabels.ContainsValue (which might be a linear search anyway).
|
||||
// Dump the labels into a sorted list.
|
||||
if (labelDupCheck.ContainsKey(kvp.Value.Label)) {
|
||||
//
|
||||
// We want to use newSym.Label rather than kvp.Value.Label, because the latter
|
||||
// won't have the non-unique local tag.
|
||||
if (labelDupCheck.ContainsKey(newSym.Label)) {
|
||||
report.Add(FileLoadItem.Type.Warning,
|
||||
string.Format(Res.Strings.ERR_DUPLICATE_LABEL_FMT,
|
||||
kvp.Value.Label, intKey));
|
||||
string.Format(Res.Strings.ERR_DUPLICATE_LABEL_FMT, newSym.Label, intKey));
|
||||
continue;
|
||||
}
|
||||
labelDupCheck.Add(kvp.Value.Label, string.Empty);
|
||||
labelDupCheck.Add(newSym.Label, string.Empty);
|
||||
|
||||
proj.UserLabels[intKey] = newSym;
|
||||
}
|
||||
@ -720,11 +722,13 @@ namespace SourceGen {
|
||||
/// is generated in the FileLoadReport.
|
||||
/// </summary>
|
||||
/// <param name="ssym">Deserialized data.</param>
|
||||
/// <param name="userLabelOffset">If the symbol is a user label, this is the file offset.
|
||||
/// If not, pass -1. Used for non-unique locals.</param>
|
||||
/// <param name="report">Error report object.</param>
|
||||
/// <param name="outSym">Created symbol.</param>
|
||||
/// <returns>True on success.</returns>
|
||||
private static bool CreateSymbol(SerSymbol ssym, FileLoadReport report,
|
||||
out Symbol outSym) {
|
||||
private static bool CreateSymbol(SerSymbol ssym, int userLabelOffset,
|
||||
FileLoadReport report, out Symbol outSym) {
|
||||
outSym = null;
|
||||
Symbol.Source source;
|
||||
Symbol.Type type;
|
||||
@ -736,12 +740,27 @@ namespace SourceGen {
|
||||
labelAnno = (Symbol.LabelAnnotation)Enum.Parse(
|
||||
typeof(Symbol.LabelAnnotation), ssym.LabelAnno);
|
||||
}
|
||||
if (type == Symbol.Type.NonUniqueLocalAddr && source != Symbol.Source.User) {
|
||||
throw new ArgumentException("unexpected source for non-unique local");
|
||||
}
|
||||
} catch (ArgumentException) {
|
||||
report.Add(FileLoadItem.Type.Warning, Res.Strings.ERR_BAD_SYMBOL_ST +
|
||||
": " + ssym.Source + "/" + ssym.Type);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!Asm65.Label.ValidateLabel(ssym.Label)) {
|
||||
report.Add(FileLoadItem.Type.Warning, Res.Strings.ERR_BAD_SYMBOL_LABEL +
|
||||
": " + ssym.Label);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (type == Symbol.Type.NonUniqueLocalAddr) {
|
||||
outSym = new Symbol(ssym.Label, ssym.Value, labelAnno, userLabelOffset);
|
||||
} else {
|
||||
outSym = new Symbol(ssym.Label, ssym.Value, source, type, labelAnno);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -757,7 +776,7 @@ namespace SourceGen {
|
||||
FileLoadReport report, out DefSymbol outDefSym) {
|
||||
outDefSym = null;
|
||||
|
||||
if (!CreateSymbol(serDefSym, report, out Symbol sym)) {
|
||||
if (!CreateSymbol(serDefSym, -1, report, out Symbol sym)) {
|
||||
return false;
|
||||
}
|
||||
if (!CreateFormatDescriptor(serDefSym.DataDescriptor, contentVersion, report,
|
||||
|
@ -50,6 +50,7 @@ limitations under the License.
|
||||
<system:String x:Key="str_ErrBadLocalVariableFmt">Bad local variable {0}</system:String>
|
||||
<system:String x:Key="str_ErrBadLvTableFmt">Invalid local variable table at +{0:x6}</system:String>
|
||||
<system:String x:Key="str_ErrBadRange">Bad range</system:String>
|
||||
<system:String x:Key="str_ErrBadSymbolLabel">Malformed label in symbol</system:String>
|
||||
<system:String x:Key="str_ErrBadSymbolSt">Unknown Source or Type in symbol</system:String>
|
||||
<system:String x:Key="str_ErrBadSymrefPart">Bad symbol reference part</system:String>
|
||||
<system:String x:Key="str_ErrBadTypeHint">Type hint not recognized</system:String>
|
||||
|
@ -81,6 +81,8 @@ namespace SourceGen.Res {
|
||||
(string)Application.Current.FindResource("str_ErrBadLvTableFmt");
|
||||
public static string ERR_BAD_RANGE =
|
||||
(string)Application.Current.FindResource("str_ErrBadRange");
|
||||
public static string ERR_BAD_SYMBOL_LABEL =
|
||||
(string)Application.Current.FindResource("str_ErrBadSymbolLabel");
|
||||
public static string ERR_BAD_SYMBOL_ST =
|
||||
(string)Application.Current.FindResource("str_ErrBadSymbolSt");
|
||||
public static string ERR_BAD_SYMREF_PART =
|
||||
|
88
SourceGen/SGTestData/Source/2023-non-unique-labels.S
Normal file
88
SourceGen/SGTestData/Source/2023-non-unique-labels.S
Normal file
@ -0,0 +1,88 @@
|
||||
; Copyright 2019 faddenSoft. All Rights Reserved.
|
||||
; See the LICENSE.txt file for distribution terms (Apache 2.0).
|
||||
;
|
||||
; Assembler: Merlin 32
|
||||
|
||||
org $1000
|
||||
|
||||
; Test conflict with auto-label.
|
||||
start lda #$00 ;do not label
|
||||
:L1000 lda #$01 ;EDIT: set label to :L1000 (dup of auto)
|
||||
ldx start
|
||||
ldy :L1000
|
||||
|
||||
; Test local/global having same name.
|
||||
ldx #$02
|
||||
loop1 dex ;EDIT
|
||||
bne loop1
|
||||
|
||||
ldx #$03
|
||||
:loop1 dex ;EDIT
|
||||
bne :loop1
|
||||
|
||||
; Test nested loops, and ref to a non-unique local on the other side
|
||||
; of a global.
|
||||
global1 nop ;EDIT
|
||||
ldx #$04
|
||||
:loop1 ldy #$05 ;EDIT: local, name "loop"
|
||||
|
||||
:loop2 dey ;EDIT: local, name "loop"
|
||||
bne :loop2
|
||||
dex
|
||||
bne :loop1
|
||||
jmp btarg
|
||||
|
||||
global2 nop ;EDIT
|
||||
|
||||
btarg nop ;EDIT: local, name "loop"
|
||||
|
||||
; Test hand-over-hand locals branching forward.
|
||||
global3 nop ;EDIT
|
||||
ldx #$06
|
||||
ldy #$07
|
||||
dex
|
||||
beq :fwd1
|
||||
dey
|
||||
beq :fwd2
|
||||
:fwd1 nop ;EDIT
|
||||
:fwd2 nop ;EDIT
|
||||
|
||||
; Test loop with a global in the middle.
|
||||
global4 nop ;EDIT
|
||||
ldx #$08
|
||||
gloop dex ;EDIT: local, name "loop"
|
||||
global5 nop
|
||||
bne gloop
|
||||
|
||||
nop
|
||||
|
||||
; Test symbolic references.
|
||||
|
||||
global6 nop
|
||||
:spin1 jsr :spin2 ;EDIT: local, name "spin1", operand ref to ":spin2"
|
||||
:spin2 jsr :spin1 ;EDIT: local, name "spin2", operand ref to ":spin1"
|
||||
nop
|
||||
:spin3 lda :spin3 ;EDIT: local, name "spin1", operand ref to ":spin1"
|
||||
|
||||
; Semi-related: test labels that are nothing but underscores.
|
||||
global_ nop
|
||||
ldx #$40
|
||||
__ dex
|
||||
bne __
|
||||
beq ___
|
||||
___ ldx #$41
|
||||
:__ dex
|
||||
bne :__
|
||||
|
||||
nop
|
||||
|
||||
; Semi-related: test annotations (mostly to confirm that the suffix chars
|
||||
; aren't appearing in the assembly output)
|
||||
anno lda #$42 ;EDIT: add '?'
|
||||
anno1 lda anno
|
||||
|
||||
|
||||
rts
|
||||
|
||||
dw anno1 ;EDIT: use table generator
|
||||
|
@ -118,6 +118,19 @@ namespace SourceGen {
|
||||
public string SourceTypeString { get; private set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Label without the non-unique tag.
|
||||
/// </summary>
|
||||
public string LabelForSerialization {
|
||||
get {
|
||||
if (SymbolType != Type.NonUniqueLocalAddr) {
|
||||
return Label;
|
||||
} else {
|
||||
return Label.Substring(0, Label.Length - NON_UNIQUE_LEN);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// True if the symbol's type is an internal label (auto or user). Will be false
|
||||
/// for external addresses (including variables) and constants.
|
||||
@ -234,26 +247,41 @@ namespace SourceGen {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts a label to displayable form by stripping the uniquification tag (if any)
|
||||
/// and appending the optional annotation. This is needed for display of WeakSymbolRefs.
|
||||
/// Converts a label to displayable form by stripping the uniquification tag (if any),
|
||||
/// inserting the non-unique label prefix if appropriate, and appending the optional
|
||||
/// annotation character.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// There's generally two ways to display a label:
|
||||
/// (1) When displaying labels on-screen, we get a label with the uniquification tag,
|
||||
/// and we want to show the non-unique label prefix ('@' or ':') and annotation.
|
||||
/// (2) When generating assembly source, we get a remapped label with no uniquification
|
||||
/// tag, and we don't want to show the prefix or annotation.
|
||||
/// For case #2, there's no reason to call here. (We're currently doing so because
|
||||
/// remapping isn't happening yet, but that should change soon. When that happens, we
|
||||
/// should be able to eliminate the showNonUnique arg.)
|
||||
/// </remarks>
|
||||
/// <param name="label">Base label string. Has the uniquification tag, but no
|
||||
/// annotation char or non-unique prefix.</param>
|
||||
/// <param name="anno">Annotation; may be None.</param>
|
||||
/// <param name="showNonUnique">Set true if the returned label should show the
|
||||
/// non-unique label prefix.</param>
|
||||
/// <param name="formatter">Format object that holds the non-unique label prefix
|
||||
/// string.</param>
|
||||
/// <returns>Formatted label.</returns>
|
||||
public static string ConvertLabelForDisplay(string label, LabelAnnotation anno,
|
||||
bool isNonUnique, Asm65.Formatter formatter) {
|
||||
bool showNonUnique, Asm65.Formatter formatter) {
|
||||
StringBuilder sb = new StringBuilder(label.Length + 2);
|
||||
|
||||
if (isNonUnique) {
|
||||
if (showNonUnique) {
|
||||
sb.Append(formatter.NonUniqueLabelPrefix);
|
||||
}
|
||||
|
||||
// NOTE: could make this a length check + label[Length - NON_UNIQUE_LEN]
|
||||
int nbrk = label.IndexOf(UNIQUE_TAG_CHAR);
|
||||
if (nbrk >= 0) {
|
||||
Debug.Assert(nbrk == label.Length - NON_UNIQUE_LEN);
|
||||
sb.Append(label.Substring(0, nbrk));
|
||||
if (label.Length > NON_UNIQUE_LEN &&
|
||||
label[label.Length - NON_UNIQUE_LEN] == UNIQUE_TAG_CHAR) {
|
||||
// showNonUnique may be false if generating assembly code (but by this
|
||||
// point the unique tag should be remapped away)
|
||||
sb.Append(label.Substring(0, label.Length - NON_UNIQUE_LEN));
|
||||
} else {
|
||||
sb.Append(label);
|
||||
}
|
||||
@ -273,7 +301,8 @@ namespace SourceGen {
|
||||
/// </summary>
|
||||
/// <param name="label">Label to examine.</param>
|
||||
/// <param name="nonUniquePrefix">For address symbols, the prefix string for
|
||||
/// non-unique labels. May be null if not validating a user label.</param>
|
||||
/// non-unique labels (e.g. '@' or ':'). May be null if not validating a user
|
||||
/// label.</param>
|
||||
/// <param name="isValid">True if the entire label is valid.</param>
|
||||
/// <param name="isLenValid">True if the label has a valid length.</param>
|
||||
/// <param name="isFirstCharValid">True if the first character is valid.</param>
|
||||
|
@ -702,6 +702,8 @@ limitations under the License.
|
||||
<WrapPanel Grid.Row="0">
|
||||
<ToggleButton Content="User" Width="40" Margin="2,2"
|
||||
IsChecked="{Binding SymFilterUserLabels}"/>
|
||||
<ToggleButton Content="NonU" Width="40" Margin="2,2"
|
||||
IsChecked="{Binding SymFilterNonUniqueLabels}"/>
|
||||
<ToggleButton Content="Proj" Width="40" Margin="2,2"
|
||||
IsChecked="{Binding SymFilterProjectSymbols}"/>
|
||||
<ToggleButton Content="Plat" Width="40" Margin="2,2"
|
||||
|
@ -1554,6 +1554,8 @@ namespace SourceGen.WpfGui {
|
||||
//
|
||||
// Symbols list filter options.
|
||||
//
|
||||
|
||||
private bool mSymFilterUserLabels;
|
||||
public bool SymFilterUserLabels {
|
||||
get { return mSymFilterUserLabels; }
|
||||
set {
|
||||
@ -1563,7 +1565,17 @@ namespace SourceGen.WpfGui {
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
private bool mSymFilterUserLabels;
|
||||
private bool mSymFilterNonUniqueLabels;
|
||||
public bool SymFilterNonUniqueLabels {
|
||||
get { return mSymFilterNonUniqueLabels; }
|
||||
set {
|
||||
mSymFilterNonUniqueLabels = value;
|
||||
AppSettings.Global.SetBool(AppSettings.SYMWIN_SHOW_NON_UNIQUE, value);
|
||||
SymbolsListFilterChanged();
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
private bool mSymFilterProjectSymbols;
|
||||
public bool SymFilterProjectSymbols {
|
||||
get { return mSymFilterProjectSymbols; }
|
||||
set {
|
||||
@ -1573,7 +1585,7 @@ namespace SourceGen.WpfGui {
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
private bool mSymFilterProjectSymbols;
|
||||
private bool mSymFilterPlatformSymbols;
|
||||
public bool SymFilterPlatformSymbols {
|
||||
get { return mSymFilterPlatformSymbols; }
|
||||
set {
|
||||
@ -1583,7 +1595,7 @@ namespace SourceGen.WpfGui {
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
private bool mSymFilterPlatformSymbols;
|
||||
private bool mSymFilterAutoLabels;
|
||||
public bool SymFilterAutoLabels {
|
||||
get { return mSymFilterAutoLabels; }
|
||||
set {
|
||||
@ -1593,7 +1605,7 @@ namespace SourceGen.WpfGui {
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
private bool mSymFilterAutoLabels;
|
||||
private bool mSymFilterAddresses;
|
||||
public bool SymFilterAddresses {
|
||||
get { return mSymFilterAddresses; }
|
||||
set {
|
||||
@ -1603,7 +1615,7 @@ namespace SourceGen.WpfGui {
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
private bool mSymFilterAddresses;
|
||||
private bool mSymFilterConstants;
|
||||
public bool SymFilterConstants {
|
||||
get { return mSymFilterConstants; }
|
||||
set {
|
||||
@ -1613,7 +1625,6 @@ namespace SourceGen.WpfGui {
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
private bool mSymFilterConstants;
|
||||
|
||||
/// <summary>
|
||||
/// Symbols list DataGrid item.
|
||||
@ -1659,6 +1670,7 @@ namespace SourceGen.WpfGui {
|
||||
return;
|
||||
}
|
||||
if ((SymFilterUserLabels != true && sli.Sym.SymbolSource == Symbol.Source.User) ||
|
||||
(SymFilterNonUniqueLabels != true && sli.Sym.IsNonUnique) ||
|
||||
(SymFilterProjectSymbols != true && sli.Sym.SymbolSource == Symbol.Source.Project) ||
|
||||
(SymFilterPlatformSymbols != true && sli.Sym.SymbolSource == Symbol.Source.Platform) ||
|
||||
(SymFilterAutoLabels != true && sli.Sym.SymbolSource == Symbol.Source.Auto) ||
|
||||
|
Loading…
Reference in New Issue
Block a user