Compare commits

..

50 Commits

Author SHA1 Message Date
Ratstail91 eaad8d5241 Messing with tests 2023-08-28 23:31:09 +10:00
Ratstail91 308fba1a8c Added carriage return as escapable character 2023-08-28 22:04:21 +10:00
Ratstail91 bcc9df928a Investigating mingw behaviour 2023-08-28 21:59:06 +10:00
Ratstail91 c66e77ec57 Merge branch 'main' of https://github.com/Add00/Toy into Add00-main 2023-08-28 21:30:21 +10:00
Kayne Ruse 9dc9316853 Merge pull request #116 from hiperiondev/main
Correct format
2023-08-29 13:07:22 +10:00
hiperiondev a864a1a226 Correct format 2023-08-28 23:57:46 -03:00
Kayne Ruse c645026620 Merge pull request #115 from hiperiondev/main
Add disassemblre group option
2023-08-29 12:50:56 +10:00
hiperiondev a9ccd65da1 Add disassemblre group option 2023-08-28 23:46:02 -03:00
Add00 113c067c96 updated path error messages 2023-08-27 23:39:32 -04:00
Add00 01f710a4f3 Merge branch 'Ratstail91:main' into main 2023-08-24 17:14:33 -04:00
Add00 eb4c44193c added path method and more tests 2023-08-24 17:09:20 -04:00
Kayne Ruse 0da5201829 Merge pull request #114 from hiperiondev/main
Correct disassembler
2023-08-24 21:43:15 +10:00
Add00 214351abaa view result 2023-08-23 23:19:33 -04:00
hiperiondev 6be29ed8c5 Add implicit fn return 2023-08-23 20:48:06 -03:00
hiperiondev 6341d3337f Correct disassembler 2023-08-23 12:37:28 -03:00
Kayne Ruse d4f952eafc Merge pull request #110 from hiperiondev/main
Add disassembler alternative format
2023-08-23 22:09:33 +10:00
hiperiondev d5bc07d3b3 Add header reference 2023-08-23 08:36:27 -03:00
hiperiondev 5a851f6fbe Rename 2023-08-22 20:35:22 -03:00
hiperiondev d8c6a3ec27 Correct memory leak 2023-08-22 20:21:43 -03:00
hiperiondev b5883e248b Correct format 2023-08-22 19:45:14 -03:00
hiperiondev 52048f2466 Correct literal format 2023-08-22 19:31:06 -03:00
hiperiondev 6b8e95d250 Add disassembler alternative format 2023-08-22 18:23:27 -03:00
Add00 73965bc0e4 input and output can now be closed 2023-08-21 22:47:32 -04:00
Ratstail91 5721edc2d1 Tweaked disassembler pretty printing, because I'm bored 2023-08-22 07:27:36 +10:00
Ratstail91 db52c13613 Removed extra scope around for loop body blocks, resolved #107 2023-08-22 01:11:49 +10:00
Add00 46e274d182 Merge branch 'Ratstail91:main' into main 2023-08-21 10:54:27 -04:00
Ratstail91 7290efe069 Tweaked valgrind test
@add00 you'll want to merge these and test them
2023-08-22 00:43:48 +10:00
Add00 925f13abf5 potential fix for mingw32 issue 2023-08-19 22:10:29 -04:00
Add00 9a56a86ec8 add read/write for bools, and fixed sanitize issue 2023-08-19 21:51:44 -04:00
Add00 3ddda21ff2 Improved error messages, and feedback improvements 2023-08-19 15:41:21 -04:00
Ratstail91 0cf92bdeae Added contributors to the README, removed a binary that was accidentally committed 2023-08-19 06:53:34 +10:00
Add00 65acdd2730 in and out file marked as static 2023-08-15 22:53:16 -04:00
Add00 1603ea1798 mostly fixed sanitization issue 2023-08-14 23:09:13 -04:00
Add00 79f2e231db fix stack overflow issue 2023-08-14 22:22:20 -04:00
Add00 ab0720a5ef memory leak and several bugs fixed 2023-08-14 22:02:33 -04:00
Add00 901940a3d0 Merge branch 'Ratstail91:main' into main 2023-08-14 18:56:13 -04:00
Kayne Ruse 4c9a2e5378 Merge pull request #106 from hiperiondev/main
Disassembler: Some optimizations
2023-08-15 03:57:29 +10:00
hiperiondev 1e11e9eea7 Start independent code from PC zero. Add hierarchical notation for function index. Add guard for end literals. Some presentation formats. 2023-08-14 14:46:07 -03:00
Add00 a0acd27be1 partly fixed memory leak issue 2023-08-13 22:27:54 -04:00
Add00 0c005d0af2 added file operations and additional tests 2023-08-12 16:02:54 -04:00
Add00 38ba2273dd added accessors, write and additional tests 2023-08-10 23:00:26 -04:00
Add00 1b8d8cfba0 Removed debug code 2023-08-09 08:48:40 -04:00
Add00 648a5f84db fixed close function 2023-08-08 23:41:23 -04:00
Add00 e2dda434f8 Fixed memory leak 2023-08-08 19:25:18 -04:00
Add00 5a8e2c0527 Fixed path 2023-08-08 19:05:35 -04:00
Add00 dea5cf6d43 removed HAL 2023-08-08 19:04:27 -04:00
Add00 930115f94c Merge branch 'Ratstail91:main' into main 2023-08-08 13:57:57 -04:00
Add00 2fa6b7ee23 added basic read, and an improved HAL 2023-08-06 09:39:06 -04:00
Add00 43b58eb421 Library rename, added HAL, added open function 2023-08-04 23:13:43 -04:00
Add00 36b4a494ae io library file creation 2023-08-02 22:19:09 -04:00
27 changed files with 2594 additions and 227 deletions
+1 -1
View File
@@ -2,7 +2,7 @@ name: Comprehensive Tests
on: on:
push: push:
branches: [ "main", "dev" ] branches: [ "main", "*" ]
pull_request: pull_request:
branches: [ "main" ] branches: [ "main" ]
+56 -32
View File
@@ -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/
+10
View File
@@ -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
+940
View File
@@ -0,0 +1,940 @@
#include "lib_fileio.h"
#include "toy_memory.h"
#include "drive_system.h"
#include <limits.h>
#include <stdio.h>
typedef struct Toy_File
{
FILE* fp;
Toy_RefString* mode;
Toy_RefString* path;
} Toy_File;
Toy_File* createToyFile(Toy_RefString* mode, Toy_RefString* path) {
Toy_File* file = TOY_ALLOCATE(Toy_File, 1);
file->fp = NULL;
file->mode = Toy_copyRefString(mode);
file->path = Toy_copyRefString(path);
return file;
}
void deleteToyFile(Toy_File* file) {
Toy_deleteRefString(file->mode);
Toy_deleteRefString(file->path);
TOY_FREE(Toy_File, file);
}
static int nativeOpen(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
if (arguments->count < 1) {
interpreter->errorOutput("Too few arguments open(string, string) expects two arguments\n");
return -1;
}
else if (arguments->count > 2) {
interpreter->errorOutput("Too many arguments open(string, string) expects two arguments\n");
return -1;
}
Toy_Literal modeLiteral = arguments->count == 2? Toy_popLiteralArray(arguments) : TOY_TO_STRING_LITERAL(Toy_createRefString("r"));
Toy_Literal drivePathLiteral = Toy_popLiteralArray(arguments);
// parse the drivePath (if it's an identifier)
Toy_Literal drivePathLiteralIdn = drivePathLiteral;
if (TOY_IS_IDENTIFIER(drivePathLiteral) && Toy_parseIdentifierToValue(interpreter, &drivePathLiteral)) {
Toy_freeLiteral(drivePathLiteralIdn);
}
// check the drivePath type
if (!TOY_IS_STRING(drivePathLiteral)) {
interpreter->errorOutput("Incorrect argument type expected a string as the first argument to open(string, string)\n");
Toy_freeLiteral(drivePathLiteral);
Toy_freeLiteral(modeLiteral);
return -1;
}
Toy_Literal filePathLiteral = Toy_getDrivePathLiteral(interpreter, &drivePathLiteral);
if (TOY_IS_NULL(filePathLiteral)) {
interpreter->errorOutput("File not found in the specified drive\n");
Toy_freeLiteral(drivePathLiteral);
Toy_freeLiteral(filePathLiteral);
Toy_freeLiteral(modeLiteral);
return -1;
}
// parse the mode (if it's an identifier)
Toy_Literal modeLiteralIdn = modeLiteral;
if (TOY_IS_IDENTIFIER(modeLiteral) && Toy_parseIdentifierToValue(interpreter, &modeLiteral)) {
Toy_freeLiteral(modeLiteralIdn);
}
// check the mode type
if (!TOY_IS_STRING(modeLiteral)) {
interpreter->errorOutput("Incorrect argument type expected a string as the second argument to open(string, string)\n");
Toy_freeLiteral(drivePathLiteral);
Toy_freeLiteral(filePathLiteral);
Toy_freeLiteral(modeLiteral);
return -1;
}
const char* filePath = Toy_toCString(TOY_AS_STRING(filePathLiteral));
size_t filePathLength = Toy_lengthRefString(TOY_AS_STRING(filePathLiteral));
const char* mode = Toy_toCString(TOY_AS_STRING(modeLiteral));
// build file object
Toy_File* file = createToyFile(TOY_AS_STRING(modeLiteral), TOY_AS_STRING(filePathLiteral));
// attempt to open file
file->fp = fopen(filePath, mode);
// result
Toy_Literal fileLiteral = TOY_TO_NULL_LITERAL;
if (file->fp == NULL) {
deleteToyFile(file);
}
else {
fileLiteral = TOY_TO_OPAQUE_LITERAL(file, TOY_OPAQUE_TAG_FILE);
}
Toy_pushLiteralArray(&interpreter->stack, fileLiteral);
// cleanup
Toy_freeLiteral(fileLiteral);
Toy_freeLiteral(drivePathLiteral);
Toy_freeLiteral(filePathLiteral);
Toy_freeLiteral(modeLiteral);
return 1;
}
static int nativeClose(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
if (arguments->count != 1) {
interpreter->errorOutput("Too many arguments close() expects zero arguments\n");
return -1;
}
Toy_Literal selfLiteral = Toy_popLiteralArray(arguments);
// parse the self (if it's an identifier)
Toy_Literal selfLiteralIdn = selfLiteral;
if (TOY_IS_IDENTIFIER(selfLiteral) && Toy_parseIdentifierToValue(interpreter, &selfLiteral)) {
Toy_freeLiteral(selfLiteralIdn);
}
// check self type
if (!TOY_IS_OPAQUE(selfLiteral) && TOY_GET_OPAQUE_TAG(selfLiteral) != TOY_OPAQUE_TAG_FILE) {
interpreter->errorOutput("Incorrect self type close() expects a file type\n");
Toy_freeLiteral(selfLiteral);
return -1;
}
Toy_File* file = (Toy_File*)TOY_AS_OPAQUE(selfLiteral);
int result = 0;
if (
file->fp != stdout &&
file->fp != stdin &&
file->fp != NULL
) {
result = fclose(file->fp);
file->fp = NULL;
}
// return the result
Toy_Literal resultLiteral = TOY_TO_BOOLEAN_LITERAL(result != EOF);
Toy_pushLiteralArray(&interpreter->stack, resultLiteral);
// cleanup
deleteToyFile(file);
Toy_freeLiteral(resultLiteral);
Toy_freeLiteral(selfLiteral);
return 1;
}
static int nativeRead(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
if (arguments->count < 2) {
interpreter->errorOutput("Too few arguments read(type) expects one argument\n");
return -1;
}
else if (arguments->count > 2) {
interpreter->errorOutput("Too many arguments read(type) expects one argument\n");
return -1;
}
Toy_Literal typeLiteral = Toy_popLiteralArray(arguments);
Toy_Literal selfLiteral = Toy_popLiteralArray(arguments);
// parse the type (if it's an identifier)
Toy_Literal typeLiteralIdn = typeLiteral;
if (TOY_IS_IDENTIFIER(typeLiteral) && Toy_parseIdentifierToValue(interpreter, &typeLiteral)) {
Toy_freeLiteral(typeLiteralIdn);
}
// check the type type
if (!TOY_IS_TYPE(typeLiteral)) {
interpreter->errorOutput("Incorrect argument type expected a type as the first argument to read(type)\n");
Toy_freeLiteral(selfLiteral);
Toy_freeLiteral(typeLiteral);
return -1;
}
// parse the self (if it's an identifier)
Toy_Literal selfLiteralIdn = selfLiteral;
if (TOY_IS_IDENTIFIER(selfLiteral) && Toy_parseIdentifierToValue(interpreter, &selfLiteral)) {
Toy_freeLiteral(selfLiteralIdn);
}
// check self type
if (!TOY_IS_OPAQUE(selfLiteral) && TOY_GET_OPAQUE_TAG(selfLiteral) != TOY_OPAQUE_TAG_FILE) {
interpreter->errorOutput("Incorrect self type, read(type) expects a file type\n");
Toy_freeLiteral(selfLiteral);
Toy_freeLiteral(typeLiteral);
return -1;
}
Toy_File* file = (Toy_File*)TOY_AS_OPAQUE(selfLiteral);
Toy_Literal resultLiteral = TOY_TO_NULL_LITERAL;
int error = 0;
switch (TOY_AS_TYPE(typeLiteral).typeOf) {
case TOY_LITERAL_BOOLEAN: {
char value = '0';
error = fscanf(file->fp, "%c", &value);
resultLiteral = TOY_TO_BOOLEAN_LITERAL(value != '0');
break;
}
case TOY_LITERAL_INTEGER: {
int value = 0;
error = fscanf(file->fp, "%i", &value);
resultLiteral = TOY_TO_INTEGER_LITERAL(value);
break;
}
case TOY_LITERAL_FLOAT: {
float value = 0.0f;
error = fscanf(file->fp, "%f", &value);
resultLiteral = TOY_TO_FLOAT_LITERAL(value);
break;
}
case TOY_LITERAL_STRING: { //BUG: needs a terminator to show how much to read
char value[TOY_MAX_STRING_LENGTH] = {0};
size_t size = fread(value, sizeof(char), TOY_MAX_STRING_LENGTH - 1, file->fp);
value[size] = '\0';
resultLiteral = TOY_TO_STRING_LITERAL(Toy_createRefString(value));
break;
}
default: {
// TODO handle other types
break;
}
}
if (error != EOF) {
Toy_pushLiteralArray(&interpreter->stack, resultLiteral);
}
else {
Toy_pushLiteralArray(&interpreter->stack, TOY_TO_NULL_LITERAL);
}
// cleanup
Toy_freeLiteral(resultLiteral);
Toy_freeLiteral(typeLiteral);
Toy_freeLiteral(selfLiteral);
return 1;
}
static int nativeWrite(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
if (arguments->count < 2) {
interpreter->errorOutput("Too few arguments write(any) expects one argument\n");
return -1;
}
else if (arguments->count > 2) {
interpreter->errorOutput("Too many arguments write(any) expects one argument\n");
return -1;
}
Toy_Literal valueLiteral = Toy_popLiteralArray(arguments);
Toy_Literal selfLiteral = Toy_popLiteralArray(arguments);
// parse the value (if it's an identifier)
Toy_Literal valueLiteralIdn = valueLiteral;
if (TOY_IS_IDENTIFIER(valueLiteral) && Toy_parseIdentifierToValue(interpreter, &valueLiteral)) {
Toy_freeLiteral(valueLiteralIdn);
}
// check the value type
if (TOY_IS_NULL(valueLiteral)) {
interpreter->errorOutput("Incorrect argument type expected non null value as the first argument to write(any)\n");
Toy_freeLiteral(selfLiteral);
Toy_freeLiteral(valueLiteral);
return -1;
}
// parse the self (if it's an identifier)
Toy_Literal selfLiteralIdn = selfLiteral;
if (TOY_IS_IDENTIFIER(selfLiteral) && Toy_parseIdentifierToValue(interpreter, &selfLiteral)) {
Toy_freeLiteral(selfLiteralIdn);
}
// check self type
if (!TOY_IS_OPAQUE(selfLiteral) && TOY_GET_OPAQUE_TAG(selfLiteral) != TOY_OPAQUE_TAG_FILE) {
interpreter->errorOutput("Incorrect self type write(any) expects a file type\n");
Toy_freeLiteral(selfLiteral);
Toy_freeLiteral(valueLiteral);
return -1;
}
Toy_File* file = (Toy_File*)TOY_AS_OPAQUE(selfLiteral);
int result = 0;
switch (valueLiteral.type) {
case TOY_LITERAL_BOOLEAN: {
result = fprintf(file->fp, "%i", TOY_AS_BOOLEAN(valueLiteral));
break;
}
case TOY_LITERAL_INTEGER: {
result = fprintf(file->fp, "%i", TOY_AS_INTEGER(valueLiteral));
break;
}
case TOY_LITERAL_FLOAT: {
result = fprintf(file->fp, "%f", TOY_AS_FLOAT(valueLiteral));
break;
}
case TOY_LITERAL_STRING: {
result = fprintf(file->fp, "%s", Toy_toCString(TOY_AS_STRING(valueLiteral)));
break;
}
default: {
// TODO handle other types
break;
}
}
Toy_Literal resultLiteral = TOY_TO_BOOLEAN_LITERAL(result > 0);
Toy_pushLiteralArray(&interpreter->stack, resultLiteral);
// cleanup
Toy_freeLiteral(resultLiteral);
Toy_freeLiteral(valueLiteral);
Toy_freeLiteral(selfLiteral);
return 1;
}
static int nativeRename(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
if (arguments->count < 2) {
interpreter->errorOutput("Too few arguments rename(string) expects one argument\n");
return -1;
}
else if (arguments->count > 2) {
interpreter->errorOutput("Too many arguments rename(string) expects one argument\n");
return -1;
}
Toy_Literal valueLiteral = Toy_popLiteralArray(arguments);
Toy_Literal selfLiteral = Toy_popLiteralArray(arguments);
// parse the value (if it's an identifier)
Toy_Literal valueLiteralIdn = valueLiteral;
if (TOY_IS_IDENTIFIER(valueLiteral) && Toy_parseIdentifierToValue(interpreter, &valueLiteral)) {
Toy_freeLiteral(valueLiteralIdn);
}
// check the value type
if (!TOY_IS_STRING(valueLiteral)) {
interpreter->errorOutput("Incorrect argument type expected a string as the first argument to rename(string)\n");
Toy_freeLiteral(selfLiteral);
Toy_freeLiteral(valueLiteral);
return -1;
}
// parse the self (if it's an identifier)
Toy_Literal selfLiteralIdn = selfLiteral;
if (TOY_IS_IDENTIFIER(selfLiteral) && Toy_parseIdentifierToValue(interpreter, &selfLiteral)) {
Toy_freeLiteral(selfLiteralIdn);
}
// check self type
if (!TOY_IS_OPAQUE(selfLiteral) && TOY_GET_OPAQUE_TAG(selfLiteral) != TOY_OPAQUE_TAG_FILE) {
interpreter->errorOutput("Incorrect self type, rename(string) expects a file type\n");
Toy_freeLiteral(selfLiteral);
Toy_freeLiteral(valueLiteral);
return -1;
}
Toy_Literal filePathLiteral = Toy_getDrivePathLiteral(interpreter, &valueLiteral);
Toy_File* file = (Toy_File*)TOY_AS_OPAQUE(selfLiteral);
const char* newName = Toy_toCString(TOY_AS_STRING(filePathLiteral));
// close the file
if (file->fp != NULL) {
fclose(file->fp);
file->fp = NULL;
}
// rename the file
int result = rename(Toy_toCString(file->path), newName);
// open file again
file->fp = fopen(newName, Toy_toCString(file->mode));
// update the file object's name
Toy_deleteRefString(file->path);
file->path = Toy_createRefString(newName);
// return result
Toy_Literal resultLiteral = TOY_TO_BOOLEAN_LITERAL(result == 0);
Toy_pushLiteralArray(&interpreter->stack, resultLiteral);
// cleanup
Toy_freeLiteral(resultLiteral);
Toy_freeLiteral(filePathLiteral);
Toy_freeLiteral(valueLiteral);
Toy_freeLiteral(selfLiteral);
return 1;
}
static int nativeSeek(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
if (arguments->count < 3) {
interpreter->errorOutput("Too few arguments seek(string, int) expects two arguments\n");
return -1;
}
else if (arguments->count > 3) {
interpreter->errorOutput("Too many arguments seek(string, int) expects two arguments\n");
return -1;
}
Toy_Literal offsetLiteral = Toy_popLiteralArray(arguments);
Toy_Literal originLiteral = Toy_popLiteralArray(arguments);
Toy_Literal selfLiteral = Toy_popLiteralArray(arguments);
// parse the origin (if it's an identifier)
Toy_Literal originLiteralIdn = originLiteral;
if (TOY_IS_IDENTIFIER(originLiteral) && Toy_parseIdentifierToValue(interpreter, &originLiteral)) {
Toy_freeLiteral(originLiteralIdn);
}
// check the origin type
if (!TOY_IS_STRING(originLiteral)) {
interpreter->errorOutput("Incorrect argument type expected a string as the first argument to seek(string, int)\n");
Toy_freeLiteral(selfLiteral);
Toy_freeLiteral(offsetLiteral);
Toy_freeLiteral(originLiteral);
return -1;
}
// parse the offset (if it's an identifier)
Toy_Literal offsetLiteralIdn = offsetLiteral;
if (TOY_IS_IDENTIFIER(offsetLiteral) && Toy_parseIdentifierToValue(interpreter, &offsetLiteral)) {
Toy_freeLiteral(offsetLiteralIdn);
}
// check the offset type
if (!TOY_IS_INTEGER(offsetLiteral)) {
interpreter->errorOutput("Incorrect argument type expected a int as the second argument to seek(string, int)\n");
Toy_freeLiteral(selfLiteral);
Toy_freeLiteral(offsetLiteral);
Toy_freeLiteral(originLiteral);
return -1;
}
// parse the self (if it's an identifier)
Toy_Literal selfLiteralIdn = selfLiteral;
if (TOY_IS_IDENTIFIER(selfLiteral) && Toy_parseIdentifierToValue(interpreter, &selfLiteral)) {
Toy_freeLiteral(selfLiteralIdn);
}
// check self type
if (!TOY_IS_OPAQUE(selfLiteral) && TOY_GET_OPAQUE_TAG(selfLiteral) != TOY_OPAQUE_TAG_FILE) {
interpreter->errorOutput("Incorrect self type seek(string, int) expects a file type\n");
Toy_freeLiteral(selfLiteral);
Toy_freeLiteral(offsetLiteral);
Toy_freeLiteral(originLiteral);
return -1;
}
Toy_File* file = (Toy_File*)TOY_AS_OPAQUE(selfLiteral);
Toy_RefString* orginString = TOY_AS_STRING(originLiteral);
int offset = TOY_AS_INTEGER(offsetLiteral);
int origin = -1;
if (Toy_equalsRefStringCString(orginString, "bgn")) {
origin = SEEK_SET;
}
else if (Toy_equalsRefStringCString(orginString, "cur")) {
origin = SEEK_CUR;
}
else if (Toy_equalsRefStringCString(orginString, "end")) {
origin = SEEK_END;
}
int result = origin >= SEEK_SET && origin <= SEEK_END?
fseek(file->fp, offset, origin) : -1;
Toy_Literal resultLiteral = TOY_TO_BOOLEAN_LITERAL(result == 0);
Toy_pushLiteralArray(&interpreter->stack, resultLiteral);
// cleanup
Toy_freeLiteral(resultLiteral);
Toy_freeLiteral(originLiteral);
Toy_freeLiteral(offsetLiteral);
Toy_freeLiteral(selfLiteral);
return 1;
}
static int nativeError(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
if (arguments->count != 1) {
interpreter->errorOutput("Too many arguments error() expects zero arguments\n");
return -1;
}
Toy_Literal selfLiteral = Toy_popLiteralArray(arguments);
// parse the self (if it's an identifier)
Toy_Literal selfLiteralIdn = selfLiteral;
if (TOY_IS_IDENTIFIER(selfLiteral) && Toy_parseIdentifierToValue(interpreter, &selfLiteral)) {
Toy_freeLiteral(selfLiteralIdn);
}
// check self type
if (!TOY_IS_OPAQUE(selfLiteral) && TOY_GET_OPAQUE_TAG(selfLiteral) != TOY_OPAQUE_TAG_FILE) {
interpreter->errorOutput("Incorrect self type error() expects a file type\n");
Toy_freeLiteral(selfLiteral);
return -1;
}
Toy_File* file = (Toy_File*)TOY_AS_OPAQUE(selfLiteral);
int result = ferror(file->fp);
// return the result
Toy_Literal resultLiteral = TOY_TO_BOOLEAN_LITERAL(result != 0);
Toy_pushLiteralArray(&interpreter->stack, resultLiteral);
// cleanup
Toy_freeLiteral(selfLiteral);
return 1;
}
static int nativeCompleted(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
if (arguments->count != 1) {
interpreter->errorOutput("Too many arguments completed() expects zero arguments\n");
return -1;
}
Toy_Literal selfLiteral = Toy_popLiteralArray(arguments);
// parse the self (if it's an identifier)
Toy_Literal selfLiteralIdn = selfLiteral;
if (TOY_IS_IDENTIFIER(selfLiteral) && Toy_parseIdentifierToValue(interpreter, &selfLiteral)) {
Toy_freeLiteral(selfLiteralIdn);
}
// check self type
if (!TOY_IS_OPAQUE(selfLiteral) && TOY_GET_OPAQUE_TAG(selfLiteral) != TOY_OPAQUE_TAG_FILE) {
interpreter->errorOutput("Incorrect self type completed() expects a file type\n");
Toy_freeLiteral(selfLiteral);
return -1;
}
Toy_File* file = (Toy_File*)TOY_AS_OPAQUE(selfLiteral);
int result = feof(file->fp);
// return the result
Toy_Literal resultLiteral = TOY_TO_BOOLEAN_LITERAL(result != 0);
Toy_pushLiteralArray(&interpreter->stack, resultLiteral);
// cleanup
Toy_freeLiteral(resultLiteral);
Toy_freeLiteral(selfLiteral);
return 1;
}
static int nativePosition(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
if (arguments->count != 1) {
interpreter->errorOutput("Too many arguments position() expects zero arguments\n");
return -1;
}
Toy_Literal selfLiteral = Toy_popLiteralArray(arguments);
// parse the self (if it's an identifier)
Toy_Literal selfLiteralIdn = selfLiteral;
if (TOY_IS_IDENTIFIER(selfLiteral) && Toy_parseIdentifierToValue(interpreter, &selfLiteral)) {
Toy_freeLiteral(selfLiteralIdn);
}
// check self type
if (!TOY_IS_OPAQUE(selfLiteral) && TOY_GET_OPAQUE_TAG(selfLiteral) != TOY_OPAQUE_TAG_FILE) {
interpreter->errorOutput("Incorrect self type position() expects a file type\n");
Toy_freeLiteral(selfLiteral);
return -1;
}
Toy_File* file = (Toy_File*)TOY_AS_OPAQUE(selfLiteral);
// pervent integer overflow as ftell returns a long
int size = ftell(file->fp) > INT_MAX? INT_MAX : ftell(file->fp);
// return the result
Toy_Literal resultLiteral = TOY_TO_INTEGER_LITERAL(size);
Toy_pushLiteralArray(&interpreter->stack, resultLiteral);
// cleanup
Toy_freeLiteral(resultLiteral);
Toy_freeLiteral(selfLiteral);
return 1;
}
static int nativeSize(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
if (arguments->count != 1) {
interpreter->errorOutput("Too many arguments size() expects zero arguments\n");
return -1;
}
Toy_Literal selfLiteral = Toy_popLiteralArray(arguments);
// parse the self (if it's an identifier)
Toy_Literal selfLiteralIdn = selfLiteral;
if (TOY_IS_IDENTIFIER(selfLiteral) && Toy_parseIdentifierToValue(interpreter, &selfLiteral)) {
Toy_freeLiteral(selfLiteralIdn);
}
// check self type
if (!TOY_IS_OPAQUE(selfLiteral) && TOY_GET_OPAQUE_TAG(selfLiteral) != TOY_OPAQUE_TAG_FILE) {
interpreter->errorOutput("Incorrect self type size() expects a file type\n");
Toy_freeLiteral(selfLiteral);
return -1;
}
Toy_File* file = (Toy_File*)TOY_AS_OPAQUE(selfLiteral);
int size = 0;
fseek(file->fp, 0, SEEK_END);
// pervent integer overflow as ftell returns a long
if (ftell(file->fp) > INT_MAX) {
size = INT_MAX;
}
else {
size = ftell(file->fp);
}
fseek(file->fp, 0, SEEK_SET);
// return the result
Toy_Literal resultLiteral = TOY_TO_INTEGER_LITERAL(size);
Toy_pushLiteralArray(&interpreter->stack, resultLiteral);
// cleanup
Toy_freeLiteral(resultLiteral);
Toy_freeLiteral(selfLiteral);
return 1;
}
static int nativeMode(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
if (arguments->count != 1) {
interpreter->errorOutput("Too many arguments mode() expects zero arguments\n");
return -1;
}
Toy_Literal selfLiteral = Toy_popLiteralArray(arguments);
// parse the self (if it's an identifier)
Toy_Literal selfLiteralIdn = selfLiteral;
if (TOY_IS_IDENTIFIER(selfLiteral) && Toy_parseIdentifierToValue(interpreter, &selfLiteral)) {
Toy_freeLiteral(selfLiteralIdn);
}
// check self type
if (!TOY_IS_OPAQUE(selfLiteral) && TOY_GET_OPAQUE_TAG(selfLiteral) != TOY_OPAQUE_TAG_FILE) {
interpreter->errorOutput("Incorrect self type mode() expects a file type\n");
Toy_freeLiteral(selfLiteral);
return -1;
}
Toy_File* file = (Toy_File*)TOY_AS_OPAQUE(selfLiteral);
// return the result
Toy_Literal resultLiteral = TOY_TO_STRING_LITERAL(Toy_copyRefString(file->mode));
Toy_pushLiteralArray(&interpreter->stack, resultLiteral);
// cleanup
Toy_freeLiteral(resultLiteral);
Toy_freeLiteral(selfLiteral);
return 1;
}
static int nativePath(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
if (arguments->count != 1) {
interpreter->errorOutput("Too many arguments path() expects zero arguments\n");
return -1;
}
Toy_Literal selfLiteral = Toy_popLiteralArray(arguments);
// parse the self (if it's an identifier)
Toy_Literal selfLiteralIdn = selfLiteral;
if (TOY_IS_IDENTIFIER(selfLiteral) && Toy_parseIdentifierToValue(interpreter, &selfLiteral)) {
Toy_freeLiteral(selfLiteralIdn);
}
// check self type
if (!TOY_IS_OPAQUE(selfLiteral) && TOY_GET_OPAQUE_TAG(selfLiteral) != TOY_OPAQUE_TAG_FILE) {
interpreter->errorOutput("Incorrect self type path() expects a file type\n");
Toy_freeLiteral(selfLiteral);
return -1;
}
Toy_File* file = (Toy_File*)TOY_AS_OPAQUE(selfLiteral);
// return the result
Toy_Literal resultLiteral = TOY_TO_STRING_LITERAL(Toy_copyRefString(file->path));
Toy_pushLiteralArray(&interpreter->stack, resultLiteral);
// cleanup
Toy_freeLiteral(resultLiteral);
Toy_freeLiteral(selfLiteral);
return 1;
}
// call the hook
typedef struct Natives {
char* name;
Toy_NativeFn fn;
} Natives;
typedef struct Variable {
Toy_Literal key;
Toy_Literal identifier;
Toy_Literal literal;
} Variable;
// Helper function create a int variable
void createToyVariableInt(Variable* variable, char* key, int literal) {
variable->key = TOY_TO_STRING_LITERAL(Toy_createRefString(key));
variable->identifier = TOY_TO_IDENTIFIER_LITERAL(Toy_createRefString(key));
variable->literal = TOY_TO_INTEGER_LITERAL(literal);
}
// Helper function create a file variable
void createToyVariableFile(Variable* variable, char* key, Toy_File* literal) {
variable->key = TOY_TO_STRING_LITERAL(Toy_createRefString(key));
variable->identifier = TOY_TO_IDENTIFIER_LITERAL(Toy_createRefString(key));
variable->literal = TOY_TO_OPAQUE_LITERAL(literal, TOY_OPAQUE_TAG_FILE);
}
// Helper function to clean up variables
void deleteToyVariables(Variable variables[], int size) {
for (int i = 0; i < size; i++) {
Toy_freeLiteral(variables[i].key);
Toy_freeLiteral(variables[i].identifier);
Toy_freeLiteral(variables[i].literal);
}
}
// Helper to check for naming conflicts with existing variables
bool scopeConflict(Toy_Interpreter* interpreter, Variable variables[], int size) {
for (int i = 0; i < size; i++) {
if (Toy_isDeclaredScopeVariable(interpreter->scope, variables[i].literal)) {
interpreter->errorOutput("Can't override an existing variable\n");
deleteToyVariables(variables, size);
return true;
}
}
return false;
}
// Helper to place variables into scope should be called after scopeConflict
void exposeVariablesToScope(Toy_Interpreter* interpreter, Variable variables[], int size) {
Toy_Literal intType = TOY_TO_TYPE_LITERAL(TOY_LITERAL_INTEGER, false);
Toy_Literal opaqueType = TOY_TO_TYPE_LITERAL(TOY_LITERAL_OPAQUE, false);
for (int i = 0; i < size; i++) {
if (TOY_IS_INTEGER(variables[i].literal)) {
Toy_declareScopeVariable(interpreter->scope, variables[i].identifier, intType);
}
else if (TOY_IS_OPAQUE(variables[i].literal)) {
Toy_declareScopeVariable(interpreter->scope, variables[i].identifier, opaqueType);
}
Toy_setScopeVariable(interpreter->scope, variables[i].identifier, variables[i].literal, true);
}
Toy_freeLiteral(intType);
Toy_freeLiteral(opaqueType);
}
int Toy_hookFileIO(Toy_Interpreter* interpreter, Toy_Literal identifier, Toy_Literal alias) {
// build the natives list
Natives natives[] = {
// access
{"open", nativeOpen},
{"close", nativeClose},
// operations
{"read", nativeRead},
{"write", nativeWrite},
{"rename", nativeRename},
{"seek", nativeSeek},
// accessors
{"error", nativeError},
{"completed", nativeCompleted},
{"position", nativePosition},
{"size", nativeSize},
{"mode", nativeMode},
{"path", nativePath},
{NULL, NULL}
};
// global variables
const int VARIABLES_SIZE = 5;
Variable variables[VARIABLES_SIZE];
createToyVariableInt(&variables[0], "MAX_FILENAME_SIZE", FILENAME_MAX);
createToyVariableInt(&variables[1], "MAX_FILES_OPEN", FOPEN_MAX);
createToyVariableInt(&variables[2], "END_OF_FILE", EOF);
Toy_RefString* outMode = Toy_createRefString("w");
Toy_RefString* outName = Toy_createRefString("output");
static Toy_File* outFile;
outFile = createToyFile(outMode, outName);
outFile->fp = stdout;
createToyVariableFile(&variables[3], "output", outFile);
Toy_deleteRefString(outMode);
Toy_deleteRefString(outName);
Toy_RefString* inMode = Toy_createRefString("r");
Toy_RefString* inName = Toy_createRefString("input");
static Toy_File* inFile;
inFile = createToyFile(inMode, inName);
inFile->fp = stdin;
createToyVariableFile(&variables[4], "input", inFile);
Toy_deleteRefString(inMode);
Toy_deleteRefString(inName);
// store the library in an aliased dictionary
if (!TOY_IS_NULL(alias)) {
// make sure the name isn't taken
if (Toy_isDeclaredScopeVariable(interpreter->scope, alias)) {
interpreter->errorOutput("Can't override an existing variable\n");
Toy_freeLiteral(alias);
return -1;
}
// create the dictionary to load up with functions
Toy_LiteralDictionary* dictionary = TOY_ALLOCATE(Toy_LiteralDictionary, 1);
Toy_initLiteralDictionary(dictionary);
// load the dict with functions
for (int i = 0; natives[i].name; i++) {
Toy_Literal name = TOY_TO_STRING_LITERAL(Toy_createRefString(natives[i].name));
Toy_Literal func = TOY_TO_FUNCTION_NATIVE_LITERAL(natives[i].fn);
Toy_setLiteralDictionary(dictionary, name, func);
Toy_freeLiteral(name);
Toy_freeLiteral(func);
}
// set global variables
for (int i = 0; i < VARIABLES_SIZE; i++) {
Toy_setLiteralDictionary(dictionary, variables[i].key, variables[i].literal);
}
// build the type
Toy_Literal type = TOY_TO_TYPE_LITERAL(TOY_LITERAL_DICTIONARY, true);
Toy_Literal anyType = TOY_TO_TYPE_LITERAL(TOY_LITERAL_ANY, true);
Toy_Literal fnType = TOY_TO_TYPE_LITERAL(TOY_LITERAL_FUNCTION_NATIVE, true);
TOY_TYPE_PUSH_SUBTYPE(&type, anyType);
TOY_TYPE_PUSH_SUBTYPE(&type, fnType);
// set scope
Toy_Literal dict = TOY_TO_DICTIONARY_LITERAL(dictionary);
Toy_declareScopeVariable(interpreter->scope, alias, type);
Toy_setScopeVariable(interpreter->scope, alias, dict, false);
// cleanup
Toy_freeLiteral(dict);
Toy_freeLiteral(type);
return 0;
}
// default
for (int i = 0; natives[i].name; i++) {
Toy_injectNativeFn(interpreter, natives[i].name, natives[i].fn);
}
if (scopeConflict(interpreter, variables, VARIABLES_SIZE)) {
return -1;
}
exposeVariablesToScope(interpreter, variables, VARIABLES_SIZE);
deleteToyVariables(variables, VARIABLES_SIZE);
return 0;
}
+7
View File
@@ -0,0 +1,7 @@
#pragma once
#include "toy_interpreter.h"
#define TOY_OPAQUE_TAG_FILE 300
int Toy_hookFileIO(Toy_Interpreter* interpreter, Toy_Literal identifier, Toy_Literal alias);
+2
View File
@@ -4,6 +4,7 @@
#include "lib_standard.h" #include "lib_standard.h"
#include "lib_random.h" #include "lib_random.h"
#include "lib_runner.h" #include "lib_runner.h"
#include "lib_fileio.h"
#include "lib_math.h" #include "lib_math.h"
#include "toy_console_colors.h" #include "toy_console_colors.h"
@@ -31,6 +32,7 @@ void repl(const char* initialInput) {
Toy_injectNativeHook(&interpreter, "standard", Toy_hookStandard); Toy_injectNativeHook(&interpreter, "standard", Toy_hookStandard);
Toy_injectNativeHook(&interpreter, "random", Toy_hookRandom); Toy_injectNativeHook(&interpreter, "random", Toy_hookRandom);
Toy_injectNativeHook(&interpreter, "runner", Toy_hookRunner); Toy_injectNativeHook(&interpreter, "runner", Toy_hookRunner);
Toy_injectNativeHook(&interpreter, "fileio", Toy_hookFileIO);
Toy_injectNativeHook(&interpreter, "math", Toy_hookMath); Toy_injectNativeHook(&interpreter, "math", Toy_hookMath);
for(;;) { for(;;) {
+2
View File
@@ -3,6 +3,7 @@
#include "lib_standard.h" #include "lib_standard.h"
#include "lib_random.h" #include "lib_random.h"
#include "lib_runner.h" #include "lib_runner.h"
#include "lib_fileio.h"
#include "lib_math.h" #include "lib_math.h"
#include "toy_console_colors.h" #include "toy_console_colors.h"
@@ -116,6 +117,7 @@ void Toy_runBinary(const unsigned char* tb, size_t size) {
Toy_injectNativeHook(&interpreter, "standard", Toy_hookStandard); Toy_injectNativeHook(&interpreter, "standard", Toy_hookStandard);
Toy_injectNativeHook(&interpreter, "random", Toy_hookRandom); Toy_injectNativeHook(&interpreter, "random", Toy_hookRandom);
Toy_injectNativeHook(&interpreter, "runner", Toy_hookRunner); Toy_injectNativeHook(&interpreter, "runner", Toy_hookRunner);
Toy_injectNativeHook(&interpreter, "fileio", Toy_hookFileIO);
Toy_injectNativeHook(&interpreter, "math", Toy_hookMath); Toy_injectNativeHook(&interpreter, "math", Toy_hookMath);
Toy_runInterpreter(&interpreter, tb, (int)size); Toy_runInterpreter(&interpreter, tb, (int)size);
+61
View File
@@ -0,0 +1,61 @@
import math;
import fileio;
import standard;
fn circle(radius: int, centerX: int, centerY: int) {
for (var y: int = 0; y <= 2 * radius; y++) {
for (var x: int = 0; x <= 2 * radius; x++) {
var distance: int = round(sqrt((x - radius) * (x - radius) + (y - radius) * (y - radius)));
if (distance <= radius) {
output.write("*");
} else {
output.write(" ");
}
}
output.write("\n");
}
}
fn triangle(height: int) {
for (var i: int = 1; i <= height; i++) {
for (var j: int = 1; j <= height - i; j++) {
output.write(" ");
}
for (var j: int = 1; j <= 2 * i - 1; j++) {
output.write("*");
}
output.write("\n");
}
}
fn square(size: int) {
for (var i: int = 0; i < size; ++i) {
for (var j: int = 0; j < size; ++j) {
output.write("* ");
}
output.write("\n");
}
}
while (true) {
output.write("Enter:\n0\tfor circle\n1\tfor triangle\n2\tfor square\n> ");
var result: any = input.read(int);
if (result == 0) {
circle(2, 5, 5);
}
else if (result == 1) {
triangle(5);
}
else if (result == 2) {
square(5);
}
else {
output.write("invalid input :(\n");
}
}
+11 -10
View File
@@ -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";
+1 -1
View File
@@ -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 1
/*! /*!
### TOY_VERSION_BUILD ### TOY_VERSION_BUILD
+13 -5
View File
@@ -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
compiler->bytecode[compiler->count++] = TOY_OP_SCOPE_BEGIN; //1 byte bool closeScope = false;
if (node->pathFor.thenPath->type != TOY_AST_NODE_BLOCK) {
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
} }
compiler->bytecode[compiler->count++] = TOY_OP_SCOPE_END; //1 byte
if (closeScope) {
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);
+1 -1
View File
@@ -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
+1
View File
@@ -0,0 +1 @@
Hello, World!
+4
View File
@@ -0,0 +1,4 @@
1
8
12.5
test
+3
View File
@@ -0,0 +1,3 @@
08
12.500000
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
+164
View File
@@ -0,0 +1,164 @@
import fileio;
var PATH: string const = "scripts:/lib/file/fileio.txt";
// reset file to orginal state
fn reset() {
var writer = open(PATH, "w");
writer.write("Hello, World!\n");
writer.close();
}
// test global constants
{
assert MAX_FILENAME_SIZE > 0, "MAX_FILENAME_SIZE failed";
assert MAX_FILES_OPEN > 0, "MAX_FILES_OPEN failed";
assert END_OF_FILE == -1, "END_OF_FILE failed";
}
// test read
{
var reader = open("scripts:/lib/file/inputs.txt", "r");
assert reader.read(bool) == true, "read true bool failed";
assert reader.read(int) == 8, "read int failed";
assert reader.read(float) == 12.5, "read float failed";
assert reader.read(string) == "\ntest", "read string failed";
// invaild types
assert reader.read(type) == null, "read type failed";
assert reader.read(any) == null, "read any failed";
reader.close();
}
// test write
{
var writer = open("scripts:/lib/file/outputs.txt", "w");
assert writer.write(false) == true, "write bool failed";
assert writer.write(8) == true, "write int failed";
assert writer.write("\n") == true, "write string failed";
assert writer.write(12.5) == true, "write float failed";
assert writer.write("\nLorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n") == true, "write long string failed";
// invaild types
assert writer.write([0, 1, 2]) == false, "write array failed";
assert writer.write(["hi": "world"]) == false, "write dict failed";
writer.close();
}
// test open and close
{
var reader = open(PATH);
assert reader != null, "open failed in reading mode";
assert reader.close() == true, "close failed";
var file = open("scripts:/doesNotExist", "r");
assert file == null, "open failed on nonexisting file";
}
// test append
{
var appender = open(PATH, "a");
assert appender != null, "open failed on appending file";
assert appender.write("appended text") == true, "append failed";
appender.close();
reset();
}
// test read extended
{
var reader = open(PATH, "r+");
assert reader != null, "open failed on read extended mode";
assert reader.write("writen text") == true, "write in read extended failed";
var result = reader.read(string);
// print result;
// assert (result == "d!\n" || result == "d!\\r\n"), "read in read extended failed";
reader.close();
reset();
}
// test write extended
{
var writer = open(PATH, "w+");
assert writer != null, "open failed on write extended mode";
assert writer.write("writen text") == true, "write in write extended failed";
writer.seek("bgn", 0);
assert writer.read(string) == "writen text", "read in write extended failed";
writer.close();
reset();
}
// test rename
{
var reader = open(PATH, "r");
assert reader.rename("scripts:/lib/file/newName.txt") == true, "rename failed";
reader.rename(PATH);
reader.close();
}
// test seek
{
var reader = open(PATH, "r");
assert reader.seek("bgn", 6) == true, "seek from bgn failed";
var contents = reader.read(string);
assert contents == " World!\n", "seek failed to move file position (1st)";
assert reader.seek("end", -2) == true, "seek from end failed";
contents = reader.read(string);
print ">>>(" + contents + ")" + string( contents.length() );
assert contents == "\n", "seek failed to move file position (2nd)";
assert reader.seek("cur", -2) == true, "seek from cur failed";
contents = reader.read(string);
assert contents == "\n", "seek failed to move file position (3rd)";
assert reader.seek("CUR", 0) == false, "seek origin failed (1st)";
assert reader.seek("End", 0) == false, "seek origin failed (2nd)";
assert reader.seek("beG", 0) == false, "seek origin failed (3rd)";
assert reader.seek("xxx", 0) == false, "seek origin failed (4th)";
reader.close();
}
// test accessors
{
var reader = open(PATH, "r");
assert reader.error() == false, "error failed";
assert reader.completed() == false, "completed failed";
assert reader.position() == 0, "position failed";
assert reader.size() == 14, "size failed";
assert reader.mode() == "r", "mode failed";
reader.read(string);
assert reader.error() == false, "error failed";
assert reader.completed() == true, "completed after read failed";
assert reader.position() == 14, "position failed";
assert reader.size() == 14, "size failed";
assert reader.mode() == "r", "mode failed";
reader.close();
}
input.close();
output.close();
print "All good";
+2
View File
@@ -183,3 +183,5 @@ import math;
assert epsilionCompare(1, 1.001) == false, "epsilionCompare(1, 1.001) failed"; assert epsilionCompare(1, 1.001) == false, "epsilionCompare(1, 1.001) failed";
assert epsilionCompare(0, 0) == true, "epsilionCompare(0, 0) failed"; assert epsilionCompare(0, 0) == true, "epsilionCompare(0, 0) failed";
} }
print "All good";
+3 -1
View File
@@ -18,6 +18,7 @@
#include "../repl/lib_standard.h" #include "../repl/lib_standard.h"
#include "../repl/lib_random.h" #include "../repl/lib_random.h"
#include "../repl/lib_runner.h" #include "../repl/lib_runner.h"
#include "../repl/lib_fileio.h"
#include "../repl/lib_math.h" #include "../repl/lib_math.h"
//supress the print output //supress the print output
@@ -43,7 +44,7 @@ void runBinaryWithLibrary(const unsigned char* tb, size_t size, const char* libr
Toy_initInterpreter(&interpreter); Toy_initInterpreter(&interpreter);
//NOTE: supress print output for testing //NOTE: supress print output for testing
Toy_setInterpreterPrint(&interpreter, noPrintFn); // Toy_setInterpreterPrint(&interpreter, noPrintFn);
Toy_setInterpreterAssert(&interpreter, assertWrapper); Toy_setInterpreterAssert(&interpreter, assertWrapper);
Toy_setInterpreterError(&interpreter, errorWrapper); Toy_setInterpreterError(&interpreter, errorWrapper);
@@ -77,6 +78,7 @@ int main() {
{"standard.toy", "standard", Toy_hookStandard}, {"standard.toy", "standard", Toy_hookStandard},
{"runner.toy", "runner", Toy_hookRunner}, {"runner.toy", "runner", Toy_hookRunner},
{"random.toy", "random", Toy_hookRandom}, {"random.toy", "random", Toy_hookRandom},
{"fileio.toy", "fileio", Toy_hookFileIO},
{"math.toy", "math", Toy_hookMath}, {"math.toy", "math", Toy_hookMath},
{NULL, NULL, NULL} {NULL, NULL, NULL}
}; };
+427
View File
@@ -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;
}
+169
View File
@@ -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.
+556 -160
View File
@@ -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, "| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |");
@@ -72,7 +73,7 @@ const char *OP_STR[] = {
EP(DIS_OP_POP_STACK), // EP(DIS_OP_POP_STACK), //
EP(DIS_OP_TERNARY), // EP(DIS_OP_TERNARY), //
EP(DIS_OP_FN_END), // EP(DIS_OP_FN_END), //
}; };
const char *LIT_STR[] = { const char *LIT_STR[] = {
EP(DIS_LITERAL_NULL), // EP(DIS_LITERAL_NULL), //
@@ -95,7 +96,7 @@ const char *LIT_STR[] = {
EP(DIS_LITERAL_FUNCTION_NATIVE), // EP(DIS_LITERAL_FUNCTION_NATIVE), //
EP(DIS_LITERAL_FUNCTION_HOOK), // EP(DIS_LITERAL_FUNCTION_HOOK), //
EP(DIS_LITERAL_INDEX_BLANK), // EP(DIS_LITERAL_INDEX_BLANK), //
}; };
enum DIS_ARG_TYPE { enum DIS_ARG_TYPE {
DIS_ARG_NONE, // DIS_ARG_NONE, //
@@ -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) {
free((*prg)->program); if((*prg)->program != NULL)
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;
printf("\nFile: %s\nSize: %zu\n", filename, fsize);
if (!alt_fmt)
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));
printf("[Header Version: %d.%d.%d (%s)]\n", major, minor, patch, build);
if (!alt_fmt)
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);
SPC(spaces); if (!config.alt_format_flag) {
printf("| [args literal %d, rets literal %d]", args, rets); SPC(spaces);
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) {
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];
if (config.alt_format_flag && (opcode == 255 || opcode == 0)) {
++pc;
continue;
}
if (opcode > DIS_OP_END_OPCODES)
continue;
++pc;
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) { while (pc < len) {
opcode = (*prg)->program[pc]; 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"); printf("\n");
SPC(spaces); if (!config.alt_format_flag) {
printf("| [ %05d ](%03d) ", pc++, opcode); SPC(spaces);
printf("| ");
printf("[%05d](%03d) ", (pc++) - pc_start, opcode);
} else {
printf(" ");
pc++;
}
dis_print_opcode(opcode); dis_print_opcode(opcode);
if (opcode > DIS_OP_END_OPCODES) if (opcode >= DIS_OP_END_OPCODES)
continue; continue;
S_OP(0); if (config.alt_format_flag) {
S_OP(1); 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);
printf("\n"); if(!config.group_flag)
SPC(spaces); printf("\n");
printf("| ( Reading %d literals )\n", literalCount);
if (!config.alt_format_flag) {
SPC(spaces);
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);
SPC(spaces); if (!config.alt_format_flag) {
printf("| | [%d] ( null )\n", i); SPC(spaces);
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);
SPC(spaces); if (!config.alt_format_flag) {
printf("| | [%d] ( boolean %s )\n", i, b ? "true" : "false"); SPC(spaces);
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);
SPC(spaces); if (!config.alt_format_flag) {
printf("| | [%d] ( integer %d )\n", i, d); SPC(spaces);
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);
SPC(spaces); if (!config.alt_format_flag) {
printf("| | [%d] ( float %f )\n", i, f); SPC(spaces);
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);
SPC(spaces); if (!config.alt_format_flag) {
printf("| | [%d] ( string \"%s\" )\n", i, s); SPC(spaces);
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); SPC(spaces);
printf("| | ");
printf("[%05d] ( array ", i);
} else {
str_append(&lit_str, " .lit ARRAY ");
}
for (int i = 0; i < length; i++) { for (int i = 0; i < length; i++) {
int index = readWord((*prg)->program, pc); int index = readWord((*prg)->program, pc);
printf("%d ", index); 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); LIT_ADD(DIS_LITERAL_NULL, literal_type, literal_count);
if (!(i % 15) && i != 0) { if (!(i % 15) && i != 0) {
printf("\n"); if (!config.alt_format_flag) {
SPC(spaces); printf("\\\n");
printf("| | "); 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);
SPC(spaces); if (!config.alt_format_flag) {
printf("| | [%d] ( dictionary ", i); SPC(spaces);
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);
printf("(key: %d, val:%d) ", key, val);
if(!(i % 5) && i != 0){ if (!config.alt_format_flag)
printf("\n"); printf("(key: %d, val:%d) ", key, val);
SPC(spaces); else {
printf("| | "); char s[100];
sprintf(s, "%d,%d ", key, val);
str_append(&lit_str, s);
}
if (!(i % 5) && 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_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);
SPC(spaces); if (!config.alt_format_flag) {
printf("| | [%d] ( function index: %d )\n", i, index); SPC(spaces);
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);
SPC(spaces); if (!config.alt_format_flag) {
printf("| | [%d] ( identifier %s )\n", i, str); SPC(spaces);
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);
SPC(spaces); if (!config.alt_format_flag) {
printf("| | [%d] ( type %s: %d)\n", i, (LIT_STR[literalType] + 12), constant);
if (literalType == DIS_LITERAL_ARRAY) {
uint16_t vt = readWord((*prg)->program, pc);
SPC(spaces); SPC(spaces);
printf("| | | ( subtype: %d)\n", vt); printf("| | ");
printf("[%05d] ( type %s: %d)\n", i, (LIT_STR[literalType] + 12), constant);
} else {
char s[100];
sprintf(s, " .lit TYPE %s %d", (LIT_STR[literalType] + 12), constant);
str_append(&lit_str, s);
} }
if (literalType == DIS_LITERAL_DICTIONARY) { if (literalType == DIS_LITERAL_ARRAY) {
uint8_t kt = readWord((*prg)->program, pc); uint16_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)\n", vt);
} else {
char s[100];
sprintf(s, " SUBTYPE %d\n", vt);
str_append(&lit_str, s);
}
} else
if (literalType == DIS_LITERAL_DICTIONARY) {
uint8_t kt = readWord((*prg)->program, pc);
uint8_t vt = readWord((*prg)->program, pc);
if (!config.alt_format_flag) {
SPC(spaces);
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);
SPC(spaces); if (!config.alt_format_flag) {
printf("| | [%d] ( blank )\n", i); SPC(spaces);
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) {
SPC(spaces); if (!config.alt_format_flag) {
printf("| | \n"); SPC(spaces);
SPC(spaces); printf("|\n");
printf("| | ( fun count: %d, total size: %d )\n", functionCount, functionSize); SPC(spaces);
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;
SPC(spaces); tree_local[0] = '\0';
printf("| | |\n"); if (!config.alt_format_flag) {
SPC(spaces); sprintf(tree_local, "%s.%d", tree, fcnt);
printf("| | | ( fun %d [ start: %d, end: %d ] )", fcnt, fpc_start, fpc_end); 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);
printf("| |\n");
SPC(spaces);
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);
SPC(spaces);
printf("| | |\n"); if (!config.alt_format_flag) {
SPC(spaces + 4); SPC(spaces);
printf("| ------ CODE ------"); printf("| | |\n");
dis_disassemble_section(prg, fpc_start, fpc_end, spaces + 4, true); SPC(spaces + 4);
printf("\n"); printf("| ");
SPC(spaces + 4); printf("--- ( reading code for %s ) ---", tree_local);
printf("| ---- END CODE ----\n"); dis_disassemble_section(prg, fpc_start, fpc_end, spaces + 4, true, config);
printf("\n");
SPC(spaces + 4);
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,106 @@ 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 --");
printf("\n\n"); 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", litf->str);
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("FUNCTION_%s:\n", litf->fun);
printf("%s", litf->str);
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");
}
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);
} }
+25 -11
View File
@@ -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_ */
+60
View File
@@ -0,0 +1,60 @@
/*
* 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);
}
+25
View File
@@ -0,0 +1,25 @@
/*
* 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);
#endif /* UTILS_H_ */
+47 -2
View File
@@ -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;
} }
+2 -2
View File
@@ -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)