1
0
mirror of https://github.com/fadden/6502bench.git synced 2024-12-28 16:31:17 +00:00

Label rework, part 6

Correct handling of local variables.  We now correctly uniquify them
with regard to non-unique labels.  Because local vars can effectively
have global scope we mostly want to treat them as global, but they're
uniquified relative to other globals very late in the process, so we
can't just throw them in the symbol table and be done.  Fortunately
local variables exist in a separate namespace, so we just need to
uniquify the variables relative to the post-localization symbol table.
In other words, we take the symbol table, apply the label map, and
rename any variable that clashes.

This also fixes an older problem where we weren't masking the
leading '_' on variable labels when generating 64tass output.

The code list now makes non-unique labels obvious, but you can't tell
the difference between unique global and unique local.  What's more,
the default type value in Edit Label is now adjusted to Global for
unique locals that were auto-generated.  To make it a bit easier to
figure out what's what, the Info panel now has a "label type" line
that reports the type.

The 2023-non-unique-labels test had some additional tests added to
exercise conflicts with local variables.  The 2019-local-variables
test output changed slightly because the de-duplicated variable
naming convention was simplified.
This commit is contained in:
Andy McFadden 2019-11-18 13:26:03 -08:00
parent 88c56616f7
commit d3670c48e8
30 changed files with 317 additions and 92 deletions

View File

@ -163,6 +163,7 @@ namespace SourceGen.AsmGen {
Project = project;
Quirks = new AssemblerQuirks();
Quirks.StackIntOperandIsImmediate = true;
Quirks.LeadingUnderscoreSpecial = true;
mWorkDirectory = workDirectory;
mFileNameBase = fileNameBase;

View File

@ -40,6 +40,7 @@ namespace SourceGen.AsmGen {
bool doAddCycles = gen.Settings.GetBool(AppSettings.SRCGEN_SHOW_CYCLE_COUNTS, false);
LocalVariableLookup lvLookup = new LocalVariableLookup(proj.LvTables, proj,
gen.Localizer.LabelMap, gen.Quirks.LeadingUnderscoreSpecial,
gen.Quirks.NoRedefinableSymbols);
GenerateHeader(gen, sw);

View File

@ -201,6 +201,11 @@ namespace SourceGen.AsmGen {
/// Enumeration of quirky or buggy behavior that GenCommon needs to handle.
/// </summary>
public class AssemblerQuirks {
/// <summary>
/// Does a leading underscore in a label have a special meaning? (e.g. 64tass)
/// </summary>
public bool LeadingUnderscoreSpecial { get; set; }
/// <summary>
/// Are 8-bit constant args to MVN/MVP output without a leading '#'?
/// </summary>

View File

@ -43,7 +43,8 @@ Another common form allows backward references to labels that don't go out of sc
they're re-used. This is useful for short loops. (We use this for variables.)
As a further limitation, assemblers seem to want the first label encountered in a program
to be global.
to be global. On the plus side, all tested assemblers treat local labels as existing in
a separate namespace, so you can have both "loop" and ":loop".
The Symbol.SymbolType enum allows a label to be defined as "local or global". We can output
these with the local-symbol syntax, potentially rewriting them to have non-unique names like
@ -80,7 +81,7 @@ namespace SourceGen.AsmGen {
public class LabelLocalizer {
// Prefix string to use for labels that start with '_' when generating code for
// assemblers that assign a special meaning to leading underscores.
private const string NO_UNDER_PFX = "X";
public const string NO_UNDER_PFX = "X";
/// <summary>
/// A pairing of an offset with a label string. (Essentially mAnattribs[n].Symbol

View File

@ -1179,7 +1179,8 @@ namespace SourceGen {
/// for the benefit of future uniqueness checks.
/// </summary>
private void GenerateVariableRefs() {
LocalVariableLookup lvLookup = new LocalVariableLookup(LvTables, this, false);
LocalVariableLookup lvLookup = new LocalVariableLookup(LvTables, this,
null, false, false);
for (int offset = 0; offset < FileData.Length; ) {
// Was a table defined at this offset?
@ -1408,7 +1409,8 @@ namespace SourceGen {
}
}
LocalVariableLookup lvLookup = new LocalVariableLookup(LvTables, this, false);
LocalVariableLookup lvLookup = new LocalVariableLookup(LvTables, this,
null, false, false);
// Walk through the Anattrib array, adding xref entries to things referenced
// by the entity at the current offset.

View File

@ -437,7 +437,7 @@ namespace SourceGen {
mFormattedLineCache = new FormattedOperandCache();
mShowCycleCounts = AppSettings.Global.GetBool(AppSettings.SRCGEN_SHOW_CYCLE_COUNTS,
false);
mLvLookup = new LocalVariableLookup(mProject.LvTables, mProject, false);
mLvLookup = new LocalVariableLookup(mProject.LvTables, mProject, null, false, false);
mDisplayList.ListGen = this;
}

View File

@ -27,8 +27,9 @@ namespace SourceGen {
/// different levels:
/// (1) If the local variable label is present in the main symbol table, we use the
/// "de-duplication" table to remap it. We try not to let this happen, but it can.
/// The symbol table is latched when the object is constructed.
/// (2) If the assembler doesn't define a way to re-use variable names, we make them
/// globally unique. [currently unused]
/// globally unique. [currently not needed]
/// </remarks>
public class LocalVariableLookup {
/// <summary>
@ -36,22 +37,30 @@ namespace SourceGen {
/// </summary>
private SortedList<int, LocalVariableTable> mLvTables;
/// <summary>
/// Table of symbols, used to ensure that symbols are globally unique.
/// </summary>
private SymbolTable mSymbolTable;
/// <summary>
/// Reference to project, so we can query the Anattrib array to identify "hidden" tables.
/// </summary>
private DisasmProject mProject;
/// <summary>
/// Set to true when generating symbols for assemblers like 64tass, which assign a
/// special meaning to labels with leading underscores.
/// </summary>
private bool mMaskLeadingUnderscores;
/// <summary>
/// Set to true if we want all variables to be globally unique (because the assembler
/// can't redefine them).
/// </summary>
private bool mDoUniquify;
/// <summary>
/// List of all non-variable symbols, for uniquification. This is generated from the
/// project symbol table. When generating assembly sources, the labels are transformed
/// through the label map.
/// </summary>
private Dictionary<string, Symbol> mAllNvSymbols;
/// <summary>
/// Label uniquification helper.
///
@ -86,7 +95,7 @@ namespace SourceGen {
/// re-defined.
/// </summary>
/// <param name="symbolTable">Symbol table, for uniqueness check.</param>
public void MakeUnique(SymbolTable symbolTable) {
public void MakeUnique(Dictionary<string, Symbol> allNvSymbols) {
// The main symbol table might have user-supplied labels like "ptr_2", so we
// need to keep testing against that. However, it should not be possible for
// us to clash with other uniquified variables. So we don't need to check
@ -98,7 +107,7 @@ namespace SourceGen {
do {
Counter++;
testLabel = BaseLabel + "_" + Counter;
} while (symbolTable.TryGetValue(testLabel, out Symbol sym));
} while (allNvSymbols.TryGetValue(testLabel, out Symbol unused));
Label = testLabel;
}
}
@ -141,15 +150,18 @@ namespace SourceGen {
/// Constructor.
/// </summary>
/// <param name="lvTables">List of tables from the DisasmProject.</param>
/// <param name="symbolTable">Full SymbolTable from the DisasmProject. Used to
/// generate globally unique symbol names.</param>
/// <param name="project">Project reference.</param>
/// <param name="labelMap">Label map dictionary, used to rename the labels in
/// the project symbol table. May be null.</param>
/// <param name="maskLeadingUnderscores">If true, labels with leading underscores
/// will be prefixed.</param>
/// <param name="uniquify">Set to true if variable names cannot be redefined.</param>
public LocalVariableLookup(SortedList<int, LocalVariableTable> lvTables,
DisasmProject project, bool uniquify) {
DisasmProject project, Dictionary<string, string> labelMap,
bool maskLeadingUnderscores, bool uniquify) {
mLvTables = lvTables;
mSymbolTable = project.SymbolTable;
mProject = project;
mMaskLeadingUnderscores = maskLeadingUnderscores;
mDoUniquify = uniquify;
mCurrentTable = new LocalVariableTable();
@ -157,9 +169,29 @@ namespace SourceGen {
if (uniquify) {
mUniqueLabels = new Dictionary<string, UniqueLabel>();
}
CreateAllSymbolsDict(labelMap);
Reset();
}
private void CreateAllSymbolsDict(Dictionary<string, string> labelMap) {
SymbolTable symTab = mProject.SymbolTable;
mAllNvSymbols = new Dictionary<string, Symbol>(symTab.Count);
foreach (Symbol sym in symTab) {
if (sym.SymbolSource == Symbol.Source.Variable) {
continue;
}
if (labelMap != null && labelMap.TryGetValue(sym.Label, out string newLabel)) {
// Non-unique labels may map multiple entries to a single entry. That's
// fine; our goal here is just to avoid duplication. Besides, any symbols
// being output as locals will have the local prefix character and won't
// be a match.
mAllNvSymbols[newLabel] = sym;
} else {
mAllNvSymbols[sym.Label] = sym;
}
}
}
public void Reset() {
mRecentOffset = -1;
mRecentSymbols = null;
@ -344,15 +376,26 @@ namespace SourceGen {
// discards entries that clash by name or value.
for (int i = 0; i < lvt.Count; i++) {
DefSymbol defSym = lvt[i];
string newLabel = defSym.Label;
if (mMaskLeadingUnderscores && newLabel[0] == '_') {
newLabel = AsmGen.LabelLocalizer.NO_UNDER_PFX + newLabel;
}
// Look for non-variable symbols with the same label. Ordinarily the
// editor prevents this from happening, but there are ways to trick
// the system (e.g. add a symbol while the LvTable is hidden). We
// deal with it here.
if (mSymbolTable.TryGetNonVariableValue(defSym.Label, out Symbol unused)) {
Debug.WriteLine("Detected duplicate non-var label " + defSym.Label +
// the system (e.g. add a symbol while the LvTable is hidden, or have
// a non-unique local promoted to global). We deal with it here.
//
// TODO(someday): this is not necessary for assemblers like Merlin 32
// that put variables in a separate namespace.
if (mAllNvSymbols.TryGetValue(newLabel, out Symbol unused)) {
Debug.WriteLine("Detected duplicate non-var label " + newLabel +
" at +" + mNextLvtOffset.ToString("x6"));
string newLabel = DeDupLabel(defSym.Label);
newLabel = DeDupLabel(newLabel);
}
if (newLabel != defSym.Label) {
mDupRemap[defSym.Label] = newLabel;
defSym = new DefSymbol(defSym, newLabel);
}
@ -361,7 +404,7 @@ namespace SourceGen {
if (mUniqueLabels.TryGetValue(defSym.Label, out UniqueLabel ulab)) {
// We've seen this label before; generate a unique version by
// increasing the appended number.
ulab.MakeUnique(mSymbolTable);
ulab.MakeUnique(mAllNvSymbols);
defSym = new DefSymbol(defSym, ulab.Label);
} else {
// Haven't seen this before. Add it to the unique-labels table.
@ -394,8 +437,8 @@ namespace SourceGen {
int counter = 0;
do {
counter++;
testLabel = baseLabel + "_DUP" + counter; // make it ugly and obvious
} while (mSymbolTable.TryGetNonVariableValue(testLabel, out Symbol unused));
testLabel = baseLabel + "_" + counter;
} while (mAllNvSymbols.TryGetValue(testLabel, out Symbol unused));
return testLabel;
}

View File

@ -1784,8 +1784,8 @@ namespace SourceGen {
int selIndex = mMainWin.CodeListView_GetFirstSelectedIndex();
int offset = CodeLineList[selIndex].FileOffset;
LocalVariableLookup lvLookup = new LocalVariableLookup(mProject.LvTables,
mProject, false);
LocalVariableLookup lvLookup = new LocalVariableLookup(mProject.LvTables, mProject,
null, false, false);
int bestOffset = lvLookup.GetNearestTableOffset(offset);
Debug.Assert(bestOffset >= 0);
CreateOrEditLocalVariableTable(bestOffset);
@ -2507,7 +2507,7 @@ namespace SourceGen {
Debug.Assert(symRef.IsVariable);
LocalVariableLookup lvLookup = new LocalVariableLookup(mProject.LvTables, mProject,
false);
null, false, false);
int varOffset = lvLookup.GetDefiningTableOffset(offset, symRef);
if (varOffset <= 0) {
Debug.WriteLine("Local variable not found; offset=" + offset + " ref=" + symRef);
@ -3565,11 +3565,13 @@ namespace SourceGen {
if (line.IsCodeOrData) {
// Show number of bytes of code/data.
if (line.OffsetSpan == 1) {
mMainWin.InfoLineDescrText = string.Format(Res.Strings.INFO_LINE_SUM_SINGULAR_FMT,
lineIndex, line.OffsetSpan, lineTypeStr);
mMainWin.InfoLineDescrText =
string.Format(Res.Strings.INFO_LINE_SUM_SINGULAR_FMT,
lineIndex, line.OffsetSpan, lineTypeStr);
} else {
mMainWin.InfoLineDescrText = string.Format(Res.Strings.INFO_LINE_SUM_PLURAL_FMT,
lineIndex, line.OffsetSpan, lineTypeStr);
mMainWin.InfoLineDescrText =
string.Format(Res.Strings.INFO_LINE_SUM_PLURAL_FMT,
lineIndex, line.OffsetSpan, lineTypeStr);
}
} else {
mMainWin.InfoLineDescrText = string.Format(Res.Strings.INFO_LINE_SUM_NON_FMT,
@ -3587,7 +3589,11 @@ namespace SourceGen {
string str = string.Empty;
if (mProject.LvTables.TryGetValue(line.FileOffset,
out LocalVariableTable lvt)) {
str = lvt.Count + " entries";
if (lvt.Count == 1) {
str = "1 entry";
} else {
str = lvt.Count + " entries";
}
if (lvt.ClearPrevious) {
str += "; clear previous";
}
@ -3663,6 +3669,34 @@ namespace SourceGen {
StringBuilder sb = new StringBuilder(250);
Anattrib attr = mProject.GetAnattrib(line.FileOffset);
if (attr.Symbol != null) {
string descr;
switch (attr.Symbol.SymbolType) {
case Symbol.Type.NonUniqueLocalAddr:
descr = "non-unique local";
break;
case Symbol.Type.LocalOrGlobalAddr:
descr = "unique local";
break;
case Symbol.Type.GlobalAddr:
descr = "unique global";
break;
case Symbol.Type.GlobalAddrExport:
descr = "global + marked for export";
break;
default:
descr = "???";
break;
}
if (attr.Symbol.SymbolSource == Symbol.Source.Auto) {
descr += ", auto-generated";
} else if (attr.Symbol.LabelAnno == Symbol.LabelAnnotation.Generated) {
descr += " [gen]";
}
mMainWin.InfoLabelDescrText =
string.Format(Res.Strings.INFO_LABEL_DESCR_FMT, descr);
}
if (!mProject.OperandFormats.TryGetValue(line.FileOffset, out FormatDescriptor dfd)) {
// No user-specified format, but there may be a generated format.
mMainWin.InfoFormatBoxBrush = Brushes.Blue;

View File

@ -721,10 +721,6 @@ namespace SourceGen {
if ((flags & FormatNumericOpFlags.OmitLabelPrefixSuffix) == 0) {
symLabel = Symbol.ConvertLabelForDisplay(symLabel, sym.LabelAnno,
true, formatter);
} else {
// TODO(xyzzy): remapper will handle this
symLabel = Symbol.ConvertLabelForDisplay(symLabel, Symbol.LabelAnnotation.None,
false, formatter);
}
if (operandLen == 1) {
@ -864,10 +860,6 @@ namespace SourceGen {
if ((flags & FormatNumericOpFlags.OmitLabelPrefixSuffix) == 0) {
symLabel = Symbol.ConvertLabelForDisplay(symLabel, sym.LabelAnno,
true, formatter);
} else {
// TODO(xyzzy): remapper will handle this
symLabel = Symbol.ConvertLabelForDisplay(symLabel, Symbol.LabelAnnotation.None,
false, formatter);
}
if (operandLen == 1) {
@ -965,10 +957,6 @@ namespace SourceGen {
if ((flags & FormatNumericOpFlags.OmitLabelPrefixSuffix) == 0) {
symLabel = Symbol.ConvertLabelForDisplay(symLabel, sym.LabelAnno,
true, formatter);
} else {
// TODO(xyzzy): remapper will handle this
symLabel = Symbol.ConvertLabelForDisplay(symLabel, Symbol.LabelAnnotation.None,
false, formatter);
}
int adjustment;

View File

@ -96,6 +96,7 @@ limitations under the License.
<system:String x:Key="str_InfoAutoFormat">Format (auto):</system:String>
<system:String x:Key="str_InfoCustomFormat">Format:</system:String>
<system:String x:Key="str_InfoDefaultFormat">Format: default</system:String>
<system:String x:Key="str_InfoLabelDescrFmt">Label type: {0}</system:String>
<system:String x:Key="str_InfoLineSumNonFmt">Line {0}: {1}</system:String>
<system:String x:Key="str_InfoLineSumPluralFmt">Line {0}: {1} bytes of {2}</system:String>
<system:String x:Key="str_InfoLineSumSingularFmt">Line {0}: {1} byte of {2}</system:String>

View File

@ -173,6 +173,8 @@ namespace SourceGen.Res {
(string)Application.Current.FindResource("str_InfoCustomFormat");
public static string INFO_DEFAULT_FORMAT =
(string)Application.Current.FindResource("str_InfoDefaultFormat");
public static string INFO_LABEL_DESCR_FMT =
(string)Application.Current.FindResource("str_InfoLabelDescrFmt");
public static string INFO_LINE_SUM_NON_FMT =
(string)Application.Current.FindResource("str_InfoLineSumNonFmt");
public static string INFO_LINE_SUM_PLURAL_FMT =

View File

@ -1,6 +1,6 @@
### 6502bench SourceGen dis65 v1.0 ###
{
"_ContentVersion":3,"FileDataLength":154,"FileDataCrc32":-1096720699,"ProjectProps":{
"_ContentVersion":3,"FileDataLength":180,"FileDataCrc32":381569947,"ProjectProps":{
"CpuName":"6502","IncludeUndocumentedInstr":false,"TwoByteBrk":false,"EntryFlags":32702671,"AutoLabelStyle":"Simple","AnalysisParams":{
"AnalyzeUncategorizedData":true,"DefaultTextScanMode":"LowHighAscii","MinCharsForString":4,"SeekNearbyTargets":true,"SmartPlpHandling":true},
"PlatformSymbolFileIdentifiers":[],"ExtensionScriptFileIdentifiers":[],"ProjectSyms":{
@ -69,7 +69,7 @@
"105":{
"Label":"anno","Value":4201,"Source":"User","Type":"LocalOrGlobalAddr","LabelAnno":"Uncertain"},
"107":{
"Label":"T106B","Value":4203,"Source":"User","Type":"LocalOrGlobalAddr","LabelAnno":"Generated"},
"Label":"T106B","Value":4203,"Source":"User","Type":"GlobalAddr","LabelAnno":"Generated"},
"115":{
"Label":"skip","Value":4211,"Source":"User","Type":"NonUniqueLocalAddr","LabelAnno":"None"},
"116":{
@ -95,7 +95,17 @@
"146":{
"Label":"brl","Value":4242,"Source":"User","Type":"GlobalAddr","LabelAnno":"None"},
"149":{
"Label":"LDAL","Value":4245,"Source":"User","Type":"GlobalAddr","LabelAnno":"None"}},
"Label":"LDAL","Value":4245,"Source":"User","Type":"GlobalAddr","LabelAnno":"None"},
"160":{
"Label":"plain","Value":4256,"Source":"User","Type":"NonUniqueLocalAddr","LabelAnno":"None"},
"163":{
"Label":"plain","Value":4259,"Source":"User","Type":"NonUniqueLocalAddr","LabelAnno":"None"},
"166":{
"Label":"global8","Value":4262,"Source":"User","Type":"GlobalAddr","LabelAnno":"None"},
"169":{
"Label":"X_under1","Value":4265,"Source":"User","Type":"GlobalAddr","LabelAnno":"None"},
"172":{
"Label":"X__dub1","Value":4268,"Source":"User","Type":"NonUniqueLocalAddr","LabelAnno":"None"}},
"OperandFormats":{
"58":{
"Length":3,"Format":"NumericLE","SubFormat":"Symbol","SymbolRef":{
@ -146,4 +156,21 @@
"Length":2,"Format":"NumericLE","SubFormat":"Symbol","SymbolRef":{
"Label":"T106B","Part":"Low"}}},
"LvTables":{
}}
"154":{
"Variables":[{
"DataDescriptor":{
"Length":1,"Format":"NumericLE","SubFormat":"Hex","SymbolRef":null},
"Comment":"","HasWidth":true,"Direction":"ReadWrite","MultiMask":null,"Label":"plain","Value":17,"Source":"Variable","Type":"ExternalAddr","LabelAnno":"None"},
{
"DataDescriptor":{
"Length":1,"Format":"NumericLE","SubFormat":"Hex","SymbolRef":null},
"Comment":"","HasWidth":true,"Direction":"ReadWrite","MultiMask":null,"Label":"_under1","Value":18,"Source":"Variable","Type":"ExternalAddr","LabelAnno":"None"},
{
"DataDescriptor":{
"Length":1,"Format":"NumericLE","SubFormat":"Hex","SymbolRef":null},
"Comment":"","HasWidth":true,"Direction":"ReadWrite","MultiMask":null,"Label":"__dub1","Value":19,"Source":"Variable","Type":"ExternalAddr","LabelAnno":"None"}],"ClearPrevious":false},
"175":{
"Variables":[{
"DataDescriptor":{
"Length":1,"Format":"NumericLE","SubFormat":"Hex","SymbolRef":null},
"Comment":"","HasWidth":true,"Direction":"ReadWrite","MultiMask":null,"Label":"_under1","Value":34,"Source":"Variable","Type":"ExternalAddr","LabelAnno":"None"}],"ClearPrevious":false}}}

View File

@ -28,14 +28,14 @@ CONST_ZERO_VAR .var $f0
sta $f1,s
eor 0
ora 240,s
PROJ_ZERO_DUP1 .var $10 ;clash with project symbol
DPCODE_DUP1 .var $80 ;clash with user label
PROJ_ZERO_1 .var $10 ;clash with project symbol
DPCODE_1 .var $80 ;clash with user label
lda VAR_ZERO
lda VAR_ZERO+1
lda VAR_TWO
lda VAR_THREE
lda $04
lda PROJ_ZERO_DUP1
lda PROJ_ZERO_1
lda $11
lda DPCODE
ldx PROJ_ZERO

View File

@ -23,14 +23,14 @@ PROJ_ONE equ $01 ;project addr
sta $f1,S
eor 0
ora 240,S
]PROJ_ZERO_DUP1 equ $10 ;clash with project symbol
]DPCODE_DUP1 equ $80 ;clash with user label
]PROJ_ZERO_1 equ $10 ;clash with project symbol
]DPCODE_1 equ $80 ;clash with user label
lda ]VAR_ZERO
lda ]VAR_ZERO+1
lda ]VAR_TWO
lda ]VAR_THREE
lda $04
lda ]PROJ_ZERO_DUP1
lda ]PROJ_ZERO_1
lda $11
lda DPCODE
ldx PROJ_ZERO

View File

@ -31,8 +31,8 @@ PROJ_ONE = $01 ;project addr
.VAR_ZERO = $00
.VAR_TWO = $02
.VAR_THREE = $03
.PROJ_ZERO_DUP1 = $10 ;clash with project symbol
.DPCODE_DUP1 = $80 ;clash with user label
.PROJ_ZERO_1 = $10 ;clash with project symbol
.DPCODE_1 = $80 ;clash with user label
.CONST_ZERO_VAR = $f0
lda .VAR_ZERO
lda .VAR_ZERO+1
@ -41,12 +41,12 @@ PROJ_ONE = $01 ;project addr
.VAR_ZERO = $00
.VAR_TWO = $02
.VAR_THREE = $03
.PROJ_ZERO_DUP1 = $10 ;clash with project symbol
.DPCODE_DUP1 = $80 ;clash with user label
.PROJ_ZERO_1 = $10 ;clash with project symbol
.DPCODE_1 = $80 ;clash with user label
.CONST_ZERO_VAR = $f0
lda .VAR_THREE
lda $04
lda .PROJ_ZERO_DUP1
lda .PROJ_ZERO_1
lda $11
lda+1 DPCODE
!zone Z00002c

View File

@ -27,14 +27,14 @@ CONST_ZERO_VAR .set $f0
sta $f1,S
eor 0
ora 240,S
PROJ_ZERO_DUP1 .set $10 ;clash with project symbol
DPCODE_DUP1 .set $80 ;clash with user label
PROJ_ZERO_1 .set $10 ;clash with project symbol
DPCODE_1 .set $80 ;clash with user label
lda VAR_ZERO
lda VAR_ZERO+1
lda VAR_TWO
lda VAR_THREE
lda $04
lda PROJ_ZERO_DUP1
lda PROJ_ZERO_1
lda $11
lda z:DPCODE
ldx PROJ_ZERO

View File

@ -68,12 +68,12 @@ X___ ldx #$41
_X__ dex
bne _X__
nop
_anno lda #$42
_T106B lda _anno
anno lda #$42
T106B lda anno
clc
bcc _skip
.word _T106B
.word T106B
_skip nop
JMP1 lda JMP1
@ -91,5 +91,21 @@ LDAL .byte $af
.byte $95
.byte $10
.byte $00
nop
plain_1 .var $11
X_under1_1 .var $12
X__dub1 .var $13
lda plain_1
lda X_under1_1
lda X__dub1
_plain lda _plain
plain lda plain
global8 dex
bne plain
X_under1 lda X_under1
_X__dub1 lda _X__dub1
X_under1_1 .var $22
lda plain_1
lda X_under1_1
rts

View File

@ -67,12 +67,12 @@ ___ ldx #$41
:__ dex
bne :__
nop
:anno lda #$42
:T106B lda :anno
anno lda #$42
T106B lda anno
clc
bcc :skip
dw :T106B
dw T106B
:skip nop
JMP lda JMP
@ -90,5 +90,21 @@ LDAL dfb $af
dfb $95
dfb $10
dfb $00
nop
]plain_1 equ $11
]_under1 equ $12
]__dub1 equ $13
lda ]plain_1
lda ]_under1
lda ]__dub1
:plain lda :plain
plain lda plain
global8 dex
bne plain
X_under1 lda X_under1
:X__dub1 lda :X__dub1
]_under1 equ $22
lda ]plain_1
lda ]_under1
rts

View File

@ -68,12 +68,12 @@ ___ ldx #$41
@__ dex
bne @__
nop
@anno lda #$42
@T106B lda @anno
anno lda #$42
T106B lda anno
clc
bcc @skip
!word @T106B
!word T106B
@skip nop
JMP1 lda JMP1
@ -91,5 +91,25 @@ LDAL !byte $af
!byte $95
!byte $10
!byte $00
nop
!zone Z00009a
.plain_1 = $11
._under1 = $12
.__dub1 = $13
lda .plain_1
lda ._under1
lda .__dub1
@plain lda @plain
plain lda plain
global8 dex
bne plain
X_under1 lda X_under1
@X__dub1 lda @X__dub1
!zone Z0000af
.plain_1 = $11
.__dub1 = $13
._under1 = $22
lda .plain_1
lda ._under1
rts

View File

@ -69,12 +69,12 @@ ___: ldx #$41
@__: dex
bne @__
nop
@anno: lda #$42
@T106B: lda @anno
anno: lda #$42
T106B: lda anno
clc
bcc @skip
.word @T106B
.word T106B
@skip: nop
JMP1: lda JMP1
@ -92,5 +92,21 @@ LDAL: .byte $af
.byte $95
.byte $10
.byte $00
nop
plain_1 .set $11
_under1 .set $12
__dub1 .set $13
lda plain_1
lda _under1
lda __dub1
@plain: lda @plain
plain: lda plain
global8: dex
bne plain
X_under1: lda X_under1
@X__dub1: lda @X__dub1
_under1 .set $22
lda plain_1
lda _under1
rts

View File

@ -1,7 +1,7 @@
# 6502bench SourceGen generated linker script for 2023-non-unique-labels
MEMORY {
MAIN: file=%O, start=%S, size=65536;
# MEM000: file=%O, start=$1000, size=154;
# MEM000: file=%O, start=$1000, size=180;
}
SEGMENTS {
CODE: load=MAIN, type=rw;

View File

@ -109,17 +109,40 @@ anno1 lda anno ;NOTE: do not label, let table gen do it
; Semi-related: test opcode name labels (which are illegal for assemblers
; other than Merlin 32). We're configured for plain 6502, so it should
; remap some but not others.
JMP lda JMP ;EDIT set label (should be remapped)
JMP lda JMP ;EDIT set label (becomes JMP1 on non-Merlin)
JMP0 lda JMP0 ;EDIT set label
JMP1 lda JMP1 ;EDIT set label
JMP1 lda JMP1 ;EDIT set label (becomes JMP11 on non-Merlin)
:JMP lda :JMP ;EDIT set label
:JMP0 lda :JMP0 ;EDIT set label
:JMP1 lda :JMP1 ;EDIT set label
:JMP_ lda :JMP_ ;EDIT set label :JMP
:JMP_ lda :JMP_ ;EDIT set label :JMP (should become :JMP2)
jmp lda jmp ;EDIT set label
Jmp lda Jmp ;EDIT set label
BRA lda BRA ;EDIT set label (should NOT be remapped)
brl lda brl ;EDIT set label (should NOT be remapped)
LDAL ldal LDAL ;EDIT set label (should NOT be remapped)
; Test local-variable interaction. The goal here is to try to trick the
; code generator into creating duplicate labels.
global7 nop
]plain equ $11 ;EDIT create local var table
]_under1 equ $12
]__dub1 equ $13
lda ]plain
lda ]_under1
lda ]__dub1
:plain0 lda :plain0 ;EDIT: set label :plain
plain1 lda plain1 ;EDIT: set label :plain (should uniquify to plain)
global8 dex ; (which will then clash with the local var)
bne plain1
X_under1 lda X_under1 ;EDIT: set label (global) (trying to clash on 64tass)
:X__dub1 lda :X__dub1 ;EDIT: set label
]_under1 equ $22 ;EDIT: create local var table (don't clear)
lda ]plain
lda ]_under1
rts

View File

@ -272,10 +272,10 @@ namespace SourceGen {
}
/// <summary>
/// Returns the number of symbols in the table.
/// The number of symbols in the table.
/// </summary>
public int Count() {
return mSymbols.Count;
public int Count {
get { return mSymbols.Count; }
}
/// <summary>

View File

@ -609,8 +609,10 @@ namespace SourceGen.Tests {
if (!FileUtil.CompareTextFiles(path, compareName, out int firstDiffLine,
out string line1, out string line2)) {
ReportErrMsg("file '" + fileName + "' differs on line " + firstDiffLine);
Debug.WriteLine("File #1: " + line1);
Debug.WriteLine("File #2: " + line2);
Debug.WriteLine("Difference on line " + firstDiffLine);
Debug.WriteLine(" generated: " + line1);
Debug.WriteLine(" expected : " + line2);
return false;
}
}

View File

@ -1127,7 +1127,7 @@ namespace SourceGen.WpfGui {
LV_MATCH_FOUND_ADDRESS : LV_MATCH_FOUND_CONSTANT;
LocalVariableLookup lvLookup =
new LocalVariableLookup(mProject.LvTables, mProject, false);
new LocalVariableLookup(mProject.LvTables, mProject, null, false, false);
// If the operand is already a local variable, use whichever one the
// analyzer found.

View File

@ -160,7 +160,14 @@ namespace SourceGen.WpfGui {
IsNonUniqueChecked = true;
break;
case Symbol.Type.LocalOrGlobalAddr:
IsLocalChecked = true;
if (LabelSym.SymbolSource == Symbol.Source.Auto ||
LabelSym.LabelAnno == Symbol.LabelAnnotation.Generated) {
// Default to global, otherwise you get different behavior when
// adding a new label vs. replacing an auto or generated label.
IsGlobalChecked = true;
} else {
IsLocalChecked = true;
}
break;
case Symbol.Type.GlobalAddr:
IsGlobalChecked = true;

View File

@ -499,8 +499,9 @@ namespace SourceGen.WpfGui {
Symbol tmpSym = AutoLabel.GenerateUniqueForAddress(addr,
mProject.SymbolTable, "T");
// tmpSym was returned as an auto-label, make it a user label instead
// (with global scope)
tmpSym = new Symbol(tmpSym.Label, tmpSym.Value, Symbol.Source.User,
Symbol.Type.LocalOrGlobalAddr, Symbol.LabelAnnotation.Generated);
Symbol.Type.GlobalAddr, Symbol.LabelAnnotation.Generated);
newLabels[targetOffset] = tmpSym; // overwrites previous
targetLabel = tmpSym.Label;
AddPreviewItem(addr, targetOffset, "(+) " + targetLabel);

View File

@ -692,6 +692,7 @@ limitations under the License.
<RowDefinition Height="*" MinHeight="50"/>
</Grid.RowDefinitions>
<!-- symbols panel -->
<GroupBox Grid.Row="0" Header="Symbols">
<Grid>
<Grid.RowDefinitions>
@ -738,6 +739,7 @@ limitations under the License.
</Grid>
</GroupBox>
<!-- info panel -->
<GroupBox Grid.Row="2" Header="Info">
<ScrollViewer>
<Grid>
@ -747,6 +749,7 @@ limitations under the License.
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" TextWrapping="Wrap"
@ -754,8 +757,10 @@ limitations under the License.
<TextBlock Grid.Row="1" TextWrapping="Wrap" Foreground="DarkGray"
Text="{Binding InfoOffsetText, FallbackValue=[offset: +123456]}"
Visibility="{Binding InfoShowDebug, Converter={StaticResource BoolToVis}}"/>
<TextBlock Grid.Row="2" TextWrapping="Wrap"
Text="{Binding InfoLabelDescrText, FallbackValue=Label FUBAR (local)}"/>
<StackPanel Grid.Row="2"
<StackPanel Grid.Row="3"
Visibility="{Binding InfoFormatShowDashes, Converter={StaticResource BoolToVis}}">
<!-- For some reason putting the Visibility on the Border causes the
border to disappear even when it's supposed to be Visible. So I'm
@ -775,16 +780,16 @@ limitations under the License.
Text="{Binding InfoFormatText, FallbackValue=Format: good stuff}"/>
</Border>
</StackPanel>
<Border Grid.Row="2" BorderThickness="1" Padding="1" Margin="0,2"
<Border Grid.Row="3" BorderThickness="1" Padding="1" Margin="0,2"
BorderBrush="{Binding InfoFormatBoxBrush}"
Visibility="{Binding InfoFormatShowSolid, Converter={StaticResource BoolToVis}}">
<TextBlock TextWrapping="Wrap" Text="{Binding InfoFormatText}"/>
</Border>
<TextBox Grid.Row="3" Text="{Binding InfoPanelDetail1}" IsReadOnly="True"
<TextBox Grid.Row="4" Text="{Binding InfoPanelDetail1}" IsReadOnly="True"
TextWrapping="Wrap" BorderThickness="0"/>
<!--<TextBox Grid.Row="4" Text="{Binding InfoPanelMonoContents}" IsReadOnly="True"
<!--<TextBox Grid.Row="5" Text="{Binding InfoPanelMonoContents}" IsReadOnly="True"
FontFamily="{StaticResource GeneralMonoFont}"
TextWrapping="Wrap" BorderThickness="0"/>-->
</Grid>

View File

@ -1778,6 +1778,15 @@ namespace SourceGen.WpfGui {
}
private string mInfoOffsetText;
/// <summary>
/// Text for the label description.
/// </summary>
public string InfoLabelDescrText {
get { return mInfoLabelDescrText; }
set { mInfoLabelDescrText = value; OnPropertyChanged(); }
}
private string mInfoLabelDescrText;
public SolidColorBrush InfoFormatBoxBrush {
get { return mInfoFormatBoxBrush; }
set { mInfoFormatBoxBrush = value; OnPropertyChanged(); }
@ -1825,8 +1834,13 @@ namespace SourceGen.WpfGui {
//private string mInfoPanelMonoContents;
/// <summary>
/// Clears the contents of the info panel. Call this whenever the contents have
/// been updated.
/// </summary>
public void ClearInfoPanel() {
InfoLineDescrText = InfoOffsetText = InfoFormatText = InfoPanelDetail1 = string.Empty;
InfoLineDescrText = InfoOffsetText = InfoLabelDescrText = InfoFormatText =
InfoPanelDetail1 = string.Empty;
InfoFormatShowDashes = InfoFormatShowSolid = false;
}