#
# Copyright 2013-2014 Yuichiro Moriguchi
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
putlicense_cstyle.sh

[ -z "$PACKAGE" ] || echo "package $PACKAGE;"
[ -z "$EXTENDS" ] || [ -z "$IMPLEMENTS" ] || cln=':'
print_imports
cat definition

if [ -z "$TYPE" ]
then
  nullsym='-1'
  [ -z "$NEWLINEMODE" ] && streamsym='System.IO.TextReader'
  [ -z "$NEWLINEMODE" ] || streamsym='System.IO.Stream'
  [ -z "$NEWLINEMODE" ] && readfn='Read'
  [ -z "$NEWLINEMODE" ] || readfn='ReadByte'
  rdt='System.IO.TextReader'
else
  nullsym='null'
  rdt="System.Collections.IEnumerable"
  streamsym='System.Collections.IEnumerator'
fi

awk '{ printf("/// %s\n", $0) }' description
cat << EOF
public $ABSTRACT class ${CLASSNAME}${TEMPLATE} $cln $EXTENDS $IMPLEMENTS
{

	/* @@@-PARSER-CODE-START-@@@ */
	const int N  = 0x1000;
	const int E  = 0x0100;
	const int W  = 0x0010;
	const int S  = 0x0001;
	const int L  = W;
	const int R  = E;
	const int NE = N | E;
	const int NW = N | W;
	const int SE = S | E;
	const int SW = S | W;
	const int INITIAL = 0;

	private ${CLASSNAME}${TEMPLATE} __this__;
	private int STATE;
EOF

case "$TAPETYPE" in
DFA)
  if [ -z "$TYPE" ]
  then
    cat << EOF
	private $streamsym reader;
	private $CTYPE now = $nullsym;

	${CLASSNAME}${TEMPLATE}($streamsym rd)
	{
		reader = rd;
		now = rd.${readfn}();
		__this__ = this;
	}

	$CTYPE _getnow()
	{
		return reader.Read();
	}
EOF
  else
    cat << EOF
	private System.Collections.IEnumerator reader;
	private $CTYPE now = $nullsym;

	${CLASSNAME}${TEMPLATE}(System.Collections.IEnumerator rd)
	{
		reader = rd;
		now = rd.MoveNext() ? rd.Current : $nullsym;
		__this__ = this;
	}

	$CTYPE _getnow()
	{
		return reader.MoveNext() ? reader.Current : $nullsym;
	}
EOF
  fi
  cat << EOF

	$CTYPE _readtape()
	{
		return now;
	}

	void _writetape($CTYPE o)
	{
		now = o;
	}

	void _movetape(int direction)
	{
		switch(direction)
		{
		case E:
			if(now != $nullsym)  now = _getnow();
			return;
		default:  throw new System.Exception();
		}
	}
EOF
  ;;
*)
  if [ -z "$TYPE" ]
  then
    cat << EOF
	private $CTYPE[] _tape;
	private int _tapeptr = 0;

	${CLASSNAME}${TEMPLATE}($streamsym rd)
	{
		$CTYPE[] a = new $CTYPE[100], b;
		int p = 0;
		$CTYPE c;

		while((c = rd.${readfn}()) >= 0)
		{
			if(p >= a.Length)
			{
				b = a;
				a = new $CTYPE[a.Length * 2];
				System.Array.Copy(b, 0, a, 0, b.Length);
			}
			a[p++] = c;
		}
		b = a;
		a = new $CTYPE[p];
		System.Array.Copy(b, 0, a, 0, p);
		_tape = a;
		_tapeptr = 0;
		__this__ = this;
	}
EOF
  else
    cat << EOF
	private $CTYPE[] _tape;
	private int _tapeptr = 0;

	${CLASSNAME}${TEMPLATE}(System.Collections.IEnumerator rd)
	{
		$CTYPE[] a = new $CTYPE[100], b;
		int p = 0;

		while(rd.MoveNext())
		{
			if(p >= a.Length)
			{
				b = a;
				a = new $CTYPE[a.Length * 2];
				System.Array.Copy(b, 0, a, 0, b.Length);
			}
			a[p++] = rd.Current;
		}
		b = a;
		a = new $CTYPE[p];
		System.Array.Copy(b, 0, a, 0, p);
		_tape = a;
		_tapeptr = 0;
		__this__ = this;
	}
EOF
  fi
  cat << EOF

	$CTYPE _readtape()
	{
		if(_tapeptr < 0 || _tapeptr >= _tape.Length)
		{
			return $nullsym;
		}
		return _tape[_tapeptr];
	}

	void _writetape($CTYPE o)
	{
		if(_tapeptr >= 0 && _tapeptr < _tape.Length)
		{
			_tape[_tapeptr] = o;
		}
	}

	void _movetape(int direction)
	{
		switch(direction)
		{
		case E:
			_tapeptr += _tapeptr < _tape.Length ? 1 : 0;
			return;
		case W:
			_tapeptr -= _tapeptr >= 0 ? 1 : 0;
			return;
		default:  throw new System.Exception();
		}
	}
EOF
  ;;
esac

cat field
c='$c'
echo
cat << EOF
	private int _step($CTYPE __c__)
	{
		switch(STATE)
		{
EOF
print_states
cat << EOF
		}
		return 0;
	}

	private bool _accepted()
	{
EOF
print_accepts
cat << EOF
	}

	private int _execaction($CTYPE __c__)
	{
		switch(STATE)
		{
EOF
print_actions
cat << EOF
		}
		return 1;
	}

	private bool _execstep()
	{
		if(_step(_readtape()) != 0)
		{
			return false;
		}
		else if(_accepted())
		{
			return true;
		}
		else
		{
			throw new System.Exception();
		}
	}

	void Run()
	{
		do
		{
			_execaction(_readtape());
		}
		while(!_execstep());
	}

	static void Parse($streamsym rd)
	{
		${CLASSNAME}${TEMPLATE} r;

		r = new ${CLASSNAME}${TEMPLATE}(rd);
		r.Run();
	}

EOF
[ -z "$TYPE" ] && [ -z "$NEWLINEMODE" ] && cat << EOF
	static void Parse(System.IO.Stream rd)
	{
		Parse(new System.IO.StreamReader(rd));
	}

EOF
echo '	/* @@@-PARSER-CODE-END-@@@ */'

cat fragment
echo '}'
