diff --git a/AssemblerVVM/Program.cs b/AssemblerVVM/Program.cs deleted file mode 100644 index 7e55685..0000000 --- a/AssemblerVVM/Program.cs +++ /dev/null @@ -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 ConstID_VALUE = new Dictionary(); - Dictionary ConstKEY_ID = new Dictionary(); - Dictionary CodeMARK_POS = new Dictionary(); - - List FuncPos = new List(); //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 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 PositionAnalyse(string[] input, ref int[] posD, ref List posC, ref Dictionary 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 src = new List(); - 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 src, int[] pos, BinaryWriter bw, ref Dictionary id_v, ref Dictionary 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 code, pair pos, BinaryWriter bw, Dictionary dictStr, Dictionary 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 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 onebyte = new List{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 ninebytes = new List { opcode.DLOAD, opcode.ILOAD }; - - static List threebytes = new List { opcode.LOADDVAR, opcode.LOADIVAR, opcode.LOADSVAR, opcode.STOREDVAR, - opcode.STOREIVAR, opcode.STORESVAR, opcode.SLOAD, opcode.CALL}; - - static List fivebytes = new List {opcode.LOADCTXDVAR, opcode.LOADCTXIVAR, opcode.LOADCTXSVAR, opcode.STORECTXDVAR, - opcode.STORECTXIVAR, opcode.STORECTXSVAR}; - - static List jumps = new List {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 - }; -} diff --git a/AssemblerVVM/readme.txt b/AssemblerVVM/readme.txt deleted file mode 100644 index 5415a0e..0000000 --- a/AssemblerVVM/readme.txt +++ /dev/null @@ -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 \ No newline at end of file diff --git a/CompilerVVM/CodeGen.cs b/CompilerVVM/CodeGen.cs deleted file mode 100644 index dea005a..0000000 --- a/CompilerVVM/CodeGen.cs +++ /dev/null @@ -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 ConstData; - Dictionary Methods; - public string[] asm { get; set; } - - - public CodeGen(Dictionary ConstData, Dictionary Methods) - { - this.ConstData = ConstData; - this.Methods = Methods; - asm = null; - - foreach (KeyValuePair p in Methods) - { - Optimization(p.Value); - } - - - FillAsmCode(); - } - - private void FillAsmCode() - { - List Code = new List(); - if (ConstData.Count > 0) - { - Code.Add(".data"); - foreach (KeyValuePair pair in ConstData) - { - Code.Add(string.Format("{0} \"{1}\"", pair.Value, pair.Key)); - } - Code.Add(".endd"); - } - - foreach (KeyValuePair 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 OptimizationSub = new List(){"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(" ", ""); - } - } - } - } -} diff --git a/CompilerVVM/CustomExceptions.cs b/CompilerVVM/CustomExceptions.cs deleted file mode 100644 index 9a4fff8..0000000 --- a/CompilerVVM/CustomExceptions.cs +++ /dev/null @@ -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) - { - ; - } - } -} diff --git a/CompilerVVM/Parser.cs b/CompilerVVM/Parser.cs deleted file mode 100644 index 614d62d..0000000 --- a/CompilerVVM/Parser.cs +++ /dev/null @@ -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 Tokens; - int idvar; - Dictionary Constants; - Dictionary Methods; - int jumpid; - - public Parser(IList tokens, Dictionary TextConst, Dictionary Methods) - { - Tokens = tokens; - pointer = 0; - jumpid = 0; - Constants = TextConst; - this.Methods = Methods; - ParseMethod(); - } - - private void ParseMethod() - { - // := + - while (pointer != Tokens.Count) - { - // := method (*) - // := int | double | string - // := | 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 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 param = new List(); - 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 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 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 code_types = new List() { "int", "double", "string" }; - } -} diff --git a/CompilerVVM/ProcedureScanner.cs b/CompilerVVM/ProcedureScanner.cs deleted file mode 100644 index bd16810..0000000 --- a/CompilerVVM/ProcedureScanner.cs +++ /dev/null @@ -1,53 +0,0 @@ -п»їusing System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -namespace CompilerVVM -{ - class ProcedureScanner - { - public Dictionary Methods { get; set; } - int pointer; - - public ProcedureScanner(IList Tokens) - { - // TODO: Complete member initialization - pointer = 0; - ScanForMethods(Tokens); - } - - private void ScanForMethods(IList Tokens) - { - Methods = new Dictionary(); - 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); - } - } - } - } -} diff --git a/CompilerVVM/Program.cs b/CompilerVVM/Program.cs deleted file mode 100644 index b955f6f..0000000 --- a/CompilerVVM/Program.cs +++ /dev/null @@ -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 TextConst = new Dictionary(); - 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); - } - - } - } -} diff --git a/CompilerVVM/TokenScanner.cs b/CompilerVVM/TokenScanner.cs deleted file mode 100644 index 841e3f1..0000000 --- a/CompilerVVM/TokenScanner.cs +++ /dev/null @@ -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 tokens; - private IList list; - public IList Tokens { get { return tokens; } } - private void Scan(System.IO.TextReader input, Dictionary 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 TextConstant) - { - tokens = new List(); - this.Scan(input, TextConstant); - } - } - - enum OP - { - Semicolon, - OpenBlock, - CloseBlock, - OpenParam, - CloseParam, - Assigment, - Equal, - NotEqual, - Less, - Greater, - LessEqual, - GreaterEqual, - Add, - Sub, - Mul, - Div, - Mod - } -} diff --git a/CompilerVVM/grammar.txt b/CompilerVVM/grammar.txt deleted file mode 100644 index ca91cc7..0000000 --- a/CompilerVVM/grammar.txt +++ /dev/null @@ -1,43 +0,0 @@ -п»ї := + - - := method (* ) - - := int | double | string - := | void - - := * - := | - := 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 - - := + - := . - := " ? " - - := - - := ; - | = ; - | ; - | = ; - | if - | if else - | while - | do until ; - - := - := < | > | == | <= | >= - - := - | - | - | - | - | - | - - := + | - | * | / - - - - - diff --git a/README.md b/README.md deleted file mode 100644 index e69de29..0000000 diff --git a/VaninVM/CodeHeader.h b/VaninVM/CodeHeader.h deleted file mode 100644 index 9ee8f89..0000000 --- a/VaninVM/CodeHeader.h +++ /dev/null @@ -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 \ No newline at end of file diff --git a/VaninVM/Context.c b/VaninVM/Context.c deleted file mode 100644 index 64e5644..0000000 --- a/VaninVM/Context.c +++ /dev/null @@ -1,54 +0,0 @@ -#include "Context.h" -#include -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; -} \ No newline at end of file diff --git a/VaninVM/Context.h b/VaninVM/Context.h deleted file mode 100644 index 936ca24..0000000 --- a/VaninVM/Context.h +++ /dev/null @@ -1,34 +0,0 @@ -#ifndef CONTEXT_H -#define CONTEXT_H - -#include "CodeHeader.h" -#include - -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 \ No newline at end of file diff --git a/VaninVM/IOcode.c b/VaninVM/IOcode.c deleted file mode 100644 index f1f00c4..0000000 --- a/VaninVM/IOcode.c +++ /dev/null @@ -1,77 +0,0 @@ -#include "IOcode.h" -#include "CodeHeader.h" -#include - -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; icode=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; iConst_Header.count_const) - break; - - if (buffer[i] == 0) - (*(index))[j++]=&buffer[i+1]; - } - return 0; -} diff --git a/VaninVM/IOcode.h b/VaninVM/IOcode.h deleted file mode 100644 index c7beee9..0000000 --- a/VaninVM/IOcode.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef IOCODE_H -#define IOCODE_H - -#include "CodeHeader.h" -#include -#include - -int read_bytecode(FILE*, func***); -int read_constant(FILE*, int*, char***); -#endif \ No newline at end of file diff --git a/VaninVM/LocalVars.c b/VaninVM/LocalVars.c deleted file mode 100644 index 7023762..0000000 --- a/VaninVM/LocalVars.c +++ /dev/null @@ -1,50 +0,0 @@ -#include -#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)); - } -} diff --git a/VaninVM/LocalVars.h b/VaninVM/LocalVars.h deleted file mode 100644 index 7853c3c..0000000 --- a/VaninVM/LocalVars.h +++ /dev/null @@ -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 \ No newline at end of file diff --git a/VaninVM/Main.c b/VaninVM/Main.c deleted file mode 100644 index 502679e..0000000 --- a/VaninVM/Main.c +++ /dev/null @@ -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; -} \ No newline at end of file diff --git a/VaninVM/OpCode.h b/VaninVM/OpCode.h deleted file mode 100644 index c13bbc4..0000000 --- a/VaninVM/OpCode.h +++ /dev/null @@ -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 \ No newline at end of file diff --git a/VaninVM/ReturnStack.c b/VaninVM/ReturnStack.c deleted file mode 100644 index 85b9522..0000000 --- a/VaninVM/ReturnStack.c +++ /dev/null @@ -1,20 +0,0 @@ -#include -#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; -} \ No newline at end of file diff --git a/VaninVM/ReturnStack.h b/VaninVM/ReturnStack.h deleted file mode 100644 index 74fdab7..0000000 --- a/VaninVM/ReturnStack.h +++ /dev/null @@ -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 \ No newline at end of file diff --git a/VaninVM/TOS.c b/VaninVM/TOS.c deleted file mode 100644 index af5da47..0000000 --- a/VaninVM/TOS.c +++ /dev/null @@ -1,41 +0,0 @@ -#include -#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; -} \ No newline at end of file diff --git a/VaninVM/TOS.h b/VaninVM/TOS.h deleted file mode 100644 index 072a0ba..0000000 --- a/VaninVM/TOS.h +++ /dev/null @@ -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 \ No newline at end of file diff --git a/VaninVM/opc.txt b/VaninVM/opc.txt deleted file mode 100644 index 2bc9db8..0000000 --- a/VaninVM/opc.txt +++ /dev/null @@ -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) \ No newline at end of file diff --git a/readme.md b/readme.md new file mode 100644 index 0000000..dc4f8be --- /dev/null +++ b/readme.md @@ -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. \ No newline at end of file diff --git a/trustgraph.go b/trustgraph.go new file mode 100644 index 0000000..079d842 --- /dev/null +++ b/trustgraph.go @@ -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 +} diff --git a/trustgraph_test.go b/trustgraph_test.go new file mode 100644 index 0000000..0f66b06 --- /dev/null +++ b/trustgraph_test.go @@ -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") + } +}