From 3d87b4276d9f31d93ff0d0b743394e594cf390f0 Mon Sep 17 00:00:00 2001 From: "Michael D. Lowis" Date: Thu, 15 Apr 2021 13:22:18 -0400 Subject: [PATCH] plopped in code for a simple compiler based on sclpl. Will start reworking it into an Oberon/Cerise compiler --- cerise/ast.c | 193 +++++++++++++++++++++++++++++ cerise/atf.h | 160 ++++++++++++++++++++++++ cerise/build.sh | 3 + cerise/codegen.c | 12 ++ cerise/emalloc.c | 11 ++ cerise/lex.c | 250 +++++++++++++++++++++++++++++++++++++ cerise/main.c | 49 ++++++++ cerise/parser.c | 117 ++++++++++++++++++ cerise/pkg.c | 23 ++++ cerise/pprint.c | 217 ++++++++++++++++++++++++++++++++ cerise/sclpl | Bin 0 -> 34928 bytes cerise/sclpl.h | 313 +++++++++++++++++++++++++++++++++++++++++++++++ cerise/syms.c | 22 ++++ cerise/types.c | 59 +++++++++ cerise/value | 0 15 files changed, 1429 insertions(+) create mode 100644 cerise/ast.c create mode 100644 cerise/atf.h create mode 100755 cerise/build.sh create mode 100644 cerise/codegen.c create mode 100644 cerise/emalloc.c create mode 100644 cerise/lex.c create mode 100644 cerise/main.c create mode 100644 cerise/parser.c create mode 100644 cerise/pkg.c create mode 100644 cerise/pprint.c create mode 100755 cerise/sclpl create mode 100644 cerise/sclpl.h create mode 100644 cerise/syms.c create mode 100644 cerise/types.c create mode 100644 cerise/value diff --git a/cerise/ast.c b/cerise/ast.c new file mode 100644 index 0000000..a3fd9d4 --- /dev/null +++ b/cerise/ast.c @@ -0,0 +1,193 @@ +#include + +static AST* ast(ASTType type) { + AST* tree = emalloc(sizeof(AST)); + memset(tree, 0, sizeof(AST)); + tree->nodetype = type; + return tree; +} + +AST* String(char* val) { + AST* node = ast(AST_STRING); + node->value.text = val; + return node; +} + +char* string_value(AST* val) { + assert(val->nodetype == AST_STRING); + return val->value.text; +} + +AST* Char(int val) { + AST* node = ast(AST_CHAR); + node->value.integer = val; + return node; +} + +uint32_t char_value(AST* val) { + assert(val->nodetype == AST_CHAR); + return val->value.integer; +} + +AST* Integer(int val) { + AST* node = ast(AST_INT); + node->value.integer = val; + return node; +} + +intptr_t integer_value(AST* val) { + assert(val->nodetype == AST_INT); + return val->value.integer; +} + +AST* Float(double val) { + AST* node = ast(AST_FLOAT); + node->value.floating = val; + return node; +} + +double float_value(AST* val) { + assert(val->nodetype == AST_FLOAT); + return val->value.floating; +} + +AST* Bool(bool val) { + AST* node = ast(AST_BOOL); + node->value.integer = val; + return node; +} + +bool bool_value(AST* val) { + assert(val->nodetype == AST_BOOL); + return val->value.integer; +} + +AST* Ident(char* val) { + AST* node = ast(AST_IDENT); + node->value.text = strdup(val); + return node; +} + +char* ident_value(AST* val) { + assert(val->nodetype == AST_IDENT); + return val->value.text; +} + +AST* Var(char* name, AST* value, AST* type, int flags) { + (void)type; + AST* node = ast(AST_VAR); + node->value.var.name = name; + node->value.var.value = value; + node->value.var.flags = flags; + return node; +} + +char* var_name(AST* var) { + assert(var->nodetype == AST_VAR); + return var->value.var.name; +} + +AST* var_value(AST* var) { + assert(var->nodetype == AST_VAR); + return var->value.var.value; +} + +bool var_flagset(AST* var, int mask) { + assert(var->nodetype == AST_VAR); + return ((var->value.var.flags & mask) == mask); +} + +AST* Func(AST* args, AST* body, AST* type) +{ + (void)type; + AST* node = ast(AST_FUNC); + node->value.nodes[0] = args; + node->value.nodes[1] = body; + return node; +} + +AST* func_args(AST* func) { + assert(func->nodetype == AST_FUNC); + return func->value.nodes[0]; +} + +AST* func_body(AST* func) { + assert(func->nodetype == AST_FUNC); + return func->value.nodes[1]; +} + +AST* ExpList(void) { + AST* node = ast(AST_EXPLIST); + node->value.explist.nexprs = 0; + node->value.explist.exprs = 0; + return node; +} + +AST** explist_get(AST* explist, size_t* nexprs) { + assert(explist->nodetype == AST_EXPLIST); + *nexprs = explist->value.explist.nexprs; + return explist->value.explist.exprs; +} + +void explist_append(AST* explist, AST* expr) { + assert(explist->nodetype == AST_EXPLIST); + explist->value.explist.nexprs += 1; + explist->value.explist.exprs = realloc(explist->value.explist.exprs, explist->value.explist.nexprs * sizeof(AST*)); + explist->value.explist.exprs[explist->value.explist.nexprs-1] = expr; +} + +void explist_prepend(AST* explist, AST* expr) { + assert(explist->nodetype == AST_EXPLIST); + explist->value.explist.nexprs++; + explist->value.explist.exprs = realloc(explist->value.explist.exprs, explist->value.explist.nexprs * sizeof(AST*)); + memmove(explist->value.explist.exprs+1, explist->value.explist.exprs, explist->value.explist.nexprs-1); + explist->value.explist.exprs[0] = expr; +} + +AST* If(AST* cond, AST* b1, AST* b2) { + AST* node = ast(AST_IF); + node->value.nodes[0] = cond; + node->value.nodes[1] = b1; + node->value.nodes[2] = b2; + return node; +} + +AST* if_cond(AST* ifexp) { + assert(ifexp->nodetype == AST_IF); + return ifexp->value.nodes[0]; +} + +AST* if_then(AST* ifexp) { + assert(ifexp->nodetype == AST_IF); + return ifexp->value.nodes[1]; +} + +AST* if_else(AST* ifexp) { + assert(ifexp->nodetype == AST_IF); + return ifexp->value.nodes[2]; +} + +AST* Apply(AST* func, AST* args) { + AST* node = ast(AST_APPLY); + node->value.nodes[0] = func; + node->value.nodes[1] = args; + return node; +} + +AST* apply_func(AST* apply) { + assert(apply->nodetype == AST_APPLY); + return apply->value.nodes[0]; +} + +AST* apply_args(AST* apply) { + assert(apply->nodetype == AST_APPLY); + return apply->value.nodes[1]; +} + +AST* OpCall(int oper, AST* left, AST* right) { + AST* node = ast(AST_OPER); + node->value.op.oper = oper; + node->value.op.left = left; + node->value.op.right = right; + return node; +} diff --git a/cerise/atf.h b/cerise/atf.h new file mode 100644 index 0000000..40088ed --- /dev/null +++ b/cerise/atf.h @@ -0,0 +1,160 @@ +/** + Aardvark Test Framework - A minimalistic unit testing framework for C. + + Copyright 2014 Michael D. Lowis + + Permission to use, copy, modify, and/or distribute this software + for any purpose with or without fee is hereby granted, provided + that the above copyright notice and this permission notice appear + in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA + OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + PERFORMANCE OF THIS SOFTWARE. +*/ +#ifndef ATF_H +#define ATF_H + +#include +#include +#include +#include + +extern char* Curr_Test; +void atf_init(int argc, char** argv); +void atf_test_start(char* file, unsigned int line, char* name); +bool atf_test_assert(bool success, char* expr_str, char* file, int line); +void atf_test_fail(char* expr, char* file, int line); +int atf_print_results(void); + +#define IGNORE(msg) \ + printf("%s:%d:%s:IGNORE:\n\t%s\n", __FILE__, __LINE__, Curr_Test, msg); break + +#define CHECK(expr) \ + if(atf_test_assert((expr), #expr, __FILE__, __LINE__)) break + +#define CHECK_EXITCODE(code) \ + CHECK(ExitCode == code) + +#define TEST_SUITE(name) \ + void name(void) + +#define TEST(desc) \ + for(atf_test_start(__FILE__,__LINE__,#desc); Curr_Test != NULL; Curr_Test = NULL) + +#define RUN_TEST_SUITE(name) \ + name(); + +#define RUN_EXTERN_TEST_SUITE(name) \ + do { extern TEST_SUITE(name); RUN_TEST_SUITE(name); } while(0) + +#define EXPECT_EXIT \ + if ((ExitExpected = true, 0 == setjmp(ExitPad))) + +/* Function Definitions + *****************************************************************************/ +#ifdef INCLUDE_DEFS +#include +#include +#ifndef NO_SIGNALS +#include +#endif + +char* Curr_Test = NULL; +char* Curr_File = NULL; +unsigned int Curr_Line = 0; +static unsigned int Total = 0; +static unsigned int Failed = 0; +bool ExitExpected; +int ExitCode; +jmp_buf ExitPad; + +#ifndef NO_SIGNALS +static void handle_signal(int sig) { + /* Determine the signal name */ + char* sig_name = NULL; + switch(sig) { + case SIGABRT: sig_name = "SIGABRT"; break; + case SIGBUS: sig_name = "SIGBUS"; break; + case SIGFPE: sig_name = "SIGFPE"; break; + case SIGILL: sig_name = "SIGILL"; break; + case SIGSEGV: sig_name = "SIGSEGV"; break; + case SIGSYS: sig_name = "SIGSYS"; break; + /* If we don't recognize it then just return and let the default handler + catch it. */ + default: return; + } + /* Error and exit. No summary will be printed but the user will know which + test has crashed. */ + fprintf(stderr,"%s:%d:0:%s:CRASH (signal: %d - %s)\n", Curr_File, Curr_Line, Curr_Test, sig, sig_name); + Failed++; + (void)atf_print_results(); + _Exit(1); +} +#endif + +void atf_init(int argc, char** argv) { + /* I reserve the right to use these later */ + (void)argc; + (void)argv; + +#ifndef NO_SIGNALS + /* Init signal handler */ + signal(SIGABRT, handle_signal); + signal(SIGBUS, handle_signal); + signal(SIGFPE, handle_signal); + signal(SIGILL, handle_signal); + signal(SIGSEGV, handle_signal); + signal(SIGSYS, handle_signal); +#endif +} + +void atf_test_start(char* file, unsigned int line, char* name) { + Curr_File = file; + Curr_Line = line; + Curr_Test = name; + Total++; +} + +bool atf_test_assert(bool success, char* expr, char* file, int line) { + bool failed = !success; + if (failed) atf_test_fail(expr,file,line); + return failed; +} + +void atf_test_fail(char* expr, char* file, int line) { + Failed++; + printf("%s:%d:0:%s:FAIL:( %s )\n", file, line, Curr_Test, expr); \ +} + +int atf_print_results(void) { + static const char* results_string = + "\nUnit Test Summary" + "\n-----------------" + "\nTotal: %d" + "\nPassed: %d" + "\nFailed: %d" + "\n\n"; + printf(results_string, Total, Total - Failed, Failed); + return Failed; +} + +void exit(int code) { + if (ExitExpected) { + ExitCode = code; + ExitExpected = false; + longjmp(ExitPad, 1); + } else { + assert(!"Unexpected exit. Something went wrong"); + } +} + +#undef INCLUDE_DEFS +#endif + +#endif /* ATF_H */ \ No newline at end of file diff --git a/cerise/build.sh b/cerise/build.sh new file mode 100755 index 0000000..c5d2f06 --- /dev/null +++ b/cerise/build.sh @@ -0,0 +1,3 @@ +#!/bin/sh +ctags -R & +cc -Wall -Wextra -Werror --std=c99 -o sclpl -I. *.c diff --git a/cerise/codegen.c b/cerise/codegen.c new file mode 100644 index 0000000..a625f09 --- /dev/null +++ b/cerise/codegen.c @@ -0,0 +1,12 @@ +#include + +void codegen_init(Parser* p) { + sym_add(&(p->syms), SF_TYPEDEF, "void", VoidType()); + sym_add(&(p->syms), SF_TYPEDEF, "bool", UIntType(1u)); + sym_add(&(p->syms), SF_TYPEDEF, "byte", UIntType(8u)); + sym_add(&(p->syms), SF_TYPEDEF, "int", IntType(64u)); + sym_add(&(p->syms), SF_TYPEDEF, "uint", UIntType(64u)); + sym_add(&(p->syms), SF_TYPEDEF, "float", FloatType(32u)); + sym_add(&(p->syms), SF_TYPEDEF, "string", + ArrayOf(sym_get(&(p->syms), "byte")->type, -1)); +} diff --git a/cerise/emalloc.c b/cerise/emalloc.c new file mode 100644 index 0000000..751a40f --- /dev/null +++ b/cerise/emalloc.c @@ -0,0 +1,11 @@ +#include +void fatal(char* estr) { + perror(estr); + exit(1); +} + +void* emalloc(size_t size) { + void* ptr = malloc(size); + if (!ptr) fatal("malloc()"); + return ptr; +} diff --git a/cerise/lex.c b/cerise/lex.c new file mode 100644 index 0000000..648295e --- /dev/null +++ b/cerise/lex.c @@ -0,0 +1,250 @@ +#include +#include +#include +#include + +typedef struct { + char* keyword; + int type; +} KeywordDef; + +static const char FirstChar[256] = { + /* Whitespace */ + [' '] = 1, ['\t'] = 1, ['\r'] = 1, ['\n'] = 1, + /* comment start */ + ['#'] = 2, + /* number or op */ + ['+'] = 3, ['-'] = 3, + /* number digits */ + ['0'] = 4, ['1'] = 4, ['2'] = 4, ['3'] = 4, ['4'] = 4, + ['5'] = 4, ['6'] = 4, ['7'] = 4, ['8'] = 4, ['9'] = 4, + /* alpha characters */ + ['A'] = 5, ['B'] = 5, ['C'] = 5, ['D'] = 5, ['E'] = 5, + ['F'] = 5, ['G'] = 5, ['H'] = 5, ['I'] = 5, ['J'] = 5, + ['K'] = 5, ['L'] = 5, ['M'] = 5, ['N'] = 5, ['O'] = 5, + ['P'] = 5, ['Q'] = 5, ['R'] = 5, ['S'] = 5, ['T'] = 5, + ['U'] = 5, ['V'] = 5, ['W'] = 5, ['X'] = 5, ['Y'] = 5, + ['Z'] = 5, ['a'] = 5, ['b'] = 5, ['c'] = 5, ['d'] = 5, + ['e'] = 5, ['f'] = 5, ['g'] = 5, ['h'] = 5, ['i'] = 5, + ['j'] = 5, ['k'] = 5, ['l'] = 5, ['m'] = 5, ['n'] = 5, + ['o'] = 5, ['p'] = 5, ['q'] = 5, ['r'] = 5, ['s'] = 5, + ['t'] = 5, ['u'] = 5, ['v'] = 5, ['w'] = 5, ['x'] = 5, + ['y'] = 5, ['z'] = 5, + /* punctuation */ + ['('] = 6, [')'] = 6, ['['] = 6, [']'] = 6, ['{'] = 6, ['}'] = 6, + ['.'] = 6, [','] = 6, [':'] = 6, ['&'] = 6, ['='] = 6, [';'] = 6, + ['*'] = 6, ['\''] = 6, + /* strings */ + ['"'] = 7 +}; + +char SPACE[256] = { + [' '] = 1, ['\t'] = 1, ['\r'] = 1, ['\n'] = 1, +}; + +char DIGIT[256] = { + ['0'] = 1, ['1'] = 1, ['2'] = 1, ['3'] = 1, ['4'] = 1, + ['5'] = 1, ['6'] = 1, ['7'] = 1, ['8'] = 1, ['9'] = 1, +}; + +char ALNUM_[256] = { + ['0'] = 1, ['1'] = 1, ['2'] = 1, ['3'] = 1, ['4'] = 1, + ['5'] = 1, ['6'] = 1, ['7'] = 1, ['8'] = 1, ['9'] = 1, + ['A'] = 1, ['B'] = 1, ['C'] = 1, ['D'] = 1, ['E'] = 1, + ['F'] = 1, ['G'] = 1, ['H'] = 1, ['I'] = 1, ['J'] = 1, + ['K'] = 1, ['L'] = 1, ['M'] = 1, ['N'] = 1, ['O'] = 1, + ['P'] = 1, ['Q'] = 1, ['R'] = 1, ['S'] = 1, ['T'] = 1, + ['U'] = 1, ['V'] = 1, ['W'] = 1, ['X'] = 1, ['Y'] = 1, + ['Z'] = 1, ['a'] = 1, ['b'] = 1, ['c'] = 1, ['d'] = 1, + ['e'] = 1, ['f'] = 1, ['g'] = 1, ['h'] = 1, ['i'] = 1, + ['j'] = 1, ['k'] = 1, ['l'] = 1, ['m'] = 1, ['n'] = 1, + ['o'] = 1, ['p'] = 1, ['q'] = 1, ['r'] = 1, ['s'] = 1, + ['t'] = 1, ['u'] = 1, ['v'] = 1, ['w'] = 1, ['x'] = 1, + ['y'] = 1, ['z'] = 1, ['_'] = 1, +}; + +#define NUM_KEYWORDS (sizeof(Keywords) / sizeof(Keywords[0])) +KeywordDef Keywords[] = { + { "else", T_ELSE }, + { "false", T_BOOL }, + { "fun", T_FUN }, + { "if", T_IF }, + { "let", T_LET }, + { "provide", T_PROVIDES }, + { "require", T_REQUIRES }, + { "return", T_RETURN }, + { "struct", T_STRUCT }, + { "true", T_BOOL }, + { "type", T_TYPE }, + { "union", T_UNION }, + { "var", T_VAR }, +}; + +static int keywcmp(const void* a, const void* b) { + return strcmp(((KeywordDef*)a)->keyword, ((KeywordDef*)b)->keyword); +} + +static inline char* file_load(char* path) { + int fd = -1, nread = 0, length = 0; + struct stat sb = {0}; + char* contents = NULL; + if (((fd = open(path, O_RDONLY, 0)) >= 0) && (fstat(fd, &sb) >= 0) && (sb.st_size > 0)) { + contents = calloc(sb.st_size + 1u, 1u); + while (sb.st_size && (nread = read(fd, contents+length, sb.st_size)) > 0) + length += nread, sb.st_size -= nread; + } + if (fd > 0) close(fd); + return contents; +} + +static inline void convert_value(Tok* tok) { + switch (tok->type) { + case T_STRING: { + size_t len = strlen(tok->text+1); + char* strtext = malloc(len); + strncpy(strtext, tok->text+1, len); + strtext[len-1] = '\0'; + free(tok->text), tok->text = strtext; + break; + } + + case T_INT: { + tok->value.integer = strtol(tok->text, NULL, 0); + break; + } + + case T_ID: { + KeywordDef key = { .keyword = tok->text }; + KeywordDef* match = bsearch( + &key, Keywords, NUM_KEYWORDS, sizeof(KeywordDef), keywcmp); + if (match) { + tok->type = match->type; + if (tok->type != T_ID) + convert_value(tok); /* recurse to ensure correct conversion */ + } + break; + } + + case T_BOOL: { + tok->value.integer = (tok->text[0] == 't'); + break; + } + + default: + break; + } +} + +static inline void readtok(Parser* ctx) { + Tok* tok = &(ctx->tok); + char *beg = ctx->file->fpos, *curr = ctx->file->fpos; + tok->offset = (beg - ctx->file->fbeg); + switch (FirstChar[(int)*curr++]) { + case 1: /* skip whitespace */ + for (; SPACE[(int)*curr]; curr++); + break; + + case 2: /* skip comments */ + for (; *curr != '\n'; curr++); + break; + + case 3: /* +/- as ops or number signs */ + tok->type = *(curr-1); + if (!DIGIT[(int)*curr]) break; + /* parse it as an int */ + tok->type = T_INT; + for (; DIGIT[(int)*curr]; curr++); + break; + + case 4: + tok->type = T_INT; + for (; DIGIT[(int)*curr]; curr++); + break; + + case 5: + tok->type = T_ID; + for (; ALNUM_[(int)*curr]; curr++); + break; + + case 6: /* single char tokens */ + tok->type = *(curr-1); + break; + + case 7: /* string parsing */ + tok->type = T_STRING; + for (; *curr != '"'; curr++); + curr++; + break; + + case 0: /* error handling */ + default: + fprintf(stderr, "Failed to parse token '%c'\n", *(curr-1)); + exit(1); + } + + if (tok->type) { + size_t sz = (curr - beg); + tok->text = malloc(sz+1); + tok->text[sz] = '\0'; + strncpy(tok->text, beg, sz); + convert_value(tok); + } + + ctx->file->fpos = curr; +} + +void lexfile(Parser* ctx, char* path) { + LexFile* file = calloc(sizeof(LexFile), 1u); + file->path = strdup(path); + file->fbeg = file->fpos = file_load(path); + file->next = ctx->file; + ctx->file = file; +} + +void lex(Parser* ctx) { + ctx->tok.file = ctx->file->path; + ctx->tok.type = T_NONE; + while (ctx->tok.type == T_NONE) { + if (!ctx->file) { + /* no more files left to process */ + ctx->tok.type = T_END_FILE; + return; + } else if (!(ctx->file->fpos) || !*(ctx->file->fpos)) { + /* grab the next file to process */ + LexFile* f = ctx->file; + ctx->file = f->next; + f->next = ctx->done; + ctx->done = f; + } else { + /* parse out a token */ + readtok(ctx); + } + } +} + +static LexFile* get_file(Parser* p, char const* path) { + LexFile* lf = p->file; + while (lf && strcmp(lf->path, path)) + lf = lf->next; + if (!lf) { + lf = p->done; + while (lf && strcmp(lf->path, path)) + lf = lf->next; + } + return lf; +} + +void lexprintpos(Parser* p, FILE* file, Tok* tok) { + size_t line = 1, col = 1; + char* data = get_file(p, tok->file)->fbeg; + char* end = data + tok->offset; + for (; *data && data < end; data++) { + if (*data == '\n') { + line++; + col = 1; + } else { + col++; + } + } + fprintf(file, "%s:%zu:%zu:", tok->file, line, col); +} diff --git a/cerise/main.c b/cerise/main.c new file mode 100644 index 0000000..d1beeeb --- /dev/null +++ b/cerise/main.c @@ -0,0 +1,49 @@ +#include + +char* ARGV0; +char* Artifact = "bin"; + +/* Driver Modes + *****************************************************************************/ +static int emit_binary(Parser* ctx, int argc, char **argv) { + (void)ctx, (void)argc, (void)argv; + return 0; +} + +static int emit_library(Parser* ctx, int argc, char **argv) { + (void)ctx, (void)argc, (void)argv; + return 0; +} + +/* Main Routine and Usage + *****************************************************************************/ +void usage(void) { + fprintf(stderr, "%s\n", + "Usage: sclpl [options...] [-A artifact] [file...]\n" + "\n-A Emit the given type of artifact" + "\n-h Print help information" + ); + exit(1); +} + +int main(int argc, char **argv) { + /* Option parsing */ + OPTBEGIN { + case 'A': Artifact = EOPTARG(usage()); break; + default: usage(); + } OPTEND; + /* initialize the parser */ + Parser ctx = {0}; + for (; argc; argc--,argv++) + lexfile(&ctx, *argv); + /* Execute the main compiler process */ + if (0 == strcmp("bin", Artifact)) { + return emit_binary(&ctx, argc, argv); + } else if (0 == strcmp("lib", Artifact)) { + return emit_library(&ctx, argc, argv); + } else { + fprintf(stderr, "Unknown artifact type: '%s'\n\n", Artifact); + usage(); + } + return 1; +} diff --git a/cerise/parser.c b/cerise/parser.c new file mode 100644 index 0000000..3ed1869 --- /dev/null +++ b/cerise/parser.c @@ -0,0 +1,117 @@ +#include +#include + +//#define TRACE +#ifdef TRACE +static int Indent = 0; +#define parse_enter() \ + (printf("%*c-> %s\n", ++Indent * 2, ' ', __func__)) +#define parse_exit() \ + (printf("%*c<- %s\n", --Indent * 2, ' ', __func__)) +#else +#define parse_enter() +#define parse_exit() +#endif + +/* Precedence Table + *****************************************************************************/ +//enum { /* Define precedence levels(based on C) */ +// LVL_NONE, +// LVL_LITERAL, +// LVL_COMMA, +// LVL_ASSIGN, +// LVL_TERNARY, +// LVL_BOOL_OR, +// LVL_BOOL_AND, +// LVL_BITWISE_OR, +// LVL_BITWISE_XOR, +// LVL_BITWISE_AND, +// LVL_EQUALITY, +// LVL_RELATIONAL, +// LVL_BITSHIFT, +// LVL_ADD_SUB, +// LVL_MUL_DIV, +// LVL_PREFIX, +// LVL_POSTFIX, +//}; +// +//typedef struct { +// int level; +// AST* (*prefixfn)(Parser* p); +// AST* (*infixfn)(Parser* p, AST* left); +//} OpRule; +// +//OpRule PrecedenceTable[T_COUNT] = { +// [T_BOOL] = { .level = LVL_LITERAL, .prefixfn = literal, .infixfn = NULL }, +// [T_CHAR] = { .level = LVL_LITERAL, .prefixfn = literal, .infixfn = NULL }, +// [T_STRING] = { .level = LVL_LITERAL, .prefixfn = literal, .infixfn = NULL }, +// [T_INT] = { .level = LVL_LITERAL, .prefixfn = literal, .infixfn = NULL }, +// [T_FLOAT] = { .level = LVL_LITERAL, .prefixfn = literal, .infixfn = NULL }, +// [T_ID] = { .level = LVL_LITERAL, .prefixfn = literal, .infixfn = NULL }, +// ['('] = { .level = LVL_POSTFIX, .prefixfn = grouping, .infixfn = func_call }, +// ['.'] = { .level = LVL_POSTFIX, .prefixfn = NULL, .infixfn = dot_call }, +//}; + +/* Parsing Routines + *****************************************************************************/ +//static Tok* peek(Parser* p) { +// if (T_NONE == p->tok.type) +// lex(p); +// return &(p->tok); +//} +// +//static void error(Parser* parser, const char* fmt, ...) { +// Tok* tok = peek(parser); +// va_list args; +// va_start(args, fmt); +// lexprintpos(parser, stderr, tok); +// fprintf(stderr, " error: "); +// vfprintf(stderr, fmt, args); +// fprintf(stderr, "\n"); +// va_end(args); +// exit(1); +//} +// +//static bool matches(Parser* p, TokType type) { +// return (peek(p)->type == type); +//} +// +//static bool accept(Parser* p, TokType type) { +// if (matches(p, type)) { +// p->tok.type = T_NONE; +// return true; +// } +// return false; +//} +// +//static void expect(Parser* p, TokType type) { +// if (!accept(p, type)) +// error(p, "Unexpected token"); +//} +// +//static Tok* expect_val(Parser* p, TokType type) { +// static Tok token = {0}; +// /* perform the match */ +// if (matches(p, type)) { +// token = *(peek(p)); +// p->tok.type = T_NONE; +// } else { +// error(p, "Unexpected token"); +// } +// return &token; +//} +// +//static int consume(Parser* p) { +// int type = peek(p)->type; +// if (!accept(p, type)) +// error(p, "Unexpected token"); +// return type; +//} + +/* Grammar Definition + *****************************************************************************/ +void toplevel(Parser* p) { + parse_enter(); + (void)p; + parse_exit(); +} diff --git a/cerise/pkg.c b/cerise/pkg.c new file mode 100644 index 0000000..0bed7ff --- /dev/null +++ b/cerise/pkg.c @@ -0,0 +1,23 @@ +#include + +void pkg_add_require(Package* p, char* req) +{ + Require* rq = malloc(sizeof(Require)); + rq->path = strdup(req); + rq->next = p->requires; + p->requires = rq; +} + +void pkg_add_provide(Package* p, char* exp) +{ + Provide* pr = malloc(sizeof(Provide)); + pr->name = strdup(exp); + pr->next = p->provides; + p->provides = pr; +} + +void pkg_add_definition(Package* p, AST* ast) +{ + (void)p, (void)ast; +} + diff --git a/cerise/pprint.c b/cerise/pprint.c new file mode 100644 index 0000000..8a9705c --- /dev/null +++ b/cerise/pprint.c @@ -0,0 +1,217 @@ +#include + +static void indent(FILE* file, int depth) { + fprintf(file, "\n"); + if (depth) fprintf(file, "%*c", depth * 2, ' '); +} + +static const char* token_type_to_string(int type) { + #define TOK(name) case (name): return #name + switch(type) { + TOK(T_NONE); TOK(T_ERROR); TOK(T_END_FILE); + TOK(T_REQUIRES); TOK(T_PROVIDES); TOK(T_LET); TOK(T_VAR); + TOK(T_FUN); TOK(T_TYPE); TOK(T_STRUCT); TOK(T_UNION); + TOK(T_RETURN); TOK(T_IF); TOK(T_ELSE); TOK(T_ID); + TOK(T_CHAR); TOK(T_INT); TOK(T_FLOAT); TOK(T_BOOL); + TOK(T_STRING); + case '{': return "T_LBRACE"; + case '}': return "T_RBRACE"; + case '[': return "T_LBRACK"; + case ']': return "T_RBRACK"; + case '(': return "T_LPAR"; + case ')': return "T_RPAR"; + case ',': return "T_COMMA"; + case ':': return "T_COLON"; + case '&': return "T_AMP"; + case '\'': return "T_SQUOTE"; + case '"': return "T_DQUOTE"; + default: return "???"; + } + #undef TOK +} + +static void print_char(FILE* file, char ch) { + int i; + static const char* lookup_table[5] = { + " \0space", + "\n\0newline", + "\r\0return", + "\t\0tab", + "\v\0vtab" + }; + for(i = 0; i < 5; i++) { + if (ch == lookup_table[i][0]) { + fprintf(file, "\\%s", &(lookup_table[i][2])); + break; + } + } + if (i == 5) fprintf(file, "\\%c", ch); +} + +static void pprint_token_type(FILE* file, Tok* token) { + if (token->type > 256) + fprintf(file, "%s", token_type_to_string(token->type)); + else + fprintf(file, "%c", token->type); +} + +static void pprint_token_value(FILE* file, Tok* token) { + #define TOK(name) case (name): fprintf(file, "%s", #name); break + switch(token->type) { + /* value tokens */ + case T_STRING: fprintf(file, "\"%s\"", token->text); break; + case T_ID: fprintf(file, "%s", token->text); break; + case T_CHAR: print_char(file, token->value.integer); break; + case T_INT: fprintf(file, "%lld", token->value.integer); break; + case T_FLOAT: fprintf(file, "%f", token->value.floating); break; + case T_BOOL: fprintf(file, "%s", (token->value.integer)?"true":"false"); break; + + /* keyword tokens */ + TOK(T_NONE); TOK(T_ERROR); TOK(T_END_FILE); + TOK(T_REQUIRES); TOK(T_PROVIDES); TOK(T_LET); TOK(T_VAR); + TOK(T_FUN); TOK(T_TYPE); TOK(T_STRUCT); TOK(T_UNION); TOK(T_RETURN); + TOK(T_IF); TOK(T_ELSE); + + /* evertything else */ + default: + fprintf(file, "???"); + break; + } + #undef TOK +} + +void pprint_token(FILE* file, Tok* token, bool print_loc) +{ + if (print_loc) { + fprintf(file, "%zu:", token->offset); + } + pprint_token_type(file, token); + if (token->type > 256) { + fprintf(file, ":"); + pprint_token_value(file, token); + } + fprintf(file, "\n"); +} + +/*****************************************************************************/ + +static const char* tree_type_to_string(ASTType type) { + switch(type) { + case AST_STRING: return "T_STRING"; + case AST_SYMBOL: return "T_SYMBOL"; + case AST_IDENT: return "T_ID"; + case AST_CHAR: return "T_CHAR"; + case AST_INT: return "T_INT"; + case AST_FLOAT: return "T_FLOAT"; + case AST_BOOL: return "T_BOOL"; + default: return "???"; + } +} + +static void pprint_literal(FILE* file, AST* tree, int depth) +{ + (void)depth; + fprintf(file, "%s:", tree_type_to_string(tree->nodetype)); + switch(tree->nodetype) { + case AST_STRING: fprintf(file, "\"%s\"", string_value(tree)); break; + case AST_IDENT: fprintf(file, "%s", ident_value(tree)); break; + case AST_CHAR: fprintf(file, "%c", char_value(tree)); break; + case AST_INT: fprintf(file, "%ld", integer_value(tree)); break; + case AST_FLOAT: fprintf(file, "%lf", float_value(tree)); break; + case AST_BOOL: + fprintf(file, "%s", bool_value(tree) ? "true" : "false"); + break; + default: fprintf(file, "???"); + } +} + +static char* getvartype(AST* tree) { + if (var_flagset(tree, SF_CONSTANT)) + return "let"; + else if (var_flagset(tree, SF_TYPEDEF)) + return "typedef"; + else + return "var"; +} + +void pprint_fargs(FILE* file, AST* tree) { + size_t nargs = 0; + AST** args = explist_get(tree, &nargs); + fprintf(file, "("); + for (size_t i = 0; i < nargs; i++) { + fprintf(file, "("); + fprintf(file, "%s : type", var_name(args[i])); + fprintf(file, ") "); + } + fprintf(file, ")"); +} + +void pprint_block(FILE* file, AST* tree, int depth) { + if (!tree) return; + size_t nexprs = 0; + AST** exprs = explist_get(tree, &nexprs); + for (size_t i = 0; i < nexprs; i++) { + indent(file, depth); + pprint_tree(file, exprs[i], depth); + } +} + +void pprint_branch(FILE* file, AST* tree, int depth) { + indent(file, depth); + pprint_tree(file, tree, depth); +} + +void pprint_ifexpr(FILE* file, AST* tree, int depth) { + fprintf(file, "(if "); + pprint_tree(file, if_cond(tree), depth); + pprint_branch(file, if_then(tree), depth+1); + pprint_branch(file, if_else(tree), depth+1); + fprintf(file, ")"); +} + +void pprint_apply(FILE* file, AST* tree, int depth) { + fprintf(file, "(apply "); + pprint_tree(file, apply_func(tree), depth); + size_t nexprs = 0; + AST** exprs = explist_get(apply_args(tree), &nexprs); + for (size_t i = 0; i < nexprs; i++) { + indent(file, depth+1); + pprint_tree(file, exprs[i], depth+1); + } + fprintf(file, ")"); +} + +void pprint_tree(FILE* file, AST* tree, int depth) { + if (tree == NULL) return; + switch (tree->nodetype) { + case AST_VAR: + fprintf(file, "(%s %s ", getvartype(tree), var_name(tree)); + pprint_tree(file, var_value(tree), depth); + fprintf(file, ")"); + break; + + case AST_FUNC: + pprint_fargs(file, func_args(tree)); + pprint_block(file, func_body(tree), depth+1); + break; + + case AST_EXPLIST: + fprintf(file, "(block"); + pprint_block(file, tree, depth+1); + fprintf(file, ")"); + break; + + case AST_IF: + pprint_ifexpr(file, tree, depth); + break; + + case AST_APPLY: + pprint_apply(file, tree, depth); + break; + + default: + pprint_literal(file, tree, depth); + break; + } +} + diff --git a/cerise/sclpl b/cerise/sclpl new file mode 100755 index 0000000000000000000000000000000000000000..6fd7fbd2bae7ffd297f1fd01748f11a1dce6a5a6 GIT binary patch literal 34928 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 +#include +#include +#include +#include +#include +#include +#include +#include + +void fatal(char* estr); +void* emalloc(size_t size); + +/* Token Types + *****************************************************************************/ +typedef enum { + T_NONE = 0, + T_STRING = 256, T_ID, T_INT, T_BOOL, T_CHAR, T_FLOAT, + T_REQUIRES, T_PROVIDES, T_LET, T_VAR, T_FUN, T_TYPE, T_STRUCT, + T_UNION, T_RETURN, T_IF, T_ELSE, + T_COUNT, + T_ERROR = -2, + T_END_FILE = -1 +} TokType; + +typedef struct { + const char* file; + long offset; + TokType type; + char* text; + union { + long long integer; + double floating; + } value; +} Tok; + +/* Datatype Types + *****************************************************************************/ +typedef enum { + VOID, INT, UINT, FLOAT, ARRAY, REF, PTR, FUNC +} Kind; + +typedef struct Type { + Kind kind; + union { + struct Type* type; + size_t bits; + struct { + struct Type* type; + size_t count; + } array; + } value; +} Type; + +Type* VoidType(void); +Type* IntType(size_t nbits); +Type* UIntType(size_t nbits); +Type* FloatType(size_t nbits); +Type* ArrayOf(Type* type, size_t count); +Type* RefTo(Type* type); +Type* PtrTo(Type* type); +bool types_equal(Type* type1, Type* type2); + +/* Symbol Table + *****************************************************************************/ +typedef enum { + SF_TYPEDEF = (1 << 0), + SF_CONSTANT = (1 << 1), + SF_ARGUMENT = (1 << 2), +} SymFlags; + +typedef struct Sym { + struct Sym* next; + bool is_typedef; + int flags; + char* name; + Type* type; +} Sym; + +typedef struct { + Sym* syms; +} SymTable; + +void sym_add(SymTable* syms, int flags, char* name, Type* type); +Sym* sym_get(SymTable* syms, char* name); + +/* AST Types + *****************************************************************************/ +typedef enum { + AST_VAR, AST_FUNC, AST_EXPLIST, AST_IF, AST_APPLY, + AST_STRING, AST_SYMBOL, AST_CHAR, AST_INT, + AST_FLOAT, AST_BOOL, AST_IDENT, AST_OPER +} ASTType; + +typedef struct AST { + ASTType nodetype; + Type* datatype; + union { + struct AST* nodes[3]; + struct { + int oper; + struct AST* left; + struct AST* right; + } op; + /* Definition Node */ + struct { + char* name; + int flags; + struct AST* value; + } var; + /* Expression Block Node */ + struct { + size_t nexprs; + struct AST** exprs; + } explist; + /* String, Symbol, Identifier */ + char* text; + /* Integer */ + intptr_t integer; + /* Float */ + double floating; + } value; +} AST; + +/* String */ +AST* String(char* val); +char* string_value(AST* val); + +/* Character */ +AST* Char(int val); +uint32_t char_value(AST* val); + +/* Integer */ +AST* Integer(int val); +intptr_t integer_value(AST* val); + +/* Float */ +AST* Float(double val); +double float_value(AST* val); + +/* Bool */ +AST* Bool(bool val); +bool bool_value(AST* val); + +/* Ident */ +AST* Ident(char* val); +char* ident_value(AST* val); + +/* Definition */ +AST* Var(char* name, AST* value, AST* type, int flags); +char* var_name(AST* var); +AST* var_value(AST* var); +bool var_flagset(AST* var, int mask); + +AST* Func(AST* args, AST* body, AST* type); +AST* func_args(AST* func); +AST* func_body(AST* func); + +AST* ExpList(void); +AST** explist_get(AST* explist, size_t* nexprs); +void explist_append(AST* explist, AST* expr); +void explist_prepend(AST* explist, AST* expr); + +AST* If(AST* cond, AST* b1, AST* b2); +AST* if_cond(AST* ifexp); +AST* if_then(AST* ifexp); +AST* if_else(AST* ifexp); + +AST* Apply(AST* func, AST* args); +AST* apply_func(AST* apply); +AST* apply_args(AST* apply); + +AST* OpCall(int oper, AST* left, AST* right); + + +/* Package Definition + *****************************************************************************/ +typedef struct Require { + struct Require* next; + char* path; + char* alias; +} Require; + +typedef struct Provide { + struct Provide* next; + char* name; +} Provide; + +typedef struct Definition { + struct Provide* next; + AST* ast; +} Definition; + +typedef struct { + char* name; + SymTable* syms; + Require* requires; + Provide* provides; + Definition* definitions; +} Package; + +void pkg_add_require(Package* p, char* req); +void pkg_add_provide(Package* p, char* exp); +void pkg_add_definition(Package* p, AST* ast); + +/* Pretty Printing + *****************************************************************************/ +void pprint_token(FILE* file, Tok* token, bool print_loc); +void pprint_tree(FILE* file, AST* tree, int depth); + +/* Lexer and Parser Types + *****************************************************************************/ +typedef struct LexFile { + struct LexFile* next; + char* path; + char* fbeg; + char* fpos; +} LexFile; + +typedef struct { + LexFile* done; + LexFile* file; + Tok tok; + SymTable syms; + Package pkg; +} Parser; + +void lexfile(Parser* ctx, char* path); +void lex(Parser* ctx); +void lexprintpos(Parser* p, FILE* file, Tok* tok); +void gettoken(Parser* ctx); +void toplevel(Parser* p); +void codegen_init(Parser* p); + +/* Option Parsing + *****************************************************************************/ + +/* This variable contains the value of argv[0] so that it can be referenced + * again once the option parsing is done. This variable must be defined by the + * program. + * + * NOTE: Ensure that you define this variable with external linkage (i.e. not + * static) + */ +extern char* ARGV0; + +/* This is a helper function used by the macros in this file to parse the next + * option from the command line. + */ +static inline char* __getopt(int* p_argc, char*** p_argv) { + if (!(*p_argv)[0][1] && !(*p_argv)[1]) { + return (char*)0; + } else if ((*p_argv)[0][1]) { + return &(*p_argv)[0][1]; + } else { + *p_argv = *p_argv + 1; + *p_argc = *p_argc - 1; + return (*p_argv)[0]; + } +} + +/* This macro is almost identical to the ARGBEGIN macro from suckless.org. If + * it ain't broke, don't fix it. */ +#define OPTBEGIN \ + for ( \ + ARGV0 = *argv, argc--, argv++; \ + argv[0] && argv[0][1] && argv[0][0] == '-'; \ + argc--, argv++ \ + ) { \ + int brk_; char argc_ , **argv_, *optarg_; \ + if (argv[0][1] == '-' && !argv[0][2]) { \ + argv++, argc--; break; \ + } \ + for (brk_=0, argv[0]++, argv_=argv; argv[0][0] && !brk_; argv[0]++) { \ + if (argv_ != argv) break; \ + argc_ = argv[0][0]; \ + switch (argc_) + +/* Terminate the option parsing. */ +#define OPTEND }} + +/* Get the current option chracter */ +#define OPTC() (argc_) + +/* Get an argument from the command line and return it as a string. If no + * argument is available, this macro returns NULL */ +#define OPTARG() \ + (optarg_ = __getopt(&argc,&argv), brk_ = (optarg_!=0), optarg_) + +/* Get an argument from the command line and return it as a string. If no + * argument is available, this macro executes the provided code. If that code + * returns, then abort is called. */ +#define EOPTARG(code) \ + (optarg_ = __getopt(&argc,&argv), \ + (!optarg_ ? ((code), abort(), (char*)0) : (brk_ = 1, optarg_))) + +/* Helper macro to recognize number options */ +#define OPTNUM \ + case '0': \ + case '1': \ + case '2': \ + case '3': \ + case '4': \ + case '5': \ + case '6': \ + case '7': \ + case '8': \ + case '9' + +/* Helper macro to recognize "long" options ala GNU style. */ +#define OPTLONG \ + case '-' diff --git a/cerise/syms.c b/cerise/syms.c new file mode 100644 index 0000000..6a8f0e2 --- /dev/null +++ b/cerise/syms.c @@ -0,0 +1,22 @@ +#include + +static Sym* mksym(int flags, char* name, Type* type, Sym* next) { + Sym* sym = emalloc(sizeof(Sym)); + sym->flags = flags; + sym->name = name; + sym->type = type; + sym->next = next; + return sym; +} + +void sym_add(SymTable* syms, int flags, char* name, Type* type) { + syms->syms = mksym(flags, name, type, syms->syms); +} + +Sym* sym_get(SymTable* syms, char* name) { + Sym* sym = syms->syms; + for (; sym; sym = sym->next) + if (!strcmp(sym->name, name)) + return sym; + return NULL; +} diff --git a/cerise/types.c b/cerise/types.c new file mode 100644 index 0000000..cfaae4c --- /dev/null +++ b/cerise/types.c @@ -0,0 +1,59 @@ +#include + +static Type* mktype(Kind kind) { + Type* type = emalloc(sizeof(Type)); + memset(type, 0, sizeof(Type)); + type->kind = kind; + return type; +} + +Type* VoidType(void) { + return mktype(VOID); +} + +Type* IntType(size_t nbits) { + Type* type = mktype(INT); + type->value.bits = nbits; + return type; +} + +Type* UIntType(size_t nbits) { + Type* type = mktype(UINT); + type->value.bits = nbits; + return type; +} + +Type* FloatType(size_t nbits) { + Type* type = mktype(FLOAT); + type->value.bits = nbits; + return type; +} + +Type* ArrayOf(Type* elemtype, size_t count) { + Type* type = mktype(ARRAY); + type->value.array.type = elemtype; + type->value.array.count = count; + return type; +} + +Type* RefTo(Type* type) { + (void)type; + return NULL; +} + +Type* PtrTo(Type* type) { + (void)type; + return NULL; +} + +bool types_equal(Type* type1, Type* type2) { + if (type1->kind != type2->kind) return false; + switch (type1->kind) { + case ARRAY: + return (types_equal(type1->value.array.type, type2->value.array.type) && + (type1->value.array.count == type2->value.array.count)); + default: + return true; + } +} + diff --git a/cerise/value b/cerise/value new file mode 100644 index 0000000..e69de29 -- 2.52.0