Initial Contribution
diff --git a/sh/mknodes.sh b/sh/mknodes.sh
new file mode 100644
index 0000000..54d2e3d
--- /dev/null
+++ b/sh/mknodes.sh
@@ -0,0 +1,217 @@
+#! /bin/sh
+#	$NetBSD: mknodes.sh,v 1.1 2004/01/16 23:24:38 dsl Exp $
+
+# Copyright (c) 2003 The NetBSD Foundation, Inc.
+# All rights reserved.
+#
+# This code is derived from software contributed to The NetBSD Foundation
+# by David Laight.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+#    notice, this list of conditions and the following disclaimer in the
+#    documentation and/or other materials provided with the distribution.
+# 3. Neither the name of The NetBSD Foundation nor the names of its
+#    contributors may be used to endorse or promote products derived
+#    from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+# PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+
+nodetypes=$1
+nodes_pat=$2
+objdir="$3"
+
+exec <$nodetypes
+exec >$objdir/nodes.h.tmp
+
+echo "/*"
+echo " * This file was generated by mknodes.sh"
+echo " */"
+echo
+
+tagno=0
+while IFS=; read -r line; do
+	line="${line%%#*}"
+	IFS=' 	'
+	set -- $line
+	IFS=
+	[ -z "$2" ] && continue
+	case "$line" in
+	[" 	"]* )
+		IFS=' '
+		[ $field = 0 ] && struct_list="$struct_list $struct"
+		eval field_${struct}_$field=\"\$*\"
+		eval numfld_$struct=\$field
+		field=$(($field + 1))
+		;;
+	* )
+		define=$1
+		struct=$2
+		echo "#define $define $tagno"
+		tagno=$(($tagno + 1))
+		eval define_$struct=\"\$define_$struct \$define\"
+		struct_define="$struct_define $struct"
+		field=0
+		;;
+	esac
+done
+
+echo
+
+IFS=' '
+for struct in $struct_list; do
+	echo
+	echo
+	echo "struct $struct {"
+	field=0
+	while
+		eval line=\"\$field_${struct}_$field\"
+		field=$(($field + 1))
+		[ -n "$line" ]
+	do
+		IFS=' '
+		set -- $line
+		name=$1
+		case $2 in
+		nodeptr ) type="union node *";;
+		nodelist ) type="struct nodelist *";;
+		string ) type="char *";;
+		int ) type="int ";;
+		* ) name=; shift 2; type="$*";;
+		esac
+		echo "      $type$name;"
+	done
+	echo "};"
+done
+
+echo
+echo
+echo "union node {"
+echo "      int type;"
+for struct in $struct_list; do
+	echo "      struct $struct $struct;"
+done
+echo "};"
+echo
+echo
+echo "struct nodelist {"
+echo "	struct nodelist *next;"
+echo "	union node *n;"
+echo "};"
+echo
+echo
+echo "union node *copyfunc(union node *);"
+echo "void freefunc(union node *);"
+
+mv $objdir/nodes.h.tmp $objdir/nodes.h || exit 1
+
+exec <$nodes_pat
+exec >$objdir/nodes.c.tmp
+
+echo "/*"
+echo " * This file was generated by mknodes.sh"
+echo " */"
+echo
+
+while IFS=; read -r line; do
+	IFS=' 	'
+	set -- $line
+	IFS=
+	case "$1" in
+	'%SIZES' )
+		echo "static const short nodesize[$tagno] = {"
+		IFS=' '
+		for struct in $struct_define; do
+			echo "      SHELL_ALIGN(sizeof (struct $struct)),"
+		done
+		echo "};"
+		;;
+	'%CALCSIZE' )
+		echo "      if (n == NULL)"
+		echo "	    return;"
+		echo "      funcblocksize += nodesize[n->type];"
+		echo "      switch (n->type) {"
+		IFS=' '
+		for struct in $struct_list; do
+			eval defines=\"\$define_$struct\"
+			for define in $defines; do
+				echo "      case $define:"
+			done
+			eval field=\$numfld_$struct
+			while
+				[ $field != 0 ]
+			do
+				eval line=\"\$field_${struct}_$field\"
+				field=$(($field - 1))
+				IFS=' '
+				set -- $line
+				name=$1
+				cl=")"
+				case $2 in
+				nodeptr ) fn=calcsize;;
+				nodelist ) fn=sizenodelist;;
+				string ) fn="funcstringsize += strlen"
+					cl=") + 1";;
+				* ) continue;;
+				esac
+				echo "	    ${fn}(n->$struct.$name${cl};"
+			done
+			echo "	    break;"
+		done
+		echo "      };"
+		;;
+	'%COPY' )
+		echo "      if (n == NULL)"
+		echo "	    return NULL;"
+		echo "      new = funcblock;"
+		echo "      funcblock = (char *) funcblock + nodesize[n->type];"
+		echo "      switch (n->type) {"
+		IFS=' '
+		for struct in $struct_list; do
+			eval defines=\"\$define_$struct\"
+			for define in $defines; do
+				echo "      case $define:"
+			done
+			eval field=\$numfld_$struct
+			while
+				[ $field != 0 ]
+			do
+				eval line=\"\$field_${struct}_$field\"
+				field=$(($field - 1))
+				IFS=' '
+				set -- $line
+				name=$1
+				case $2 in
+				nodeptr ) fn="copynode(";;
+				nodelist ) fn="copynodelist(";;
+				string ) fn="nodesavestr(";;
+				int ) fn=;;
+				* ) continue;;
+				esac
+				f="$struct.$name"
+				echo "	    new->$f = ${fn}n->$f${fn:+)};"
+			done
+			echo "	    break;"
+		done
+		echo "      };"
+		echo "      new->type = n->type;"
+		;;
+	* ) echo "$line";;
+	esac
+done
+
+mv $objdir/nodes.c.tmp $objdir/nodes.c || exit 1