commit - /dev/null
commit + 1fd6a24895e5c39d792bec617ffc1b74b9f36975
blob - /dev/null
blob + afdbb6da6b208dcf5e0277d889950329c37a6c1d (mode 644)
--- /dev/null
+++ cc/irc/Makefile
+CFLAGS = -ansi -Wno-deprecated-non-prototype
+
+all: irc
+
+clean:
+ rm -f irc
+
+run: all
+ ./irc < test.ir
+
+
blob - /dev/null
blob + 2f31738bf40a18397495225e27f790e317199bff (mode 644)
--- /dev/null
+++ cc/irc/irc.c
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <ctype.h>
+
+
+// LEXER
+
+enum {
+ TK_INT = 128,
+ TK_REG,
+ TK_IDENT,
+ TK_EOF,
+};
+
+union {
+ long i;
+ char *s;
+} lval;
+
+int linenum = 1;
+
+peekch (void)
+{
+ int ch;
+ ch = getchar ();
+ ungetc (ch, stdin);
+ return ch;
+}
+
+nextch (void)
+{
+ int ch;
+ ch = getchar ();
+ if (ch == '\n')
+ ++linenum;
+ return ch;
+}
+
+parse_int (void)
+{
+ long i = 0;
+
+ while (isdigit (peekch ()))
+ i = i * 10 + (nextch () - '0');
+
+ lval.i = i;
+ return 0;
+}
+
+isname (ch)
+{
+ return isalnum (ch) || ch == '_';
+}
+
+error (line, msg)
+char *msg;
+{
+ fprintf (stderr, "%d: error: %s\n", line, msg);
+ exit (1);
+ return -1;
+}
+
+lex (void)
+{
+ size_t cap, len;
+ char *s;
+ long i;
+ int ch;
+
+begin:
+ while (isspace (peekch ()))
+ nextch ();
+
+ ch = peekch ();
+
+ if (isdigit (ch)) {
+ parse_int ();
+ return TK_INT;
+ } else if (isalpha (ch) || ch == '_') {
+ cap = 10;
+ len = 0;
+ s = malloc (cap + 1);
+
+ while (isname (peekch ())) {
+ if (len == cap) {
+ cap *= 2;
+ s = realloc (s, cap + 1);
+ }
+ s[len++] = nextch ();
+ }
+ s[len] = '\0';
+ lval.s = s;
+ return TK_IDENT;
+ } else switch (ch) {
+ case '$':
+ nextch ();
+ parse_int ();
+ return TK_REG;
+ case '(':
+ case ')':
+ case '{':
+ case '}':
+ case ':':
+ case ';':
+ case ',':
+ case '=':
+ case '*':
+ return nextch ();
+ case '#':
+ while (1) {
+ ch = peekch ();
+ if (ch == EOF || ch == '\n')
+ break;
+ nextch ();
+ }
+ goto begin;
+ case EOF:
+ return TK_EOF;
+ default:
+ return error (linenum, "invalid input");
+ }
+}
+
+// AST DATA TYPES
+
+enum dtype_type {
+ DT_NONE,
+ DT_BYTE,
+ DT_WORD,
+ DT_PTR,
+};
+
+struct dtype {
+ enum dtype_type type;
+ struct dtype *inner;
+};
+
+enum expr_type {
+ EX_INT,
+ EX_ALLOCA,
+ EX_ADD,
+ EX_READ,
+ EX_CALL,
+};
+
+struct expr {
+ enum expr_type type;
+ union {
+ int i;
+ struct {
+ int num;
+ int off;
+ } alloca;
+ struct {
+ int l, r;
+ } bin;
+ struct {
+ char *fn;
+ int nargs;
+ int args[8];
+ } call;
+ };
+};
+
+enum ir_type {
+ IR_LET,
+ IR_WRITE,
+ IR_RET,
+};
+
+struct ir {
+ struct ir *next, *prev;
+ enum ir_type type;
+ int line;
+
+ union {
+ int reg;
+ struct {
+ int dest;
+ struct dtype dt;
+ struct expr val;
+ } let;
+ struct {
+ int dest, src;
+ } write;
+ };
+};
+
+enum reg_type {
+ R_NONE,
+ R_PARAM,
+ R_LOCAL,
+ R_LABEL,
+};
+
+struct reg {
+ enum reg_type type;
+ struct dtype dt;
+ int off;
+};
+
+#define NREGS 128
+struct func {
+ char *name;
+ struct dtype dt;
+ struct reg regs[NREGS];
+ struct ir *body;
+ int stoff;
+};
+
+// MISC
+
+sizeof_dt (dt)
+struct dtype *dt;
+{
+ switch (dt->type) {
+ case DT_NONE:
+ return error (linenum, "sizeof_dt(DT_NONE)");
+ case DT_BYTE:
+ return 1;
+ case DT_WORD:
+ case DT_PTR:
+ return 2;
+ }
+}
+
+assert_dt_eq (a, b)
+struct dtype *a, *b;
+{
+ if (a->type != b->type)
+ return error (linenum, "type mismatch");
+
+ if (a->type == DT_PTR)
+ return assert_dt_eq (a->inner, b->inner);
+
+ return 0;
+}
+
+assert_dt_ptr (ptr, to)
+struct dtype *ptr, *to;
+{
+ if (ptr->type != DT_PTR)
+ return error (linenum, "not a pointer");
+
+ return assert_dt_eq (ptr->inner, to);
+}
+
+
+// PARSER
+
+#define new(T) ((T *)calloc (1, sizeof (T)))
+#define expect(exp) (lex () != (exp) ? error (linenum, "expected " #exp) : 0)
+#define stalloc(fn, nbytes) ((fn)->stoff -= (((nbytes) + 1) & ~1))
+
+dtype (dt)
+struct dtype *dt;
+{
+ int tk;
+
+ tk = lex ();
+
+ if (tk == '*') {
+ dt->type = DT_PTR;
+ dt->inner = new (struct dtype);
+ return dtype (dt->inner);
+ }
+
+ if (tk != TK_IDENT)
+ goto err;
+
+ if (strcmp (lval.s, "byte") == 0) {
+ dt->type = DT_BYTE;
+ } else if (strcmp (lval.s, "word") == 0) {
+ dt->type = DT_WORD;
+ } else {
+ err:
+ error (linenum, "expected dtype");
+ }
+ return 0;
+}
+
+expr (fn, dt, e)
+struct func *fn;
+struct dtype *dt;
+struct expr *e;
+{
+ int tk;
+
+ tk = lex ();
+
+ if (tk == TK_INT) {
+ e->type = EX_INT;
+ e->i = lval.i;
+ expect (';');
+ return 0;
+ }
+
+ if (tk != TK_IDENT)
+ goto err;
+
+ if (strcmp (lval.s, "alloca") == 0) {
+ if (dt->type != DT_PTR)
+ error (linenum, "the result of alloca must be stored in a pointer");
+
+ e->type = EX_ALLOCA;
+ expect (TK_INT);
+ e->alloca.num = lval.i;
+ stalloc (fn, sizeof_dt (dt->inner) * e->alloca.num);
+ e->alloca.off = fn->stoff;
+ expect (';');
+ } else if (strcmp (lval.s, "add") == 0) {
+ e->type = EX_ADD;
+ expect (TK_REG);
+ e->bin.l = lval.i;
+ expect (',');
+ expect (TK_REG);
+ e->bin.r = lval.i;
+ expect (';');
+
+ assert_dt_eq (dt, &fn->regs[e->bin.l].dt);
+ assert_dt_eq (dt, &fn->regs[e->bin.r].dt);
+ } else if (strcmp (lval.s, "read") == 0) {
+ e->type = EX_READ;
+ expect (TK_REG);
+ e->i = lval.i;
+ expect (';');
+
+ assert_dt_ptr (&fn->regs[e->i].dt, dt);
+ } else if (strcmp (lval.s, "call") == 0) {
+ e->type = EX_CALL;
+ expect (TK_IDENT);
+ e->call.fn = lval.s;
+ e->call.nargs = 0;
+
+ while ((tk = lex ()) == ',') {
+ expect (TK_REG);
+ e->call.args[e->call.nargs++] = lval.i;
+ }
+
+ if (tk != ';')
+ error (linenum, "invalid call");
+
+ // TODO: assert_dt_*
+ } else {
+ err:
+ error (linenum, "expected expr");
+ }
+ return 0;
+}
+
+stmt (fn, ir, tk)
+struct func *fn;
+struct ir *ir;
+{
+ struct reg *r;
+
+ if (tk != TK_IDENT)
+ goto err;
+
+ ir->line = linenum;
+
+ if (strcmp (lval.s, "let") == 0) {
+ ir->type = IR_LET;
+ expect (TK_REG);
+ ir->let.dest = lval.i;
+ expect (':');
+ dtype (&ir->let.dt);
+ expect ('=');
+ expr (fn, &ir->let.dt, &ir->let.val);
+
+ r = &fn->regs[ir->let.dest];
+ r->type = R_LOCAL;
+ r->dt = ir->let.dt;
+ stalloc (fn, sizeof_dt (&r->dt));
+ r->off = fn->stoff;
+ } else if (strcmp (lval.s, "write") == 0) {
+ ir->type = IR_WRITE;
+ expect (TK_REG);
+ ir->write.dest = lval.i;
+ expect (',');
+ expect (TK_REG);
+ ir->write.src = lval.i;
+ expect (';');
+
+ assert_dt_ptr (&fn->regs[ir->write.dest].dt, &fn->regs[ir->write.src].dt);
+ } else if (strcmp (lval.s, "ret") == 0) {
+ ir->type = IR_RET;
+ expect (TK_REG);
+ ir->reg = lval.i;
+ expect (';');
+
+ assert_dt_eq (&fn->dt, &fn->regs[ir->reg].dt);
+ } else {
+ err:
+ printf ("%d\n", tk);
+ error (linenum, "expected IR stmt");
+ }
+ return 0;
+}
+
+func (fn)
+struct func *fn;
+{
+ struct ir *ir = NULL;
+ int tk, i, stoff;
+
+ expect (TK_IDENT);
+ fn->name = lval.s;
+
+ expect ('(');
+ stoff = 4;
+
+ // parse parameter list
+ while (1) {
+ tk = lex ();
+ switch (tk) {
+ case ',':
+ break;
+ case ')':
+ goto rt;
+ case TK_REG:
+ i = lval.i;
+ expect (':');
+ fn->regs[i].type = R_PARAM;
+ fn->regs[i].off = stoff;
+ dtype (&fn->regs[i].dt);
+ stoff += (sizeof_dt (&fn->regs[i].dt) + 1) & ~1;
+ break;
+ default:
+ printf ("%d\n", tk);
+ error (linenum, "invalid parameter list");
+ }
+ }
+
+rt:
+ expect (':');
+ dtype (&fn->dt);
+ expect ('{');
+
+ fn->stoff = 0;
+
+ while ((tk = lex ()) != '}') {
+ if (ir == NULL) {
+ ir = new (struct ir);
+ fn->body = ir;
+ } else {
+ ir->next = new (struct ir);
+ ir->next->prev = ir;
+ ir = ir->next;
+ }
+
+ stmt (fn, ir, tk);
+ }
+
+ return 0;
+}
+
+parse (void)
+{
+ struct func fn;
+ int tk;
+
+ while ((tk = lex ()) != TK_EOF) {
+ if (tk != TK_IDENT)
+ goto err;
+
+ if (strcmp (lval.s, "fn") == 0) {
+ memset (&fn, 0, sizeof (fn));
+ func (&fn);
+ gen (&fn);
+ } else {
+ err:
+ error (linenum, "expected fn");
+ }
+ }
+
+ return 0;
+}
+
+// IR PRINTING
+
+print_dt (dt)
+struct dtype *dt;
+{
+ switch (dt->type) {
+ case DT_NONE:
+ error (0, "print_dt(DT_NONE)");
+ break;
+ case DT_BYTE:
+ printf ("byte");
+ break;
+ case DT_WORD:
+ printf ("word");
+ break;
+ case DT_PTR:
+ putchar ('*');
+ print_dt (dt->inner);
+ break;
+ }
+ return 0;
+}
+
+print_ex (e)
+struct expr *e;
+{
+ int i;
+
+ switch (e->type) {
+ case EX_INT:
+ printf ("%d", e->i);
+ break;
+ case EX_ALLOCA:
+ printf ("alloca %d", e->alloca.num);
+ break;
+ case EX_ADD:
+ printf ("add $%d, $%d", e->bin.l, e->bin.r);
+ break;
+ case EX_READ:
+ printf ("read $%d", e->i);
+ break;
+ case EX_CALL:
+ printf ("call %s", e->call.fn);
+ for (i = 0; i < e->call.nargs; ++i)
+ printf (", $%d", e->call.args[i]);
+ break;
+ }
+ return 0;
+}
+
+print_ir (ir)
+struct ir *ir;
+{
+ switch (ir->type) {
+ case IR_LET:
+ printf ("let $%d: ", ir->let.dest);
+ print_dt (&ir->let.dt);
+ printf (" = ");
+ print_ex (&ir->let.val);
+ puts (";");
+ break;
+ case IR_WRITE:
+ printf ("write $%d, $%d;\n", ir->write.dest, ir->write.src);
+ break;
+ case IR_RET:
+ printf ("ret $%d;\n", ir->reg);
+ break;
+ }
+ return 0;
+}
+
+// ASM MISC
+
+enum x86_reg {
+ AX,
+ BX,
+ CX,
+ DX,
+};
+
+char *
+dt_reg (reg, dt)
+enum x86_reg reg;
+struct dtype *dt;
+{
+ switch (dt->type) {
+ case DT_NONE:
+ return error (0, "dt_reg(DT_NONE)"), NULL;
+ case DT_BYTE:
+ switch (reg) {
+ case AX:
+ return "al";
+ case BX:
+ return "bl";
+ case CX:
+ return "cl";
+ case DX:
+ return "dl";
+ }
+ break;
+ case DT_WORD:
+ case DT_PTR:
+ switch (reg) {
+ case AX:
+ return "ax";
+ case BX:
+ return "bx";
+ case CX:
+ return "cx";
+ case DX:
+ return "dx";
+ }
+ break;
+ }
+}
+
+char *
+dt_size (dt)
+struct dtype *dt;
+{
+ switch (dt->type) {
+ case DT_NONE:
+ return error (0, "dt_size(DT_NONE)"), NULL;
+ case DT_BYTE:
+ return "byte";
+ case DT_WORD:
+ case DT_PTR:
+ return "word";
+ }
+}
+
+// ASM GEN
+
+load (dest, src)
+enum x86_reg dest;
+struct reg *src;
+{
+ char *reg, *size;
+
+ switch (src->type) {
+ case R_NONE:
+ return error (0, "load(R_NONE)");
+ case R_LOCAL:
+ case R_PARAM:
+ reg = dt_reg (dest, &src->dt);
+ size = dt_size (&src->dt);
+ printf ("\tmov %s, %s [bp + %d]\n",
+ reg, size, src->off);
+ break;
+ case R_LABEL:
+ error (0, "todo: load(R_LABEL)");
+ }
+ return 0;
+}
+
+store (dest, src)
+struct reg *dest;
+enum x86_reg src;
+{
+ char *reg, *size;
+
+ switch (dest->type) {
+ case R_NONE:
+ return error (0, "store(R_NONE)");
+ case R_LOCAL:
+ reg = dt_reg (src, &dest->dt);
+ size = dt_size (&dest->dt);
+ printf ("\tmov %s [bp + %d], %s\n",
+ size, dest->off, reg);
+ break;
+ case R_PARAM:
+ return error (0, "store(R_PARAM)");
+ case R_LABEL:
+ return error (0, "store(R_PARAM)");
+ }
+ return 0;
+}
+
+gen_expr (fn, dt, e)
+struct func *fn;
+struct dtype *dt;
+struct expr *e;
+{
+ struct reg *r;
+ int i, cnt;
+
+ switch (e->type) {
+ case EX_INT:
+ printf ("\tmov ax, %d\n", e->i);
+ break;
+ case EX_ALLOCA:
+ printf ("\tlea ax, [bp + %d]\n", e->alloca.off);
+ break;
+ case EX_ADD:
+ load (AX, &fn->regs[e->bin.l]);
+ load (DX, &fn->regs[e->bin.l]);
+ puts ("\tadd ax, dx");
+ break;
+ case EX_READ:
+ load (BX, &fn->regs[e->i]);
+ printf ("\tmov %s, %s [bx]\n", dt_reg (AX, dt), dt_size (dt));
+ break;
+ case EX_CALL:
+ cnt = 0;
+ for (i = e->call.nargs - 1; i >= 0; --i) {
+ r = &fn->regs[e->call.args[i]];
+
+ switch (r->dt.type) {
+ case DT_NONE:
+ error (0, "gen_expr(): call with DT_NONE");
+ break;
+ case DT_BYTE:
+ case DT_WORD:
+ case DT_PTR:
+ load (AX, r);
+ puts ("\tpush ax");
+ break;
+ }
+
+ cnt += sizeof_dt (&r->dt);
+ }
+ printf ("\tcall %s\n", e->call.fn);
+ printf ("\tadd sp, %d\n", cnt);
+ break;
+ }
+ return 0;
+}
+
+gen_ir (fn, ir)
+struct func *fn;
+struct ir *ir;
+{
+ struct dtype *dt;
+
+ printf ("\t; ");
+ print_ir (ir);
+
+ switch (ir->type) {
+ case IR_LET:
+ gen_expr (fn, &fn->regs[ir->let.dest].dt, &ir->let.val);
+ store (&fn->regs[ir->let.dest], AX);
+ break;
+ case IR_WRITE:
+ load (AX, &fn->regs[ir->write.src]);
+ load (BX, &fn->regs[ir->write.dest]);
+ dt = &fn->regs[ir->write.src].dt;
+ printf ("\tmov %s [bx], %s\n", dt_size (dt), dt_reg (AX, dt));
+ break;
+ case IR_RET:
+ load (AX, &fn->regs[ir->reg]);
+ if (ir->next != NULL)
+ puts ("\tjmp .ret");
+ break;
+ }
+ puts ("");
+ return 0;
+}
+
+gen (fn)
+struct func *fn;
+{
+ struct ir *ir;
+
+ printf ("%s:\n", fn->name);
+ puts ("\tpush bp");
+ puts ("\tmov bp, sp");
+ printf ("\tsub sp, %d\n", -fn->stoff);
+ puts ("");
+
+ for (ir = fn->body; ir != NULL; ir = ir->next)
+ gen_ir (fn, ir);
+
+ puts (".ret:");
+ printf ("\tadd sp, %d\n", -fn->stoff);
+ puts ("\tpop bp");
+ puts ("\tret");
+ puts ("");
+
+ return 0;
+}
+
+// MAIN
+
+main (void)
+{
+ parse ();
+ return 0;
+}
blob - /dev/null
blob + ee9aae6cc5412c809cf4605a38aa14fef756c131 (mode 644)
--- /dev/null
+++ cc/irc/test.ir
+
+fn add ($0: word, $1: word): word {
+ # int res;
+ let $2: *word = alloca 1;
+
+ # res = $0 + $1;
+ let $3: word = add $0, $1;
+ write $2, $3;
+
+ # return res;
+ let $4: word = read $2;
+ ret $4;
+}
+
+fn main ($0: word, $1: **byte): word {
+ # int x, y, z;
+ let $2: *word = alloca 1; # x
+ let $3: *word = alloca 1; # y
+ let $4: *word = alloca 1; # z
+
+ # x = 3;
+ let $5: word = 3;
+ write $2, $5;
+
+ # y = 2;
+ let $6: word = 2;
+ write $3, $6;
+
+ # z = add(x, y);
+ let $7: word = read $2;
+ let $8: word = read $3;
+ let $9: word = call add, $7, $8;
+ write $4, $9;
+
+ # return z;
+ let $10: word = read $4;
+ ret $10;
+}
blob - /dev/null
blob + 1da0bd827530fb298c7da740561894dfd2f592e0 (mode 644)
Binary files /dev/null and sys/.loader.asm.swp differ
blob - /dev/null
blob + 8343815d60afa69b4a0d8da66581b71e26aced45 (mode 644)
--- /dev/null
+++ sys/Makefile
+.SUFFIXES: .asm .bin
+
+all: floppy.img
+
+clean:
+ rm -f floppy.img *.bin
+
+run: floppy.img
+ qemu-system-i386 -M pc -m 4M -fda floppy.img
+
+floppy.img: loader.bin kern.bin
+ cat loader.bin kern.bin > floppy.img
+
+.asm.bin:
+ nasm -fbin -o $@ $<
blob - /dev/null
blob + 0b45a1a612f911b3a57817aaac3dfcf139356a27 (mode 644)
--- /dev/null
+++ sys/kern.asm
+[org 0]
+[bits 16]
+[cpu 286]
+
+_start:
+ mov ax, 0x18
+ mov es, ax
+ mov byte [es:0], 'H'
+ jmp $
+
+hello:
+ db "Hello World", 13, 10, 0
blob - /dev/null
blob + 649daf4117b26c0b0bf6f6238848a68d524663b4 (mode 644)
--- /dev/null
+++ sys/loader.asm
+[org 0x7C00]
+[bits 16]
+[cpu 286]
+
+KERN_BEGIN equ 0x8000
+
+_start:
+ ; load 32KiB from floppy
+ mov ah, 0x02
+ mov al, 63
+ mov ch, 0
+ mov cl, 2
+ mov dh, 0
+ mov bx, (KERN_BEGIN >> 4)
+ mov es, bx
+ xor bx, bx
+ int 0x13
+ jc _start
+
+ ; zero out IDT
+ cli
+ cld
+ mov ax, 0x80
+ mov es, ax
+ xor ax, ax
+ xor di, di
+ mov cx, (256 * 8 / 2)
+ rep stosw
+ lidt [idtr]
+
+ ; set up GDT
+ lgdt [gdtr]
+
+ smsw ax
+ or ax, 1
+ lmsw ax
+
+ mov ax, 0x10
+ mov ds, ax
+ mov es, ax
+ mov ss, ax
+ jmp 0x08:0
+
+idtr:
+ dw (256 * 8) - 1
+ dd 0x800
+
+gdtr:
+ dw gdt.end - gdt - 1
+ dd gdt
+
+gdt:
+ dq 0
+
+ ; kernel code
+ dw 65535
+ dw (KERN_BEGIN & 0xffff)
+ db (KERN_BEGIN >> 16) & 0xf
+ db 0x9A
+ dw 0
+
+ ; kernel data
+ dw 65535
+ dw (KERN_BEGIN & 0xffff)
+ db (KERN_BEGIN >> 16) & 0xf
+ db 0x92
+ dw 0
+
+ ; vidmem
+ dw 4000
+ dw 0x8000
+ db 0x0b
+ db 0x92
+ dw 0
+.end:
+
+times 510 - ($ - $$) db 0
+dw 0xAA55