private void PreProcess(System.IO.Stream stream) { System.IO.BinaryReader reader = new System.IO.BinaryReader(stream); int address = 0; if (reader.PeekChar() == 65279) // UTF-8 identify char { reader.ReadChar(); } List <string> labelNames = PreProcessLabels(stream); reader.BaseStream.Seek(0, System.IO.SeekOrigin.Begin); while (reader.BaseStream.Length != reader.BaseStream.Position) { #region Init, Process comments, labels, reserve if (reader.PeekChar() == 65279) // UTF-8 identify char { reader.ReadChar(); } string instruction = ""; SkipSpaces(stream); if (reader.BaseStream.Length == reader.BaseStream.Position) { break; } if (char.IsLetter((char)reader.PeekChar()) || (char)reader.PeekChar() == '_') { while (char.IsLetterOrDigit((char)reader.PeekChar()) || (char)reader.PeekChar() == ':' || (char)reader.PeekChar() == '_') { instruction += reader.ReadChar(); } } if (skipComments(reader)) { continue; } if (instruction.EndsWith(":")) { string label = instruction.Substring(0, instruction.Length - 1); if (!instructions.ContainsKey(label) && !constants.ContainsKey(label) && !registers.ContainsKey(label)) { labels.Add(label, address); } else { throw new Exception("This word is reserved!"); } continue; } #region Reserve if (instruction.ToLower() == "reserve") { SkipSpaces(stream); int size; if (!readIntValue(stream, reader, out size)) { throw new Exception("Expected size!"); } SkipSpaces(stream); if ((char)reader.PeekChar() == ',') { reader.ReadChar(); } else { throw new Exception("Expected ','!"); } SkipSpaces(stream); int mult = 0; if (!readIntValue(stream, reader, out mult)) { throw new Exception("Expected multiplier!"); } address += size * mult; continue; } #endregion #region ConstToMemory if (instruction.ToLower() == "memory") { int size; do { size = 0; if ((char)reader.PeekChar() == ',') { reader.ReadChar(); } SkipSpaces(stream); if ((char)reader.PeekChar() == '[') { reader.ReadChar(); readIntValue(stream, reader, out size); if ((char)reader.PeekChar() == ']') { reader.ReadChar(); } else { throw new Exception("Expected ']'"); } } SkipSpaces(stream); if (char.IsLetter((char)reader.PeekChar()) || (char)reader.PeekChar() == '_') { string reg = readIdentifier(stream, reader); if (constants.ContainsKey(reg)) { address += 4; } else if (labels.ContainsKey(reg)) { address += 4; } else { throw new Exception("Identifier not found!"); } } if (char.IsDigit((char)reader.PeekChar())) { int val = readIntLiteral(stream, reader); if (((val < byte.MaxValue && val > sbyte.MinValue) && size == 0) || size == 1) { address += 1; } else if (((val < ushort.MaxValue && val > short.MinValue) && size == 0) || size == 2) { address += 2; } else if (((val < int.MaxValue && val > int.MinValue) && size == 0) || size == 4) { address += 4; } else { throw new Exception("Too big number!"); } } if ((char)reader.PeekChar() == '"') { string lit = readStringLiteral(stream, reader); byte[] bytes = Encoding.ASCII.GetBytes(lit); address += bytes.Length; } if ((char)reader.PeekChar() == '\'') { char lit = readCharLiteral(stream, reader); byte[] bytes = Encoding.ASCII.GetBytes("" + lit); address += bytes.Length; } SkipSpaces(stream); }while ((char)reader.PeekChar() == ','); continue; } #endregion #endregion #region Read parameters AssemblerOpcodeSet opcodes = instructions[instruction.ToLower()]; // get opcode from instruction List <int> args = new List <int>(); List <AssemblerParameters> _params = new List <AssemblerParameters>(); int parnum = 4; if (opcodes.Count == 1) { parnum = instructionSetProvider.InstructionSet[opcodes.Opcodes[0]].ParametersCount; } for (int i = 0; i < parnum; i++) { SkipSpaces(stream); bool pointer = false; if ((char)reader.PeekChar() == '[') { pointer = true; reader.ReadChar(); } if (char.IsLetter((char)reader.PeekChar()) || (char)reader.PeekChar() == '_') { // parameter is register/const string reg = readIdentifier(stream, reader); PointerType?pointerType = pointer ? pointerType = PointerType.Bit8 : null; if (!pointer && reg.ToLower() == "byte" || reg.ToLower() == "word" || reg.ToLower() == "dword" || reg.ToLower() == "addr" || reg.ToLower() == "qword") { SkipSpaces(stream); if ((char)reader.PeekChar() == '[') { pointer = true; reader.ReadChar(); } if (pointer) { reg = readIdentifier(stream, reader); } } if (constants.ContainsKey(reg)) { args.Add(constants[reg]); _params.Add(pointer ? AssemblerParameters.Pointer : AssemblerParameters.Value); } else if (labelNames.Contains(reg)) { args.Add(int.MaxValue); _params.Add(pointer ? AssemblerParameters.Pointer : AssemblerParameters.Address); } else if (registers.ContainsKey(reg)) { args.Add(registers[reg.ToLower()].Item1); _params.Add(pointer ? AssemblerParameters.PointerInRegister : AssemblerParameters.Register); } else { throw new Exception("Undefined identifier: " + reg); } } else if (char.IsDigit((char)reader.PeekChar()) || (char)reader.PeekChar() == '-') { // parameter is value/number args.Add(readIntLiteral(stream, reader)); _params.Add(pointer ? AssemblerParameters.Pointer : AssemblerParameters.Value); } if (pointer) { if ((char)reader.PeekChar() == ']') { reader.ReadChar(); } else { throw new Exception("Expected ']'!"); } } SkipSpaces(stream); if ((char)reader.PeekChar() == ',') { reader.ReadChar(); } else { break; } } #endregion #region Memory usage calculating byte opcode = opcodes.Find(_params.ToArray()); AssemblerInstruction asm = InstructionSetProvider.InstructionSet[opcode]; //byte paramstypes = 0; //writer.Write(opcode); address += 1; //writer.Write(paramstypes); address += 1; //for (int i = 0; i < args.Count; i++) //{ // if (_params[i] == AssemblerParameters.Register) // { // paramstypes |= (byte)(0x00 << (i * 2)); // } // else if ((_params[i] & AssemblerParameters.Value) != 0) // { // if ((_params[i] & AssemblerParameters.Pointer) != 0) // Address // { // paramstypes |= (byte)(0x02 << (i * 2)); // } // else // { // if (args[i] < byte.MaxValue) // paramstypes |= (byte)(0x00 << (i * 2)); // else if (args[i] < short.MaxValue) // paramstypes |= (byte)(0x01 << (i * 2)); // else // paramstypes |= (byte)(0x02 << (i * 2)); // } // } // else if ((_params[i] & AssemblerParameters.Pointer) != 0) // { // if ((_params[i] & AssemblerParameters.Register) != 0) // paramstypes |= (byte)(0x01 << (i * 2)); // else // paramstypes |= (byte)(0x00 << (i * 2)); // } //} for (int i = 0; i < args.Count; i++) { if (_params[i] == AssemblerParameters.Register) { address += 1; } else if ((_params[i] & AssemblerParameters.Value) != 0) { if ((_params[i] & AssemblerParameters.Pointer) != 0) // Address { address += 4; } else { if (args[i] < byte.MaxValue && args[i] > sbyte.MinValue) { address += 1; } else if (args[i] < ushort.MaxValue && args[i] > short.MinValue) { address += 2; } else { address += 4; } } } else if ((_params[i] & AssemblerParameters.Pointer) != 0) { if ((_params[i] & AssemblerParameters.Register) != 0) { address += 1; } else { address += 4; } } } #endregion } stream.Seek(0, System.IO.SeekOrigin.Begin); }
public byte[] Compile(System.IO.Stream stream) { System.IO.BinaryReader reader = new System.IO.BinaryReader(stream); System.IO.MemoryStream buffer = new System.IO.MemoryStream(); System.IO.BinaryWriter writer = new System.IO.BinaryWriter(buffer); line = 1; int address = 0; PreProcess(stream); while (reader.BaseStream.Length != reader.BaseStream.Position) { if (reader.PeekChar() == 65279) // UTF-8 identify char { reader.ReadChar(); } string instruction = ""; SkipSpaces(stream); if (reader.BaseStream.Length == reader.BaseStream.Position) { break; } if (char.IsLetter((char)reader.PeekChar()) || (char)reader.PeekChar() == '_') { while (char.IsLetterOrDigit((char)reader.PeekChar()) || (char)reader.PeekChar() == ':' || (char)reader.PeekChar() == '_') { instruction += reader.ReadChar(); } } if (skipComments(reader)) // skip comments { continue; } if (instruction.EndsWith(":")) // check if a label { continue; } #region Reserve if (instruction.ToLower() == "reserve") { SkipSpaces(stream); int size; if (!readIntValue(stream, reader, out size)) { throw new Exception("Expected size!"); } SkipSpaces(stream); if ((char)reader.PeekChar() == ',') { reader.ReadChar(); } else { throw new Exception("Expected ','!"); } SkipSpaces(stream); int mult = 0; if (!readIntValue(stream, reader, out mult)) { throw new Exception("Expected multiplier!"); } writer.Write(new byte[size * mult], 0, size * mult); address += size * mult; continue; } #endregion #region ConstToMemory if (instruction.ToLower() == "memory") { int size = 0; do { size = 0; if ((char)reader.PeekChar() == ',') { reader.ReadChar(); } SkipSpaces(stream); if ((char)reader.PeekChar() == '[') { reader.ReadChar(); readIntValue(stream, reader, out size); if ((char)reader.PeekChar() == ']') { reader.ReadChar(); } else { throw new Exception("Expected ']'"); } } SkipSpaces(stream); if (char.IsLetter((char)reader.PeekChar()) || (char)reader.PeekChar() == '_') { string reg = readIdentifier(stream, reader); if (constants.ContainsKey(reg)) { writer.Write(constants[reg]); address += 4; } else if (labels.ContainsKey(reg)) { writer.Write(labels[reg]); address += 4; } else { throw new Exception("Identifier not found!"); } } if (char.IsDigit((char)reader.PeekChar())) { int val = readIntLiteral(stream, reader); if (((val < byte.MaxValue && val > sbyte.MinValue) && size == 0) || size == 1) { writer.Write((byte)val); address += 1; } else if (((val < ushort.MaxValue && val > short.MinValue) && size == 0) || size == 2) { writer.Write((short)val); address += 2; } else if (((val < int.MaxValue && val > int.MinValue) && size == 0) || size == 4) { writer.Write(val); address += 4; } else { throw new Exception("Too big number!"); } } if ((char)reader.PeekChar() == '"') { string lit = readStringLiteral(stream, reader); byte[] bytes = ASCIIEncoding.ASCII.GetBytes(lit); writer.Write(bytes, 0, bytes.Length); address += bytes.Length; } if ((char)reader.PeekChar() == '\'') { char lit = readCharLiteral(stream, reader); byte[] bytes = ASCIIEncoding.ASCII.GetBytes("" + lit); writer.Write(bytes, 0, bytes.Length); address += bytes.Length; } SkipSpaces(stream); }while ((char)reader.PeekChar() == ','); continue; } #endregion AssemblerOpcodeSet opcodes = instructions[instruction.ToLower()]; // get opcode from instruction List <AssemblerParameterValue> args = new List <AssemblerParameterValue>(); List <AssemblerParameters> @params = new List <AssemblerParameters>(); int parnum = 4; if (opcodes.Count == 1) { parnum = instructionSetProvider.InstructionSet[opcodes.Opcodes[0]].ParametersCount; } for (int i = 0; i < parnum; i++) { SkipSpaces(stream); bool pointer = false; if ((char)reader.PeekChar() == '[') { pointer = true; reader.ReadChar(); } if (char.IsLetter((char)reader.PeekChar()) || (char)reader.PeekChar() == '_' || (char)reader.PeekChar() == '[') { // parameter is register/const string reg = readIdentifier(stream, reader); PointerType?pointerType = pointer ? pointerType = PointerType.Bit8 : null; if (!pointer && reg.ToLower() == "byte" || reg.ToLower() == "word" || reg.ToLower() == "dword" || reg.ToLower() == "addr" || reg.ToLower() == "qword") { SkipSpaces(stream); if ((char)reader.PeekChar() == '[') { pointer = true; reader.ReadChar(); } if (pointer) { if (reg.ToLower() == "byte") { pointerType = PointerType.Bit8; } else if (reg.ToLower() == "word") { pointerType = PointerType.Bit16; } else if (reg.ToLower() == "dword" || reg.ToLower() == "addr") { pointerType = PointerType.Bit32; } else if (reg.ToLower() == "qword") { pointerType = PointerType.Bit64; } reg = readIdentifier(stream, reader); } } if (constants.ContainsKey(reg)) { args.Add(new AssemblerParameterValue(constants[reg], pointerType, null)); @params.Add(pointer ? AssemblerParameters.Pointer : AssemblerParameters.Value); } else if (labels.ContainsKey(reg)) { args.Add(new AssemblerParameterValue(labels[reg], pointerType, null)); @params.Add(pointer ? AssemblerParameters.Pointer : AssemblerParameters.Address); } else if (registers.ContainsKey(reg)) { args.Add(new AssemblerParameterValue(registers[reg.ToLower()].Item1, pointerType, registers[reg.ToLower()].Item2)); @params.Add(pointer ? AssemblerParameters.PointerInRegister : AssemblerParameters.Register); } else { throw new Exception("Undefined identifier: " + reg); } } else if (char.IsDigit((char)reader.PeekChar()) || (char)reader.PeekChar() == '-') { // parameter is value/number args.Add(readIntLiteral(stream, reader)); @params.Add(pointer ? AssemblerParameters.Pointer : AssemblerParameters.Value); } if (pointer) { if ((char)reader.PeekChar() == ']') { reader.ReadChar(); } else { throw new Exception("Expected ']'!"); } } SkipSpaces(stream); if ((char)reader.PeekChar() == ',') { reader.ReadChar(); } else { break; } } byte opcode = opcodes.Find(@params.ToArray()); AssemblerInstruction asm = instructionSetProvider.InstructionSet[opcode]; byte paramstypes = EncodeParamsTypes(args, @params); int startaddress = address; writer.Write(opcode); address += 1; writer.Write(paramstypes); address += 1; for (int i = 0; i < args.Count; i++) { if (@params[i] == AssemblerParameters.Register) { writer.Write((byte)args[i].Value); address += 1; } else if ((@params[i] & AssemblerParameters.Value) != 0) { int arg = args[i].Value; if ((@params[i] & AssemblerParameters.Pointer) != 0) // Address { address += 4; if (asm.ConvertLabelsToOffsets) { writer.Write(arg - address); } else { writer.Write(arg); } } else { if (arg < byte.MaxValue && arg > sbyte.MinValue) { writer.Write((byte)arg); address += 1; } else if (arg < ushort.MaxValue && arg > short.MinValue) { writer.Write((short)arg); address += 2; } else { writer.Write(arg); address += 4; } } } else if ((@params[i] & AssemblerParameters.Pointer) != 0) { if ((@params[i] & AssemblerParameters.Register) != 0) { writer.Write((byte)args[i].Value); address += 1; } else { writer.Write(args[i].Value); address += 4; } } } } byte[] zero = BitConverter.GetBytes(0); buffer.Write(zero, 0, zero.Length); //instructionSetProvider.Memory.Write(instructionSetProvider.ProgramMemory, buffer.ToArray()); return(buffer.ToArray()); }