language

Some fools attempt at an interpreted language
Log | Files | Refs

commit 2e807b0bc8404bfecca4a04c263ff24c65f9bbef
parent 60bc79a2a1d45616b3d08a2847d575bcd2171199
Author: Paul Longtine <paullongtine@gmail.com>
Date:   Mon Apr 25 14:08:50 2016

if statements work nicely, yadada, now you can include external files

Diffstat:
 doc/SPECIFICATION           |  21 ++++---
 src/lc/interpreter.py       |  15 ++---
 src/lc/main.py              |   4 +-
 src/lc/memonic.py           |   7 +-
 src/lc/parser.py            |  23 ++++++--
 src/lc/test_files/extern.ti |   4 +-
 src/lc/test_files/fibb.ti   |   2 +-
 src/lc/test_files/if.ti     |  26 +---------
 src/vm/Makefile             |   1 +-
 src/vm/inc/ins_def.h        |   7 ++-
 src/vm/inc/ins_mdata.h      |  14 ++---
 src/vm/inc/var_ops.h        |   2 +-
 src/vm/src/ins_def.c        | 134 +++++++++++++++++++++++++++++----------------
 src/vm/src/proc.c           |   4 +-
 src/vm/src/var_ops.c        |  14 ++++-
 15 files changed, 174 insertions(+), 104 deletions(-)

diff --git a/doc/SPECIFICATION b/doc/SPECIFICATION @@ -236,12 +236,15 @@ the result on the stack. Behaves like Arithmetic instructions, besides NOT instruction. Pushes boolean to TOS ------------------------------------------------------------------------------- -50 GTHAN - Greather than -51 LTHAN - Less than -52 EQ - Equal to -53 NOT - Inverts TOS if TOS is boolean -54 OR - Boolean OR -55 AND - Boolean AND +50 GTHAN - Greater than +51 LTHAN - Less than +52 GTHAN_EQ - Greater than or equal to +53 LTHAN_EQ - Less than or equal to +54 EQ - Equal to +55 NEQ - Not equal to +56 NOT - Inverts TOS if TOS is boolean +57 OR - Boolean OR +58 AND - Boolean AND ------------------------------------------------------------------------------- 6 - Loops ------------------------------------------------------------------------------- @@ -269,11 +272,11 @@ to TOS For arrays, key-value arrays, etc ------------------------------------------------------------------------------- -80 PUSH N<ref> - Call 'push' method of <ref> TBI +80 NEW - Call 'new' method of <ref> TBI -81 DEL N<ref> - Call 'delete' method of <ref> TBI +81 DEL - Call 'delete' method of <ref> TBI -82 GET N<ref> - Call 'get' method of <ref> TBI +82 INDEX - Call 'get' method of <ref> TBI 83 GETP N<ref> - Get property of <ref> in object contained in TOS. pushes TBI to stack diff --git a/src/lc/interpreter.py b/src/lc/interpreter.py @@ -99,10 +99,11 @@ class Expression(AbstractToken): ["*", Opcode(OP_MULT)], ["/", Opcode(OP_DIV)], ["==", Opcode(OP_EQ)], - [">", Opcode(OP_GTHAN)], - ["<", Opcode(OP_LTHAN)], - [">=", Opcode(OP_GTHAN_EQ)], - ["=<", Opcode(OP_LTHAN_EQ)] + ["!=", Opcode(OP_NEQ)], + [">", Opcode(OP_LTHAN)], + ["<", Opcode(OP_GTHAN)], + [">=", Opcode(OP_LTHAN_EQ)], + ["=<", Opcode(OP_GTHAN_EQ)] ] self.operator_names = list(map(lambda x: x[0], self.operators)) @@ -220,10 +221,10 @@ class Interpreter(): if i != False: self.line[2].append(i) - def nxt(self): - if len(self.program) >= self.ln + 1: + def nxt(self, n): + if len(self.program) <= self.ln + n: return self.program[self.ln] - return self.program[self.ln + 1] + return self.program[self.ln + n] def new_name(self, index): self.name_dec(self.line[1][index]) diff --git a/src/lc/main.py b/src/lc/main.py @@ -1,3 +1,5 @@ +#!/usr/bin/python3 + from interpreter import * def tobytearray(l, n, ba): @@ -11,8 +13,6 @@ def tobytearray(l, n, ba): if type(i) is int: ba.append(i) - print((" "*n)+hex(i)) - return(ba) diff --git a/src/lc/memonic.py b/src/lc/memonic.py @@ -40,9 +40,10 @@ OP_LTHAN = 0x51 OP_GTHAN_EQ = 0x52 OP_LTHAN_EQ = 0x53 OP_EQ = 0x54 -OP_NOT = 0x55 -OP_OR = 0x56 -OP_AND = 0x57 +OP_NEQ = 0x55 +OP_NOT = 0x56 +OP_OR = 0x57 +OP_AND = 0x58 OP_STARTL = 0x60 OP_CLOOP = 0x61 diff --git a/src/lc/parser.py b/src/lc/parser.py @@ -90,6 +90,16 @@ class Parser(): AtomicSymbol(":") ]) + self.statement_include = Statement( + "include", + expression=[ + AtomicSymbol("include"), + self.label_def, + AtomicSymbol(";") + ], + init=(lambda x: []) + ) + self.statement_codeblock_begin = Statement( "codeblock_begin", expression=[ @@ -147,7 +157,7 @@ class Parser(): x.op(OP_IFDO), x.add_directive(lambda x: [x.op(OP_DONE)], cond=( - lambda x: x.nxt()[0].name in ["else", "else_if"])) + lambda x: x.nxt(1)[0].name in ["else", "else_if"])) ]) ) @@ -165,7 +175,7 @@ class Parser(): x.op(OP_IFDO), x.add_directive(lambda x: [x.op(OP_DONE)], cond=( - lambda x: x.nxt()[0].name in ["else", "else_if"])) + lambda x: x.nxt(1)[0].name in ["else", "else_if"])) ]) ) @@ -295,11 +305,13 @@ class Parser(): ) self.active_tokens = [ + self.statement_include, self.statement_codeblock_begin, self.statement_codeblock_end, self.statement_return, self.statement_print, self.statement_if, + self.statement_else_if, self.statement_else, self.statement_for, self.statement_while, @@ -325,7 +337,12 @@ class Parser(): for a in self.active_tokens: r = a.match(l) if r: - rv.append([a,r,[]]) + if a.name == "include": + t = Parser(r[1][0] + ".ti") + l = t.get_statements() + rv.extend(l) + else: + rv.append([a,r,[]]) break return rv diff --git a/src/lc/test_files/extern.ti b/src/lc/test_files/extern.ti @@ -0,0 +1,4 @@ +func some_external_function(int x) -> int: +{ + return x*2; +} diff --git a/src/lc/test_files/fibb.ti b/src/lc/test_files/fibb.ti @@ -1,7 +1,7 @@ int a = 0; int b = 1; -while a > 100000000: +while a < 100000000: { a = a + b; print b; diff --git a/src/lc/test_files/if.ti b/src/lc/test_files/if.ti @@ -1,25 +1,3 @@ -func test (int y) -> int: -{ - int z = 2; - return y * z; -} +include extern; -int x = 3; - -if 3 == x: -{ - x = x + 1; - - if 4 == x: - { - print "I will die"; - } else if 5 == x: - { - print "If this works"; - } else: - { - print "God help me"; - } -} - -print test(x); +print some_external_function(3); diff --git a/src/vm/Makefile b/src/vm/Makefile @@ -3,6 +3,7 @@ INC_DIR = inc CC = gcc CFLAGS = -std=c99 -Wall -I$(INC_DIR) +DEBUG = -D DEBUG DEPS = $(INC_DIR)/is_mdata.h \ helper.h \ diff --git a/src/vm/inc/ins_def.h b/src/vm/inc/ins_def.h @@ -75,15 +75,22 @@ void _ins_def_LTHAN (rt_t*, bc_cont*); void _ins_def_GTHAN_EQ (rt_t*, bc_cont*); void _ins_def_LTHAN_EQ (rt_t*, bc_cont*); void _ins_def_EQ (rt_t*, bc_cont*); +void _ins_def_NEQ (rt_t*, bc_cont*); void _ins_def_NOT (rt_t*, bc_cont*); void _ins_def_OR (rt_t*, bc_cont*); void _ins_def_AND (rt_t*, bc_cont*); +/* HELPER FUNCTIONS */ +void _ins_def_loop_break(rt_t*); +/* END HELPER FUNCTIONS */ void _ins_def_STARTL (rt_t*, bc_cont*); void _ins_def_CLOOP (rt_t*, bc_cont*); void _ins_def_BREAK (rt_t*, bc_cont*); void _ins_def_ENDL (rt_t*, bc_cont*); +/* HELPER FUNCTIONS */ +void _ins_def_branch_to_end_if(rt_t*); +/* END HELPER FUNCTIONS */ void _ins_def_GOTO (rt_t*, bc_cont*); void _ins_def_JUMPF (rt_t*, bc_cont*); void _ins_def_IFDO (rt_t*, bc_cont*); diff --git a/src/vm/inc/ins_mdata.h b/src/vm/inc/ins_mdata.h @@ -64,9 +64,10 @@ /* G_THAN_EQ */ INS_MDATA[0x52] = encode(0, A_BYTE, A_BYTE, A_BYTE); \ /* G_LHAN_EQ */ INS_MDATA[0x53] = encode(0, A_BYTE, A_BYTE, A_BYTE); \ /* EQ */ INS_MDATA[0x54] = encode(0, A_BYTE, A_BYTE, A_BYTE); \ -/* NOT */ INS_MDATA[0x55] = encode(0, A_BYTE, A_BYTE, A_BYTE); \ -/* OR */ INS_MDATA[0x56] = encode(0, A_BYTE, A_BYTE, A_BYTE); \ -/* AND */ INS_MDATA[0x57] = encode(0, A_BYTE, A_BYTE, A_BYTE); \ +/* NE */ INS_MDATA[0x55] = encode(0, A_BYTE, A_BYTE, A_BYTE); \ +/* NOT */ INS_MDATA[0x56] = encode(0, A_BYTE, A_BYTE, A_BYTE); \ +/* OR */ INS_MDATA[0x57] = encode(0, A_BYTE, A_BYTE, A_BYTE); \ +/* AND */ INS_MDATA[0x58] = encode(0, A_BYTE, A_BYTE, A_BYTE); \ \ /* STARTL */ INS_MDATA[0x60] = encode(0, A_BYTE, A_BYTE, A_BYTE); \ /* CLOOP */ INS_MDATA[0x61] = encode(0, A_BYTE, A_BYTE, A_BYTE); \ @@ -143,9 +144,10 @@ /* G_THAN_EQ */ INS_ADATA[0x52] = encode(0, BTOI, BTOI, BTOI); \ /* G_LHAN_EQ */ INS_ADATA[0x53] = encode(0, BTOI, BTOI, BTOI); \ /* EQ */ INS_ADATA[0x54] = encode(0, BTOI, BTOI, BTOI); \ -/* NOT */ INS_ADATA[0x55] = encode(0, BTOI, BTOI, BTOI); \ -/* OR */ INS_ADATA[0x56] = encode(0, BTOI, BTOI, BTOI); \ -/* AND */ INS_ADATA[0x57] = encode(0, BTOI, BTOI, BTOI); \ +/* NEQ */ INS_ADATA[0x55] = encode(0, BTOI, BTOI, BTOI); \ +/* NOT */ INS_ADATA[0x56] = encode(0, BTOI, BTOI, BTOI); \ +/* OR */ INS_ADATA[0x57] = encode(0, BTOI, BTOI, BTOI); \ +/* AND */ INS_ADATA[0x58] = encode(0, BTOI, BTOI, BTOI); \ \ /* STARTL */ INS_ADATA[0x60] = encode(0, BTOI, BTOI, BTOI); \ /* CLOOP */ INS_ADATA[0x61] = encode(0, BTOI, BTOI, BTOI); \ diff --git a/src/vm/inc/var_ops.h b/src/vm/inc/var_ops.h @@ -48,4 +48,6 @@ var_cont* var_eq_float(var_cont*, var_cont*); var_cont* var_eq_int(var_cont*, var_cont*); var_cont* var_eq(var_cont*, var_cont*); +var_cont* var_not(var_cont*); + #endif //VAR_OPS_H diff --git a/src/vm/src/ins_def.c b/src/vm/src/ins_def.c @@ -56,12 +56,13 @@ void init_ins_def( void ) INS_DEF[0x50] = _ins_def_GTHAN; INS_DEF[0x51] = _ins_def_LTHAN; - INS_DEF[0x51] = _ins_def_GTHAN_EQ; - INS_DEF[0x52] = _ins_def_LTHAN_EQ; - INS_DEF[0x53] = _ins_def_EQ; - INS_DEF[0x54] = _ins_def_NOT; - INS_DEF[0x55] = _ins_def_OR; - INS_DEF[0x56] = _ins_def_AND; + INS_DEF[0x52] = _ins_def_GTHAN_EQ; + INS_DEF[0x53] = _ins_def_LTHAN_EQ; + INS_DEF[0x54] = _ins_def_EQ; + INS_DEF[0x55] = _ins_def_NEQ; + INS_DEF[0x56] = _ins_def_NOT; + INS_DEF[0x57] = _ins_def_OR; + INS_DEF[0x58] = _ins_def_AND; INS_DEF[0x60] = _ins_def_STARTL; INS_DEF[0x61] = _ins_def_CLOOP; @@ -379,8 +380,28 @@ void _ins_def_EQ (rt_t* ctx, bc_cont* line) pc_inc(ctx->pc, 1); } +void _ins_def_NEQ (rt_t* ctx, bc_cont* line) +{ + var_cont* A = stk_pop(ctx->stack); + var_cont* B = stk_pop(ctx->stack); + + var_cont* C = var_eq(A, B); + + C = var_not(C); + + stk_push(ctx->stack, C); + + pc_inc(ctx->pc, 1); +} + void _ins_def_NOT (rt_t* ctx, bc_cont* line) { + var_cont* A = stk_pop(ctx->stack); + + var_cont* C = var_not(A); + + stk_push(ctx->stack, C); + pc_inc(ctx->pc, 1); } void _ins_def_OR (rt_t* ctx, bc_cont* line) @@ -392,6 +413,21 @@ void _ins_def_AND (rt_t* ctx, bc_cont* line) pc_inc(ctx->pc, 1); } +/* HELPER FUNCTIONS */ +void _ins_def_loop_break(rt_t* ctx) +{ + while (pc_safe(ctx->pc)) + { + pc_update(ctx->pc); + pc_inc(ctx->pc, 1); + + if (ctx->pc->line->op == 0x6F) + { + break; + } + } +} +/* END HELPER FUNCIONS */ void _ins_def_STARTL (rt_t* ctx, bc_cont* line) { pc_branch(ctx->pc, ctx->pc->address); @@ -406,16 +442,7 @@ void _ins_def_CLOOP (rt_t* ctx, bc_cont* line) if (value < 1) { pc_return(ctx->pc); - while (pc_safe(ctx->pc)) - { - pc_update(ctx->pc); - pc_inc(ctx->pc, 1); - - if (ctx->pc->line->op == 0x6F) - { - break; - } - } + _ins_def_loop_break(ctx); } else { pc_inc(ctx->pc, 1); @@ -423,20 +450,60 @@ void _ins_def_CLOOP (rt_t* ctx, bc_cont* line) } void _ins_def_BREAK (rt_t* ctx, bc_cont* line) { - pc_inc(ctx->pc, 1); + pc_return(ctx->pc); + + _ins_def_loop_break(ctx); } void _ins_def_ENDL (rt_t* ctx, bc_cont* line) { pc_return(ctx->pc); } -void _ins_def_GOTO (rt_t* ctx, bc_cont* line) +/* HELPER FUNCTIONS */ +void _ins_def_branch_to_end_if(rt_t* ctx) { + int level = 0; + while (pc_safe(ctx->pc)) + { + pc_inc(ctx->pc, 1); + pc_update(ctx->pc); + + // Is this instruction another IF statement? + if (ctx->pc->line->op == 0x72) + { + // Increment the if statement depth counter + level++; + } else + // Is the instruction an ELSE statement? + if (ctx->pc->line->op == 0x73) + { + // We're done here if we're in our scope + if (level == 0) break; + } else + // Is the instruction a DONE statement? + if (ctx->pc->line->op == 0x7E) + { + // And we're not in another if statement, we're done here + if (level == 0) break; + + level--; + } + } + pc_inc(ctx->pc, 1); } +/* END HELPER FUNCTIONS */ +void _ins_def_GOTO (rt_t* ctx, bc_cont* line) +{ + int value = var_data_get_G_INT(line->varg[0]); + + pc_branch(ctx->pc, value); +} void _ins_def_JUMPF (rt_t* ctx, bc_cont* line) { - pc_inc(ctx->pc, 1); + int value = var_data_get_G_INT(line->varg[0]); + + pc_inc(ctx->pc, value); } void _ins_def_IFDO (rt_t* ctx, bc_cont* line) { @@ -447,33 +514,7 @@ void _ins_def_IFDO (rt_t* ctx, bc_cont* line) // If the value is false, find an ELSE statement or DONE statement. if (value < 1) { - int level = 0; - while (pc_safe(ctx->pc)) - { - pc_update(ctx->pc); - pc_inc(ctx->pc, 1); - - // Is this instruction another IF statement? - if (ctx->pc->line->op == 0x72) - { - // Increment the if statement depth counter - level++; - } else - // Is the instruction an ELSE statement? - if (ctx->pc->line->op == 0x73) - { - // We're done here. - break; - } else - // Is the instruction a DONE statement? - if (ctx->pc->line->op == 0x7E) - { - // And we're not in another if statement, we're done here - if (level == 0) break; - - level--; - } - } + _ins_def_branch_to_end_if(ctx); } else { pc_inc(ctx->pc, 1); @@ -482,6 +523,7 @@ void _ins_def_IFDO (rt_t* ctx, bc_cont* line) void _ins_def_ELSE (rt_t* ctx, bc_cont* line) { pc_inc(ctx->pc, 1); + _ins_def_branch_to_end_if(ctx); } void _ins_def_DONE (rt_t* ctx, bc_cont* line) { diff --git a/src/vm/src/proc.c b/src/vm/src/proc.c @@ -34,7 +34,9 @@ void proc_run(rt_t* ctx) for (n = 0; pc_safe(ctx->pc); pc_update(ctx->pc)) { -//printf("%i - %i: %x\n", n, ctx->pc->address, ctx->pc->line->op); +#ifdef DEBUG + printf("LINE[%i]: %x\n", ctx->pc->address, ctx->pc->line->op); +#endif INS_DEF[ctx->pc->line->op](ctx, ctx->pc->line); diff --git a/src/vm/src/var_ops.c b/src/vm/src/var_ops.c @@ -404,8 +404,6 @@ var_cont* var_lthan_eq(var_cont* A, var_cont* B) return rv; } - - var_cont* var_eq_float(var_cont* A, var_cont* B) { var_cont* var = var_new(G_INT); @@ -453,3 +451,15 @@ var_cont* var_eq(var_cont* A, var_cont* B) return rv; } +var_cont* var_not(var_cont* A) +{ + var_cont* rv = var_new(G_INT); + + int val = var_data_get_G_INT(A); + if (val < 1) val = 1; + else val = 0; + + var_set(rv, var_data_alloc_G_INT(val), G_INT); + + return rv; +}