Parsing exprs, enum_decls, Introduce intern table, symbol table

This commit is contained in:
Krzosa Karol
2022-04-29 11:22:10 +02:00
parent d462892e14
commit 9cbbb4d616
20 changed files with 1831 additions and 335 deletions

57
common.c Normal file
View File

@@ -0,0 +1,57 @@
function S64
clamp_top_s64(S64 val, S64 max){
if(val>max)return max;
return val;
}
function SizeU
get_align_offset(SizeU size, SizeU align){
SizeU mask = align - 1;
SizeU val = size & mask;
if(val){
val = align - val;
}
return val;
}
function SizeU
align_up(SizeU size, SizeU align){
SizeU result = size + get_align_offset(size, align);
return result;
}
function U64
hash_fnv(String string) {
U64 hash = (U64)14695981039346656037ULL;
for (U64 i = 0; i < string.len; i++) {
hash = hash ^ (U64)(string.str[i]);
hash = hash * (U64)1099511628211ULL;
}
return hash;
}
function U64
is_pow2(U64 x) {
assert(x != 0);
B32 result = (x & (x - 1llu)) == 0;
return result;
}
function U64
wrap_around_pow2(U64 x, U64 power_of_2) {
assert(is_pow2(power_of_2));
U64 r = (((x)&((power_of_2)-1llu)));
return r;
}
function B32
string_compare(String a, String b){
if(a.len != b.len)
return false;
for(S64 i = 0; i < a.len; i++){
if(a.str[i] != b.str[i])
return false;
}
return true;
}

50
decl.c Normal file
View File

@@ -0,0 +1,50 @@
function Decl *
decl_new(Parser *p, Decl_Kind kind, Token *token, Intern_String name){
Decl *result = arena_push_struct(&p->main_arena, Decl);
memory_zero(result, sizeof(Decl));
result->token = token;
result->kind = kind;
result->name = name;
return result;
}
function Decl_Enum_Child *
decl_enum_child(Parser *p, Token *token, Expr *expr){
Decl_Enum_Child *result = arena_push_struct(&p->main_arena, Decl_Enum_Child);
memory_zero(result, sizeof(Decl_Enum_Child));
result->expr = expr;
result->token = token;
return result;
}
function Decl *
decl_enum(Parser *p, Token *token, Intern_String name){
Decl *result = decl_new(p, DK_Enum, token, name);
return result;
}
function Decl *
decl_struct(Parser *p, Token *token, Intern_String name){
Decl *result = decl_new(p, DK_Struct, token, name);
return result;
}
function Decl *
decl_union(Parser *p, Token *token, Intern_String name){
Decl *result = decl_new(p, DK_Union, token, name);
return result;
}
function void
decl_aggregate_push(Decl *a, Decl *b){
SLLQueuePush(a->aggregate_val.first, a->aggregate_val.last, b);
}
function void
decl_function_push(Decl *a, Decl *b){
SLLQueuePush(a->func_val.first, a->func_val.last, b);
}
function void
decl_enum_push(Decl *a, Decl_Enum_Child *b){
SLLQueuePush(a->enum_val.first, a->enum_val.last, b);
}

63
decl.h Normal file
View File

@@ -0,0 +1,63 @@
#pragma once
typedef struct Note Note;
typedef struct Decl Decl;
typedef struct Decl_Enum_Child Decl_Enum_Child;
typedef enum Decl_Kind{
DK_None,
DK_Variable,
DK_Typedef,
DK_Struct,
DK_Union,
DK_Enum,
DK_Function,
}Decl_Kind;
struct Note{
Intern_String string;
Token *token;
Expr *expr;
Note *next;
Note *first;
Note *last;
};
struct Decl_Enum_Child{
Decl_Enum_Child *next;
Token *token; // name
Expr *expr;
};
struct Decl{
Decl_Kind kind;
Decl *next;
Intern_String name;
Token *token;
Note *first_note;
Note *last_note;
union{
struct{
Decl_Enum_Child *first;
Decl_Enum_Child *last;
} enum_val;
struct{
Decl *first;
Decl *last;
} aggregate_val;
struct{
Decl *first;
Decl *last;
Type *return_type;
}func_val;
struct{
Type *type;
Expr *expr;
}var_val;
struct{
Type *type;
}typedef_val;
};
};

74
expr.c Normal file
View File

@@ -0,0 +1,74 @@
function Expr *
expr_new(Parser *p, Expr_Kind kind, Token *token){
Expr *expr = arena_push_struct(&p->main_arena, Expr);
memory_zero(expr, sizeof(Expr));
expr->kind = kind;
expr->token = token;
return expr;
}
function Expr *
expr_atom(Parser *p, Token *token){
Expr *expr = expr_new(p, EK_Atom, token);
return expr;
}
function Expr *
expr_unary(Parser *p, Token *op, Expr *exp){
Expr *expr = expr_new(p, EK_Unary, op);
expr->unary.expr = exp;
return expr;
}
function Expr *
expr_binary(Parser *p, Token *op, Expr *left, Expr *right){
Expr *expr = expr_new(p, EK_Binary, op);
expr->binary.left = left;
expr->binary.right = right;
return expr;
}
function Expr *
expr_ternary(Parser *p, Token *op, Expr *cond, Expr *on_true, Expr *on_false){
Expr *expr = expr_new(p, EK_Ternary, op);
expr->ternary.cond = cond;
expr->ternary.on_true = on_true;
expr->ternary.on_false = on_false;
return expr;
}
function Expr *
expr_call(Parser *p, Token *token, Expr *atom, Expr *list){
Expr *expr = expr_new(p, EK_Call, token);
expr->call.atom = atom;
expr->call.list = list;
return expr;
}
function Expr *
expr_index(Parser *p, Token *token, Expr *atom, Expr *index){
Expr *expr = expr_new(p, EK_Index, token);
expr->index.atom = atom;
expr->index.index = index;
return expr;
}
function Expr *
expr_cast(Parser *p, Token *token, Type *type, Expr *exp){
Expr *expr = expr_new(p, EK_Cast, token);
expr->cast.type = type;
expr->cast.expr = exp;
return expr;
}
function Expr *
expr_list(Parser *p, Token *token){
Expr *expr = expr_new(p, EK_List, token);
return expr;
}
function void
expr_list_push(Expr *list, Expr *expr){
SLLQueuePush(list->list.first, list->list.last, expr);
}

50
expr.h Normal file
View File

@@ -0,0 +1,50 @@
#pragma once
typedef struct Expr Expr;
typedef enum Expr_Kind{
EK_None,
EK_Atom,
EK_Unary,
EK_Binary,
EK_Ternary,
EK_Cast,
EK_List,
EK_Call,
EK_Index,
} Expr_Kind;
struct Expr {
Expr_Kind kind;
Token *token;
Expr *next;
union {
struct {
Type *type;
Expr* expr;
} cast;
struct {
Expr *first;
Expr *last;
} list;
struct {
Expr *atom;
Expr *list;
} call;
struct {
Expr *atom;
Expr *index;
} index;
struct {
Expr* expr;
} unary;
struct {
Expr* left;
Expr* right;
} binary;
struct {
Expr* cond;
Expr* on_true;
Expr* on_false;
} ternary;
};
};

View File

@@ -32,8 +32,20 @@ typedef double F64;
const B32 true = 1;
const B32 false = 0;
#define kib(x) ((x)*1024llu)
#define mib(x) (kib(x)*1024llu)
#define gib(x) (mib(x)*1024llu)
typedef struct String{
U8 *str;
S64 len;
}String;
#define SLLQueuePush(f,l,n) do{\
if((f)==0){\
(f)=(l)=(n);\
}\
else{\
(l)=(l)->next=(n);\
} \
}while(0)

498
lex.c Normal file
View File

@@ -0,0 +1,498 @@
global Token token_end_of_stream = {};
function Token *
token_alloc(Tokens *t){
if(t->cap == 0){
t->cap = 1024;
t->tokens = malloc(sizeof(Token)*t->cap);
}
else if(t->len+1 > t->cap){
t->cap *= 2;
t->tokens = realloc(t->tokens, sizeof(Token)*t->cap);
}
Token *result = t->tokens + t->len++;
memory_zero(result, sizeof(*result));
return result;
}
function void
lex_advance(Lex_Stream *s){
if(*s->stream == '\n'){
s->stream++;
s->line++;
s->line_begin = s->stream;
}
else if(*s->stream == 0){
// Don't advance, end of stream
}
else{
s->stream++;
}
}
function B32
lex_is_whitespace(U8 c){
B32 result = c == '\n' || c == '\r' || c == ' ' || c == '\r';
return result;
}
function B32
lex_is_alphabetic(U8 c){
B32 result = (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z');
return result;
}
function B32
lex_is_numeric(U8 c){
B32 result = c >= '0' && c <= '9';
return result;
}
function B32
lex_is_alphanumeric(U8 c){
B32 result = lex_is_numeric(c) || lex_is_alphabetic(c);
return result;
}
function void
lex_set_len(Lex_Stream *s, Token *token){
assert(s->stream > token->str);
token->len = s->stream - token->str;
}
function U8
lexc(Lex_Stream *s){
return *s->stream;
}
function void
token_error(Token *t, String error_val){
t->kind = TK_Error;
t->error_val = error_val;
}
function void
lex_parse_string(Lex_Stream *s, Token *t, U8 c){
for(;;){
if(lexc(s) == '\\') lex_advance(s);
else if(lexc(s) == c) break;
else if(lexc(s) == 0){
token_error(t, lit("Unterminated string, reached end of file"));
break;
}
lex_advance(s);
}
if(t->kind != TK_Error){
lex_advance(s);
lex_set_len(s,t);
}
}
function void
lex_token_seed(Lex_Stream *s, Token *t){
t->str = s->stream;
t->file = s->filename;
t->line = s->line;
t->line_begin = s->line_begin;
}
function U64
parse_u64(U8 *str, S64 len){
U64 result = 0;
U64 m = 1;
for(S64 i = len - 1; i >= 0; --i){
U64 val = str[i] - '0';
U64 new_val = val * m;
assert_msg(result+new_val >= result, "Integer overflow!");
result+=new_val;
m *= 10;
}
return result;
}
function void
token_push_error(Lex_Stream *stream, Tokens *tokens, String error_val){
Token *token = token_alloc(tokens);
token->kind = TK_Error;
token->error_val = error_val;
lex_token_seed(stream, token);
}
function void
lex_base(Lex_Stream *s, Tokens *tokens){
while(*s->stream){
while(lex_is_whitespace(*s->stream))
lex_advance(s);
#define CASE2(op, OpName, Assign) \
case op: \
if (lexc(s) == '=') { \
lex_advance(s); \
t->kind = Assign; \
} else { \
t->kind = OpName; \
} \
break
#define CASE3(op, OpName, Assign, Incr) \
case op: \
if (lexc(s) == '=') { \
lex_advance(s); \
t->kind = Assign; \
} else if (lexc(s) == op) { \
lex_advance(s); \
t->kind = Incr; \
} else { \
t->kind = OpName; \
} \
break
Token *t = token_alloc(tokens);
lex_token_seed(s, t);
lex_advance(s);
switch(*t->str) {
CASE2('!', TK_Not, TK_NotEquals);
CASE2('^', TK_BitXor, TK_XorAssign);
CASE2('=', TK_Assign, TK_Equals);
CASE2('*', TK_Mul, TK_MulAssign);
CASE2('%', TK_Mod, TK_ModAssign);
CASE3('+', TK_Add, TK_AddAssign, TK_Increment);
CASE3('&', TK_BitAnd, TK_AndAssign, TK_And);
CASE3('|', TK_BitOr, TK_OrAssign, TK_Or);
#undef CASE2
#undef CASE3
case '@': t->kind = TK_At; break;
case '(': t->kind = TK_OpenParen; break;
case ')': t->kind = TK_CloseParen; break;
case '{': t->kind = TK_OpenBrace; break;
case '}': t->kind = TK_CloseBrace; break;
case '[': t->kind = TK_OpenBracket; break;
case ']': t->kind = TK_CloseBracket; break;
case ',': t->kind = TK_Comma; break;
case '~': t->kind = TK_Neg; break;
case '?': t->kind = TK_Question; break;
case ';': t->kind = TK_Semicolon; break;
case '#': {
t->kind = TK_Pound;
// @Todo(Krzosa): Some convenient way to recognize macros
} break;
case '.': {
if(s->stream[0] == '.' && s->stream[1] == '.') {
lex_advance(s);
lex_advance(s);
t->kind = TK_ThreeDots;
}
else {
t->kind = TK_Dot;
}
} break;
case '<': {
if (lexc(s) == '<') {
lex_advance(s);
if (lexc(s) == '=') {
lex_advance(s);
t->kind = TK_LeftShiftAssign;
}
else {
t->kind = TK_LeftShift;
}
}
else if (lexc(s) == '=') {
lex_advance(s);
t->kind = TK_LesserThenOrEqual;
}
else {
t->kind = TK_LesserThen;
}
} break;
case '>': {
if (lexc(s) == '>') {
lex_advance(s);
if (lexc(s) == '=') {
lex_advance(s);
t->kind = TK_RightShiftAssign;
}
else {
t->kind = TK_RightShift;
}
}
else if (lexc(s) == '=') {
lex_advance(s);
t->kind = TK_GreaterThenOrEqual;
}
else {
t->kind = TK_GreaterThen;
}
} break;
case ':': {
if (lexc(s) == ':') {
lex_advance(s);
t->kind = TK_DoubleColon;
}
else {
t->kind = TK_Colon;
}
} break;
case '-':{
if (lexc(s) == '=') {
lex_advance(s);
t->kind = TK_SubAssign;
}
else if (lexc(s) == '-') {
lex_advance(s);
t->kind = TK_Decrement;
}
else if (lexc(s) == '>') {
lex_advance(s);
t->kind = TK_Arrow;
}
else {
t->kind = TK_Sub;
}
} break;
case '\'':{not_implemented;} break;
case '"': {
t->kind = TK_U8Lit;
lex_parse_string(s,t,'"');
if(t->kind != TK_Error){
t->str += 1;
t->len -= 2;
}
} break;
case '/': {
if(lexc(s) == '='){
t->kind = TK_DivAssign;
lex_advance(s);
}
else if(lexc(s) == '/'){
lex_advance(s);
if(lexc(s) == '/'){
lex_advance(s);
t->kind = TK_DocComment;
}
else {
t->kind = TK_Comment;
}
for(;;){
if(lexc(s) == '\n' || lexc(s) == 0) break;
lex_advance(s);
}
lex_set_len(s,t);
}
else if(lexc(s) == '*'){
lex_advance(s);
t->kind = TK_Comment;
for(;;){
if(s->stream[0] == '*' && s->stream[1] == '/'){
lex_advance(s);
lex_advance(s);
break;
}
else if(lexc(s) == 0){
token_error(t, lit("Unterminated block comment"));
break;
}
lex_advance(s);
}
lex_set_len(s,t);
}
else t->kind = TK_Div;
} break;
case '0':
case '1':case '2':case '3':
case '4':case '5':case '6':
case '7':case '8':case '9': {
t->kind = TK_Int;
while(lex_is_numeric(lexc(s)))
lex_advance(s);
lex_set_len(s, t);
t->int_val = parse_u64(t->str, t->len);
} break;
case 'l':{
if(s->stream[0] == 'i' && s->stream[1] == 't' && s->stream[2] == '(' && s->stream[3] == '"'){
t->kind = TK_StringLit;
lex_advance(s);lex_advance(s);lex_advance(s);lex_advance(s);
lex_parse_string(s,t,'"');
if(s->stream[0] == ')') {
t->str += 5;
t->len -= 6;
lex_advance(s);
}
else token_error(t, lit("Unterminated string literal, missing closing parenthesis"));
break;
}
};
case 'A':case 'a':case 'M':case 'm':case 'B':
case 'b':case 'N':case 'n':case 'C':case 'c':case 'O':
case 'o':case 'D':case 'd':case 'P':case 'p':case 'E':
case 'e':case 'Q':case 'q':case 'F':case 'f':case 'R':
case 'r':case 'G':case 'g':case 'S':case 's':case 'H':
case 'h':case 'T':case 't':case 'I':case 'i':case 'U':
case 'u':case 'J':case 'j':case 'V':case 'v':case 'K':
case 'k':case 'W':case 'w':case 'L':case 'X':
case 'x':case 'Z':case 'z':case 'Y':case 'y':case '_': {
t->kind = TK_Identifier;
while(lex_is_alphanumeric(lexc(s)) || lexc(s) == '_')
lex_advance(s);
lex_set_len(s,t);
} break;
default: {
token_error(t, lit("Unknown token"));
} break;
}
if(t->len==0){
lex_set_len(s,t);
}
}
// Token end of stream
Token *t = token_alloc(tokens);
*t = token_end_of_stream;
tokens->len -= 1;
}
function Tokens
lex_stream(String in_stream, String filename){
Lex_Stream stream = {in_stream.str, in_stream.str, filename, 0};
Tokens tokens = {};
lex_base(&stream, &tokens);
return tokens;
}
function void
parser_lex_stream(Parser *p, String in_stream, String filename){
Lex_Stream stream = {in_stream.str, in_stream.str, filename, 0};
p->tokens.len = 0;
p->tokens.iter = 0;
lex_base(&stream, &p->tokens);
intern_tokens(p);
}
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
function B32
token_compare(Token *t, String str){
B32 result = string_compare(t->string, str);
return result;
}
function B32
token_is_comment(Token *token){
B32 result = token->kind == TK_Comment || token->kind == TK_DocComment;
return result;
}
function Token *
token_get(Parser *p){
Token *token = p->tokens.tokens + p->tokens.iter;
return token;
}
function B32
intern_compare(Intern_String a, Intern_String b){
B32 result = a.s.str == b.s.str;
return result;
}
function Token *
token_is_keyword(Parser *p, Intern_String keyword){
assert(intern_is_keyword(p, keyword));
Token *t = token_get(p);
if(t->kind == TK_Keyword && intern_compare(t->intern_val, keyword)){
return t;
}
return 0;
}
function void
token_advance(Parser *p){
do{
p->tokens.iter = clamp_top_s64(p->tokens.iter + 1, p->tokens.len);
}while(token_is_comment(token_get(p)));
}
function Token *
token_next(Parser *p){
Token *token = token_get(p);
token_advance(p);
return token;
}
function Token *
token_match(Parser *p, Token_Kind kind){
Token *token = token_get(p);
if(token->kind == kind){
return token_next(p);
}
return 0;
}
function Token *
token_match_keyword(Parser *p, Intern_String keyword){
assert(intern_is_keyword(p, keyword));
Token *token = token_get(p);
if(token->kind == TK_Keyword && intern_compare(keyword, token->intern_val)){
return token_next(p);
}
return 0;
}
function Token *
token_expect(Parser *p, Token_Kind kind){
Token *token = token_get(p);
if(token->kind == kind){
return token_next(p);
}
parser_push_error(p, token,
"Expected token of kind: %s, got instead token of kind: %s",
token_kind_string[kind].str, token_kind_string[token->kind].str);
return 0;
}
function B32
token_is(Parser *p, Token_Kind kind){
B32 result = token_get(p)->kind == kind;
return result;
}
function Token *
token_is_assignment(Parser *p){
Token *t = token_get(p);
if(t->kind >= TK_Assign && t->kind <= TK_RightShiftAssign)
return t;
return 0;
}
function Token *
token_peek(Parser *p, S64 count){
S64 index = clamp_top_s64(p->tokens.iter + count, p->tokens.len);
Token *result = p->tokens.tokens + index;
return result;
}
function Token *
token_peek_is(Parser *p, S64 count, Token_Kind kind){
Token *token = token_peek(p, count);
if(token->kind == kind)
return token;
return 0;
}

8
lex.h
View File

@@ -1,4 +1,7 @@
#pragma once
typedef struct Intern_String{
String s;
}Intern_String;
typedef enum Token_Kind{
meta("End of stream")TK_End,
@@ -59,6 +62,7 @@ typedef enum Token_Kind{
TK_Identifier,
TK_StringLit,
TK_U8Lit,
TK_Character,
TK_Error,
TK_Float,
TK_Int,
@@ -77,6 +81,7 @@ typedef struct Token{
union {
S64 int_val;
String error_val;
Intern_String intern_val;
};
String file;
@@ -88,6 +93,7 @@ typedef struct Tokens{
Token *tokens;
S64 len;
S64 cap;
S64 iter;
}Tokens;
typedef struct Lex_Stream{
@@ -105,6 +111,8 @@ global String token_kind_string[] = {
[TK_Error] = lit("Error"),
[TK_Comment] = lit("Comment"),
[TK_Identifier] = lit("Identifier"),
[TK_Keyword] = lit("Keyword"),
[TK_Character] = lit("Character"),
[TK_StringLit] = lit("StringLiteral"),
[TK_U8Lit] = lit("U8Literal"),
[TK_Float] = lit("Float"),

436
main.c
View File

@@ -1,341 +1,41 @@
#include "os.cpp"
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <windows.h>
#include "lang.h"
#include "os.h"
#include "memory.h"
#include "lex.h"
global FILE *global_output_file;
#define lex_print(...) fprintf(global_output_file, __VA_ARGS__)
#include "parser.h"
#include "type.h"
#include "expr.h"
#include "decl.h"
function void
memory_zero(void *p, SizeU size){
U8 *pp = p;
for(SizeU i = 0; i < size; i++)
pp[i] = 0;
}
function B32
string_compare(String a, String b){
if(a.len != b.len)
return false;
for(S64 i = 0; i < a.len; i++){
if(a.str[i] != b.str[i])
return false;
}
return true;
}
function Token *
token_alloc(Tokens *t){
if(t->cap == 0){
t->cap = 1024;
t->tokens = malloc(sizeof(Token)*t->cap);
}
else if(t->len+1 > t->cap){
t->cap *= 2;
t->tokens = realloc(t->tokens, sizeof(Token)*t->cap);
}
Token *result = t->tokens + t->len++;
memory_zero(result, sizeof(*result));
return result;
}
function void
lex_advance(Lex_Stream *s){
if(*s->stream == '\n'){
s->stream++;
s->line++;
s->line_begin = s->stream;
}
else if(*s->stream == 0){
// Don't advance, end of stream
}
else{
s->stream++;
}
}
function U64
parse_u64(U8 *str, S64 len){
U64 result = 0;
U64 m = 1;
for(S64 i = len - 1; i >= 0; --i){
U64 val = str[i] - '0';
result += val * m;
m *= 10;
}
return result;
}
function B32
lex_is_whitespace(U8 c){
B32 result = c == '\n' || c == '\r' || c == ' ' || c == '\r';
return result;
}
function B32
lex_is_alphabetic(U8 c){
B32 result = (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z');
return result;
}
function B32
lex_is_numeric(U8 c){
B32 result = c >= '0' && c <= '9';
return result;
}
function B32
lex_is_alphanumeric(U8 c){
B32 result = lex_is_numeric(c) || lex_is_alphabetic(c);
return result;
}
function void
lex_set_len(Lex_Stream *s, Token *token){
assert(s->stream > token->str);
token->len = s->stream - token->str;
}
function U8
lexc(Lex_Stream *s){
return *s->stream;
}
function void
token_error(Token *t, String error_val){
t->kind = TK_Error;
t->error_val = error_val;
}
function void
lex_parse_string(Lex_Stream *s, Token *t, U8 c){
for(;;){
if(lexc(s) == '\\') lex_advance(s);
else if(lexc(s) == c) break;
else if(lexc(s) == 0){
token_error(t, lit("Unterminated string, reached end of file"));
break;
}
lex_advance(s);
}
if(t->kind != TK_Error){
lex_advance(s);
lex_set_len(s,t);
}
}
function void
lex_token_seed(Lex_Stream *s, Token *t){
t->str = s->stream;
t->file = s->filename;
t->line = s->line;
t->line_begin = s->line_begin;
}
function void
token_push_error(Lex_Stream *stream, Tokens *tokens, String error_val){
Token *token = token_alloc(tokens);
token->kind = TK_Error;
token->error_val = error_val;
lex_token_seed(stream, token);
}
function void
lex_base(Lex_Stream *s, Tokens *tokens){
while(*s->stream){
while(lex_is_whitespace(*s->stream))
lex_advance(s);
#define CASE2(op, OpName, Assign) \
case op: \
if (lexc(s) == '=') { \
lex_advance(s); \
t->kind = Assign; \
} else { \
t->kind = OpName; \
} \
break
#define CASE3(op, OpName, Assign, Incr) \
case op: \
if (lexc(s) == '=') { \
lex_advance(s); \
t->kind = Assign; \
} else if (lexc(s) == op) { \
lex_advance(s); \
t->kind = Incr; \
} else { \
t->kind = OpName; \
} \
break
Token *t = token_alloc(tokens);
lex_token_seed(s, t);
lex_advance(s);
switch(*t->str) {
CASE2('!', TK_Not, TK_NotEquals);
CASE2('^', TK_BitXor, TK_XorAssign);
CASE2('=', TK_Assign, TK_Equals);
CASE2('*', TK_Mul, TK_MulAssign);
CASE2('%', TK_Mod, TK_ModAssign);
CASE3('+', TK_Add, TK_AddAssign, TK_Increment);
CASE3('&', TK_BitAnd, TK_AndAssign, TK_And);
CASE3('|', TK_BitOr, TK_OrAssign, TK_Or);
#undef CASE2
#undef CASE3
case '@': t->kind = TK_At; break;
case '(': t->kind = TK_OpenParen; break;
case ')': t->kind = TK_CloseParen; break;
case '{': t->kind = TK_OpenBrace; break;
case '}': t->kind = TK_CloseBrace; break;
case '[': t->kind = TK_OpenBracket; break;
case ']': t->kind = TK_CloseBracket; break;
case ',': t->kind = TK_Comma; break;
case '~': t->kind = TK_Neg; break;
case '?': t->kind = TK_Question; break;
case ';': t->kind = TK_Semicolon; break;
case '-':{
if (lexc(s) == '=') {
lex_advance(s);
t->kind = TK_SubAssign;
}
else if (lexc(s) == '-') {
lex_advance(s);
t->kind = TK_Decrement;
}
else if (lexc(s) == '>') {
lex_advance(s);
t->kind = TK_Arrow;
}
else {
t->kind = TK_Sub;
}
} break;
case '\'':{not_implemented;} break;
case '"': {
t->kind = TK_U8Lit;
lex_parse_string(s,t,'"');
if(t->kind != TK_Error){
t->str += 1;
t->len -= 2;
}
} break;
case '/': {
if(lexc(s) == '/'){
lex_advance(s);
if(lexc(s) == '/'){
lex_advance(s);
t->kind = TK_DocComment;
}
else {
t->kind = TK_Comment;
}
for(;;){
if(lexc(s) == '\n' || lexc(s) == 0) break;
lex_advance(s);
}
lex_set_len(s,t);
}
else if(lexc(s) == '*'){
lex_advance(s);
t->kind = TK_Comment;
for(;;){
if(s->stream[0] == '*' && s->stream[1] == '/'){
lex_advance(s);
lex_advance(s);
break;
}
else if(lexc(s) == 0){
token_error(t, lit("Unterminated block comment"));
break;
}
lex_advance(s);
}
lex_set_len(s,t);
}
else t->kind = TK_Div;
} break;
case '0':
case '1':case '2':case '3':
case '4':case '5':case '6':
case '7':case '8':case '9': {
t->kind = TK_Int;
while(lex_is_numeric(lexc(s)))
lex_advance(s);
lex_set_len(s, t);
t->int_val = parse_u64(t->str, t->len);
} break;
case 'l':{
if(s->stream[0] == 'i' && s->stream[1] == 't' && s->stream[2] == '(' && s->stream[3] == '"'){
t->kind = TK_StringLit;
lex_advance(s);lex_advance(s);lex_advance(s);lex_advance(s);
lex_parse_string(s,t,'"');
if(s->stream[0] == ')') {
t->str += 5;
t->len -= 6;
lex_advance(s);
}
else token_error(t, lit("Unterminated string literal, missing closing parenthesis"));
break;
}
};
case 'A':case 'a':case 'M':case 'm':case 'B':
case 'b':case 'N':case 'n':case 'C':case 'c':case 'O':
case 'o':case 'D':case 'd':case 'P':case 'p':case 'E':
case 'e':case 'Q':case 'q':case 'F':case 'f':case 'R':
case 'r':case 'G':case 'g':case 'S':case 's':case 'H':
case 'h':case 'T':case 't':case 'I':case 'i':case 'U':
case 'u':case 'J':case 'j':case 'V':case 'v':case 'K':
case 'k':case 'W':case 'w':case 'L':case 'X':
case 'x':case 'Z':case 'z':case 'Y':case 'y':case '_': {
t->kind = TK_Identifier;
while(lex_is_alphanumeric(lexc(s)) || lexc(s) == '_')
lex_advance(s);
lex_set_len(s,t);
} break;
default: {
token_error(t, lit("Unknown token"));
} break;
}
}
}
function Tokens
lex_stream(String in_stream, String filename){
Lex_Stream stream = {in_stream.str, in_stream.str, filename, 0};
Tokens tokens = {};
lex_base(&stream, &tokens);
return tokens;
}
function void
token_print(Tokens tokens){
lex_print("\n== Token count = %d\n", (S32)tokens.len);
for(Token *t = tokens.tokens; t != tokens.tokens + tokens.len; t++){
lex_print("%s %.*s\n", token_kind_string[t->kind].str, (S32)t->len, t->str);
}
}
function B32
token_compare(Token *t, String str){
B32 result = string_compare(t->string, str);
return result;
}
#include "common.c"
#include "memory.c"
#include "parser.c"
#include "os_win32.c"
#include "lex.c"
#include "expr.c"
#include "decl.c"
#include "type.c"
#include "parse_expr.c"
#include "parse_decl.c"
#include "print.c"
function void
lex_test(){
Tokens t;
t = lex_stream(lit("32523 42524 \"U8Literal\""), lit("test"));
token_print(t);
t = lex_stream(lit("3252342510 42524 \"U8Literal\""), lit("test"));
//tokens_print(t);
assert(t.len == 3);
assert(t.tokens[0].int_val == 32523);
assert(t.tokens[0].int_val == 3252342510);
assert(t.tokens[1].int_val == 42524);
assert(t.tokens[2].kind == TK_U8Lit);
assert(token_compare(t.tokens + 2, lit("U8Literal")));
t = lex_stream(lit("_identifier Thing Thing2 lit(\"String_Test\")"), lit("test"));
token_print(t);
//tokens_print(t);
assert(t.tokens[0].kind == TK_Identifier);
assert(t.tokens[1].kind == TK_Identifier);
assert(t.tokens[2].kind == TK_Identifier);
@@ -345,10 +45,68 @@ lex_test(){
assert(token_compare(t.tokens+2, lit("Thing2")));
assert(token_compare(t.tokens+3, lit("String_Test")));
t = lex_stream(lit("lit(\"String_Test\"{})(324*=+=-/ *% // Comment \n Thing /*Thing*/ /*Error"), lit("test"));
t = lex_stream(lit("lit(\"String_Test\"{})(324*=+=-/ *% // Comment \n"
"Thing /*Thing*/ += -= =- +/%^&*&&|| |>> << <<= >>=/*Error"),
lit("test"));
assert(t.tokens[0].kind == TK_Error);
token_print(t);
//tokens_print(t);
}
function void
parser_test(){
Parser p = {};
{
parser_init(&p);
Intern_String a = intern_string(&p, lit("Thing"));
Intern_String b = intern_string(&p, lit("Thing"));
assert(a.s.str == b.s.str);
}
parser_lex_stream(&p, lit("S64 thing; S64 second_var = 10;"), lit("File"));
assert(token_match(&p, TK_Keyword));
assert(token_match(&p, TK_Identifier));
assert(token_match(&p, TK_Semicolon));
assert(token_match(&p, TK_Keyword));
assert(token_match(&p, TK_Identifier));
assert(token_match(&p, TK_Assign));
assert(token_match(&p, TK_Int));
assert(token_match(&p, TK_Semicolon));
assert(token_match(&p, TK_End));
assert(token_match(&p, TK_End));
assert(token_match(&p, TK_End));
String exprs[] = {
lit("(4+2*53)"),
lit("((4+2)*53"),
lit("++5"),
lit("5--"), // @Todo(Krzosa):
lit("-5"),
lit("(+5)"),
lit("(S64)5"),
lit("(S64)5+3"),
lit("534>43?435:42"),
lit("(534>43?435:42,234,(S64)42,Thing[10][2],Thing(1,2))"),
};
for(S64 i = 0; i < buff_cap(exprs); i++){
parser_lex_stream(&p, exprs[i], lit("File"));
Expr *expr = parse_expr(&p);
assert(expr);
expr_print(expr);
lex_print("\n");
}
type_test(&p);
lex_new_line();
String decls[] = {
lit("enum Thing{ Thing_1, Thing_2 = 2}"),
};
for(S64 i = 0; i < buff_cap(decls); i++){
parser_lex_stream(&p, decls[i], lit("File"));
Decl *decl = parse_decl_global(&p);
assert(decl);
decl_print(decl);
lex_new_line();
}
}
function S32
@@ -356,8 +114,28 @@ os_main(){
global_output_file = fopen("output.txt", "w");
assert_msg(global_output_file, "Failed to open output.txt");
lex_test();
parser_test();
/*
String keywords[]={
lit("S64"),
lit("U64"),
lit("void"),
lit("SizeU"),
lit("struct"),
lit("union"),
lit("function"),
lit("global"),
};
for(S64 i = 0; i < buff_cap(keywords); i++){
lex_print("global Intern_String keyword_%s;\n", keywords[i].str);
}
for(S64 i = 0; i < buff_cap(keywords); i++){
lex_print("keyword_%s = intern_string(p, lit(\"%s\"));\n", keywords[i].str, keywords[i].str);
}
*/
fclose(global_output_file);
return 0;
}

47
memory.c Normal file
View File

@@ -0,0 +1,47 @@
global const SizeU default_reserve_size = gib(4);
global const SizeU default_alignment = 8;
global const SizeU additional_commit_size = mib(1);
function void
memory_copy(U8 *dst, U8 *src, SizeU size){
for(SizeU i = 0; i < size; i++){
dst[i] = src[i];
}
}
function void
memory_zero(void *p, SizeU size){
U8 *pp = p;
for(SizeU i = 0; i < size; i++)
pp[i] = 0;
}
function void
arena_init(Arena *a){
a->memory = os_reserve(default_reserve_size);
a->alignment = default_alignment;
}
function void *
arena_push_size(Arena *a, SizeU size){
SizeU generous_size = size + a->alignment;
if(generous_size>a->memory.commit){
if(a->memory.reserve == 0){
arena_init(a);
}
os_commit(&a->memory, generous_size+additional_commit_size);
}
a->len = align_up(a->len, a->alignment);
void *result = (U8*)a->memory.data + a->len;
a->len += size;
return result;
}
function String
arena_push_string_copy(Arena *arena, String string){
U8 *copy = arena_push_array(arena, U8, string.len+1);
memory_copy(copy, string.str, string.len);
copy[string.len] = 0;
return (String){copy, string.len};
}

12
memory.h Normal file
View File

@@ -0,0 +1,12 @@
typedef struct Arena{
OS_Memory memory;
U64 len;
U64 alignment;
}Arena;
function B32 string_compare(String a, String b);
function void *arena_push_size(Arena *a, SizeU size);
function String arena_push_string_copy(Arena *arena, String string);
#define arena_push_array(a,T,c) arena_push_size(a,sizeof(T)*(c))
#define arena_push_struct(a,T) arena_push_array(a,T,1)

9
os.h Normal file
View File

@@ -0,0 +1,9 @@
typedef struct OS_Memory{
void *data;
SizeU commit;
SizeU reserve;
}OS_Memory;
function OS_Memory os_reserve(SizeU size);
function void os_commit(OS_Memory *m, SizeU size);

View File

@@ -1,9 +1,5 @@
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <windows.h>
#include "types.h"
function S32 os_main();
const SizeU page_size = 4096;
LRESULT CALLBACK
WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam){
@@ -25,3 +21,21 @@ WinMain(HINSTANCE hInstance, HINSTANCE a, LPSTR b, int nShowCmd){
ShowWindow(window_handle, nShowCmd);
return os_main();
}
function OS_Memory
os_reserve(SizeU size){
OS_Memory result = {0};
SizeU adjusted_size = align_up(size, page_size);
result.data = VirtualAlloc(0, adjusted_size, MEM_RESERVE, PAGE_READWRITE);
assert_msg(result.data, "Failed to reserve virtual memory");
result.reserve = adjusted_size;
return result;
}
function void
os_commit(OS_Memory *m, SizeU size){
SizeU commit = align_up(size, page_size);
void *p = VirtualAlloc((U8 *)m->data + m->commit, commit, MEM_COMMIT, PAGE_READWRITE);
assert_msg(p, "Failed to commit more memory");
m->commit += commit;
}

60
parse_decl.c Normal file
View File

@@ -0,0 +1,60 @@
function Decl *
parse_decl_enum(Parser *p){
Token *token = token_get(p);
Intern_String name = {};
if(token_match(p, TK_Identifier)){
name = token->intern_val;
}
Decl *result = decl_enum(p, token, name);
if(token_match(p, TK_OpenBrace)){
for(;;){
Token *token = token_get(p);
if(token_match(p, TK_Identifier)){
Expr *expr = 0;
if(token_match(p, TK_Assign)){
expr = parse_expr(p);
}
Decl_Enum_Child *child = decl_enum_child(p, token, expr);
decl_enum_push(result, child);
}
else break;
if(!token_match(p, TK_Comma))
break;
}
token_expect(p, TK_CloseBrace);
}
else {
if(name.s.str == 0){
parser_push_error(p, token, "Unnamed enum without body is illegal");
}
}
return result;
}
function Decl *
parse_decl_global(Parser *p){
Decl *result = 0;
if(token_match_keyword(p, keyword_enum)){
result = parse_decl_enum(p);
}
else if(token_match_keyword(p, keyword_typedef)){
}
else if(token_match_keyword(p, keyword_union)){
}
else if(token_match_keyword(p, keyword_struct)){
}
else if(token_match_keyword(p, keyword_global)){
}
else if(token_match_keyword(p, keyword_function)){
}
return result;
}

281
parse_expr.c Normal file
View File

@@ -0,0 +1,281 @@
function Expr* parse_expr(Parser* p);
function Expr* parse_list_expr(Parser* p);
function Expr*
parse_atom_expr(Parser* p){
Expr* result = 0;
if (token_is(p, TK_Identifier) ||
token_is(p, TK_StringLit) ||
token_is(p, TK_U8Lit) ||
token_is(p, TK_Int)){
result = expr_atom(p, token_next(p));
}
else if (token_match(p, TK_OpenParen)){
result = parse_list_expr(p);
token_expect(p, TK_CloseParen);
}
else {
parser_push_error(p, token_next(p), "Invalid expression token");
}
return result;
}
function Expr*
parse_postfix_expr(Parser* p){
Expr* result = parse_atom_expr(p);
while (token_is(p, TK_Dot)
|| token_is(p, TK_Arrow)
|| token_is(p, TK_DoubleColon)
|| token_is(p, TK_OpenParen)
|| token_is(p, TK_OpenBracket)
|| token_is(p, TK_Decrement)
|| token_is(p, TK_Increment)){
Token *op = token_get(p);
if (token_match(p, TK_Arrow)
|| token_match(p, TK_DoubleColon)
|| token_match(p, TK_Dot)){
Expr* r = parse_atom_expr(p);
result = expr_binary(p, op, result, r);
}
else if (token_match(p, TK_OpenParen)){
Expr* list = 0;
if (!token_match(p, TK_CloseParen)){
list = parse_list_expr(p);
token_expect(p, TK_CloseParen);
}
result = expr_call(p, op, result, list);
}
else if (token_match(p, TK_OpenBracket)){
Expr* list = 0;
if (!token_match(p, TK_CloseBracket)){
list = parse_list_expr(p);
token_match(p, TK_CloseBracket);
}
result = expr_index(p, op, result, list);
}
else {
assert(op->kind == TK_Increment || op->kind == TK_Decrement);
token_next(p);
if (op->kind == TK_Increment) op->kind = TK_PostIncrement;
else if (op->kind == TK_Decrement) op->kind = TK_PostDecrement;
result = expr_unary(p, op, result);
}
}
return result;
}
function
Expr* parse_unary_expr(Parser* p) {
Expr* result = 0;
if (token_is(p, TK_Sub)
|| token_is(p, TK_Add)
|| token_is(p, TK_Mul)
|| token_is(p, TK_BitAnd)
|| token_is(p, TK_Not)
|| token_is(p, TK_Neg)
|| token_is(p, TK_Increment)
|| token_is(p, TK_Decrement)) {
Token *op = token_next(p);
result = parse_unary_expr(p);
result = expr_unary(p, op, result);
}
else if (token_is_keyword(p, keyword_sizeof)) {
Token *token = token_next(p);
result = parse_unary_expr(p);
result = expr_unary(p, token, result);
}
else if (token_is(p, TK_OpenParen)) { // cast requires lookahead
Token *token = token_peek(p, 1);
if (token->kind == TK_Keyword || token->kind == TK_Identifier) {
Type *type = type_get(p, token);
if(type != type_undefined){
token_next(p);
token_next(p);
// @Todo(Krzosa): Parse pointer types
token_expect(p, TK_CloseParen);
result = parse_unary_expr(p);
result = expr_cast(p, token, type, result);
}
else {
result = parse_postfix_expr(p);
}
}
else {
result = parse_postfix_expr(p);
}
}
else {
result = parse_postfix_expr(p);
}
return result;
}
function
Expr* parse_mul_expr(Parser* p) {
Expr* result = parse_unary_expr(p);
while (token_is(p, TK_Mul)
|| token_is(p, TK_Div)
|| token_is(p, TK_Mod)) {
Token *op = token_next(p);
Expr* r = parse_unary_expr(p);
result = expr_binary(p, op, result, r);
}
return result;
}
function
Expr* parse_add_expr(Parser* p) {
Expr* result = parse_mul_expr(p);
while (token_is(p, TK_Add)
|| token_is(p, TK_Sub)) {
Token *op = token_next(p);
Expr* right = parse_mul_expr(p);
result = expr_binary(p, op, result, right);
}
return result;
}
function
Expr* parse_shift_expr(Parser* p) {
Expr* result = parse_add_expr(p);
while (token_is(p, TK_RightShift)
|| token_is(p, TK_LeftShift)) {
Token *op = token_next(p);
Expr* r = parse_add_expr(p);
result = expr_binary(p, op, result, r);
}
return result;
}
function
Expr* parse_compare_expr(Parser* p) {
Expr* result = parse_shift_expr(p);
while (token_is(p, TK_LesserThen)
|| token_is(p, TK_GreaterThen)
|| token_is(p, TK_LesserThenOrEqual)
|| token_is(p, TK_GreaterThenOrEqual)) {
Token *op = token_next(p);
Expr* r = parse_shift_expr(p);
result = expr_binary(p, op, result, r);
}
return result;
}
function
Expr* parse_equality_expr(Parser* p) {
Expr* result = parse_compare_expr(p);
while (token_is(p, TK_Equals)
|| token_is(p, TK_NotEquals)) {
Token *op = token_next(p);
Expr* r = parse_compare_expr(p);
result = expr_binary(p, op, result, r);
}
return result;
}
function
Expr* parse_bit_and_expr(Parser* p) {
Expr* result = parse_equality_expr(p);
while (token_is(p, TK_BitAnd)) {
Token *op = token_next(p);
Expr* r = parse_equality_expr(p);
result = expr_binary(p, op, result, r);
}
return result;
}
function
Expr* parse_bit_xor_expr(Parser* p) {
Expr* result = parse_bit_and_expr(p);
while (token_is(p, TK_BitXor)) {
Token *op = token_next(p);
Expr* r = parse_bit_and_expr(p);
result = expr_binary(p, op, result, r);
}
return result;
}
function
Expr* parse_bit_or_expr(Parser* p) {
Expr* result = parse_bit_xor_expr(p);
while (token_is(p, TK_BitOr)) {
Token *op = token_next(p);
Expr* r = parse_bit_xor_expr(p);
result = expr_binary(p, op, result, r);
}
return result;
}
function
Expr* parse_and_expr(Parser* p) {
Expr* result = parse_bit_or_expr(p);
while (token_is(p, TK_And)) {
Token *op = token_next(p);
Expr* r = parse_bit_or_expr(p);
result = expr_binary(p, op, result, r);
}
return result;
}
function
Expr* parse_or_expr(Parser* p) {
Expr* result = parse_and_expr(p);
while (token_is(p, TK_Or)) {
Token *op = token_next(p);
Expr* r = parse_and_expr(p);
result = expr_binary(p, op, result, r);
}
return result;
}
function
Expr* parse_ternary_expr(Parser* p) {
Expr* result = parse_or_expr(p);
if (token_is(p, TK_Question)) {
Token *token = token_next(p);
Expr* on_true = parse_ternary_expr(p);
token_expect(p, TK_Colon);
Expr* on_false = parse_ternary_expr(p);
result = expr_ternary(p, token, result, on_true, on_false);
}
return result;
}
function
Expr* parse_assign_expr(Parser* p) {
Expr* result = parse_ternary_expr(p);
if (token_is_assignment(p)) {
Token *op = token_next(p);
Expr* right = parse_assign_expr(p);
result = expr_binary(p, op, result, right);
}
return result;
}
function
Expr* parse_list_expr(Parser* p) {
Expr* result = parse_assign_expr(p);
if (token_is(p, TK_Comma)) {
Expr *list = expr_list(p, token_get(p));
expr_list_push(list, result);
result = list;
}
while (token_is(p, TK_Comma)) {
Token *token = token_next(p);
Expr* expr = parse_assign_expr(p);
expr_list_push(result, expr);
}
return result;
}
function Expr*
parse_expr(Parser* p) {
return parse_assign_expr(p);
}

214
parser.c Normal file
View File

@@ -0,0 +1,214 @@
global Intern_String keyword_s64;
global Intern_String keyword_u64;
global Intern_String keyword_void;
global Intern_String keyword_sizeu;
global Intern_String keyword_sizeof;
global Intern_String keyword_enum;
global Intern_String keyword_typedef;
global Intern_String keyword_struct;
global Intern_String keyword_union;
global Intern_String keyword_function;
global Intern_String keyword_global;
function void
parser_init(Parser *p){
p->interns_count = 4096;
p->interns = arena_push_array(&p->intern_table_arena, Intern_String, p->interns_count);
memory_zero(p->interns, sizeof(Intern_String)*p->interns_count);
p->symbols_count = 4096;
p->symbols = arena_push_array(&p->intern_table_arena, Intern_String, p->symbols_count);
memory_zero(p->symbols, sizeof(Intern_String)*p->symbols_count);
keyword_s64 = intern_string(p, lit("S64"));
keyword_u64 = intern_string(p, lit("U64"));
keyword_void = intern_string(p, lit("void"));
keyword_sizeu = intern_string(p, lit("SizeU"));
keyword_sizeof = intern_string(p, lit("sizeof"));
keyword_struct = intern_string(p, lit("struct"));
keyword_enum = intern_string(p, lit("enum"));
keyword_typedef = intern_string(p, lit("typedef"));
keyword_union = intern_string(p, lit("union"));
keyword_function = intern_string(p, lit("function"));
keyword_global = intern_string(p, lit("global"));
p->first_keyword = keyword_s64.s.str;
p->last_keyword = keyword_global.s.str;
type_insert(p, type_s64, keyword_s64);
type_insert(p, type_u64, keyword_u64);
type_insert(p, type_sizeu, keyword_sizeu);
type_insert(p, type_void, keyword_void);
}
function B32
intern_is_keyword(Parser *p, Intern_String intern){
if(intern.s.str >= p->first_keyword && intern.s.str <= p->last_keyword)
return true;
return false;
}
function void
parser_push_error(Parser *p, Token *token, char *str, ...){
String string;
{
va_list args1, args2;
va_start(args1, str);
va_copy(args2, args1);
string.len = vsnprintf(0, 0, str, args2);
va_end(args2);
string.str = arena_push_size(&p->main_arena, string.len + 1);
vsnprintf((char*)string.str, string.len + 1, str, args1);
va_end(args1);
}
Parser_Error *error = arena_push_struct(&p->main_arena, Parser_Error);
error->message = string;
error->next = 0;
error->token = token;
SLLQueuePush(p->first_error, p->last_error, error);
}
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
typedef struct Table_Index{
U64 hash;
U64 index;
U64 iter;
U64 max_size;
}Table_Index;
function Table_Index
table_index_from_hash(U64 hash, U64 max_size){
Table_Index result = {0};
result.hash = hash;
result.index = result.hash % max_size;
result.iter = result.index;
result.max_size = max_size;
return result;
}
function Table_Index
table_index_from_string(String string, U64 max_size){
U64 hash = hash_fnv(string);
Table_Index result = table_index_from_hash(hash, max_size);
return result;
}
function B32
table_index_advance(Table_Index *index){
index->iter = wrap_around_pow2(index->iter + 1, index->max_size);
B32 result = index->iter == index->index;
return result;
}
function Intern_String
intern_string(Parser *p, String string){
Intern_String result = {};
Table_Index index = table_index_from_string(string, p->interns_count);
for(;;){
Intern_String *intern = p->interns + index.iter;
if(intern->s.str == 0){
result.s = arena_push_string_copy(&p->main_arena, string);
*intern = result;
break;
}
else if(string_compare(intern->s, string)){
result = *intern;
break;
}
if (table_index_advance(&index))
break;
}
return result;
}
function void
intern_tokens(Parser *p){
for(S64 i = 0; i < p->tokens.len; i++){
Token *t = p->tokens.tokens + i;
if(t->kind == TK_Identifier){
t->intern_val = intern_string(p, t->string);
if(intern_is_keyword(p, t->intern_val)){
t->kind = TK_Keyword;
}
}
}
}
function void
symbol_insert(Parser *p, Symbol symbol){
String string = symbol.string.s;
Table_Index index = table_index_from_string(string, p->symbols_count);
for(;;){
Symbol *slot = p->symbols + index.iter;
if(slot->string.s.str == 0){
*slot = symbol;
break;
}
else if(slot->string.s.str == string.str){
invalid_codepath;
break;
}
if (table_index_advance(&index))
break;
}
}
function Symbol *
symbol_get(Parser *p, Intern_String string){
Table_Index index = table_index_from_string(string.s, p->symbols_count);
for(;;){
Symbol *slot = p->symbols + index.iter;
if(slot->string.s.str == string.s.str){
return slot;
}
if (table_index_advance(&index))
break;
}
return 0;
}
function void
type_insert(Parser *p, Type *type, Intern_String string){
Symbol symbol = {.kind=SK_Type, .string=string, .type=type};
symbol_insert(p, symbol);
}
function Type *
type_get(Parser *p, Token *token){
Type *result = 0;
if(token->kind == TK_Identifier || token->kind == TK_Keyword){
Symbol *symbol = symbol_get(p, token->intern_val);
if(symbol){
if(symbol->kind == SK_Type){
result = symbol->type;
}
else {
parser_push_error(p, token, "Symbol is not a type");
}
}
else{
parser_push_error(p, token, "Undefined type");
}
}
else {
parser_push_error(p, token, "Trying to lookup a type with token of wrong kind");
}
if(!result){
result = type_undefined;
}
return result;
}

46
parser.h Normal file
View File

@@ -0,0 +1,46 @@
#pragma once
typedef struct Type Type;
typedef struct Parser_Error Parser_Error;
typedef enum Symbol_Kind{
SK_None,
SK_Type,
}Symbol_Kind;
typedef struct Symbol{
Symbol_Kind kind;
Intern_String string;
struct{
Type *type;
};
}Symbol;
struct Parser_Error{
Parser_Error *next;
String message;
Token *token;
};
typedef struct Parser{
Arena main_arena;
Arena intern_table_arena;
Arena symbol_table_arena;
Symbol *symbols;
S64 symbols_count;
Intern_String *interns;
S64 interns_count;
U8 *first_keyword;
U8 *last_keyword;
Parser_Error *first_error;
Parser_Error *last_error;
Tokens tokens;
}Parser;
function Intern_String intern_string(Parser *p, String string);
function void type_insert(Parser *p, Type *type, Intern_String string);

133
print.c Normal file
View File

@@ -0,0 +1,133 @@
global FILE *global_output_file;
#define lex_print(...) fprintf(global_output_file, __VA_ARGS__)
#define lex_new_line() lex_print("\n")
function void
tokens_print(Tokens tokens){
lex_print("\n== Token count = %d\n", (S32)tokens.len);
for(Token *t = tokens.tokens; t != tokens.tokens + tokens.len; t++){
lex_print("%s \"%.*s\"\n", token_kind_string[t->kind].str, (S32)t->len, t->str);
}
}
function void
token_print(Token *token){
lex_print("%.*s", (S32)token->len, token->str);
}
function Type *type_pointer(Parser *p, Type *base);
function void expr_print(Expr *expr);
function void
type_print(Type *type){
switch(type->kind) {
case TK_S64: case TK_U64:
case TK_SizeU: case TK_Void: {
lex_print("%s", type_kind_string[type->kind].str);
} break;
case TK_Pointer:{
type_print(type->pointer);
lex_print("*");
} break;
case TK_Array:{
type_print(type->array.pointer);
lex_print("[");
expr_print(type->array.size);
lex_print("]");
} break;
default: {invalid_codepath;} break;
}
}
function void
type_test(Parser *p){
Type *t = type_pointer(p, type_s64);
t = type_pointer(p, t);
type_print(t);
}
function void
expr_print(Expr *expr){
switch(expr->kind) {
case EK_Atom: {
token_print(expr->token);
} break;
case EK_Binary:{
lex_print("(");
expr_print(expr->binary.left);
token_print(expr->token);
expr_print(expr->binary.right);
lex_print(")");
} break;
case EK_Unary:{
lex_print("(");
token_print(expr->token);
expr_print(expr->unary.expr);
lex_print(")");
} break;
case EK_Ternary:{
lex_print("(");
expr_print(expr->ternary.cond);
lex_print("?");
expr_print(expr->ternary.on_true);
lex_print(":");
expr_print(expr->ternary.on_false);
lex_print(")");
} break;
case EK_List:{
lex_print("(");
for(Expr *n = expr->list.first; n; n=n->next){
expr_print(n);
if(n!=expr->list.last) lex_print(",");
}
lex_print(")");
}break;
case EK_Cast:{
lex_print("(");
lex_print("(");
type_print(expr->cast.type);
lex_print(")");
expr_print(expr->cast.expr);
lex_print(")");
} break;
case EK_Index:{
expr_print(expr->index.atom);
lex_print("[");
expr_print(expr->index.index);
lex_print("]");
}break;
case EK_Call:{
expr_print(expr->call.atom);
expr_print(expr->call.list);
}break;
default: {invalid_codepath;} break;
}
}
function void
decl_print(Decl *decl){
switch(decl->kind) {
case DK_Enum: {
lex_print("enum %s{\n", decl->name.s.str);
for(Decl_Enum_Child *n = decl->enum_val.first; n; n=n->next){
lex_print(" ");
token_print(n->token);
if(n->expr){
lex_print(" = ");
expr_print(n->expr);
}
lex_print(",");
lex_new_line();
}
lex_print("};\n");
} break;
default: {invalid_codepath;} break;
}
}

25
type.c Normal file
View File

@@ -0,0 +1,25 @@
function Type *
type_new(Parser *p, Type_Kind kind){
Type *result = arena_push_struct(&p->main_arena, Type);
memory_zero(result, sizeof(Type));
result->kind = kind;
return result;
}
function Type *
type_pointer(Parser *p, Type *base){
Type *result = type_new(p, TK_Pointer);
result->size = sizeof(SizeU);
result->pointer = base;
return result;
}
function Type *
type_array(Parser *p, Type *base, Expr *index){
Type *result = type_new(p, TK_Array);
result->array.pointer = base;
result->array.size = index;
return result;
}

65
type.h Normal file
View File

@@ -0,0 +1,65 @@
#pragma once
typedef struct Type Type;
typedef struct Expr Expr;
typedef enum Type_Kind{
TK_None,
TK_Void,
TK_S64,
TK_U64,
TK_SizeU,
TK_Undefined,
TK_Function,
TK_Pointer,
TK_Array,
TK_Struct,
TK_Union,
} Type_Kind;
struct Type{
Type_Kind kind;
SizeU size;
union{
Type *pointer;
struct{
Type *pointer;
Expr *size;
} array;
};
};
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
global String type_kind_string[] = {
[TK_None] = lit("None"),
[TK_Void] = lit("void"),
[TK_S64] = lit("S64"),
[TK_U64] = lit("U64"),
[TK_SizeU] = lit("SizeU"),
[TK_Undefined] = lit("Undefined"),
[TK_Pointer] = lit("Pointer"),
[TK_Array] = lit("Array"),
[TK_Struct] = lit("Struct"),
[TK_Union] = lit("Union"),
};
global Type type_table[] = {
[TK_None] = {0},
[TK_Void] = {TK_Void},
[TK_S64] = {TK_S64, sizeof(S64)},
[TK_U64] = {TK_U64, sizeof(U64)},
[TK_SizeU] = {TK_SizeU, sizeof(SizeU)},
[TK_Undefined] = {TK_Undefined},
[TK_Pointer] = {TK_Pointer,sizeof(SizeU)},
[TK_Array] = {TK_Array,sizeof(SizeU)},
[TK_Struct] = {TK_Struct},
[TK_Union] = {TK_Union},
};
global Type *type_void = type_table + 1;
global Type *type_s64 = type_table + 2;
global Type *type_u64 = type_table + 3;
global Type *type_sizeu = type_table + 4;
global Type *type_undefined = type_table + 5;