diff --git a/assert.h b/assert.h new file mode 100644 index 0000000..48beede --- /dev/null +++ b/assert.h @@ -0,0 +1,7 @@ +#pragma once + +#if defined(__dreamcast__) +#include "assert_dreamcast.h" +#else +#include "assert_hosted.h" +#endif diff --git a/assert_dreamcast.h b/assert_dreamcast.h new file mode 100644 index 0000000..62158df --- /dev/null +++ b/assert_dreamcast.h @@ -0,0 +1,41 @@ +#pragma once + +#include "printf.h" +#include "class_file.h" + +#define assert(b) \ + do { \ + if (!(b)) { \ + printf("%s:%d %s: assertion `%s` failed\n", __FILE__, __LINE__, __func__, #b); \ + while (1); \ + } \ + } while (0); + +static inline void assert_print_string(struct constant * constant) +{ + for (int i = 0; i < constant->utf8.length; i++) { + printc(constant->utf8.bytes[i]); + } + printc('\n'); +} + +#define assertvm(vm, b) \ +do { \ + if (!(b)) { \ + printf("%s:%d %s: vm assertion `%s` failed\n", __FILE__, __LINE__, __func__, #b); \ + \ + struct class_entry * class_entry = vm->current_frame->class_entry; \ + struct constant * class_constant = &class_entry->class_file->constant_pool[class_entry->class_file->this_class - 1]; \ + assert(class_constant->tag == CONSTANT_Class); \ + struct constant * class_name_constant = &class_entry->class_file->constant_pool[class_constant->class.name_index - 1]; \ + assert(class_name_constant->tag == CONSTANT_Utf8); \ + assert_print_string(class_name_constant); \ + \ + struct method_info * method_info = vm->current_frame->method; \ + struct constant * method_name_constant = &class_entry->class_file->constant_pool[method_info->name_index - 1]; \ + assert(method_name_constant->tag == CONSTANT_Utf8); \ + assert_print_string(method_name_constant); \ + \ + while (1); \ + } \ + } while (0); diff --git a/assert_hosted.h b/assert_hosted.h new file mode 100644 index 0000000..09dc5c0 --- /dev/null +++ b/assert_hosted.h @@ -0,0 +1,16 @@ +#pragma once + +extern void __assert_fail (const char *__assertion, const char *__file, + unsigned int __line, const char *__function) + __attribute__ ((__noreturn__)); + +#define __ASSERT_FUNCTION __func__ + +#define assert(expr) \ + ({ \ + if (!(expr)) \ + __assert_fail (#expr, __FILE__, __LINE__, __ASSERT_FUNCTION); \ + }) + +#define fail(expr) \ + (__assert_fail (#expr, __FILE__, __LINE__, __ASSERT_FUNCTION);) diff --git a/ast.h b/ast.h new file mode 100644 index 0000000..982c95d --- /dev/null +++ b/ast.h @@ -0,0 +1,47 @@ +#pragma once + +struct token; + +struct expression { + struct token * constant; +}; + +enum statement_type { + STATEMENT_RETURN, + STATEMENT_IF, + STATEMENT_IF_ELSE, +}; + +struct statement; + +struct statement_return { + struct expression * expression; +}; + +struct statement_if { + struct expression * expression; + struct statement * statement; +}; + +struct statement_if_else { + struct expression * expression; + struct statement * statement; +}; + +struct statement { + enum statement_type type; + union { + struct statement_return * statement_return; + struct statement_if * statement_if; + struct statement_if_else * statement_if_else; + }; +}; + +struct function_definition { + struct token * name; + struct statement * statements; +}; + +struct program { + struct function_definition * function_definition; +}; diff --git a/grammar.txt b/grammar.txt new file mode 100644 index 0000000..35763a8 --- /dev/null +++ b/grammar.txt @@ -0,0 +1,7 @@ + ::= + ::= "int" "(" "void" ")" "{" "}" + ::= "return" ";" | "if" "(" ")" [ "else" ] + ::= "return" ";" + ::= + ::= ? An identifier token ? + ::= ? A constant token ? diff --git a/malloc.c b/malloc.c new file mode 100644 index 0000000..88433d4 --- /dev/null +++ b/malloc.c @@ -0,0 +1,33 @@ +#include "assert.h" +#include "malloc.h" + +struct arena { + uint8_t * mem; + uint32_t size; + uint32_t ix; +}; + +static uint8_t class_mem[0x100000]; + +struct arena class_arena = { + .mem = class_mem, + .size = (sizeof (class_mem)), + .ix = 0, +}; + +void malloc_class_arena_reset() +{ + class_arena.ix = 0; +} + +void * malloc_class_arena(uint32_t size) +{ + if (size == 0) + return nullptr; + + assert((class_arena.ix & (~3)) == class_arena.ix); + void * ptr = &class_arena.mem[class_arena.ix]; + size = (size + 3) & (~3); + class_arena.ix += size; + return ptr; +} diff --git a/parser.c b/parser.c new file mode 100644 index 0000000..2de949d --- /dev/null +++ b/parser.c @@ -0,0 +1,35 @@ +#include "parser.h" +#include "lexer.h" +#include "assert.h" + +struct token_reader { + bool have_token; + struct token token; + struct lexer_state lexer_state; +}; + +struct token peek(struct token_reader * reader) +{ + if (reader->have_token) { + return reader->token; + } else { + reader->token = lexer_next_token(reader->lexer_state); + reader->have_token = true; + return reader->token; + } +} + +struct token consume(struct token_reader * reader) +{ + struct token token = peek(reader); + reader->have_token = false; +} + +void expect_type(struct token_reader * reader, enum token_type token_type) +{ + struct token token = consume(reader); + if (!(token->type == token_type)) { + printf("token->type=%d token_type=%d\n", token->type, token_type); + fail(token->type == token_type); + } +}