mirror of
https://github.com/krgamestudios/Toy.git
synced 2026-04-15 23:04:08 +10:00
Basic infile reading is working, untested
This commit is contained in:
199
repl/main.c
199
repl/main.c
@@ -1,11 +1,89 @@
|
|||||||
#include "toy_memory.h"
|
#include "toy.h"
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
//handle command line arguments
|
||||||
|
typedef struct CmdLine {
|
||||||
|
bool error;
|
||||||
|
bool help;
|
||||||
|
bool version;
|
||||||
|
const char* infile;
|
||||||
|
} CmdLine;
|
||||||
|
|
||||||
|
void usageCmdLine(int argc, const char* argv[]) {
|
||||||
|
printf("Usage: %s [ -h | -v | -f source.toy ]\n\n", argv[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void helpCmdLine(int argc, const char* argv[]) {
|
||||||
|
usageCmdLine(argc, argv);
|
||||||
|
|
||||||
|
printf(" -h, --help\t\t\tShow this help then exit.\n");
|
||||||
|
printf(" -v, --version\t\t\tShow version and copyright information then exit.\n");
|
||||||
|
printf(" -f, --file infile\t\tParse, compile and execute the source file then exit.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void versionCmdLine(int argc, const char* argv[]) {
|
||||||
|
printf("The Toy Programming Language, Version %d.%d.%d %s\n\n", TOY_VERSION_MAJOR, TOY_VERSION_MINOR, TOY_VERSION_PATCH, TOY_VERSION_BUILD);
|
||||||
|
|
||||||
|
//copy/pasted from the license file - there's a way to include it directly, but it's too finnicky to bother
|
||||||
|
const char* license = "\
|
||||||
|
Copyright (c) 2020-2024 Kayne Ruse, KR Game Studios\n\
|
||||||
|
\n\
|
||||||
|
This software is provided 'as-is', without any express or implied\n\
|
||||||
|
warranty. In no event will the authors be held liable for any damages\n\
|
||||||
|
arising from the use of this software.\n\
|
||||||
|
\n\
|
||||||
|
Permission is granted to anyone to use this software for any purpose,\n\
|
||||||
|
including commercial applications, and to alter it and redistribute it\n\
|
||||||
|
freely, subject to the following restrictions:\n\
|
||||||
|
\n\
|
||||||
|
1. The origin of this software must not be misrepresented; you must not\n\
|
||||||
|
claim that you wrote the original software. If you use this software\n\
|
||||||
|
in a product, an acknowledgment in the product documentation would be\n\
|
||||||
|
appreciated but is not required.\n\
|
||||||
|
2. Altered source versions must be plainly marked as such, and must not be\n\
|
||||||
|
misrepresented as being the original software.\n\
|
||||||
|
3. This notice may not be removed or altered from any source distribution.\n\n";
|
||||||
|
|
||||||
|
printf(license);
|
||||||
|
}
|
||||||
|
|
||||||
|
CmdLine parseCmdLine(int argc, const char* argv[]) {
|
||||||
|
CmdLine cmd = { .error = false, .help = false, .version = false, .infile = NULL };
|
||||||
|
|
||||||
|
for (int i = 1; i < argc; i++) {
|
||||||
|
if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help")) {
|
||||||
|
cmd.help = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (!strcmp(argv[i], "-v") || !strcmp(argv[i], "--version")) {
|
||||||
|
cmd.version = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (!strcmp(argv[i], "-f") || !strcmp(argv[i], "--file")) {
|
||||||
|
if (argc < i + 1) {
|
||||||
|
cmd.error = true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
cmd.infile = argv[++i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
else {
|
||||||
|
cmd.error = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return cmd;
|
||||||
|
}
|
||||||
|
|
||||||
|
//utilities
|
||||||
unsigned char* readFile(const char* path, int* size) {
|
unsigned char* readFile(const char* path, int* size) {
|
||||||
//open the file
|
//open the file
|
||||||
FILE* file = fopen(path, "rb");
|
FILE* file = fopen(path, "rb");
|
||||||
if (file == NULL) {
|
if (file == NULL) {
|
||||||
|
*size = -1; //missing file error
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -24,7 +102,7 @@ unsigned char* readFile(const char* path, int* size) {
|
|||||||
//
|
//
|
||||||
if (fread(buffer, sizeof(unsigned char), *size, file) < *size) {
|
if (fread(buffer, sizeof(unsigned char), *size, file) < *size) {
|
||||||
fclose(file);
|
fclose(file);
|
||||||
*size = -1; //singal a read error
|
*size = -2; //singal a read error
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -32,21 +110,120 @@ unsigned char* readFile(const char* path, int* size) {
|
|||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void dir(char* dest, const char* src) {
|
||||||
|
//extract the directory from src, and store it in dest
|
||||||
|
const char* p = strrchr(src, '/');
|
||||||
|
int len = p != NULL ? p - src + 1 : 0;
|
||||||
|
strncpy(dest, src, len);
|
||||||
|
dest[len] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, char* argv[]) {
|
#define APPEND(dest, src) \
|
||||||
int size = 0;
|
sprintf(dest + strlen(dest), src)
|
||||||
unsigned char* buffer = readFile("../repl/main.c", &size); //for now, just grab the main.c file as a test
|
|
||||||
|
|
||||||
if (buffer == NULL) {
|
//main file
|
||||||
fprintf(stderr, "Failed to open the file\n");
|
int main(int argc, const char* argv[]) {
|
||||||
|
CmdLine cmd = parseCmdLine(argc, argv);
|
||||||
|
|
||||||
|
if (cmd.error) {
|
||||||
|
usageCmdLine(argc, argv);
|
||||||
|
}
|
||||||
|
else if (cmd.help) {
|
||||||
|
helpCmdLine(argc, argv);
|
||||||
|
}
|
||||||
|
else if (cmd.version) {
|
||||||
|
versionCmdLine(argc, argv);
|
||||||
|
}
|
||||||
|
else if (cmd.infile != NULL) {
|
||||||
|
//run the given file
|
||||||
|
int size;
|
||||||
|
unsigned char* source = readFile(cmd.infile, &size);
|
||||||
|
|
||||||
|
//check the file
|
||||||
|
if (source == NULL) {
|
||||||
|
if (size == 0) {
|
||||||
|
fprintf(stderr, TOY_CC_ERROR "ERROR: Could not parse an empty file, exiting\n" TOY_CC_RESET);
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (size < 0) {
|
else if (size == -1) {
|
||||||
fprintf(stderr, "Failed to read the file\n");
|
fprintf(stderr, TOY_CC_ERROR "ERROR: File not found, exiting\n" TOY_CC_RESET);
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
TOY_FREE_ARRAY(unsigned char, buffer, size);
|
else {
|
||||||
|
fprintf(stderr, TOY_CC_ERROR "ERROR: Unknown error while reading file, exiting\n" TOY_CC_RESET);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Toy_Lexer lexer;
|
||||||
|
Toy_bindLexer(&lexer, (char*)source);
|
||||||
|
|
||||||
|
Toy_Parser parser;
|
||||||
|
Toy_bindParser(&parser, &lexer);
|
||||||
|
|
||||||
|
Toy_Bucket* bucket = NULL;
|
||||||
|
TOY_BUCKET_INIT(Toy_Ast, bucket, 32);
|
||||||
|
Toy_Ast* ast = Toy_scanParser(&bucket, &parser);
|
||||||
|
|
||||||
|
Toy_Bytecode bc = Toy_compileBytecode(ast);
|
||||||
|
|
||||||
|
//run the setup
|
||||||
|
Toy_VM vm;
|
||||||
|
Toy_initVM(&vm);
|
||||||
|
Toy_bindVM(&vm, bc.ptr, bc.capacity);
|
||||||
|
|
||||||
|
//run
|
||||||
|
Toy_runVM(&vm);
|
||||||
|
|
||||||
|
//debugging result
|
||||||
|
printf("printing the stack result\n\ntype\tvalue\n");
|
||||||
|
for (int i = 0; i < vm.stack.count; i++) {
|
||||||
|
Toy_Value v = vm.stack.ptr[i];
|
||||||
|
|
||||||
|
printf(" %d\t ", v.type);
|
||||||
|
|
||||||
|
switch(v.type) {
|
||||||
|
case TOY_VALUE_NULL:
|
||||||
|
printf("null");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TOY_VALUE_BOOLEAN:
|
||||||
|
printf("%s", TOY_VALUE_AS_BOOLEAN(v) ? "true" : "false");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TOY_VALUE_INTEGER:
|
||||||
|
printf("%d", TOY_VALUE_AS_INTEGER(v));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TOY_VALUE_FLOAT:
|
||||||
|
printf("%f", TOY_VALUE_AS_FLOAT(v));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TOY_VALUE_STRING:
|
||||||
|
case TOY_VALUE_ARRAY:
|
||||||
|
case TOY_VALUE_DICTIONARY:
|
||||||
|
case TOY_VALUE_FUNCTION:
|
||||||
|
case TOY_VALUE_OPAQUE:
|
||||||
|
printf("???");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
//cleanup
|
||||||
|
Toy_freeVM(&vm);
|
||||||
|
TOY_BUCKET_FREE(bucket);
|
||||||
|
TOY_FREE_ARRAY(unsigned char, source, size);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
usageCmdLine(argc, argv);
|
||||||
|
}
|
||||||
|
|
||||||
printf("All good\n");
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//TODO: simple and consistent way to print an AST and Toy_Value
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
CC=gcc
|
CC=gcc
|
||||||
CFLAGS+=-g -Wall -Werror -Wno-unused-parameter -Wno-unused-function -Wno-unused-variable
|
CFLAGS+=-g -Wall -Werror -Wno-unused-parameter -Wno-unused-function -Wno-unused-variable
|
||||||
LIBS+=-lm -lToy
|
LIBS+=-lm -lToy
|
||||||
LDFLAGS+=-Wl,-rpath,'.'
|
LDFLAGS+=-Wl,-R -Wl,'$$ORIGIN'
|
||||||
|
|
||||||
#directories
|
#directories
|
||||||
REPL_ROOTDIR=..
|
REPL_ROOTDIR=..
|
||||||
|
|||||||
1
scripts/example.toy
Normal file
1
scripts/example.toy
Normal file
@@ -0,0 +1 @@
|
|||||||
|
(1 + 2) * (3 + 4);
|
||||||
@@ -236,6 +236,10 @@ void Toy_bindLexer(Toy_Lexer* lexer, const char* source) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Toy_Token Toy_private_scanLexer(Toy_Lexer* lexer) {
|
Toy_Token Toy_private_scanLexer(Toy_Lexer* lexer) {
|
||||||
|
if (lexer->source == NULL) {
|
||||||
|
return makeErrorToken(lexer, "Missing source code in lexer");
|
||||||
|
}
|
||||||
|
|
||||||
eatWhitespace(lexer);
|
eatWhitespace(lexer);
|
||||||
|
|
||||||
lexer->start = lexer->current;
|
lexer->start = lexer->current;
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ static void advance(Toy_Parser* parser) {
|
|||||||
parser->current = Toy_private_scanLexer(parser->lexer);
|
parser->current = Toy_private_scanLexer(parser->lexer);
|
||||||
|
|
||||||
if (parser->current.type == TOY_TOKEN_ERROR) {
|
if (parser->current.type == TOY_TOKEN_ERROR) {
|
||||||
printError(parser, parser->current, "Read error");
|
printError(parser, parser->current, "Can't read the source code");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user