Exemplo n.º 1
0
        /// <summary>
        /// Gets the symbol associated with a symbol reference.  If uniquification is enabled,
        /// the unique-label map for the specified offset will be used to transform the
        /// symbol reference.
        /// </summary>
        /// <param name="offset">Offset of start of instruction.</param>
        /// <param name="symRef">Reference to symbol.</param>
        /// <returns>Symbol, or null if no match found.</returns>
        public DefSymbol GetSymbol(int offset, WeakSymbolRef symRef)
        {
            AdvanceToOffset(offset);

            // The symRef uses the non-uniquified symbol, so we need to get the unique value at
            // the current offset.  We may need to do this even when variables can be
            // redefined, because we might have a variable that's a duplicate of a user label
            // or project symbol.

            // Start by applying the de-duplication map.
            string label = symRef.Label;

            if (mDupRemap.TryGetValue(symRef.Label, out string remap))
            {
                label = remap;
            }
            //Debug.WriteLine("GetSymbol " + symRef.Label + " -> " + label);
            if (mUniqueLabels != null && mUniqueLabels.TryGetValue(label, out UniqueLabel ulab))
            {
                //Debug.WriteLine("  Unique var " + symRef.Label + " -> " + ulab.Label);
                label = ulab.Label;
            }
            DefSymbol defSym = mCurrentTable.GetByLabel(label);

            // In theory this is okay, but in practice the only things asking for symbols are
            // entirely convinced that the symbol exists here.  So this is probably a bug.
            Debug.Assert(defSym != null);

            return(defSym);
        }
Exemplo n.º 2
0
            public void Add(DefSymbol defSym)
            {
                bool doRead  = true;
                bool doWrite = true;

                if (defSym.Direction == DefSymbol.DirectionFlags.Read)
                {
                    doWrite = false;
                }
                else if (defSym.Direction == DefSymbol.DirectionFlags.Write)
                {
                    doRead = false;
                }

                for (int i = 0; i < defSym.DataDescriptor.Length; i++)
                {
                    // See if there's already something here.  If we reach the end of the
                    // bank, wrap around.
                    int addr = (defSym.Value & 0xff0000) + ((defSym.Value + i) & 0xffff);
                    addr &= mMultiMask.AddressMask;     // use minimal address
                    DefSymbol curSym;
                    if (doRead)
                    {
                        mByReadAddress.TryGetValue(addr, out curSym);
                        mByReadAddress[addr] = (curSym == null) ? defSym :
                                               (DefSymbol)HighestPriority(defSym, curSym);
                    }
                    if (doWrite)
                    {
                        mByWriteAddress.TryGetValue(addr, out curSym);
                        mByWriteAddress[addr] = (curSym == null) ? defSym :
                                                (DefSymbol)HighestPriority(defSym, curSym);
                    }
                }
            }
Exemplo n.º 3
0
 /// <summary>
 /// Constructs a DefSymbol from an existing DefSymbol, with a different label.  Use
 /// this to change the label while keeping everything else the same.
 /// </summary>
 /// <remarks>
 /// This can't be a simple Rename() function that uses a copy constructor because
 /// the label is in the base class.
 ///
 /// The Xrefs reference points to the actual XrefSet in the original.  This is not
 /// ideal, but it's the easiest way to keep xrefs working across Lv de-duplication
 /// (you actually *want* xrefs added to copies to be held by the original).
 /// </remarks>
 /// <param name="defSym">Source DefSymbol.</param>
 /// <param name="label">Label to use.</param>
 public DefSymbol(DefSymbol defSym, string label)
     : this(label, defSym.Value, defSym.SymbolSource, defSym.SymbolType,
            defSym.LabelAnno, defSym.DataDescriptor.FormatSubType,
            defSym.DataDescriptor.Length, defSym.HasWidth, defSym.Comment,
            defSym.Direction, defSym.MultiMask, defSym.Tag)
 {
     Debug.Assert(SymbolSource == Source.Variable);
     Xrefs = defSym.Xrefs;
 }
Exemplo n.º 4
0
        /// <summary>
        /// Searches the table for symbols with matching address values.  Ignores constants and
        /// variables.
        /// </summary>
        /// <param name="addr">Address to find.</param>
        /// <returns>First matching symbol found, or null if nothing matched.</returns>
        public Symbol FindNonVariableByAddress(int addr, OpDef.MemoryEffect effect)
        {
            bool tryRead, tryWrite;

            if (effect == OpDef.MemoryEffect.Read)
            {
                tryRead  = true;
                tryWrite = false;
            }
            else if (effect == OpDef.MemoryEffect.Write)
            {
                tryRead  = false;
                tryWrite = true;
            }
            else if (effect == OpDef.MemoryEffect.ReadModifyWrite ||
                     effect == OpDef.MemoryEffect.None)
            {
                tryRead = tryWrite = true;
            }
            else
            {
                Debug.Assert(false);
                return(null);
            }

            Symbol sym = null;

            if (tryRead)
            {
                mSymbolsByReadAddress.TryGetValue(addr, out sym);
            }
            if (tryWrite && sym == null)
            {
                mSymbolsByWriteAddress.TryGetValue(addr, out sym);
            }

            if (sym == null)
            {
                // Nothing matched, check the match groups.
                foreach (KeyValuePair <DefSymbol.MultiAddressMask, MaskGroup> kvp in mMaskGroups)
                {
                    DefSymbol.MultiAddressMask multiMask = kvp.Key;
                    if ((addr & multiMask.CompareMask) == multiMask.CompareValue)
                    {
                        MaskGroup group  = kvp.Value;
                        DefSymbol defSym = kvp.Value.Find(addr, tryRead, tryWrite);
                        if (defSym != null)
                        {
                            sym = defSym;
                            break;
                        }
                    }
                }
            }
            return(sym);
        }
Exemplo n.º 5
0
        /// <summary>
        /// Restores a de-duplicated symbol to original form.
        /// </summary>
        /// <remarks>
        /// Another kluge on the de-duplication system.  This is used by the instruction
        /// operand editor's "edit variable" shortcut mechanism, because trying to edit the
        /// DefSymbol with the de-duplicated name ends badly.
        /// </remarks>
        /// <param name="sym">Symbol to un-de-duplicate.</param>
        /// <returns>Original or un-de-duplicated symbol.</returns>
        public DefSymbol GetOriginalForm(DefSymbol sym)
        {
            string orig = UnDeDuplicate(sym.Label);

            if (orig == sym.Label)
            {
                return(sym);
            }
            return(new DefSymbol(sym, orig));
        }
Exemplo n.º 6
0
        /// <summary>
        /// Adds a symbol to the address table.  All affected addresses are updated.  If an
        /// existing symbol is already present at an address, the new or old symbol will be
        /// selected in priority order.
        /// </summary>
        /// <param name="sym">Symbol to add.</param>
        private void AddAddressTableEntry(Symbol sym)
        {
            if (sym.IsConstant)
            {
                return;
            }
            if (sym.SymbolSource == Symbol.Source.Variable)
            {
                return;
            }
            if (sym is DefSymbol && ((DefSymbol)sym).MultiMask != null)
            {
                AddMultiMaskEntry((DefSymbol)sym);
                return;
            }

            bool doRead  = true;
            bool doWrite = true;
            int  width   = 1;

            if (sym is DefSymbol)
            {
                DefSymbol defSym = (DefSymbol)sym;
                width = defSym.DataDescriptor.Length;
                if (defSym.Direction == DefSymbol.DirectionFlags.Read)
                {
                    doWrite = false;
                }
                else if (defSym.Direction == DefSymbol.DirectionFlags.Write)
                {
                    doRead = false;
                }
            }

            for (int i = 0; i < width; i++)
            {
                // See if there's already something here.  If we reach the end of the
                // bank, wrap around.
                int    addr = (sym.Value & 0xff0000) + ((sym.Value + i) & 0xffff);
                Symbol curSym;
                if (doRead)
                {
                    mSymbolsByReadAddress.TryGetValue(addr, out curSym);
                    mSymbolsByReadAddress[addr] = (curSym == null) ? sym :
                                                  HighestPriority(sym, curSym);
                }
                if (doWrite)
                {
                    mSymbolsByWriteAddress.TryGetValue(addr, out curSym);
                    mSymbolsByWriteAddress[addr] = (curSym == null) ? sym :
                                                   HighestPriority(sym, curSym);
                }
            }
        }
Exemplo n.º 7
0
 private void AddMultiMaskEntry(DefSymbol defSym)
 {
     DefSymbol.MultiAddressMask multiMask = defSym.MultiMask;
     mMaskGroups.TryGetValue(multiMask, out MaskGroup group);
     if (group == null)
     {
         group = new MaskGroup(multiMask);
         mMaskGroups.Add(multiMask, group);
     }
     group.Add(defSym);
 }
Exemplo n.º 8
0
            public SerLocalVariableTable(LocalVariableTable varTab)
            {
                Variables = new List <SerDefSymbol>(varTab.Count);
                for (int i = 0; i < varTab.Count; i++)
                {
                    DefSymbol defSym = varTab[i];
                    Variables.Add(new SerDefSymbol(defSym));
                }

                ClearPrevious = varTab.ClearPrevious;
            }
Exemplo n.º 9
0
 public SerDefSymbol(DefSymbol defSym) : base(defSym)
 {
     DataDescriptor = new SerFormatDescriptor(defSym.DataDescriptor);
     Comment        = defSym.Comment;
     HasWidth       = defSym.HasWidth;
     Direction      = defSym.Direction.ToString();
     if (defSym.MultiMask != null)
     {
         MultiMask = new SerMultiMask(defSym.MultiMask);
     }
 }
Exemplo n.º 10
0
 /// <summary>
 /// Finds symbols that overlap with the specified value and width.  If more than one
 /// matching symbol is found, an arbitrary match will be returned.  Comparisons are
 /// only performed between symbols of the same type, so addresses and constants do
 /// not clash.
 /// </summary>
 /// <param name="value">Value to compare.</param>
 /// <param name="width">Width to check, useful when checking for collisions.  When
 ///   doing a simple variable lookup, this should be set to 1.</param>
 /// <returns>One matching symbol, or null if none matched.</returns>
 public DefSymbol GetByValueRange(int value, int width, Symbol.Type type)
 {
     foreach (KeyValuePair <string, DefSymbol> kvp in mVarByLabel)
     {
         if (DefSymbol.CheckOverlap(kvp.Value, value, width, type))
         {
             return(kvp.Value);
         }
     }
     return(null);
 }
Exemplo n.º 11
0
 /// <summary>
 /// Determines whether symbol one is "wider" than symbol two.  It's wider if it
 /// has a width, and the other symbol either doesn't have a width or has a width
 /// but is narrower.
 /// </summary>
 public static bool IsWider(DefSymbol a, DefSymbol b)
 {
     if (!a.HasWidth && !b.HasWidth)
     {
         return(false);
     }
     else if (a.HasWidth && !b.HasWidth)
     {
         return(true);
     }
     else if (!a.HasWidth && b.HasWidth)
     {
         return(false);
     }
     else
     {
         return(a.DataDescriptor.Length > b.DataDescriptor.Length);
     }
 }
Exemplo n.º 12
0
        /// <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);
        }
Exemplo n.º 13
0
        /// <summary>
        /// Creates a DefSymbol from a SerDefSymbol.
        /// </summary>
        /// <param name="serDefSym">Deserialized data.</param>
        /// <param name="contentVersion">Serialization version.</param>
        /// <param name="report">Error report object.</param>
        /// <param name="outDefSym">Created symbol.</param>
        /// <returns></returns>
        private static bool CreateDefSymbol(SerDefSymbol serDefSym, int contentVersion,
                                            FileLoadReport report, out DefSymbol outDefSym)
        {
            outDefSym = null;

            if (!CreateSymbol(serDefSym, report, out Symbol sym))
            {
                return(false);
            }
            if (!CreateFormatDescriptor(serDefSym.DataDescriptor, contentVersion, report,
                                        out FormatDescriptor dfd))
            {
                return(false);
            }
            DefSymbol.DirectionFlags direction;
            if (string.IsNullOrEmpty(serDefSym.Direction))
            {
                direction = DefSymbol.DirectionFlags.ReadWrite;
            }
            else
            {
                try {
                    direction = (DefSymbol.DirectionFlags)
                                Enum.Parse(typeof(DefSymbol.DirectionFlags), serDefSym.Direction);
                } catch (ArgumentException) {
                    report.Add(FileLoadItem.Type.Warning, Res.Strings.ERR_BAD_DEF_SYMBOL_DIR +
                               ": " + serDefSym.Direction);
                    return(false);
                }
            }


            DefSymbol.MultiAddressMask multiMask = null;
            if (serDefSym.MultiMask != null)
            {
                multiMask = new DefSymbol.MultiAddressMask(serDefSym.MultiMask.CompareMask,
                                                           serDefSym.MultiMask.CompareValue, serDefSym.MultiMask.AddressMask);
            }

            outDefSym = DefSymbol.Create(sym, dfd, serDefSym.HasWidth, serDefSym.Comment,
                                         direction, multiMask);
            return(true);
        }
Exemplo n.º 14
0
        /// <summary>
        /// Adds an additional annotation to an EQU directive, indicating whether the symbol
        /// is a constant or an address, and (if address) how many bytes it spans.
        /// </summary>
        /// <param name="formatter">Formatter object.</param>
        /// <param name="operand">Formatted operand string.</param>
        /// <param name="defSym">Project/platform/variable symbol.</param>
        /// <returns></returns>
        public static string AnnotateEquDirective(Formatter formatter, string operand,
                                                  DefSymbol defSym)
        {
            string typeStr;

            if (defSym.IsConstant)
            {
                if (defSym.SymbolSource == Symbol.Source.Variable)
                {
                    typeStr = Res.Strings.EQU_STACK_RELATIVE;
                }
                else
                {
                    typeStr = Res.Strings.EQU_CONSTANT;
                }
            }
            else
            {
                typeStr = Res.Strings.EQU_ADDRESS;
            }

            string msgStr = null;

            if (defSym.HasWidth)
            {
                msgStr = typeStr + "/" + defSym.DataDescriptor.Length;
            }
            else if (defSym.IsConstant)
            {
                // not entirely convinced we want this, but there's currently no other way
                // to tell the difference between an address and a constant from the code list
                msgStr = typeStr;
            }

            if (msgStr == null)
            {
                return(operand);
            }
            else
            {
                return(operand + "  {" + msgStr + "}");
            }
        }
Exemplo n.º 15
0
        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);
        }
Exemplo n.º 16
0
        /// <summary>
        /// Adds a symbol to the variable table.  Existing entries with the same name or
        /// overlapping values will be removed.
        /// </summary>
        /// <param name="newSym">Symbol to add.</param>
        public void AddOrReplace(DefSymbol newSym)
        {
            if (!newSym.IsConstant && newSym.SymbolType != Symbol.Type.ExternalAddr)
            {
                Debug.Assert(false, "Unexpected symbol type " + newSym.SymbolType);
                return;
            }
            if (!newSym.IsVariable)
            {
                Debug.Assert(false, "Unexpected symbol source " + newSym.SymbolSource);
                return;
            }

            // Remove existing entries that match on label or value.  The value check must
            // take the width into account.
            if (mVarByLabel.TryGetValue(newSym.Label, out DefSymbol labelSym))
            {
                mVarByLabel.Remove(labelSym.Label);
                mVarByValue.Remove(labelSym);
            }

            // Inefficient, but the list should be small.
            DefSymbol valSym;

            while ((valSym = GetByValueRange(newSym.Value,
                                             newSym.DataDescriptor.Length, newSym.SymbolType)) != null)
            {
                mVarByLabel.Remove(valSym.Label);
                mVarByValue.Remove(valSym);
            }

            mVarByLabel.Add(newSym.Label, newSym);
            mVarByValue.Add(newSym);
            Debug.Assert(mVarByValue.Count == mVarByLabel.Count);

            mNeedSort = true;
        }
Exemplo n.º 17
0
        /// <summary>
        /// Updates internal state to reflect the state of the world at the specified offset.
        /// </summary>
        /// <remarks>
        /// When the offset is greater than or equal to its value on a previous call, we can
        /// do an incremental update.  If the offset moves backward, we have to reset and walk
        /// forward again.
        /// </remarks>
        /// <param name="targetOffset">Target offset.</param>
        private void AdvanceToOffset(int targetOffset)
        {
            if (mNextLvtIndex < 0)
            {
                return;
            }
            if (targetOffset < mRecentOffset)
            {
                // We went backwards.
                Reset(false);
            }
            while (mNextLvtOffset <= targetOffset)
            {
                if (!mProject.GetAnattrib(mNextLvtOffset).IsStart)
                {
                    // Hidden table, ignore it.
                    Debug.WriteLine("Ignoring LvTable at +" + mNextLvtOffset.ToString("x6"));
                }
                else
                {
                    // Process this table.
                    LocalVariableTable lvt = mLvTables.Values[mNextLvtIndex];
                    if (lvt.ClearPrevious)
                    {
                        mCurrentTable.Clear();
                    }

                    // Create a list for GetVariablesDefinedAtOffset
                    mRecentSymbols = new List <DefSymbol>();
                    mRecentOffset  = mNextLvtOffset;

                    // Merge the new entries into the work table.  This automatically
                    // discards entries that clash by name or value.
                    for (int i = 0; i < lvt.Count; i++)
                    {
                        DefSymbol defSym   = lvt[i];
                        string    newLabel = defSym.Label;

                        if (mMaskLeadingUnderscores && newLabel[0] == '_')
                        {
                            newLabel = AsmGen.LabelLocalizer.NO_UNDER_PFX + newLabel;
                        }

                        // Look for non-variable symbols with the same label.  Ordinarily the
                        // editor prevents this from happening, but there are ways to trick
                        // the system (e.g. add a symbol while the LvTable is hidden, or have
                        // a non-unique local promoted to global).  We deal with it here.
                        //
                        // TODO(someday): this is not necessary for assemblers like Merlin 32
                        // that put variables in a separate namespace.
                        if (mAllNvSymbols.TryGetValue(newLabel, out Symbol unused))
                        {
                            Debug.WriteLine("Detected duplicate non-var label " + newLabel +
                                            " at +" + mNextLvtOffset.ToString("x6"));
                            newLabel = GenerateDeDupLabel(newLabel);
                        }

                        if (newLabel != defSym.Label)
                        {
                            mDupRemap[defSym.Label] = newLabel;
                            defSym = new DefSymbol(defSym, newLabel);
                        }

                        if (mDoUniquify)
                        {
                            if (mUniqueLabels.TryGetValue(defSym.Label, out UniqueLabel ulab))
                            {
                                // We've seen this label before; generate a unique version by
                                // increasing the appended number.
                                ulab.MakeUnique(mAllNvSymbols);
                                defSym = new DefSymbol(defSym, ulab.Label);
                            }
                            else
                            {
                                // Haven't seen this before.  Add it to the unique-labels table.
                                mUniqueLabels.Add(defSym.Label, new UniqueLabel(defSym.Label));
                            }
                        }
                        mCurrentTable.AddOrReplace(defSym);

                        mRecentSymbols.Add(defSym);
                    }

                    //mCurrentTable.DebugDump(mNextLvtOffset);
                }

                // Update state to look for next table.
                mNextLvtIndex++;
                if (mNextLvtIndex < mLvTables.Keys.Count)
                {
                    mNextLvtOffset = mLvTables.Keys[mNextLvtIndex];
                }
                else
                {
                    mNextLvtOffset = mProject.FileDataLength;   // never reached
                }
            }
        }
Exemplo n.º 18
0
 /// <summary>
 /// Constructs a DefSymbol from an existing DefSymbol, with a different label.  Use
 /// this to change the label while keeping everything else the same.
 /// </summary>
 /// <remarks>
 /// This can't be a simple Rename() function that uses a copy constructor because
 /// the label is in the base class.
 /// </remarks>
 /// <param name="defSym">Source DefSymbol.</param>
 /// <param name="label">Label to use.</param>
 public DefSymbol(DefSymbol defSym, string label)
     : this(label, defSym.Value, defSym.SymbolSource, defSym.SymbolType,
            defSym.DataDescriptor.FormatSubType, defSym.DataDescriptor.Length,
            defSym.HasWidth, defSym.Comment, defSym.Direction, defSym.MultiMask, defSym.Tag)
 {
 }
Exemplo n.º 19
0
        /// <summary>
        /// Loads platform symbols.
        /// </summary>
        /// <param name="fileIdent">Relative pathname of file to open.</param>
        /// <param name="report">Report of warnings and errors.</param>
        /// <returns>True on success (no errors), false on failure.</returns>
        public bool LoadFromFile(string fileIdent, string projectDir, out FileLoadReport report)
        {
            // These files shouldn't be enormous.  Do it the easy way.
            report = new FileLoadReport(fileIdent);

            ExternalFile ef = ExternalFile.CreateFromIdent(fileIdent);

            if (ef == null)
            {
                report.Add(FileLoadItem.Type.Error,
                           CommonUtil.Properties.Resources.ERR_FILE_NOT_FOUND + ": " + fileIdent);
                return(false);
            }

            string pathName = ef.GetPathName(projectDir);

            if (pathName == null)
            {
                report.Add(FileLoadItem.Type.Error,
                           Properties.Resources.ERR_BAD_IDENT + ": " + fileIdent);
                return(false);
            }
            string[] lines;
            try {
                lines = File.ReadAllLines(pathName);
            } catch (IOException ioe) {
                Debug.WriteLine("Platform symbol load failed: " + ioe);
                report.Add(FileLoadItem.Type.Error,
                           CommonUtil.Properties.Resources.ERR_FILE_NOT_FOUND + ": " + pathName);
                return(false);
            }

            string tag = string.Empty;

            int lineNum = 0;

            foreach (string line in lines)
            {
                lineNum++;      // first line is line 1, says Vim and VisualStudio
                if (string.IsNullOrEmpty(line) || line[0] == ';')
                {
                    // ignore
                }
                else if (line[0] == '*')
                {
                    if (line.StartsWith(TAG_CMD))
                    {
                        tag = ParseTag(line);
                    }
                    else
                    {
                        // Do something clever with *SYNOPSIS?
                        Debug.WriteLine("CMD: " + line);
                    }
                }
                else
                {
                    MatchCollection matches = sNameValueRegex.Matches(line);
                    if (matches.Count == 1)
                    {
                        //Debug.WriteLine("GOT '" + matches[0].Groups[1] + "' " +
                        //    matches[0].Groups[2] + " '" + matches[0].Groups[3] + "'");
                        string label   = matches[0].Groups[1].Value;
                        bool   isConst = (matches[0].Groups[2].Value[0] == '=');
                        string badParseMsg;
                        int    value, numBase;
                        bool   parseOk;
                        if (isConst)
                        {
                            // Allow various numeric options, and preserve the value.
                            parseOk = Asm65.Number.TryParseInt(matches[0].Groups[3].Value,
                                                               out value, out numBase);
                            badParseMsg =
                                CommonUtil.Properties.Resources.ERR_INVALID_NUMERIC_CONSTANT;
                        }
                        else
                        {
                            // Allow things like "05/1000".  Always hex.
                            numBase = 16;
                            parseOk = Asm65.Address.ParseAddress(matches[0].Groups[3].Value,
                                                                 (1 << 24) - 1, out value);
                            badParseMsg = CommonUtil.Properties.Resources.ERR_INVALID_ADDRESS;
                        }
                        if (!parseOk)
                        {
                            report.Add(lineNum, FileLoadItem.NO_COLUMN, FileLoadItem.Type.Warning,
                                       badParseMsg);
                        }
                        else
                        {
                            string comment = matches[0].Groups[4].Value;
                            if (comment.Length > 0)
                            {
                                // remove ';'
                                comment = comment.Substring(1);
                            }
                            FormatDescriptor.SubType subType =
                                FormatDescriptor.GetSubTypeForBase(numBase);
                            DefSymbol symDef = new DefSymbol(label, value, Symbol.Source.Platform,
                                                             isConst ? Symbol.Type.Constant : Symbol.Type.ExternalAddr,
                                                             subType, comment, tag);
                            if (mSymbols.ContainsKey(label))
                            {
                                // This is very easy to do -- just define the same symbol twice
                                // in the same file.  We don't really need to do anything about
                                // it though.
                                Debug.WriteLine("NOTE: stomping previous definition of " + label);
                            }
                            mSymbols[label] = symDef;
                        }
                    }
                    else
                    {
                        report.Add(lineNum, FileLoadItem.NO_COLUMN, FileLoadItem.Type.Warning,
                                   CommonUtil.Properties.Resources.ERR_SYNTAX);
                    }
                }
            }

            return(!report.HasErrors);
        }
Exemplo n.º 20
0
 public SerDefSymbol(DefSymbol defSym) : base(defSym)
 {
     DataDescriptor = new SerFormatDescriptor(defSym.DataDescriptor);
     Comment        = defSym.Comment;
 }
Exemplo n.º 21
0
        /// <summary>
        /// Loads platform symbols.
        /// </summary>
        /// <param name="fileIdent">External file identifier of symbol file.</param>
        /// <param name="projectDir">Full path to project directory.</param>
        /// <param name="loadOrdinal">Platform file load order.</param>
        /// <param name="report">Report of warnings and errors.</param>
        /// <returns>True on success (no errors), false on failure.</returns>
        public bool LoadFromFile(string fileIdent, string projectDir, int loadOrdinal,
                                 out FileLoadReport report)
        {
            report = new FileLoadReport(fileIdent);

            ExternalFile ef = ExternalFile.CreateFromIdent(fileIdent);

            if (ef == null)
            {
                report.Add(FileLoadItem.Type.Error,
                           CommonUtil.Properties.Resources.ERR_FILE_NOT_FOUND + ": " + fileIdent);
                return(false);
            }
            string pathName = ef.GetPathName(projectDir);

            if (pathName == null)
            {
                report.Add(FileLoadItem.Type.Error,
                           Res.Strings.ERR_BAD_IDENT + ": " + fileIdent);
                return(false);
            }

            // These files shouldn't be enormous.  Just read the entire thing into a string array.
            string[] lines;
            try {
                lines = File.ReadAllLines(pathName);
            } catch (IOException ioe) {
                Debug.WriteLine("Platform symbol load failed: " + ioe);
                report.Add(FileLoadItem.Type.Error,
                           CommonUtil.Properties.Resources.ERR_FILE_NOT_FOUND + ": " + pathName);
                return(false);
            }

            string tag = string.Empty;

            DefSymbol.MultiAddressMask multiMask = null;

            int lineNum = 0;

            foreach (string line in lines)
            {
                lineNum++;      // first line is line 1, says Vim and VisualStudio
                if (string.IsNullOrEmpty(line) || line[0] == ';')
                {
                    // ignore
                }
                else if (line[0] == '*')
                {
                    if (line.StartsWith(TAG_CMD))
                    {
                        tag = ParseTag(line);
                    }
                    else if (line.StartsWith(MULTI_MASK_CMD))
                    {
                        if (!ParseMask(line, out multiMask, out string badMaskMsg))
                        {
                            report.Add(lineNum, FileLoadItem.NO_COLUMN, FileLoadItem.Type.Warning,
                                       badMaskMsg);
                        }
                        //Debug.WriteLine("Mask is now " + mask.ToString("x6"));
                    }
                    else
                    {
                        // Do something clever with *SYNOPSIS?
                        Debug.WriteLine("Ignoring CMD: " + line);
                    }
                }
                else
                {
                    MatchCollection matches = sNameValueRegex.Matches(line);
                    if (matches.Count == 1)
                    {
                        string label      = matches[0].Groups[GROUP_NAME].Value;
                        char   typeAndDir = matches[0].Groups[GROUP_TYPE].Value[0];
                        bool   isConst    = (typeAndDir == '=');
                        DefSymbol.DirectionFlags direction = DefSymbol.DirectionFlags.ReadWrite;
                        if (typeAndDir == '<')
                        {
                            direction = DefSymbol.DirectionFlags.Read;
                        }
                        else if (typeAndDir == '>')
                        {
                            direction = DefSymbol.DirectionFlags.Write;
                        }

                        string badParseMsg;
                        int    value, numBase;
                        bool   parseOk;
                        string valueStr = matches[0].Groups[GROUP_VALUE].Value;
                        if (isConst)
                        {
                            // Allow various numeric options, and preserve the value.  We
                            // don't limit the value range.
                            parseOk     = Asm65.Number.TryParseInt(valueStr, out value, out numBase);
                            badParseMsg =
                                CommonUtil.Properties.Resources.ERR_INVALID_NUMERIC_CONSTANT;
                        }
                        else if (valueStr.ToUpperInvariant().Equals(ERASE_VALUE_STR))
                        {
                            parseOk     = true;
                            value       = ERASE_VALUE;
                            numBase     = 10;
                            badParseMsg = CommonUtil.Properties.Resources.ERR_INVALID_ADDRESS;
                        }
                        else
                        {
                            // Allow things like "05/1000".  Always hex.
                            numBase = 16;
                            parseOk = Asm65.Address.ParseAddress(valueStr, (1 << 24) - 1,
                                                                 out value);
                            // limit to positive 24-bit values
                            parseOk    &= (value >= 0 && value < 0x01000000);
                            badParseMsg = CommonUtil.Properties.Resources.ERR_INVALID_ADDRESS;
                        }

                        int    width    = -1;
                        string widthStr = matches[0].Groups[GROUP_WIDTH].Value;
                        if (parseOk && !string.IsNullOrEmpty(widthStr))
                        {
                            parseOk = Asm65.Number.TryParseInt(widthStr, out width,
                                                               out int ignoredBase);
                            if (parseOk)
                            {
                                if (width < DefSymbol.MIN_WIDTH || width > DefSymbol.MAX_WIDTH)
                                {
                                    parseOk     = false;
                                    badParseMsg = Res.Strings.ERR_INVALID_WIDTH;
                                }
                            }
                            else
                            {
                                badParseMsg =
                                    CommonUtil.Properties.Resources.ERR_INVALID_NUMERIC_CONSTANT;
                            }
                        }

                        if (parseOk && multiMask != null && !isConst)
                        {
                            // We need to ensure that all possible values fit within the mask.
                            // We don't test AddressValue here, because it's okay for the
                            // canonical value to be outside the masked range.
                            int testWidth = (width > 0) ? width : 1;
                            for (int testValue = value; testValue < value + testWidth; testValue++)
                            {
                                if ((testValue & multiMask.CompareMask) != multiMask.CompareValue)
                                {
                                    parseOk     = false;
                                    badParseMsg = Res.Strings.ERR_VALUE_INCOMPATIBLE_WITH_MASK;
                                    Debug.WriteLine("Mask FAIL: value=" + value.ToString("x6") +
                                                    " width=" + width +
                                                    " testValue=" + testValue.ToString("x6") +
                                                    " mask=" + multiMask);
                                    break;
                                }
                            }
                        }

                        if (!parseOk)
                        {
                            report.Add(lineNum, FileLoadItem.NO_COLUMN, FileLoadItem.Type.Warning,
                                       badParseMsg);
                        }
                        else
                        {
                            string comment = matches[0].Groups[GROUP_COMMENT].Value;
                            if (comment.Length > 0)
                            {
                                // remove ';'
                                comment = comment.Substring(1);
                            }
                            FormatDescriptor.SubType subType =
                                FormatDescriptor.GetSubTypeForBase(numBase);
                            DefSymbol symDef = new DefSymbol(label, value, Symbol.Source.Platform,
                                                             isConst ? Symbol.Type.Constant : Symbol.Type.ExternalAddr,
                                                             subType, width, width > 0, comment, direction, multiMask,
                                                             tag, loadOrdinal, fileIdent);
                            if (mSymbols.ContainsKey(label))
                            {
                                // This is very easy to do -- just define the same symbol twice
                                // in the same file.  We don't really need to do anything about
                                // it though.
                                Debug.WriteLine("NOTE: stomping previous definition of " + label);
                            }
                            mSymbols[label] = symDef;
                        }
                    }
                    else
                    {
                        report.Add(lineNum, FileLoadItem.NO_COLUMN, FileLoadItem.Type.Warning,
                                   CommonUtil.Properties.Resources.ERR_SYNTAX);
                    }
                }
            }

            return(!report.HasErrors);
        }
Exemplo n.º 22
0
        private static Symbol HighestPriority(Symbol sym1, Symbol sym2)
        {
            // First determinant is symbol source.  User labels have highest priority, then
            // project symbols, then platform symbols, then auto labels.
            if ((int)sym1.SymbolSource < (int)sym2.SymbolSource)
            {
                return(sym1);
            }
            else if ((int)sym1.SymbolSource > (int)sym2.SymbolSource)
            {
                return(sym2);
            }

            // Same source.  Are they platform symbols?
            if (sym1.SymbolSource == Symbol.Source.Platform)
            {
                // Sort by file load order.  Symbols from files loaded later, which will have
                // a higher ordinal, have priority.
                int lo1 = ((DefSymbol)sym1).LoadOrdinal;
                int lo2 = ((DefSymbol)sym2).LoadOrdinal;
                if (lo1 > lo2)
                {
                    return(sym1);
                }
                else if (lo1 < lo2)
                {
                    return(sym2);
                }
            }

            // Same source, so this is e.g. two project symbol definitions that overlap.  We
            // handle this by selecting whichever one was defined closer to the target address,
            // i.e. whichever one has the higher value.
            // TODO(someday): this mishandles bank wrap... do we care?
            if (sym1.Value > sym2.Value)
            {
                return(sym1);
            }
            else if (sym1.Value < sym2.Value)
            {
                return(sym2);
            }

            // Check widths.  Prefer the narrower definition.
            if (sym1 is DefSymbol && sym2 is DefSymbol)
            {
                DefSymbol dsym1 = (DefSymbol)sym1;
                DefSymbol dsym2 = (DefSymbol)sym2;
                if (DefSymbol.IsWider(dsym1, dsym2))
                {
                    return(dsym2);
                }
                else if (DefSymbol.IsWider(dsym2, dsym1))
                {
                    return(dsym1);
                }
            }

            // In the absence of anything better, we select them alphabetically.  (If they have
            // the same name, value, and source, there's not much to distinguish them anyway.)
            if (Asm65.Label.LABEL_COMPARER.Compare(sym1.Label, sym2.Label) < 0)
            {
                return(sym1);
            }
            else
            {
                return(sym2);
            }
        }
Exemplo n.º 23
0
        /// <summary>
        /// Updates internal state to reflect the state of the world at the specified offset.
        /// </summary>
        /// <remarks>
        /// When the offset is greater than or equal to its value on a previous call, we can
        /// do an incremental update.  If the offset moves backward, we have to reset and walk
        /// forward again.
        /// </remarks>
        /// <param name="targetOffset">Target offset.</param>
        private void AdvanceToOffset(int targetOffset)
        {
            if (mNextLvtIndex < 0)
            {
                return;
            }
            if (targetOffset < mRecentOffset)
            {
                // We went backwards.
                Reset();
            }
            while (mNextLvtOffset <= targetOffset)
            {
                if (!mProject.GetAnattrib(mNextLvtOffset).IsStart)
                {
                    // Hidden table, ignore it.
                    Debug.WriteLine("Ignoring LvTable at +" + mNextLvtOffset.ToString("x6"));
                }
                else
                {
                    // Process this table.
                    LocalVariableTable lvt = mLvTables.Values[mNextLvtIndex];
                    if (lvt.ClearPrevious)
                    {
                        mCurrentTable.Clear();
                    }

                    // Create a list for GetVariablesDefinedAtOffset
                    mRecentSymbols = new List <DefSymbol>();
                    mRecentOffset  = mNextLvtOffset;

                    // Merge the new entries into the work table.  This automatically
                    // discards entries that clash by name or value.
                    for (int i = 0; i < lvt.Count; i++)
                    {
                        DefSymbol defSym = lvt[i];

                        // Look for non-variable symbols with the same label.  Ordinarily the
                        // editor prevents this from happening, but there are ways to trick
                        // the system (e.g. add a symbol while the LvTable is hidden).  We
                        // deal with it here.
                        if (mSymbolTable.TryGetNonVariableValue(defSym.Label, out Symbol unused))
                        {
                            Debug.WriteLine("Detected duplicate non-var label " + defSym.Label +
                                            " at +" + mNextLvtOffset.ToString("x6"));
                            string newLabel = DeDupLabel(defSym.Label);
                            mDupRemap[defSym.Label] = newLabel;
                            defSym = new DefSymbol(defSym, newLabel);
                        }

                        if (mDoUniquify)
                        {
                            if (mUniqueLabels.TryGetValue(defSym.Label, out UniqueLabel ulab))
                            {
                                // We've seen this label before; generate a unique version by
                                // increasing the appended number.
                                ulab.MakeUnique(mSymbolTable);
                                defSym = new DefSymbol(defSym, ulab.Label);
                            }
                            else
                            {
                                // Haven't seen this before.  Add it to the unique-labels table.
                                mUniqueLabels.Add(defSym.Label, new UniqueLabel(defSym.Label));
                            }
                        }
                        mCurrentTable.AddOrReplace(defSym);

                        mRecentSymbols.Add(defSym);
                    }

                    //mCurrentTable.DebugDump(mNextLvtOffset);
                }

                // Update state to look for next table.
                mNextLvtIndex++;
                if (mNextLvtIndex < mLvTables.Keys.Count)
                {
                    mNextLvtOffset = mLvTables.Keys[mNextLvtIndex];
                }
                else
                {
                    mNextLvtOffset = mProject.FileDataLength;   // never reached
                }
            }
        }
Exemplo n.º 24
0
        /// <summary>
        /// Format a numeric operand value according to the specified sub-format.
        /// </summary>
        /// <param name="formatter">Text formatter.</param>
        /// <param name="symbolTable">Full table of project symbols.</param>
        /// <param name="lvLookup">Local variable lookup object.  May be null if not
        ///   formatting an instruction.</param>
        /// <param name="labelMap">Symbol label remap, for local label conversion.  May be
        ///   null.</param>
        /// <param name="dfd">Operand format descriptor.</param>
        /// <param name="offset">Offset of start of instruction or data pseudo-op, for
        ///   variable name lookup.  Okay to pass -1 when not formatting an instruction.</param>
        /// <param name="operandValue">Operand's value.  For most things this comes directly
        ///   out of the code, for relative branches it's a 24-bit absolute address.</param>
        /// <param name="operandLen">Length of operand, in bytes.  For an instruction, this
        ///   does not include the opcode byte.  For a relative branch, this will be 2.</param>
        /// <param name="flags">Special handling.</param>
        public static string FormatNumericOperand(Formatter formatter, SymbolTable symbolTable,
                                                  LocalVariableLookup lvLookup, Dictionary <string, string> labelMap,
                                                  FormatDescriptor dfd, int offset, int operandValue, int operandLen,
                                                  FormatNumericOpFlags flags)
        {
            Debug.Assert(operandLen > 0);
            int hexMinLen = operandLen * 2;

            switch (dfd.FormatSubType)
            {
            case FormatDescriptor.SubType.None:
            case FormatDescriptor.SubType.Hex:
            case FormatDescriptor.SubType.Address:
                return(formatter.FormatHexValue(operandValue, hexMinLen));

            case FormatDescriptor.SubType.Decimal:
                return(formatter.FormatDecimalValue(operandValue));

            case FormatDescriptor.SubType.Binary:
                return(formatter.FormatBinaryValue(operandValue, hexMinLen * 4));

            case FormatDescriptor.SubType.Ascii:
            case FormatDescriptor.SubType.HighAscii:
            case FormatDescriptor.SubType.C64Petscii:
            case FormatDescriptor.SubType.C64Screen:
                CharEncoding.Encoding enc = SubTypeToEnc(dfd.FormatSubType);
                return(formatter.FormatCharacterValue(operandValue, enc));

            case FormatDescriptor.SubType.Symbol:
                if (lvLookup != null && dfd.SymbolRef.IsVariable)
                {
                    Debug.Assert(operandLen == 1);          // only doing 8-bit stuff
                    DefSymbol defSym = lvLookup.GetSymbol(offset, dfd.SymbolRef);
                    if (defSym != null)
                    {
                        StringBuilder sb = new StringBuilder();
                        FormatNumericSymbolCommon(formatter, defSym, null,
                                                  dfd, operandValue, operandLen, flags, sb);
                        return(sb.ToString());
                    }
                    else
                    {
                        Debug.WriteLine("Local variable format failed");
                        Debug.Assert(false);
                        return(formatter.FormatHexValue(operandValue, hexMinLen));
                    }
                }
                else if (symbolTable.TryGetNonVariableValue(dfd.SymbolRef.Label,
                                                            out Symbol sym))
                {
                    StringBuilder sb = new StringBuilder();

                    switch (formatter.ExpressionMode)
                    {
                    case Formatter.FormatConfig.ExpressionMode.Common:
                        FormatNumericSymbolCommon(formatter, sym, labelMap,
                                                  dfd, operandValue, operandLen, flags, sb);
                        break;

                    case Formatter.FormatConfig.ExpressionMode.Cc65:
                        FormatNumericSymbolCc65(formatter, sym, labelMap,
                                                dfd, operandValue, operandLen, flags, sb);
                        break;

                    case Formatter.FormatConfig.ExpressionMode.Merlin:
                        FormatNumericSymbolMerlin(formatter, sym, labelMap,
                                                  dfd, operandValue, operandLen, flags, sb);
                        break;

                    default:
                        Debug.Assert(false, "Unknown expression mode " +
                                     formatter.ExpressionMode);
                        return("???");
                    }

                    return(sb.ToString());
                }
                else
                {
                    return(formatter.FormatHexValue(operandValue, hexMinLen));
                }

            default:
                // should not see REMOVE or ASCII_GENERIC here
                Debug.Assert(false);
                return("???");
            }
        }