WIP allocator for compiler.
This commit is contained in:
parent
6310390cc4
commit
373caf7b5e
|
|
@ -0,0 +1,33 @@
|
|||
# Plan 9 coding conventions for C (http://man.9front.org/6/style)
|
||||
BasedOnStyle: LLVM
|
||||
IndentWidth: 2
|
||||
TabWidth: 2
|
||||
UseTab: Always
|
||||
|
||||
SpaceBeforeParens: Never
|
||||
SpaceBeforeAssignmentOperators: true
|
||||
AllowShortIfStatementsOnASingleLine: WithoutElse
|
||||
AllowShortLoopsOnASingleLine: true
|
||||
RemoveBracesLLVM: true
|
||||
|
||||
BreakBeforeBraces: Custom
|
||||
BraceWrapping:
|
||||
AfterCaseLabel: false
|
||||
AfterClass: false
|
||||
AfterControlStatement: Never
|
||||
AfterEnum: false
|
||||
AfterFunction: true
|
||||
AfterNamespace: false
|
||||
AfterStruct: false
|
||||
AfterUnion: false
|
||||
AfterExternBlock: false
|
||||
BeforeCatch: false
|
||||
BeforeElse: false
|
||||
IndentBraces: false
|
||||
AlwaysBreakAfterReturnType: TopLevelDefinitions
|
||||
DerivePointerAlignment: false
|
||||
PointerAlignment: Right
|
||||
AlignOperands: Align
|
||||
AlignAfterOpenBracket: Align
|
||||
SortIncludes: Never
|
||||
IndentCaseLabels: false
|
||||
214
lexer.c
214
lexer.c
|
|
@ -2,51 +2,73 @@
|
|||
|
||||
#include "lexer.h"
|
||||
|
||||
typedef struct {
|
||||
typedef struct lexer_s Lexer;
|
||||
struct lexer_s {
|
||||
const char *start;
|
||||
const char *current;
|
||||
i32 line;
|
||||
} Lexer;
|
||||
};
|
||||
|
||||
Lexer lexer;
|
||||
|
||||
void init_lexer(const char *source) {
|
||||
void
|
||||
init_lexer(const char *source)
|
||||
{
|
||||
lexer.start = source;
|
||||
lexer.current = source;
|
||||
lexer.line = 1;
|
||||
}
|
||||
|
||||
static bool is_alpha(char c) {
|
||||
static bool
|
||||
is_alpha(char c)
|
||||
{
|
||||
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_';
|
||||
}
|
||||
|
||||
static bool is_digit(char c) { return c >= '0' && c <= '9'; }
|
||||
static bool
|
||||
is_digit(char c)
|
||||
{
|
||||
return c >= '0' && c <= '9';
|
||||
}
|
||||
|
||||
static bool is_at_end() { return *lexer.current == '\0'; }
|
||||
static bool
|
||||
is_at_end()
|
||||
{
|
||||
return *lexer.current == '\0';
|
||||
}
|
||||
|
||||
static char advance() {
|
||||
static char
|
||||
advance()
|
||||
{
|
||||
lexer.current++;
|
||||
return lexer.current[-1];
|
||||
}
|
||||
|
||||
char peek() { return *lexer.current; }
|
||||
char
|
||||
peek()
|
||||
{
|
||||
return *lexer.current;
|
||||
}
|
||||
|
||||
static char peek_next() {
|
||||
if (is_at_end())
|
||||
return '\0';
|
||||
static char
|
||||
peek_next()
|
||||
{
|
||||
if(is_at_end()) return '\0';
|
||||
return lexer.current[1];
|
||||
}
|
||||
|
||||
static bool match(char expected) {
|
||||
if (is_at_end())
|
||||
return false;
|
||||
if (*lexer.current != expected)
|
||||
return false;
|
||||
static bool
|
||||
match(char expected)
|
||||
{
|
||||
if(is_at_end()) return false;
|
||||
if(*lexer.current != expected) return false;
|
||||
lexer.current++;
|
||||
return true;
|
||||
}
|
||||
|
||||
static Token make_token(TokenType type) {
|
||||
static Token
|
||||
make_token(TokenType type)
|
||||
{
|
||||
Token token;
|
||||
token.type = type;
|
||||
token.start = lexer.start;
|
||||
|
|
@ -55,7 +77,9 @@ static Token make_token(TokenType type) {
|
|||
return token;
|
||||
}
|
||||
|
||||
static Token error_token(const char *message) {
|
||||
static Token
|
||||
error_token(const char *message)
|
||||
{
|
||||
Token token;
|
||||
token.type = TOKEN_ERROR;
|
||||
token.start = message;
|
||||
|
|
@ -64,10 +88,12 @@ static Token error_token(const char *message) {
|
|||
return token;
|
||||
}
|
||||
|
||||
static void skip_whitespace() {
|
||||
for (;;) {
|
||||
static void
|
||||
skip_whitespace()
|
||||
{
|
||||
for(;;) {
|
||||
char c = peek();
|
||||
switch (c) {
|
||||
switch(c) {
|
||||
case ' ':
|
||||
case '\r':
|
||||
case '\t':
|
||||
|
|
@ -78,19 +104,17 @@ static void skip_whitespace() {
|
|||
advance();
|
||||
break;
|
||||
case '/':
|
||||
if (peek_next() == '/') {
|
||||
if(peek_next() == '/') {
|
||||
// Single-line comment: skip until newline or end of file
|
||||
advance();
|
||||
while (peek() != '\n' && !is_at_end())
|
||||
advance();
|
||||
} else if (peek_next() == '*') {
|
||||
while(peek() != '\n' && !is_at_end()) advance();
|
||||
} else if(peek_next() == '*') {
|
||||
// Multi-line comment: skip until '*/' or end of file
|
||||
advance();
|
||||
advance();
|
||||
while (!is_at_end()) {
|
||||
if (peek() == '\n')
|
||||
lexer.line++;
|
||||
if (peek() == '*' && peek_next() == '/') {
|
||||
while(!is_at_end()) {
|
||||
if(peek() == '\n') lexer.line++;
|
||||
if(peek() == '*' && peek_next() == '/') {
|
||||
advance();
|
||||
advance();
|
||||
break; // Exit loop, comment ended
|
||||
|
|
@ -107,9 +131,10 @@ static void skip_whitespace() {
|
|||
}
|
||||
}
|
||||
|
||||
static TokenType check_keyword(i32 start, i32 length, const char *rest,
|
||||
TokenType type) {
|
||||
if (lexer.current - lexer.start == start + length &&
|
||||
static TokenType
|
||||
check_keyword(i32 start, i32 length, const char *rest, TokenType type)
|
||||
{
|
||||
if(lexer.current - lexer.start == start + length &&
|
||||
memcmp(lexer.start + start, rest, length) == 0) {
|
||||
return type;
|
||||
}
|
||||
|
|
@ -117,11 +142,13 @@ static TokenType check_keyword(i32 start, i32 length, const char *rest,
|
|||
return TOKEN_IDENTIFIER;
|
||||
}
|
||||
|
||||
static TokenType identifierType() {
|
||||
switch (lexer.start[0]) {
|
||||
static TokenType
|
||||
identifierType()
|
||||
{
|
||||
switch(lexer.start[0]) {
|
||||
case 'a':
|
||||
if (lexer.current - lexer.start > 1) {
|
||||
switch (lexer.start[1]) {
|
||||
if(lexer.current - lexer.start > 1) {
|
||||
switch(lexer.start[1]) {
|
||||
case 'n':
|
||||
return check_keyword(2, 1, "d", TOKEN_OPERATOR_AND);
|
||||
case 's':
|
||||
|
|
@ -130,8 +157,8 @@ static TokenType identifierType() {
|
|||
}
|
||||
break;
|
||||
case 'c':
|
||||
if (lexer.current - lexer.start > 1) {
|
||||
switch (lexer.start[1]) {
|
||||
if(lexer.current - lexer.start > 1) {
|
||||
switch(lexer.start[1]) {
|
||||
case 'l':
|
||||
return check_keyword(2, 3, "ose", TOKEN_KEYWORD_CLOSE);
|
||||
case 'o':
|
||||
|
|
@ -142,8 +169,8 @@ static TokenType identifierType() {
|
|||
case 'e':
|
||||
return check_keyword(1, 3, "lse", TOKEN_KEYWORD_ELSE);
|
||||
case 'f':
|
||||
if (lexer.current - lexer.start > 1) {
|
||||
switch (lexer.start[1]) {
|
||||
if(lexer.current - lexer.start > 1) {
|
||||
switch(lexer.start[1]) {
|
||||
case 'a':
|
||||
return check_keyword(2, 3, "lse", TOKEN_KEYWORD_FALSE);
|
||||
case 'o':
|
||||
|
|
@ -155,8 +182,8 @@ static TokenType identifierType() {
|
|||
}
|
||||
break;
|
||||
case 'i':
|
||||
if (lexer.current - lexer.start > 1) {
|
||||
switch (lexer.start[1]) {
|
||||
if(lexer.current - lexer.start > 1) {
|
||||
switch(lexer.start[1]) {
|
||||
case 'f':
|
||||
return check_keyword(2, 0, "", TOKEN_KEYWORD_IF);
|
||||
case 's':
|
||||
|
|
@ -168,8 +195,8 @@ static TokenType identifierType() {
|
|||
case '3':
|
||||
return check_keyword(2, 1, "2", TOKEN_TYPE_INT);
|
||||
case 'n':
|
||||
if (lexer.current - lexer.start > 2) {
|
||||
switch (lexer.start[2]) {
|
||||
if(lexer.current - lexer.start > 2) {
|
||||
switch(lexer.start[2]) {
|
||||
case 'i':
|
||||
return check_keyword(3, 2, "t", TOKEN_KEYWORD_INIT);
|
||||
case 't':
|
||||
|
|
@ -181,8 +208,8 @@ static TokenType identifierType() {
|
|||
}
|
||||
break;
|
||||
case 'n':
|
||||
if (lexer.current - lexer.start > 1) {
|
||||
switch (lexer.start[1]) {
|
||||
if(lexer.current - lexer.start > 1) {
|
||||
switch(lexer.start[1]) {
|
||||
case 'a':
|
||||
return check_keyword(2, 1, "t", TOKEN_TYPE_NAT);
|
||||
case 'i':
|
||||
|
|
@ -191,8 +218,8 @@ static TokenType identifierType() {
|
|||
}
|
||||
break;
|
||||
case 'o':
|
||||
if (lexer.current - lexer.start > 1) {
|
||||
switch (lexer.start[1]) {
|
||||
if(lexer.current - lexer.start > 1) {
|
||||
switch(lexer.start[1]) {
|
||||
case 'p':
|
||||
return check_keyword(2, 2, "en", TOKEN_KEYWORD_OPEN);
|
||||
case 'r':
|
||||
|
|
@ -201,8 +228,9 @@ static TokenType identifierType() {
|
|||
}
|
||||
break;
|
||||
case 'p':
|
||||
if (lexer.current - lexer.start > 1) {
|
||||
switch (lexer.start[1]) { case 't':
|
||||
if(lexer.current - lexer.start > 1) {
|
||||
switch(lexer.start[1]) {
|
||||
case 't':
|
||||
return check_keyword(2, 1, "r", TOKEN_TYPE_PTR);
|
||||
|
||||
case 'l':
|
||||
|
|
@ -211,15 +239,15 @@ static TokenType identifierType() {
|
|||
}
|
||||
break;
|
||||
case 'r':
|
||||
if (lexer.current - lexer.start > 1) {
|
||||
switch (lexer.start[1]) {
|
||||
if(lexer.current - lexer.start > 1) {
|
||||
switch(lexer.start[1]) {
|
||||
case 'e':
|
||||
if (lexer.current - lexer.start > 2) {
|
||||
switch (lexer.start[2]) {
|
||||
if(lexer.current - lexer.start > 2) {
|
||||
switch(lexer.start[2]) {
|
||||
case 't':
|
||||
return check_keyword(3, 3, "urn", TOKEN_KEYWORD_RETURN);
|
||||
case 'a':
|
||||
if (lexer.current - lexer.start > 3) {
|
||||
if(lexer.current - lexer.start > 3) {
|
||||
switch(lexer.start[3]) {
|
||||
case 'd':
|
||||
return check_keyword(4, 0, "", TOKEN_KEYWORD_READ);
|
||||
|
|
@ -234,11 +262,11 @@ static TokenType identifierType() {
|
|||
}
|
||||
break;
|
||||
case 's':
|
||||
if (lexer.current - lexer.start > 1) {
|
||||
switch (lexer.start[1]) {
|
||||
if(lexer.current - lexer.start > 1) {
|
||||
switch(lexer.start[1]) {
|
||||
case 't':
|
||||
if (lexer.current - lexer.start > 2) {
|
||||
switch (lexer.start[2]) {
|
||||
if(lexer.current - lexer.start > 2) {
|
||||
switch(lexer.start[2]) {
|
||||
case 'r':
|
||||
return check_keyword(3, 0, "", TOKEN_TYPE_STR);
|
||||
case 'a':
|
||||
|
|
@ -249,8 +277,8 @@ static TokenType identifierType() {
|
|||
}
|
||||
break;
|
||||
case 't':
|
||||
if (lexer.current - lexer.start > 1) {
|
||||
switch (lexer.start[1]) {
|
||||
if(lexer.current - lexer.start > 1) {
|
||||
switch(lexer.start[1]) {
|
||||
case 'h':
|
||||
return check_keyword(2, 2, "is", TOKEN_KEYWORD_THIS);
|
||||
case 'r':
|
||||
|
|
@ -259,8 +287,8 @@ static TokenType identifierType() {
|
|||
}
|
||||
break;
|
||||
case 'u':
|
||||
if (lexer.current - lexer.start > 1) {
|
||||
switch (lexer.start[1]) {
|
||||
if(lexer.current - lexer.start > 1) {
|
||||
switch(lexer.start[1]) {
|
||||
case 's':
|
||||
return check_keyword(2, 1, "e", TOKEN_KEYWORD_USE);
|
||||
case '8':
|
||||
|
|
@ -273,8 +301,8 @@ static TokenType identifierType() {
|
|||
}
|
||||
break;
|
||||
case 'w':
|
||||
if (lexer.current - lexer.start > 1) {
|
||||
switch (lexer.start[1]) {
|
||||
if(lexer.current - lexer.start > 1) {
|
||||
switch(lexer.start[1]) {
|
||||
case 'h':
|
||||
return check_keyword(2, 3, "ile", TOKEN_KEYWORD_WHILE);
|
||||
case 'r':
|
||||
|
|
@ -283,8 +311,8 @@ static TokenType identifierType() {
|
|||
}
|
||||
break;
|
||||
case 'b':
|
||||
if (lexer.current - lexer.start > 1) {
|
||||
switch (lexer.start[1]) {
|
||||
if(lexer.current - lexer.start > 1) {
|
||||
switch(lexer.start[1]) {
|
||||
case 'y':
|
||||
return check_keyword(2, 2, "te", TOKEN_TYPE_U8);
|
||||
case 'o':
|
||||
|
|
@ -305,23 +333,24 @@ static TokenType identifierType() {
|
|||
return TOKEN_IDENTIFIER;
|
||||
}
|
||||
|
||||
static Token identifier() {
|
||||
while (is_alpha(peek()) || is_digit(peek()))
|
||||
advance();
|
||||
static Token
|
||||
identifier()
|
||||
{
|
||||
while(is_alpha(peek()) || is_digit(peek())) advance();
|
||||
return make_token(identifierType());
|
||||
}
|
||||
|
||||
static Token number() {
|
||||
while (is_digit(peek()))
|
||||
advance();
|
||||
static Token
|
||||
number()
|
||||
{
|
||||
while(is_digit(peek())) advance();
|
||||
|
||||
/* Look for a fractional part. */
|
||||
if (peek() == '.' && is_digit(peek_next())) {
|
||||
if(peek() == '.' && is_digit(peek_next())) {
|
||||
/* Consume the ".". */
|
||||
advance();
|
||||
|
||||
while (is_digit(peek()))
|
||||
advance();
|
||||
while(is_digit(peek())) advance();
|
||||
|
||||
return make_token(TOKEN_LITERAL_REAL);
|
||||
}
|
||||
|
|
@ -329,36 +358,35 @@ static Token number() {
|
|||
return make_token(TOKEN_LITERAL_INT);
|
||||
}
|
||||
|
||||
static Token string() {
|
||||
while (peek() != '"' && !is_at_end()) {
|
||||
if (peek() == '\n')
|
||||
lexer.line++;
|
||||
static Token
|
||||
string()
|
||||
{
|
||||
while(peek() != '"' && !is_at_end()) {
|
||||
if(peek() == '\n') lexer.line++;
|
||||
advance();
|
||||
}
|
||||
|
||||
if (is_at_end())
|
||||
return error_token("Unterminated string.");
|
||||
if(is_at_end()) return error_token("Unterminated string.");
|
||||
|
||||
/* The closing quote. */
|
||||
advance();
|
||||
return make_token(TOKEN_LITERAL_STR);
|
||||
}
|
||||
|
||||
Token next_token() {
|
||||
Token
|
||||
next_token()
|
||||
{
|
||||
skip_whitespace();
|
||||
lexer.start = lexer.current;
|
||||
|
||||
if (is_at_end())
|
||||
return make_token(TOKEN_EOF);
|
||||
if(is_at_end()) return make_token(TOKEN_EOF);
|
||||
|
||||
char c = advance();
|
||||
if (is_alpha(c))
|
||||
return identifier();
|
||||
if(is_alpha(c)) return identifier();
|
||||
char next = peek();
|
||||
if ((c == '-' && is_digit(next)) || is_digit(c))
|
||||
return number();
|
||||
if((c == '-' && is_digit(next)) || is_digit(c)) return number();
|
||||
|
||||
switch (c) {
|
||||
switch(c) {
|
||||
case '(':
|
||||
return make_token(TOKEN_LPAREN);
|
||||
case ')':
|
||||
|
|
@ -406,8 +434,10 @@ Token next_token() {
|
|||
return error_token("Unexpected character.");
|
||||
}
|
||||
|
||||
const char *token_type_to_string(TokenType type) {
|
||||
switch (type) {
|
||||
const char *
|
||||
token_type_to_string(TokenType type)
|
||||
{
|
||||
switch(type) {
|
||||
case TOKEN_EOF:
|
||||
return "EOF";
|
||||
case TOKEN_IDENTIFIER:
|
||||
|
|
|
|||
7
lexer.h
7
lexer.h
|
|
@ -83,16 +83,17 @@ typedef enum {
|
|||
TOKEN_ARROW_RIGHT
|
||||
} TokenType;
|
||||
|
||||
typedef struct {
|
||||
typedef struct token_s Token;
|
||||
struct token_s {
|
||||
TokenType type;
|
||||
const char *start;
|
||||
i32 length;
|
||||
i32 line;
|
||||
} Token;
|
||||
};
|
||||
|
||||
void init_lexer(const char *source);
|
||||
Token next_token();
|
||||
const char* token_type_to_string(TokenType type);
|
||||
const char *token_type_to_string(TokenType type);
|
||||
char peek();
|
||||
|
||||
#endif
|
||||
|
|
|
|||
88
libc.c
88
libc.c
|
|
@ -1,35 +1,37 @@
|
|||
#include "libc.h"
|
||||
|
||||
void mcpy(void *to, void *from, u32 length) {
|
||||
void
|
||||
mcpy(void *to, void *from, u32 length)
|
||||
{
|
||||
u8 *src, *dest;
|
||||
if (to == nil || from == nil) return;
|
||||
if(to == nil || from == nil) return;
|
||||
|
||||
src = (u8 *)from;
|
||||
dest = (u8 *)to;
|
||||
|
||||
while (length-- > 0) {
|
||||
*(dest++) = *(src++);
|
||||
}
|
||||
while(length-- > 0) *(dest++) = *(src++);
|
||||
return;
|
||||
}
|
||||
|
||||
i32 scpy(char *to, const char *from, u32 length) {
|
||||
i32
|
||||
scpy(char *to, const char *from, u32 length)
|
||||
{
|
||||
u32 i;
|
||||
if (to == nil || from == nil) return -1;
|
||||
if (length == 0) {return 0;}
|
||||
for (i = 0; i < length - 1 && from[i] != '\0'; i++) {
|
||||
to[i] = from[i];
|
||||
}
|
||||
if(to == nil || from == nil) return -1;
|
||||
if(length == 0) return 0;
|
||||
for(i = 0; i < length - 1 && from[i] != '\0'; i++) to[i] = from[i];
|
||||
to[i] = '\0';
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool seq(const char *s1, const char *s2) {
|
||||
if (s1 == nil && s2 == nil) return true;
|
||||
if (s1 == nil || s2 == nil) return false;
|
||||
bool
|
||||
seq(const char *s1, const char *s2)
|
||||
{
|
||||
if(s1 == nil && s2 == nil) return true;
|
||||
if(s1 == nil || s2 == nil) return false;
|
||||
|
||||
while (*s1 && *s2) {
|
||||
if (*s1 != *s2) return false;
|
||||
while(*s1 && *s2) {
|
||||
if(*s1 != *s2) return false;
|
||||
s1++;
|
||||
s2++;
|
||||
}
|
||||
|
|
@ -37,36 +39,58 @@ bool seq(const char *s1, const char *s2) {
|
|||
return (*s1 == '\0' && *s2 == '\0');
|
||||
}
|
||||
|
||||
bool sleq(const char *s1, const char *s2, u32 length) {
|
||||
bool
|
||||
sleq(const char *s1, const char *s2, u32 length)
|
||||
{
|
||||
u32 i;
|
||||
if (s1 == nil && s2 == nil) return true;
|
||||
if (s1 == nil || s2 == nil) return false;
|
||||
if(s1 == nil && s2 == nil) return true;
|
||||
if(s1 == nil || s2 == nil) return false;
|
||||
|
||||
i = 0;
|
||||
while (i < length && *s1 && *s2) {
|
||||
if (*s1 != *s2) return false;
|
||||
while(i < length && *s1 && *s2) {
|
||||
if(*s1 != *s2) return false;
|
||||
s1++;
|
||||
s2++;
|
||||
i++;
|
||||
}
|
||||
if (i == length) return true;
|
||||
if(i == length) return true;
|
||||
return (*s1 == '\0' && *s2 == '\0');
|
||||
}
|
||||
|
||||
u32 slen(const char *str) {
|
||||
u32
|
||||
slen(const char *str)
|
||||
{
|
||||
u32 i;
|
||||
if (str == nil) {return 0;}
|
||||
for (i = 0; str[i] != '\0'; i++) {
|
||||
;
|
||||
}
|
||||
if(str == nil) return 0;
|
||||
for(i = 0; str[i] != '\0'; i++);
|
||||
return i;
|
||||
}
|
||||
|
||||
u32 snlen(const char *str, u32 max_len) {
|
||||
u32
|
||||
snlen(const char *str, u32 max_len)
|
||||
{
|
||||
u32 i;
|
||||
if (str == nil) {return 0;}
|
||||
for (i = 0; i < max_len && str[i] != '\0'; i++) {
|
||||
;
|
||||
}
|
||||
if(str == nil) return 0;
|
||||
for(i = 0; i < max_len && str[i] != '\0'; i++);
|
||||
return i;
|
||||
}
|
||||
|
||||
void *
|
||||
aaloc(Arena *arena, u32 size)
|
||||
{
|
||||
u32 pos;
|
||||
if(arena == nil) return nil;
|
||||
if(arena->count + size > arena->capacity) return nil;
|
||||
|
||||
pos = arena->count;
|
||||
arena->count += size;
|
||||
return &arena->tape[pos];
|
||||
}
|
||||
|
||||
u32
|
||||
afree(Arena *arena)
|
||||
{
|
||||
u32 freed = arena->count;
|
||||
arena->count = 0;
|
||||
return freed;
|
||||
}
|
||||
|
|
|
|||
41
libc.h
41
libc.h
|
|
@ -15,21 +15,21 @@
|
|||
|
||||
#ifdef HAVE_STDINT
|
||||
#include <stdint.h>
|
||||
typedef uint8_t u8;
|
||||
typedef int8_t i8;
|
||||
typedef uint16_t u16;
|
||||
typedef int16_t i16;
|
||||
typedef uint32_t u32;
|
||||
typedef int32_t i32;
|
||||
typedef float f32;
|
||||
typedef uint8_t u8;
|
||||
typedef int8_t i8;
|
||||
typedef uint16_t u16;
|
||||
typedef int16_t i16;
|
||||
typedef uint32_t u32;
|
||||
typedef int32_t i32;
|
||||
typedef float f32;
|
||||
#else
|
||||
typedef unsigned char u8;
|
||||
typedef signed char i8;
|
||||
typedef unsigned short u16;
|
||||
typedef signed short i16;
|
||||
typedef unsigned int u32;
|
||||
typedef signed int i32;
|
||||
typedef float f32;
|
||||
typedef unsigned char u8;
|
||||
typedef signed char i8;
|
||||
typedef unsigned short u16;
|
||||
typedef signed short i16;
|
||||
typedef unsigned int u32;
|
||||
typedef signed int i32;
|
||||
typedef float f32;
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_STDBOOL
|
||||
|
|
@ -44,7 +44,7 @@ typedef u8 bool;
|
|||
#include <stddef.h>
|
||||
#define nil NULL
|
||||
#else
|
||||
#define nil ((void*)0)
|
||||
#define nil ((void *)0)
|
||||
#endif
|
||||
|
||||
#define I8_MIN -128
|
||||
|
|
@ -69,11 +69,20 @@ typedef u8 bool;
|
|||
|
||||
#define USED(x) ((void)(x))
|
||||
|
||||
typedef struct arena_s Arena;
|
||||
struct arena_s {
|
||||
u8 *tape;
|
||||
u32 count;
|
||||
u32 capacity;
|
||||
};
|
||||
|
||||
void mcpy(void *dest, void *src, u32 n);
|
||||
i32 scpy(char* to, const char *from, u32 length);
|
||||
i32 scpy(char *to, const char *from, u32 length);
|
||||
bool seq(const char *s1, const char *s2);
|
||||
bool sleq(const char *s1, const char *s2, u32 length);
|
||||
u32 slen(const char *str);
|
||||
u32 snlen(const char *str, u32 max_len);
|
||||
void *aalloc(Arena *arena, u32 size);
|
||||
u32 afree(Arena *arena);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
14
main.c
14
main.c
|
|
@ -2,22 +2,24 @@
|
|||
#include <stdlib.h>
|
||||
|
||||
#define EMBED_FILE(name) \
|
||||
void emit_##name(const char *filename) { \
|
||||
void emit_##name(const char *filename) \
|
||||
{ \
|
||||
FILE *f = fopen(filename, "wb"); \
|
||||
if (f) { \
|
||||
if(f) { \
|
||||
fwrite(name, 1, name##_len, f); \
|
||||
fclose(f); \
|
||||
} \
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
char *name;
|
||||
|
||||
if (argc > 1) {
|
||||
if(argc > 1)
|
||||
name = argv[1];
|
||||
} else {
|
||||
else
|
||||
name = "'u'";
|
||||
}
|
||||
|
||||
printf("nuqneH %s?\n", name);
|
||||
return EXIT_SUCCESS;
|
||||
|
|
|
|||
160
parser.c
160
parser.c
|
|
@ -1,23 +1,46 @@
|
|||
#include "parser.h"
|
||||
|
||||
bool push(TokenStack *ts, Token t) {
|
||||
if (ts->count >= ts->capacity) return false;
|
||||
Parser parser;
|
||||
|
||||
bool
|
||||
advance()
|
||||
{
|
||||
parser.previous = parser.current;
|
||||
|
||||
for(;;) {
|
||||
parser.current = next_token();
|
||||
if(parser.current.type != TOKEN_ERROR) return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
push(TokenStack *ts, Token t)
|
||||
{
|
||||
if(ts->count >= ts->capacity) return false;
|
||||
ts->stack[ts->count++] = t;
|
||||
return true;
|
||||
}
|
||||
|
||||
Token pop(TokenStack *ts) {
|
||||
if (ts->count == 0) return (Token){TOKEN_ERROR, nil, -1, -1};
|
||||
Token
|
||||
pop(TokenStack *ts)
|
||||
{
|
||||
if(ts->count == 0) return (Token){TOKEN_ERROR, nil, -1, -1};
|
||||
return ts->stack[--ts->count];
|
||||
}
|
||||
|
||||
Token top(TokenStack *ts) {
|
||||
if (ts->count == 0) return (Token){TOKEN_ERROR, nil, -1, -1};
|
||||
Token
|
||||
top(TokenStack *ts)
|
||||
{
|
||||
if(ts->count == 0) return (Token){TOKEN_ERROR, nil, -1, -1};
|
||||
return ts->stack[ts->count - 1];
|
||||
}
|
||||
|
||||
bool enqueue(TokenQueue *tq, Token t) {
|
||||
if (tq->count >= tq->capacity) return false;
|
||||
bool
|
||||
enqueue(TokenQueue *tq, Token t)
|
||||
{
|
||||
if(tq->count >= tq->capacity) return false;
|
||||
|
||||
tq->queue[tq->end] = t;
|
||||
tq->end = (tq->end + 1) % tq->capacity; // Wrap around
|
||||
|
|
@ -25,8 +48,10 @@ bool enqueue(TokenQueue *tq, Token t) {
|
|||
return true;
|
||||
}
|
||||
|
||||
Token dequeue(TokenQueue *tq) {
|
||||
if (tq->count == 0) return (Token){TOKEN_ERROR, NULL, -1, -1};
|
||||
Token
|
||||
dequeue(TokenQueue *tq)
|
||||
{
|
||||
if(tq->count == 0) return (Token){TOKEN_ERROR, NULL, -1, -1};
|
||||
|
||||
Token t = tq->queue[tq->start];
|
||||
tq->start = (tq->start + 1) % tq->capacity; // Wrap around
|
||||
|
|
@ -34,18 +59,119 @@ Token dequeue(TokenQueue *tq) {
|
|||
return t;
|
||||
}
|
||||
|
||||
Token peek_queue(TokenQueue *tq) {
|
||||
if (tq->count == 0) return (Token){TOKEN_ERROR, NULL, -1, -1};
|
||||
Token
|
||||
peek_queue(TokenQueue *tq)
|
||||
{
|
||||
if(tq->count == 0) return (Token){TOKEN_ERROR, NULL, -1, -1};
|
||||
return tq->queue[tq->start];
|
||||
}
|
||||
|
||||
bool expression() {
|
||||
|
||||
u32
|
||||
idx_from_arena(Arena *arena, void *p)
|
||||
{
|
||||
return (u32)((u8 *)p - arena->tape);
|
||||
}
|
||||
|
||||
bool compile(char *source) {
|
||||
TokenStack operators;
|
||||
TokenQueue output;
|
||||
void *
|
||||
ptr_from_arena(Arena *arena, u32 i)
|
||||
{
|
||||
return &arena->tape[i];
|
||||
}
|
||||
|
||||
ArenaList *
|
||||
al_create(Arena *arena, u32 size)
|
||||
{
|
||||
ArenaList *meta = aalloc(arena, sizeof(ArenaList));
|
||||
if(!meta) return nil;
|
||||
|
||||
meta->size = size + sizeof(u32);
|
||||
meta->arena = arena;
|
||||
meta->head = 0;
|
||||
meta->tail = 0;
|
||||
|
||||
return meta;
|
||||
}
|
||||
|
||||
void *
|
||||
al_append(ArenaList *list, void **out_payload)
|
||||
{
|
||||
void *node = aalloc(list->arena, list->size);
|
||||
if(!node) return nil;
|
||||
|
||||
u32 idx = idx_from_arena(list->arena, node);
|
||||
void *payload = node; /* Payload starts at offset 0 */
|
||||
|
||||
void *cdr_ptr = (u8 *)node + (list->size - sizeof(u32));
|
||||
|
||||
*(u32 *)cdr_ptr = 0;
|
||||
|
||||
if(list->tail != 0) {
|
||||
void *prev_node = ptr_from_arena(list->arena, list->tail);
|
||||
void *prev_cdr = (u8 *)prev_node + (list->size - sizeof(u32));
|
||||
*(u32 *)prev_cdr = idx;
|
||||
} else {
|
||||
list->head = idx;
|
||||
}
|
||||
|
||||
list->tail = idx;
|
||||
|
||||
if(out_payload) *out_payload = payload;
|
||||
return payload;
|
||||
}
|
||||
|
||||
void *
|
||||
al_head(ArenaList *list)
|
||||
{
|
||||
if(list->head == 0) return nil;
|
||||
return ptr_from_arena(list->arena, list->head);
|
||||
}
|
||||
|
||||
void *
|
||||
al_tail(ArenaList *list)
|
||||
{
|
||||
if(list->tail == 0) return nil;
|
||||
return ptr_from_arena(list->arena, list->tail);
|
||||
}
|
||||
|
||||
SymbolLink *
|
||||
symbol_table_find(ArenaList *table, const char *name)
|
||||
{
|
||||
void *current = al_head(table);
|
||||
Arena *arena = table->arena;
|
||||
|
||||
while(current != nil) {
|
||||
SymbolLink *link = (SymbolLink *)current;
|
||||
|
||||
if(seq(link->s.name.start, name)) return link;
|
||||
|
||||
u32 next_idx = link->cdr;
|
||||
current = (next_idx == 0) ? nil : ptr_from_arena(arena, next_idx);
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
/****************************************************
|
||||
* Parser
|
||||
***************************************************/
|
||||
|
||||
bool
|
||||
expression()
|
||||
{
|
||||
Token operator_stack[256];
|
||||
TokenStack operators = {0};
|
||||
operators.stack = operator_stack;
|
||||
operators.capacity = 256;
|
||||
|
||||
Token output_queue[256];
|
||||
TokenQueue output = {0};
|
||||
output.queue = output_queue;
|
||||
output.capacity = 256;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
compile(char *source)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
100
parser.h
100
parser.h
|
|
@ -4,8 +4,7 @@
|
|||
#include "libc.h"
|
||||
#include "lexer.h"
|
||||
|
||||
typedef enum { GLOBAL, LOCAL, VAR } ScopeType;
|
||||
typedef enum {
|
||||
typedef enum symbol_type_e {
|
||||
VOID,
|
||||
BOOL,
|
||||
I8,
|
||||
|
|
@ -18,72 +17,60 @@ typedef enum {
|
|||
F16,
|
||||
F32,
|
||||
STR,
|
||||
PLEX,
|
||||
ARRAY,
|
||||
FUNCTION
|
||||
FUNCTION,
|
||||
PLEX,
|
||||
METHOD,
|
||||
TRAIT,
|
||||
} SymbolType;
|
||||
|
||||
typedef struct arena_list_s ArenaList;
|
||||
typedef struct symbol_s Symbol;
|
||||
typedef struct symbol_tab_s SymbolTable;
|
||||
typedef struct value_type_s ValueType;
|
||||
typedef struct plex_fields_tab_s PlexFieldsTable;
|
||||
typedef struct plex_def_s PlexDef;
|
||||
typedef struct plex_tab_s PlexTable;
|
||||
typedef struct scope_s Scope;
|
||||
typedef struct scope_tab_s ScopeTable;
|
||||
typedef struct symbol_link_s SymbolLink;
|
||||
typedef struct token_stack_s TokenStack;
|
||||
typedef struct queue_s TokenQueue;
|
||||
typedef struct parser_s Parser;
|
||||
|
||||
struct value_type_s {
|
||||
SymbolType type;
|
||||
u32 name;
|
||||
u32 size;
|
||||
u32 table_ref; // if it is a heap object
|
||||
};
|
||||
|
||||
struct plex_def_s {
|
||||
u32 name;
|
||||
u32 size;
|
||||
u32 field_ref_start;
|
||||
u32 field_count;
|
||||
};
|
||||
|
||||
struct plex_fields_tab_s {
|
||||
u32 *plex_refs;
|
||||
ValueType *fields;
|
||||
u32 count;
|
||||
u32 capacity;
|
||||
};
|
||||
|
||||
struct plex_tab_s {
|
||||
PlexDef *symbols;
|
||||
u32 count;
|
||||
u32 capacity;
|
||||
};
|
||||
|
||||
#define MAX_SYMBOL_NAME_LENGTH 64
|
||||
struct symbol_s {
|
||||
char name[MAX_SYMBOL_NAME_LENGTH];
|
||||
u8 name_length;
|
||||
Token name;
|
||||
SymbolType type;
|
||||
ScopeType scope;
|
||||
u32 ref; // vm->mp if global, vm->pc local, register if var
|
||||
u32 size; // size of symbol
|
||||
u32 size;
|
||||
i32 scope;
|
||||
union type_def {
|
||||
struct trait_def {
|
||||
u32 field_ref_start; /* reference to field list of symbols */
|
||||
u32 methods_ref_start; /* zero if none */
|
||||
} trait;
|
||||
struct plex_def {
|
||||
u32 field_ref_start; /* reference to field list of symbols */
|
||||
u32 methods_ref_start; /* zero if none */
|
||||
} plex;
|
||||
struct function_def {
|
||||
SymbolType return_type;
|
||||
u32 arguments_ref_start; /* reference to field list of symbols */
|
||||
} function;
|
||||
struct array_def {
|
||||
SymbolType type;
|
||||
u32 length; /* zero means "unbounded" */
|
||||
} array;
|
||||
struct field_def {
|
||||
u32 offset;
|
||||
} field;
|
||||
} def;
|
||||
};
|
||||
|
||||
#define MAX_SYMBOLS 256
|
||||
struct symbol_tab_s {
|
||||
Symbol symbols[MAX_SYMBOLS];
|
||||
u8 count;
|
||||
i32 parent;
|
||||
struct symbol_link_s {
|
||||
Symbol s;
|
||||
u32 cdr; /* zero means "end of list" */
|
||||
};
|
||||
|
||||
struct scope_tab_s {
|
||||
SymbolTable *scopes;
|
||||
struct arena_list_s {
|
||||
Arena *arena;
|
||||
u32 head;
|
||||
u32 tail;
|
||||
u32 size;
|
||||
u32 count;
|
||||
u32 capacity;
|
||||
i32 scope_ref;
|
||||
u32 depth;
|
||||
i32 parent;
|
||||
};
|
||||
|
||||
struct token_stack_s {
|
||||
|
|
@ -100,6 +87,11 @@ struct queue_s {
|
|||
i32 count;
|
||||
};
|
||||
|
||||
struct parser_s {
|
||||
Token current;
|
||||
Token previous;
|
||||
};
|
||||
|
||||
bool push(TokenStack *ts, Token t);
|
||||
Token pop(TokenStack *ts);
|
||||
Token top(TokenStack *ts);
|
||||
|
|
|
|||
|
|
@ -3,7 +3,9 @@
|
|||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
FILE *in;
|
||||
int c;
|
||||
long count = 0;
|
||||
|
|
@ -11,19 +13,19 @@ int main(int argc, char *argv[]) {
|
|||
char *var_name;
|
||||
char *p;
|
||||
|
||||
if (argc != 2) {
|
||||
if(argc != 2) {
|
||||
fprintf(stderr, "Usage: %s <input_file>\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
in = fopen(argv[1], "rb");
|
||||
if (!in) {
|
||||
if(!in) {
|
||||
perror("Error opening input file");
|
||||
return 1;
|
||||
}
|
||||
|
||||
var_name = (char *)malloc(strlen(argv[1]) + 1);
|
||||
if (!var_name) {
|
||||
if(!var_name) {
|
||||
perror("Memory allocation failed");
|
||||
fclose(in);
|
||||
return 1;
|
||||
|
|
@ -31,24 +33,21 @@ int main(int argc, char *argv[]) {
|
|||
|
||||
strcpy(var_name, argv[1]);
|
||||
|
||||
for (p = var_name; *p; ++p) {
|
||||
if (!isalnum((unsigned char)*p)) {
|
||||
*p = '_';
|
||||
}
|
||||
}
|
||||
for(p = var_name; *p; ++p)
|
||||
if(!isalnum((unsigned char)*p)) *p = '_';
|
||||
|
||||
printf("unsigned char %s[] = {\n", var_name);
|
||||
|
||||
c = fgetc(in);
|
||||
while (c != EOF) {
|
||||
while(c != EOF) {
|
||||
printf(" 0x%02x", c);
|
||||
count++;
|
||||
|
||||
int next = fgetc(in);
|
||||
if (next != EOF) {
|
||||
if(next != EOF) {
|
||||
printf(",");
|
||||
ungetc(next, in);
|
||||
if (++col >= 12) {
|
||||
if(++col >= 12) {
|
||||
printf("\n");
|
||||
col = 0;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue