Author: mesyeti <mesyeti@mesyeti.uk>
rename basic-boot to basic
| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
diff --git a/basic/.gitignore b/basic/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..631d23f7093ec4d51a6bf2ededb3b33c0630dd30 --- /dev/null +++ b/basic/.gitignore @@ -0,0 +1 @@ +nitronb diff --git a/basic/Makefile b/basic/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..785906776db0027224492a1270d26eb186a99c75 --- /dev/null +++ b/basic/Makefile @@ -0,0 +1,49 @@ +SOURCES := $(wildcard source/*.c) $(wildcard source/**/*.c) +OBJECTS := $(patsubst source/%.c,bin/%.o,$(SOURCES)) +OUT := nitronb +LD := $(CC) + +override CFLAGS += -std=c99 -Wall -Wextra -Wuninitialized -Wundef -pedantic +override LDLIBS += -lm + +ifeq ($(BUILD),release) + override CFLAGS += -O3 + #override CPPFLAGS += -NDEBUG +else + override CFLAGS += -Og -g + ifeq ($(ASAN), y) + override CFLAGS += -fno-omit-frame-pointer -fsanitize=address + override LDFLAGS += -fsanitize=address + endif +endif + +.SECONDEXPANSION: + +deps.filter := %.c %.h +deps.option := -MM +define deps +$$(filter $$(deps.filter),,$$(shell $(CC) $(CFLAGS) $(CPPFLAGS) -E $(deps.option) $(1))) +endef + +all: $(OUT) + @: + +run: $(OUT) + '$(dir $<)$(notdir $<)' $(RUNFLAGS) + +$(OUT): $(OBJECTS) + $(LD) $(LDFLAGS) $^ $(LDLIBS) -o $@ + +bin/: + mkdir -p bin + +bin/%.o: source/%.c $(call deps,source/%.c) | bin/ + $(CC) $(CFLAGS) $(CPPFLAGS) $< -c -o $@ + +clean: + rm -r bin + +distclean: clean + rm $(OUT) + +.PHONY: all run clean distclean diff --git a/basic/example.bas b/basic/example.bas new file mode 100644 index 0000000000000000000000000000000000000000..2267bac07513ff4c398f934c27ab667969854ed0 --- /dev/null +++ b/basic/example.bas @@ -0,0 +1,10 @@ +'NITRON + +extern C func puts(ptr(char)) int + +puts "Hello, world!" + +dim ret as int +ret = puts("Hello again, world!") + +quit ret diff --git a/basic/source/common.h b/basic/source/common.h new file mode 100644 index 0000000000000000000000000000000000000000..94f4fb2029fd67dc73686715ded950e26256c9a6 --- /dev/null +++ b/basic/source/common.h @@ -0,0 +1,9 @@ +#ifndef N_COMMON_H +#define N_COMMON_H + +#include <stddef.h> +#include <stdint.h> +#include <stdlib.h> +#include <stdbool.h> + +#endif diff --git a/basic/source/error.c b/basic/source/error.c new file mode 100644 index 0000000000000000000000000000000000000000..2149922c18c01d2bd86757208d040c3983d37e91 --- /dev/null +++ b/basic/source/error.c @@ -0,0 +1,67 @@ +#include <stdio.h> +#include <stdarg.h> +#include <assert.h> +#include "mem.h" +#include "error.h" + +#define FMT(RET, FORMAT) do { \ + int n = 0; \ + size_t size = 0; \ + va_list ap; \ +\ + va_start(ap, FORMAT); \ + n = vsnprintf(RET, size, FORMAT, ap); \ + va_end(ap); \ +\ + assert(n >= 0); \ +\ + size = n + 1; \ + RET = (char*) SafeMalloc(size); \ + if (RET == NULL) { \ + return; \ + } \ +\ + va_start(ap, FORMAT); \ + n = vsnprintf(RET, size, FORMAT, ap); \ + va_end(ap); \ +\ + assert(n >= 0); \ +} while (0); + +void PrintError(ErrorInfo err, const char* format, ...) { + char* ret = NULL; + + FMT(ret, format); + + #if 0 + fprintf(stderr, "error: %s:%d: %s\n", err.file, (int) err.line, ret); + #else + #define RED "\x1b[31m" + #define BLUE "\x1b[34m" + #define RESET "\x1b[0m" + fprintf( + stderr, RED "error: " BLUE "%s:%d: " RESET "%s\n", + err.file, (int) err.line, ret + ); + #endif + + exit(1); +} + +void PrintWarning(ErrorInfo err, const char* format, ...) { + char* ret = NULL; + + FMT(ret, format); + + #if 0 + fprintf(stderr, "error: %s:%d: %s\n", err.file, (int) err.line, ret); + #else + #define YELLOW "\x1b[33m" + #define BLUE "\x1b[34m" + #define RESET "\x1b[0m" + fprintf( + stderr, YELLOW "warning: " BLUE "%s:%d: " RESET "%s\n", + err.file, (int) err.line, ret + ); + #endif +} diff --git a/basic/source/error.h b/basic/source/error.h new file mode 100644 index 0000000000000000000000000000000000000000..de5ff9f8e56c78843c3d6aefae933fcc325e3de4 --- /dev/null +++ b/basic/source/error.h @@ -0,0 +1,14 @@ +#ifndef N_ERROR_H +#define N_ERROR_H + +#include "common.h" + +typedef struct { + const char* file; + size_t line; +} ErrorInfo; + +void PrintError(ErrorInfo err, const char* format, ...); +void PrintWarning(ErrorInfo err, const char* format, ...); + +#endif diff --git a/basic/source/lexer.c b/basic/source/lexer.c new file mode 100644 index 0000000000000000000000000000000000000000..06ae344d28b518f6745713a23d6a05af98a2075c --- /dev/null +++ b/basic/source/lexer.c @@ -0,0 +1,224 @@ +#include <stdio.h> +#include <assert.h> +#include <string.h> +#include "lexer.h" +#include "string.h" + +Lexer Lexer_Init(FILE* file, const char* fileName) { + Lexer lexer; + lexer.file = file; + lexer.success = true; + lexer.fileName = fileName; + lexer.line = 1; + return lexer; +} + +void Lexer_Free(Lexer* lexer) { + fclose(lexer->file); +} + +static bool IsSeparator(char ch) { + switch (ch) { + case ' ': + case '\n': + case '\t': + case '(': + case ')': + case ',': + case '+': + case '-': + case '*': + case '/': + case '%': + case '=': + case '<': + case '>': + case '\'': return true; + default: return false; + } +} + +static bool IsNumeric(const char* str) { + size_t len = strlen(str); + + for (size_t i = 0; i < len; ++ i) { + if ((str[i] < '0') || (str[i] > '9')) return false; + } + + return true; +} + +#define GET_CHAR(VAR) \ + do { \ + if (fread(&VAR, 1, 1, lexer->file) != 1) { \ + return LEXER_EOF; \ + } \ + if (VAR == '\n') ++ lexer->line; \ + } while (0); + +#define GET_CHAR_ERROR(VAR) \ + do { \ + if (fread(&VAR, 1, 1, lexer->file) != 1) { \ + ErrorInfo err = {lexer->fileName, lexer->line}; \ + PrintError(err, "Unexpected EOF"); \ + lexer->success = false; \ + return LEXER_EOF; \ + } \ + if (VAR == '\n') ++ lexer->line; \ + } while (0); + +#define TOKEN(TYPE, CONTENTS) ((Token) \ + {(TYPE), (ErrorInfo) {lexer->fileName, lexer->line}, (CONTENTS)}) + +int Lexer_Next(Lexer* lexer, Token* token) { + char ch; + + GET_CHAR(ch) + + switch (ch) { + case '"': { + String string = String_New(); + + while (true) { + GET_CHAR_ERROR(ch) + if (ch == '"') break; + + String_AddChar(&string, ch); + } + + *token = TOKEN(TOKEN_STRING, string.contents); + return LEXER_TOKEN; + } + case '(': *token = TOKEN(TOKEN_LPAREN, NULL); return LEXER_TOKEN; + case ')': *token = TOKEN(TOKEN_RPAREN, NULL); return LEXER_TOKEN; + case ',': *token = TOKEN(TOKEN_COMMA, NULL); return LEXER_TOKEN; + case '+': *token = TOKEN(TOKEN_ADD, NULL); return LEXER_TOKEN; + case '-': *token = TOKEN(TOKEN_SUBTRACT, NULL); return LEXER_TOKEN; + case '*': *token = TOKEN(TOKEN_MULTIPLY, NULL); return LEXER_TOKEN; + case '/': *token = TOKEN(TOKEN_DIVIDE, NULL); return LEXER_TOKEN; + case '%': *token = TOKEN(TOKEN_MOD, NULL); return LEXER_TOKEN; + case '=': *token = TOKEN(TOKEN_EQUAL, NULL); return LEXER_TOKEN; + case '<': *token = TOKEN(TOKEN_LESS, NULL); return LEXER_TOKEN; + case '>': *token = TOKEN(TOKEN_GREATER, NULL); return LEXER_TOKEN; + case '\n': *token = TOKEN(TOKEN_LINE, NULL); return LEXER_TOKEN; + case '\'': { + while (true) { + GET_CHAR(ch); + + if (ch == '\n') { + return LEXER_NONE; + } + } + return LEXER_EOF; + } + case ' ': + case '\t': return LEXER_NONE; + default: { + // must be an identifier, keyword, or integer + String string = String_FromChar(ch); + + while (true) { + GET_CHAR_ERROR(ch) + if (IsSeparator(ch)) { + fseek(lexer->file, -1, SEEK_CUR); + if (ch == '\n') -- lexer->line; + break; + } + + String_AddChar(&string, ch); + } + + if (IsNumeric(string.contents)) { + *token = TOKEN(TOKEN_INT, string.contents); + return LEXER_TOKEN; + } + if (!strcmp(string.contents, "extern")) { + *token = TOKEN(TOKEN_EXTERN, NULL); + String_Free(&string); + return LEXER_TOKEN; + } + if (!strcmp(string.contents, "func") || !strcmp(string.contents, "function")) { + *token = TOKEN(TOKEN_FUNC, NULL); + String_Free(&string); + return LEXER_TOKEN; + } + if (!strcmp(string.contents, "sub")) { + *token = TOKEN(TOKEN_SUB, NULL); + String_Free(&string); + return LEXER_TOKEN; + } + if (!strcmp(string.contents, "dim")) { + *token = TOKEN(TOKEN_DIM, NULL); + String_Free(&string); + return LEXER_TOKEN; + } + if (!strcmp(string.contents, "as")) { + *token = TOKEN(TOKEN_AS, NULL); + String_Free(&string); + return LEXER_TOKEN; + } + if (!strcmp(string.contents, "quit")) { + *token = TOKEN(TOKEN_QUIT, NULL); + String_Free(&string); + return LEXER_TOKEN; + } + if (!strcmp(string.contents, "ptr")) { + *token = TOKEN(TOKEN_PTR, NULL); + String_Free(&string); + return LEXER_TOKEN; + } + if (!strcmp(string.contents, "end")) { + *token = TOKEN(TOKEN_END, NULL); + String_Free(&string); + return LEXER_TOKEN; + } + + *token = TOKEN(TOKEN_IDENTIFIER, string.contents); + return LEXER_TOKEN; + } + } +} + +const char* Lexer_TypeVAsString(TokenType type) { + switch (type) { + case TOKEN_NULL: return "null"; + case TOKEN_EXTERN: return "extern"; + case TOKEN_FUNC: return "func"; + case TOKEN_SUB: return "sub"; + case TOKEN_DIM: return "dim"; + case TOKEN_AS: return "as"; + case TOKEN_QUIT: return "quit"; + case TOKEN_PTR: return "ptr"; + case TOKEN_END: return "end"; + case TOKEN_IDENTIFIER: return "identifier"; + case TOKEN_STRING: return "string"; + case TOKEN_INT: return "int"; + case TOKEN_LINE: return "line"; + case TOKEN_LPAREN: return "lparen"; + case TOKEN_RPAREN: return "rparen"; + case TOKEN_COMMA: return "comma"; + case TOKEN_ADD: return "add"; + case TOKEN_SUBTRACT: return "subtract"; + case TOKEN_MULTIPLY: return "multiply"; + case TOKEN_DIVIDE: return "divide"; + case TOKEN_MOD: return "mod"; + case TOKEN_EQUAL: return "equal"; + case TOKEN_LESS: return "less"; + case TOKEN_GREATER: return "greater"; + default: assert(0); + } +} + +const char* Lexer_TypeAsString(Token* token) { + return Lexer_TypeVAsString(token->type); +} + +void Lexer_PrintToken(Token* token) { + printf("%s: %s\n", Lexer_TypeAsString(token), token->contents); +} + +void Lexer_FreeToken(Token* token) { + if (token->contents) { + free(token->contents); + } +} diff --git a/basic/source/lexer.h b/basic/source/lexer.h new file mode 100644 index 0000000000000000000000000000000000000000..0f3e15fa515f4e38f3882d1480fa461bb3e6a706 --- /dev/null +++ b/basic/source/lexer.h @@ -0,0 +1,70 @@ +#ifndef N_LEXER_H +#define N_LEXER_H + +#include <stdio.h> +#include "error.h" +#include "common.h" + +typedef enum { + TOKEN_NULL = 0, + + // keywords + TOKEN_EXTERN, + TOKEN_FUNC, + TOKEN_SUB, + TOKEN_DIM, + TOKEN_AS, + TOKEN_QUIT, + TOKEN_PTR, + TOKEN_END, + + // misc + TOKEN_IDENTIFIER, + TOKEN_STRING, + TOKEN_INT, + TOKEN_LINE, + + // characters + TOKEN_LPAREN, + TOKEN_RPAREN, + TOKEN_COMMA, + + // operators + TOKEN_ADD, + TOKEN_SUBTRACT, + TOKEN_MULTIPLY, + TOKEN_DIVIDE, + TOKEN_MOD, + TOKEN_EQUAL, + TOKEN_LESS, + TOKEN_GREATER +} TokenType; + +enum { + LEXER_TOKEN, + LEXER_EOF, + LEXER_NONE +}; + +typedef struct { + TokenType type; + ErrorInfo err; + char* contents; +} Token; + +typedef struct { + FILE* file; + bool success; + const char* fileName; + size_t line; +} Lexer; + +Lexer Lexer_Init(FILE* file, const char* fileName); +void Lexer_Free(Lexer* lexer); +int Lexer_Next(Lexer* lexer, Token* token); +const char* Lexer_TypeVAsString(TokenType type); +const char* Lexer_TypeAsString(Token* token); +void Lexer_PrintToken(Token* token); +void Lexer_FreeToken(Token* token); + +#endif diff --git a/basic/source/main.c b/basic/source/main.c new file mode 100644 index 0000000000000000000000000000000000000000..a8e3fa95d0afaa3a9ac44b0c75f86f336a150b30 --- /dev/null +++ b/basic/source/main.c @@ -0,0 +1,76 @@ +#include <stdio.h> +#include <string.h> +#include "lexer.h" +#include "state.h" +#include "parser.h" +#include "common.h" +#include "semanticAnalysis.h" + +int main(int argc, char** argv) { + const char* source = NULL; + + bool printNodes = false; + bool printTokens = false; + + if (argc == 1) { + printf( + "Usage: %s SOURCE [FLAGS]\n", argv[0] + ); + } + + for (int i = 1; i < argc; ++ i) { + if (argv[i][0] != '-') { + if (source) { + fprintf(stderr, "Source file set multiple times"); + return 1; + } + + source = argv[i]; + } + else if (strcmp(argv[i], "--dp") == 0) { + printNodes = true; + } + else if (strcmp(argv[i], "--dl") == 0) { + printTokens = true; + } + else { + fprintf(stderr, "Unknown flag: %s\n", argv[i]); + return 1; + } + } + + if (!source) { + fprintf(stderr, "No source file provided\n"); + return 1; + } + + FILE* sourceFile = fopen(source, "r"); + + if (!sourceFile) { + fprintf(stderr, "Failed to open '%s'\n", source); + return 1; + } + + Parser parser = Parser_Init(sourceFile, source, printTokens); + + size_t len; + Node* ret = Parser_Parse(&parser, &len); + + if (printNodes) { + for (size_t i = 0; i < len; ++ i) { + Parser_PrintNode(&ret[i]); + } + + return 0; + } + + SemanticAnalysis_Init(8); + + for (size_t i = 0; i < len; ++ i){ + SemanticAnalysis_Analyse(&ret[i]); + } + + State_DumpInfo(); + + return 0; +} diff --git a/basic/source/mem.c b/basic/source/mem.c new file mode 100644 index 0000000000000000000000000000000000000000..bcef6460e47b9108ddcc2f316a9836fd77855b03 --- /dev/null +++ b/basic/source/mem.c @@ -0,0 +1,27 @@ +#include <stdio.h> +#include "mem.h" +#include "common.h" + +void* SafeMalloc(size_t size) { + if (size == 0) return NULL; + + void* ret = malloc(size); + + if (ret == NULL) { + fprintf(stderr, "Malloc returned NULL\n"); + exit(1); + } + + return ret; +} + +void* SafeRealloc(void* ptr, size_t size) { + void* ret = realloc(ptr, size); + + if ((ret == NULL) && (size > 0)) { + fprintf(stderr, "Malloc returned NULL\n"); + exit(1); + } + + return ret; +} diff --git a/basic/source/mem.h b/basic/source/mem.h new file mode 100644 index 0000000000000000000000000000000000000000..1254b31036c2ac43f2f96bc0063f85ab6766d742 --- /dev/null +++ b/basic/source/mem.h @@ -0,0 +1,11 @@ +#ifndef N_MEM_H +#define N_MEM_H + +#include "common.h" + +#define NEW(T) (T*) SafeMalloc(sizeof(T)) + +void* SafeMalloc(size_t size); +void* SafeRealloc(void* ptr, size_t size); + +#endif diff --git a/basic/source/parser.c b/basic/source/parser.c new file mode 100644 index 0000000000000000000000000000000000000000..2ae234724509cccb38c4a2cc5db7aacef610e5c1 --- /dev/null +++ b/basic/source/parser.c @@ -0,0 +1,664 @@ +#include <stdio.h> +#include <assert.h> +#include <string.h> +#include "mem.h" +#include "util.h" +#include "parser.h" + +Parser Parser_Init(FILE* file, const char* fileName, bool printTokens) { + Parser ret; + Lexer lexer = Lexer_Init(file, fileName); + + Token* tokens = SafeMalloc(64 * sizeof(Token)); + size_t tokensLen = 0; + size_t tokensCap = 64; + + bool lexing = true; + while (lexing) { + Token token; + + int status = Lexer_Next(&lexer, &token); + + switch (status) { + case LEXER_TOKEN: { + tokens[tokensLen] = token; + ++ tokensLen; + + if (tokensLen >= tokensCap) { + tokensCap += 64; + tokens = SafeRealloc(tokens, tokensCap * sizeof(Token)); + } + break; + } + case LEXER_EOF: lexing = false; break; + case LEXER_NONE: continue; + } + } + + tokens = SafeRealloc(tokens, tokensLen * sizeof(Token)); + ret.tokens = tokens; + ret.tokenNum = tokensLen; + ret.i = 0; + + if (printTokens) { + for (size_t i = 0; i < tokensLen; ++ i) { + Lexer_PrintToken(&tokens[i]); + } + + exit(0); + } + + return ret; +} + +#define INFO(TYPE) ((NodeInfo) {TYPE, p->tokens[p->i].err}) + +static Node ParseBinary(Parser* p); +static Node ParseNode(Parser* p); + +static void Advance(Parser* p) { + ++ p->i; + + if (p->i >= p->tokenNum) { + PrintError(p->tokens[p->tokenNum - 1].err, "Unexpected EOF"); + } +} + +static void Expect(Parser* p, TokenType type) { + if (p->tokens[p->i].type != type) { + Token token2; + token2.type = type; + + PrintError( + p->tokens[p->i].err, "Expected %s, got %s", + Lexer_TypeAsString(&token2), Lexer_TypeAsString(&p->tokens[p->i]) + ); + } +} + +static Node ParseAtom(Parser* p) { + Token* token = &p->tokens[p->i]; + Node ret; + + Advance(p); + + switch (token->type) { + case TOKEN_IDENTIFIER: { + ret.ident = (IdentifierNode) {INFO(NODE_IDENTIFIER), NewString(token->contents)}; + return ret; + } + case TOKEN_STRING: { + ret.string = (StringNode) {INFO(NODE_STRING), NewString(token->contents)}; + return ret; + } + case TOKEN_INT: { + ret.integer = (IntNode) {INFO(NODE_INT), atoi(token->contents)}; + return ret; + } + case TOKEN_LPAREN: { + ret = ParseBinary(p); + Expect(p, TOKEN_RPAREN); + Advance(p); + return ret; + } + default: { + PrintError( + token->err, "Failed to parse atom, got %s", + Lexer_TypeAsString(token) + ); + exit(1); + } + } +} + +static bool IsUnaryOperator(Token* tok) { + switch (tok->type) { + case TOKEN_ADD: + case TOKEN_SUBTRACT: return true; + default: return false; + } +} + +static Node ParseUnary(Parser* p) { + Token* tok = &p->tokens[p->i]; + + if (IsUnaryOperator(tok)) { + Advance(p); + Node operand = ParseUnary(p); + Node* operandPtr = SafeMalloc(sizeof(Node)); + *operandPtr = operand; + + Node ret; + ret.unary = (UnaryNode) { + INFO(NODE_UNARY_OP), operandPtr, tok->type + }; + return ret; + } + else { + return ParseAtom(p); + } +} + +static Node ParseMulDivMod(Parser* p) { + Node left = ParseUnary(p); + + while ( + (p->tokens[p->i].type == TOKEN_MULTIPLY) || + (p->tokens[p->i].type == TOKEN_DIVIDE) || + (p->tokens[p->i].type == TOKEN_MOD) + ) { + TokenType op = p->tokens[p->i].type; + Advance(p); + Node right = ParseUnary(p); + + Node* leftPtr = SafeMalloc(sizeof(Node)); + Node* rightPtr = SafeMalloc(sizeof(Node)); + *leftPtr = left; + *rightPtr = right; + + left.bin = (BinaryNode) { + INFO(NODE_BINARY_OP), leftPtr, rightPtr, op + }; + } + + return left; +} + +static Node ParseAddSub(Parser* p) { + Node left = ParseMulDivMod(p); + + while ( + (p->tokens[p->i].type == TOKEN_ADD) || + (p->tokens[p->i].type == TOKEN_SUB) + ) { + TokenType op = p->tokens[p->i].type; + Advance(p); + Node right = ParseMulDivMod(p); + + Node* leftPtr = SafeMalloc(sizeof(Node)); + Node* rightPtr = SafeMalloc(sizeof(Node)); + *leftPtr = left; + *rightPtr = right; + + left.bin = (BinaryNode) { + INFO(NODE_BINARY_OP), leftPtr, rightPtr, op + }; + } + + return left; +} + +static Node ParseComparison(Parser* p) { + Node left = ParseAddSub(p); + + while ( + (p->tokens[p->i].type == TOKEN_EQUAL) || + (p->tokens[p->i].type == TOKEN_LESS) || + (p->tokens[p->i].type == TOKEN_GREATER) + ) { + TokenType op = p->tokens[p->i].type; + Advance(p); + Node right = ParseAddSub(p); + + Node* leftPtr = SafeMalloc(sizeof(Node)); + Node* rightPtr = SafeMalloc(sizeof(Node)); + *leftPtr = left; + *rightPtr = right; + + left.bin = (BinaryNode) { + INFO(NODE_BINARY_OP), leftPtr, rightPtr, op + }; + } + + return left; +} + +static Node ParseBinary(Parser* p) { + return ParseComparison(p); +} + +static Node ParseType(Parser* p) { + Node ret; + + switch (p->tokens[p->i].type) { + case TOKEN_PTR: { + Advance(p); + Expect(p, TOKEN_LPAREN); + Advance(p); + + Node innerType = ParseType(p); + ret.ptr = (PtrNode) {INFO(NODE_PTR), SafeMalloc(sizeof(Node))}; + *ret.ptr.inner = innerType; + + Advance(p); + Expect(p, TOKEN_RPAREN); + return ret; + } + case TOKEN_IDENTIFIER: { + ret.ident = (IdentifierNode) { + INFO(NODE_IDENTIFIER), NewString(p->tokens[p->i].contents) + }; + return ret; + } + default: { + PrintError( + p->tokens[p->i].err, "Unexpected %s token in type", + Lexer_TypeAsString(&p->tokens[p->i]) + ); + exit(1); + } + } +} + +static FuncDec ParseFuncDec(Parser* p) { + FuncDecParam* params = NULL; + size_t paramsNum = 0; + + bool sub = p->tokens[p->i].type == TOKEN_SUB; + + Advance(p); + FuncDec ret; + + Expect(p, TOKEN_IDENTIFIER); + ret.name = NewString(p->tokens[p->i].contents); + + Advance(p); + Expect(p, TOKEN_LPAREN); + Advance(p); + + while (p->tokens[p->i].type != TOKEN_RPAREN) { + FuncDecParam param; + Expect(p, TOKEN_IDENTIFIER); + param.name = NewString(p->tokens[p->i].contents); + + Advance(p); + Expect(p, TOKEN_AS); + + Advance(p); + Node typeNode = ParseType(p); + Node* typePtr = SafeMalloc(sizeof(Node)); + *typePtr = typeNode; + param.type = typePtr; + + ++ paramsNum; + params = SafeRealloc(params, paramsNum * sizeof(FuncDecParam)); + params[paramsNum - 1] = param; + + Advance(p); + if ( + (p->tokens[p->i].type != TOKEN_COMMA) && + (p->tokens[p->i].type != TOKEN_RPAREN) + ) { + PrintError( + p->tokens[p->i].err, "Unexpected %s token in parameter list", + Lexer_TypeAsString(&p->tokens[p->i]) + ); + } + + if (p->tokens[p->i].type == TOKEN_COMMA) { + Advance(p); + } + } + + ret.params = params; + ret.paramsNum = paramsNum; + + Advance(p); + if (sub) { + Expect(p, TOKEN_LINE); + } + else { + ret.ret = SafeMalloc(sizeof(Node)); + *ret.ret = ParseType(p); + Advance(p); + Expect(p, TOKEN_LINE); + } + + return ret; +} + +static Node ParseFuncDef(Parser* p) { + FuncDefNode ret; + ret.i = INFO(NODE_FUNC_DEF); + ret.dec = ParseFuncDec(p); + Advance(p); + + ret.body = NULL; + ret.bodyLen = 0; + + while (p->tokens[p->i].type != TOKEN_END) { + if (p->tokens[p->i].type == TOKEN_LINE) { + Advance(p); + continue; + } + + Node node = ParseNode(p); + + ++ ret.bodyLen; + ret.body = SafeRealloc(ret.body, ret.bodyLen * sizeof(Node)); + ret.body[ret.bodyLen - 1] = node; + } + + Advance(p); + Expect(p, TOKEN_LINE); + + Node node; + node.funcDef = ret; + return node; +} + +static Node ParseDim(Parser* p) { + DimNode ret; + ret.i = INFO(NODE_DIM); + + Advance(p); + Expect(p, TOKEN_IDENTIFIER); + ret.name = NewString(p->tokens[p->i].contents); + + Advance(p); + Expect(p, TOKEN_AS); + + Advance(p); + ret.varType = SafeMalloc(sizeof(Node)); + *ret.varType = ParseType(p); + + + Advance(p); + Expect(p, TOKEN_LINE); + + Node node; + node.dim = ret; + return node; +} + +static Node ParseFuncCall(Parser* p) { + FuncCallNode ret; + ret.i = INFO(NODE_FUNC_CALL); + ret.func = NewString(p->tokens[p->i].contents); + + Advance(p); + Node* params = NULL; + size_t paramsNum = 0; + + while (p->tokens[p->i].type != TOKEN_LINE) { + Node param = ParseBinary(p); + + ++ paramsNum; + params = SafeRealloc(params, paramsNum * sizeof(Node)); + params[paramsNum - 1] = param; + + if ( + (p->tokens[p->i].type != TOKEN_LINE) && + (p->tokens[p->i].type != TOKEN_COMMA) + ) { + PrintError( + p->tokens[p->i].err, "Unexpected %s token in parameter list", + Lexer_TypeAsString(&p->tokens[p->i]) + ); + } + if (p->tokens[p->i].type == TOKEN_COMMA) { + Advance(p); + } + } + + ret.params = params; + ret.paramsNum = paramsNum; + + Node node; + node.funcCall = ret; + return node; +} + +static Node ParseAssign(Parser* p) { + AssignNode ret; + ret.i = INFO(NODE_ASSIGN); + ret.variable = NewString(p->tokens[p->i].contents); + + Advance(p); + Expect(p, TOKEN_EQUAL); + Advance(p); + + ret.rValue = SafeMalloc(sizeof(Node)); + *ret.rValue = ParseBinary(p); + + Expect(p, TOKEN_LINE); + + Node node; + node.assign = ret; + return node; +} + +static Node ParseNode(Parser* p) { + switch (p->tokens[p->i].type) { + case TOKEN_FUNC: + case TOKEN_SUB: return ParseFuncDef(p); + case TOKEN_DIM: return ParseDim(p); + case TOKEN_IDENTIFIER: { + if (p->i == p->tokenNum - 1) { + PrintError(p->tokens[p->i].err, "Unexpected EOF"); + } + + if (p->tokens[p->i + 1].type == TOKEN_EQUAL) { + return ParseAssign(p); + } + + return ParseFuncCall(p); + } + default: { + PrintError( + p->tokens[p->i].err, "Unexpected %s token", + Lexer_TypeAsString(&p->tokens[p->i]) + ); + exit(1); + } + } +} + +void Parser_PrintNode(Node* node) { + switch (node->i.type) { + case NODE_INT: printf("%d", node->integer.value); break; + case NODE_STRING: printf("%s", node->string.value); break; + case NODE_IDENTIFIER: printf("%s", node->ident.name); break; + case NODE_BINARY_OP: { + printf("("); + Parser_PrintNode(node->bin.left); + + switch (node->bin.op) { + case TOKEN_ADD: printf("+"); break; + case TOKEN_SUBTRACT: printf("-"); break; + case TOKEN_MULTIPLY: printf("*"); break; + case TOKEN_DIVIDE: printf("/"); break; + case TOKEN_MOD: printf("%%"); break; + case TOKEN_EQUAL: printf("="); break; + case TOKEN_LESS: printf("<"); break; + case TOKEN_GREATER: printf(">"); break; + default: assert(0); + } + + Parser_PrintNode(node->bin.right); + printf(")"); + break; + } + case NODE_UNARY_OP: { + printf("("); + + switch (node->unary.op) { + case TOKEN_ADD: printf("+"); break; + case TOKEN_SUBTRACT: printf("-"); break; + default: assert(0); + } + + Parser_PrintNode(node->unary.operand); + printf(")"); + break; + } + case NODE_PTR: { + printf("ptr("); + Parser_PrintNode(node->ptr.inner); + break; + } + case NODE_FUNC_DEF: { + if (node->funcDef.dec.ret) { + printf("func "); + } + else { + printf("sub "); + } + + printf("%s(", node->funcDef.dec.name); + + for (size_t i = 0; i < node->funcDef.dec.paramsNum; ++ i) { + printf("%s as ", node->funcDef.dec.params[i].name); + Parser_PrintNode(node->funcDef.dec.params[i].type); + + if (i < node->funcDef.dec.paramsNum - 1) { + printf(", "); + } + } + + printf(")\n"); + + for (size_t i = 0; i < node->funcDef.bodyLen; ++ i) { + printf("\t"); + Parser_PrintNode(&node->funcDef.body[i]); + puts(""); + } + puts("end"); + break; + } + case NODE_DIM: { + printf("dim %s as ", node->dim.name); + Parser_PrintNode(node->dim.varType); + puts(""); + break; + } + case NODE_FUNC_CALL: { + printf("%s ", node->funcCall.func); + + for (size_t i = 0; i < node->funcCall.paramsNum; ++ i) { + Parser_PrintNode(&node->funcCall.params[i]); + + if (i < node->funcCall.paramsNum - 1) { + printf(", "); + } + } + puts(""); + break; + } + case NODE_ASSIGN: { + printf("%s = ", node->assign.variable); + Parser_PrintNode(node->assign.rValue); + puts(""); + break; + } + default: { + printf("unknown %d\n", node->i.type); + assert(0); + } + } +} + +Node* Parser_Parse(Parser* p, size_t* lenOut) { + Node* ret = NULL; + size_t len = 0; + + for (p->i = 0; p->i < p->tokenNum; ++ p->i) { + if (p->tokens[p->i].type == TOKEN_LINE) continue; + + Node node = ParseNode(p); + + ++ len; + ret = SafeRealloc(ret, len * sizeof(Node)); + ret[len - 1] = node; + } + + for (size_t i = 0; i < p->tokenNum; ++ i) { + Lexer_FreeToken(&p->tokens[i]); + } + free(p->tokens); + + *lenOut = len; + return ret; +} + +void Parser_FreeNode(Node* node) { + switch (node->i.type) { + case NODE_STRING: free(node->string.value); break; + case NODE_IDENTIFIER: free(node->ident.name); break; + case NODE_BINARY_OP: { + Parser_FreeNode(node->bin.left); + Parser_FreeNode(node->bin.right); + free(node->bin.left); + free(node->bin.right); + break; + } + case NODE_UNARY_OP: { + Parser_FreeNode(node->unary.operand); + free(node->unary.operand); + break; + } + case NODE_PTR: { + Parser_FreeNode(node->ptr.inner); + free(node->ptr.inner); + break; + } + case NODE_FUNC_DEF: { + if (node->funcDef.dec.ret) { + Parser_FreeNode(node->funcDef.dec.ret); + free(node->funcDef.dec.ret); + } + + for (size_t i = 0; i < node->funcDef.dec.paramsNum; ++ i) { + Parser_FreeNode(node->funcDef.dec.params[i].type); + free(node->funcDef.dec.params[i].type); + } + + free(node->funcDef.dec.name); + + for (size_t i = 0; i < node->funcDef.bodyLen; ++ i) { + Parser_FreeNode(&node->funcDef.body[i]); + } + free(node->funcDef.body); + break; + } + case NODE_DIM: { + free(node->dim.name); + Parser_FreeNode(node->dim.varType); + free(node->dim.varType); + break; + } + case NODE_FUNC_CALL: { + free(node->funcCall.func); + + for (size_t i = 0; i < node->funcCall.paramsNum; ++ i) { + Parser_FreeNode(&node->funcCall.params[i]); + } + free(node->funcCall.params); + break; + } + case NODE_ASSIGN: { + free(node->assign.variable); + Parser_FreeNode(node->assign.rValue); + free(node->assign.rValue); + break; + } + default: return; + } +} + +const char* Parser_TypeStr(NodeType type) { + switch (type) { + case NODE_NONE: return "none"; + case NODE_INT: return "int"; + case NODE_STRING: return "string"; + case NODE_IDENTIFIER: return "identifier"; + case NODE_BINARY_OP: return "binary operation"; + case NODE_UNARY_OP: return "unary operation"; + case NODE_PTR: return "ptr"; + case NODE_FUNC_DEF: return "function definition"; + case NODE_DIM: return "dim"; + case NODE_FUNC_CALL: return "function call"; + case NODE_ASSIGN: return "assignment"; + default: return "???"; + } +} diff --git a/basic/source/parser.h b/basic/source/parser.h new file mode 100644 index 0000000000000000000000000000000000000000..9e643df70c4de70613cbcd791b17f86efca21126 --- /dev/null +++ b/basic/source/parser.h @@ -0,0 +1,127 @@ +#ifndef N_PARSER_H +#define N_PARSER_H + +#include "lexer.h" +#include "error.h" +#include "common.h" + +typedef enum { + NODE_NONE, + NODE_INT, + NODE_STRING, + NODE_IDENTIFIER, + NODE_BINARY_OP, + NODE_UNARY_OP, + NODE_PTR, + NODE_FUNC_DEF, + NODE_DIM, + NODE_FUNC_CALL, + NODE_ASSIGN +} NodeType; + +typedef struct { + NodeType type; + ErrorInfo err; +} NodeInfo; + +typedef union Node Node; + +typedef struct { + NodeInfo i; + int value; +} IntNode; + +typedef struct { + NodeInfo i; + char* value; +} StringNode; + +typedef struct { + NodeInfo i; + char* name; +} IdentifierNode; + +typedef struct { + NodeInfo i; + Node* left; + Node* right; + TokenType op; +} BinaryNode; + +typedef struct { + NodeInfo i; + Node* operand; + TokenType op; +} UnaryNode; + +typedef struct { + NodeInfo i; + Node* inner; +} PtrNode; + +typedef struct { + Node* type; + char* name; +} FuncDecParam; + +typedef struct { + FuncDecParam* params; + size_t paramsNum; + Node* ret; + char* name; +} FuncDec; + +typedef struct { + NodeInfo i; + FuncDec dec; + Node* body; + size_t bodyLen; +} FuncDefNode; + +typedef struct { + NodeInfo i; + char* name; + Node* varType; +} DimNode; + +typedef struct { + NodeInfo i; + char* func; + Node* params; + size_t paramsNum; +} FuncCallNode; + +typedef struct { + NodeInfo i; + char* variable; + Node* rValue; +} AssignNode; + +union Node { + NodeInfo i; + IntNode integer; + StringNode string; + IdentifierNode ident; + BinaryNode bin; + UnaryNode unary; + PtrNode ptr; + FuncDefNode funcDef; + DimNode dim; + FuncCallNode funcCall; + AssignNode assign; +}; + +typedef struct { + Token* tokens; + size_t tokenNum; + size_t i; +} Parser; + +Parser Parser_Init(FILE* file, const char* fileName, bool printTokens); +void Parser_PrintNode(Node* node); +Node* Parser_Parse(Parser* p, size_t* lenOut); +void Parser_FreeNode(Node* node); + +const char* Parser_TypeStr(NodeType type); + +#endif diff --git a/basic/source/semanticAnalysis.c b/basic/source/semanticAnalysis.c new file mode 100644 index 0000000000000000000000000000000000000000..c275153bb71bcc85fc06e2e5a9372f795796eb04 --- /dev/null +++ b/basic/source/semanticAnalysis.c @@ -0,0 +1,382 @@ +#include <assert.h> +#include <string.h> +#include "mem.h" +#include "util.h" +#include "error.h" +#include "state.h" +#include "parser.h" +#include "semanticAnalysis.h" + +void SemanticAnalysis_Init(size_t wordSize) { + State_Init(); + + // add primitive types + State_MakePrimitive("u8", 1, PRIM_UINT); + State_MakePrimitive("i8", 1, PRIM_INT); + State_MakePrimitive("u16", 2, PRIM_UINT); + State_MakePrimitive("i16", 2, PRIM_INT); + State_MakePrimitive("u32", 4, PRIM_UINT); + State_MakePrimitive("i32", 4, PRIM_INT); + State_MakePrimitive("u64", 8, PRIM_UINT); + State_MakePrimitive("i64", 8, PRIM_INT); + State_MakePrimitive("uint", wordSize, PRIM_UINT); + State_MakePrimitive("int", wordSize, PRIM_INT); + State_MakePrimitive("char", 1, PRIM_UINT); + State_MakePrimitive("f32", 4, PRIM_FLOAT); + State_MakePrimitive("f64", 8, PRIM_FLOAT); + State_MakePrimitive("bool", 1, PRIM_UINT); + State_MakePrimitive("__lit", 0, PRIM_INT); + + Type type; + type.name = NewString("unit"); + type.type = TYPE_UNIT; + State_AddType(type); +} + +void Expect(Node* node, NodeType type) { + if (node->i.type != type) { + PrintError(node->i.err, + "Expected %s, got %s", Parser_TypeStr(type), + Parser_TypeStr(node->i.type) + ); + } +} + +void Unexpected(Node* node) { + PrintError(node->i.err, "Unexpected %s", Parser_TypeStr(node->i.type)); +} + +static UsedType NodeAsUsedType(Node* node) { + UsedType ret; + ret.ptr = 0; + ret.array = false; // no arrays yet + + while (true) { + switch (node->i.type) { + case NODE_PTR: { + node = node->ptr.inner; + ++ ret.ptr; + continue; + } + case NODE_IDENTIFIER: { + Type* type = State_GetType(node->ident.name); + + if (!type) { + PrintError(node->i.err, "Type '%s' does not exist", node->ident.name); + } + + ret.typeIdx = type - state.types; + return ret; + } + default: { + Unexpected(node); + exit(1); + } + } + } +} + +static Type* GetTypeFromUsed(UsedType type) { + return &state.types[type.typeIdx]; +} + +#define GET_PRIM(NAME, PTR) \ + ((UsedType) {(PTR), State_GetType(NAME) - state.types, 0}) + +static UsedType EvalType(Node* node); + +static UsedType EvalBinOp(Node* node) { + UsedType left = EvalType(node->bin.left); + UsedType right = EvalType(node->bin.right); + + Type* leftType = GetTypeFromUsed(left); + Type* rightType = GetTypeFromUsed(right); + + if ((leftType->type != TYPE_PRIM) || (rightType->type != TYPE_PRIM)) { + PrintError(node->i.err, "You can only use primitive types in binary expressions"); + } + + if (left.ptr) { + if (right.ptr) { + switch (node->bin.op) { + case TOKEN_EQUAL: + case TOKEN_LESS: + case TOKEN_GREATER: return GET_PRIM("bool", 0); + case TOKEN_SUB: return GET_PRIM("uint", 0); + default: { + PrintError( + node->i.err, "Operation '%s' not allowed here", + Lexer_TypeVAsString(node->bin.op) + ); + } + } + } + else { + switch (node->bin.op) { + case TOKEN_ADD: + case TOKEN_SUB: { + if (rightType->primType == PRIM_FLOAT) { + PrintError(node->i.err, "Cannot add float to pointer"); + } + return left; + } + default: { + PrintError( + node->i.err, "Operation '%s' not allowed here", + Lexer_TypeVAsString(node->bin.op) + ); + } + } + } + } + else if (right.ptr) { + switch (node->bin.op) { + case TOKEN_ADD: + case TOKEN_SUB: { + if (leftType->primType == PRIM_FLOAT) { + PrintError(node->i.err, "Cannot add float to pointer"); + } + return right; + } + default: { + PrintError( + node->i.err, "Operation '%s' not allowed here", + Lexer_TypeVAsString(node->bin.op) + ); + } + } + } + else if (!right.ptr) { + switch (node->bin.op) { + case TOKEN_EQUAL: return GET_PRIM("bool", 0); + case TOKEN_LESS: + case TOKEN_GREATER: { + if ((leftType->type != TYPE_PRIM) || (rightType->type != TYPE_PRIM)) { + PrintError( + node->i.err, "Operation '%s' only works on primitives", + Lexer_TypeVAsString(node->bin.op) + ); + } + return GET_PRIM("bool", 0); + } + case TOKEN_ADD: + case TOKEN_SUBTRACT: + case TOKEN_MULTIPLY: + case TOKEN_DIVIDE: + case TOKEN_MOD: { + if ((leftType->type != TYPE_PRIM) || (rightType->type != TYPE_PRIM)) { + PrintError( + node->i.err, "Operation '%s' only works on primitives", + Lexer_TypeVAsString(node->bin.op) + ); + } + + if (leftType->primType == rightType->primType) { + if (leftType->size > rightType->size) { + return left; + } + else { + return right; + } + } + else { + PrintError( + node->i.err, "Incompatible types in '%s' operation", + Lexer_TypeVAsString(node->bin.op) + ); + } + } + default: break; + } + + PrintError( + node->i.err, "Operation '%s' not allowed here", + Lexer_TypeVAsString(node->bin.op) + ); + } + + exit(1); +} + +static UsedType EvalType(Node* node) { + static bool inFunc = false; + + switch (node->i.type) { + case NODE_INT: return GET_PRIM("__lit", 0); + case NODE_STRING: return GET_PRIM("char", 1); + case NODE_IDENTIFIER: { + Var* var = State_GetVar(node->ident.name); + + if (!var) { + PrintError( + node->i.err, "Variable '%s' doesn't exist", node->ident.name + ); + } + + return var->type; + } + case NODE_BINARY_OP: return EvalBinOp(node); + case NODE_UNARY_OP: { + UsedType operand = EvalType(node->unary.operand); + Type* type = GetTypeFromUsed(operand); + + if (type->type != TYPE_PRIM) { + PrintError(node->i.err, + "Only primitive types can be used with unary operators" + ); + } + + if ((type->primType == PRIM_UINT) && (node->unary.op == TOKEN_SUBTRACT)) { + PrintWarning(node->i.err, "Using negative sign on unsigned value"); + } + + return operand; + } + case NODE_PTR: { + UsedType type = EvalType(node->ptr.inner); + ++ type.ptr; + return type; + } + case NODE_FUNC_DEF: { + if (inFunc) { + PrintError(node->i.err, "Nested function definitions are not allowed"); + } + + Function func; + func.sub = node->funcDef.dec.ret != NULL; + + if (!func.sub) { + func.ret = NodeAsUsedType(node->funcDef.dec.ret); + } + + func.paramsLen = node->funcDef.dec.paramsNum; + func.params = SafeMalloc(func.paramsLen * sizeof(FuncParam)); + + for (size_t i = 0; i < func.paramsLen; ++ i) { + func.params[i].type = NodeAsUsedType( + node->funcDef.dec.params[i].type + ); + func.params[i].name = node->funcDef.dec.params[i].name; + } + + func.name = NewString(node->funcDef.dec.name); + State_AddFunc(func); + + // now analyse the body + State_AddScope(); + inFunc = true; + + // add parameters to this scope + for (size_t i = 0; i < func.paramsLen; ++ i) { + Var var; + var.type = func.params[i].type; + var.name = NewString(func.params[i].name); + State_AddVar(var); + } + + for (size_t i = 0; i < node->funcDef.bodyLen; ++ i) { + EvalType(&node->funcDef.body[i]); + } + inFunc = false; + State_FreeScope(); + return GET_PRIM("unit", 0); + } + case NODE_FUNC_CALL: { + Function* func = State_GetFunc(node->funcCall.func); + if (!func) { + PrintError(node->i.err, "Function %s does not exist", node->funcCall.func); + } + + if (func->paramsLen != node->funcCall.paramsNum) { + PrintError( + node->i.err, "Expected %d parameters, got %d", + func->paramsLen, node->funcCall.paramsNum + ); + } + + for (size_t i = 0; i < func->paramsLen; ++ i) { + UsedType type = EvalType(&node->funcCall.params[i]); + UsedType param = func->params[i].type; + Type* paramType = GetTypeFromUsed(param); + Type* callType = GetTypeFromUsed(type); + + bool paramLit = strcmp(callType->name, "__lit") == 0; + + if (!State_UsedTypeEq(type, param)) { + if ( + (callType->type == TYPE_PRIM) && (paramType->type == TYPE_PRIM) && + (callType->primType == paramType->primType) && + (paramType->size >= callType->size) + ) { + continue; + } + + if (paramLit && (paramType->type == TYPE_PRIM)) continue; + + PrintError(node->i.err, + "Expected %s for parameter %s, got %s", + paramType->name, func->params[i].name, callType->name + ); + } + } + + if (func->sub) { + return GET_PRIM("unit", 0); + } + else { + return func->ret; + } + } + case NODE_DIM: { + Var var; + var.type = NodeAsUsedType(node->dim.varType); + var.name = NewString(node->dim.name); + State_AddVar(var); + return GET_PRIM("unit", 0); + } + case NODE_ASSIGN: { + Var* var = State_GetVar(node->assign.variable); + + if (!var) { + PrintError( + node->i.err, "Variable '%s' doesn't exist", + node->assign.variable + ); + } + + UsedType left = var->type; + UsedType right = EvalType(node->assign.rValue); + + Type* leftType = GetTypeFromUsed(left); + Type* rightType = GetTypeFromUsed(right); + + bool compatible = true; + + if ((left.ptr != right.ptr) || (leftType->type != rightType->type)) { + compatible = false; + } + else if (leftType->type == TYPE_PRIM) { + if (leftType->primType != rightType->primType) compatible = false; + else if (leftType->size < rightType->size) compatible = false; + } + + if (!compatible) { + PrintError( + node->i.err, "Type '%s' cannot be assigned to '%s' variable", + GetTypeFromUsed(left)->name, GetTypeFromUsed(right)->name + ); + } + + return GET_PRIM("unit", 0); + } + default: { + Unexpected(node); + } + } + + assert(0); +} + +void SemanticAnalysis_Analyse(Node* node) { + EvalType(node); +} diff --git a/basic/source/semanticAnalysis.h b/basic/source/semanticAnalysis.h new file mode 100644 index 0000000000000000000000000000000000000000..341ccb8ac4a96ebcd1d94b58b4aad9fa914a881e --- /dev/null +++ b/basic/source/semanticAnalysis.h @@ -0,0 +1,9 @@ +#ifndef N_SEMANTIC_ANALYSIS_H +#define N_SEMANTIC_ANALYSIS_H + +#include "common.h" + +void SemanticAnalysis_Init(size_t wordSize); +void SemanticAnalysis_Analyse(Node* node); + +#endif diff --git a/basic/source/state.c b/basic/source/state.c new file mode 100644 index 0000000000000000000000000000000000000000..c2d901ca81d47638cf32a652631f8562859bda74 --- /dev/null +++ b/basic/source/state.c @@ -0,0 +1,127 @@ +#include <stdio.h> +#include <string.h> +#include "mem.h" +#include "util.h" +#include "state.h" + +State state; + +void State_Init(void) { + state.types = NULL; + state.typeNum = 0; + state.scopes[0] = NULL; + state.scopeSize[0] = 0; + state.scopeNum = 1; + state.funcs = NULL; + state.funcNum = 0; +} + +void State_AddType(Type type) { + ++ state.typeNum; + state.types = SafeRealloc(state.types, state.typeNum * sizeof(Type)); + state.types[state.typeNum - 1] = type; +} + +void State_AddVar(Var var) { + size_t scope = state.scopeNum - 1; + + ++ state.scopeSize[scope]; + state.scopes[scope] = SafeRealloc( + state.scopes[scope], state.scopeSize[scope] * sizeof(Var) + ); + state.scopes[scope][state.scopeSize[scope] - 1] = var; +} + +bool State_AddScope(void) { + if (state.scopeNum >= 16) return false; + + ++ state.scopeNum; + state.scopeSize[state.scopeNum - 1] = 0; + state.scopes[state.scopeNum - 1] = NULL; + return true; +} + +void State_AddFunc(Function func) { + ++ state.funcNum; + state.funcs = SafeRealloc(state.funcs, state.funcNum * sizeof(Function)); + state.funcs[state.funcNum - 1] = func; +} + +void State_FreeScope(void) { + Var* scope = state.scopes[state.scopeNum - 1]; + size_t scopeNum = state.scopeSize[state.scopeNum - 1]; + + for (size_t i = 0; i < scopeNum; ++ i) { + free(scope[i].name); + } + + -- state.scopeNum; +} + +Var* State_GetVar(const char* name) { + for (size_t i = state.scopeNum; i --> 0;) { + for (size_t j = 0; j < state.scopeSize[i]; ++ j) { + if (strcmp(state.scopes[i][j].name, name) == 0) { + return &state.scopes[i][j]; + } + } + } + + return NULL; +} + +Type* State_GetType(const char* name) { + for (size_t i = 0; i < state.typeNum; ++ i) { + if (strcmp(state.types[i].name, name) == 0) { + return &state.types[i]; + } + } + + return NULL; +} + +Function* State_GetFunc(const char* name) { + for (size_t i = 0; i < state.funcNum; ++ i) { + if (strcmp(state.funcs[i].name, name) == 0) { + return &state.funcs[i]; + } + } + + return NULL; +} + +void State_MakePrimitive(const char* name, size_t size, int primType) { + Type type; + type.type = TYPE_PRIM; + type.name = NewString(name); + type.size = size; + type.primType = primType; + State_AddType(type); +} + +bool State_UsedTypeEq(UsedType a, UsedType b) { + return (a.ptr == b.ptr) && (a.typeIdx == b.typeIdx) && (a.array == b.array); +} + +void State_DumpInfo(void) { + puts("TYPES"); + puts("====="); + for (size_t i = 0; i < state.typeNum; ++ i) { + printf("- %s\n", state.types[i].name); + } + puts("\n"); + + puts("GLOBALS"); + puts("======="); + for (size_t i = 0; i < state.scopeSize[0]; ++ i) { + printf("- %s\n", state.scopes[0][i].name); + } + puts("\n"); + + puts("FUNCTIONS"); + puts("========="); + for (size_t i = 0; i < state.funcNum; ++ i) { + printf("- %s\n", state.funcs[i].name); + } + puts("\n"); +} diff --git a/basic/source/state.h b/basic/source/state.h new file mode 100644 index 0000000000000000000000000000000000000000..bff6a6faeea769784107c85cb53b3b8e1e1da066 --- /dev/null +++ b/basic/source/state.h @@ -0,0 +1,80 @@ +#ifndef N_STATE_H +#define N_STATE_H + +#include "common.h" + +enum { + TYPE_PRIM, // is this "primitive", or Primula the manul? + TYPE_STRUCT, + TYPE_UNIT +}; + +enum { + PRIM_UINT, + PRIM_INT, + PRIM_FLOAT +}; + +typedef struct { + size_t ptr; + size_t typeIdx; + size_t array; // 0 if not array, contains length if not array +} UsedType; + +typedef struct { + int type; + char* name; + size_t size; + + // only for "struct" types + UsedType* structure; + size_t structLen; + + // only for "primitive" types + int primType; +} Type; + +typedef struct { + UsedType type; + char* name; +} Var; + +typedef struct { + UsedType type; + char* name; +} FuncParam; + +typedef struct { + bool sub; + UsedType ret; + FuncParam* params; + size_t paramsLen; + char* name; +} Function; + +typedef struct { + Type* types; + size_t typeNum; + Var* scopes[16]; + size_t scopeSize[16]; + size_t scopeNum; + Function* funcs; + size_t funcNum; +} State; + +extern State state; + +void State_Init(void); +void State_AddType(Type type); +void State_AddVar(Var var); +bool State_AddScope(void); +void State_AddFunc(Function func); +void State_FreeScope(void); +Var* State_GetVar(const char* name); +Type* State_GetType(const char* name); +Function* State_GetFunc(const char* name); +void State_MakePrimitive(const char* name, size_t size, int primType); +bool State_UsedTypeEq(UsedType a, UsedType b); +void State_DumpInfo(void); + +#endif diff --git a/basic/source/string.c b/basic/source/string.c new file mode 100644 index 0000000000000000000000000000000000000000..7e42275935d2fa0e7044dae2263a0c206aadf2de --- /dev/null +++ b/basic/source/string.c @@ -0,0 +1,48 @@ +#include <stdio.h> +#include <string.h> +#include "mem.h" +#include "string.h" + +String String_New(void) { + char* contents = SafeMalloc(1); + *contents = 0; + + return (String) { + contents, 1 + }; +} + +String String_FromChar(char ch) { + String ret = String_New(); + String_AddChar(&ret, ch); + return ret; +} + +void String_Free(String* string) { + free(string->contents); +} + +void String_Add(String* string, char* value) { + size_t newLen = strlen(string->contents) + strlen(value) + 1; + size_t newCap = string->capacity; + + while (newCap < newLen) { + newCap *= 2; + } + + if (newCap != string->capacity) { + string->capacity = newCap; + string->contents = SafeRealloc(string->contents, newCap); + } + + strcat(string->contents, value); +} + +void String_AddChar(String* string, char ch) { + char str[] = {ch, 0}; + String_Add(string, str); +} + +size_t String_Len(String* string) { + return strlen(string->contents); +} diff --git a/basic/source/string.h b/basic/source/string.h new file mode 100644 index 0000000000000000000000000000000000000000..98e30f87cba52e57745b1493d7be6621416d8936 --- /dev/null +++ b/basic/source/string.h @@ -0,0 +1,18 @@ +#ifndef N_STRING_H +#define N_STRING_H + +#include "common.h" + +typedef struct { + char* contents; + size_t capacity; +} String; + +String String_New(void); +String String_FromChar(char ch); +void String_Free(String* string); +void String_Add(String* string, char* value); +void String_AddChar(String* string, char ch); +size_t String_Len(String* string); + +#endif diff --git a/basic/source/util.c b/basic/source/util.c new file mode 100644 index 0000000000000000000000000000000000000000..3524bb0b4c307b7a93a3b07c1c2c13fe438d9956 --- /dev/null +++ b/basic/source/util.c @@ -0,0 +1,16 @@ +#include <string.h> +#include "mem.h" +#include "common.h" + +char* NewString(const char* src) { + char* ret = SafeMalloc(strlen(src) + 1); + strcpy(ret, src); + return ret; +} + +char* ConcatString(const char* first, const char* second) { + char* ret = SafeMalloc(strlen(first) + strlen(second) + 1); + strcpy(ret, first); + strcat(ret, second); + return ret; +} diff --git a/basic/source/util.h b/basic/source/util.h new file mode 100644 index 0000000000000000000000000000000000000000..aa57880a037cf533331c0e4cdedfcef4953b4465 --- /dev/null +++ b/basic/source/util.h @@ -0,0 +1,22 @@ +#ifndef N_UTIL_H +#define N_UTIL_H + +#include <stdio.h> + +#define FUNCTION_POINTER(TYPE, NAME, ...) TYPE (*NAME)(__VA_ARGS__) +#define MIN(A, B) (((A) < (B))? (A) : (B)) +#define MAX(A, B) (((A) > (B))? (A) : (B)) + +#define SWAP(TYPE, A, B) \ + do { \ + TYPE* macro##a = &(A); \ + TYPE* macro##b = &(B); \ + TYPE macro##tmp = *macro##a; \ + *macro##a = *macro##b; \ + *macro##b = macro##tmp; \ + } while (0); + +char* NewString(const char* src); +char* ConcatString(const char* first, const char* second); + +#endif diff --git a/basic/test.bas b/basic/test.bas new file mode 100644 index 0000000000000000000000000000000000000000..af13a8b74c4cbcb49dd5ac303c39c0578ebf48fb --- /dev/null +++ b/basic/test.bas @@ -0,0 +1,20 @@ +'NITRON + +dim foo as int + +func manul(foo as int, bar as int) int + dim bar as u32 +end + +manul 1, (2 * 3) + -5 * 4 + +foo = 3 + 4 + +dim a as int +dim b as f32 +dim c as int + +manul a + c, 5 + +dim myPtr as ptr(int) +myPtr = myPtr * 5 diff --git a/basic-boot/.gitignore b/basic-boot/.gitignore deleted file mode 100644 index 631d23f7093ec4d51a6bf2ededb3b33c0630dd30..0000000000000000000000000000000000000000 --- a/basic-boot/.gitignore +++ /dev/null @@ -1 +0,0 @@ -nitronb diff --git a/basic-boot/Makefile b/basic-boot/Makefile deleted file mode 100644 index 785906776db0027224492a1270d26eb186a99c75..0000000000000000000000000000000000000000 --- a/basic-boot/Makefile +++ /dev/null @@ -1,49 +0,0 @@ -SOURCES := $(wildcard source/*.c) $(wildcard source/**/*.c) -OBJECTS := $(patsubst source/%.c,bin/%.o,$(SOURCES)) -OUT := nitronb -LD := $(CC) - -override CFLAGS += -std=c99 -Wall -Wextra -Wuninitialized -Wundef -pedantic -override LDLIBS += -lm - -ifeq ($(BUILD),release) - override CFLAGS += -O3 - #override CPPFLAGS += -NDEBUG -else - override CFLAGS += -Og -g - ifeq ($(ASAN), y) - override CFLAGS += -fno-omit-frame-pointer -fsanitize=address - override LDFLAGS += -fsanitize=address - endif -endif - -.SECONDEXPANSION: - -deps.filter := %.c %.h -deps.option := -MM -define deps -$$(filter $$(deps.filter),,$$(shell $(CC) $(CFLAGS) $(CPPFLAGS) -E $(deps.option) $(1))) -endef - -all: $(OUT) - @: - -run: $(OUT) - '$(dir $<)$(notdir $<)' $(RUNFLAGS) - -$(OUT): $(OBJECTS) - $(LD) $(LDFLAGS) $^ $(LDLIBS) -o $@ - -bin/: - mkdir -p bin - -bin/%.o: source/%.c $(call deps,source/%.c) | bin/ - $(CC) $(CFLAGS) $(CPPFLAGS) $< -c -o $@ - -clean: - rm -r bin - -distclean: clean - rm $(OUT) - -.PHONY: all run clean distclean diff --git a/basic-boot/example.bas b/basic-boot/example.bas deleted file mode 100644 index 2267bac07513ff4c398f934c27ab667969854ed0..0000000000000000000000000000000000000000 --- a/basic-boot/example.bas +++ /dev/null @@ -1,10 +0,0 @@ -'NITRON - -extern C func puts(ptr(char)) int - -puts "Hello, world!" - -dim ret as int -ret = puts("Hello again, world!") - -quit ret diff --git a/basic-boot/source/common.h b/basic-boot/source/common.h deleted file mode 100644 index 94f4fb2029fd67dc73686715ded950e26256c9a6..0000000000000000000000000000000000000000 --- a/basic-boot/source/common.h +++ /dev/null @@ -1,9 +0,0 @@ -#ifndef N_COMMON_H -#define N_COMMON_H - -#include <stddef.h> -#include <stdint.h> -#include <stdlib.h> -#include <stdbool.h> - -#endif diff --git a/basic-boot/source/error.c b/basic-boot/source/error.c deleted file mode 100644 index 2149922c18c01d2bd86757208d040c3983d37e91..0000000000000000000000000000000000000000 --- a/basic-boot/source/error.c +++ /dev/null @@ -1,67 +0,0 @@ -#include <stdio.h> -#include <stdarg.h> -#include <assert.h> -#include "mem.h" -#include "error.h" - -#define FMT(RET, FORMAT) do { \ - int n = 0; \ - size_t size = 0; \ - va_list ap; \ -\ - va_start(ap, FORMAT); \ - n = vsnprintf(RET, size, FORMAT, ap); \ - va_end(ap); \ -\ - assert(n >= 0); \ -\ - size = n + 1; \ - RET = (char*) SafeMalloc(size); \ - if (RET == NULL) { \ - return; \ - } \ -\ - va_start(ap, FORMAT); \ - n = vsnprintf(RET, size, FORMAT, ap); \ - va_end(ap); \ -\ - assert(n >= 0); \ -} while (0); - -void PrintError(ErrorInfo err, const char* format, ...) { - char* ret = NULL; - - FMT(ret, format); - - #if 0 - fprintf(stderr, "error: %s:%d: %s\n", err.file, (int) err.line, ret); - #else - #define RED "\x1b[31m" - #define BLUE "\x1b[34m" - #define RESET "\x1b[0m" - fprintf( - stderr, RED "error: " BLUE "%s:%d: " RESET "%s\n", - err.file, (int) err.line, ret - ); - #endif - - exit(1); -} - -void PrintWarning(ErrorInfo err, const char* format, ...) { - char* ret = NULL; - - FMT(ret, format); - - #if 0 - fprintf(stderr, "error: %s:%d: %s\n", err.file, (int) err.line, ret); - #else - #define YELLOW "\x1b[33m" - #define BLUE "\x1b[34m" - #define RESET "\x1b[0m" - fprintf( - stderr, YELLOW "warning: " BLUE "%s:%d: " RESET "%s\n", - err.file, (int) err.line, ret - ); - #endif -} diff --git a/basic-boot/source/error.h b/basic-boot/source/error.h deleted file mode 100644 index de5ff9f8e56c78843c3d6aefae933fcc325e3de4..0000000000000000000000000000000000000000 --- a/basic-boot/source/error.h +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef N_ERROR_H -#define N_ERROR_H - -#include "common.h" - -typedef struct { - const char* file; - size_t line; -} ErrorInfo; - -void PrintError(ErrorInfo err, const char* format, ...); -void PrintWarning(ErrorInfo err, const char* format, ...); - -#endif diff --git a/basic-boot/source/lexer.c b/basic-boot/source/lexer.c deleted file mode 100644 index 06ae344d28b518f6745713a23d6a05af98a2075c..0000000000000000000000000000000000000000 --- a/basic-boot/source/lexer.c +++ /dev/null @@ -1,224 +0,0 @@ -#include <stdio.h> -#include <assert.h> -#include <string.h> -#include "lexer.h" -#include "string.h" - -Lexer Lexer_Init(FILE* file, const char* fileName) { - Lexer lexer; - lexer.file = file; - lexer.success = true; - lexer.fileName = fileName; - lexer.line = 1; - return lexer; -} - -void Lexer_Free(Lexer* lexer) { - fclose(lexer->file); -} - -static bool IsSeparator(char ch) { - switch (ch) { - case ' ': - case '\n': - case '\t': - case '(': - case ')': - case ',': - case '+': - case '-': - case '*': - case '/': - case '%': - case '=': - case '<': - case '>': - case '\'': return true; - default: return false; - } -} - -static bool IsNumeric(const char* str) { - size_t len = strlen(str); - - for (size_t i = 0; i < len; ++ i) { - if ((str[i] < '0') || (str[i] > '9')) return false; - } - - return true; -} - -#define GET_CHAR(VAR) \ - do { \ - if (fread(&VAR, 1, 1, lexer->file) != 1) { \ - return LEXER_EOF; \ - } \ - if (VAR == '\n') ++ lexer->line; \ - } while (0); - -#define GET_CHAR_ERROR(VAR) \ - do { \ - if (fread(&VAR, 1, 1, lexer->file) != 1) { \ - ErrorInfo err = {lexer->fileName, lexer->line}; \ - PrintError(err, "Unexpected EOF"); \ - lexer->success = false; \ - return LEXER_EOF; \ - } \ - if (VAR == '\n') ++ lexer->line; \ - } while (0); - -#define TOKEN(TYPE, CONTENTS) ((Token) \ - {(TYPE), (ErrorInfo) {lexer->fileName, lexer->line}, (CONTENTS)}) - -int Lexer_Next(Lexer* lexer, Token* token) { - char ch; - - GET_CHAR(ch) - - switch (ch) { - case '"': { - String string = String_New(); - - while (true) { - GET_CHAR_ERROR(ch) - if (ch == '"') break; - - String_AddChar(&string, ch); - } - - *token = TOKEN(TOKEN_STRING, string.contents); - return LEXER_TOKEN; - } - case '(': *token = TOKEN(TOKEN_LPAREN, NULL); return LEXER_TOKEN; - case ')': *token = TOKEN(TOKEN_RPAREN, NULL); return LEXER_TOKEN; - case ',': *token = TOKEN(TOKEN_COMMA, NULL); return LEXER_TOKEN; - case '+': *token = TOKEN(TOKEN_ADD, NULL); return LEXER_TOKEN; - case '-': *token = TOKEN(TOKEN_SUBTRACT, NULL); return LEXER_TOKEN; - case '*': *token = TOKEN(TOKEN_MULTIPLY, NULL); return LEXER_TOKEN; - case '/': *token = TOKEN(TOKEN_DIVIDE, NULL); return LEXER_TOKEN; - case '%': *token = TOKEN(TOKEN_MOD, NULL); return LEXER_TOKEN; - case '=': *token = TOKEN(TOKEN_EQUAL, NULL); return LEXER_TOKEN; - case '<': *token = TOKEN(TOKEN_LESS, NULL); return LEXER_TOKEN; - case '>': *token = TOKEN(TOKEN_GREATER, NULL); return LEXER_TOKEN; - case '\n': *token = TOKEN(TOKEN_LINE, NULL); return LEXER_TOKEN; - case '\'': { - while (true) { - GET_CHAR(ch); - - if (ch == '\n') { - return LEXER_NONE; - } - } - return LEXER_EOF; - } - case ' ': - case '\t': return LEXER_NONE; - default: { - // must be an identifier, keyword, or integer - String string = String_FromChar(ch); - - while (true) { - GET_CHAR_ERROR(ch) - if (IsSeparator(ch)) { - fseek(lexer->file, -1, SEEK_CUR); - if (ch == '\n') -- lexer->line; - break; - } - - String_AddChar(&string, ch); - } - - if (IsNumeric(string.contents)) { - *token = TOKEN(TOKEN_INT, string.contents); - return LEXER_TOKEN; - } - if (!strcmp(string.contents, "extern")) { - *token = TOKEN(TOKEN_EXTERN, NULL); - String_Free(&string); - return LEXER_TOKEN; - } - if (!strcmp(string.contents, "func") || !strcmp(string.contents, "function")) { - *token = TOKEN(TOKEN_FUNC, NULL); - String_Free(&string); - return LEXER_TOKEN; - } - if (!strcmp(string.contents, "sub")) { - *token = TOKEN(TOKEN_SUB, NULL); - String_Free(&string); - return LEXER_TOKEN; - } - if (!strcmp(string.contents, "dim")) { - *token = TOKEN(TOKEN_DIM, NULL); - String_Free(&string); - return LEXER_TOKEN; - } - if (!strcmp(string.contents, "as")) { - *token = TOKEN(TOKEN_AS, NULL); - String_Free(&string); - return LEXER_TOKEN; - } - if (!strcmp(string.contents, "quit")) { - *token = TOKEN(TOKEN_QUIT, NULL); - String_Free(&string); - return LEXER_TOKEN; - } - if (!strcmp(string.contents, "ptr")) { - *token = TOKEN(TOKEN_PTR, NULL); - String_Free(&string); - return LEXER_TOKEN; - } - if (!strcmp(string.contents, "end")) { - *token = TOKEN(TOKEN_END, NULL); - String_Free(&string); - return LEXER_TOKEN; - } - - *token = TOKEN(TOKEN_IDENTIFIER, string.contents); - return LEXER_TOKEN; - } - } -} - -const char* Lexer_TypeVAsString(TokenType type) { - switch (type) { - case TOKEN_NULL: return "null"; - case TOKEN_EXTERN: return "extern"; - case TOKEN_FUNC: return "func"; - case TOKEN_SUB: return "sub"; - case TOKEN_DIM: return "dim"; - case TOKEN_AS: return "as"; - case TOKEN_QUIT: return "quit"; - case TOKEN_PTR: return "ptr"; - case TOKEN_END: return "end"; - case TOKEN_IDENTIFIER: return "identifier"; - case TOKEN_STRING: return "string"; - case TOKEN_INT: return "int"; - case TOKEN_LINE: return "line"; - case TOKEN_LPAREN: return "lparen"; - case TOKEN_RPAREN: return "rparen"; - case TOKEN_COMMA: return "comma"; - case TOKEN_ADD: return "add"; - case TOKEN_SUBTRACT: return "subtract"; - case TOKEN_MULTIPLY: return "multiply"; - case TOKEN_DIVIDE: return "divide"; - case TOKEN_MOD: return "mod"; - case TOKEN_EQUAL: return "equal"; - case TOKEN_LESS: return "less"; - case TOKEN_GREATER: return "greater"; - default: assert(0); - } -} - -const char* Lexer_TypeAsString(Token* token) { - return Lexer_TypeVAsString(token->type); -} - -void Lexer_PrintToken(Token* token) { - printf("%s: %s\n", Lexer_TypeAsString(token), token->contents); -} - -void Lexer_FreeToken(Token* token) { - if (token->contents) { - free(token->contents); - } -} diff --git a/basic-boot/source/lexer.h b/basic-boot/source/lexer.h deleted file mode 100644 index 0f3e15fa515f4e38f3882d1480fa461bb3e6a706..0000000000000000000000000000000000000000 --- a/basic-boot/source/lexer.h +++ /dev/null @@ -1,70 +0,0 @@ -#ifndef N_LEXER_H -#define N_LEXER_H - -#include <stdio.h> -#include "error.h" -#include "common.h" - -typedef enum { - TOKEN_NULL = 0, - - // keywords - TOKEN_EXTERN, - TOKEN_FUNC, - TOKEN_SUB, - TOKEN_DIM, - TOKEN_AS, - TOKEN_QUIT, - TOKEN_PTR, - TOKEN_END, - - // misc - TOKEN_IDENTIFIER, - TOKEN_STRING, - TOKEN_INT, - TOKEN_LINE, - - // characters - TOKEN_LPAREN, - TOKEN_RPAREN, - TOKEN_COMMA, - - // operators - TOKEN_ADD, - TOKEN_SUBTRACT, - TOKEN_MULTIPLY, - TOKEN_DIVIDE, - TOKEN_MOD, - TOKEN_EQUAL, - TOKEN_LESS, - TOKEN_GREATER -} TokenType; - -enum { - LEXER_TOKEN, - LEXER_EOF, - LEXER_NONE -}; - -typedef struct { - TokenType type; - ErrorInfo err; - char* contents; -} Token; - -typedef struct { - FILE* file; - bool success; - const char* fileName; - size_t line; -} Lexer; - -Lexer Lexer_Init(FILE* file, const char* fileName); -void Lexer_Free(Lexer* lexer); -int Lexer_Next(Lexer* lexer, Token* token); -const char* Lexer_TypeVAsString(TokenType type); -const char* Lexer_TypeAsString(Token* token); -void Lexer_PrintToken(Token* token); -void Lexer_FreeToken(Token* token); - -#endif diff --git a/basic-boot/source/main.c b/basic-boot/source/main.c deleted file mode 100644 index a8e3fa95d0afaa3a9ac44b0c75f86f336a150b30..0000000000000000000000000000000000000000 --- a/basic-boot/source/main.c +++ /dev/null @@ -1,76 +0,0 @@ -#include <stdio.h> -#include <string.h> -#include "lexer.h" -#include "state.h" -#include "parser.h" -#include "common.h" -#include "semanticAnalysis.h" - -int main(int argc, char** argv) { - const char* source = NULL; - - bool printNodes = false; - bool printTokens = false; - - if (argc == 1) { - printf( - "Usage: %s SOURCE [FLAGS]\n", argv[0] - ); - } - - for (int i = 1; i < argc; ++ i) { - if (argv[i][0] != '-') { - if (source) { - fprintf(stderr, "Source file set multiple times"); - return 1; - } - - source = argv[i]; - } - else if (strcmp(argv[i], "--dp") == 0) { - printNodes = true; - } - else if (strcmp(argv[i], "--dl") == 0) { - printTokens = true; - } - else { - fprintf(stderr, "Unknown flag: %s\n", argv[i]); - return 1; - } - } - - if (!source) { - fprintf(stderr, "No source file provided\n"); - return 1; - } - - FILE* sourceFile = fopen(source, "r"); - - if (!sourceFile) { - fprintf(stderr, "Failed to open '%s'\n", source); - return 1; - } - - Parser parser = Parser_Init(sourceFile, source, printTokens); - - size_t len; - Node* ret = Parser_Parse(&parser, &len); - - if (printNodes) { - for (size_t i = 0; i < len; ++ i) { - Parser_PrintNode(&ret[i]); - } - - return 0; - } - - SemanticAnalysis_Init(8); - - for (size_t i = 0; i < len; ++ i){ - SemanticAnalysis_Analyse(&ret[i]); - } - - State_DumpInfo(); - - return 0; -} diff --git a/basic-boot/source/mem.c b/basic-boot/source/mem.c deleted file mode 100644 index bcef6460e47b9108ddcc2f316a9836fd77855b03..0000000000000000000000000000000000000000 --- a/basic-boot/source/mem.c +++ /dev/null @@ -1,27 +0,0 @@ -#include <stdio.h> -#include "mem.h" -#include "common.h" - -void* SafeMalloc(size_t size) { - if (size == 0) return NULL; - - void* ret = malloc(size); - - if (ret == NULL) { - fprintf(stderr, "Malloc returned NULL\n"); - exit(1); - } - - return ret; -} - -void* SafeRealloc(void* ptr, size_t size) { - void* ret = realloc(ptr, size); - - if ((ret == NULL) && (size > 0)) { - fprintf(stderr, "Malloc returned NULL\n"); - exit(1); - } - - return ret; -} diff --git a/basic-boot/source/mem.h b/basic-boot/source/mem.h deleted file mode 100644 index 1254b31036c2ac43f2f96bc0063f85ab6766d742..0000000000000000000000000000000000000000 --- a/basic-boot/source/mem.h +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef N_MEM_H -#define N_MEM_H - -#include "common.h" - -#define NEW(T) (T*) SafeMalloc(sizeof(T)) - -void* SafeMalloc(size_t size); -void* SafeRealloc(void* ptr, size_t size); - -#endif diff --git a/basic-boot/source/parser.c b/basic-boot/source/parser.c deleted file mode 100644 index 2ae234724509cccb38c4a2cc5db7aacef610e5c1..0000000000000000000000000000000000000000 --- a/basic-boot/source/parser.c +++ /dev/null @@ -1,664 +0,0 @@ -#include <stdio.h> -#include <assert.h> -#include <string.h> -#include "mem.h" -#include "util.h" -#include "parser.h" - -Parser Parser_Init(FILE* file, const char* fileName, bool printTokens) { - Parser ret; - Lexer lexer = Lexer_Init(file, fileName); - - Token* tokens = SafeMalloc(64 * sizeof(Token)); - size_t tokensLen = 0; - size_t tokensCap = 64; - - bool lexing = true; - while (lexing) { - Token token; - - int status = Lexer_Next(&lexer, &token); - - switch (status) { - case LEXER_TOKEN: { - tokens[tokensLen] = token; - ++ tokensLen; - - if (tokensLen >= tokensCap) { - tokensCap += 64; - tokens = SafeRealloc(tokens, tokensCap * sizeof(Token)); - } - break; - } - case LEXER_EOF: lexing = false; break; - case LEXER_NONE: continue; - } - } - - tokens = SafeRealloc(tokens, tokensLen * sizeof(Token)); - ret.tokens = tokens; - ret.tokenNum = tokensLen; - ret.i = 0; - - if (printTokens) { - for (size_t i = 0; i < tokensLen; ++ i) { - Lexer_PrintToken(&tokens[i]); - } - - exit(0); - } - - return ret; -} - -#define INFO(TYPE) ((NodeInfo) {TYPE, p->tokens[p->i].err}) - -static Node ParseBinary(Parser* p); -static Node ParseNode(Parser* p); - -static void Advance(Parser* p) { - ++ p->i; - - if (p->i >= p->tokenNum) { - PrintError(p->tokens[p->tokenNum - 1].err, "Unexpected EOF"); - } -} - -static void Expect(Parser* p, TokenType type) { - if (p->tokens[p->i].type != type) { - Token token2; - token2.type = type; - - PrintError( - p->tokens[p->i].err, "Expected %s, got %s", - Lexer_TypeAsString(&token2), Lexer_TypeAsString(&p->tokens[p->i]) - ); - } -} - -static Node ParseAtom(Parser* p) { - Token* token = &p->tokens[p->i]; - Node ret; - - Advance(p); - - switch (token->type) { - case TOKEN_IDENTIFIER: { - ret.ident = (IdentifierNode) {INFO(NODE_IDENTIFIER), NewString(token->contents)}; - return ret; - } - case TOKEN_STRING: { - ret.string = (StringNode) {INFO(NODE_STRING), NewString(token->contents)}; - return ret; - } - case TOKEN_INT: { - ret.integer = (IntNode) {INFO(NODE_INT), atoi(token->contents)}; - return ret; - } - case TOKEN_LPAREN: { - ret = ParseBinary(p); - Expect(p, TOKEN_RPAREN); - Advance(p); - return ret; - } - default: { - PrintError( - token->err, "Failed to parse atom, got %s", - Lexer_TypeAsString(token) - ); - exit(1); - } - } -} - -static bool IsUnaryOperator(Token* tok) { - switch (tok->type) { - case TOKEN_ADD: - case TOKEN_SUBTRACT: return true; - default: return false; - } -} - -static Node ParseUnary(Parser* p) { - Token* tok = &p->tokens[p->i]; - - if (IsUnaryOperator(tok)) { - Advance(p); - Node operand = ParseUnary(p); - Node* operandPtr = SafeMalloc(sizeof(Node)); - *operandPtr = operand; - - Node ret; - ret.unary = (UnaryNode) { - INFO(NODE_UNARY_OP), operandPtr, tok->type - }; - return ret; - } - else { - return ParseAtom(p); - } -} - -static Node ParseMulDivMod(Parser* p) { - Node left = ParseUnary(p); - - while ( - (p->tokens[p->i].type == TOKEN_MULTIPLY) || - (p->tokens[p->i].type == TOKEN_DIVIDE) || - (p->tokens[p->i].type == TOKEN_MOD) - ) { - TokenType op = p->tokens[p->i].type; - Advance(p); - Node right = ParseUnary(p); - - Node* leftPtr = SafeMalloc(sizeof(Node)); - Node* rightPtr = SafeMalloc(sizeof(Node)); - *leftPtr = left; - *rightPtr = right; - - left.bin = (BinaryNode) { - INFO(NODE_BINARY_OP), leftPtr, rightPtr, op - }; - } - - return left; -} - -static Node ParseAddSub(Parser* p) { - Node left = ParseMulDivMod(p); - - while ( - (p->tokens[p->i].type == TOKEN_ADD) || - (p->tokens[p->i].type == TOKEN_SUB) - ) { - TokenType op = p->tokens[p->i].type; - Advance(p); - Node right = ParseMulDivMod(p); - - Node* leftPtr = SafeMalloc(sizeof(Node)); - Node* rightPtr = SafeMalloc(sizeof(Node)); - *leftPtr = left; - *rightPtr = right; - - left.bin = (BinaryNode) { - INFO(NODE_BINARY_OP), leftPtr, rightPtr, op - }; - } - - return left; -} - -static Node ParseComparison(Parser* p) { - Node left = ParseAddSub(p); - - while ( - (p->tokens[p->i].type == TOKEN_EQUAL) || - (p->tokens[p->i].type == TOKEN_LESS) || - (p->tokens[p->i].type == TOKEN_GREATER) - ) { - TokenType op = p->tokens[p->i].type; - Advance(p); - Node right = ParseAddSub(p); - - Node* leftPtr = SafeMalloc(sizeof(Node)); - Node* rightPtr = SafeMalloc(sizeof(Node)); - *leftPtr = left; - *rightPtr = right; - - left.bin = (BinaryNode) { - INFO(NODE_BINARY_OP), leftPtr, rightPtr, op - }; - } - - return left; -} - -static Node ParseBinary(Parser* p) { - return ParseComparison(p); -} - -static Node ParseType(Parser* p) { - Node ret; - - switch (p->tokens[p->i].type) { - case TOKEN_PTR: { - Advance(p); - Expect(p, TOKEN_LPAREN); - Advance(p); - - Node innerType = ParseType(p); - ret.ptr = (PtrNode) {INFO(NODE_PTR), SafeMalloc(sizeof(Node))}; - *ret.ptr.inner = innerType; - - Advance(p); - Expect(p, TOKEN_RPAREN); - return ret; - } - case TOKEN_IDENTIFIER: { - ret.ident = (IdentifierNode) { - INFO(NODE_IDENTIFIER), NewString(p->tokens[p->i].contents) - }; - return ret; - } - default: { - PrintError( - p->tokens[p->i].err, "Unexpected %s token in type", - Lexer_TypeAsString(&p->tokens[p->i]) - ); - exit(1); - } - } -} - -static FuncDec ParseFuncDec(Parser* p) { - FuncDecParam* params = NULL; - size_t paramsNum = 0; - - bool sub = p->tokens[p->i].type == TOKEN_SUB; - - Advance(p); - FuncDec ret; - - Expect(p, TOKEN_IDENTIFIER); - ret.name = NewString(p->tokens[p->i].contents); - - Advance(p); - Expect(p, TOKEN_LPAREN); - Advance(p); - - while (p->tokens[p->i].type != TOKEN_RPAREN) { - FuncDecParam param; - Expect(p, TOKEN_IDENTIFIER); - param.name = NewString(p->tokens[p->i].contents); - - Advance(p); - Expect(p, TOKEN_AS); - - Advance(p); - Node typeNode = ParseType(p); - Node* typePtr = SafeMalloc(sizeof(Node)); - *typePtr = typeNode; - param.type = typePtr; - - ++ paramsNum; - params = SafeRealloc(params, paramsNum * sizeof(FuncDecParam)); - params[paramsNum - 1] = param; - - Advance(p); - if ( - (p->tokens[p->i].type != TOKEN_COMMA) && - (p->tokens[p->i].type != TOKEN_RPAREN) - ) { - PrintError( - p->tokens[p->i].err, "Unexpected %s token in parameter list", - Lexer_TypeAsString(&p->tokens[p->i]) - ); - } - - if (p->tokens[p->i].type == TOKEN_COMMA) { - Advance(p); - } - } - - ret.params = params; - ret.paramsNum = paramsNum; - - Advance(p); - if (sub) { - Expect(p, TOKEN_LINE); - } - else { - ret.ret = SafeMalloc(sizeof(Node)); - *ret.ret = ParseType(p); - Advance(p); - Expect(p, TOKEN_LINE); - } - - return ret; -} - -static Node ParseFuncDef(Parser* p) { - FuncDefNode ret; - ret.i = INFO(NODE_FUNC_DEF); - ret.dec = ParseFuncDec(p); - Advance(p); - - ret.body = NULL; - ret.bodyLen = 0; - - while (p->tokens[p->i].type != TOKEN_END) { - if (p->tokens[p->i].type == TOKEN_LINE) { - Advance(p); - continue; - } - - Node node = ParseNode(p); - - ++ ret.bodyLen; - ret.body = SafeRealloc(ret.body, ret.bodyLen * sizeof(Node)); - ret.body[ret.bodyLen - 1] = node; - } - - Advance(p); - Expect(p, TOKEN_LINE); - - Node node; - node.funcDef = ret; - return node; -} - -static Node ParseDim(Parser* p) { - DimNode ret; - ret.i = INFO(NODE_DIM); - - Advance(p); - Expect(p, TOKEN_IDENTIFIER); - ret.name = NewString(p->tokens[p->i].contents); - - Advance(p); - Expect(p, TOKEN_AS); - - Advance(p); - ret.varType = SafeMalloc(sizeof(Node)); - *ret.varType = ParseType(p); - - - Advance(p); - Expect(p, TOKEN_LINE); - - Node node; - node.dim = ret; - return node; -} - -static Node ParseFuncCall(Parser* p) { - FuncCallNode ret; - ret.i = INFO(NODE_FUNC_CALL); - ret.func = NewString(p->tokens[p->i].contents); - - Advance(p); - Node* params = NULL; - size_t paramsNum = 0; - - while (p->tokens[p->i].type != TOKEN_LINE) { - Node param = ParseBinary(p); - - ++ paramsNum; - params = SafeRealloc(params, paramsNum * sizeof(Node)); - params[paramsNum - 1] = param; - - if ( - (p->tokens[p->i].type != TOKEN_LINE) && - (p->tokens[p->i].type != TOKEN_COMMA) - ) { - PrintError( - p->tokens[p->i].err, "Unexpected %s token in parameter list", - Lexer_TypeAsString(&p->tokens[p->i]) - ); - } - if (p->tokens[p->i].type == TOKEN_COMMA) { - Advance(p); - } - } - - ret.params = params; - ret.paramsNum = paramsNum; - - Node node; - node.funcCall = ret; - return node; -} - -static Node ParseAssign(Parser* p) { - AssignNode ret; - ret.i = INFO(NODE_ASSIGN); - ret.variable = NewString(p->tokens[p->i].contents); - - Advance(p); - Expect(p, TOKEN_EQUAL); - Advance(p); - - ret.rValue = SafeMalloc(sizeof(Node)); - *ret.rValue = ParseBinary(p); - - Expect(p, TOKEN_LINE); - - Node node; - node.assign = ret; - return node; -} - -static Node ParseNode(Parser* p) { - switch (p->tokens[p->i].type) { - case TOKEN_FUNC: - case TOKEN_SUB: return ParseFuncDef(p); - case TOKEN_DIM: return ParseDim(p); - case TOKEN_IDENTIFIER: { - if (p->i == p->tokenNum - 1) { - PrintError(p->tokens[p->i].err, "Unexpected EOF"); - } - - if (p->tokens[p->i + 1].type == TOKEN_EQUAL) { - return ParseAssign(p); - } - - return ParseFuncCall(p); - } - default: { - PrintError( - p->tokens[p->i].err, "Unexpected %s token", - Lexer_TypeAsString(&p->tokens[p->i]) - ); - exit(1); - } - } -} - -void Parser_PrintNode(Node* node) { - switch (node->i.type) { - case NODE_INT: printf("%d", node->integer.value); break; - case NODE_STRING: printf("%s", node->string.value); break; - case NODE_IDENTIFIER: printf("%s", node->ident.name); break; - case NODE_BINARY_OP: { - printf("("); - Parser_PrintNode(node->bin.left); - - switch (node->bin.op) { - case TOKEN_ADD: printf("+"); break; - case TOKEN_SUBTRACT: printf("-"); break; - case TOKEN_MULTIPLY: printf("*"); break; - case TOKEN_DIVIDE: printf("/"); break; - case TOKEN_MOD: printf("%%"); break; - case TOKEN_EQUAL: printf("="); break; - case TOKEN_LESS: printf("<"); break; - case TOKEN_GREATER: printf(">"); break; - default: assert(0); - } - - Parser_PrintNode(node->bin.right); - printf(")"); - break; - } - case NODE_UNARY_OP: { - printf("("); - - switch (node->unary.op) { - case TOKEN_ADD: printf("+"); break; - case TOKEN_SUBTRACT: printf("-"); break; - default: assert(0); - } - - Parser_PrintNode(node->unary.operand); - printf(")"); - break; - } - case NODE_PTR: { - printf("ptr("); - Parser_PrintNode(node->ptr.inner); - break; - } - case NODE_FUNC_DEF: { - if (node->funcDef.dec.ret) { - printf("func "); - } - else { - printf("sub "); - } - - printf("%s(", node->funcDef.dec.name); - - for (size_t i = 0; i < node->funcDef.dec.paramsNum; ++ i) { - printf("%s as ", node->funcDef.dec.params[i].name); - Parser_PrintNode(node->funcDef.dec.params[i].type); - - if (i < node->funcDef.dec.paramsNum - 1) { - printf(", "); - } - } - - printf(")\n"); - - for (size_t i = 0; i < node->funcDef.bodyLen; ++ i) { - printf("\t"); - Parser_PrintNode(&node->funcDef.body[i]); - puts(""); - } - puts("end"); - break; - } - case NODE_DIM: { - printf("dim %s as ", node->dim.name); - Parser_PrintNode(node->dim.varType); - puts(""); - break; - } - case NODE_FUNC_CALL: { - printf("%s ", node->funcCall.func); - - for (size_t i = 0; i < node->funcCall.paramsNum; ++ i) { - Parser_PrintNode(&node->funcCall.params[i]); - - if (i < node->funcCall.paramsNum - 1) { - printf(", "); - } - } - puts(""); - break; - } - case NODE_ASSIGN: { - printf("%s = ", node->assign.variable); - Parser_PrintNode(node->assign.rValue); - puts(""); - break; - } - default: { - printf("unknown %d\n", node->i.type); - assert(0); - } - } -} - -Node* Parser_Parse(Parser* p, size_t* lenOut) { - Node* ret = NULL; - size_t len = 0; - - for (p->i = 0; p->i < p->tokenNum; ++ p->i) { - if (p->tokens[p->i].type == TOKEN_LINE) continue; - - Node node = ParseNode(p); - - ++ len; - ret = SafeRealloc(ret, len * sizeof(Node)); - ret[len - 1] = node; - } - - for (size_t i = 0; i < p->tokenNum; ++ i) { - Lexer_FreeToken(&p->tokens[i]); - } - free(p->tokens); - - *lenOut = len; - return ret; -} - -void Parser_FreeNode(Node* node) { - switch (node->i.type) { - case NODE_STRING: free(node->string.value); break; - case NODE_IDENTIFIER: free(node->ident.name); break; - case NODE_BINARY_OP: { - Parser_FreeNode(node->bin.left); - Parser_FreeNode(node->bin.right); - free(node->bin.left); - free(node->bin.right); - break; - } - case NODE_UNARY_OP: { - Parser_FreeNode(node->unary.operand); - free(node->unary.operand); - break; - } - case NODE_PTR: { - Parser_FreeNode(node->ptr.inner); - free(node->ptr.inner); - break; - } - case NODE_FUNC_DEF: { - if (node->funcDef.dec.ret) { - Parser_FreeNode(node->funcDef.dec.ret); - free(node->funcDef.dec.ret); - } - - for (size_t i = 0; i < node->funcDef.dec.paramsNum; ++ i) { - Parser_FreeNode(node->funcDef.dec.params[i].type); - free(node->funcDef.dec.params[i].type); - } - - free(node->funcDef.dec.name); - - for (size_t i = 0; i < node->funcDef.bodyLen; ++ i) { - Parser_FreeNode(&node->funcDef.body[i]); - } - free(node->funcDef.body); - break; - } - case NODE_DIM: { - free(node->dim.name); - Parser_FreeNode(node->dim.varType); - free(node->dim.varType); - break; - } - case NODE_FUNC_CALL: { - free(node->funcCall.func); - - for (size_t i = 0; i < node->funcCall.paramsNum; ++ i) { - Parser_FreeNode(&node->funcCall.params[i]); - } - free(node->funcCall.params); - break; - } - case NODE_ASSIGN: { - free(node->assign.variable); - Parser_FreeNode(node->assign.rValue); - free(node->assign.rValue); - break; - } - default: return; - } -} - -const char* Parser_TypeStr(NodeType type) { - switch (type) { - case NODE_NONE: return "none"; - case NODE_INT: return "int"; - case NODE_STRING: return "string"; - case NODE_IDENTIFIER: return "identifier"; - case NODE_BINARY_OP: return "binary operation"; - case NODE_UNARY_OP: return "unary operation"; - case NODE_PTR: return "ptr"; - case NODE_FUNC_DEF: return "function definition"; - case NODE_DIM: return "dim"; - case NODE_FUNC_CALL: return "function call"; - case NODE_ASSIGN: return "assignment"; - default: return "???"; - } -} diff --git a/basic-boot/source/parser.h b/basic-boot/source/parser.h deleted file mode 100644 index 9e643df70c4de70613cbcd791b17f86efca21126..0000000000000000000000000000000000000000 --- a/basic-boot/source/parser.h +++ /dev/null @@ -1,127 +0,0 @@ -#ifndef N_PARSER_H -#define N_PARSER_H - -#include "lexer.h" -#include "error.h" -#include "common.h" - -typedef enum { - NODE_NONE, - NODE_INT, - NODE_STRING, - NODE_IDENTIFIER, - NODE_BINARY_OP, - NODE_UNARY_OP, - NODE_PTR, - NODE_FUNC_DEF, - NODE_DIM, - NODE_FUNC_CALL, - NODE_ASSIGN -} NodeType; - -typedef struct { - NodeType type; - ErrorInfo err; -} NodeInfo; - -typedef union Node Node; - -typedef struct { - NodeInfo i; - int value; -} IntNode; - -typedef struct { - NodeInfo i; - char* value; -} StringNode; - -typedef struct { - NodeInfo i; - char* name; -} IdentifierNode; - -typedef struct { - NodeInfo i; - Node* left; - Node* right; - TokenType op; -} BinaryNode; - -typedef struct { - NodeInfo i; - Node* operand; - TokenType op; -} UnaryNode; - -typedef struct { - NodeInfo i; - Node* inner; -} PtrNode; - -typedef struct { - Node* type; - char* name; -} FuncDecParam; - -typedef struct { - FuncDecParam* params; - size_t paramsNum; - Node* ret; - char* name; -} FuncDec; - -typedef struct { - NodeInfo i; - FuncDec dec; - Node* body; - size_t bodyLen; -} FuncDefNode; - -typedef struct { - NodeInfo i; - char* name; - Node* varType; -} DimNode; - -typedef struct { - NodeInfo i; - char* func; - Node* params; - size_t paramsNum; -} FuncCallNode; - -typedef struct { - NodeInfo i; - char* variable; - Node* rValue; -} AssignNode; - -union Node { - NodeInfo i; - IntNode integer; - StringNode string; - IdentifierNode ident; - BinaryNode bin; - UnaryNode unary; - PtrNode ptr; - FuncDefNode funcDef; - DimNode dim; - FuncCallNode funcCall; - AssignNode assign; -}; - -typedef struct { - Token* tokens; - size_t tokenNum; - size_t i; -} Parser; - -Parser Parser_Init(FILE* file, const char* fileName, bool printTokens); -void Parser_PrintNode(Node* node); -Node* Parser_Parse(Parser* p, size_t* lenOut); -void Parser_FreeNode(Node* node); - -const char* Parser_TypeStr(NodeType type); - -#endif diff --git a/basic-boot/source/semanticAnalysis.c b/basic-boot/source/semanticAnalysis.c deleted file mode 100644 index c275153bb71bcc85fc06e2e5a9372f795796eb04..0000000000000000000000000000000000000000 --- a/basic-boot/source/semanticAnalysis.c +++ /dev/null @@ -1,382 +0,0 @@ -#include <assert.h> -#include <string.h> -#include "mem.h" -#include "util.h" -#include "error.h" -#include "state.h" -#include "parser.h" -#include "semanticAnalysis.h" - -void SemanticAnalysis_Init(size_t wordSize) { - State_Init(); - - // add primitive types - State_MakePrimitive("u8", 1, PRIM_UINT); - State_MakePrimitive("i8", 1, PRIM_INT); - State_MakePrimitive("u16", 2, PRIM_UINT); - State_MakePrimitive("i16", 2, PRIM_INT); - State_MakePrimitive("u32", 4, PRIM_UINT); - State_MakePrimitive("i32", 4, PRIM_INT); - State_MakePrimitive("u64", 8, PRIM_UINT); - State_MakePrimitive("i64", 8, PRIM_INT); - State_MakePrimitive("uint", wordSize, PRIM_UINT); - State_MakePrimitive("int", wordSize, PRIM_INT); - State_MakePrimitive("char", 1, PRIM_UINT); - State_MakePrimitive("f32", 4, PRIM_FLOAT); - State_MakePrimitive("f64", 8, PRIM_FLOAT); - State_MakePrimitive("bool", 1, PRIM_UINT); - State_MakePrimitive("__lit", 0, PRIM_INT); - - Type type; - type.name = NewString("unit"); - type.type = TYPE_UNIT; - State_AddType(type); -} - -void Expect(Node* node, NodeType type) { - if (node->i.type != type) { - PrintError(node->i.err, - "Expected %s, got %s", Parser_TypeStr(type), - Parser_TypeStr(node->i.type) - ); - } -} - -void Unexpected(Node* node) { - PrintError(node->i.err, "Unexpected %s", Parser_TypeStr(node->i.type)); -} - -static UsedType NodeAsUsedType(Node* node) { - UsedType ret; - ret.ptr = 0; - ret.array = false; // no arrays yet - - while (true) { - switch (node->i.type) { - case NODE_PTR: { - node = node->ptr.inner; - ++ ret.ptr; - continue; - } - case NODE_IDENTIFIER: { - Type* type = State_GetType(node->ident.name); - - if (!type) { - PrintError(node->i.err, "Type '%s' does not exist", node->ident.name); - } - - ret.typeIdx = type - state.types; - return ret; - } - default: { - Unexpected(node); - exit(1); - } - } - } -} - -static Type* GetTypeFromUsed(UsedType type) { - return &state.types[type.typeIdx]; -} - -#define GET_PRIM(NAME, PTR) \ - ((UsedType) {(PTR), State_GetType(NAME) - state.types, 0}) - -static UsedType EvalType(Node* node); - -static UsedType EvalBinOp(Node* node) { - UsedType left = EvalType(node->bin.left); - UsedType right = EvalType(node->bin.right); - - Type* leftType = GetTypeFromUsed(left); - Type* rightType = GetTypeFromUsed(right); - - if ((leftType->type != TYPE_PRIM) || (rightType->type != TYPE_PRIM)) { - PrintError(node->i.err, "You can only use primitive types in binary expressions"); - } - - if (left.ptr) { - if (right.ptr) { - switch (node->bin.op) { - case TOKEN_EQUAL: - case TOKEN_LESS: - case TOKEN_GREATER: return GET_PRIM("bool", 0); - case TOKEN_SUB: return GET_PRIM("uint", 0); - default: { - PrintError( - node->i.err, "Operation '%s' not allowed here", - Lexer_TypeVAsString(node->bin.op) - ); - } - } - } - else { - switch (node->bin.op) { - case TOKEN_ADD: - case TOKEN_SUB: { - if (rightType->primType == PRIM_FLOAT) { - PrintError(node->i.err, "Cannot add float to pointer"); - } - return left; - } - default: { - PrintError( - node->i.err, "Operation '%s' not allowed here", - Lexer_TypeVAsString(node->bin.op) - ); - } - } - } - } - else if (right.ptr) { - switch (node->bin.op) { - case TOKEN_ADD: - case TOKEN_SUB: { - if (leftType->primType == PRIM_FLOAT) { - PrintError(node->i.err, "Cannot add float to pointer"); - } - return right; - } - default: { - PrintError( - node->i.err, "Operation '%s' not allowed here", - Lexer_TypeVAsString(node->bin.op) - ); - } - } - } - else if (!right.ptr) { - switch (node->bin.op) { - case TOKEN_EQUAL: return GET_PRIM("bool", 0); - case TOKEN_LESS: - case TOKEN_GREATER: { - if ((leftType->type != TYPE_PRIM) || (rightType->type != TYPE_PRIM)) { - PrintError( - node->i.err, "Operation '%s' only works on primitives", - Lexer_TypeVAsString(node->bin.op) - ); - } - return GET_PRIM("bool", 0); - } - case TOKEN_ADD: - case TOKEN_SUBTRACT: - case TOKEN_MULTIPLY: - case TOKEN_DIVIDE: - case TOKEN_MOD: { - if ((leftType->type != TYPE_PRIM) || (rightType->type != TYPE_PRIM)) { - PrintError( - node->i.err, "Operation '%s' only works on primitives", - Lexer_TypeVAsString(node->bin.op) - ); - } - - if (leftType->primType == rightType->primType) { - if (leftType->size > rightType->size) { - return left; - } - else { - return right; - } - } - else { - PrintError( - node->i.err, "Incompatible types in '%s' operation", - Lexer_TypeVAsString(node->bin.op) - ); - } - } - default: break; - } - - PrintError( - node->i.err, "Operation '%s' not allowed here", - Lexer_TypeVAsString(node->bin.op) - ); - } - - exit(1); -} - -static UsedType EvalType(Node* node) { - static bool inFunc = false; - - switch (node->i.type) { - case NODE_INT: return GET_PRIM("__lit", 0); - case NODE_STRING: return GET_PRIM("char", 1); - case NODE_IDENTIFIER: { - Var* var = State_GetVar(node->ident.name); - - if (!var) { - PrintError( - node->i.err, "Variable '%s' doesn't exist", node->ident.name - ); - } - - return var->type; - } - case NODE_BINARY_OP: return EvalBinOp(node); - case NODE_UNARY_OP: { - UsedType operand = EvalType(node->unary.operand); - Type* type = GetTypeFromUsed(operand); - - if (type->type != TYPE_PRIM) { - PrintError(node->i.err, - "Only primitive types can be used with unary operators" - ); - } - - if ((type->primType == PRIM_UINT) && (node->unary.op == TOKEN_SUBTRACT)) { - PrintWarning(node->i.err, "Using negative sign on unsigned value"); - } - - return operand; - } - case NODE_PTR: { - UsedType type = EvalType(node->ptr.inner); - ++ type.ptr; - return type; - } - case NODE_FUNC_DEF: { - if (inFunc) { - PrintError(node->i.err, "Nested function definitions are not allowed"); - } - - Function func; - func.sub = node->funcDef.dec.ret != NULL; - - if (!func.sub) { - func.ret = NodeAsUsedType(node->funcDef.dec.ret); - } - - func.paramsLen = node->funcDef.dec.paramsNum; - func.params = SafeMalloc(func.paramsLen * sizeof(FuncParam)); - - for (size_t i = 0; i < func.paramsLen; ++ i) { - func.params[i].type = NodeAsUsedType( - node->funcDef.dec.params[i].type - ); - func.params[i].name = node->funcDef.dec.params[i].name; - } - - func.name = NewString(node->funcDef.dec.name); - State_AddFunc(func); - - // now analyse the body - State_AddScope(); - inFunc = true; - - // add parameters to this scope - for (size_t i = 0; i < func.paramsLen; ++ i) { - Var var; - var.type = func.params[i].type; - var.name = NewString(func.params[i].name); - State_AddVar(var); - } - - for (size_t i = 0; i < node->funcDef.bodyLen; ++ i) { - EvalType(&node->funcDef.body[i]); - } - inFunc = false; - State_FreeScope(); - return GET_PRIM("unit", 0); - } - case NODE_FUNC_CALL: { - Function* func = State_GetFunc(node->funcCall.func); - if (!func) { - PrintError(node->i.err, "Function %s does not exist", node->funcCall.func); - } - - if (func->paramsLen != node->funcCall.paramsNum) { - PrintError( - node->i.err, "Expected %d parameters, got %d", - func->paramsLen, node->funcCall.paramsNum - ); - } - - for (size_t i = 0; i < func->paramsLen; ++ i) { - UsedType type = EvalType(&node->funcCall.params[i]); - UsedType param = func->params[i].type; - Type* paramType = GetTypeFromUsed(param); - Type* callType = GetTypeFromUsed(type); - - bool paramLit = strcmp(callType->name, "__lit") == 0; - - if (!State_UsedTypeEq(type, param)) { - if ( - (callType->type == TYPE_PRIM) && (paramType->type == TYPE_PRIM) && - (callType->primType == paramType->primType) && - (paramType->size >= callType->size) - ) { - continue; - } - - if (paramLit && (paramType->type == TYPE_PRIM)) continue; - - PrintError(node->i.err, - "Expected %s for parameter %s, got %s", - paramType->name, func->params[i].name, callType->name - ); - } - } - - if (func->sub) { - return GET_PRIM("unit", 0); - } - else { - return func->ret; - } - } - case NODE_DIM: { - Var var; - var.type = NodeAsUsedType(node->dim.varType); - var.name = NewString(node->dim.name); - State_AddVar(var); - return GET_PRIM("unit", 0); - } - case NODE_ASSIGN: { - Var* var = State_GetVar(node->assign.variable); - - if (!var) { - PrintError( - node->i.err, "Variable '%s' doesn't exist", - node->assign.variable - ); - } - - UsedType left = var->type; - UsedType right = EvalType(node->assign.rValue); - - Type* leftType = GetTypeFromUsed(left); - Type* rightType = GetTypeFromUsed(right); - - bool compatible = true; - - if ((left.ptr != right.ptr) || (leftType->type != rightType->type)) { - compatible = false; - } - else if (leftType->type == TYPE_PRIM) { - if (leftType->primType != rightType->primType) compatible = false; - else if (leftType->size < rightType->size) compatible = false; - } - - if (!compatible) { - PrintError( - node->i.err, "Type '%s' cannot be assigned to '%s' variable", - GetTypeFromUsed(left)->name, GetTypeFromUsed(right)->name - ); - } - - return GET_PRIM("unit", 0); - } - default: { - Unexpected(node); - } - } - - assert(0); -} - -void SemanticAnalysis_Analyse(Node* node) { - EvalType(node); -} diff --git a/basic-boot/source/semanticAnalysis.h b/basic-boot/source/semanticAnalysis.h deleted file mode 100644 index 341ccb8ac4a96ebcd1d94b58b4aad9fa914a881e..0000000000000000000000000000000000000000 --- a/basic-boot/source/semanticAnalysis.h +++ /dev/null @@ -1,9 +0,0 @@ -#ifndef N_SEMANTIC_ANALYSIS_H -#define N_SEMANTIC_ANALYSIS_H - -#include "common.h" - -void SemanticAnalysis_Init(size_t wordSize); -void SemanticAnalysis_Analyse(Node* node); - -#endif diff --git a/basic-boot/source/state.c b/basic-boot/source/state.c deleted file mode 100644 index c2d901ca81d47638cf32a652631f8562859bda74..0000000000000000000000000000000000000000 --- a/basic-boot/source/state.c +++ /dev/null @@ -1,127 +0,0 @@ -#include <stdio.h> -#include <string.h> -#include "mem.h" -#include "util.h" -#include "state.h" - -State state; - -void State_Init(void) { - state.types = NULL; - state.typeNum = 0; - state.scopes[0] = NULL; - state.scopeSize[0] = 0; - state.scopeNum = 1; - state.funcs = NULL; - state.funcNum = 0; -} - -void State_AddType(Type type) { - ++ state.typeNum; - state.types = SafeRealloc(state.types, state.typeNum * sizeof(Type)); - state.types[state.typeNum - 1] = type; -} - -void State_AddVar(Var var) { - size_t scope = state.scopeNum - 1; - - ++ state.scopeSize[scope]; - state.scopes[scope] = SafeRealloc( - state.scopes[scope], state.scopeSize[scope] * sizeof(Var) - ); - state.scopes[scope][state.scopeSize[scope] - 1] = var; -} - -bool State_AddScope(void) { - if (state.scopeNum >= 16) return false; - - ++ state.scopeNum; - state.scopeSize[state.scopeNum - 1] = 0; - state.scopes[state.scopeNum - 1] = NULL; - return true; -} - -void State_AddFunc(Function func) { - ++ state.funcNum; - state.funcs = SafeRealloc(state.funcs, state.funcNum * sizeof(Function)); - state.funcs[state.funcNum - 1] = func; -} - -void State_FreeScope(void) { - Var* scope = state.scopes[state.scopeNum - 1]; - size_t scopeNum = state.scopeSize[state.scopeNum - 1]; - - for (size_t i = 0; i < scopeNum; ++ i) { - free(scope[i].name); - } - - -- state.scopeNum; -} - -Var* State_GetVar(const char* name) { - for (size_t i = state.scopeNum; i --> 0;) { - for (size_t j = 0; j < state.scopeSize[i]; ++ j) { - if (strcmp(state.scopes[i][j].name, name) == 0) { - return &state.scopes[i][j]; - } - } - } - - return NULL; -} - -Type* State_GetType(const char* name) { - for (size_t i = 0; i < state.typeNum; ++ i) { - if (strcmp(state.types[i].name, name) == 0) { - return &state.types[i]; - } - } - - return NULL; -} - -Function* State_GetFunc(const char* name) { - for (size_t i = 0; i < state.funcNum; ++ i) { - if (strcmp(state.funcs[i].name, name) == 0) { - return &state.funcs[i]; - } - } - - return NULL; -} - -void State_MakePrimitive(const char* name, size_t size, int primType) { - Type type; - type.type = TYPE_PRIM; - type.name = NewString(name); - type.size = size; - type.primType = primType; - State_AddType(type); -} - -bool State_UsedTypeEq(UsedType a, UsedType b) { - return (a.ptr == b.ptr) && (a.typeIdx == b.typeIdx) && (a.array == b.array); -} - -void State_DumpInfo(void) { - puts("TYPES"); - puts("====="); - for (size_t i = 0; i < state.typeNum; ++ i) { - printf("- %s\n", state.types[i].name); - } - puts("\n"); - - puts("GLOBALS"); - puts("======="); - for (size_t i = 0; i < state.scopeSize[0]; ++ i) { - printf("- %s\n", state.scopes[0][i].name); - } - puts("\n"); - - puts("FUNCTIONS"); - puts("========="); - for (size_t i = 0; i < state.funcNum; ++ i) { - printf("- %s\n", state.funcs[i].name); - } - puts("\n"); -} diff --git a/basic-boot/source/state.h b/basic-boot/source/state.h deleted file mode 100644 index bff6a6faeea769784107c85cb53b3b8e1e1da066..0000000000000000000000000000000000000000 --- a/basic-boot/source/state.h +++ /dev/null @@ -1,80 +0,0 @@ -#ifndef N_STATE_H -#define N_STATE_H - -#include "common.h" - -enum { - TYPE_PRIM, // is this "primitive", or Primula the manul? - TYPE_STRUCT, - TYPE_UNIT -}; - -enum { - PRIM_UINT, - PRIM_INT, - PRIM_FLOAT -}; - -typedef struct { - size_t ptr; - size_t typeIdx; - size_t array; // 0 if not array, contains length if not array -} UsedType; - -typedef struct { - int type; - char* name; - size_t size; - - // only for "struct" types - UsedType* structure; - size_t structLen; - - // only for "primitive" types - int primType; -} Type; - -typedef struct { - UsedType type; - char* name; -} Var; - -typedef struct { - UsedType type; - char* name; -} FuncParam; - -typedef struct { - bool sub; - UsedType ret; - FuncParam* params; - size_t paramsLen; - char* name; -} Function; - -typedef struct { - Type* types; - size_t typeNum; - Var* scopes[16]; - size_t scopeSize[16]; - size_t scopeNum; - Function* funcs; - size_t funcNum; -} State; - -extern State state; - -void State_Init(void); -void State_AddType(Type type); -void State_AddVar(Var var); -bool State_AddScope(void); -void State_AddFunc(Function func); -void State_FreeScope(void); -Var* State_GetVar(const char* name); -Type* State_GetType(const char* name); -Function* State_GetFunc(const char* name); -void State_MakePrimitive(const char* name, size_t size, int primType); -bool State_UsedTypeEq(UsedType a, UsedType b); -void State_DumpInfo(void); - -#endif diff --git a/basic-boot/source/string.c b/basic-boot/source/string.c deleted file mode 100644 index 7e42275935d2fa0e7044dae2263a0c206aadf2de..0000000000000000000000000000000000000000 --- a/basic-boot/source/string.c +++ /dev/null @@ -1,48 +0,0 @@ -#include <stdio.h> -#include <string.h> -#include "mem.h" -#include "string.h" - -String String_New(void) { - char* contents = SafeMalloc(1); - *contents = 0; - - return (String) { - contents, 1 - }; -} - -String String_FromChar(char ch) { - String ret = String_New(); - String_AddChar(&ret, ch); - return ret; -} - -void String_Free(String* string) { - free(string->contents); -} - -void String_Add(String* string, char* value) { - size_t newLen = strlen(string->contents) + strlen(value) + 1; - size_t newCap = string->capacity; - - while (newCap < newLen) { - newCap *= 2; - } - - if (newCap != string->capacity) { - string->capacity = newCap; - string->contents = SafeRealloc(string->contents, newCap); - } - - strcat(string->contents, value); -} - -void String_AddChar(String* string, char ch) { - char str[] = {ch, 0}; - String_Add(string, str); -} - -size_t String_Len(String* string) { - return strlen(string->contents); -} diff --git a/basic-boot/source/string.h b/basic-boot/source/string.h deleted file mode 100644 index 98e30f87cba52e57745b1493d7be6621416d8936..0000000000000000000000000000000000000000 --- a/basic-boot/source/string.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef N_STRING_H -#define N_STRING_H - -#include "common.h" - -typedef struct { - char* contents; - size_t capacity; -} String; - -String String_New(void); -String String_FromChar(char ch); -void String_Free(String* string); -void String_Add(String* string, char* value); -void String_AddChar(String* string, char ch); -size_t String_Len(String* string); - -#endif diff --git a/basic-boot/source/util.c b/basic-boot/source/util.c deleted file mode 100644 index 3524bb0b4c307b7a93a3b07c1c2c13fe438d9956..0000000000000000000000000000000000000000 --- a/basic-boot/source/util.c +++ /dev/null @@ -1,16 +0,0 @@ -#include <string.h> -#include "mem.h" -#include "common.h" - -char* NewString(const char* src) { - char* ret = SafeMalloc(strlen(src) + 1); - strcpy(ret, src); - return ret; -} - -char* ConcatString(const char* first, const char* second) { - char* ret = SafeMalloc(strlen(first) + strlen(second) + 1); - strcpy(ret, first); - strcat(ret, second); - return ret; -} diff --git a/basic-boot/source/util.h b/basic-boot/source/util.h deleted file mode 100644 index aa57880a037cf533331c0e4cdedfcef4953b4465..0000000000000000000000000000000000000000 --- a/basic-boot/source/util.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef N_UTIL_H -#define N_UTIL_H - -#include <stdio.h> - -#define FUNCTION_POINTER(TYPE, NAME, ...) TYPE (*NAME)(__VA_ARGS__) -#define MIN(A, B) (((A) < (B))? (A) : (B)) -#define MAX(A, B) (((A) > (B))? (A) : (B)) - -#define SWAP(TYPE, A, B) \ - do { \ - TYPE* macro##a = &(A); \ - TYPE* macro##b = &(B); \ - TYPE macro##tmp = *macro##a; \ - *macro##a = *macro##b; \ - *macro##b = macro##tmp; \ - } while (0); - -char* NewString(const char* src); -char* ConcatString(const char* first, const char* second); - -#endif diff --git a/basic-boot/test.bas b/basic-boot/test.bas deleted file mode 100644 index af13a8b74c4cbcb49dd5ac303c39c0578ebf48fb..0000000000000000000000000000000000000000 --- a/basic-boot/test.bas +++ /dev/null @@ -1,20 +0,0 @@ -'NITRON - -dim foo as int - -func manul(foo as int, bar as int) int - dim bar as u32 -end - -manul 1, (2 * 3) + -5 * 4 - -foo = 3 + 4 - -dim a as int -dim b as f32 -dim c as int - -manul a + c, 5 - -dim myPtr as ptr(int) -myPtr = myPtr * 5