From: mike lowis Date: Thu, 22 Apr 2021 02:06:48 +0000 (-0400) Subject: added scaffolding to generate assembly code X-Git-Url: https://git.mdlowis.com/?a=commitdiff_plain;h=e311f8901375f3dddf2b875f4ebf8b6aba2fb88c;p=proto%2Fobnc.git added scaffolding to generate assembly code --- diff --git a/cerise/build.sh b/cerise/build.sh index ec4bcc0..6328d79 100755 --- a/cerise/build.sh +++ b/cerise/build.sh @@ -1,6 +1,7 @@ #!/bin/sh ctags -R & cc -g -D CERISE_TESTS -Wall -Wextra --std=c99 -o cerisec-test *.c \ - && ./cerisec-test -# && cc -g -Wall -Wextra -Werror --std=c99 -o cerisec *.c -[ $? -gt 0 ] && printf "\a" + && ./cerisec-test \ + && cc -g -Wall -Wextra -Werror --std=c99 -o cerisec *.c \ + && ./cerisec tests/Module.m +#[ $? -gt 0 ] && printf "\a" diff --git a/cerise/cerise.h b/cerise/cerise.h index 08df7eb..84339aa 100644 --- a/cerise/cerise.h +++ b/cerise/cerise.h @@ -125,11 +125,10 @@ typedef struct { void lexfile(Parser* ctx, char* path); void lex(Parser* ctx); void lexprintpos(Parser* p, FILE* file, Tok* tok); -void module(Parser* p, Item* item); +void compile(char* fname); /* Code Generation *****************************************************************************/ - extern Type BoolType, IntType, RealType, StringType; void codegen_setint(Item* item, Type* type, long long val); @@ -137,84 +136,5 @@ void codegen_setreal(Item* item, double val); void codegen_setstr(Item* item, char* val); void codegen_unop(int op, Item* a); void codegen_binop(int op, Item* a, Item* b); -void codegen_startproc(long long localsz); +void codegen_startproc(char* name, long long localsz); void codegen_endproc(void); - -/* 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/codegen.c b/cerise/codegen.c index 94d8319..8601913 100644 --- a/cerise/codegen.c +++ b/cerise/codegen.c @@ -207,15 +207,21 @@ void codegen_binop(int op, Item* a, Item* b) } } -void codegen_startproc(long long localsz) +void codegen_startproc(char* name, long long localsz) { - printf(" pushq rbp\n"); - printf(" movq rsp, rbp\n"); - printf(" sub $%lld, rsp\n", localsz); + printf(" .text\n"); + printf(" .globl %s\n", name); + printf("%s:\n", name); + printf(" pushq %%rbp\n"); + printf(" movq %%rsp, %%rbp\n"); + if (localsz > 0) + { + printf(" sub $%lld, %%rsp\n", localsz); + } } void codegen_endproc(void) { - printf(" pop rbp"); - printf(" ret"); + printf(" pop %%rbp\n"); + printf(" ret\n"); } diff --git a/cerise/main.c b/cerise/main.c index cea9b8f..22e0052 100644 --- a/cerise/main.c +++ b/cerise/main.c @@ -2,61 +2,14 @@ #ifndef CERISE_TESTS -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)) + if (argc >= 2) { - return emit_library(&ctx, argc, argv); + compile( argv[1] ); } - else - { - fprintf(stderr, "Unknown artifact type: '%s'\n\n", Artifact); - usage(); - } - return 1; + + return 0; } #else diff --git a/cerise/parser.c b/cerise/parser.c index d3ca8f9..c91309e 100644 --- a/cerise/parser.c +++ b/cerise/parser.c @@ -1,5 +1,8 @@ #include "cerise.h" #include +#include +#include +#include //#define TRACE #ifdef TRACE @@ -413,7 +416,7 @@ RULE(var_decl) { name = expect_text(p, IDENT); export = accept(p, '*'); - sym = symbol_new(p, name, SYM_CONST, export); + sym = symbol_new(p, name, SYM_VAR, export); nsyms++; if (!accept(p, ',')) @@ -471,12 +474,21 @@ RULE(const_decl) RULE(statement_seq) { - (void)item; if (matches(p, IDENT)) { + char* text = expect_text(p, IDENT); if (accept(p, '=')) { - + Symbol* sym = symbol_get(p, text); + if (!sym) + { + error(p, "undefined variable '%s'", text); + } + else if (sym->class != SYM_VAR) + { + error(p, "assignment to non-variable '%s'", text); + } + expression(p, item); } else { @@ -552,7 +564,7 @@ RULE(module) if (accept(p, BEGIN)) { - codegen_startproc(0); + codegen_startproc("Module", 0); statement_seq(p, item); codegen_endproc(); } @@ -566,6 +578,51 @@ RULE(module) expect(p, ';'); } +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; +} + +void compile(char* fname) +{ + char* fcontents = file_load(fname); + module( + &(Parser){ + .scope = &RealSym, + .file = &(LexFile){ + .path = fname, + .fbeg = fcontents, + .fpos = fcontents, + } + }, + &(Item){0} + ); + + printf(" .text\n"); + printf(" .globl main\n"); + printf("main:\n"); + printf(" pushq %%rbp\n"); + printf(" movq %%rsp, %%rbp\n"); + printf(" call Module\n"); + printf(" pop %%rbp\n"); + printf(" ret\n"); +} + /* Grammar Unit Tests *****************************************************************************/ #ifdef CERISE_TESTS diff --git a/cerise/tests/Module.m b/cerise/tests/Module.m new file mode 100644 index 0000000..7eefeac --- /dev/null +++ b/cerise/tests/Module.m @@ -0,0 +1,6 @@ +module Module; +const FOO = 42; +var a : Int; +begin + a = FOO * 3; +end Module;