Browse Source

Implemented C version of cc_knight-native

Jeremiah Orians 4 years ago
parent
commit
8ebcfbbd5a

+ 1 - 0
.gitignore

@@ -21,6 +21,7 @@ __pycache__/
 roms/
 prototypes/
 test/stage0_test_scratch/
+scratch/
 
 # Generated files that don't need to be version controlled
 *.so

+ 21 - 0
stage2/High_level_prototypes/cc_knight-native/.gitignore

@@ -0,0 +1,21 @@
+## Copyright (C) 2020 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 <http://www.gnu.org/licenses/>.
+
+
+# The compiled C compiler
+cc_knight-native
+# temp files
+*.tmp

+ 61 - 0
stage2/High_level_prototypes/cc_knight-native/cc.c

@@ -0,0 +1,61 @@
+/* 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 <http://www.gnu.org/licenses/>.
+ */
+#include<stdlib.h>
+#include<stdio.h>
+#include<string.h>
+#include"cc.h"
+
+/* The core functions */
+void initialize_types();
+struct token_list* read_all_tokens(FILE* a, struct token_list* current, char* filename);
+struct token_list* reverse_list(struct token_list* head);
+struct token_list* program();
+void recursive_output(struct token_list* i, FILE* out);
+int match(char* a, char* b);
+void file_print(char* s, FILE* f);
+char* parse_string(char* string);
+
+int main()
+{
+	hold_string = calloc(MAX_STRING, sizeof(char));
+	FILE* in = fopen("tape_01", "r");
+	FILE* destination_file = fopen("tape_02", "w");
+
+	global_token = read_all_tokens(in, global_token, "tape_01");
+
+	if(NULL == global_token)
+	{
+		file_print("Either no input files were given or they were empty\n", stderr);
+		exit(EXIT_FAILURE);
+	}
+	global_token = reverse_list(global_token);
+
+	initialize_types();
+	reset_hold_string();
+	struct token_list* output_list = program();
+
+	/* Output the program we have compiled */
+	file_print("\n# Core program\n", destination_file);
+	recursive_output(output_list, destination_file);
+	/* file_print("\n:ELF_data\n", destination_file); */
+	file_print("\n\n# Program global variables\n", destination_file);
+	recursive_output(globals_list, destination_file);
+	file_print("\n# Program strings\n", destination_file);
+	recursive_output(strings_list, destination_file);
+	file_print("\n:STACK\n", destination_file);
+	return EXIT_SUCCESS;
+}

+ 81 - 0
stage2/High_level_prototypes/cc_knight-native/cc.h

@@ -0,0 +1,81 @@
+/* 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 <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#define MAX_STRING 4096
+// CONSTANT MAX_STRING 4096
+#define FALSE 0
+// CONSTANT FALSE 0
+#define TRUE 1
+// CONSTANT TRUE 1
+
+void file_print(char* s, FILE* f);
+int match(char* a, char* b);
+char* copy_string(char* target, char* source);
+void reset_hold_string();
+int in_set(int c, char* s);
+
+struct type
+{
+	struct type* next;
+	int size;
+	int offset;
+	struct type* indirect;
+	struct type* members;
+	struct type* type;
+	char* name;
+};
+
+struct token_list
+{
+	struct token_list* next;
+	union
+	{
+		struct token_list* locals;
+		struct token_list* prev;
+	};
+	char* s;
+	union
+	{
+		struct type* type;
+		char* filename;
+	};
+	union
+	{
+		struct token_list* arguments;
+		int depth;
+		int linenumber;
+	};
+};
+
+/* What types we have */
+struct type* global_types;
+struct type* prim_types;
+
+/* What we are currently working on */
+struct token_list* global_token;
+
+/* Output reorder collections*/
+struct token_list* strings_list;
+struct token_list* globals_list;
+
+/* Make our string collection more efficient */
+char* hold_string;
+int string_index;

+ 1173 - 0
stage2/High_level_prototypes/cc_knight-native/cc_core.c

@@ -0,0 +1,1173 @@
+/* Copyright (C) 2016 Jeremiah Orians
+ * Copyright (C) 2018 Jan (janneke) Nieuwenhuizen <janneke@gnu.org>
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#include "cc.h"
+#include "gcc_req.h"
+#include <stdint.h>
+
+/* Global lists */
+struct token_list* global_symbol_list;
+struct token_list* global_function_list;
+struct token_list* global_constant_list;
+
+/* Core lists for this file */
+struct token_list* function;
+struct token_list* out;
+
+/* What we are currently working on */
+struct type* current_target;
+char* break_target_head;
+char* break_target_func;
+char* break_target_num;
+struct token_list* break_frame;
+int current_count;
+struct type* last_type;
+int Address_of;
+
+/* Imported functions */
+char* parse_string(char* string);
+int escape_lookup(char* c);
+char* numerate_number(int a);
+int numerate_string(char *a);
+char* number_to_hex(int a, int bytes);
+
+struct token_list* emit(char *s, struct token_list* head)
+{
+	struct token_list* t = calloc(1, sizeof(struct token_list));
+	t->next = head;
+	t->s = s;
+	return t;
+}
+
+void emit_out(char* s)
+{
+	out = emit(s, out);
+}
+
+struct token_list* uniqueID(char* s, struct token_list* l, char* num)
+{
+	l = emit(s, l);
+	l = emit("_", l);
+	l = emit(num, l);
+	l = emit("\n", l);
+	return l;
+}
+
+void uniqueID_out(char* s, char* num)
+{
+	out = uniqueID(s, out, num);
+}
+
+struct token_list* sym_declare(char *s, struct type* t, struct token_list* list)
+{
+	struct token_list* a = calloc(1, sizeof(struct token_list));
+	a->next = list;
+	a->s = s;
+	a->type = t;
+	return a;
+}
+
+struct token_list* sym_lookup(char *s, struct token_list* symbol_list)
+{
+	struct token_list* i;
+	for(i = symbol_list; NULL != i; i = i->next)
+	{
+		if(match(i->s, s)) return i;
+	}
+	return NULL;
+}
+
+void line_error()
+{
+	file_print(global_token->filename, stderr);
+	file_print(":", stderr);
+	file_print(numerate_number(global_token->linenumber), stderr);
+	file_print(":", stderr);
+}
+
+void require_match(char* message, char* required)
+{
+	if(!match(global_token->s, required))
+	{
+		line_error();
+		file_print(message, stderr);
+		exit(EXIT_FAILURE);
+	}
+	global_token = global_token->next;
+}
+
+void expression();
+void function_call(char* s, int bool)
+{
+	require_match("ERROR in process_expression_list\nNo ( was found\n", "(");
+	int passed = 0;
+	emit_out("PUSHR R13 R15\t# Prevent overwriting in recursion\n");
+	emit_out("PUSHR R14 R15\t# Protect the old base pointer\n");
+	emit_out("COPY R13 R15\t# Copy new base pointer\n");
+
+	if(global_token->s[0] != ')')
+	{
+		expression();
+		emit_out("PUSHR R0 R15\t#_process_expression1\n");
+		passed = 1;
+
+		while(global_token->s[0] == ',')
+		{
+			global_token = global_token->next;
+			expression();
+			emit_out("PUSHR R0 R15\t#_process_expression2\n");
+			passed = passed + 1;
+		}
+	}
+
+	require_match("ERROR in process_expression_list\nNo ) was found\n", ")");
+
+	if(TRUE == bool)
+	{
+		emit_out("LOAD R0 R14 ");
+		emit_out(s);
+		emit_out("\nMOVE R14 R13\n");
+		emit_out("CALL R0 R15\n");
+	}
+	else
+	{
+		emit_out("MOVE R14 R13\n");
+		emit_out("CALLI R15 @FUNCTION_");
+		emit_out(s);
+		emit_out("\n");
+	}
+
+	for(; passed > 0; passed = passed - 1)
+	{
+		emit_out("POPR R1 R15\t# _process_expression_locals\n");
+	}
+	emit_out("POPR R14 R15\t# Restore old base pointer\n");
+	emit_out("POPR R13 R15\t# Prevent overwrite\n");
+}
+
+void constant_load(struct token_list* a)
+{
+	emit_out("LOADI R0 ");
+	emit_out(a->arguments->s);
+	emit_out("\n");
+}
+
+void variable_load(struct token_list* a)
+{
+	if(match("FUNCTION", a->type->name) && match("(", global_token->s))
+	{
+		function_call(numerate_number(a->depth), TRUE);
+		return;
+	}
+	current_target = a->type;
+	emit_out("ADDI R0 R14 ");
+	emit_out(numerate_number(a->depth));
+	emit_out("\n");
+
+	if(TRUE == Address_of) return;
+	if(match("=", global_token->s)) return;
+
+	emit_out("LOAD R0 R0 0\n");
+}
+
+void function_load(struct token_list* a)
+{
+	if(match("(", global_token->s))
+	{
+		function_call(a->s, FALSE);
+		return;
+	}
+
+	emit_out("LOADUI R0 $FUNCTION_");
+	emit_out(a->s);
+	emit_out("\n");
+}
+
+void global_load(struct token_list* a)
+{
+	current_target = a->type;
+	emit_out("LOADUI R0 $GLOBAL_");
+	emit_out(a->s);
+	emit_out("\n");
+	if(!match("=", global_token->s)) emit_out("LOAD R0 R0 0\n");
+}
+
+/*
+ * primary-expr:
+ * FAILURE
+ * "String"
+ * 'Char'
+ * [0-9]*
+ * [a-z,A-Z]*
+ * ( expression )
+ */
+
+void primary_expr_failure()
+{
+	line_error();
+	file_print("Recieved ", stderr);
+	file_print(global_token->s, stderr);
+	file_print(" in primary_expr\n", stderr);
+	exit(EXIT_FAILURE);
+}
+
+void primary_expr_string()
+{
+	char* number_string = numerate_number(current_count);
+	current_count = current_count + 1;
+	emit_out("LOADUI R0 $STRING_");
+	uniqueID_out(function->s, number_string);
+
+	/* The target */
+	strings_list = emit(":STRING_", strings_list);
+	strings_list = uniqueID(function->s, strings_list, number_string);
+
+	/* Parse the string */
+	strings_list = emit(parse_string(global_token->s), strings_list);
+	global_token = global_token->next;
+}
+
+void primary_expr_char()
+{
+	emit_out("LOADI R0 ");
+	emit_out(numerate_number(escape_lookup(global_token->s + 1)));
+	emit_out("\n");
+	global_token = global_token->next;
+}
+
+void primary_expr_number()
+{
+	int size = numerate_string(global_token->s);
+	if((32768 > size) && (size > -32768))
+	{
+		emit_out("LOADI R0 ");
+		emit_out(global_token->s);
+	}
+	else
+	{
+		emit_out("LOADR R0 4\nJUMP 4\n'");
+		emit_out(number_to_hex(size, 4));
+		emit_out("'");
+	}
+	emit_out("\n");
+	global_token = global_token->next;
+}
+
+void primary_expr_variable()
+{
+	char* s = global_token->s;
+	global_token = global_token->next;
+	struct token_list* a = sym_lookup(s, global_constant_list);
+	if(NULL != a)
+	{
+		constant_load(a);
+		return;
+	}
+
+	a= sym_lookup(s, function->locals);
+	if(NULL != a)
+	{
+		variable_load(a);
+		return;
+	}
+
+	a = sym_lookup(s, function->arguments);
+	if(NULL != a)
+	{
+		variable_load(a);
+		return;
+	}
+
+	a= sym_lookup(s, global_function_list);
+	if(NULL != a)
+	{
+		function_load(a);
+		return;
+	}
+
+	a = sym_lookup(s, global_symbol_list);
+	if(NULL != a)
+	{
+		global_load(a);
+		return;
+	}
+
+	line_error();
+	file_print(s ,stderr);
+	file_print(" is not a defined symbol\n", stderr);
+	exit(EXIT_FAILURE);
+}
+
+void primary_expr();
+struct type* promote_type(struct type* a, struct type* b)
+{
+	if(NULL == b)
+	{
+		return a;
+	}
+	if(NULL == a)
+	{
+		return b;
+	}
+
+	struct type* i;
+	for(i = global_types; NULL != i; i = i->next)
+	{
+		if(a->name == i->name) break;
+		if(b->name == i->name) break;
+		if(a->name == i->indirect->name) break;
+		if(b->name == i->indirect->name) break;
+	}
+	return i;
+}
+
+void common_recursion(FUNCTION f)
+{
+	last_type = current_target;
+	global_token = global_token->next;
+	emit_out("PUSHR R0 R15\t#_common_recursion\n");
+	f();
+	current_target = promote_type(current_target, last_type);
+	emit_out("POPR R1 R15\t# _common_recursion\n");
+}
+
+void general_recursion( FUNCTION f, char* s, char* name, FUNCTION iterate)
+{
+	if(match(name, global_token->s))
+	{
+		common_recursion(f);
+		emit_out(s);
+		iterate();
+	}
+}
+
+int ceil_log2(int a)
+{
+	int result = 0;
+	if((a & (a - 1)) == 0)
+	{
+		result = -1;
+	}
+
+	while(a > 0)
+	{
+		result = result + 1;
+		a = a >> 1;
+	}
+
+	return result;
+}
+
+/*
+ * postfix-expr:
+ *         primary-expr
+ *         postfix-expr [ expression ]
+ *         postfix-expr ( expression-list-opt )
+ *         postfix-expr -> member
+ */
+struct type* lookup_member(struct type* parent, char* name);
+void postfix_expr_arrow()
+{
+	emit_out("# looking up offset\n");
+	global_token = global_token->next;
+
+	struct type* i = lookup_member(current_target, global_token->s);
+	current_target = i->type;
+	global_token = global_token->next;
+
+	if(0 != i->offset)
+	{
+		emit_out("# -> offset calculation\n");
+		emit_out("ADDUI R0 R0 ");
+		emit_out(numerate_number(i->offset));
+		emit_out("\n");
+	}
+
+	if(!match("=", global_token->s) && (4 == i->size))
+	{
+		emit_out("LOAD R0 R0 0\n");
+	}
+}
+
+void postfix_expr_array()
+{
+	struct type* array = current_target;
+	common_recursion(expression);
+	current_target = array;
+	char* assign = "LOAD R0 R0 0\n";
+
+	/* Add support for Ints */
+	if(match("char*",  current_target->name))
+	{
+		assign = "LOAD8 R0 R0 0\n";
+	}
+	else
+	{
+		emit_out("SALI R0 ");
+		emit_out(numerate_number(ceil_log2(current_target->indirect->size)));
+		emit_out("\n");
+	}
+
+	emit_out("ADD R0 R0 R1\n");
+	require_match("ERROR in postfix_expr\nMissing ]\n", "]");
+
+	if(match("=", global_token->s))
+	{
+		assign = "";
+	}
+
+	emit_out(assign);
+}
+
+/*
+ * unary-expr:
+ *         postfix-expr
+ *         - postfix-expr
+ *         !postfix-expr
+ *         sizeof ( type )
+ */
+struct type* type_name();
+void unary_expr_sizeof()
+{
+	global_token = global_token->next;
+	require_match("ERROR in unary_expr\nMissing (\n", "(");
+	struct type* a = type_name();
+	require_match("ERROR in unary_expr\nMissing )\n", ")");
+
+	emit_out("LOADUI R0 ");
+	emit_out(numerate_number(a->size));
+	emit_out("\n");
+}
+
+void postfix_expr_stub()
+{
+	if(match("[", global_token->s))
+	{
+		postfix_expr_array();
+		postfix_expr_stub();
+	}
+
+	if(match("->", global_token->s))
+	{
+		postfix_expr_arrow();
+		postfix_expr_stub();
+	}
+}
+
+void postfix_expr()
+{
+	primary_expr();
+	postfix_expr_stub();
+}
+
+/*
+ * additive-expr:
+ *         postfix-expr
+ *         additive-expr * postfix-expr
+ *         additive-expr / postfix-expr
+ *         additive-expr % postfix-expr
+ *         additive-expr + postfix-expr
+ *         additive-expr - postfix-expr
+ *         additive-expr << postfix-expr
+ *         additive-expr >> postfix-expr
+ */
+void additive_expr_stub()
+{
+	general_recursion(postfix_expr, "ADD R0 R1 R0\n", "+", additive_expr_stub);
+	general_recursion(postfix_expr, "SUB R0 R1 R0\n", "-", additive_expr_stub);
+	general_recursion(postfix_expr, "MUL R0 R1 R0\n", "*", additive_expr_stub);
+	general_recursion(postfix_expr, "DIVU R0 R1 R0\n", "/", additive_expr_stub);
+	general_recursion(postfix_expr, "MODU R0 R1 R0\n", "%", additive_expr_stub);
+	general_recursion(postfix_expr, "SAL R0 R1 R0\n", "<<", additive_expr_stub);
+	general_recursion(postfix_expr, "SAR R0 R1 R0\n", ">>", additive_expr_stub);
+}
+
+
+void additive_expr()
+{
+	postfix_expr();
+	additive_expr_stub();
+}
+
+
+/*
+ * relational-expr:
+ *         additive_expr
+ *         relational-expr < additive_expr
+ *         relational-expr <= additive_expr
+ *         relational-expr >= additive_expr
+ *         relational-expr > additive_expr
+ */
+
+void relational_expr_stub()
+{
+	general_recursion(additive_expr, "CMPSKIP.GE R1 R0\nLOADUI R2 1\nMOVE R0 R2\n", "<", relational_expr_stub);
+	general_recursion(additive_expr, "CMPSKIP.G R1 R0\nLOADUI R2 1\nMOVE R0 R2\n", "<=", relational_expr_stub);
+	general_recursion(additive_expr, "CMPSKIP.L R1 R0\nLOADUI R2 1\nMOVE R0 R2\n", ">=", relational_expr_stub);
+	general_recursion(additive_expr, "CMPSKIP.LE R1 R0\nLOADUI R2 1\nMOVE R0 R2\n", ">", relational_expr_stub);
+	general_recursion(additive_expr, "CMPSKIP.NE R1 R0\nLOADUI R2 1\nMOVE R0 R2\n", "==", relational_expr_stub);
+	general_recursion(additive_expr, "CMPSKIP.E R1 R0\nLOADUI R2 1\nMOVE R0 R2\n", "!=", relational_expr_stub);
+}
+
+void relational_expr()
+{
+	additive_expr();
+	relational_expr_stub();
+}
+
+/*
+ * bitwise-expr:
+ *         relational-expr
+ *         bitwise-expr & bitwise-expr
+ *         bitwise-expr && bitwise-expr
+ *         bitwise-expr | bitwise-expr
+ *         bitwise-expr || bitwise-expr
+ *         bitwise-expr ^ bitwise-expr
+ */
+void bitwise_expr_stub()
+{
+	general_recursion(relational_expr, "AND R0 R0 R1\n", "&", bitwise_expr_stub);
+	general_recursion(relational_expr, "AND R0 R0 R1\n", "&&", bitwise_expr_stub);
+	general_recursion(relational_expr, "OR R0 R0 R1\n", "|", bitwise_expr_stub);
+	general_recursion(relational_expr, "OR R0 R0 R1\n", "||", bitwise_expr_stub);
+	general_recursion(relational_expr, "XOR R0 R0 R1\n", "^", bitwise_expr_stub);
+}
+
+
+void bitwise_expr()
+{
+	relational_expr();
+	bitwise_expr_stub();
+}
+
+/*
+ * expression:
+ *         bitwise-or-expr
+ *         bitwise-or-expr = expression
+ */
+
+void primary_expr()
+{
+	if(match("&", global_token->s))
+	{
+		Address_of = TRUE;
+		global_token = global_token->next;
+	}
+	else
+	{
+		Address_of = FALSE;
+	}
+
+	if(match("sizeof", global_token->s)) unary_expr_sizeof();
+	else if('-' == global_token->s[0])
+	{
+		common_recursion(primary_expr);
+		emit_out("NEG R0 R0\n");
+	}
+	else if('!' == global_token->s[0])
+	{
+		common_recursion(postfix_expr);
+		emit_out("XORI R0 R0 1\n");
+	}
+	else if(global_token->s[0] == '(')
+	{
+		global_token = global_token->next;
+		expression();
+		require_match("Error in Primary expression\nDidn't get )\n", ")");
+	}
+	else if(global_token->s[0] == '\'') primary_expr_char();
+	else if(global_token->s[0] == '"') primary_expr_string();
+	else if(in_set(global_token->s[0], "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_")) primary_expr_variable();
+	else if(in_set(global_token->s[0], "0123456789")) primary_expr_number();
+	else primary_expr_failure();
+}
+
+void expression()
+{
+	bitwise_expr();
+	if(match("=", global_token->s))
+	{
+		char* store;
+		if(!match("]", global_token->prev->s) || !match("char*", current_target->name))
+		{
+			store = "STORE R0 R1 0\n";
+		}
+		else
+		{
+			store = "STORE8 R0 R1 0\n";
+		}
+
+		common_recursion(expression);
+		emit_out(store);
+		current_target = NULL;
+	}
+}
+
+
+/* Process local variable */
+void collect_local()
+{
+	struct type* type_size = type_name();
+	struct token_list* a = sym_declare(global_token->s, type_size, function->locals);
+	if(match("main", function->s) && (NULL == function->locals))
+	{
+		a->depth = 4;
+	}
+	else if((NULL == function->arguments) && (NULL == function->locals))
+	{
+		a->depth = 4;
+	}
+	else if(NULL == function->locals)
+	{
+		a->depth = function->arguments->depth + 8;
+	}
+	else
+	{
+		a->depth = function->locals->depth + 4;
+	}
+
+	function->locals = a;
+
+	emit_out("# Defining local ");
+	emit_out(global_token->s);
+	emit_out("\n");
+
+	global_token = global_token->next;
+
+	if(match("=", global_token->s))
+	{
+		global_token = global_token->next;
+		expression();
+	}
+
+	require_match("ERROR in collect_local\nMissing ;\n", ";");
+
+	emit_out("PUSHR R0 R15\t#");
+	emit_out(a->s);
+	emit_out("\n");
+}
+
+void statement();
+
+/* Evaluate if statements */
+void process_if()
+{
+	char* number_string = numerate_number(current_count);
+	current_count = current_count + 1;
+
+	emit_out("# IF_");
+	uniqueID_out(function->s, number_string);
+
+	global_token = global_token->next;
+	require_match("ERROR in process_if\nMISSING (\n", "(");
+	expression();
+
+	emit_out("JUMP.Z R0 @ELSE_");
+	uniqueID_out(function->s, number_string);
+
+	require_match("ERROR in process_if\nMISSING )\n", ")");
+	statement();
+
+	emit_out("JUMP @_END_IF_");
+	uniqueID_out(function->s, number_string);
+	emit_out(":ELSE_");
+	uniqueID_out(function->s, number_string);
+
+	if(match("else", global_token->s))
+	{
+		global_token = global_token->next;
+		statement();
+	}
+	emit_out(":_END_IF_");
+	uniqueID_out(function->s, number_string);
+}
+
+void process_for()
+{
+	struct token_list* nested_locals = break_frame;
+	char* nested_break_head = break_target_head;
+	char* nested_break_func = break_target_func;
+	char* nested_break_num = break_target_num;
+
+	char* number_string = numerate_number(current_count);
+	current_count = current_count + 1;
+
+	break_target_head = "FOR_END_";
+	break_target_num = number_string;
+	break_frame = function->locals;
+	break_target_func = function->s;
+
+	emit_out("# FOR_initialization_");
+	uniqueID_out(function->s, number_string);
+
+	global_token = global_token->next;
+
+	require_match("ERROR in process_for\nMISSING (\n", "(");
+	if(!match(";",global_token->s))
+	{
+		expression();
+	}
+
+	emit_out(":FOR_");
+	uniqueID_out(function->s, number_string);
+
+	require_match("ERROR in process_for\nMISSING ;1\n", ";");
+	expression();
+
+	emit_out("JUMP.Z R0 @FOR_END_");
+	uniqueID_out(function->s, number_string);
+	emit_out("JUMP @FOR_THEN_");
+	uniqueID_out(function->s, number_string);
+	emit_out(":FOR_ITER_");
+	uniqueID_out(function->s, number_string);
+
+	require_match("ERROR in process_for\nMISSING ;2\n", ";");
+	expression();
+
+	emit_out("JUMP @FOR_");
+	uniqueID_out(function->s, number_string);
+	emit_out(":FOR_THEN_");
+	uniqueID_out(function->s, number_string);
+
+	require_match("ERROR in process_for\nMISSING )\n", ")");
+	statement();
+
+	emit_out("JUMP @FOR_ITER_");
+	uniqueID_out(function->s, number_string);
+	emit_out(":FOR_END_");
+	uniqueID_out(function->s, number_string);
+
+	break_target_head = nested_break_head;
+	break_target_func = nested_break_func;
+	break_target_num = nested_break_num;
+	break_frame = nested_locals;
+}
+
+/* Process Assembly statements */
+void process_asm()
+{
+	global_token = global_token->next;
+	require_match("ERROR in process_asm\nMISSING (\n", "(");
+	while(34 == global_token->s[0])
+	{/* 34 == " */
+		emit_out((global_token->s + 1));
+		emit_out("\n");
+		global_token = global_token->next;
+	}
+	require_match("ERROR in process_asm\nMISSING )\n", ")");
+	require_match("ERROR in process_asm\nMISSING ;\n", ";");
+}
+
+/* Process do while loops */
+void process_do()
+{
+	struct token_list* nested_locals = break_frame;
+	char* nested_break_head = break_target_head;
+	char* nested_break_func = break_target_func;
+	char* nested_break_num = break_target_num;
+
+	char* number_string = numerate_number(current_count);
+	current_count = current_count + 1;
+
+	break_target_head = "DO_END_";
+	break_target_num = number_string;
+	break_frame = function->locals;
+	break_target_func = function->s;
+
+	emit_out(":DO_");
+	uniqueID_out(function->s, number_string);
+
+	global_token = global_token->next;
+	statement();
+
+	require_match("ERROR in process_do\nMISSING while\n", "while");
+	require_match("ERROR in process_do\nMISSING (\n", "(");
+	expression();
+	require_match("ERROR in process_do\nMISSING )\n", ")");
+	require_match("ERROR in process_do\nMISSING ;\n", ";");
+
+	emit_out("JUMP.NZ R0 @DO_");
+	uniqueID_out(function->s, number_string);
+	emit_out(":DO_END_");
+	uniqueID_out(function->s, number_string);
+
+	break_frame = nested_locals;
+	break_target_head = nested_break_head;
+	break_target_func = nested_break_func;
+	break_target_num = nested_break_num;
+}
+
+
+/* Process while loops */
+void process_while()
+{
+	struct token_list* nested_locals = break_frame;
+	char* nested_break_head = break_target_head;
+	char* nested_break_func = break_target_func;
+	char* nested_break_num = break_target_num;
+
+	char* number_string = numerate_number(current_count);
+	current_count = current_count + 1;
+
+	break_target_head = "END_WHILE_";
+	break_target_num = number_string;
+	break_frame = function->locals;
+	break_target_func = function->s;
+
+	emit_out(":WHILE_");
+	uniqueID_out(function->s, number_string);
+
+	global_token = global_token->next;
+	require_match("ERROR in process_while\nMISSING (\n", "(");
+	expression();
+
+	emit_out("JUMP.Z R0 @END_WHILE_");
+	uniqueID_out(function->s, number_string);
+	emit_out("# THEN_while_");
+	uniqueID_out(function->s, number_string);
+
+	require_match("ERROR in process_while\nMISSING )\n", ")");
+	statement();
+
+	emit_out("JUMP @WHILE_");
+	uniqueID_out(function->s, number_string);
+	emit_out(":END_WHILE_");
+	uniqueID_out(function->s, number_string);
+
+	break_target_head = nested_break_head;
+	break_target_func = nested_break_func;
+	break_target_num = nested_break_num;
+	break_frame = nested_locals;
+}
+
+/* Ensure that functions return */
+void return_result()
+{
+	global_token = global_token->next;
+	if(global_token->s[0] != ';') expression();
+
+	require_match("ERROR in return_result\nMISSING ;\n", ";");
+
+	struct token_list* i;
+	for(i = function->locals; NULL != i; i = i->next)
+	{
+		emit_out("POPR R1 R15\t# _return_result_locals\n");
+	}
+	emit_out("RET R15\n");
+}
+
+void process_break()
+{
+	if(NULL == break_target_head)
+	{
+		line_error();
+		file_print("Not inside of a loop or case statement", stderr);
+		exit(EXIT_FAILURE);
+	}
+	struct token_list* i = function->locals;
+	while(i != break_frame)
+	{
+		if(NULL == i) break;
+		emit_out("POPR R1 R15\t# break_cleanup_locals\n");
+		i = i->next;
+	}
+	global_token = global_token->next;
+	emit_out("JUMP @");
+	emit_out(break_target_head);
+	emit_out(break_target_func);
+	emit_out("_");
+	emit_out(break_target_num);
+	emit_out("\n");
+	require_match("ERROR in break statement\nMissing ;\n", ";");
+}
+
+void recursive_statement()
+{
+	global_token = global_token->next;
+	struct token_list* frame = function->locals;
+
+	while(!match("}", global_token->s))
+	{
+		statement();
+	}
+	global_token = global_token->next;
+
+	/* Clean up any locals added */
+	if(!match("RET R15\n", out->s))
+	{
+		struct token_list* i;
+		for(i = function->locals; frame != i; i = i->next)
+		{
+			emit_out( "POPR R1 R15\t# _recursive_statement_locals\n");
+		}
+	}
+	function->locals = frame;
+}
+
+/*
+ * statement:
+ *     { statement-list-opt }
+ *     type-name identifier ;
+ *     type-name identifier = expression;
+ *     if ( expression ) statement
+ *     if ( expression ) statement else statement
+ *     do statement while ( expression ) ;
+ *     while ( expression ) statement
+ *     for ( expression ; expression ; expression ) statement
+ *     asm ( "assembly" ... "assembly" ) ;
+ *     goto label ;
+ *     label:
+ *     return ;
+ *     break ;
+ *     expr ;
+ */
+
+struct type* lookup_type(char* s, struct type* start);
+void statement()
+{
+	if(global_token->s[0] == '{')
+	{
+		recursive_statement();
+	}
+	else if(':' == global_token->s[0])
+	{
+		emit_out(global_token->s);
+		emit_out("\t#C goto label\n");
+		global_token = global_token->next;
+	}
+	else if((NULL != lookup_type(global_token->s, prim_types)) ||
+	          match("struct", global_token->s))
+	{
+		collect_local();
+	}
+	else if(match("if", global_token->s))
+	{
+		process_if();
+	}
+	else if(match("do", global_token->s))
+	{
+		process_do();
+	}
+	else if(match("while", global_token->s))
+	{
+		process_while();
+	}
+	else if(match("for", global_token->s))
+	{
+		process_for();
+	}
+	else if(match("asm", global_token->s))
+	{
+		process_asm();
+	}
+	else if(match("goto", global_token->s))
+	{
+		global_token = global_token->next;
+		emit_out("JUMP @");
+		emit_out(global_token->s);
+		emit_out("\n");
+		global_token = global_token->next;
+		require_match("ERROR in statement\nMissing ;\n", ";");
+	}
+	else if(match("return", global_token->s))
+	{
+		return_result();
+	}
+	else if(match("break", global_token->s))
+	{
+		process_break();
+	}
+	else if(match("continue", global_token->s))
+	{
+		global_token = global_token->next;
+		emit_out("\n#continue statement\n");
+		require_match("ERROR in statement\nMissing ;\n", ";");
+	}
+	else
+	{
+		expression();
+		require_match("ERROR in statement\nMISSING ;\n", ";");
+	}
+}
+
+/* Collect function arguments */
+void collect_arguments()
+{
+	global_token = global_token->next;
+
+	while(!match(")", global_token->s))
+	{
+		struct type* type_size = type_name();
+		if(global_token->s[0] == ')')
+		{
+			/* foo(int,char,void) doesn't need anything done */
+			continue;
+		}
+		else if(global_token->s[0] != ',')
+		{
+			/* deal with foo(int a, char b) */
+			struct token_list* a = sym_declare(global_token->s, type_size, function->arguments);
+			if(NULL == function->arguments)
+			{
+				a->depth = 0;
+			}
+			else
+			{
+				a->depth = function->arguments->depth + 4;
+			}
+
+			global_token = global_token->next;
+			function->arguments = a;
+		}
+
+		/* ignore trailing comma (needed for foo(bar(), 1); expressions*/
+		if(global_token->s[0] == ',') global_token = global_token->next;
+	}
+	global_token = global_token->next;
+}
+
+void declare_function()
+{
+	current_count = 0;
+	function = sym_declare(global_token->prev->s, NULL, global_function_list);
+
+	/* allow previously defined functions to be looked up */
+	global_function_list = function;
+	collect_arguments();
+
+	/* If just a prototype don't waste time */
+	if(global_token->s[0] == ';') global_token = global_token->next;
+	else
+	{
+		emit_out("# Defining function ");
+		emit_out(function->s);
+		emit_out("\n");
+		emit_out(":FUNCTION_");
+		emit_out(function->s);
+		emit_out("\n");
+		statement();
+
+		/* Prevent duplicate RET R15S */
+		if(!match("RET R15\n", out->s))
+		{
+			emit_out("RET R15\n");
+		}
+	}
+}
+
+/*
+ * program:
+ *     declaration
+ *     declaration program
+ *
+ * declaration:
+ *     CONSTANT identifer value
+ *     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
+ */
+struct token_list* program()
+{
+	Address_of = FALSE;
+	out = NULL;
+	function = NULL;
+	struct type* type_size;
+
+new_type:
+	if (NULL == global_token) return out;
+	if(match("CONSTANT", global_token->s))
+	{
+		global_token = global_token->next;
+		global_constant_list = sym_declare(global_token->s, NULL, global_constant_list);
+		global_constant_list->arguments = global_token->next;
+		global_token = global_token->next->next;
+	}
+	else
+	{
+		type_size = type_name();
+		if(NULL == type_size)
+		{
+			goto new_type;
+		}
+		/* Add to global symbol table */
+		global_symbol_list = sym_declare(global_token->s, type_size, global_symbol_list);
+		global_token = global_token->next;
+		if(match(";", global_token->s))
+		{
+			/* Ensure 4 bytes are allocated for the global */
+			globals_list = emit(":GLOBAL_", globals_list);
+			globals_list = emit(global_token->prev->s, globals_list);
+			globals_list = emit("\nNULL\n", globals_list);
+
+			global_token = global_token->next;
+		}
+		else if(match("(", global_token->s)) declare_function();
+		else if(match("=",global_token->s))
+		{
+			/* Store the global's value*/
+			globals_list = emit(":GLOBAL_", globals_list);
+			globals_list = emit(global_token->prev->s, globals_list);
+			globals_list = emit("\n", globals_list);
+			global_token = global_token->next;
+			if(in_set(global_token->s[0], "0123456789"))
+			{ /* Assume Int */
+				globals_list = emit("%", globals_list);
+				globals_list = emit(global_token->s, globals_list);
+				globals_list = emit("\n", globals_list);
+			}
+			else if(('"' == global_token->s[0]))
+			{ /* Assume a string*/
+				globals_list = emit(parse_string(global_token->s), globals_list);
+			}
+			else
+			{
+				line_error();
+				file_print("Recieved ", stderr);
+				file_print(global_token->s, stderr);
+				file_print(" in program\n", stderr);
+				exit(EXIT_FAILURE);
+			}
+
+			global_token = global_token->next;
+			require_match("ERROR in Program\nMissing ;\n", ";");
+		}
+		else
+		{
+			line_error();
+			file_print("Recieved ", stderr);
+			file_print(global_token->s, stderr);
+			file_print(" in program\n", stderr);
+			exit(EXIT_FAILURE);
+		}
+	}
+	goto new_type;
+}
+
+void recursive_output(struct token_list* i, FILE* out)
+{
+	if(NULL == i) return;
+	recursive_output(i->next, out);
+	file_print(i->s, out);
+}

+ 218 - 0
stage2/High_level_prototypes/cc_knight-native/cc_reader.c

@@ -0,0 +1,218 @@
+/* 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 <http://www.gnu.org/licenses/>.
+ */
+
+#include "cc.h"
+FILE* input;
+struct token_list* token;
+int line;
+char* file;
+
+int clearWhiteSpace(int c)
+{
+	if((32 == c) || (9 == c)) return clearWhiteSpace(fgetc(input));
+	else if (10 == c)
+	{
+		line = line + 1;
+		return clearWhiteSpace(fgetc(input));
+	}
+	return c;
+}
+
+int consume_byte(int c)
+{
+	hold_string[string_index] = c;
+	string_index = string_index + 1;
+	return fgetc(input);
+}
+
+int consume_word(int c, int frequent)
+{
+	int escape = FALSE;
+	do
+	{
+		if(!escape && '\\' == c ) escape = TRUE;
+		else escape = FALSE;
+		c = consume_byte(c);
+	} while(escape || (c != frequent));
+	return fgetc(input);
+}
+
+
+void fixup_label()
+{
+	int hold = ':';
+	int prev;
+	int i = 0;
+	do
+	{
+		prev = hold;
+		hold = hold_string[i];
+		hold_string[i] = prev;
+		i = i + 1;
+	} while(0 != hold);
+}
+
+int in_set(int c, char* s)
+{
+	while(0 != s[0])
+	{
+		if(c == s[0]) return TRUE;
+		s = s + 1;
+	}
+	return FALSE;
+}
+
+int preserve_keyword(int c)
+{
+	while(in_set(c, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_"))
+	{
+		c = consume_byte(c);
+	}
+	if(':' == c)
+	{
+		fixup_label();
+		return 32;
+	}
+	return c;
+}
+
+int preserve_symbol(int c)
+{
+	while(in_set(c, "<=>|&!-"))
+	{
+		c = consume_byte(c);
+	}
+	return c;
+}
+
+int purge_macro(int ch)
+{
+	while(10 != ch) ch = fgetc(input);
+	return ch;
+}
+
+void reset_hold_string()
+{
+	int i = string_index + 2;
+	while(0 != i)
+	{
+		hold_string[i] = 0;
+		i = i - 1;
+	}
+}
+
+int get_token(int c)
+{
+	struct token_list* current = calloc(1, sizeof(struct token_list));
+
+reset:
+	reset_hold_string();
+	string_index = 0;
+
+	c = clearWhiteSpace(c);
+	if('#' == c)
+	{
+		c = purge_macro(c);
+		goto reset;
+	}
+	else if(in_set(c, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_"))
+	{
+		c = preserve_keyword(c);
+	}
+	else if(in_set(c, "<=>|&!-"))
+	{
+		c = preserve_symbol(c);
+	}
+	else if(c == '\'')
+	{ /* 39 == ' */
+		c = consume_word(c, '\'');
+	}
+	else if(c == '"')
+	{
+		c = consume_word(c, '"');
+	}
+	else if(c == '/')
+	{
+		c = consume_byte(c);
+		if(c == '*')
+		{
+			c = fgetc(input);
+			while(c != '/')
+			{
+				while(c != '*')
+				{
+					c = fgetc(input);
+					if(10 == c) line = line + 1;
+				}
+				c = fgetc(input);
+				if(10 == c) line = line + 1;
+			}
+			c = fgetc(input);
+			goto reset;
+		}
+		else if(c == '/')
+		{
+			c = fgetc(input);
+			goto reset;
+		}
+	}
+	else if(c == EOF)
+	{
+		free(current);
+		return c;
+	}
+	else
+	{
+		c = consume_byte(c);
+	}
+
+	/* More efficiently allocate memory for string */
+	current->s = calloc(string_index + 2, sizeof(char));
+	copy_string(current->s, hold_string);
+
+	current->prev = token;
+	current->next = token;
+	current->linenumber = line;
+	current->filename = file;
+	token = current;
+	return c;
+}
+
+struct token_list* reverse_list(struct token_list* head)
+{
+	struct token_list* root = NULL;
+	while(NULL != head)
+	{
+		struct token_list* next = head->next;
+		head->next = root;
+		root = head;
+		head = next;
+	}
+	return root;
+}
+
+struct token_list* read_all_tokens(FILE* a, struct token_list* current, char* filename)
+{
+	input  = a;
+	line = 1;
+	file = filename;
+	token = current;
+	int ch =fgetc(input);
+	while(EOF != ch) ch = get_token(ch);
+
+	return token;
+}

+ 171 - 0
stage2/High_level_prototypes/cc_knight-native/cc_strings.c

@@ -0,0 +1,171 @@
+/* Copyright (C) 2016 Jeremiah Orians
+ * Copyright (C) 2018 Jan (janneke) Nieuwenhuizen <janneke@gnu.org>
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#include "cc.h"
+#include <stdint.h>
+
+struct token_list* emit(char *s, struct token_list* head);
+int char2hex(int c);
+
+char upcase(char a)
+{
+	if(in_set(a, "abcdefghijklmnopqrstuvwxyz"))
+	{
+		a = a - 32;
+	}
+
+	return a;
+}
+
+int hexify(int c, int high)
+{
+	int i = char2hex(c);
+
+	if(0 > i)
+	{
+		file_print("Tried to print non-hex number\n", stderr);
+		exit(EXIT_FAILURE);
+	}
+
+	if(high)
+	{
+		i = i << 4;
+	}
+	return i;
+}
+
+int escape_lookup(char* c);
+int weird(char* string)
+{
+	int c;
+	string = string + 1;
+weird_reset:
+	c = string[0];
+	if(0 == c) return FALSE;
+	if('\\' == c)
+	{
+		c = escape_lookup(string);
+		if('x' == string[1]) string = string + 2;
+		string = string + 1;
+	}
+
+	if(!in_set(c, "\t\n !#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~")) return TRUE;
+	if(in_set(c, " \t\n\r") && (':' == string[1])) return TRUE;
+	string = string + 1;
+	goto weird_reset;
+}
+
+/* Lookup escape values */
+int escape_lookup(char* c)
+{
+	if('\\' != c[0]) return c[0];
+
+	if(c[1] == 'x')
+	{
+		int t1 = hexify(c[2], TRUE);
+		int t2 = hexify(c[3], FALSE);
+		return t1 + t2;
+	}
+	else if(c[1] == 't') return 9;
+	else if(c[1] == 'n') return 10;
+	else if(c[1] == 'v') return 11;
+	else if(c[1] == 'f') return 12;
+	else if(c[1] == 'r') return 13;
+	else if(c[1] == 'e') return 27;
+	else if(c[1] == '"') return 34;
+	else if(c[1] == '\'') return 39;
+	else if(c[1] == '\\') return 92;
+
+	file_print("Unknown escape recieved: ", stderr);
+	file_print(c, stderr);
+	file_print(" Unable to process\n", stderr);
+	exit(EXIT_FAILURE);
+}
+
+/* Deal with human strings */
+char* collect_regular_string(char* string)
+{
+	string_index = 0;
+
+collect_regular_string_reset:
+	if(string[0] == '\\')
+	{
+		hold_string[string_index] = escape_lookup(string);
+		if (string[1] == 'x') string = string + 2;
+		string = string + 2;
+	}
+	else
+	{
+		hold_string[string_index] = string[0];
+		string = string + 1;
+	}
+
+	string_index = string_index + 1;
+	if(string[0] != 0) goto collect_regular_string_reset;
+
+	hold_string[string_index] = '"';
+	hold_string[string_index + 1] = '\n';
+	char* message = calloc(string_index + 3, sizeof(char));
+	copy_string(message, hold_string);
+	reset_hold_string();
+	return message;
+}
+
+/* Deal with non-human strings */
+char* collect_weird_string(char* string)
+{
+	string_index = 1;
+	int temp;
+	char* table = "0123456789ABCDEF";
+
+	hold_string[0] = '\'';
+collect_weird_string_reset:
+	string = string + 1;
+	hold_string[string_index] = ' ';
+	temp = escape_lookup(string);
+	hold_string[string_index + 1] = table[(temp >> 4)];
+	hold_string[string_index + 2] = table[(temp & 15)];
+
+	if(string[0] == '\\')
+	{
+		if(string[1] == 'x') string = string + 2;
+		string = string + 1;
+	}
+
+	string_index = string_index + 3;
+	if(string[1] != 0) goto collect_weird_string_reset;
+
+	hold_string[string_index] = ' ';
+	hold_string[string_index + 1] = '0';
+	hold_string[string_index + 2] = '0';
+	hold_string[string_index + 3] = '\'';
+	hold_string[string_index + 4] = '\n';
+
+	char* hold = calloc(string_index + 6, sizeof(char));
+	copy_string(hold, hold_string);
+	reset_hold_string();
+	return hold;
+}
+
+/* Parse string to deal with hex characters*/
+char* parse_string(char* string)
+{
+	/* the string */
+	if(weird(string)) return collect_weird_string(string);
+	else return collect_regular_string(string);
+}

+ 260 - 0
stage2/High_level_prototypes/cc_knight-native/cc_types.c

@@ -0,0 +1,260 @@
+/* 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 <http://www.gnu.org/licenses/>.
+ */
+
+#include "cc.h"
+#include <stdint.h>
+void line_error();
+int numerate_string(char *a);
+
+/* Initialize default types */
+void initialize_types()
+{
+	/* Define void */
+	global_types = calloc(1, sizeof(struct type));
+	global_types->name = "void";
+	global_types->size = 4;
+	global_types->type = global_types;
+	/* void* has the same properties as void */
+	global_types->indirect = global_types;
+
+	/* Define int */
+	struct type* a = calloc(1, sizeof(struct type));
+	a->name = "int";
+	a->size = 4;
+	/* int* has the same properties as int */
+	a->indirect = a;
+	a->type = a;
+
+	/* Define char* */
+	struct type* b = calloc(1, sizeof(struct type));
+	b->name = "char*";
+	b->size = 4;
+	b->type = b;
+
+	/* Define char */
+	struct type* c = calloc(1, sizeof(struct type));
+	c->name = "char";
+	c->size = 1;
+	c->type = c;
+
+	/* Define char** */
+	struct type* d = calloc(1, sizeof(struct type));
+	d->name = "char**";
+	d->size = 4;
+	d->type = c;
+	d->indirect = d;
+
+	/*fix up indrects for chars */
+	c->indirect = b;
+	b->indirect = d;
+
+	/* Define FILE */
+	struct type* e = calloc(1, sizeof(struct type));
+	e->name = "FILE";
+	e->size = 4;
+	e->type = e;
+	/* FILE* has the same properties as FILE */
+	e->indirect = e;
+
+	/* Define FUNCTION */
+	struct type* f = calloc(1, sizeof(struct type));
+	f->name = "FUNCTION";
+	f->size = 4;
+	f->type = f;
+	/* FUNCTION* has the same properties as FUNCTION */
+	f->indirect = f;
+
+	/* Define UNSIGNED */
+	struct type* g = calloc(1, sizeof(struct type));
+	g->name = "unsigned";
+	g->size = 4;
+	g->type = g;
+	/* unsigned* has the same properties as unsigned */
+	g->indirect = g;
+
+	/* Finalize type list */
+	f->next = g;
+	e->next = f;
+	d->next = e;
+	c->next = e;
+	a->next = c;
+	global_types->next = a;
+	prim_types = global_types;
+}
+
+struct type* lookup_type(char* s, struct type* start)
+{
+	struct type* i;
+	for(i = start; NULL != i; i = i->next)
+	{
+		if(match(i->name, s))
+		{
+			return i;
+		}
+	}
+	return NULL;
+}
+
+struct type* lookup_member(struct type* parent, char* name)
+{
+	struct type* i;
+	for(i = parent->members; NULL != i; i = i->members)
+	{
+		if(match(i->name, name)) return i;
+	}
+
+	file_print("ERROR in lookup_member ", stderr);
+	file_print(parent->name, stderr);
+	file_print("->", stderr);
+	file_print(global_token->s, stderr);
+	file_print(" does not exist\n", stderr);
+	line_error();
+	file_print("\n", stderr);
+	exit(EXIT_FAILURE);
+}
+
+struct type* type_name();
+void require_match(char* message, char* required);
+
+int member_size;
+struct type* build_member(struct type* last, int offset)
+{
+	struct type* member_type = type_name();
+	struct type* i = calloc(1, sizeof(struct type));
+	i->name = global_token->s;
+	global_token = global_token->next;
+	i->members = last;
+
+	/* Check to see if array */
+	if(match( "[", global_token->s))
+	{
+		global_token = global_token->next;
+		i->size = member_type->type->size * numerate_string(global_token->s);
+		global_token = global_token->next;
+		require_match("Struct only supports [num] form\n", "]");
+	}
+	else
+	{
+		i->size = member_type->size;
+	}
+	member_size = i->size;
+	i->type = member_type;
+	i->offset = offset;
+	return i;
+}
+
+struct type* build_union(struct type* last, int offset)
+{
+	int size = 0;
+	global_token = global_token->next;
+	require_match("ERROR in build_union\nMissing {\n", "{");
+	while('}' != global_token->s[0])
+	{
+		last = build_member(last, offset);
+		if(member_size > size)
+		{
+			size = member_size;
+		}
+		require_match("ERROR in build_union\nMissing ;\n", ";");
+	}
+	member_size = size;
+	global_token = global_token->next;
+	return last;
+}
+
+void create_struct()
+{
+	int offset = 0;
+	member_size = 0;
+	struct type* head = calloc(1, sizeof(struct type));
+	struct type* i = calloc(1, sizeof(struct type));
+	head->name = global_token->s;
+	i->name = global_token->s;
+	head->indirect = i;
+	i->indirect = head;
+	head->next = global_types;
+	global_types = head;
+	global_token = global_token->next;
+	i->size = 4;
+	require_match("ERROR in create_struct\n Missing {\n", "{");
+	struct type* last = NULL;
+	while('}' != global_token->s[0])
+	{
+		if(match(global_token->s, "union"))
+		{
+			last = build_union(last, offset);
+		}
+		else
+		{
+			last = build_member(last, offset);
+		}
+		offset = offset + member_size;
+		require_match("ERROR in create_struct\n Missing ;\n", ";");
+	}
+
+	global_token = global_token->next;
+	require_match("ERROR in create_struct\n Missing ;\n", ";");
+
+	head->size = offset;
+	head->members = last;
+	i->members = last;
+}
+
+
+/*
+ * type-name:
+ *     char *
+ *     int
+ *     struct
+ *     FILE
+ *     void
+ */
+struct type* type_name()
+{
+	int structure = match("struct", global_token->s);
+
+	if(structure)
+	{
+		global_token = global_token->next;
+	}
+
+	struct type* ret = lookup_type(global_token->s, global_types);
+
+	if(NULL == ret && !structure)
+	{
+		file_print("Unknown type ", stderr);
+		file_print(global_token->s, stderr);
+		file_print("\n", stderr);
+		line_error();
+		exit(EXIT_FAILURE);
+	}
+	else if(NULL == ret)
+	{
+		create_struct();
+		return NULL;
+	}
+
+	global_token = global_token->next;
+
+	while(global_token->s[0] == '*')
+	{
+		ret = ret->indirect;
+		global_token = global_token->next;
+	}
+
+	return ret;
+}

+ 27 - 0
stage2/High_level_prototypes/cc_knight-native/functions/file_print.c

@@ -0,0 +1,27 @@
+/* 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 <http://www.gnu.org/licenses/>.
+ */
+#include<stdio.h>
+// void fputc(char s, FILE* f);
+
+void file_print(char* s, FILE* f)
+{
+	while(0 != s[0])
+	{
+		fputc(s[0], f);
+		s = s + 1;
+	}
+}

+ 35 - 0
stage2/High_level_prototypes/cc_knight-native/functions/match.c

@@ -0,0 +1,35 @@
+/* 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 <http://www.gnu.org/licenses/>.
+ */
+
+#define FALSE 0
+// CONSTANT FALSE 0
+#define TRUE 1
+// CONSTANT TRUE 1
+
+int match(char* a, char* b)
+{
+	int i = -1;
+	do
+	{
+		i = i + 1;
+		if(a[i] != b[i])
+		{
+			return FALSE;
+		}
+	} while((0 != a[i]) && (0 !=b[i]));
+	return TRUE;
+}

+ 46 - 0
stage2/High_level_prototypes/cc_knight-native/functions/number_pack.c

@@ -0,0 +1,46 @@
+/* Copyright (C) 2016 Jeremiah Orians
+ * This file is part of M2-Planet.
+ *
+ * M2-Planet 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.
+ *
+ * M2-Planet 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 M2-Planet.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include<stdlib.h>
+#include<string.h>
+#include<stdio.h>
+// void* calloc(int count, int size);
+int hex2char(int c);
+void file_print(char* s, FILE* f);
+
+char* number_to_hex(int a, int bytes)
+{
+	char* result = calloc(1 + (bytes << 1), sizeof(char));
+	if(NULL == result)
+	{
+		file_print("calloc failed in number_to_hex\n", stderr);
+		exit(EXIT_FAILURE);
+	}
+	int i = 0;
+
+	int divisor = (bytes << 3);
+
+	/* Simply collect numbers until divisor is gone */
+	while(0 != divisor)
+	{
+		divisor = divisor - 4;
+		result[i] = hex2char((a >> divisor) & 0xF);
+		i = i + 1;
+	}
+
+	return result;
+}

+ 148 - 0
stage2/High_level_prototypes/cc_knight-native/functions/numerate_number.c

@@ -0,0 +1,148 @@
+/* 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 <http://www.gnu.org/licenses/>.
+ */
+#include<stdlib.h>
+#include<string.h>
+// void* calloc(int count, int size);
+#define TRUE 1
+//CONSTANT TRUE 1
+#define FALSE 0
+//CONSTANT FALSE 0
+
+char* numerate_number(int a)
+{
+	char* result = calloc(16, sizeof(char));
+	int i = 0;
+
+	/* Deal with Zero case */
+	if(0 == a)
+	{
+		result[0] = '0';
+		return result;
+	}
+
+	/* Deal with negatives */
+	if(0 > a)
+	{
+		result[0] = '-';
+		i = 1;
+		a = a * -1;
+	}
+
+	/* Using the largest 10^n number possible in 32bits */
+	int divisor = 0x3B9ACA00;
+	/* Skip leading Zeros */
+	while(0 == (a / divisor)) divisor = divisor / 10;
+
+	/* Now simply collect numbers until divisor is gone */
+	while(0 < divisor)
+	{
+		result[i] = ((a / divisor) + 48);
+		a = a % divisor;
+		divisor = divisor / 10;
+		i = i + 1;
+	}
+
+	return result;
+}
+
+int char2hex(int c)
+{
+	if (c >= '0' && c <= '9') return (c - 48);
+	else if (c >= 'a' && c <= 'f') return (c - 87);
+	else if (c >= 'A' && c <= 'F') return (c - 55);
+	else return -1;
+}
+
+int hex2char(int c)
+{
+	if((c >= 0) && (c <= 9)) return (c + 48);
+	else if((c >= 10) && (c <= 15)) return (c + 55);
+	else return -1;
+}
+
+int char2dec(int c)
+{
+	if (c >= '0' && c <= '9') return (c - 48);
+	else return -1;
+}
+
+int dec2char(int c)
+{
+	if((c >= 0) && (c <= 9)) return (c + 48);
+	else return -1;
+}
+
+int numerate_string(char *a)
+{
+	int count = 0;
+	int index;
+	int negative;
+
+	/* If NULL string */
+	if(0 == a[0])
+	{
+		return 0;
+	}
+	/* Deal with hex */
+	else if (a[0] == '0' && a[1] == 'x')
+	{
+		if('-' == a[2])
+		{
+			negative = TRUE;
+			index = 3;
+		}
+		else
+		{
+			negative = FALSE;
+			index = 2;
+		}
+
+		while(0 != a[index])
+		{
+			if(-1 == char2hex(a[index])) return 0;
+			count = (16 * count) + char2hex(a[index]);
+			index = index + 1;
+		}
+	}
+	/* Deal with decimal */
+	else
+	{
+		if('-' == a[0])
+		{
+			negative = TRUE;
+			index = 1;
+		}
+		else
+		{
+			negative = FALSE;
+			index = 0;
+		}
+
+		while(0 != a[index])
+		{
+			if(-1 == char2dec(a[index])) return 0;
+			count = (10 * count) + char2dec(a[index]);
+			index = index + 1;
+		}
+	}
+
+	if(negative)
+	{
+		count = count * -1;
+	}
+	return count;
+}

+ 61 - 0
stage2/High_level_prototypes/cc_knight-native/functions/string.c

@@ -0,0 +1,61 @@
+/* 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 <http://www.gnu.org/licenses/>.
+ */
+#include<stdlib.h>
+#define MAX_STRING 4096
+//CONSTANT MAX_STRING 4096
+// void* calloc(int count, int size);
+
+char* copy_string(char* target, char* source)
+{
+	while(0 != source[0])
+	{
+		target[0] = source[0];
+		target = target + 1;
+		source = source + 1;
+	}
+	return target;
+}
+
+char* postpend_char(char* s, char a)
+{
+	char* ret = calloc(MAX_STRING, sizeof(char));
+	char* hold = copy_string(ret, s);
+	hold[0] = a;
+	return ret;
+}
+
+char* prepend_char(char a, char* s)
+{
+	char* ret = calloc(MAX_STRING, sizeof(char));
+	ret[0] = a;
+	copy_string((ret+1), s);
+	return ret;
+}
+
+char* prepend_string(char* add, char* base)
+{
+	char* ret = calloc(MAX_STRING, sizeof(char));
+	copy_string(copy_string(ret, add), base);
+	return ret;
+}
+
+int string_length(char* a)
+{
+	int i = 0;
+	while(0 != a[i]) i = i + 1;
+	return i;
+}

+ 21 - 0
stage2/High_level_prototypes/cc_knight-native/gcc_req.h

@@ -0,0 +1,21 @@
+/* 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 <http://www.gnu.org/licenses/>.
+ */
+
+// Exists only because gcc doesn't support naked Function pointers
+// And thus adds just enough support that M2-Plant can leverage the feature
+// in its self-host
+typedef void (*FUNCTION) ();

+ 40 - 0
stage2/High_level_prototypes/cc_knight-native/makefile

@@ -0,0 +1,40 @@
+## 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 <http://www.gnu.org/licenses/>.
+
+
+all: cc_knight-native
+
+CC?=gcc
+CFLAGS=-D_GNU_SOURCE -O0 -std=c99 -ggdb
+
+cc_knight-native: cc_reader.c cc_strings.c cc_core.c cc.c cc_types.c cc.h
+	$(CC) $(CFLAGS) \
+	functions/match.c \
+	functions/numerate_number.c \
+	functions/number_pack.c \
+	functions/file_print.c \
+	functions/string.c \
+	cc_reader.c \
+	cc_strings.c \
+	cc_types.c \
+	cc_core.c \
+	cc.c \
+	cc.h \
+	gcc_req.h \
+	-o cc_knight-native
+
+clean: cc_knight-native
+	rm -f cc_knight-native

+ 18 - 16
stage2/High_level_prototypes/cc_x86/cc_core.c

@@ -37,6 +37,7 @@ char* break_target_num;
 struct token_list* break_frame;
 int current_count;
 struct type* last_type;
+int Address_of;
 
 /* Imported functions */
 char* parse_string(char* string);
@@ -44,8 +45,6 @@ int escape_lookup(char* c);
 char* numerate_number(int a);
 
 
-
-
 struct token_list* emit(char *s, struct token_list* head)
 {
 	struct token_list* t = calloc(1, sizeof(struct token_list));
@@ -179,8 +178,9 @@ void variable_load(struct token_list* a)
 	emit_out("LOAD_BASE_ADDRESS_eax %");
 	emit_out(numerate_number(a->depth));
 	emit_out("\n");
+
+	if(TRUE == Address_of) return;
 	if(match("=", global_token->s)) return;
-	if(match("char**", a->type->name)) return;
 
 	emit_out("LOAD_INTEGER\n");
 }
@@ -388,7 +388,7 @@ void postfix_expr_arrow()
 		emit_out("\nADD_ebx_to_eax\n");
 	}
 
-	if(!match("=", global_token->s) && !match("char**", current_target->name))
+	if(!match("=", global_token->s) && (4 == i->size))
 	{
 		emit_out("LOAD_INTEGER\n");
 	}
@@ -553,6 +553,16 @@ void bitwise_expr()
 
 void primary_expr()
 {
+	if(match("&", global_token->s))
+	{
+		Address_of = TRUE;
+		global_token = global_token->next;
+	}
+	else
+	{
+		Address_of = FALSE;
+	}
+
 	if(match("sizeof", global_token->s)) unary_expr_sizeof();
 	else if('-' == global_token->s[0])
 	{
@@ -608,7 +618,7 @@ void collect_local()
 	struct token_list* a = sym_declare(global_token->s, type_size, function->locals);
 	if(match("main", function->s) && (NULL == function->locals))
 	{
-		a->depth = -4;
+		a->depth = -20;
 	}
 	else if((NULL == function->arguments) && (NULL == function->locals))
 	{
@@ -1004,12 +1014,7 @@ void collect_arguments()
 		{
 			/* deal with foo(int a, char b) */
 			struct token_list* a = sym_declare(global_token->s, type_size, function->arguments);
-			if(match("main", function->s))
-			{
-				if(match("argc", a->s)) a->depth = 4;
-				if(match("argv", a->s)) a->depth = 8;
-			}
-			else if(NULL == function->arguments)
+			if(NULL == function->arguments)
 			{
 				a->depth = -4;
 			}
@@ -1047,10 +1052,6 @@ void declare_function()
 		emit_out(":FUNCTION_");
 		emit_out(function->s);
 		emit_out("\n");
-		if(match("main", function->s))
-		{
-			emit_out("COPY_esp_to_ebp\t# Deal with special case\n");
-		}
 		statement();
 
 		/* Prevent duplicate RETURNS */
@@ -1081,6 +1082,7 @@ void declare_function()
  */
 struct token_list* program()
 {
+	Address_of = FALSE;
 	out = NULL;
 	function = NULL;
 	struct type* type_size;
@@ -1109,7 +1111,7 @@ new_type:
 			/* Ensure 4 bytes are allocated for the global */
 			globals_list = emit(":GLOBAL_", globals_list);
 			globals_list = emit(global_token->prev->s, globals_list);
-			globals_list = emit("\nNOP\n", globals_list);
+			globals_list = emit("\nNULL\n", globals_list);
 
 			global_token = global_token->next;
 		}

+ 1 - 1
stage2/High_level_prototypes/cc_x86/makefile

@@ -15,7 +15,7 @@
 ## along with stage0.  If not, see <http://www.gnu.org/licenses/>.
 
 
-all: M2-Planet
+all: cc_x86
 
 CC?=gcc
 CFLAGS=-D_GNU_SOURCE -O0 -std=c99 -ggdb

+ 7 - 3
stage2/cc_x86.s

@@ -62,6 +62,8 @@
 	CALLI R15 @file_print       ; Write string
 	MOVE R0 R11                 ; using Contents of strings_list
 	CALLI R15 @recursive_output ; Recursively write
+	LOADUI R0 $header_string4   ; Using our final header string
+	CALLI R15 @file_print       ; Write string
 	HALT                        ; We have completed compiling our input
 
 ;; Symbol lists
@@ -83,8 +85,6 @@
 "
 :header_string2
 	"
-:ELF_data
-
 # Program global variables
 "
 
@@ -93,6 +93,10 @@
 # Program strings
 "
 
+:header_string4
+	"
+:ELF_end
+"
 
 ;; clearWhiteSpace function
 ;; Receives a character in R0 and FILE* in R1 and line_num in R11
@@ -3245,7 +3249,7 @@ Missing ;
 	":GLOBAL_"
 :program_string1
 	"
-NOP
+NULL
 "
 :program_string2
 	"Received "

+ 1 - 1
test/SHA256SUMS

@@ -1,5 +1,5 @@
 695698ebc7ed1d3acbcded1bd832a6b49b9a7c2a37c216a9fccdc0e89e976e99  roms/CAT
-d04462af441ec9c2d23080b654b4cc30f34cc27b09669146db02be7652ffdf81  roms/cc_x86
+1b44b454b8e7beab41ecc4fb81220ef0a396bfeb954a3589861b6807dea0c313  roms/cc_x86
 662b14485df5da61c3f5ad63151932985914b2fe074c21798e20ba2d83b45ecc  roms/DEHEX
 f4bbf9e9c4828170d0c153ac265382dc705643f95efd2a029243326d426be5a4  roms/forth
 96ade767f30e3d9037a6c597cefb103942c8ec104264a3551017f091b10646e1  roms/lisp