Packaged toy as a dll

This commit is contained in:
2022-09-11 07:56:06 +01:00
parent 5b420e0799
commit 95ba865cab
14 changed files with 136 additions and 43 deletions

View File

@@ -3,6 +3,12 @@ export OUTDIR = out
all: $(OUTDIR)
$(MAKE) -C source
library: clean $(OUTDIR)
$(MAKE) -C source library
static: clean $(OUTDIR)
$(MAKE) -C source static
test: clean $(OUTDIR)
$(MAKE) -C test

View File

@@ -2,6 +2,20 @@
#include <stdio.h>
#include <string.h>
#include <assert.h>
//test variable sizes based on platform
#define STATIC_ASSERT(test_for_true) static_assert((test_for_true), "(" #test_for_true ") failed")
STATIC_ASSERT(sizeof(char) == 1);
STATIC_ASSERT(sizeof(short) == 2);
STATIC_ASSERT(sizeof(int) == 4);
STATIC_ASSERT(sizeof(float) == 4);
STATIC_ASSERT(sizeof(unsigned char) == 1);
STATIC_ASSERT(sizeof(unsigned short) == 2);
STATIC_ASSERT(sizeof(unsigned int) == 4);
#ifndef TOY_EXPORT
//declare the singleton
Command command;
@@ -107,3 +121,5 @@ void copyrightCommand(int argc, const char* argv[]) {
printf("2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.\n\n");
printf("3. This notice may not be removed or altered from any source distribution.\n\n");
}
#endif

View File

@@ -9,6 +9,26 @@
#define TOY_VERSION_PATCH 0
#define TOY_VERSION_BUILD __DATE__ " " __TIME__
//platform exports/imports
#if defined(WIN32) || defined(_WIN32)
#if defined(TOY_EXPORT)
#define TOY_API __declspec(dllexport)
#else
#define TOY_API __declspec(dllimport)
#endif
#elif defined(linux)
#define TOY_API extern
#else
#define TOY_API
#endif
#ifndef TOY_EXPORT
//for processing the command line arguments
typedef struct {
bool error;
@@ -29,6 +49,7 @@ void initCommand(int argc, const char* argv[]);
void usageCommand(int argc, const char* argv[]);
void helpCommand(int argc, const char* argv[]);
void copyrightCommand(int argc, const char* argv[]);
#endif
//NOTE: assigning to a byte from a short loses data
#define AS_USHORT(value) (*(unsigned short*)(&(value)))

View File

@@ -1,7 +1,7 @@
#pragma once
#include "common.h"
#include "opcodes.h"
#include "node.h"
#include "literal_array.h"
@@ -13,9 +13,9 @@ typedef struct Compiler {
int count;
} Compiler;
void initCompiler(Compiler* compiler);
void writeCompiler(Compiler* compiler, Node* node);
void freeCompiler(Compiler* compiler);
TOY_API void initCompiler(Compiler* compiler);
TOY_API void writeCompiler(Compiler* compiler, Node* node);
TOY_API void freeCompiler(Compiler* compiler);
//embed the header with version information, data section, code section, etc.
unsigned char* collateCompiler(Compiler* compiler, int* size);
//embed the header, data section, code section, function section, etc.
TOY_API unsigned char* collateCompiler(Compiler* compiler, int* size);

View File

@@ -2032,9 +2032,11 @@ static void readInterpreterSections(Interpreter* interpreter) {
//data section
const unsigned short literalCount = readShort(interpreter->bytecode, &interpreter->count);
#ifndef TOY_EXPORT
if (command.verbose) {
printf(NOTICE "Reading %d literals\n" RESET, literalCount);
}
#endif
for (int i = 0; i < literalCount; i++) {
const unsigned char literalType = readByte(interpreter->bytecode, &interpreter->count);
@@ -2044,9 +2046,11 @@ static void readInterpreterSections(Interpreter* interpreter) {
//read the null
pushLiteralArray(&interpreter->literalCache, TO_NULL_LITERAL);
#ifndef TOY_EXPORT
if (command.verbose) {
printf("(null)\n");
}
#endif
break;
case LITERAL_BOOLEAN: {
@@ -2056,9 +2060,11 @@ static void readInterpreterSections(Interpreter* interpreter) {
pushLiteralArray(&interpreter->literalCache, literal);
freeLiteral(literal);
#ifndef TOY_EXPORT
if (command.verbose) {
printf("(boolean %s)\n", b ? "true" : "false");
}
#endif
}
break;
@@ -2068,9 +2074,11 @@ static void readInterpreterSections(Interpreter* interpreter) {
pushLiteralArray(&interpreter->literalCache, literal);
freeLiteral(literal);
#ifndef TOY_EXPORT
if (command.verbose) {
printf("(integer %d)\n", d);
}
#endif
}
break;
@@ -2080,9 +2088,11 @@ static void readInterpreterSections(Interpreter* interpreter) {
pushLiteralArray(&interpreter->literalCache, literal);
freeLiteral(literal);
#ifndef TOY_EXPORT
if (command.verbose) {
printf("(float %f)\n", f);
}
#endif
}
break;
@@ -2093,9 +2103,11 @@ static void readInterpreterSections(Interpreter* interpreter) {
pushLiteralArray(&interpreter->literalCache, literal);
freeLiteral(literal);
#ifndef TOY_EXPORT
if (command.verbose) {
printf("(string \"%s\")\n", s);
}
#endif
}
break;
@@ -2111,12 +2123,14 @@ static void readInterpreterSections(Interpreter* interpreter) {
pushLiteralArray(array, interpreter->literalCache.literals[index]);
}
#ifndef TOY_EXPORT
if (command.verbose) {
printf("(array ");
Literal literal = TO_ARRAY_LITERAL(array);
printLiteral(literal);
printf(")\n");
}
#endif
//finally, push the array proper
Literal literal = TO_ARRAY_LITERAL(array);
@@ -2140,12 +2154,14 @@ static void readInterpreterSections(Interpreter* interpreter) {
setLiteralDictionary(dictionary, interpreter->literalCache.literals[key], interpreter->literalCache.literals[val]);
}
#ifndef TOY_EXPORT
if (command.verbose) {
printf("(dictionary ");
Literal literal = TO_DICTIONARY_LITERAL(dictionary);
printLiteral(literal);
printf(")\n");
}
#endif
//finally, push the dictionary proper
Literal literal = TO_DICTIONARY_LITERAL(dictionary);
@@ -2167,9 +2183,11 @@ static void readInterpreterSections(Interpreter* interpreter) {
//push to the literal cache
pushLiteralArray(&interpreter->literalCache, literal);
#ifndef TOY_EXPORT
if (command.verbose) {
printf("(function)\n");
}
#endif
}
break;
@@ -2181,9 +2199,11 @@ static void readInterpreterSections(Interpreter* interpreter) {
pushLiteralArray(&interpreter->literalCache, identifier);
#ifndef TOY_EXPORT
if (command.verbose) {
printf("(identifier %s (hash: %x))\n", AS_IDENTIFIER(identifier), identifier.as.identifier.hash);
}
#endif
freeLiteral(identifier);
}
@@ -2199,13 +2219,13 @@ static void readInterpreterSections(Interpreter* interpreter) {
//save the type
pushLiteralArray(&interpreter->literalCache, typeLiteral);
#ifndef TOY_EXPORT
if (command.verbose) {
printf("(type ");
printLiteral(typeLiteral);
printf(")\n");
}
// freeLiteral(typeLiteral);
#endif
}
break;
@@ -2234,11 +2254,13 @@ static void readInterpreterSections(Interpreter* interpreter) {
//save the type
pushLiteralArray(&interpreter->literalCache, typeLiteral); //copied
#ifndef TOY_EXPORT
if (command.verbose) {
printf("(type ");
printLiteral(typeLiteral);
printf(")\n");
}
#endif
freeLiteral(typeLiteral);
}
@@ -2336,11 +2358,13 @@ void runInterpreter(Interpreter* interpreter, unsigned char* bytecode, int lengt
const char* build = readString(interpreter->bytecode, &interpreter->count);
#ifndef TOY_EXPORT
if (command.verbose) {
if (strncmp(build, TOY_VERSION_BUILD, strlen(TOY_VERSION_BUILD))) {
printf(WARN "Warning: interpreter/bytecode build mismatch\n" RESET);
}
}
#endif
consumeByte(interpreter, OP_SECTION_END, interpreter->bytecode, &interpreter->count);
@@ -2348,9 +2372,11 @@ void runInterpreter(Interpreter* interpreter, unsigned char* bytecode, int lengt
readInterpreterSections(interpreter);
//code section
#ifndef TOY_EXPORT
if (command.verbose) {
printf(NOTICE "executing bytecode\n" RESET);
}
#endif
//execute the interpreter
execInterpreter(interpreter);

View File

@@ -1,5 +1,6 @@
#pragma once
#include "common.h"
#include "literal.h"
#include "literal_array.h"
#include "literal_dictionary.h"
@@ -33,17 +34,17 @@ typedef struct Interpreter {
//native function API
typedef int (*NativeFn)(Interpreter* interpreter, LiteralArray* arguments);
bool injectNativeFn(Interpreter* interpreter, char* name, NativeFn func);
TOY_API bool injectNativeFn(Interpreter* interpreter, char* name, NativeFn func);
//TODO: injectNativeHook
//utilities for the host program
bool parseIdentifierToValue(Interpreter* interpreter, Literal* literalPtr);
void setInterpreterPrint(Interpreter* interpreter, PrintFn printOutput);
void setInterpreterAssert(Interpreter* interpreter, PrintFn assertOutput);
void setInterpreterError(Interpreter* interpreter, PrintFn errorOutput);
TOY_API bool parseIdentifierToValue(Interpreter* interpreter, Literal* literalPtr);
TOY_API void setInterpreterPrint(Interpreter* interpreter, PrintFn printOutput);
TOY_API void setInterpreterAssert(Interpreter* interpreter, PrintFn assertOutput);
TOY_API void setInterpreterError(Interpreter* interpreter, PrintFn errorOutput);
//main access
void initInterpreter(Interpreter* interpreter); //start of program
void runInterpreter(Interpreter* interpreter, unsigned char* bytecode, int length); //run the code
void resetInterpreter(Interpreter* interpreter); //use this to reset the interpreter's environment between runs
void freeInterpreter(Interpreter* interpreter); //end of program
TOY_API void initInterpreter(Interpreter* interpreter); //start of program
TOY_API void runInterpreter(Interpreter* interpreter, unsigned char* bytecode, int length); //run the code
TOY_API void resetInterpreter(Interpreter* interpreter); //use this to reset the interpreter's environment between runs
TOY_API void freeInterpreter(Interpreter* interpreter); //end of program

View File

@@ -109,10 +109,12 @@ static Token makeErrorToken(Lexer* lexer, char* msg) {
token.length = strlen(msg);
token.line = lexer->line;
#ifndef TOY_EXPORT
if (command.verbose) {
printf("err:");
printToken(&token);
}
#endif
return token;
}
@@ -125,11 +127,13 @@ static Token makeToken(Lexer* lexer, TokenType type) {
token.lexeme = &lexer->source[lexer->current - token.length];
token.line = lexer->line;
#ifndef TOY_EXPORT
//BUG #10: this shows TOKEN_EOF twice due to the overarching structure of the program - can't be fixed
if (command.verbose) {
printf("tok:");
printToken(&token);
}
#endif
return token;
}
@@ -152,6 +156,7 @@ static Token makeIntegerOrFloat(Lexer* lexer) {
token.length = lexer->current - lexer->start;
token.line = lexer->line;
#ifndef TOY_EXPORT
if (command.verbose) {
if (type == TOKEN_LITERAL_INTEGER) {
printf("int:");
@@ -160,6 +165,7 @@ static Token makeIntegerOrFloat(Lexer* lexer) {
}
printToken(&token);
}
#endif
return token;
}
@@ -182,10 +188,12 @@ static Token makeString(Lexer* lexer, char terminator) {
token.length = lexer->current - lexer->start - 2;
token.line = lexer->line;
#ifndef TOY_EXPORT
if (command.verbose) {
printf("str:");
printToken(&token);
}
#endif
return token;
}
@@ -207,10 +215,12 @@ static Token makeKeywordOrIdentifier(Lexer* lexer) {
token.length = lexer->current - lexer->start;
token.line = lexer->line;
#ifndef TOY_EXPORT
if (command.verbose) {
printf("kwd:");
printToken(&token);
}
#endif
return token;
}
@@ -224,10 +234,12 @@ static Token makeKeywordOrIdentifier(Lexer* lexer) {
token.length = lexer->current - lexer->start;
token.line = lexer->line;
#ifndef TOY_EXPORT
if (command.verbose) {
printf("idf:");
printToken(&token);
}
#endif
return token;
}

View File

@@ -19,7 +19,7 @@ typedef struct {
int line;
} Token;
void initLexer(Lexer* lexer, char* source);
TOY_API void initLexer(Lexer* lexer, char* source);
Token scanLexer(Lexer* lexer);
//for debugging

View File

@@ -94,7 +94,7 @@ typedef struct {
#define TO_IDENTIFIER_LITERAL(value, l) _toIdentifierLiteral(value, l)
#define TO_TYPE_LITERAL(value, c) ((Literal){ LITERAL_TYPE, { .type.typeOf = value, .type.constant = c, .type.subtypes = NULL, .type.capacity = 0, .type.count = 0 }})
void freeLiteral(Literal literal);
TOY_API void freeLiteral(Literal literal);
#define IS_TRUTHY(x) _isTruthy(x)
@@ -103,17 +103,16 @@ void freeLiteral(Literal literal);
#define TYPE_PUSH_SUBTYPE(lit, subtype) _typePushSubtype(lit, subtype)
//BUGFIX: macros are not functions
bool _isTruthy(Literal x);
Literal _toStringLiteral(char* str, int length);
Literal _toIdentifierLiteral(char* str, int length);
Literal* _typePushSubtype(Literal* lit, Literal subtype);
TOY_API bool _isTruthy(Literal x);
TOY_API Literal _toStringLiteral(char* str, int length);
TOY_API Literal _toIdentifierLiteral(char* str, int length);
TOY_API Literal* _typePushSubtype(Literal* lit, Literal subtype);
//utils
Literal copyLiteral(Literal original);
char* copyString(char* original, int length);
bool literalsAreEqual(Literal lhs, Literal rhs);
int hashLiteral(Literal lit);
void printLiteral(Literal literal);
void printLiteralCustom(Literal literal, void (printFn)(const char*));
TOY_API Literal copyLiteral(Literal original);
TOY_API char* copyString(char* original, int length);
TOY_API bool literalsAreEqual(Literal lhs, Literal rhs);
TOY_API int hashLiteral(Literal lit);
TOY_API void printLiteral(Literal literal);
TOY_API void printLiteralCustom(Literal literal, void (printFn)(const char*));

View File

@@ -5,13 +5,24 @@ CFLAGS +=$(addprefix -I,$(IDIR)) -g -Wall -W -pedantic -Wno-unused-parameter -Wn
LIBS +=
ODIR = obj
SRC = $(wildcard *.c)
SRC = $(filter-out $(wildcard *main.c),$(wildcard *.c))
OBJ = $(addprefix $(ODIR)/,$(SRC:.c=.o))
OUT = ../$(OUTDIR)/toy
OUTNAME = toy
OUT = ../$(OUTDIR)/$(OUTNAME).dll
LIBLINE =-Wl,--out-implib=../$(OUTDIR)/lib$(OUTNAME).dll.a -Wl,--export-all-symbols -Wl,--enable-auto-import -Wl,--whole-archive $(OBJ) -Wl,--no-whole-archive
all: $(OBJ)
$(CC) -o $(OUT) $^ $(CFLAGS) $(LIBS)
REPLSRC = $(wildcard repl_main.c)
REPLOUT = $(OUTNAME)repl.exe
all: library $(addprefix $(ODIR)/,$(REPLSRC:.c=.o))
$(CC) -DTOY_IMPORT $(CFLAGS) -o ../$(OUTDIR)/$(REPLOUT) $(addprefix $(ODIR)/,$(REPLSRC:.c=.o)) $(LIBS) -L$(realpath $(shell pwd)/../$(OUTDIR)) -l$(OUTNAME)
library: $(OBJ)
$(CC) -DTOY_EXPORT $(CFLAGS) -shared -o $(OUT) $(LIBLINE)
static: $(OBJ) $(addprefix $(ODIR)/,$(REPLSRC:.c=.o))
$(CC) $(CFLAGS) -o ../$(OUTDIR)/$(REPLOUT) $(addprefix $(ODIR)/,$(REPLSRC:.c=.o)) $(OBJ) $(LIBS)
$(OBJ): | $(ODIR)

View File

@@ -1,5 +1,6 @@
#pragma once
#include "common.h"
#include "literal.h"
#include "opcodes.h"
#include "token_types.h"
@@ -153,7 +154,8 @@ union _node {
NodeIndex index;
};
void freeNode(Node* node);
TOY_API void freeNode(Node* node);
void emitNodeLiteral(Node** nodeHandle, Literal literal);
void emitNodeUnary(Node** nodeHandle, Opcode opcode, Node* child);
void emitNodeBinary(Node** nodeHandle, Node* rhs, Opcode opcode); //handled node becomes lhs

View File

@@ -59,9 +59,11 @@ static void consume(Parser* parser, TokenType tokenType, const char* msg) {
}
static void synchronize(Parser* parser) {
#ifndef TOY_EXPORT
if (command.verbose) {
fprintf(stderr, ERROR "synchronizing\n" RESET);
}
#endif
while (parser->current.type != TOKEN_EOF) {
switch(parser->current.type) {

View File

@@ -1,7 +1,6 @@
#pragma once
#include "parser.h"
#include "common.h"
#include "lexer.h"
#include "node.h"
@@ -16,6 +15,6 @@ typedef struct {
Token previous;
} Parser;
void initParser(Parser* parser, Lexer* lexer);
void freeParser(Parser* parser);
Node* scanParser(Parser* parser);
TOY_API void initParser(Parser* parser, Lexer* lexer);
TOY_API void freeParser(Parser* parser);
TOY_API Node* scanParser(Parser* parser);

View File

@@ -5,8 +5,6 @@
#include "compiler.h"
#include "interpreter.h"
#include "memory.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>