write bytecode debugging script and start working on functions
This commit is contained in:
126
debug_arbin.py
Normal file
126
debug_arbin.py
Normal file
@@ -0,0 +1,126 @@
|
|||||||
|
import struct
|
||||||
|
from enum import Enum, EnumMeta, auto
|
||||||
|
|
||||||
|
class AutoEnumMeta(EnumMeta):
|
||||||
|
@classmethod
|
||||||
|
def __prepare__(metacls, clsname, bases, **kwargs):
|
||||||
|
d = super().__prepare__(clsname, bases, **kwargs)
|
||||||
|
d['_next_value'] = 254
|
||||||
|
return d
|
||||||
|
|
||||||
|
def _generate_next_value_(cls, name, start, count, last_values):
|
||||||
|
value = cls._next_value
|
||||||
|
cls._next_value += 1
|
||||||
|
return value
|
||||||
|
|
||||||
|
class OperationType(Enum, metaclass=AutoEnumMeta):
|
||||||
|
OP_LOAD_CONST = auto()
|
||||||
|
OP_DECLARE = auto()
|
||||||
|
OP_LOAD_NULL = auto()
|
||||||
|
OP_JUMP = auto()
|
||||||
|
|
||||||
|
class Types(Enum, metaclass=AutoEnumMeta):
|
||||||
|
TYPE_OP_STRING = auto()
|
||||||
|
TYPE_OP_NUMBER = auto()
|
||||||
|
|
||||||
|
def read_arbin(filename):
|
||||||
|
with open(filename, "rb") as f:
|
||||||
|
# Read and verify file identifier (4 bytes)
|
||||||
|
file_id = f.read(4)
|
||||||
|
if file_id != b"ARBI":
|
||||||
|
raise ValueError("Invalid file identifier")
|
||||||
|
|
||||||
|
# Read version number (uint64_t, little-endian)
|
||||||
|
version_number, = struct.unpack("<Q", f.read(8))
|
||||||
|
|
||||||
|
# Read regCount, constantsSize, bytecodeSize (all uint64_t, little-endian)
|
||||||
|
reg_count, = struct.unpack("<Q", f.read(8))
|
||||||
|
constants_size, = struct.unpack("<Q", f.read(8))
|
||||||
|
bytecode_size, = struct.unpack("<Q", f.read(8))
|
||||||
|
|
||||||
|
# Read constants buffer (raw bytes)
|
||||||
|
constants = f.read(constants_size)
|
||||||
|
|
||||||
|
# Read bytecode array (uint64_t, little-endian)
|
||||||
|
bytecode = []
|
||||||
|
for _ in range(bytecode_size):
|
||||||
|
instr, = struct.unpack("<Q", f.read(8))
|
||||||
|
bytecode.append(instr)
|
||||||
|
|
||||||
|
return {
|
||||||
|
"version": version_number,
|
||||||
|
"register_count": reg_count,
|
||||||
|
"constants_size": constants_size,
|
||||||
|
"bytecode_size": bytecode_size,
|
||||||
|
"constants": constants,
|
||||||
|
"bytecode": bytecode,
|
||||||
|
}
|
||||||
|
|
||||||
|
class print_opcode:
|
||||||
|
def start(registers,data, i):
|
||||||
|
print()
|
||||||
|
match data['bytecode'][i]:
|
||||||
|
case OperationType.OP_LOAD_CONST.value:
|
||||||
|
return print_opcode.OP_LOAD_CONST(registers,data, i)
|
||||||
|
case OperationType.OP_DECLARE.value:
|
||||||
|
return print_opcode.OP_DECLARE(registers,data, i)
|
||||||
|
case OperationType.OP_LOAD_NULL.value:
|
||||||
|
return print_opcode.OP_LOAD_NULL(registers,data, i)
|
||||||
|
|
||||||
|
def OP_LOAD_CONST(registers,data, i) -> int:
|
||||||
|
print("OP_LOAD_CONST ", end="")
|
||||||
|
i+=1
|
||||||
|
register = data["bytecode"][i]
|
||||||
|
print("To Register",register,"", end="")
|
||||||
|
i+=1
|
||||||
|
match data["bytecode"][i]:
|
||||||
|
case Types.TYPE_OP_STRING.value:
|
||||||
|
print("TYPE_OP_STRING ", end="")
|
||||||
|
case Types.TYPE_OP_NUMBER.value:
|
||||||
|
print("TYPE_OP_NUMBER ", end="")
|
||||||
|
i+=1
|
||||||
|
length = data["bytecode"][i]
|
||||||
|
i+=1
|
||||||
|
offset = data["bytecode"][i]
|
||||||
|
i+=1
|
||||||
|
print("Length",length,"", end="")
|
||||||
|
print("Offset",offset,"")
|
||||||
|
registers[register] = data["constants"][offset:offset+length].decode()
|
||||||
|
print("const value:", registers[register])
|
||||||
|
return i
|
||||||
|
|
||||||
|
def OP_DECLARE(registers,data, i) -> int:
|
||||||
|
print("OP_DECLARE ", end="")
|
||||||
|
i+=1
|
||||||
|
length = data["bytecode"][i]
|
||||||
|
i+=1
|
||||||
|
offset = data["bytecode"][i]
|
||||||
|
i+=1
|
||||||
|
from_register = data["bytecode"][i]
|
||||||
|
i+=1
|
||||||
|
print("Name Length",length,"", end="")
|
||||||
|
print("Name Offset",offset,"", end="")
|
||||||
|
print("From Register",from_register,"")
|
||||||
|
print("output: let", data['constants'][offset:offset+length].decode(),'=',registers[from_register])
|
||||||
|
return i
|
||||||
|
def OP_LOAD_NULL(registers,data, i) -> int:
|
||||||
|
print("OP_LOAD_NULL ", end="")
|
||||||
|
i+=1
|
||||||
|
to_register = data["bytecode"][i]
|
||||||
|
i+=1
|
||||||
|
print("To Register",to_register,"")
|
||||||
|
registers[to_register] = "null"
|
||||||
|
return i
|
||||||
|
if __name__ == "__main__":
|
||||||
|
filename = "out.arbin"
|
||||||
|
data = read_arbin(filename)
|
||||||
|
print(f"Version: {data['version']}")
|
||||||
|
print(f"Register Count: {data['register_count']}")
|
||||||
|
print(f"Constants Size: {data['constants_size']} bytes")
|
||||||
|
print(f"Bytecode Length: {data['bytecode_size']} elements")
|
||||||
|
|
||||||
|
registers = ["null"]*data['register_count']
|
||||||
|
|
||||||
|
i=0
|
||||||
|
while i<len(data["bytecode"]):
|
||||||
|
i=print_opcode.start(registers,data,i)
|
||||||
30
src/translator/bytecode_spec.md
Normal file
30
src/translator/bytecode_spec.md
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
# Bytecode Specification
|
||||||
|
|
||||||
|
## OP_LOAD_CONST
|
||||||
|
|
||||||
|
loads and initialises a value from the constant buffer into the provided register.
|
||||||
|
|
||||||
|
this operation 4 operands.
|
||||||
|
|
||||||
|
1. the register to write to.
|
||||||
|
2. the type of data from the constant buffer.
|
||||||
|
3. the length of the data in the constant buffer.
|
||||||
|
4. the offset in the constant buffer.
|
||||||
|
|
||||||
|
## OP_DECLARE
|
||||||
|
|
||||||
|
initilises a variable on the current scope with a given value. errors if the variable is already initilises on the current scope.
|
||||||
|
|
||||||
|
this operation takes 3 operands.
|
||||||
|
|
||||||
|
1. the length of the variable name.
|
||||||
|
2. the offset in the constant buffer of the variable name.
|
||||||
|
3. the register of the given value
|
||||||
|
|
||||||
|
## OP_LOAD_NULL
|
||||||
|
|
||||||
|
sets a given register to null.
|
||||||
|
|
||||||
|
this operation takes 1 operand.
|
||||||
|
|
||||||
|
1. the register to set to null.
|
||||||
@@ -1,33 +1,29 @@
|
|||||||
#include "../translator.h"
|
|
||||||
#include "declaration.h"
|
#include "declaration.h"
|
||||||
#include "../../parser/declaration/declaration.h"
|
#include "../../parser/declaration/declaration.h"
|
||||||
|
#include "../translator.h"
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
size_t translate_parsed_declaration(Translated *translated,
|
size_t translate_parsed_declaration(Translated *translated,
|
||||||
ParsedValue *parsedValue) {
|
DArray delcarations) {
|
||||||
DArray *delcarations = (DArray *)parsedValue->data;
|
set_registers(translated, 1);
|
||||||
set_registers(translated, 2);
|
|
||||||
size_t first = 0;
|
size_t first = 0;
|
||||||
for (size_t i = 0; i < delcarations->size; i++) {
|
for (size_t i = 0; i < delcarations.size; i++) {
|
||||||
// TODO: add function delclaration
|
// TODO: add function delclaration
|
||||||
ParsedSingleDeclaration*singleDeclaration = darray_get(delcarations, i);
|
ParsedSingleDeclaration *singleDeclaration = darray_get(&delcarations, i);
|
||||||
size_t temp = translate_parsed(translated, singleDeclaration->from);
|
size_t temp = translate_parsed(translated, singleDeclaration->from);
|
||||||
if (i==0) first = temp;
|
if (i == 0)
|
||||||
|
first = temp;
|
||||||
size_t length = strlen(singleDeclaration->name);
|
size_t length = strlen(singleDeclaration->name);
|
||||||
size_t offset = arena_push(&translated->constants, singleDeclaration->name, length);
|
size_t offset =
|
||||||
|
arena_push(&translated->constants, singleDeclaration->name, length);
|
||||||
push_instruction_code(translated, OP_LOAD_CONST);
|
|
||||||
push_instruction_code(translated, 1);
|
|
||||||
push_instruction_code(translated, TYPE_OP_STRING);
|
|
||||||
push_instruction_code(translated,length);
|
|
||||||
push_instruction_code(translated, offset);
|
|
||||||
|
|
||||||
push_instruction_code(translated, OP_DECLARE);
|
push_instruction_code(translated, OP_DECLARE);
|
||||||
|
push_instruction_code(translated, length);
|
||||||
|
push_instruction_code(translated, offset);
|
||||||
push_instruction_code(translated, 0);
|
push_instruction_code(translated, 0);
|
||||||
push_instruction_code(translated, 1);
|
|
||||||
}
|
}
|
||||||
if (delcarations->size != 1) {
|
if (delcarations.size != 1) {
|
||||||
push_instruction_code(translated, OP_LOAD_NULL);
|
push_instruction_code(translated, OP_LOAD_NULL);
|
||||||
push_instruction_code(translated, 0);
|
push_instruction_code(translated, 0);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,9 +2,7 @@
|
|||||||
#define BYTECODE_DECLARATION_H
|
#define BYTECODE_DECLARATION_H
|
||||||
#include "../translator.h"
|
#include "../translator.h"
|
||||||
|
|
||||||
size_t translate_parsed_string(Translated *translated, ParsedValue *parsedValue);
|
|
||||||
|
|
||||||
size_t translate_parsed_declaration(Translated *translated,
|
size_t translate_parsed_declaration(Translated *translated,
|
||||||
ParsedValue *parsedValue);
|
DArray delcarations);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
9
src/translator/function/function.c
Normal file
9
src/translator/function/function.c
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
#include "function.h"
|
||||||
|
#include "../translator.h"
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
size_t translate_parsed_function(Translated *translated,
|
||||||
|
ParsedValue *parsedValue) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
8
src/translator/function/function.h
Normal file
8
src/translator/function/function.h
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
#ifndef BYTECODE_FUNCTION_H
|
||||||
|
#define BYTECODE_FUNCTION_H
|
||||||
|
#include "../translator.h"
|
||||||
|
|
||||||
|
size_t translate_parsed_function(Translated *translated,
|
||||||
|
ParsedValue *parsedValue);
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -5,14 +5,13 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
size_t translate_parsed_number(Translated *translated, ParsedValue *parsedValue) {
|
size_t translate_parsed_number(Translated *translated, char *number_str, size_t to_register) {
|
||||||
char *number_str = (char*)parsedValue->data;
|
|
||||||
size_t length = strlen(number_str);
|
size_t length = strlen(number_str);
|
||||||
size_t number_pos = arena_push(&translated->constants, number_str, length);
|
size_t number_pos = arena_push(&translated->constants, number_str, length);
|
||||||
set_registers(translated, 1);
|
set_registers(translated, to_register+1);
|
||||||
|
|
||||||
size_t start = push_instruction_code(translated, OP_LOAD_CONST);
|
size_t start = push_instruction_code(translated, OP_LOAD_CONST);
|
||||||
push_instruction_code(translated, 0);
|
push_instruction_code(translated, to_register);
|
||||||
|
|
||||||
push_instruction_code(translated, TYPE_OP_NUMBER);
|
push_instruction_code(translated, TYPE_OP_NUMBER);
|
||||||
push_instruction_code(translated,length);
|
push_instruction_code(translated,length);
|
||||||
|
|||||||
@@ -2,6 +2,6 @@
|
|||||||
#define BYTECODE_NUMBER_H
|
#define BYTECODE_NUMBER_H
|
||||||
#include "../translator.h"
|
#include "../translator.h"
|
||||||
|
|
||||||
size_t translate_parsed_number(Translated *translated, ParsedValue *parsedValue);
|
size_t translate_parsed_number(Translated *translated, char *number_str, size_t to_register);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -1,18 +1,16 @@
|
|||||||
#include "../translator.h"
|
#include "../translator.h"
|
||||||
#include "../../parser/string/string.h"
|
|
||||||
#include "string.h"
|
#include "string.h"
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
size_t translate_parsed_string(Translated *translated, ParsedValue *parsedValue) {
|
size_t translate_parsed_string(Translated *translated, ParsedString parsedString, size_t to_register) {
|
||||||
ParsedString *parsedString = (ParsedString*)parsedValue->data;
|
size_t string_pos = arena_push(&translated->constants, parsedString.string, parsedString.length);
|
||||||
size_t string_pos = arena_push(&translated->constants, parsedString->string, parsedString->length);
|
set_registers(translated, to_register+1);
|
||||||
set_registers(translated, 1);
|
|
||||||
size_t start = push_instruction_code(translated, OP_LOAD_CONST);
|
size_t start = push_instruction_code(translated, OP_LOAD_CONST);
|
||||||
push_instruction_code(translated, 0);
|
push_instruction_code(translated, to_register);
|
||||||
push_instruction_code(translated, TYPE_OP_STRING);
|
push_instruction_code(translated, TYPE_OP_STRING);
|
||||||
push_instruction_code(translated,parsedString->length);
|
push_instruction_code(translated,parsedString.length);
|
||||||
push_instruction_code(translated, string_pos);
|
push_instruction_code(translated, string_pos);
|
||||||
return start;
|
return start;
|
||||||
}
|
}
|
||||||
@@ -1,7 +1,8 @@
|
|||||||
#ifndef BYTECODE_STRING_H
|
#ifndef BYTECODE_STRING_H
|
||||||
#define BYTECODE_STRING_H
|
#define BYTECODE_STRING_H
|
||||||
#include "../translator.h"
|
#include "../translator.h"
|
||||||
|
#include "../../parser/string/string.h"
|
||||||
|
|
||||||
size_t translate_parsed_string(Translated *translated, ParsedValue *parsedValue);
|
size_t translate_parsed_string(Translated *translated, ParsedString parsedString, size_t to_register);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -82,11 +82,11 @@ void set_registers(Translated *translator, size_t count) {
|
|||||||
size_t translate_parsed(Translated *translated, ParsedValue *parsedValue) {
|
size_t translate_parsed(Translated *translated, ParsedValue *parsedValue) {
|
||||||
switch (parsedValue->type) {
|
switch (parsedValue->type) {
|
||||||
case AST_STRING:
|
case AST_STRING:
|
||||||
return translate_parsed_string(translated, parsedValue);
|
return translate_parsed_string(translated, *((ParsedString*)parsedValue->data), 0);
|
||||||
case AST_DECLARATION:
|
case AST_DECLARATION:
|
||||||
return translate_parsed_declaration(translated, parsedValue);
|
return translate_parsed_declaration(translated, *((DArray*)parsedValue->data));
|
||||||
case AST_NUMBER:
|
case AST_NUMBER:
|
||||||
return translate_parsed_number(translated, parsedValue);
|
return translate_parsed_number(translated, (char*)parsedValue->data, 0);
|
||||||
case AST_NULL:
|
case AST_NULL:
|
||||||
set_registers(translated, 1);
|
set_registers(translated, 1);
|
||||||
size_t output = push_instruction_code(translated, OP_LOAD_NULL);
|
size_t output = push_instruction_code(translated, OP_LOAD_NULL);
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
typedef enum { OP_LOAD_CONST = 255, OP_DECLARE, OP_LOAD_NULL, OP_JUMP } OperationType;
|
typedef enum { OP_LOAD_CONST = 255, OP_DECLARE, OP_LOAD_NULL } OperationType;
|
||||||
typedef enum { TYPE_OP_STRING = 255, TYPE_OP_NUMBER } types;
|
typedef enum { TYPE_OP_STRING = 255, TYPE_OP_NUMBER } types;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
|||||||
Reference in New Issue
Block a user