Skip to content

Commit

Permalink
Make it a compiler :)
Browse files Browse the repository at this point in the history
  • Loading branch information
semahawk committed Jun 25, 2015
1 parent 68b6363 commit bfe63a6
Show file tree
Hide file tree
Showing 10 changed files with 601 additions and 9 deletions.
438 changes: 437 additions & 1 deletion ast.c

Large diffs are not rendered by default.

19 changes: 18 additions & 1 deletion ast.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,14 @@
struct lexer;
struct nodes_list;

/* assembly sections */
struct section {
char buffer[1 << 20]; /* 1MiB (yeaah) */
unsigned pos; /* current position for when writing to the buffer */
};

extern struct section *currsect;

enum node_type {
NT_NOP,
NT_INTEGER,
Expand Down Expand Up @@ -103,6 +111,8 @@ struct node {
/* pointer to a function that is responsible for executing the node
* and maintaining the stack (ie. pushing the node's result value onto it) */
struct node *(*execf)(struct node *);
/* pointer to a function that is responsible for compiling the node */
struct node *(*compf)(struct node *);
/* a scope in which the expression exists */
/* this is where all the variables and alike where be searched for */
/* (of cource, following `scope`s parent scopes) */
Expand Down Expand Up @@ -156,7 +166,8 @@ struct node {

struct { /* NT_CALL (<name> [opts]()) */
char *name;
char opts[26];
struct node *fun;
char *opts;
struct node **args;
} call;

Expand All @@ -183,6 +194,9 @@ struct node {
/* that is, if it's `true', the function will be executed automatically */
/* if `false' it has to be called explicitly */
bool execute;
/* whether the body of the function has already been compiled (written)
* into the output assembly file */
bool compiled;
} fun;

struct { /* NT_PRINT */
Expand Down Expand Up @@ -219,10 +233,13 @@ struct node *new_if(struct parser *parser, struct lexer *lex,
struct node *new_fun(struct parser *parser, struct lexer *lex, char *name,
struct nob_type *ret_type, struct nob_type **params, struct node *body,
char *opts, bool execute);
struct node *new_call(struct parser *parser, struct lexer *lex, struct node *,
struct node **args, char *opts);
struct node *new_print(struct parser *parser, struct lexer *lex,
struct nodes_list *exprs);

void exec_nodes(struct node *node);
void comp_nodes(struct node *node);

#if DEBUG
void dump_nodes(struct node *node);
Expand Down
13 changes: 13 additions & 0 deletions debug.c
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,19 @@ void debug_ast_exec(struct node *nd, const char *fmt, ...)
}
}

void debug_ast_comp(struct node *nd, const char *fmt, ...)
{
if (NM_DEBUG_GET_FLAG(NM_DEBUG_AST)){
va_list vl;

va_start(vl, fmt);
fprintf(stderr, "%p: (#%u) compile node: ", (void *)nd, nd->id);
vfprintf(stderr, fmt, vl);
fprintf(stderr, "\n");
va_end(vl);
}
}

/*
* vi: ft=c:ts=2:sw=2:expandtab
*/
Expand Down
1 change: 1 addition & 0 deletions debug.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ extern uint32_t NM_debug_flags;

void debug_ast_new (struct node *node, const char *fmt, ...);
void debug_ast_exec(struct node *node, const char *fmt, ...);
void debug_ast_comp(struct node *node, const char *fmt, ...);

#endif /* DEBUG_H */

Expand Down
3 changes: 0 additions & 3 deletions infnum.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,6 @@
* [1] http://en.literateprograms.org/Arbitrary-precision_integer_arithmetic_(C)
*/

#define MIN(a, b) ((a) < (b) ? (a) : (b))
#define MAX(a, b) ((a) > (b) ? (a) : (b))

/* returns digit #<i> from struct infnum <n> or zero in case of an overflow */
#define DIGIT(n, i) (((i) < (n).nmemb) ? (n).digits[i] : 0)

Expand Down
48 changes: 45 additions & 3 deletions nemo.c
Original file line number Diff line number Diff line change
Expand Up @@ -42,15 +42,22 @@
#include <string.h>
#include <getopt.h>
#include <locale.h>
#include <unistd.h>

#include "ast.h"
#include "config.h"
#include "debug.h"
#include "mem.h"
#include "parser.h"
#include "version.h"
#include "util.h"
#include "nob.h"

/* the output file in case we are compiling */
FILE *outfile;
/* and it's name */
char outfilename[32];

int main(int argc, char *argv[])
{
char *locale;
Expand All @@ -63,6 +70,9 @@ int main(int argc, char *argv[])
/* THE scope */
struct scope *_main = new_scope("main", NULL);

/* are we compiling? */
bool compile = false;

if (((locale = getenv("LC_ALL")) && *locale) ||
((locale = getenv("LC_CTYPE")) && *locale) ||
((locale = getenv("LANG")) && *locale)){
Expand All @@ -79,8 +89,11 @@ int main(int argc, char *argv[])
/* initialize the types (which includes creating the standard types) and everything related */
types_init();

while ((ch = getopt(argc, argv, "d:v")) != -1){
while ((ch = getopt(argc, argv, "cd:v")) != -1){
switch (ch){
case 'c':
compile = true;
break;
case 'd':
#ifdef DEBUG
switch (*optarg){
Expand Down Expand Up @@ -138,7 +151,35 @@ int main(int argc, char *argv[])
goto end;
}

exec_nodes(root);
if (compile){
char systemcall[128];
char *noextname = strdup(argv[0]);
char *p = strrchr(noextname, '.');
/* remove the extension from the file name */
if (p) *p = '\0';

snprintf(outfilename, sizeof(outfilename), "%s.asm", noextname);

if ((outfile = fopen(outfilename, "w")) == NULL){
perror("nemo: fopen");
exit(1);
}

/* compile the program (ie. write all the assembly out into <outfile>) */
comp_nodes(root);
/* close the assembly file so we can proceed and compile it */
fclose(outfile);

snprintf(systemcall, sizeof(systemcall), "nasm -f elf32 %s.asm -o %s.o", noextname, noextname);
system(systemcall);

snprintf(systemcall, sizeof(systemcall), "ld -o %s %s.o", noextname, noextname);
system(systemcall);

free(noextname);
} else
exec_nodes(root);

/* TODO clean up after the parser, lexer, etc. */
} else {
/* interactive */
Expand Down Expand Up @@ -182,11 +223,12 @@ int main(int argc, char *argv[])
* Qntal, Helium Vola
* Mourning Beloveth, Doom:VS, Draconian
* Lascaille's Shroud
* Thy Light, Furia, Vinterland
*
* Johann Strauss
*
* Family Guy, The Office, Monty Python, The I.T. Crowd
* Black Books
* Black Books, The Big Bang Theory
*
*/

Expand Down
4 changes: 4 additions & 0 deletions nemo.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#ifndef NEMO_H
#define NEMO_H

#include <stdio.h>
#include <stdint.h>

#if HAVE_STDBOOL_H
Expand All @@ -26,6 +27,9 @@
/* one small, quite handy, typedef */
typedef unsigned char byte_t;

/* the file into which all the assembly will go */
extern FILE *outfile;

#endif /* NEMO_H */

/*
Expand Down
59 changes: 59 additions & 0 deletions parser.c
Original file line number Diff line number Diff line change
Expand Up @@ -501,8 +501,15 @@ static struct node *postfix_expr(struct parser *parser, struct lexer *lex)
ret->lvalue = false;
} else if (accept(parser, lex, TOK_LPAREN)){
force(parser, lex, TOK_RPAREN);
/* target () */
if (NM_DEBUG_GET_FLAG(NM_DEBUG_PARSER))
printf("(function call)");

if (target->type == NT_NAME || target->type == NT_FUN){
ret = new_call(parser, lex, target, NULL, NULL);
ret->lvalue = false; /* hmm.. */
} else
/* hmmm */;
}
}

Expand Down Expand Up @@ -1122,6 +1129,50 @@ static struct node *expr(struct parser *parser, struct lexer *lex)
return NULL;
}

/* we turn these into calls so that the user isn't forced to do this every
* time he wants to branch out:
*
* if (...){
* ...
* }() else {
* ...
* }();
*
* this feature is actually open to conversation as it strikes a bit against
* consistency, observe:
*
* my function = { ... };
*
* if (...)
* function();
* else
* ...;
*
* in this example the 'true' branch would return the result of the
* function, and not the function itself, like here:
*
* my function = { ... };
*
* if (...)
* function;
* else
* ...;
*
* in order to actually return an anonymous function using brackets, the
* user would have to do this:
*
* if (...){
* { ... }
* } else {
* { ... }
* };
*/
if (body->type == NT_FUN)
body = new_call(parser, lex, body, NULL, NULL);

if (elsee->type == NT_FUN)
elsee = new_call(parser, lex, elsee, NULL, NULL);

ret = new_if(parser, lex, guard, body, elsee);
ret->lvalue = false;
/* }}} */
Expand Down Expand Up @@ -1193,6 +1244,14 @@ static struct node *expr(struct parser *parser, struct lexer *lex)

ret = new_decl(parser, lex, name, flags, value, parser->curr_scope);
ret->lvalue = false; /* hmm.. */

if (value)
/* see if the assigned value is a function */
if (value->type == NT_FUN)
/* we make the assignment so that the function knows the name it was
* given during the declaration (necessary for the assembly so the
* functions don't have cryptic names) */
value->in.fun.name = name;
/* }}} */
}
else if (accept_keyword(parser, lex, "print")){
Expand Down
19 changes: 18 additions & 1 deletion util.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,11 @@
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdarg.h>
#include <string.h>

#include "ast.h"
#include "nemo.h"

/*
* A small little function to print a byte in it's binary form (4 bits long).
Expand Down Expand Up @@ -63,7 +68,19 @@ const char *itob64(int64_t num)
}

/*
* vi: ft=c:ts=2:sw=2:expandtab
* Write a line into the <currsect> buffer (defined in ast.c)
*/
void out(const char *fmt, ...)
{
va_list vl;

va_start(vl, fmt);
currsect->pos += vsprintf(currsect->buffer + currsect->pos, fmt, vl);
currsect->pos += sprintf(currsect->buffer + currsect->pos, "\n");
va_end(vl);
}

/*
* vi: ft=c:ts=2:sw=2:expandtab
*/

6 changes: 6 additions & 0 deletions util.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,12 @@
#include <string.h>
#include <errno.h>

#include "ast.h"
#include "config.h"

#define MAX(a,b) (((a) > (b)) ? (a) : (b))
#define MIN(a,b) (((a) < (b)) ? (a) : (b))

#ifndef HAVE_STRDUP
#define strdup(p) strdup_(p, __FILE__, __LINE__)
char *strdup_(char *p, const char *file, unsigned line)
Expand All @@ -39,6 +43,8 @@ const char *itob4(int number);
const char *itob8(int number);
const char *itob64(int64_t number);

void out(const char *fmt, ...);

#endif /* UTIL_H */

/*
Expand Down

0 comments on commit bfe63a6

Please sign in to comment.