1
0
mirror of https://github.com/fadden/6502bench.git synced 2024-11-29 10:50:28 +00:00

Add selectable auto-label styles

SourceGen creates "auto" labels when it finds a reference to an
address that doesn't have a label associated with it.  The label for
address $1234 would be "L1234".  This change allows the project to
specify alternative label naming conventions, annotating them with
information from the cross-reference data.  For example, a subroutine
entry point (i.e. the target of a JSR) would be "S_1234".  (The
underscore was added to avoid confusion when an annotation letter
is the same as a hex digit.)

Also, tweaked the way the preferred clipboard line format is stored
in the settings file (was an integer, now an enumeration string).
This commit is contained in:
Andy McFadden 2019-04-14 16:36:16 -07:00
parent 47b1363738
commit 97a372a884
17 changed files with 374 additions and 78 deletions

View File

@ -91,6 +91,8 @@ namespace SourceGen.AppForms {
this.showAsmIdentCheckBox = new System.Windows.Forms.CheckBox();
this.disableLabelLocalizationCheckBox = new System.Windows.Forms.CheckBox();
this.displayFormatTabPage = new System.Windows.Forms.TabPage();
this.expressionStyleComboBox = new System.Windows.Forms.ComboBox();
this.expressionStyleLabel = new System.Windows.Forms.Label();
this.fmtExplanationLabel = new System.Windows.Forms.Label();
this.quickDisplayFormatGroup = new System.Windows.Forms.GroupBox();
this.displayFmtQuickComboBox = new System.Windows.Forms.ComboBox();
@ -157,8 +159,6 @@ namespace SourceGen.AppForms {
this.defineData1Label = new System.Windows.Forms.Label();
this.equDirectiveTextBox = new System.Windows.Forms.TextBox();
this.equDirectiveLabel = new System.Windows.Forms.Label();
this.expressionStyleLabel = new System.Windows.Forms.Label();
this.expressionStyleComboBox = new System.Windows.Forms.ComboBox();
this.settingsTabControl.SuspendLayout();
this.codeViewTabPage.SuspendLayout();
this.codeViewMiscGroupBox.SuspendLayout();
@ -752,6 +752,24 @@ namespace SourceGen.AppForms {
this.displayFormatTabPage.Text = "Display Format";
this.displayFormatTabPage.UseVisualStyleBackColor = true;
//
// expressionStyleComboBox
//
this.expressionStyleComboBox.FormattingEnabled = true;
this.expressionStyleComboBox.Location = new System.Drawing.Point(98, 153);
this.expressionStyleComboBox.Name = "expressionStyleComboBox";
this.expressionStyleComboBox.Size = new System.Drawing.Size(121, 21);
this.expressionStyleComboBox.TabIndex = 5;
this.expressionStyleComboBox.SelectedIndexChanged += new System.EventHandler(this.expressionStyleComboBox_SelectedIndexChanged);
//
// expressionStyleLabel
//
this.expressionStyleLabel.AutoSize = true;
this.expressionStyleLabel.Location = new System.Drawing.Point(7, 156);
this.expressionStyleLabel.Name = "expressionStyleLabel";
this.expressionStyleLabel.Size = new System.Drawing.Size(85, 13);
this.expressionStyleLabel.TabIndex = 4;
this.expressionStyleLabel.Text = "Expression style:";
//
// fmtExplanationLabel
//
this.fmtExplanationLabel.AutoSize = true;
@ -1468,24 +1486,6 @@ namespace SourceGen.AppForms {
this.equDirectiveLabel.Text = "Equate:";
this.equDirectiveLabel.TextAlign = System.Drawing.ContentAlignment.TopRight;
//
// expressionStyleLabel
//
this.expressionStyleLabel.AutoSize = true;
this.expressionStyleLabel.Location = new System.Drawing.Point(7, 156);
this.expressionStyleLabel.Name = "expressionStyleLabel";
this.expressionStyleLabel.Size = new System.Drawing.Size(85, 13);
this.expressionStyleLabel.TabIndex = 4;
this.expressionStyleLabel.Text = "Expression style:";
//
// expressionStyleComboBox
//
this.expressionStyleComboBox.FormattingEnabled = true;
this.expressionStyleComboBox.Location = new System.Drawing.Point(98, 153);
this.expressionStyleComboBox.Name = "expressionStyleComboBox";
this.expressionStyleComboBox.Size = new System.Drawing.Size(121, 21);
this.expressionStyleComboBox.TabIndex = 5;
this.expressionStyleComboBox.SelectedIndexChanged += new System.EventHandler(this.expressionStyleComboBox_SelectedIndexChanged);
//
// EditAppSettings
//
this.AcceptButton = this.okButton;

View File

@ -37,6 +37,15 @@ namespace SourceGen.AppForms {
PseudoOp = 3
}
/// <summary>
/// Clipboard format enumeration. Numbers must match order of items in combo box.
/// </summary>
public enum ClipLineFormat {
Unknown = -1,
AssemblerSource = 0,
Disassembly = 1
}
/// <summary>
/// ProjectView reference. When the user hits Apply, the object's ApplyAppSettings
/// method will be invoked.
@ -140,7 +149,7 @@ namespace SourceGen.AppForms {
showCol5, showCol6, showCol7, showCol8 };
Debug.Assert(NUM_COLUMNS == 9);
// Extract formats from column-width button labels.
// Extract format strings from column-width button labels.
for (int i = 0; i < NUM_COLUMNS; i++) {
mColButtons[i].Click += ColumnVisibilityButtonClick;
mColumnFormats[i] = mColButtons[i].Text;
@ -230,7 +239,8 @@ namespace SourceGen.AppForms {
upperSCheckBox.Checked = mSettings.GetBool(AppSettings.FMT_UPPER_OPERAND_S, false);
upperXYCheckBox.Checked = mSettings.GetBool(AppSettings.FMT_UPPER_OPERAND_XY, false);
int clipIndex = mSettings.GetInt(AppSettings.CLIP_LINE_FORMAT, 0);
int clipIndex = mSettings.GetEnum(AppSettings.CLIP_LINE_FORMAT,
typeof(ClipLineFormat), 0);
if (clipIndex >= 0 && clipIndex < clipboardFormatComboBox.Items.Count) {
clipboardFormatComboBox.SelectedIndex = clipIndex;
}
@ -422,7 +432,8 @@ namespace SourceGen.AppForms {
}
private void clipboardFormatComboBox_SelectedIndexChanged(object sender, EventArgs e) {
mSettings.SetInt(AppSettings.CLIP_LINE_FORMAT, clipboardFormatComboBox.SelectedIndex);
mSettings.SetEnum(AppSettings.CLIP_LINE_FORMAT, typeof(ClipLineFormat),
clipboardFormatComboBox.SelectedIndex);
SetDirty(true);
}

View File

@ -45,6 +45,9 @@ namespace SourceGen.AppForms {
"This is a test to gauge column widths"}, -1);
this.tabControl1 = new System.Windows.Forms.TabControl();
this.generalTab = new System.Windows.Forms.TabPage();
this.miscGroupBox = new System.Windows.Forms.GroupBox();
this.autoLabelStyleComboBox = new System.Windows.Forms.ComboBox();
this.autoLabelStyleLabel = new System.Windows.Forms.Label();
this.analysisGroupBox = new System.Windows.Forms.GroupBox();
this.seekAltTargetCheckBox = new System.Windows.Forms.CheckBox();
this.minStringCharsComboBox = new System.Windows.Forms.ComboBox();
@ -86,6 +89,7 @@ namespace SourceGen.AppForms {
this.applyButton = new System.Windows.Forms.Button();
this.tabControl1.SuspendLayout();
this.generalTab.SuspendLayout();
this.miscGroupBox.SuspendLayout();
this.analysisGroupBox.SuspendLayout();
this.entryFlagsGroupBox.SuspendLayout();
this.cpuGroupBox.SuspendLayout();
@ -112,6 +116,7 @@ namespace SourceGen.AppForms {
//
// generalTab
//
this.generalTab.Controls.Add(this.miscGroupBox);
this.generalTab.Controls.Add(this.analysisGroupBox);
this.generalTab.Controls.Add(this.entryFlagsGroupBox);
this.generalTab.Controls.Add(this.cpuGroupBox);
@ -123,6 +128,40 @@ namespace SourceGen.AppForms {
this.generalTab.Text = "General";
this.generalTab.UseVisualStyleBackColor = true;
//
// miscGroupBox
//
this.miscGroupBox.Controls.Add(this.autoLabelStyleComboBox);
this.miscGroupBox.Controls.Add(this.autoLabelStyleLabel);
this.miscGroupBox.Location = new System.Drawing.Point(7, 177);
this.miscGroupBox.Name = "miscGroupBox";
this.miscGroupBox.Size = new System.Drawing.Size(422, 100);
this.miscGroupBox.TabIndex = 3;
this.miscGroupBox.TabStop = false;
this.miscGroupBox.Text = "Miscellaneous";
//
// autoLabelStyleComboBox
//
this.autoLabelStyleComboBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.autoLabelStyleComboBox.FormattingEnabled = true;
this.autoLabelStyleComboBox.Items.AddRange(new object[] {
"Simple (\"L1234\")",
"Annotated (\"W_1234\")",
"Fully Annotated (\"DWR_1234\")"});
this.autoLabelStyleComboBox.Location = new System.Drawing.Point(98, 19);
this.autoLabelStyleComboBox.Name = "autoLabelStyleComboBox";
this.autoLabelStyleComboBox.Size = new System.Drawing.Size(318, 21);
this.autoLabelStyleComboBox.TabIndex = 1;
this.autoLabelStyleComboBox.SelectedIndexChanged += new System.EventHandler(this.autoLabelStyleComboBox_SelectedIndexChanged);
//
// autoLabelStyleLabel
//
this.autoLabelStyleLabel.AutoSize = true;
this.autoLabelStyleLabel.Location = new System.Drawing.Point(6, 22);
this.autoLabelStyleLabel.Name = "autoLabelStyleLabel";
this.autoLabelStyleLabel.Size = new System.Drawing.Size(81, 13);
this.autoLabelStyleLabel.TabIndex = 0;
this.autoLabelStyleLabel.Text = "Auto-label style:";
//
// analysisGroupBox
//
this.analysisGroupBox.Controls.Add(this.seekAltTargetCheckBox);
@ -568,6 +607,8 @@ namespace SourceGen.AppForms {
this.Load += new System.EventHandler(this.EditProperties_Load);
this.tabControl1.ResumeLayout(false);
this.generalTab.ResumeLayout(false);
this.miscGroupBox.ResumeLayout(false);
this.miscGroupBox.PerformLayout();
this.analysisGroupBox.ResumeLayout(false);
this.analysisGroupBox.PerformLayout();
this.entryFlagsGroupBox.ResumeLayout(false);
@ -628,5 +669,8 @@ namespace SourceGen.AppForms {
private System.Windows.Forms.Label configuredScriptsLabel;
private System.Windows.Forms.Button importSymbolsButton;
private System.Windows.Forms.CheckBox seekAltTargetCheckBox;
private System.Windows.Forms.GroupBox miscGroupBox;
private System.Windows.Forms.ComboBox autoLabelStyleComboBox;
private System.Windows.Forms.Label autoLabelStyleLabel;
}
}

View File

@ -112,6 +112,13 @@ namespace SourceGen.AppForms {
}
minStringCharsComboBox.SelectedIndex = selIndex;
selIndex = (int) mWorkProps.AutoLabelStyle;
if (selIndex < 0 || selIndex >= autoLabelStyleComboBox.Items.Count) {
Debug.Assert(false, "bad AutoLabelStyle " + mWorkProps.AutoLabelStyle);
selIndex = 0;
}
autoLabelStyleComboBox.SelectedIndex = selIndex;
LoadProjectSymbols();
LoadPlatformSymbolFiles();
LoadExtensionScriptNames();
@ -245,6 +252,7 @@ namespace SourceGen.AppForms {
}
private void minStringCharsComboBox_SelectedIndexChanged(object sender, EventArgs e) {
// ComboBox must be the value 0, then N+2 in each subsequent entry (3, 4, 5, ...).
int index = minStringCharsComboBox.SelectedIndex;
int newVal;
if (index == 0) {
@ -260,6 +268,15 @@ namespace SourceGen.AppForms {
}
}
private void autoLabelStyleComboBox_SelectedIndexChanged(object sender, EventArgs e) {
AutoLabel.Style newStyle = (AutoLabel.Style)autoLabelStyleComboBox.SelectedIndex;
if (newStyle != mWorkProps.AutoLabelStyle) {
mWorkProps.AutoLabelStyle = newStyle;
mDirty = true;
UpdateControls();
}
}
#endregion General

View File

@ -385,7 +385,7 @@ namespace SourceGen.AppForms {
// won't generate identical labels for different addresses, and we do
// want to generate a single label if more than one table entry refers
// to the same target.
Symbol tmpSym = SymbolTable.GenerateUniqueForAddress(addr,
Symbol tmpSym = AutoLabel.GenerateUniqueForAddress(addr,
mProject.SymbolTable, "T");
// tmpSym was returned as an auto-label, make it a user label instead
tmpSym = new Symbol(tmpSym.Label, tmpSym.Value, Symbol.Source.User,

View File

@ -1731,11 +1731,13 @@ namespace SourceGen.AppForms {
// Edit > Copy (Ctrl+C)
private void copyToolStripMenuItem_Click(object sender, EventArgs e) {
const int AssemblerSource = 0;
const int Disassembly = 1;
const bool addCsv = true;
int format = AppSettings.Global.GetInt(AppSettings.CLIP_LINE_FORMAT, AssemblerSource);
EditAppSettings.ClipLineFormat format =
(EditAppSettings.ClipLineFormat) AppSettings.Global.GetEnum(
AppSettings.CLIP_LINE_FORMAT,
typeof(EditAppSettings.ClipLineFormat),
(int) EditAppSettings.ClipLineFormat.AssemblerSource);
StringBuilder fullText = new StringBuilder(codeListView.SelectedIndices.Count * 50);
StringBuilder csv = new StringBuilder(codeListView.SelectedIndices.Count * 40);
StringBuilder sb = new StringBuilder(100);
@ -1743,7 +1745,7 @@ namespace SourceGen.AppForms {
int addrAdj = mProject.CpuDef.HasAddr16 ? 6 : 9;
int disAdj = 0;
int bytesWidth = 0;
if (format == Disassembly) {
if (format == EditAppSettings.ClipLineFormat.Disassembly) {
// A limit of 8 gets us 4 bytes from dense display ("20edfd60") and 3 if spaces
// are included ("20 ed fd") with no excess. We want to increase it to 11 so
// we can always show 4 bytes.
@ -1766,7 +1768,7 @@ namespace SourceGen.AppForms {
case DisplayList.Line.Type.EquDirective:
case DisplayList.Line.Type.RegWidthDirective:
case DisplayList.Line.Type.OrgDirective:
if (format == Disassembly) {
if (format == EditAppSettings.ClipLineFormat.Disassembly) {
if (!string.IsNullOrEmpty(parts.Addr)) {
sb.Append(parts.Addr);
sb.Append(": ");
@ -1791,7 +1793,7 @@ namespace SourceGen.AppForms {
sb.Append("\r\n");
break;
case DisplayList.Line.Type.LongComment:
if (format == Disassembly) {
if (format == EditAppSettings.ClipLineFormat.Disassembly) {
TextUtil.AppendPaddedString(sb, string.Empty, disAdj);
}
sb.Append(parts.Comment);

View File

@ -243,6 +243,40 @@ namespace SourceGen {
Dirty = true;
}
/// <summary>
/// Retrieves an enumerated value setting.
/// </summary>
/// <param name="name">Setting name.</param>
/// <param name="enumType">Enum type that the value is part of.</param>
/// <param name="defaultValue">Setting default value.</param>
/// <returns>The value found, or the default value if no setting with the specified
/// name exists, or the stored value is not a member of the specified enumerated
/// type.</returns>
public int GetEnum(string name, Type enumType, int defaultValue) {
if (!mSettings.TryGetValue(name, out string valueStr)) {
return defaultValue;
}
try {
object o = Enum.Parse(enumType, valueStr);
return (int)o;
} catch (ArgumentException ae) {
Debug.WriteLine("Failed to parse " + valueStr + " (enum " + enumType + "): " +
ae.Message);
return defaultValue;
}
}
/// <summary>
/// Sets an enumerated setting.
/// </summary>
/// <param name="name">Setting name.</param>
/// <param name="enumType">Enum type.</param>
/// <param name="value">Setting value (integer enum index).</param>
public void SetEnum(string name, Type enumType, int value) {
mSettings[name] = Enum.GetName(enumType, value);
Dirty = true;
}
/// <summary>
/// Retrieves a string setting. The default value will be returned if the key
/// is not found, or if the value is null.

View File

@ -20,7 +20,7 @@ using System.Diagnostics;
namespace SourceGen.AsmGen {
public class AssemblerVersion {
/// <summary>
/// Version string reported by the assembler.
/// Version string reported by the assembler. Retained mostly for debugging.
/// </summary>
public string VersionStr { get; private set; }
@ -49,7 +49,7 @@ namespace SourceGen.AsmGen {
}
public override string ToString() {
return "[" + VersionStr + "/" + Version + "]";
return "['" + VersionStr + "'/" + Version + "]";
}
}

164
SourceGen/AutoLabel.cs Normal file
View File

@ -0,0 +1,164 @@
/*
* Copyright 2019 faddenSoft
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
namespace SourceGen {
/// <summary>
/// Functions for generation of "auto" labels.
/// </summary>
public static class AutoLabel {
/// <summary>
/// Auto-label style enumeration. Values were chosen to map directly to a combo box.
/// </summary>
public enum Style {
Unknown = -1,
Simple = 0,
Annotated = 1,
FullyAnnotated = 2
}
/// <summary>
/// Generates a unique address symbol. Does not add the symbol to the table.
///
/// This does not follow any Formatter rules -- labels are always entirely upper-case.
/// </summary>
/// <param name="addr">Address that label will be applied to.</param>
/// <param name="symbols">Symbol table, for uniqueness check.</param>
/// <param name="prefix">Prefix to use; must start with a letter.</param>
/// <returns>Newly-created, unique symbol.</returns>
public static Symbol GenerateUniqueForAddress(int addr, SymbolTable symbols,
string prefix) {
// $1234 == L1234, $05/1234 == L51234.
string label = prefix + addr.ToString("X4"); // always upper-case
if (symbols.TryGetValue(label, out Symbol unused)) {
const int MAX_RENAME = 999;
string baseLabel = label;
StringBuilder sb = new StringBuilder(baseLabel.Length + 8);
int index = -1;
do {
// This is expected to be unlikely and infrequent, so a simple linear
// probe for uniqueness is fine. Labels are based on the address, not
// the offset, so even without user-created labels there's still an
// opportunity for duplication.
index++;
sb.Clear();
sb.Append(baseLabel);
sb.Append('_');
sb.Append(index);
label = sb.ToString();
} while (index <= MAX_RENAME && symbols.TryGetValue(label, out unused));
if (index > MAX_RENAME) {
// I give up
throw new Exception("Too many identical symbols: " + label);
}
}
Symbol sym = new Symbol(label, addr, Symbol.Source.Auto,
Symbol.Type.LocalOrGlobalAddr);
return sym;
}
/// <summary>
/// Source reference type.
///
/// The enum is in priority order, i.e. the lowest-valued item "wins" in situations
/// where only one value is used.
/// </summary>
[Flags]
private enum RefTypes {
None = 0,
SubCall = 1 << 0,
Branch = 1 << 1,
DataRef = 1 << 2,
Write = 1 << 3,
Read = 1 << 4,
}
private static readonly char[] TAGS = { 'S', 'B', 'D', 'W', 'R' };
/// <summary>
/// Generates an auto-label with a prefix string based on the XrefSet.
/// </summary>
/// <param name="addr">Address that label will be applied to.</param>
/// <param name="symbols">Symbol table, for uniqueness check.</param>
/// <param name="xset">Cross-references for this location.</param>
/// <returns>Newly-created, unique symbol.</returns>
public static Symbol GenerateAnnotatedLabel(int addr, SymbolTable symbols,
XrefSet xset, Style style) {
Debug.Assert(xset != null);
Debug.Assert(style != Style.Simple);
RefTypes rtypes = RefTypes.None;
foreach (XrefSet.Xref xr in xset) {
switch (xr.Type) {
case XrefSet.XrefType.SubCallOp:
rtypes |= RefTypes.SubCall;
break;
case XrefSet.XrefType.BranchOp:
rtypes |= RefTypes.Branch;
break;
case XrefSet.XrefType.RefFromData:
rtypes |= RefTypes.DataRef;
break;
case XrefSet.XrefType.MemAccessOp:
switch (xr.AccType) {
case Asm65.OpDef.MemoryEffect.Read:
rtypes |= RefTypes.Read;
break;
case Asm65.OpDef.MemoryEffect.Write:
rtypes |= RefTypes.Write;
break;
case Asm65.OpDef.MemoryEffect.ReadModifyWrite:
rtypes |= RefTypes.Read;
rtypes |= RefTypes.Write;
break;
case Asm65.OpDef.MemoryEffect.None:
case Asm65.OpDef.MemoryEffect.Unknown:
break;
default:
Debug.Assert(false);
break;
}
break;
default:
Debug.Assert(false);
break;
}
}
if (rtypes == RefTypes.None) {
// unexpected
Debug.Assert(false);
return GenerateUniqueForAddress(addr, symbols, "X_");
}
StringBuilder sb = new StringBuilder(8);
for (int i = 0; i < TAGS.Length; i++) {
if (((int) rtypes & (1 << i)) != 0) {
sb.Append(TAGS[i]);
if (style == Style.Annotated) {
break;
}
}
}
sb.Append('_');
return GenerateUniqueForAddress(addr, symbols, sb.ToString());
}
}
}

View File

@ -311,7 +311,7 @@ namespace SourceGen {
// incorporates the address. It's possible through various means to end
// up with a user or platform label that matches an auto label, so we
// need to do some renaming in that case. Shouldn't happen often.
Symbol sym = SymbolTable.GenerateUniqueForAddress(mAnattribs[targetOffset].Address,
Symbol sym = AutoLabel.GenerateUniqueForAddress(mAnattribs[targetOffset].Address,
mProject.SymbolTable, "L");
mAnattribs[targetOffset].Symbol = sym;
// This will throw if the symbol already exists. That is the desired

View File

@ -477,6 +477,13 @@ namespace SourceGen {
GenerateXrefs();
reanalysisTimer.EndTask("GenerateXrefs");
// replace simple auto-labels ("L1234") with annotated versions ("WR_1234")
if (ProjectProps.AutoLabelStyle != AutoLabel.Style.Simple) {
reanalysisTimer.StartTask("AnnotateAutoLabels");
AnnotateAutoLabels();
reanalysisTimer.EndTask("AnnotateAutoLabels");
}
reanalysisTimer.StartTask("GenerateActiveDefSymbolList");
// Generate the list of project/platform symbols that are being used. This forms
// the list of EQUates at the top of the file.
@ -676,7 +683,7 @@ namespace SourceGen {
/// Call this after the code and data analysis passes have completed. This doesn't
/// interact with labels, so the ordering there doesn't matter.
/// </summary>
public void GeneratePlatformSymbolRefs() {
private void GeneratePlatformSymbolRefs() {
bool checkNearby = ProjectProps.AnalysisParams.SeekNearbyTargets;
for (int offset = 0; offset < mAnattribs.Length; ) {
@ -738,7 +745,7 @@ namespace SourceGen {
///
/// Call this after the code and data analysis passes have completed.
/// </summary>
public void GenerateXrefs() {
private void GenerateXrefs() {
// Xref generation. There are two general categories of references:
// (1) Numeric reference. Comes from instructions (e.g. "LDA $1000" or "BRA $1000")
// and Numeric/Address data items.
@ -901,6 +908,39 @@ namespace SourceGen {
return xset; // will be null if not found
}
/// <summary>
/// Replaces generic auto-labels with fancier versions generated from xrefs.
/// </summary>
private void AnnotateAutoLabels() {
AutoLabel.Style style = ProjectProps.AutoLabelStyle;
Debug.Assert(style != AutoLabel.Style.Simple);
for (int offset = 0; offset < mAnattribs.Length; offset++) {
Anattrib attr = mAnattribs[offset];
if (attr.Symbol != null && attr.Symbol.SymbolSource == Symbol.Source.Auto) {
XrefSet xset = GetXrefSet(offset);
if (xset == null) {
// Nothing useful to do here. This is unexpected, since auto-labels
// should only exist because something referenced the offset.
continue;
}
Symbol newSym =
AutoLabel.GenerateAnnotatedLabel(attr.Address, SymbolTable, xset, style);
if (!newSym.Equals(attr.Symbol)) {
//Debug.WriteLine("Replace " + attr.Symbol.Label + " with " +newSym.Label);
// Replace the symbol in Anattribs, update the symbol table, then
// call Refactor to update everything that referenced it.
Symbol oldSym = mAnattribs[offset].Symbol;
mAnattribs[offset].Symbol = newSym;
SymbolTable.Remove(oldSym);
SymbolTable.Add(newSym);
RefactorLabel(offset, oldSym.Label);
}
}
}
}
/// <summary>
/// Generates the list of project/platform symbols that are being used. Any
/// DefSymbol with a non-empty Xrefs is included. Previous contents are cleared.

View File

@ -185,6 +185,7 @@ namespace SourceGen {
public string CpuName { get; set; }
public bool IncludeUndocumentedInstr { get; set; }
public int EntryFlags { get; set; }
public string AutoLabelStyle { get; set; }
public SerAnalysisParameters AnalysisParams { get; set; }
public List<string> PlatformSymbolFileIdentifiers { get; set; }
public List<string> ExtensionScriptFileIdentifiers { get; set; }
@ -195,6 +196,7 @@ namespace SourceGen {
CpuName = Asm65.CpuDef.GetCpuNameFromType(props.CpuType);
IncludeUndocumentedInstr = props.IncludeUndocumentedInstr;
EntryFlags = props.EntryFlags.AsInt;
AutoLabelStyle = props.AutoLabelStyle.ToString();
AnalysisParams = new SerAnalysisParameters(props.AnalysisParams);
// External file identifiers require no conversion.
@ -461,6 +463,12 @@ namespace SourceGen {
proj.ProjectProps.CpuType = Asm65.CpuDef.GetCpuTypeFromName(spf.ProjectProps.CpuName);
proj.ProjectProps.IncludeUndocumentedInstr = spf.ProjectProps.IncludeUndocumentedInstr;
proj.ProjectProps.EntryFlags = Asm65.StatusFlags.FromInt(spf.ProjectProps.EntryFlags);
if (Enum.TryParse<AutoLabel.Style>(spf.ProjectProps.AutoLabelStyle,
out AutoLabel.Style als)) {
proj.ProjectProps.AutoLabelStyle = als;
} else {
// unknown value, leave as default
}
proj.ProjectProps.AnalysisParams = new ProjectProperties.AnalysisParameters();
proj.ProjectProps.AnalysisParams.AnalyzeUncategorizedData =
spf.ProjectProps.AnalysisParams.AnalyzeUncategorizedData;

View File

@ -26,6 +26,12 @@ namespace SourceGen {
/// All fields are explicitly handled by the ProjectFile serializer.
/// </summary>
public class ProjectProperties {
//
// NOTE:
// If you add or modify a member, make sure to update the copy constructor and
// add serialization code to ProjectFile.
//
/// <summary>
/// Some parameters we feed to the analyzers.
/// </summary>
@ -61,6 +67,11 @@ namespace SourceGen {
/// </summary>
public Asm65.StatusFlags EntryFlags { get; set; }
/// <summary>
/// Naming style for auto-generated labels.
/// </summary>
public AutoLabel.Style AutoLabelStyle { get; set; }
/// <summary>
/// Configurable parameters for the analyzers.
/// </summary>
@ -101,6 +112,7 @@ namespace SourceGen {
CpuType = src.CpuType;
IncludeUndocumentedInstr = src.IncludeUndocumentedInstr;
EntryFlags = src.EntryFlags;
AutoLabelStyle = src.AutoLabelStyle;
AnalysisParams = new AnalysisParameters(src.AnalysisParams);

View File

@ -227,9 +227,12 @@ data operand, and provides an indication of the nature of the reference:</p>
<li>data - address referenced by data (e.g. .DD2 addr)</li>
</ul>
<p>In addition, the source will be identified as a symbolic ("Sym") or
numeric ("Num") reference. Symbolic references may be offset from the
actual operand value; if this is the case, the adjustment will be shown
as well.</p>
numeric ("Num") reference. Most will be symbolic, because SourceGen
generates symbols automatically. However, references to addresses that
are offset from a symbol will also create a numeric reference entry.
For example, "LDA addr+1" will create a symbolic reference at &lt;addr&gt;
(shown in the table with an adjustment of "+1") and a numeric reference
at &lt;addr+1&gt;.</p>
<p>Double-clicking on a reference moves the code list selection to that
reference, and adds the previous selection to the navigation stack.</p>

View File

@ -131,6 +131,7 @@
<Compile Include="AsmGen\IGenerator.cs" />
<Compile Include="AsmGen\LabelLocalizer.cs" />
<Compile Include="AsmGen\StringGather.cs" />
<Compile Include="AutoLabel.cs" />
<Compile Include="NavStack.cs" />
<Compile Include="ChangeSet.cs" />
<Compile Include="CodeAnalysis.cs" />

View File

@ -211,42 +211,5 @@ namespace SourceGen {
mSymbolsByValue.Remove(sym);
ChangeSerial++;
}
/// <summary>
/// Generates a unique address symbol. Does not add the symbol to the list.
/// </summary>
/// <param name="addr">Address that label will be applied to.</param>
/// <param name="symbols">Symbol table.</param>
/// <param name="prefix">Prefix to use; must start with a letter.</param>
/// <returns>Newly-created, unique symbol.</returns>
public static Symbol GenerateUniqueForAddress(int addr, SymbolTable symbols,
string prefix) {
// $1234 == L1234, $05/1234 == L51234.
string label = prefix + addr.ToString("X4"); // always upper-case
if (symbols.TryGetValue(label, out Symbol unused)) {
const int MAX_RENAME = 999;
string baseLabel = label;
StringBuilder sb = new StringBuilder(baseLabel.Length + 8);
int index = -1;
do {
// This is expected to be unlikely and infrequent, so a simple linear
// probe for uniqueness is fine.
index++;
sb.Clear();
sb.Append(baseLabel);
sb.Append('_');
sb.Append(index);
label = sb.ToString();
} while (index <= MAX_RENAME && symbols.TryGetValue(label, out unused));
if (index > MAX_RENAME) {
// I give up
throw new Exception("Too many identical symbols");
}
}
Symbol sym = new Symbol(label, addr, Symbol.Source.Auto,
Symbol.Type.LocalOrGlobalAddr);
return sym;
}
}
}

View File

@ -28,9 +28,6 @@ namespace SourceGen {
public class XrefSet : IEnumerable<XrefSet.Xref> {
/// <summary>
/// Reference type. This is mostly useful for display to the user.
///
/// The enum is in priority order, i.e. the lowest-valued
/// item "wins" in situations where only one value is used.
/// </summary>
public enum XrefType {
Unknown = 0,