pass-lang/src/main.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;
}