Compare commits
No commits in common. "b1eceec1d242d76154cf3275a2295dae55bafbb3" and "c309d6158a2135d2f5378db203a3f76e14301586" have entirely different histories.
b1eceec1d2
...
c309d6158a
27 changed files with 263 additions and 2832 deletions
|
@ -1,504 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using System.Text.RegularExpressions;
|
|
||||||
|
|
||||||
namespace AssemblerVVM
|
|
||||||
{
|
|
||||||
class pair
|
|
||||||
{
|
|
||||||
public int start;
|
|
||||||
public int end;
|
|
||||||
public pair(int one, int two)
|
|
||||||
{
|
|
||||||
start = one;
|
|
||||||
end = two;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class str_header
|
|
||||||
{
|
|
||||||
public byte[] signature
|
|
||||||
{ get; set; }
|
|
||||||
public int version
|
|
||||||
{ get; set; }
|
|
||||||
public int const_count
|
|
||||||
{ get; set; }
|
|
||||||
public int size_const
|
|
||||||
{ get; set; }
|
|
||||||
|
|
||||||
public str_header()
|
|
||||||
{
|
|
||||||
signature = new byte[2];
|
|
||||||
signature[0] = 0xBA;
|
|
||||||
signature[1] = 0xBA;
|
|
||||||
version = 0100;
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte[] Serialize()
|
|
||||||
{
|
|
||||||
using (MemoryStream m = new MemoryStream())
|
|
||||||
{
|
|
||||||
using (BinaryWriter writer = new BinaryWriter(m))
|
|
||||||
{
|
|
||||||
writer.Write(signature);
|
|
||||||
writer.Write(version);
|
|
||||||
writer.Write(const_count);
|
|
||||||
writer.Write(size_const);
|
|
||||||
}
|
|
||||||
return m.ToArray();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class funcH_common
|
|
||||||
{
|
|
||||||
public ushort start_id
|
|
||||||
{ get; set; }
|
|
||||||
public int count_of_funcs
|
|
||||||
{ get; set; }
|
|
||||||
|
|
||||||
public funcH_common(ushort id, int count)
|
|
||||||
{
|
|
||||||
start_id = id;
|
|
||||||
count_of_funcs = count;
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte[] Serialize()
|
|
||||||
{
|
|
||||||
using (MemoryStream m = new MemoryStream())
|
|
||||||
{
|
|
||||||
using (BinaryWriter writer = new BinaryWriter(m))
|
|
||||||
{
|
|
||||||
writer.Write(start_id);
|
|
||||||
writer.Write(count_of_funcs);
|
|
||||||
|
|
||||||
}
|
|
||||||
return m.ToArray();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class funcH_signature
|
|
||||||
{
|
|
||||||
public int size_func
|
|
||||||
{ get; set; }
|
|
||||||
public int size_bytecode
|
|
||||||
{ get; set; }
|
|
||||||
public int size_signature
|
|
||||||
{ get; set; }
|
|
||||||
|
|
||||||
public byte[] Serialize()
|
|
||||||
{
|
|
||||||
using (MemoryStream m = new MemoryStream())
|
|
||||||
{
|
|
||||||
using (BinaryWriter writer = new BinaryWriter(m))
|
|
||||||
{
|
|
||||||
writer.Write(size_func);
|
|
||||||
writer.Write(size_bytecode);
|
|
||||||
writer.Write(size_signature);
|
|
||||||
}
|
|
||||||
return m.ToArray();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class funcH_bytecode
|
|
||||||
{
|
|
||||||
public ushort id
|
|
||||||
{ get; set; }
|
|
||||||
public int count_locals
|
|
||||||
{ get; set; }
|
|
||||||
public int count_args
|
|
||||||
{ get; set; }
|
|
||||||
|
|
||||||
public byte[] Serialize()
|
|
||||||
{
|
|
||||||
using (MemoryStream m = new MemoryStream())
|
|
||||||
{
|
|
||||||
using (BinaryWriter writer = new BinaryWriter(m))
|
|
||||||
{
|
|
||||||
writer.Write(id);
|
|
||||||
writer.Write(count_locals);
|
|
||||||
writer.Write(count_args);
|
|
||||||
}
|
|
||||||
return m.ToArray();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public funcH_bytecode()
|
|
||||||
{
|
|
||||||
count_locals = 0;
|
|
||||||
count_args = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class Program
|
|
||||||
{
|
|
||||||
static int Main(string[] args)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
if (args.Length < 1)
|
|
||||||
{
|
|
||||||
Console.WriteLine("No input files");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
Dictionary<int, string> ConstID_VALUE = new Dictionary<int, string>();
|
|
||||||
Dictionary<string, int> ConstKEY_ID = new Dictionary<string, int>();
|
|
||||||
Dictionary<string, int> CodeMARK_POS = new Dictionary<string, int>();
|
|
||||||
|
|
||||||
List<pair> FuncPos = new List<pair>(); //This array defines first and last line of every procedure
|
|
||||||
|
|
||||||
string outname = args[0].Replace(".vasm","")+".vvm";
|
|
||||||
if (args.Length > 1)
|
|
||||||
outname = args[1];
|
|
||||||
|
|
||||||
int[] pos_d = new int[2] { 0, 0 }; //This array defines first and last line of data segment
|
|
||||||
string[] source = System.IO.File.ReadAllLines(args[0]); //Array of source code
|
|
||||||
|
|
||||||
List<string> src = PositionAnalyse(source, ref pos_d, ref FuncPos, ref CodeMARK_POS);
|
|
||||||
|
|
||||||
using (var bw = new BinaryWriter(File.Open(outname, FileMode.OpenOrCreate))) //Writing into a file with bytecode
|
|
||||||
{
|
|
||||||
HeaderAnalyse(src, pos_d, bw, ref ConstID_VALUE, ref ConstKEY_ID);
|
|
||||||
funcH_common FuncCommonH = new funcH_common(CRC16_alg("main"), FuncPos.Count); //We define there that start procedure calls "main"
|
|
||||||
bw.Write(FuncCommonH.Serialize()); //We also define there number of procedures in our code
|
|
||||||
for (int i = 0; i < FuncPos.Count; i++)
|
|
||||||
{
|
|
||||||
FuncAnalyse(src, FuncPos[i], bw, ConstKEY_ID, CodeMARK_POS);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static List<string> PositionAnalyse(string[] input, ref int[] posD, ref List<pair> posC, ref Dictionary<string, int> marks)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* This function fills arrays that define positions of functions and data in source text
|
|
||||||
* Return value - is an array of source text without comments, empty strings etc
|
|
||||||
* ---
|
|
||||||
* input - is an array of source text
|
|
||||||
* posD - is an array of start and end position of data segment
|
|
||||||
* posC - is an array of start and end position of every procedure
|
|
||||||
* marks - is an array of labes
|
|
||||||
*/
|
|
||||||
List<string> src = new List<string>();
|
|
||||||
bool func_flag = false;
|
|
||||||
int pos1 = 0, pos2 = 0, numline = 0;
|
|
||||||
foreach (string s in input)
|
|
||||||
if (s != "") //Skip empty strings
|
|
||||||
{
|
|
||||||
if (func_flag == true && Regex.IsMatch(s, @"\w+:")) //Labels cannot be outside of procedure
|
|
||||||
{
|
|
||||||
marks.Add(s.Trim(' ', '\t', ':'), numline);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
src.Add(s.Trim(' ', '\t'));
|
|
||||||
|
|
||||||
if (s.Contains(".data")) //Checking data segment
|
|
||||||
posD[0] = src.Count - 1;
|
|
||||||
if (s.Contains(".endd"))
|
|
||||||
posD[1] = src.Count - 1;
|
|
||||||
|
|
||||||
if (s.Contains(".proc")) //Checking procedure segment
|
|
||||||
{
|
|
||||||
numline = 0;
|
|
||||||
pos1 = src.Count - 1;
|
|
||||||
func_flag = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (s.Contains(".endp"))
|
|
||||||
{
|
|
||||||
pos2 = src.Count - 1;
|
|
||||||
if (func_flag == true)
|
|
||||||
{
|
|
||||||
func_flag = false;
|
|
||||||
posC.Add(new pair(pos1, pos2));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
numline++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return src;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void HeaderAnalyse(List<string> src, int[] pos, BinaryWriter bw, ref Dictionary<int, string> id_v, ref Dictionary<string, int> k_id)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* This function creates bytecode header. Header contains signature, version, text constants and their size
|
|
||||||
* ---
|
|
||||||
* src - clear source text
|
|
||||||
* pos - position of data segment in source text
|
|
||||||
* bw - writer to a file
|
|
||||||
* id_v, k_id - dictionaries for text constatns
|
|
||||||
*/
|
|
||||||
str_header ConstH = new str_header(); //Object that stores all text consntants.
|
|
||||||
string pattern = "\".*\""; //Pattern to take text constants (to delete)
|
|
||||||
string pattern_adv = "\"[^\"\\\\]*(?:\\\\.[^\"\\\\]*)*\""; //Advanced patternn
|
|
||||||
int j = 1;
|
|
||||||
for (int i = pos[0] + 1; i < pos[1]; i++) //pos[0] = .data ; pos[0]+1 = first text const
|
|
||||||
{
|
|
||||||
int position = src[i].IndexOf(" ");
|
|
||||||
string key = src[i].Substring(0, position);
|
|
||||||
string value = Regex.Match(src[i], pattern_adv).ToString();
|
|
||||||
value = value.Substring(1, value.Length-2).Replace(@"\n", "\n").Replace(@"\r", "\r").Replace("\\\"","\"") + "\0";
|
|
||||||
id_v.Add(j, value); k_id.Add(key, j++); //All contstants have their numeric equivalent, so we store both.
|
|
||||||
ConstH.const_count++; ConstH.size_const += (value.Length); //Defining total size of constants
|
|
||||||
}
|
|
||||||
bw.Write(ConstH.Serialize());
|
|
||||||
for (int i = 1; i < j; i++)
|
|
||||||
{
|
|
||||||
bw.Write(Encoding.ASCII.GetBytes(id_v[i]));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void FuncAnalyse(List<string> code, pair pos, BinaryWriter bw, Dictionary<string, int> dictStr, Dictionary<string, int> dictJmp)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* This function writes an actual procedure in bytecode.
|
|
||||||
* It will decode text-name of instructio into bytecode aswell as agruments for instruction
|
|
||||||
* ---
|
|
||||||
* code - clear source code
|
|
||||||
* pos - position of procedures
|
|
||||||
* dicStr - dictionary for text constants
|
|
||||||
* dictJmp - dictionary for every jump
|
|
||||||
*/
|
|
||||||
string name = "";
|
|
||||||
MemoryStream str = new MemoryStream();
|
|
||||||
funcH_signature sign = new funcH_signature();
|
|
||||||
funcH_bytecode bc = new funcH_bytecode();
|
|
||||||
|
|
||||||
string[] current_str = code[pos.start].Split(' '); //Spliting string in case of arguments for instruction
|
|
||||||
switch (current_str.Length)
|
|
||||||
{
|
|
||||||
case 4: //2 arg instruction
|
|
||||||
bc.count_args = System.Convert.ToInt32(current_str[3]);
|
|
||||||
bc.count_locals = System.Convert.ToInt32(current_str[2]);
|
|
||||||
name = current_str[1];
|
|
||||||
break;
|
|
||||||
case 3: //1 arg intruction
|
|
||||||
bc.count_locals = System.Convert.ToInt32(current_str[2]);
|
|
||||||
name = current_str[1];
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 2: //No arg
|
|
||||||
name = current_str[1];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
bc.id = CRC16_alg(name); //Hash encode for function name
|
|
||||||
name += "\0";
|
|
||||||
sign.size_signature = name.Length;
|
|
||||||
using (BinaryWriter writer = new BinaryWriter(str))
|
|
||||||
{
|
|
||||||
int j = 1;
|
|
||||||
for (int i = pos.start + 1; i < pos.end; i++)
|
|
||||||
{
|
|
||||||
current_str = code[i].Split(' ');
|
|
||||||
opcode current_opc = (opcode)Enum.Parse(typeof(opcode), current_str[0].ToUpper());
|
|
||||||
writer.Write((byte)current_opc);
|
|
||||||
|
|
||||||
if (current_opc == opcode.DLOAD)
|
|
||||||
writer.Write(Convert.ToDouble(current_str[1]));
|
|
||||||
else if (current_opc == opcode.ILOAD)
|
|
||||||
writer.Write(Convert.ToInt64(current_str[1]));
|
|
||||||
else if (current_opc == opcode.SLOAD)
|
|
||||||
writer.Write((ushort)dictStr[current_str[1]]);
|
|
||||||
else if (current_opc == opcode.CALL)
|
|
||||||
writer.Write(CRC16_alg(current_str[1]));
|
|
||||||
else if (threebytes.Contains(current_opc))
|
|
||||||
writer.Write(ushort.Parse(current_str[1]));
|
|
||||||
else if (fivebytes.Contains(current_opc))
|
|
||||||
{
|
|
||||||
writer.Write(CRC16_alg(current_str[1]));
|
|
||||||
writer.Write(ushort.Parse(current_str[2]));
|
|
||||||
}
|
|
||||||
else if (jumps.Contains(current_opc)) //Pain in the arse
|
|
||||||
writer.Write(FindOffset(code, pos, j, ((ushort)dictJmp[current_str[1]]-j)));
|
|
||||||
j++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
byte[] bcode = str.ToArray();
|
|
||||||
sign.size_bytecode = bcode.Length;
|
|
||||||
sign.size_func = 22 + sign.size_bytecode + sign.size_signature; //Magic number 22 - size of meta-info for
|
|
||||||
|
|
||||||
bw.Write(sign.Serialize());
|
|
||||||
bw.Write(Encoding.ASCII.GetBytes(name));
|
|
||||||
bw.Write(bc.Serialize());
|
|
||||||
bw.Write(bcode);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static short FindOffset(List<string> code, pair pos, int curr_pos, int off)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* This function calculating offset of bytes to jump a label.
|
|
||||||
*/
|
|
||||||
short result = 0;
|
|
||||||
if (off > 0) //Jumping forward
|
|
||||||
{
|
|
||||||
for (int i = curr_pos + 1; i < curr_pos + off; i++)
|
|
||||||
{
|
|
||||||
result += OpCodeSize((opcode)Enum.Parse(typeof(opcode), code[pos.start+i].Split(' ')[0].ToUpper()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else //Jumping backward
|
|
||||||
{
|
|
||||||
for (int i = curr_pos; i >= curr_pos + off; i--)
|
|
||||||
{
|
|
||||||
result -= OpCodeSize((opcode)Enum.Parse(typeof(opcode), code[pos.start+i].Split(' ')[0].ToUpper()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static short OpCodeSize(opcode opc)
|
|
||||||
{
|
|
||||||
short result = 0;
|
|
||||||
if (jumps.Contains(opc) || threebytes.Contains(opc))
|
|
||||||
result += 3;
|
|
||||||
else if (fivebytes.Contains(opc))
|
|
||||||
result += 5;
|
|
||||||
else if (ninebytes.Contains(opc))
|
|
||||||
result += 9;
|
|
||||||
else result++;
|
|
||||||
return result;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public static ushort CRC16_alg(string msg)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* HashFunction on Cyclic redundacy check algorythm
|
|
||||||
*/
|
|
||||||
byte[] text = Encoding.ASCII.GetBytes(msg);
|
|
||||||
const ushort polinom = 0xa001;
|
|
||||||
ushort code = 0xffff;
|
|
||||||
|
|
||||||
for (int i = 0, size = text.Length; i < size; ++i)
|
|
||||||
{
|
|
||||||
code ^= (ushort)(text[i] << 8);
|
|
||||||
|
|
||||||
for (uint j = 0; j < 8; ++j)
|
|
||||||
{
|
|
||||||
code >>= 1;
|
|
||||||
if ((code & 0x01) != 0) code ^= polinom;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return code;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*static List<opcode> onebyte = new List<opcode>{opcode.INVALID, opcode.DLOAD0, opcode.ILOAD0, opcode.SLOAD0, opcode.DLOAD1, opcode.ILOAD1, opcode.DLOADM1,
|
|
||||||
opcode.ILOADM1, opcode.DADD, opcode.IADD, opcode.DSUB, opcode.ISUB, opcode.DMUL, opcode.IMUL, opcode.DDIV, opcode.IDIV, opcode.IMOD, opcode.DNEG,
|
|
||||||
opcode.INEG, opcode.IAOR, opcode.IAAND, opcode.IAXOR, opcode.IPRINT, opcode.DPRINT, opcode.SPRINT, opcode.I2D, opcode.D2I, opcode.S2I, opcode.SWAP,
|
|
||||||
opcode.POP, opcode.LOADDVAR0, opcode.LOADDVAR1, opcode.LOADDVAR2, opcode.LOADDVAR3, opcode.LOADIVAR0, opcode.LOADIVAR1, opcode.LOADIVAR2, opcode.LOADIVAR3,
|
|
||||||
opcode.LOADSVAR0, opcode.LOADSVAR1, opcode.LOADSVAR2, opcode.LOADSVAR3, opcode.STOREDVAR0, opcode.STOREDVAR1, opcode.STOREDVAR2, opcode.STOREDVAR3,
|
|
||||||
opcode.STOREIVAR0, opcode.STOREIVAR1, opcode.STOREIVAR2, opcode.STOREIVAR3, opcode.STORESVAR0, opcode.STORESVAR1, opcode.STORESVAR2, opcode.STORESVAR3,
|
|
||||||
opcode.ICMP, opcode.DCMP, opcode.DUMP, opcode.STOP, opcode.RETURN, opcode.BREAK};*/
|
|
||||||
|
|
||||||
static List<opcode> ninebytes = new List<opcode> { opcode.DLOAD, opcode.ILOAD };
|
|
||||||
|
|
||||||
static List<opcode> threebytes = new List<opcode> { opcode.LOADDVAR, opcode.LOADIVAR, opcode.LOADSVAR, opcode.STOREDVAR,
|
|
||||||
opcode.STOREIVAR, opcode.STORESVAR, opcode.SLOAD, opcode.CALL};
|
|
||||||
|
|
||||||
static List<opcode> fivebytes = new List<opcode> {opcode.LOADCTXDVAR, opcode.LOADCTXIVAR, opcode.LOADCTXSVAR, opcode.STORECTXDVAR,
|
|
||||||
opcode.STORECTXIVAR, opcode.STORECTXSVAR};
|
|
||||||
|
|
||||||
static List<opcode> jumps = new List<opcode> {opcode.JA, opcode.IFICMPE, opcode.IFICMPG, opcode.IFICMPGE, opcode.IFICMPL,
|
|
||||||
opcode.IFICMPLE, opcode.IFICMPNE};
|
|
||||||
}
|
|
||||||
|
|
||||||
enum opcode
|
|
||||||
{
|
|
||||||
INVALID,
|
|
||||||
DLOAD,
|
|
||||||
ILOAD,
|
|
||||||
SLOAD,
|
|
||||||
DLOAD0,
|
|
||||||
ILOAD0,
|
|
||||||
SLOAD0,
|
|
||||||
DLOAD1,
|
|
||||||
ILOAD1,
|
|
||||||
DLOADM1,
|
|
||||||
ILOADM1,
|
|
||||||
DADD,
|
|
||||||
IADD,
|
|
||||||
DSUB,
|
|
||||||
ISUB,
|
|
||||||
DMUL,
|
|
||||||
IMUL,
|
|
||||||
DDIV,
|
|
||||||
IDIV,
|
|
||||||
IMOD,
|
|
||||||
DNEG,
|
|
||||||
INEG,
|
|
||||||
IAOR,
|
|
||||||
IAAND,
|
|
||||||
IAXOR,
|
|
||||||
IPRINT,
|
|
||||||
DPRINT,
|
|
||||||
SPRINT,
|
|
||||||
I2D,
|
|
||||||
D2I,
|
|
||||||
S2I,
|
|
||||||
SWAP,
|
|
||||||
POP,
|
|
||||||
LOADDVAR0,
|
|
||||||
LOADDVAR1,
|
|
||||||
LOADDVAR2,
|
|
||||||
LOADDVAR3,
|
|
||||||
LOADIVAR0,
|
|
||||||
LOADIVAR1,
|
|
||||||
LOADIVAR2,
|
|
||||||
LOADIVAR3,
|
|
||||||
LOADSVAR0,
|
|
||||||
LOADSVAR1,
|
|
||||||
LOADSVAR2,
|
|
||||||
LOADSVAR3,
|
|
||||||
STOREDVAR0,
|
|
||||||
STOREDVAR1,
|
|
||||||
STOREDVAR2,
|
|
||||||
STOREDVAR3,
|
|
||||||
STOREIVAR0,
|
|
||||||
STOREIVAR1,
|
|
||||||
STOREIVAR2,
|
|
||||||
STOREIVAR3,
|
|
||||||
STORESVAR0,
|
|
||||||
STORESVAR1,
|
|
||||||
STORESVAR2,
|
|
||||||
STORESVAR3,
|
|
||||||
LOADDVAR,
|
|
||||||
LOADIVAR,
|
|
||||||
LOADSVAR,
|
|
||||||
STOREDVAR,
|
|
||||||
STOREIVAR,
|
|
||||||
STORESVAR,
|
|
||||||
LOADCTXDVAR,
|
|
||||||
LOADCTXIVAR,
|
|
||||||
LOADCTXSVAR,
|
|
||||||
STORECTXDVAR,
|
|
||||||
STORECTXIVAR,
|
|
||||||
STORECTXSVAR,
|
|
||||||
DCMP,
|
|
||||||
ICMP,
|
|
||||||
JA,
|
|
||||||
IFICMPNE,
|
|
||||||
IFICMPE,
|
|
||||||
IFICMPG,
|
|
||||||
IFICMPGE,
|
|
||||||
IFICMPL,
|
|
||||||
IFICMPLE,
|
|
||||||
DUMP,
|
|
||||||
STOP,
|
|
||||||
CALL,
|
|
||||||
RETURN,
|
|
||||||
BREAK
|
|
||||||
};
|
|
||||||
}
|
|
|
@ -1,61 +0,0 @@
|
||||||
VVM Assembler.
|
|
||||||
Описание.
|
|
||||||
|
|
||||||
Параметром утилите подается текстовый файл с ассемблерными инструкциями для VVM.
|
|
||||||
|
|
||||||
|
|
||||||
Код разивается на блоки:
|
|
||||||
-Один константный блок
|
|
||||||
-Переменное количество процедурных блоков с кодом.
|
|
||||||
|
|
||||||
Блоки могут идти в любом порядке, но они не должны быть вложенными или пересекающимися.
|
|
||||||
Каждая инструкция или информация о блоке должна начинаться с новой строки.
|
|
||||||
Константный блок начинается с препроцессорной инструкции .data и заканчивается .endd
|
|
||||||
Внутри константного строки располагаются так:
|
|
||||||
signature "string"
|
|
||||||
|
|
||||||
Пример:
|
|
||||||
.data
|
|
||||||
str1 "Hello World!"
|
|
||||||
str2 "Second String!"
|
|
||||||
.endd
|
|
||||||
|
|
||||||
Процедурные блоки начинаются с препроцессорной инструкции
|
|
||||||
.proc name [num_of_locals] [num_of_args]
|
|
||||||
и заканчиваются на .endp
|
|
||||||
|
|
||||||
Пример:
|
|
||||||
|
|
||||||
.proc main
|
|
||||||
DLOAD1
|
|
||||||
DPRINT
|
|
||||||
STOP
|
|
||||||
.endp
|
|
||||||
|
|
||||||
Стартовая процедура носит имя main .
|
|
||||||
|
|
||||||
Реализована поддержка меток. Метка должна находится на отдельной строке и выглядит так
|
|
||||||
name:
|
|
||||||
|
|
||||||
Пример:
|
|
||||||
|
|
||||||
.data
|
|
||||||
src2 "Done"
|
|
||||||
.endd
|
|
||||||
|
|
||||||
.proc main
|
|
||||||
ILOAD0
|
|
||||||
ILOAD -3
|
|
||||||
again:
|
|
||||||
CALL inc
|
|
||||||
IFICMPNE again
|
|
||||||
SLOAD src2
|
|
||||||
SPRINT
|
|
||||||
STOP
|
|
||||||
.endp
|
|
||||||
|
|
||||||
.proc inc
|
|
||||||
ILOAD1
|
|
||||||
IADD
|
|
||||||
RETURN
|
|
||||||
.endp
|
|
|
@ -1,68 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace CompilerVVM
|
|
||||||
{
|
|
||||||
class CodeGen
|
|
||||||
{
|
|
||||||
Dictionary<string, string> ConstData;
|
|
||||||
Dictionary<string, MethodAtom> Methods;
|
|
||||||
public string[] asm { get; set; }
|
|
||||||
|
|
||||||
|
|
||||||
public CodeGen(Dictionary<string, string> ConstData, Dictionary<string, MethodAtom> Methods)
|
|
||||||
{
|
|
||||||
this.ConstData = ConstData;
|
|
||||||
this.Methods = Methods;
|
|
||||||
asm = null;
|
|
||||||
|
|
||||||
foreach (KeyValuePair<string, MethodAtom> p in Methods)
|
|
||||||
{
|
|
||||||
Optimization(p.Value);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
FillAsmCode();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void FillAsmCode()
|
|
||||||
{
|
|
||||||
List<string> Code = new List<string>();
|
|
||||||
if (ConstData.Count > 0)
|
|
||||||
{
|
|
||||||
Code.Add(".data");
|
|
||||||
foreach (KeyValuePair<string, string> pair in ConstData)
|
|
||||||
{
|
|
||||||
Code.Add(string.Format("{0} \"{1}\"", pair.Value, pair.Key));
|
|
||||||
}
|
|
||||||
Code.Add(".endd");
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (KeyValuePair<string, MethodAtom> entry in Methods)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < entry.Value.Code.Count; i++)
|
|
||||||
Code.Add(entry.Value.Code[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
asm = Code.ToArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void Optimization(MethodAtom Method)
|
|
||||||
{
|
|
||||||
List<string> OptimizationSub = new List<string>(){"LOADDVAR", "LOADIVAR", "LOADSVAR", "STOREDVAR", "STOREIVAR",
|
|
||||||
"STORESVAR"};
|
|
||||||
|
|
||||||
for (int i = 0; i < Method.Code.Count; i++ )
|
|
||||||
{
|
|
||||||
string[] parts = Method.Code[i].Split(' ');
|
|
||||||
if (OptimizationSub.Contains(parts[0]) && int.Parse(parts[1]) < 4)
|
|
||||||
{
|
|
||||||
Method.Code[i] = Method.Code[i].Replace(" ", "");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,35 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace CompilerVVM
|
|
||||||
{
|
|
||||||
public class ScannerException : Exception
|
|
||||||
{
|
|
||||||
public ScannerException(string message)
|
|
||||||
: base(message)
|
|
||||||
{
|
|
||||||
;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class ProcedureException : Exception
|
|
||||||
{
|
|
||||||
public ProcedureException(string message)
|
|
||||||
: base(message)
|
|
||||||
{
|
|
||||||
;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class ParserException : Exception
|
|
||||||
{
|
|
||||||
public ParserException(string message)
|
|
||||||
: base(message)
|
|
||||||
{
|
|
||||||
;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,558 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace CompilerVVM
|
|
||||||
{
|
|
||||||
public class Parser
|
|
||||||
{
|
|
||||||
int pointer;
|
|
||||||
IList<object> Tokens;
|
|
||||||
int idvar;
|
|
||||||
Dictionary<string, string> Constants;
|
|
||||||
Dictionary<string, MethodAtom> Methods;
|
|
||||||
int jumpid;
|
|
||||||
|
|
||||||
public Parser(IList<object> tokens, Dictionary<string, string> TextConst, Dictionary<string, MethodAtom> Methods)
|
|
||||||
{
|
|
||||||
Tokens = tokens;
|
|
||||||
pointer = 0;
|
|
||||||
jumpid = 0;
|
|
||||||
Constants = TextConst;
|
|
||||||
this.Methods = Methods;
|
|
||||||
ParseMethod();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ParseMethod()
|
|
||||||
{
|
|
||||||
//<program> := <method>+
|
|
||||||
while (pointer != Tokens.Count)
|
|
||||||
{
|
|
||||||
//<method> := method <type_method> <ident>(<param>*) <block>
|
|
||||||
//<type> := int | double | string
|
|
||||||
//<type_method> := <type> | void
|
|
||||||
MethodAtom method = null;
|
|
||||||
if (!Tokens[pointer++].Equals("method"))
|
|
||||||
throw new ParserException("No method detected");
|
|
||||||
else
|
|
||||||
{
|
|
||||||
method = Methods[Tokens[++pointer].ToString()];
|
|
||||||
idvar = method.NumOfParams;
|
|
||||||
method.Code.Add(String.Format(".proc {0}", method.Name, method.NumOfParams));
|
|
||||||
|
|
||||||
pointer += 3 + (2 * method.NumOfParams);
|
|
||||||
if (Tokens[pointer].Equals(OP.OpenBlock))
|
|
||||||
{
|
|
||||||
pointer++;
|
|
||||||
ParseBlock(method);
|
|
||||||
}
|
|
||||||
else throw new ParserException("No code block in method: " + method.Name);
|
|
||||||
|
|
||||||
if (method.Name == "main")
|
|
||||||
method.Code.Add("STOP");
|
|
||||||
else if (method.Type == "void")
|
|
||||||
method.Code.Add("RETURN");
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (method.Code[method.Code.Count - 1] != "RETURN")
|
|
||||||
throw new ParserException("No return sequence in method:" + method.Name);
|
|
||||||
}
|
|
||||||
method.Code.Add(".endp");
|
|
||||||
|
|
||||||
method.NumOfLocals = method.Variables.Count;
|
|
||||||
method.Code[0] = String.Format(".proc {0} {1} {2}", method.Name, method.NumOfLocals, method.NumOfParams);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ParseBlock(MethodAtom method)
|
|
||||||
{
|
|
||||||
while (!Tokens[pointer].Equals(OP.CloseBlock))
|
|
||||||
{
|
|
||||||
if (Tokens[pointer].Equals(OP.Semicolon))
|
|
||||||
{
|
|
||||||
pointer++;
|
|
||||||
}
|
|
||||||
else if (code_types.Contains(Tokens[pointer].ToString()))
|
|
||||||
DeclareVar(method);
|
|
||||||
else if (Tokens[pointer + 1].Equals(OP.Assigment))
|
|
||||||
{
|
|
||||||
List<Variable> NeededVars = method.Variables.FindAll(x => x.Name == Tokens[pointer].ToString());
|
|
||||||
if (NeededVars.Count == 0)
|
|
||||||
throw new ParserException(string.Format("Variable {0} is not defined", Tokens[pointer].ToString()));
|
|
||||||
else
|
|
||||||
{
|
|
||||||
pointer += 2;
|
|
||||||
ParseExpression(method, NeededVars[NeededVars.Count - 1].Type);
|
|
||||||
switch (NeededVars[NeededVars.Count - 1].Type)
|
|
||||||
{
|
|
||||||
case "int":
|
|
||||||
method.Code.Add(string.Format("STOREIVAR {0}", NeededVars[NeededVars.Count - 1].ID));
|
|
||||||
break;
|
|
||||||
case "double":
|
|
||||||
method.Code.Add(string.Format("STOREDVAR {0}", NeededVars[NeededVars.Count - 1].ID));
|
|
||||||
break;
|
|
||||||
case "string":
|
|
||||||
method.Code.Add(string.Format("STORESVAR {0}", NeededVars[NeededVars.Count - 1].ID));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (Tokens[pointer].ToString() == "return")
|
|
||||||
{
|
|
||||||
ParseSingleExpr(method, pointer + 1, method.Type);
|
|
||||||
method.Code.Add("RETURN");
|
|
||||||
pointer += 3;
|
|
||||||
}
|
|
||||||
else if (Tokens[pointer].ToString() == "if")
|
|
||||||
{
|
|
||||||
if (!Tokens[pointer + 1].Equals(OP.OpenParam) || !Tokens[pointer + 5].Equals(OP.CloseParam))
|
|
||||||
throw new ParserException("Wrong if statement");
|
|
||||||
string var1 = GetTypeOfVar(method, pointer + 2);
|
|
||||||
string var2 = GetTypeOfVar(method, pointer + 4);
|
|
||||||
if (var1 != var2)
|
|
||||||
throw new ParserException("Incompatible variable types in if statement");
|
|
||||||
int jump = jumpid++;
|
|
||||||
ParseSingleExpr(method, pointer + 4, var2);
|
|
||||||
ParseSingleExpr(method, pointer + 2, var1);
|
|
||||||
|
|
||||||
switch ((OP)Tokens[pointer + 3])
|
|
||||||
{
|
|
||||||
case OP.Equal:
|
|
||||||
method.Code.Add(string.Format("IFICMPNE jump_{0}", jump));
|
|
||||||
break;
|
|
||||||
case OP.NotEqual:
|
|
||||||
method.Code.Add(string.Format("IFICMPE jump_{0}", jump));
|
|
||||||
break;
|
|
||||||
case OP.Greater:
|
|
||||||
method.Code.Add(string.Format("IFICMPLE jump_{0}", jump));
|
|
||||||
break;
|
|
||||||
case OP.GreaterEqual:
|
|
||||||
method.Code.Add(string.Format("IFICMPL jump_{0}", jump));
|
|
||||||
break;
|
|
||||||
case OP.Less:
|
|
||||||
method.Code.Add(string.Format("IFICMPGE jump_{0}", jump));
|
|
||||||
break;
|
|
||||||
case OP.LessEqual:
|
|
||||||
method.Code.Add(string.Format("IFICMPG jump_{0}", jump));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
method.Code.Add("POP");
|
|
||||||
method.Code.Add("POP");
|
|
||||||
if (!Tokens[pointer + 6].Equals(OP.OpenBlock))
|
|
||||||
throw new ParserException("No { code } in if statement");
|
|
||||||
pointer += 7;
|
|
||||||
ParseBlock(method);
|
|
||||||
if (Tokens[pointer].ToString() != "else")
|
|
||||||
{
|
|
||||||
method.Code.Add(string.Format("jump_{0}:", jump));
|
|
||||||
method.Code.Add("POP");
|
|
||||||
method.Code.Add("POP");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
int jump2 = jumpid++;
|
|
||||||
method.Code.Add(string.Format("JA jump_{0}", jump2));
|
|
||||||
if (!Tokens[pointer + 1].Equals(OP.OpenBlock))
|
|
||||||
throw new ParserException("No { code } in else statement");
|
|
||||||
method.Code.Add(string.Format("jump_{0}:", jump));
|
|
||||||
method.Code.Add("POP");
|
|
||||||
method.Code.Add("POP");
|
|
||||||
pointer += 2;
|
|
||||||
ParseBlock(method);
|
|
||||||
method.Code.Add(string.Format("jump_{0}:", jump2));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (Tokens[pointer].ToString() == "while")
|
|
||||||
{
|
|
||||||
if (!Tokens[pointer + 1].Equals(OP.OpenParam) || !Tokens[pointer + 5].Equals(OP.CloseParam))
|
|
||||||
throw new ParserException("Wrong while statement");
|
|
||||||
string var1 = GetTypeOfVar(method, pointer + 2);
|
|
||||||
string var2 = GetTypeOfVar(method, pointer + 4);
|
|
||||||
if (var1 != var2)
|
|
||||||
throw new ParserException("Incompatible variable types in while statement");
|
|
||||||
int jump = jumpid++;
|
|
||||||
int jump2 = jumpid++;
|
|
||||||
|
|
||||||
method.Code.Add(string.Format("jump_{0}:", jump));
|
|
||||||
ParseSingleExpr(method, pointer + 4, var2);
|
|
||||||
ParseSingleExpr(method, pointer + 2, var1);
|
|
||||||
|
|
||||||
switch ((OP)Tokens[pointer + 3])
|
|
||||||
{
|
|
||||||
case OP.Equal:
|
|
||||||
method.Code.Add(string.Format("IFICMPNE jump_{0}", jump2));
|
|
||||||
break;
|
|
||||||
case OP.NotEqual:
|
|
||||||
method.Code.Add(string.Format("IFICMPE jump_{0}", jump2));
|
|
||||||
break;
|
|
||||||
case OP.Greater:
|
|
||||||
method.Code.Add(string.Format("IFICMPLE jump_{0}", jump2));
|
|
||||||
break;
|
|
||||||
case OP.GreaterEqual:
|
|
||||||
method.Code.Add(string.Format("IFICMPL jump_{0}", jump2));
|
|
||||||
break;
|
|
||||||
case OP.Less:
|
|
||||||
method.Code.Add(string.Format("IFICMPGE jump_{0}", jump2));
|
|
||||||
break;
|
|
||||||
case OP.LessEqual:
|
|
||||||
method.Code.Add(string.Format("IFICMPG jump_{0}", jump2));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
method.Code.Add("POP");
|
|
||||||
method.Code.Add("POP");
|
|
||||||
if (!Tokens[pointer + 6].Equals(OP.OpenBlock))
|
|
||||||
throw new ParserException("No { code } in while statement");
|
|
||||||
pointer += 7;
|
|
||||||
ParseBlock(method);
|
|
||||||
method.Code.Add(string.Format("JA jump_{0}", jump));
|
|
||||||
method.Code.Add(string.Format("jump_{0}:", jump2));
|
|
||||||
}
|
|
||||||
else if (Tokens[pointer].ToString() == "do")
|
|
||||||
{
|
|
||||||
int jump = jumpid++;
|
|
||||||
int jump2 = jumpid++;
|
|
||||||
method.Code.Add(string.Format("JA jump_{0}", jump2));
|
|
||||||
method.Code.Add(string.Format("jump_{0}:", jump));
|
|
||||||
method.Code.Add("POP");
|
|
||||||
method.Code.Add("POP");
|
|
||||||
method.Code.Add(string.Format("jump_{0}:", jump2));
|
|
||||||
pointer += 2;
|
|
||||||
ParseBlock(method);
|
|
||||||
|
|
||||||
if (!Tokens[pointer + 1].Equals(OP.OpenParam) || !Tokens[pointer + 5].Equals(OP.CloseParam) ||
|
|
||||||
Tokens[pointer].ToString() != "until")
|
|
||||||
throw new ParserException("Wrong until statement");
|
|
||||||
string var1 = GetTypeOfVar(method, pointer + 2);
|
|
||||||
string var2 = GetTypeOfVar(method, pointer + 4);
|
|
||||||
if (var1 != var2)
|
|
||||||
throw new Exception("Incompatible variable types in until statement");
|
|
||||||
|
|
||||||
ParseSingleExpr(method, pointer + 4, var2);
|
|
||||||
ParseSingleExpr(method, pointer + 2, var1);
|
|
||||||
|
|
||||||
switch ((OP)Tokens[pointer + 3])
|
|
||||||
{
|
|
||||||
case OP.Equal:
|
|
||||||
method.Code.Add(string.Format("IFICMPNE jump_{0}", jump));
|
|
||||||
break;
|
|
||||||
case OP.NotEqual:
|
|
||||||
method.Code.Add(string.Format("IFICMPE jump_{0}", jump));
|
|
||||||
break;
|
|
||||||
case OP.Greater:
|
|
||||||
method.Code.Add(string.Format("IFICMPLE jump_{0}", jump));
|
|
||||||
break;
|
|
||||||
case OP.GreaterEqual:
|
|
||||||
method.Code.Add(string.Format("IFICMPL jump_{0}", jump));
|
|
||||||
break;
|
|
||||||
case OP.Less:
|
|
||||||
method.Code.Add(string.Format("IFICMPGE jump_{0}", jump));
|
|
||||||
break;
|
|
||||||
case OP.LessEqual:
|
|
||||||
method.Code.Add(string.Format("IFICMPG jump_{0}", jump));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
method.Code.Add("POP");
|
|
||||||
method.Code.Add("POP");
|
|
||||||
pointer += 7;
|
|
||||||
}
|
|
||||||
else if (Tokens[pointer].ToString() == "print")
|
|
||||||
{
|
|
||||||
pointer += 2;
|
|
||||||
string type = GetTypeOfVar(method, pointer);
|
|
||||||
ParseSingleExpr(method, pointer, type);
|
|
||||||
pointer += 3;
|
|
||||||
switch (type)
|
|
||||||
{
|
|
||||||
case "int":
|
|
||||||
method.Code.Add("IPRINT");
|
|
||||||
break;
|
|
||||||
case "double":
|
|
||||||
method.Code.Add("DPRINT");
|
|
||||||
break;
|
|
||||||
case "string":
|
|
||||||
method.Code.Add("SPRINT");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (Tokens[pointer+1].Equals(OP.OpenParam))
|
|
||||||
{
|
|
||||||
ParseCall(method);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pointer++;
|
|
||||||
}
|
|
||||||
private void ParseExpression(MethodAtom method, string type)
|
|
||||||
{
|
|
||||||
if (Tokens[pointer + 1].Equals(OP.Semicolon))
|
|
||||||
{
|
|
||||||
ParseSingleExpr(method, pointer, type);
|
|
||||||
pointer += 2;
|
|
||||||
}
|
|
||||||
else if (Tokens[pointer + 1].Equals(OP.OpenParam))
|
|
||||||
{
|
|
||||||
ParseCall(method, type);
|
|
||||||
}
|
|
||||||
else if (Tokens[pointer].Equals(OP.Sub))
|
|
||||||
{
|
|
||||||
ParseSingleExpr(method, pointer + 1, type);
|
|
||||||
switch (type)
|
|
||||||
{
|
|
||||||
case "int":
|
|
||||||
method.Code.Add("INEG");
|
|
||||||
break;
|
|
||||||
case "double":
|
|
||||||
method.Code.Add("DNEG");
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new ParserException("Incompatible types");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (Tokens[pointer + 1].Equals(OP.Add))
|
|
||||||
{
|
|
||||||
int prevpointer = pointer;
|
|
||||||
pointer += 2;
|
|
||||||
|
|
||||||
ParseExpression(method, type);
|
|
||||||
ParseSingleExpr(method, prevpointer, type);
|
|
||||||
|
|
||||||
switch (type)
|
|
||||||
{
|
|
||||||
case "int":
|
|
||||||
method.Code.Add("IADD");
|
|
||||||
break;
|
|
||||||
case "double":
|
|
||||||
method.Code.Add("DADD");
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new ParserException("Incompatible types");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (Tokens[pointer + 1].Equals(OP.Sub))
|
|
||||||
{
|
|
||||||
int prevpointer = pointer;
|
|
||||||
pointer += 2;
|
|
||||||
|
|
||||||
ParseExpression(method, type);
|
|
||||||
ParseSingleExpr(method, prevpointer, type);
|
|
||||||
|
|
||||||
switch (type)
|
|
||||||
{
|
|
||||||
case "int":
|
|
||||||
method.Code.Add("ISUB");
|
|
||||||
break;
|
|
||||||
case "double":
|
|
||||||
method.Code.Add("DSUB");
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new ParserException("Incompatible types");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (Tokens[pointer + 1].Equals(OP.Mul))
|
|
||||||
{
|
|
||||||
int prevpointer = pointer;
|
|
||||||
pointer += 2;
|
|
||||||
|
|
||||||
ParseExpression(method, type);
|
|
||||||
ParseSingleExpr(method, prevpointer, type);
|
|
||||||
|
|
||||||
switch (type)
|
|
||||||
{
|
|
||||||
case "int":
|
|
||||||
method.Code.Add("IMUL");
|
|
||||||
break;
|
|
||||||
case "double":
|
|
||||||
method.Code.Add("DMUL");
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new ParserException("Incompatible types");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (Tokens[pointer + 1].Equals(OP.Div))
|
|
||||||
{
|
|
||||||
int prevpointer = pointer;
|
|
||||||
pointer += 2;
|
|
||||||
|
|
||||||
ParseExpression(method, type);
|
|
||||||
ParseSingleExpr(method, prevpointer, type);
|
|
||||||
|
|
||||||
switch (type)
|
|
||||||
{
|
|
||||||
case "int":
|
|
||||||
method.Code.Add("IDIV");
|
|
||||||
break;
|
|
||||||
case "double":
|
|
||||||
method.Code.Add("DDIV");
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new ParserException("Incompatible types");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (Tokens[pointer + 1].Equals(OP.Mod))
|
|
||||||
{
|
|
||||||
int prevpointer = pointer;
|
|
||||||
pointer += 2;
|
|
||||||
|
|
||||||
ParseExpression(method, type);
|
|
||||||
ParseSingleExpr(method, prevpointer, type);
|
|
||||||
|
|
||||||
switch (type)
|
|
||||||
{
|
|
||||||
case "int":
|
|
||||||
method.Code.Add("IMOD");
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new ParserException("Incompatible types");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ParseCall(MethodAtom method, string type = null)
|
|
||||||
{
|
|
||||||
if (Methods.ContainsKey(Tokens[pointer].ToString()))
|
|
||||||
{
|
|
||||||
MethodAtom CallMethod = Methods[Tokens[pointer].ToString()];
|
|
||||||
if (type != null && type != CallMethod.Type)
|
|
||||||
throw new ParserException("Incompatible types when call method" + CallMethod.Name);
|
|
||||||
|
|
||||||
pointer += 2;
|
|
||||||
List<object> param = new List<object>();
|
|
||||||
while (!Tokens[pointer++].Equals(OP.CloseParam))
|
|
||||||
{
|
|
||||||
param.Add(Tokens[pointer]);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (param.Count != CallMethod.NumOfParams)
|
|
||||||
throw new ParserException("Wrong params when call method" + CallMethod.Name);
|
|
||||||
|
|
||||||
for (int i = 0; i < param.Count; i++)
|
|
||||||
{
|
|
||||||
ParseSingleExpr(method, pointer - 2 - i, CallMethod.Variables[i].Type);
|
|
||||||
}
|
|
||||||
|
|
||||||
method.Code.Add(string.Format("CALL {0}", CallMethod.Name));
|
|
||||||
|
|
||||||
}
|
|
||||||
else throw new ParserException("Undefined method to call");
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ParseSingleExpr(MethodAtom method, int pointer, string type)
|
|
||||||
{
|
|
||||||
if (Tokens[pointer] is StringBuilder)
|
|
||||||
{
|
|
||||||
if (type == "string")
|
|
||||||
method.Code.Add(string.Format("SLOAD {0}", Constants[Tokens[pointer++].ToString()]));
|
|
||||||
else
|
|
||||||
throw new ParserException("Incompatible type");
|
|
||||||
}
|
|
||||||
else if (Tokens[pointer] is Number)
|
|
||||||
{
|
|
||||||
switch (type)
|
|
||||||
{
|
|
||||||
case "int":
|
|
||||||
if (!Tokens[pointer].ToString().Contains("."))
|
|
||||||
{
|
|
||||||
method.Code.Add(string.Format("ILOAD {0}", Tokens[pointer++].ToString()));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else throw new ParserException("Incompatible type");
|
|
||||||
|
|
||||||
case "double":
|
|
||||||
method.Code.Add(string.Format("DLOAD {0}", Tokens[pointer++].ToString()));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
List<Variable> NeededVars = method.Variables.FindAll(x => x.Name == Tokens[pointer].ToString());
|
|
||||||
if (NeededVars.Count != 0)
|
|
||||||
{
|
|
||||||
if (NeededVars[NeededVars.Count - 1].Type != type)
|
|
||||||
throw new ParserException("Incompatible type");
|
|
||||||
else
|
|
||||||
{
|
|
||||||
switch (type)
|
|
||||||
{
|
|
||||||
case "int":
|
|
||||||
method.Code.Add(string.Format("LOADIVAR {0}", NeededVars[NeededVars.Count - 1].ID));
|
|
||||||
break;
|
|
||||||
case "double":
|
|
||||||
method.Code.Add(string.Format("LOADDVAR {0}", NeededVars[NeededVars.Count - 1].ID));
|
|
||||||
break;
|
|
||||||
case "string":
|
|
||||||
method.Code.Add(string.Format("LOADSVAR {0}", NeededVars[NeededVars.Count - 1].ID));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else throw new ParserException("Can't parse sequence");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void DeclareVar(MethodAtom method)
|
|
||||||
{
|
|
||||||
method.Variables.Add(new Variable(idvar++, Tokens[pointer].ToString(), Tokens[pointer + 1].ToString()));
|
|
||||||
if (Tokens[pointer + 2].Equals(OP.Semicolon))
|
|
||||||
{
|
|
||||||
pointer += 3; return;
|
|
||||||
}
|
|
||||||
else if (Tokens[pointer + 2].Equals(OP.Assigment))
|
|
||||||
{
|
|
||||||
pointer += 3;
|
|
||||||
ParseExpression(method, method.Variables[idvar - 1].Type);
|
|
||||||
switch (method.Variables[idvar - 1].Type)
|
|
||||||
{
|
|
||||||
case "int":
|
|
||||||
method.Code.Add(string.Format("STOREIVAR {0}", idvar - 1));
|
|
||||||
break;
|
|
||||||
|
|
||||||
case "double":
|
|
||||||
method.Code.Add(string.Format("STOREDVAR {0}", idvar - 1));
|
|
||||||
break;
|
|
||||||
|
|
||||||
case "string":
|
|
||||||
method.Code.Add(string.Format("STORESVAR {0}", idvar - 1));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Tokens[pointer].Equals(OP.Semicolon))
|
|
||||||
{
|
|
||||||
pointer++; return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
throw new ParserException("Wrong variable defenition");
|
|
||||||
}
|
|
||||||
|
|
||||||
private string GetTypeOfVar(MethodAtom method, int pointer)
|
|
||||||
{
|
|
||||||
string result = null;
|
|
||||||
if (Tokens[pointer] is StringBuilder)
|
|
||||||
result = "string";
|
|
||||||
else if (Tokens[pointer] is Number)
|
|
||||||
{
|
|
||||||
if (Tokens[pointer].ToString().Contains("."))
|
|
||||||
result = "double";
|
|
||||||
else result = "int";
|
|
||||||
}
|
|
||||||
else if (Methods.ContainsKey(Tokens[pointer].ToString()))
|
|
||||||
{
|
|
||||||
result = Methods[Tokens[pointer].ToString()].Type;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
List<Variable> isVariable = method.Variables.FindAll(x => x.Name == Tokens[pointer].ToString());
|
|
||||||
if (isVariable.Count == 0)
|
|
||||||
throw new ParserException("No defined variable with name "+Tokens[pointer].ToString());
|
|
||||||
else result = isVariable[isVariable.Count - 1].Type;
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
List<string> code_types = new List<string>() { "int", "double", "string" };
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,53 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace CompilerVVM
|
|
||||||
{
|
|
||||||
class ProcedureScanner
|
|
||||||
{
|
|
||||||
public Dictionary<string, MethodAtom> Methods { get; set; }
|
|
||||||
int pointer;
|
|
||||||
|
|
||||||
public ProcedureScanner(IList<object> Tokens)
|
|
||||||
{
|
|
||||||
// TODO: Complete member initialization
|
|
||||||
pointer = 0;
|
|
||||||
ScanForMethods(Tokens);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ScanForMethods(IList<object> Tokens)
|
|
||||||
{
|
|
||||||
Methods = new Dictionary<string, MethodAtom>();
|
|
||||||
while (pointer != Tokens.Count)
|
|
||||||
{
|
|
||||||
MethodAtom method = null;
|
|
||||||
if (Tokens[pointer++].Equals("method"))
|
|
||||||
{
|
|
||||||
if (!Tokens[pointer].Equals("void") && !Tokens[pointer].Equals("int") &&
|
|
||||||
!Tokens[pointer].Equals("double") && !Tokens[pointer].Equals("string"))
|
|
||||||
{
|
|
||||||
throw new ProcedureException("Wrong method defenition");
|
|
||||||
}
|
|
||||||
int idvar = 0;
|
|
||||||
method = new MethodAtom(Tokens[++pointer].ToString());
|
|
||||||
method.Type = Tokens[pointer++ - 1].ToString();
|
|
||||||
if (!Tokens[pointer++].Equals(OP.OpenParam))
|
|
||||||
throw new ProcedureException("Wrong method defenition of method: "+method.Name);
|
|
||||||
else
|
|
||||||
{
|
|
||||||
while (!Tokens[pointer].Equals(OP.CloseParam))
|
|
||||||
{
|
|
||||||
Variable a = new Variable(idvar++, Tokens[pointer].ToString(), Tokens[pointer + 1].ToString());
|
|
||||||
method.Variables.Add(a);
|
|
||||||
method.NumOfParams++;
|
|
||||||
pointer += 2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Methods.Add(method.Name, method);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,53 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace CompilerVVM
|
|
||||||
{
|
|
||||||
class Program
|
|
||||||
{
|
|
||||||
static void Main(string[] args)
|
|
||||||
{
|
|
||||||
if (args.Length != 1)
|
|
||||||
{
|
|
||||||
Console.WriteLine("No input file");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
try
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* This program translate source code into assembly instructions
|
|
||||||
* This can be done in several steps:
|
|
||||||
* 1. Compiler finds tokens (individual parts such as text, spec. symbols, numbers etc);
|
|
||||||
* 2. Compiler goes through tokens and defines functions
|
|
||||||
* 3. Compiler parse every function into assembler instruction
|
|
||||||
*/
|
|
||||||
TokenScanner scanner = null;
|
|
||||||
ProcedureScanner procscanner = null;
|
|
||||||
Parser parser = null;
|
|
||||||
CodeGen code = null;
|
|
||||||
Dictionary<string, string> TextConst = new Dictionary<string, string>();
|
|
||||||
using (System.IO.TextReader input = System.IO.File.OpenText(args[0]))
|
|
||||||
{
|
|
||||||
scanner = new TokenScanner(input, TextConst);
|
|
||||||
procscanner = new ProcedureScanner(scanner.Tokens);
|
|
||||||
parser = new Parser(scanner.Tokens, TextConst, procscanner.Methods);
|
|
||||||
|
|
||||||
code = new CodeGen(TextConst, procscanner.Methods);
|
|
||||||
//ByteCode.GenerateByteCode(code.asm, args[0] + ".vvm");
|
|
||||||
System.IO.File.WriteAllLines(args[0] + ".vasm", code.asm);
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
Console.Error.WriteLine(e.Message);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,293 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using System.IO;
|
|
||||||
using System.Globalization;
|
|
||||||
|
|
||||||
namespace CompilerVVM
|
|
||||||
{
|
|
||||||
class TokenScanner
|
|
||||||
{
|
|
||||||
int idconst = 1;
|
|
||||||
private IList<object> tokens;
|
|
||||||
private IList<object> list;
|
|
||||||
public IList<object> Tokens { get { return tokens; } }
|
|
||||||
private void Scan(System.IO.TextReader input, Dictionary<string, string> dict)
|
|
||||||
{
|
|
||||||
while (input.Peek() != -1)
|
|
||||||
{
|
|
||||||
char ch = (char)input.Peek();
|
|
||||||
|
|
||||||
if (char.IsWhiteSpace(ch))
|
|
||||||
{
|
|
||||||
input.Read();
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (char.IsLetter(ch) || ch == '_')
|
|
||||||
{
|
|
||||||
StringBuilder accum = new StringBuilder();
|
|
||||||
|
|
||||||
while (char.IsLetter(ch) || ch == '_' || char.IsNumber(ch))
|
|
||||||
{
|
|
||||||
accum.Append(ch);
|
|
||||||
input.Read();
|
|
||||||
|
|
||||||
if (input.Peek() == -1)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ch = (char)input.Peek();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.tokens.Add(accum.ToString());
|
|
||||||
}
|
|
||||||
else if (ch == '"')
|
|
||||||
{
|
|
||||||
StringBuilder accum = new StringBuilder();
|
|
||||||
|
|
||||||
input.Read();
|
|
||||||
|
|
||||||
if (input.Peek() == -1)
|
|
||||||
{
|
|
||||||
throw new ScannerException("Unterminated string");
|
|
||||||
}
|
|
||||||
|
|
||||||
while ((ch = (char)input.Peek()) != '"')
|
|
||||||
{
|
|
||||||
accum.Append(ch);
|
|
||||||
input.Read();
|
|
||||||
|
|
||||||
if (input.Peek() == -1)
|
|
||||||
{
|
|
||||||
throw new ScannerException("Unterminated string");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
input.Read();
|
|
||||||
dict.Add(accum.ToString(), string.Format("text_const_{0}", idconst++));
|
|
||||||
this.tokens.Add(accum);
|
|
||||||
}
|
|
||||||
else if (char.IsDigit(ch))
|
|
||||||
{
|
|
||||||
StringBuilder accum = new StringBuilder();
|
|
||||||
|
|
||||||
while (char.IsDigit(ch) || ch == '.')
|
|
||||||
{
|
|
||||||
accum.Append(ch);
|
|
||||||
input.Read();
|
|
||||||
|
|
||||||
if (input.Peek() == -1)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ch = (char)input.Peek();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.tokens.Add(new Number(accum.ToString()));
|
|
||||||
}
|
|
||||||
else if (ch == '(')
|
|
||||||
{
|
|
||||||
this.tokens.Add(OP.OpenParam);
|
|
||||||
input.Read();
|
|
||||||
|
|
||||||
if (input.Peek() == -1)
|
|
||||||
{
|
|
||||||
throw new ScannerException("Unterminated parameter section");
|
|
||||||
}
|
|
||||||
|
|
||||||
while ((ch = (char)input.Peek()) != ')')
|
|
||||||
{
|
|
||||||
if (char.IsLetter(ch) || ch == '_')
|
|
||||||
{
|
|
||||||
StringBuilder accum = new StringBuilder();
|
|
||||||
|
|
||||||
while (char.IsLetter(ch) || ch == '_')
|
|
||||||
{
|
|
||||||
accum.Append(ch);
|
|
||||||
input.Read();
|
|
||||||
|
|
||||||
if (input.Peek() == -1)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ch = (char)input.Peek();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.tokens.Add(accum.ToString());
|
|
||||||
}
|
|
||||||
else if (char.IsDigit(ch))
|
|
||||||
{
|
|
||||||
StringBuilder accum = new StringBuilder();
|
|
||||||
|
|
||||||
while (char.IsDigit(ch) || ch == '.')
|
|
||||||
{
|
|
||||||
accum.Append(ch);
|
|
||||||
input.Read();
|
|
||||||
|
|
||||||
if (input.Peek() == -1)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ch = (char)input.Peek();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.tokens.Add(new Number(accum.ToString()));
|
|
||||||
}
|
|
||||||
else if (ch == '"')
|
|
||||||
{
|
|
||||||
StringBuilder accum = new StringBuilder();
|
|
||||||
|
|
||||||
input.Read();
|
|
||||||
|
|
||||||
if (input.Peek() == -1)
|
|
||||||
{
|
|
||||||
throw new ScannerException("Unterminated string");
|
|
||||||
}
|
|
||||||
|
|
||||||
while ((ch = (char)input.Peek()) != '"')
|
|
||||||
{
|
|
||||||
accum.Append(ch);
|
|
||||||
input.Read();
|
|
||||||
|
|
||||||
if (input.Peek() == -1)
|
|
||||||
{
|
|
||||||
throw new ScannerException("Unterminated string");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
input.Read();
|
|
||||||
dict.Add(accum.ToString(), string.Format("text_const_{0}", idconst++));
|
|
||||||
this.tokens.Add(accum);
|
|
||||||
}
|
|
||||||
else if (char.IsWhiteSpace(ch) || ch == ',')
|
|
||||||
input.Read();
|
|
||||||
else switch (ch)
|
|
||||||
{
|
|
||||||
case '=':
|
|
||||||
input.Read();
|
|
||||||
if ((char)input.Peek() == '=')
|
|
||||||
{
|
|
||||||
input.Read();
|
|
||||||
this.tokens.Add(OP.Equal);
|
|
||||||
}
|
|
||||||
else this.tokens.Add(OP.Assigment);
|
|
||||||
break;
|
|
||||||
case '<':
|
|
||||||
input.Read();
|
|
||||||
if ((char)input.Peek() == '=')
|
|
||||||
{
|
|
||||||
input.Read();
|
|
||||||
this.tokens.Add(OP.LessEqual);
|
|
||||||
}
|
|
||||||
else this.tokens.Add(OP.Less);
|
|
||||||
break;
|
|
||||||
case '>':
|
|
||||||
input.Read();
|
|
||||||
if ((char)input.Peek() == '=')
|
|
||||||
{
|
|
||||||
input.Read();
|
|
||||||
this.tokens.Add(OP.GreaterEqual);
|
|
||||||
}
|
|
||||||
else this.tokens.Add(OP.Greater);
|
|
||||||
break;
|
|
||||||
case '!':
|
|
||||||
input.Read();
|
|
||||||
if ((char)input.Peek() == '=')
|
|
||||||
{
|
|
||||||
input.Read();
|
|
||||||
this.tokens.Add(OP.NotEqual);
|
|
||||||
}
|
|
||||||
else throw new Exception("!");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.tokens.Add(OP.CloseParam);
|
|
||||||
input.Read();
|
|
||||||
}
|
|
||||||
else switch (ch)
|
|
||||||
{
|
|
||||||
case ';':
|
|
||||||
input.Read();
|
|
||||||
this.tokens.Add(OP.Semicolon);
|
|
||||||
break;
|
|
||||||
case '{':
|
|
||||||
input.Read();
|
|
||||||
this.tokens.Add(OP.OpenBlock);
|
|
||||||
break;
|
|
||||||
case '}':
|
|
||||||
input.Read();
|
|
||||||
this.tokens.Add(OP.CloseBlock);
|
|
||||||
break;
|
|
||||||
case '+':
|
|
||||||
input.Read();
|
|
||||||
this.tokens.Add(OP.Add);
|
|
||||||
break;
|
|
||||||
case '-':
|
|
||||||
input.Read();
|
|
||||||
this.tokens.Add(OP.Sub);
|
|
||||||
break;
|
|
||||||
case '*':
|
|
||||||
input.Read();
|
|
||||||
this.tokens.Add(OP.Mul);
|
|
||||||
break;
|
|
||||||
case '/':
|
|
||||||
input.Read();
|
|
||||||
this.tokens.Add(OP.Div);
|
|
||||||
break;
|
|
||||||
case '%':
|
|
||||||
input.Read();
|
|
||||||
this.tokens.Add(OP.Mod);
|
|
||||||
break;
|
|
||||||
case '=':
|
|
||||||
input.Read();
|
|
||||||
if ((char)input.Peek() == '=')
|
|
||||||
{
|
|
||||||
input.Read();
|
|
||||||
this.tokens.Add(OP.Equal);
|
|
||||||
}
|
|
||||||
else this.tokens.Add(OP.Assigment);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new ScannerException("Scanner encountered unrecognized character '" + ch + "'");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public TokenScanner(TextReader input, Dictionary<string, string> TextConstant)
|
|
||||||
{
|
|
||||||
tokens = new List<object>();
|
|
||||||
this.Scan(input, TextConstant);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
enum OP
|
|
||||||
{
|
|
||||||
Semicolon,
|
|
||||||
OpenBlock,
|
|
||||||
CloseBlock,
|
|
||||||
OpenParam,
|
|
||||||
CloseParam,
|
|
||||||
Assigment,
|
|
||||||
Equal,
|
|
||||||
NotEqual,
|
|
||||||
Less,
|
|
||||||
Greater,
|
|
||||||
LessEqual,
|
|
||||||
GreaterEqual,
|
|
||||||
Add,
|
|
||||||
Sub,
|
|
||||||
Mul,
|
|
||||||
Div,
|
|
||||||
Mod
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,43 +0,0 @@
|
||||||
<program> := <method>+
|
|
||||||
|
|
||||||
<method> := method <type_method> <ident>(<param>* ) <block>
|
|
||||||
|
|
||||||
<type> := int | double | string
|
|
||||||
<type_method> := <type> | void
|
|
||||||
|
|
||||||
<ident> := <char> <ident_rest>*
|
|
||||||
<ident_rest> := <char> | <digit>
|
|
||||||
<digit> := 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
|
|
||||||
|
|
||||||
<int> := <digit>+
|
|
||||||
<double> := <int>.<int>
|
|
||||||
<string> := " <char>? "
|
|
||||||
|
|
||||||
<param> := <type> <ident>
|
|
||||||
|
|
||||||
<block> := <call>;
|
|
||||||
| <ident> = <expr>;
|
|
||||||
| <type> <ident>;
|
|
||||||
| <type> <ident> = <expr>;
|
|
||||||
| if <condit> <block>
|
|
||||||
| if <condit> <block> else <block>
|
|
||||||
| while <condit> <block>
|
|
||||||
| do <block> until <condit>;
|
|
||||||
|
|
||||||
<condit> := <int> <cond_op> <int>
|
|
||||||
<cond_op> := < | > | == | <= | >=
|
|
||||||
|
|
||||||
<expr> := <int>
|
|
||||||
| <double>
|
|
||||||
| <string>
|
|
||||||
| <int> <arith_op> <int>
|
|
||||||
| <double> <arith_op> <double>
|
|
||||||
| <ident>
|
|
||||||
| <call>
|
|
||||||
|
|
||||||
<arith_op> := + | - | * | /
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,39 +0,0 @@
|
||||||
#ifndef CODE_HEADER
|
|
||||||
#define CODE_HEADER
|
|
||||||
#pragma pack(push, 1)
|
|
||||||
struct
|
|
||||||
{
|
|
||||||
char signature[2];
|
|
||||||
int version;
|
|
||||||
int count_const;
|
|
||||||
int size_const;
|
|
||||||
}Const_Header;
|
|
||||||
|
|
||||||
struct
|
|
||||||
{
|
|
||||||
unsigned short id_start;
|
|
||||||
int count_code;
|
|
||||||
}ByteCodeH_Common;
|
|
||||||
|
|
||||||
struct
|
|
||||||
{
|
|
||||||
int size_func;
|
|
||||||
int size_bytecode;
|
|
||||||
int size_signature;
|
|
||||||
}ByteCodeH_Signat;
|
|
||||||
|
|
||||||
struct
|
|
||||||
{
|
|
||||||
unsigned short id;
|
|
||||||
int count_locals;
|
|
||||||
int count_args;
|
|
||||||
}ByteCodeH_Primary;
|
|
||||||
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
int count_locals;
|
|
||||||
int count_args;
|
|
||||||
char* code;
|
|
||||||
} func;
|
|
||||||
#endif
|
|
||||||
#pragma pop
|
|
|
@ -1,54 +0,0 @@
|
||||||
#include "Context.h"
|
|
||||||
#include <malloc.h>
|
|
||||||
context* create_context(int function, func** hash, char** code)
|
|
||||||
{
|
|
||||||
context* cont;
|
|
||||||
cont = (context*)malloc(sizeof(context));
|
|
||||||
|
|
||||||
cont->id = function;
|
|
||||||
cont->locals=(l_var*)malloc(sizeof(l_var)*hash[function]->count_locals);
|
|
||||||
*(code)=hash[function]->code;
|
|
||||||
return cont;
|
|
||||||
}
|
|
||||||
|
|
||||||
void remove_context(context* cont)
|
|
||||||
{
|
|
||||||
free(cont->locals);
|
|
||||||
free(cont);
|
|
||||||
}
|
|
||||||
|
|
||||||
void push_context(context* cont)
|
|
||||||
{
|
|
||||||
c_node* node;
|
|
||||||
node = (c_node*)malloc(sizeof(c_node));
|
|
||||||
node->obj=cont;
|
|
||||||
node->prev = node_last;
|
|
||||||
node_last = node;
|
|
||||||
}
|
|
||||||
context* pop_context()
|
|
||||||
{
|
|
||||||
context* poped = node_last->obj;
|
|
||||||
c_node* last = node_last;
|
|
||||||
node_last = node_last->prev;
|
|
||||||
|
|
||||||
free(last);
|
|
||||||
return poped;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Find Context in Context Stack.
|
|
||||||
context* find_context(int id)
|
|
||||||
{
|
|
||||||
context* result = NULL;
|
|
||||||
c_node* current = node_last;
|
|
||||||
while (current != NULL || current->prev != NULL)
|
|
||||||
{
|
|
||||||
if (current->obj->id == id)
|
|
||||||
{
|
|
||||||
result = current->obj;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
current = current->prev;
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
|
@ -1,34 +0,0 @@
|
||||||
#ifndef CONTEXT_H
|
|
||||||
#define CONTEXT_H
|
|
||||||
|
|
||||||
#include "CodeHeader.h"
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
typedef union
|
|
||||||
{
|
|
||||||
double d_data;
|
|
||||||
long long i_data;
|
|
||||||
char* s_data;
|
|
||||||
} l_var;
|
|
||||||
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
int id;
|
|
||||||
l_var* locals;
|
|
||||||
} context;
|
|
||||||
|
|
||||||
typedef struct NODE
|
|
||||||
{
|
|
||||||
context* obj;
|
|
||||||
struct NODE* prev;
|
|
||||||
} c_node;
|
|
||||||
|
|
||||||
c_node* node_last;
|
|
||||||
|
|
||||||
context* create_context(int function, func** hash,char** code);
|
|
||||||
void push_context(context*);
|
|
||||||
context* pop_context();
|
|
||||||
void remove_context(context*);
|
|
||||||
context* find_context(int id);
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,77 +0,0 @@
|
||||||
#include "IOcode.h"
|
|
||||||
#include "CodeHeader.h"
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
int version = 100;
|
|
||||||
|
|
||||||
int read_bytecode(FILE* stream, func*** hash)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
char* name;
|
|
||||||
char* code;
|
|
||||||
func* function;
|
|
||||||
|
|
||||||
*(hash) = (func**)malloc(sizeof(func*)*65536);
|
|
||||||
fread_s(&ByteCodeH_Common, sizeof(ByteCodeH_Common), sizeof(ByteCodeH_Common), 1, stream);
|
|
||||||
|
|
||||||
for (i=0; i<ByteCodeH_Common.count_code; i++)
|
|
||||||
{
|
|
||||||
function = (func*)malloc(sizeof(func));
|
|
||||||
|
|
||||||
fread(&ByteCodeH_Signat, sizeof(ByteCodeH_Signat), 1, stream);
|
|
||||||
name = (char*)malloc(ByteCodeH_Signat.size_signature);
|
|
||||||
fread(name, ByteCodeH_Signat.size_signature, 1, stream);
|
|
||||||
free(name);
|
|
||||||
|
|
||||||
fread(&ByteCodeH_Primary, sizeof(ByteCodeH_Primary), 1, stream);
|
|
||||||
code = (char*)malloc(ByteCodeH_Signat.size_bytecode);
|
|
||||||
fread(code, ByteCodeH_Signat.size_bytecode, 1, stream);
|
|
||||||
|
|
||||||
function->code=code;
|
|
||||||
function->count_args=ByteCodeH_Primary.count_args;
|
|
||||||
function->count_locals=ByteCodeH_Primary.count_locals;
|
|
||||||
(*(hash))[ByteCodeH_Primary.id]=function;
|
|
||||||
}
|
|
||||||
return ByteCodeH_Common.id_start;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
int read_constant(FILE* stream, int* count, char*** index)
|
|
||||||
{
|
|
||||||
int i, j;
|
|
||||||
char* buffer;
|
|
||||||
|
|
||||||
fread_s(&Const_Header, sizeof(Const_Header), sizeof(Const_Header), 1, stream); //Reading first part of header
|
|
||||||
if (Const_Header.signature[0]==Const_Header.signature[1]== 0xBA)
|
|
||||||
{
|
|
||||||
printf("%s", "Wrong file-format");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Const_Header.version != version)
|
|
||||||
{
|
|
||||||
printf("%s", "Unsupported bytecode format");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
*(count) = Const_Header.count_const;
|
|
||||||
|
|
||||||
buffer = (char*)malloc(Const_Header.size_const+1);
|
|
||||||
buffer[0]=0;
|
|
||||||
*(index) = (char**)malloc(sizeof(char**)*Const_Header.count_const+1);
|
|
||||||
|
|
||||||
|
|
||||||
fread_s(buffer+1, Const_Header.size_const, sizeof(char), Const_Header.size_const, stream); //Reading constant values
|
|
||||||
|
|
||||||
j=0;
|
|
||||||
(*(index))[j++]=buffer;
|
|
||||||
for (i = 0; i<Const_Header.size_const+1; i++)
|
|
||||||
{
|
|
||||||
if (j>Const_Header.count_const)
|
|
||||||
break;
|
|
||||||
|
|
||||||
if (buffer[i] == 0)
|
|
||||||
(*(index))[j++]=&buffer[i+1];
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
|
@ -1,10 +0,0 @@
|
||||||
#ifndef IOCODE_H
|
|
||||||
#define IOCODE_H
|
|
||||||
|
|
||||||
#include "CodeHeader.h"
|
|
||||||
#include <malloc.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
int read_bytecode(FILE*, func***);
|
|
||||||
int read_constant(FILE*, int*, char***);
|
|
||||||
#endif
|
|
|
@ -1,50 +0,0 @@
|
||||||
#include <string.h>
|
|
||||||
#include "LocalVars.h"
|
|
||||||
#include "TOS.h"
|
|
||||||
|
|
||||||
long long getlocal_int(context* cont, int id)
|
|
||||||
{
|
|
||||||
long long result;
|
|
||||||
result = (cont->locals)[id].i_data;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
double getlocal_double(context* cont, int id)
|
|
||||||
{
|
|
||||||
double result;
|
|
||||||
result = (cont->locals)[id].d_data;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
char* getlocal_string(context* cont, int id)
|
|
||||||
{
|
|
||||||
char* result;
|
|
||||||
result = (cont->locals)[id].s_data;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
void putlocal_int(long long* num, context* cont, int id)
|
|
||||||
{
|
|
||||||
memmove((cont->locals)+id, num, sizeof (long long));
|
|
||||||
}
|
|
||||||
|
|
||||||
void putlocal_double(double* num, context* cont, int id)
|
|
||||||
{
|
|
||||||
memmove((cont->locals)+id, num, sizeof(double));
|
|
||||||
}
|
|
||||||
|
|
||||||
void putlocal_string(char* str, context* cont, int id)
|
|
||||||
{
|
|
||||||
memmove((cont->locals)+id, str, sizeof(int*));
|
|
||||||
}
|
|
||||||
|
|
||||||
void args_to_local(context* cont, func** hash)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
long long tmp;
|
|
||||||
for (i=0; i<(hash[cont->id]->count_args); i++)
|
|
||||||
{
|
|
||||||
tmp = pop_int();
|
|
||||||
memmove(&((cont->locals)[i]), &tmp, sizeof(long long));
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,14 +0,0 @@
|
||||||
#ifndef LOCALVARS_H
|
|
||||||
#define LOCALVARS_H
|
|
||||||
#include "Context.h"
|
|
||||||
|
|
||||||
long long getlocal_int(context*, int);
|
|
||||||
double getlocal_double(context*, int);
|
|
||||||
char* getlocal_string(context*, int);
|
|
||||||
|
|
||||||
void putlocal_int(long long*, context*, int);
|
|
||||||
void putlocal_double(double*, context*, int);
|
|
||||||
void putlocal_string(char*, context*, int);
|
|
||||||
|
|
||||||
void args_to_local(context*, func**);
|
|
||||||
#endif
|
|
623
VaninVM/Main.c
623
VaninVM/Main.c
|
@ -1,623 +0,0 @@
|
||||||
#include "OpCode.h"
|
|
||||||
|
|
||||||
#include "IOcode.h"
|
|
||||||
#include "CodeHeader.h"
|
|
||||||
|
|
||||||
#include "TOS.h"
|
|
||||||
#include "Context.h"
|
|
||||||
#include "ReturnStack.h"
|
|
||||||
#include "LocalVars.h"
|
|
||||||
|
|
||||||
|
|
||||||
long long cmp_int(long long* a, long long* b);
|
|
||||||
double cmp_double(double* a, double* b);
|
|
||||||
int run_interpreter(char* filename);
|
|
||||||
|
|
||||||
int main(int argc, char** argv)
|
|
||||||
{
|
|
||||||
int return_code;
|
|
||||||
if (argc<2)
|
|
||||||
{
|
|
||||||
printf("%s", "File is not specified");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return_code = run_interpreter(argv[1]);
|
|
||||||
return return_code;
|
|
||||||
}
|
|
||||||
|
|
||||||
int run_interpreter(char* filename)
|
|
||||||
{
|
|
||||||
//ByteCode Variables
|
|
||||||
FILE* input;
|
|
||||||
|
|
||||||
//ExecutionProcess Variables
|
|
||||||
double d1, d2;
|
|
||||||
long long i1, i2;
|
|
||||||
unsigned short s1;
|
|
||||||
short s2;
|
|
||||||
char *code;
|
|
||||||
int ip, startfunc;
|
|
||||||
|
|
||||||
//ConstSection Variables
|
|
||||||
int const_count;
|
|
||||||
char** const_index;
|
|
||||||
|
|
||||||
//CodeSection Variables
|
|
||||||
func** phash_table;
|
|
||||||
context* current_context;
|
|
||||||
|
|
||||||
//Running Variable
|
|
||||||
int exec_status = 1;
|
|
||||||
|
|
||||||
fopen_s(&input, filename, "rb");
|
|
||||||
//const_pull
|
|
||||||
if (read_constant(input, &const_count, &const_index) != 0)
|
|
||||||
return 1;
|
|
||||||
//code_pull
|
|
||||||
startfunc = read_bytecode(input, &phash_table);
|
|
||||||
fclose(input);
|
|
||||||
|
|
||||||
initTOS(3000);
|
|
||||||
|
|
||||||
initRStack(1000);
|
|
||||||
ip = 0;
|
|
||||||
|
|
||||||
current_context = create_context(startfunc, phash_table, &code);
|
|
||||||
|
|
||||||
node_last = NULL;
|
|
||||||
|
|
||||||
while (exec_status)
|
|
||||||
{
|
|
||||||
switch (code[ip++])
|
|
||||||
{
|
|
||||||
case INVALID:
|
|
||||||
//DO(INVALID, "Invalid instruction.", 1)
|
|
||||||
break;
|
|
||||||
case DLOAD:
|
|
||||||
//DO(DLOAD, "Load double on TOS, inlined into insn stream.", 9)
|
|
||||||
d1 = *((double*)(code+ip));
|
|
||||||
push_double(d1);
|
|
||||||
ip+=8; break;
|
|
||||||
case ILOAD:
|
|
||||||
//DO(ILOAD, "Load int on TOS, inlined into insn stream.", 9)
|
|
||||||
i1 = *((long long*)(code+ip));
|
|
||||||
push_int(i1);
|
|
||||||
ip+=8; break;
|
|
||||||
case SLOAD:
|
|
||||||
s1 = *((short*)(code+ip));
|
|
||||||
push_int((long long)(const_index[s1]));
|
|
||||||
ip+=2; break;
|
|
||||||
case DLOAD0:
|
|
||||||
// DO(DLOAD0, "Load double 0 on TOS.", 1)
|
|
||||||
push_double(0);
|
|
||||||
break;
|
|
||||||
case ILOAD0:
|
|
||||||
//DO(ILOAD0, "Load int 0 on TOS.", 1)
|
|
||||||
push_int(0);
|
|
||||||
break;
|
|
||||||
case SLOAD0:
|
|
||||||
//DO(SLOAD0, "Load empty string on TOS.", 1)
|
|
||||||
push_int((long long)(const_index[0]));
|
|
||||||
break;
|
|
||||||
case DLOAD1:
|
|
||||||
//DO(DLOAD1, "Load double 1 on TOS.", 1)
|
|
||||||
push_double(1);
|
|
||||||
break;
|
|
||||||
case ILOAD1:
|
|
||||||
//DO(ILOAD1, "Load int 1 on TOS.", 1)
|
|
||||||
push_int(1);
|
|
||||||
break;
|
|
||||||
case DLOADM1:
|
|
||||||
//DO(DLOADM1, "Load double -1 on TOS.", 1)
|
|
||||||
push_double(-1);
|
|
||||||
break;
|
|
||||||
case ILOADM1:
|
|
||||||
//DO(ILOADM1, "Load int -1 on TOS.", 1)
|
|
||||||
push_int(-1);
|
|
||||||
break;
|
|
||||||
case DADD:
|
|
||||||
//DO(DADD, "Add 2 doubles on TOS, push value back.", 1)
|
|
||||||
d1 = pop_double();
|
|
||||||
d2 = pop_double();
|
|
||||||
d1 += d2;
|
|
||||||
push_double(d1);
|
|
||||||
break;
|
|
||||||
case IADD:
|
|
||||||
//DO(IADD, "Add 2 ints on TOS, push value back.", 1)
|
|
||||||
i1 = pop_int();
|
|
||||||
i2 = pop_int();
|
|
||||||
i1 += i2;
|
|
||||||
push_int(i1);
|
|
||||||
break;
|
|
||||||
case DSUB:
|
|
||||||
//DO(DSUB, "Subtract 2 doubles on TOS (lower from upper), push value back.", 1)
|
|
||||||
d1 = pop_double();
|
|
||||||
d2 = pop_double();
|
|
||||||
d1 -= d2;
|
|
||||||
push_double(d1);
|
|
||||||
break;
|
|
||||||
case ISUB:
|
|
||||||
//DO(ISUB, "Subtract 2 ints on TOS (lower from upper), push value back.", 1)
|
|
||||||
i1 = pop_int();
|
|
||||||
i2 = pop_int();
|
|
||||||
i1 -= i2;
|
|
||||||
push_int(i1);
|
|
||||||
break;
|
|
||||||
case DMUL:
|
|
||||||
//DO(DMUL, "Multiply 2 doubles on TOS, push value back.", 1)
|
|
||||||
d1 = pop_double();
|
|
||||||
d2 = pop_double();
|
|
||||||
d1 *= d2;
|
|
||||||
push_double(d1);
|
|
||||||
break;
|
|
||||||
case IMUL:
|
|
||||||
//DO(IMUL, "Multiply 2 ints on TOS, push value back.", 1)
|
|
||||||
i1 = pop_int();
|
|
||||||
i2 = pop_int();
|
|
||||||
i1 *= i2;
|
|
||||||
push_int(i1);
|
|
||||||
break;
|
|
||||||
case DDIV:
|
|
||||||
//DO(DDIV, "Divide 2 doubles on TOS (upper to lower), push value back.", 1)
|
|
||||||
d1 = pop_double();
|
|
||||||
d2 = pop_double();
|
|
||||||
d1 = d1/d2;
|
|
||||||
push_double(d1);
|
|
||||||
break;
|
|
||||||
case IDIV:
|
|
||||||
//DO(IDIV, "Divide 2 ints on TOS (upper to lower), push value back.", 1)
|
|
||||||
i1 = pop_int();
|
|
||||||
i2 = pop_int();
|
|
||||||
i1 = i1/i2;
|
|
||||||
push_int(i1);
|
|
||||||
break;
|
|
||||||
case IMOD:
|
|
||||||
//DO(IMOD, "Modulo operation on 2 ints on TOS (upper to lower), push value back.", 1)
|
|
||||||
i1 = pop_int();
|
|
||||||
i2 = pop_int();
|
|
||||||
i1 = i1 % i2;
|
|
||||||
push_int(i1);
|
|
||||||
break;
|
|
||||||
case DNEG:
|
|
||||||
//DO(DNEG, "Negate double on TOS.", 1)
|
|
||||||
d1 = pop_double();
|
|
||||||
d1 = -d1;
|
|
||||||
push_double(d1);
|
|
||||||
break;
|
|
||||||
case INEG:
|
|
||||||
//DO(INEG, "Negate int on TOS.", 1)
|
|
||||||
i1 = pop_int();
|
|
||||||
i1 = - i1;
|
|
||||||
push_int(i1);
|
|
||||||
break;
|
|
||||||
case IAOR:
|
|
||||||
//DO(IAOR, "Arithmetic OR of 2 ints on TOS, push value back.", 1)
|
|
||||||
i1 = pop_int();
|
|
||||||
i2 = pop_int();
|
|
||||||
i1 = i1 | i2;
|
|
||||||
push_int(i1);
|
|
||||||
break;
|
|
||||||
case IAAND:
|
|
||||||
//DO(IAAND, "Arithmetic AND of 2 ints on TOS, push value back.", 1)
|
|
||||||
i1 = pop_int();
|
|
||||||
i2 = pop_int();
|
|
||||||
i1 = i1 & i2;
|
|
||||||
push_int(i1);
|
|
||||||
break;
|
|
||||||
case IAXOR:
|
|
||||||
//DO(IAXOR, "Arithmetic XOR of 2 ints on TOS, push value back.", 1)
|
|
||||||
i1 = pop_int();
|
|
||||||
i2 = pop_int();
|
|
||||||
i1 = i1 ^ i2;
|
|
||||||
push_int(i1);
|
|
||||||
break;
|
|
||||||
case IPRINT:
|
|
||||||
//DO(IPRINT, "Pop and print integer TOS.", 1)
|
|
||||||
i1 = pop_int();
|
|
||||||
printf("%llu", i1);
|
|
||||||
break;
|
|
||||||
case DPRINT:
|
|
||||||
//DO(DPRINT, "Pop and print double TOS.", 1)
|
|
||||||
d1 = pop_double();
|
|
||||||
printf("%f", d1);
|
|
||||||
break;
|
|
||||||
case SPRINT:
|
|
||||||
//DO(SPRINT, "Pop and print string TOS.", 1)
|
|
||||||
i1 = pop_int();
|
|
||||||
printf("%s", (char*)i1);
|
|
||||||
break;
|
|
||||||
case I2D:
|
|
||||||
//DO(I2D, "Convert int on TOS to double.", 1)
|
|
||||||
i1 = pop_int();
|
|
||||||
d1 = (double)i1;
|
|
||||||
push_double(d1);
|
|
||||||
break;
|
|
||||||
case D2I:
|
|
||||||
//DO(D2I, "Convert double on TOS to int.", 1)
|
|
||||||
d1 = pop_double();
|
|
||||||
i1 = (int)d1;
|
|
||||||
push_int(i1);
|
|
||||||
break;
|
|
||||||
case S2I:
|
|
||||||
//DO(S2I, "Convert string on TOS to int.", 1)
|
|
||||||
break;
|
|
||||||
case SWAP:
|
|
||||||
//DO(SWAP, "Swap 2 topmost values.", 1)
|
|
||||||
i1 = pop_int();
|
|
||||||
i2 = pop_int();
|
|
||||||
push_int(i1);
|
|
||||||
push_int(i2);
|
|
||||||
break;
|
|
||||||
case POP:
|
|
||||||
//DO(POP, "Remove topmost value.", 1)
|
|
||||||
TOS--;
|
|
||||||
break;
|
|
||||||
case LOADDVAR0:
|
|
||||||
//DO(LOADDVAR0, "Load double from variable 0, push on TOS.", 1)
|
|
||||||
d1 = getlocal_double(current_context, 0);
|
|
||||||
push_double(d1);
|
|
||||||
break;
|
|
||||||
case LOADDVAR1:
|
|
||||||
//DO(LOADDVAR1, "Load double from variable 1, push on TOS.", 1)
|
|
||||||
d1 = getlocal_double(current_context, 1);
|
|
||||||
push_double(d1);
|
|
||||||
break;
|
|
||||||
case LOADDVAR2:
|
|
||||||
//DO(LOADDVAR2, "Load double from variable 2, push on TOS.", 1)
|
|
||||||
d1 = getlocal_double(current_context, 2);
|
|
||||||
push_double(d1);
|
|
||||||
break;
|
|
||||||
case LOADDVAR3:
|
|
||||||
//DO(LOADDVAR3, "Load double from variable 3, push on TOS.", 1)
|
|
||||||
d1 = getlocal_double(current_context, 3);
|
|
||||||
push_double(d1);
|
|
||||||
break;
|
|
||||||
case LOADIVAR0:
|
|
||||||
//DO(LOADIVAR0, "Load int from variable 0, push on TOS.", 1)
|
|
||||||
i1 = getlocal_int(current_context, 0);
|
|
||||||
push_int(i1);
|
|
||||||
break;
|
|
||||||
case LOADIVAR1:
|
|
||||||
//DO(LOADIVAR1, "Load int from variable 1, push on TOS.", 1)
|
|
||||||
i1 = getlocal_int(current_context, 1);
|
|
||||||
push_int(i1);
|
|
||||||
break;
|
|
||||||
case LOADIVAR2:
|
|
||||||
//DO(LOADIVAR2, "Load int from variable 2, push on TOS.", 1)
|
|
||||||
i1 = getlocal_int(current_context, 2);
|
|
||||||
push_int(i1);
|
|
||||||
break;
|
|
||||||
case LOADIVAR3:
|
|
||||||
//DO(LOADIVAR3, "Load int from variable 3, push on TOS.", 1)
|
|
||||||
i1 = getlocal_int(current_context, 3);
|
|
||||||
push_int(i1);
|
|
||||||
break;
|
|
||||||
case LOADSVAR0:
|
|
||||||
//DO(LOADSVAR0, "Load string from variable 0, push on TOS.", 1)
|
|
||||||
i1 = (long long)getlocal_string(current_context, 0);
|
|
||||||
push_int(i1);
|
|
||||||
break;
|
|
||||||
case LOADSVAR1:
|
|
||||||
//DO(LOADSVAR1, "Load string from variable 1, push on TOS.", 1)
|
|
||||||
i1 = (long long)getlocal_string(current_context, 1);
|
|
||||||
push_int(i1);
|
|
||||||
break;
|
|
||||||
case LOADSVAR2:
|
|
||||||
//DO(LOADSVAR2, "Load string from variable 2, push on TOS.", 1)
|
|
||||||
i1 = (long long)getlocal_string(current_context, 2);
|
|
||||||
push_int(i1);
|
|
||||||
break;
|
|
||||||
case LOADSVAR3:
|
|
||||||
//DO(LOADSVAR3, "Load string from variable 3, push on TOS.", 1)
|
|
||||||
i1 = (long long)getlocal_string(current_context, 3);
|
|
||||||
push_int(i1);
|
|
||||||
break;
|
|
||||||
case STOREDVAR0:
|
|
||||||
//DO(STOREDVAR0, "Pop TOS and store to double variable 0.", 1)
|
|
||||||
d1 = pop_double();
|
|
||||||
putlocal_double(&d1, current_context, 0);
|
|
||||||
break;
|
|
||||||
case STOREDVAR1:
|
|
||||||
//DO(STOREDVAR1, "Pop TOS and store to double variable 1.", 1)
|
|
||||||
d1 = pop_double();
|
|
||||||
putlocal_double(&d1, current_context, 1);
|
|
||||||
break;
|
|
||||||
case STOREDVAR2:
|
|
||||||
//DO(STOREDVAR2, "Pop TOS and store to double variable 2.", 1)
|
|
||||||
d1 = pop_double();
|
|
||||||
putlocal_double(&d1, current_context, 2);
|
|
||||||
break;
|
|
||||||
case STOREDVAR3:
|
|
||||||
//DO(STOREDVAR3, "Pop TOS and store to double variable 3.", 1)
|
|
||||||
d1 = pop_double();
|
|
||||||
putlocal_double(&d1, current_context, 3);
|
|
||||||
break;
|
|
||||||
case STOREIVAR0:
|
|
||||||
//DO(STOREIVAR0, "Pop TOS and store to int variable 0.", 1)
|
|
||||||
i1 = pop_int();
|
|
||||||
putlocal_int(&i1, current_context, 0);
|
|
||||||
break;
|
|
||||||
case STOREIVAR1:
|
|
||||||
//DO(STOREIVAR1, "Pop TOS and store to int variable 1.", 1)
|
|
||||||
i1 = pop_int();
|
|
||||||
putlocal_int(&i1, current_context, 1);
|
|
||||||
break;
|
|
||||||
case STOREIVAR2:
|
|
||||||
//DO(STOREIVAR2, "Pop TOS and store to int variable 2.", 1)
|
|
||||||
i1 = pop_int();
|
|
||||||
putlocal_int(&i1, current_context, 2);
|
|
||||||
break;
|
|
||||||
case STOREIVAR3:
|
|
||||||
//DO(STOREIVAR3, "Pop TOS and store to int variable 3.", 1)
|
|
||||||
i1 = pop_int();
|
|
||||||
putlocal_int(&i1, current_context, 3);
|
|
||||||
break;
|
|
||||||
case STORESVAR0:
|
|
||||||
//DO(STORESVAR0, "Pop TOS and store to string variable 0.", 1)
|
|
||||||
i1 = pop_int();
|
|
||||||
putlocal_string((char*)&i1, current_context, 0);
|
|
||||||
break;
|
|
||||||
case STORESVAR1:
|
|
||||||
//DO(STORESVAR1, "Pop TOS and store to string variable 1.", 1)
|
|
||||||
i1 = pop_int();
|
|
||||||
putlocal_string((char*)&i1, current_context, 1);
|
|
||||||
break;
|
|
||||||
case STORESVAR2:
|
|
||||||
//DO(STORESVAR2, "Pop TOS and store to string variable 2.", 1)
|
|
||||||
i1 = pop_int();
|
|
||||||
putlocal_string((char*)&i1, current_context, 2);
|
|
||||||
break;
|
|
||||||
case STORESVAR3:
|
|
||||||
//DO(STORESVAR3, "Pop TOS and store to string variable 3.", 1)
|
|
||||||
i1 = pop_int();
|
|
||||||
putlocal_string((char*)&i1, current_context, 3);
|
|
||||||
break;
|
|
||||||
case LOADDVAR:
|
|
||||||
//DO(LOADDVAR, "Load double from variable, whose 2-byte is id inlined to insn stream, push on TOS.", 3)
|
|
||||||
s1 = *((unsigned short*)(code+ip));
|
|
||||||
d1 = getlocal_double(current_context, s1);
|
|
||||||
push_double(d1);
|
|
||||||
ip+=2; break;
|
|
||||||
case LOADIVAR:
|
|
||||||
//DO(LOADIVAR, "Load int from variable, whose 2-byte id is inlined to insn stream, push on TOS.", 3)
|
|
||||||
s1 = *((unsigned short*)(code+ip));
|
|
||||||
i1 = getlocal_int(current_context, s1);
|
|
||||||
push_int(i1);
|
|
||||||
ip+=2; break;
|
|
||||||
case LOADSVAR:
|
|
||||||
//DO(LOADSVAR, "Load string from variable, whose 2-byte id is inlined to insn stream, push on TOS.", 3)
|
|
||||||
s1 = *((unsigned short*)(code+ip));
|
|
||||||
i1 = (long long)getlocal_string(current_context, s1);
|
|
||||||
push_int(i1);
|
|
||||||
ip+=2; break;
|
|
||||||
case STOREDVAR:
|
|
||||||
//DO(STOREDVAR, "Pop TOS and store to double variable, whose 2-byte id is inlined to insn stream.", 3)
|
|
||||||
s1 = *((unsigned short*)(code+ip));
|
|
||||||
d1 = pop_double();
|
|
||||||
putlocal_double(&d1, current_context, s1);
|
|
||||||
ip+=2; break;
|
|
||||||
case STOREIVAR:
|
|
||||||
//DO(STOREIVAR, "Pop TOS and store to int variable, whose 2-byte id is inlined to insn stream.", 3)
|
|
||||||
s1 = *((unsigned short*)(code+ip));
|
|
||||||
i1 = pop_int();
|
|
||||||
putlocal_int(&i1, current_context, s1);
|
|
||||||
ip+=2; break;
|
|
||||||
case STORESVAR:
|
|
||||||
//DO(STORESVAR, "Pop TOS and store to string variable, whose 2-byte id is inlined to insn stream.", 3)
|
|
||||||
s1 = *((short*)(code+ip));
|
|
||||||
i1 = pop_int();
|
|
||||||
putlocal_string((char*)&i1, current_context, s1);
|
|
||||||
ip+=2; break;
|
|
||||||
case LOADCTXDVAR:
|
|
||||||
//DO(LOADCTXDVAR, "Load double from variable, whose 2-byte context and 2-byte id inlined to insn stream, push on TOS.", 5)
|
|
||||||
s1 = *((unsigned short*)(code+ip));
|
|
||||||
ip+=2;
|
|
||||||
s2 = *((short*)(code+ip));
|
|
||||||
if (find_context(s1) != NULL)
|
|
||||||
{
|
|
||||||
d1 = getlocal_double(find_context(s1), s2);
|
|
||||||
push_double(d1);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
printf("%s", "Context Not Found");
|
|
||||||
exec_status = 0;
|
|
||||||
}
|
|
||||||
ip+=2; break;
|
|
||||||
case LOADCTXIVAR:
|
|
||||||
//DO(LOADCTXIVAR, "Load int from variable, whose 2-byte context and 2-byte id is inlined to insn stream, push on TOS.", 5)
|
|
||||||
s1 = *((unsigned short*)(code+ip));
|
|
||||||
ip+=2;
|
|
||||||
s2 = *((short*)(code+ip));
|
|
||||||
if (find_context(s1) != NULL)
|
|
||||||
{
|
|
||||||
i1 = getlocal_int(find_context(s1), s2);
|
|
||||||
push_int(i1);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
printf("%s", "Context Not Found");
|
|
||||||
exec_status = 0;
|
|
||||||
}
|
|
||||||
ip+=2; break;
|
|
||||||
case LOADCTXSVAR:
|
|
||||||
//DO(LOADCTXSVAR, "Load string from variable, whose 2-byte context and 2-byte id is inlined to insn stream, push on TOS.", 5)
|
|
||||||
s1 = *((unsigned short*)(code+ip));
|
|
||||||
ip+=2;
|
|
||||||
s2 = *((short*)(code+ip));
|
|
||||||
if (find_context(s1) != NULL)
|
|
||||||
{
|
|
||||||
i1 = (long long)getlocal_string(find_context(s1), s2);
|
|
||||||
push_double(i1);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
printf("%s", "Context Not Found");
|
|
||||||
exec_status = 0;
|
|
||||||
}
|
|
||||||
ip+=2; break;
|
|
||||||
case STORECTXDVAR:
|
|
||||||
//DO(STORECTXDVAR, "Pop TOS and store to double variable, whose 2-byte context and 2-byte id is inlined to insn stream.", 5)
|
|
||||||
s1 = *((unsigned short*)(code+ip));
|
|
||||||
ip+=2;
|
|
||||||
s2 = *((short*)(code+ip));
|
|
||||||
d1 = pop_double();
|
|
||||||
if (find_context(s1) != NULL)
|
|
||||||
{
|
|
||||||
putlocal_double(&d1, find_context(s1), s2);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
printf("%s", "Context Not Found");
|
|
||||||
exec_status = 0;
|
|
||||||
}
|
|
||||||
ip+=2; break;
|
|
||||||
case STORECTXIVAR:
|
|
||||||
//DO(STORECTXIVAR, "Pop TOS and store to int variable, whose 2-byte context and 2-byte id is inlined to insn stream.", 5)
|
|
||||||
s1 = *((unsigned short*)(code+ip));
|
|
||||||
ip+=2;
|
|
||||||
s2 = *((short*)(code+ip));
|
|
||||||
i1 = pop_int();
|
|
||||||
if (find_context(s1) != NULL)
|
|
||||||
{
|
|
||||||
putlocal_int(&i1, find_context(s1), s2);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
printf("%s", "Context Not Found");
|
|
||||||
exec_status = 0;
|
|
||||||
}
|
|
||||||
ip+=2; break;
|
|
||||||
case STORECTXSVAR:
|
|
||||||
//DO(STORECTXSVAR, "Pop TOS and store to string variable, whose 2-byte context and 2-byte id is inlined to insn stream.", 5)
|
|
||||||
s1 = *((unsigned short*)(code+ip));
|
|
||||||
ip+=2;
|
|
||||||
s2 = *((short*)(code+ip));
|
|
||||||
i1 = pop_int();
|
|
||||||
if (find_context(s1) != NULL)
|
|
||||||
{
|
|
||||||
putlocal_string((char*)&d1, find_context(s1), s2);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
printf("%s", "Context Not Found");
|
|
||||||
exec_status = 0;
|
|
||||||
}
|
|
||||||
ip+=2; break;
|
|
||||||
case DCMP:
|
|
||||||
//DO(DCMP, "Compare 2 topmost doubles, pushing libc-style comparator value cmp(upper, lower) as integer.", 1)
|
|
||||||
d1 = TOS[tp-1];
|
|
||||||
d2 = TOS[tp-2];
|
|
||||||
push_double(cmp_double(&d1, &d2));
|
|
||||||
break;
|
|
||||||
case ICMP:
|
|
||||||
//DO(ICMP, "Compare 2 topmost ints, pushing libc-style comparator value cmp(upper, lower) as integer.", 1)
|
|
||||||
i1 = get_int(tp-1);
|
|
||||||
i2 = get_int(tp-2);
|
|
||||||
push_int(cmp_int(&i1, &i2));
|
|
||||||
break;
|
|
||||||
case JA:
|
|
||||||
//DO(JA, "Jump always, next two bytes - signed offset of jump destination.", 3)
|
|
||||||
s2 = *((short*)(code+ip));
|
|
||||||
ip += (2+s2); break;
|
|
||||||
case IFICMPNE:
|
|
||||||
// DO(IFICMPNE, "Compare two topmost integers and jump if upper != lower, next two bytes - signed offset of jump destination.", 3)
|
|
||||||
s2 = *((short*)(code+ip));
|
|
||||||
ip+=2;
|
|
||||||
i1 = get_int(tp-1);
|
|
||||||
i2 = get_int(tp-2);
|
|
||||||
if (i1 != i2)
|
|
||||||
ip += s2;
|
|
||||||
break;
|
|
||||||
case IFICMPE:
|
|
||||||
//DO(IFICMPE, "Compare two topmost integers and jump if upper == lower, next two bytes - signed offset of jump destination.", 3)
|
|
||||||
s2 = *((short*)(code+ip));
|
|
||||||
ip+=2;
|
|
||||||
i1 = get_int(tp-1);
|
|
||||||
i2 = get_int(tp-2);
|
|
||||||
if (i1 == i2)
|
|
||||||
ip += s2;
|
|
||||||
break;
|
|
||||||
case IFICMPG:
|
|
||||||
//DO(IFICMPG, "Compare two topmost integers and jump if upper > lower, next two bytes - signed offset of jump destination.", 3)
|
|
||||||
s2 = *((short*)(code+ip));
|
|
||||||
ip+=2;
|
|
||||||
i1 = get_int(tp-1);
|
|
||||||
i2 = get_int(tp-2);
|
|
||||||
if (i1 > i2)
|
|
||||||
ip += s2;
|
|
||||||
break;
|
|
||||||
case IFICMPGE:
|
|
||||||
//DO(IFICMPGE, "Compare two topmost integers and jump if upper >= lower, next two bytes - signed offset of jump destination.", 3)
|
|
||||||
s2 = *((short*)(code+ip));
|
|
||||||
ip+=2;
|
|
||||||
i1 = get_int(tp-1);
|
|
||||||
i2 = get_int(tp-2);
|
|
||||||
if (i1 >= i2)
|
|
||||||
ip += s2;
|
|
||||||
break;
|
|
||||||
case IFICMPL:
|
|
||||||
//DO(IFICMPL, "Compare two topmost integers and jump if upper < lower, next two bytes - signed offset of jump destination.", 3)
|
|
||||||
s2 = *((short*)(code+ip));
|
|
||||||
ip+=2;
|
|
||||||
i1 = get_int(tp-1);
|
|
||||||
i2 = get_int(tp-2);
|
|
||||||
if (i1 < i2)
|
|
||||||
ip += s2;
|
|
||||||
break;
|
|
||||||
case IFICMPLE:
|
|
||||||
//DO(IFICMPLE, "Compare two topmost integers and jump if upper <= lower, next two bytes - signed offset of jump destination.", 3)
|
|
||||||
s2 = *((short*)(code+ip));
|
|
||||||
ip+=2;
|
|
||||||
i1 = get_int(tp-1);
|
|
||||||
i2 = get_int(tp-2);
|
|
||||||
if (i1 <= i2)
|
|
||||||
ip += s2;
|
|
||||||
break;
|
|
||||||
case DUMP:
|
|
||||||
//DO(DUMP, "Dump value on TOS, without removing it.", 1)
|
|
||||||
i1 = get_int(tp-1);
|
|
||||||
d1 = TOS[tp-1];
|
|
||||||
printf("TOS: Double:%e Integer:%llu Hex:%#08llx", d1, i1, i1);
|
|
||||||
break;
|
|
||||||
case STOP:
|
|
||||||
//DO(STOP, "Stop execution.", 1)
|
|
||||||
exec_status = 0;
|
|
||||||
break;
|
|
||||||
case CALL:
|
|
||||||
//DO(CALL, "Call function, next two bytes - unsigned function id.", 3)
|
|
||||||
s1 = *((unsigned short*)(code+ip));
|
|
||||||
ip+=2; push_ret(ip);
|
|
||||||
push_context(current_context);
|
|
||||||
current_context = create_context(s1, phash_table, &code);
|
|
||||||
args_to_local(current_context, phash_table);
|
|
||||||
ip = 0; break;
|
|
||||||
case RETURN:
|
|
||||||
//DO(RETURN, "Return to call location", 1)
|
|
||||||
remove_context(current_context);
|
|
||||||
current_context = pop_context();
|
|
||||||
code = phash_table[current_context->id]->code;
|
|
||||||
ip = pop_ret(); break;
|
|
||||||
case BREAK:
|
|
||||||
//DO(BREAK, "Breakpoint for the debugger.", 1)
|
|
||||||
getchar();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
remove_context(current_context);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
double cmp_double(long long* a, long long* b)
|
|
||||||
{
|
|
||||||
if (*a == *b) return 0;
|
|
||||||
else if (*a > *b) return 1;
|
|
||||||
else return -1;
|
|
||||||
}
|
|
||||||
long long cmp_int(long long* a, long long* b)
|
|
||||||
{
|
|
||||||
if (*a == *b) return 0;
|
|
||||||
else if (*a > *b) return 1;
|
|
||||||
else return -1;
|
|
||||||
}
|
|
|
@ -1,89 +0,0 @@
|
||||||
#ifndef OPCODE_H
|
|
||||||
#define OPCODE_H
|
|
||||||
enum opcode
|
|
||||||
{
|
|
||||||
INVALID,
|
|
||||||
DLOAD,
|
|
||||||
ILOAD,
|
|
||||||
SLOAD,
|
|
||||||
DLOAD0,
|
|
||||||
ILOAD0,
|
|
||||||
SLOAD0,
|
|
||||||
DLOAD1,
|
|
||||||
ILOAD1,
|
|
||||||
DLOADM1,
|
|
||||||
ILOADM1,
|
|
||||||
DADD,
|
|
||||||
IADD,
|
|
||||||
DSUB,
|
|
||||||
ISUB,
|
|
||||||
DMUL,
|
|
||||||
IMUL,
|
|
||||||
DDIV,
|
|
||||||
IDIV,
|
|
||||||
IMOD,
|
|
||||||
DNEG,
|
|
||||||
INEG,
|
|
||||||
IAOR,
|
|
||||||
IAAND,
|
|
||||||
IAXOR,
|
|
||||||
IPRINT,
|
|
||||||
DPRINT,
|
|
||||||
SPRINT,
|
|
||||||
I2D,
|
|
||||||
D2I,
|
|
||||||
S2I,
|
|
||||||
SWAP,
|
|
||||||
POP,
|
|
||||||
LOADDVAR0,
|
|
||||||
LOADDVAR1,
|
|
||||||
LOADDVAR2,
|
|
||||||
LOADDVAR3,
|
|
||||||
LOADIVAR0,
|
|
||||||
LOADIVAR1,
|
|
||||||
LOADIVAR2,
|
|
||||||
LOADIVAR3,
|
|
||||||
LOADSVAR0,
|
|
||||||
LOADSVAR1,
|
|
||||||
LOADSVAR2,
|
|
||||||
LOADSVAR3,
|
|
||||||
STOREDVAR0,
|
|
||||||
STOREDVAR1,
|
|
||||||
STOREDVAR2,
|
|
||||||
STOREDVAR3,
|
|
||||||
STOREIVAR0,
|
|
||||||
STOREIVAR1,
|
|
||||||
STOREIVAR2,
|
|
||||||
STOREIVAR3,
|
|
||||||
STORESVAR0,
|
|
||||||
STORESVAR1,
|
|
||||||
STORESVAR2,
|
|
||||||
STORESVAR3,
|
|
||||||
LOADDVAR,
|
|
||||||
LOADIVAR,
|
|
||||||
LOADSVAR,
|
|
||||||
STOREDVAR,
|
|
||||||
STOREIVAR,
|
|
||||||
STORESVAR,
|
|
||||||
LOADCTXDVAR,
|
|
||||||
LOADCTXIVAR,
|
|
||||||
LOADCTXSVAR,
|
|
||||||
STORECTXDVAR,
|
|
||||||
STORECTXIVAR,
|
|
||||||
STORECTXSVAR,
|
|
||||||
DCMP,
|
|
||||||
ICMP,
|
|
||||||
JA,
|
|
||||||
IFICMPNE,
|
|
||||||
IFICMPE,
|
|
||||||
IFICMPG,
|
|
||||||
IFICMPGE,
|
|
||||||
IFICMPL,
|
|
||||||
IFICMPLE,
|
|
||||||
DUMP,
|
|
||||||
STOP,
|
|
||||||
CALL,
|
|
||||||
RETURN,
|
|
||||||
BREAK
|
|
||||||
};
|
|
||||||
#endif
|
|
|
@ -1,20 +0,0 @@
|
||||||
#include <malloc.h>
|
|
||||||
#include "ReturnStack.h"
|
|
||||||
|
|
||||||
void push_ret(int num)
|
|
||||||
{
|
|
||||||
RStack[rp++] = num;
|
|
||||||
}
|
|
||||||
|
|
||||||
int pop_ret()
|
|
||||||
{
|
|
||||||
int num = RStack[--rp];
|
|
||||||
return num;
|
|
||||||
}
|
|
||||||
|
|
||||||
int initRStack(int size)
|
|
||||||
{
|
|
||||||
RStack = (int*)calloc(1, size);
|
|
||||||
rp = 0;
|
|
||||||
return 0;
|
|
||||||
}
|
|
|
@ -1,9 +0,0 @@
|
||||||
#ifndef RETURNSTACK_H
|
|
||||||
#define RETURNSTACK_H
|
|
||||||
|
|
||||||
int* RStack;
|
|
||||||
int rp;
|
|
||||||
int initRStack(int);
|
|
||||||
void push_ret(int);
|
|
||||||
int pop_ret();
|
|
||||||
#endif
|
|
|
@ -1,41 +0,0 @@
|
||||||
#include <malloc.h>
|
|
||||||
#include "TOS.h"
|
|
||||||
|
|
||||||
void push_int(long long num)
|
|
||||||
{
|
|
||||||
tos_num number;
|
|
||||||
number.num_i = num;
|
|
||||||
TOS[tp++] = number.num_d;
|
|
||||||
}
|
|
||||||
|
|
||||||
long long pop_int()
|
|
||||||
{
|
|
||||||
tos_num number;
|
|
||||||
number.num_d = TOS[--tp];
|
|
||||||
return number.num_i;
|
|
||||||
}
|
|
||||||
|
|
||||||
long long get_int(int id)
|
|
||||||
{
|
|
||||||
tos_num number;
|
|
||||||
number.num_d = TOS[id];
|
|
||||||
return number.num_i;
|
|
||||||
}
|
|
||||||
|
|
||||||
void push_double(double num)
|
|
||||||
{
|
|
||||||
TOS[tp++] = num;
|
|
||||||
}
|
|
||||||
|
|
||||||
double pop_double()
|
|
||||||
{
|
|
||||||
double num = TOS[--tp];
|
|
||||||
return num;
|
|
||||||
}
|
|
||||||
|
|
||||||
int initTOS(int count)
|
|
||||||
{
|
|
||||||
TOS = (double*)calloc(count, sizeof(double*));
|
|
||||||
tp = 0;
|
|
||||||
return 0;
|
|
||||||
}
|
|
|
@ -1,19 +0,0 @@
|
||||||
#ifndef TOS_H
|
|
||||||
#define TOS_H
|
|
||||||
|
|
||||||
typedef union
|
|
||||||
{
|
|
||||||
double num_d;
|
|
||||||
long long num_i;
|
|
||||||
} tos_num;
|
|
||||||
|
|
||||||
double* TOS;
|
|
||||||
int tp;
|
|
||||||
int initTOS(int);
|
|
||||||
void push_int(long long);
|
|
||||||
void push_double(double);
|
|
||||||
long long pop_int();
|
|
||||||
long long get_int(int);
|
|
||||||
double pop_double();
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,85 +0,0 @@
|
||||||
#define FOR_BYTECODES(DO) \
|
|
||||||
?-DO(INVALID, "Invalid instruction.", 1) \
|
|
||||||
+DO(DLOAD, "Load double on TOS, inlined into insn stream.", 9) \
|
|
||||||
+DO(ILOAD, "Load int on TOS, inlined into insn stream.", 9) \
|
|
||||||
+DO(SLOAD, "Load string reference on TOS, next two bytes - constant id.", 3) \
|
|
||||||
+DO(DLOAD0, "Load double 0 on TOS.", 1) \
|
|
||||||
+DO(ILOAD0, "Load int 0 on TOS.", 1) \
|
|
||||||
+DO(SLOAD0, "Load empty string on TOS.", 1) \
|
|
||||||
+DO(DLOAD1, "Load double 1 on TOS.", 1) \
|
|
||||||
+DO(ILOAD1, "Load int 1 on TOS.", 1) \
|
|
||||||
+DO(DLOADM1, "Load double -1 on TOS.", 1) \
|
|
||||||
+DO(ILOADM1, "Load int -1 on TOS.", 1) \
|
|
||||||
+DO(DADD, "Add 2 doubles on TOS, push value back.", 1) \
|
|
||||||
+DO(IADD, "Add 2 ints on TOS, push value back.", 1) \
|
|
||||||
+DO(DSUB, "Subtract 2 doubles on TOS (lower from upper), push value back.", 1) \
|
|
||||||
+DO(ISUB, "Subtract 2 ints on TOS (lower from upper), push value back.", 1) \
|
|
||||||
+DO(DMUL, "Multiply 2 doubles on TOS, push value back.", 1) \
|
|
||||||
+DO(IMUL, "Multiply 2 ints on TOS, push value back.", 1) \
|
|
||||||
+DO(DDIV, "Divide 2 doubles on TOS (upper to lower), push value back.", 1) \
|
|
||||||
+DO(IDIV, "Divide 2 ints on TOS (upper to lower), push value back.", 1) \
|
|
||||||
+DO(IMOD, "Modulo operation on 2 ints on TOS (upper to lower), push value back.", 1) \
|
|
||||||
+DO(DNEG, "Negate double on TOS.", 1) \
|
|
||||||
+DO(INEG, "Negate int on TOS.", 1) \
|
|
||||||
+DO(IAOR, "Arithmetic OR of 2 ints on TOS, push value back.", 1) \
|
|
||||||
+DO(IAAND, "Arithmetic AND of 2 ints on TOS, push value back.", 1) \
|
|
||||||
+DO(IAXOR, "Arithmetic XOR of 2 ints on TOS, push value back.", 1) \
|
|
||||||
+DO(IPRINT, "Pop and print integer TOS.", 1) \
|
|
||||||
+DO(DPRINT, "Pop and print double TOS.", 1) \
|
|
||||||
+DO(SPRINT, "Pop and print string TOS.", 1) \
|
|
||||||
+DO(I2D, "Convert int on TOS to double.", 1) \
|
|
||||||
+DO(D2I, "Convert double on TOS to int.", 1) \
|
|
||||||
+DO(S2I, "Convert string on TOS to int.", 1) \
|
|
||||||
+DO(SWAP, "Swap 2 topmost values.", 1) \
|
|
||||||
+DO(POP, "Remove topmost value.", 1) \
|
|
||||||
+DO(LOADDVAR0, "Load double from variable 0, push on TOS.", 1) \
|
|
||||||
+DO(LOADDVAR1, "Load double from variable 1, push on TOS.", 1) \
|
|
||||||
+DO(LOADDVAR2, "Load double from variable 2, push on TOS.", 1) \
|
|
||||||
+DO(LOADDVAR3, "Load double from variable 3, push on TOS.", 1) \
|
|
||||||
+DO(LOADIVAR0, "Load int from variable 0, push on TOS.", 1) \
|
|
||||||
+DO(LOADIVAR1, "Load int from variable 1, push on TOS.", 1) \
|
|
||||||
+DO(LOADIVAR2, "Load int from variable 2, push on TOS.", 1) \
|
|
||||||
+DO(LOADIVAR3, "Load int from variable 3, push on TOS.", 1) \
|
|
||||||
+DO(LOADSVAR0, "Load string from variable 0, push on TOS.", 1) \
|
|
||||||
+DO(LOADSVAR1, "Load string from variable 1, push on TOS.", 1) \
|
|
||||||
+DO(LOADSVAR2, "Load string from variable 2, push on TOS.", 1) \
|
|
||||||
+DO(LOADSVAR3, "Load string from variable 3, push on TOS.", 1) \
|
|
||||||
+DO(STOREDVAR0, "Pop TOS and store to double variable 0.", 1) \
|
|
||||||
+DO(STOREDVAR1, "Pop TOS and store to double variable 1.", 1) \
|
|
||||||
+DO(STOREDVAR2, "Pop TOS and store to double variable 2.", 1) \
|
|
||||||
+DO(STOREDVAR3, "Pop TOS and store to double variable 3.", 1) \
|
|
||||||
+DO(STOREIVAR0, "Pop TOS and store to int variable 0.", 1) \
|
|
||||||
+DO(STOREIVAR1, "Pop TOS and store to int variable 1.", 1) \
|
|
||||||
+DO(STOREIVAR2, "Pop TOS and store to int variable 2.", 1) \
|
|
||||||
+DO(STOREIVAR3, "Pop TOS and store to int variable 3.", 1) \
|
|
||||||
+DO(STORESVAR0, "Pop TOS and store to string variable 0.", 1) \
|
|
||||||
+DO(STORESVAR1, "Pop TOS and store to string variable 1.", 1) \
|
|
||||||
+DO(STORESVAR2, "Pop TOS and store to string variable 2.", 1) \
|
|
||||||
+DO(STORESVAR3, "Pop TOS and store to string variable 3.", 1) \
|
|
||||||
+DO(LOADDVAR, "Load double from variable, whose 2-byte is id inlined to insn stream, push on TOS.", 3) \
|
|
||||||
+DO(LOADIVAR, "Load int from variable, whose 2-byte id is inlined to insn stream, push on TOS.", 3) \
|
|
||||||
+DO(LOADSVAR, "Load string from variable, whose 2-byte id is inlined to insn stream, push on TOS.", 3) \
|
|
||||||
+DO(STOREDVAR, "Pop TOS and store to double variable, whose 2-byte id is inlined to insn stream.", 3) \
|
|
||||||
+DO(STOREIVAR, "Pop TOS and store to int variable, whose 2-byte id is inlined to insn stream.", 3) \
|
|
||||||
+DO(STORESVAR, "Pop TOS and store to string variable, whose 2-byte id is inlined to insn stream.", 3) \
|
|
||||||
+DO(LOADCTXDVAR, "Load double from variable, whose 2-byte context and 2-byte id inlined to insn stream, push on TOS.", 5) \
|
|
||||||
+DO(LOADCTXIVAR, "Load int from variable, whose 2-byte context and 2-byte id is inlined to insn stream, push on TOS.", 5) \
|
|
||||||
+DO(LOADCTXSVAR, "Load string from variable, whose 2-byte context and 2-byte id is inlined to insn stream, push on TOS.", 5) \
|
|
||||||
+DO(STORECTXDVAR, "Pop TOS and store to double variable, whose 2-byte context and 2-byte id is inlined to insn stream.", 5) \
|
|
||||||
+DO(STORECTXIVAR, "Pop TOS and store to int variable, whose 2-byte context and 2-byte id is inlined to insn stream.", 5) \
|
|
||||||
+DO(STORECTXSVAR, "Pop TOS and store to string variable, whose 2-byte context and 2-byte id is inlined to insn stream.", 5) \
|
|
||||||
?+DO(DCMP, "Compare 2 topmost doubles, pushing libc-style comparator value cmp(upper, lower) as integer.", 1) \
|
|
||||||
?+DO(ICMP, "Compare 2 topmost ints, pushing libc-style comparator value cmp(upper, lower) as integer.", 1) \
|
|
||||||
+DO(JA, "Jump always, next two bytes - signed offset of jump destination.", 3) \
|
|
||||||
+DO(IFICMPNE, "Compare two topmost integers and jump if upper != lower, next two bytes - signed offset of jump destination.", 3) \
|
|
||||||
+DO(IFICMPE, "Compare two topmost integers and jump if upper == lower, next two bytes - signed offset of jump destination.", 3) \
|
|
||||||
+DO(IFICMPG, "Compare two topmost integers and jump if upper > lower, next two bytes - signed offset of jump destination.", 3) \
|
|
||||||
+DO(IFICMPGE, "Compare two topmost integers and jump if upper >= lower, next two bytes - signed offset of jump destination.", 3) \
|
|
||||||
+DO(IFICMPL, "Compare two topmost integers and jump if upper < lower, next two bytes - signed offset of jump destination.", 3) \
|
|
||||||
+DO(IFICMPLE, "Compare two topmost integers and jump if upper <= lower, next two bytes - signed offset of jump destination.", 3) \
|
|
||||||
+DO(DUMP, "Dump value on TOS, without removing it.", 1) \
|
|
||||||
+DO(STOP, "Stop execution.", 1) \
|
|
||||||
+DO(CALL, "Call function, next two bytes - unsigned function id.", 3) \
|
|
||||||
?DO(CALLNATIVE, "Call native function, next two bytes - id of the native function.", 3) \
|
|
||||||
+DO(RETURN, "Return to call location", 1) \
|
|
||||||
?+DO(BREAK, "Breakpoint for the debugger.", 1)
|
|
8
readme.md
Normal file
8
readme.md
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
## TrustGraph
|
||||||
|
|
||||||
|
An implementation of the basic EigenTrust algorithm (http://nlp.stanford.edu/pubs/eigentrust.pdf).
|
||||||
|
|
||||||
|
The algorithm is meant to find the trustworthiness of peers in a distributed system. A (potentially sparse) matrix is populated with values representing how much peers trust each other. A map is also populated with how much trust is extended by default to a sub-set of peers. From that starting point, the algorithm converges on the global trustworthiness of each peer.
|
||||||
|
|
||||||
|
### To-Do
|
||||||
|
This is a first pass. It does not yet implement distributed EigenTrust. There is also some room to improve error handling.
|
142
trustgraph.go
Normal file
142
trustgraph.go
Normal file
|
@ -0,0 +1,142 @@
|
||||||
|
// Package trustGraph is based on EigenTrust
|
||||||
|
// http://nlp.stanford.edu/pubs/eigentrust.pdf
|
||||||
|
package trustGraph
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Group represents a group of peers. Peers need to be given unique, int IDs.
|
||||||
|
// Certainty represents the threshold of RMS change at which the algorithm will
|
||||||
|
// escape. Max is the maximum number of loos the algorithm will perform before
|
||||||
|
// escaping (regardless of certainty). These default to 0.001 and 200
|
||||||
|
// respectivly and generally don't need to be changed.
|
||||||
|
type Group struct {
|
||||||
|
trustGrid map[int]map[int]float32
|
||||||
|
initialTrust map[int]float32
|
||||||
|
Certainty float32
|
||||||
|
Max int
|
||||||
|
Alpha float32
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewGroup is the constructor for Group.
|
||||||
|
func NewGroup() Group {
|
||||||
|
return Group{
|
||||||
|
trustGrid: map[int]map[int]float32{},
|
||||||
|
initialTrust: map[int]float32{},
|
||||||
|
Certainty: 0.001,
|
||||||
|
Max: 200,
|
||||||
|
Alpha: 0.95,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add will add or override a trust relationship. The first arg is the peer who
|
||||||
|
// is extending trust, the second arg is the peer being trusted (by the peer
|
||||||
|
// in the first arg). The 3rd arg is the amount of trust, which must be
|
||||||
|
func (g Group) Add(truster, trusted int, amount float32) (err error) {
|
||||||
|
err = float32InRange(amount)
|
||||||
|
if err == nil {
|
||||||
|
a, ok := g.trustGrid[truster]
|
||||||
|
if !ok {
|
||||||
|
a = map[int]float32{}
|
||||||
|
g.trustGrid[truster] = a
|
||||||
|
}
|
||||||
|
a[trusted] = amount
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// InitialTrust sets the vaulues used to seed the calculation as well as the
|
||||||
|
// corrective factor used by Alpha.
|
||||||
|
func (g Group) InitialTrust(trusted int, amount float32) (err error) {
|
||||||
|
err = float32InRange(amount)
|
||||||
|
if err == nil {
|
||||||
|
g.initialTrust[trusted] = amount
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// float32InRange is a helper to check that a value is 0.0 <= x <= 1.0
|
||||||
|
func float32InRange(x float32) error {
|
||||||
|
if x < 0 {
|
||||||
|
return errors.New("Trust amount cannot be less than 0")
|
||||||
|
}
|
||||||
|
if x > 1 {
|
||||||
|
return errors.New("Trust amount cannot be greater than 1")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compute will approximate the trustworthyness of each peer from the
|
||||||
|
// information known of how much peers trust eachother.
|
||||||
|
// It wil loop, upto g.Max times or until the average difference between
|
||||||
|
// iterations is less than g.Certainty.
|
||||||
|
func (g Group) Compute() map[int]float32 {
|
||||||
|
if len(g.initialTrust) == 0 {
|
||||||
|
return map[int]float32{}
|
||||||
|
}
|
||||||
|
t0 := g.initialTrust //trust map for previous iteration
|
||||||
|
|
||||||
|
for i := 0; i < g.Max; i++ {
|
||||||
|
t1 := *g.computeIteration(&t0) // trust map for current iteration
|
||||||
|
d := avgD(&t0, &t1)
|
||||||
|
t0 = t1
|
||||||
|
if d < g.Certainty {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return t0
|
||||||
|
}
|
||||||
|
|
||||||
|
// computeIteration is broken out of Compute to aid comprehension. It is the
|
||||||
|
// inner loop of Compute. It loops over every value in t (the current trust map)
|
||||||
|
// and looks up how much trust that peer extends to every other peer. The
|
||||||
|
// product of the direct trust and indirect trust
|
||||||
|
func (g Group) computeIteration(t0 *map[int]float32) *map[int]float32 {
|
||||||
|
|
||||||
|
t1 := map[int]float32{}
|
||||||
|
for truster, directTrust := range *t0 {
|
||||||
|
for trusted, indirectTrust := range g.trustGrid[truster] {
|
||||||
|
if trusted != truster {
|
||||||
|
t1[trusted] += directTrust * indirectTrust
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// normalize the trust values
|
||||||
|
// in the EigenTrust paper, this was not done every step, but I prefer to
|
||||||
|
// Not doing it means the diff (d) needs to be normalized in
|
||||||
|
// proportion to the values (because they increase with every iteration)
|
||||||
|
highestTrust := float32(0)
|
||||||
|
for _, v := range t1 {
|
||||||
|
if v > highestTrust {
|
||||||
|
highestTrust = v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//Todo handle highestTrust == 0
|
||||||
|
for i, v := range t1 {
|
||||||
|
t1[i] = (v/highestTrust)*g.Alpha + (1-g.Alpha)*g.initialTrust[i]
|
||||||
|
}
|
||||||
|
|
||||||
|
return &t1
|
||||||
|
}
|
||||||
|
|
||||||
|
// abs is helper to take abs of float32
|
||||||
|
func abs(x float32) float32 {
|
||||||
|
if x < 0 {
|
||||||
|
return -x
|
||||||
|
}
|
||||||
|
return x
|
||||||
|
}
|
||||||
|
|
||||||
|
// avgD is helper to compare 2 maps of float32s and return the average
|
||||||
|
// difference between them
|
||||||
|
func avgD(t0, t1 *map[int]float32) float32 {
|
||||||
|
d := float32(0)
|
||||||
|
for i, v := range *t1 {
|
||||||
|
d += abs(v - (*t0)[i])
|
||||||
|
}
|
||||||
|
d = d / float32(len(*t0))
|
||||||
|
return d
|
||||||
|
}
|
113
trustgraph_test.go
Normal file
113
trustgraph_test.go
Normal file
|
@ -0,0 +1,113 @@
|
||||||
|
package trustGraph
|
||||||
|
|
||||||
|
import (
|
||||||
|
"math"
|
||||||
|
"math/rand"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestBasic(t *testing.T) {
|
||||||
|
g := NewGroup()
|
||||||
|
g.Add(1, 2, 1)
|
||||||
|
g.Add(1, 3, .5)
|
||||||
|
g.Add(2, 1, 1)
|
||||||
|
g.Add(2, 3, .5)
|
||||||
|
g.Add(3, 1, 1)
|
||||||
|
g.Add(3, 2, 1)
|
||||||
|
|
||||||
|
g.InitialTrust(1, 1)
|
||||||
|
|
||||||
|
out := g.Compute()
|
||||||
|
|
||||||
|
if out[1] < 0.975 {
|
||||||
|
t.Error("Trust in node 1 should be closer to 1.00")
|
||||||
|
}
|
||||||
|
|
||||||
|
if out[2] < 0.93 {
|
||||||
|
t.Error("Trust in node 2 should be closer to 1.00")
|
||||||
|
}
|
||||||
|
if out[3] < 0.4 || out[3] > 0.6 {
|
||||||
|
t.Error("Trust in node 3 should be closer to 0.50")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRand(t *testing.T) {
|
||||||
|
peers := 200
|
||||||
|
rand.Seed(time.Now().UTC().UnixNano())
|
||||||
|
g := NewGroup()
|
||||||
|
|
||||||
|
//randomly set actual trust values for peers
|
||||||
|
actualTrust := make([]float32, peers)
|
||||||
|
for i := 0; i < peers; i++ {
|
||||||
|
actualTrust[i] = rand.Float32()
|
||||||
|
}
|
||||||
|
|
||||||
|
// peer0 is set to and granted 100% trust
|
||||||
|
actualTrust[0] = 1
|
||||||
|
g.InitialTrust(0, 1)
|
||||||
|
|
||||||
|
// set 30% of trust values to +/- 10% of actual trust
|
||||||
|
for i := 0; i < peers; i++ {
|
||||||
|
for j := 0; j < peers; j++ {
|
||||||
|
if rand.Float32() > .7 {
|
||||||
|
g.Add(i, j, randNorm(actualTrust[j]))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// compute trust
|
||||||
|
out := g.Compute()
|
||||||
|
|
||||||
|
// find RMS error
|
||||||
|
e := float32(0)
|
||||||
|
for i := 0; i < peers; i++ {
|
||||||
|
x := actualTrust[i] - out[i]
|
||||||
|
e += x * x
|
||||||
|
}
|
||||||
|
e = float32(math.Sqrt(float64(e / float32(peers))))
|
||||||
|
|
||||||
|
if e > .2 {
|
||||||
|
t.Error("RMS Error should be less than 20% for a 30% full trust grid of 200 nodes")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// randNorm takes a float and returns a value within +/- 10%,
|
||||||
|
// without going over 1
|
||||||
|
func randNorm(x float32) float32 {
|
||||||
|
r := rand.Float32()*.2 + .9
|
||||||
|
x *= r
|
||||||
|
if x > 1 {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
return x
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRangeError(t *testing.T) {
|
||||||
|
g := NewGroup()
|
||||||
|
|
||||||
|
err := g.Add(1, 2, 1.1)
|
||||||
|
if err.Error() != "Trust amount cannot be greater than 1" {
|
||||||
|
t.Error("Expected error")
|
||||||
|
}
|
||||||
|
|
||||||
|
err = g.Add(1, 2, -1)
|
||||||
|
if err.Error() != "Trust amount cannot be less than 0" {
|
||||||
|
t.Error("Expected error less than 0 error")
|
||||||
|
}
|
||||||
|
|
||||||
|
err = g.Add(1, 2, 1)
|
||||||
|
if err != nil {
|
||||||
|
t.Error("Did not expected error")
|
||||||
|
}
|
||||||
|
|
||||||
|
err = g.Add(1, 2, 0)
|
||||||
|
if err != nil {
|
||||||
|
t.Error("Did not expected error")
|
||||||
|
}
|
||||||
|
|
||||||
|
err = g.Add(1, 2, 0.5)
|
||||||
|
if err != nil {
|
||||||
|
t.Error("Did not expected error")
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue