Handle LVT entries for operand target label edits

The "edit operand target label" feature now handles local variables.
The individual symbol is edited in the table, the same way it would
if the appropriate option were selected from the Edit Instruction
Operand dialog.

Also, show the address in the Edit Label dialog.  It feels
unobtrusive and is occasionally useful.
This commit is contained in:
Andy McFadden committed 2025-06-26 09:59:54 -07:00
1 parent 8ab6294c8f
commit 0d64e0a94f
5 files changed
+88 -12

No files matched your search

+70 -3
View File
@@ -2482,7 +2482,8 @@ namespace SourceGen {
return false;
}
// TODO(someday): see if a local variable is defined for this operand.
// See if a local variable is defined for this operand.
// TODO(maybe): we don't currently get this far for 65816 stack relative stuff.
OpDef opDef = project.CpuDef.GetOpDef(project.FileData[selOffset]);
if ((opDef.IsDirectPageInstruction || opDef.IsStackRelInstruction) &&
attr.DataDescriptor != null && attr.DataDescriptor.HasSymbol &&
@@ -2551,8 +2552,8 @@ namespace SourceGen {
Debug.Assert(internalLabelOffset >= 0);
DoEditLabel(internalLabelOffset);
} else if (isLV) {
// Formatted as a local variable, do nothing.
// TODO(someday): make this edit the specific symbol in the table
// Formatted as a local variable, edit individual symbol.
DoEditLVOperand(selOffset);
} else {
// Create or edit project symbol.
if (externalSym != null && externalSym.SymbolSource == Symbol.Source.Project) {
@@ -2570,6 +2571,72 @@ namespace SourceGen {
}
}
/// <summary>
/// Edits the local variable referenced by an instruction operand.
/// </summary>
/// <remarks>
/// This is used by the "edit operand target label" feature. Double-clicking on an LVT
/// entry edits the whole table rather than a single entry.
/// </remarks>
/// <param name="selOffset">Offset of instruction.</param>
private void DoEditLVOperand(int selOffset) {
OpDef opDef = mProject.CpuDef.GetOpDef(mProject.FileData[selOffset]);
if (!opDef.IsDirectPageInstruction && !opDef.IsStackRelInstruction) {
Debug.Assert(false);
return;
}
Anattrib attr = mProject.GetAnattrib(selOffset);
if (!attr.DataDescriptor.SymbolRef.IsVariable) {
Debug.Assert(false);
return;
}
int operandValue = attr.OperandAddress;
if (operandValue < 0) {
Debug.Assert(false);
return;
}
// Find the table in which the symbol is defined.
LocalVariableLookup lvLookup =
new LocalVariableLookup(mProject.LvTables, mProject, null, false, false);
int lvTableOffset = lvLookup.GetDefiningTableOffset(selOffset,
attr.DataDescriptor.SymbolRef);
if (lvTableOffset < 0) {
Debug.Assert(false, "LV table not found");
return;
}
LocalVariableTable lvt = mProject.LvTables[lvTableOffset];
// The SymbolRef is a weak reference, by label. Get the actual symbol definition
// from the table. Because of the de-duplication stuff, we need to use the general
// LV lookup function (I think).
DefSymbol sym = lvLookup.GetSymbol(selOffset, operandValue,
opDef.IsDirectPageInstruction ? Symbol.Type.ExternalAddr : Symbol.Type.Constant);
if (sym == null) {
Debug.Assert(false, "LV sym not found");
return;
}
// Un-de-duplicate the label.
DefSymbol origSym = lvLookup.GetOriginalForm(sym);
EditDefSymbol dlg = new EditDefSymbol(mMainWin, mFormatter,
lvt.GetSortedByLabel(), origSym, origSym,
mProject.SymbolTable, true, true);
if (dlg.ShowDialog() == true) {
if (origSym != dlg.NewSym) {
// A change as made. Clone the table, replace the entry, and store the table.
Debug.Assert(dlg.NewSym != null);
ChangeSet cs = new ChangeSet(1);
LocalVariableTable editedLvTable = new LocalVariableTable(lvt);
editedLvTable.AddOrReplace(dlg.NewSym);
UndoableChange uc = UndoableChange.CreateLocalVariableTableChange(lvTableOffset,
lvt, editedLvTable);
cs.Add(uc);
ApplyUndoableChanges(cs);
}
}
}
public bool CanCreateLocalVariableTable() {
if (SelectionAnalysis.mNumItemsSelected != 1) {
return false;
+6 -2
View File
@@ -702,7 +702,7 @@ namespace SourceGen {
}
/// <summary>
/// Format the symbol and adjustment using common expression syntax.
/// Format the symbol and adjustment using common expression syntax (ACME, 64tass).
/// </summary>
private static void FormatNumericSymbolCommon(Formatter formatter, Symbol sym,
Dictionary<string, string> labelMap, FormatDescriptor dfd,
@@ -864,7 +864,11 @@ namespace SourceGen {
}
// Starting with a '(' makes it look like an indirect operand, so we need
// to prefix the expression with a no-op addition.
// to prefix the expression with a no-op addition. In most cases we could
// use a unary '+', but ACME rejects data operands like "+(absl >> 8)-16"
// (see test 20030-labels-and-symbols). (Check flags & Is64Tass here?)
// TODO: this is only ambiguous for instruction operands; data operands don't need
// special treatment.
if (sb[0] == '(' && (flags & FormatNumericOpFlags.HasHashPrefix) == 0) {
sb.Insert(0, "0+");
}
+2 -1
View File
@@ -30,6 +30,7 @@ limitations under the License.
<Window.Resources>
<system:String x:Key="str_NonUniqueLocalFmt">_Non-unique local ('{0}')</system:String>
<system:String x:Key="str_EnterLabelFmt">Enter label for ${0}:</system:String>
</Window.Resources>
<Grid Margin="8">
@@ -43,7 +44,7 @@ limitations under the License.
</Grid.RowDefinitions>
<StackPanel Grid.Column="0" Grid.Row="0" Grid.ColumnSpan="2">
<TextBlock Text="Enter label:"/>
<TextBlock Text="{Binding EnterLabelText, FallbackValue=Enter label for $1234:}"/>
<TextBox Name="labelTextBox" Margin="0,2,0,0" FontFamily="{StaticResource GeneralMonoFont}"
Text="{Binding LabelText, UpdateSourceTrigger=PropertyChanged}"/>
<TextBlock Name="maxLengthLabel" Text="• Must be 2-32 characters long (or blank to remove)"
+8 -4
View File
@@ -80,6 +80,12 @@ namespace SourceGen.WpfGui {
}
string mLabelText;
public string EnterLabelText {
get { return mEnterLabelText; }
set { mEnterLabelText = value; OnPropertyChanged(); }
}
string mEnterLabelText;
// Radio buttons.
public bool mIsNonUniqueChecked, mIsNonUniqueEnabled;
public bool IsNonUniqueChecked {
@@ -144,16 +150,14 @@ namespace SourceGen.WpfGui {
string fmt = (string)FindResource("str_NonUniqueLocalFmt");
NonUniqueButtonLabel = string.Format(fmt, mFormatter.NonUniqueLabelPrefix);
fmt = (string)FindResource("str_EnterLabelFmt");
EnterLabelText = string.Format(fmt, formatter.FormatAddress(address, address > 0xffff));
if (mAddress == Address.NON_ADDR) {
NonAddrWarningVis = Visibility.Visible;
} else {
NonAddrWarningVis = Visibility.Collapsed;
}
#if DEBUG
this.Title += " ($" + formatter.FormatAddress(address, address > 0xffff) + ")";
#endif
}
private void Window_Loaded(object sender, RoutedEventArgs e) {
+2 -2
View File
@@ -345,8 +345,8 @@ address specified by the operand and editing the label there. For example,
if you use this on the line <code>LDA $1234</code>, it would open the
label edit dialog for the line at address $1234.</p>
<p>When used on references to addresses outside the scope of the file, the
project symbol editor will be opened instead. This does not currently
allow editing of local variable table entries.</p>
project symbol editor will be opened instead. This works for project symbols
and local variable table entries.</p>
<p>This also works for data items formatted as 16- or 24-bit addresses.</p>
<p>Note: the target address is taken from the operand even when a symbol is
provided. For example, sometimes jump tables will encode (address - 1)