diff --git a/cc_core.c b/cc_core.c
index 81869a5..46621c2 100644
--- a/cc_core.c
+++ b/cc_core.c
@@ -376,6 +376,31 @@ struct token_list* postfix_expr(struct token_list* out, struct token_list* funct
}
}
+/*
+ * unary-expr:
+ * postfix-expr
+ * - postfix-expr
+ * !postfix-expr
+ */
+struct token_list* unary_expr(struct token_list* out, struct token_list* function)
+{
+ if(!strcmp("-", global_token->s))
+ {
+ out = emit("LOAD_IMMEDIATE_eax %0\n", out);
+ out = common_recursion(postfix_expr, out, function);
+ out = emit("SUBTRACT_eax_from_ebx_into_ebx\nMOVE_ebx_to_eax\n", out);
+ }
+ else if(!strcmp("!", global_token->s))
+ {
+ out = emit("LOAD_IMMEDIATE_eax %1\n", out);
+ out = common_recursion(postfix_expr, out, function);
+ out = emit("XOR_ebx_eax_into_eax\n", out);
+ }
+ else out = postfix_expr(out, function);
+
+ return out;
+}
+
/*
* additive-expr:
* postfix-expr
@@ -384,16 +409,16 @@ struct token_list* postfix_expr(struct token_list* out, struct token_list* funct
*/
struct token_list* additive_expr(struct token_list* out, struct token_list* function)
{
- out = postfix_expr(out, function);
+ out = unary_expr(out, function);
while(1)
{
- if(global_token->s[0] == '+')
+ if(!strcmp("+", global_token->s))
{
out = common_recursion(postfix_expr, out, function);
out = emit("ADD_ebx_to_eax\n", out);
}
- else if(global_token->s[0] == '-')
+ else if(!strcmp("-", global_token->s))
{
out = common_recursion(postfix_expr, out, function);
out = emit("SUBTRACT_eax_from_ebx_into_ebx\nMOVE_ebx_to_eax\n", out);
diff --git a/makefile b/makefile
index df74613..9f3b913 100644
--- a/makefile
+++ b/makefile
@@ -19,6 +19,9 @@ clean:
./test/test0/cleanup.sh
./test/test1/cleanup.sh
./test/test2/cleanup.sh
+ ./test/test3/cleanup.sh
+ ./test/test4/cleanup.sh
+ ./test/test99/cleanup.sh
# Directories
bin:
@@ -28,7 +31,7 @@ results:
mkdir -p test/results
# tests
-test: test0-binary test1-binary test2-binary | results
+test: test0-binary test1-binary test2-binary test3-binary test4-binary test99-binary | results
sha256sum -c test/test.answers
test0-binary: M2-Planet | results
@@ -40,6 +43,15 @@ test1-binary: M2-Planet | results
test2-binary: M2-Planet | results
test/test2/hello.sh
+test3-binary: M2-Planet | results
+ test/test3/hello.sh
+
+test4-binary: M2-Planet | results
+ test/test4/hello.sh
+
+test99-binary: M2-Planet | results
+ test/test99/hello.sh
+
# Generate test answers
.PHONY: Generate-test-answers
Generate-test-answers:
diff --git a/test/common_x86/x86_defs.M1 b/test/common_x86/x86_defs.M1
index 8d38d69..895eec7 100644
--- a/test/common_x86/x86_defs.M1
+++ b/test/common_x86/x86_defs.M1
@@ -41,6 +41,7 @@ DEFINE LOAD_INTEGER 8B00
DEFINE MOVEZBL 0FB6C0
DEFINE MOVE_ebx_to_eax 89D8
DEFINE NOP 00000000
+DEFINE NOT_eax F7D0
DEFINE OR_eax_ebx 09D8
DEFINE POP_eax 58
DEFINE POP_ebx 5B
@@ -62,3 +63,4 @@ DEFINE STORE_INTEGER 8903
DEFINE SUBTRACT_eax_from_ebx_into_ebx 29C3
DEFINE MOVE_ebx_to_eax 89D8
DEFINE TEST 85C0
+DEFINE XOR_ebx_eax_into_eax 31D8
diff --git a/test/test.answers b/test/test.answers
index 3e6b945..d839db1 100644
--- a/test/test.answers
+++ b/test/test.answers
@@ -1,3 +1,6 @@
-be3e57116e09c63e7819a391c550d2bdde2eb9f3409d9a54fcd09d2062b75dcf test/results/test0-binary
-9d26baf5537e489ba73c24feb229d863e356d4796a876f6dc773cc191bc0ce99 test/results/test1-binary
-62e9942a705bb4b01756786b9f0df43035b93c4c8b878aa90b99c7f0c65dfb99 test/results/test2-binary
+646164d0e3de386d0c534cc5abd415e331c4bfa289e5755688b0ac15b082b8e3 test/results/test0-binary
+117b1837f95ca77de4a30b2b0428472ce60433ea82b0ca6d2e5f57316ef20c9a test/results/test1-binary
+3de3e1eabc6b808fbe172c7bb5a4e677a272fcbec7f73f2f896090051280d95a test/results/test2-binary
+97c9a95f88b63cf318b8caae963abc899004dc17c9695d7f5a2b0f7d4cf7dcb8 test/results/test3-binary
+e20f8dbbfaf58b3706e7b445dcb63ee8ff071d0efb6bfc00c89ed9365d5555eb test/results/test4-binary
+be3e57116e09c63e7819a391c550d2bdde2eb9f3409d9a54fcd09d2062b75dcf test/results/test99-binary
diff --git a/test/test0/.gitignore b/test/test0/.gitignore
index cc8b713..e483926 100644
--- a/test/test0/.gitignore
+++ b/test/test0/.gitignore
@@ -1,8 +1,6 @@
# Ignore the files created by script
-cc0.M1
-cc0.hex2
-cc1
-cc2
+*.M1
+*.hex2
# A place to put a good run for comparison
actual.M1
diff --git a/test/test0/cleanup.sh b/test/test0/cleanup.sh
index 136c1a3..b60e8d8 100755
--- a/test/test0/cleanup.sh
+++ b/test/test0/cleanup.sh
@@ -1,6 +1,4 @@
#! /bin/sh
-rm -f test/test0/cc0.M1
-rm -f test/test0/cc0.hex2
-rm -f test/test0/cc1
-rm -f test/test0/cc2
+rm -f test/test0/return.M1
+rm -f test/test0/return.hex2
exit 0
diff --git a/test/test0/hello.sh b/test/test0/hello.sh
index 3e3742c..44ba6e6 100755
--- a/test/test0/hello.sh
+++ b/test/test0/hello.sh
@@ -1,26 +1,17 @@
#! /bin/sh
-set -ex
+set -x
# Build the test
-bin/M2-Planet -f test/test0/cc500.c -o test/test0/cc0.M1 || exit 1
+bin/M2-Planet -f test/test0/return.c -o test/test0/return.M1 || exit 1
# Macro assemble with libc written in M1-Macro
-M1 -f test/common_x86/x86_defs.M1 -f test/common_x86/libc.M1 -f test/test0/cc0.M1 --LittleEndian --Architecture 1 -o test/test0/cc0.hex2 || exit 2
+M1 -f test/common_x86/x86_defs.M1 -f test/common_x86/libc.M1 -f test/test0/return.M1 --LittleEndian --Architecture 1 -o test/test0/return.hex2 || exit 2
# Resolve all linkages
-hex2 -f test/common_x86/ELF-i386.hex2 -f test/test0/cc0.hex2 --LittleEndian --Architecture 1 --BaseAddress 0x8048000 -o test/results/test0-binary --exec_enable || exit 3
+hex2 -f test/common_x86/ELF-i386.hex2 -f test/test0/return.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
+ # Verify that the compiled program returns the correct result
+ ./test/results/test0-binary
+ [ 42 = $? ] || exit 3
fi
exit 0
diff --git a/test/test1/for.c b/test/test0/return.c
similarity index 77%
rename from test/test1/for.c
rename to test/test0/return.c
index 4b398e1..7929a73 100644
--- a/test/test1/for.c
+++ b/test/test0/return.c
@@ -15,22 +15,7 @@
* along with stage0. If not, see .
*/
-#include
-int putchar(int);
-
int main()
{
- int max = 90;
- int i;
- int j;
- for(i = 65; i <= max; i = i + 1)
- {
- putchar(i);
- for(j = i + 1; j <= max; j = j + 1)
- {
- putchar(j);
- }
- putchar(10);
- }
- return 0;
+ return 42;
}
diff --git a/test/test1/.gitignore b/test/test1/.gitignore
index a8bb3dd..e483926 100644
--- a/test/test1/.gitignore
+++ b/test/test1/.gitignore
@@ -1,7 +1,6 @@
# Ignore the files created by script
-for.M1
-for.hex2
-proof
+*.M1
+*.hex2
# A place to put a good run for comparison
actual.M1
diff --git a/test/test1/cleanup.sh b/test/test1/cleanup.sh
index 627c28f..e6b127f 100755
--- a/test/test1/cleanup.sh
+++ b/test/test1/cleanup.sh
@@ -1,5 +1,4 @@
#! /bin/sh
-rm -f test/test1/for.M1
-rm -f test/test1/for.hex2
-rm -f test/test1/proof
+rm -f test/test1/library_call.M1
+rm -f test/test1/library_call.hex2
exit 0
diff --git a/test/test1/hello.sh b/test/test1/hello.sh
index 0cd53b3..9ae5397 100755
--- a/test/test1/hello.sh
+++ b/test/test1/hello.sh
@@ -1,18 +1,18 @@
#! /bin/sh
-set -ex
+set -x
# Build the test
-bin/M2-Planet -f test/test1/for.c -o test/test1/for.M1 || exit 1
+bin/M2-Planet -f test/test1/library_call.c -o test/test1/library_call.M1 || exit 1
# Macro assemble with libc written in M1-Macro
-M1 -f test/common_x86/x86_defs.M1 -f test/common_x86/libc.M1 -f test/test1/for.M1 --LittleEndian --Architecture 1 -o test/test1/for.hex2 || exit 2
+M1 -f test/common_x86/x86_defs.M1 -f test/common_x86/libc.M1 -f test/test1/library_call.M1 --LittleEndian --Architecture 1 -o test/test1/library_call.hex2 || exit 2
# Resolve all linkages
-hex2 -f test/common_x86/ELF-i386.hex2 -f test/test1/for.hex2 --LittleEndian --Architecture 1 --BaseAddress 0x8048000 -o test/results/test1-binary --exec_enable || exit 3
+hex2 -f test/common_x86/ELF-i386.hex2 -f test/test1/library_call.hex2 --LittleEndian --Architecture 1 --BaseAddress 0x8048000 -o test/results/test1-binary --exec_enable || exit 3
# Ensure binary works if host machine supports test
if [ "$(get_machine)" = "x86_64" ]
then
- # Verify that the resulting file works
- ./test/results/test1-binary >| test/test1/proof || exit 4
- out=$(sha256sum -c test/test1/proof.answer)
- [ "$out" = "test/test1/proof: OK" ] || exit 5
+ # Verify that the compiled program returns the correct result
+ out=$(./test/results/test1-binary 2>&1)
+ [ 42 = $? ] || exit 3
+ [ "$out" = "Hello mes" ] || exit 4
fi
exit 0
diff --git a/test/test1/library_call.c b/test/test1/library_call.c
new file mode 100644
index 0000000..811f7d3
--- /dev/null
+++ b/test/test1/library_call.c
@@ -0,0 +1,38 @@
+/* Copyright (C) 2016 Jeremiah Orians
+ * This file is part of stage0.
+ *
+ * stage0 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 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 .
+ */
+
+/* Ensure that C library calls function correctly */
+
+#include
+int putchar(int);
+void exit(int);
+
+int main()
+{
+ putchar(72);
+ putchar(101);
+ putchar(108);
+ putchar(108);
+ putchar(111);
+ putchar(32);
+ putchar(109);
+ putchar(101);
+ putchar(115);
+ putchar(10);
+ exit(42);
+ return 1;
+}
diff --git a/test/test1/proof.answer b/test/test1/proof.answer
deleted file mode 100644
index 665a740..0000000
--- a/test/test1/proof.answer
+++ /dev/null
@@ -1 +0,0 @@
-7dc238b12da104224bdb3d64edea5b5e150964faf868556bbc05d346590e3664 test/test1/proof
diff --git a/test/test2/.gitignore b/test/test2/.gitignore
index cc8b713..e483926 100644
--- a/test/test2/.gitignore
+++ b/test/test2/.gitignore
@@ -1,8 +1,6 @@
# Ignore the files created by script
-cc0.M1
-cc0.hex2
-cc1
-cc2
+*.M1
+*.hex2
# A place to put a good run for comparison
actual.M1
diff --git a/test/test2/cc.c b/test/test2/cc.c
deleted file mode 100644
index 361a3f2..0000000
--- a/test/test2/cc.c
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * 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
- */
-
-#include "cc.h"
-
-/* Imported functions */
-void emit(int n, char *s);
-void sym_define_global(int current_symbol);
-int sym_declare_global(char *s);
-void save_int(char *p, int n);
-void get_token();
-void program();
-
-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;
- }
-}
-
-
-int main()
-{
- code_offset = 134512640; /* 0x08048000 */
- be_start();
- nextc = getchar();
- get_token();
- program();
- be_finish();
- return 0;
-}
diff --git a/test/test2/cc.h b/test/test2/cc.h
deleted file mode 100644
index 1a4d1c4..0000000
--- a/test/test2/cc.h
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * 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);
-
-/* Our globals */
-int code_offset;
-char *code;
-int codepos;
-int i;
-int nextc;
diff --git a/test/test2/cc1.c b/test/test2/cc1.c
deleted file mode 100644
index 5532188..0000000
--- a/test/test2/cc1.c
+++ /dev/null
@@ -1,681 +0,0 @@
-/*
- * 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
- */
-
-#include "cc.h"
-
-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;
-}
-
-char *token;
-int token_size;
-
-void error()
-{
- exit(1);
-}
-
-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();
-}
-
-int code_size;
-
-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 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();
- }
-}
diff --git a/test/test2/cleanup.sh b/test/test2/cleanup.sh
index 083e6ad..ea7143d 100755
--- a/test/test2/cleanup.sh
+++ b/test/test2/cleanup.sh
@@ -1,6 +1,4 @@
#! /bin/sh
-rm -f test/test2/cc0.M1
-rm -f test/test2/cc0.hex2
-rm -f test/test2/cc1
-rm -f test/test2/cc2
+rm -f test/test2/if.M1
+rm -f test/test2/if.hex2
exit 0
diff --git a/test/test2/hello.sh b/test/test2/hello.sh
index 2bf379e..7f33d43 100755
--- a/test/test2/hello.sh
+++ b/test/test2/hello.sh
@@ -1,26 +1,18 @@
#! /bin/sh
-set -ex
+set -x
# Build the test
-bin/M2-Planet -f test/test2/cc.h -f test/test2/cc1.c -f test/test2/cc.c -o test/test2/cc0.M1 || exit 1
+bin/M2-Planet -f test/test2/if.c -o test/test2/if.M1 || exit 1
# Macro assemble with libc written in M1-Macro
-M1 -f test/common_x86/x86_defs.M1 -f test/common_x86/libc.M1 -f test/test2/cc0.M1 --LittleEndian --Architecture 1 -o test/test2/cc0.hex2 || exit 2
+M1 -f test/common_x86/x86_defs.M1 -f test/common_x86/libc.M1 -f test/test2/if.M1 --LittleEndian --Architecture 1 -o test/test2/if.hex2 || exit 2
# Resolve all linkages
-hex2 -f test/common_x86/ELF-i386.hex2 -f test/test2/cc0.hex2 --LittleEndian --Architecture 1 --BaseAddress 0x8048000 -o test/results/test2-binary --exec_enable || exit 3
+hex2 -f test/common_x86/ELF-i386.hex2 -f test/test2/if.hex2 --LittleEndian --Architecture 1 --BaseAddress 0x8048000 -o test/results/test2-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/test2-binary < test/test0/cc500.c >| test/test2/cc1 || exit 4
- out=$(sha256sum -c test/test2/proof0.answer)
- [ "$out" = "test/test2/cc1: OK" ] || exit 5
-
- # Make it executable
- exec_enable test/test2/cc1
-
- # Verify that the result of it compiling itself can compile itself
- ./test/test2/cc1 < test/test0/cc500.c >| test/test2/cc2 || exit 6
- out=$(sha256sum -c test/test2/proof1.answer)
- [ "$out" = "test/test2/cc2: OK" ] || exit 7
+ # Verify that the compiled program returns the correct result
+ out=$(./test/results/test2-binary 2>&1 )
+ [ 42 = $? ] || exit 4
+ [ "$out" = "Hello mes" ] || exit 5
fi
exit 0
diff --git a/test/test2/if.c b/test/test2/if.c
new file mode 100644
index 0000000..37c57e6
--- /dev/null
+++ b/test/test2/if.c
@@ -0,0 +1,56 @@
+/* Copyright (C) 2016 Jeremiah Orians
+ * This file is part of stage0.
+ *
+ * stage0 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 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 .
+ */
+
+/* Validate that IF statements behave correctly */
+int putchar(int);
+void exit(int);
+
+int main()
+{
+ if(0 == 0)
+ {
+ putchar(72);
+ putchar(101);
+ putchar(108);
+ putchar(108);
+ putchar(111);
+ putchar(32);
+ }
+ else
+ {
+ exit(2);
+ }
+
+ if(1 == 0)
+ {
+ exit(3);
+ }
+ else
+ {
+ putchar(109);
+ putchar(101);
+ putchar(115);
+ putchar(10);
+ }
+
+ if(1 == 1)
+ {
+ exit(42);
+ }
+
+ return 1;
+}
diff --git a/test/test2/proof0.answer b/test/test2/proof0.answer
deleted file mode 100644
index a1b87d1..0000000
--- a/test/test2/proof0.answer
+++ /dev/null
@@ -1 +0,0 @@
-3987b6a29775e015c11e35008ad0d0b3ee57f32655dc26f2360000b345139f54 test/test2/cc1
diff --git a/test/test2/proof1.answer b/test/test2/proof1.answer
deleted file mode 100644
index 5bf6885..0000000
--- a/test/test2/proof1.answer
+++ /dev/null
@@ -1 +0,0 @@
-3987b6a29775e015c11e35008ad0d0b3ee57f32655dc26f2360000b345139f54 test/test2/cc2
diff --git a/test/test3/.gitignore b/test/test3/.gitignore
new file mode 100644
index 0000000..e483926
--- /dev/null
+++ b/test/test3/.gitignore
@@ -0,0 +1,6 @@
+# Ignore the files created by script
+*.M1
+*.hex2
+
+# A place to put a good run for comparison
+actual.M1
diff --git a/test/test3/cleanup.sh b/test/test3/cleanup.sh
new file mode 100755
index 0000000..a72e6ba
--- /dev/null
+++ b/test/test3/cleanup.sh
@@ -0,0 +1,4 @@
+#! /bin/sh
+rm -f test/test3/constant.M1
+rm -f test/test3/constant.hex2
+exit 0
diff --git a/test/test3/constant.c b/test/test3/constant.c
new file mode 100644
index 0000000..04cd649
--- /dev/null
+++ b/test/test3/constant.c
@@ -0,0 +1,77 @@
+/* Copyright (C) 2016 Jeremiah Orians
+ * This file is part of stage0.
+ *
+ * stage0 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 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 .
+ */
+
+/* Validate that IF statements behave correctly */
+int putchar(int);
+void exit(int);
+
+#define TRUE 1
+#define FALSE 0
+#define H 72
+#define e 101
+#define l 108
+#define o 111
+#define space 32
+#define newline 10
+#define m 109
+#define s 115
+// CONSTANT TRUE 1
+// CONSTANT FALSE 0
+// CONSTANT H 72
+// CONSTANT e 101
+// CONSTANT l 108
+// CONSTANT o 111
+// CONSTANT space 32
+// CONSTANT newline 10
+// CONSTANT m 109
+// CONSTANT s 115
+
+int main()
+{
+ if(TRUE)
+ {
+ putchar(H);
+ putchar(e);
+ putchar(l);
+ putchar(l);
+ putchar(o);
+ putchar(space);
+ }
+ else
+ {
+ exit(2);
+ }
+
+ if(FALSE)
+ {
+ exit(3);
+ }
+ else
+ {
+ putchar(m);
+ putchar(e);
+ putchar(s);
+ putchar(newline);
+ }
+
+ if(1 < 2)
+ {
+ exit(42);
+ }
+
+ return 1;
+}
diff --git a/test/test3/hello.sh b/test/test3/hello.sh
new file mode 100755
index 0000000..323ae85
--- /dev/null
+++ b/test/test3/hello.sh
@@ -0,0 +1,18 @@
+#! /bin/sh
+set -x
+# Build the test
+bin/M2-Planet -f test/test3/constant.c -o test/test3/constant.M1 || exit 1
+# Macro assemble with libc written in M1-Macro
+M1 -f test/common_x86/x86_defs.M1 -f test/common_x86/libc.M1 -f test/test3/constant.M1 --LittleEndian --Architecture 1 -o test/test3/constant.hex2 || exit 2
+# Resolve all linkages
+hex2 -f test/common_x86/ELF-i386.hex2 -f test/test3/constant.hex2 --LittleEndian --Architecture 1 --BaseAddress 0x8048000 -o test/results/test3-binary --exec_enable || exit 3
+
+# Ensure binary works if host machine supports test
+if [ "$(get_machine)" = "x86_64" ]
+then
+ # Verify that the compiled program returns the correct result
+ out=$(./test/results/test3-binary 2>&1 )
+ [ 42 = $? ] || exit 4
+ [ "$out" = "Hello mes" ] || exit 5
+fi
+exit 0
diff --git a/test/test4/.gitignore b/test/test4/.gitignore
new file mode 100644
index 0000000..e483926
--- /dev/null
+++ b/test/test4/.gitignore
@@ -0,0 +1,6 @@
+# Ignore the files created by script
+*.M1
+*.hex2
+
+# A place to put a good run for comparison
+actual.M1
diff --git a/test/test4/call.c b/test/test4/call.c
new file mode 100644
index 0000000..7dcb484
--- /dev/null
+++ b/test/test4/call.c
@@ -0,0 +1,67 @@
+/* Copyright (C) 2016 Jeremiah Orians
+ * This file is part of stage0.
+ *
+ * stage0 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 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 .
+ */
+
+/* Validate that IF statements behave correctly */
+int putchar(int);
+void exit(int);
+
+#define TRUE 1
+#define FALSE 0
+// CONSTANT TRUE 1
+// CONSTANT FALSE 0
+
+int foo(int a)
+{
+ if(!a)
+ {
+ putchar(72);
+ putchar(101);
+ putchar(108);
+ putchar(108);
+ putchar(111);
+ putchar(32);
+ return TRUE;
+ }
+ return FALSE;
+}
+
+int main()
+{
+ if(foo(FALSE))
+ {
+ putchar(109);
+ putchar(101);
+ putchar(115);
+ putchar(10);
+ }
+ else
+ {
+ exit(2);
+ }
+
+ if(foo(TRUE))
+ {
+ exit(3);
+ }
+
+ if(2 > -1)
+ {
+ exit(42);
+ }
+
+ return 1;
+}
diff --git a/test/test4/cleanup.sh b/test/test4/cleanup.sh
new file mode 100755
index 0000000..f2c8289
--- /dev/null
+++ b/test/test4/cleanup.sh
@@ -0,0 +1,4 @@
+#! /bin/sh
+rm -f test/test4/call.M1
+rm -f test/test4/call.hex2
+exit 0
diff --git a/test/test4/hello.sh b/test/test4/hello.sh
new file mode 100755
index 0000000..989ea82
--- /dev/null
+++ b/test/test4/hello.sh
@@ -0,0 +1,18 @@
+#! /bin/sh
+set -x
+# Build the test
+bin/M2-Planet -f test/test4/call.c -o test/test4/call.M1 || exit 1
+# Macro assemble with libc written in M1-Macro
+M1 -f test/common_x86/x86_defs.M1 -f test/common_x86/libc.M1 -f test/test4/call.M1 --LittleEndian --Architecture 1 -o test/test4/call.hex2 || exit 2
+# Resolve all linkages
+hex2 -f test/common_x86/ELF-i386.hex2 -f test/test4/call.hex2 --LittleEndian --Architecture 1 --BaseAddress 0x8048000 -o test/results/test4-binary --exec_enable || exit 3
+
+# Ensure binary works if host machine supports test
+if [ "$(get_machine)" = "x86_64" ]
+then
+ # Verify that the compiled program returns the correct result
+ out=$(./test/results/test4-binary 2>&1 )
+ [ 42 = $? ] || exit 4
+ [ "$out" = "Hello mes" ] || exit 5
+fi
+exit 0
diff --git a/test/test99/.gitignore b/test/test99/.gitignore
new file mode 100644
index 0000000..cc8b713
--- /dev/null
+++ b/test/test99/.gitignore
@@ -0,0 +1,8 @@
+# Ignore the files created by script
+cc0.M1
+cc0.hex2
+cc1
+cc2
+
+# A place to put a good run for comparison
+actual.M1
diff --git a/test/test0/cc500.c b/test/test99/cc500.c
similarity index 100%
rename from test/test0/cc500.c
rename to test/test99/cc500.c
diff --git a/test/test99/cleanup.sh b/test/test99/cleanup.sh
new file mode 100755
index 0000000..1da69f8
--- /dev/null
+++ b/test/test99/cleanup.sh
@@ -0,0 +1,8 @@
+#! /bin/bash
+pushd test/test99/ > /dev/null
+rm -f cc0.M1
+rm -f cc0.hex2
+rm -f cc1
+rm -f cc2
+popd > /dev/null
+exit 0
diff --git a/test/test99/hello.sh b/test/test99/hello.sh
new file mode 100755
index 0000000..afd2a28
--- /dev/null
+++ b/test/test99/hello.sh
@@ -0,0 +1,26 @@
+#! /bin/sh
+set -ex
+# Build the test
+bin/M2-Planet -f test/test99/cc500.c -o test/test99/cc0.M1 || exit 1
+# Macro assemble with libc written in M1-Macro
+M1 -f test/common_x86/x86_defs.M1 -f test/common_x86/libc.M1 -f test/test99/cc0.M1 --LittleEndian --Architecture 1 -o test/test99/cc0.hex2 || exit 2
+# Resolve all linkages
+hex2 -f test/common_x86/ELF-i386.hex2 -f test/test99/cc0.hex2 --LittleEndian --Architecture 1 --BaseAddress 0x8048000 -o test/results/test99-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/test99-binary < test/test99/cc500.c >| test/test99/cc1 || exit 4
+ out=$(sha256sum -c test/test99/proof0.answer)
+ [ "$out" = "test/test99/cc1: OK" ] || exit 5
+
+ # Make it executable
+ exec_enable test/test99/cc1
+
+ # Verify that the result of it compiling itself can compile itself
+ ./test/test99/cc1 < test/test99/cc500.c >| test/test99/cc2 || exit 6
+ out=$(sha256sum -c test/test99/proof1.answer)
+ [ "$out" = "test/test99/cc2: OK" ] || exit 7
+fi
+exit 0
diff --git a/test/test0/proof0.answer b/test/test99/proof0.answer
similarity index 78%
rename from test/test0/proof0.answer
rename to test/test99/proof0.answer
index 9b8f616..df0b02a 100644
--- a/test/test0/proof0.answer
+++ b/test/test99/proof0.answer
@@ -1 +1 @@
-3987b6a29775e015c11e35008ad0d0b3ee57f32655dc26f2360000b345139f54 test/test0/cc1
+3987b6a29775e015c11e35008ad0d0b3ee57f32655dc26f2360000b345139f54 test/test99/cc1
diff --git a/test/test0/proof1.answer b/test/test99/proof1.answer
similarity index 78%
rename from test/test0/proof1.answer
rename to test/test99/proof1.answer
index e3a0909..cb050de 100644
--- a/test/test0/proof1.answer
+++ b/test/test99/proof1.answer
@@ -1 +1 @@
-3987b6a29775e015c11e35008ad0d0b3ee57f32655dc26f2360000b345139f54 test/test0/cc2
+3987b6a29775e015c11e35008ad0d0b3ee57f32655dc26f2360000b345139f54 test/test99/cc2