2025-07-20 03:35:04 +08:00
|
|
|
|
using LibCLCC.NET.Operations;
|
2025-07-25 00:06:07 +10:00
|
|
|
|
using Microsoft.Win32.SafeHandles;
|
2025-07-20 03:35:04 +08:00
|
|
|
|
using SVM.Core;
|
2025-07-20 20:45:10 +08:00
|
|
|
|
using SVM.Core.Utils;
|
|
|
|
|
|
using System;
|
2025-07-20 03:35:04 +08:00
|
|
|
|
using System.Collections.Generic;
|
2025-07-20 20:45:10 +08:00
|
|
|
|
using System.Reflection.Emit;
|
|
|
|
|
|
using System.Text;
|
2025-07-20 03:35:04 +08:00
|
|
|
|
|
|
|
|
|
|
namespace SVM.Assembler.Core
|
|
|
|
|
|
{
|
|
|
|
|
|
public class Linker
|
|
|
|
|
|
{
|
|
|
|
|
|
public static OperationResult<IntermediateObject?> Link(List<IntermediateObject> objs)
|
|
|
|
|
|
{
|
|
|
|
|
|
OperationResult<IntermediateObject?> operationResult = new OperationResult<IntermediateObject?>(null);
|
|
|
|
|
|
IntermediateObject intermediateObject = new IntermediateObject();
|
|
|
|
|
|
foreach (var item in objs)
|
|
|
|
|
|
{
|
|
|
|
|
|
foreach (var inst in item.instructions)
|
|
|
|
|
|
{
|
|
|
|
|
|
intermediateObject.instructions.Add(inst);
|
|
|
|
|
|
}
|
|
|
|
|
|
foreach (var data in item.data)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (!intermediateObject.data.TryAdd(data.Key, data.Value))
|
|
|
|
|
|
{
|
|
|
|
|
|
intermediateObject.data[data.Key] = data.Value;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
foreach (var kv in item.consts)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (!intermediateObject.consts.TryAdd(kv.Key, kv.Value))
|
|
|
|
|
|
{
|
|
|
|
|
|
intermediateObject.consts[kv.Key] = kv.Value;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-07-27 04:15:34 +10:00
|
|
|
|
operationResult.Result = intermediateObject;
|
2025-07-20 03:35:04 +08:00
|
|
|
|
return operationResult;
|
|
|
|
|
|
}
|
2025-07-25 00:06:07 +10:00
|
|
|
|
public static bool TryParseRegister(string input, LinkingContext context, out byte registerID)
|
2025-07-24 23:09:01 +10:00
|
|
|
|
{
|
|
|
|
|
|
if (input.StartsWith("$"))
|
|
|
|
|
|
{
|
2025-07-25 00:06:07 +10:00
|
|
|
|
var regValue = input[1..];
|
|
|
|
|
|
if (context.Definition.RegisterNames.TryGetValue(regValue, out var regID))
|
|
|
|
|
|
{
|
|
|
|
|
|
registerID = regID;
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
return byte.TryParse(regValue, out registerID);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
if (context.IntermediateObject.TryGetConst(input, out var realStr))
|
|
|
|
|
|
{
|
|
|
|
|
|
return TryParseRegister(realStr, context, out registerID);
|
|
|
|
|
|
}
|
2025-07-24 23:09:01 +10:00
|
|
|
|
}
|
|
|
|
|
|
registerID = byte.MaxValue;
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
2025-07-30 01:24:02 +10:00
|
|
|
|
public static bool TryParseInt32(string input, LinkingContext context, out int value)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (int.TryParse(input, out value))
|
|
|
|
|
|
{
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
if (context.IntermediateObject.TryGetConst(input, out var realStr))
|
|
|
|
|
|
{
|
|
|
|
|
|
return TryParseInt32(realStr, context, out value);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
value = byte.MaxValue;
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
public static bool TryParseInt64(string input, LinkingContext context, out long value)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (long.TryParse(input, out value))
|
|
|
|
|
|
{
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
if (context.IntermediateObject.TryGetConst(input, out var realStr))
|
|
|
|
|
|
{
|
|
|
|
|
|
return TryParseInt64(realStr, context, out value);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
value = byte.MaxValue;
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
2025-07-25 00:06:07 +10:00
|
|
|
|
public unsafe static void WriteData(SVMInstruction* inst, SVMNativeTypes nativeType, int Pos, byte* dataStart)
|
|
|
|
|
|
{
|
|
|
|
|
|
var size = nativeType switch
|
|
|
|
|
|
{
|
|
|
|
|
|
SVMNativeTypes.Int8 => sizeof(sbyte),
|
|
|
|
|
|
SVMNativeTypes.Int16 => sizeof(short),
|
|
|
|
|
|
SVMNativeTypes.Int32 => sizeof(int),
|
|
|
|
|
|
SVMNativeTypes.Int64 => sizeof(long),
|
|
|
|
|
|
SVMNativeTypes.UInt8 => sizeof(byte),
|
|
|
|
|
|
SVMNativeTypes.UInt16 => sizeof(ushort),
|
|
|
|
|
|
SVMNativeTypes.UInt32 => sizeof(uint),
|
|
|
|
|
|
SVMNativeTypes.UInt64 => sizeof(ulong),
|
|
|
|
|
|
SVMNativeTypes.Float => sizeof(float),
|
|
|
|
|
|
SVMNativeTypes.Double => sizeof(double),
|
|
|
|
|
|
_ => 0,
|
|
|
|
|
|
};
|
2025-07-28 23:11:24 +10:00
|
|
|
|
Buffer.MemoryCopy(dataStart, ((byte*)inst) + Pos * sizeof(byte), size, size);
|
2025-07-25 00:06:07 +10:00
|
|
|
|
}
|
|
|
|
|
|
public unsafe static bool ParseAndWriteData(SVMInstruction* inst, SVMNativeTypes nativeType, int Pos, string value)
|
|
|
|
|
|
{
|
|
|
|
|
|
switch (nativeType)
|
|
|
|
|
|
{
|
|
|
|
|
|
case SVMNativeTypes.Int8:
|
|
|
|
|
|
{
|
|
|
|
|
|
if (sbyte.TryParse(value, out sbyte v))
|
|
|
|
|
|
{
|
|
|
|
|
|
WriteData(inst, nativeType, Pos, (byte*)&v);
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
|
|
case SVMNativeTypes.Int16:
|
|
|
|
|
|
{
|
|
|
|
|
|
if (short.TryParse(value, out short v))
|
|
|
|
|
|
{
|
|
|
|
|
|
WriteData(inst, nativeType, Pos, (byte*)&v);
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
|
|
case SVMNativeTypes.Int32:
|
|
|
|
|
|
{
|
|
|
|
|
|
if (int.TryParse(value, out int v))
|
|
|
|
|
|
{
|
|
|
|
|
|
WriteData(inst, nativeType, Pos, (byte*)&v);
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
|
|
case SVMNativeTypes.Int64:
|
|
|
|
|
|
{
|
|
|
|
|
|
if (long.TryParse(value, out long v))
|
|
|
|
|
|
{
|
|
|
|
|
|
WriteData(inst, nativeType, Pos, (byte*)&v);
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
|
|
case SVMNativeTypes.UInt8:
|
|
|
|
|
|
{
|
|
|
|
|
|
if (byte.TryParse(value, out byte v))
|
|
|
|
|
|
{
|
|
|
|
|
|
WriteData(inst, nativeType, Pos, (byte*)&v);
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
|
|
case SVMNativeTypes.UInt16:
|
|
|
|
|
|
{
|
|
|
|
|
|
if (ushort.TryParse(value, out ushort v))
|
|
|
|
|
|
{
|
|
|
|
|
|
WriteData(inst, nativeType, Pos, (byte*)&v);
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
|
|
case SVMNativeTypes.UInt32:
|
|
|
|
|
|
{
|
|
|
|
|
|
if (uint.TryParse(value, out uint v))
|
|
|
|
|
|
{
|
|
|
|
|
|
WriteData(inst, nativeType, Pos, (byte*)&v);
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
|
|
case SVMNativeTypes.UInt64:
|
|
|
|
|
|
{
|
|
|
|
|
|
if (ulong.TryParse(value, out ulong v))
|
|
|
|
|
|
{
|
|
|
|
|
|
WriteData(inst, nativeType, Pos, (byte*)&v);
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
|
|
case SVMNativeTypes.Float:
|
|
|
|
|
|
{
|
|
|
|
|
|
if (float.TryParse(value, out float v))
|
|
|
|
|
|
{
|
|
|
|
|
|
WriteData(inst, nativeType, Pos, (byte*)&v);
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
|
|
case SVMNativeTypes.Double:
|
|
|
|
|
|
{
|
|
|
|
|
|
if (double.TryParse(value, out double v))
|
|
|
|
|
|
{
|
|
|
|
|
|
WriteData(inst, nativeType, Pos, (byte*)&v);
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
|
|
default:
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
public unsafe static bool ProcessDefinedEnum(string enumName, string input, InstructionParameter parameter, LinkingContext context, SVMInstruction* inst)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (context.Definition.Enums.TryGetValue(enumName, out var enumDef))
|
|
|
|
|
|
{
|
|
|
|
|
|
if (enumDef.TryGetValue(input, out var enumValue))
|
|
|
|
|
|
{
|
|
|
|
|
|
return ParseAndWriteData(inst, parameter.ExpectdValue.Type, parameter.ExpectdValue.Pos, enumValue);
|
|
|
|
|
|
}
|
|
|
|
|
|
if (context.IntermediateObject.TryGetConst(input, out var constValue))
|
|
|
|
|
|
{
|
|
|
|
|
|
return ProcessDefinedEnum(enumName, constValue, parameter, context, inst);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
public unsafe static bool ProcessInternalEnum(string enumName, string input, InstructionParameter parameter, LinkingContext context, SVMInstruction* inst)
|
|
|
|
|
|
{
|
|
|
|
|
|
switch (enumName)
|
|
|
|
|
|
{
|
|
|
|
|
|
case "NativeType":
|
|
|
|
|
|
{
|
|
|
|
|
|
if (Enum.TryParse<SVMNativeTypes>(input, out var enumV))
|
|
|
|
|
|
{
|
|
|
|
|
|
WriteData(inst, parameter.ExpectdValue.Type, parameter.ExpectdValue.Pos, (byte*)&enumV);
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
|
|
case "bOp":
|
|
|
|
|
|
{
|
|
|
|
|
|
if (Enum.TryParse<BMathOp>(input, out var enumV))
|
|
|
|
|
|
{
|
|
|
|
|
|
WriteData(inst, parameter.ExpectdValue.Type, parameter.ExpectdValue.Pos, (byte*)&enumV);
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
|
|
default:
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
if (context.IntermediateObject.TryGetConst(input, out var value))
|
|
|
|
|
|
{
|
|
|
|
|
|
return ProcessInternalEnum(enumName, value, parameter, context, inst);
|
|
|
|
|
|
}
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
2025-07-30 01:24:02 +10:00
|
|
|
|
public unsafe static OperationResult<bool> translate(InstructionDefinition def, LinkingContext context, IntermediateInstruction iinstruction, SVMInstruction* instruction)
|
2025-07-21 01:47:31 +08:00
|
|
|
|
{
|
2025-07-30 01:24:02 +10:00
|
|
|
|
OperationResult<bool> result = new OperationResult<bool>(false);
|
|
|
|
|
|
//SVMInstruction instruction = new SVMInstruction();
|
2025-07-24 23:09:01 +10:00
|
|
|
|
for (int i = 0; i < iinstruction.Parameters.Count; i++)
|
|
|
|
|
|
{
|
|
|
|
|
|
var para = iinstruction.Parameters[i];
|
|
|
|
|
|
var paraDef = def.ParameterPattern[i];
|
|
|
|
|
|
string converter = paraDef.ExpectdValue.Converter;
|
2025-07-25 00:06:07 +10:00
|
|
|
|
if (para.Content == null)
|
|
|
|
|
|
{
|
|
|
|
|
|
return result;
|
|
|
|
|
|
}
|
2025-07-24 23:09:01 +10:00
|
|
|
|
if (converter.StartsWith("InternalEnum:"))
|
|
|
|
|
|
{
|
|
|
|
|
|
var enumName = converter["InternalEnum:".Length..];
|
2025-07-30 01:24:02 +10:00
|
|
|
|
ProcessInternalEnum(enumName, para.Content, paraDef, context, instruction);
|
2025-07-25 00:06:07 +10:00
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
if (converter.StartsWith("Enum:"))
|
|
|
|
|
|
{
|
|
|
|
|
|
var enumName = converter["Enum:".Length..];
|
2025-07-30 01:24:02 +10:00
|
|
|
|
ProcessInternalEnum(enumName, para.Content, paraDef, context, instruction);
|
2025-07-24 23:09:01 +10:00
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
switch (converter)
|
|
|
|
|
|
{
|
|
|
|
|
|
case "Register":
|
2025-07-25 00:06:07 +10:00
|
|
|
|
{
|
2025-07-30 01:24:02 +10:00
|
|
|
|
if (!TryParseRegister(para.Content, context, out var registerID))
|
|
|
|
|
|
{
|
|
|
|
|
|
return result;
|
|
|
|
|
|
}
|
|
|
|
|
|
WriteData(instruction, paraDef.ExpectdValue.Type, paraDef.ExpectdValue.Pos, ®isterID);
|
|
|
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
|
|
case "Integer32":
|
|
|
|
|
|
{
|
|
|
|
|
|
if (!TryParseInt32(para.Content, context, out var registerID))
|
|
|
|
|
|
{
|
|
|
|
|
|
return result;
|
|
|
|
|
|
}
|
|
|
|
|
|
WriteData(instruction, paraDef.ExpectdValue.Type, paraDef.ExpectdValue.Pos, (byte*)®isterID);
|
2025-07-25 00:06:07 +10:00
|
|
|
|
}
|
2025-07-24 23:09:01 +10:00
|
|
|
|
break;
|
|
|
|
|
|
default:
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-07-30 01:24:02 +10:00
|
|
|
|
result.Result = true;
|
2025-07-21 01:47:31 +08:00
|
|
|
|
return result;
|
|
|
|
|
|
}
|
2025-07-20 20:45:10 +08:00
|
|
|
|
public unsafe static OperationResult<ManagedSVMProgram?> Finialize(ISADefinition definition, IntermediateObject Obj)
|
2025-07-20 03:35:04 +08:00
|
|
|
|
{
|
|
|
|
|
|
OperationResult<ManagedSVMProgram?> operationResult = new OperationResult<ManagedSVMProgram?>(null);
|
2025-07-20 20:45:10 +08:00
|
|
|
|
ManagedSVMProgram program = new ManagedSVMProgram();
|
2025-07-25 00:06:07 +10:00
|
|
|
|
LinkingContext context = new LinkingContext(program, Obj, definition);
|
2025-07-20 20:45:10 +08:00
|
|
|
|
List<byte[]> Data = new List<byte[]>();
|
|
|
|
|
|
uint offset = 0;
|
|
|
|
|
|
foreach (var item in Obj.data)
|
|
|
|
|
|
{
|
|
|
|
|
|
var data = Encoding.UTF8.GetBytes(item.Value);
|
|
|
|
|
|
byte[] data2 = new byte[data.Length + sizeof(int)];
|
|
|
|
|
|
fixed (byte* ptr = data2)
|
|
|
|
|
|
{
|
|
|
|
|
|
int len = data.Length;
|
|
|
|
|
|
((IntPtr)ptr).SetData(len);
|
|
|
|
|
|
}
|
|
|
|
|
|
Buffer.BlockCopy(data, 0, data2, sizeof(int), data.Length);
|
|
|
|
|
|
context.DataOffsets.Add(item.Key, offset);
|
|
|
|
|
|
offset += (uint)data2.Length;
|
|
|
|
|
|
Data.Add(data);
|
|
|
|
|
|
}
|
|
|
|
|
|
foreach (var item in Obj.instructions)
|
|
|
|
|
|
{
|
2025-07-21 01:47:31 +08:00
|
|
|
|
if (definition.InstructionDefinitions.TryGetValue(item.inst, out var def))
|
2025-07-20 20:45:10 +08:00
|
|
|
|
{
|
2025-07-21 01:47:31 +08:00
|
|
|
|
|
2025-07-30 01:24:02 +10:00
|
|
|
|
var instruction = stackalloc SVMInstruction[def.InstructionCount];
|
|
|
|
|
|
var inst = translate(def, context, item, instruction);
|
2025-07-20 20:45:10 +08:00
|
|
|
|
if (operationResult.CheckAndInheritErrorAndWarnings(inst))
|
|
|
|
|
|
{
|
|
|
|
|
|
return operationResult;
|
|
|
|
|
|
}
|
2025-07-30 01:24:02 +10:00
|
|
|
|
if (inst.Result)
|
|
|
|
|
|
{
|
|
|
|
|
|
for (int i = 0; i < def.InstructionCount; i++)
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
|
|
program.instructions.Add(instruction[i]);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
}
|
2025-07-20 20:45:10 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
program.Datas = new byte[offset];
|
|
|
|
|
|
int offset2 = 0;
|
|
|
|
|
|
foreach (var item in Data)
|
|
|
|
|
|
{
|
|
|
|
|
|
Buffer.BlockCopy(item, 0, program.Datas, offset2, item.Length);
|
|
|
|
|
|
offset2 += item.Length;
|
|
|
|
|
|
}
|
2025-07-27 04:15:34 +10:00
|
|
|
|
operationResult.Result = program;
|
2025-07-20 03:35:04 +08:00
|
|
|
|
return operationResult;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|