mirror of
https://github.com/danbulant/Cosmos
synced 2026-05-19 20:39:01 +00:00
374 lines
14 KiB
C#
374 lines
14 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using System.Reflection;
|
|
using System.IO;
|
|
|
|
namespace Cosmos.Compiler.Assembler
|
|
{
|
|
public class DataMember : BaseAssemblerElement, IComparable<DataMember>
|
|
{
|
|
public const string IllegalIdentifierChars = "&.,+$<>{}-`\'/\\ ()[]*!=";
|
|
public static string GetStaticFieldName( FieldInfo aField )
|
|
{
|
|
return FilterStringForIncorrectChars( "static_field__" + MethodInfoLabelGenerator.GetFullName( aField.DeclaringType ) + "." + aField.Name );
|
|
}
|
|
|
|
public static string FilterStringForIncorrectChars( string aName )
|
|
{
|
|
string xTempResult = aName;
|
|
foreach( char c in IllegalIdentifierChars )
|
|
{
|
|
xTempResult = xTempResult.Replace( c, '_' );
|
|
}
|
|
return String.Intern( xTempResult );
|
|
}
|
|
|
|
public DataMember( string aName, Stream aData )
|
|
{
|
|
Name = aName;
|
|
RawDefaultValue = new byte[ aData.Length ];
|
|
aData.Read( RawDefaultValue,
|
|
0,
|
|
RawDefaultValue.Length );
|
|
}
|
|
|
|
public bool IsComment {
|
|
get;
|
|
set;
|
|
}
|
|
|
|
public byte[] RawDefaultValue
|
|
{
|
|
get;
|
|
set;
|
|
}
|
|
public uint Alignment
|
|
{
|
|
get;
|
|
set;
|
|
}
|
|
|
|
private object[] UntypedDefaultValue;
|
|
|
|
public DataMember(string aName, params object[] aDefaultValue) {
|
|
Name = aName;
|
|
UntypedDefaultValue = aDefaultValue;
|
|
}
|
|
|
|
public DataMember(string aName, string aValue) {
|
|
Name = aName;
|
|
var xBytes = ASCIIEncoding.ASCII.GetBytes(aValue);
|
|
var xBytes2 = new byte[xBytes.Length + 1];
|
|
xBytes.CopyTo(xBytes2, 0);
|
|
xBytes2[xBytes2.Length - 1] = 0;
|
|
RawDefaultValue = xBytes2;
|
|
}
|
|
|
|
public DataMember(string aName, byte[] aDefaultValue)
|
|
{
|
|
Name = aName;
|
|
RawDefaultValue = aDefaultValue;
|
|
//UntypedDefaultValue = aDefaultValue;
|
|
}
|
|
|
|
public DataMember( string aName, short[] aDefaultValue )
|
|
{
|
|
Name = aName;
|
|
RawDefaultValue = new byte[ aDefaultValue.Length * 2 ];
|
|
for( int i = 0; i < aDefaultValue.Length; i++ )
|
|
{
|
|
Array.Copy( BitConverter.GetBytes( aDefaultValue[ i ] ), 0,
|
|
RawDefaultValue, i * 2, 2 );
|
|
}
|
|
//UntypedDefaultValue = aDefaultValue;
|
|
}
|
|
|
|
public DataMember( string aName, params ushort[] aDefaultValue )
|
|
{
|
|
Name = aName;
|
|
RawDefaultValue = new byte[ aDefaultValue.Length * 2 ];
|
|
for( int i = 0; i < aDefaultValue.Length; i++ )
|
|
{
|
|
Array.Copy( BitConverter.GetBytes( aDefaultValue[ i ] ), 0,
|
|
RawDefaultValue, i * 2, 2 );
|
|
}
|
|
//UntypedDefaultValue = aDefaultValue;
|
|
}
|
|
|
|
public DataMember( string aName, params uint[] aDefaultValue )
|
|
{
|
|
Name = aName;
|
|
//RawDefaultValue = new byte[aDefaultValue.Length * 4];
|
|
//for (int i = 0; i < aDefaultValue.Length; i++) {
|
|
// Array.Copy(BitConverter.GetBytes(aDefaultValue[i]), 0,
|
|
// RawDefaultValue, i * 4, 4);
|
|
//}
|
|
UntypedDefaultValue = aDefaultValue.Cast<object>().ToArray();
|
|
}
|
|
|
|
public DataMember( string aName, params int[] aDefaultValue )
|
|
{
|
|
Name = aName;
|
|
//RawDefaultValue = new byte[aDefaultValue.Length * 4];
|
|
//for (int i = 0; i < aDefaultValue.Length; i++) {
|
|
// Array.Copy(BitConverter.GetBytes(aDefaultValue[i]), 0,
|
|
// RawDefaultValue, i * 4, 4);
|
|
//}
|
|
UntypedDefaultValue = aDefaultValue.Cast<object>().ToArray();
|
|
}
|
|
|
|
public string Name
|
|
{
|
|
get;
|
|
private set;
|
|
}
|
|
|
|
public override void WriteText( Assembler aAssembler, TextWriter aOutput )
|
|
{
|
|
if( RawDefaultValue != null )
|
|
{
|
|
if( RawDefaultValue.Length == 0 )
|
|
{
|
|
aOutput.Write( Name );
|
|
aOutput.Write( ":" );
|
|
return;
|
|
}
|
|
if( ( from item in RawDefaultValue
|
|
group item by item
|
|
into i
|
|
select i ).Count() > 1 || RawDefaultValue.Length < 250 )
|
|
{
|
|
if( IsGlobal )
|
|
{
|
|
aOutput.Write( "global " );
|
|
aOutput.WriteLine( Name );
|
|
}
|
|
aOutput.Write( Name );
|
|
aOutput.Write( " db " );
|
|
for( int i = 0; i < ( RawDefaultValue.Length - 1 ); i++ )
|
|
{
|
|
aOutput.Write( RawDefaultValue[ i ] );
|
|
aOutput.Write( ", " );
|
|
}
|
|
aOutput.Write( RawDefaultValue.Last() );
|
|
}
|
|
else
|
|
{
|
|
//aOutputWriter.WriteLine("TIMES 0x50000 db 0");
|
|
aOutput.Write( "global " );
|
|
aOutput.WriteLine( Name );
|
|
aOutput.Write( Name );
|
|
aOutput.Write( ": TIMES " );
|
|
aOutput.Write( RawDefaultValue.Length );
|
|
aOutput.Write( " db " );
|
|
aOutput.Write( RawDefaultValue[ 0 ] );
|
|
}
|
|
return;
|
|
}
|
|
if( UntypedDefaultValue != null )
|
|
{
|
|
StringBuilder xSB = new StringBuilder();
|
|
if( IsGlobal )
|
|
{
|
|
aOutput.Write( "global " );
|
|
aOutput.WriteLine( Name );
|
|
}
|
|
aOutput.Write( Name );
|
|
aOutput.Write( " dd " );
|
|
Func<object, string> xGetTextForItem = delegate( object aItem )
|
|
{
|
|
var xElementRef = aItem as ElementReference;
|
|
if( xElementRef == null )
|
|
{
|
|
return ( aItem ?? 0 ).ToString();
|
|
}
|
|
else
|
|
{
|
|
if( xElementRef.Offset == 0 )
|
|
{
|
|
return xElementRef.Name;
|
|
}
|
|
return xElementRef.Name + " + " + xElementRef.Offset;
|
|
}
|
|
};
|
|
for( int i = 0; i < ( UntypedDefaultValue.Length - 1 ); i++ )
|
|
{
|
|
aOutput.Write( xGetTextForItem( UntypedDefaultValue[ i ] ) );
|
|
aOutput.Write( ", " );
|
|
}
|
|
aOutput.Write( xGetTextForItem( UntypedDefaultValue.Last() ) );
|
|
return;
|
|
}
|
|
throw new Exception( "Situation unsupported!" );
|
|
}
|
|
|
|
public int CompareTo( DataMember other )
|
|
{
|
|
return String.Compare( Name, other.Name );
|
|
}
|
|
|
|
public bool IsGlobal
|
|
{
|
|
get;
|
|
set;
|
|
}
|
|
|
|
public override ulong? ActualAddress
|
|
{
|
|
get
|
|
{
|
|
// TODO: for now, we dont have any data alignment
|
|
return StartAddress;
|
|
}
|
|
}
|
|
|
|
public override void UpdateAddress( Assembler aAssembler, ref ulong xAddress )
|
|
{
|
|
if( Alignment > 0 )
|
|
{
|
|
if( xAddress % Alignment != 0 )
|
|
{
|
|
xAddress += Alignment - ( xAddress % Alignment );
|
|
}
|
|
}
|
|
base.UpdateAddress( aAssembler, ref xAddress );
|
|
if( RawDefaultValue != null )
|
|
{
|
|
xAddress += ( ulong )RawDefaultValue.LongLength;
|
|
}
|
|
if( UntypedDefaultValue != null )
|
|
{
|
|
// TODO: what to do with 64bit target platforms? right now we only support 32bit
|
|
xAddress += ( ulong )( UntypedDefaultValue.LongLength * 4 );
|
|
}
|
|
}
|
|
|
|
public override bool IsComplete( Assembler aAssembler )
|
|
{
|
|
if( UntypedDefaultValue != null &&
|
|
UntypedDefaultValue.LongLength > 0 )
|
|
{
|
|
foreach( var xReference in ( from item in UntypedDefaultValue
|
|
let xRef = item as ElementReference
|
|
where xRef != null
|
|
select xRef ) )
|
|
{
|
|
var xRef = aAssembler.TryResolveReference( xReference );
|
|
if( xRef == null )
|
|
{
|
|
return false;
|
|
}
|
|
else if( !xRef.IsComplete( aAssembler ) )
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
public override byte[] GetData( Assembler aAssembler )
|
|
{
|
|
if( UntypedDefaultValue != null &&
|
|
UntypedDefaultValue.LongLength > 0 )
|
|
{
|
|
var xBuff = ( byte[] )Array.CreateInstance( typeof( byte ), UntypedDefaultValue.LongLength * 4 );
|
|
for( int i = 0; i < UntypedDefaultValue.Length; i++ )
|
|
{
|
|
var xRef = UntypedDefaultValue[ i ] as ElementReference;
|
|
byte[] xTemp;
|
|
if( xRef != null )
|
|
{
|
|
var xTheRef = aAssembler.TryResolveReference( xRef );
|
|
if( xTheRef == null )
|
|
{
|
|
throw new Exception( "Reference not found!" );
|
|
}
|
|
if( !xTheRef.ActualAddress.HasValue )
|
|
{
|
|
Console.Write( "" );
|
|
}
|
|
xTemp = BitConverter.GetBytes( xTheRef.ActualAddress.Value );
|
|
}
|
|
else
|
|
{
|
|
if( UntypedDefaultValue[ i ] is int )
|
|
{
|
|
xTemp = BitConverter.GetBytes( ( int )UntypedDefaultValue[ i ] );
|
|
}
|
|
else
|
|
{
|
|
if( UntypedDefaultValue[ i ] is uint )
|
|
{
|
|
xTemp = BitConverter.GetBytes( ( uint )UntypedDefaultValue[ i ] );
|
|
}
|
|
else
|
|
{
|
|
throw new Exception( "Invalid value inside UntypedDefaultValue" );
|
|
}
|
|
}
|
|
}
|
|
Array.Copy( xTemp, 0, xBuff, i * 4, 4 );
|
|
}
|
|
return xBuff;
|
|
}
|
|
return RawDefaultValue;
|
|
}
|
|
|
|
public override void WriteData( Assembler aAssembler, Stream aOutput )
|
|
{
|
|
if( UntypedDefaultValue != null &&
|
|
UntypedDefaultValue.LongLength > 0 )
|
|
{
|
|
//var xBuff = (byte[])Array.CreateInstance(typeof(byte), UntypedDefaultValue.LongLength * 4);
|
|
for( int i = 0; i < UntypedDefaultValue.Length; i++ )
|
|
{
|
|
var xRef = UntypedDefaultValue[ i ] as ElementReference;
|
|
//byte[] xTemp;
|
|
if( xRef != null )
|
|
{
|
|
var xTheRef = aAssembler.TryResolveReference( xRef );
|
|
if( xTheRef == null )
|
|
{
|
|
throw new Exception( "Reference not found!" );
|
|
}
|
|
if( !xTheRef.ActualAddress.HasValue )
|
|
{
|
|
Console.Write( "" );
|
|
}
|
|
aOutput.Write( BitConverter.GetBytes( xTheRef.ActualAddress.Value ), 0, 4 );
|
|
//xTemp = BitConverter.GetBytes();
|
|
}
|
|
else
|
|
{
|
|
if( UntypedDefaultValue[ i ] is int )
|
|
{
|
|
aOutput.Write( BitConverter.GetBytes( ( int )UntypedDefaultValue[ i ] ), 0, 4 );
|
|
//xTemp = BitConverter.GetBytes((int)UntypedDefaultValue[i]);
|
|
}
|
|
else
|
|
{
|
|
if( UntypedDefaultValue[ i ] is uint )
|
|
{
|
|
aOutput.Write( BitConverter.GetBytes( ( uint )UntypedDefaultValue[ i ] ), 0, 4 );
|
|
|
|
//xTemp = BitConverter.GetBytes((uint)UntypedDefaultValue[i]);
|
|
}
|
|
else
|
|
{
|
|
throw new Exception( "Invalid value inside UntypedDefaultValue" );
|
|
}
|
|
}
|
|
}
|
|
//Array.Copy(xTemp, 0, xBuff, i * 4, 4);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
aOutput.Write( RawDefaultValue, 0, RawDefaultValue.Length );
|
|
}
|
|
}
|
|
}
|
|
}
|