private FormattedSymbol CreateFormattedSymbol(DefSymbol defSym) { string typeStr; if (defSym.IsConstant) { typeStr = Res.Strings.ABBREV_CONSTANT; } else { typeStr = Res.Strings.ABBREV_ADDRESS; if (defSym.Direction == DefSymbol.DirectionFlags.Read) { typeStr += "<"; } else if (defSym.Direction == DefSymbol.DirectionFlags.Write) { typeStr += ">"; } } FormattedSymbol fsym = new FormattedSymbol( defSym, defSym.GenerateDisplayLabel(mFormatter), mFormatter.FormatValueInBase(defSym.Value, defSym.DataDescriptor.NumBase), typeStr, defSym.HasWidth ? defSym.DataDescriptor.Length.ToString() : NO_WIDTH_STR, defSym.Comment); return(fsym); }
/// <summary> /// Constructor. lvt will be null when creating a new entry. /// </summary> public EditLocalVariableTable(Window owner, DisasmProject project, Formatter formatter, LocalVariableTable lvt, int offset) { InitializeComponent(); Owner = owner; DataContext = this; mProject = project; mFormatter = formatter; mSymbolTable = project.SymbolTable; mOffset = NewOffset = offset; if (lvt != null) { mWorkTable = new LocalVariableTable(lvt); mIsNotNewTable = true; } else { mWorkTable = new LocalVariableTable(); } for (int i = 0; i < mWorkTable.Count; i++) { DefSymbol defSym = mWorkTable[i]; Variables.Add(CreateFormattedSymbol(defSym)); } }
private void projectSymbolsListView_MouseDoubleClick(object sender, MouseEventArgs e) { ListViewHitTestInfo info = projectSymbolsListView.HitTest(e.X, e.Y); DefSymbol defSym = WorkProps.ProjectSyms[info.Item.Text]; DoEditSymbol(defSym); }
/// <summary> /// Loads the project symbols into the ListView. /// </summary> private void LoadProjectSymbols() { // The set should be small enough that we don't need to worry about updating // the item list incrementally. //Debug.WriteLine("LPS loading " + WorkProps.ProjectSyms.Count + " project symbols"); projectSymbolsListView.BeginUpdate(); projectSymbolsListView.Items.Clear(); foreach (KeyValuePair <string, DefSymbol> kvp in WorkProps.ProjectSyms) { DefSymbol defSym = kvp.Value; string typeStr; if (defSym.SymbolType == Symbol.Type.Constant) { typeStr = Properties.Resources.ABBREV_CONSTANT; } else { typeStr = Properties.Resources.ABBREV_ADDRESS; } ListViewItem lvi = new ListViewItem(); lvi.Text = defSym.Label; mSymbolSubArray[0] = new ListViewItem.ListViewSubItem(lvi, NumFormatter.FormatValueInBase(defSym.Value, defSym.DataDescriptor.NumBase)); mSymbolSubArray[1] = new ListViewItem.ListViewSubItem(lvi, typeStr); mSymbolSubArray[2] = new ListViewItem.ListViewSubItem(lvi, defSym.Comment); lvi.SubItems.AddRange(mSymbolSubArray); projectSymbolsListView.Items.Add(lvi); } projectSymbolsListView.EndUpdate(); }
private void DoEditSymbol(DefSymbol defSym) { EditDefSymbol dlg = new EditDefSymbol(this, mFormatter, mWorkTable.GetSortedByLabel(), defSym, mSymbolTable, true, false); dlg.ShowDialog(); if (dlg.DialogResult == true) { // Label might have changed, so remove old before adding new. mWorkTable.RemoveByLabel(defSym.Label); mWorkTable.AddOrReplace(dlg.NewSym); // Replace entry in items source. for (int i = 0; i < Variables.Count; i++) { if (Variables[i].DefSym == defSym) { Variables[i] = CreateFormattedSymbol(dlg.NewSym); break; } } UpdateControls(); } }
/// <summary> /// Constructor, for editing a local variable, or editing a project symbol with /// the value field locked. /// </summary> /// <remarks> /// TODO(someday): disable the "constant" radio button unless CPU=65816. /// </remarks> public EditDefSymbol(Window owner, Formatter formatter, SortedList <string, DefSymbol> defList, DefSymbol defSym, SymbolTable symbolTable, bool isVariable, bool lockValueAndType) { InitializeComponent(); Owner = owner; DataContext = this; mNumFormatter = formatter; mDefSymbolList = defList; mOldSym = defSym; mSymbolTable = symbolTable; IsVariable = isVariable; mReadOnlyValueAndType = lockValueAndType; Label = Value = VarWidth = Comment = string.Empty; int maxWidth; if (isVariable) { ConstantLabel = (string)FindResource("str_VariableConstant"); maxWidth = 256; } else { ConstantLabel = (string)FindResource("str_ProjectConstant"); maxWidth = 65536; } mIsWidthOptional = !isVariable; string fmt = (string)FindResource("str_WidthLimitFmt"); WidthLimitLabel = string.Format(fmt, maxWidth); }
private void RemoveSymbolButton_Click(object sender, RoutedEventArgs e) { // Single-select list view, button dimmed when no selection. Debug.Assert(symbolsList.SelectedItems.Count == 1); int selectionIndex = symbolsList.SelectedIndex; FormattedSymbol item = (FormattedSymbol)symbolsList.SelectedItems[0]; DefSymbol defSym = item.DefSym; mWorkTable.RemoveByLabel(defSym.Label); for (int i = 0; i < Variables.Count; i++) { if (Variables[i].DefSym == defSym) { Variables.RemoveAt(i); break; } } UpdateControls(); // Restore selection to the item that used to come after the one we just deleted, // so you can hit "Remove" repeatedly to delete multiple items. int newCount = symbolsList.Items.Count; if (selectionIndex >= newCount) { selectionIndex = newCount - 1; } if (selectionIndex >= 0) { symbolsList.SelectedIndex = selectionIndex; removeSymbolButton.Focus(); // so you can keep banging on Enter } }
private void DoEditSymbol(DefSymbol defSym) { EditDefSymbol dlg = new EditDefSymbol(this, mFormatter, mWorkProps.ProjectSyms, defSym, defSym, null); dlg.ShowDialog(); if (dlg.DialogResult == true) { // Label might have changed, so remove old before adding new. mWorkProps.ProjectSyms.Remove(defSym.Label); mWorkProps.ProjectSyms[dlg.NewSym.Label] = dlg.NewSym; IsDirty = true; // Replace entry in items source. int i; for (i = 0; i < ProjectSymbols.Count; i++) { if (ProjectSymbols[i].DefSym == defSym) { ProjectSymbols[i] = CreateFormattedSymbol(dlg.NewSym); break; } } Debug.Assert(i != ProjectSymbols.Count); UpdateControls(); okButton.Focus(); } }
private void removeSymbolButton_Click(object sender, EventArgs e) { // Single-select list view, button dimmed when no selection. Debug.Assert(projectSymbolsListView.SelectedItems.Count == 1); int selectionIndex = projectSymbolsListView.SelectedIndices[0]; ListViewItem item = projectSymbolsListView.SelectedItems[0]; DefSymbol defSym = WorkProps.ProjectSyms[item.Text]; WorkProps.ProjectSyms.Remove(defSym.Label); mDirty = true; LoadProjectSymbols(); UpdateControls(); // Restore selection, so you can hit "Remove" repeatedly to delete // multiple items. int newCount = projectSymbolsListView.Items.Count; if (selectionIndex >= newCount) { selectionIndex = newCount - 1; } if (selectionIndex >= 0) { projectSymbolsListView.SelectedIndices.Add(selectionIndex); removeSymbolButton.Focus(); } }
private void editSymbolButton_Click(object sender, EventArgs e) { // Single-select list view, button dimmed when no selection. Debug.Assert(projectSymbolsListView.SelectedItems.Count == 1); ListViewItem item = projectSymbolsListView.SelectedItems[0]; DefSymbol defSym = WorkProps.ProjectSyms[item.Text]; DoEditSymbol(defSym); }
private void EditSymbolButton_Click(object sender, EventArgs e) { // Single-select list view, button dimmed when no selection. Debug.Assert(projectSymbolsList.SelectedItems.Count == 1); FormattedSymbol item = (FormattedSymbol)projectSymbolsList.SelectedItems[0]; DefSymbol defSym = mWorkProps.ProjectSyms[item.Label]; DoEditSymbol(defSym); }
private void okButton_Click(object sender, EventArgs e) { bool isConstant = constantRadioButton.Checked; ParseValue(out int value, out int numBase); FormatDescriptor.SubType subType = FormatDescriptor.GetSubTypeForBase(numBase); DefSym = new DefSymbol(labelTextBox.Text, value, Symbol.Source.Project, isConstant ? Symbol.Type.Constant : Symbol.Type.ExternalAddr, subType, commentTextBox.Text, string.Empty); }
public FormattedSymbol(DefSymbol defSym, string label, string value, string type, string width, string comment) { DefSym = defSym; Label = label; Value = value; Type = type; Width = width; Comment = comment; }
private void EditSymbolButton_Click(object sender, EventArgs e) { // Single-select list view, button dimmed when no selection. Debug.Assert(symbolsList.SelectedItems.Count == 1); FormattedSymbol item = (FormattedSymbol)symbolsList.SelectedItems[0]; DefSymbol defSym = mWorkTable.GetByLabel(item.Label); Debug.Assert(defSym != null); DoEditSymbol(defSym); }
private void SymbolsList_MouseDoubleClick(object sender, MouseButtonEventArgs e) { if (!symbolsList.GetClickRowColItem(e, out int unusedRow, out int unusedCol, out object objItem)) { // Header or empty area; ignore. return; } FormattedSymbol item = (FormattedSymbol)objItem; DefSymbol defSym = mWorkTable.GetByLabel(item.Label); DoEditSymbol(defSym); }
// IGenerator public void OutputLocalVariableTable(int offset, List <DefSymbol> newDefs, LocalVariableTable allDefs) { OutputLine(string.Empty, "!zone", "Z" + offset.ToString("x6"), string.Empty); for (int i = 0; i < allDefs.Count; i++) { DefSymbol defSym = allDefs[i]; string valueStr = PseudoOp.FormatNumericOperand(SourceFormatter, Project.SymbolTable, null, defSym.DataDescriptor, defSym.Value, 1, PseudoOp.FormatNumericOpFlags.None); OutputEquDirective(SourceFormatter.FormatVariableLabel(defSym.Label), valueStr, defSym.Comment); } }
private void OkButton_Click(object sender, RoutedEventArgs e) { ParseValue(out int value, out int numBase); FormatDescriptor.SubType subType = FormatDescriptor.GetSubTypeForBase(numBase); int width = -1; if (IsConstant && !IsVariable) { // width field is ignored, don't bother parsing } else if (!string.IsNullOrEmpty(VarWidth)) { bool ok = Asm65.Number.TryParseInt(VarWidth, out width, out int unusedNumBase); Debug.Assert(ok); } DefSymbol.DirectionFlags direction; if (IsReadChecked && IsWriteChecked) { direction = DefSymbol.DirectionFlags.ReadWrite; } else if (IsReadChecked) { direction = DefSymbol.DirectionFlags.Read; } else if (IsWriteChecked) { direction = DefSymbol.DirectionFlags.Write; } else { Debug.Assert(false); direction = DefSymbol.DirectionFlags.None; } // Parse and strip the annotation. string trimLabel = Symbol.TrimAndValidateLabel(Label, string.Empty, out bool unused1, out bool unused2, out bool unused3, out bool unused4, out Symbol.LabelAnnotation anno); NewSym = new DefSymbol(trimLabel, value, IsVariable ? Symbol.Source.Variable : Symbol.Source.Project, IsConstant ? Symbol.Type.Constant : Symbol.Type.ExternalAddr, anno, subType, width, width > 0, Comment, direction, null, string.Empty); DialogResult = true; }
private void DoEditSymbol(DefSymbol defSym) { EditDefSymbol dlg = new EditDefSymbol(NumFormatter, WorkProps.ProjectSyms); dlg.DefSym = defSym; dlg.ShowDialog(); if (dlg.DialogResult == DialogResult.OK) { // Label might have changed, so remove old before adding new. WorkProps.ProjectSyms.Remove(defSym.Label); WorkProps.ProjectSyms[dlg.DefSym.Label] = dlg.DefSym; mDirty = true; LoadProjectSymbols(); UpdateControls(); } dlg.Dispose(); }
// IGenerator public void OutputLocalVariableTable(int offset, List <DefSymbol> newDefs, LocalVariableTable allDefs) { // We can do better here, but it requires knowing whether anything in "newDefs" // overwrote a previous entry. If everything is new, we don't need to start // a new zone, and can just output newDefs. (We don't need to start a new zone // on a "clear previous".) OutputLine(string.Empty, "!zone", "Z" + offset.ToString("x6"), string.Empty); for (int i = 0; i < allDefs.Count; i++) { DefSymbol defSym = allDefs[i]; string valueStr = PseudoOp.FormatNumericOperand(SourceFormatter, Project.SymbolTable, null, defSym.DataDescriptor, defSym.Value, 1, PseudoOp.FormatNumericOpFlags.OmitLabelPrefixSuffix); OutputEquDirective(SourceFormatter.FormatVariableLabel(defSym.Label), valueStr, defSym.Comment); } }
/// <summary> /// Prepares the project symbols ListView. /// </summary> private void LoadProjectSymbols() { ProjectSymbols.Clear(); foreach (KeyValuePair <string, DefSymbol> kvp in mWorkProps.ProjectSyms) { DefSymbol defSym = kvp.Value; ProjectSymbols.Add(CreateFormattedSymbol(defSym)); } // This doesn't seem to enable "live sorting". It does an initial sort, but // without calling the Sorting function. I'm not sure what the point of this is, // or how to cause the DataGrid to behave like somebody clicked on a header. //ICollectionView view = // CollectionViewSource.GetDefaultView(projectSymbolsList.ItemsSource); //SortDescriptionCollection sortDes = view.SortDescriptions; //sortDes.Add(new SortDescription("Value", ListSortDirection.Descending)); //projectSymbolsList.Columns[0].SortDirection = ListSortDirection.Ascending; //view.Refresh(); }
/// <summary> /// Loads entries from the work table into the items source. /// </summary> private FormattedSymbol CreateFormattedSymbol(DefSymbol defSym) { string typeStr; if (defSym.IsConstant) { typeStr = Res.Strings.ABBREV_STACK_RELATIVE; } else { typeStr = Res.Strings.ABBREV_ADDRESS; } FormattedSymbol fsym = new FormattedSymbol( defSym, defSym.GenerateDisplayLabel(mFormatter), mFormatter.FormatValueInBase(defSym.Value, defSym.DataDescriptor.NumBase), typeStr, defSym.DataDescriptor.Length, defSym.Comment); return(fsym); }
private void RemoveSymbolButton_Click(object sender, RoutedEventArgs e) { // Single-select list view, button dimmed when no selection. Debug.Assert(projectSymbolsList.SelectedItems.Count == 1); int selectionIndex = projectSymbolsList.SelectedIndex; FormattedSymbol item = (FormattedSymbol)projectSymbolsList.SelectedItems[0]; DefSymbol defSym = item.DefSym; mWorkProps.ProjectSyms.Remove(defSym.Label); IsDirty = true; for (int i = 0; i < ProjectSymbols.Count; i++) { if (ProjectSymbols[i].DefSym == defSym) { ProjectSymbols.RemoveAt(i); break; } } UpdateControls(); // Restore selection to the item that used to come after the one we just deleted, // so you can hit "Remove" repeatedly to delete multiple items. int newCount = projectSymbolsList.Items.Count; if (selectionIndex >= newCount) { selectionIndex = newCount - 1; } if (selectionIndex >= 0) { projectSymbolsList.SelectedIndex = selectionIndex; removeSymbolButton.Focus(); } }
/// <summary> /// Gathers a list of platform symbols from the project's symbol table. /// </summary> private List <PlatSym> GeneratePlatSymList() { List <PlatSym> platSyms = new List <PlatSym>(); SymbolTable symTab = mProject.SymbolTable; foreach (Symbol sym in symTab) { if (!(sym is DefSymbol)) { // ignore user labels continue; } DefSymbol defSym = sym as DefSymbol; if (defSym.SymbolSource != Symbol.Source.Platform) { // ignore project symbols continue; } platSyms.Add(new PlatSym(defSym.Label, defSym.Value, defSym.Tag)); } return(platSyms); }
/// <summary> /// Validates input and updates controls appropriately. /// </summary> private void UpdateControls() { if (!IsLoaded) { return; } // Label must be valid and not already exist in the table we're editing. (For project // symbols, it's okay if an identical label exists elsewhere.) bool labelValid = Asm65.Label.ValidateLabel(Label); bool labelUnique; // NOTE: should be using Asm65.Label.LABEL_COMPARER? if (mDefSymbolList.TryGetValue(Label, out DefSymbol existing)) { // It's okay if it's the same object. labelUnique = (existing == mOldSym); } else { labelUnique = true; } // For local variables, do a secondary uniqueness check across the full symbol table. if (labelUnique && mSymbolTable != null) { labelUnique = !mSymbolTable.TryGetValue(Label, out Symbol sym); // It's okay if this and the other are both variables. if (!labelUnique && IsVariable && sym.IsVariable) { labelUnique = true; } } // Value must be blank, meaning "erase any earlier definition", or valid value. // (Hmm... don't currently have a way to specify "no symbol" in DefSymbol.) //if (!string.IsNullOrEmpty(valueTextBox.Text)) { bool valueValid = ParseValue(out int thisValue, out int unused2); //} else { // valueValid = true; //} bool widthValid = true; int thisWidth = -1; if (IsConstant && !IsVariable) { // width field is ignored } else if (string.IsNullOrEmpty(VarWidth)) { // blank field is okay if the width is optional widthValid = mIsWidthOptional; } else if (!Asm65.Number.TryParseInt(VarWidth, out thisWidth, out int unusedBase) || thisWidth < DefSymbol.MIN_WIDTH || thisWidth > DefSymbol.MAX_WIDTH || (IsVariable && thisWidth > 256)) { // All widths must be between 1 and 65536. For a variable, the full thing must // fit on zero page without wrapping. We test for 256 here so that we highlight // the "bad width" label, rather than the "it doesn't fit on the page" label. widthValid = false; } bool valueRangeValid = true; if (IsVariable && valueValid && widthValid) { // $ff with width 1 is okay, $ff with width 2 is not if (thisValue < 0 || thisValue + thisWidth > 256) { valueRangeValid = false; } } Symbol.Type symbolType = IsConstant ? Symbol.Type.Constant : Symbol.Type.ExternalAddr; // For a variable, the value must also be unique within the table. Values have // width, so we need to check for overlap. bool valueUniqueValid = true; if (IsVariable && valueValid && widthValid) { foreach (KeyValuePair <string, DefSymbol> kvp in mDefSymbolList) { if (kvp.Value != mOldSym && DefSymbol.CheckOverlap(kvp.Value, thisValue, thisWidth, symbolType)) { valueUniqueValid = false; break; } } } bool rwValid = true; if (!IsVariable && IsAddress) { rwValid = IsReadChecked || IsWriteChecked; } labelNotesLabel.Foreground = labelValid ? mDefaultLabelColor : Brushes.Red; labelUniqueLabel.Foreground = projectLabelUniqueLabel.Foreground = labelUnique ? mDefaultLabelColor : Brushes.Red; valueNotesLabel.Foreground = valueValid ? mDefaultLabelColor : Brushes.Red; varValueRangeLabel.Foreground = valueRangeValid ? mDefaultLabelColor : Brushes.Red; varValueUniqueLabel.Foreground = valueUniqueValid ? mDefaultLabelColor : Brushes.Red; widthNotesLabel.Foreground = widthValid ? mDefaultLabelColor : Brushes.Red; checkReadWriteLabel.Foreground = rwValid ? mDefaultLabelColor : Brushes.Red; IsValid = labelValid && labelUnique && valueValid && valueRangeValid && valueUniqueValid && widthValid && rwValid; }
/// <summary> /// Validates input and updates controls appropriately. /// </summary> private void UpdateControls() { if (!IsLoaded) { return; } // Label must be valid and not already exist in the table we're editing. (For project // symbols, it's okay if an identical label exists elsewhere.) string trimLabel = Symbol.TrimAndValidateLabel(Label, string.Empty, out bool labelValid, out bool unused1, out bool unused2, out bool unused3, out Symbol.LabelAnnotation unused4); bool labelUnique; if (mDefSymbolList.TryGetValue(trimLabel, out DefSymbol existing)) { // We found a match. See if we're just seeing the symbol we're editing. // If there's no "original" symbol, then the fact that we matched anything // means the label is not unique. Otherwise, we consider it unique if the // label matches the original symbol. // // We only need to check the label. Since we're comparing the original // symbol to the value from the symbol table, it should be a total match, // but the other fields don't actually matter. It's safer to let the Symbol // class comparison operators do the work though. labelUnique = (existing == mOrigSym); //labelUnique = mOrigSym != null && // Asm65.Label.LABEL_COMPARER.Equals(existing.Label, mOrigSym.Label); } else { labelUnique = true; } // For local variables, do a secondary uniqueness check across the full symbol table. if (labelUnique && mSymbolTable != null) { labelUnique = !mSymbolTable.TryGetValue(trimLabel, out Symbol sym); // It's okay if this and the other are both variables. if (!labelUnique && IsVariable && sym.IsVariable) { labelUnique = true; } } // Value must be blank, meaning "erase any earlier definition", or valid value. // (Hmm... don't currently have a way to specify "no symbol" in DefSymbol.) //if (!string.IsNullOrEmpty(valueTextBox.Text)) { bool valueValid = ParseValue(out int thisValue, out int unused5); //} else { // valueValid = true; //} bool widthValid = true; int thisWidth = -1; if (IsConstant && !IsVariable) { // width field is ignored } else if (string.IsNullOrEmpty(VarWidth)) { // blank field is okay if the width is optional widthValid = mIsWidthOptional; } else if (!Asm65.Number.TryParseInt(VarWidth, out thisWidth, out int unusedBase) || thisWidth < DefSymbol.MIN_WIDTH || thisWidth > DefSymbol.MAX_WIDTH || (IsVariable && thisWidth > MAX_VAR_WIDTH)) { // All widths must be between 1 and 65536. For a variable, the full thing must // fit on zero page, except on 65816 where a 16-bit access at $ff can extend // off the end of the direct page. // // We test the variable width here so that we highlight the "width limit" label, // rather than the "value range" label. widthValid = false; } bool valueRangeValid = true; if (IsVariable && valueValid && widthValid) { // $ff with width 1 is okay, $ff with width 2 is okay on 65816, width=3 is bad if (thisValue < 0 || thisValue + thisWidth > MAX_VAR_WIDTH) { valueRangeValid = false; } } else if (IsAddress && valueValid) { // limit to positive 24-bit integers; use a long for value+width so we // don't get fooled by overflow long lvalue = thisValue; if (thisWidth > 0) { lvalue += thisWidth - 1; } if (thisValue < 0 || lvalue > 0x00ffffff) { valueRangeValid = false; } } Symbol.Type symbolType = IsConstant ? Symbol.Type.Constant : Symbol.Type.ExternalAddr; // For a variable, the value must also be unique within the table. Values have // width, so we need to check for overlap. bool valueUniqueValid = true; if (IsVariable && valueValid && widthValid) { foreach (KeyValuePair <string, DefSymbol> kvp in mDefSymbolList) { if (kvp.Value != mOrigSym && DefSymbol.CheckOverlap(kvp.Value, thisValue, thisWidth, symbolType)) { valueUniqueValid = false; break; } } } bool rwValid = true; if (!IsVariable && IsAddress) { rwValid = IsReadChecked || IsWriteChecked; } labelNotesLabel.Foreground = labelValid ? mDefaultLabelColor : Brushes.Red; labelUniqueLabel.Foreground = projectLabelUniqueLabel.Foreground = labelUnique ? mDefaultLabelColor : Brushes.Red; valueNotesLabel.Foreground = valueValid ? mDefaultLabelColor : Brushes.Red; addrValueRangeLabel.Foreground = valueRangeValid ? mDefaultLabelColor : Brushes.Red; varValueRangeLabel.Foreground = valueRangeValid ? mDefaultLabelColor : Brushes.Red; varValueUniqueLabel.Foreground = valueUniqueValid ? mDefaultLabelColor : Brushes.Red; widthNotesLabel.Foreground = widthValid ? mDefaultLabelColor : Brushes.Red; checkReadWriteLabel.Foreground = rwValid ? mDefaultLabelColor : Brushes.Red; IsValid = labelValid && labelUnique && valueValid && valueRangeValid && valueUniqueValid && widthValid && rwValid; }
/// <summary> /// Constructor, for editing a project or platform symbol. /// </summary> public EditDefSymbol(Window owner, Formatter formatter, SortedList <string, DefSymbol> defList, DefSymbol defSym, SymbolTable symbolTable) : this(owner, formatter, defList, defSym, symbolTable, false, false) { }
/// <summary> /// Validates input and updates controls appropriately. /// </summary> private void UpdateControls() { if (!IsLoaded) { return; } // Label must be valid and not already exist in the table we're editing. (For project // symbols, it's okay if an identical label exists elsewhere.) string trimLabel = Symbol.TrimAndValidateLabel(Label, string.Empty, out bool labelValid, out bool unused1, out bool unused2, out bool unused3, out Symbol.LabelAnnotation unused4); bool labelUnique; if (mDefSymbolList.TryGetValue(trimLabel, out DefSymbol existing)) { // We found a match. See if we're just seeing the symbol we're editing. // // We only want to check the label, not the entire symbol, because otherwise // things can go funny when multiple edits are done without flushing the data // back to the symbol table. For example, when this is invoked from the // Edit Project Symbol button in the instruction operand editor, the user might // edit the comment field of an existing project symbol, hit OK here, then try // to edit it again before closing the operand editor. In that case we get // passed the edited DefSymbol, which no longer fully matches what's in the // symbol table. // // TODO: we still don't handle the case where the user changes the label from // FOO to FOO1 and then back to FOO without closing the instruction edit dialog. // The problem is that we find a match for FOO in the symbol table without // realizing that it was the original name before the edits began. To fix this // we need to pass in the original label as well as the recently-edited symbol, // and allow the new name to match either. //labelUnique = (existing == mOldSym); labelUnique = Asm65.Label.LABEL_COMPARER.Equals(existing.Label, mOldSym.Label); } else { labelUnique = true; } // For local variables, do a secondary uniqueness check across the full symbol table. if (labelUnique && mSymbolTable != null) { labelUnique = !mSymbolTable.TryGetValue(trimLabel, out Symbol sym); // It's okay if this and the other are both variables. if (!labelUnique && IsVariable && sym.IsVariable) { labelUnique = true; } } // Value must be blank, meaning "erase any earlier definition", or valid value. // (Hmm... don't currently have a way to specify "no symbol" in DefSymbol.) //if (!string.IsNullOrEmpty(valueTextBox.Text)) { bool valueValid = ParseValue(out int thisValue, out int unused5); //} else { // valueValid = true; //} bool widthValid = true; int thisWidth = -1; if (IsConstant && !IsVariable) { // width field is ignored } else if (string.IsNullOrEmpty(VarWidth)) { // blank field is okay if the width is optional widthValid = mIsWidthOptional; } else if (!Asm65.Number.TryParseInt(VarWidth, out thisWidth, out int unusedBase) || thisWidth < DefSymbol.MIN_WIDTH || thisWidth > DefSymbol.MAX_WIDTH || (IsVariable && thisWidth > MAX_VAR_WIDTH)) { // All widths must be between 1 and 65536. For a variable, the full thing must // fit on zero page, except on 65816 where a 16-bit access at $ff can extend // off the end of the direct page. // // We test the variable width here so that we highlight the "width limit" label, // rather than the "value range" label. widthValid = false; } bool valueRangeValid = true; if (IsVariable && valueValid && widthValid) { // $ff with width 1 is okay, $ff with width 2 is okay on 65816, width=3 is bad if (thisValue < 0 || thisValue + thisWidth > MAX_VAR_WIDTH) { valueRangeValid = false; } } else if (IsAddress && valueValid) { // limit to positive 24-bit integers; use a long for value+width so we // don't get fooled by overflow long lvalue = thisValue; if (thisWidth > 0) { lvalue += thisWidth - 1; } if (thisValue < 0 || lvalue > 0x00ffffff) { valueRangeValid = false; } } Symbol.Type symbolType = IsConstant ? Symbol.Type.Constant : Symbol.Type.ExternalAddr; // For a variable, the value must also be unique within the table. Values have // width, so we need to check for overlap. bool valueUniqueValid = true; if (IsVariable && valueValid && widthValid) { foreach (KeyValuePair <string, DefSymbol> kvp in mDefSymbolList) { if (kvp.Value != mOldSym && DefSymbol.CheckOverlap(kvp.Value, thisValue, thisWidth, symbolType)) { valueUniqueValid = false; break; } } } bool rwValid = true; if (!IsVariable && IsAddress) { rwValid = IsReadChecked || IsWriteChecked; } labelNotesLabel.Foreground = labelValid ? mDefaultLabelColor : Brushes.Red; labelUniqueLabel.Foreground = projectLabelUniqueLabel.Foreground = labelUnique ? mDefaultLabelColor : Brushes.Red; valueNotesLabel.Foreground = valueValid ? mDefaultLabelColor : Brushes.Red; addrValueRangeLabel.Foreground = valueRangeValid ? mDefaultLabelColor : Brushes.Red; varValueRangeLabel.Foreground = valueRangeValid ? mDefaultLabelColor : Brushes.Red; varValueUniqueLabel.Foreground = valueUniqueValid ? mDefaultLabelColor : Brushes.Red; widthNotesLabel.Foreground = widthValid ? mDefaultLabelColor : Brushes.Red; checkReadWriteLabel.Foreground = rwValid ? mDefaultLabelColor : Brushes.Red; IsValid = labelValid && labelUnique && valueValid && valueRangeValid && valueUniqueValid && widthValid && rwValid; }
private void ImportSymbolsButton_Click(object sender, RoutedEventArgs e) { OpenFileDialog fileDlg = new OpenFileDialog() { Filter = ProjectFile.FILENAME_FILTER + "|" + Res.Strings.FILE_FILTER_ALL, FilterIndex = 1 }; if (fileDlg.ShowDialog() != true) { return; } string projPathName = Path.GetFullPath(fileDlg.FileName); DisasmProject newProject = new DisasmProject(); if (!ProjectFile.DeserializeFromFile(projPathName, newProject, out FileLoadReport report)) { // Unable to open project file. Report error and bail. ProjectLoadIssues dlg = new ProjectLoadIssues(this, report.Format(), ProjectLoadIssues.Buttons.Cancel); dlg.ShowDialog(); // ignore dlg.DialogResult return; } // Import all user labels that were marked as "global export". These become // external-address project symbols with unspecified width. int foundCount = 0; foreach (KeyValuePair <int, Symbol> kvp in newProject.UserLabels) { if (kvp.Value.SymbolType == Symbol.Type.GlobalAddrExport) { Symbol sym = kvp.Value; DefSymbol defSym = new DefSymbol(sym.Label, sym.Value, Symbol.Source.Project, Symbol.Type.ExternalAddr, FormatDescriptor.SubType.None); mWorkProps.ProjectSyms[defSym.Label] = defSym; foundCount++; } } if (foundCount != 0) { IsDirty = true; LoadProjectSymbols(); // just reload the whole set UpdateControls(); } newProject.Cleanup(); // Tell the user we did something. Might be nice to tell them how many weren't // already present. string msg; if (foundCount == 0) { msg = Res.Strings.SYMBOL_IMPORT_NONE; } else { msg = string.Format(Res.Strings.SYMBOL_IMPORT_GOOD_FMT, foundCount); } MessageBox.Show(msg, Res.Strings.SYMBOL_IMPORT_CAPTION, MessageBoxButton.OK, MessageBoxImage.Information); }
private void importSymbolsButton_Click(object sender, EventArgs e) { OpenFileDialog fileDlg = new OpenFileDialog(); fileDlg.Filter = ProjectFile.FILENAME_FILTER + "|" + Properties.Resources.FILE_FILTER_ALL; fileDlg.FilterIndex = 1; if (fileDlg.ShowDialog() != DialogResult.OK) { return; } string projPathName = Path.GetFullPath(fileDlg.FileName); DisasmProject newProject = new DisasmProject(); if (!ProjectFile.DeserializeFromFile(projPathName, newProject, out FileLoadReport report)) { ProjectLoadIssues dlg = new ProjectLoadIssues(); dlg.Messages = report.Format(); dlg.CanContinue = false; dlg.ShowDialog(); // ignore dlg.DialogResult dlg.Dispose(); return; } // Import all user labels that were marked as "global export". These become // external-address project symbols. int foundCount = 0; foreach (KeyValuePair <int, Symbol> kvp in newProject.UserLabels) { if (kvp.Value.SymbolType == Symbol.Type.GlobalAddrExport) { Symbol sym = kvp.Value; DefSymbol defSym = new DefSymbol(sym.Label, sym.Value, Symbol.Source.Project, Symbol.Type.ExternalAddr, FormatDescriptor.SubType.None, string.Empty, string.Empty); WorkProps.ProjectSyms[defSym.Label] = defSym; foundCount++; } } if (foundCount != 0) { mDirty = true; LoadProjectSymbols(); UpdateControls(); } newProject.Cleanup(); // Tell the user we did something. Might be nice to tell them how many weren't // already present. string msg; if (foundCount == 0) { msg = Properties.Resources.SYMBOL_IMPORT_NONE; } else { msg = string.Format(Properties.Resources.SYMBOL_IMPORT_GOOD, foundCount); } MessageBox.Show(msg, Properties.Resources.SYMBOL_IMPORT_CAPTION, MessageBoxButtons.OK, MessageBoxIcon.Information); }
/// <summary> /// Gathers a list of platform symbols from the project's symbol table. /// </summary> private List <PlSymbol> GeneratePlSymbolList() { List <PlSymbol> plSymbols = new List <PlSymbol>(); SymbolTable symTab = mProject.SymbolTable; foreach (Symbol sym in symTab) { PlSymbol.Source plsSource; switch (sym.SymbolSource) { case Symbol.Source.Platform: plsSource = PlSymbol.Source.Platform; break; case Symbol.Source.Project: plsSource = PlSymbol.Source.Project; break; case Symbol.Source.User: plsSource = PlSymbol.Source.User; break; case Symbol.Source.Variable: case Symbol.Source.Auto: // don't forward these to plugins continue; default: Debug.Assert(false); continue; } PlSymbol.Type plsType; switch (sym.SymbolType) { case Symbol.Type.LocalOrGlobalAddr: case Symbol.Type.GlobalAddr: case Symbol.Type.GlobalAddrExport: case Symbol.Type.ExternalAddr: plsType = PlSymbol.Type.Address; break; case Symbol.Type.Constant: plsType = PlSymbol.Type.Constant; break; default: Debug.Assert(false); continue; } int width = -1; string tag = string.Empty; if (sym is DefSymbol) { DefSymbol defSym = sym as DefSymbol; width = defSym.DataDescriptor.Length; tag = defSym.Tag; } plSymbols.Add(new PlSymbol(sym.Label, sym.Value, width, plsSource, plsType, tag)); } return(plSymbols); }