nooc

nooc programming language compiler
git clone git://git.nihaljere.xyz/nooc
Log | Files | Refs | LICENSE

main.c (4595B)


      1 #include <assert.h>
      2 #include <fcntl.h>
      3 #include <stdbool.h>
      4 #include <string.h>
      5 #include <stdint.h>
      6 #include <stdio.h>
      7 #include <sys/stat.h>
      8 #include <sys/mman.h>
      9 #include <unistd.h>
     10 
     11 #include "array.h"
     12 #include "nooc.h"
     13 #include "stack.h"
     14 #include "ir.h"
     15 #include "util.h"
     16 #include "elf.h"
     17 #include "type.h"
     18 #include "map.h"
     19 #include "target.h"
     20 
     21 static struct stack blocks;
     22 struct assgns assgns;
     23 struct exprs exprs;
     24 struct target targ;
     25 struct toplevel toplevel;
     26 struct map *typesmap;
     27 char *infile;
     28 
     29 struct block parse(const struct token *const start);
     30 struct token *lex(struct slice start);
     31 
     32 uint64_t
     33 data_push(const char *const ptr, const size_t len)
     34 {
     35 	array_push((&toplevel.data), ptr, len);
     36 	return DATA_OFFSET + toplevel.data.len - len;
     37 }
     38 
     39 uint64_t
     40 data_pushzero(const size_t len)
     41 {
     42 	array_zero((&toplevel.data), len);
     43 	return DATA_OFFSET + toplevel.data.len - len;
     44 }
     45 
     46 void
     47 data_set(const uint64_t addr, const void *const ptr, const size_t len)
     48 {
     49 	memcpy(&toplevel.data.data[addr - DATA_OFFSET], ptr, len);
     50 }
     51 
     52 void
     53 evalexpr(struct decl *const decl)
     54 {
     55 	struct expr *expr = &exprs.data[decl->val];
     56 	if (expr->kind == EXPR_LIT) {
     57 		switch (expr->class) {
     58 		case C_INT: {
     59 			const struct type *const type = &types.data[decl->type];
     60 			data_set(decl->w.addr, &expr->d.v.v, type->size);
     61 			break;
     62 		}
     63 		case C_STR: {
     64 			const uint64_t addr = data_push(expr->d.v.v.s.data, expr->d.v.v.s.len);
     65 			decl->w.addr = addr;
     66 			break;
     67 		}
     68 		default:
     69 			error(expr->start->line, expr->start->col, "genexpr: unknown value type!");
     70 		}
     71 	} else {
     72 		error(expr->start->line, expr->start->col, "cannot evaluate expression at compile time");
     73 	}
     74 }
     75 
     76 void
     77 gentoplevel(struct toplevel *toplevel, const struct block *const block)
     78 {
     79 	char syscallname[] = "syscall0";
     80 	stackpush(&blocks, block);
     81 	typecheck(&blocks, block);
     82 	struct iproc iproc = { 0 };
     83 	uint64_t curaddr = TEXT_OFFSET;
     84 
     85 	iproc.s = (struct slice){8, 8, syscallname};
     86 	for (int i = 1; i < 8; i++) {
     87 		syscallname[7]++;
     88 		iproc.s.data = strdup(syscallname);
     89 		iproc.addr = curaddr;
     90 		array_add((&toplevel->code), iproc);
     91 		curaddr += targ.emitsyscall(&toplevel->text, i);
     92 	}
     93 	for (int i = 0; i < block->len; i++) {
     94 		const struct statement *const statement = &block->data[i];
     95 
     96 		switch (statement->kind) {
     97 		case STMT_EXPR:
     98 			die("toplevel expressions are unimplemented");
     99 		case STMT_ASSGN:
    100 			die("toplevel assignments are unimplemented");
    101 		case STMT_DECL: {
    102 			struct decl *const decl = &block->decls.data[statement->idx];
    103 			const struct expr *const expr = &exprs.data[decl->val];
    104 			const struct type *const type = &types.data[decl->type];
    105 
    106 			if (type->class == TYPE_PROC) {
    107 				assert(expr->class == C_PROC);
    108 				assert(expr->kind == EXPR_PROC);
    109 				iproc = (struct iproc){
    110 					.s = decl->s,
    111 					.addr = curaddr
    112 				};
    113 
    114 				if (slice_cmplit(&decl->s, "main") == 0)
    115 					toplevel->entry = curaddr;
    116 
    117 				stackpush(&blocks, &expr->d.proc.block);
    118 				typecheck(&blocks, &expr->d.proc.block);
    119 				genproc(&blocks, &iproc, &expr->d.proc);
    120 				array_add((&toplevel->code), iproc);
    121 				curaddr += targ.emitproc(&toplevel->text, &iproc);
    122 				stackpop(&blocks);
    123 			} else {
    124 				if (slice_cmplit(&decl->s, "main") == 0)
    125 					die("global main must be procedure");
    126 
    127 				if (type->class == TYPE_ARRAY) {
    128 					const struct type *const subtype = &types.data[type->d.arr.subtype];
    129 					decl->w.addr = data_pushzero(subtype->size * type->d.arr.len);
    130 				} else {
    131 					decl->w.addr = data_pushzero(type->size);
    132 				}
    133 
    134 				evalexpr(decl);
    135 			}
    136 			break;
    137 		}
    138 		default:
    139 			die("unreachable");
    140 		}
    141 
    142 	}
    143 	stackpop(&blocks);
    144 }
    145 
    146 int
    147 main(int argc, char *argv[])
    148 {
    149 	targ = x64_target;
    150 	if (argc < 3) {
    151 		fprintf(stderr, "not enough args\n");
    152 		return 1;
    153 	}
    154 
    155 	infile = argv[1];
    156 	const int in = open(infile, 0, O_RDONLY);
    157 	if (in < 0) {
    158 		fprintf(stderr, "couldn't open input\n");
    159 		return 1;
    160 	}
    161 
    162 	struct stat statbuf;
    163 	if (fstat(in, &statbuf) < 0) {
    164 		close(in);
    165 		fprintf(stderr, "failed to stat in file\n");
    166 		return 1;
    167 	}
    168 
    169 	char *const addr = mmap(NULL, statbuf.st_size, PROT_READ, MAP_PRIVATE, in, 0);
    170 	close(in);
    171 	if (addr == NULL) {
    172 		fprintf(stderr, "failed to map input file into memory\n");
    173 		return 1;
    174 	}
    175 
    176 	const struct token *const head = lex((struct slice){statbuf.st_size, statbuf.st_size, addr});
    177 
    178 	typesmap = mkmap(16);
    179 	inittypes();
    180 	const struct block statements = parse(head);
    181 
    182 	gentoplevel(&toplevel, &statements);
    183 
    184 	FILE *const out = fopen(argv[2], "w");
    185 	if (!out) {
    186 		close(in);
    187 		fprintf(stderr, "couldn't open output\n");
    188 		return 1;
    189 	}
    190 
    191 	munmap(addr, statbuf.st_size);
    192 
    193 	elf(toplevel.entry, &toplevel.text, &toplevel.data, out);
    194 
    195 	fclose(out);
    196 }