1
0
mirror of https://github.com/fadden/6502bench.git synced 2024-11-26 06:49:19 +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:
Andy McFadden 2019-11-15 20:40:14 -08:00
parent be65f280a3
commit 8273631917
9 changed files with 185 additions and 28 deletions

View File

@ -77,6 +77,7 @@ namespace SourceGen {
// Symbol-list window options. // Symbol-list window options.
public const string SYMWIN_SHOW_USER = "symwin-show-user"; 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_AUTO = "symwin-show-auto";
public const string SYMWIN_SHOW_PROJECT = "symwin-show-project"; public const string SYMWIN_SHOW_PROJECT = "symwin-show-project";
public const string SYMWIN_SHOW_PLATFORM = "symwin-show-platform"; public const string SYMWIN_SHOW_PLATFORM = "symwin-show-platform";

View File

@ -308,11 +308,12 @@ namespace SourceGen {
// actually used is expected to do something reasonable by default. // actually used is expected to do something reasonable by default.
settings.SetBool(AppSettings.SYMWIN_SHOW_USER, true); 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_PROJECT, true);
settings.SetBool(AppSettings.SYMWIN_SHOW_PLATFORM, false); settings.SetBool(AppSettings.SYMWIN_SHOW_PLATFORM, false);
settings.SetBool(AppSettings.SYMWIN_SHOW_AUTO, 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_ADDR, true);
settings.SetBool(AppSettings.SYMWIN_SHOW_CONST, true);
settings.SetBool(AppSettings.SYMWIN_SORT_ASCENDING, true); settings.SetBool(AppSettings.SYMWIN_SORT_ASCENDING, true);
settings.SetInt(AppSettings.SYMWIN_SORT_COL, (int)Symbol.SymbolSortField.Name); settings.SetInt(AppSettings.SYMWIN_SORT_COL, (int)Symbol.SymbolSortField.Name);
@ -502,6 +503,8 @@ namespace SourceGen {
// Configure the Symbols window. // Configure the Symbols window.
mMainWin.SymFilterUserLabels = mMainWin.SymFilterUserLabels =
settings.GetBool(AppSettings.SYMWIN_SHOW_USER, false); settings.GetBool(AppSettings.SYMWIN_SHOW_USER, false);
mMainWin.SymFilterNonUniqueLabels =
settings.GetBool(AppSettings.SYMWIN_SHOW_NON_UNIQUE, false);
mMainWin.SymFilterAutoLabels = mMainWin.SymFilterAutoLabels =
settings.GetBool(AppSettings.SYMWIN_SHOW_AUTO, false); settings.GetBool(AppSettings.SYMWIN_SHOW_AUTO, false);
mMainWin.SymFilterProjectSymbols = mMainWin.SymFilterProjectSymbols =

View File

@ -279,7 +279,7 @@ namespace SourceGen {
public SerSymbol() { } public SerSymbol() { }
public SerSymbol(Symbol sym) { public SerSymbol(Symbol sym) {
Label = sym.Label; Label = sym.LabelForSerialization; // use bare label here
Value = sym.Value; Value = sym.Value;
Source = sym.SymbolSource.ToString(); Source = sym.SymbolSource.ToString();
Type = sym.SymbolType.ToString(); Type = sym.SymbolType.ToString();
@ -308,7 +308,7 @@ namespace SourceGen {
public SerWeakSymbolRef() { } public SerWeakSymbolRef() { }
public SerWeakSymbolRef(WeakSymbolRef weakSym) { public SerWeakSymbolRef(WeakSymbolRef weakSym) {
Label = weakSym.Label; Label = weakSym.Label; // retain non-unique tag in weak refs
Part = weakSym.ValuePart.ToString(); Part = weakSym.ValuePart.ToString();
} }
} }
@ -642,7 +642,7 @@ namespace SourceGen {
continue; continue;
} }
if (!CreateSymbol(kvp.Value, report, out Symbol newSym)) { if (!CreateSymbol(kvp.Value, intKey, report, out Symbol newSym)) {
continue; continue;
} }
if (newSym.SymbolSource != Symbol.Source.User) { 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 // 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). // can't test UserLabels.ContainsValue (which might be a linear search anyway).
// Dump the labels into a sorted list. // 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, report.Add(FileLoadItem.Type.Warning,
string.Format(Res.Strings.ERR_DUPLICATE_LABEL_FMT, string.Format(Res.Strings.ERR_DUPLICATE_LABEL_FMT, newSym.Label, intKey));
kvp.Value.Label, intKey));
continue; continue;
} }
labelDupCheck.Add(kvp.Value.Label, string.Empty); labelDupCheck.Add(newSym.Label, string.Empty);
proj.UserLabels[intKey] = newSym; proj.UserLabels[intKey] = newSym;
} }
@ -720,11 +722,13 @@ namespace SourceGen {
/// is generated in the FileLoadReport. /// is generated in the FileLoadReport.
/// </summary> /// </summary>
/// <param name="ssym">Deserialized data.</param> /// <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="report">Error report object.</param>
/// <param name="outSym">Created symbol.</param> /// <param name="outSym">Created symbol.</param>
/// <returns>True on success.</returns> /// <returns>True on success.</returns>
private static bool CreateSymbol(SerSymbol ssym, FileLoadReport report, private static bool CreateSymbol(SerSymbol ssym, int userLabelOffset,
out Symbol outSym) { FileLoadReport report, out Symbol outSym) {
outSym = null; outSym = null;
Symbol.Source source; Symbol.Source source;
Symbol.Type type; Symbol.Type type;
@ -736,12 +740,27 @@ namespace SourceGen {
labelAnno = (Symbol.LabelAnnotation)Enum.Parse( labelAnno = (Symbol.LabelAnnotation)Enum.Parse(
typeof(Symbol.LabelAnnotation), ssym.LabelAnno); 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) { } catch (ArgumentException) {
report.Add(FileLoadItem.Type.Warning, Res.Strings.ERR_BAD_SYMBOL_ST + report.Add(FileLoadItem.Type.Warning, Res.Strings.ERR_BAD_SYMBOL_ST +
": " + ssym.Source + "/" + ssym.Type); ": " + ssym.Source + "/" + ssym.Type);
return false; 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); outSym = new Symbol(ssym.Label, ssym.Value, source, type, labelAnno);
}
return true; return true;
} }
@ -757,7 +776,7 @@ namespace SourceGen {
FileLoadReport report, out DefSymbol outDefSym) { FileLoadReport report, out DefSymbol outDefSym) {
outDefSym = null; outDefSym = null;
if (!CreateSymbol(serDefSym, report, out Symbol sym)) { if (!CreateSymbol(serDefSym, -1, report, out Symbol sym)) {
return false; return false;
} }
if (!CreateFormatDescriptor(serDefSym.DataDescriptor, contentVersion, report, if (!CreateFormatDescriptor(serDefSym.DataDescriptor, contentVersion, report,

View File

@ -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_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_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_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_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_ErrBadSymrefPart">Bad symbol reference part</system:String>
<system:String x:Key="str_ErrBadTypeHint">Type hint not recognized</system:String> <system:String x:Key="str_ErrBadTypeHint">Type hint not recognized</system:String>

View File

@ -81,6 +81,8 @@ namespace SourceGen.Res {
(string)Application.Current.FindResource("str_ErrBadLvTableFmt"); (string)Application.Current.FindResource("str_ErrBadLvTableFmt");
public static string ERR_BAD_RANGE = public static string ERR_BAD_RANGE =
(string)Application.Current.FindResource("str_ErrBadRange"); (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 = public static string ERR_BAD_SYMBOL_ST =
(string)Application.Current.FindResource("str_ErrBadSymbolSt"); (string)Application.Current.FindResource("str_ErrBadSymbolSt");
public static string ERR_BAD_SYMREF_PART = public static string ERR_BAD_SYMREF_PART =

View 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

View File

@ -118,6 +118,19 @@ namespace SourceGen {
public string SourceTypeString { get; private set; } 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> /// <summary>
/// True if the symbol's type is an internal label (auto or user). Will be false /// True if the symbol's type is an internal label (auto or user). Will be false
/// for external addresses (including variables) and constants. /// for external addresses (including variables) and constants.
@ -234,26 +247,41 @@ namespace SourceGen {
} }
/// <summary> /// <summary>
/// Converts a label to displayable form by stripping the uniquification tag (if any) /// 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. /// inserting the non-unique label prefix if appropriate, and appending the optional
/// annotation character.
/// </summary> /// </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 /// <param name="label">Base label string. Has the uniquification tag, but no
/// annotation char or non-unique prefix.</param> /// annotation char or non-unique prefix.</param>
/// <param name="anno">Annotation; may be None.</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> /// <returns>Formatted label.</returns>
public static string ConvertLabelForDisplay(string label, LabelAnnotation anno, 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); StringBuilder sb = new StringBuilder(label.Length + 2);
if (isNonUnique) { if (showNonUnique) {
sb.Append(formatter.NonUniqueLabelPrefix); sb.Append(formatter.NonUniqueLabelPrefix);
} }
// NOTE: could make this a length check + label[Length - NON_UNIQUE_LEN] if (label.Length > NON_UNIQUE_LEN &&
int nbrk = label.IndexOf(UNIQUE_TAG_CHAR); label[label.Length - NON_UNIQUE_LEN] == UNIQUE_TAG_CHAR) {
if (nbrk >= 0) { // showNonUnique may be false if generating assembly code (but by this
Debug.Assert(nbrk == label.Length - NON_UNIQUE_LEN); // point the unique tag should be remapped away)
sb.Append(label.Substring(0, nbrk)); sb.Append(label.Substring(0, label.Length - NON_UNIQUE_LEN));
} else { } else {
sb.Append(label); sb.Append(label);
} }
@ -273,7 +301,8 @@ namespace SourceGen {
/// </summary> /// </summary>
/// <param name="label">Label to examine.</param> /// <param name="label">Label to examine.</param>
/// <param name="nonUniquePrefix">For address symbols, the prefix string for /// <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="isValid">True if the entire label is valid.</param>
/// <param name="isLenValid">True if the label has a valid length.</param> /// <param name="isLenValid">True if the label has a valid length.</param>
/// <param name="isFirstCharValid">True if the first character is valid.</param> /// <param name="isFirstCharValid">True if the first character is valid.</param>

View File

@ -702,6 +702,8 @@ limitations under the License.
<WrapPanel Grid.Row="0"> <WrapPanel Grid.Row="0">
<ToggleButton Content="User" Width="40" Margin="2,2" <ToggleButton Content="User" Width="40" Margin="2,2"
IsChecked="{Binding SymFilterUserLabels}"/> IsChecked="{Binding SymFilterUserLabels}"/>
<ToggleButton Content="NonU" Width="40" Margin="2,2"
IsChecked="{Binding SymFilterNonUniqueLabels}"/>
<ToggleButton Content="Proj" Width="40" Margin="2,2" <ToggleButton Content="Proj" Width="40" Margin="2,2"
IsChecked="{Binding SymFilterProjectSymbols}"/> IsChecked="{Binding SymFilterProjectSymbols}"/>
<ToggleButton Content="Plat" Width="40" Margin="2,2" <ToggleButton Content="Plat" Width="40" Margin="2,2"

View File

@ -1554,6 +1554,8 @@ namespace SourceGen.WpfGui {
// //
// Symbols list filter options. // Symbols list filter options.
// //
private bool mSymFilterUserLabels;
public bool SymFilterUserLabels { public bool SymFilterUserLabels {
get { return mSymFilterUserLabels; } get { return mSymFilterUserLabels; }
set { set {
@ -1563,7 +1565,17 @@ namespace SourceGen.WpfGui {
OnPropertyChanged(); 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 { public bool SymFilterProjectSymbols {
get { return mSymFilterProjectSymbols; } get { return mSymFilterProjectSymbols; }
set { set {
@ -1573,7 +1585,7 @@ namespace SourceGen.WpfGui {
OnPropertyChanged(); OnPropertyChanged();
} }
} }
private bool mSymFilterProjectSymbols; private bool mSymFilterPlatformSymbols;
public bool SymFilterPlatformSymbols { public bool SymFilterPlatformSymbols {
get { return mSymFilterPlatformSymbols; } get { return mSymFilterPlatformSymbols; }
set { set {
@ -1583,7 +1595,7 @@ namespace SourceGen.WpfGui {
OnPropertyChanged(); OnPropertyChanged();
} }
} }
private bool mSymFilterPlatformSymbols; private bool mSymFilterAutoLabels;
public bool SymFilterAutoLabels { public bool SymFilterAutoLabels {
get { return mSymFilterAutoLabels; } get { return mSymFilterAutoLabels; }
set { set {
@ -1593,7 +1605,7 @@ namespace SourceGen.WpfGui {
OnPropertyChanged(); OnPropertyChanged();
} }
} }
private bool mSymFilterAutoLabels; private bool mSymFilterAddresses;
public bool SymFilterAddresses { public bool SymFilterAddresses {
get { return mSymFilterAddresses; } get { return mSymFilterAddresses; }
set { set {
@ -1603,7 +1615,7 @@ namespace SourceGen.WpfGui {
OnPropertyChanged(); OnPropertyChanged();
} }
} }
private bool mSymFilterAddresses; private bool mSymFilterConstants;
public bool SymFilterConstants { public bool SymFilterConstants {
get { return mSymFilterConstants; } get { return mSymFilterConstants; }
set { set {
@ -1613,7 +1625,6 @@ namespace SourceGen.WpfGui {
OnPropertyChanged(); OnPropertyChanged();
} }
} }
private bool mSymFilterConstants;
/// <summary> /// <summary>
/// Symbols list DataGrid item. /// Symbols list DataGrid item.
@ -1659,6 +1670,7 @@ namespace SourceGen.WpfGui {
return; return;
} }
if ((SymFilterUserLabels != true && sli.Sym.SymbolSource == Symbol.Source.User) || if ((SymFilterUserLabels != true && sli.Sym.SymbolSource == Symbol.Source.User) ||
(SymFilterNonUniqueLabels != true && sli.Sym.IsNonUnique) ||
(SymFilterProjectSymbols != true && sli.Sym.SymbolSource == Symbol.Source.Project) || (SymFilterProjectSymbols != true && sli.Sym.SymbolSource == Symbol.Source.Project) ||
(SymFilterPlatformSymbols != true && sli.Sym.SymbolSource == Symbol.Source.Platform) || (SymFilterPlatformSymbols != true && sli.Sym.SymbolSource == Symbol.Source.Platform) ||
(SymFilterAutoLabels != true && sli.Sym.SymbolSource == Symbol.Source.Auto) || (SymFilterAutoLabels != true && sli.Sym.SymbolSource == Symbol.Source.Auto) ||