#!/bin/bash
#
# Shell script used to build the OSL Portable Core.
#
## zsh would have been better, for it has arrays. But bash will do,
## with the help of cut. That's more portable (I hope).
#
## We use bash for integer arithmetics and more
## If you really don't have bash, you should use expr intead of $[ ] 's
#


################### FUNCTION FOR INTERACTIVE USE ONLY ####################

function srcfiles () {
  echo */*.[hc] *.[hc] *.mc build.sh README* INTERNALS TODO Makefile
}

function test () {
  echo
  ./oslpcore "$@" 2>err
  echo
}

function view_error () {
  exec $PAGER err
}


###################### OBJECT FILE BUILDER ROUTINES #########################

function meta_c () {
  #set -x #set debugging on

  ### Initialize file names according to arguments ###
	BASENAME=$(basename $1 .mc)
	MC_FILE=$BASENAME.mc
	CO1=$BASENAME.co1
	CO2=$BASENAME.co2
	HO1=$BASENAME.ho1
	HO2=$BASENAME.ho2

	# CO1 is where the array of enum->code goes
	# CO2 is where the actual code goes
	# HO1 is where the enum declaration goes
	# HO2 is where the prototypes & user defined stuff go

  ### execute given meta_c file as a shell script ###
	source $MC_FILE
}

################# USEFUL SUBROUTINES FOR OBJECT FILE BUILDER ###############
function TMPFILE () {
  for i ; do
    t=/tmp/_$$.$i	# should be unique
    echo -n > $t	# truncate file
    eval "$i=$t"
    #eval echo \$$i
  done
}


HO1 () {
  for i ; do
    echo "$i" >> $HO1
  done
}
CO1 () {
  for i ; do
    echo "$i" >> $CO1
  done
}
HO2 () {
  for i ; do
    echo "$i" >> $HO2
  done
}
CO2 () {
  for i ; do
    echo "$i" >> $CO2
  done
}

LITERAL () {
  CO2 "$@"
}

INSTR () {
# $1 C-able identifier
# $2 Usual forth identifier
# $3 Comment
# $4 implementation code
  HO1 "$ENUM$1,	/* $3 */"
  HO2 "$CODERET $CODE$1 $CODEARGS ;  /* $3 */"
  CO1 "{ $CODE$1, \"$1\", \"$2\"	/* $3 */ },"
  CO2 "$CODERET $CODE$1 $CODEARGS	/* $3 */$4"
}


_push_ () {
  eval "$1=\"\$$2:\$$1\""
}

_pop_ () {
  eval "$2=\"\`echo \$$1|cut -d: -f1 \`\""
  eval "$1=\"\`echo \$$1|cut -d: -f2-\`\""
}

_push_local () {
  _push_ localstack "$*"
}
_pop_local () {
  _pop_ localstack "$*"
}

increment () {
  eval "$1="'$[$'"$1+${2:-1}"']'
}

localdef () {
  increment local $1
}

localref () {
  echo -n "__local__$[$dynlocal+${2:-0}]"
}


putinstr () {
  echo "${1}," >> $CO1
  increment org
}
Immediate () {
  putinstr "${1}"	# could be different in a char-aligned impl.
}

Assemble () {
  case "x${1}" in

    ### Comments ###
	x|x/*)	;;

    ### Macro definition ###
	x:)	text="_mc_macro_${2} () { : "
		while read i a z &&
		  case "$i" in
		    \;) text="$text ; }" ; false ;;
		    \;*) text="$text ; "'
			'"Assemble \"`echo $i | cut -c2-`\" \"$a\" \"$z\" }" ;;
		    *)  text="$text ; Assemble \"$i\" \"$a\" \"$z\"" ;;
		  esac
		do : everything is in the "while" condition statement
		done
		eval $text
		;;
    ### Macro call ###
	x\$*)	macro=`echo ${1} | cut -f2 -d\$`
		shift
		_push_local dynlocal
		dynlocal=$local
		"_mc_macro_${macro}" "$@"
		_pop_local dynlocal
		;;

    ### Assembler with shell expansion ###
	x\!\!*)	eval Assemble `echo $* | cut -f3- -d\!` ;;
    ### Back door to the assembler ###
	x\!*)	eval `echo $* | cut -f2- -d\!` ;;

    ### Labels ###
	x*:)	label=`echo ${1} | cut -f1 -d:`
		echo "#define ${CODE}${label} (&${code_array}[${org}])" >> $HO1
		;;

    ### Pushing Immediate values ###
	x[0-9-]*)
		putinstr "${CODE}IMM"
		Immediate ${1}
		;;
	x#[0-9-]*)
		putinstr "${CODE}IMM"
		Immediate `echo ${1} | cut -f2 -d#`
		;;
	x#*)	putinstr "${CODE}IMM"
		Immediate "${CODE}`echo $1 | cut -c2-`"
		;;

    ### Echoing a literal C value for the instruction ###
	x\*)	putinstr "(${*})"
		;;

    ### General case: instruction ###
	x*)	putinstr "${CODE}${1}"
		case "x${2}" in
		    x|x#*)	;;
		    *)		putinstr "${2}"
				;;
		esac
		;;
    esac
}

THREADED_CODE () {
  # use: THREADED_CODE threaded_core_array_name <<'END'
  code_array=$1

  org=0		# current address
  local=0	# count for locals
  dynlocal=0	# current scope for locals
  localstack=""	# empty stack for local scopes

  echo "pcore_cell $code_array [] = {" >> $CO1
  while read instr arg zap ; do
    Assemble $instr $arg $zap
  done
  echo "${CODE}End_Of_Dump };" >> $CO1
}

BEGIN_META_C () {

  ### make temporary files ###

  ### clear output files
	echo> $CO1 "/* Ouput of \`\`build.sh meta_c $MC_FILE'', do not edit */"
	echo> $CO2 "/* Ouput of \`\`build.sh meta_c $MC_FILE'', do not edit */"
	echo> $HO1 "/* Ouput of \`\`build.sh meta_c $MC_FILE'', do not edit */"
	echo> $HO2 "/* Ouput of \`\`build.sh meta_c $MC_FILE'', do not edit */"

  ### Init some variables/constants

}

END_META_C () {
  ### store the result in actual output files

	: "Creating output .h file $HO_FILE"

	: "Creating output .c file $CO_FILE"

  ### Done !
	exit
}


##################### MAIN FUNCTION OF THE SCRIPT ########################

function debug () {
  set -x
  "$@"
}

#function main () {
  "$@"
#}
