#!/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"
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);
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 '-'
}
}
-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");
}
#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<artifact> 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
#include "cerise.h"
#include <stdarg.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/stat.h>
//#define TRACE
#ifdef TRACE
{
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, ','))
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
{
if (accept(p, BEGIN))
{
- codegen_startproc(0);
+ codegen_startproc("Module", 0);
statement_seq(p, item);
codegen_endproc();
}
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
--- /dev/null
+module Module;
+const FOO = 42;
+var a : Int;
+begin
+ a = FOO * 3;
+end Module;