add parser, compiler, breakout opcodes, fix test
This commit is contained in:
parent
697b6de2ff
commit
0d958be440
|
@ -33,7 +33,7 @@ type «token» {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* example */
|
! example
|
||||||
type Vec3 {
|
type Vec3 {
|
||||||
init(x real, y real, z real) {
|
init(x real, y real, z real) {
|
||||||
this.x = x;
|
this.x = x;
|
||||||
|
@ -128,7 +128,7 @@ described in "tunnel" section
|
||||||
:END:
|
:END:
|
||||||
The following is a list of global operators and their effect:
|
The following is a list of global operators and their effect:
|
||||||
|
|
||||||
- //
|
- !
|
||||||
- comment
|
- comment
|
||||||
- ??
|
- ??
|
||||||
- unwrap or
|
- unwrap or
|
||||||
|
@ -225,8 +225,8 @@ also used for letting constants
|
||||||
coerces a type as another type if possible
|
coerces a type as another type if possible
|
||||||
|
|
||||||
#+begin_src zre
|
#+begin_src zre
|
||||||
let «token» = 0; // default is int
|
let «token» = 0; ! default is int
|
||||||
some_functon(«token» as real); // needs a real
|
some_functon(«token» as real); ! needs a real
|
||||||
#+end_src zre
|
#+end_src zre
|
||||||
|
|
||||||
=in=
|
=in=
|
||||||
|
@ -308,7 +308,7 @@ connected tunnel
|
||||||
filesystem or through the graph
|
filesystem or through the graph
|
||||||
|
|
||||||
#+begin_src zre
|
#+begin_src zre
|
||||||
/* client */
|
! client
|
||||||
let endpoint = Client("tcp://path/to/source");
|
let endpoint = Client("tcp://path/to/source");
|
||||||
let tunnel = endpoint.attach(user, auth);
|
let tunnel = endpoint.attach(user, auth);
|
||||||
let data = tunnel.open("/some/resource").read();
|
let data = tunnel.open("/some/resource").read();
|
||||||
|
@ -316,7 +316,7 @@ std.write(data);
|
||||||
data.flush();
|
data.flush();
|
||||||
endpoint.clunk();
|
endpoint.clunk();
|
||||||
|
|
||||||
/* server */
|
! server
|
||||||
let server = Server("tcp://0.0.0.0:25565");
|
let server = Server("tcp://0.0.0.0:25565");
|
||||||
s.bind("/some/resource", fn () str {
|
s.bind("/some/resource", fn () str {
|
||||||
return "hello world";
|
return "hello world";
|
||||||
|
@ -404,9 +404,9 @@ Error handling is much like in C/C++ where a try catch can be used.
|
||||||
|
|
||||||
#+begin_src zre
|
#+begin_src zre
|
||||||
let rr = nil;
|
let rr = nil;
|
||||||
let var = rr ?? 0; /* value is 0 */
|
let var = rr ?? 0; ! value is 0
|
||||||
try {
|
try {
|
||||||
let other_var = 1 / rr; /* will panic */
|
let other_var = 1 / rr; ! will panic
|
||||||
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
print("Caught error ${e}");
|
print("Caught error ${e}");
|
||||||
|
@ -455,7 +455,7 @@ use "./some_local_file.zre"
|
||||||
:CUSTOM_ID: assertion
|
:CUSTOM_ID: assertion
|
||||||
:END:
|
:END:
|
||||||
#+begin_src zre
|
#+begin_src zre
|
||||||
assert(«expression», «expected output») /* returns «error or none» */
|
assert(«expression», «expected output») ! returns «error or none»
|
||||||
#+end_src zre
|
#+end_src zre
|
||||||
|
|
||||||
** Measurements
|
** Measurements
|
||||||
|
|
|
@ -1,18 +1,18 @@
|
||||||
use "common.ztl";
|
use "common.ztl";
|
||||||
|
|
||||||
fn main(argc real, argv str[]) {
|
fn main(argc real, argv str[]) {
|
||||||
let screen_width = 800; /* implied uint32 */
|
let screen_width = 800; ! implied uint32
|
||||||
let screen_height = 450; /* implied uint32 */
|
let screen_height = 450; ! implied uint32
|
||||||
|
|
||||||
let username = argv[0]; /* implied str */
|
let username = argv[0]; ! implied str
|
||||||
let password = argv[1]; /* implied str */
|
let password = argv[1]; ! implied str
|
||||||
|
|
||||||
let me = Player(username, Vec3(0.0, 1.0, 2.0), PURPLE); /* implied Player struct */
|
let me = Player(username, Vec3(0.0, 1.0, 2.0), PURPLE); ! implied Player struct
|
||||||
|
|
||||||
let running = true;
|
let running = true;
|
||||||
while (running) {
|
while (running) {
|
||||||
window("zwl client", screen_width, screen_height) {
|
window("zwl client", screen_width, screen_height) {
|
||||||
splitbox(parent.size * 0.25) {
|
splitbox(parent.size 0.25) {
|
||||||
canvas("2D") {
|
canvas("2D") {
|
||||||
if (button("logout")) {
|
if (button("logout")) {
|
||||||
me.logout();
|
me.logout();
|
||||||
|
@ -20,7 +20,7 @@ fn main(argc real, argv str[]) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
splitbox(parent.size * 0.75) {
|
splitbox(parent.size 0.75) {
|
||||||
canvas("3D") {
|
canvas("3D") {
|
||||||
model(Floor(Vec3(0, 0, 0), 30));
|
model(Floor(Vec3(0, 0, 0), 30));
|
||||||
me.update();
|
me.update();
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
/**
|
!!
|
||||||
* Note that these look like classes but act like structs
|
! Note that these look like classes but act like structs
|
||||||
* the methods actually have a implied struct as their first argument
|
! the methods actually have a implied struct as their first argument
|
||||||
*/
|
!!
|
||||||
|
|
||||||
/**
|
!!
|
||||||
* Camera .
|
! Camera .
|
||||||
*/
|
!!
|
||||||
type Camera {
|
type Camera {
|
||||||
init(pos Vec3, look Vec3) {
|
init(pos Vec3, look Vec3) {
|
||||||
this.setting = "CAMERA_PERSPECTIVE";
|
this.setting = "CAMERA_PERSPECTIVE";
|
||||||
|
@ -16,9 +16,9 @@ type Camera {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
!!
|
||||||
* Player .
|
! Player .
|
||||||
*/
|
!!
|
||||||
type Player {
|
type Player {
|
||||||
init(username str, pos Vec3, color Color) {
|
init(username str, pos Vec3, color Color) {
|
||||||
this.server = Client("tcp://localhost:25565");
|
this.server = Client("tcp://localhost:25565");
|
||||||
|
|
|
@ -0,0 +1,148 @@
|
||||||
|
/**
|
||||||
|
* ZRE - A lightweight: portable programming language for permacomputing.
|
||||||
|
* Copyright (C) 2025 zongor
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation: either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful:
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not: see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "compiler.h"
|
||||||
|
#include "parser.h"
|
||||||
|
|
||||||
|
#define MEMORY_SIZE 1024
|
||||||
|
|
||||||
|
Code *demo_add_compile() {
|
||||||
|
Code *code = (Code *)malloc(sizeof(Code));
|
||||||
|
Word memory[MEMORY_SIZE] = {0}; /* Memory array */
|
||||||
|
code->memory = memory;
|
||||||
|
code->size = MEMORY_SIZE;
|
||||||
|
|
||||||
|
int i = 1;
|
||||||
|
memory[0].c[0] = 0;
|
||||||
|
memory[0].c[1] = 'z';
|
||||||
|
memory[0].c[2] = 'r';
|
||||||
|
memory[0].c[3] = 'e';
|
||||||
|
memory[i++].u = OP_ADD_REAL;
|
||||||
|
memory[i++].u = 102;
|
||||||
|
memory[i++].u = 103;
|
||||||
|
memory[i++].u = 103;
|
||||||
|
memory[i++].u = OP_SUB_UINT;
|
||||||
|
memory[i++].u = 100;
|
||||||
|
memory[i++].u = 101;
|
||||||
|
memory[i++].u = 100;
|
||||||
|
memory[i++].u = OP_JGT_UINT;
|
||||||
|
memory[i++].u = 100;
|
||||||
|
memory[i++].u = 99;
|
||||||
|
memory[i++].u = 1;
|
||||||
|
memory[i++].u = OP_REAL_TO_STRING;
|
||||||
|
memory[i++].u = 103;
|
||||||
|
memory[i++].u = 1;
|
||||||
|
memory[i++].u = 200;
|
||||||
|
memory[i++].u = OP_PRINT_STRING;
|
||||||
|
memory[i++].u = 201;
|
||||||
|
memory[i++].u = 1;
|
||||||
|
memory[i++].u = 1;
|
||||||
|
memory[i++].u = OP_REAL_TO_UINT;
|
||||||
|
memory[i++].u = 103;
|
||||||
|
memory[i++].u = 1;
|
||||||
|
memory[i++].u = 103;
|
||||||
|
memory[i++].u = OP_UINT_TO_STRING;
|
||||||
|
memory[i++].u = 103;
|
||||||
|
memory[i++].u = 1;
|
||||||
|
memory[i++].u = 104;
|
||||||
|
memory[i++].u = OP_PRINT_STRING;
|
||||||
|
memory[i++].u = 105;
|
||||||
|
memory[i++].u = 1;
|
||||||
|
memory[i++].u = 1;
|
||||||
|
memory[i++].u = OP_READ_STRING;
|
||||||
|
memory[i++].u = 1;
|
||||||
|
memory[i++].u = 1;
|
||||||
|
memory[i++].u = 109;
|
||||||
|
memory[i++].u = OP_PRINT_STRING;
|
||||||
|
memory[i++].u = 110;
|
||||||
|
memory[i++].u = 1;
|
||||||
|
memory[i++].u = 1;
|
||||||
|
memory[i++].u = OP_HALT;
|
||||||
|
memory[i++].u = 0;
|
||||||
|
memory[i++].u = 0;
|
||||||
|
memory[i++].u = 0;
|
||||||
|
memory[99].u = 0;
|
||||||
|
memory[100].u = 5;
|
||||||
|
memory[101].u = 1;
|
||||||
|
memory[102].q = FLOAT_TO_Q16_16(5.0f);
|
||||||
|
memory[103].q = FLOAT_TO_Q16_16(5.0f);
|
||||||
|
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
|
Code *compile(char *buffer) {
|
||||||
|
Code *code = (Code *)malloc(sizeof(Code));
|
||||||
|
Word memory[MEMORY_SIZE] = {0}; /* Memory array */
|
||||||
|
code->memory = memory;
|
||||||
|
code->size = MEMORY_SIZE;
|
||||||
|
|
||||||
|
/* char number[100]; */
|
||||||
|
memory[0].c[0] = 0;
|
||||||
|
memory[0].c[1] = 'z';
|
||||||
|
memory[0].c[2] = 'r';
|
||||||
|
memory[0].c[3] = 'e';
|
||||||
|
|
||||||
|
new_Tokenizer(buffer);
|
||||||
|
Token t = nextToken();
|
||||||
|
do {
|
||||||
|
debug_printToken(t);
|
||||||
|
switch (t.type) {
|
||||||
|
case TOKEN_PRINT:
|
||||||
|
case TOKEN_ADD:
|
||||||
|
case TOKEN_INT:
|
||||||
|
/* strncpy(number, t.start, t.length); */
|
||||||
|
/* number[t.length + 1] = '\0'; */
|
||||||
|
/* int i = strtol(number, NULL, 10); */
|
||||||
|
/* memory[ptr].i = i; */
|
||||||
|
/* break; */
|
||||||
|
case TOKEN_LEFT_PAREN:
|
||||||
|
case TOKEN_RIGHT_PAREN:
|
||||||
|
case TOKEN_LEFT_BRACE:
|
||||||
|
case TOKEN_RIGHT_BRACE:
|
||||||
|
case TOKEN_IDENTIFIER:
|
||||||
|
case TOKEN_STRING:
|
||||||
|
case TOKEN_FLOAT:
|
||||||
|
case TOKEN_UINT:
|
||||||
|
case TOKEN_SUB:
|
||||||
|
case TOKEN_MUL:
|
||||||
|
case TOKEN_DIV:
|
||||||
|
case TOKEN_FALSE:
|
||||||
|
case TOKEN_TRUE:
|
||||||
|
case TOKEN_EOF:
|
||||||
|
case TOKEN_ERROR:
|
||||||
|
case TOKEN_MOD:
|
||||||
|
case TOKEN_GT:
|
||||||
|
case TOKEN_LT:
|
||||||
|
case TOKEN_EQ:
|
||||||
|
case TOKEN_GE:
|
||||||
|
case TOKEN_LE:
|
||||||
|
case TOKEN_NE:
|
||||||
|
case TOKEN_NULL:
|
||||||
|
case TOKEN_AND:
|
||||||
|
case TOKEN_OR:
|
||||||
|
case TOKEN_XOR:
|
||||||
|
case TOKEN_SHIFTRIGHT:
|
||||||
|
case TOKEN_SHIFTLEFT:
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
t = nextToken();
|
||||||
|
} while (t.type != TOKEN_EOF);
|
||||||
|
|
||||||
|
return code;
|
||||||
|
}
|
|
@ -0,0 +1,32 @@
|
||||||
|
/**
|
||||||
|
* ZRE - A lightweight, portable programming language for permacomputing.
|
||||||
|
* Copyright (C) 2025 zongor
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#ifndef ZRE_COMPILER_H
|
||||||
|
#define ZRE_COMPILER_H
|
||||||
|
|
||||||
|
#include "opcodes.h"
|
||||||
|
|
||||||
|
typedef struct Code Code;
|
||||||
|
struct Code {
|
||||||
|
Word *memory;
|
||||||
|
uint32_t size;
|
||||||
|
};
|
||||||
|
|
||||||
|
Code* demo_add_compile ();
|
||||||
|
Code* compile (char *buffer);
|
||||||
|
|
||||||
|
#endif
|
70
src/main.c
70
src/main.c
|
@ -15,86 +15,32 @@
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
#include "parser.h"
|
||||||
|
#include "compiler.h"
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
#include "vm.h"
|
#include "vm.h"
|
||||||
#ifdef __EMSCRIPTEN__
|
#ifdef __EMSCRIPTEN__
|
||||||
#include <emscripten.h>
|
#include <emscripten.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* #define MEMORY_SIZE 65536 /\* 64KB memory (adjustable) *\/ */
|
|
||||||
#define MEMORY_SIZE 1024
|
|
||||||
|
|
||||||
Word memory[MEMORY_SIZE] = {0}; /* Memory array */
|
|
||||||
uint32_t pc = 1; /* Program counter */
|
uint32_t pc = 1; /* Program counter */
|
||||||
|
|
||||||
|
Code *code;
|
||||||
|
|
||||||
void mainloop() {
|
void mainloop() {
|
||||||
pc = step_vm(memory, MEMORY_SIZE, pc);
|
pc = step_vm(code->memory, code->size, pc);
|
||||||
if (pc == 0) {
|
if (pc == 0) {
|
||||||
#ifdef __EMSCRIPTEN__
|
#ifdef __EMSCRIPTEN__
|
||||||
emscripten_cancel_main_loop(); /* this should "kill" the app. */
|
emscripten_cancel_main_loop(); /* this should "kill" the app. */
|
||||||
#else
|
#else
|
||||||
core_dump(memory, MEMORY_SIZE);
|
core_dump(code->memory, code->size);
|
||||||
exit(0);
|
exit(0);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int main() {
|
int main(int argc, char **argv) {
|
||||||
|
code = demo_add_compile();
|
||||||
int i = 1;
|
|
||||||
memory[0].c[0] = 'z';
|
|
||||||
memory[0].c[1] = 'r';
|
|
||||||
memory[0].c[2] = 'e';
|
|
||||||
memory[0].c[3] = '0';
|
|
||||||
memory[i++].u = OP_ADD_REAL;
|
|
||||||
memory[i++].u = 102;
|
|
||||||
memory[i++].u = 103;
|
|
||||||
memory[i++].u = 103;
|
|
||||||
memory[i++].u = OP_SUB_UINT;
|
|
||||||
memory[i++].u = 100;
|
|
||||||
memory[i++].u = 101;
|
|
||||||
memory[i++].u = 100;
|
|
||||||
memory[i++].u = OP_JGT_UINT;
|
|
||||||
memory[i++].u = 100;
|
|
||||||
memory[i++].u = 99;
|
|
||||||
memory[i++].u = 1;
|
|
||||||
memory[i++].u = OP_REAL_TO_STRING;
|
|
||||||
memory[i++].u = 103;
|
|
||||||
memory[i++].u = 1;
|
|
||||||
memory[i++].u = 200;
|
|
||||||
memory[i++].u = OP_PRINT_STRING;
|
|
||||||
memory[i++].u = 201;
|
|
||||||
memory[i++].u = 1;
|
|
||||||
memory[i++].u = 1;
|
|
||||||
memory[i++].u = OP_REAL_TO_UINT;
|
|
||||||
memory[i++].u = 103;
|
|
||||||
memory[i++].u = 1;
|
|
||||||
memory[i++].u = 103;
|
|
||||||
memory[i++].u = OP_UINT_TO_STRING;
|
|
||||||
memory[i++].u = 103;
|
|
||||||
memory[i++].u = 1;
|
|
||||||
memory[i++].u = 104;
|
|
||||||
memory[i++].u = OP_PRINT_STRING;
|
|
||||||
memory[i++].u = 105;
|
|
||||||
memory[i++].u = 1;
|
|
||||||
memory[i++].u = 1;
|
|
||||||
memory[i++].u = OP_READ_STRING;
|
|
||||||
memory[i++].u = 1;
|
|
||||||
memory[i++].u = 1;
|
|
||||||
memory[i++].u = 109;
|
|
||||||
memory[i++].u = OP_PRINT_STRING;
|
|
||||||
memory[i++].u = 110;
|
|
||||||
memory[i++].u = 1;
|
|
||||||
memory[i++].u = 1;
|
|
||||||
memory[i++].u = OP_HALT;
|
|
||||||
memory[i++].u = 0;
|
|
||||||
memory[i++].u = 0;
|
|
||||||
memory[i++].u = 0;
|
|
||||||
memory[99].u = 0;
|
|
||||||
memory[100].u = 5;
|
|
||||||
memory[101].u = 1;
|
|
||||||
memory[102].q = FLOAT_TO_Q16_16(5.0f);
|
|
||||||
memory[103].q = FLOAT_TO_Q16_16(5.0f);
|
|
||||||
|
|
||||||
#ifdef __EMSCRIPTEN__
|
#ifdef __EMSCRIPTEN__
|
||||||
emscripten_set_main_loop(mainloop, 0, 1);
|
emscripten_set_main_loop(mainloop, 0, 1);
|
||||||
|
|
|
@ -0,0 +1,84 @@
|
||||||
|
/**
|
||||||
|
* ZRE - A lightweight, portable programming language for permacomputing.
|
||||||
|
* Copyright (C) 2025 zongor
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#ifndef ZRE_OPCODES_H
|
||||||
|
#define ZRE_OPCODES_H
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
|
||||||
|
typedef union {
|
||||||
|
int32_t i; /* Integers */
|
||||||
|
int32_t q; /* Q16.16 (32-bit fixed-point) */
|
||||||
|
uint32_t u; /* Unsigned integers */
|
||||||
|
char c[4]; /* 4 Byte char array for string packing */
|
||||||
|
} Word;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
OP_HALT, /* terminate execution */
|
||||||
|
OP_ADD_INT, /* dest = src1 + src2 */
|
||||||
|
OP_SUB_INT, /* dest = src1 - src2 */
|
||||||
|
OP_MUL_INT, /* dest = src1 * src2 */
|
||||||
|
OP_DIV_INT, /* dest = src1 / src2 */
|
||||||
|
OP_JEQ_INT, /* jump to address dest if src1 as int == src2 as int */
|
||||||
|
OP_JGT_INT, /* jump to address dest if src1 as int > src2 as int*/
|
||||||
|
OP_JLT_INT, /* jump to address dest if src1 as int < src2 as int */
|
||||||
|
OP_JLE_INT, /* jump to address dest if src1 as int <= src2 as int */
|
||||||
|
OP_JGE_INT, /* jump to address dest if src1 as int >= src2 as int*/
|
||||||
|
OP_INT_TO_REAL, /* dest = src1 as f32 */
|
||||||
|
OP_ADD_UINT, /* dest = src1 + src2 */
|
||||||
|
OP_SUB_UINT, /* dest = src1 - src2 */
|
||||||
|
OP_MUL_UINT, /* dest = src1 * src2 */
|
||||||
|
OP_DIV_UINT, /* dest = src1 / src2 */
|
||||||
|
OP_JEQ_UINT, /* jump to address dest if src1 as int == src2 as uint */
|
||||||
|
OP_JGT_UINT, /* jump to address dest if src1 as int > src2 as uint*/
|
||||||
|
OP_JLT_UINT, /* jump to address dest if src1 as int < src2 as uint */
|
||||||
|
OP_JLE_UINT, /* jump to address dest if src1 as int <= src2 as uint */
|
||||||
|
OP_JGE_UINT, /* jump to address dest if src1 as int >= src2 as uint*/
|
||||||
|
OP_UINT_TO_REAL, /* dest = src1 as f32 */
|
||||||
|
OP_ADD_REAL, /* dest = src1 + src2 */
|
||||||
|
OP_SUB_REAL, /* dest = src1 - src2 */
|
||||||
|
OP_MUL_REAL, /* dest = src1 * src2 */
|
||||||
|
OP_DIV_REAL, /* dest = src1 / src2 */
|
||||||
|
OP_JEQ_REAL, /* jump to address dest if src1 as real == src2 as real */
|
||||||
|
OP_JGE_REAL, /* jump to address dest if src1 as real >= src2 as real */
|
||||||
|
OP_JGT_REAL, /* jump to address dest if src1 as real > src2 as real */
|
||||||
|
OP_JLT_REAL, /* jump to address dest if src1 as real < src2 as real */
|
||||||
|
OP_JLE_REAL, /* jump to address dest if src1 as real <= src2 as real */
|
||||||
|
OP_REAL_TO_INT, /* dest = src1 as int */
|
||||||
|
OP_REAL_TO_UINT, /* dest = src1 as int */
|
||||||
|
OP_MOV, /* dest = src1 */
|
||||||
|
OP_JMP, /* jump to address src1 unconditionally */
|
||||||
|
OP_INT_TO_STRING, /* dest = src1 as str */
|
||||||
|
OP_UINT_TO_STRING, /* dest = src1 as str */
|
||||||
|
OP_REAL_TO_STRING, /* dest = src1 as str */
|
||||||
|
OP_READ_STRING, /* dest = read as str */
|
||||||
|
OP_PRINT_STRING, /* write src1 to stdout */
|
||||||
|
OP_CMP_STRING, /* dest = src1 as str == src2 as str */
|
||||||
|
} Opcode;
|
||||||
|
|
||||||
|
/* Constants for Q16.16 */
|
||||||
|
#define Q16_16_SCALE (1 << 16)
|
||||||
|
#define Q16_16_SCALE_FLOAT 65536.0f
|
||||||
|
#define Q16_16_FRACTION_MASK 0x0000FFFF
|
||||||
|
#define Q16_16_INT_MASK 0xFFFF0000
|
||||||
|
|
||||||
|
/* Convert float to Q16.16 (with rounding) */
|
||||||
|
#define FLOAT_TO_Q16_16(f) ((int32_t)((f) * Q16_16_SCALE_FLOAT + 0.5f))
|
||||||
|
/* Convert Q16.16 to float */
|
||||||
|
#define Q16_16_TO_FLOAT(q) ((float)(q) / Q16_16_SCALE_FLOAT)
|
||||||
|
|
||||||
|
#endif
|
346
src/parser.c
346
src/parser.c
|
@ -15,3 +15,349 @@
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "parser.h"
|
||||||
|
|
||||||
|
#define HASHSIZE 150
|
||||||
|
static TokenMap *hashtab_Token[HASHSIZE];
|
||||||
|
|
||||||
|
unsigned int hash_Token(char *s) {
|
||||||
|
unsigned int hashval;
|
||||||
|
for (hashval = 0; *s != '\0'; s++)
|
||||||
|
hashval = *s + 31 * hashval;
|
||||||
|
return hashval % HASHSIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
TokenMap *lookup_Token(char *s) {
|
||||||
|
TokenMap *np;
|
||||||
|
for (np = hashtab_Token[hash_Token(s)]; np != NULL; np = np->next)
|
||||||
|
if (strcmp(s, np->keyword) == 0)
|
||||||
|
return np;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
TokenType get_Token(char *s) {
|
||||||
|
TokenMap *np;
|
||||||
|
for (np = hashtab_Token[hash_Token(s)]; np != NULL; np = np->next)
|
||||||
|
if (strcmp(s, np->keyword) == 0)
|
||||||
|
return np->token;
|
||||||
|
return TOKEN_IDENTIFIER;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *strdup(const char *s) {
|
||||||
|
size_t len = strlen(s) + 1;
|
||||||
|
char *copy = malloc(len);
|
||||||
|
if (copy) {
|
||||||
|
memcpy(copy, s, len);
|
||||||
|
}
|
||||||
|
return copy;
|
||||||
|
}
|
||||||
|
|
||||||
|
TokenMap *put_Token(char *keyword, TokenType token) {
|
||||||
|
TokenMap *np;
|
||||||
|
unsigned int hashval;
|
||||||
|
if ((np = lookup_Token(keyword)) == NULL) {
|
||||||
|
np = (TokenMap *)malloc(sizeof(*np));
|
||||||
|
if (np == NULL || (np->keyword = strdup(keyword)) == NULL)
|
||||||
|
return NULL;
|
||||||
|
hashval = hash_Token(keyword);
|
||||||
|
np->next = hashtab_Token[hashval];
|
||||||
|
hashtab_Token[hashval] = np;
|
||||||
|
}
|
||||||
|
np->token = token;
|
||||||
|
return np;
|
||||||
|
}
|
||||||
|
|
||||||
|
void new_TokenMap() {
|
||||||
|
put_Token("nil", TOKEN_NULL);
|
||||||
|
put_Token("and", TOKEN_AND);
|
||||||
|
put_Token("or", TOKEN_OR);
|
||||||
|
put_Token("xor", TOKEN_XOR);
|
||||||
|
put_Token("mod", TOKEN_MOD);
|
||||||
|
put_Token("eq", TOKEN_EQ);
|
||||||
|
put_Token("ge", TOKEN_GE);
|
||||||
|
put_Token("lt", TOKEN_LT);
|
||||||
|
put_Token("le", TOKEN_LE);
|
||||||
|
put_Token("ne", TOKEN_NE);
|
||||||
|
put_Token("gt", TOKEN_GT);
|
||||||
|
put_Token("ge", TOKEN_GE);
|
||||||
|
put_Token("srl", TOKEN_SHIFTRIGHT);
|
||||||
|
put_Token("sll", TOKEN_SHIFTLEFT);
|
||||||
|
put_Token("int", TOKEN_INT);
|
||||||
|
put_Token("print", TOKEN_PRINT);
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef struct Tokenizer Tokenizer;
|
||||||
|
struct Tokenizer {
|
||||||
|
char *start;
|
||||||
|
char *current;
|
||||||
|
int32_t line;
|
||||||
|
};
|
||||||
|
|
||||||
|
Tokenizer tokenizer;
|
||||||
|
|
||||||
|
void new_Tokenizer(char *src) {
|
||||||
|
tokenizer.start = src;
|
||||||
|
tokenizer.current = src;
|
||||||
|
tokenizer.line = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool isAlpha(char c) {
|
||||||
|
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_' ||
|
||||||
|
c == '\'' || c == '?';
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool isDigit(char c) { return (c >= '0' && c <= '9') || c == '-'; }
|
||||||
|
|
||||||
|
static bool isAtEnd() { return *tokenizer.current == '\0'; }
|
||||||
|
|
||||||
|
static Token makeToken(TokenType type) {
|
||||||
|
Token token;
|
||||||
|
token.type = type;
|
||||||
|
token.start = tokenizer.start;
|
||||||
|
token.length = (int32_t)(tokenizer.current - tokenizer.start);
|
||||||
|
token.line = tokenizer.line;
|
||||||
|
return token;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Token errorToken(char *msg) {
|
||||||
|
Token token;
|
||||||
|
token.type = TOKEN_ERROR;
|
||||||
|
token.start = msg;
|
||||||
|
token.length = (int32_t)strlen(msg);
|
||||||
|
token.line = tokenizer.line;
|
||||||
|
return token;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char advance() {
|
||||||
|
tokenizer.current++;
|
||||||
|
return tokenizer.current[-1];
|
||||||
|
}
|
||||||
|
|
||||||
|
static char peek() { return *tokenizer.current; }
|
||||||
|
|
||||||
|
static char peekNext() {
|
||||||
|
if (isAtEnd())
|
||||||
|
return '\0';
|
||||||
|
return tokenizer.current[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
static void skipWhitespace() {
|
||||||
|
for (;;) {
|
||||||
|
char c = peek();
|
||||||
|
switch (c) {
|
||||||
|
case ' ':
|
||||||
|
case '\r':
|
||||||
|
case '\t':
|
||||||
|
advance();
|
||||||
|
break;
|
||||||
|
case '\n':
|
||||||
|
tokenizer.line++;
|
||||||
|
advance();
|
||||||
|
break;
|
||||||
|
case '!':
|
||||||
|
while (peek() != '\n' && !isAtEnd())
|
||||||
|
advance();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *currentTokenToS() {
|
||||||
|
int32_t size = tokenizer.current - tokenizer.start;
|
||||||
|
char *str = (char *)malloc(sizeof(size));
|
||||||
|
strncpy(str, tokenizer.start, size);
|
||||||
|
str[size] = '\0';
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
static TokenType identifierType() {
|
||||||
|
char *check = currentTokenToS();
|
||||||
|
TokenType t = get_Token(check);
|
||||||
|
free(check);
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Token identifier() {
|
||||||
|
while (isAlpha(peek()) || isDigit(peek()))
|
||||||
|
advance();
|
||||||
|
return makeToken(identifierType());
|
||||||
|
}
|
||||||
|
|
||||||
|
static Token number() {
|
||||||
|
bool is_float = false;
|
||||||
|
while (isDigit(peek()))
|
||||||
|
advance();
|
||||||
|
|
||||||
|
/* Look for a fractional part. */
|
||||||
|
if (peek() == '.' && isDigit(peekNext())) {
|
||||||
|
is_float = true;
|
||||||
|
/* Consume the ".". */
|
||||||
|
advance();
|
||||||
|
|
||||||
|
while (isDigit(peek()))
|
||||||
|
advance();
|
||||||
|
}
|
||||||
|
|
||||||
|
return makeToken((is_float)
|
||||||
|
? TOKEN_FLOAT
|
||||||
|
: TOKEN_INT); /* or measure if ends in postscript */
|
||||||
|
}
|
||||||
|
|
||||||
|
static Token string() {
|
||||||
|
while (peek() != '"' && !isAtEnd()) {
|
||||||
|
if (peek() == '\n')
|
||||||
|
tokenizer.line++;
|
||||||
|
advance();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isAtEnd())
|
||||||
|
return errorToken("Unterminated string.");
|
||||||
|
|
||||||
|
/* The closing quote. */
|
||||||
|
advance();
|
||||||
|
return makeToken(TOKEN_STRING);
|
||||||
|
}
|
||||||
|
|
||||||
|
Token nextToken() {
|
||||||
|
skipWhitespace();
|
||||||
|
tokenizer.start = tokenizer.current;
|
||||||
|
if (isAtEnd())
|
||||||
|
return makeToken(TOKEN_EOF);
|
||||||
|
|
||||||
|
char c = advance();
|
||||||
|
if (isAlpha(c))
|
||||||
|
return identifier();
|
||||||
|
if (isDigit(c))
|
||||||
|
return number();
|
||||||
|
switch (c) {
|
||||||
|
case '(':
|
||||||
|
return makeToken(TOKEN_LEFT_PAREN);
|
||||||
|
case ')':
|
||||||
|
return makeToken(TOKEN_RIGHT_PAREN);
|
||||||
|
case '{':
|
||||||
|
return makeToken(TOKEN_LEFT_BRACE);
|
||||||
|
case '}':
|
||||||
|
return makeToken(TOKEN_RIGHT_BRACE);
|
||||||
|
case '+':
|
||||||
|
return makeToken(TOKEN_ADD);
|
||||||
|
case '/':
|
||||||
|
return makeToken(TOKEN_DIV);
|
||||||
|
case '-':
|
||||||
|
return makeToken(TOKEN_SUB);
|
||||||
|
case '*':
|
||||||
|
return makeToken(TOKEN_MUL);
|
||||||
|
case ';':
|
||||||
|
return makeToken(TOKEN_SEMICOLON);
|
||||||
|
case '"':
|
||||||
|
return string();
|
||||||
|
}
|
||||||
|
|
||||||
|
return errorToken("Unexpected character.");
|
||||||
|
}
|
||||||
|
|
||||||
|
void debug_printToken(Token t) {
|
||||||
|
char *str = currentTokenToS();
|
||||||
|
|
||||||
|
switch (t.type) {
|
||||||
|
case TOKEN_LEFT_PAREN:
|
||||||
|
printf("TOKEN_LEFT_PAREN %s line_no=%d\n", str, t.line);
|
||||||
|
break;
|
||||||
|
case TOKEN_RIGHT_PAREN:
|
||||||
|
printf("TOKEN_RIGHT_PAREN %s line_no=%d\n", str, t.line);
|
||||||
|
break;
|
||||||
|
case TOKEN_LEFT_BRACE:
|
||||||
|
printf("TOKEN_LEFT_BRACE %s line_no=%d\n", str, t.line);
|
||||||
|
break;
|
||||||
|
case TOKEN_RIGHT_BRACE:
|
||||||
|
printf("TOKEN_RIGHT_BRACE %s line_no=%d\n", str, t.line);
|
||||||
|
break;
|
||||||
|
case TOKEN_IDENTIFIER:
|
||||||
|
printf("TOKEN_IDENTIFIER %s line_no=%d\n", str, t.line);
|
||||||
|
break;
|
||||||
|
case TOKEN_STRING:
|
||||||
|
printf("TOKEN_STRING %s line_no=%d\n", str, t.line);
|
||||||
|
break;
|
||||||
|
case TOKEN_FLOAT:
|
||||||
|
printf("TOKEN_FLOAT %s line_no=%d\n", str, t.line);
|
||||||
|
break;
|
||||||
|
case TOKEN_ERROR:
|
||||||
|
printf("TOKEN_ERROR %s line_no=%d\n", str, t.line);
|
||||||
|
break;
|
||||||
|
case TOKEN_FALSE:
|
||||||
|
printf("TOKEN_FALSE %s line_no=%d\n", str, t.line);
|
||||||
|
break;
|
||||||
|
case TOKEN_TRUE:
|
||||||
|
printf("TOKEN_TRUE %s line_no=%d\n", str, t.line);
|
||||||
|
break;
|
||||||
|
case TOKEN_EOF:
|
||||||
|
printf("TOKEN_EOF %s line_no=%d\n", str, t.line);
|
||||||
|
break;
|
||||||
|
case TOKEN_ADD:
|
||||||
|
printf("TOKEN_ADD %s line_no=%d\n", str, t.line);
|
||||||
|
break;
|
||||||
|
case TOKEN_SUB:
|
||||||
|
printf("TOKEN_SUB %s line_no=%d\n", str, t.line);
|
||||||
|
break;
|
||||||
|
case TOKEN_MUL:
|
||||||
|
printf("TOKEN_MUL %s line_no=%d\n", str, t.line);
|
||||||
|
break;
|
||||||
|
case TOKEN_DIV:
|
||||||
|
printf("TOKEN_DIV %s line_no=%d\n", str, t.line);
|
||||||
|
break;
|
||||||
|
case TOKEN_MOD:
|
||||||
|
printf("TOKEN_MOD %s line_no=%d\n", str, t.line);
|
||||||
|
break;
|
||||||
|
case TOKEN_INT:
|
||||||
|
printf("TOKEN_INT %s line_no=%d\n", str, t.line);
|
||||||
|
break;
|
||||||
|
case TOKEN_UINT:
|
||||||
|
printf("TOKEN_UINT %s line_no=%d\n", str, t.line);
|
||||||
|
break;
|
||||||
|
case TOKEN_SHIFTRIGHT:
|
||||||
|
printf("TOKEN_SHIFTRIGHT %s line_no=%d\n", str, t.line);
|
||||||
|
break;
|
||||||
|
case TOKEN_SHIFTLEFT:
|
||||||
|
printf("TOKEN_SHIFTLEFT %s line_no=%d\n", str, t.line);
|
||||||
|
break;
|
||||||
|
case TOKEN_GT:
|
||||||
|
printf("TOKEN_GT %s line_no=%d\n", str, t.line);
|
||||||
|
break;
|
||||||
|
case TOKEN_LT:
|
||||||
|
printf("TOKEN_LT %s line_no=%d\n", str, t.line);
|
||||||
|
break;
|
||||||
|
case TOKEN_EQ:
|
||||||
|
printf("TOKEN_EQ %s line_no=%d\n", str, t.line);
|
||||||
|
break;
|
||||||
|
case TOKEN_GE:
|
||||||
|
printf("TOKEN_GE %s line_no=%d\n", str, t.line);
|
||||||
|
break;
|
||||||
|
case TOKEN_LE:
|
||||||
|
printf("TOKEN_LE %s line_no=%d\n", str, t.line);
|
||||||
|
break;
|
||||||
|
case TOKEN_NE:
|
||||||
|
printf("TOKEN_NE %s line_no=%d\n", str, t.line);
|
||||||
|
break;
|
||||||
|
case TOKEN_NULL:
|
||||||
|
printf("TOKEN_NULL %s line_no=%d\n", str, t.line);
|
||||||
|
break;
|
||||||
|
case TOKEN_AND:
|
||||||
|
printf("TOKEN_AND %s line_no=%d\n", str, t.line);
|
||||||
|
break;
|
||||||
|
case TOKEN_OR:
|
||||||
|
printf("TOKEN_OR %s line_no=%d\n", str, t.line);
|
||||||
|
break;
|
||||||
|
case TOKEN_XOR:
|
||||||
|
printf("TOKEN_XOR %s line_no=%d\n", str, t.line);
|
||||||
|
break;
|
||||||
|
case TOKEN_SEMICOLON:
|
||||||
|
printf("TOKEN_SEMICOLON %s line_no=%d\n", str, t.line);
|
||||||
|
break;
|
||||||
|
case TOKEN_PRINT:
|
||||||
|
printf("TOKEN_PRINT %s line_no=%d\n", str, t.line);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
free(str);
|
||||||
|
}
|
||||||
|
|
83
src/parser.h
83
src/parser.h
|
@ -15,3 +15,86 @@
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
#ifndef ZRE_PARSER_H
|
||||||
|
#define ZRE_PARSER_H
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
typedef enum TokenType
|
||||||
|
{
|
||||||
|
/* Single char tokens */
|
||||||
|
TOKEN_LEFT_PAREN,
|
||||||
|
TOKEN_RIGHT_PAREN,
|
||||||
|
TOKEN_LEFT_BRACE,
|
||||||
|
TOKEN_RIGHT_BRACE,
|
||||||
|
TOKEN_SEMICOLON,
|
||||||
|
/* Literals */
|
||||||
|
TOKEN_IDENTIFIER,
|
||||||
|
TOKEN_STRING,
|
||||||
|
TOKEN_FLOAT,
|
||||||
|
TOKEN_INT,
|
||||||
|
TOKEN_UINT,
|
||||||
|
/* TOKEN_ARRAY, */
|
||||||
|
/* TOKEN_MAP, */
|
||||||
|
TOKEN_FALSE,
|
||||||
|
TOKEN_TRUE,
|
||||||
|
TOKEN_EOF,
|
||||||
|
TOKEN_ERROR,
|
||||||
|
/* Keywords */
|
||||||
|
TOKEN_ADD,
|
||||||
|
TOKEN_SUB,
|
||||||
|
TOKEN_MUL,
|
||||||
|
TOKEN_DIV,
|
||||||
|
TOKEN_MOD,
|
||||||
|
TOKEN_GT,
|
||||||
|
TOKEN_LT,
|
||||||
|
TOKEN_EQ,
|
||||||
|
TOKEN_GE,
|
||||||
|
TOKEN_LE,
|
||||||
|
TOKEN_NE,
|
||||||
|
TOKEN_NULL,
|
||||||
|
TOKEN_AND,
|
||||||
|
TOKEN_OR,
|
||||||
|
TOKEN_XOR,
|
||||||
|
TOKEN_SHIFTRIGHT,
|
||||||
|
TOKEN_SHIFTLEFT,
|
||||||
|
TOKEN_PRINT,
|
||||||
|
} TokenType;
|
||||||
|
|
||||||
|
typedef struct Token Token;
|
||||||
|
struct Token
|
||||||
|
{
|
||||||
|
TokenType type;
|
||||||
|
char *start;
|
||||||
|
int32_t length;
|
||||||
|
int32_t line;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct SourceCode SourceCode;
|
||||||
|
struct SourceCode
|
||||||
|
{
|
||||||
|
size_t size;
|
||||||
|
char *buf;
|
||||||
|
int count;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct TokenMap TokenMap;
|
||||||
|
struct TokenMap
|
||||||
|
{
|
||||||
|
struct TokenMap* next;
|
||||||
|
char* keyword;
|
||||||
|
TokenType token;
|
||||||
|
};
|
||||||
|
|
||||||
|
unsigned int hash_Token(char* s);
|
||||||
|
TokenMap* lookup_Token(char* s);
|
||||||
|
TokenType get_Token(char* s);
|
||||||
|
TokenMap* put_Token(char* keyword, TokenType token);
|
||||||
|
|
||||||
|
void new_Tokenizer (char *src);
|
||||||
|
void new_TokenMap ();
|
||||||
|
void debug_printToken (Token t);
|
||||||
|
Token nextToken();
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
63
src/vm.h
63
src/vm.h
|
@ -18,68 +18,7 @@
|
||||||
#ifndef ZRE_VM_H
|
#ifndef ZRE_VM_H
|
||||||
#define ZRE_VM_H
|
#define ZRE_VM_H
|
||||||
|
|
||||||
#include "common.h"
|
#include "opcodes.h"
|
||||||
|
|
||||||
/* Constants for Q16.16 */
|
|
||||||
#define Q16_16_SCALE (1 << 16)
|
|
||||||
#define Q16_16_SCALE_FLOAT 65536.0f
|
|
||||||
#define Q16_16_FRACTION_MASK 0x0000FFFF
|
|
||||||
#define Q16_16_INT_MASK 0xFFFF0000
|
|
||||||
|
|
||||||
/* Convert float to Q16.16 (with rounding) */
|
|
||||||
#define FLOAT_TO_Q16_16(f) ((int32_t)((f) * Q16_16_SCALE_FLOAT + 0.5f))
|
|
||||||
/* Convert Q16.16 to float */
|
|
||||||
#define Q16_16_TO_FLOAT(q) ((float)(q) / Q16_16_SCALE_FLOAT)
|
|
||||||
|
|
||||||
typedef union {
|
|
||||||
int32_t i; /* Integers */
|
|
||||||
int32_t q; /* Q16.16 (32-bit fixed-point) */
|
|
||||||
uint32_t u; /* Unsigned integers */
|
|
||||||
char c[4]; /* 4 Byte char array for string packing */
|
|
||||||
} Word;
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
OP_HALT, /* terminate execution */
|
|
||||||
OP_ADD_INT, /* dest = src1 + src2 */
|
|
||||||
OP_SUB_INT, /* dest = src1 - src2 */
|
|
||||||
OP_MUL_INT, /* dest = src1 * src2 */
|
|
||||||
OP_DIV_INT, /* dest = src1 / src2 */
|
|
||||||
OP_JEQ_INT, /* jump to address dest if src1 as int == src2 as int */
|
|
||||||
OP_JGT_INT, /* jump to address dest if src1 as int > src2 as int*/
|
|
||||||
OP_JLT_INT, /* jump to address dest if src1 as int < src2 as int */
|
|
||||||
OP_JLE_INT, /* jump to address dest if src1 as int <= src2 as int */
|
|
||||||
OP_JGE_INT, /* jump to address dest if src1 as int >= src2 as int*/
|
|
||||||
OP_INT_TO_REAL, /* dest = src1 as f32 */
|
|
||||||
OP_ADD_UINT, /* dest = src1 + src2 */
|
|
||||||
OP_SUB_UINT, /* dest = src1 - src2 */
|
|
||||||
OP_MUL_UINT, /* dest = src1 * src2 */
|
|
||||||
OP_DIV_UINT, /* dest = src1 / src2 */
|
|
||||||
OP_JEQ_UINT, /* jump to address dest if src1 as int == src2 as uint */
|
|
||||||
OP_JGT_UINT, /* jump to address dest if src1 as int > src2 as uint*/
|
|
||||||
OP_JLT_UINT, /* jump to address dest if src1 as int < src2 as uint */
|
|
||||||
OP_JLE_UINT, /* jump to address dest if src1 as int <= src2 as uint */
|
|
||||||
OP_JGE_UINT, /* jump to address dest if src1 as int >= src2 as uint*/
|
|
||||||
OP_UINT_TO_REAL, /* dest = src1 as f32 */
|
|
||||||
OP_ADD_REAL, /* dest = src1 + src2 */
|
|
||||||
OP_SUB_REAL, /* dest = src1 - src2 */
|
|
||||||
OP_MUL_REAL, /* dest = src1 * src2 */
|
|
||||||
OP_DIV_REAL, /* dest = src1 / src2 */
|
|
||||||
OP_JEQ_REAL, /* jump to address dest if src1 as real == src2 as real */
|
|
||||||
OP_JGE_REAL, /* jump to address dest if src1 as real >= src2 as real */
|
|
||||||
OP_JGT_REAL, /* jump to address dest if src1 as real > src2 as real */
|
|
||||||
OP_JLT_REAL, /* jump to address dest if src1 as real < src2 as real */
|
|
||||||
OP_JLE_REAL, /* jump to address dest if src1 as real <= src2 as real */
|
|
||||||
OP_REAL_TO_INT, /* dest = src1 as int */
|
|
||||||
OP_REAL_TO_UINT, /* dest = src1 as int */
|
|
||||||
OP_MOV, /* dest = src1 */
|
|
||||||
OP_JMP, /* jump to address src1 unconditionally */
|
|
||||||
OP_INT_TO_STRING, /* dest = src1 as str */
|
|
||||||
OP_UINT_TO_STRING, /* dest = src1 as str */
|
|
||||||
OP_REAL_TO_STRING, /* dest = src1 as str */
|
|
||||||
OP_READ_STRING, /* dest = read as str */
|
|
||||||
OP_PRINT_STRING, /* write src1 to stdout */
|
|
||||||
OP_CMP_STRING, /* dest = src1 as str == src2 as str */
|
|
||||||
} Opcode;
|
|
||||||
|
|
||||||
uint32_t step_vm(Word *memory, uint32_t memory_size, uint32_t pc);
|
uint32_t step_vm(Word *memory, uint32_t memory_size, uint32_t pc);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue