diff --git a/example/test.sh b/example/test.sh
deleted file mode 100755
index e1054bb..0000000
--- a/example/test.sh
+++ /dev/null
@@ -1,26 +0,0 @@
-#! /bin/bash
-## Copyright (C) 2016 Jeremiah Orians
-## This file is part of stage0.
-##
-## stage0 is free software: you an redistribute it and/or modify
-## it under the terms of the GNU General Public License as published by
-## the Free Software Foundation, either version 3 of the License, or
-## (at your option) any later version.
-##
-## stage0 is distributed in the hope that it will be useful,
-## but WITHOUT ANY WARRANTY; without even the implied warranty of
-## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-## GNU General Public License for more details.
-##
-## You should have received a copy of the GNU General Public License
-## along with stage0. If not, see .
-
-
-# An example command for compiling a source file
-M2-Planet input.c output.M1
-
-# An exmaple command for converting the M1 file into a Hex2 object file ready for linking
-M1-Macro -f x86_defs.M1 -f libc.M1 -f output.M1 --LittleEndian --Architecture 1 -o output.hex2
-
-# An example command for converting the Hex2 object file into a runnable x86 binary with an ELF header
-hex2-linker -f ELF-i386.hex2 -f output.hex2 --LittleEndian --Architecture 1 --BaseAddress 0x8048000 -o FINAL_BINARY
diff --git a/makefile b/makefile
new file mode 100644
index 0000000..a77290f
--- /dev/null
+++ b/makefile
@@ -0,0 +1,43 @@
+# Prevent rebuilding
+VPATH = bin:test:test/results
+
+all: M2-Planet
+
+CC=gcc
+CFLAGS=-D_GNU_SOURCE -O0 -std=c99 -ggdb
+
+M2-Planet: cc_reader.c cc_strings.c cc.c cc.h | bin
+ $(CC) $(CFLAGS) cc_reader.c cc_strings.c cc.c cc.h -o bin/M2-Planet
+
+# Clean up after ourselves
+.PHONY: clean
+clean:
+ rm -rf bin/ test/results/
+ ./test/test0/cleanup.sh
+
+# Directories
+bin:
+ mkdir -p bin
+
+results:
+ mkdir -p test/results
+
+# tests
+test: test0-binary | results
+ sha256sum -c test/test.answers
+
+test0-binary: M2-Planet | results
+ test/test0/hello.sh
+
+# Generate test answers
+.PHONY: Generate-test-answers
+Generate-test-answers:
+ sha256sum test/results/* >| test/test.answers
+
+DESTDIR:=
+PREFIX:=/usr/local
+bindir:=$(DESTDIR)$(PREFIX)/bin
+.PHONY: install
+install: M2-Planet
+ mkdir -p $(bindir)
+ cp $^ $(bindir)
diff --git a/test/.gitignore b/test/.gitignore
new file mode 100644
index 0000000..784bf20
--- /dev/null
+++ b/test/.gitignore
@@ -0,0 +1,2 @@
+# Ignore all generated contents of tests
+results/
diff --git a/test/test.answers b/test/test.answers
new file mode 100644
index 0000000..7080ebd
--- /dev/null
+++ b/test/test.answers
@@ -0,0 +1 @@
+be3e57116e09c63e7819a391c550d2bdde2eb9f3409d9a54fcd09d2062b75dcf test/results/test0-binary
diff --git a/test/test0/.gitignore b/test/test0/.gitignore
new file mode 100644
index 0000000..7cf60ea
--- /dev/null
+++ b/test/test0/.gitignore
@@ -0,0 +1,5 @@
+# Ignore the files created by script
+cc0.M1
+cc0.hex2
+cc1
+cc2
diff --git a/example/ELF-i386.hex2 b/test/test0/ELF-i386.hex2
similarity index 100%
rename from example/ELF-i386.hex2
rename to test/test0/ELF-i386.hex2
diff --git a/test/test0/cc500.c b/test/test0/cc500.c
new file mode 100644
index 0000000..6579f69
--- /dev/null
+++ b/test/test0/cc500.c
@@ -0,0 +1,769 @@
+/*
+ * Copyright (C) 2006 Edmund GRIMLEY EVANS
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/*
+ * A self-compiling compiler for a small subset of C.
+ */
+
+/* Our library functions. */
+void exit(int);
+int getchar(void);
+void *malloc(int);
+int putchar(int);
+
+/* The first thing defined must be main(). */
+int main1();
+int main()
+{
+ int a = 10;
+ int b = a;
+ return main1();
+}
+
+char *my_realloc(char *old, int oldlen, int newlen)
+{
+ char *new = malloc(newlen);
+ int i = 0;
+ while (i <= oldlen - 1) {
+ new[i] = old[i];
+ i = i + 1;
+ }
+ return new;
+}
+
+int nextc;
+char *token;
+int token_size;
+
+void error()
+{
+ exit(1);
+}
+
+int i;
+
+void takechar()
+{
+ if (token_size <= i + 1) {
+ int x = (i + 10) << 1;
+ token = my_realloc(token, token_size, x);
+ token_size = x;
+ }
+ token[i] = nextc;
+ i = i + 1;
+ nextc = getchar();
+}
+
+void get_token()
+{
+ int w = 1;
+ while (w) {
+ w = 0;
+ while ((nextc == ' ') | (nextc == 9) | (nextc == 10))
+ nextc = getchar();
+ i = 0;
+ while ((('a' <= nextc) & (nextc <= 'z')) |
+ (('0' <= nextc) & (nextc <= '9')) | (nextc == '_'))
+ takechar();
+ if (i == 0)
+ while ((nextc == '<') | (nextc == '=') | (nextc == '>') |
+ (nextc == '|') | (nextc == '&') | (nextc == '!'))
+ takechar();
+ if (i == 0) {
+ if (nextc == 39) {
+ takechar();
+ while (nextc != 39)
+ takechar();
+ takechar();
+ }
+ else if (nextc == '"') {
+ takechar();
+ while (nextc != '"')
+ takechar();
+ takechar();
+ }
+ else if (nextc == '/') {
+ takechar();
+ if (nextc == '*') {
+ nextc = getchar();
+ while (nextc != '/') {
+ while (nextc != '*')
+ nextc = getchar();
+ nextc = getchar();
+ }
+ nextc = getchar();
+ w = 1;
+ }
+ }
+ else if (nextc != 0-1)
+ takechar();
+ }
+ token[i] = 0;
+ }
+}
+
+int peek(char *s)
+{
+ int i = 0;
+ while ((s[i] == token[i]) & (s[i] != 0))
+ i = i + 1;
+ return s[i] == token[i];
+}
+
+int accept(char *s)
+{
+ if (peek(s)) {
+ get_token();
+ return 1;
+ }
+ else
+ return 0;
+}
+
+void expect(char *s)
+{
+ if (accept(s) == 0)
+ error();
+}
+
+char *code;
+int code_size;
+int codepos;
+int code_offset;
+
+void save_int(char *p, int n)
+{
+ p[0] = n;
+ p[1] = n >> 8;
+ p[2] = n >> 16;
+ p[3] = n >> 24;
+}
+
+int load_int(char *p)
+{
+ return ((p[0] & 255) + ((p[1] & 255) << 8) +
+ ((p[2] & 255) << 16) + ((p[3] & 255) << 24));
+}
+
+void emit(int n, char *s)
+{
+ i = 0;
+ if (code_size <= codepos + n) {
+ int x = (codepos + n) << 1;
+ code = my_realloc(code, code_size, x);
+ code_size = x;
+ }
+ while (i <= n - 1) {
+ code[codepos] = s[i];
+ codepos = codepos + 1;
+ i = i + 1;
+ }
+}
+
+void be_push()
+{
+ emit(1, "\x50"); /* push %eax */
+}
+
+void be_pop(int n)
+{
+ emit(6, "\x81\xc4...."); /* add $(n * 4),%esp */
+ save_int(code + codepos - 4, n << 2);
+}
+
+char *table;
+int table_size;
+int table_pos;
+int stack_pos;
+
+int sym_lookup(char *s)
+{
+ int t = 0;
+ int current_symbol = 0;
+ while (t <= table_pos - 1) {
+ i = 0;
+ while ((s[i] == table[t]) & (s[i] != 0)) {
+ i = i + 1;
+ t = t + 1;
+ }
+ if (s[i] == table[t])
+ current_symbol = t;
+ while (table[t] != 0)
+ t = t + 1;
+ t = t + 6;
+ }
+ return current_symbol;
+}
+
+void sym_declare(char *s, int type, int value)
+{
+ int t = table_pos;
+ i = 0;
+ while (s[i] != 0) {
+ if (table_size <= t + 10) {
+ int x = (t + 10) << 1;
+ table = my_realloc(table, table_size, x);
+ table_size = x;
+ }
+ table[t] = s[i];
+ i = i + 1;
+ t = t + 1;
+ }
+ table[t] = 0;
+ table[t + 1] = type;
+ save_int(table + t + 2, value);
+ table_pos = t + 6;
+}
+
+int sym_declare_global(char *s)
+{
+ int current_symbol = sym_lookup(s);
+ if (current_symbol == 0) {
+ sym_declare(s, 'U', code_offset);
+ current_symbol = table_pos - 6;
+ }
+ return current_symbol;
+}
+
+void sym_define_global(int current_symbol)
+{
+ int i;
+ int j;
+ int t = current_symbol;
+ int v = codepos + code_offset;
+ if (table[t + 1] != 'U')
+ error(); /* symbol redefined */
+ i = load_int(table + t + 2) - code_offset;
+ while (i) {
+ j = load_int(code + i) - code_offset;
+ save_int(code + i, v);
+ i = j;
+ }
+ table[t + 1] = 'D';
+ save_int(table + t + 2, v);
+}
+
+int number_of_args;
+
+void sym_get_value(char *s)
+{
+ int t;
+ if ((t = sym_lookup(s)) == 0)
+ error();
+ emit(5, "\xb8...."); /* mov $n,%eax */
+ save_int(code + codepos - 4, load_int(table + t + 2));
+ if (table[t + 1] == 'D') { /* defined global */
+ }
+ else if (table[t + 1] == 'U') /* undefined global */
+ save_int(table + t + 2, codepos + code_offset - 4);
+ else if (table[t + 1] == 'L') { /* local variable */
+ int k = (stack_pos - table[t + 2] - 1) << 2;
+ emit(7, "\x8d\x84\x24...."); /* lea (n * 4)(%esp),%eax */
+ save_int(code + codepos - 4, k);
+ }
+ else if (table[t + 1] == 'A') { /* argument */
+ int k = (stack_pos + number_of_args - table[t + 2] + 1) << 2;
+ emit(7, "\x8d\x84\x24...."); /* lea (n * 4)(%esp),%eax */
+ save_int(code + codepos - 4, k);
+ }
+ else
+ error();
+}
+
+void be_start()
+{
+ emit(16, "\x7f\x45\x4c\x46\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00");
+ emit(16, "\x02\x00\x03\x00\x01\x00\x00\x00\x54\x80\x04\x08\x34\x00\x00\x00");
+ emit(16, "\x00\x00\x00\x00\x00\x00\x00\x00\x34\x00\x20\x00\x01\x00\x00\x00");
+ emit(16, "\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x80\x04\x08");
+ emit(16, "\x00\x80\x04\x08\x10\x4b\x00\x00\x10\x4b\x00\x00\x07\x00\x00\x00");
+ emit(16, "\x00\x10\x00\x00\xe8\x00\x00\x00\x00\x89\xc3\x31\xc0\x40\xcd\x80");
+
+ sym_define_global(sym_declare_global("exit"));
+ /* pop %ebx ; pop %ebx ; xor %eax,%eax ; inc %eax ; int $0x80 */
+ emit(7, "\x5b\x5b\x31\xc0\x40\xcd\x80");
+
+ sym_define_global(sym_declare_global("getchar"));
+ /* mov $3,%eax ; xor %ebx,%ebx ; push %ebx ; mov %esp,%ecx */
+ emit(10, "\xb8\x03\x00\x00\x00\x31\xdb\x53\x89\xe1");
+ /* xor %edx,%edx ; inc %edx ; int $0x80 */
+ /* test %eax,%eax ; pop %eax ; jne . + 7 */
+ emit(10, "\x31\xd2\x42\xcd\x80\x85\xc0\x58\x75\x05");
+ /* mov $-1,%eax ; ret */
+ emit(6, "\xb8\xff\xff\xff\xff\xc3");
+
+ sym_define_global(sym_declare_global("malloc"));
+ /* mov 4(%esp),%eax */
+ emit(4, "\x8b\x44\x24\x04");
+ /* push %eax ; xor %ebx,%ebx ; mov $45,%eax ; int $0x80 */
+ emit(10, "\x50\x31\xdb\xb8\x2d\x00\x00\x00\xcd\x80");
+ /* pop %ebx ; add %eax,%ebx ; push %eax ; push %ebx ; mov $45,%eax */
+ emit(10, "\x5b\x01\xc3\x50\x53\xb8\x2d\x00\x00\x00");
+ /* int $0x80 ; pop %ebx ; cmp %eax,%ebx ; pop %eax ; je . + 7 */
+ emit(8, "\xcd\x80\x5b\x39\xc3\x58\x74\x05");
+ /* mov $-1,%eax ; ret */
+ emit(6, "\xb8\xff\xff\xff\xff\xc3");
+
+ sym_define_global(sym_declare_global("putchar"));
+ /* mov $4,%eax ; xor %ebx,%ebx ; inc %ebx */
+ emit(8, "\xb8\x04\x00\x00\x00\x31\xdb\x43");
+ /* lea 4(%esp),%ecx ; mov %ebx,%edx ; int $0x80 ; ret */
+ emit(9, "\x8d\x4c\x24\x04\x89\xda\xcd\x80\xc3");
+
+ save_int(code + 85, codepos - 89); /* entry set to first thing in file */
+}
+
+void be_finish()
+{
+ save_int(code + 68, codepos);
+ save_int(code + 72, codepos);
+ i = 0;
+ while (i <= codepos - 1) {
+ putchar(code[i]);
+ i = i + 1;
+ }
+}
+
+void promote(int type)
+{
+ /* 1 = char lval, 2 = int lval, 3 = other */
+ if (type == 1)
+ emit(3, "\x0f\xbe\x00"); /* movsbl (%eax),%eax */
+ else if (type == 2)
+ emit(2, "\x8b\x00"); /* mov (%eax),%eax */
+}
+
+int expression();
+
+/*
+ * primary-expr:
+ * identifier
+ * constant
+ * ( expression )
+ */
+int primary_expr()
+{
+ int type;
+ if (('0' <= token[0]) & (token[0] <= '9')) {
+ int n = 0;
+ i = 0;
+ while (token[i]) {
+ n = (n << 1) + (n << 3) + token[i] - '0';
+ i = i + 1;
+ }
+ emit(5, "\xb8...."); /* mov $x,%eax */
+ save_int(code + codepos - 4, n);
+ type = 3;
+ }
+ else if (('a' <= token[0]) & (token[0] <= 'z')) {
+ sym_get_value(token);
+ type = 2;
+ }
+ else if (accept("(")) {
+ type = expression();
+ if (peek(")") == 0)
+ error();
+ }
+ else if ((token[0] == 39) & (token[1] != 0) &
+ (token[2] == 39) & (token[3] == 0)) {
+ emit(5, "\xb8...."); /* mov $x,%eax */
+ save_int(code + codepos - 4, token[1]);
+ type = 3;
+ }
+ else if (token[0] == '"') {
+ int i = 0;
+ int j = 1;
+ int k;
+ while (token[j] != '"') {
+ if ((token[j] == 92) & (token[j + 1] == 'x')) {
+ if (token[j + 2] <= '9')
+ k = token[j + 2] - '0';
+ else
+ k = token[j + 2] - 'a' + 10;
+ k = k << 4;
+ if (token[j + 3] <= '9')
+ k = k + token[j + 3] - '0';
+ else
+ k = k + token[j + 3] - 'a' + 10;
+ token[i] = k;
+ j = j + 4;
+ }
+ else {
+ token[i] = token[j];
+ j = j + 1;
+ }
+ i = i + 1;
+ }
+ token[i] = 0;
+ /* call ... ; the string ; pop %eax */
+ emit(5, "\xe8....");
+ save_int(code + codepos - 4, i + 1);
+ emit(i + 1, token);
+ emit(1, "\x58");
+ type = 3;
+ }
+ else
+ error();
+ get_token();
+ return type;
+}
+
+void binary1(int type)
+{
+ promote(type);
+ be_push();
+ stack_pos = stack_pos + 1;
+}
+
+int binary2(int type, int n, char *s)
+{
+ promote(type);
+ emit(n, s);
+ stack_pos = stack_pos - 1;
+ return 3;
+}
+
+/*
+ * postfix-expr:
+ * primary-expr
+ * postfix-expr [ expression ]
+ * postfix-expr ( expression-list-opt )
+ */
+int postfix_expr()
+{
+ int type = primary_expr();
+ if (accept("[")) {
+ binary1(type); /* pop %ebx ; add %ebx,%eax */
+ binary2(expression(), 3, "\x5b\x01\xd8");
+ expect("]");
+ type = 1;
+ }
+ else if (accept("(")) {
+ int s = stack_pos;
+ be_push();
+ stack_pos = stack_pos + 1;
+ if (accept(")") == 0) {
+ promote(expression());
+ be_push();
+ stack_pos = stack_pos + 1;
+ while (accept(",")) {
+ promote(expression());
+ be_push();
+ stack_pos = stack_pos + 1;
+ }
+ expect(")");
+ }
+ emit(7, "\x8b\x84\x24...."); /* mov (n * 4)(%esp),%eax */
+ save_int(code + codepos - 4, (stack_pos - s - 1) << 2);
+ emit(2, "\xff\xd0"); /* call *%eax */
+ be_pop(stack_pos - s);
+ stack_pos = s;
+ type = 3;
+ }
+ return type;
+}
+
+/*
+ * additive-expr:
+ * postfix-expr
+ * additive-expr + postfix-expr
+ * additive-expr - postfix-expr
+ */
+int additive_expr()
+{
+ int type = postfix_expr();
+ while (1) {
+ if (accept("+")) {
+ binary1(type); /* pop %ebx ; add %ebx,%eax */
+ type = binary2(postfix_expr(), 3, "\x5b\x01\xd8");
+ }
+ else if (accept("-")) {
+ binary1(type); /* pop %ebx ; sub %eax,%ebx ; mov %ebx,%eax */
+ type = binary2(postfix_expr(), 5, "\x5b\x29\xc3\x89\xd8");
+ }
+ else
+ return type;
+ }
+}
+
+/*
+ * shift-expr:
+ * additive-expr
+ * shift-expr << additive-expr
+ * shift-expr >> additive-expr
+ */
+int shift_expr()
+{
+ int type = additive_expr();
+ while (1) {
+ if (accept("<<")) {
+ binary1(type); /* mov %eax,%ecx ; pop %eax ; shl %cl,%eax */
+ type = binary2(additive_expr(), 5, "\x89\xc1\x58\xd3\xe0");
+ }
+ else if (accept(">>")) {
+ binary1(type); /* mov %eax,%ecx ; pop %eax ; sar %cl,%eax */
+ type = binary2(additive_expr(), 5, "\x89\xc1\x58\xd3\xf8");
+ }
+ else
+ return type;
+ }
+}
+
+/*
+ * relational-expr:
+ * shift-expr
+ * relational-expr <= shift-expr
+ */
+int relational_expr()
+{
+ int type = shift_expr();
+ while (accept("<=")) {
+ binary1(type);
+ /* pop %ebx ; cmp %eax,%ebx ; setle %al ; movzbl %al,%eax */
+ type = binary2(shift_expr(),
+ 9, "\x5b\x39\xc3\x0f\x9e\xc0\x0f\xb6\xc0");
+ }
+ return type;
+}
+
+/*
+ * equality-expr:
+ * relational-expr
+ * equality-expr == relational-expr
+ * equality-expr != relational-expr
+ */
+int equality_expr()
+{
+ int type = relational_expr();
+ while (1) {
+ if (accept("==")) {
+ binary1(type);
+ /* pop %ebx ; cmp %eax,%ebx ; sete %al ; movzbl %al,%eax */
+ type = binary2(relational_expr(),
+ 9, "\x5b\x39\xc3\x0f\x94\xc0\x0f\xb6\xc0");
+ }
+ else if (accept("!=")) {
+ binary1(type);
+ /* pop %ebx ; cmp %eax,%ebx ; setne %al ; movzbl %al,%eax */
+ type = binary2(relational_expr(),
+ 9, "\x5b\x39\xc3\x0f\x95\xc0\x0f\xb6\xc0");
+ }
+ else
+ return type;
+ }
+}
+
+/*
+ * bitwise-and-expr:
+ * equality-expr
+ * bitwise-and-expr & equality-expr
+ */
+int bitwise_and_expr()
+{
+ int type = equality_expr();
+ while (accept("&")) {
+ binary1(type); /* pop %ebx ; and %ebx,%eax */
+ type = binary2(equality_expr(), 3, "\x5b\x21\xd8");
+ }
+ return type;
+}
+
+/*
+ * bitwise-or-expr:
+ * bitwise-and-expr
+ * bitwise-and-expr | bitwise-or-expr
+ */
+int bitwise_or_expr()
+{
+ int type = bitwise_and_expr();
+ while (accept("|")) {
+ binary1(type); /* pop %ebx ; or %ebx,%eax */
+ type = binary2(bitwise_and_expr(), 3, "\x5b\x09\xd8");
+ }
+ return type;
+}
+
+/*
+ * expression:
+ * bitwise-or-expr
+ * bitwise-or-expr = expression
+ */
+int expression()
+{
+ int type = bitwise_or_expr();
+ if (accept("=")) {
+ be_push();
+ stack_pos = stack_pos + 1;
+ promote(expression());
+ if (type == 2)
+ emit(3, "\x5b\x89\x03"); /* pop %ebx ; mov %eax,(%ebx) */
+ else
+ emit(3, "\x5b\x88\x03"); /* pop %ebx ; mov %al,(%ebx) */
+ stack_pos = stack_pos - 1;
+ type = 3;
+ }
+ return type;
+}
+
+/*
+ * type-name:
+ * char *
+ * int
+ */
+void type_name()
+{
+ get_token();
+ while (accept("*")) {
+ }
+}
+
+/*
+ * statement:
+ * { statement-list-opt }
+ * type-name identifier ;
+ * type-name identifier = expression;
+ * if ( expression ) statement
+ * if ( expression ) statement else statement
+ * while ( expression ) statement
+ * return ;
+ * expr ;
+ */
+void statement()
+{
+ int p1;
+ int p2;
+ if (accept("{")) {
+ int n = table_pos;
+ int s = stack_pos;
+ while (accept("}") == 0)
+ statement();
+ table_pos = n;
+ be_pop(stack_pos - s);
+ stack_pos = s;
+ }
+ else if (peek("char") | peek("int")) {
+ type_name();
+ sym_declare(token, 'L', stack_pos);
+ get_token();
+ if (accept("="))
+ promote(expression());
+ expect(";");
+ be_push();
+ stack_pos = stack_pos + 1;
+ }
+ else if (accept("if")) {
+ expect("(");
+ promote(expression());
+ emit(8, "\x85\xc0\x0f\x84...."); /* test %eax,%eax ; je ... */
+ p1 = codepos;
+ expect(")");
+ statement();
+ emit(5, "\xe9...."); /* jmp ... */
+ p2 = codepos;
+ save_int(code + p1 - 4, codepos - p1);
+ if (accept("else"))
+ statement();
+ save_int(code + p2 - 4, codepos - p2);
+ }
+ else if (accept("while")) {
+ expect("(");
+ p1 = codepos;
+ promote(expression());
+ emit(8, "\x85\xc0\x0f\x84...."); /* test %eax,%eax ; je ... */
+ p2 = codepos;
+ expect(")");
+ statement();
+ emit(5, "\xe9...."); /* jmp ... */
+ save_int(code + codepos - 4, p1 - codepos);
+ save_int(code + p2 - 4, codepos - p2);
+ }
+ else if (accept("return")) {
+ if (peek(";") == 0)
+ promote(expression());
+ expect(";");
+ be_pop(stack_pos);
+ emit(1, "\xc3"); /* ret */
+ }
+ else {
+ expression();
+ expect(";");
+ }
+}
+
+/*
+ * program:
+ * declaration
+ * declaration program
+ *
+ * declaration:
+ * type-name identifier ;
+ * type-name identifier ( parameter-list ) ;
+ * type-name identifier ( parameter-list ) statement
+ *
+ * parameter-list:
+ * parameter-declaration
+ * parameter-list, parameter-declaration
+ *
+ * parameter-declaration:
+ * type-name identifier-opt
+ */
+void program()
+{
+ int current_symbol;
+ while (token[0]) {
+ type_name();
+ current_symbol = sym_declare_global(token);
+ get_token();
+ if (accept(";")) {
+ sym_define_global(current_symbol);
+ emit(4, "\x00\x00\x00\x00");
+ }
+ else if (accept("(")) {
+ int n = table_pos;
+ number_of_args = 0;
+ while (accept(")") == 0) {
+ number_of_args = number_of_args + 1;
+ type_name();
+ if (peek(")") == 0) {
+ sym_declare(token, 'A', number_of_args);
+ get_token();
+ }
+ accept(","); /* ignore trailing comma */
+ }
+ if (accept(";") == 0) {
+ sym_define_global(current_symbol);
+ statement();
+ emit(1, "\xc3"); /* ret */
+ }
+ table_pos = n;
+ }
+ else
+ error();
+ }
+}
+
+int main1()
+{
+ code_offset = 134512640; /* 0x08048000 */
+ be_start();
+ nextc = getchar();
+ get_token();
+ program();
+ be_finish();
+ return 0;
+}
diff --git a/test/test0/cleanup.sh b/test/test0/cleanup.sh
new file mode 100755
index 0000000..136c1a3
--- /dev/null
+++ b/test/test0/cleanup.sh
@@ -0,0 +1,6 @@
+#! /bin/sh
+rm -f test/test0/cc0.M1
+rm -f test/test0/cc0.hex2
+rm -f test/test0/cc1
+rm -f test/test0/cc2
+exit 0
diff --git a/test/test0/hello.sh b/test/test0/hello.sh
new file mode 100755
index 0000000..8e2a575
--- /dev/null
+++ b/test/test0/hello.sh
@@ -0,0 +1,26 @@
+#! /bin/sh
+set -ex
+# Build the test
+bin/M2-Planet test/test0/cc500.c test/test0/cc0.M1 || exit 1
+# Macro assemble with libc written in M1-Macro
+M1 -f test/test0/x86_defs.M1 -f test/test0/libc.M1 -f test/test0/cc0.M1 --LittleEndian --Architecture 1 -o test/test0/cc0.hex2 || exit 2
+# Resolve all linkages
+hex2 -f test/test0/ELF-i386.hex2 -f test/test0/cc0.hex2 --LittleEndian --Architecture 1 --BaseAddress 0x8048000 -o test/results/test0-binary --exec_enable || exit 3
+
+# Ensure binary works if host machine supports test
+if [ "$(get_machine)" = "x86_64" ]
+then
+ # Verify that the compiled program can compile itself
+ ./test/results/test0-binary < test/test0/cc500.c >| test/test0/cc1 || exit 4
+ out=$(sha256sum -c test/test0/proof0.answer)
+ [ "$out" = "test/test0/cc1: OK" ] || exit 5
+
+ # Make it executable
+ exec_enable test/test0/cc1
+
+ # Verify that the result of it compiling itself can compile itself
+ ./test/test0/cc1 < test/test0/cc500.c >| test/test0/cc2 || exit 6
+ out=$(sha256sum -c test/test0/proof1.answer)
+ [ "$out" = "test/test0/cc2: OK" ] || exit 7
+fi
+exit 0
diff --git a/example/libc.M1 b/test/test0/libc.M1
similarity index 100%
rename from example/libc.M1
rename to test/test0/libc.M1
diff --git a/test/test0/proof0.answer b/test/test0/proof0.answer
new file mode 100644
index 0000000..9b8f616
--- /dev/null
+++ b/test/test0/proof0.answer
@@ -0,0 +1 @@
+3987b6a29775e015c11e35008ad0d0b3ee57f32655dc26f2360000b345139f54 test/test0/cc1
diff --git a/test/test0/proof1.answer b/test/test0/proof1.answer
new file mode 100644
index 0000000..e3a0909
--- /dev/null
+++ b/test/test0/proof1.answer
@@ -0,0 +1 @@
+3987b6a29775e015c11e35008ad0d0b3ee57f32655dc26f2360000b345139f54 test/test0/cc2
diff --git a/example/x86_defs.M1 b/test/test0/x86_defs.M1
similarity index 100%
rename from example/x86_defs.M1
rename to test/test0/x86_defs.M1