compiler_experiment

Unnamed repository; edit this file 'description' to name the repository.
git clone https://git.deepztream.com/compiler_experiment
Log | Files | Refs

commit 9c5e2860156e8ccb4d34a710183dd411f1c2d5c1
Author: William Djupström <william@deepztream.com>
Date:   Fri,  4 Sep 2026 22:49:55 +0200

Initialize repo

Diffstat:
AMakefile | 20++++++++++++++++++++
AReferences | 1+
Adlib.h | 417+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Alexer.c | 404+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Alexer.h | 81+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Amain.c | 70++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aparser.c | 579+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aparser.h | 118+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Atest_input/binop.dc | 8++++++++
Atest_input/block.dc | 9+++++++++
Atest_input/func.dc | 4++++
Atest_input/input.dc | 19+++++++++++++++++++
Atest_input/pepeg.dc | 1002+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Atest_input/var.dc | 3+++
14 files changed, 2735 insertions(+), 0 deletions(-)

diff --git a/Makefile b/Makefile @@ -0,0 +1,20 @@ +.PHONY: run clean + +CFLAGS = -Wall -Wextra -Wswitch-enum -ggdb + +SOURCE_FILES = main.c +SOURCE_FILES += lexer.c +SOURCE_FILES += parser.c + +HEADER_FILES = dlib.h +HEADER_FILES += lexer.h +HEADER_FILES += parser.h + +dc: $(SOURCE_FILES) $(HEADER_FILES) + gcc $(CFLAGS) -o $@ $(SOURCE_FILES) + +run: dc + ./dc input.dc + +clean: + rm *.o dc diff --git a/References b/References @@ -0,0 +1 @@ +https://pp.ipd.kit.edu/uploads/publikationen/braun13cc.pdf diff --git a/dlib.h b/dlib.h @@ -0,0 +1,417 @@ +#ifndef DLIB_H +#define DLIB_H 1 + +#include <assert.h> +#include <ctype.h> +#include <fcntl.h> +#include <limits.h> +#include <stdarg.h> +#include <stdio.h> +#include <stdbool.h> +#include <stdint.h> +#include <stdlib.h> +#include <errno.h> +#include <string.h> +#include <unistd.h> + +#define unimplemented() \ + do { \ + fprintf(stderr, "%s:%i:1: Error: not implemented %s\n", __FILE__, __LINE__, __func__); \ + abort(); \ + } while (0) + +#define pop_arg(argc, argv) ((argc)--, *(argv)++) + +#define da_append(da, new)\ + do {\ + if ((da)->capacity <= (da)->count) {\ + (da)->capacity = (da)->capacity ? (da)->capacity * 2 : 16;\ + (da)->items = realloc((da)->items, sizeof(*(da)->items) * (da)->capacity);\ + }\ + (da)->items[(da)->count++] = (new);\ + } while(0) + +#define da_prepend(da, new)\ + do {\ + if ((da)->capacity <= (da)->count) {\ + (da)->capacity = (da)->capacity ? (da)->capacity * 2 : 16;\ + (da)->items = realloc((da)->items, sizeof(*(da)->items) * (da)->capacity);\ + }\ + memmove((da)->items + 1, (da)->items, sizeof(*(da)->items) * ((da)->count++));\ + (da)->items[0] = (new);\ + } while(0) + +#define da_reserve(da, len)\ + do {\ + if ((da)->capacity >= (len)) break;\ + (da)->capacity = (len);\ + (da)->items = realloc((da)->items, sizeof(*(da)->items) * (len));\ + } while(0) + +#define da_expand(da, size)\ + do {\ + if ((da)->count >= (size)) break;\ + da_reserve(da, size);\ + (da)->count = (size);\ + } while(0) + +#define da_delete(da, index)\ + do {\ + assert(index >= 0 && index < (da)->count);\ + (da)->items[index] = (da)->items[--(da)->count];\ + } while (0) + +typedef struct { + union { + char *items; + const char *data; + }; + union { + ssize_t count; + ssize_t length; + }; + ssize_t capacity; +} Sb; +#define String_builder Sb + +typedef struct { + union { + const char *items; + const char *data; + }; + union { + ssize_t count; + ssize_t length; + }; +} Sv; +#define String_view Sv + +typedef struct { + void *base; + void *head; + void *end; +} Temp_allocator; + +#define TA_DEFAULT_SIZE (1024*1024) + +void ta_init(Temp_allocator *ta, size_t size); +void *ta_alloc(Temp_allocator *ta, size_t size); + +#define sb_append_char da_append +void sb_printf(Sb *sb, const char *fmt, ...); +void sb_append_cstr(Sb *sb, const char *cstr); +void sb_append_sv(Sb *sb, Sv sv); + +bool sb_read(Sb *sb, int fd); +bool sb_read_file(Sb *sb, const char *file_name); +void sb_write(int fd, Sb sb); + +void sb_release(Sb *sb); + +#define sv_literal(str) ((Sv){.items = (str), .count = (sizeof (str) - 1)}) + +Sv sv_from_sb(Sb sb); +Sv sv_from_cstr(const char *cstr); +ssize_t sv_find_char(Sv sv, char c); + +Sv sv_chop(Sv sv, ssize_t count, Sv *rest); +Sv sv_chop_delim(Sv sv, char c, Sv *rest); + +Sv sv_getline(Sv *sv); + +Sv sv_trim_left(Sv sv); +Sv sv_trim_right(Sv sv); +Sv sv_trim(Sv sv); + +Sv sv_substring(Sv sv, ssize_t start, ssize_t req_count); + +int sv_compare(Sv sv1, Sv sv2); +bool sv_equal(Sv sv1, Sv sv2); +bool sv_starts_with_cstr(Sv sv, const char *cstr); + +void sv_write(int fd, Sv sv); + +#ifdef DLIB_IMPLEMENTATION + +void +ta_init(Temp_allocator *ta, size_t size) +{ + ta->base = malloc(size); + ta->head = ta->base; + ta->end = ta->base + size; +} + +void * +ta_alloc(Temp_allocator *ta, size_t size) +{ + if (!ta->base) { + ta->base = malloc(TA_DEFAULT_SIZE); + ta->head = ta->base; + ta->end = ta->base + TA_DEFAULT_SIZE; + } + void *result = ta->head; + ta->head += (size + 0xF) & ~0xFul; + if (ta->head >= ta->end) { + fprintf(stderr, "Error: Temp allocator out of memory\n"); + exit(1); + } + return result; +} + +void +sb_printf(Sb *sb, const char *fmt, ...) { + va_list args, args_copy; + va_start(args, fmt); + va_copy(args_copy, args); + int len = vsnprintf(NULL, 0, fmt, args_copy) + 1; + ssize_t new_size = sb->count + len; + da_reserve(sb, new_size); + va_end(args_copy); + vsnprintf(sb->items + sb->count, len, fmt, args); + va_end(args); + sb->count = new_size - 1; +} + +void +sb_append_cstr(Sb *sb, const char *cstr) +{ + ssize_t len = strlen(cstr); + da_reserve(sb, sb->count + len); + strcpy(sb->items + sb->count, cstr); + sb->count += len; +} + +void +sb_append_sv(Sb *sb, Sv sv) +{ + da_reserve(sb, sb->count + sv.count); + memcpy(sb->items + sb->count, sv.items, sv.count); + sb->count += sv.count; +} + +bool +sb_read(Sb *sb, int fd) +{ + ssize_t read_count; + ssize_t buf_size = 4096; + char *buf = malloc(buf_size); + do { + read_count = read(fd, buf, buf_size); + if (read_count < 0) { + if (errno == EINTR) { + continue; + } + perror("sb_read()"); + return false; + } + if (read_count == 0) { + break; + } + sb_append_sv(sb, ((Sv) {.items = buf, .length = read_count})); + if (read_count < buf_size) { + break; + } + } while (1); + free(buf); + return true; +} + +bool +sb_read_file(Sb *sb, const char *file_name) +{ + int fd = open(file_name, O_RDONLY); + if (fd < 0) { + perror("sb_read()"); + return false; + } + ssize_t read_count; + ssize_t buf_size = 4096; + char *buf = malloc(buf_size); + do { + read_count = read(fd, buf, buf_size); + if (read_count < 0) { + if (errno == EINTR) { + continue; + } + perror("sb_read_file()"); + return false; + } + if (read_count == 0) { + break; + } + sb_append_sv(sb, ((Sv) {.items = buf, .length = read_count})); + } while (1); + free(buf); + return true; +} + +void +sb_write(int fd, Sb sb) +{ + write(fd, sb.items, sb.length); +} + +void +sb_release(Sb *sb) +{ + if (sb->capacity) { + free(sb->items); + sb->items = NULL; + sb->count = 0; + sb->capacity = 0; + } +} + +/* String view functions */ + +void +sv_write(int fd, Sv sv) +{ + write(fd, sv.items, sv.count); +} + +Sv +sv_from_sb(Sb sb) +{ + return (Sv) {.items = sb.items, .count = sb.count}; +} + +Sv +sv_from_cstr(const char *cstr) +{ + return (Sv) {.items = cstr, .count = strlen(cstr)}; +} + +ssize_t +sv_find_char(Sv sv, char c) +{ + ssize_t pos = 0; + while (sv.count > pos && sv.items[pos] != c) + pos++; + for (pos = 0; pos < sv.count && sv.items[pos] != c; pos++); + return pos < sv.count ? pos : -1; +} + +Sv +sv_chop_delim(Sv sv, char c, Sv *rest) +{ + ssize_t pos = sv_find_char(sv, c); + Sv res = sv; + if (pos > 0) { + res.count = pos; + + rest->count -= pos + 1; + rest->items += pos + 1; + } + return res; +} + +Sv +sv_chop(Sv sv, ssize_t count, Sv *rest) +{ + Sv left = {0}; + ssize_t lcount, rcount; + if (count > sv.count) { + lcount = sv.count; + rcount = 0; + } else if (-count > sv.count) { + lcount = 0; + rcount = sv.count; + } else if (count < 0) { + lcount = sv.count + count; + rcount = -count; + } else { + lcount = count; + rcount = sv.count - count; + } + left.items = sv.items; + left.count = lcount; + if (rest) { + rest->items = sv.items + lcount; + rest->count = rcount; + } + return left; +} + +Sv +sv_trim_left(Sv sv) +{ + while (sv.count && isspace(sv.items[0])) { + sv.count--; + sv.items++; + } + return sv; +} + +Sv +sv_trim_right(Sv sv) +{ + while (sv.count && isspace(sv.items[sv.count - 1])) { + sv.count--; + } + return sv; +} + +Sv +sv_trim(Sv sv) +{ + return sv_trim_right(sv_trim_left(sv)); +} + +Sv +sv_substring(Sv sv, ssize_t start, ssize_t req_count) +{ + Sv ss = {0}; + if (start >= sv.count) return ss; + ss.count = (req_count < sv.count - start) ? req_count : sv.count - start; + ss.items = sv.items + start; + return ss; +} + +int +sv_compare(Sv sv1, Sv sv2) +{ + if (sv1.items == sv2.items && sv1.count == sv2.count) return 0; + signed char diff; + ssize_t pos; + for (pos = 0; pos < sv1.count; pos++) { + if (pos == sv2.count) return 1; + if ((diff = sv1.items[pos] - sv2.items[pos])) return diff; + } + return pos < sv2.count ? -1 : 0; +} + +bool +sv_equal(Sv sv1, Sv sv2) +{ + if (sv1.count != sv2.count) return false; + if (sv1.items == sv2.items) return true; + ssize_t pos; + for (pos = 0; pos < sv1.count && sv1.items[pos] == sv2.items[pos]; pos++); + return pos == sv1.count; +} + +bool +sv_starts_with_cstr(Sv sv, const char *cstr) +{ + size_t cstr_len = strlen(cstr); + assert(cstr_len <= SSIZE_MAX); + if (sv.count < (ssize_t) cstr_len) return false; + ssize_t pos; + for (pos = 0; pos < (ssize_t) cstr_len && sv.items[pos] == cstr[pos]; pos++); + return pos == (ssize_t) cstr_len; +} + +Sv +sv_getline(Sv *sv) +{ + Sv line = sv_chop_delim(*sv, '\n', sv); + if (line.count && line.items[line.count - 1] == '\r') { + line.count--; + } + return line; +} + +#endif // DLIB_IMPLEMENTATION + +#endif // DLIB_H diff --git a/lexer.c b/lexer.c @@ -0,0 +1,404 @@ +#include <fcntl.h> + +#include "dlib.h" +#include "lexer.h" + +Sv keywords[] = { + [T_RETURN - T_KEYWORDS_] = sv_literal("return"), + [T_IF - T_KEYWORDS_] = sv_literal("if"), + [T_ELSE - T_KEYWORDS_] = sv_literal("else"), + [T_WHILE - T_KEYWORDS_] = sv_literal("while"), + [T_FOR - T_KEYWORDS_] = sv_literal("for"), + [T_SWITCH - T_KEYWORDS_] = sv_literal("switch"), + [T_CASE - T_KEYWORDS_] = sv_literal("case"), + [T_DEFAULT - T_KEYWORDS_] = sv_literal("default"), + [T_BREAK - T_KEYWORDS_] = sv_literal("break"), + [T_CONTINUE - T_KEYWORDS_] = sv_literal("continue"), + [T_TYPEDEF - T_KEYWORDS_] = sv_literal("typedef"), + [T_FUNC - T_KEYWORDS_] = sv_literal("func"), + [T_VAR - T_KEYWORDS_] = sv_literal("var"), + [T_CONST - T_KEYWORDS_] = sv_literal("const"), + [T_STRUCT - T_KEYWORDS_] = sv_literal("struct"), + [T_UNION - T_KEYWORDS_] = sv_literal("union"), + [T_ENUM - T_KEYWORDS_] = sv_literal("enum"), + [T_OPERATOR - T_KEYWORDS_] = sv_literal("operator"), +}; + +static_assert(T_COUNT_ - T_KEYWORDS_ == 18, "keywords[] wrong length"); +int keywords_count = (sizeof(keywords) / sizeof(keywords[0])); + +void +sb_append_loc(Sb *sb, Loc loc) +{ + sb_printf(sb, "%.*s:%li:%li: ", (int) loc.filename.count, loc.filename.items, loc.line, loc.column); +} + +void +sb_append_token_kind(Sb *sb, Token_kind kind) +{ + if (kind >= 32 && kind <= 127) sb_append_char(sb, kind); + else if (kind == T_ERROR_) sb_append_cstr(sb, "T_ERROR_"); + else if (kind == T_EOF) sb_append_cstr(sb, "T_EOF"); + else if (kind == T_INVALID) sb_append_cstr(sb, "T_INVALID"); + else if (kind == T_WHITESPACE) sb_append_cstr(sb, "T_WHITESPACE"); + else if (kind == T_IDENT) sb_append_cstr(sb, "T_IDENT"); + else if (kind == T_NUMBER) sb_append_cstr(sb, "T_NUMBER"); + else if (kind == T_SQ_STRING) sb_append_cstr(sb, "T_SQ_STRING"); + else if (kind == T_DQ_STRING) sb_append_cstr(sb, "T_DQ_STRING"); + else if (kind == T_RETURN) sb_append_cstr(sb, "T_RETURN"); + else if (kind == T_IF) sb_append_cstr(sb, "T_IF"); + else if (kind == T_ELSE) sb_append_cstr(sb, "T_ELSE"); + else if (kind == T_WHILE) sb_append_cstr(sb, "T_WHILE"); + else if (kind == T_FOR) sb_append_cstr(sb, "T_FOR"); + else if (kind == T_SWITCH) sb_append_cstr(sb, "T_SWITCH"); + else if (kind == T_CASE) sb_append_cstr(sb, "T_CASE"); + else if (kind == T_DEFAULT) sb_append_cstr(sb, "T_DEFAULT"); + else if (kind == T_BREAK) sb_append_cstr(sb, "T_BREAK"); + else if (kind == T_CONTINUE) sb_append_cstr(sb, "T_CONTINUE"); + else if (kind == T_TYPEDEF) sb_append_cstr(sb, "T_TYPEDEF"); + else if (kind == T_FUNC) sb_append_cstr(sb, "T_FUNC"); + else if (kind == T_VAR) sb_append_cstr(sb, "T_VAR"); + else if (kind == T_CONST) sb_append_cstr(sb, "T_CONST"); + else if (kind == T_STRUCT) sb_append_cstr(sb, "T_STRUCT"); + else if (kind == T_UNION) sb_append_cstr(sb, "T_UNION"); + else if (kind == T_ENUM) sb_append_cstr(sb, "T_ENUM"); + else if (kind == T_OPERATOR) sb_append_cstr(sb, "T_OPERATOR"); + else sb_append_cstr(sb, "(unknown token)"); +} + +void +print_loc(Loc loc) +{ + fprintf(stderr, "%.*s:%li:%li: ", (int) loc.filename.count, loc.filename.items, loc.line, loc.column); +} + +void +print_loc_pad(Loc loc, int min_width) +{ + int len = fprintf(stderr, "%.*s:%li:%li: ", (int) loc.filename.count, loc.filename.items, loc.line, loc.column); + if (len < min_width) { + fprintf(stderr, "%*s", min_width - len, ""); + } +} + +void +debug_print_token(Token t) +{ + print_loc(t.loc); + if (t.kind == T_ERROR_) { + fprintf(stderr, "ERROR"); + } else if (t.kind >= 32 && t.kind < 127) { + fprintf(stderr, "'%c'", t.kind); + } else if (t.kind == T_EOF) { + fprintf(stderr, "EOF"); + } else if (t.kind == T_WHITESPACE) { + fprintf(stderr, "WHITESPACE(%.*s)", (int) t.sv.count, t.sv.items); + } else if (t.kind == T_IDENT) { + fprintf(stderr, "IDENT(%.*s)", (int) t.sv.count, t.sv.items); + } else if (t.kind == T_EOF) { + fprintf(stderr, "NUMBER(%.*s)", (int) t.sv.count, t.sv.items); + } else if (t.kind == T_SQ_STRING || t.kind == T_DQ_STRING) { + fprintf(stderr, "STRING(%.*s)", (int) t.sv.count, t.sv.items); + } else if (t.kind == T_RETURN) { + fprintf(stderr, "return"); + } else if (t.kind == T_IF) { + fprintf(stderr, "if"); + } else if (t.kind == T_ELSE) { + fprintf(stderr, "else"); + } else if (t.kind == T_WHILE) { + fprintf(stderr, "while"); + } else if (t.kind == T_FOR) { + fprintf(stderr, "for"); + } else if (t.kind == T_SWITCH) { + fprintf(stderr, "switch"); + } else if (t.kind == T_CASE) { + fprintf(stderr, "case"); + } else if (t.kind == T_DEFAULT) { + fprintf(stderr, "default"); + } else if (t.kind == T_BREAK) { + fprintf(stderr, "break"); + } else if (t.kind == T_CONTINUE) { + fprintf(stderr, "continue"); + } else if (t.kind == T_TYPEDEF) { + fprintf(stderr, "typedef"); + } else if (t.kind == T_FUNC) { + fprintf(stderr, "func"); + } else if (t.kind == T_VAR) { + fprintf(stderr, "var"); + } else if (t.kind == T_CONST) { + fprintf(stderr, "const"); + } else if (t.kind == T_STRUCT) { + fprintf(stderr, "struct"); + } else if (t.kind == T_UNION) { + fprintf(stderr, "union"); + } else if (t.kind == T_ENUM) { + fprintf(stderr, "enum"); + } else if (t.kind == T_OPERATOR) { + fprintf(stderr, "operator"); + } else { + fprintf(stderr, "unknown token 0x%02x", t.kind); + } + fprintf(stderr, "\n"); +} + +int +next_char(Lexer *lexer) +{ + if (!lexer->source.count) return EOF; + char c = *lexer->source.items++; + lexer->source.count--; + if (c == '\n') { + lexer->current_loc.column = 1; + lexer->current_loc.line++; + } else { + lexer->current_loc.column++; + } + return c; +} + +int +next_char_if(Lexer *lexer, int (*pred)(int)) +{ + if (!lexer->source.count) return EOF; + if (pred(*lexer->source.items)) { + return next_char(lexer); + } + return CHAR_INVALID; +} + +int +is_ident_char(int c) +{ + return c == '_' || + (c >= '0' && c <= '9') || + (c >= 'A' && c <= 'Z') || + (c >= 'a' && c <= 'z'); +} + +int +is_symbol_char(int c) +{ + return c == '+' || + c == '-' || + c == '*' || + c == '/' || + c == '%' || + c == '(' || + c == ')' || + c == '[' || + c == ']' || + c == '<' || + c == '>' || + c == '{' || + c == '}' || + c == '=' || + c == '&' || + c == '|' || + c == '^' || + c == '~' || + c == '?' || + c == '!' || + c == '.' || + c == ',' || + c == ':' || + c == ';' || + /* c == '`' || */ + /* c == '#' || */ + /* c == '@' || */ + /* c == '$' || */ + 0; +} + +int +skip_comment(Lexer *lexer) +{ + Loc start_loc = lexer->current_loc; + int len = 0; + if (sv_starts_with_cstr(lexer->source, "/*")) { + len = 2; + next_char(lexer); + next_char(lexer); + while (lexer->source.count && !sv_starts_with_cstr(lexer->source, "*/")) { + if (sv_starts_with_cstr(lexer->source, "/*")) { + len += skip_comment(lexer); + } else { + len++; + next_char(lexer); + } + } + if (!lexer->source.count) { + print_loc(start_loc); + fprintf(stderr, "Error: unterminated comment\n"); + return -1; + } + next_char(lexer); + next_char(lexer); + len += 2; + } else if (sv_starts_with_cstr(lexer->source, "//")) { + char next; + while ((next = next_char(lexer)) != '\n' && next != EOF) len++; + } + return len; +} + +Token +next_token(Lexer *lexer) +{ + Loc start_loc = lexer->current_loc; + Token result = { .loc = start_loc, .sv = { .items = lexer->source.items, .count = 0 } }; + + if (!lexer->source.count) { + result.kind = T_EOF; + return result; + } + + int c = next_char_if(lexer, isspace); + size_t len = 0; + + { + bool whitespace = false; + int comment_len = 0; + while (isspace(c) || (comment_len = skip_comment(lexer))) { + if (comment_len < 0) { + return (Token) { + .kind = T_ERROR_, + .loc = start_loc, + }; + } else if (comment_len > 0) { + len += comment_len; + } else { + len++; + } + whitespace = true; + while ((c = next_char_if(lexer, isspace)) >= 0) len++; + } + if (whitespace) { + result.kind = T_WHITESPACE; + result.sv.count = len; + return result; + } + } + + len = 1; + + c = next_char(lexer); + + if (isdigit(c)) { + while (next_char_if(lexer, isdigit) >= 0) len++; + result.kind = T_NUMBER; + result.sv.count = len; + return result; + } + + if (is_ident_char(c)) { + while (next_char_if(lexer, is_ident_char) >= 0) len++; + result.sv.count = len; + result.kind = get_keyword_kind(result.sv); + return result; + } + + if (is_symbol_char(c)) { + result.kind = c; + result.sv.count = len; + return result; + } + + if (c == '\'' || c == '"') { + char next; + while ((next = next_char(lexer)) != EOF && next != c) { + len++; + if (next == '\\') { + next_char(lexer); + len++; + } + } + if (next != c) { + print_loc(start_loc); + fprintf(stderr, "Error: unterminated %s quoted string\n", c == '"' ? "double" : "single"); + + return (Token) { + .kind = T_ERROR_, + .loc = start_loc, + }; + } + result.kind = c == '"' ? T_DQ_STRING : T_SQ_STRING; + result.sv.count = ++len; + return result; + } + + print_loc(start_loc); + fprintf(stderr, "Error: unknown character '%c'\n", c); + + return (Token) { + .kind = T_ERROR_, + .loc = start_loc, + }; +} + +Token +peek_token(Lexer *lexer) +{ + Lexer peek = *lexer; + return next_token(&peek); +} + +Token_kind +get_keyword_kind(Sv sv) +{ + int i = 0; + for (;i < keywords_count; i++) { + if (sv_equal(sv, keywords[i])) { + return i + T_KEYWORDS_; + } + } + return T_IDENT; +} + +Token +next_token_if(Lexer *lexer, int (*pred)(Token)) +{ + Lexer peek = *lexer; + Token t = next_token(&peek); + if (pred(t)) { + *lexer = peek; + return t; + } + return (Token) { + .kind = T_INVALID, + .loc = lexer->current_loc, + }; +} + +void +skip_whitespace(Lexer *lexer) +{ + Lexer peek = *lexer; + Token t = next_token(&peek); + if (t.kind == T_WHITESPACE) { + *lexer = peek; + } +} + +Token +expect_token_kind(Lexer *lexer, Token_kind kind) +{ + Token t = next_token(lexer); + if (t.kind != kind) { + Sb error = {0}; + + sb_append_loc(&error, t.loc); + sb_append_cstr(&error, "Error: expected token "); + sb_append_token_kind(&error, kind); + sb_append_cstr(&error, ", but got "); + sb_append_token_kind(&error, t.kind); + + fprintf(stderr, "%.*s\n", (int) error.count, error.items); + + sb_release(&error); + return (Token) { + .kind = T_ERROR_, + .loc = t.loc, + }; + } + return t; +} diff --git a/lexer.h b/lexer.h @@ -0,0 +1,81 @@ +#ifndef DC_LEXER_H +#define DC_LEXER_H + +#include "dlib.h" + +typedef struct { + Sv filename; + size_t line, column; +} Loc; + +typedef enum { + T_ERROR_ = 0, + T_EOF = 256, + T_INVALID, + T_WHITESPACE, + T_IDENT, + T_NUMBER, + T_SQ_STRING, + T_DQ_STRING, + + T_KEYWORDS_, + + T_RETURN = T_KEYWORDS_, + T_IF, + T_ELSE, + T_WHILE, + T_FOR, + T_SWITCH, + T_CASE, + T_DEFAULT, + T_BREAK, + T_CONTINUE, + T_TYPEDEF, + T_FUNC, + T_VAR, + T_CONST, + T_STRUCT, + T_UNION, + T_ENUM, + T_OPERATOR, + + T_COUNT_ +} Token_kind; + +typedef struct { + Token_kind kind; + Loc loc; + Sv sv; +} Token; + +typedef struct { + Sv source; + Loc current_loc; +} Lexer; + +#define CHAR_INVALID (-2) +int next_char(Lexer *lexer); +int next_char_if(Lexer *lexer, int (*pred)(int)); + +int is_ident_char(int c); +int is_symbol_char(int c); + +int skip_comment(Lexer *lexer); +Token next_token(Lexer *lexer); +Token peek_token(Lexer *lexer); + +Token_kind get_keyword_kind(Sv sv); + +Token next_token_if(Lexer *lexer, int (*pred)(Token)); +Token next_token_if_kind(Lexer *lexer, Token_kind kind); +Token expect_token_kind(Lexer *lexer, Token_kind kind); +void skip_whitespace(Lexer *lexer); + +void sb_append_token_kind(Sb *sb, Token_kind kind); +void sb_append_loc(Sb *sb, Loc loc); + +void print_loc(Loc loc); +void print_loc_pad(Loc loc, int min_width); +void debug_print_token(Token t); + +#endif /* DC_LEXER_H */ diff --git a/main.c b/main.c @@ -0,0 +1,70 @@ +#define DLIB_IMPLEMENTATION +#include "dlib.h" + +#include "lexer.h" +#include "parser.h" + +Ast_node * +malloc_ast() +{ + void *result = malloc(sizeof(Ast_node)); + if (!result) { + fprintf(stderr, "malloc_ast(): Out of memory\n"); + abort(); + } + return result; +} + +void +free_ast(Ast_node *node) +{ + free(node); +} + +void +usage(FILE *out, const char *program_name) +{ + fprintf(out, "Usage: %s <input>\n", program_name); +} + +int +main(int argc, char **argv) +{ + assert(argc > 0); + char *program_name = pop_arg(argc, argv); + if (!argc) { + fprintf(stderr, "Error: Missing input file\n"); + usage(stderr, program_name); + return 1; + } + Sb input_source = {0}; + char *input_file_name = pop_arg(argc, argv); + if (!sb_read_file(&input_source, input_file_name)) { + return 1; + } + Lexer lexer = { + .source = sv_from_sb(input_source), + .current_loc = { + .filename = sv_from_cstr(input_file_name), + .line = 1, + .column = 1 + } + }; + Parser parser = { + .lexer = lexer, + .ast_alloc = malloc_ast, + .ast_free = free_ast, + }; + Ast_node_list ast = parse(&parser); + for (int i = 0; i < ast.count; ++i) { + debug_print_ast_node(ast.items[i], 0); + } + /* + Token t; + while ((t = next_token(&lexer)).kind != T_EOF && t.kind != T_ERROR) { + if (t.kind != T_WHITESPACE) debug_print_token(t); + } + debug_print_token(t); + */ + return 0; +} diff --git a/parser.c b/parser.c @@ -0,0 +1,579 @@ +#include "lexer.h" +#include "parser.h" + +int binop_precedence[] = { + [BINOP_INVALID] = 250, + [BINOP_ADD] = 20, + [BINOP_SUB] = 20, + [BINOP_MUL] = 10, + [BINOP_DIV] = 10, + [BINOP_MOD] = 10, + [BINOP_BAND] = 60, + [BINOP_BOR] = 80, + [BINOP_BXOR] = 70, + [BINOP_LSHIFT] = 30, + [BINOP_RSHIFT] = 30, + [BINOP_ASSIGN] = 121, + [BINOP_ADD_ASSIGN] = 121, + [BINOP_SUB_ASSIGN] = 121, + [BINOP_MUL_ASSIGN] = 121, + [BINOP_DIV_ASSIGN] = 121, + [BINOP_MOD_ASSIGN] = 121, + [BINOP_BAND_ASSIGN] = 121, + [BINOP_BOR_ASSIGN] = 121, + [BINOP_BXOR_ASSIGN] = 121, + [BINOP_LSHIFT_ASSIGN] = 121, + [BINOP_RSHIFT_ASSIGN] = 121, + [BINOP_LAND] = 90, + [BINOP_LOR] = 110, + [BINOP_LXOR] = 100, + [BINOP_LT] = 40, + [BINOP_LE] = 40, + [BINOP_EQ] = 50, + [BINOP_NEQ] = 50, + [BINOP_GE] = 40, + [BINOP_GT] = 40, + [BINOP_COMMA] = 130, + [BINOP_ALL_] = 140, +}; + +Ast_node * +new_ast_node(Parser *p, Ast_kind kind, Token loc) +{ + Ast_node *result = p->ast_alloc(); + result->kind = kind; + result->start_tok = loc; + return result; +} + +Ast_node * +parse_postfix(Parser *p, Ast_node *child) +{ + (void) p; + return child; +} + +Ast_node * +parse_primitive(Parser *p) +{ + Ast_node *result; + Token t = next_token(&p->lexer); + if (t.kind == T_NUMBER) { + result = new_ast_node(p, AST_NUMBER, t); + } else if (t.kind == T_IDENT) { + result = new_ast_node(p, AST_IDENT, t); + } else if (t.kind == '(') { + result = parse_expression(p); + expect_token_kind(&p->lexer, ')'); + } else { + Sb sb = {0}; + sb_append_loc(&sb, t.loc); + sb_append_cstr(&sb, "Error: invalid primitive "); + sb_append_token_kind(&sb, t.kind); + sb_append_char(&sb, '\n'); + sb_write(2, sb); + sb_release(&sb); + abort(); + } + return parse_postfix(p, result); +} + +Ast_node * +parse_prefix(Parser *p) +{ + Ast_node *result = parse_primitive(p); + return result; +} + +Binop +collect_binop(Parser *p) +{ + Lexer saved_lexer; + Token peek = peek_token(&p->lexer); + Binop result = { .tok = peek }; + switch((int) peek.kind) { + case '+': + next_token(&p->lexer); + peek = peek_token(&p->lexer); + if (peek.kind == '=') { + next_token(&p->lexer); + result.kind = BINOP_ADD_ASSIGN; + result.tok.sv.count++; + } else { + result.kind = BINOP_ADD; + } + break; + case '-': + next_token(&p->lexer); + peek = peek_token(&p->lexer); + if (peek.kind == '=') { + next_token(&p->lexer); + result.kind = BINOP_SUB_ASSIGN; + result.tok.sv.count++; + } else { + result.kind = BINOP_SUB; + } + break; + case '*': + next_token(&p->lexer); + peek = peek_token(&p->lexer); + if (peek.kind == '=') { + next_token(&p->lexer); + result.kind = BINOP_MUL_ASSIGN; + result.tok.sv.count++; + } else { + result.kind = BINOP_MUL; + } + break; + case '/': + next_token(&p->lexer); + peek = peek_token(&p->lexer); + if (peek.kind == '=') { + next_token(&p->lexer); + result.kind = BINOP_DIV_ASSIGN; + result.tok.sv.count++; + } else { + result.kind = BINOP_DIV; + } + break; + case '%': + next_token(&p->lexer); + peek = peek_token(&p->lexer); + if (peek.kind == '=') { + next_token(&p->lexer); + result.kind = BINOP_MOD_ASSIGN; + result.tok.sv.count++; + } else { + result.kind = BINOP_MOD; + } + break; + case '&': + next_token(&p->lexer); + peek = peek_token(&p->lexer); + if (peek.kind == '=') { + next_token(&p->lexer); + result.kind = BINOP_BAND_ASSIGN; + result.tok.sv.count++; + } else if (peek.kind == '&') { + next_token(&p->lexer); + result.kind = BINOP_LAND; + result.tok.sv.count++; + } else { + result.kind = BINOP_BAND; + } + break; + case '|': + next_token(&p->lexer); + peek = peek_token(&p->lexer); + if (peek.kind == '=') { + next_token(&p->lexer); + result.kind = BINOP_BOR_ASSIGN; + result.tok.sv.count++; + } else if (peek.kind == '|') { + next_token(&p->lexer); + result.kind = BINOP_LOR; + result.tok.sv.count++; + } else { + result.kind = BINOP_BOR; + } + break; + case '^': + next_token(&p->lexer); + peek = peek_token(&p->lexer); + if (peek.kind == '=') { + next_token(&p->lexer); + result.kind = BINOP_BXOR_ASSIGN; + result.tok.sv.count++; + } else if (peek.kind == '^') { + next_token(&p->lexer); + result.kind = BINOP_LXOR; + result.tok.sv.count++; + } else { + result.kind = BINOP_BXOR; + } + break; + case '<': + next_token(&p->lexer); + peek = peek_token(&p->lexer); + if (peek.kind == '=') { + next_token(&p->lexer); + result.kind = BINOP_LE; + result.tok.sv.count++; + } else if (peek.kind == '<') { + next_token(&p->lexer); + peek = peek_token(&p->lexer); + if (peek.kind == '=') { + next_token(&p->lexer); + result.kind = BINOP_LSHIFT_ASSIGN; + result.tok.sv.count++; + } else { + result.kind = BINOP_LSHIFT; + result.tok.sv.count++; + } + } else { + result.kind = BINOP_LT; + } + break; + case '>': + next_token(&p->lexer); + peek = peek_token(&p->lexer); + if (peek.kind == '=') { + next_token(&p->lexer); + result.kind = BINOP_GE; + result.tok.sv.count++; + } else if (peek.kind == '>') { + next_token(&p->lexer); + peek = peek_token(&p->lexer); + if (peek.kind == '=') { + next_token(&p->lexer); + result.kind = BINOP_RSHIFT_ASSIGN; + result.tok.sv.count++; + } else { + result.kind = BINOP_RSHIFT; + result.tok.sv.count++; + } + } else { + result.kind = BINOP_GT; + } + break; + case '=': + next_token(&p->lexer); + peek = peek_token(&p->lexer); + if (peek.kind == '=') { + next_token(&p->lexer); + result.kind = BINOP_EQ; + result.tok.sv.count++; + } else { + result.kind = BINOP_ASSIGN; + } + break; + case '!': + saved_lexer = p->lexer; + next_token(&p->lexer); + peek = peek_token(&p->lexer); + if (peek.kind == '=') { + next_token(&p->lexer); + result.kind = BINOP_NEQ; + result.tok.sv.count++; + } else { + p->lexer = saved_lexer; + result.kind = BINOP_INVALID; + } + break; + case ',': + next_token(&p->lexer); + result.kind = BINOP_COMMA; + break; + default: + result.kind = BINOP_INVALID; + break; + } + return result; +} + +Ast_node * +parse_binop(Parser *p, int precedence, Ast_node *left_child) +{ + Lexer saved_lexer; + Ast_node *left; + Ast_node *right = NULL; + Ast_node *result; + Binop binop; + int next_prec; + if (!left_child) { + left = parse_prefix(p); + } else { + left = left_child; + } + do { + saved_lexer = p->lexer; + skip_whitespace(&p->lexer); + Binop binop_peek = collect_binop(p); + next_prec = binop_precedence[binop_peek.kind]; + if (binop_peek.kind == BINOP_INVALID) { + break; + } + if (next_prec > precedence) { + p->lexer = saved_lexer; + break; + } + if (next_prec < precedence) { + p->lexer = saved_lexer; + skip_whitespace(&p->lexer); + if (right) { + right = parse_binop(p, next_prec, right); + } else { + left = parse_binop(p, next_prec, left); + } + continue; + } + skip_whitespace(&p->lexer); + if (right) { + result = new_ast_node(p, AST_BINOP, binop.tok); + result->binop.op = binop; + result->binop.left = left; + result->binop.right = right; + left = result; + } + binop = binop_peek; + if (next_prec & 1) { + right = parse_binop(p, next_prec, NULL); + } else { + right = parse_prefix(p); + } + } while (1); + if (right) { + result = new_ast_node(p, AST_BINOP, binop.tok); + result->binop.op = binop; + result->binop.left = left; + result->binop.right = right; + left = result; + } + return left; +} + +Ast_node * +parse_expression(Parser *p) +{ + Ast_node *result = parse_binop(p, binop_precedence[BINOP_ALL_], NULL); + return result; +} + +Ast_node * +parse_type(Parser *p) +{ + Token base = expect_token_kind(&p->lexer, T_IDENT); + return new_ast_node(p, AST_TYPE, base); +} + +Ast_node * +parse_var_declaration(Parser *p) +{ + Token var_name; + Ast_node *var_type = NULL; + Ast_node *var_value = NULL; + Ast_node *result; + + var_name = expect_token_kind(&p->lexer, T_IDENT); + skip_whitespace(&p->lexer); + expect_token_kind(&p->lexer, ':'); + skip_whitespace(&p->lexer); + if (peek_token(&p->lexer).kind != '=') { + var_type = parse_type(p); + skip_whitespace(&p->lexer); + } + if (peek_token(&p->lexer).kind == '=') { + next_token(&p->lexer); + skip_whitespace(&p->lexer); + var_value = parse_expression(p); + } + result = new_ast_node(p, AST_VAR_DECL, var_name); + result->var.name = var_name; + result->var.type = var_type; + result->var.value = var_value; + + return result; +} + +Ast_node * +parse_var_declaration_statement(Parser *p) { + Token start_tok; + start_tok = expect_token_kind(&p->lexer, T_VAR); + + skip_whitespace(&p->lexer); + Ast_node *result = parse_var_declaration(p); + + skip_whitespace(&p->lexer); + expect_token_kind(&p->lexer, ';'); + + result->start_tok = start_tok; + return result; +} + +Ast_node * +parse_block(Parser *p) +{ + Token end_tok; + Token start_tok = expect_token_kind(&p->lexer, '{'); + skip_whitespace(&p->lexer); + Ast_node *node, *result; + Ast_node_list list = {0}; + Token peek; + skip_whitespace(&p->lexer); + while ((peek = peek_token(&p->lexer)).kind != '}') { + if (peek.kind == T_VAR) { + node = parse_var_declaration_statement(p); + } else if (peek.kind == ';') { + next_token(&p->lexer); + skip_whitespace(&p->lexer); + continue; + } else if (peek.kind == '{') { + node = parse_block(p); + } else if (peek.kind == T_EOF) { + // Leaking nodes + free(list.items); + + print_loc(start_tok.loc); + fprintf(stderr, "Error: unterminated block\n"); + return new_ast_node(p, AST_ERROR, peek); + } else if (peek.kind == T_ERROR_) { + // Leaking nodes + free(list.items); + return new_ast_node(p, AST_ERROR, peek); + } else { + node = parse_expression(p); + expect_token_kind(&p->lexer, ';'); + } + da_append(&list, node); + skip_whitespace(&p->lexer); + } + end_tok = expect_token_kind(&p->lexer, '}'); + result = new_ast_node(p, AST_BLOCK, start_tok); + result->block.list = list; + result->block.end_tok = end_tok; + return result; +} + +Ast_node_list +parse_func_arg_declaraction_list(Parser *p) +{ + Token peek; + Ast_node *node; + Ast_node_list list = {0}; + while ((peek = peek_token(&p->lexer)).kind != ')') { + node = parse_var_declaration(p); + da_append(&list, node); + skip_whitespace(&p->lexer); + } + return list; +} + +Ast_node * +parse_func_declaration_statement(Parser *p) +{ + Ast_node *ret_type = NULL; + Ast_node *result; + Token start_tok = expect_token_kind(&p->lexer, T_FUNC); + skip_whitespace(&p->lexer); + Token name = expect_token_kind(&p->lexer, T_IDENT); + + skip_whitespace(&p->lexer); + expect_token_kind(&p->lexer, '('); + skip_whitespace(&p->lexer); + Ast_node_list arg_list = parse_func_arg_declaraction_list(p); + expect_token_kind(&p->lexer, ')'); + + skip_whitespace(&p->lexer); + if (peek_token(&p->lexer).kind == '-') { + expect_token_kind(&p->lexer, '-'); + expect_token_kind(&p->lexer, '>'); + skip_whitespace(&p->lexer); + ret_type = parse_type(p); + skip_whitespace(&p->lexer); + } + + Ast_node *body = parse_block(p); + + result = new_ast_node(p, AST_FUNC_DECL, start_tok); + result->func.body = body; + result->func.ret_type = ret_type; + result->func.name = name; + result->func.arg_list = arg_list; + return result; +} + +Ast_node_list +parse(Parser *p) +{ + Ast_node *node; + Ast_node_list list = {0}; + Token peek; + skip_whitespace(&p->lexer); + while ((peek = peek_token(&p->lexer)).kind != T_EOF) { + if (peek.kind == T_VAR) { + node = parse_var_declaration_statement(p); + } else if (peek.kind == T_FUNC) { + node = parse_func_declaration_statement(p); + } else if (peek.kind == T_ERROR_) { + abort(); + } else { + Sb sb = {0}; + sb_append_loc(&sb, peek.loc); + sb_append_cstr(&sb, "Error: invalid top level declaration at token "); + sb_append_token_kind(&sb, peek.kind); + sb_append_char(&sb, '\n'); + sb_write(2, sb); + sb_release(&sb); + abort(); + } + da_append(&list, node); + skip_whitespace(&p->lexer); + } + return list; +} + +void +debug_print_ast_node(Ast_node *node, int indent) +{ + if (!node) { + fprintf(stderr, "%*s", indent * 2, ""); + fprintf(stderr, "(null)"); + return; + } + int min_width = node->start_tok.loc.filename.count + 11; + print_loc_pad(node->start_tok.loc, min_width); + fprintf(stderr, "%*s", indent * 2, ""); + + switch (node->kind) { + case AST_TYPE: + fprintf(stderr, "Type(%.*s)\n", (int) node->start_tok.sv.count, node->start_tok.sv.items); + break; + case AST_VAR_DECL: + fprintf(stderr, "VarDecl(%.*s)\n", (int) node->var.name.sv.count, node->var.name.sv.items); + if (node->var.type) { + debug_print_ast_node(node->var.type, indent + 1); + } + if (node->var.value) { + debug_print_ast_node(node->var.value, indent + 1); + } + break; + case AST_FUNC_DECL: + fprintf(stderr, "FuncDecl(%.*s)\n", (int) node->func.name.sv.count, node->func.name.sv.items); + if (node->func.ret_type) { + debug_print_ast_node(node->func.ret_type, indent + 1); + } + for (int i = 0; i < node->func.arg_list.count; ++i) { + debug_print_ast_node(node->func.arg_list.items[i], indent + 1); + } + debug_print_ast_node(node->func.body, indent + 1); + break; + case AST_TYPE_DECL: + fprintf(stderr, "TypeDecl\n"); + break; + case AST_BLOCK: + fprintf(stderr, "Block {\n"); + for (int i = 0; i < node->block.list.count; ++i) { + debug_print_ast_node(node->block.list.items[i], indent + 1); + } + print_loc_pad(node->block.end_tok.loc, min_width); + fprintf(stderr, "%*s\n", indent * 2, "}"); + break; + case AST_BINOP: + fprintf(stderr, "Binop(%.*s)\n", (int) node->binop.op.tok.sv.count, node->binop.op.tok.sv.items); + debug_print_ast_node(node->binop.left, indent + 1); + debug_print_ast_node(node->binop.right, indent + 1); + break; + case AST_NUMBER: + fprintf(stderr, "Number(%.*s)\n", (int) node->start_tok.sv.count, node->start_tok.sv.items); + break; + case AST_IDENT: + fprintf(stderr, "Ident(%.*s)\n", (int) node->start_tok.sv.count, node->start_tok.sv.items); + break; + case AST_ERROR: + fprintf(stderr, "Error\n"); + break; + default: + fprintf(stderr, "Unreachable\n"); + abort(); + } +} diff --git a/parser.h b/parser.h @@ -0,0 +1,118 @@ +#ifndef DC_PARSER_H +#define DC_PARSER_H + +typedef enum { + BINOP_INVALID, + + BINOP_ADD, + BINOP_SUB, + BINOP_MUL, + BINOP_DIV, + BINOP_MOD, + BINOP_BAND, + BINOP_BOR, + BINOP_BXOR, + BINOP_LSHIFT, + BINOP_RSHIFT, + + BINOP_ASSIGN, + + BINOP_ADD_ASSIGN, + BINOP_SUB_ASSIGN, + BINOP_MUL_ASSIGN, + BINOP_DIV_ASSIGN, + BINOP_MOD_ASSIGN, + BINOP_BAND_ASSIGN, + BINOP_BOR_ASSIGN, + BINOP_BXOR_ASSIGN, + BINOP_LSHIFT_ASSIGN, + BINOP_RSHIFT_ASSIGN, + + BINOP_LAND, + BINOP_LOR, + BINOP_LXOR, + BINOP_LT, + BINOP_LE, + BINOP_EQ, + BINOP_NEQ, + BINOP_GE, + BINOP_GT, + + BINOP_COMMA, + BINOP_ALL_, +} Binop_kind; + +typedef struct { + Binop_kind kind; + Token tok; +} Binop; + +typedef enum { + AST_ERROR = 0, + AST_TYPE, + AST_VAR_DECL, + AST_FUNC_DECL, + AST_TYPE_DECL, + AST_BLOCK, + AST_BINOP, + AST_NUMBER, + AST_IDENT, +} Ast_kind; + +typedef struct Ast_node Ast_node; + +typedef struct { + Ast_node **items; + int count; + int capacity; +} Ast_node_list; + +struct Ast_node { + Ast_kind kind; + Token start_tok; + union { + struct { + Binop op; + Ast_node *left; + Ast_node *right; + } binop; + struct { + Token name; + Ast_node *type; + Ast_node *value; + } var; + struct { + Token name; + Ast_node_list arg_list; + Ast_node *ret_type; + Ast_node *body; + } func; + struct { + Ast_node_list list; + Token end_tok; + } block; + }; +}; + +typedef Ast_node *(*Ast_alloc_fn)(); +typedef void (*Ast_free_fn)(Ast_node *); + +typedef struct { + Lexer lexer; + Ast_alloc_fn ast_alloc; + Ast_free_fn ast_free; +} Parser; + +Ast_node *parse_postfix(Parser *p, Ast_node *child); +Ast_node *parse_primitive(Parser *p); +Ast_node *parse_prefix(Parser *p); +Ast_node *parse_binop(Parser *p, int precedence, Ast_node *left_child); +Ast_node *parse_expression(Parser *p); +Ast_node *parse_type(Parser *p); +Ast_node *parse_var_declaration(Parser *p); + +Ast_node_list parse(Parser *p); + +void debug_print_ast_node(Ast_node *node, int indent); + +#endif /* DC_PARSER_H */ diff --git a/test_input/binop.dc b/test_input/binop.dc @@ -0,0 +1,8 @@ +var i:= 1+2; +var j:= 1+2+3+4; +var k:= 1+2*3; +var l:= 1+2*3+4; +var m:= 1+2+3*4; +var n:= 1+2+3*4+5; + +var assign := i = j + 4 = k; diff --git a/test_input/block.dc b/test_input/block.dc @@ -0,0 +1,9 @@ +var i := 50; +var j : = 69; +{ + var k: i32 = 10; + var m: i64; + ;;;; +} + +var n : i16= 1337; diff --git a/test_input/func.dc b/test_input/func.dc @@ -0,0 +1,4 @@ +func fib(count: i32) { + var a := 0; + var b := 1; +} diff --git a/test_input/input.dc b/test_input/input.dc @@ -0,0 +1,19 @@ +// Basic 2 dimensional vector +typedef Vec2i: struct { + a: int; + b: int; +}; + +/************************************************************ + * Operator overloading for `Vec2i + Vec2i` * + * /* Now we have the ability to support nested comments */ * + * Returns a new `Vec2i` with it's elements being * + * the result of element-wise summation of the operands. * + ************************************************************/ + +operator[infix, prec('+')] + (left: Vec2i, right: Vec2i) -> Vec2i { + var result: Vec2i = left; + result.a += right.a; + result.b += right.b; + return result; +} diff --git a/test_input/pepeg.dc b/test_input/pepeg.dc @@ -0,0 +1,1002 @@ +var first := 1; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +var second := 1337; diff --git a/test_input/var.dc b/test_input/var.dc @@ -0,0 +1,3 @@ +var i := 10; +var j: i32 = 0; +var k :i64;