os

An operating system
git clone https://erai.gay/code/os/
Log | Files | Refs | README | LICENSE

commit a730892ab4180d210c6bce747aee00756bb2b23c
parent 15c86d14159eae6ce5efd60a179f8d5bdf37f6a5
Author: erai <erai@omiltem.net>
Date:   Tue, 17 Sep 2024 09:12:43 -0400

c generator

Diffstat:
M.gitignore | 1+
Mbootstrap.sh | 5++++-
Acout.c | 618+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 623 insertions(+), 1 deletion(-)

diff --git a/.gitignore b/.gitignore @@ -4,6 +4,7 @@ disk cc0 cc1 cc2 +cc2.c gencc parse3.c parsepeg2.c diff --git a/bootstrap.sh b/bootstrap.sh @@ -2,7 +2,7 @@ LIBS="bufio.c lib.c alloc.c syscall.c" PEG="peg.c peglib.c parsepeg.c" -SOURCES="cc1.c type.c parse2.c parse3.c peglib.c as.c decl.c node.c" +SOURCES="cc1.c type.c parse2.c parse3.c peglib.c as.c decl.c node.c cout.c" # Build the bootstrap compiler from c gcc -Wall -Wextra -Wno-unused -pedantic -std=c99 ./cc0.c -o cc0 @@ -25,3 +25,6 @@ cmp peg0 peg || echo peg mismatch # Verify that the saved bootstrap parsepeg.c came from peg.peg ./peg peg.peg -o parsepeg2.c cmp parsepeg.c parsepeg2.c || echo parsepeg mismatch + +./cc1 -C ${LIBS} ${SOURCES} -o cc2.c +cmp cc0.c cc2.c || echo bootstrap mismatch diff --git a/cout.c b/cout.c @@ -0,0 +1,618 @@ +ctranslate(c: *compiler) { + var d: *decl; + var seen: int; + var has_enum: int; + + fputs(c.cout, "#ifndef my__start\n"); + fputs(c.cout, "#define my__start main\n"); + fputs(c.cout, "#endif\n"); + fputs(c.cout, "#ifndef my_syscall\n"); + fputs(c.cout, "#define my_syscall syscall\n"); + fputs(c.cout, "#endif\n"); + + // Pass: forward declare all structs + d = first_decl(c); + loop { + if !d { + break; + } + + if d.struct_defined { + fputs(c.cout, "struct my_"); + fputs(c.cout, d.name); + fputs(c.cout, ";\n"); + } + + d = next_decl(c, d); + } + + // Pass: define structs + d = first_decl(c); + loop { + if !d { + break; + } + + if d.struct_defined { + ctranslate_struct(c, d); + } + + d = next_decl(c, d); + } + + // Pass: define enums + d = first_decl(c); + has_enum = 0; + seen = 0; + loop { + if !d { + break; + } + + if d.enum_defined { + if !has_enum { + fputs(c.cout, "enum {\n"); + has_enum = 1; + } + if seen { + fputs(c.cout, ",\n"); + } + fputs(c.cout, "\tmy_"); + fputs(c.cout, d.name); + fputs(c.cout, " = "); + fputd(c.cout, d.enum_value); + seen = 1; + } + + d = next_decl(c, d); + } + if has_enum { + fputs(c.cout, "\n};\n"); + } + + // Pass: forward declare all functions + d = first_decl(c); + loop { + if !d { + break; + } + + if d.func_defined { + ctranslate_type(c, d.func_type, d.name, 0); + fputs(c.cout, ";\n"); + } + + d = next_decl(c, d); + } + + // Pass: define functions + d = first_decl(c); + loop { + if !d { + break; + } + + if d.func_defined { + ctranslate_func(c, d); + } + + d = next_decl(c, d); + } + + flush_coutput(c); +} + +ctranslate_type(c: *compiler, ty: *type, name: *byte, ptr: int) { + var arg: *type; + if ty.kind == TY_VOID { + fputs(c.cout, "void "); + if name && name[0] { + fputs(c.cout, " my_"); + fputs(c.cout, name); + } + } else if ty.kind == TY_INT { + fputs(c.cout, "unsigned long "); + if name && name[0] { + fputs(c.cout, " my_"); + fputs(c.cout, name); + } + } else if ty.kind == TY_BYTE { + fputs(c.cout, "unsigned char "); + if name && name[0] { + fputs(c.cout, " my_"); + fputs(c.cout, name); + } + } else if ty.kind == TY_PTR { + ctranslate_type(c, ty.val, "", 1); + fputs(c.cout, "*"); + if name && name[0] { + fputs(c.cout, " my_"); + fputs(c.cout, name); + } + } else if ty.kind == TY_FUNC { + ctranslate_type(c, ty.val, "", 1); + if ptr { + die("fixme cdecl order is hard"); + } + if name && name[0] { + fputs(c.cout, " my_"); + fputs(c.cout, name); + } + fputs(c.cout, "("); + if ptr { + fputs(c.cout, "*"); + } + arg = ty.arg; + if arg { + loop { + ctranslate_type(c, arg.val, "", 1); + arg = arg.arg; + if arg { + fputs(c.cout, ", "); + } else { + break; + } + } + } else { + fputs(c.cout, "void"); + } + fputs(c.cout, ")"); + } else if ty.kind == TY_STRUCT { + fputs(c.cout, "struct my_"); + fputs(c.cout, ty.st.name); + if name && name[0] { + fputs(c.cout, " my_"); + fputs(c.cout, name); + } + } else { + die("invalid type"); + } +} + +ctranslate_zero(c: *compiler, ty: *type) { + var n: *node; + var v: *decl; + var arg: *type; + if ty.kind == TY_VOID { + die("invalid zero void"); + } else if ty.kind == TY_INT { + fputs(c.cout, "0"); + } else if ty.kind == TY_BYTE { + fputs(c.cout, "0"); + } else if ty.kind == TY_PTR { + fputs(c.cout, "0"); + } else if ty.kind == TY_FUNC { + fputs(c.cout, "0"); + } else if ty.kind == TY_STRUCT { + fputs(c.cout, "{"); + n = ty.st.struct_def.b; + loop { + if !n { + break; + } + v = find(c, ty.st.name, n.a.a.s, 0); + ctranslate_zero(c, v.member_type); + n = n.b; + } + fputs(c.cout, "}"); + } else { + die("invalid type"); + } +} + +ctranslate_struct(c: *compiler, d: *decl) { + var v: *decl; + var n: *node; + fputs(c.cout, "struct my_"); + fputs(c.cout, d.name); + fputs(c.cout, " {\n"); + n = d.struct_def.b; + loop { + if !n { + break; + } + + v = find(c, d.name, n.a.a.s, 0); + + fputs(c.cout, "\t"); + ctranslate_type(c, v.member_type, n.a.a.s, 1); + fputs(c.cout, ";\n"); + + n = n.b; + } + fputs(c.cout, "};\n"); +} + +ctranslate_vars(c: *compiler, n: *node) { + var kind: int; + var child: *node; + + if !n { + return; + } + + kind = n.kind; + if kind == N_CONDLIST { + loop { + if !n { + break; + } + ctranslate_vars(c, n.a.b); + n = n.b; + } + } else if kind == N_STMTLIST { + loop { + if !n { + break; + } + ctranslate_vars(c, n.a); + n = n.b; + } + } else if kind == N_LOOP { + ctranslate_vars(c, n.a); + } else if kind == N_VARDECL { + fputs(c.cout, "\t"); + ctranslate_type(c, n.t, n.a.s, 1); + fputs(c.cout, " = "); + ctranslate_zero(c, n.t); + fputs(c.cout, ";\n"); + } +} + +ctranslate_str(c: *compiler, s: *byte) { + var i: int; + var ch: int; + i = 0; + fputs(c.cout, "(unsigned char *)\""); + loop { + if !s[i] { + break; + } + + ch = s[i]:int; + + if ch < 32 || ch > 127 || ch == '\\' || ch == '"' { + fputc(c.cout, '\\'); + fputc(c.cout, '0' + (ch >> 6) & 7); + fputc(c.cout, '0' + (ch >> 3) & 7); + fputc(c.cout, '0' + (ch & 7)); + } else { + fputc(c.cout, ch); + } + + i = i + 1; + } + fputs(c.cout, "\""); +} + +ctranslate_expr(c: *compiler, n: *node) { + if n.kind == N_STR { + ctranslate_str(c, n.s); + } else if n.kind == N_NUM { + fputd(c.cout, n.n); + fputs(c.cout, "UL"); + } else if n.kind == N_CHAR { + fputd(c.cout, n.n); + } else if n.kind == N_CALL { + fputs(c.cout, "("); + ctranslate_expr(c, n.a); + fputs(c.cout, ")"); + fputs(c.cout, "("); + n = n.b; + loop { + if !n { + break; + } + fputs(c.cout, "("); + ctranslate_expr(c, n.a); + fputs(c.cout, ")"); + n = n.b; + if n { + fputs(c.cout, ","); + } + } + fputs(c.cout, ")"); + } else if n.kind == N_DOT { + fputs(c.cout, "("); + ctranslate_expr(c, n.a); + fputs(c.cout, ")"); + if n.a.t.kind == TY_PTR { + fputs(c.cout, "->"); + } else { + fputs(c.cout, "."); + } + fputs(c.cout, "my_"); + fputs(c.cout, n.b.s); + } else if n.kind == N_IDENT { + fputs(c.cout, "my_"); + fputs(c.cout, n.s); + } else if n.kind == N_ASSIGN { + fputs(c.cout, "("); + ctranslate_expr(c, n.a); + fputs(c.cout, ")=("); + ctranslate_expr(c, n.b); + fputs(c.cout, ")"); + } else if n.kind == N_SIZEOF { + fputd(c.cout, type_sizeof(c, n.a.t)); + fputs(c.cout, "UL"); + } else if n.kind == N_REF { + fputs(c.cout, "&("); + ctranslate_expr(c, n.a); + fputs(c.cout, ")"); + } else if n.kind == N_DEREF { + fputs(c.cout, "*("); + ctranslate_expr(c, n.a); + fputs(c.cout, ")"); + } else if n.kind == N_INDEX { + fputs(c.cout, "("); + ctranslate_expr(c, n.a); + fputs(c.cout, ")["); + ctranslate_expr(c, n.b); + fputs(c.cout, "]"); + } else if n.kind == N_LT { + fputs(c.cout, "(unsigned long)(((long)("); + ctranslate_expr(c, n.a); + fputs(c.cout, "))<((long)("); + ctranslate_expr(c, n.b); + fputs(c.cout, ")))"); + } else if n.kind == N_LE { + fputs(c.cout, "(unsigned long)(((long)("); + ctranslate_expr(c, n.a); + fputs(c.cout, "))<=((long)("); + ctranslate_expr(c, n.b); + fputs(c.cout, ")))"); + } else if n.kind == N_GT { + fputs(c.cout, "(unsigned long)(((long)("); + ctranslate_expr(c, n.a); + fputs(c.cout, "))>((long)("); + ctranslate_expr(c, n.b); + fputs(c.cout, ")))"); + } else if n.kind == N_GE { + fputs(c.cout, "(unsigned long)(((long)("); + ctranslate_expr(c, n.a); + fputs(c.cout, "))>=((long)("); + ctranslate_expr(c, n.b); + fputs(c.cout, ")))"); + } else if n.kind == N_EQ { + fputs(c.cout, "(unsigned long)(((long)("); + ctranslate_expr(c, n.a); + fputs(c.cout, "))==((long)("); + ctranslate_expr(c, n.b); + fputs(c.cout, ")))"); + } else if n.kind == N_NE { + fputs(c.cout, "(unsigned long)(((long)("); + ctranslate_expr(c, n.a); + fputs(c.cout, "))!=((long)("); + ctranslate_expr(c, n.b); + fputs(c.cout, ")))"); + } else if n.kind == N_BNOT { + fputs(c.cout, "(unsigned long)(!("); + ctranslate_expr(c, n.a); + fputs(c.cout, "))"); + } else if n.kind == N_BOR { + fputs(c.cout, "(unsigned long)(("); + ctranslate_expr(c, n.a); + fputs(c.cout, ")||("); + ctranslate_expr(c, n.b); + fputs(c.cout, "))"); + } else if n.kind == N_BAND { + fputs(c.cout, "(unsigned long)(("); + ctranslate_expr(c, n.a); + fputs(c.cout, ")&&("); + ctranslate_expr(c, n.b); + fputs(c.cout, "))"); + } else if n.kind == N_POS { + ctranslate_expr(c, n.a); + } else if n.kind == N_NEG { + fputs(c.cout, "("); + ctranslate_type(c, n.t, "", 1); + fputs(c.cout, ")(-(unsigned long)("); + ctranslate_expr(c, n.a); + fputs(c.cout, "))"); + } else if n.kind == N_NOT { + fputs(c.cout, "("); + ctranslate_type(c, n.t, "", 1); + fputs(c.cout, ")(~(unsigned long)("); + ctranslate_expr(c, n.a); + fputs(c.cout, "))"); + } else if n.kind == N_ADD { + fputs(c.cout, "("); + ctranslate_type(c, n.t, "", 1); + fputs(c.cout, ")(((unsigned long)("); + ctranslate_expr(c, n.a); + fputs(c.cout, "))+((unsigned long)("); + ctranslate_expr(c, n.b); + fputs(c.cout, ")))"); + } else if n.kind == N_SUB { + fputs(c.cout, "("); + ctranslate_type(c, n.t, "", 1); + fputs(c.cout, ")(((unsigned long)("); + ctranslate_expr(c, n.a); + fputs(c.cout, "))-((unsigned long)("); + ctranslate_expr(c, n.b); + fputs(c.cout, ")))"); + } else if n.kind == N_MUL { + fputs(c.cout, "("); + ctranslate_type(c, n.t, "", 1); + fputs(c.cout, ")(((long)("); + ctranslate_expr(c, n.a); + fputs(c.cout, "))*((long)("); + ctranslate_expr(c, n.b); + fputs(c.cout, ")))"); + } else if n.kind == N_DIV { + fputs(c.cout, "("); + ctranslate_type(c, n.t, "", 1); + fputs(c.cout, ")(((long)("); + ctranslate_expr(c, n.a); + fputs(c.cout, "))/((long)("); + ctranslate_expr(c, n.b); + fputs(c.cout, ")))"); + } else if n.kind == N_MOD { + fputs(c.cout, "("); + ctranslate_type(c, n.t, "", 1); + fputs(c.cout, ")(((long)("); + ctranslate_expr(c, n.a); + fputs(c.cout, "))%((long)("); + ctranslate_expr(c, n.b); + fputs(c.cout, ")))"); + } else if n.kind == N_LSH { + fputs(c.cout, "("); + ctranslate_type(c, n.t, "", 1); + fputs(c.cout, ")(((unsigned long)("); + ctranslate_expr(c, n.a); + fputs(c.cout, "))<<((unsigned long)("); + ctranslate_expr(c, n.b); + fputs(c.cout, ")))"); + } else if n.kind == N_RSH { + fputs(c.cout, "("); + ctranslate_type(c, n.t, "", 1); + fputs(c.cout, ")(((unsigned long)("); + ctranslate_expr(c, n.a); + fputs(c.cout, "))>>((unsigned long)("); + ctranslate_expr(c, n.b); + fputs(c.cout, ")))"); + } else if n.kind == N_AND { + fputs(c.cout, "("); + ctranslate_type(c, n.t, "", 1); + fputs(c.cout, ")(((unsigned long)("); + ctranslate_expr(c, n.a); + fputs(c.cout, "))&((unsigned long)("); + ctranslate_expr(c, n.b); + fputs(c.cout, ")))"); + } else if n.kind == N_OR { + fputs(c.cout, "("); + ctranslate_type(c, n.t, "", 1); + fputs(c.cout, ")(((unsigned long)("); + ctranslate_expr(c, n.a); + fputs(c.cout, "))|((unsigned long)("); + ctranslate_expr(c, n.b); + fputs(c.cout, ")))"); + } else if n.kind == N_XOR { + fputs(c.cout, "("); + ctranslate_type(c, n.t, "", 1); + fputs(c.cout, ")(((unsigned long)("); + ctranslate_expr(c, n.a); + fputs(c.cout, "))^((unsigned long)("); + ctranslate_expr(c, n.b); + fputs(c.cout, ")))"); + } else if n.kind == N_CAST { + fputs(c.cout, "("); + ctranslate_type(c, n.t, "", 1); + fputs(c.cout, ")"); + ctranslate_expr(c, n.a); + } else { + fdputd(2, n.kind); + die("invalid expr"); + } +} + +ctranslate_stmt(c: *compiler, n: *node) { + var kind: int; + var child: *node; + + if !n { + return; + } + + kind = n.kind; + if kind == N_CONDLIST { + fputs(c.cout, "\t"); + loop { + fputs(c.cout, "if ("); + + ctranslate_expr(c, n.a.a); + + fputs(c.cout, ") {\n"); + + ctranslate_stmt(c, n.a.b); + + n = n.b; + + fputs(c.cout, "\t}"); + + if !n { + fputs(c.cout, "\n"); + break; + } + + fputs(c.cout, " else "); + + if !n.a.a { + fputs(c.cout, "{\n"); + ctranslate_stmt(c, n.a.b); + fputs(c.cout, "\t}\n"); + break; + } + } + } else if kind == N_STMTLIST { + loop { + if !n { + break; + } + + ctranslate_stmt(c, n.a); + + n = n.b; + } + } else if kind == N_LOOP { + fputs(c.cout, "\twhile (1) {\n"); + ctranslate_stmt(c, n.a); + fputs(c.cout, "\t}\n"); + } else if kind == N_BREAK { + fputs(c.cout, "\tbreak;\n"); + } else if kind == N_CONTINUE { + fputs(c.cout, "\tcontinue;\n"); + } else if kind == N_RETURN { + fputs(c.cout, "\treturn"); + if n.a { + fputs(c.cout, " "); + ctranslate_expr(c, n.a); + } + fputs(c.cout, ";\n"); + } else if kind == N_LABEL { + fputs(c.cout, "my_"); + fputs(c.cout, n.a.s); + fputs(c.cout, ":\n"); + } else if kind == N_GOTO { + fputs(c.cout, "\tgoto "); + fputs(c.cout, "my_"); + fputs(c.cout, n.a.s); + fputs(c.cout, ";\n"); + } else if kind != N_VARDECL { + fputs(c.cout, "\t"); + ctranslate_expr(c, n); + fputs(c.cout, ";\n"); + } +} + +ctranslate_func(c: *compiler, d: *decl) { + var n: *node; + var ty: *type; + if d.func_def { + ctranslate_type(c, d.func_type.val, "", 1); + fputs(c.cout, "my_"); + fputs(c.cout, d.name); + fputs(c.cout, "("); + n = d.func_def.a.b.a; + ty = d.func_type.arg; + loop { + if !n { + break; + } + + ctranslate_type(c, ty.val, n.a.a.s, 1); + + n = n.b; + ty = ty.arg; + + if n { + fputs(c.cout, ", "); + } + } + fputs(c.cout, ")\n"); + fputs(c.cout, "{\n"); + ctranslate_vars(c, d.func_def.b); + ctranslate_stmt(c, d.func_def.b); + fputs(c.cout, "}\n"); + } +}