226 lines
5.1 KiB
C
226 lines
5.1 KiB
C
#include <stddef.h>
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <stdint.h>
|
|
#include <string.h>
|
|
|
|
#include "bytecode.h"
|
|
#include "format.h"
|
|
#include "io.h"
|
|
#include "lex.h"
|
|
|
|
#define ELF_HEADER_SIZE 0xb0
|
|
|
|
enum map_type {
|
|
MAP_LEFT_TIMES,
|
|
MAP_RIGHT_TIMES,
|
|
MAP_LEFT_PLUS,
|
|
MAP_RIGHT_PLUS,
|
|
};
|
|
|
|
static enum map_type maps[16];
|
|
static size_t mapi = 0;
|
|
|
|
static char* label_names[2048];
|
|
static symbol label_symbols[2048];
|
|
static size_t labeli = 0;
|
|
|
|
enum map_type pop(void) {
|
|
if (mapi <= 0) {
|
|
fprintf(stderr, "unmatched }\n");
|
|
exit(1);
|
|
}
|
|
|
|
return maps[--mapi];
|
|
}
|
|
|
|
void push(enum map_type type) {
|
|
if (mapi >= 16) {
|
|
fprintf(stderr, "out of maps\n");
|
|
exit(1);
|
|
}
|
|
|
|
maps[mapi++] = type;
|
|
}
|
|
|
|
symbol lookup_label(const char* name) {
|
|
for (size_t i = 0; i < labeli; i++) {
|
|
if (strcmp(label_names[i], name) == 0) {
|
|
fprintf(stderr, "%s\n", name);
|
|
return label_symbols[i];
|
|
}
|
|
}
|
|
|
|
if (labeli >= 2048) {
|
|
fprintf(stderr, "out of labels\n");
|
|
exit(1);
|
|
}
|
|
|
|
fprintf(stderr, "%s:\n", name);
|
|
|
|
unsigned long len = strlen(name) + 1;
|
|
label_names[labeli] = malloc(len);
|
|
memcpy(label_names[labeli], name, len);
|
|
label_symbols[labeli] = new_symbol();
|
|
return label_symbols[labeli++];
|
|
}
|
|
|
|
void nomap(void) {
|
|
if (mapi > 0) {
|
|
fprintf(stderr, "expected all maps to be closed before new label or EOF\n");
|
|
exit(1);
|
|
}
|
|
}
|
|
|
|
void begin_map(enum map_type type) {
|
|
if (next().type != TOK_MAP_BEGIN) {
|
|
fprintf(stderr, "expected {\n");
|
|
exit(1);
|
|
}
|
|
push(type);
|
|
}
|
|
|
|
symbol compile(void) {
|
|
symbol entry_point = init_bytecode();
|
|
|
|
while (true) {
|
|
struct token tok = next();
|
|
switch (tok.type) {
|
|
case TOK_COMM:
|
|
comm();
|
|
break;
|
|
case TOK_ASSOCL:
|
|
assocl();
|
|
break;
|
|
case TOK_ASSOCR:
|
|
assocr();
|
|
break;
|
|
case TOK_DISTL:
|
|
distl();
|
|
break;
|
|
case TOK_DISTR:
|
|
distr();
|
|
break;
|
|
case TOK_FACTL:
|
|
factl();
|
|
break;
|
|
case TOK_FACTR:
|
|
factr();
|
|
break;
|
|
case TOK_MAPL:
|
|
begin_map(MAP_LEFT_TIMES);
|
|
mapl_begin();
|
|
break;
|
|
case TOK_MAPR:
|
|
begin_map(MAP_RIGHT_TIMES);
|
|
mapr_begin();
|
|
break;
|
|
case TOK_UNITIL:
|
|
unitil();
|
|
break;
|
|
case TOK_UNITIR:
|
|
unitir();
|
|
break;
|
|
case TOK_UNITEL:
|
|
unitel();
|
|
break;
|
|
case TOK_UNITER:
|
|
uniter();
|
|
break;
|
|
case TOK_COMM_PLUS:
|
|
comm_plus();
|
|
break;
|
|
case TOK_ASSOCL_PLUS:
|
|
assocl_plus();
|
|
break;
|
|
case TOK_ASSOCR_PLUS:
|
|
assocr_plus();
|
|
break;
|
|
case TOK_MAPL_PLUS:
|
|
begin_map(MAP_LEFT_PLUS);
|
|
mapl_plus_begin();
|
|
break;
|
|
case TOK_MAPR_PLUS:
|
|
begin_map(MAP_RIGHT_PLUS);
|
|
mapr_plus_begin();
|
|
break;
|
|
case TOK_INL:
|
|
inl();
|
|
break;
|
|
case TOK_INR:
|
|
inr();
|
|
break;
|
|
case TOK_OUT:
|
|
out();
|
|
break;
|
|
case TOK_HALT:
|
|
halt();
|
|
break;
|
|
case TOK_LABEL:
|
|
nomap();
|
|
define_executable_symbol(lookup_label(tok.identifier));
|
|
break;
|
|
case TOK_JUMP:
|
|
fprintf(stderr, "!jump %s\n", tok.identifier);
|
|
nomap();
|
|
jump(lookup_label(tok.identifier));
|
|
break;
|
|
case TOK_MAP_BEGIN:
|
|
fprintf(stderr, "unexpected {\n");
|
|
exit(1);
|
|
break;
|
|
case TOK_MAP_END:
|
|
; enum map_type type = pop();
|
|
switch (type) {
|
|
case MAP_LEFT_TIMES:
|
|
mapl_end();
|
|
break;
|
|
case MAP_RIGHT_TIMES:
|
|
mapr_end();
|
|
break;
|
|
case MAP_LEFT_PLUS:
|
|
mapl_plus_end();
|
|
break;
|
|
case MAP_RIGHT_PLUS:
|
|
mapr_plus_end();
|
|
break;
|
|
}
|
|
break;
|
|
case TOK_EOF:
|
|
goto eof;
|
|
case TOK_IF:
|
|
nomap();
|
|
struct token a = next();
|
|
struct token b = next();
|
|
fprintf(stderr, "!if %s %s\n", a.identifier, b.identifier);
|
|
symbol aa = lookup_label(a.identifier);
|
|
symbol bb = lookup_label(b.identifier);
|
|
if (a.type != TOK_JUMP || b.type != TOK_JUMP) {
|
|
fprintf(stderr, "arguments to 'if' should be labels\n");
|
|
exit(1);
|
|
}
|
|
jump_if(aa, bb);
|
|
break;
|
|
}
|
|
}
|
|
eof:
|
|
nomap();
|
|
finish_bytecode();
|
|
return entry_point;
|
|
}
|
|
|
|
int main(int argc, char** argv) {
|
|
if (argc != 3) {
|
|
fprintf(stderr, "usage: %s <output file> <source file>\n", argv[0]);
|
|
exit(1);
|
|
}
|
|
open_files(argv[2], argv[1]);
|
|
|
|
elf_executable();
|
|
symbol entry_point = compile();
|
|
finish_executable(entry_point);
|
|
|
|
close_files();
|
|
return 0;
|
|
}
|