Compare commits
28 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| b602e2ff87 | |||
| 0b99eb7b0c | |||
| 2505cedc79 | |||
| d7035a59c8 | |||
| ea584d8950 | |||
| 2ce9a0cf42 | |||
| b77f0fb50d | |||
| edb5a52562 | |||
| 9dc9316853 | |||
| a864a1a226 | |||
| c645026620 | |||
| a9ccd65da1 | |||
| 0da5201829 | |||
| 6be29ed8c5 | |||
| 6341d3337f | |||
| d4f952eafc | |||
| d5bc07d3b3 | |||
| 5a851f6fbe | |||
| d8c6a3ec27 | |||
| b5883e248b | |||
| 52048f2466 | |||
| 6b8e95d250 | |||
| 5721edc2d1 | |||
| db52c13613 | |||
| 7290efe069 | |||
| 0cf92bdeae | |||
| 4c9a2e5378 | |||
| 1e11e9eea7 |
@@ -1,17 +1,26 @@
|
|||||||
name: Comprehensive Tests
|
name: Continuous Integration v1.x
|
||||||
|
|
||||||
|
#trigger when these occur
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches: [ "main", "dev" ]
|
branches:
|
||||||
|
- v1
|
||||||
pull_request:
|
pull_request:
|
||||||
branches: [ "main" ]
|
types:
|
||||||
|
- opened
|
||||||
|
- edited
|
||||||
|
- reopened
|
||||||
|
branches:
|
||||||
|
- v1
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
#testing the CI workflows under multiple supported conditions
|
||||||
jobs:
|
jobs:
|
||||||
test-valgrind:
|
test-valgrind:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
- name: install valgrind
|
- name: install valgrind
|
||||||
run: sudo apt install valgrind
|
run: sudo apt install valgrind
|
||||||
- name: make test (valgrind)
|
- name: make test (valgrind)
|
||||||
@@ -21,7 +30,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
- name: make test (sanitized)
|
- name: make test (sanitized)
|
||||||
run: make test-sanitized
|
run: make test-sanitized
|
||||||
|
|
||||||
@@ -29,6 +38,6 @@ jobs:
|
|||||||
runs-on: windows-latest
|
runs-on: windows-latest
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
- name: make test (mingw32)
|
- name: make test (mingw32)
|
||||||
run: make test
|
run: make test
|
||||||
+56
-32
@@ -1,35 +1,59 @@
|
|||||||
#Editor generated files
|
# Prerequisites
|
||||||
*.suo
|
*.d
|
||||||
*.ncb
|
|
||||||
*.user
|
|
||||||
compile_commands.json
|
|
||||||
|
|
||||||
#Directories
|
# Object files
|
||||||
Release/
|
|
||||||
Debug/
|
|
||||||
Out/
|
|
||||||
release/
|
|
||||||
debug/
|
|
||||||
out/
|
|
||||||
bin/
|
|
||||||
.cache/
|
|
||||||
.vs/
|
|
||||||
|
|
||||||
#Project generated files
|
|
||||||
*.db
|
|
||||||
*.o
|
*.o
|
||||||
*.a
|
*.ko
|
||||||
*.so
|
*.obj
|
||||||
*.dll
|
*.elf
|
||||||
*.exe
|
|
||||||
*.meta
|
|
||||||
*.log
|
|
||||||
*.out
|
|
||||||
*.stackdump
|
|
||||||
*.tb
|
|
||||||
*.filters
|
|
||||||
[Dd]ocs/
|
|
||||||
|
|
||||||
#Shell files
|
# Linker output
|
||||||
*.bat
|
*.ilk
|
||||||
*.sh
|
*.map
|
||||||
|
*.exp
|
||||||
|
|
||||||
|
# Precompiled Headers
|
||||||
|
*.gch
|
||||||
|
*.pch
|
||||||
|
|
||||||
|
# Libraries
|
||||||
|
*.lib
|
||||||
|
*.a
|
||||||
|
*.la
|
||||||
|
*.lo
|
||||||
|
|
||||||
|
# Shared objects (inc. Windows DLLs)
|
||||||
|
*.dll
|
||||||
|
*.so
|
||||||
|
*.so.*
|
||||||
|
*.dylib
|
||||||
|
|
||||||
|
# Executables
|
||||||
|
*.exe
|
||||||
|
*.out
|
||||||
|
*.app
|
||||||
|
*.i*86
|
||||||
|
*.x86_64
|
||||||
|
*.hex
|
||||||
|
|
||||||
|
# Debug files
|
||||||
|
*.dSYM/
|
||||||
|
*.su
|
||||||
|
*.idb
|
||||||
|
*.pdb
|
||||||
|
|
||||||
|
# Kernel Module Compile Results
|
||||||
|
*.mod*
|
||||||
|
*.cmd
|
||||||
|
.tmp_versions/
|
||||||
|
modules.order
|
||||||
|
Module.symvers
|
||||||
|
Mkfile.old
|
||||||
|
dkms.conf
|
||||||
|
|
||||||
|
.cproject
|
||||||
|
.project
|
||||||
|
.settings/
|
||||||
|
temp/
|
||||||
|
Release/
|
||||||
|
out/
|
||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
# License
|
# License
|
||||||
|
|
||||||
Copyright (c) 2020-2023 Kayne Ruse, KR Game Studios
|
Copyright (c) 2020-2024 Kayne Ruse, KR Game Studios
|
||||||
|
|
||||||
This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software.
|
This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software.
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
<image src="toylogo.png" />
|
<image src="toylogo.png" />
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
# Toy
|
# Toy v1
|
||||||
|
|
||||||
The Toy programming language is an imperative bytecode-intermediate embedded scripting language. It isn't intended to operate on its own, but rather as part of another program, the "host". This process is intended to allow a decent amount of easy customisation by the host's end user, by exposing logic in script files. Alternatively, binary files in a custom format can be used as well.
|
The Toy programming language is an imperative bytecode-intermediate embedded scripting language. It isn't intended to operate on its own, but rather as part of another program, the "host". This process is intended to allow a decent amount of easy customisation by the host's end user, by exposing logic in script files. Alternatively, binary files in a custom format can be used as well.
|
||||||
|
|
||||||
@@ -35,6 +35,8 @@ Run `make install-tools` to install a number of tools, including:
|
|||||||
|
|
||||||
* VSCode syntax highlighting
|
* VSCode syntax highlighting
|
||||||
|
|
||||||
|
Other tools such as a disassembler are available, as well - simply run `make` in the correct directory.
|
||||||
|
|
||||||
## Syntax
|
## Syntax
|
||||||
|
|
||||||
```
|
```
|
||||||
@@ -69,6 +71,14 @@ print tally(); //3
|
|||||||
|
|
||||||
This source code is covered by the zlib license (see [LICENSE.md](LICENSE.md)).
|
This source code is covered by the zlib license (see [LICENSE.md](LICENSE.md)).
|
||||||
|
|
||||||
|
# Contributions
|
||||||
|
|
||||||
|
@hiperiondev - Disassembler, porting support and feedback
|
||||||
|
@add00 - Library support
|
||||||
|
@gruelingpine185 - Unofficial MacOS support
|
||||||
|
@solar-mist - Minor bugfixes
|
||||||
|
Unnamed Individuals - Feedback
|
||||||
|
|
||||||
# Patrons via Patreon
|
# Patrons via Patreon
|
||||||
|
|
||||||
* Seth A. Robinson
|
* Seth A. Robinson
|
||||||
|
|||||||
+3
-3
@@ -661,7 +661,7 @@ static int nativeConcat(Toy_Interpreter* interpreter, Toy_LiteralArray* argument
|
|||||||
}
|
}
|
||||||
|
|
||||||
//get the combined length for the new string
|
//get the combined length for the new string
|
||||||
size_t length = TOY_AS_STRING(selfLiteral)->length + TOY_AS_STRING(otherLiteral)->length + 1;
|
size_t length = TOY_AS_STRING(selfLiteral)->length + TOY_AS_STRING(otherLiteral)->length;
|
||||||
|
|
||||||
if (length > TOY_MAX_STRING_LENGTH) {
|
if (length > TOY_MAX_STRING_LENGTH) {
|
||||||
interpreter->errorOutput("Can't concatenate these strings, result is too long (error found in concat)\n");
|
interpreter->errorOutput("Can't concatenate these strings, result is too long (error found in concat)\n");
|
||||||
@@ -671,8 +671,8 @@ static int nativeConcat(Toy_Interpreter* interpreter, Toy_LiteralArray* argument
|
|||||||
}
|
}
|
||||||
|
|
||||||
//allocate the space and generate
|
//allocate the space and generate
|
||||||
char* buffer = TOY_ALLOCATE(char, length);
|
char* buffer = TOY_ALLOCATE(char, length + 1);
|
||||||
snprintf(buffer, length, "%s%s", Toy_toCString(TOY_AS_STRING(selfLiteral)), Toy_toCString(TOY_AS_STRING(otherLiteral)));
|
snprintf(buffer, length + 1, "%s%s", Toy_toCString(TOY_AS_STRING(selfLiteral)), Toy_toCString(TOY_AS_STRING(otherLiteral)));
|
||||||
|
|
||||||
Toy_Literal result = TOY_TO_STRING_LITERAL(Toy_createRefString(buffer));
|
Toy_Literal result = TOY_TO_STRING_LITERAL(Toy_createRefString(buffer));
|
||||||
|
|
||||||
|
|||||||
+11
-10
@@ -1,12 +1,13 @@
|
|||||||
import standard;
|
fn f() {
|
||||||
var array = [42];
|
//
|
||||||
|
}
|
||||||
|
|
||||||
var result = null;
|
fn g() {
|
||||||
|
fn i() {
|
||||||
|
//
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//problematic line
|
fn h() {
|
||||||
result = max(0, array[0]);
|
//
|
||||||
|
}
|
||||||
assert result == 42, "Indexing in argument list failed";
|
|
||||||
|
|
||||||
|
|
||||||
print "All good";
|
|
||||||
@@ -362,8 +362,8 @@ void Toy_emitASTNodeAnd(Toy_ASTNode** nodeHandle, Toy_ASTNode* rhs) {
|
|||||||
Toy_ASTNode* tmp = TOY_ALLOCATE(Toy_ASTNode, 1);
|
Toy_ASTNode* tmp = TOY_ALLOCATE(Toy_ASTNode, 1);
|
||||||
|
|
||||||
tmp->type = TOY_AST_NODE_AND;
|
tmp->type = TOY_AST_NODE_AND;
|
||||||
tmp->binary.left = *nodeHandle;
|
tmp->pathAnd.left = *nodeHandle;
|
||||||
tmp->binary.right = rhs;
|
tmp->pathAnd.right = rhs;
|
||||||
|
|
||||||
*nodeHandle = tmp;
|
*nodeHandle = tmp;
|
||||||
}
|
}
|
||||||
@@ -372,8 +372,8 @@ void Toy_emitASTNodeOr(Toy_ASTNode** nodeHandle, Toy_ASTNode* rhs) {
|
|||||||
Toy_ASTNode* tmp = TOY_ALLOCATE(Toy_ASTNode, 1);
|
Toy_ASTNode* tmp = TOY_ALLOCATE(Toy_ASTNode, 1);
|
||||||
|
|
||||||
tmp->type = TOY_AST_NODE_OR;
|
tmp->type = TOY_AST_NODE_OR;
|
||||||
tmp->binary.left = *nodeHandle;
|
tmp->pathOr.left = *nodeHandle;
|
||||||
tmp->binary.right = rhs;
|
tmp->pathOr.right = rhs;
|
||||||
|
|
||||||
*nodeHandle = tmp;
|
*nodeHandle = tmp;
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -64,7 +64,7 @@ The current patch version of Toy. This value is embedded into the bytecode.
|
|||||||
This value MUST fit into an unsigned char.
|
This value MUST fit into an unsigned char.
|
||||||
!*/
|
!*/
|
||||||
|
|
||||||
#define TOY_VERSION_PATCH 0
|
#define TOY_VERSION_PATCH 2
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
### TOY_VERSION_BUILD
|
### TOY_VERSION_BUILD
|
||||||
|
|||||||
+11
-3
@@ -841,12 +841,20 @@ static Toy_Opcode Toy_writeCompilerWithJumps(Toy_Compiler* compiler, Toy_ASTNode
|
|||||||
compiler->count += sizeof(unsigned short); //2 bytes
|
compiler->count += sizeof(unsigned short); //2 bytes
|
||||||
|
|
||||||
//write the body
|
//write the body
|
||||||
|
bool closeScope = false;
|
||||||
|
if (node->pathFor.thenPath->type != TOY_AST_NODE_BLOCK) {
|
||||||
compiler->bytecode[compiler->count++] = TOY_OP_SCOPE_BEGIN; //1 byte
|
compiler->bytecode[compiler->count++] = TOY_OP_SCOPE_BEGIN; //1 byte
|
||||||
|
closeScope = true;
|
||||||
|
}
|
||||||
|
|
||||||
override = Toy_writeCompilerWithJumps(compiler, node->pathFor.thenPath, &breakAddresses, &continueAddresses, jumpOffsets, rootNode);
|
override = Toy_writeCompilerWithJumps(compiler, node->pathFor.thenPath, &breakAddresses, &continueAddresses, jumpOffsets, rootNode);
|
||||||
if (override != TOY_OP_EOF) {//compensate for indexing & dot notation being screwy
|
if (override != TOY_OP_EOF) {//compensate for indexing & dot notation being screwy
|
||||||
compiler->bytecode[compiler->count++] = (unsigned char)override; //1 byte
|
compiler->bytecode[compiler->count++] = (unsigned char)override; //1 byte
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (closeScope) {
|
||||||
compiler->bytecode[compiler->count++] = TOY_OP_SCOPE_END; //1 byte
|
compiler->bytecode[compiler->count++] = TOY_OP_SCOPE_END; //1 byte
|
||||||
|
}
|
||||||
|
|
||||||
//for-breaks actually jump to the bottom
|
//for-breaks actually jump to the bottom
|
||||||
int jumpToIncrement = compiler->count;
|
int jumpToIncrement = compiler->count;
|
||||||
@@ -857,6 +865,9 @@ static Toy_Opcode Toy_writeCompilerWithJumps(Toy_Compiler* compiler, Toy_ASTNode
|
|||||||
compiler->bytecode[compiler->count++] = (unsigned char)override; //1 byte
|
compiler->bytecode[compiler->count++] = (unsigned char)override; //1 byte
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//BUGFIX: clear the stack after each loop
|
||||||
|
compiler->bytecode[compiler->count++] = TOY_OP_POP_STACK; //1 byte
|
||||||
|
|
||||||
compiler->bytecode[compiler->count++] = TOY_OP_JUMP; //1 byte
|
compiler->bytecode[compiler->count++] = TOY_OP_JUMP; //1 byte
|
||||||
unsigned short tmpVal = jumpToStart + jumpOffsets;
|
unsigned short tmpVal = jumpToStart + jumpOffsets;
|
||||||
memcpy(compiler->bytecode + compiler->count, &tmpVal, sizeof(tmpVal));
|
memcpy(compiler->bytecode + compiler->count, &tmpVal, sizeof(tmpVal));
|
||||||
@@ -880,9 +891,6 @@ static Toy_Opcode Toy_writeCompilerWithJumps(Toy_Compiler* compiler, Toy_ASTNode
|
|||||||
memcpy(compiler->bytecode + point, &tmpVal, sizeof(tmpVal));
|
memcpy(compiler->bytecode + point, &tmpVal, sizeof(tmpVal));
|
||||||
}
|
}
|
||||||
|
|
||||||
//clear the stack after use
|
|
||||||
compiler->bytecode[compiler->count++] = TOY_OP_POP_STACK; //1 byte
|
|
||||||
|
|
||||||
//cleanup
|
//cleanup
|
||||||
Toy_freeLiteralArray(&breakAddresses);
|
Toy_freeLiteralArray(&breakAddresses);
|
||||||
Toy_freeLiteralArray(&continueAddresses);
|
Toy_freeLiteralArray(&continueAddresses);
|
||||||
|
|||||||
@@ -455,8 +455,8 @@ static void printToBuffer(const char* str) {
|
|||||||
globalPrintBuffer = TOY_GROW_ARRAY(char, globalPrintBuffer, oldCapacity, globalPrintCapacity);
|
globalPrintBuffer = TOY_GROW_ARRAY(char, globalPrintBuffer, oldCapacity, globalPrintCapacity);
|
||||||
}
|
}
|
||||||
|
|
||||||
snprintf(globalPrintBuffer + globalPrintCount, strlen(str) + 1, "%s", str ? str : "\0");
|
size_t total = snprintf(globalPrintBuffer + globalPrintCount, strlen(str) + 1, "%s", str ? str : "\0");
|
||||||
globalPrintCount += strlen(str);
|
globalPrintCount += total;
|
||||||
}
|
}
|
||||||
|
|
||||||
//exposed functions
|
//exposed functions
|
||||||
|
|||||||
+1
-1
@@ -22,7 +22,7 @@ void* Toy_private_defaultMemoryAllocator(void* pointer, size_t oldSize, size_t n
|
|||||||
void* mem = realloc(pointer, newSize);
|
void* mem = realloc(pointer, newSize);
|
||||||
|
|
||||||
if (mem == NULL) {
|
if (mem == NULL) {
|
||||||
fprintf(stderr, TOY_CC_ERROR "[internal] Memory allocation error (requested %zu, replacing %zu)\n" TOY_CC_RESET, newSize, oldSize);
|
fprintf(stderr, TOY_CC_ERROR "[internal] Memory allocation error (requested %d, replacing %d)\n" TOY_CC_RESET, (int)newSize, (int)oldSize);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -15,7 +15,7 @@ all: $(OBJ) $(TESTS:%.c=../$(TOY_OUTDIR)/%.exe)
|
|||||||
../$(TOY_OUTDIR)/%.exe: $(ODIR)/%.o
|
../$(TOY_OUTDIR)/%.exe: $(ODIR)/%.o
|
||||||
@$(CC) -o $@ $< $(TARGETS:../source/%.c=$(ODIR)/%.o) $(CFLAGS) $(LIBS)
|
@$(CC) -o $@ $< $(TARGETS:../source/%.c=$(ODIR)/%.o) $(CFLAGS) $(LIBS)
|
||||||
ifeq ($(shell uname)$(DISABLE_VALGRIND),Linux)
|
ifeq ($(shell uname)$(DISABLE_VALGRIND),Linux)
|
||||||
valgrind --leak-check=full --track-origins=yes $@
|
valgrind --leak-check=full --track-origins=yes --show-leak-kinds=all $@
|
||||||
else
|
else
|
||||||
$@
|
$@
|
||||||
endif
|
endif
|
||||||
|
|||||||
@@ -0,0 +1,427 @@
|
|||||||
|
/*
|
||||||
|
* Project: https://github.com/likle/cargs
|
||||||
|
* License: MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <cargs.h>
|
||||||
|
#include <memory.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#define CAG_OPTION_PRINT_DISTANCE 4
|
||||||
|
#define CAG_OPTION_PRINT_MIN_INDENTION 20
|
||||||
|
|
||||||
|
static void cag_option_print_value(const cag_option *option,
|
||||||
|
size_t *accessor_length, FILE *destination) {
|
||||||
|
if (option->value_name != NULL) {
|
||||||
|
*accessor_length += fprintf(destination, "=%s", option->value_name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void cag_option_print_letters(const cag_option *option, bool *first,
|
||||||
|
size_t *accessor_length, FILE *destination) {
|
||||||
|
const char *access_letter;
|
||||||
|
access_letter = option->access_letters;
|
||||||
|
if (access_letter != NULL) {
|
||||||
|
while (*access_letter) {
|
||||||
|
if (*first) {
|
||||||
|
*accessor_length += fprintf(destination, "-%c", *access_letter);
|
||||||
|
*first = false;
|
||||||
|
} else {
|
||||||
|
*accessor_length += fprintf(destination, ", -%c",
|
||||||
|
*access_letter);
|
||||||
|
}
|
||||||
|
++access_letter;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void cag_option_print_name(const cag_option *option, bool *first,
|
||||||
|
size_t *accessor_length, FILE *destination) {
|
||||||
|
if (option->access_name != NULL) {
|
||||||
|
if (*first) {
|
||||||
|
*accessor_length += fprintf(destination, "--%s",
|
||||||
|
option->access_name);
|
||||||
|
} else {
|
||||||
|
*accessor_length += fprintf(destination, ", --%s",
|
||||||
|
option->access_name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t cag_option_get_print_indention(const cag_option *options,
|
||||||
|
size_t option_count) {
|
||||||
|
size_t option_index, indention, result;
|
||||||
|
const cag_option *option;
|
||||||
|
|
||||||
|
result = CAG_OPTION_PRINT_MIN_INDENTION;
|
||||||
|
|
||||||
|
for (option_index = 0; option_index < option_count; ++option_index) {
|
||||||
|
indention = CAG_OPTION_PRINT_DISTANCE;
|
||||||
|
option = &options[option_index];
|
||||||
|
if (option->access_letters != NULL && *option->access_letters) {
|
||||||
|
indention += strlen(option->access_letters) * 4 - 2;
|
||||||
|
if (option->access_name != NULL) {
|
||||||
|
indention += strlen(option->access_name) + 4;
|
||||||
|
}
|
||||||
|
} else if (option->access_name != NULL) {
|
||||||
|
indention += strlen(option->access_name) + 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (option->value_name != NULL) {
|
||||||
|
indention += strlen(option->value_name) + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (indention > result) {
|
||||||
|
result = indention;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cag_option_print(const cag_option *options, size_t option_count,
|
||||||
|
FILE *destination) {
|
||||||
|
size_t option_index, indention, i, accessor_length;
|
||||||
|
const cag_option *option;
|
||||||
|
bool first;
|
||||||
|
|
||||||
|
indention = cag_option_get_print_indention(options, option_count);
|
||||||
|
|
||||||
|
for (option_index = 0; option_index < option_count; ++option_index) {
|
||||||
|
option = &options[option_index];
|
||||||
|
accessor_length = 0;
|
||||||
|
first = true;
|
||||||
|
|
||||||
|
fputs(" ", destination);
|
||||||
|
|
||||||
|
cag_option_print_letters(option, &first, &accessor_length, destination);
|
||||||
|
cag_option_print_name(option, &first, &accessor_length, destination);
|
||||||
|
cag_option_print_value(option, &accessor_length, destination);
|
||||||
|
|
||||||
|
for (i = accessor_length; i < indention; ++i) {
|
||||||
|
fputs(" ", destination);
|
||||||
|
}
|
||||||
|
|
||||||
|
fputs(" ", destination);
|
||||||
|
fputs(option->description, destination);
|
||||||
|
|
||||||
|
fprintf(destination, "\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void cag_option_prepare(cag_option_context *context, const cag_option *options,
|
||||||
|
size_t option_count, int argc, char **argv) {
|
||||||
|
// This just initialized the values to the beginning of all the arguments.
|
||||||
|
context->options = options;
|
||||||
|
context->option_count = option_count;
|
||||||
|
context->argc = argc;
|
||||||
|
context->argv = argv;
|
||||||
|
context->index = 1;
|
||||||
|
context->inner_index = 0;
|
||||||
|
context->forced_end = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const cag_option* cag_option_find_by_name(cag_option_context *context,
|
||||||
|
char *name, size_t name_size) {
|
||||||
|
const cag_option *option;
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
// We loop over all the available options and stop as soon as we have found
|
||||||
|
// one. We don't use any hash map table, since there won't be that many
|
||||||
|
// arguments anyway.
|
||||||
|
for (i = 0; i < context->option_count; ++i) {
|
||||||
|
option = &context->options[i];
|
||||||
|
|
||||||
|
// The option might not have an item name, we can just skip those.
|
||||||
|
if (option->access_name == NULL) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to compare the name of the access name. We can use the name_size or
|
||||||
|
// this comparison, since we are guaranteed to have null-terminated access
|
||||||
|
// names.
|
||||||
|
if (strncmp(option->access_name, name, name_size) == 0) {
|
||||||
|
return option;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const cag_option* cag_option_find_by_letter(cag_option_context *context,
|
||||||
|
char letter) {
|
||||||
|
const cag_option *option;
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
// We loop over all the available options and stop as soon as we have found
|
||||||
|
// one. We don't use any look up table, since there won't be that many
|
||||||
|
// arguments anyway.
|
||||||
|
for (i = 0; i < context->option_count; ++i) {
|
||||||
|
option = &context->options[i];
|
||||||
|
|
||||||
|
// If this option doesn't have any access letters we will skip them.
|
||||||
|
if (option->access_letters == NULL) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify whether this option has the access letter in it's access letter
|
||||||
|
// string. If it does, then this is our option.
|
||||||
|
if (strchr(option->access_letters, letter) != NULL) {
|
||||||
|
return option;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void cag_option_parse_value(cag_option_context *context,
|
||||||
|
const cag_option *option, char **c) {
|
||||||
|
// And now let's check whether this option is supposed to have a value, which
|
||||||
|
// is the case if there is a value name set. The value can be either submitted
|
||||||
|
// with a '=' sign or a space, which means we would have to jump over to the
|
||||||
|
// next argv index. This is somewhat ugly, but we do it to behave the same as
|
||||||
|
// the other option parsers.
|
||||||
|
if (option->value_name != NULL) {
|
||||||
|
if (**c == '=') {
|
||||||
|
context->value = ++(*c);
|
||||||
|
} else {
|
||||||
|
// If the next index is larger or equal to the argument count, then the
|
||||||
|
// parameter for this option is missing. The user will know about this,
|
||||||
|
// since the value pointer of the context will be NULL because we don't
|
||||||
|
// set it here in that case.
|
||||||
|
if (context->argc > context->index + 1) {
|
||||||
|
// We consider this argv to be the value, no matter what the contents
|
||||||
|
// are.
|
||||||
|
++context->index;
|
||||||
|
*c = context->argv[context->index];
|
||||||
|
context->value = *c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Move c to the end of the value, to not confuse the caller about our
|
||||||
|
// position.
|
||||||
|
while (**c) {
|
||||||
|
++(*c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void cag_option_parse_access_name(cag_option_context *context, char **c) {
|
||||||
|
const cag_option *option;
|
||||||
|
char *n;
|
||||||
|
|
||||||
|
// Now we need to extract the access name, which is any symbol up to a '=' or
|
||||||
|
// a '\0'.
|
||||||
|
n = *c;
|
||||||
|
while (**c && **c != '=') {
|
||||||
|
++*c;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now this will obviously always be true, but we are paranoid. Sometimes. It
|
||||||
|
// doesn't hurt to check.
|
||||||
|
assert(*c >= n);
|
||||||
|
|
||||||
|
// Figure out which option this name belongs to. This might return NULL if the
|
||||||
|
// name is not registered, which means the user supplied an unknown option. In
|
||||||
|
// that case we return true to indicate that we finished with this option. We
|
||||||
|
// have to skip the value parsing since we don't know whether the user thinks
|
||||||
|
// this option has one or not. Since we don't set any identifier specifically,
|
||||||
|
// it will remain '?' within the context.
|
||||||
|
option = cag_option_find_by_name(context, n, (size_t) (*c - n));
|
||||||
|
if (option == NULL) {
|
||||||
|
// Since this option is invalid, we will move on to the next index. There is
|
||||||
|
// nothing we can do about this.
|
||||||
|
++context->index;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We found an option and now we can specify the identifier within the
|
||||||
|
// context.
|
||||||
|
context->identifier = option->identifier;
|
||||||
|
|
||||||
|
// And now we try to parse the value. This function will also check whether
|
||||||
|
// this option is actually supposed to have a value.
|
||||||
|
cag_option_parse_value(context, option, c);
|
||||||
|
|
||||||
|
// And finally we move on to the next index.
|
||||||
|
++context->index;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void cag_option_parse_access_letter(cag_option_context *context,
|
||||||
|
char **c) {
|
||||||
|
const cag_option *option;
|
||||||
|
char *n = *c;
|
||||||
|
char *v;
|
||||||
|
|
||||||
|
// Figure out which option this letter belongs to. This might return NULL if
|
||||||
|
// the letter is not registered, which means the user supplied an unknown
|
||||||
|
// option. In that case we return true to indicate that we finished with this
|
||||||
|
// option. We have to skip the value parsing since we don't know whether the
|
||||||
|
// user thinks this option has one or not. Since we don't set any identifier
|
||||||
|
// specifically, it will remain '?' within the context.
|
||||||
|
option = cag_option_find_by_letter(context, n[context->inner_index]);
|
||||||
|
if (option == NULL) {
|
||||||
|
++context->index;
|
||||||
|
context->inner_index = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We found an option and now we can specify the identifier within the
|
||||||
|
// context.
|
||||||
|
context->identifier = option->identifier;
|
||||||
|
|
||||||
|
// And now we try to parse the value. This function will also check whether
|
||||||
|
// this option is actually supposed to have a value.
|
||||||
|
v = &n[++context->inner_index];
|
||||||
|
cag_option_parse_value(context, option, &v);
|
||||||
|
|
||||||
|
// Check whether we reached the end of this option argument.
|
||||||
|
if (*v == '\0') {
|
||||||
|
++context->index;
|
||||||
|
context->inner_index = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void cag_option_shift(cag_option_context *context, int start, int option,
|
||||||
|
int end) {
|
||||||
|
char *tmp;
|
||||||
|
int a_index, shift_index, shift_count, left_index, right_index;
|
||||||
|
|
||||||
|
shift_count = option - start;
|
||||||
|
|
||||||
|
// There is no shift is required if the start and the option have the same
|
||||||
|
// index.
|
||||||
|
if (shift_count == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Lets loop through the option strings first, which we will move towards the
|
||||||
|
// beginning.
|
||||||
|
for (a_index = option; a_index < end; ++a_index) {
|
||||||
|
// First remember the current option value, because we will have to save
|
||||||
|
// that later at the beginning.
|
||||||
|
tmp = context->argv[a_index];
|
||||||
|
|
||||||
|
// Let's loop over all option values and shift them one towards the end.
|
||||||
|
// This will override the option value we just stored temporarily.
|
||||||
|
for (shift_index = 0; shift_index < shift_count; ++shift_index) {
|
||||||
|
left_index = a_index - shift_index;
|
||||||
|
right_index = a_index - shift_index - 1;
|
||||||
|
context->argv[left_index] = context->argv[right_index];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now restore the saved option value at the beginning.
|
||||||
|
context->argv[a_index - shift_count] = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The new index will be before all non-option values, in such a way that they
|
||||||
|
// all will be moved again in the next fetch call.
|
||||||
|
context->index = end - shift_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool cag_option_is_argument_string(const char *c) {
|
||||||
|
return *c == '-' && *(c + 1) != '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
static int cag_option_find_next(cag_option_context *context) {
|
||||||
|
int next_index, next_option_index;
|
||||||
|
char *c;
|
||||||
|
|
||||||
|
// Prepare to search the next option at the next index.
|
||||||
|
next_index = context->index;
|
||||||
|
next_option_index = next_index;
|
||||||
|
|
||||||
|
// Grab a pointer to the string and verify that it is not the end. If it is
|
||||||
|
// the end, we have to return false to indicate that we finished.
|
||||||
|
c = context->argv[next_option_index];
|
||||||
|
if (context->forced_end || c == NULL) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check whether it is a '-'. We need to find the next option - and an option
|
||||||
|
// always starts with a '-'. If there is a string "-\0", we don't consider it
|
||||||
|
// as an option neither.
|
||||||
|
while (!cag_option_is_argument_string(c)) {
|
||||||
|
c = context->argv[++next_option_index];
|
||||||
|
if (c == NULL) {
|
||||||
|
// We reached the end and did not find any argument anymore. Let's tell
|
||||||
|
// our caller that we reached the end.
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Indicate that we found an option which can be processed. The index of the
|
||||||
|
// next option will be returned.
|
||||||
|
return next_option_index;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool cag_option_fetch(cag_option_context *context) {
|
||||||
|
char *c;
|
||||||
|
int old_index, new_index;
|
||||||
|
|
||||||
|
// Reset our identifier to a question mark, which indicates an "unknown"
|
||||||
|
// option. The value is set to NULL, to make sure we are not carrying the
|
||||||
|
// parameter from the previous option to this one.
|
||||||
|
context->identifier = '?';
|
||||||
|
context->value = NULL;
|
||||||
|
|
||||||
|
// Check whether there are any options left to parse and remember the old
|
||||||
|
// index as well as the new index. In the end we will move the option junk to
|
||||||
|
// the beginning, so that non option arguments can be read.
|
||||||
|
old_index = context->index;
|
||||||
|
new_index = cag_option_find_next(context);
|
||||||
|
if (new_index >= 0) {
|
||||||
|
context->index = new_index;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Grab a pointer to the beginning of the option. At this point, the next
|
||||||
|
// character must be a '-', since if it was not the prepare function would
|
||||||
|
// have returned false. We will skip that symbol and proceed.
|
||||||
|
c = context->argv[context->index];
|
||||||
|
assert(*c == '-');
|
||||||
|
++c;
|
||||||
|
|
||||||
|
// Check whether this is a long option, starting with a double "--".
|
||||||
|
if (*c == '-') {
|
||||||
|
++c;
|
||||||
|
|
||||||
|
// This might be a double "--" which indicates the end of options. If this
|
||||||
|
// is the case, we will not move to the next index. That ensures that
|
||||||
|
// another call to the fetch function will not skip the "--".
|
||||||
|
if (*c == '\0') {
|
||||||
|
context->forced_end = true;
|
||||||
|
} else {
|
||||||
|
// We parse now the access name. All information about it will be written
|
||||||
|
// to the context.
|
||||||
|
cag_option_parse_access_name(context, &c);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// This is no long option, so we can just parse an access letter.
|
||||||
|
cag_option_parse_access_letter(context, &c);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Move the items so that the options come first followed by non-option
|
||||||
|
// arguments.
|
||||||
|
cag_option_shift(context, old_index, new_index, context->index);
|
||||||
|
|
||||||
|
return context->forced_end == false;
|
||||||
|
}
|
||||||
|
|
||||||
|
char cag_option_get(const cag_option_context *context) {
|
||||||
|
// We just return the identifier here.
|
||||||
|
return context->identifier;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* cag_option_get_value(const cag_option_context *context) {
|
||||||
|
// We just return the internal value pointer of the context.
|
||||||
|
return context->value;
|
||||||
|
}
|
||||||
|
|
||||||
|
int cag_option_get_index(const cag_option_context *context) {
|
||||||
|
// Either we point to a value item,
|
||||||
|
return context->index;
|
||||||
|
}
|
||||||
@@ -0,0 +1,169 @@
|
|||||||
|
/*
|
||||||
|
* Project: https://github.com/likle/cargs
|
||||||
|
* License: MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef CARGS_H_
|
||||||
|
#define CARGS_H_
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is a simple alternative cross-platform implementation of getopt, which
|
||||||
|
* is used to parse argument strings submitted to the executable (argc and argv
|
||||||
|
* which are received in the main function).
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef CAG_LIBRARY_H
|
||||||
|
#define CAG_LIBRARY_H
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#if defined(_WIN32) || defined(__CYGWIN__)
|
||||||
|
#define CAG_EXPORT __declspec(dllexport)
|
||||||
|
#define CAG_IMPORT __declspec(dllimport)
|
||||||
|
#elif __GNUC__ >= 4
|
||||||
|
#define CAG_EXPORT __attribute__((visibility("default")))
|
||||||
|
#define CAG_IMPORT __attribute__((visibility("default")))
|
||||||
|
#else
|
||||||
|
#define CAG_EXPORT
|
||||||
|
#define CAG_IMPORT
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(CAG_SHARED)
|
||||||
|
#if defined(CAG_EXPORTS)
|
||||||
|
#define CAG_PUBLIC CAG_EXPORT
|
||||||
|
#else
|
||||||
|
#define CAG_PUBLIC CAG_IMPORT
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
#define CAG_PUBLIC
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An option is used to describe a flag/argument option submitted when the
|
||||||
|
* program is run.
|
||||||
|
*/
|
||||||
|
typedef struct cag_option {
|
||||||
|
const char identifier;
|
||||||
|
const char *access_letters;
|
||||||
|
const char *access_name;
|
||||||
|
const char *value_name;
|
||||||
|
const char *description;
|
||||||
|
} cag_option;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A context is used to iterate over all options provided. It stores the parsing
|
||||||
|
* state.
|
||||||
|
*/
|
||||||
|
typedef struct cag_option_context {
|
||||||
|
const struct cag_option *options;
|
||||||
|
size_t option_count;
|
||||||
|
int argc;
|
||||||
|
char **argv;
|
||||||
|
int index;
|
||||||
|
int inner_index;
|
||||||
|
bool forced_end;
|
||||||
|
char identifier;
|
||||||
|
char *value;
|
||||||
|
} cag_option_context;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is just a small macro which calculates the size of an array.
|
||||||
|
*/
|
||||||
|
#define CAG_ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Prints all options to the terminal.
|
||||||
|
*
|
||||||
|
* This function prints all options to the terminal. This can be used to
|
||||||
|
* generate the output for a "--help" option.
|
||||||
|
*
|
||||||
|
* @param options The options which will be printed.
|
||||||
|
* @param option_count The option count which will be printed.
|
||||||
|
* @param destination The destination where the output will be printed.
|
||||||
|
*/
|
||||||
|
CAG_PUBLIC void cag_option_print(const cag_option *options, size_t option_count,
|
||||||
|
FILE *destination);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Prepare argument options context for parsing.
|
||||||
|
*
|
||||||
|
* This function prepares the context for iteration and initializes the context
|
||||||
|
* with the supplied options and arguments. After the context has been prepared,
|
||||||
|
* it can be used to fetch arguments from it.
|
||||||
|
*
|
||||||
|
* @param context The context which will be initialized.
|
||||||
|
* @param options The registered options which are available for the program.
|
||||||
|
* @param option_count The amount of options which are available for the
|
||||||
|
* program.
|
||||||
|
* @param argc The amount of arguments the user supplied in the main function.
|
||||||
|
* @param argv A pointer to the arguments of the main function.
|
||||||
|
*/
|
||||||
|
CAG_PUBLIC void cag_option_prepare(cag_option_context *context,
|
||||||
|
const cag_option *options, size_t option_count, int argc, char **argv);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Fetches an option from the argument list.
|
||||||
|
*
|
||||||
|
* This function fetches a single option from the argument list. The context
|
||||||
|
* will be moved to that item. Information can be extracted from the context
|
||||||
|
* after the item has been fetched.
|
||||||
|
* The arguments will be re-ordered, which means that non-option arguments will
|
||||||
|
* be moved to the end of the argument list. After all options have been
|
||||||
|
* fetched, all non-option arguments will be positioned after the index of
|
||||||
|
* the context.
|
||||||
|
*
|
||||||
|
* @param context The context from which we will fetch the option.
|
||||||
|
* @return Returns true if there was another option or false if the end is
|
||||||
|
* reached.
|
||||||
|
*/
|
||||||
|
CAG_PUBLIC bool cag_option_fetch(cag_option_context *context);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Gets the identifier of the option.
|
||||||
|
*
|
||||||
|
* This function gets the identifier of the option, which should be unique to
|
||||||
|
* this option and can be used to determine what kind of option this is.
|
||||||
|
*
|
||||||
|
* @param context The context from which the option was fetched.
|
||||||
|
* @return Returns the identifier of the option.
|
||||||
|
*/
|
||||||
|
CAG_PUBLIC char cag_option_get(const cag_option_context *context);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Gets the value from the option.
|
||||||
|
*
|
||||||
|
* This function gets the value from the option, if any. If the option does not
|
||||||
|
* contain a value, this function will return NULL.
|
||||||
|
*
|
||||||
|
* @param context The context from which the option was fetched.
|
||||||
|
* @return Returns a pointer to the value or NULL if there is no value.
|
||||||
|
*/
|
||||||
|
CAG_PUBLIC const char* cag_option_get_value(const cag_option_context *context);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Gets the current index of the context.
|
||||||
|
*
|
||||||
|
* This function gets the index within the argv arguments of the context. The
|
||||||
|
* context always points to the next item which it will inspect. This is
|
||||||
|
* particularly useful to inspect the original argument array, or to get
|
||||||
|
* non-option arguments after option fetching has finished.
|
||||||
|
*
|
||||||
|
* @param context The context from which the option was fetched.
|
||||||
|
* @return Returns the current index of the context.
|
||||||
|
*/
|
||||||
|
CAG_PUBLIC int cag_option_get_index(const cag_option_context *context);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
} // extern "C"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* CARGS_H_ */
|
||||||
|
|
||||||
Binary file not shown.
+524
-125
@@ -2,7 +2,7 @@
|
|||||||
* disassembler.c
|
* disassembler.c
|
||||||
*
|
*
|
||||||
* Created on: 10 ago. 2023
|
* Created on: 10 ago. 2023
|
||||||
* Original Author: egonzalez
|
* Original Author: Emiliano Augusto Gonzalez (egonzalez . hiperion @ gmail . com)
|
||||||
*
|
*
|
||||||
* Further modified by Kayne Ruse, and added to the Toy Programming Language tool repository.
|
* Further modified by Kayne Ruse, and added to the Toy Programming Language tool repository.
|
||||||
*/
|
*/
|
||||||
@@ -13,6 +13,7 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#include "disassembler_utils.h"
|
||||||
#include "disassembler.h"
|
#include "disassembler.h"
|
||||||
|
|
||||||
#define SPC(n) printf("%.*s", n, "| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |");
|
#define SPC(n) printf("%.*s", n, "| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |");
|
||||||
@@ -106,59 +107,60 @@ enum DIS_ARG_TYPE {
|
|||||||
DIS_ARG_STRING //
|
DIS_ARG_STRING //
|
||||||
};
|
};
|
||||||
|
|
||||||
const uint8_t OP_ARGS[DIS_OP_END_OPCODES][2] = {
|
const uint8_t OP_ARGS[DIS_OP_END_OPCODES][3] = {
|
||||||
{ DIS_ARG_NONE, DIS_ARG_NONE }, // DIS_OP_EOF
|
// | first arg | second arg | jump |
|
||||||
{ DIS_ARG_NONE, DIS_ARG_NONE }, // DIS_OP_PASS
|
{ DIS_ARG_NONE, DIS_ARG_NONE, false }, // DIS_OP_EOF
|
||||||
{ DIS_ARG_NONE, DIS_ARG_NONE }, // DIS_OP_ASSERT
|
{ DIS_ARG_NONE, DIS_ARG_NONE, false }, // DIS_OP_PASS
|
||||||
{ DIS_ARG_NONE, DIS_ARG_NONE }, // DIS_OP_PRINT
|
{ DIS_ARG_NONE, DIS_ARG_NONE, false }, // DIS_OP_ASSERT
|
||||||
{ DIS_ARG_BYTE, DIS_ARG_NONE }, // DIS_OP_LITERAL
|
{ DIS_ARG_NONE, DIS_ARG_NONE, false }, // DIS_OP_PRINT
|
||||||
{ DIS_ARG_WORD, DIS_ARG_NONE }, // DIS_OP_LITERAL_LONG
|
{ DIS_ARG_BYTE, DIS_ARG_NONE, false }, // DIS_OP_LITERAL
|
||||||
{ DIS_ARG_NONE, DIS_ARG_NONE }, // DIS_OP_LITERAL_RAW
|
{ DIS_ARG_WORD, DIS_ARG_NONE, false }, // DIS_OP_LITERAL_LONG
|
||||||
{ DIS_ARG_NONE, DIS_ARG_NONE }, // DIS_OP_NEGATE
|
{ DIS_ARG_NONE, DIS_ARG_NONE, false }, // DIS_OP_LITERAL_RAW
|
||||||
{ DIS_ARG_NONE, DIS_ARG_NONE }, // DIS_OP_ADDITION
|
{ DIS_ARG_NONE, DIS_ARG_NONE, false }, // DIS_OP_NEGATE
|
||||||
{ DIS_ARG_NONE, DIS_ARG_NONE }, // DIS_OP_SUBTRACTION
|
{ DIS_ARG_NONE, DIS_ARG_NONE, false }, // DIS_OP_ADDITION
|
||||||
{ DIS_ARG_NONE, DIS_ARG_NONE }, // DIS_OP_MULTIPLICATION
|
{ DIS_ARG_NONE, DIS_ARG_NONE, false }, // DIS_OP_SUBTRACTION
|
||||||
{ DIS_ARG_NONE, DIS_ARG_NONE }, // DIS_OP_DIVISION
|
{ DIS_ARG_NONE, DIS_ARG_NONE, false }, // DIS_OP_MULTIPLICATION
|
||||||
{ DIS_ARG_NONE, DIS_ARG_NONE }, // DIS_OP_MODULO
|
{ DIS_ARG_NONE, DIS_ARG_NONE, false }, // DIS_OP_DIVISION
|
||||||
{ DIS_ARG_NONE, DIS_ARG_NONE }, // DIS_OP_GROUPING_BEGIN
|
{ DIS_ARG_NONE, DIS_ARG_NONE, false }, // DIS_OP_MODULO
|
||||||
{ DIS_ARG_NONE, DIS_ARG_NONE }, // DIS_OP_GROUPING_END
|
{ DIS_ARG_NONE, DIS_ARG_NONE, false }, // DIS_OP_GROUPING_BEGIN
|
||||||
{ DIS_ARG_NONE, DIS_ARG_NONE }, // DIS_OP_SCOPE_BEGIN
|
{ DIS_ARG_NONE, DIS_ARG_NONE, false }, // DIS_OP_GROUPING_END
|
||||||
{ DIS_ARG_NONE, DIS_ARG_NONE }, // DIS_OP_SCOPE_END
|
{ DIS_ARG_NONE, DIS_ARG_NONE, false }, // DIS_OP_SCOPE_BEGIN
|
||||||
{ DIS_ARG_NONE, DIS_ARG_NONE }, // DIS_OP_TYPE_DECL_removed
|
{ DIS_ARG_NONE, DIS_ARG_NONE, false }, // DIS_OP_SCOPE_END
|
||||||
{ DIS_ARG_NONE, DIS_ARG_NONE }, // DIS_OP_TYPE_DECL_LONG_removed
|
{ DIS_ARG_NONE, DIS_ARG_NONE, false }, // DIS_OP_TYPE_DECL_removed
|
||||||
{ DIS_ARG_BYTE, DIS_ARG_BYTE }, // DIS_OP_VAR_DECL
|
{ DIS_ARG_NONE, DIS_ARG_NONE, false }, // DIS_OP_TYPE_DECL_LONG_removed
|
||||||
{ DIS_ARG_WORD, DIS_ARG_WORD }, // DIS_OP_VAR_DECL_LONG
|
{ DIS_ARG_BYTE, DIS_ARG_BYTE, false }, // DIS_OP_VAR_DECL
|
||||||
{ DIS_ARG_BYTE, DIS_ARG_BYTE }, // DIS_OP_FN_DECL
|
{ DIS_ARG_WORD, DIS_ARG_WORD, false }, // DIS_OP_VAR_DECL_LONG
|
||||||
{ DIS_ARG_WORD, DIS_ARG_WORD }, // DIS_OP_FN_DECL_LONG
|
{ DIS_ARG_BYTE, DIS_ARG_BYTE, false }, // DIS_OP_FN_DECL
|
||||||
{ DIS_ARG_NONE, DIS_ARG_NONE }, // DIS_OP_VAR_ASSIGN
|
{ DIS_ARG_WORD, DIS_ARG_WORD, false }, // DIS_OP_FN_DECL_LONG
|
||||||
{ DIS_ARG_NONE, DIS_ARG_NONE }, // DIS_OP_VAR_ADDITION_ASSIGN
|
{ DIS_ARG_NONE, DIS_ARG_NONE, false }, // DIS_OP_VAR_ASSIGN
|
||||||
{ DIS_ARG_NONE, DIS_ARG_NONE }, // DIS_OP_VAR_SUBTRACTION_ASSIGN
|
{ DIS_ARG_NONE, DIS_ARG_NONE, false }, // DIS_OP_VAR_ADDITION_ASSIGN
|
||||||
{ DIS_ARG_NONE, DIS_ARG_NONE }, // DIS_OP_VAR_MULTIPLICATION_ASSIGN
|
{ DIS_ARG_NONE, DIS_ARG_NONE, false }, // DIS_OP_VAR_SUBTRACTION_ASSIGN
|
||||||
{ DIS_ARG_NONE, DIS_ARG_NONE }, // DIS_OP_VAR_DIVISION_ASSIGN
|
{ DIS_ARG_NONE, DIS_ARG_NONE, false }, // DIS_OP_VAR_MULTIPLICATION_ASSIGN
|
||||||
{ DIS_ARG_NONE, DIS_ARG_NONE }, // DIS_OP_VAR_MODULO_ASSIGN
|
{ DIS_ARG_NONE, DIS_ARG_NONE, false }, // DIS_OP_VAR_DIVISION_ASSIGN
|
||||||
{ DIS_ARG_NONE, DIS_ARG_NONE }, // DIS_OP_TYPE_CAST
|
{ DIS_ARG_NONE, DIS_ARG_NONE, false }, // DIS_OP_VAR_MODULO_ASSIGN
|
||||||
{ DIS_ARG_NONE, DIS_ARG_NONE }, // DIS_OP_TYPE_OF
|
{ DIS_ARG_NONE, DIS_ARG_NONE, false }, // DIS_OP_TYPE_CAST
|
||||||
{ DIS_ARG_NONE, DIS_ARG_NONE }, // DIS_OP_IMPORT
|
{ DIS_ARG_NONE, DIS_ARG_NONE, false }, // DIS_OP_TYPE_OF
|
||||||
{ DIS_ARG_NONE, DIS_ARG_NONE }, // DIS_OP_EXPORT_removed
|
{ DIS_ARG_NONE, DIS_ARG_NONE, false }, // DIS_OP_IMPORT
|
||||||
{ DIS_ARG_NONE, DIS_ARG_NONE }, // DIS_OP_INDEX
|
{ DIS_ARG_NONE, DIS_ARG_NONE, false }, // DIS_OP_EXPORT_removed
|
||||||
{ DIS_ARG_BYTE, DIS_ARG_NONE }, // DIS_OP_INDEX_ASSIGN
|
{ DIS_ARG_NONE, DIS_ARG_NONE, false }, // DIS_OP_INDEX
|
||||||
{ DIS_ARG_NONE, DIS_ARG_NONE }, // DIS_OP_INDEX_ASSIGN_INTERMEDIATE
|
{ DIS_ARG_BYTE, DIS_ARG_NONE, false }, // DIS_OP_INDEX_ASSIGN
|
||||||
{ DIS_ARG_NONE, DIS_ARG_NONE }, // DIS_OP_DOT
|
{ DIS_ARG_NONE, DIS_ARG_NONE, false }, // DIS_OP_INDEX_ASSIGN_INTERMEDIATE
|
||||||
{ DIS_ARG_NONE, DIS_ARG_NONE }, // DIS_OP_COMPARE_EQUAL
|
{ DIS_ARG_NONE, DIS_ARG_NONE, false }, // DIS_OP_DOT
|
||||||
{ DIS_ARG_NONE, DIS_ARG_NONE }, // DIS_OP_COMPARE_NOT_EQUAL
|
{ DIS_ARG_NONE, DIS_ARG_NONE, false }, // DIS_OP_COMPARE_EQUAL
|
||||||
{ DIS_ARG_NONE, DIS_ARG_NONE }, // DIS_OP_COMPARE_LESS
|
{ DIS_ARG_NONE, DIS_ARG_NONE, false }, // DIS_OP_COMPARE_NOT_EQUAL
|
||||||
{ DIS_ARG_NONE, DIS_ARG_NONE }, // DIS_OP_COMPARE_LESS_EQUAL
|
{ DIS_ARG_NONE, DIS_ARG_NONE, false }, // DIS_OP_COMPARE_LESS
|
||||||
{ DIS_ARG_NONE, DIS_ARG_NONE }, // DIS_OP_COMPARE_GREATER
|
{ DIS_ARG_NONE, DIS_ARG_NONE, false }, // DIS_OP_COMPARE_LESS_EQUAL
|
||||||
{ DIS_ARG_NONE, DIS_ARG_NONE }, // DIS_OP_COMPARE_GREATER_EQUAL
|
{ DIS_ARG_NONE, DIS_ARG_NONE, false }, // DIS_OP_COMPARE_GREATER
|
||||||
{ DIS_ARG_NONE, DIS_ARG_NONE }, // DIS_OP_INVERT
|
{ DIS_ARG_NONE, DIS_ARG_NONE, false }, // DIS_OP_COMPARE_GREATER_EQUAL
|
||||||
{ DIS_ARG_WORD, DIS_ARG_NONE }, // DIS_OP_AND
|
{ DIS_ARG_NONE, DIS_ARG_NONE, false }, // DIS_OP_INVERT
|
||||||
{ DIS_ARG_WORD, DIS_ARG_NONE }, // DIS_OP_OR
|
{ DIS_ARG_WORD, DIS_ARG_NONE, true }, // DIS_OP_AND
|
||||||
{ DIS_ARG_WORD, DIS_ARG_NONE }, // DIS_OP_JUMP
|
{ DIS_ARG_WORD, DIS_ARG_NONE, true }, // DIS_OP_OR
|
||||||
{ DIS_ARG_WORD, DIS_ARG_NONE }, // DIS_OP_IF_FALSE_JUMP
|
{ DIS_ARG_WORD, DIS_ARG_NONE, true }, // DIS_OP_JUMP
|
||||||
{ DIS_ARG_NONE, DIS_ARG_NONE }, // DIS_OP_FN_CALL
|
{ DIS_ARG_WORD, DIS_ARG_NONE, true }, // DIS_OP_IF_FALSE_JUMP
|
||||||
{ DIS_ARG_WORD, DIS_ARG_NONE }, // DIS_OP_FN_RETURN
|
{ DIS_ARG_NONE, DIS_ARG_NONE, false }, // DIS_OP_FN_CALL
|
||||||
{ DIS_ARG_NONE, DIS_ARG_NONE }, // DIS_OP_POP_STACK
|
{ DIS_ARG_WORD, DIS_ARG_NONE, false }, // DIS_OP_FN_RETURN
|
||||||
{ DIS_ARG_NONE, DIS_ARG_NONE }, // DIS_OP_TERNARY
|
{ DIS_ARG_NONE, DIS_ARG_NONE, false }, // DIS_OP_POP_STACK
|
||||||
|
{ DIS_ARG_NONE, DIS_ARG_NONE, false }, // DIS_OP_TERNARY
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct dis_program_s {
|
typedef struct dis_program_s {
|
||||||
@@ -167,10 +169,24 @@ typedef struct dis_program_s {
|
|||||||
uint32_t pc;
|
uint32_t pc;
|
||||||
} dis_program_t;
|
} dis_program_t;
|
||||||
|
|
||||||
typedef struct dis_func_op_s {
|
typedef struct fun_code_s {
|
||||||
uint32_t start;
|
uint32_t start;
|
||||||
uint32_t end;
|
uint32_t len;
|
||||||
} dis_func_op_t;
|
char *fun;
|
||||||
|
} fun_code_t;
|
||||||
|
|
||||||
|
typedef struct lit_s {
|
||||||
|
char *fun;
|
||||||
|
char *str;
|
||||||
|
} *lit_t;
|
||||||
|
|
||||||
|
uint32_t jump_label;
|
||||||
|
uint32_t function_queue_len = 0;
|
||||||
|
uint32_t lit_fn_queue_len = 0;
|
||||||
|
queue_node_t *function_queue_front = NULL;
|
||||||
|
queue_node_t *function_queue_rear = NULL;
|
||||||
|
queue_node_t *lit_fn_queue_front = NULL;
|
||||||
|
queue_node_t *lit_fn_queue_rear = NULL;
|
||||||
|
|
||||||
static void dis_print_opcode(uint8_t op);
|
static void dis_print_opcode(uint8_t op);
|
||||||
|
|
||||||
@@ -220,16 +236,18 @@ static void consumeByte(uint8_t byte, uint8_t *tb, uint32_t *count) {
|
|||||||
|
|
||||||
static void dis_disassembler_init(dis_program_t **prg) {
|
static void dis_disassembler_init(dis_program_t **prg) {
|
||||||
(*prg) = malloc(sizeof(struct dis_program_s));
|
(*prg) = malloc(sizeof(struct dis_program_s));
|
||||||
|
(*prg)->program = NULL;
|
||||||
(*prg)->len = 0;
|
(*prg)->len = 0;
|
||||||
(*prg)->pc = 0;
|
(*prg)->pc = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void dis_disassembler_deinit(dis_program_t **prg) {
|
static void dis_disassembler_deinit(dis_program_t **prg) {
|
||||||
|
if((*prg)->program != NULL)
|
||||||
free((*prg)->program);
|
free((*prg)->program);
|
||||||
free((*prg));
|
free((*prg));
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint8_t dis_load_file(const char *filename, dis_program_t **prg) {
|
static uint8_t dis_load_file(const char *filename, dis_program_t **prg, bool alt_fmt) {
|
||||||
FILE *f;
|
FILE *f;
|
||||||
size_t fsize, bytes;
|
size_t fsize, bytes;
|
||||||
uint32_t count = 0;
|
uint32_t count = 0;
|
||||||
@@ -250,18 +268,26 @@ static uint8_t dis_load_file(const char *filename, dis_program_t **prg) {
|
|||||||
(*prg)->program[count++] = buf;
|
(*prg)->program[count++] = buf;
|
||||||
|
|
||||||
(*prg)->len = fsize;
|
(*prg)->len = fsize;
|
||||||
|
|
||||||
|
if (!alt_fmt)
|
||||||
printf("\nFile: %s\nSize: %zu\n", filename, fsize);
|
printf("\nFile: %s\nSize: %zu\n", filename, fsize);
|
||||||
|
else
|
||||||
|
printf("\n.comment File: %s, Size: %zu\n", filename, fsize);
|
||||||
|
|
||||||
fclose(f);
|
fclose(f);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void dis_read_header(dis_program_t **prg) {
|
static void dis_read_header(dis_program_t **prg, bool alt_fmt) {
|
||||||
const unsigned char major = readByte((*prg)->program, &((*prg)->pc));
|
const unsigned char major = readByte((*prg)->program, &((*prg)->pc));
|
||||||
const unsigned char minor = readByte((*prg)->program, &((*prg)->pc));
|
const unsigned char minor = readByte((*prg)->program, &((*prg)->pc));
|
||||||
const unsigned char patch = readByte((*prg)->program, &((*prg)->pc));
|
const unsigned char patch = readByte((*prg)->program, &((*prg)->pc));
|
||||||
const char *build = readString((*prg)->program, &((*prg)->pc));
|
const char *build = readString((*prg)->program, &((*prg)->pc));
|
||||||
|
|
||||||
|
if (!alt_fmt)
|
||||||
printf("[Header Version: %d.%d.%d (%s)]\n", major, minor, patch, build);
|
printf("[Header Version: %d.%d.%d (%s)]\n", major, minor, patch, build);
|
||||||
|
else
|
||||||
|
printf(".comment Header Version: %d.%d.%d (%s)\n", major, minor, patch, build);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void dis_print_opcode(uint8_t op) {
|
static void dis_print_opcode(uint8_t op) {
|
||||||
@@ -278,76 +304,171 @@ static void dis_print_opcode(uint8_t op) {
|
|||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
#define S_OP(n) \
|
#define S_OP(n, p) \
|
||||||
switch (OP_ARGS[opcode][n]) { \
|
switch (OP_ARGS[opcode][n]) { \
|
||||||
case DIS_ARG_NONE: \
|
case DIS_ARG_NONE: \
|
||||||
break; \
|
break; \
|
||||||
case DIS_ARG_BYTE: \
|
case DIS_ARG_BYTE: \
|
||||||
uint = readByte((*prg)->program, &pc); \
|
uint = readByte((*prg)->program, &pc); \
|
||||||
printf(" b(%d)", uint); \
|
if (p) printf(" b(%d)", uint); \
|
||||||
break; \
|
break; \
|
||||||
case DIS_ARG_WORD: \
|
case DIS_ARG_WORD: \
|
||||||
uint = readWord((*prg)->program, &pc);\
|
uint = readWord((*prg)->program, &pc);\
|
||||||
printf(" w(%d)", uint); \
|
if (p) printf(" w(%d)", uint); \
|
||||||
break; \
|
break; \
|
||||||
case DIS_ARG_INTEGER: \
|
case DIS_ARG_INTEGER: \
|
||||||
intg = readInt((*prg)->program, &pc); \
|
intg = readInt((*prg)->program, &pc); \
|
||||||
printf(" i(%d)", intg); \
|
if (p) printf(" i(%d)", intg); \
|
||||||
break; \
|
break; \
|
||||||
case DIS_ARG_FLOAT: \
|
case DIS_ARG_FLOAT: \
|
||||||
flt = readFloat((*prg)->program, &pc); \
|
flt = readFloat((*prg)->program, &pc); \
|
||||||
printf(" f(%f)", flt); \
|
if (p) printf(" f(%f)", flt); \
|
||||||
break; \
|
break; \
|
||||||
case DIS_ARG_STRING: \
|
case DIS_ARG_STRING: \
|
||||||
str = readString((*prg)->program, &pc); \
|
str = readString((*prg)->program, &pc); \
|
||||||
printf(" s(%s)", str); \
|
if (p) printf(" s(%s)", str); \
|
||||||
break; \
|
break; \
|
||||||
default: \
|
default: \
|
||||||
printf("ERROR, unknown argument type\n"); \
|
printf("ERROR, unknown argument type\n"); \
|
||||||
exit(1); \
|
exit(1); \
|
||||||
}
|
}
|
||||||
|
|
||||||
static void dis_disassemble_section(dis_program_t **prg, uint32_t pc, uint32_t len, uint8_t spaces, bool is_function) {
|
static void dis_disassemble_section(dis_program_t **prg, uint32_t pc, uint32_t len, uint8_t spaces, bool is_function, options_t config) {
|
||||||
uint8_t opcode;
|
uint8_t opcode = 0;
|
||||||
uint32_t uint;
|
uint16_t uint = 0;
|
||||||
int32_t intg;
|
int32_t intg = 0;
|
||||||
float flt;
|
float flt = 0;
|
||||||
char *str;
|
char *str = NULL;
|
||||||
|
|
||||||
// first 4 bytes of the program section within a function are actually specifying the parameter and return lists
|
// first 4 bytes of the program section within a function are actually specifying the parameter and return lists
|
||||||
if (is_function) {
|
if (is_function) {
|
||||||
printf("\n");
|
printf("\n");
|
||||||
uint16_t args = readWord((*prg)->program, &pc);
|
uint16_t args = readWord((*prg)->program, &pc);
|
||||||
uint16_t rets = readWord((*prg)->program, &pc);
|
uint16_t rets = readWord((*prg)->program, &pc);
|
||||||
|
if (!config.alt_format_flag) {
|
||||||
SPC(spaces);
|
SPC(spaces);
|
||||||
printf("| [args literal %d, rets literal %d]", args, rets);
|
printf("| ");
|
||||||
|
} else
|
||||||
|
printf(" .comment args:%d, rets:%d", args, rets);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32_t pc_start = pc;
|
||||||
|
|
||||||
|
uint32_t labels_qty = 0;
|
||||||
|
uint16_t *label_line = NULL;
|
||||||
|
uint32_t *label_id = NULL;
|
||||||
|
if (config.alt_format_flag) {
|
||||||
|
// first pass: search jump labels
|
||||||
|
label_line = malloc(sizeof(uint16_t));
|
||||||
|
label_id = malloc(sizeof(uint32_t));
|
||||||
|
|
||||||
while (pc < len) {
|
while (pc < len) {
|
||||||
|
label_line = realloc(label_line, (labels_qty + 1) * sizeof(uint16_t));
|
||||||
|
label_id = realloc(label_id, (labels_qty + 1) * sizeof(uint32_t));
|
||||||
|
|
||||||
opcode = (*prg)->program[pc];
|
opcode = (*prg)->program[pc];
|
||||||
printf("\n");
|
if (config.alt_format_flag && (opcode == 255 || opcode == 0)) {
|
||||||
SPC(spaces);
|
++pc;
|
||||||
printf("| [ %05d ](%03d) ", pc++, opcode);
|
continue;
|
||||||
dis_print_opcode(opcode);
|
}
|
||||||
|
|
||||||
if (opcode > DIS_OP_END_OPCODES)
|
if (opcode > DIS_OP_END_OPCODES)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
S_OP(0);
|
++pc;
|
||||||
S_OP(1);
|
|
||||||
|
S_OP(0, 0);
|
||||||
|
|
||||||
|
if (OP_ARGS[opcode][2]) {
|
||||||
|
label_line[labels_qty] = uint;
|
||||||
|
label_id[labels_qty] = jump_label++;
|
||||||
|
++labels_qty;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
S_OP(1, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
pc = pc_start;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (pc < len) {
|
||||||
|
opcode = (*prg)->program[pc];
|
||||||
|
|
||||||
|
if (config.alt_format_flag) {
|
||||||
|
for (uint32_t lbl = 0; lbl < labels_qty; lbl++) {
|
||||||
|
if (pc - pc_start == label_line[lbl]) {
|
||||||
|
printf("\nJL_%04d_:", label_id[lbl]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (config.alt_format_flag && (opcode == 255 || opcode == 0)) {
|
||||||
|
++pc;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("\n");
|
||||||
|
if (!config.alt_format_flag) {
|
||||||
|
SPC(spaces);
|
||||||
|
printf("| ");
|
||||||
|
printf("[%05d](%03d) ", (pc++) - pc_start, opcode);
|
||||||
|
} else {
|
||||||
|
printf(" ");
|
||||||
|
pc++;
|
||||||
|
}
|
||||||
|
|
||||||
|
dis_print_opcode(opcode);
|
||||||
|
|
||||||
|
if (opcode >= DIS_OP_END_OPCODES)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (config.alt_format_flag) {
|
||||||
|
if (OP_ARGS[opcode][2]) {
|
||||||
|
uint = readWord((*prg)->program, &pc);
|
||||||
|
for (uint32_t lbl = 0; lbl < labels_qty; lbl++) {
|
||||||
|
if (uint == label_line[lbl]) {
|
||||||
|
printf(" JL_%04d_", label_id[lbl]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
S_OP(0, 1);
|
||||||
|
} else
|
||||||
|
S_OP(0, 1);
|
||||||
|
|
||||||
|
S_OP(1, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (config.alt_format_flag) {
|
||||||
|
free(label_line);
|
||||||
|
free(label_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (config.alt_format_flag && (*prg)->program[pc - 5] != DIS_OP_FN_RETURN)
|
||||||
|
printf("\n FN_RETURN w(0)");
|
||||||
}
|
}
|
||||||
|
|
||||||
#define LIT_ADD(a, b, c) b[c] = a; ++c;
|
#define LIT_ADD(a, b, c) b[c] = a; ++c;
|
||||||
static void dis_read_interpreter_sections(dis_program_t **prg, uint32_t *pc, uint8_t spaces) {
|
static void dis_read_interpreter_sections(dis_program_t **prg, uint32_t *pc, uint8_t spaces, char *tree, options_t config) {
|
||||||
uint32_t literal_count = 0;
|
uint32_t literal_count = 0;
|
||||||
uint8_t literal_type[65536];
|
uint8_t literal_type[65536];
|
||||||
|
char *lit_str = NULL;
|
||||||
|
|
||||||
const unsigned short literalCount = readWord((*prg)->program, pc);
|
const unsigned short literalCount = readWord((*prg)->program, pc);
|
||||||
|
|
||||||
|
if(!config.group_flag)
|
||||||
printf("\n");
|
printf("\n");
|
||||||
|
|
||||||
|
if (!config.alt_format_flag) {
|
||||||
SPC(spaces);
|
SPC(spaces);
|
||||||
printf("| ( Reading %d literals )\n", literalCount);
|
printf("| ");
|
||||||
|
printf(" ");
|
||||||
|
printf("--- ( Reading %d literals from cache ) ---\n", literalCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (config.alt_format_flag)
|
||||||
|
lit_str = calloc(1, sizeof(char));
|
||||||
|
|
||||||
for (int i = 0; i < literalCount; i++) {
|
for (int i = 0; i < literalCount; i++) {
|
||||||
const unsigned char literalType = readByte((*prg)->program, pc);
|
const unsigned char literalType = readByte((*prg)->program, pc);
|
||||||
@@ -355,58 +476,119 @@ static void dis_read_interpreter_sections(dis_program_t **prg, uint32_t *pc, uin
|
|||||||
switch (literalType) {
|
switch (literalType) {
|
||||||
case DIS_LITERAL_NULL:
|
case DIS_LITERAL_NULL:
|
||||||
LIT_ADD(DIS_LITERAL_NULL, literal_type, literal_count);
|
LIT_ADD(DIS_LITERAL_NULL, literal_type, literal_count);
|
||||||
|
if (!config.alt_format_flag) {
|
||||||
SPC(spaces);
|
SPC(spaces);
|
||||||
printf("| | [%d] ( null )\n", i);
|
printf("| | ");
|
||||||
|
printf("[%05d] ( null )\n", i);
|
||||||
|
} else {
|
||||||
|
str_append(&lit_str, " .lit NULL\n");
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DIS_LITERAL_BOOLEAN: {
|
case DIS_LITERAL_BOOLEAN: {
|
||||||
const bool b = readByte((*prg)->program, pc);
|
const bool b = readByte((*prg)->program, pc);
|
||||||
LIT_ADD(DIS_LITERAL_BOOLEAN, literal_type, literal_count);
|
LIT_ADD(DIS_LITERAL_BOOLEAN, literal_type, literal_count);
|
||||||
|
if (!config.alt_format_flag) {
|
||||||
SPC(spaces);
|
SPC(spaces);
|
||||||
printf("| | [%d] ( boolean %s )\n", i, b ? "true" : "false");
|
printf("| | ");
|
||||||
|
printf("[%05d] ( boolean %s )\n", i, b ? "true" : "false");
|
||||||
|
} else {
|
||||||
|
char bs[10];
|
||||||
|
sprintf(bs, "%s\n", b ? "true" : "false");
|
||||||
|
str_append(&lit_str, " .lit BOOLEAN ");
|
||||||
|
str_append(&lit_str, bs);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DIS_LITERAL_INTEGER: {
|
case DIS_LITERAL_INTEGER: {
|
||||||
const int d = readInt((*prg)->program, pc);
|
const int d = readInt((*prg)->program, pc);
|
||||||
LIT_ADD(DIS_LITERAL_INTEGER, literal_type, literal_count);
|
LIT_ADD(DIS_LITERAL_INTEGER, literal_type, literal_count);
|
||||||
|
if (!config.alt_format_flag) {
|
||||||
SPC(spaces);
|
SPC(spaces);
|
||||||
printf("| | [%d] ( integer %d )\n", i, d);
|
printf("| | ");
|
||||||
|
printf("[%05d] ( integer %d )\n", i, d);
|
||||||
|
} else {
|
||||||
|
char ds[20];
|
||||||
|
sprintf(ds, "%d\n", d);
|
||||||
|
str_append(&lit_str, " .lit INTEGER ");
|
||||||
|
str_append(&lit_str, ds);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DIS_LITERAL_FLOAT: {
|
case DIS_LITERAL_FLOAT: {
|
||||||
const float f = readFloat((*prg)->program, pc);
|
const float f = readFloat((*prg)->program, pc);
|
||||||
LIT_ADD(DIS_LITERAL_FLOAT, literal_type, literal_count);
|
LIT_ADD(DIS_LITERAL_FLOAT, literal_type, literal_count);
|
||||||
|
if (!config.alt_format_flag) {
|
||||||
SPC(spaces);
|
SPC(spaces);
|
||||||
printf("| | [%d] ( float %f )\n", i, f);
|
printf("| | ");
|
||||||
|
printf("[%05d] ( float %f )\n", i, f);
|
||||||
|
} else {
|
||||||
|
char fs[20];
|
||||||
|
sprintf(fs, "%f\n", f);
|
||||||
|
str_append(&lit_str, " .lit FLOAT ");
|
||||||
|
str_append(&lit_str, fs);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DIS_LITERAL_STRING: {
|
case DIS_LITERAL_STRING: {
|
||||||
const char *s = readString((*prg)->program, pc);
|
const char *s = readString((*prg)->program, pc);
|
||||||
LIT_ADD(DIS_LITERAL_STRING, literal_type, literal_count);
|
LIT_ADD(DIS_LITERAL_STRING, literal_type, literal_count);
|
||||||
|
if (!config.alt_format_flag) {
|
||||||
SPC(spaces);
|
SPC(spaces);
|
||||||
printf("| | [%d] ( string \"%s\" )\n", i, s);
|
printf("| | ");
|
||||||
|
printf("[%05d] ( string \"%s\" )\n", i, s);
|
||||||
|
} else {
|
||||||
|
str_append(&lit_str, " .lit STRING \"");
|
||||||
|
str_append(&lit_str, s);
|
||||||
|
str_append(&lit_str, "\"\n");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DIS_LITERAL_ARRAY_INTERMEDIATE:
|
case DIS_LITERAL_ARRAY_INTERMEDIATE:
|
||||||
case DIS_LITERAL_ARRAY: {
|
case DIS_LITERAL_ARRAY: {
|
||||||
unsigned short length = readWord((*prg)->program, pc);
|
unsigned short length = readWord((*prg)->program, pc);
|
||||||
SPC(spaces);
|
if (!config.alt_format_flag) {
|
||||||
printf("| | [%d] ( array ", i);
|
|
||||||
for (int i = 0; i < length; i++) {
|
|
||||||
int index = readWord((*prg)->program, pc);
|
|
||||||
printf("%d ", index);
|
|
||||||
LIT_ADD(DIS_LITERAL_NULL, literal_type, literal_count);
|
|
||||||
if (!(i % 15) && i != 0) {
|
|
||||||
printf("\n");
|
|
||||||
SPC(spaces);
|
SPC(spaces);
|
||||||
printf("| | ");
|
printf("| | ");
|
||||||
|
printf("[%05d] ( array ", i);
|
||||||
|
} else {
|
||||||
|
str_append(&lit_str, " .lit ARRAY ");
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < length; i++) {
|
||||||
|
int index = readWord((*prg)->program, pc);
|
||||||
|
if (!config.alt_format_flag) {
|
||||||
|
printf("%d ", index);
|
||||||
|
} else {
|
||||||
|
char ds[20];
|
||||||
|
sprintf(ds, "%d ", index);
|
||||||
|
str_append(&lit_str, ds);
|
||||||
|
|
||||||
|
}
|
||||||
|
LIT_ADD(DIS_LITERAL_NULL, literal_type, literal_count);
|
||||||
|
if (!(i % 15) && i != 0) {
|
||||||
|
if (!config.alt_format_flag) {
|
||||||
|
printf("\\\n");
|
||||||
|
SPC(spaces);
|
||||||
|
printf("| | ");
|
||||||
|
printf(" ");
|
||||||
|
} else {
|
||||||
|
str_append(&lit_str, "\\\n ");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
printf(")\n");
|
}
|
||||||
|
if (!config.alt_format_flag) {
|
||||||
|
printf(")");
|
||||||
|
printf("\n");
|
||||||
|
} else {
|
||||||
|
str_append(&lit_str, "\n");
|
||||||
|
}
|
||||||
|
|
||||||
LIT_ADD(DIS_LITERAL_ARRAY, literal_type, literal_count);
|
LIT_ADD(DIS_LITERAL_ARRAY, literal_type, literal_count);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -414,19 +596,42 @@ static void dis_read_interpreter_sections(dis_program_t **prg, uint32_t *pc, uin
|
|||||||
case DIS_LITERAL_DICTIONARY_INTERMEDIATE:
|
case DIS_LITERAL_DICTIONARY_INTERMEDIATE:
|
||||||
case DIS_LITERAL_DICTIONARY: {
|
case DIS_LITERAL_DICTIONARY: {
|
||||||
unsigned short length = readWord((*prg)->program, pc);
|
unsigned short length = readWord((*prg)->program, pc);
|
||||||
|
if (!config.alt_format_flag) {
|
||||||
SPC(spaces);
|
SPC(spaces);
|
||||||
printf("| | [%d] ( dictionary ", i);
|
printf("| | ");
|
||||||
|
printf("[%05d] ( dictionary ", i);
|
||||||
|
} else {
|
||||||
|
str_append(&lit_str, " .lit DICTIONARY ");
|
||||||
|
}
|
||||||
for (int i = 0; i < length / 2; i++) {
|
for (int i = 0; i < length / 2; i++) {
|
||||||
int key = readWord((*prg)->program, pc);
|
int key = readWord((*prg)->program, pc);
|
||||||
int val = readWord((*prg)->program, pc);
|
int val = readWord((*prg)->program, pc);
|
||||||
|
|
||||||
|
if (!config.alt_format_flag)
|
||||||
printf("(key: %d, val:%d) ", key, val);
|
printf("(key: %d, val:%d) ", key, val);
|
||||||
|
else {
|
||||||
|
char s[100];
|
||||||
|
sprintf(s, "%d,%d ", key, val);
|
||||||
|
str_append(&lit_str, s);
|
||||||
|
}
|
||||||
|
|
||||||
if (!(i % 5) && i != 0) {
|
if (!(i % 5) && i != 0) {
|
||||||
printf("\n");
|
if (!config.alt_format_flag) {
|
||||||
|
printf("\\\n");
|
||||||
SPC(spaces);
|
SPC(spaces);
|
||||||
printf("| | ");
|
printf("| | ");
|
||||||
|
printf(" ");
|
||||||
|
} else {
|
||||||
|
str_append(&lit_str, "\\\n ");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
printf(")\n");
|
}
|
||||||
|
if (!config.alt_format_flag) {
|
||||||
|
printf(")");
|
||||||
|
printf("\n");
|
||||||
|
} else {
|
||||||
|
str_append(&lit_str, "\n");
|
||||||
|
}
|
||||||
LIT_ADD(DIS_LITERAL_DICTIONARY, literal_type, literal_count);
|
LIT_ADD(DIS_LITERAL_DICTIONARY, literal_type, literal_count);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -434,16 +639,30 @@ static void dis_read_interpreter_sections(dis_program_t **prg, uint32_t *pc, uin
|
|||||||
case DIS_LITERAL_FUNCTION: {
|
case DIS_LITERAL_FUNCTION: {
|
||||||
unsigned short index = readWord((*prg)->program, pc);
|
unsigned short index = readWord((*prg)->program, pc);
|
||||||
LIT_ADD(DIS_LITERAL_FUNCTION_INTERMEDIATE, literal_type, literal_count);
|
LIT_ADD(DIS_LITERAL_FUNCTION_INTERMEDIATE, literal_type, literal_count);
|
||||||
|
if (!config.alt_format_flag) {
|
||||||
SPC(spaces);
|
SPC(spaces);
|
||||||
printf("| | [%d] ( function index: %d )\n", i, index);
|
printf("| | ");
|
||||||
|
printf("[%05d] ( function index: %d )\n", i, index);
|
||||||
|
} else {
|
||||||
|
char s[100];
|
||||||
|
sprintf(s, " .lit FUNCTION %d\n", index);
|
||||||
|
str_append(&lit_str, s);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DIS_LITERAL_IDENTIFIER: {
|
case DIS_LITERAL_IDENTIFIER: {
|
||||||
const char *str = readString((*prg)->program, pc);
|
const char *str = readString((*prg)->program, pc);
|
||||||
LIT_ADD(DIS_LITERAL_IDENTIFIER, literal_type, literal_count);
|
LIT_ADD(DIS_LITERAL_IDENTIFIER, literal_type, literal_count);
|
||||||
|
if (!config.alt_format_flag) {
|
||||||
SPC(spaces);
|
SPC(spaces);
|
||||||
printf("| | [%d] ( identifier %s )\n", i, str);
|
printf("| | ");
|
||||||
|
printf("[%05d] ( identifier %s )\n", i, str);
|
||||||
|
} else {
|
||||||
|
str_append(&lit_str, " .lit IDENTIFIER ");
|
||||||
|
str_append(&lit_str, str);
|
||||||
|
str_append(&lit_str, "\n");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -451,44 +670,96 @@ static void dis_read_interpreter_sections(dis_program_t **prg, uint32_t *pc, uin
|
|||||||
case DIS_LITERAL_TYPE_INTERMEDIATE: {
|
case DIS_LITERAL_TYPE_INTERMEDIATE: {
|
||||||
uint8_t literalType = readByte((*prg)->program, pc);
|
uint8_t literalType = readByte((*prg)->program, pc);
|
||||||
uint8_t constant = readByte((*prg)->program, pc);
|
uint8_t constant = readByte((*prg)->program, pc);
|
||||||
|
if (!config.alt_format_flag) {
|
||||||
SPC(spaces);
|
SPC(spaces);
|
||||||
printf("| | [%d] ( type %s: %d)\n", i, (LIT_STR[literalType] + 12), constant);
|
printf("| | ");
|
||||||
if (literalType == DIS_LITERAL_ARRAY) {
|
printf("[%05d] ( type %s: %d)\n", i, (LIT_STR[literalType] + 12), constant);
|
||||||
uint16_t vt = readWord((*prg)->program, pc);
|
} else {
|
||||||
SPC(spaces);
|
char s[100];
|
||||||
printf("| | | ( subtype: %d)\n", vt);
|
sprintf(s, " .lit TYPE %s %d", (LIT_STR[literalType] + 12), constant);
|
||||||
|
str_append(&lit_str, s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (literalType == DIS_LITERAL_ARRAY) {
|
||||||
|
uint16_t vt = readWord((*prg)->program, pc);
|
||||||
|
if (!config.alt_format_flag) {
|
||||||
|
SPC(spaces);
|
||||||
|
printf("| | ");
|
||||||
|
printf("\n ( subtype: %d)\n", vt);
|
||||||
|
} else {
|
||||||
|
char s[100];
|
||||||
|
sprintf(s, " SUBTYPE %d\n", vt);
|
||||||
|
str_append(&lit_str, s);
|
||||||
|
}
|
||||||
|
} else
|
||||||
if (literalType == DIS_LITERAL_DICTIONARY) {
|
if (literalType == DIS_LITERAL_DICTIONARY) {
|
||||||
uint8_t kt = readWord((*prg)->program, pc);
|
uint8_t kt = readWord((*prg)->program, pc);
|
||||||
uint8_t vt = readWord((*prg)->program, pc);
|
uint8_t vt = readWord((*prg)->program, pc);
|
||||||
|
if (!config.alt_format_flag) {
|
||||||
SPC(spaces);
|
SPC(spaces);
|
||||||
printf("| | | ( subtype: [%d, %d] )\n", kt, vt);
|
printf("| | ");
|
||||||
|
printf("\n ( subtype: [%d, %d] )\n\n\n", kt, vt);
|
||||||
|
} else {
|
||||||
|
char s[100];
|
||||||
|
sprintf(s, " SUBTYPE %d,%d\n", kt, vt);
|
||||||
|
str_append(&lit_str, s);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
if (!config.alt_format_flag)
|
||||||
|
printf("\n");
|
||||||
|
else
|
||||||
|
str_append(&lit_str, "\n");
|
||||||
|
}
|
||||||
|
|
||||||
LIT_ADD(literalType, literal_type, literal_count);
|
LIT_ADD(literalType, literal_type, literal_count);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DIS_LITERAL_INDEX_BLANK:
|
case DIS_LITERAL_INDEX_BLANK:
|
||||||
LIT_ADD(DIS_LITERAL_INDEX_BLANK, literal_type, literal_count);
|
LIT_ADD(DIS_LITERAL_INDEX_BLANK, literal_type, literal_count);
|
||||||
|
if (!config.alt_format_flag) {
|
||||||
SPC(spaces);
|
SPC(spaces);
|
||||||
printf("| | [%d] ( blank )\n", i);
|
printf("| | ");
|
||||||
|
printf("[%05d] ( blank )\n", i);
|
||||||
|
} else {
|
||||||
|
str_append(&lit_str, " .lit BLANK\n");
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!config.group_flag) {
|
||||||
|
printf(lit_str);
|
||||||
|
} else {
|
||||||
|
lit_t fn_str = (lit_t)(lit_fn_queue_rear->data);
|
||||||
|
fn_str->str = calloc(1, strlen(lit_str) + 1);
|
||||||
|
strcpy(fn_str->str, lit_str);
|
||||||
|
}
|
||||||
|
free(lit_str);
|
||||||
|
|
||||||
consumeByte(DIS_OP_SECTION_END, (*prg)->program, pc);
|
consumeByte(DIS_OP_SECTION_END, (*prg)->program, pc);
|
||||||
|
|
||||||
|
if (!config.alt_format_flag) {
|
||||||
|
SPC(spaces);
|
||||||
|
printf("| ");
|
||||||
|
printf("--- ( end literal section ) ---\n");
|
||||||
|
}
|
||||||
|
|
||||||
int functionCount = readWord((*prg)->program, pc);
|
int functionCount = readWord((*prg)->program, pc);
|
||||||
int functionSize = readWord((*prg)->program, pc);
|
int functionSize = readWord((*prg)->program, pc);
|
||||||
|
|
||||||
if (functionCount) {
|
if (functionCount) {
|
||||||
|
if (!config.alt_format_flag) {
|
||||||
SPC(spaces);
|
SPC(spaces);
|
||||||
printf("| | \n");
|
printf("|\n");
|
||||||
SPC(spaces);
|
SPC(spaces);
|
||||||
printf("| | ( fun count: %d, total size: %d )\n", functionCount, functionSize);
|
printf("| ");
|
||||||
|
printf("--- ( fn count: %d, total size: %d ) ---\n", functionCount, functionSize);
|
||||||
|
}
|
||||||
|
|
||||||
uint32_t fcnt = 0;
|
uint32_t fcnt = 0;
|
||||||
|
char tree_local[2048];
|
||||||
|
|
||||||
for (uint32_t i = 0; i < literal_count; i++) {
|
for (uint32_t i = 0; i < literal_count; i++) {
|
||||||
if (literal_type[i] == DIS_LITERAL_FUNCTION_INTERMEDIATE) {
|
if (literal_type[i] == DIS_LITERAL_FUNCTION_INTERMEDIATE) {
|
||||||
size_t size = (size_t) readWord((*prg)->program, pc);
|
size_t size = (size_t) readWord((*prg)->program, pc);
|
||||||
@@ -496,29 +767,73 @@ static void dis_read_interpreter_sections(dis_program_t **prg, uint32_t *pc, uin
|
|||||||
uint32_t fpc_start = *pc;
|
uint32_t fpc_start = *pc;
|
||||||
uint32_t fpc_end = *pc + size - 1;
|
uint32_t fpc_end = *pc + size - 1;
|
||||||
|
|
||||||
|
tree_local[0] = '\0';
|
||||||
|
if (!config.alt_format_flag) {
|
||||||
|
sprintf(tree_local, "%s.%d", tree, fcnt);
|
||||||
|
if (tree_local[0] == '_')
|
||||||
|
memcpy(tree_local, tree_local + 1, strlen(tree_local));
|
||||||
|
} else {
|
||||||
|
sprintf(tree_local, "%s_%d", tree, fcnt);
|
||||||
|
if (tree_local[0] == '_')
|
||||||
|
memcpy(tree_local, tree_local + 1, strlen(tree_local));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!config.alt_format_flag) {
|
||||||
SPC(spaces);
|
SPC(spaces);
|
||||||
printf("| | |\n");
|
printf("| |\n");
|
||||||
SPC(spaces);
|
SPC(spaces);
|
||||||
printf("| | | ( fun %d [ start: %d, end: %d ] )", fcnt, fpc_start, fpc_end);
|
printf("| | ");
|
||||||
|
printf("( fun %s [ start: %d, end: %d ] )", tree_local, fpc_start, fpc_end);
|
||||||
|
} else {
|
||||||
|
if (!config.group_flag)
|
||||||
|
printf("\nLIT_FUN_%s:", tree_local);
|
||||||
|
else {
|
||||||
|
lit_t new_lit = malloc(sizeof(struct lit_s));
|
||||||
|
new_lit->fun = calloc(1, strlen(tree_local) + 1);
|
||||||
|
strcpy(new_lit->fun, tree_local);
|
||||||
|
dis_enqueue((void*) new_lit, &lit_fn_queue_front, &lit_fn_queue_rear, &lit_fn_queue_len);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if ((*prg)->program[*pc + size - 1] != DIS_OP_FN_END) {
|
if ((*prg)->program[*pc + size - 1] != DIS_OP_FN_END) {
|
||||||
printf("\nERROR: Failed to find function end\n");
|
printf("\nERROR: Failed to find function end\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
dis_read_interpreter_sections(prg, &fpc_start, spaces + 4);
|
dis_read_interpreter_sections(prg, &fpc_start, spaces + 4, tree_local, config);
|
||||||
|
|
||||||
|
if (!config.alt_format_flag) {
|
||||||
SPC(spaces);
|
SPC(spaces);
|
||||||
printf("| | |\n");
|
printf("| | |\n");
|
||||||
SPC(spaces + 4);
|
SPC(spaces + 4);
|
||||||
printf("| ------ CODE ------");
|
printf("| ");
|
||||||
dis_disassemble_section(prg, fpc_start, fpc_end, spaces + 4, true);
|
printf("--- ( reading code for %s ) ---", tree_local);
|
||||||
|
dis_disassemble_section(prg, fpc_start, fpc_end, spaces + 4, true, config);
|
||||||
printf("\n");
|
printf("\n");
|
||||||
SPC(spaces + 4);
|
SPC(spaces + 4);
|
||||||
printf("| ---- END CODE ----\n");
|
printf("| ");
|
||||||
|
printf("--- ( end code section ) ---\n");
|
||||||
|
} else {
|
||||||
|
fun_code_t *fun = malloc(sizeof(struct fun_code_s));
|
||||||
|
fun->fun = malloc(strlen(tree_local) + 1);
|
||||||
|
strcpy(fun->fun, tree_local);
|
||||||
|
fun->start = fpc_start;
|
||||||
|
fun->len = fpc_end;
|
||||||
|
dis_enqueue((void*) fun, &function_queue_front, &function_queue_rear, &function_queue_len);
|
||||||
|
}
|
||||||
|
|
||||||
fcnt++;
|
fcnt++;
|
||||||
*pc += size;
|
*pc += size;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!config.alt_format_flag) {
|
||||||
|
SPC(spaces);
|
||||||
|
printf("|\n");
|
||||||
|
SPC(spaces);
|
||||||
|
printf("| ");
|
||||||
|
printf("--- ( end fn section ) ---\n");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
consumeByte(DIS_OP_SECTION_END, (*prg)->program, pc);
|
consumeByte(DIS_OP_SECTION_END, (*prg)->program, pc);
|
||||||
@@ -526,25 +841,109 @@ static void dis_read_interpreter_sections(dis_program_t **prg, uint32_t *pc, uin
|
|||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
void disassemble(const char *filename) {
|
void disassemble(const char *filename, options_t config) {
|
||||||
dis_program_t *prg;
|
dis_program_t *prg;
|
||||||
|
|
||||||
dis_disassembler_init(&prg);
|
jump_label = 0;
|
||||||
if (dis_load_file(filename, &prg))
|
|
||||||
exit(1);
|
|
||||||
|
|
||||||
dis_read_header(&prg);
|
dis_disassembler_init(&prg);
|
||||||
|
if (dis_load_file(filename, &prg, config.alt_format_flag)) {
|
||||||
|
dis_disassembler_deinit(&prg);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
dis_read_header(&prg, config.alt_format_flag);
|
||||||
|
|
||||||
|
printf("\n.start MAIN\n");
|
||||||
|
|
||||||
consumeByte(DIS_OP_SECTION_END, prg->program, &(prg->pc));
|
consumeByte(DIS_OP_SECTION_END, prg->program, &(prg->pc));
|
||||||
|
|
||||||
printf("\n| ---- LITERALS ----");
|
if (!config.group_flag) {
|
||||||
dis_read_interpreter_sections(&prg, &(prg->pc), 0);
|
if (config.alt_format_flag)
|
||||||
printf("| -- END LITERALS --\n|");
|
printf("\nLIT_MAIN:");
|
||||||
|
|
||||||
printf("\n| ---- PROGRAM ----");
|
dis_read_interpreter_sections(&prg, &(prg->pc), 0, "", config);
|
||||||
dis_disassemble_section(&prg, prg->pc, prg->len, 0, false);
|
|
||||||
printf("\n| -- END PROGRAM --");
|
if (!config.alt_format_flag) {
|
||||||
|
printf("|\n| ");
|
||||||
|
printf("--- ( reading main code ) ---");
|
||||||
|
} else
|
||||||
|
printf("\nMAIN:");
|
||||||
|
|
||||||
|
dis_disassemble_section(&prg, prg->pc, prg->len, 0, false, config);
|
||||||
|
|
||||||
|
if (!config.alt_format_flag) {
|
||||||
|
printf("\n| ");
|
||||||
|
printf("--- ( end main code section ) ---");
|
||||||
|
} else
|
||||||
|
printf("\n");
|
||||||
|
|
||||||
|
if (config.alt_format_flag) {
|
||||||
|
while (function_queue_front != NULL) {
|
||||||
|
fun_code_t *fun = (fun_code_t*) function_queue_front->data;
|
||||||
|
printf("\nFUN_%s:", fun->fun);
|
||||||
|
free(fun->fun);
|
||||||
|
|
||||||
|
dis_disassemble_section(&prg, fun->start, fun->len, 0, true, config);
|
||||||
|
|
||||||
|
dis_dequeue(&function_queue_front, &function_queue_rear, &function_queue_len);
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
config.alt_format_flag = true;
|
||||||
|
|
||||||
|
lit_t new_lit = malloc(sizeof(struct lit_s));
|
||||||
|
new_lit->fun = calloc(1, 6 * sizeof(char));
|
||||||
|
strcpy(new_lit->fun, "MAIN");
|
||||||
|
dis_enqueue((void*) new_lit, &lit_fn_queue_front, &lit_fn_queue_rear, &lit_fn_queue_len);
|
||||||
|
|
||||||
|
dis_read_interpreter_sections(&prg, &(prg->pc), 0, "", config);
|
||||||
|
printf("\n");
|
||||||
|
|
||||||
|
while (lit_fn_queue_front != NULL) {
|
||||||
|
lit_t litf = (lit_t) lit_fn_queue_front->data;
|
||||||
|
|
||||||
|
if (!strcmp(litf->fun, "MAIN")) {
|
||||||
|
printf("MAIN:\n");
|
||||||
|
printf("%s", str_replace_substr_all(litf->str, ".lit FUNCTION ", ".lit FUNCTION (code=FUN_) "));
|
||||||
|
|
||||||
|
dis_disassemble_section(&prg, prg->pc, prg->len, 0, false, config);
|
||||||
|
free(litf->fun);
|
||||||
|
free(litf->str);
|
||||||
|
dis_dequeue(&lit_fn_queue_front, &lit_fn_queue_rear, &lit_fn_queue_len);
|
||||||
|
printf("\n\n");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("FUN_%s:\n", litf->fun);
|
||||||
|
char sbtr[strlen(litf->fun) + 19];
|
||||||
|
sprintf(sbtr, ".lit FUNCTION (code=FUN_%s_) ", litf->fun);
|
||||||
|
printf("%s", str_replace_substr_all(litf->str, ".lit FUNCTION ", sbtr));
|
||||||
|
|
||||||
|
queue_node_t *fqf = function_queue_front;
|
||||||
|
while (fqf != NULL) {
|
||||||
|
fun_code_t *fun = (fun_code_t*) fqf->data;
|
||||||
|
if (!strcmp(fun->fun, litf->fun)) {
|
||||||
|
dis_disassemble_section(&prg, fun->start, fun->len, 0, true, config);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
fqf = fqf->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(litf->fun);
|
||||||
|
free(litf->str);
|
||||||
|
dis_dequeue(&lit_fn_queue_front, &lit_fn_queue_rear, &lit_fn_queue_len);
|
||||||
|
|
||||||
printf("\n\n");
|
printf("\n\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
while (function_queue_front != NULL) {
|
||||||
|
free(((fun_code_t*)(function_queue_front->data))->fun);
|
||||||
|
dis_dequeue(&function_queue_front, &function_queue_rear, &function_queue_len);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("\n");
|
||||||
dis_disassembler_deinit(&prg);
|
dis_disassembler_deinit(&prg);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,20 @@
|
|||||||
|
/*
|
||||||
|
* disassembler.c
|
||||||
|
*
|
||||||
|
* Created on: 10 ago. 2023
|
||||||
|
* Original Author: Emiliano Augusto Gonzalez (egonzalez . hiperion @ gmail . com)
|
||||||
|
*
|
||||||
|
* Further modified by Kayne Ruse, and added to the Toy Programming Language tool repository.
|
||||||
|
*/
|
||||||
|
|
||||||
#ifndef DISASSEMBLER_H_
|
#ifndef DISASSEMBLER_H_
|
||||||
#define DISASSEMBLER_H_
|
#define DISASSEMBLER_H_
|
||||||
|
|
||||||
|
typedef struct options_s {
|
||||||
|
bool alt_format_flag;
|
||||||
|
bool group_flag;
|
||||||
|
} options_t;
|
||||||
|
|
||||||
typedef enum DIS_OPCODES {
|
typedef enum DIS_OPCODES {
|
||||||
DIS_OP_EOF, //
|
DIS_OP_EOF, //
|
||||||
|
|
||||||
@@ -13,8 +27,8 @@ typedef enum DIS_OPCODES {
|
|||||||
|
|
||||||
// data
|
// data
|
||||||
DIS_OP_LITERAL, //
|
DIS_OP_LITERAL, //
|
||||||
DIS_OP_LITERAL_LONG, // for more than 256 literals in a chunk
|
DIS_OP_LITERAL_LONG, //
|
||||||
DIS_OP_LITERAL_RAW, // forcibly get the raw value of the literal
|
DIS_OP_LITERAL_RAW, //
|
||||||
|
|
||||||
// arithmetic operators
|
// arithmetic operators
|
||||||
DIS_OP_NEGATE, //
|
DIS_OP_NEGATE, //
|
||||||
@@ -33,21 +47,21 @@ typedef enum DIS_OPCODES {
|
|||||||
DIS_OP_TYPE_DECL_removed, // deprecated
|
DIS_OP_TYPE_DECL_removed, // deprecated
|
||||||
DIS_OP_TYPE_DECL_LONG_removed, // deprecated
|
DIS_OP_TYPE_DECL_LONG_removed, // deprecated
|
||||||
|
|
||||||
DIS_OP_VAR_DECL, // declare a variable to be used (as a literal)
|
DIS_OP_VAR_DECL, //
|
||||||
DIS_OP_VAR_DECL_LONG, // declare a variable to be used (as a long literal)
|
DIS_OP_VAR_DECL_LONG, //
|
||||||
|
|
||||||
DIS_OP_FN_DECL, // declare a function to be used (as a literal)
|
DIS_OP_FN_DECL, //
|
||||||
DIS_OP_FN_DECL_LONG, // declare a function to be used (as a long literal)
|
DIS_OP_FN_DECL_LONG, //
|
||||||
|
|
||||||
DIS_OP_VAR_ASSIGN, // assign to a literal
|
DIS_OP_VAR_ASSIGN, //
|
||||||
DIS_OP_VAR_ADDITION_ASSIGN, //
|
DIS_OP_VAR_ADDITION_ASSIGN, //
|
||||||
DIS_OP_VAR_SUBTRACTION_ASSIGN, //
|
DIS_OP_VAR_SUBTRACTION_ASSIGN, //
|
||||||
DIS_OP_VAR_MULTIPLICATION_ASSIGN, //
|
DIS_OP_VAR_MULTIPLICATION_ASSIGN, //
|
||||||
DIS_OP_VAR_DIVISION_ASSIGN, //
|
DIS_OP_VAR_DIVISION_ASSIGN, //
|
||||||
DIS_OP_VAR_MODULO_ASSIGN, //
|
DIS_OP_VAR_MODULO_ASSIGN, //
|
||||||
|
|
||||||
DIS_OP_TYPE_CAST, // temporarily change a type of an atomic value
|
DIS_OP_TYPE_CAST, //
|
||||||
DIS_OP_TYPE_OF, // get the type of a variable
|
DIS_OP_TYPE_OF, //
|
||||||
|
|
||||||
DIS_OP_IMPORT, //
|
DIS_OP_IMPORT, //
|
||||||
DIS_OP_EXPORT_removed, // deprecated
|
DIS_OP_EXPORT_removed, // deprecated
|
||||||
@@ -65,7 +79,7 @@ typedef enum DIS_OPCODES {
|
|||||||
DIS_OP_COMPARE_LESS_EQUAL, //
|
DIS_OP_COMPARE_LESS_EQUAL, //
|
||||||
DIS_OP_COMPARE_GREATER, //
|
DIS_OP_COMPARE_GREATER, //
|
||||||
DIS_OP_COMPARE_GREATER_EQUAL, //
|
DIS_OP_COMPARE_GREATER_EQUAL, //
|
||||||
DIS_OP_INVERT, // for booleans
|
DIS_OP_INVERT, //
|
||||||
|
|
||||||
// logical operators
|
// logical operators
|
||||||
DIS_OP_AND, //
|
DIS_OP_AND, //
|
||||||
@@ -114,6 +128,6 @@ typedef enum DIS_LITERAL_TYPE {
|
|||||||
DIS_LITERAL_INDEX_BLANK, // for blank indexing i.e. arr[:]
|
DIS_LITERAL_INDEX_BLANK, // for blank indexing i.e. arr[:]
|
||||||
} dis_literal_type_t;
|
} dis_literal_type_t;
|
||||||
|
|
||||||
extern void disassemble(const char *filename);
|
extern void disassemble(const char *filename, options_t config);
|
||||||
|
|
||||||
#endif /* DISASSEMBLER_H_ */
|
#endif /* DISASSEMBLER_H_ */
|
||||||
|
|||||||
@@ -0,0 +1,92 @@
|
|||||||
|
/*
|
||||||
|
* utils.c
|
||||||
|
*
|
||||||
|
* Created on: 10 ago. 2023
|
||||||
|
* Original Author: Emiliano Augusto Gonzalez (egonzalez . hiperion @ gmail . com)
|
||||||
|
*
|
||||||
|
* Further modified by Kayne Ruse, and added to the Toy Programming Language tool repository.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "disassembler_utils.h"
|
||||||
|
|
||||||
|
void dis_enqueue(void *x, queue_node_t **queue_front, queue_node_t **queue_rear, uint32_t *len) {
|
||||||
|
queue_node_t *temp;
|
||||||
|
|
||||||
|
temp = (queue_node_t*) malloc(sizeof(struct queue_node_s));
|
||||||
|
temp->data = x;
|
||||||
|
temp->next = NULL;
|
||||||
|
|
||||||
|
if ((*queue_front) == NULL && (*queue_rear) == NULL) {
|
||||||
|
(*queue_front) = (*queue_rear) = temp;
|
||||||
|
++(*len);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
(*queue_rear)->next = temp;
|
||||||
|
(*queue_rear) = temp;
|
||||||
|
|
||||||
|
++(*len);
|
||||||
|
}
|
||||||
|
|
||||||
|
void dis_dequeue(queue_node_t **queue_front, queue_node_t **queue_rear, uint32_t *len) {
|
||||||
|
struct queue_node_s *temp = (*queue_front);
|
||||||
|
|
||||||
|
if ((*queue_front) == NULL) {
|
||||||
|
printf("Error : QUEUE is empty!!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if ((*queue_front) == (*queue_rear))
|
||||||
|
(*queue_front) = (*queue_rear) = NULL;
|
||||||
|
|
||||||
|
else
|
||||||
|
(*queue_front) = (*queue_front)->next;
|
||||||
|
|
||||||
|
--(*len);
|
||||||
|
free(temp->data);
|
||||||
|
free(temp);
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
|
||||||
|
void str_append(char **str, const char *app) {
|
||||||
|
if ((*str) == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
*str = realloc(*str, (strlen(*str) + strlen(app) + 1) * sizeof(char));
|
||||||
|
memcpy((*str) + strlen(*str), app, strlen(app) + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
char* str_replace_substr_all(char *mainstr, char *substr, char *newstr) {
|
||||||
|
int lenmain, lensub, i, j, lennew, startindex = -1, c;
|
||||||
|
lenmain = strlen(mainstr);
|
||||||
|
lensub = strlen(substr);
|
||||||
|
lennew = strlen(newstr);
|
||||||
|
char *result = (char*) malloc(sizeof(char) * (lenmain + 200));
|
||||||
|
for (c = 0, i = 0; i < lenmain; i++) {
|
||||||
|
if (lenmain - i >= lensub && *(mainstr + i) == *(substr)) {
|
||||||
|
startindex = i;
|
||||||
|
for (j = 1; j < lensub; j++)
|
||||||
|
if (*(mainstr + i + j) != *(substr + j)) {
|
||||||
|
startindex = -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (startindex != -1) {
|
||||||
|
for (j = 0; j < lennew; j++, c++) {
|
||||||
|
*(result + c) = *(newstr + j);
|
||||||
|
}
|
||||||
|
i = i + lensub - 1;
|
||||||
|
} else {
|
||||||
|
*(result + c) = *(mainstr + i);
|
||||||
|
c++;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
*(result + c) = *(mainstr + i);
|
||||||
|
c++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*(result + c) = '\0';
|
||||||
|
return result;
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
/*
|
||||||
|
* utils.h
|
||||||
|
*
|
||||||
|
* Created on: 10 ago. 2023
|
||||||
|
* Original Author: Emiliano Augusto Gonzalez (egonzalez . hiperion @ gmail . com)
|
||||||
|
*
|
||||||
|
* Further modified by Kayne Ruse, and added to the Toy Programming Language tool repository.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef UTILS_H_
|
||||||
|
#define UTILS_H_
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
typedef struct queue_node_s {
|
||||||
|
void *data;
|
||||||
|
struct queue_node_s *next;
|
||||||
|
} queue_node_t;
|
||||||
|
|
||||||
|
void dis_enqueue(void *x, queue_node_t **queue_front, queue_node_t **queue_rear, uint32_t *len);
|
||||||
|
void dis_dequeue(queue_node_t **queue_front, queue_node_t **queue_rear, uint32_t *len);
|
||||||
|
|
||||||
|
void str_append(char **str, const char *app);
|
||||||
|
char* str_replace_substr_all(char *mainstr, char *substr, char *newstr);
|
||||||
|
|
||||||
|
#endif /* UTILS_H_ */
|
||||||
@@ -1,8 +1,53 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "cargs.h"
|
||||||
#include "disassembler.h"
|
#include "disassembler.h"
|
||||||
|
|
||||||
int main(int argc, const char* argv[]) {
|
static struct cag_option options[] = {
|
||||||
disassemble(argv[1]);
|
{
|
||||||
|
.identifier = 'a',
|
||||||
|
.access_letters = "a",
|
||||||
|
.access_name = NULL,
|
||||||
|
.value_name = NULL,
|
||||||
|
.description = "Alternate format"
|
||||||
|
}, {
|
||||||
|
.identifier = 'g',
|
||||||
|
.access_letters = "g",
|
||||||
|
.access_name = NULL,
|
||||||
|
.value_name = NULL,
|
||||||
|
.description = "Group literals with functions"
|
||||||
|
}, {
|
||||||
|
.identifier = 'h',
|
||||||
|
.access_letters = "h",
|
||||||
|
.access_name = "help",
|
||||||
|
.description = "Shows the command help"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
int main(int argc, char *argv[]) {
|
||||||
|
char identifier;
|
||||||
|
cag_option_context context;
|
||||||
|
options_t config = { false, false };
|
||||||
|
|
||||||
|
cag_option_prepare(&context, options, CAG_ARRAY_SIZE(options), argc, argv);
|
||||||
|
while (cag_option_fetch(&context)) {
|
||||||
|
identifier = cag_option_get(&context);
|
||||||
|
switch (identifier) {
|
||||||
|
case 'a':
|
||||||
|
config.alt_format_flag = true;
|
||||||
|
break;
|
||||||
|
case 'g':
|
||||||
|
config.group_flag = true;
|
||||||
|
config.alt_format_flag = true;
|
||||||
|
break;
|
||||||
|
case 'h':
|
||||||
|
printf("Usage: disassembler [OPTION] file\n");
|
||||||
|
cag_option_print(options, CAG_ARRAY_SIZE(options), stdout);
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
disassemble(argv[context.index], config);
|
||||||
|
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,8 +7,8 @@ LIBS+=
|
|||||||
ODIR = obj
|
ODIR = obj
|
||||||
SRC = $(wildcard *.c)
|
SRC = $(wildcard *.c)
|
||||||
OBJ = $(addprefix $(ODIR)/,$(SRC:.c=.o))
|
OBJ = $(addprefix $(ODIR)/,$(SRC:.c=.o))
|
||||||
OUTNAME=
|
OUTDIR=../../out
|
||||||
OUT=disassembler
|
OUT=$(OUTDIR)/disassembler
|
||||||
|
|
||||||
all: $(OBJ)
|
all: $(OBJ)
|
||||||
$(CC) $(CFLAGS) -o $(OUT) $(OBJ) $(LIBS)
|
$(CC) $(CFLAGS) -o $(OUT) $(OBJ) $(LIBS)
|
||||||
|
|||||||
Reference in New Issue
Block a user