1
0
mirror of https://github.com/fadden/6502bench.git synced 2024-07-02 19:29:29 +00:00
6502bench/SourceGen/DefSymbol.cs
Andy McFadden 0ed1547e79 Set Anattrib DataDescriptor for local variable references
We now generate FormatDescriptors with WeakSymbolRefs for direct
page references that match variable table entries.

LocalVariableTable got a rewrite.  We need to be unique in both
name and address, but for the address we have to take the width into
account as well.  We also want to sort the display by address
rather than name.  (Some people might want it sorted by name, but
we can worry about that some other time.)

Updated the DefSymbol editor to require value uniqueness.  Note
addresses and constants exist in separate namespaces.

The various symbols are added to the SymbolTable so that uniqueness
checks work correctly.  This also allows the operand generation to
appear to work, but it doesn't yet handle redefinition of symbols.
2019-08-28 18:01:38 -07:00

204 lines
8.1 KiB
C#

/*
* 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.Diagnostics;
namespace SourceGen {
/// <summary>
/// Subclass of Symbol used for symbols defined in the platform or project.
///
/// Instances are immutable, except for the Xrefs field.
/// </summary>
/// <remarks>
/// The Xrefs field isn't really part of the object. It's just convenient to reference
/// them from here.
/// </remarks>
public class DefSymbol : Symbol {
// width to use when width doesn't matter; use 1 to try to get a prefab object
public const int NO_WIDTH = 1;
public const int MIN_WIDTH = 1;
public const int MAX_WIDTH = 4;
/// <summary>
/// Data format descriptor.
/// </summary>
public FormatDescriptor DataDescriptor { get; private set; }
/// <summary>
/// User-supplied comment.
/// </summary>
public string Comment { get; private set; }
/// <summary>
/// Platform symbols only: tag used to organize symbols into groups. Used by
/// extension scripts.
/// </summary>
/// <remarks>
/// This is not included in DefSymbol serialization because symbols with tags are
/// not stored in the project file. It's only set when symbols are parsed out of
/// platform symbol files.
/// </remarks>
public string Tag { get; private set; }
/// <summary>
/// Cross-reference data, generated by the analyzer.
/// </summary>
/// <remarks>
/// This is just a convenient place to reference some data generated at run-time. It's
/// not serialized, and not included in the test for equality.
/// </remarks>
public XrefSet Xrefs { get; private set; }
// NOTE: might be nice to identify the symbol's origin, e.g. which platform
// symbol file it was defined in. This could then be stored in a
// DisplayList line, for benefit of the Info panel.
/// <summary>
/// Internal base-object constructor, called by other constructors.
/// </summary>
private DefSymbol(string label, int value, Source source, Type type)
: base(label, value, source, type) {
Debug.Assert(source == Source.Platform || source == Source.Project ||
source == Source.Variable);
Debug.Assert(type == Type.ExternalAddr || type == Type.Constant);
Xrefs = new XrefSet();
}
/// <summary>
/// Constructor.
/// </summary>
/// <param name="label">Symbol's label.</param>
/// <param name="value">Symbol's value.</param>
/// <param name="source">Symbol source (general point of origin).</param>
/// <param name="type">Symbol type.</param>
/// <param name="formatSubType">Format descriptor sub-type, so we know how the
/// user wants the value to be displayed.</param>
/// <param name="comment">End-of-line comment.</param>
/// <param name="tag">Symbol tag, used for grouping platform symbols.</param>
public DefSymbol(string label, int value, Source source, Type type,
FormatDescriptor.SubType formatSubType, string comment, string tag)
: this(label, value, source, type, formatSubType, comment, tag, NO_WIDTH) { }
/// <summary>
/// Constructor. Used for local variables, which have a meaningful width.
/// </summary>
/// <param name="label">Symbol's label.</param>
/// <param name="value">Symbol's value.</param>
/// <param name="source">Symbol source (general point of origin).</param>
/// <param name="type">Symbol type.</param>
/// <param name="formatSubType">Format descriptor sub-type, so we know how the
/// user wants the value to be displayed.</param>
/// <param name="comment">End-of-line comment.</param>
/// <param name="tag">Symbol tag, used for grouping platform symbols.</param>
/// <param name="width">Variable width.</param>
public DefSymbol(string label, int value, Source source, Type type,
FormatDescriptor.SubType formatSubType, string comment, string tag, int width)
: this(label, value, source, type) {
Debug.Assert(comment != null);
Debug.Assert(tag != null);
DataDescriptor = FormatDescriptor.Create(width,
FormatDescriptor.Type.NumericLE, formatSubType);
Comment = comment;
Tag = tag;
}
/// <summary>
/// Constructs a DefSymbol from a Symbol and a format descriptor. This is used
/// for project symbols.
/// </summary>
/// <param name="sym">Base symbol.</param>
/// <param name="dfd">Format descriptor.</param>
/// <param name="comment">End-of-line comment.</param>
public DefSymbol(Symbol sym, FormatDescriptor dfd, string comment)
: this(sym.Label, sym.Value, sym.SymbolSource, sym.SymbolType) {
Debug.Assert(comment != null);
DataDescriptor = dfd;
Comment = comment;
Tag = string.Empty;
}
/// <summary>
/// Determines whether a symbol overlaps with a region. Useful for variables.
/// </summary>
/// <param name="a">Symbol to check.</param>
/// <param name="value">Address.</param>
/// <param name="width">Symbol width.</param>
/// <param name="type">Symbol type to check against.</param>
/// <returns>True if the symbols overlap.</returns>
public static bool CheckOverlap(DefSymbol a, int value, int width, Type type) {
if (a.DataDescriptor.Length <= 0 || width <= 0) {
return false;
}
if (a.Value < 0 || value < 0) {
return false;
}
if (a.SymbolType != type) {
return false;
}
int maxStart = Math.Max(a.Value, value);
int minEnd = Math.Min(a.Value + a.DataDescriptor.Length - 1, value + width - 1);
return (maxStart <= minEnd);
}
public static bool operator ==(DefSymbol a, DefSymbol b) {
if (ReferenceEquals(a, b)) {
return true; // same object, or both null
}
if (ReferenceEquals(a, null) || ReferenceEquals(b, null)) {
return false; // one is null
}
return a.Equals(b);
}
public static bool operator !=(DefSymbol a, DefSymbol b) {
return !(a == b);
}
public override bool Equals(object obj) {
if (!(obj is DefSymbol)) {
return false;
}
// Do base-class equality comparison and the ReferenceEquals check.
if (!base.Equals(obj)) {
return false;
}
// All fields must be equal, except Xrefs.
DefSymbol other = (DefSymbol)obj;
if (DataDescriptor != other.DataDescriptor ||
Comment != other.Comment ||
Tag != other.Tag) {
return false;
}
return true;
}
public override int GetHashCode() {
return base.GetHashCode() ^
DataDescriptor.GetHashCode() ^
Comment.GetHashCode() ^
Tag.GetHashCode();
}
public override string ToString() {
return base.ToString() + ":" + DataDescriptor + ";" + Comment +
(string.IsNullOrEmpty(Tag) ? "" : " [" + Tag + "]");
}
}
}