diff --git a/Asm65/Formatter.cs b/Asm65/Formatter.cs
index ac46ec7..3453eff 100644
--- a/Asm65/Formatter.cs
+++ b/Asm65/Formatter.cs
@@ -37,9 +37,9 @@ namespace Asm65 {
/// because it guarantees that a given Formatter object will produce the same number of
/// lines of output.
///
- /// NOTE: if the CpuDef changes, the cached values in the Formatter will become invalid.
- /// Discard the Formatter and create a new one. (This could be fixed by keying off of
- /// the OpDef instead of OpDef.Opcode, but that's less convenient.)
+ /// NOTE: if the CpuDef changes, the cached values in the Formatter will become invalid
+ /// (e.g. mOpcodeStrings). Discard the Formatter and create a new one. (This could be
+ /// fixed by keying off of the OpDef instead of OpDef.Opcode, but that's less convenient.)
///
public class Formatter {
///
@@ -54,12 +54,13 @@ namespace Asm65 {
public bool mUpperOperandA; // display acc operand in upper case?
public bool mUpperOperandS; // display stack operand in upper case?
public bool mUpperOperandXY; // display index register operand in upper case?
- public bool mBankSelectBackQuote; // use '`' rather than '^' for bank select?
+
public bool mAddSpaceLongComment; // insert space after delimiter for long comments?
// functional changes to assembly output
public bool mSuppressHexNotation; // omit '$' before hex digits
public bool mSuppressImpliedAcc; // emit just "LSR" rather than "LSR A"?
+ public bool mBankSelectBackQuote; // use '`' rather than '^' for bank selector?
public string mForceDirectOperandPrefix; // these may be null or empty
public string mForceAbsOpcodeSuffix;
@@ -68,7 +69,8 @@ namespace Asm65 {
public string mForceLongOpcodeSuffix;
public string mForceLongOperandPrefix;
- public string mLocalVariableLablePrefix; // Merlin 32 puts ']' before var names
+ public string mLocalVariableLabelPrefix; // e.g. Merlin 32 puts ']' before var names
+ public string mNonUniqueLabelPrefix; // e.g. ':' or '@' before local label
public string mEndOfLineCommentDelimiter; // usually ';'
public string mFullLineCommentDelimiterBase; // usually ';' or '*', WITHOUT extra space
@@ -291,7 +293,7 @@ namespace Asm65 {
///
public FormatConfig Config { get { return mFormatConfig; } }
- // Bits and pieces.
+ // Cached bits and pieces.
char mHexFmtChar;
string mHexPrefix;
string mAccChar;
@@ -365,6 +367,13 @@ namespace Asm65 {
get { return mFormatConfig.mBoxLineCommentDelimiter; }
}
+ ///
+ /// Prefix for non-unique address labels.
+ ///
+ public string NonUniqueLabelPrefix {
+ get { return mFormatConfig.mNonUniqueLabelPrefix; }
+ }
+
///
/// When formatting a symbol with an offset, if this flag is set, generate code that
/// assumes the assembler applies the adjustment, then shifts the result. If not,
@@ -391,6 +400,10 @@ namespace Asm65 {
mFormatConfig.mBoxLineCommentDelimiter = string.Empty;
}
+ if (string.IsNullOrEmpty(mFormatConfig.mNonUniqueLabelPrefix)) {
+ mFormatConfig.mNonUniqueLabelPrefix = "@";
+ }
+
if (mFormatConfig.mAddSpaceLongComment) {
mFullLineCommentDelimiterPlus = mFormatConfig.mFullLineCommentDelimiterBase + " ";
} else {
@@ -617,8 +630,8 @@ namespace Asm65 {
/// specified.
///
public string FormatVariableLabel(string label) {
- if (!string.IsNullOrEmpty(mFormatConfig.mLocalVariableLablePrefix)) {
- return mFormatConfig.mLocalVariableLablePrefix + label;
+ if (!string.IsNullOrEmpty(mFormatConfig.mLocalVariableLabelPrefix)) {
+ return mFormatConfig.mLocalVariableLabelPrefix + label;
} else {
return label;
}
diff --git a/SourceGen/AppSettings.cs b/SourceGen/AppSettings.cs
index 1ac0013..2f34016 100644
--- a/SourceGen/AppSettings.cs
+++ b/SourceGen/AppSettings.cs
@@ -66,6 +66,7 @@ namespace SourceGen {
public const string FMT_PSEUDO_OP_NAMES = "fmt-pseudo-op-names";
public const string FMT_CHAR_DELIM = "fmt-char-delim";
public const string FMT_STRING_DELIM = "fmt-string-delim";
+ public const string FMT_NON_UNIQUE_LABEL_PREFIX = "fmt-non-unique-label-prefix";
public const string FMT_LOCAL_VARIABLE_PREFIX = "fmt-local-variable-prefix";
public const string CLIP_LINE_FORMAT = "clip-line-format";
diff --git a/SourceGen/AsmGen/AsmAcme.cs b/SourceGen/AsmGen/AsmAcme.cs
index 3f860a5..eaf1a80 100644
--- a/SourceGen/AsmGen/AsmAcme.cs
+++ b/SourceGen/AsmGen/AsmAcme.cs
@@ -190,10 +190,11 @@ namespace SourceGen.AsmGen {
config.mForceDirectOperandPrefix = string.Empty;
config.mForceAbsOperandPrefix = string.Empty;
config.mForceLongOperandPrefix = string.Empty;
- config.mLocalVariableLablePrefix = ".";
+ config.mLocalVariableLabelPrefix = ".";
config.mEndOfLineCommentDelimiter = ";";
config.mFullLineCommentDelimiterBase = ";";
config.mBoxLineCommentDelimiter = ";";
+ config.mNonUniqueLabelPrefix = "@";
config.mExpressionMode = Formatter.FormatConfig.ExpressionMode.Common;
Formatter.DelimiterSet charSet = new Formatter.DelimiterSet();
@@ -387,7 +388,7 @@ namespace SourceGen.AsmGen {
operand = RawData.GetWord(data, offset, length, false);
operandStr = PseudoOp.FormatNumericOperand(formatter, Project.SymbolTable,
mLocalizer.LabelMap, dfd, operand, length,
- PseudoOp.FormatNumericOpFlags.StripAnnotation);
+ PseudoOp.FormatNumericOpFlags.StripLabelPrefixSuffix);
break;
case FormatDescriptor.Type.NumericBE:
opcodeStr = sDataOpNames.GetDefineBigData(length);
@@ -398,7 +399,7 @@ namespace SourceGen.AsmGen {
operand = RawData.GetWord(data, offset, length, true);
operandStr = PseudoOp.FormatNumericOperand(formatter, Project.SymbolTable,
mLocalizer.LabelMap, dfd, operand, length,
- PseudoOp.FormatNumericOpFlags.StripAnnotation);
+ PseudoOp.FormatNumericOpFlags.StripLabelPrefixSuffix);
}
break;
case FormatDescriptor.Type.Fill:
@@ -515,7 +516,7 @@ namespace SourceGen.AsmGen {
string valueStr = PseudoOp.FormatNumericOperand(SourceFormatter,
Project.SymbolTable, null, defSym.DataDescriptor, defSym.Value, 1,
- PseudoOp.FormatNumericOpFlags.StripAnnotation);
+ PseudoOp.FormatNumericOpFlags.StripLabelPrefixSuffix);
OutputEquDirective(SourceFormatter.FormatVariableLabel(defSym.Label),
valueStr, defSym.Comment);
}
diff --git a/SourceGen/AsmGen/AsmCc65.cs b/SourceGen/AsmGen/AsmCc65.cs
index 35cdfce..43b6d8a 100644
--- a/SourceGen/AsmGen/AsmCc65.cs
+++ b/SourceGen/AsmGen/AsmCc65.cs
@@ -189,6 +189,7 @@ namespace SourceGen.AsmGen {
config.mEndOfLineCommentDelimiter = ";";
config.mFullLineCommentDelimiterBase = ";";
config.mBoxLineCommentDelimiter = ";";
+ config.mNonUniqueLabelPrefix = "@";
config.mExpressionMode = Formatter.FormatConfig.ExpressionMode.Cc65;
Formatter.DelimiterSet charSet = new Formatter.DelimiterSet();
@@ -421,7 +422,7 @@ namespace SourceGen.AsmGen {
operand = RawData.GetWord(data, offset, length, false);
operandStr = PseudoOp.FormatNumericOperand(formatter, Project.SymbolTable,
mLocalizer.LabelMap, dfd, operand, length,
- PseudoOp.FormatNumericOpFlags.StripAnnotation);
+ PseudoOp.FormatNumericOpFlags.StripLabelPrefixSuffix);
break;
case FormatDescriptor.Type.NumericBE:
opcodeStr = sDataOpNames.GetDefineBigData(length);
@@ -432,7 +433,7 @@ namespace SourceGen.AsmGen {
operand = RawData.GetWord(data, offset, length, true);
operandStr = PseudoOp.FormatNumericOperand(formatter, Project.SymbolTable,
mLocalizer.LabelMap, dfd, operand, length,
- PseudoOp.FormatNumericOpFlags.StripAnnotation);
+ PseudoOp.FormatNumericOpFlags.StripLabelPrefixSuffix);
}
break;
case FormatDescriptor.Type.Fill:
@@ -547,7 +548,7 @@ namespace SourceGen.AsmGen {
// Use an operand length of 1 so values are shown as concisely as possible.
string valueStr = PseudoOp.FormatNumericOperand(SourceFormatter,
Project.SymbolTable, null, defSym.DataDescriptor, defSym.Value, 1,
- PseudoOp.FormatNumericOpFlags.StripAnnotation);
+ PseudoOp.FormatNumericOpFlags.StripLabelPrefixSuffix);
OutputLine(SourceFormatter.FormatVariableLabel(defSym.Label),
SourceFormatter.FormatPseudoOp(sDataOpNames.VarDirective),
valueStr, SourceFormatter.FormatEolComment(defSym.Comment));
diff --git a/SourceGen/AsmGen/AsmMerlin32.cs b/SourceGen/AsmGen/AsmMerlin32.cs
index 6faae0e..f6e3223 100644
--- a/SourceGen/AsmGen/AsmMerlin32.cs
+++ b/SourceGen/AsmGen/AsmMerlin32.cs
@@ -160,10 +160,11 @@ namespace SourceGen.AsmGen {
config.mForceDirectOperandPrefix = string.Empty;
config.mForceAbsOperandPrefix = string.Empty;
config.mForceLongOperandPrefix = string.Empty;
- config.mLocalVariableLablePrefix = "]";
+ config.mLocalVariableLabelPrefix = "]";
config.mEndOfLineCommentDelimiter = ";";
config.mFullLineCommentDelimiterBase = ";";
config.mBoxLineCommentDelimiter = string.Empty;
+ config.mNonUniqueLabelPrefix = ":";
config.mExpressionMode = Formatter.FormatConfig.ExpressionMode.Merlin;
Formatter.DelimiterSet charSet = new Formatter.DelimiterSet();
@@ -248,7 +249,7 @@ namespace SourceGen.AsmGen {
operand = RawData.GetWord(data, offset, length, false);
operandStr = PseudoOp.FormatNumericOperand(formatter, Project.SymbolTable,
mLocalizer.LabelMap, dfd, operand, length,
- PseudoOp.FormatNumericOpFlags.StripAnnotation);
+ PseudoOp.FormatNumericOpFlags.StripLabelPrefixSuffix);
break;
case FormatDescriptor.Type.NumericBE:
opcodeStr = sDataOpNames.GetDefineBigData(length);
@@ -259,7 +260,7 @@ namespace SourceGen.AsmGen {
operand = RawData.GetWord(data, offset, length, true);
operandStr = PseudoOp.FormatNumericOperand(formatter, Project.SymbolTable,
mLocalizer.LabelMap, dfd, operand, length,
- PseudoOp.FormatNumericOpFlags.StripAnnotation);
+ PseudoOp.FormatNumericOpFlags.StripLabelPrefixSuffix);
}
break;
case FormatDescriptor.Type.Fill:
@@ -439,7 +440,7 @@ namespace SourceGen.AsmGen {
foreach (DefSymbol defSym in newDefs) {
string valueStr = PseudoOp.FormatNumericOperand(SourceFormatter,
Project.SymbolTable, null, defSym.DataDescriptor, defSym.Value, 1,
- PseudoOp.FormatNumericOpFlags.StripAnnotation);
+ PseudoOp.FormatNumericOpFlags.StripLabelPrefixSuffix);
OutputLine(SourceFormatter.FormatVariableLabel(defSym.Label),
SourceFormatter.FormatPseudoOp(sDataOpNames.VarDirective),
valueStr, SourceFormatter.FormatEolComment(defSym.Comment));
diff --git a/SourceGen/AsmGen/AsmTass64.cs b/SourceGen/AsmGen/AsmTass64.cs
index 78bf284..767c223 100644
--- a/SourceGen/AsmGen/AsmTass64.cs
+++ b/SourceGen/AsmGen/AsmTass64.cs
@@ -197,6 +197,7 @@ namespace SourceGen.AsmGen {
config.mEndOfLineCommentDelimiter = ";";
config.mFullLineCommentDelimiterBase = ";";
config.mBoxLineCommentDelimiter = ";";
+ config.mNonUniqueLabelPrefix = ""; // should be '_', but that's a valid label char
config.mExpressionMode = Formatter.FormatConfig.ExpressionMode.Common;
}
@@ -453,7 +454,7 @@ namespace SourceGen.AsmGen {
UpdateCharacterEncoding(dfd);
operandStr = PseudoOp.FormatNumericOperand(formatter, Project.SymbolTable,
mLocalizer.LabelMap, dfd, operand, length,
- PseudoOp.FormatNumericOpFlags.StripAnnotation);
+ PseudoOp.FormatNumericOpFlags.StripLabelPrefixSuffix);
break;
case FormatDescriptor.Type.NumericBE:
opcodeStr = sDataOpNames.GetDefineBigData(length);
@@ -465,7 +466,7 @@ namespace SourceGen.AsmGen {
operand = RawData.GetWord(data, offset, length, true);
operandStr = PseudoOp.FormatNumericOperand(formatter, Project.SymbolTable,
mLocalizer.LabelMap, dfd, operand, length,
- PseudoOp.FormatNumericOpFlags.StripAnnotation);
+ PseudoOp.FormatNumericOpFlags.StripLabelPrefixSuffix);
}
break;
case FormatDescriptor.Type.Fill:
@@ -582,7 +583,7 @@ namespace SourceGen.AsmGen {
foreach (DefSymbol defSym in newDefs) {
string valueStr = PseudoOp.FormatNumericOperand(SourceFormatter,
Project.SymbolTable, null, defSym.DataDescriptor, defSym.Value, 1,
- PseudoOp.FormatNumericOpFlags.StripAnnotation);
+ PseudoOp.FormatNumericOpFlags.StripLabelPrefixSuffix);
OutputLine(SourceFormatter.FormatVariableLabel(defSym.Label),
SourceFormatter.FormatPseudoOp(sDataOpNames.VarDirective),
valueStr, SourceFormatter.FormatEolComment(defSym.Comment));
diff --git a/SourceGen/AsmGen/GenCommon.cs b/SourceGen/AsmGen/GenCommon.cs
index 48c3db3..ef6f522 100644
--- a/SourceGen/AsmGen/GenCommon.cs
+++ b/SourceGen/AsmGen/GenCommon.cs
@@ -157,7 +157,7 @@ namespace SourceGen.AsmGen {
// Use an operand length of 1 so values are shown as concisely as possible.
string valueStr = PseudoOp.FormatNumericOperand(formatter, proj.SymbolTable,
gen.Localizer.LabelMap, defSym.DataDescriptor, defSym.Value, 1,
- PseudoOp.FormatNumericOpFlags.StripAnnotation);
+ PseudoOp.FormatNumericOpFlags.StripLabelPrefixSuffix);
gen.OutputEquDirective(defSym.Label, valueStr, defSym.Comment);
prevConst = defSym.IsConstant;
@@ -204,7 +204,7 @@ namespace SourceGen.AsmGen {
string formattedOperand = null;
int operandLen = instrLen - 1;
- PseudoOp.FormatNumericOpFlags opFlags = PseudoOp.FormatNumericOpFlags.StripAnnotation;
+ PseudoOp.FormatNumericOpFlags opFlags = PseudoOp.FormatNumericOpFlags.StripLabelPrefixSuffix;
bool isPcRelBankWrap = false;
// Tweak branch instructions. We want to show the absolute address rather
@@ -245,10 +245,10 @@ namespace SourceGen.AsmGen {
// Special handling for the double-operand block move.
string opstr1 = PseudoOp.FormatNumericOperand(formatter, proj.SymbolTable,
gen.Localizer.LabelMap, dfd, operand >> 8, 1,
- PseudoOp.FormatNumericOpFlags.StripAnnotation);
+ PseudoOp.FormatNumericOpFlags.StripLabelPrefixSuffix);
string opstr2 = PseudoOp.FormatNumericOperand(formatter, proj.SymbolTable,
gen.Localizer.LabelMap, dfd, operand & 0xff, 1,
- PseudoOp.FormatNumericOpFlags.StripAnnotation);
+ PseudoOp.FormatNumericOpFlags.StripLabelPrefixSuffix);
if (gen.Quirks.BlockMoveArgsReversed) {
string tmp = opstr1;
opstr1 = opstr2;
diff --git a/SourceGen/DisasmProject.cs b/SourceGen/DisasmProject.cs
index 08f73cc..7c8fbdf 100644
--- a/SourceGen/DisasmProject.cs
+++ b/SourceGen/DisasmProject.cs
@@ -1098,6 +1098,10 @@ namespace SourceGen {
/// Merges symbols from UserLabels into SymbolTable. Existing entries with matching
/// labels will be replaced.
///
+ ///
+ /// It might make sense to exclude non-unique labels, but that's probably better done
+ /// with a UI filter option.
+ ///
private void UpdateAndMergeUserLabels() {
// We store symbols as label+value, but for a user label the actual value is
// the address of the offset the label is associated with, which can change if
diff --git a/SourceGen/DisplayList.cs b/SourceGen/DisplayList.cs
index f8941af..14bb69f 100644
--- a/SourceGen/DisplayList.cs
+++ b/SourceGen/DisplayList.cs
@@ -322,6 +322,9 @@ namespace SourceGen {
OnPropertyChanged(CountString);
OnPropertyChanged(IndexerName);
+ // TODO(performance): this causes the ListView to format the entire listing, despite
+ // being virtual. So we're regenerating the entire list after something trivial,
+ // like renaming a label. Need to figure this out.
OnCollectionReset();
}
diff --git a/SourceGen/LineListGen.cs b/SourceGen/LineListGen.cs
index 666b007..4b604fc 100644
--- a/SourceGen/LineListGen.cs
+++ b/SourceGen/LineListGen.cs
@@ -871,7 +871,8 @@ namespace SourceGen {
PseudoOp.FormatNumericOpFlags.None);
valueStr = PseudoOp.AnnotateEquDirective(formatter, valueStr, defSym);
string comment = formatter.FormatEolComment(defSym.Comment);
- FormattedParts parts = FormattedParts.CreateEquDirective(defSym.AnnotatedLabel,
+ FormattedParts parts = FormattedParts.CreateEquDirective(
+ defSym.GenerateDisplayLabel(formatter),
formatter.FormatPseudoOp(opNames.EquDirective),
valueStr, comment);
line.Parts = parts;
@@ -1183,7 +1184,7 @@ namespace SourceGen {
string labelStr = string.Empty;
if (attr.Symbol != null) {
- labelStr = attr.Symbol.AnnotatedLabel;
+ labelStr = attr.Symbol.GenerateDisplayLabel(mFormatter);
}
OpDef op = mProject.CpuDef.GetOpDef(data[offset]);
@@ -1316,7 +1317,7 @@ namespace SourceGen {
addrStr = mFormatter.FormatAddress(attr.Address, !mProject.CpuDef.HasAddr16);
if (attr.Symbol != null) {
- labelStr = attr.Symbol.AnnotatedLabel;
+ labelStr = attr.Symbol.GenerateDisplayLabel(mFormatter);
}
bytesStr = mFormatter.FormatBytes(data, offset, attr.Length);
@@ -1394,7 +1395,7 @@ namespace SourceGen {
addrStr = PseudoOp.AnnotateEquDirective(mFormatter, addrStr, defSym);
string comment = mFormatter.FormatEolComment(defSym.Comment);
return FormattedParts.CreateEquDirective(
- mFormatter.FormatVariableLabel(defSym.AnnotatedLabel),
+ mFormatter.FormatVariableLabel(defSym.GenerateDisplayLabel(mFormatter)),
mFormatter.FormatPseudoOp(mPseudoOpNames.VarDirective),
addrStr, comment);
}
@@ -1436,7 +1437,7 @@ namespace SourceGen {
addrStr = mFormatter.FormatAddress(attr.Address, !mProject.CpuDef.HasAddr16);
if (attr.Symbol != null) {
- labelStr = attr.Symbol.AnnotatedLabel;
+ labelStr = attr.Symbol.GenerateDisplayLabel(mFormatter);
} else {
labelStr = string.Empty;
}
diff --git a/SourceGen/MainController.cs b/SourceGen/MainController.cs
index bb577dd..4f6ad03 100644
--- a/SourceGen/MainController.cs
+++ b/SourceGen/MainController.cs
@@ -466,7 +466,9 @@ namespace SourceGen {
mFormatterConfig.mFullLineCommentDelimiterBase = ";";
mFormatterConfig.mBoxLineCommentDelimiter = string.Empty;
- mFormatterConfig.mLocalVariableLablePrefix =
+ mFormatterConfig.mNonUniqueLabelPrefix =
+ settings.GetString(AppSettings.FMT_NON_UNIQUE_LABEL_PREFIX, string.Empty);
+ mFormatterConfig.mLocalVariableLabelPrefix =
settings.GetString(AppSettings.FMT_LOCAL_VARIABLE_PREFIX, string.Empty);
string chrDelCereal = settings.GetString(AppSettings.FMT_CHAR_DELIM, null);
@@ -1709,8 +1711,8 @@ namespace SourceGen {
int offset = CodeLineList[selIndex].FileOffset;
Anattrib attr = mProject.GetAnattrib(offset);
- EditLabel dlg = new EditLabel(mMainWin, attr.Symbol, attr.Address,
- mProject.SymbolTable);
+ EditLabel dlg = new EditLabel(mMainWin, attr.Symbol, attr.Address, offset,
+ mProject.SymbolTable, mOutputFormatter);
if (dlg.ShowDialog() != true) {
return;
}
@@ -3456,6 +3458,10 @@ namespace SourceGen {
#region Symbols panel
+ ///
+ /// Populates the ItemsSource for the Symbols window. Each entry in the project
+ /// symbol table is added.
+ ///
private void PopulateSymbolsList() {
mMainWin.SymbolsList.Clear();
foreach (Symbol sym in mProject.SymbolTable) {
@@ -3475,7 +3481,7 @@ namespace SourceGen {
}
MainWindow.SymbolsListItem sli = new MainWindow.SymbolsListItem(sym,
- sourceTypeStr, valueStr, sym.AnnotatedLabel);
+ sourceTypeStr, valueStr, sym.GenerateDisplayLabel(mOutputFormatter));
mMainWin.SymbolsList.Add(sli);
}
}
diff --git a/SourceGen/PseudoOp.cs b/SourceGen/PseudoOp.cs
index eb4564e..4d8a0c7 100644
--- a/SourceGen/PseudoOp.cs
+++ b/SourceGen/PseudoOp.cs
@@ -549,10 +549,10 @@ namespace SourceGen {
///
[Flags]
public enum FormatNumericOpFlags {
- None = 0,
- IsPcRel = 1, // opcode is PC relative, e.g. branch or PER
- HasHashPrefix = 1 << 1, // operand has a leading '#', avoiding ambiguity sometimes
- StripAnnotation = 1 << 2, // don't show annotation character
+ None = 0,
+ IsPcRel = 1, // opcode is PC relative, e.g. branch or PER
+ HasHashPrefix = 1 << 1, // operand has a leading '#', reducing ambiguity
+ StripLabelPrefixSuffix = 1 << 2, // don't show annotation char or non-unique prefix
}
///
@@ -641,7 +641,7 @@ namespace SourceGen {
Debug.Assert(operandLen == 1); // only doing 8-bit stuff
DefSymbol defSym = lvLookup.GetSymbol(offset, dfd.SymbolRef);
if (defSym != null) {
- // For local variables we're doing trivial add/subtract and don't
+ // For local variables we're doing a trivial add and don't
// wrap, so the "common" format works for everybody.
StringBuilder sb = new StringBuilder();
FormatNumericSymbolCommon(formatter, defSym, null,
@@ -699,6 +699,8 @@ namespace SourceGen {
int adjustment, symbolValue;
+ // Start by remapping the label, if necessary. The remapped label may have a
+ // local-variable prefix character.
string symLabel = sym.Label;
if (labelMap != null && labelMap.TryGetValue(symLabel, out string newLabel)) {
symLabel = newLabel;
@@ -706,9 +708,16 @@ namespace SourceGen {
if (sym.IsVariable) {
symLabel = formatter.FormatVariableLabel(symLabel);
}
- // TODO(xyzzy): non-unique prefix
- if ((flags & FormatNumericOpFlags.StripAnnotation) == 0) {
- symLabel = Symbol.AppendAnnotation(symLabel, sym.LabelAnno);
+
+ // Now put the prefix/suffix back on if desired. We don't want to mess with it
+ // if it's from the assembler.
+ if ((flags & FormatNumericOpFlags.StripLabelPrefixSuffix) == 0) {
+ symLabel = Symbol.ConvertLabelForDisplay(symLabel, sym.LabelAnno,
+ sym.IsNonUnique, formatter);
+ } else {
+ // TODO(xyzzy): remapper will handle this
+ symLabel = Symbol.ConvertLabelForDisplay(symLabel, Symbol.LabelAnnotation.None,
+ false, formatter);
}
if (operandLen == 1) {
@@ -845,9 +854,13 @@ namespace SourceGen {
if (labelMap != null && labelMap.TryGetValue(symLabel, out string newLabel)) {
symLabel = newLabel;
}
- // TODO(xyzzy): non-unique prefix
- if ((flags & FormatNumericOpFlags.StripAnnotation) == 0) {
- symLabel = Symbol.AppendAnnotation(symLabel, sym.LabelAnno);
+ if ((flags & FormatNumericOpFlags.StripLabelPrefixSuffix) == 0) {
+ symLabel = Symbol.ConvertLabelForDisplay(symLabel, sym.LabelAnno,
+ sym.IsNonUnique, formatter);
+ } else {
+ // TODO(xyzzy): remapper will handle this
+ symLabel = Symbol.ConvertLabelForDisplay(symLabel, Symbol.LabelAnnotation.None,
+ false, formatter);
}
if (operandLen == 1) {
@@ -942,9 +955,13 @@ namespace SourceGen {
if (labelMap != null && labelMap.TryGetValue(symLabel, out string newLabel)) {
symLabel = newLabel;
}
- // TODO(xyzzy): non-unique prefix
- if ((flags & FormatNumericOpFlags.StripAnnotation) == 0) {
- symLabel = Symbol.AppendAnnotation(symLabel, sym.LabelAnno);
+ if ((flags & FormatNumericOpFlags.StripLabelPrefixSuffix) == 0) {
+ symLabel = Symbol.ConvertLabelForDisplay(symLabel, sym.LabelAnno,
+ sym.IsNonUnique, formatter);
+ } else {
+ // TODO(xyzzy): remapper will handle this
+ symLabel = Symbol.ConvertLabelForDisplay(symLabel, Symbol.LabelAnnotation.None,
+ false, formatter);
}
int adjustment;
diff --git a/SourceGen/Sandbox/ScriptManager.cs b/SourceGen/Sandbox/ScriptManager.cs
index cc4b848..9970a32 100644
--- a/SourceGen/Sandbox/ScriptManager.cs
+++ b/SourceGen/Sandbox/ScriptManager.cs
@@ -224,6 +224,9 @@ namespace SourceGen.Sandbox {
}
PlSymbol.Type plsType;
switch (sym.SymbolType) {
+ case Symbol.Type.NonUniqueLocalAddr:
+ // don't forward these to plugins
+ continue;
case Symbol.Type.LocalOrGlobalAddr:
case Symbol.Type.GlobalAddr:
case Symbol.Type.GlobalAddrExport:
diff --git a/SourceGen/Symbol.cs b/SourceGen/Symbol.cs
index cc4c857..af15c1a 100644
--- a/SourceGen/Symbol.cs
+++ b/SourceGen/Symbol.cs
@@ -15,6 +15,7 @@
*/
using System;
using System.Diagnostics;
+using System.Text;
namespace SourceGen {
///
@@ -22,6 +23,9 @@ namespace SourceGen {
///
public class Symbol {
public const char UNCERTAIN_CHAR = '?';
+ private const char NO_ANNO_CHAR = '\ufffd'; // REPLACEMENT CHARACTER '�'
+ private const char UNIQUE_TAG_CHAR = '\u00a7'; // SECTION SIGN
+ private const int NON_UNIQUE_LEN = 7; // NON_UNIQUE_CHAR + 6 hex digits
///
/// How was the symbol defined?
@@ -42,6 +46,16 @@ namespace SourceGen {
/// Unique or non-unique address label? Is it required to be global or exported?
/// Constants get a separate type.
///
+ ///
+ /// There's really just three types: unique address symbol, non-unique address symbol,
+ /// and constant. There's also a set of boolean flags indicating whether the symbol
+ /// should be forced to be global, whether it should be included in the export table,
+ /// and whether it's internal or external.
+ ///
+ /// It turns out that many combinations of type and flag don't actually make sense,
+ /// e.g. I don't know what a non-unique exported external constant is, so we just
+ /// enumerate the combinations that make sense.
+ ///
public enum Type {
Unknown = 0,
@@ -103,11 +117,6 @@ namespace SourceGen {
///
public string SourceTypeString { get; private set; }
- ///
- /// Label with annotations. Generated from Label and LabelAnno.
- ///
- public string AnnotatedLabel { get; private set; }
-
///
/// True if the symbol's type is an internal label (auto or user). Will be false
@@ -124,6 +133,13 @@ namespace SourceGen {
get { return SymbolSource == Source.Variable; }
}
+ ///
+ /// True if the symbol is a non-unique local.
+ ///
+ public bool IsNonUnique {
+ get { return SymbolType == Type.NonUniqueLocalAddr; }
+ }
+
///
/// True if the symbol represents a constant value.
///
@@ -142,10 +158,11 @@ namespace SourceGen {
/// Symbol value.
/// User-defined, auto-generated, ?
/// Type of symbol this is.
+ /// Optional annotation.
public Symbol(string label, int value, Source source, Type type,
LabelAnnotation labelAnno) {
Debug.Assert(Asm65.Label.ValidateLabel(label));
- Debug.Assert(type != Type.NonUniqueLocalAddr);
+ Debug.Assert(type != Type.NonUniqueLocalAddr || value == 0xdead); // use other ctor
Label = label;
Value = value;
SymbolType = type;
@@ -172,24 +189,80 @@ namespace SourceGen {
default: tc = '?'; break;
}
SourceTypeString = "" + sc + tc;
-
- // Generate AnnotatedLabel.
- AnnotatedLabel = AppendAnnotation(Label, LabelAnno);
}
///
/// Constructor for non-unique labels.
///
- ///
- ///
- ///
- ///
- ///
- ///
- public Symbol(string label, int value, Source source, Type type,
- LabelAnnotation labelAnno, int offset)
- : this(label, value, source, type, labelAnno) {
- Debug.Assert(false); // TODO(xyzzy)
+ /// Label string. Syntax assumed valid.
+ /// Symbol value.
+ /// Optional annotation.
+ /// Tag that makes a non-unique label unique, e.g. the
+ /// offset for which a user label has been created.
+ public Symbol(string label, int value, LabelAnnotation labelAnno, int uniqueTag)
+ : this(label, 0xdead, Source.User, Type.NonUniqueLocalAddr, labelAnno) {
+ Debug.Assert(uniqueTag >= 0 && uniqueTag < 0x01000000); // fit in 6 hex digits
+ Debug.Assert(label.IndexOf(UNIQUE_TAG_CHAR) < 0); // already extended?
+
+ Value = value; // passed a bogus value earlier for assert
+
+ // Add tag to label to make it unique.
+ Label = label + UNIQUE_TAG_CHAR + uniqueTag.ToString("x6");
+ }
+
+ ///
+ /// Generates a displayable form of the label. This will have the non-unique label
+ /// prefix and annotation suffix, and will have the non-unique tag removed.
+ ///
+ /// Formatter object.
+ /// Label suitable for display.
+ public string GenerateDisplayLabel(Asm65.Formatter formatter) {
+ return ConvertLabelForDisplay(Label, LabelAnno, IsNonUnique, formatter);
+ }
+
+ ///
+ /// Returns the annotation suffix character, or NO_ANNO_CHAR if nothing appropriate.
+ ///
+ private static char GetLabelAnnoChar(LabelAnnotation anno) {
+ char ch = NO_ANNO_CHAR;
+ if (anno == LabelAnnotation.Uncertain) {
+ ch = UNCERTAIN_CHAR;
+ } else if (anno == LabelAnnotation.Generated) {
+ //ch = '\u00a4'; // CURRENCY SIGN '¤'
+ }
+ return ch;
+ }
+
+ ///
+ /// 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.
+ ///
+ /// Base label string. Has the uniquification tag, but no
+ /// annotation char or non-unique prefix.
+ /// Annotation; may be None.
+ /// Formatted label.
+ public static string ConvertLabelForDisplay(string label, LabelAnnotation anno,
+ bool isNonUnique, Asm65.Formatter formatter) {
+ StringBuilder sb = new StringBuilder(label.Length + 2);
+
+ if (isNonUnique) {
+ 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));
+ } else {
+ sb.Append(label);
+ }
+
+ char annoChar = GetLabelAnnoChar(anno);
+ if (annoChar != NO_ANNO_CHAR) {
+ sb.Append(annoChar);
+ }
+ return sb.ToString();
}
///
@@ -199,14 +272,20 @@ namespace SourceGen {
/// trimmed version of the string is returned.
///
/// Label to examine.
+ /// For address symbols, the prefix string for
+ /// non-unique labels. May be null if not validating a user label.
/// True if the entire label is valid.
/// True if the label has a valid length.
/// True if the first character is valid.
+ /// True if the first character indicates that this is
+ /// a non-unique label.
/// Annotation found, or None if none found.
/// Trimmed version of the string.
- public static string TrimAndValidateLabel(string label, out bool isValid,
- out bool isLenValid, out bool isFirstCharValid, out LabelAnnotation anno) {
+ public static string TrimAndValidateLabel(string label, string nonUniquePrefix,
+ out bool isValid, out bool isLenValid, out bool isFirstCharValid,
+ out bool hasNonUniquePrefix, out LabelAnnotation anno) {
anno = LabelAnnotation.None;
+ hasNonUniquePrefix = false;
// Do we have at least one char?
if (string.IsNullOrEmpty(label)) {
@@ -221,6 +300,14 @@ namespace SourceGen {
trimLabel = trimLabel.Substring(0, trimLabel.Length - 1);
}
+ // Check for leading non-unique ident char.
+ if (trimLabel.Length > 0 && !string.IsNullOrEmpty(nonUniquePrefix)) {
+ if (trimLabel[0] == nonUniquePrefix[0]) {
+ hasNonUniquePrefix = true;
+ trimLabel = trimLabel.Substring(1);
+ }
+ }
+
// Now that we're down to the base string, do the full validation test. If it
// passes, we don't need to dig any deeper.
isValid = Asm65.Label.ValidateLabelDetail(trimLabel, out isLenValid,
@@ -229,22 +316,6 @@ namespace SourceGen {
return trimLabel;
}
- ///
- /// Augments a label string with an annotation identifier.
- ///
- /// String to augment.
- /// Annotation; may be None.
- /// Original or updated string.
- public static string AppendAnnotation(string label, LabelAnnotation anno) {
- if (anno == LabelAnnotation.Uncertain) {
- return label + UNCERTAIN_CHAR;
- //} else if (anno == LabelAnnotation.Generated) {
- // return label + '\u00a4'; // CURRENCY_SIGN '¤'
- } else {
- return label;
- }
- }
-
public override string ToString() {
return Label + "{" + SymbolSource + "," + SymbolType +
diff --git a/SourceGen/WpfGui/EditAppSettings.xaml b/SourceGen/WpfGui/EditAppSettings.xaml
index d09c3de..cadf92f 100644
--- a/SourceGen/WpfGui/EditAppSettings.xaml
+++ b/SourceGen/WpfGui/EditAppSettings.xaml
@@ -504,7 +504,8 @@ limitations under the License.
+ IsChecked="{Binding DisableLabelLocalization}"
+ Visibility="Collapsed"/>
@@ -571,6 +572,14 @@ limitations under the License.
+
+
+
+
+
+
+
+ _Non-unique local ('{0}')
+
+
@@ -47,18 +53,24 @@ limitations under the License.
-
+
-
-
-
+
+
+
+
-
-
+
+
diff --git a/SourceGen/WpfGui/EditLabel.xaml.cs b/SourceGen/WpfGui/EditLabel.xaml.cs
index 3e669da..ca783ff 100644
--- a/SourceGen/WpfGui/EditLabel.xaml.cs
+++ b/SourceGen/WpfGui/EditLabel.xaml.cs
@@ -20,6 +20,8 @@ using System.Runtime.CompilerServices;
using System.Windows;
using System.Windows.Media;
+using Asm65;
+
namespace SourceGen.WpfGui {
///
/// Edit a label.
@@ -31,6 +33,11 @@ namespace SourceGen.WpfGui {
///
public Symbol LabelSym { get; private set; }
+ ///
+ /// Unique tag, for non-unique label creation. (Currently using offset.)
+ ///
+ private int mUniqueTag;
+
///
/// Address we are editing the label for.
///
@@ -41,18 +48,27 @@ namespace SourceGen.WpfGui {
///
private SymbolTable mSymbolTable;
+ ///
+ /// Label formatter.
+ ///
+ private Formatter mFormatter;
+
// Dialog label text color, saved off at dialog load time.
private Brush mDefaultLabelColor;
+ ///
+ /// Recursion guard.
+ ///
+ private bool mInUpdateControls;
+
+ public string NonUniqueButtonLabel { get; private set; }
+
///
/// Set to true when input is valid. Controls whether the OK button is enabled.
///
public bool IsValid {
get { return mIsValid; }
- set {
- mIsValid = value;
- OnPropertyChanged();
- }
+ set { mIsValid = value; OnPropertyChanged(); }
}
private bool mIsValid;
@@ -61,14 +77,51 @@ namespace SourceGen.WpfGui {
///
public string LabelText {
get { return mLabelText; }
- set {
- mLabelText = value;
- LabelTextBox_TextChanged();
- OnPropertyChanged();
- }
+ set { mLabelText = value; OnPropertyChanged(); UpdateControls(); }
}
string mLabelText;
+ // Radio buttons.
+ public bool mIsNonUniqueChecked, mIsNonUniqueEnabled;
+ public bool IsNonUniqueChecked {
+ get { return mIsNonUniqueChecked; }
+ set { mIsNonUniqueChecked = value; OnPropertyChanged(); UpdateControls(); }
+ }
+ public bool IsNonUniqueEnabled {
+ get { return mIsNonUniqueEnabled; }
+ set { mIsNonUniqueEnabled = value; OnPropertyChanged(); }
+ }
+
+ public bool mIsLocalChecked, mIsLocalEnabled;
+ public bool IsLocalChecked {
+ get { return mIsLocalChecked; }
+ set { mIsLocalChecked = value; OnPropertyChanged(); UpdateControls(); }
+ }
+ public bool IsLocalEnabled {
+ get { return mIsLocalEnabled; }
+ set { mIsLocalEnabled = value; OnPropertyChanged(); }
+ }
+
+ public bool mIsGlobalChecked, mIsGlobalEnabled;
+ public bool IsGlobalChecked {
+ get { return mIsGlobalChecked; }
+ set { mIsGlobalChecked = value; OnPropertyChanged(); UpdateControls(); }
+ }
+ public bool IsGlobalEnabled {
+ get { return mIsGlobalEnabled; }
+ set { mIsGlobalEnabled = value; OnPropertyChanged(); }
+ }
+
+ public bool mIsExportedChecked, mIsExportedEnabled;
+ public bool IsExportedChecked {
+ get { return mIsExportedChecked; }
+ set { mIsExportedChecked = value; OnPropertyChanged(); UpdateControls(); }
+ }
+ public bool IsExportedEnabled {
+ get { return mIsExportedEnabled; }
+ set { mIsExportedEnabled = value; OnPropertyChanged(); }
+ }
+
// INotifyPropertyChanged implementation
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged([CallerMemberName] string propertyName = "") {
@@ -76,43 +129,53 @@ namespace SourceGen.WpfGui {
}
- public EditLabel(Window owner, Symbol origSym, int address, SymbolTable symbolTable) {
+ public EditLabel(Window owner, Symbol origSym, int address, int uniqueTag,
+ SymbolTable symbolTable, Formatter formatter) {
InitializeComponent();
Owner = owner;
DataContext = this;
LabelSym = origSym;
mAddress = address;
+ mUniqueTag = uniqueTag;
mSymbolTable = symbolTable;
+ mFormatter = formatter;
+
+ string fmt = (string)FindResource("str_NonUniqueLocalFmt");
+ NonUniqueButtonLabel = string.Format(fmt, mFormatter.NonUniqueLabelPrefix);
}
private void Window_Loaded(object sender, RoutedEventArgs e) {
mDefaultLabelColor = maxLengthLabel.Foreground;
+ IsNonUniqueEnabled = IsLocalEnabled = IsGlobalEnabled = IsExportedEnabled = true;
+
if (LabelSym == null) {
LabelText = string.Empty;
- radioButtonLocal.IsChecked = true;
+ IsGlobalChecked = true;
} else {
- LabelText = LabelSym.AnnotatedLabel;
+ LabelText = LabelSym.GenerateDisplayLabel(mFormatter);
switch (LabelSym.SymbolType) {
case Symbol.Type.NonUniqueLocalAddr:
- Debug.Assert(false); // TODO(xyzzy)
+ IsNonUniqueChecked = true;
break;
case Symbol.Type.LocalOrGlobalAddr:
- radioButtonLocal.IsChecked = true;
+ IsLocalChecked = true;
break;
case Symbol.Type.GlobalAddr:
- radioButtonGlobal.IsChecked = true;
+ IsGlobalChecked = true;
break;
case Symbol.Type.GlobalAddrExport:
- radioButtonExport.IsChecked = true;
+ IsExportedChecked = true;
break;
default:
Debug.Assert(false); // WTF
- radioButtonLocal.IsChecked = true;
+ IsGlobalChecked = true;
break;
}
}
+
+ UpdateControls();
}
private void Window_ContentRendered(object sender, EventArgs e) {
@@ -120,48 +183,39 @@ namespace SourceGen.WpfGui {
labelTextBox.Focus();
}
- private void LabelTextBox_TextChanged() {
-#if false
- string str = LabelText;
- bool valid = true;
-
- if (str.Length == 1 || str.Length > Asm65.Label.MAX_LABEL_LEN) {
- valid = false;
- maxLengthLabel.Foreground = Brushes.Red;
- } else {
- maxLengthLabel.Foreground = mDefaultLabelColor;
+ private void UpdateControls() {
+ if (mInUpdateControls) {
+ return;
}
+ mInUpdateControls = true;
- // Regex never matches on strings of length 0 or 1, but we don't want
- // to complain about that since we're already doing that above.
- // TODO(maybe): Ideally this wouldn't light up if the only problem was a
- // non-alpha first character, since the next test will call that out.
- if (str.Length > 1) {
- if (!Asm65.Label.ValidateLabel(str)) {
- valid = false;
- validCharsLabel.Foreground = Brushes.Red;
- } else {
- validCharsLabel.Foreground = mDefaultLabelColor;
- }
- } else {
- validCharsLabel.Foreground = mDefaultLabelColor;
- }
+ LabelTextChanged();
- if (str.Length > 0 &&
- !((str[0] >= 'A' && str[0] <= 'Z') || (str[0] >= 'a' && str[0] <= 'z') ||
- str[0] == '_')) {
- // This should have been caught by the regex. We just want to set the
- // color on the "first character must be" instruction text.
- Debug.Assert(!valid);
- firstLetterLabel.Foreground = Brushes.Red;
- } else {
- firstLetterLabel.Foreground = mDefaultLabelColor;
- }
-#endif
+ mInUpdateControls = false;
+ }
+
+ private bool mHadNonUniquePrefix = false;
+
+ private void LabelTextChanged() {
bool isBlank = (LabelText.Length == 0);
- string trimLabel = Symbol.TrimAndValidateLabel(LabelText, out bool isValid,
- out bool isLenValid, out bool isFirstCharValid, out Symbol.LabelAnnotation anno);
+ // Strip leading non-unique prefix and the trailing annotation.
+ string trimLabel = Symbol.TrimAndValidateLabel(LabelText,
+ mFormatter.NonUniqueLabelPrefix, out bool isValid, out bool isLenValid,
+ out bool isFirstCharValid, out bool hasNonUniquePrefix,
+ out Symbol.LabelAnnotation anno);
+
+ // If they type '@'/':'/'.' at the start of the label, switch the radio button.
+ // Alternatively, if they choose a different radio button, remove the prefix.
+ // We only want to do this on the first event so we don't wedge the control.
+ if (hasNonUniquePrefix && !mHadNonUniquePrefix && !IsNonUniqueChecked) {
+ IsNonUniqueChecked = true;
+ } else if (hasNonUniquePrefix && mHadNonUniquePrefix && !IsNonUniqueChecked) {
+ LabelText = LabelText.Substring(1);
+ hasNonUniquePrefix = false;
+ }
+ mHadNonUniquePrefix = hasNonUniquePrefix;
+
if (isBlank || isLenValid) {
maxLengthLabel.Foreground = mDefaultLabelColor;
} else {
@@ -180,18 +234,30 @@ namespace SourceGen.WpfGui {
validCharsLabel.Foreground = Brushes.Red;
}
- // Refuse to continue if the label already exists. The only exception is if
- // it's the same symbol, and it's user-defined. (If they're trying to edit an
- // auto label, we want to force them to change the name.)
+#if false
+ if (hasNonUniqueTag) {
+ IsNonUniqueChecked = true;
+ IsLocalEnabled = IsGlobalEnabled = IsExportedEnabled = false;
+ } else {
+ IsNonUniqueEnabled = IsLocalEnabled = IsGlobalEnabled = IsExportedEnabled = true;
+ }
+#endif
+
+ // Refuse to continue if the label already exists and this isn't a non-unique label.
+ // The only exception is if it's the same symbol, and it's user-defined. (If
+ // they're trying to edit an auto label, we want to force them to change the name.)
//
// NOTE: if label matching is case-insensitive, we want to allow a situation
// where a label is being renamed from "FOO" to "Foo". We should be able to
// test for object equality on the Symbol to determine if we're renaming a
// symbol to itself.
- if (isValid && mSymbolTable.TryGetValue(trimLabel, out Symbol sym) &&
+ if (!IsNonUniqueChecked && isValid &&
+ mSymbolTable.TryGetValue(trimLabel, out Symbol sym) &&
(sym != LabelSym || LabelSym.SymbolSource != Symbol.Source.User)) {
isValid = false;
notDuplicateLabel.Foreground = Brushes.Red;
+ } else if (IsNonUniqueChecked) {
+ notDuplicateLabel.Foreground = Brushes.Gray;
} else {
notDuplicateLabel.Foreground = mDefaultLabelColor;
}
@@ -204,23 +270,32 @@ namespace SourceGen.WpfGui {
LabelSym = null;
} else {
Symbol.Type symbolType;
- // TODO(xyzzy): non-local
- if (radioButtonLocal.IsChecked == true) {
+ if (IsNonUniqueChecked) {
+ symbolType = Symbol.Type.NonUniqueLocalAddr;
+ } else if (IsLocalChecked == true) {
symbolType = Symbol.Type.LocalOrGlobalAddr;
- } else if (radioButtonGlobal.IsChecked == true) {
+ } else if (IsGlobalChecked == true) {
symbolType = Symbol.Type.GlobalAddr;
- } else if (radioButtonExport.IsChecked == true) {
+ } else if (IsExportedChecked == true) {
symbolType = Symbol.Type.GlobalAddrExport;
} else {
Debug.Assert(false); // WTF
- symbolType = Symbol.Type.LocalOrGlobalAddr;
+ symbolType = Symbol.Type.GlobalAddr;
}
- // Parse and strip the annotation.
- string trimLabel = Symbol.TrimAndValidateLabel(LabelText, out bool unused1,
- out bool unused2, out bool unused3, out Symbol.LabelAnnotation anno);
+ // Parse and strip the annotation and optional non-unique tag.
+ string trimLabel = Symbol.TrimAndValidateLabel(LabelText,
+ mFormatter.NonUniqueLabelPrefix, out bool unused1, out bool unused2,
+ out bool unused3, out bool hasNonUniquePrefix,
+ out Symbol.LabelAnnotation anno);
- LabelSym = new Symbol(trimLabel, mAddress, Symbol.Source.User, symbolType, anno);
+ if (IsNonUniqueChecked) {
+ LabelSym = new Symbol(trimLabel, mAddress, anno, mUniqueTag);
+ } else {
+ Debug.Assert(!hasNonUniquePrefix);
+ LabelSym = new Symbol(trimLabel, mAddress, Symbol.Source.User, symbolType,
+ anno);
+ }
}
DialogResult = true;
}
diff --git a/SourceGen/WpfGui/EditLocalVariableTable.xaml.cs b/SourceGen/WpfGui/EditLocalVariableTable.xaml.cs
index 1f55e79..a94ddcf 100644
--- a/SourceGen/WpfGui/EditLocalVariableTable.xaml.cs
+++ b/SourceGen/WpfGui/EditLocalVariableTable.xaml.cs
@@ -175,7 +175,7 @@ namespace SourceGen.WpfGui {
FormattedSymbol fsym = new FormattedSymbol(
defSym,
- defSym.AnnotatedLabel,
+ defSym.GenerateDisplayLabel(mFormatter),
mFormatter.FormatValueInBase(defSym.Value, defSym.DataDescriptor.NumBase),
typeStr,
defSym.DataDescriptor.Length,
diff --git a/SourceGen/WpfGui/EditProjectProperties.xaml.cs b/SourceGen/WpfGui/EditProjectProperties.xaml.cs
index d7056c7..0b1f6a9 100644
--- a/SourceGen/WpfGui/EditProjectProperties.xaml.cs
+++ b/SourceGen/WpfGui/EditProjectProperties.xaml.cs
@@ -485,7 +485,7 @@ namespace SourceGen.WpfGui {
FormattedSymbol fsym = new FormattedSymbol(
defSym,
- defSym.AnnotatedLabel,
+ defSym.GenerateDisplayLabel(mFormatter),
mFormatter.FormatValueInBase(defSym.Value, defSym.DataDescriptor.NumBase),
typeStr,
defSym.HasWidth ? defSym.DataDescriptor.Length.ToString() : NO_WIDTH_STR,