From 8d095136397f4e5d17be1881ea5e5822e6d5b60f Mon Sep 17 00:00:00 2001 From: AlexVanin Date: Tue, 14 Jan 2014 22:01:44 +0400 Subject: [PATCH 01/24] First Commit --- README.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..e69de29 From 9d30a3f8f502d32ea0c1d1370e259f7ec6380a7a Mon Sep 17 00:00:00 2001 From: AlexVanin Date: Tue, 14 Jan 2014 22:13:31 +0400 Subject: [PATCH 02/24] First alpha version. Added support for putting\getting from TOS int and double --- VaninVM/IOcode.c | 12 ++++++++++++ VaninVM/IOcode.h | 8 ++++++++ VaninVM/Main.c | 36 ++++++++++++++++++++++++++++++++++++ VaninVM/TOS.c | 35 +++++++++++++++++++++++++++++++++++ VaninVM/TOS.h | 18 ++++++++++++++++++ 5 files changed, 109 insertions(+) create mode 100644 VaninVM/IOcode.c create mode 100644 VaninVM/IOcode.h create mode 100644 VaninVM/Main.c create mode 100644 VaninVM/TOS.c create mode 100644 VaninVM/TOS.h diff --git a/VaninVM/IOcode.c b/VaninVM/IOcode.c new file mode 100644 index 0000000..3fa879a --- /dev/null +++ b/VaninVM/IOcode.c @@ -0,0 +1,12 @@ +#include "IOcode.h" + +char* read_bytecode(char* path) +{ + FILE* input; + char* buffer = (char*)calloc(1, 1000); //Early version without bytecode file + fopen_s(&input, "bytecode", "rb"); + fread_s(buffer, 1000, sizeof(char), 1000, input); //Early version without bytecode file + fclose(input); + + return buffer; +} diff --git a/VaninVM/IOcode.h b/VaninVM/IOcode.h new file mode 100644 index 0000000..4cdd8f5 --- /dev/null +++ b/VaninVM/IOcode.h @@ -0,0 +1,8 @@ +#ifndef IOCODE_H +#define IOCODE_H + +#include +#include + +char* read_bytecode(char*); +#endif \ No newline at end of file diff --git a/VaninVM/Main.c b/VaninVM/Main.c new file mode 100644 index 0000000..daa0427 --- /dev/null +++ b/VaninVM/Main.c @@ -0,0 +1,36 @@ +#include "IOcode.h" +#include "TOS.h" + + +int main(int argc, char** argv) +{ + char* code; + int ip; + + + int exec_status = 1; + + code = read_bytecode("bytecode"); + initTOS(); + + ip = 0; + + while (exec_status) + { + switch (code[ip]) + { + case 1: + push_double(12.1); + ip++; + break; + + case 78: + exec_status = 0; + break; + } + } + printf("%f", pop_double()); + getchar(); + return 0; + +} \ No newline at end of file diff --git a/VaninVM/TOS.c b/VaninVM/TOS.c new file mode 100644 index 0000000..cf38a6f --- /dev/null +++ b/VaninVM/TOS.c @@ -0,0 +1,35 @@ +#include +#include "TOS.h" + +void push_int(int num) +{ + TOS[tp++] = num; +} + +int pop_int() +{ + int num = TOS[--tp]; + return num; +} + +void push_double(double num) +{ + tos_num cont = { num }; + push_int(cont.num_i[0]); + push_int(cont.num_i[1]); +} + +double pop_double() +{ + tos_num cont; + cont.num_i[1] = pop_int(); + cont.num_i[0] = pop_int(); + return cont.num_d; +} + +int initTOS() +{ + TOS = (int*)calloc(1, 1500); + tp = 0; + return 0; +} \ No newline at end of file diff --git a/VaninVM/TOS.h b/VaninVM/TOS.h new file mode 100644 index 0000000..6d48711 --- /dev/null +++ b/VaninVM/TOS.h @@ -0,0 +1,18 @@ +#ifndef TOS_H +#define TOS_H + +typedef union +{ + double num_d; + int num_i[2]; +} tos_num; + +int* TOS; +int tp; +int initTOS(); +void push_int(int); +void push_double(double); +int pop_int(); +double pop_double(); + +#endif \ No newline at end of file From 0e0c64007f3d8ed5e1721de0af4e383c8430eae2 Mon Sep 17 00:00:00 2001 From: AlexVanin Date: Wed, 15 Jan 2014 13:54:42 +0400 Subject: [PATCH 03/24] Added enum for instructions --- VaninVM/Main.c | 31 ++++++++++++++++++++++++++----- VaninVM/OpCode.h | 13 +++++++++++++ 2 files changed, 39 insertions(+), 5 deletions(-) create mode 100644 VaninVM/OpCode.h diff --git a/VaninVM/Main.c b/VaninVM/Main.c index daa0427..85ed4f4 100644 --- a/VaninVM/Main.c +++ b/VaninVM/Main.c @@ -1,5 +1,6 @@ #include "IOcode.h" #include "TOS.h" +#include "OpCode.h" int main(int argc, char** argv) @@ -19,12 +20,32 @@ int main(int argc, char** argv) { switch (code[ip]) { - case 1: - push_double(12.1); - ip++; - break; + case DLOAD0: + // DO(DLOAD0, "Load double 0 on TOS.", 1) + push_double(0); + ip++; break; + case ILOAD0: + //DO(ILOAD0, "Load int 0 on TOS.", 1) + push_int(0); + ip++; break; + case DLOAD1: + //DO(DLOAD1, "Load double 1 on TOS.", 1) + push_double(1); + ip++; break; + case ILOAD1: + //DO(ILOAD1, "Load int 1 on TOS.", 1) + push_int(1); + ip++; break; + case DLOADM1: + //DO(DLOADM1, "Load double -1 on TOS.", 1) + push_double(-1); + ip++; break; + case ILOADM1: + //DO(ILOADM1, "Load int -1 on TOS.", 1) + push_int(-1); + ip++; break; - case 78: + case STOP: exec_status = 0; break; } diff --git a/VaninVM/OpCode.h b/VaninVM/OpCode.h new file mode 100644 index 0000000..ae42a0f --- /dev/null +++ b/VaninVM/OpCode.h @@ -0,0 +1,13 @@ +#ifndef OPCODE_H +#define OPCODE_H +enum opcode +{ + DLOAD0, + ILOAD0, + DLOAD1, + ILOAD1, + DLOADM1, + ILOADM1, + STOP +}; +#endif \ No newline at end of file From c70ee283ba0d10d77f8f0d72027ff3a0d3e24b56 Mon Sep 17 00:00:00 2001 From: AlexVanin Date: Sun, 26 Jan 2014 09:37:18 +0400 Subject: [PATCH 04/24] Added new opcodes and list of avaliable opcodes --- VaninVM/Main.c | 80 +++++++++++++++++++++++++++++++++++++++++++-- VaninVM/OpCode.h | 16 +++++++++ VaninVM/opc.txt | 85 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 179 insertions(+), 2 deletions(-) create mode 100644 VaninVM/opc.txt diff --git a/VaninVM/Main.c b/VaninVM/Main.c index 85ed4f4..45c985b 100644 --- a/VaninVM/Main.c +++ b/VaninVM/Main.c @@ -5,6 +5,8 @@ int main(int argc, char** argv) { + double d1, d2; + int i1, i2; char* code; int ip; @@ -44,13 +46,87 @@ int main(int argc, char** argv) //DO(ILOADM1, "Load int -1 on TOS.", 1) push_int(-1); ip++; break; - + case DADD: + d1 = pop_double(); + d2 = pop_double(); + d1 += d2; + push_double(d1); + ip++; break; + case IADD: + i1 = pop_int(); + i2 = pop_int(); + i1 += i2; + push_int(i1); + ip++; break; + case DSUB: + d1 = pop_double(); + d2 = pop_double(); + d1 -= d2; + push_double(d1); + ip++; break; + case ISUB: + i1 = pop_int(); + i2 = pop_int(); + i1 -= i2; + push_int(i1); + ip++; break; + case DMUL: + d1 = pop_double(); + d2 = pop_double(); + d1 *= d2; + push_double(d1); + ip++; break; + case IMUL: + i1 = pop_int(); + i2 = pop_int(); + i1 *= i2; + push_int(i1); + ip++; break; + case DDIV: + d1 = pop_double(); + d2 = pop_double(); + d1 /= d2; + push_double(d1); + ip++; break; + case IDIV: + i1 = pop_int(); + i2 = pop_int(); + i1 /= i2; + push_int(i1); + ip++; break; + case IMOD: + i1 = pop_int(); + i2 = pop_int(); + i1 %= i2; + push_int(i1); + ip++; break; + case DNEG: + d1 = pop_double(); + d1 = -d1; + push_double(d1); + ip++; break; + case INEG: + i1 = pop_int(); + i1 = - i1; + push_int(i1); + ip++; break; + case IAOR: + i1 = pop_int(); + i2 = pop_int(); + i1 = i1 | i2; + push_int(i1); + ip++;break; + case DPRINT: + printf("%f", pop_double()); + ip++; break; + case IPRINT: + printf("%d", pop_int()); + ip++; break; case STOP: exec_status = 0; break; } } - printf("%f", pop_double()); getchar(); return 0; diff --git a/VaninVM/OpCode.h b/VaninVM/OpCode.h index ae42a0f..1654e82 100644 --- a/VaninVM/OpCode.h +++ b/VaninVM/OpCode.h @@ -8,6 +8,22 @@ enum opcode ILOAD1, DLOADM1, ILOADM1, + DADD, + IADD, + DSUB, + ISUB, + DMUL, + IMUL, + DDIV, + IDIV, + IMOD, + DNEG, + INEG, + IAOR, + IAAND, + IAXOR, + IPRINT, + DPRINT, STOP }; #endif \ No newline at end of file diff --git a/VaninVM/opc.txt b/VaninVM/opc.txt new file mode 100644 index 0000000..3980373 --- /dev/null +++ b/VaninVM/opc.txt @@ -0,0 +1,85 @@ +#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 0.", 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 0.", 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 0.", 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-stryle 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 From 486b73fcea29c37e4de3dd0afaa7b57ff19027b8 Mon Sep 17 00:00:00 2001 From: AlexVanin Date: Sun, 26 Jan 2014 10:39:22 +0400 Subject: [PATCH 05/24] Changed organisation of TOS. Now its 8-byte stack instead 4-byte before --- VaninVM/Main.c | 34 ++++++++++++++++++++++++++++------ VaninVM/TOS.c | 21 ++++++++++----------- VaninVM/TOS.h | 2 +- 3 files changed, 39 insertions(+), 18 deletions(-) diff --git a/VaninVM/Main.c b/VaninVM/Main.c index 45c985b..1aaf41e 100644 --- a/VaninVM/Main.c +++ b/VaninVM/Main.c @@ -47,87 +47,109 @@ int main(int argc, char** argv) push_int(-1); ip++; 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); ip++; 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); ip++; 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); ip++; 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); ip++; 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); ip++; 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); ip++; break; case DDIV: + //DO(DDIV, "Divide 2 doubles on TOS (upper to lower), push value back.", 1) d1 = pop_double(); d2 = pop_double(); d1 /= d2; push_double(d1); ip++; break; case IDIV: + //DO(IDIV, "Divide 2 ints on TOS (upper to lower), push value back.", 1) i1 = pop_int(); i2 = pop_int(); i1 /= i2; push_int(i1); ip++; 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 %= i2; push_int(i1); ip++; break; case DNEG: + //DO(DNEG, "Negate double on TOS.", 1) d1 = pop_double(); d1 = -d1; push_double(d1); ip++; break; case INEG: + //DO(INEG, "Negate int on TOS.", 1) i1 = pop_int(); i1 = - i1; push_int(i1); ip++; 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); - ip++;break; - case DPRINT: - printf("%f", pop_double()); ip++; break; + case IAAND: + //DO(IAAND, "Arithmetic AND of 2 ints on TOS, push value back.", 1) + ip++; break; + case IAXOR: + //DO(IAXOR, "Arithmetic XOR of 2 ints on TOS, push value back.", 1) case IPRINT: - printf("%d", pop_int()); + //DO(IPRINT, "Pop and print integer TOS.", 1) + i1 = pop_int(); + push_int(i1); + printf("%d", i1); + ip++; break; + case DPRINT: + //DO(DPRINT, "Pop and print double TOS.", 1) + d1 = pop_double(); + push_double(d1); + printf("%f", d1); ip++; break; case STOP: + //DO(STOP, "Stop execution.", 1) exec_status = 0; break; } } - getchar(); return 0; - } \ No newline at end of file diff --git a/VaninVM/TOS.c b/VaninVM/TOS.c index cf38a6f..27f4ab5 100644 --- a/VaninVM/TOS.c +++ b/VaninVM/TOS.c @@ -3,33 +3,32 @@ void push_int(int num) { - TOS[tp++] = num; + tos_num number; + number.num_i[1] = num; + TOS[tp++] = number.num_d; } int pop_int() { - int num = TOS[--tp]; - return num; + tos_num number; + number.num_d = TOS[--tp]; + return number.num_i[1]; } void push_double(double num) { - tos_num cont = { num }; - push_int(cont.num_i[0]); - push_int(cont.num_i[1]); + TOS[tp++] = num; } double pop_double() { - tos_num cont; - cont.num_i[1] = pop_int(); - cont.num_i[0] = pop_int(); - return cont.num_d; + double num = TOS[--tp]; + return num; } int initTOS() { - TOS = (int*)calloc(1, 1500); + TOS = (double*)calloc(1, 12000); tp = 0; return 0; } \ No newline at end of file diff --git a/VaninVM/TOS.h b/VaninVM/TOS.h index 6d48711..b95f1a2 100644 --- a/VaninVM/TOS.h +++ b/VaninVM/TOS.h @@ -7,7 +7,7 @@ typedef union int num_i[2]; } tos_num; -int* TOS; +double* TOS; int tp; int initTOS(); void push_int(int); From 17e632ad0bcc44a318e40e482110d502f2075ff5 Mon Sep 17 00:00:00 2001 From: AlexVanin Date: Sun, 26 Jan 2014 11:45:07 +0400 Subject: [PATCH 06/24] TOS finally changed to work with 8-bit long integers, added a few instructions --- VaninVM/Main.c | 38 +++++++++++++++++++++++++++++++++++++- VaninVM/OpCode.h | 7 +++++++ VaninVM/TOS.c | 8 ++++---- VaninVM/TOS.h | 6 +++--- VaninVM/opc.txt | 20 ++++++++++---------- 5 files changed, 61 insertions(+), 18 deletions(-) diff --git a/VaninVM/Main.c b/VaninVM/Main.c index 1aaf41e..0ef1a76 100644 --- a/VaninVM/Main.c +++ b/VaninVM/Main.c @@ -6,7 +6,7 @@ int main(int argc, char** argv) { double d1, d2; - int i1, i2; + long long i1, i2; char* code; int ip; @@ -22,6 +22,19 @@ int main(int argc, char** argv) { switch (code[ip]) { + case INVALID: + //DO(INVALID, "Invalid instruction.", 1) + ip++; 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++; break; case DLOAD0: // DO(DLOAD0, "Load double 0 on TOS.", 1) push_double(0); @@ -145,6 +158,29 @@ int main(int argc, char** argv) push_double(d1); printf("%f", d1); ip++; break; + case I2D: + //DO(I2D, "Convert int on TOS to double.", 1) + i1 = pop_int(); + d1 = (double)i1; + push_double(d1); + ip++; break; + case D2I: + //DO(D2I, "Convert double on TOS to int.", 1) + d1 = pop_double(); + i1 = (int)d1; + push_int(i1); + ip++; break; + case SWAP: + //DO(SWAP, "Swap 2 topmost values.", 1) + i1 = pop_int(); + i2 = pop_int(); + push_int(i1); + push_int(i2); + ip++; break; + case POP: + //DO(POP, "Remove topmost value.", 1) + TOS--; + ip++; break; case STOP: //DO(STOP, "Stop execution.", 1) exec_status = 0; diff --git a/VaninVM/OpCode.h b/VaninVM/OpCode.h index 1654e82..49eca60 100644 --- a/VaninVM/OpCode.h +++ b/VaninVM/OpCode.h @@ -2,6 +2,9 @@ #define OPCODE_H enum opcode { + INVALID, + DLOAD, + ILOAD, DLOAD0, ILOAD0, DLOAD1, @@ -24,6 +27,10 @@ enum opcode IAXOR, IPRINT, DPRINT, + I2D, + D2I, + SWAP, + POP, STOP }; #endif \ No newline at end of file diff --git a/VaninVM/TOS.c b/VaninVM/TOS.c index 27f4ab5..25f398b 100644 --- a/VaninVM/TOS.c +++ b/VaninVM/TOS.c @@ -1,18 +1,18 @@ #include #include "TOS.h" -void push_int(int num) +void push_int(long long num) { tos_num number; - number.num_i[1] = num; + number.num_i = num; TOS[tp++] = number.num_d; } -int pop_int() +long long pop_int() { tos_num number; number.num_d = TOS[--tp]; - return number.num_i[1]; + return number.num_i; } void push_double(double num) diff --git a/VaninVM/TOS.h b/VaninVM/TOS.h index b95f1a2..68a909c 100644 --- a/VaninVM/TOS.h +++ b/VaninVM/TOS.h @@ -4,15 +4,15 @@ typedef union { double num_d; - int num_i[2]; + long long num_i; } tos_num; double* TOS; int tp; int initTOS(); -void push_int(int); +void push_int(long long); void push_double(double); -int pop_int(); +long long pop_int(); double pop_double(); #endif \ No newline at end of file diff --git a/VaninVM/opc.txt b/VaninVM/opc.txt index 3980373..51b882b 100644 --- a/VaninVM/opc.txt +++ b/VaninVM/opc.txt @@ -1,7 +1,7 @@ #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(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) \ @@ -22,16 +22,16 @@ +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(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(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(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) \ @@ -68,7 +68,7 @@ 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-stryle comparator value cmp(upper, lower) as integer.", 1) \ + 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) \ From 792724bcd14e86a4727104869674c90aadfd0057 Mon Sep 17 00:00:00 2001 From: AlexVanin Date: Mon, 27 Jan 2014 08:43:58 +0400 Subject: [PATCH 07/24] Added constant-support --- VaninVM/IOcode.c | 38 +++++++++++++++++++++++++++++++++----- VaninVM/IOcode.h | 3 ++- VaninVM/Main.c | 32 +++++++++++++++++++++++++++++++- VaninVM/OpCode.h | 2 ++ VaninVM/opc.txt | 8 ++++---- 5 files changed, 72 insertions(+), 11 deletions(-) diff --git a/VaninVM/IOcode.c b/VaninVM/IOcode.c index 3fa879a..c9c3c21 100644 --- a/VaninVM/IOcode.c +++ b/VaninVM/IOcode.c @@ -1,12 +1,40 @@ #include "IOcode.h" +#include "CodeHeader.h" -char* read_bytecode(char* path) +char* read_bytecode(FILE* stream) { - FILE* input; char* buffer = (char*)calloc(1, 1000); //Early version without bytecode file - fopen_s(&input, "bytecode", "rb"); - fread_s(buffer, 1000, sizeof(char), 1000, input); //Early version without bytecode file - fclose(input); + fread_s(buffer, 1000, sizeof(char), 1000, stream); //Early version without bytecode file return buffer; } + +int read_constant(FILE* stream, int* count, char*** index) +{ + int i, j; + char* buffer; + + fread_s(&First_Header, sizeof(First_Header), sizeof(First_Header), 1, stream); //Reading first part of header + *(count) = First_Header.count_const; + + buffer = (char*)malloc(First_Header.size_const); + *(index) = (char**)malloc(sizeof(char**)*2); + + + fread_s(buffer, First_Header.size_const, sizeof(char), First_Header.size_const, stream); //Reading constant values + + j=0; + if (First_Header.count_const>0) + { + (*(index))[j++] = buffer; + for (i = 0; i #include -char* read_bytecode(char*); +char* read_bytecode(FILE*); +int read_constant(FILE*, int*, char***); #endif \ No newline at end of file diff --git a/VaninVM/Main.c b/VaninVM/Main.c index 0ef1a76..ed562bf 100644 --- a/VaninVM/Main.c +++ b/VaninVM/Main.c @@ -1,19 +1,39 @@ #include "IOcode.h" #include "TOS.h" #include "OpCode.h" +#include "CodeHeader.h" + int main(int argc, char** argv) { + //ByteCode Variables + FILE* input; + + //ExecutionProcess Variables double d1, d2; long long i1, i2; + short s1; char* code; int ip; + //ConstSection Variables + int const_count; + char** const_index; + //Execution Variable int exec_status = 1; - code = read_bytecode("bytecode"); + fopen_s(&input, "bytecode", "rb"); + + //const_pull + read_constant(input, &const_count, &const_index); + + code=read_bytecode(input); + + fclose(input); + + initTOS(); ip = 0; @@ -35,6 +55,10 @@ int main(int argc, char** argv) i1 = *((long long*)(code+(++ip))); push_int(i1); ip++; break; + case SLOAD: + s1 = *((short*)(code+(++ip))); + push_int((long long)(const_index[s1])); + ip++; break; case DLOAD0: // DO(DLOAD0, "Load double 0 on TOS.", 1) push_double(0); @@ -158,6 +182,11 @@ int main(int argc, char** argv) push_double(d1); printf("%f", d1); ip++; break; + case SPRINT: + i1 = pop_int(); + push_int(i1); + printf("%s", (char*)i1); + ip++; break; case I2D: //DO(I2D, "Convert int on TOS to double.", 1) i1 = pop_int(); @@ -187,5 +216,6 @@ int main(int argc, char** argv) break; } } + getchar(); return 0; } \ No newline at end of file diff --git a/VaninVM/OpCode.h b/VaninVM/OpCode.h index 49eca60..ee490e1 100644 --- a/VaninVM/OpCode.h +++ b/VaninVM/OpCode.h @@ -5,6 +5,7 @@ enum opcode INVALID, DLOAD, ILOAD, + SLOAD, DLOAD0, ILOAD0, DLOAD1, @@ -27,6 +28,7 @@ enum opcode IAXOR, IPRINT, DPRINT, + SPRINT, I2D, D2I, SWAP, diff --git a/VaninVM/opc.txt b/VaninVM/opc.txt index 51b882b..eea5921 100644 --- a/VaninVM/opc.txt +++ b/VaninVM/opc.txt @@ -2,7 +2,7 @@ -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(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) \ @@ -46,15 +46,15 @@ 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 0.", 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 0.", 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 0.", 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) \ From 77124400643fd0dfbc6dd68d50d5f98bbdb1a985 Mon Sep 17 00:00:00 2001 From: AlexVanin Date: Mon, 27 Jan 2014 16:09:25 +0400 Subject: [PATCH 08/24] Added support for functions and dynamic contexts. Improved work with constant pool --- VaninVM/CodeHeader.h | 39 ++++++++++++++++++++++++++++++ VaninVM/Context.c | 33 ++++++++++++++++++++++++++ VaninVM/Context.h | 27 +++++++++++++++++++++ VaninVM/IOcode.c | 55 ++++++++++++++++++++++++++++++------------- VaninVM/IOcode.h | 3 ++- VaninVM/Main.c | 43 +++++++++++++++++++++++---------- VaninVM/OpCode.h | 4 +++- VaninVM/ReturnStack.c | 20 ++++++++++++++++ VaninVM/ReturnStack.h | 9 +++++++ 9 files changed, 202 insertions(+), 31 deletions(-) create mode 100644 VaninVM/CodeHeader.h create mode 100644 VaninVM/Context.c create mode 100644 VaninVM/Context.h create mode 100644 VaninVM/ReturnStack.c create mode 100644 VaninVM/ReturnStack.h diff --git a/VaninVM/CodeHeader.h b/VaninVM/CodeHeader.h new file mode 100644 index 0000000..8e00649 --- /dev/null +++ b/VaninVM/CodeHeader.h @@ -0,0 +1,39 @@ +#ifndef CODE_HEADER +#define CODE_HEADER +#pragma pack(push, 1) +struct +{ + char signature[4]; + int version; + int count_const; + int size_const; +}First_Header; + +struct +{ + short id_start; + int count_code; +}ByteCodeH_Common; + +struct +{ + int size_func; + int size_bytecode; + int size_signature; +}ByteCodeH_Signat; + +struct +{ + 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 new file mode 100644 index 0000000..b798f11 --- /dev/null +++ b/VaninVM/Context.c @@ -0,0 +1,33 @@ +#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=malloc(8*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() +{ + c_node* last = node_last; + node_last = node_last->prev; + return last->obj; +} \ No newline at end of file diff --git a/VaninVM/Context.h b/VaninVM/Context.h new file mode 100644 index 0000000..d0208e3 --- /dev/null +++ b/VaninVM/Context.h @@ -0,0 +1,27 @@ +#ifndef CONTEXT_H +#define CONTEXT_H + +#include "CodeHeader.h" +#include + + +typedef struct +{ + int id; + void* 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*); + +#endif \ No newline at end of file diff --git a/VaninVM/IOcode.c b/VaninVM/IOcode.c index c9c3c21..43b898c 100644 --- a/VaninVM/IOcode.c +++ b/VaninVM/IOcode.c @@ -1,12 +1,37 @@ #include "IOcode.h" #include "CodeHeader.h" +#include -char* read_bytecode(FILE* stream) +int read_bytecode(FILE* stream, func*** hash) { - char* buffer = (char*)calloc(1, 1000); //Early version without bytecode file - fread_s(buffer, 1000, sizeof(char), 1000, stream); //Early version without bytecode file + 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; - return buffer; } int read_constant(FILE* stream, int* count, char*** index) @@ -17,24 +42,22 @@ int read_constant(FILE* stream, int* count, char*** index) fread_s(&First_Header, sizeof(First_Header), sizeof(First_Header), 1, stream); //Reading first part of header *(count) = First_Header.count_const; - buffer = (char*)malloc(First_Header.size_const); - *(index) = (char**)malloc(sizeof(char**)*2); + buffer = (char*)malloc(First_Header.size_const+1); + buffer[0]=0; + *(index) = (char**)malloc(sizeof(char**)*First_Header.count_const); - fread_s(buffer, First_Header.size_const, sizeof(char), First_Header.size_const, stream); //Reading constant values + fread_s(buffer+1, First_Header.size_const, sizeof(char), First_Header.size_const, stream); //Reading constant values j=0; - if (First_Header.count_const>0) + (*(index))[j++]=buffer; + for (i = 0; i #include -char* read_bytecode(FILE*); +int read_bytecode(FILE*, func***); int read_constant(FILE*, int*, char***); #endif \ No newline at end of file diff --git a/VaninVM/Main.c b/VaninVM/Main.c index ed562bf..cb96402 100644 --- a/VaninVM/Main.c +++ b/VaninVM/Main.c @@ -2,6 +2,8 @@ #include "TOS.h" #include "OpCode.h" #include "CodeHeader.h" +#include "Context.h" +#include "ReturnStack.h" @@ -15,29 +17,33 @@ int main(int argc, char** argv) long long i1, i2; short s1; char* code; - int ip; + int ip, startfunc; //ConstSection Variables int const_count; char** const_index; - //Execution Variable + //CodeSection Variables + func** phash_table; + context* current_context; + + //Running Variable int exec_status = 1; fopen_s(&input, "bytecode", "rb"); - //const_pull read_constant(input, &const_count, &const_index); - - code=read_bytecode(input); - + //code_pull + startfunc = read_bytecode(input, &phash_table); fclose(input); initTOS(); - + initRStack(); ip = 0; + current_context = create_context(startfunc, phash_table, &code); + while (exec_status) { switch (code[ip]) @@ -54,11 +60,11 @@ int main(int argc, char** argv) //DO(ILOAD, "Load int on TOS, inlined into insn stream.", 9) i1 = *((long long*)(code+(++ip))); push_int(i1); - ip++; break; + ip+=8; break; case SLOAD: s1 = *((short*)(code+(++ip))); push_int((long long)(const_index[s1])); - ip++; break; + ip+=2; break; case DLOAD0: // DO(DLOAD0, "Load double 0 on TOS.", 1) push_double(0); @@ -173,18 +179,16 @@ int main(int argc, char** argv) case IPRINT: //DO(IPRINT, "Pop and print integer TOS.", 1) i1 = pop_int(); - push_int(i1); printf("%d", i1); ip++; break; case DPRINT: //DO(DPRINT, "Pop and print double TOS.", 1) d1 = pop_double(); - push_double(d1); printf("%f", d1); ip++; break; case SPRINT: + //DO(SPRINT, "Pop and print string TOS.", 1) i1 = pop_int(); - push_int(i1); printf("%s", (char*)i1); ip++; break; case I2D: @@ -213,9 +217,22 @@ int main(int argc, char** argv) case STOP: //DO(STOP, "Stop execution.", 1) exec_status = 0; - break; + break; + case CALL: + s1 = *((short*)(code+(++ip))); + ip+=2; push_ret(ip); + push_context(current_context); + current_context = create_context(s1, phash_table, &code); + ip = 0; break; + case RETURN: + remove_context(current_context); + current_context = pop_context(); + code = phash_table[current_context->id]->code; + ip = pop_ret(); break; + } } + remove_context(current_context); getchar(); return 0; } \ No newline at end of file diff --git a/VaninVM/OpCode.h b/VaninVM/OpCode.h index ee490e1..af9e9da 100644 --- a/VaninVM/OpCode.h +++ b/VaninVM/OpCode.h @@ -33,6 +33,8 @@ enum opcode D2I, SWAP, POP, - STOP + STOP, + CALL, + RETURN }; #endif \ No newline at end of file diff --git a/VaninVM/ReturnStack.c b/VaninVM/ReturnStack.c new file mode 100644 index 0000000..45e33b1 --- /dev/null +++ b/VaninVM/ReturnStack.c @@ -0,0 +1,20 @@ +#include +#include "ReturnStack.h" + +void push_ret(int num) +{ + RStack[rp++] = num; +} + +int pop_ret() +{ + int num = RStack[--rp]; + return num; +} + +int initRStack() +{ + RStack = (int*)calloc(1, 1000); + rp = 0; + return 0; +} \ No newline at end of file diff --git a/VaninVM/ReturnStack.h b/VaninVM/ReturnStack.h new file mode 100644 index 0000000..317baf1 --- /dev/null +++ b/VaninVM/ReturnStack.h @@ -0,0 +1,9 @@ +#ifndef RETURNSTACK_H +#define RETURNSTACK_H + +int* RStack; +int rp; +int initRStack(); +void push_ret(int); +int pop_ret(); +#endif \ No newline at end of file From 159c5ed01f228ac77c7999ac44139fa4f299c274 Mon Sep 17 00:00:00 2001 From: AlexVanin Date: Tue, 28 Jan 2014 12:46:28 +0400 Subject: [PATCH 09/24] First full version. Added all opcodes, improved work with contexts --- VaninVM/CodeHeader.h | 4 +- VaninVM/Context.c | 18 ++ VaninVM/Context.h | 1 + VaninVM/IOcode.c | 28 +- VaninVM/LocalVars.c | 38 +++ VaninVM/LocalVars.h | 12 + VaninVM/Main.c | 750 ++++++++++++++++++++++++++++++++----------- VaninVM/OpCode.h | 51 ++- VaninVM/TOS.c | 7 + VaninVM/TOS.h | 1 + VaninVM/opc.txt | 108 +++---- 11 files changed, 767 insertions(+), 251 deletions(-) create mode 100644 VaninVM/LocalVars.c create mode 100644 VaninVM/LocalVars.h diff --git a/VaninVM/CodeHeader.h b/VaninVM/CodeHeader.h index 8e00649..76e2427 100644 --- a/VaninVM/CodeHeader.h +++ b/VaninVM/CodeHeader.h @@ -3,11 +3,11 @@ #pragma pack(push, 1) struct { - char signature[4]; + char signature[2]; int version; int count_const; int size_const; -}First_Header; +}Const_Header; struct { diff --git a/VaninVM/Context.c b/VaninVM/Context.c index b798f11..ff65c06 100644 --- a/VaninVM/Context.c +++ b/VaninVM/Context.c @@ -30,4 +30,22 @@ context* pop_context() c_node* last = node_last; node_last = node_last->prev; return last->obj; +} + +//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 index d0208e3..f0eedec 100644 --- a/VaninVM/Context.h +++ b/VaninVM/Context.h @@ -23,5 +23,6 @@ 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 index 43b898c..90c54e2 100644 --- a/VaninVM/IOcode.c +++ b/VaninVM/IOcode.c @@ -2,6 +2,8 @@ #include "CodeHeader.h" #include +int version = 0100; + int read_bytecode(FILE* stream, func*** hash) { int i; @@ -39,21 +41,33 @@ int read_constant(FILE* stream, int* count, char*** index) int i, j; char* buffer; - fread_s(&First_Header, sizeof(First_Header), sizeof(First_Header), 1, stream); //Reading first part of header - *(count) = First_Header.count_const; + 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; + } - buffer = (char*)malloc(First_Header.size_const+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**)*First_Header.count_const); + *(index) = (char**)malloc(sizeof(char**)*Const_Header.count_const); - fread_s(buffer+1, First_Header.size_const, sizeof(char), First_Header.size_const, stream); //Reading constant values + 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) diff --git a/VaninVM/LocalVars.c b/VaninVM/LocalVars.c new file mode 100644 index 0000000..fbaab2c --- /dev/null +++ b/VaninVM/LocalVars.c @@ -0,0 +1,38 @@ +#include +#include "LocalVars.h" + +long long getlocal_int(context* cont, int id) +{ + long long result; + result = ((long long*)(cont->locals))[id]; + return result; +} + +double getlocal_double(context* cont, int id) +{ + double result; + result = ((double*)(cont->locals))[id]; + return result; +} + +int getlocal_string(context* cont, int id) +{ + long long result; + result = ((long long*)(cont->locals))[id]; + return (int)result; +} + +void putlocal_int(long long* num, context* cont, int id) +{ + memcpy(((long long*)cont->locals)+id, num, sizeof(long long)); +} + +void putlocal_double(double* num, context* cont, int id) +{ + memcpy(((double*)cont->locals)+id, num, sizeof(double)); +} + +void putlocal_string(int* str, context* cont, int id) +{ + memcpy(((long long*)cont->locals)+id, (long long*)str, sizeof(long long)); +} diff --git a/VaninVM/LocalVars.h b/VaninVM/LocalVars.h new file mode 100644 index 0000000..efb873d --- /dev/null +++ b/VaninVM/LocalVars.h @@ -0,0 +1,12 @@ +#ifndef LOCALVARS_H +#define LOCALVARS_H +#include "Context.h" + +long long getlocal_int(context*, int); +double getlocal_double(context*, int); +int getlocal_string(context*, int); + +void putlocal_int(long long*, context*, int); +void putlocal_double(double*, context*, int); +void putlocal_string(int*, context*, int); +#endif \ No newline at end of file diff --git a/VaninVM/Main.c b/VaninVM/Main.c index cb96402..c476d4e 100644 --- a/VaninVM/Main.c +++ b/VaninVM/Main.c @@ -1,11 +1,16 @@ -#include "IOcode.h" -#include "TOS.h" #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 main(int argc, char** argv) { @@ -15,7 +20,7 @@ int main(int argc, char** argv) //ExecutionProcess Variables double d1, d2; long long i1, i2; - short s1; + short s1, s2; char* code; int ip, startfunc; @@ -30,209 +35,580 @@ int main(int argc, char** argv) //Running Variable int exec_status = 1; - fopen_s(&input, "bytecode", "rb"); + + if (argc<2) + { + printf("%s", "File is not specified"); + return 1; + } + + fopen_s(&input, argv[1], "rb"); //const_pull - read_constant(input, &const_count, &const_index); + if (read_constant(input, &const_count, &const_index) != 0) + return 1; //code_pull startfunc = read_bytecode(input, &phash_table); fclose(input); - + initTOS(); initRStack(); 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) - ip++; break; - case DLOAD: - //DO(DLOAD, "Load double on TOS, inlined into insn stream.", 9) - d1 = *((double*)(code+(++ip))); + case INVALID: + //DO(INVALID, "Invalid instruction.", 1) + ip++; 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); + ip++; break; + case ILOAD0: + //DO(ILOAD0, "Load int 0 on TOS.", 1) + push_int(0); + ip++; break; + case SLOAD0: + //DO(SLOAD0, "Load empty string on TOS.", 1) + push_int((long long)(const_index[0])); + ip++; break; + case DLOAD1: + //DO(DLOAD1, "Load double 1 on TOS.", 1) + push_double(1); + ip++; break; + case ILOAD1: + //DO(ILOAD1, "Load int 1 on TOS.", 1) + push_int(1); + ip++; break; + case DLOADM1: + //DO(DLOADM1, "Load double -1 on TOS.", 1) + push_double(-1); + ip++; break; + case ILOADM1: + //DO(ILOADM1, "Load int -1 on TOS.", 1) + push_int(-1); + ip++; 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); + ip++; 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); + ip++; break; + case DSUB: + //DO(DSUB, "Subtract 2 doubles on TOS (lower from upper), push value back.", 1) + d1 = pop_double(); + d2 = pop_double(); + d2 -= d1; + push_double(d2); + ip++; break; + case ISUB: + //DO(ISUB, "Subtract 2 ints on TOS (lower from upper), push value back.", 1) + i1 = pop_int(); + i2 = pop_int(); + i2 -= i1; + push_int(i2); + ip++; 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); + ip++; 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); + ip++; 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); + ip++; 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); + ip++; 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); + ip++; break; + case DNEG: + //DO(DNEG, "Negate double on TOS.", 1) + d1 = pop_double(); + d1 = -d1; + push_double(d1); + ip++; break; + case INEG: + //DO(INEG, "Negate int on TOS.", 1) + i1 = pop_int(); + i1 = - i1; + push_int(i1); + ip++; 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); + ip++; 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); + ip++; 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); + ip++; break; + case IPRINT: + //DO(IPRINT, "Pop and print integer TOS.", 1) + i1 = pop_int(); + printf("%llu", i1); + ip++; break; + case DPRINT: + //DO(DPRINT, "Pop and print double TOS.", 1) + d1 = pop_double(); + printf("%f", d1); + ip++; break; + case SPRINT: + //DO(SPRINT, "Pop and print string TOS.", 1) + i1 = pop_int(); + printf("%s", (char*)i1); + ip++; break; + case I2D: + //DO(I2D, "Convert int on TOS to double.", 1) + i1 = pop_int(); + d1 = (double)i1; + push_double(d1); + ip++; break; + case D2I: + //DO(D2I, "Convert double on TOS to int.", 1) + d1 = pop_double(); + i1 = (int)d1; + push_int(i1); + ip++; break; + case S2I: + //DO(S2I, "Convert string on TOS to int.", 1) + ip++; break; + case SWAP: + //DO(SWAP, "Swap 2 topmost values.", 1) + i1 = pop_int(); + i2 = pop_int(); + push_int(i1); + push_int(i2); + ip++; break; + case POP: + //DO(POP, "Remove topmost value.", 1) + TOS--; + ip++; break; + case LOADDVAR0: + //DO(LOADDVAR0, "Load double from variable 0, push on TOS.", 1) + d1 = getlocal_double(current_context, 0); + push_double(d1); + ip++;break; + case LOADDVAR1: + //DO(LOADDVAR1, "Load double from variable 1, push on TOS.", 1) + d1 = getlocal_double(current_context, 1); + push_double(d1); + ip++;break; + case LOADDVAR2: + //DO(LOADDVAR2, "Load double from variable 2, push on TOS.", 1) + d1 = getlocal_double(current_context, 2); + push_double(d1); + ip++;break; + case LOADDVAR3: + //DO(LOADDVAR3, "Load double from variable 3, push on TOS.", 1) + d1 = getlocal_double(current_context, 3); + push_double(d1); + ip++; break; + case LOADIVAR0: + //DO(LOADIVAR0, "Load int from variable 0, push on TOS.", 1) + i1 = getlocal_int(current_context, 0); + push_int(i1); + ip++; break; + case LOADIVAR1: + //DO(LOADIVAR1, "Load int from variable 1, push on TOS.", 1) + i1 = getlocal_int(current_context, 1); + push_int(i1); + ip++; break; + case LOADIVAR2: + //DO(LOADIVAR2, "Load int from variable 2, push on TOS.", 1) + i1 = getlocal_int(current_context, 2); + push_int(i1); + ip++; break; + case LOADIVAR3: + //DO(LOADIVAR3, "Load int from variable 3, push on TOS.", 1) + i1 = getlocal_int(current_context, 3); + push_int(i1); + ip++; 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); + ip++; 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); + ip++; 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); + ip++; 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); + ip++; break; + case STOREDVAR0: + //DO(STOREDVAR0, "Pop TOS and store to double variable 0.", 1) + d1 = pop_double(); + putlocal_double(&d1, current_context, 0); + ip++; break; + case STOREDVAR1: + //DO(STOREDVAR1, "Pop TOS and store to double variable 1.", 1) + d1 = pop_double(); + putlocal_double(&d1, current_context, 1); + ip++; break; + case STOREDVAR2: + //DO(STOREDVAR2, "Pop TOS and store to double variable 2.", 1) + d1 = pop_double(); + putlocal_double(&d1, current_context, 2); + ip++; break; + case STOREDVAR3: + //DO(STOREDVAR3, "Pop TOS and store to double variable 3.", 1) + d1 = pop_double(); + putlocal_double(&d1, current_context, 3); + ip++; break; + case STOREIVAR0: + //DO(STOREIVAR0, "Pop TOS and store to int variable 0.", 1) + i1 = pop_int(); + putlocal_int(&i1, current_context, 0); + ip++; break; + case STOREIVAR1: + //DO(STOREIVAR1, "Pop TOS and store to int variable 1.", 1) + i1 = pop_int(); + putlocal_int(&i1, current_context, 1); + ip++; break; + case STOREIVAR2: + //DO(STOREIVAR2, "Pop TOS and store to int variable 2.", 1) + i1 = pop_int(); + putlocal_int(&i1, current_context, 2); + ip++; break; + case STOREIVAR3: + //DO(STOREIVAR3, "Pop TOS and store to int variable 3.", 1) + i1 = pop_int(); + putlocal_int(&i1, current_context, 3); + ip++; break; + case STORESVAR0: + //DO(STORESVAR0, "Pop TOS and store to string variable 0.", 1) + i1 = pop_int(); + putlocal_string((int*)&i1, current_context, 0); + ip++; break; + case STORESVAR1: + //DO(STORESVAR1, "Pop TOS and store to string variable 1.", 1) + i1 = pop_int(); + putlocal_string((int*)&i1, current_context, 1); + ip++; break; + case STORESVAR2: + //DO(STORESVAR2, "Pop TOS and store to string variable 2.", 1) + i1 = pop_int(); + putlocal_string((int*)&i1, current_context, 2); + ip++; break; + case STORESVAR3: + //DO(STORESVAR3, "Pop TOS and store to string variable 3.", 1) + i1 = pop_int(); + putlocal_string((int*)&i1, current_context, 3); + ip++; break; + case LOADDVAR: + //DO(LOADDVAR, "Load double from variable, whose 2-byte is id inlined to insn stream, push on TOS.", 3) + s1 = *((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 = *((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 = *((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 = *((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 = *((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((int*)&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 = *((short*)(code+(++ip))); + ip+=2; + s2 = *((short*)(code+(ip))); + if (find_context(s1) != NULL) + { + d1 = getlocal_double(find_context(s1), s2); push_double(d1); - ip+=8; break; - case ILOAD: - //DO(ILOAD, "Load int on TOS, inlined into insn stream.", 9) - i1 = *((long long*)(code+(++ip))); + } + 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 = *((short*)(code+(++ip))); + ip+=2; + s2 = *((short*)(code+(ip))); + if (find_context(s1) != NULL) + { + i1 = getlocal_int(find_context(s1), s2); 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); - ip++; break; - case ILOAD0: - //DO(ILOAD0, "Load int 0 on TOS.", 1) - push_int(0); - ip++; break; - case DLOAD1: - //DO(DLOAD1, "Load double 1 on TOS.", 1) - push_double(1); - ip++; break; - case ILOAD1: - //DO(ILOAD1, "Load int 1 on TOS.", 1) - push_int(1); - ip++; break; - case DLOADM1: - //DO(DLOADM1, "Load double -1 on TOS.", 1) - push_double(-1); - ip++; break; - case ILOADM1: - //DO(ILOADM1, "Load int -1 on TOS.", 1) - push_int(-1); - ip++; 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); - ip++; 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); - ip++; 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); - ip++; 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); - ip++; 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); - ip++; 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); - ip++; break; - case DDIV: - //DO(DDIV, "Divide 2 doubles on TOS (upper to lower), push value back.", 1) - d1 = pop_double(); - d2 = pop_double(); - d1 /= d2; - push_double(d1); - ip++; break; - case IDIV: - //DO(IDIV, "Divide 2 ints on TOS (upper to lower), push value back.", 1) - i1 = pop_int(); - i2 = pop_int(); - i1 /= i2; - push_int(i1); - ip++; 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 %= i2; - push_int(i1); - ip++; break; - case DNEG: - //DO(DNEG, "Negate double on TOS.", 1) - d1 = pop_double(); - d1 = -d1; - push_double(d1); - ip++; break; - case INEG: - //DO(INEG, "Negate int on TOS.", 1) - i1 = pop_int(); - i1 = - i1; - push_int(i1); - ip++; 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); - ip++; break; - case IAAND: - //DO(IAAND, "Arithmetic AND of 2 ints on TOS, push value back.", 1) - ip++; break; - case IAXOR: - //DO(IAXOR, "Arithmetic XOR of 2 ints on TOS, push value back.", 1) - case IPRINT: - //DO(IPRINT, "Pop and print integer TOS.", 1) - i1 = pop_int(); - printf("%d", i1); - ip++; break; - case DPRINT: - //DO(DPRINT, "Pop and print double TOS.", 1) - d1 = pop_double(); - printf("%f", d1); - ip++; break; - case SPRINT: - //DO(SPRINT, "Pop and print string TOS.", 1) - i1 = pop_int(); - printf("%s", (char*)i1); - ip++; break; - case I2D: - //DO(I2D, "Convert int on TOS to double.", 1) - i1 = pop_int(); - d1 = (double)i1; - push_double(d1); - ip++; break; - case D2I: - //DO(D2I, "Convert double on TOS to int.", 1) - d1 = pop_double(); - i1 = (int)d1; - push_int(i1); - ip++; break; - case SWAP: - //DO(SWAP, "Swap 2 topmost values.", 1) - i1 = pop_int(); - i2 = pop_int(); - push_int(i1); - push_int(i2); - ip++; break; - case POP: - //DO(POP, "Remove topmost value.", 1) - TOS--; - ip++; break; - case STOP: - //DO(STOP, "Stop execution.", 1) - exec_status = 0; - break; - case CALL: - s1 = *((short*)(code+(++ip))); - ip+=2; push_ret(ip); - push_context(current_context); - current_context = create_context(s1, phash_table, &code); - ip = 0; break; - case RETURN: - remove_context(current_context); - current_context = pop_context(); - code = phash_table[current_context->id]->code; - ip = pop_ret(); break; - + } + 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 = *((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 = *((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 = *((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 = *((short*)(code+(++ip))); + ip+=2; + s2 = *((short*)(code+(ip))); + i1 = pop_int(); + if (find_context(s1) != NULL) + { + putlocal_string((int*)&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)); + ip++; 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)); + ip++; break; + case JA: + //DO(JA, "Jump always, next two bytes - signed offset of jump destination.", 3) + s1 = *((short*)(code+(++ip))); + ip += (2+s1); break; + case IFICMPNE: + // DO(IFICMPNE, "Compare two topmost integers and jump if upper != lower, next two bytes - signed offset of jump destination.", 3) + s1 = *((short*)(code+(++ip))); + ip+=2; + i1 = get_int(tp-1); + i2 = get_int(tp-2); + if (i1 != i2) + ip += s1; + break; + case IFICMPE: + //DO(IFICMPE, "Compare two topmost integers and jump if upper == lower, next two bytes - signed offset of jump destination.", 3) + s1 = *((short*)(code+(++ip))); + ip+=2; + i1 = get_int(tp-1); + i2 = get_int(tp-2); + if (i1 == i2) + ip += s1; + break; + case IFICMPG: + //DO(IFICMPG, "Compare two topmost integers and jump if upper > lower, next two bytes - signed offset of jump destination.", 3) + s1 = *((short*)(code+(++ip))); + ip+=2; + i1 = get_int(tp-1); + i2 = get_int(tp-2); + if (i1 > i2) + ip += s1; + break; + case IFICMPGE: + //DO(IFICMPGE, "Compare two topmost integers and jump if upper >= lower, next two bytes - signed offset of jump destination.", 3) + s1 = *((short*)(code+(++ip))); + ip+=2; + i1 = get_int(tp-1); + i2 = get_int(tp-2); + if (i1 >= i2) + ip += s1; + break; + case IFICMPL: + //DO(IFICMPL, "Compare two topmost integers and jump if upper < lower, next two bytes - signed offset of jump destination.", 3) + s1 = *((short*)(code+(++ip))); + ip+=2; + i1 = get_int(tp-1); + i2 = get_int(tp-2); + if (i1 < i2) + ip += s1; + break; + case IFICMPLE: + //DO(IFICMPLE, "Compare two topmost integers and jump if upper <= lower, next two bytes - signed offset of jump destination.", 3) + s1 = *((short*)(code+(++ip))); + ip+=2; + i1 = get_int(tp-1); + i2 = get_int(tp-2); + if (i1 <= i2) + ip += s1; + 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); + ip++; 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 = *((short*)(code+(++ip))); + ip+=2; push_ret(ip); + push_context(current_context); + current_context = create_context(s1, phash_table, &code); + 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(); + ip++; break; } } remove_context(current_context); - getchar(); + 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 index af9e9da..c13bbc4 100644 --- a/VaninVM/OpCode.h +++ b/VaninVM/OpCode.h @@ -8,6 +8,7 @@ enum opcode SLOAD, DLOAD0, ILOAD0, + SLOAD0, DLOAD1, ILOAD1, DLOADM1, @@ -31,10 +32,58 @@ enum opcode 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 + RETURN, + BREAK }; #endif \ No newline at end of file diff --git a/VaninVM/TOS.c b/VaninVM/TOS.c index 25f398b..973fc12 100644 --- a/VaninVM/TOS.c +++ b/VaninVM/TOS.c @@ -15,6 +15,13 @@ long long pop_int() 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; diff --git a/VaninVM/TOS.h b/VaninVM/TOS.h index 68a909c..93572dc 100644 --- a/VaninVM/TOS.h +++ b/VaninVM/TOS.h @@ -13,6 +13,7 @@ int initTOS(); 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 index eea5921..2bc9db8 100644 --- a/VaninVM/opc.txt +++ b/VaninVM/opc.txt @@ -1,11 +1,11 @@ #define FOR_BYTECODES(DO) \ - -DO(INVALID, "Invalid instruction.", 1) \ + ?-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(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) \ @@ -26,60 +26,60 @@ +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(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(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(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 + +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 From 808f62b97e81d66bdcb0041818f2633aae64d04f Mon Sep 17 00:00:00 2001 From: AlexVanin Date: Tue, 28 Jan 2014 13:56:45 +0400 Subject: [PATCH 10/24] Changed the way local variables are works, now it is a bunch of unions. ReturnStack now have changable size. Strins are now char* instead int --- VaninVM/Context.c | 2 +- VaninVM/Context.h | 8 +++++++- VaninVM/LocalVars.c | 21 +++++++++++---------- VaninVM/LocalVars.h | 4 ++-- VaninVM/Main.c | 6 +++--- VaninVM/ReturnStack.c | 4 ++-- VaninVM/ReturnStack.h | 2 +- 7 files changed, 27 insertions(+), 20 deletions(-) diff --git a/VaninVM/Context.c b/VaninVM/Context.c index ff65c06..e1cc2e5 100644 --- a/VaninVM/Context.c +++ b/VaninVM/Context.c @@ -6,7 +6,7 @@ context* create_context(int function, func** hash, char** code) cont = (context*)malloc(sizeof(context)); cont->id = function; - cont->locals=malloc(8*hash[function]->count_locals); + cont->locals=(l_var*)malloc(sizeof(l_var)*hash[function]->count_locals); *(code)=hash[function]->code; return cont; } diff --git a/VaninVM/Context.h b/VaninVM/Context.h index f0eedec..936ca24 100644 --- a/VaninVM/Context.h +++ b/VaninVM/Context.h @@ -4,11 +4,17 @@ #include "CodeHeader.h" #include +typedef union +{ + double d_data; + long long i_data; + char* s_data; +} l_var; typedef struct { int id; - void* locals; + l_var* locals; } context; typedef struct NODE diff --git a/VaninVM/LocalVars.c b/VaninVM/LocalVars.c index fbaab2c..21e5a83 100644 --- a/VaninVM/LocalVars.c +++ b/VaninVM/LocalVars.c @@ -4,35 +4,36 @@ long long getlocal_int(context* cont, int id) { long long result; - result = ((long long*)(cont->locals))[id]; + result = (cont->locals)[id].i_data; return result; } double getlocal_double(context* cont, int id) { double result; - result = ((double*)(cont->locals))[id]; + result = (cont->locals)[id].d_data; return result; } -int getlocal_string(context* cont, int id) +char* getlocal_string(context* cont, int id) { - long long result; - result = ((long long*)(cont->locals))[id]; - return (int)result; + char* result; + result = (cont->locals)[id].s_data; + return result; } void putlocal_int(long long* num, context* cont, int id) { - memcpy(((long long*)cont->locals)+id, num, sizeof(long long)); + //memcpy(((long long*)cont->locals)+id, num, sizeof(long long)); + memcpy((cont->locals)+id, num, sizeof (long long)); } void putlocal_double(double* num, context* cont, int id) { - memcpy(((double*)cont->locals)+id, num, sizeof(double)); + memcpy((cont->locals)+id, num, sizeof(double)); } -void putlocal_string(int* str, context* cont, int id) +void putlocal_string(char* str, context* cont, int id) { - memcpy(((long long*)cont->locals)+id, (long long*)str, sizeof(long long)); + memcpy((cont->locals)+id, str, sizeof(int*)); } diff --git a/VaninVM/LocalVars.h b/VaninVM/LocalVars.h index efb873d..581a0db 100644 --- a/VaninVM/LocalVars.h +++ b/VaninVM/LocalVars.h @@ -4,9 +4,9 @@ long long getlocal_int(context*, int); double getlocal_double(context*, int); -int getlocal_string(context*, int); +char* getlocal_string(context*, int); void putlocal_int(long long*, context*, int); void putlocal_double(double*, context*, int); -void putlocal_string(int*, context*, int); +void putlocal_string(char*, context*, int); #endif \ No newline at end of file diff --git a/VaninVM/Main.c b/VaninVM/Main.c index c476d4e..f7c07b3 100644 --- a/VaninVM/Main.c +++ b/VaninVM/Main.c @@ -21,7 +21,7 @@ int main(int argc, char** argv) double d1, d2; long long i1, i2; short s1, s2; - char* code; + char *code; int ip, startfunc; //ConstSection Variables @@ -52,7 +52,7 @@ int main(int argc, char** argv) initTOS(); - initRStack(); + initRStack(1000); ip = 0; current_context = create_context(startfunc, phash_table, &code); @@ -596,7 +596,7 @@ int main(int argc, char** argv) } } remove_context(current_context); - + getchar(); return 0; } diff --git a/VaninVM/ReturnStack.c b/VaninVM/ReturnStack.c index 45e33b1..85b9522 100644 --- a/VaninVM/ReturnStack.c +++ b/VaninVM/ReturnStack.c @@ -12,9 +12,9 @@ int pop_ret() return num; } -int initRStack() +int initRStack(int size) { - RStack = (int*)calloc(1, 1000); + 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 index 317baf1..74fdab7 100644 --- a/VaninVM/ReturnStack.h +++ b/VaninVM/ReturnStack.h @@ -3,7 +3,7 @@ int* RStack; int rp; -int initRStack(); +int initRStack(int); void push_ret(int); int pop_ret(); #endif \ No newline at end of file From 73c63fa7aa9590314afa853a0079a21de090e270 Mon Sep 17 00:00:00 2001 From: AlexVanin Date: Tue, 28 Jan 2014 14:13:21 +0400 Subject: [PATCH 11/24] Now ip changes in switch statement --- VaninVM/Main.c | 188 ++++++++++++++++++++++++------------------------- 1 file changed, 94 insertions(+), 94 deletions(-) diff --git a/VaninVM/Main.c b/VaninVM/Main.c index f7c07b3..6523a96 100644 --- a/VaninVM/Main.c +++ b/VaninVM/Main.c @@ -60,351 +60,351 @@ int main(int argc, char** argv) while (exec_status) { - switch (code[ip]) + switch (code[ip++]) { case INVALID: //DO(INVALID, "Invalid instruction.", 1) - ip++; break; + break; case DLOAD: //DO(DLOAD, "Load double on TOS, inlined into insn stream.", 9) - d1 = *((double*)(code+(++ip))); + 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))); + i1 = *((long long*)(code+ip)); push_int(i1); ip+=8; break; case SLOAD: - s1 = *((short*)(code+(++ip))); + 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); - ip++; break; + break; case ILOAD0: //DO(ILOAD0, "Load int 0 on TOS.", 1) push_int(0); - ip++; break; + break; case SLOAD0: //DO(SLOAD0, "Load empty string on TOS.", 1) push_int((long long)(const_index[0])); - ip++; break; + break; case DLOAD1: //DO(DLOAD1, "Load double 1 on TOS.", 1) push_double(1); - ip++; break; + break; case ILOAD1: //DO(ILOAD1, "Load int 1 on TOS.", 1) push_int(1); - ip++; break; + break; case DLOADM1: //DO(DLOADM1, "Load double -1 on TOS.", 1) push_double(-1); - ip++; break; + break; case ILOADM1: //DO(ILOADM1, "Load int -1 on TOS.", 1) push_int(-1); - ip++; break; + 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); - ip++; break; + 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); - ip++; break; + break; case DSUB: //DO(DSUB, "Subtract 2 doubles on TOS (lower from upper), push value back.", 1) d1 = pop_double(); d2 = pop_double(); d2 -= d1; push_double(d2); - ip++; break; + break; case ISUB: //DO(ISUB, "Subtract 2 ints on TOS (lower from upper), push value back.", 1) i1 = pop_int(); i2 = pop_int(); i2 -= i1; push_int(i2); - ip++; break; + 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); - ip++; break; + 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); - ip++; break; + 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); - ip++; break; + 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); - ip++; break; + 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); - ip++; break; + break; case DNEG: //DO(DNEG, "Negate double on TOS.", 1) d1 = pop_double(); d1 = -d1; push_double(d1); - ip++; break; + break; case INEG: //DO(INEG, "Negate int on TOS.", 1) i1 = pop_int(); i1 = - i1; push_int(i1); - ip++; break; + 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); - ip++; break; + 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); - ip++; break; + 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); - ip++; break; + break; case IPRINT: //DO(IPRINT, "Pop and print integer TOS.", 1) i1 = pop_int(); printf("%llu", i1); - ip++; break; + break; case DPRINT: //DO(DPRINT, "Pop and print double TOS.", 1) d1 = pop_double(); printf("%f", d1); - ip++; break; + break; case SPRINT: //DO(SPRINT, "Pop and print string TOS.", 1) i1 = pop_int(); printf("%s", (char*)i1); - ip++; break; + break; case I2D: //DO(I2D, "Convert int on TOS to double.", 1) i1 = pop_int(); d1 = (double)i1; push_double(d1); - ip++; break; + break; case D2I: //DO(D2I, "Convert double on TOS to int.", 1) d1 = pop_double(); i1 = (int)d1; push_int(i1); - ip++; break; + break; case S2I: //DO(S2I, "Convert string on TOS to int.", 1) - ip++; break; + break; case SWAP: //DO(SWAP, "Swap 2 topmost values.", 1) i1 = pop_int(); i2 = pop_int(); push_int(i1); push_int(i2); - ip++; break; + break; case POP: //DO(POP, "Remove topmost value.", 1) TOS--; - ip++; break; + break; case LOADDVAR0: //DO(LOADDVAR0, "Load double from variable 0, push on TOS.", 1) d1 = getlocal_double(current_context, 0); push_double(d1); - ip++;break; + break; case LOADDVAR1: //DO(LOADDVAR1, "Load double from variable 1, push on TOS.", 1) d1 = getlocal_double(current_context, 1); push_double(d1); - ip++;break; + break; case LOADDVAR2: //DO(LOADDVAR2, "Load double from variable 2, push on TOS.", 1) d1 = getlocal_double(current_context, 2); push_double(d1); - ip++;break; + break; case LOADDVAR3: //DO(LOADDVAR3, "Load double from variable 3, push on TOS.", 1) d1 = getlocal_double(current_context, 3); push_double(d1); - ip++; break; + break; case LOADIVAR0: //DO(LOADIVAR0, "Load int from variable 0, push on TOS.", 1) i1 = getlocal_int(current_context, 0); push_int(i1); - ip++; break; + break; case LOADIVAR1: //DO(LOADIVAR1, "Load int from variable 1, push on TOS.", 1) i1 = getlocal_int(current_context, 1); push_int(i1); - ip++; break; + break; case LOADIVAR2: //DO(LOADIVAR2, "Load int from variable 2, push on TOS.", 1) i1 = getlocal_int(current_context, 2); push_int(i1); - ip++; break; + break; case LOADIVAR3: //DO(LOADIVAR3, "Load int from variable 3, push on TOS.", 1) i1 = getlocal_int(current_context, 3); push_int(i1); - ip++; break; + 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); - ip++; break; + 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); - ip++; break; + 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); - ip++; break; + 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); - ip++; break; + break; case STOREDVAR0: //DO(STOREDVAR0, "Pop TOS and store to double variable 0.", 1) d1 = pop_double(); putlocal_double(&d1, current_context, 0); - ip++; break; + break; case STOREDVAR1: //DO(STOREDVAR1, "Pop TOS and store to double variable 1.", 1) d1 = pop_double(); putlocal_double(&d1, current_context, 1); - ip++; break; + break; case STOREDVAR2: //DO(STOREDVAR2, "Pop TOS and store to double variable 2.", 1) d1 = pop_double(); putlocal_double(&d1, current_context, 2); - ip++; break; + break; case STOREDVAR3: //DO(STOREDVAR3, "Pop TOS and store to double variable 3.", 1) d1 = pop_double(); putlocal_double(&d1, current_context, 3); - ip++; break; + break; case STOREIVAR0: //DO(STOREIVAR0, "Pop TOS and store to int variable 0.", 1) i1 = pop_int(); putlocal_int(&i1, current_context, 0); - ip++; break; + break; case STOREIVAR1: //DO(STOREIVAR1, "Pop TOS and store to int variable 1.", 1) i1 = pop_int(); putlocal_int(&i1, current_context, 1); - ip++; break; + break; case STOREIVAR2: //DO(STOREIVAR2, "Pop TOS and store to int variable 2.", 1) i1 = pop_int(); putlocal_int(&i1, current_context, 2); - ip++; break; + break; case STOREIVAR3: //DO(STOREIVAR3, "Pop TOS and store to int variable 3.", 1) i1 = pop_int(); putlocal_int(&i1, current_context, 3); - ip++; break; + break; case STORESVAR0: //DO(STORESVAR0, "Pop TOS and store to string variable 0.", 1) i1 = pop_int(); - putlocal_string((int*)&i1, current_context, 0); - ip++; break; + 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((int*)&i1, current_context, 1); - ip++; break; + 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((int*)&i1, current_context, 2); - ip++; break; + 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((int*)&i1, current_context, 3); - ip++; break; + 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 = *((short*)(code+(++ip))); + s1 = *((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 = *((short*)(code+(++ip))); + s1 = *((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 = *((short*)(code+(++ip))); + s1 = *((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 = *((short*)(code+(++ip))); + s1 = *((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 = *((short*)(code+(++ip))); + s1 = *((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))); + s1 = *((short*)(code+ip)); i1 = pop_int(); - putlocal_string((int*)&i1, current_context, s1); + 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 = *((short*)(code+(++ip))); + s1 = *((short*)(code+ip)); ip+=2; - s2 = *((short*)(code+(ip))); + s2 = *((short*)(code+ip)); if (find_context(s1) != NULL) { d1 = getlocal_double(find_context(s1), s2); @@ -418,9 +418,9 @@ int main(int argc, char** argv) 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 = *((short*)(code+(++ip))); + s1 = *((short*)(code+ip)); ip+=2; - s2 = *((short*)(code+(ip))); + s2 = *((short*)(code+ip)); if (find_context(s1) != NULL) { i1 = getlocal_int(find_context(s1), s2); @@ -434,9 +434,9 @@ int main(int argc, char** argv) 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 = *((short*)(code+(++ip))); + s1 = *((short*)(code+ip)); ip+=2; - s2 = *((short*)(code+(ip))); + s2 = *((short*)(code+ip)); if (find_context(s1) != NULL) { i1 = (long long)getlocal_string(find_context(s1), s2); @@ -450,9 +450,9 @@ int main(int argc, char** argv) 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 = *((short*)(code+(++ip))); + s1 = *((short*)(code+ip)); ip+=2; - s2 = *((short*)(code+(ip))); + s2 = *((short*)(code+ip)); d1 = pop_double(); if (find_context(s1) != NULL) { @@ -466,9 +466,9 @@ int main(int argc, char** argv) 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 = *((short*)(code+(++ip))); + s1 = *((short*)(code+ip)); ip+=2; - s2 = *((short*)(code+(ip))); + s2 = *((short*)(code+ip)); i1 = pop_int(); if (find_context(s1) != NULL) { @@ -482,13 +482,13 @@ int main(int argc, char** argv) 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 = *((short*)(code+(++ip))); + s1 = *((short*)(code+ip)); ip+=2; - s2 = *((short*)(code+(ip))); + s2 = *((short*)(code+ip)); i1 = pop_int(); if (find_context(s1) != NULL) { - putlocal_string((int*)&d1, find_context(s1), s2); + putlocal_string((char*)&d1, find_context(s1), s2); } else { @@ -501,20 +501,20 @@ int main(int argc, char** argv) d1 = TOS[tp-1]; d2 = TOS[tp-2]; push_double(cmp_double(&d1, &d2)); - ip++; break; + 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)); - ip++; break; + break; case JA: //DO(JA, "Jump always, next two bytes - signed offset of jump destination.", 3) - s1 = *((short*)(code+(++ip))); + s1 = *((short*)(code+ip)); ip += (2+s1); break; case IFICMPNE: // DO(IFICMPNE, "Compare two topmost integers and jump if upper != lower, next two bytes - signed offset of jump destination.", 3) - s1 = *((short*)(code+(++ip))); + s1 = *((short*)(code+ip)); ip+=2; i1 = get_int(tp-1); i2 = get_int(tp-2); @@ -523,7 +523,7 @@ int main(int argc, char** argv) break; case IFICMPE: //DO(IFICMPE, "Compare two topmost integers and jump if upper == lower, next two bytes - signed offset of jump destination.", 3) - s1 = *((short*)(code+(++ip))); + s1 = *((short*)(code+ip)); ip+=2; i1 = get_int(tp-1); i2 = get_int(tp-2); @@ -532,7 +532,7 @@ int main(int argc, char** argv) break; case IFICMPG: //DO(IFICMPG, "Compare two topmost integers and jump if upper > lower, next two bytes - signed offset of jump destination.", 3) - s1 = *((short*)(code+(++ip))); + s1 = *((short*)(code+ip)); ip+=2; i1 = get_int(tp-1); i2 = get_int(tp-2); @@ -541,7 +541,7 @@ int main(int argc, char** argv) break; case IFICMPGE: //DO(IFICMPGE, "Compare two topmost integers and jump if upper >= lower, next two bytes - signed offset of jump destination.", 3) - s1 = *((short*)(code+(++ip))); + s1 = *((short*)(code+ip)); ip+=2; i1 = get_int(tp-1); i2 = get_int(tp-2); @@ -550,7 +550,7 @@ int main(int argc, char** argv) break; case IFICMPL: //DO(IFICMPL, "Compare two topmost integers and jump if upper < lower, next two bytes - signed offset of jump destination.", 3) - s1 = *((short*)(code+(++ip))); + s1 = *((short*)(code+ip)); ip+=2; i1 = get_int(tp-1); i2 = get_int(tp-2); @@ -559,7 +559,7 @@ int main(int argc, char** argv) break; case IFICMPLE: //DO(IFICMPLE, "Compare two topmost integers and jump if upper <= lower, next two bytes - signed offset of jump destination.", 3) - s1 = *((short*)(code+(++ip))); + s1 = *((short*)(code+ip)); ip+=2; i1 = get_int(tp-1); i2 = get_int(tp-2); @@ -571,14 +571,14 @@ int main(int argc, char** argv) i1 = get_int(tp-1); d1 = TOS[tp-1]; printf("TOS: Double:%e Integer:%llu Hex:%#08llx", d1, i1, i1); - ip++; break; + 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 = *((short*)(code+(++ip))); + s1 = *((short*)(code+ip)); ip+=2; push_ret(ip); push_context(current_context); current_context = create_context(s1, phash_table, &code); @@ -592,7 +592,7 @@ int main(int argc, char** argv) case BREAK: //DO(BREAK, "Breakpoint for the debugger.", 1) getchar(); - ip++; break; + break; } } remove_context(current_context); From 5eda4968c78c5edf2a98b61481e0fe1adedf375f Mon Sep 17 00:00:00 2001 From: AlexVanin Date: Tue, 28 Jan 2014 14:33:26 +0400 Subject: [PATCH 12/24] Changed the way CALL works: not it is copy into local variables arguments from stack --- VaninVM/LocalVars.c | 19 +++++++++++++++---- VaninVM/LocalVars.h | 2 ++ VaninVM/Main.c | 1 + 3 files changed, 18 insertions(+), 4 deletions(-) diff --git a/VaninVM/LocalVars.c b/VaninVM/LocalVars.c index 21e5a83..9c8eeec 100644 --- a/VaninVM/LocalVars.c +++ b/VaninVM/LocalVars.c @@ -1,5 +1,6 @@ #include #include "LocalVars.h" +#include "TOS.h" long long getlocal_int(context* cont, int id) { @@ -24,16 +25,26 @@ char* getlocal_string(context* cont, int id) void putlocal_int(long long* num, context* cont, int id) { - //memcpy(((long long*)cont->locals)+id, num, sizeof(long long)); - memcpy((cont->locals)+id, num, sizeof (long long)); + memmove((cont->locals)+id, num, sizeof (long long)); } void putlocal_double(double* num, context* cont, int id) { - memcpy((cont->locals)+id, num, sizeof(double)); + memmove((cont->locals)+id, num, sizeof(double)); } void putlocal_string(char* str, context* cont, int id) { - memcpy((cont->locals)+id, str, sizeof(int*)); + memmove((cont->locals)+id, str, sizeof(int*)); +} + +void args_to_local(context* cont, func** hash) +{ + int i; + long long tmp; + for (i=(hash[cont->id]->count_args)-1; i>=0; i--) + { + tmp = pop_int(); + memmove(&((cont->locals)[i]), &tmp, sizeof(long long)); + } } diff --git a/VaninVM/LocalVars.h b/VaninVM/LocalVars.h index 581a0db..7853c3c 100644 --- a/VaninVM/LocalVars.h +++ b/VaninVM/LocalVars.h @@ -9,4 +9,6 @@ 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 index 6523a96..71cb5ef 100644 --- a/VaninVM/Main.c +++ b/VaninVM/Main.c @@ -582,6 +582,7 @@ int main(int argc, char** argv) 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) From 3b2abd8de40010ff5746196ad429e3024e9ac39a Mon Sep 17 00:00:00 2001 From: AlexVanin Date: Tue, 28 Jan 2014 14:43:49 +0400 Subject: [PATCH 13/24] Changed layout of Main.c file --- VaninVM/Main.c | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/VaninVM/Main.c b/VaninVM/Main.c index 71cb5ef..b60273c 100644 --- a/VaninVM/Main.c +++ b/VaninVM/Main.c @@ -11,8 +11,21 @@ long long cmp_int(long long* a, long long* b); double cmp_double(double* a, double* b); +void run_intepreter(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]); + +} + +int run_interpreter(char* filename) { //ByteCode Variables FILE* input; @@ -35,14 +48,7 @@ int main(int argc, char** argv) //Running Variable int exec_status = 1; - - if (argc<2) - { - printf("%s", "File is not specified"); - return 1; - } - - fopen_s(&input, argv[1], "rb"); + fopen_s(&input, filename, "rb"); //const_pull if (read_constant(input, &const_count, &const_index) != 0) return 1; From ff0ef7f0bba9ac31cff05bd6fa61b6b8b61a8046 Mon Sep 17 00:00:00 2001 From: AlexVanin Date: Wed, 29 Jan 2014 14:13:11 +0400 Subject: [PATCH 14/24] VaninVM/Main.c --- VaninVM/IOcode.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VaninVM/IOcode.c b/VaninVM/IOcode.c index 90c54e2..ad5ebb5 100644 --- a/VaninVM/IOcode.c +++ b/VaninVM/IOcode.c @@ -2,7 +2,7 @@ #include "CodeHeader.h" #include -int version = 0100; +int version = 100; int read_bytecode(FILE* stream, func*** hash) { From e2d0d562997a051ee423d19155a302c0665b4b60 Mon Sep 17 00:00:00 2001 From: AlexVanin Date: Wed, 29 Jan 2014 21:37:48 +0400 Subject: [PATCH 15/24] Fixed major bug with compiling in release-mode: wrong allocated memory. initTOS now takes size of TOS as parameter. Improved work with contexts: now memory releases after popping context from stack --- VaninVM/Context.c | 5 ++++- VaninVM/IOcode.c | 2 +- VaninVM/Main.c | 13 +++++++------ VaninVM/TOS.c | 4 ++-- VaninVM/TOS.h | 2 +- 5 files changed, 15 insertions(+), 11 deletions(-) diff --git a/VaninVM/Context.c b/VaninVM/Context.c index e1cc2e5..64e5644 100644 --- a/VaninVM/Context.c +++ b/VaninVM/Context.c @@ -27,9 +27,12 @@ void push_context(context* cont) } context* pop_context() { + context* poped = node_last->obj; c_node* last = node_last; node_last = node_last->prev; - return last->obj; + + free(last); + return poped; } //Find Context in Context Stack. diff --git a/VaninVM/IOcode.c b/VaninVM/IOcode.c index ad5ebb5..f1f00c4 100644 --- a/VaninVM/IOcode.c +++ b/VaninVM/IOcode.c @@ -58,7 +58,7 @@ int read_constant(FILE* stream, int* count, char*** index) buffer = (char*)malloc(Const_Header.size_const+1); buffer[0]=0; - *(index) = (char**)malloc(sizeof(char**)*Const_Header.count_const); + *(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 diff --git a/VaninVM/Main.c b/VaninVM/Main.c index b60273c..e7f7b27 100644 --- a/VaninVM/Main.c +++ b/VaninVM/Main.c @@ -11,7 +11,7 @@ long long cmp_int(long long* a, long long* b); double cmp_double(double* a, double* b); -void run_intepreter(char* filename); +int run_interpreter(char* filename); int main(int argc, char** argv) { @@ -21,8 +21,9 @@ int main(int argc, char** argv) printf("%s", "File is not specified"); return 1; } - return_code = run_interpreter(argv[1]); + return_code = run_interpreter(argv[1]); + return return_code; } int run_interpreter(char* filename) @@ -56,12 +57,13 @@ int run_interpreter(char* filename) startfunc = read_bytecode(input, &phash_table); fclose(input); + initTOS(3000); - initTOS(); initRStack(1000); ip = 0; current_context = create_context(startfunc, phash_table, &code); + node_last = NULL; while (exec_status) @@ -70,7 +72,7 @@ int run_interpreter(char* filename) { case INVALID: //DO(INVALID, "Invalid instruction.", 1) - break; + break; case DLOAD: //DO(DLOAD, "Load double on TOS, inlined into insn stream.", 9) d1 = *((double*)(code+ip)); @@ -602,8 +604,7 @@ int run_interpreter(char* filename) break; } } - remove_context(current_context); - getchar(); + remove_context(current_context); return 0; } diff --git a/VaninVM/TOS.c b/VaninVM/TOS.c index 973fc12..af5da47 100644 --- a/VaninVM/TOS.c +++ b/VaninVM/TOS.c @@ -33,9 +33,9 @@ double pop_double() return num; } -int initTOS() +int initTOS(int count) { - TOS = (double*)calloc(1, 12000); + 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 index 93572dc..072a0ba 100644 --- a/VaninVM/TOS.h +++ b/VaninVM/TOS.h @@ -9,7 +9,7 @@ typedef union double* TOS; int tp; -int initTOS(); +int initTOS(int); void push_int(long long); void push_double(double); long long pop_int(); From 9177bdcc2c6daeb7c99e22b1683ff56e6ec12843 Mon Sep 17 00:00:00 2001 From: AlexVanin Date: Wed, 29 Jan 2014 21:42:03 +0400 Subject: [PATCH 16/24] Simple Assembler for VaninVM. Wrote on C#. Short tutor in readme.txt --- AssemblerVVM/Program.cs | 468 ++++++++++++++++++++++++++++++++++++++++ AssemblerVVM/readme.txt | 61 ++++++ 2 files changed, 529 insertions(+) create mode 100644 AssemblerVVM/Program.cs create mode 100644 AssemblerVVM/readme.txt diff --git a/AssemblerVVM/Program.cs b/AssemblerVVM/Program.cs new file mode 100644 index 0000000..e9f53a9 --- /dev/null +++ b/AssemblerVVM/Program.cs @@ -0,0 +1,468 @@ +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(); + + string outname = args[0]+".vvm"; + if (args.Length > 1) + outname = args[1]; + + + int[] pos_d = new int[2] { 0, 0 }; + string[] source = System.IO.File.ReadAllLines(args[0]); + List src = PositionAnalyse(source, ref pos_d, ref FuncPos, ref CodeMARK_POS); + + + using (var bw = new BinaryWriter(File.Open(outname, FileMode.OpenOrCreate))) + { + + HeaderAnalyse(src, pos_d, bw, ref ConstID_VALUE, ref ConstKEY_ID); + funcH_common FuncCommonH = new funcH_common(CRC16_alg("main"), FuncPos.Count); + bw.Write(FuncCommonH.Serialize()); + 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) + { + List src = new List(); + bool func_flag = false; + int pos1 = 0, pos2 = 0, numline = 0; + foreach (string s in input) + if (s != "") + { + if (func_flag == true && Regex.IsMatch(s, @"\w+:")) + { + marks.Add(s.Trim(' ', '\t', ':'), numline); + } + else + { + src.Add(s.Trim(' ', '\t')); + + if (s.Contains(".data")) + posD[0] = src.Count - 1; + if (s.Contains(".endd")) + posD[1] = src.Count - 1; + + if (s.Contains(".proc")) + { + 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) + { + str_header ConstH = new str_header(); + string pattern = "\".*\""; + int j = 1; + for (int i = pos[0] + 1; i < pos[1]; i++) + { + int position = src[i].IndexOf(" "); + string key = src[i].Substring(0, position); + string value = Regex.Match(src[i], pattern).ToString().Trim('"').Replace(@"\n", "\n").Replace(@"\r", "\r") + "\0"; + id_v.Add(j, value); k_id.Add(key, j++); + ConstH.const_count++; ConstH.size_const += (value.Length); + } + 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) + { + 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(' '); + switch (current_str.Length) + { + case 4: + 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: + bc.count_locals = System.Convert.ToInt32(current_str[2]); + name = current_str[1]; + break; + + case 2: + name = current_str[1]; + break; + } + bc.id = CRC16_alg(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)) + 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; + + 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) + { + short result = 0; + if (off > 0) + { + 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 + { + 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) + { + 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 new file mode 100644 index 0000000..5415a0e --- /dev/null +++ b/AssemblerVVM/readme.txt @@ -0,0 +1,61 @@ +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 From 2ff331b755d0c1dc22c74948afc140e598da1a6f Mon Sep 17 00:00:00 2001 From: AlexVanin Date: Wed, 29 Jan 2014 22:09:31 +0400 Subject: [PATCH 17/24] Fixed bug, when hash code of function was sign and it did not took a place in hash table properly --- VaninVM/CodeHeader.h | 4 ++-- VaninVM/Main.c | 55 ++++++++++++++++++++++---------------------- 2 files changed, 30 insertions(+), 29 deletions(-) diff --git a/VaninVM/CodeHeader.h b/VaninVM/CodeHeader.h index 76e2427..9ee8f89 100644 --- a/VaninVM/CodeHeader.h +++ b/VaninVM/CodeHeader.h @@ -11,7 +11,7 @@ struct struct { - short id_start; + unsigned short id_start; int count_code; }ByteCodeH_Common; @@ -24,7 +24,7 @@ struct struct { - short id; + unsigned short id; int count_locals; int count_args; }ByteCodeH_Primary; diff --git a/VaninVM/Main.c b/VaninVM/Main.c index e7f7b27..d96ada4 100644 --- a/VaninVM/Main.c +++ b/VaninVM/Main.c @@ -34,7 +34,8 @@ int run_interpreter(char* filename) //ExecutionProcess Variables double d1, d2; long long i1, i2; - short s1, s2; + unsigned short s1; + short s2; char *code; int ip, startfunc; @@ -374,31 +375,31 @@ int run_interpreter(char* filename) break; case LOADDVAR: //DO(LOADDVAR, "Load double from variable, whose 2-byte is id inlined to insn stream, push on TOS.", 3) - s1 = *((short*)(code+ip)); + 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 = *((short*)(code+ip)); + 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 = *((short*)(code+ip)); + 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 = *((short*)(code+ip)); + 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 = *((short*)(code+ip)); + s1 = *((unsigned short*)(code+ip)); i1 = pop_int(); putlocal_int(&i1, current_context, s1); ip+=2; break; @@ -410,7 +411,7 @@ int run_interpreter(char* filename) 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 = *((short*)(code+ip)); + s1 = *((unsigned short*)(code+ip)); ip+=2; s2 = *((short*)(code+ip)); if (find_context(s1) != NULL) @@ -426,7 +427,7 @@ int run_interpreter(char* filename) 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 = *((short*)(code+ip)); + s1 = *((unsigned short*)(code+ip)); ip+=2; s2 = *((short*)(code+ip)); if (find_context(s1) != NULL) @@ -442,7 +443,7 @@ int run_interpreter(char* filename) 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 = *((short*)(code+ip)); + s1 = *((unsigned short*)(code+ip)); ip+=2; s2 = *((short*)(code+ip)); if (find_context(s1) != NULL) @@ -458,7 +459,7 @@ int run_interpreter(char* filename) 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 = *((short*)(code+ip)); + s1 = *((unsigned short*)(code+ip)); ip+=2; s2 = *((short*)(code+ip)); d1 = pop_double(); @@ -474,7 +475,7 @@ int run_interpreter(char* filename) 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 = *((short*)(code+ip)); + s1 = *((unsigned short*)(code+ip)); ip+=2; s2 = *((short*)(code+ip)); i1 = pop_int(); @@ -490,7 +491,7 @@ int run_interpreter(char* filename) 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 = *((short*)(code+ip)); + s1 = *((unsigned short*)(code+ip)); ip+=2; s2 = *((short*)(code+ip)); i1 = pop_int(); @@ -518,61 +519,61 @@ int run_interpreter(char* filename) break; case JA: //DO(JA, "Jump always, next two bytes - signed offset of jump destination.", 3) - s1 = *((short*)(code+ip)); - ip += (2+s1); break; + 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) - s1 = *((short*)(code+ip)); + s2 = *((short*)(code+ip)); ip+=2; i1 = get_int(tp-1); i2 = get_int(tp-2); if (i1 != i2) - ip += s1; + 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) - s1 = *((short*)(code+ip)); + s2 = *((short*)(code+ip)); ip+=2; i1 = get_int(tp-1); i2 = get_int(tp-2); if (i1 == i2) - ip += s1; + 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) - s1 = *((short*)(code+ip)); + s2 = *((short*)(code+ip)); ip+=2; i1 = get_int(tp-1); i2 = get_int(tp-2); if (i1 > i2) - ip += s1; + 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) - s1 = *((short*)(code+ip)); + s2 = *((short*)(code+ip)); ip+=2; i1 = get_int(tp-1); i2 = get_int(tp-2); if (i1 >= i2) - ip += s1; + 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) - s1 = *((short*)(code+ip)); + s2 = *((short*)(code+ip)); ip+=2; i1 = get_int(tp-1); i2 = get_int(tp-2); if (i1 < i2) - ip += s1; + 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) - s1 = *((short*)(code+ip)); + s2 = *((short*)(code+ip)); ip+=2; i1 = get_int(tp-1); i2 = get_int(tp-2); if (i1 <= i2) - ip += s1; + ip += s2; break; case DUMP: //DO(DUMP, "Dump value on TOS, without removing it.", 1) @@ -586,7 +587,7 @@ int run_interpreter(char* filename) break; case CALL: //DO(CALL, "Call function, next two bytes - unsigned function id.", 3) - s1 = *((short*)(code+ip)); + s1 = *((unsigned short*)(code+ip)); ip+=2; push_ret(ip); push_context(current_context); current_context = create_context(s1, phash_table, &code); From 23b8731e40b37084be4dbc2eaa3a456526b3e4a2 Mon Sep 17 00:00:00 2001 From: AlexVanin Date: Thu, 13 Feb 2014 11:07:19 +0400 Subject: [PATCH 18/24] Fixed bug when arguments of functon where in memory in wrong order --- VaninVM/LocalVars.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VaninVM/LocalVars.c b/VaninVM/LocalVars.c index 9c8eeec..7023762 100644 --- a/VaninVM/LocalVars.c +++ b/VaninVM/LocalVars.c @@ -42,7 +42,7 @@ void args_to_local(context* cont, func** hash) { int i; long long tmp; - for (i=(hash[cont->id]->count_args)-1; i>=0; i--) + for (i=0; i<(hash[cont->id]->count_args); i++) { tmp = pop_int(); memmove(&((cont->locals)[i]), &tmp, sizeof(long long)); From 095dafa97d20f7f9c454b7f5723ca8c0a3279860 Mon Sep 17 00:00:00 2001 From: AlexVanin Date: Fri, 21 Feb 2014 15:00:08 +0400 Subject: [PATCH 19/24] Fixed some bugs with ariphmetic operations --- VaninVM/Main.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/VaninVM/Main.c b/VaninVM/Main.c index d96ada4..502679e 100644 --- a/VaninVM/Main.c +++ b/VaninVM/Main.c @@ -134,15 +134,15 @@ int run_interpreter(char* filename) //DO(DSUB, "Subtract 2 doubles on TOS (lower from upper), push value back.", 1) d1 = pop_double(); d2 = pop_double(); - d2 -= d1; - push_double(d2); + 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(); - i2 -= i1; - push_int(i2); + i1 -= i2; + push_int(i1); break; case DMUL: //DO(DMUL, "Multiply 2 doubles on TOS, push value back.", 1) From c2219325c9d6c6ca945040776095cefe4ed16b34 Mon Sep 17 00:00:00 2001 From: AlexVanin Date: Fri, 21 Feb 2014 15:02:01 +0400 Subject: [PATCH 20/24] Added first final version of Compiler for VaninVM --- CompilerVVM/ByteCode.cs | 456 ++++++++++++++++++++++++++ CompilerVVM/CodeGen.cs | 68 ++++ CompilerVVM/CustomExceptions.cs | 35 ++ CompilerVVM/Parser.cs | 558 ++++++++++++++++++++++++++++++++ CompilerVVM/ProcedureScanner.cs | 53 +++ CompilerVVM/Program.cs | 43 +++ CompilerVVM/TokenScanner.cs | 293 +++++++++++++++++ CompilerVVM/grammar.txt | 43 +++ 8 files changed, 1549 insertions(+) create mode 100644 CompilerVVM/ByteCode.cs create mode 100644 CompilerVVM/CodeGen.cs create mode 100644 CompilerVVM/CustomExceptions.cs create mode 100644 CompilerVVM/Parser.cs create mode 100644 CompilerVVM/ProcedureScanner.cs create mode 100644 CompilerVVM/Program.cs create mode 100644 CompilerVVM/TokenScanner.cs create mode 100644 CompilerVVM/grammar.txt diff --git a/CompilerVVM/ByteCode.cs b/CompilerVVM/ByteCode.cs new file mode 100644 index 0000000..7fb0dfc --- /dev/null +++ b/CompilerVVM/ByteCode.cs @@ -0,0 +1,456 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading.Tasks; + +namespace CompilerVVM +{ + 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; + } + } + + public class ByteCode + { + public static void GenerateByteCode(string[] code, string outname) + { + Dictionary ConstID_VALUE = new Dictionary(); + Dictionary ConstKEY_ID = new Dictionary(); + Dictionary CodeMARK_POS = new Dictionary(); + + List FuncPos = new List(); + + int[] pos_d = new int[2] { 0, 0 }; + string[] source = code; + List src = PositionAnalyse(source, ref pos_d, ref FuncPos, ref CodeMARK_POS); + + + using (var bw = new BinaryWriter(File.Open(outname, FileMode.OpenOrCreate))) + { + + HeaderAnalyse(src, pos_d, bw, ref ConstID_VALUE, ref ConstKEY_ID); + funcH_common FuncCommonH = new funcH_common(CRC16_alg("main"), FuncPos.Count); + bw.Write(FuncCommonH.Serialize()); + for (int i = 0; i < FuncPos.Count; i++) + { + FuncAnalyse(src, FuncPos[i], bw, ConstKEY_ID, CodeMARK_POS); + } + } + } + + private static List PositionAnalyse(string[] input, ref int[] posD, ref List posC, ref Dictionary marks) + { + List src = new List(); + bool func_flag = false; + int pos1 = 0, pos2 = 0, numline = 0; + foreach (string s in input) + if (s != "") + { + if (func_flag == true && Regex.IsMatch(s, @"\w+:")) + { + marks.Add(s.Trim(' ', '\t', ':'), numline); + } + else + { + src.Add(s.Trim(' ', '\t')); + + if (s.Contains(".data")) + posD[0] = src.Count - 1; + if (s.Contains(".endd")) + posD[1] = src.Count - 1; + + if (s.Contains(".proc")) + { + 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; + } + private static void HeaderAnalyse(List src, int[] pos, BinaryWriter bw, ref Dictionary id_v, ref Dictionary k_id) + { + str_header ConstH = new str_header(); + string pattern = "\".*\""; + int j = 1; + for (int i = pos[0] + 1; i < pos[1]; i++) + { + int position = src[i].IndexOf(" "); + string key = src[i].Substring(0, position); + string value = Regex.Match(src[i], pattern).ToString().Trim('"').Replace(@"\n", "\n").Replace(@"\r", "\r") + "\0"; + id_v.Add(j, value); k_id.Add(key, j++); + ConstH.const_count++; ConstH.size_const += (value.Length); + } + bw.Write(ConstH.Serialize()); + for (int i = 1; i < j; i++) + { + bw.Write(Encoding.ASCII.GetBytes(id_v[i])); + } + } + private static void FuncAnalyse(List code, pair pos, BinaryWriter bw, Dictionary dictStr, Dictionary dictJmp) + { + 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(' '); + switch (current_str.Length) + { + case 4: + 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: + bc.count_locals = System.Convert.ToInt32(current_str[2]); + name = current_str[1]; + break; + + case 2: + name = current_str[1]; + break; + } + bc.id = CRC16_alg(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)) + 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; + + bw.Write(sign.Serialize()); + bw.Write(Encoding.ASCII.GetBytes(name)); + bw.Write(bc.Serialize()); + bw.Write(bcode); + } + + private static short FindOffset(List code, pair pos, int curr_pos, int off) + { + short result = 0; + if (off > 0) + { + 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 + { + 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; + } + + private 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; + + } + + private static ushort CRC16_alg(string msg) + { + 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/CompilerVVM/CodeGen.cs b/CompilerVVM/CodeGen.cs new file mode 100644 index 0000000..dea005a --- /dev/null +++ b/CompilerVVM/CodeGen.cs @@ -0,0 +1,68 @@ +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 new file mode 100644 index 0000000..9a4fff8 --- /dev/null +++ b/CompilerVVM/CustomExceptions.cs @@ -0,0 +1,35 @@ +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 new file mode 100644 index 0000000..614d62d --- /dev/null +++ b/CompilerVVM/Parser.cs @@ -0,0 +1,558 @@ +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 new file mode 100644 index 0000000..bd16810 --- /dev/null +++ b/CompilerVVM/ProcedureScanner.cs @@ -0,0 +1,53 @@ +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 new file mode 100644 index 0000000..1226d5a --- /dev/null +++ b/CompilerVVM/Program.cs @@ -0,0 +1,43 @@ +using System; +using System.Collections.Generic; +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 + { + 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"); + return; + } + } + catch (Exception e) + { + Console.Error.WriteLine(e.Message); + } + + } + } +} diff --git a/CompilerVVM/TokenScanner.cs b/CompilerVVM/TokenScanner.cs new file mode 100644 index 0000000..841e3f1 --- /dev/null +++ b/CompilerVVM/TokenScanner.cs @@ -0,0 +1,293 @@ +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 new file mode 100644 index 0000000..ca91cc7 --- /dev/null +++ b/CompilerVVM/grammar.txt @@ -0,0 +1,43 @@ + := + + + := method (* ) + + := int | double | string + := | void + + := * + := | + := 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 + + := + + := . + := " ? " + + := + + := ; + | = ; + | ; + | = ; + | if + | if else + | while + | do until ; + + := + := < | > | == | <= | >= + + := + | + | + | + | + | + | + + := + | - | * | / + + + + + From 6ccb8b56fbf94222713837b72f1f7292eb941d64 Mon Sep 17 00:00:00 2001 From: AlexVanin Date: Mon, 16 Feb 2015 18:26:06 +0800 Subject: [PATCH 21/24] Minor changes: more comments, changed pattern for constant matching --- AssemblerVVM/Program.cs | 104 +++++++++++++++++++++++++++------------- 1 file changed, 70 insertions(+), 34 deletions(-) diff --git a/AssemblerVVM/Program.cs b/AssemblerVVM/Program.cs index e9f53a9..7e55685 100644 --- a/AssemblerVVM/Program.cs +++ b/AssemblerVVM/Program.cs @@ -140,33 +140,34 @@ namespace AssemblerVVM { static int Main(string[] args) { + /* + * + */ if (args.Length < 1) { Console.WriteLine("No input files"); return 1; } - Dictionary ConstID_VALUE = new Dictionary(); + Dictionary ConstID_VALUE = new Dictionary(); Dictionary ConstKEY_ID = new Dictionary(); Dictionary CodeMARK_POS = new Dictionary(); - List FuncPos = new List(); + List FuncPos = new List(); //This array defines first and last line of every procedure - string outname = args[0]+".vvm"; + 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 - int[] pos_d = new int[2] { 0, 0 }; - string[] source = System.IO.File.ReadAllLines(args[0]); List src = PositionAnalyse(source, ref pos_d, ref FuncPos, ref CodeMARK_POS); - - - using (var bw = new BinaryWriter(File.Open(outname, FileMode.OpenOrCreate))) + + 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); - bw.Write(FuncCommonH.Serialize()); + 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); @@ -178,13 +179,22 @@ namespace AssemblerVVM 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 != "") + if (s != "") //Skip empty strings { - if (func_flag == true && Regex.IsMatch(s, @"\w+:")) + if (func_flag == true && Regex.IsMatch(s, @"\w+:")) //Labels cannot be outside of procedure { marks.Add(s.Trim(' ', '\t', ':'), numline); } @@ -192,12 +202,12 @@ namespace AssemblerVVM { src.Add(s.Trim(' ', '\t')); - if (s.Contains(".data")) + 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")) + if (s.Contains(".proc")) //Checking procedure segment { numline = 0; pos1 = src.Count - 1; @@ -218,18 +228,29 @@ namespace AssemblerVVM } return src; } + static void HeaderAnalyse(List src, int[] pos, BinaryWriter bw, ref Dictionary id_v, ref Dictionary k_id) { - str_header ConstH = new str_header(); - string pattern = "\".*\""; + /* + * 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++) + 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).ToString().Trim('"').Replace(@"\n", "\n").Replace(@"\r", "\r") + "\0"; - id_v.Add(j, value); k_id.Add(key, j++); - ConstH.const_count++; ConstH.size_const += (value.Length); + 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++) @@ -237,32 +258,41 @@ namespace AssemblerVVM 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(' '); + + string[] current_str = code[pos.start].Split(' '); //Spliting string in case of arguments for instruction switch (current_str.Length) { - case 4: + 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: + case 3: //1 arg intruction bc.count_locals = System.Convert.ToInt32(current_str[2]); name = current_str[1]; break; - case 2: - name = current_str[1]; + case 2: //No arg + name = current_str[1]; break; } - bc.id = CRC16_alg(name); + bc.id = CRC16_alg(name); //Hash encode for function name name += "\0"; sign.size_signature = name.Length; using (BinaryWriter writer = new BinaryWriter(str)) @@ -289,7 +319,7 @@ namespace AssemblerVVM writer.Write(CRC16_alg(current_str[1])); writer.Write(ushort.Parse(current_str[2])); } - else if (jumps.Contains(current_opc)) + else if (jumps.Contains(current_opc)) //Pain in the arse writer.Write(FindOffset(code, pos, j, ((ushort)dictJmp[current_str[1]]-j))); j++; } @@ -297,7 +327,7 @@ namespace AssemblerVVM byte[] bcode = str.ToArray(); sign.size_bytecode = bcode.Length; - sign.size_func = 22 + sign.size_bytecode + sign.size_signature; + 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)); @@ -307,15 +337,18 @@ namespace AssemblerVVM 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) + 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 + else //Jumping backward { for (int i = curr_pos; i >= curr_pos + off; i--) { @@ -341,6 +374,9 @@ namespace AssemblerVVM 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; From 64c9c01371d0359ec2dcc86afb9cd095905f86ad Mon Sep 17 00:00:00 2001 From: AlexVanin Date: Wed, 18 Feb 2015 12:31:58 +0800 Subject: [PATCH 22/24] Small changes --- CompilerVVM/Program.cs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/CompilerVVM/Program.cs b/CompilerVVM/Program.cs index 1226d5a..b955f6f 100644 --- a/CompilerVVM/Program.cs +++ b/CompilerVVM/Program.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; @@ -17,6 +18,13 @@ namespace CompilerVVM } 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; @@ -29,7 +37,9 @@ namespace CompilerVVM parser = new Parser(scanner.Tokens, TextConst, procscanner.Methods); code = new CodeGen(TextConst, procscanner.Methods); - ByteCode.GenerateByteCode(code.asm, args[0] + ".vvm"); + //ByteCode.GenerateByteCode(code.asm, args[0] + ".vvm"); + System.IO.File.WriteAllLines(args[0] + ".vasm", code.asm); + return; } } From b1eceec1d242d76154cf3275a2295dae55bafbb3 Mon Sep 17 00:00:00 2001 From: AlexVanin Date: Wed, 18 Feb 2015 12:34:57 +0800 Subject: [PATCH 23/24] Delete ByteCode.cs To seperate process: 1) into asm 2) into bytecode --- CompilerVVM/ByteCode.cs | 456 ---------------------------------------- 1 file changed, 456 deletions(-) delete mode 100644 CompilerVVM/ByteCode.cs diff --git a/CompilerVVM/ByteCode.cs b/CompilerVVM/ByteCode.cs deleted file mode 100644 index 7fb0dfc..0000000 --- a/CompilerVVM/ByteCode.cs +++ /dev/null @@ -1,456 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Text; -using System.Text.RegularExpressions; -using System.Threading.Tasks; - -namespace CompilerVVM -{ - 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; - } - } - - public class ByteCode - { - public static void GenerateByteCode(string[] code, string outname) - { - Dictionary ConstID_VALUE = new Dictionary(); - Dictionary ConstKEY_ID = new Dictionary(); - Dictionary CodeMARK_POS = new Dictionary(); - - List FuncPos = new List(); - - int[] pos_d = new int[2] { 0, 0 }; - string[] source = code; - List src = PositionAnalyse(source, ref pos_d, ref FuncPos, ref CodeMARK_POS); - - - using (var bw = new BinaryWriter(File.Open(outname, FileMode.OpenOrCreate))) - { - - HeaderAnalyse(src, pos_d, bw, ref ConstID_VALUE, ref ConstKEY_ID); - funcH_common FuncCommonH = new funcH_common(CRC16_alg("main"), FuncPos.Count); - bw.Write(FuncCommonH.Serialize()); - for (int i = 0; i < FuncPos.Count; i++) - { - FuncAnalyse(src, FuncPos[i], bw, ConstKEY_ID, CodeMARK_POS); - } - } - } - - private static List PositionAnalyse(string[] input, ref int[] posD, ref List posC, ref Dictionary marks) - { - List src = new List(); - bool func_flag = false; - int pos1 = 0, pos2 = 0, numline = 0; - foreach (string s in input) - if (s != "") - { - if (func_flag == true && Regex.IsMatch(s, @"\w+:")) - { - marks.Add(s.Trim(' ', '\t', ':'), numline); - } - else - { - src.Add(s.Trim(' ', '\t')); - - if (s.Contains(".data")) - posD[0] = src.Count - 1; - if (s.Contains(".endd")) - posD[1] = src.Count - 1; - - if (s.Contains(".proc")) - { - 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; - } - private static void HeaderAnalyse(List src, int[] pos, BinaryWriter bw, ref Dictionary id_v, ref Dictionary k_id) - { - str_header ConstH = new str_header(); - string pattern = "\".*\""; - int j = 1; - for (int i = pos[0] + 1; i < pos[1]; i++) - { - int position = src[i].IndexOf(" "); - string key = src[i].Substring(0, position); - string value = Regex.Match(src[i], pattern).ToString().Trim('"').Replace(@"\n", "\n").Replace(@"\r", "\r") + "\0"; - id_v.Add(j, value); k_id.Add(key, j++); - ConstH.const_count++; ConstH.size_const += (value.Length); - } - bw.Write(ConstH.Serialize()); - for (int i = 1; i < j; i++) - { - bw.Write(Encoding.ASCII.GetBytes(id_v[i])); - } - } - private static void FuncAnalyse(List code, pair pos, BinaryWriter bw, Dictionary dictStr, Dictionary dictJmp) - { - 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(' '); - switch (current_str.Length) - { - case 4: - 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: - bc.count_locals = System.Convert.ToInt32(current_str[2]); - name = current_str[1]; - break; - - case 2: - name = current_str[1]; - break; - } - bc.id = CRC16_alg(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)) - 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; - - bw.Write(sign.Serialize()); - bw.Write(Encoding.ASCII.GetBytes(name)); - bw.Write(bc.Serialize()); - bw.Write(bcode); - } - - private static short FindOffset(List code, pair pos, int curr_pos, int off) - { - short result = 0; - if (off > 0) - { - 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 - { - 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; - } - - private 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; - - } - - private static ushort CRC16_alg(string msg) - { - 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 - }; -} From c309d6158a2135d2f5378db203a3f76e14301586 Mon Sep 17 00:00:00 2001 From: Adam Colton Date: Tue, 1 Mar 2016 15:38:55 -0500 Subject: [PATCH 24/24] Initial commit --- readme.md | 8 +++ trustgraph.go | 142 +++++++++++++++++++++++++++++++++++++++++++++ trustgraph_test.go | 113 ++++++++++++++++++++++++++++++++++++ 3 files changed, 263 insertions(+) create mode 100644 readme.md create mode 100644 trustgraph.go create mode 100644 trustgraph_test.go 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") + } +}