--- /dev/null	Fri Dec 21 15:00:15 2018
+++ new/usr/src/tools/smatch/src/show-parse.c	Fri Dec 21 15:00:15 2018
@@ -0,0 +1,1174 @@
+/*
+ * sparse/show-parse.c
+ *
+ * Copyright (C) 2003 Transmeta Corp.
+ *               2003-2004 Linus Torvalds
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * Print out results of parsing for debugging and testing.
+ */
+#include <stdarg.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#include "lib.h"
+#include "allocate.h"
+#include "token.h"
+#include "parse.h"
+#include "symbol.h"
+#include "scope.h"
+#include "expression.h"
+#include "target.h"
+
+static int show_symbol_expr(struct symbol *sym);
+static int show_string_expr(struct expression *expr);
+
+static void do_debug_symbol(struct symbol *sym, int indent)
+{
+	static const char indent_string[] = "                                  ";
+	static const char *typestr[] = {
+		[SYM_UNINITIALIZED] = "none",
+		[SYM_PREPROCESSOR] = "cpp.",
+		[SYM_BASETYPE] = "base",
+		[SYM_NODE] = "node",
+		[SYM_PTR] = "ptr.",
+		[SYM_FN] = "fn..",
+		[SYM_ARRAY] = "arry",
+		[SYM_STRUCT] = "strt",
+		[SYM_UNION] = "unin",
+		[SYM_ENUM] = "enum",
+		[SYM_TYPEDEF] = "tdef",
+		[SYM_TYPEOF] = "tpof",
+		[SYM_MEMBER] = "memb",
+		[SYM_BITFIELD] = "bitf",
+		[SYM_LABEL] = "labl",
+		[SYM_RESTRICT] = "rstr",
+		[SYM_FOULED] = "foul",
+		[SYM_BAD] = "bad.",
+	};
+	struct context *context;
+	int i;
+
+	if (!sym)
+		return;
+	fprintf(stderr, "%.*s%s%3d:%lu %s %s (as: %d) %p (%s:%d:%d) %s\n",
+		indent, indent_string, typestr[sym->type],
+		sym->bit_size, sym->ctype.alignment,
+		modifier_string(sym->ctype.modifiers), show_ident(sym->ident), sym->ctype.as,
+		sym, stream_name(sym->pos.stream), sym->pos.line, sym->pos.pos,
+		builtin_typename(sym) ?: "");
+	i = 0;
+	FOR_EACH_PTR(sym->ctype.contexts, context) {
+		/* FIXME: should print context expression */
+		fprintf(stderr, "< context%d: in=%d, out=%d\n",
+			i, context->in, context->out);
+		fprintf(stderr, "  end context%d >\n", i);
+		i++;
+	} END_FOR_EACH_PTR(context);
+	if (sym->type == SYM_FN) {
+		struct symbol *arg;
+		i = 0;
+		FOR_EACH_PTR(sym->arguments, arg) {
+			fprintf(stderr, "< arg%d:\n", i);
+			do_debug_symbol(arg, 0);
+			fprintf(stderr, "  end arg%d >\n", i);
+			i++;
+		} END_FOR_EACH_PTR(arg);
+	}
+	do_debug_symbol(sym->ctype.base_type, indent+2);
+}
+
+void debug_symbol(struct symbol *sym)
+{
+	do_debug_symbol(sym, 0);
+}
+
+/*
+ * Symbol type printout. The type system is by far the most
+ * complicated part of C - everything else is trivial.
+ */
+const char *modifier_string(unsigned long mod)
+{
+	static char buffer[100];
+	int len = 0;
+	int i;
+	struct mod_name {
+		unsigned long mod;
+		const char *name;
+	} *m;
+
+	static struct mod_name mod_names[] = {
+		{MOD_AUTO,		"auto"},
+		{MOD_REGISTER,		"register"},
+		{MOD_STATIC,		"static"},
+		{MOD_EXTERN,		"extern"},
+		{MOD_CONST,		"const"},
+		{MOD_VOLATILE,		"volatile"},
+		{MOD_SIGNED,		"[signed]"},
+		{MOD_UNSIGNED,		"[unsigned]"},
+		{MOD_CHAR,		"[char]"},
+		{MOD_SHORT,		"[short]"},
+		{MOD_LONG,		"[long]"},
+		{MOD_LONGLONG,		"[long long]"},
+		{MOD_LONGLONGLONG,	"[long long long]"},
+		{MOD_TYPEDEF,		"[typedef]"},
+		{MOD_TLS,		"[tls]"},
+		{MOD_INLINE,		"inline"},
+		{MOD_ADDRESSABLE,	"[addressable]"},
+		{MOD_NOCAST,		"[nocast]"},
+		{MOD_NODEREF,		"[noderef]"},
+		{MOD_ACCESSED,		"[accessed]"},
+		{MOD_TOPLEVEL,		"[toplevel]"},
+		{MOD_ASSIGNED,		"[assigned]"},
+		{MOD_TYPE,		"[type]"},
+		{MOD_SAFE,		"[safe]"},
+		{MOD_USERTYPE,		"[usertype]"},
+		{MOD_NORETURN,		"[noreturn]"},
+		{MOD_EXPLICITLY_SIGNED,	"[explicitly-signed]"},
+		{MOD_BITWISE,		"[bitwise]"},
+		{MOD_PURE,		"[pure]"},
+	};
+
+	for (i = 0; i < ARRAY_SIZE(mod_names); i++) {
+		m = mod_names + i;
+		if (mod & m->mod) {
+			char c;
+			const char *name = m->name;
+			while ((c = *name++) != '\0' && len + 2 < sizeof buffer)
+				buffer[len++] = c;
+			buffer[len++] = ' ';
+		}
+	}
+	buffer[len] = 0;
+	return buffer;
+}
+
+static void show_struct_member(struct symbol *sym)
+{
+	printf("\t%s:%d:%ld at offset %ld.%d", show_ident(sym->ident), sym->bit_size, sym->ctype.alignment, sym->offset, sym->bit_offset);
+	printf("\n");
+}
+
+void show_symbol_list(struct symbol_list *list, const char *sep)
+{
+	struct symbol *sym;
+	const char *prepend = "";
+
+	FOR_EACH_PTR(list, sym) {
+		puts(prepend);
+		prepend = ", ";
+		show_symbol(sym);
+	} END_FOR_EACH_PTR(sym);
+}
+
+struct type_name {
+	char *start;
+	char *end;
+};
+
+static void FORMAT_ATTR(2) prepend(struct type_name *name, const char *fmt, ...)
+{
+	static char buffer[512];
+	int n;
+
+	va_list args;
+	va_start(args, fmt);
+	n = vsprintf(buffer, fmt, args);
+	va_end(args);
+
+	name->start -= n;
+	memcpy(name->start, buffer, n);
+}
+
+static void FORMAT_ATTR(2) append(struct type_name *name, const char *fmt, ...)
+{
+	static char buffer[512];
+	int n;
+
+	va_list args;
+	va_start(args, fmt);
+	n = vsprintf(buffer, fmt, args);
+	va_end(args);
+
+	memcpy(name->end, buffer, n);
+	name->end += n;
+}
+
+static struct ctype_name {
+	struct symbol *sym;
+	const char *name;
+} typenames[] = {
+	{ & char_ctype,  "char" },
+	{ &schar_ctype,  "signed char" },
+	{ &uchar_ctype,  "unsigned char" },
+	{ & short_ctype, "short" },
+	{ &sshort_ctype, "signed short" },
+	{ &ushort_ctype, "unsigned short" },
+	{ & int_ctype,   "int" },
+	{ &sint_ctype,   "signed int" },
+	{ &uint_ctype,   "unsigned int" },
+	{ &slong_ctype,  "signed long" },
+	{ & long_ctype,  "long" },
+	{ &ulong_ctype,  "unsigned long" },
+	{ & llong_ctype, "long long" },
+	{ &sllong_ctype, "signed long long" },
+	{ &ullong_ctype, "unsigned long long" },
+	{ & lllong_ctype, "long long long" },
+	{ &slllong_ctype, "signed long long long" },
+	{ &ulllong_ctype, "unsigned long long long" },
+
+	{ &void_ctype,   "void" },
+	{ &bool_ctype,   "bool" },
+	{ &string_ctype, "string" },
+
+	{ &float_ctype,  "float" },
+	{ &double_ctype, "double" },
+	{ &ldouble_ctype,"long double" },
+	{ &incomplete_ctype, "incomplete type" },
+	{ &int_type, "abstract int" },
+	{ &fp_type, "abstract fp" },
+	{ &label_ctype, "label type" },
+	{ &bad_ctype, "bad type" },
+};
+
+const char *builtin_typename(struct symbol *sym)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(typenames); i++)
+		if (typenames[i].sym == sym)
+			return typenames[i].name;
+	return NULL;
+}
+
+const char *builtin_ctypename(struct ctype *ctype)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(typenames); i++)
+		if (&typenames[i].sym->ctype == ctype)
+			return typenames[i].name;
+	return NULL;
+}
+
+static void do_show_type(struct symbol *sym, struct type_name *name)
+{
+	const char *typename;
+	unsigned long mod = 0;
+	int as = 0;
+	int was_ptr = 0;
+	int restr = 0;
+	int fouled = 0;
+
+deeper:
+	if (!sym || (sym->type != SYM_NODE && sym->type != SYM_ARRAY &&
+		     sym->type != SYM_BITFIELD)) {
+		const char *s;
+		size_t len;
+
+		if (as)
+			prepend(name, "<asn:%d>", as);
+
+		s = modifier_string(mod);
+		len = strlen(s);
+		name->start -= len;    
+		memcpy(name->start, s, len);  
+		mod = 0;
+		as = 0;
+	}
+
+	if (!sym)
+		goto out;
+
+	if ((typename = builtin_typename(sym))) {
+		int len = strlen(typename);
+		if (name->start != name->end)
+			*--name->start = ' ';
+		name->start -= len;
+		memcpy(name->start, typename, len);
+		goto out;
+	}
+
+	/* Prepend */
+	switch (sym->type) {
+	case SYM_PTR:
+		prepend(name, "*");
+		mod = sym->ctype.modifiers;
+		as = sym->ctype.as;
+		was_ptr = 1;
+		break;
+
+	case SYM_FN:
+		if (was_ptr) {
+			prepend(name, "( ");
+			append(name, " )");
+			was_ptr = 0;
+		}
+		append(name, "( ... )");
+		break;
+
+	case SYM_STRUCT:
+		if (name->start != name->end)
+			*--name->start = ' ';
+		prepend(name, "struct %s", show_ident(sym->ident));
+		goto out;
+
+	case SYM_UNION:
+		if (name->start != name->end)
+			*--name->start = ' ';
+		prepend(name, "union %s", show_ident(sym->ident));
+		goto out;
+
+	case SYM_ENUM:
+		prepend(name, "enum %s ", show_ident(sym->ident));
+		break;
+
+	case SYM_NODE:
+		append(name, "%s", show_ident(sym->ident));
+		mod |= sym->ctype.modifiers;
+		as |= sym->ctype.as;
+		break;
+
+	case SYM_BITFIELD:
+		mod |= sym->ctype.modifiers;
+		as |= sym->ctype.as;
+		append(name, ":%d", sym->bit_size);
+		break;
+
+	case SYM_LABEL:
+		append(name, "label(%s:%p)", show_ident(sym->ident), sym);
+		return;
+
+	case SYM_ARRAY:
+		mod |= sym->ctype.modifiers;
+		as |= sym->ctype.as;
+		if (was_ptr) {
+			prepend(name, "( ");
+			append(name, " )");
+			was_ptr = 0;
+		}
+		append(name, "[%lld]", get_expression_value(sym->array_size));
+		break;
+
+	case SYM_RESTRICT:
+		if (!sym->ident) {
+			restr = 1;
+			break;
+		}
+		if (name->start != name->end)
+			*--name->start = ' ';
+		prepend(name, "restricted %s", show_ident(sym->ident));
+		goto out;
+
+	case SYM_FOULED:
+		fouled = 1;
+		break;
+
+	default:
+		if (name->start != name->end)
+			*--name->start = ' ';
+		prepend(name, "unknown type %d", sym->type);
+		goto out;
+	}
+
+	sym = sym->ctype.base_type;
+	goto deeper;
+
+out:
+	if (restr)
+		prepend(name, "restricted ");
+	if (fouled)
+		prepend(name, "fouled ");
+}
+
+void show_type(struct symbol *sym)
+{
+	char array[200];
+	struct type_name name;
+
+	name.start = name.end = array+100;
+	do_show_type(sym, &name);
+	*name.end = 0;
+	printf("%s", name.start);
+}
+
+const char *show_typename(struct symbol *sym)
+{
+	static char array[200];
+	struct type_name name;
+
+	name.start = name.end = array+100;
+	do_show_type(sym, &name);
+	*name.end = 0;
+	return name.start;
+}
+
+void show_symbol(struct symbol *sym)
+{
+	struct symbol *type;
+
+	if (!sym)
+		return;
+
+	if (sym->ctype.alignment)
+		printf(".align %ld\n", sym->ctype.alignment);
+
+	show_type(sym);
+	type = sym->ctype.base_type;
+	if (!type) {
+		printf("\n");
+		return;
+	}
+
+	/*
+	 * Show actual implementation information
+	 */
+	switch (type->type) {
+		struct symbol *member;
+
+	case SYM_STRUCT:
+	case SYM_UNION:
+		printf(" {\n");
+		FOR_EACH_PTR(type->symbol_list, member) {
+			show_struct_member(member);
+		} END_FOR_EACH_PTR(member);
+		printf("}\n");
+		break;
+
+	case SYM_FN: {
+		struct statement *stmt = type->stmt;
+		printf("\n");
+		if (stmt) {
+			int val;
+			val = show_statement(stmt);
+			if (val)
+				printf("\tmov.%d\t\tretval,%d\n", stmt->ret->bit_size, val);
+			printf("\tret\n");
+		}
+		break;
+	}
+
+	default:
+		printf("\n");
+		break;
+	}
+
+	if (sym->initializer) {
+		printf(" = \n");
+		show_expression(sym->initializer);
+	}
+}
+
+static int show_symbol_init(struct symbol *sym);
+
+static int new_pseudo(void)
+{
+	static int nr = 0;
+	return ++nr;
+}
+
+static int new_label(void)
+{
+	static int label = 0;
+	return ++label;
+}
+
+static void show_switch_statement(struct statement *stmt)
+{
+	int val = show_expression(stmt->switch_expression);
+	struct symbol *sym;
+	printf("\tswitch v%d\n", val);
+
+	/*
+	 * Debugging only: Check that the case list is correct
+	 * by printing it out.
+	 *
+	 * This is where a _real_ back-end would go through the
+	 * cases to decide whether to use a lookup table or a
+	 * series of comparisons etc
+	 */
+	printf("# case table:\n");
+	FOR_EACH_PTR(stmt->switch_case->symbol_list, sym) {
+		struct statement *case_stmt = sym->stmt;
+		struct expression *expr = case_stmt->case_expression;
+		struct expression *to = case_stmt->case_to;
+
+		if (!expr) {
+			printf("    default");
+		} else {
+			if (expr->type == EXPR_VALUE) {
+				printf("    case %lld", expr->value);
+				if (to) {
+					if (to->type == EXPR_VALUE) {
+						printf(" .. %lld", to->value);
+					} else {
+						printf(" .. what?");
+					}
+				}
+			} else
+				printf("    what?");
+		}
+		printf(": .L%p\n", sym);
+	} END_FOR_EACH_PTR(sym);
+	printf("# end case table\n");
+
+	show_statement(stmt->switch_statement);
+
+	if (stmt->switch_break->used)
+		printf(".L%p:\n", stmt->switch_break);
+}
+
+static void show_symbol_decl(struct symbol_list *syms)
+{
+	struct symbol *sym;
+	FOR_EACH_PTR(syms, sym) {
+		show_symbol_init(sym);
+	} END_FOR_EACH_PTR(sym);
+}
+
+static int show_return_stmt(struct statement *stmt);
+
+/*
+ * Print out a statement
+ */
+int show_statement(struct statement *stmt)
+{
+	if (!stmt)
+		return 0;
+	switch (stmt->type) {
+	case STMT_DECLARATION:
+		show_symbol_decl(stmt->declaration);
+		return 0;
+	case STMT_RETURN:
+		return show_return_stmt(stmt);
+	case STMT_COMPOUND: {
+		struct statement *s;
+		int last = 0;
+
+		if (stmt->inline_fn) {
+			show_statement(stmt->args);
+			printf("\tbegin_inline \t%s\n", show_ident(stmt->inline_fn->ident));
+		}
+		FOR_EACH_PTR(stmt->stmts, s) {
+			last = show_statement(s);
+		} END_FOR_EACH_PTR(s);
+		if (stmt->ret) {
+			int addr, bits;
+			printf(".L%p:\n", stmt->ret);
+			addr = show_symbol_expr(stmt->ret);
+			bits = stmt->ret->bit_size;
+			last = new_pseudo();
+			printf("\tld.%d\t\tv%d,[v%d]\n", bits, last, addr);
+		}
+		if (stmt->inline_fn)
+			printf("\tend_inlined\t%s\n", show_ident(stmt->inline_fn->ident));
+		return last;
+	}
+
+	case STMT_EXPRESSION:
+		return show_expression(stmt->expression);
+	case STMT_IF: {
+		int val, target;
+		struct expression *cond = stmt->if_conditional;
+
+/* This is only valid if nobody can jump into the "dead" statement */
+#if 0
+		if (cond->type == EXPR_VALUE) {
+			struct statement *s = stmt->if_true;
+			if (!cond->value)
+				s = stmt->if_false;
+			show_statement(s);
+			break;
+		}
+#endif
+		val = show_expression(cond);
+		target = new_label();
+		printf("\tje\t\tv%d,.L%d\n", val, target);
+		show_statement(stmt->if_true);
+		if (stmt->if_false) {
+			int last = new_label();
+			printf("\tjmp\t\t.L%d\n", last);
+			printf(".L%d:\n", target);
+			target = last;
+			show_statement(stmt->if_false);
+		}
+		printf(".L%d:\n", target);
+		break;
+	}
+	case STMT_SWITCH:
+		show_switch_statement(stmt);
+		break;
+
+	case STMT_CASE:
+		printf(".L%p:\n", stmt->case_label);
+		show_statement(stmt->case_statement);
+		break;
+
+	case STMT_ITERATOR: {
+		struct statement  *pre_statement = stmt->iterator_pre_statement;
+		struct expression *pre_condition = stmt->iterator_pre_condition;
+		struct statement  *statement = stmt->iterator_statement;
+		struct statement  *post_statement = stmt->iterator_post_statement;
+		struct expression *post_condition = stmt->iterator_post_condition;
+		int val, loop_top = 0, loop_bottom = 0;
+
+		show_symbol_decl(stmt->iterator_syms);
+		show_statement(pre_statement);
+		if (pre_condition) {
+			if (pre_condition->type == EXPR_VALUE) {
+				if (!pre_condition->value) {
+					loop_bottom = new_label();   
+					printf("\tjmp\t\t.L%d\n", loop_bottom);
+				}
+			} else {
+				loop_bottom = new_label();
+				val = show_expression(pre_condition);
+				printf("\tje\t\tv%d, .L%d\n", val, loop_bottom);
+			}
+		}
+		if (!post_condition || post_condition->type != EXPR_VALUE || post_condition->value) {
+			loop_top = new_label();
+			printf(".L%d:\n", loop_top);
+		}
+		show_statement(statement);
+		if (stmt->iterator_continue->used)
+			printf(".L%p:\n", stmt->iterator_continue);
+		show_statement(post_statement);
+		if (!post_condition) {
+			printf("\tjmp\t\t.L%d\n", loop_top);
+		} else if (post_condition->type == EXPR_VALUE) {
+			if (post_condition->value)
+				printf("\tjmp\t\t.L%d\n", loop_top);
+		} else {
+			val = show_expression(post_condition);
+			printf("\tjne\t\tv%d, .L%d\n", val, loop_top);
+		}
+		if (stmt->iterator_break->used)
+			printf(".L%p:\n", stmt->iterator_break);
+		if (loop_bottom)
+			printf(".L%d:\n", loop_bottom);
+		break;
+	}
+	case STMT_NONE:
+		break;
+	
+	case STMT_LABEL:
+		printf(".L%p:\n", stmt->label_identifier);
+		show_statement(stmt->label_statement);
+		break;
+
+	case STMT_GOTO:
+		if (stmt->goto_expression) {
+			int val = show_expression(stmt->goto_expression);
+			printf("\tgoto\t\t*v%d\n", val);
+		} else {
+			printf("\tgoto\t\t.L%p\n", stmt->goto_label);
+		}
+		break;
+	case STMT_ASM:
+		printf("\tasm( .... )\n");
+		break;
+	case STMT_CONTEXT: {
+		int val = show_expression(stmt->expression);
+		printf("\tcontext( %d )\n", val);
+		break;
+	}
+	case STMT_RANGE: {
+		int val = show_expression(stmt->range_expression);
+		int low = show_expression(stmt->range_low);
+		int high = show_expression(stmt->range_high);
+		printf("\trange( %d %d-%d)\n", val, low, high); 
+		break;
+	}	
+	}
+	return 0;
+}
+
+static int show_call_expression(struct expression *expr)
+{
+	struct symbol *direct;
+	struct expression *arg, *fn;
+	int fncall, retval;
+	int framesize;
+
+	if (!expr->ctype) {
+		warning(expr->pos, "\tcall with no type!");
+		return 0;
+	}
+
+	framesize = 0;
+	FOR_EACH_PTR_REVERSE(expr->args, arg) {
+		int new = show_expression(arg);
+		int size = arg->ctype->bit_size;
+		printf("\tpush.%d\t\tv%d\n", size, new);
+		framesize += bits_to_bytes(size);
+	} END_FOR_EACH_PTR_REVERSE(arg);
+
+	fn = expr->fn;
+
+	/* Remove dereference, if any */
+	direct = NULL;
+	if (fn->type == EXPR_PREOP) {
+		if (fn->unop->type == EXPR_SYMBOL) {
+			struct symbol *sym = fn->unop->symbol;
+			if (sym->ctype.base_type->type == SYM_FN)
+				direct = sym;
+		}
+	}
+	if (direct) {
+		printf("\tcall\t\t%s\n", show_ident(direct->ident));
+	} else {
+		fncall = show_expression(fn);
+		printf("\tcall\t\t*v%d\n", fncall);
+	}
+	if (framesize)
+		printf("\tadd.%d\t\tvSP,vSP,$%d\n", bits_in_pointer, framesize);
+
+	retval = new_pseudo();
+	printf("\tmov.%d\t\tv%d,retval\n", expr->ctype->bit_size, retval);
+	return retval;
+}
+
+static int show_comma(struct expression *expr)
+{
+	show_expression(expr->left);
+	return show_expression(expr->right);
+}
+
+static int show_binop(struct expression *expr)
+{
+	int left = show_expression(expr->left);
+	int right = show_expression(expr->right);
+	int new = new_pseudo();
+	const char *opname;
+	static const char *name[] = {
+		['+'] = "add", ['-'] = "sub",
+		['*'] = "mul", ['/'] = "div",
+		['%'] = "mod", ['&'] = "and",
+		['|'] = "lor", ['^'] = "xor"
+	};
+	unsigned int op = expr->op;
+
+	opname = show_special(op);
+	if (op < ARRAY_SIZE(name))
+		opname = name[op];
+	printf("\t%s.%d\t\tv%d,v%d,v%d\n", opname,
+		expr->ctype->bit_size,
+		new, left, right);
+	return new;
+}
+
+static int show_slice(struct expression *expr)
+{
+	int target = show_expression(expr->base);
+	int new = new_pseudo();
+	printf("\tslice.%d\t\tv%d,v%d,%d\n", expr->r_nrbits, target, new, expr->r_bitpos);
+	return new;
+}
+
+static int show_regular_preop(struct expression *expr)
+{
+	int target = show_expression(expr->unop);
+	int new = new_pseudo();
+	static const char *name[] = {
+		['!'] = "nonzero", ['-'] = "neg",
+		['~'] = "not",
+	};
+	unsigned int op = expr->op;
+	const char *opname;
+
+	opname = show_special(op);
+	if (op < ARRAY_SIZE(name))
+		opname = name[op];
+	printf("\t%s.%d\t\tv%d,v%d\n", opname, expr->ctype->bit_size, new, target);
+	return new;
+}
+
+/*
+ * FIXME! Not all accesses are memory loads. We should
+ * check what kind of symbol is behind the dereference.
+ */
+static int show_address_gen(struct expression *expr)
+{
+	return show_expression(expr->unop);
+}
+
+static int show_load_gen(int bits, struct expression *expr, int addr)
+{
+	int new = new_pseudo();
+
+	printf("\tld.%d\t\tv%d,[v%d]\n", bits, new, addr);
+	return new;
+}
+
+static void show_store_gen(int bits, int value, struct expression *expr, int addr)
+{
+	/* FIXME!!! Bitfield store! */
+	printf("\tst.%d\t\tv%d,[v%d]\n", bits, value, addr);
+}
+
+static int show_assignment(struct expression *expr)
+{
+	struct expression *target = expr->left;
+	int val, addr, bits;
+
+	if (!expr->ctype)
+		return 0;
+
+	bits = expr->ctype->bit_size;
+	val = show_expression(expr->right);
+	addr = show_address_gen(target);
+	show_store_gen(bits, val, target, addr);
+	return val;
+}
+
+static int show_return_stmt(struct statement *stmt)
+{
+	struct expression *expr = stmt->ret_value;
+	struct symbol *target = stmt->ret_target;
+
+	if (expr && expr->ctype) {
+		int val = show_expression(expr);
+		int bits = expr->ctype->bit_size;
+		int addr = show_symbol_expr(target);
+		show_store_gen(bits, val, NULL, addr);
+	}
+	printf("\tret\t\t(%p)\n", target);
+	return 0;
+}
+
+static int show_initialization(struct symbol *sym, struct expression *expr)
+{
+	int val, addr, bits;
+
+	if (!expr->ctype)
+		return 0;
+
+	bits = expr->ctype->bit_size;
+	val = show_expression(expr);
+	addr = show_symbol_expr(sym);
+	// FIXME! The "target" expression is for bitfield store information.
+	// Leave it NULL, which works fine.
+	show_store_gen(bits, val, NULL, addr);
+	return 0;
+}
+
+static int show_access(struct expression *expr)
+{
+	int addr = show_address_gen(expr);
+	return show_load_gen(expr->ctype->bit_size, expr, addr);
+}
+
+static int show_inc_dec(struct expression *expr, int postop)
+{
+	int addr = show_address_gen(expr->unop);
+	int retval, new;
+	const char *opname = expr->op == SPECIAL_INCREMENT ? "add" : "sub";
+	int bits = expr->ctype->bit_size;
+
+	retval = show_load_gen(bits, expr->unop, addr);
+	new = retval;
+	if (postop)
+		new = new_pseudo();
+	printf("\t%s.%d\t\tv%d,v%d,$1\n", opname, bits, new, retval);
+	show_store_gen(bits, new, expr->unop, addr);
+	return retval;
+}	
+
+static int show_preop(struct expression *expr)
+{
+	/*
+	 * '*' is an lvalue access, and is fundamentally different
+	 * from an arithmetic operation. Maybe it should have an
+	 * expression type of its own..
+	 */
+	if (expr->op == '*')
+		return show_access(expr);
+	if (expr->op == SPECIAL_INCREMENT || expr->op == SPECIAL_DECREMENT)
+		return show_inc_dec(expr, 0);
+	return show_regular_preop(expr);
+}
+
+static int show_postop(struct expression *expr)
+{
+	return show_inc_dec(expr, 1);
+}	
+
+static int show_symbol_expr(struct symbol *sym)
+{
+	int new = new_pseudo();
+
+	if (sym->initializer && sym->initializer->type == EXPR_STRING)
+		return show_string_expr(sym->initializer);
+
+	if (sym->ctype.modifiers & (MOD_TOPLEVEL | MOD_EXTERN | MOD_STATIC)) {
+		printf("\tmovi.%d\t\tv%d,$%s\n", bits_in_pointer, new, show_ident(sym->ident));
+		return new;
+	}
+	if (sym->ctype.modifiers & MOD_ADDRESSABLE) {
+		printf("\taddi.%d\t\tv%d,vFP,$%lld\n", bits_in_pointer, new, sym->value);
+		return new;
+	}
+	printf("\taddi.%d\t\tv%d,vFP,$offsetof(%s:%p)\n", bits_in_pointer, new, show_ident(sym->ident), sym);
+	return new;
+}
+
+static int show_symbol_init(struct symbol *sym)
+{
+	struct expression *expr = sym->initializer;
+
+	if (expr) {
+		int val, addr, bits;
+
+		bits = expr->ctype->bit_size;
+		val = show_expression(expr);
+		addr = show_symbol_expr(sym);
+		show_store_gen(bits, val, NULL, addr);
+	}
+	return 0;
+}
+
+static int type_is_signed(struct symbol *sym)
+{
+	if (sym->type == SYM_NODE)
+		sym = sym->ctype.base_type;
+	if (sym->type == SYM_PTR)
+		return 0;
+	return !(sym->ctype.modifiers & MOD_UNSIGNED);
+}
+
+static int show_cast_expr(struct expression *expr)
+{
+	struct symbol *old_type, *new_type;
+	int op = show_expression(expr->cast_expression);
+	int oldbits, newbits;
+	int new, is_signed;
+
+	old_type = expr->cast_expression->ctype;
+	new_type = expr->cast_type;
+	
+	oldbits = old_type->bit_size;
+	newbits = new_type->bit_size;
+	if (oldbits >= newbits)
+		return op;
+	new = new_pseudo();
+	is_signed = type_is_signed(old_type);
+	if (is_signed) {
+		printf("\tsext%d.%d\tv%d,v%d\n", oldbits, newbits, new, op);
+	} else {
+		printf("\tandl.%d\t\tv%d,v%d,$%lu\n", newbits, new, op, (1UL << oldbits)-1);
+	}
+	return new;
+}
+
+static int show_value(struct expression *expr)
+{
+	int new = new_pseudo();
+	unsigned long long value = expr->value;
+
+	printf("\tmovi.%d\t\tv%d,$%llu\n", expr->ctype->bit_size, new, value);
+	return new;
+}
+
+static int show_fvalue(struct expression *expr)
+{
+	int new = new_pseudo();
+	long double value = expr->fvalue;
+
+	printf("\tmovf.%d\t\tv%d,$%Lf\n", expr->ctype->bit_size, new, value);
+	return new;
+}
+
+static int show_string_expr(struct expression *expr)
+{
+	int new = new_pseudo();
+
+	printf("\tmovi.%d\t\tv%d,&%s\n", bits_in_pointer, new, show_string(expr->string));
+	return new;
+}
+
+static int show_label_expr(struct expression *expr)
+{
+	int new = new_pseudo();
+	printf("\tmovi.%d\t\tv%d,.L%p\n",bits_in_pointer, new, expr->label_symbol);
+	return new;
+}
+
+static int show_conditional_expr(struct expression *expr)
+{
+	int cond = show_expression(expr->conditional);
+	int true = show_expression(expr->cond_true);
+	int false = show_expression(expr->cond_false);
+	int new = new_pseudo();
+
+	printf("[v%d]\tcmov.%d\t\tv%d,v%d,v%d\n", cond, expr->ctype->bit_size, new, true, false);
+	return new;
+}
+
+static int show_statement_expr(struct expression *expr)
+{
+	return show_statement(expr->statement);
+}
+
+static int show_position_expr(struct expression *expr, struct symbol *base)
+{
+	int new = show_expression(expr->init_expr);
+	struct symbol *ctype = expr->init_expr->ctype;
+	int bit_offset;
+
+	bit_offset = ctype ? ctype->bit_offset : -1;
+
+	printf("\tinsert v%d at [%d:%d] of %s\n", new,
+		expr->init_offset, bit_offset,
+		show_ident(base->ident));
+	return 0;
+}
+
+static int show_initializer_expr(struct expression *expr, struct symbol *ctype)
+{
+	struct expression *entry;
+
+	FOR_EACH_PTR(expr->expr_list, entry) {
+
+again:
+		// Nested initializers have their positions already
+		// recursively calculated - just output them too
+		if (entry->type == EXPR_INITIALIZER) {
+			show_initializer_expr(entry, ctype);
+			continue;
+		}
+
+		// Initializer indexes and identifiers should
+		// have been evaluated to EXPR_POS
+		if (entry->type == EXPR_IDENTIFIER) {
+			printf(" AT '%s':\n", show_ident(entry->expr_ident));
+			entry = entry->ident_expression;
+			goto again;
+		}
+			
+		if (entry->type == EXPR_INDEX) {
+			printf(" AT '%d..%d:\n", entry->idx_from, entry->idx_to);
+			entry = entry->idx_expression;
+			goto again;
+		}
+		if (entry->type == EXPR_POS) {
+			show_position_expr(entry, ctype);
+			continue;
+		}
+		show_initialization(ctype, entry);
+	} END_FOR_EACH_PTR(entry);
+	return 0;
+}
+
+int show_symbol_expr_init(struct symbol *sym)
+{
+	struct expression *expr = sym->initializer;
+
+	if (expr)
+		show_expression(expr);
+	return show_symbol_expr(sym);
+}
+
+/*
+ * Print out an expression. Return the pseudo that contains the
+ * variable.
+ */
+int show_expression(struct expression *expr)
+{
+	if (!expr)
+		return 0;
+
+	if (!expr->ctype) {
+		struct position *pos = &expr->pos;
+		printf("\tno type at %s:%d:%d\n",
+			stream_name(pos->stream),
+			pos->line, pos->pos);
+		return 0;
+	}
+		
+	switch (expr->type) {
+	case EXPR_CALL:
+		return show_call_expression(expr);
+		
+	case EXPR_ASSIGNMENT:
+		return show_assignment(expr);
+
+	case EXPR_COMMA:
+		return show_comma(expr);
+	case EXPR_BINOP:
+	case EXPR_COMPARE:
+	case EXPR_LOGICAL:
+		return show_binop(expr);
+	case EXPR_PREOP:
+		return show_preop(expr);
+	case EXPR_POSTOP:
+		return show_postop(expr);
+	case EXPR_SYMBOL:
+		return show_symbol_expr(expr->symbol);
+	case EXPR_DEREF:
+	case EXPR_SIZEOF:
+	case EXPR_PTRSIZEOF:
+	case EXPR_ALIGNOF:
+	case EXPR_OFFSETOF:
+		warning(expr->pos, "invalid expression after evaluation");
+		return 0;
+	case EXPR_CAST:
+	case EXPR_FORCE_CAST:
+	case EXPR_IMPLIED_CAST:
+		return show_cast_expr(expr);
+	case EXPR_VALUE:
+		return show_value(expr);
+	case EXPR_FVALUE:
+		return show_fvalue(expr);
+	case EXPR_STRING:
+		return show_string_expr(expr);
+	case EXPR_INITIALIZER:
+		return show_initializer_expr(expr, expr->ctype);
+	case EXPR_SELECT:
+	case EXPR_CONDITIONAL:
+		return show_conditional_expr(expr);
+	case EXPR_STATEMENT:
+		return show_statement_expr(expr);
+	case EXPR_LABEL:
+		return show_label_expr(expr);
+	case EXPR_SLICE:
+		return show_slice(expr);
+
+	// None of these should exist as direct expressions: they are only
+	// valid as sub-expressions of initializers.
+	case EXPR_POS:
+		warning(expr->pos, "unable to show plain initializer position expression");
+		return 0;
+	case EXPR_IDENTIFIER:
+		warning(expr->pos, "unable to show identifier expression");
+		return 0;
+	case EXPR_INDEX:
+		warning(expr->pos, "unable to show index expression");
+		return 0;
+	case EXPR_TYPE:
+		warning(expr->pos, "unable to show type expression");
+		return 0;
+	}
+	return 0;
+}
