diff --git a/makefile b/makefile index fc76689..7623851 100644 --- a/makefile +++ b/makefile @@ -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 diff --git a/source/common.c b/source/common.c index 7da9f15..10f8f77 100644 --- a/source/common.c +++ b/source/common.c @@ -2,6 +2,20 @@ #include #include +#include + +//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; @@ -106,4 +120,6 @@ void copyrightCommand(int argc, const char* argv[]) { printf("1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.\n\n"); 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"); -} \ No newline at end of file +} + +#endif \ No newline at end of file diff --git a/source/common.h b/source/common.h index efeeee5..76d602d 100644 --- a/source/common.h +++ b/source/common.h @@ -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))) \ No newline at end of file diff --git a/source/compiler.h b/source/compiler.h index 3fc43e0..c3f16bd 100644 --- a/source/compiler.h +++ b/source/compiler.h @@ -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); diff --git a/source/interpreter.c b/source/interpreter.c index bd56e6b..db8f10c 100644 --- a/source/interpreter.c +++ b/source/interpreter.c @@ -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); diff --git a/source/interpreter.h b/source/interpreter.h index 8ebe8e1..9fcd6ba 100644 --- a/source/interpreter.h +++ b/source/interpreter.h @@ -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 diff --git a/source/lexer.c b/source/lexer.c index 0efa4fd..205551f 100644 --- a/source/lexer.c +++ b/source/lexer.c @@ -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; } diff --git a/source/lexer.h b/source/lexer.h index 3211502..3a37b29 100644 --- a/source/lexer.h +++ b/source/lexer.h @@ -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 diff --git a/source/literal.h b/source/literal.h index 09574fd..e3159d5 100644 --- a/source/literal.h +++ b/source/literal.h @@ -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*)); diff --git a/source/makefile b/source/makefile index 4c8e881..daf07af 100644 --- a/source/makefile +++ b/source/makefile @@ -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) diff --git a/source/node.h b/source/node.h index e82e509..6445461 100644 --- a/source/node.h +++ b/source/node.h @@ -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 diff --git a/source/parser.c b/source/parser.c index 14c4566..d42fd30 100644 --- a/source/parser.c +++ b/source/parser.c @@ -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) { diff --git a/source/parser.h b/source/parser.h index 6559d1d..9a0f309 100644 --- a/source/parser.h +++ b/source/parser.h @@ -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); diff --git a/source/repl_main.c b/source/repl_main.c index e2918fa..a86138d 100644 --- a/source/repl_main.c +++ b/source/repl_main.c @@ -5,8 +5,6 @@ #include "compiler.h" #include "interpreter.h" -#include "memory.h" - #include #include #include