mirror of
https://github.com/danbulant/Cosmos
synced 2026-05-19 20:39:01 +00:00
205 lines
6.7 KiB
C#
205 lines
6.7 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using System.Threading;
|
|
|
|
namespace Cosmos.Compiler.Assembler
|
|
{
|
|
public class ElementReference
|
|
{
|
|
private static Dictionary<string, ElementReference> mLookup = new Dictionary<string, ElementReference>( StringComparer.InvariantCultureIgnoreCase );
|
|
public static ElementReference New( string aName, int aOffset )
|
|
{
|
|
ElementReference xResult;
|
|
if( aName.StartsWith( "." ) )
|
|
{
|
|
aName = Label.LastFullLabel + aName;
|
|
}
|
|
string xId = String.Intern( aName + "@@" + aOffset );
|
|
if( mLookup.TryGetValue( xId, out xResult ) )
|
|
{
|
|
return xResult;
|
|
}
|
|
if( aOffset == 0 )
|
|
{
|
|
xResult = new ElementReference( aName );
|
|
}
|
|
else
|
|
{
|
|
xResult = new ElementReference( aName, aOffset );
|
|
}
|
|
mLookup.Add( xId, xResult );
|
|
return xResult;
|
|
}
|
|
|
|
public static ElementReference New( string aName )
|
|
{
|
|
return New( aName, 0 );
|
|
}
|
|
|
|
private ElementReference( string aName, int aOffset )
|
|
: this( aName )
|
|
{
|
|
Offset = aOffset;
|
|
}
|
|
|
|
private ElementReference( string aName )
|
|
{
|
|
if( String.IsNullOrEmpty( aName ) )
|
|
{
|
|
throw new ArgumentNullException( "aName" );
|
|
}
|
|
if( aName == "00h" )
|
|
{
|
|
Console.Write( "" );
|
|
}
|
|
if( aName.StartsWith( "." ) )
|
|
{
|
|
Name = Label.LastFullLabel + aName;
|
|
}
|
|
else
|
|
{
|
|
Name = aName;
|
|
}
|
|
}
|
|
|
|
private ulong? mActualAddress;
|
|
|
|
private static ReaderWriterLockSlim mCacheLocker = new ReaderWriterLockSlim( LockRecursionPolicy.NoRecursion );
|
|
private static Dictionary<string, BaseAssemblerElement> mCache;// = new SortedList<string, BaseAssemblerElement>(StringComparer.InvariantCultureIgnoreCase);
|
|
private static int? mThreadId = null;
|
|
|
|
private static BaseAssemblerElement DoResolve( Assembler aAssembler, string aName )
|
|
{
|
|
if( !mThreadId.HasValue )
|
|
{
|
|
mThreadId = Thread.CurrentThread.ManagedThreadId;
|
|
}
|
|
else
|
|
{
|
|
if( mThreadId.Value != Thread.CurrentThread.ManagedThreadId )
|
|
{
|
|
throw new Exception( "Called from multiple threads" );
|
|
}
|
|
}
|
|
mCacheLocker.EnterReadLock();
|
|
try
|
|
{
|
|
if( mCache != null )
|
|
{
|
|
BaseAssemblerElement xTempResult;
|
|
if( mCache.TryGetValue( aName, out xTempResult ) )
|
|
{
|
|
return xTempResult;
|
|
}
|
|
}
|
|
}
|
|
finally
|
|
{
|
|
mCacheLocker.ExitReadLock();
|
|
}
|
|
mCacheLocker.EnterWriteLock();
|
|
try
|
|
{
|
|
if( mCache == null )
|
|
{
|
|
mCache = new Dictionary<string, BaseAssemblerElement>( StringComparer.InvariantCultureIgnoreCase );
|
|
int xMax = aAssembler.AllAssemblerElementCount;
|
|
for( int i = 0; i < xMax; i++ )
|
|
{
|
|
var xInstruction = aAssembler.GetAssemblerElement( i );
|
|
var xLabel = xInstruction as Label;
|
|
if( xLabel != null )
|
|
{
|
|
mCache.Add( xLabel.QualifiedName, xLabel );
|
|
}
|
|
var xDataMember = xInstruction as DataMember;
|
|
if( xDataMember != null )
|
|
{
|
|
if( mCache.ContainsKey( xDataMember.Name ) )
|
|
{
|
|
Console.Write( "" );
|
|
}
|
|
mCache.Add( xDataMember.Name, xDataMember );
|
|
}
|
|
}
|
|
}
|
|
BaseAssemblerElement xTempResult;
|
|
if( mCache.TryGetValue( aName, out xTempResult ) )
|
|
{
|
|
return xTempResult;
|
|
}
|
|
throw new Exception( "Cannot resolve ElementReference to '" + aName + "'!" );
|
|
//foreach(var xInstruction in aAssembler.Instructions ) {
|
|
// var xLabel = xInstruction as Label;
|
|
// if(xLabel!=null) {
|
|
// if(aName.Equals(xLabel.Name, StringComparison.InvariantCultureIgnoreCase)) {
|
|
// xTempResult = xLabel;
|
|
// break;
|
|
// }
|
|
// }
|
|
//}
|
|
//if (xTempResult == null) {
|
|
// foreach (var xDataMember in aAssembler.DataMembers) {
|
|
// if (aName.Equals(xDataMember.Name, StringComparison.InvariantCultureIgnoreCase)) {
|
|
// xTempResult = xDataMember;
|
|
// break;
|
|
// }
|
|
// }
|
|
//}
|
|
}
|
|
finally
|
|
{
|
|
mCacheLocker.ExitWriteLock();
|
|
}
|
|
}
|
|
|
|
public bool Resolve( Assembler aAssembler, out ulong aAddress )
|
|
{
|
|
//
|
|
if( mActualAddress != null )
|
|
{
|
|
aAddress = mActualAddress.Value;
|
|
return true;
|
|
}
|
|
var xElement = DoResolve( aAssembler, Name );
|
|
if( xElement != null )
|
|
{
|
|
if( xElement.ActualAddress.HasValue )
|
|
{
|
|
mActualAddress = ( ulong )( ( long )xElement.ActualAddress.Value + Offset );
|
|
aAddress = mActualAddress.Value;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
aAddress = 0;
|
|
return false;
|
|
}
|
|
|
|
public int Offset
|
|
{
|
|
get;
|
|
set;
|
|
}
|
|
|
|
public string Name
|
|
{
|
|
get;
|
|
set;
|
|
}
|
|
|
|
public override string ToString()
|
|
{
|
|
if( Offset != 0 )
|
|
{
|
|
return Name + " + " + Offset;
|
|
}
|
|
else
|
|
{
|
|
return Name;
|
|
}
|
|
}
|
|
}
|
|
}
|