#! /bin/jsh
#
# 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 "namespace $PACKAGE"
[ -z "$PACKAGE" ] || echo "{"
[ -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'
elif [ -z "$LTYPE" ]
then
  nullsym='null'
  nullsyml='-1'
  [ -z "$NEWLINEMODE" ] && streamsym='System.IO.TextReader'
  [ -z "$NEWLINEMODE" ] || streamsym='System.IO.Stream'
  [ -z "$NEWLINEMODE" ] && readfn='Read'
  [ -z "$NEWLINEMODE" ] || readfn='ReadByte'
else
  nullsym='null'
  nullsyml='null'
  streamsym='System.Collections.IEnumerator'
fi
sq="'"

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

	/* @@@-PARSER-CODE-START-@@@ */
	class TokenException : System.Exception
	{
	}

	interface Engine
	{
		int Step($streamsym __rd, $CTYPE c) $tre;
		bool Accepted();
		bool Dead();
		bool EmptyTransition();
		int Execaction($CTYPE c);
		bool Isend();
		int Recover(System.Exception e);
		int DeadState();
		int StateSize();
		int FinallyState();
	}
EOF

[ -n "$ENABLE_BACKTRACK" ] && cat << EOF

	class Continuation
	{

		private int STATE;
		private int[] __sts;
		private Engine[] __stk;
		private Object[][] __stv;

		Continuation(int s, int[] sts, Engine[] stk, object[][] stv,
				int len)
		{
			STATE = s;
			__sts = new int[len];
			__stk = new Engine[len];
			__stv = new object[len][];
			System.Array.Copy(sts, __sts, len);
			System.Array.Copy(stk, __stk, len);
			System.Array.Copy(stv, __stv, len);
		}

	}
EOF

[ -z "$TYPE" ] && echo '	private const int Invalidtoken = 0x7fff7fff;'
[ -z "$TYPE" ] || echo '	private static readonly object Invalidtoken = new {};'
cat << EOF
	readonly ${CLASSNAME}${TEMPLATE} __this__;
	private const int NinaEOF = -1;
	private const int NinaAccept = -1;
	private const int NinaFail = -9;
	private const int NinaHaltAccept = -91;
	private const int NinaHaltReject = -72;
	private const int NinaYield = -85;
	private const int NinaBegin = -2;
	private const int NinaStacklen = 72;
	private const int NinaDiscardstate = 0x40000000;
	const int INITIAL = 0;
	const int INDENT = 1;

	private int STATE;
	private int[] __sts = new int[NinaStacklen];
	private Engine[] __stk = new Engine[NinaStacklen];
	private object[][] __stv = new object[NinaStacklen][];
	private int __slen = 0;
	private $CTYPE unread = $nullsym;

	$VALTYPE _;
	System.Collections.Generic.List<$VALTYPE> _l;
	object yieldObject;
	$streamsym befstream = null;
	System.Exception exception;

	System.Text.StringBuilder _buffer;
	System.Text.StringBuilder _bufferUnicode;
	int _int;
	object _bigint;
	object _num;

	void _initlist() {
		_l = new System.Collections.Generic.List<$VALTYPE>();
	}

	void _addlist($VALTYPE o) {
		_l.Add(o);
	}

EOF

[ -n "$ENABLE_INDENT" ] && cat << EOF
	private int _indent;
	private int _indentBefore;
	private bool __is_line_begin = true;
	private int __indent_unread = -1;

EOF

[ -z "$NEWLINEMODE" ] && echo "	private $CTYPE binunread = $nullsym;"
for i in $SUBAUTOMATA
do
  ch1=`replace_strange_char $i`
  echo "	_Engine_${ch1} ENGINE_${ch1};"
done
echo "	${CLASSNAME}()"
echo "	{"
for i in $SUBAUTOMATA
do
  ch1=`replace_strange_char $i`
  echo "		ENGINE_${ch1} = new _Engine_${ch1}(this);"
done
echo "		__this__ = this;"
echo "	}"

[ -n "$ENABLE_LOG" ] && cat << EOF
EOF

if [ -n "$TYPE" ]; then
elif [ "$COMMENT" = "Java" -o "$COMMENT" = "C" ]; then
  echo '	private int __unreadcomment = -2;'
fi

if [ -n "$ENABLE_BACKTRACK" ]
then
  echo "	private $CTYPE[] __backtrack = null;"
  echo "	private int __backtrack_ptr = -1;"
  echo "	private int __backtrack_len = -1;"
  echo "	private int __backtrack_wptr = -1;"
  echo "	private int __backtrack_sym = -1;"
  echo "	private int[] __backtrack_state = null;"
  echo "	private $CTYPE[] __backtrack_wsym = null;"
  echo "	private int[] __backtrack_ptrs = null;"
  echo "	private Continuation[] __backtrack_cont = null;"
  echo "	private int __backtrack_sptr = -1;"
  echo "	private bool __backtrack_flg = false;"
fi

if [ -n "$ENABLE_LOOKAHEAD" ]
then
  echo "	private int __lookahead_state;"
  echo "	private int __lookahead_mark = -1;"
  echo "	private $CTYPE[] __lookahead = null;"
  echo "	private int __lookahead_ptr = -1;"
  echo "	private $CTYPE[] __lookaheadw = null;"
  echo "	private int __lookaheadw_ptr = -1;"
  echo "	private bool __lookahead_ok = true;"
fi

cat field
[ -n "$LEXER" ] && echo "	private $LCTYPE _unreadl = $nullsyml;"
[ -n "$LEXER" ] || echo "	private $CTYPE _unreadl = $nullsym;"
echo

function _putreadf {
  if [ -n "$3" ]; then
  elif [ "$COMMENT" = "shell" ]; then
    cat << EOF
	int ReadComment($streamsym stream)
	{
		int c;

		c = stream.${readfn}();
		if(c == ${sq}${COMMENTHEADER}${sq})
		{
			while((c = stream.${readfn}()) >= 0)
			{
				if(c == '\n')
				{
					break;
				}
			}
			return c;
		}
		else
		{
			return c;
		}
	}
EOF
  elif [ "$COMMENT" = "Java" -o "$COMMENT" = "C" ]; then
    cat << EOF
	int ReadComment($streamsym stream)
	{
		int c, state = 0;

		if(__unreadcomment >= -1)
		{
			c = __unreadcomment;
			__unreadcomment = -2;
			return c;
		}
		else if((c = stream.${readfn}()) == '/')
		{
			while((c = stream.${readfn}()) >= 0)
			{
				switch(state)
				{
				case 0:
					if(c == '*')
					{
						state = 100;
					}
					else if(c == '/')
					{
						state = 200;
					}
					else
					{
						__unreadcomment = c;
						return '/';
					}
					break;
				case 100:
					if(c == '*')
					{
						state = 101;
					}
					break;
				case 101:
					if(c == '/')
					{
						return ' ';
					}
					else
					{
						state = 100;
					}
					break;
				case 200:
					if(c == '\n')
					{
						return '\n';
					}
					break;
				}
			}
			__unreadcomment = -1;
			return '/';
		}
		else
		{
			return c;
		}
	}
EOF
  else
    cat << EOF
	int ReadComment($streamsym stream)
	{
		return stream.${readfn}();
	}
EOF
  fi

  [ -n "$ENABLE_INDENT" ] || echo "	$2 $1($streamsym stream)"
  [ -n "$ENABLE_INDENT" ] && echo "	$2 ${1}_1($streamsym stream)"
  echo '	{'
  if [ -s read ]; then
    cat read
  elif [ -z "$3" ]; then
    cat << EOF
		int c;

		c = ReadComment(stream);
		return c < 0 ? NinaEOF : c;
EOF
  else
    echo "		return ($2)stream.next();"
  fi
  echo '	}'

  if [ -n "$ENABLE_INDENT" ]; then
    cat << EOF
	$2 $1($streamsym stream)
	{
		int c;

		if(__indent_unread >= 0)
		{
			c = __indent_unread;
			__indent_unread = -1;
		}
		else if(!__is_line_begin)
		{
			c = ${1}_1(stream);
		}
		else
		{
			_indent = 0;
			while((c = ${1}_1(stream)) == ' ' || c == '\t')
			{
				_indent++;
			}
			__indent_unread = c;
			c = c >= 0 ? INDENT : c;
		}

		if(__is_line_begin = c == '\n')
		{
			_indentBefore = _indent;
		}
		return c;
	}
EOF
  fi
}

if [ -z "$LEXER" ]; then
  _putreadf _Read1l "$CTYPE" "$TYPE"
  cat << EOF

	$CTYPE _Read1($streamsym stream)
	{
		$CTYPE c;

		if(_unreadl != $nullsym)
		{
			c = _unreadl;
			_unreadl = $nullsym;
		}
EOF
  if [ -z "$TYPE" -a -z "$NEWLINEMODE" ]; then
    cat <<  EOF
		else if((c = _Read1l(stream)) == '\r' && (c = _Read1l(stream)) != '\n')
		{
			_unreadl = c;
			c = '\r';
		}
EOF
  else
    cat << EOF
		else
		{
			c = _Read1l(stream);
		}
EOF
  fi
  cat << EOF
		return c;
	}
EOF
else
  _putreadf _Read1l "$LCTYPE" "$LTYPE"
  nina_template.nfa.cs.sub2.sh "$LEXER" "$LCTYPE" "$LTYPE" "$LEXER" "$LCTYPE"
  cat << EOF

	$LCTYPE _Read1ul($streamsym stream)
	{
		$LCTYPE c;

		if(_unreadl != $nullsyml)
		{
			c = _unreadl;
			_unreadl = $nullsyml;
		}
EOF
  if [ -z "$LTYPE" -a -z "$NEWLINEMODE" ]; then
    cat <<  EOF
		else if((c = _Read1l(stream)) == '\r' && (c = _Read1l(stream)) != '\n')
		{
			_unreadl = c;
			c = '\r';
		}
EOF
  else
    cat << EOF
		else
		{
			c = _Read1l(stream);
		}
EOF
  fi
  cat << EOF
		return c;
	}

	$CTYPE _Read1($streamsym stream)
	{
		System.Text.StringBuilder b = new System.Text.StringBuilder();
		object o = null;
		bool f;
		$LCTYPE a;
		int s;

		s = STATE;  STATE = 0;
		f = ${LEXER}_Accepted();
		while(o == null)
		{
			if((a = _Read1ul(stream)) == $nullsyml)
			{
				o = ${LEXER}_Gettoken(b);
				break;
			}
			else if(${LEXER}_Step(a) == 0)
			{
				if(f)
				{
					_unreadl = a;
					o = ${LEXER}_Gettoken(b);
					b = new System.Text.StringBuilder();
					STATE = 0;
					f = ${LEXER}_Accepted();
				}
				else
				{
					o = Invalidtoken;  break;
				}
			}
			else
			{
				b.Append((char)a);
				if(f = ${LEXER}_Accepted())
				{
					if(${LEXER}_Isdead())
					{
						o = ${LEXER}_Gettoken(b);
						b = new System.Text.StringBuilder();
						STATE = 0;
						f = ${LEXER}_Accepted();
					}
				}
				else if(${LEXER}_Isdead())
				{
					o = Invalidtoken;  break;
				}
			}
		}
		STATE = s;
		return o;
	}
EOF
fi

cat << EOF

	private $CTYPE _Read($streamsym rd) $tre {
		$CTYPE c;

		while(true)
		{
			if(false)
			{
EOF
[ -n "$ENABLE_BACKTRACK" ] && cat << EOF
			}
			else if(__backtrack_sym != $nullsym) 
			{
				c = __backtrack_sym;
				__backtrack_sym = -1;
				__Logprint("Read Backtracking: ", c);
EOF
cat << EOF
			}
			else if(unread != $nullsym)
			{
				c = unread;
				unread = $nullsym;
				__Logprint("Read unread: ", c);
EOF
[ -n "$ENABLE_LOOKAHEAD" ] && cat << EOF
			}
			else if(__lookahead_ptr >= 0)
			{
				if(__lookahead_ptr < __lookahead.Length)
				{
					c = __lookahead[__lookahead_ptr++];
				}
				else
				{
					__lookahead = null;
					__lookahead_ptr = -1;
					c = _Read(rd);
				}
				__Logprint("Read Lookahead: ", c);
EOF
[ -n "$ENABLE_BACKTRACK" ] && cat << EOF
			}
			else if(__backtrack_ptr >= 0)
			{
				if(__backtrack_ptr < __backtrack_len)
				{
					c = __backtrack[__backtrack_ptr++];
				}
				else
				{
					__backtrack = null;
					__backtrack_ptr = __backtrack_wptr = -1;
					c = _Read(rd);
				}
				__Logprint("Read Backtracking: ", c);
EOF
[ -z "$NEWLINEMODE" ] && cat << EOF
			}
			else if(binunread != $nullsym)
			{
				c = unread;
				unread = $nullsym;
EOF
echo "			}"
echo "			else if((c = _Read1(rd)) != $nullsym)"
echo "			{"
[ -z "$NEWLINEMODE" ] && echo "				$CTYPE d;"
[ -n "$ENABLE_BACKTRACK" ] && echo '				__Write_backtrack(c);'
echo '				__Logprint("Read: ", c);'
[ -z "$TYPE" ] && [ -z "$NEWLINEMODE" ] && cat <<  EOF
				if(c != '\r')
				{
				}
				else if((d = _Read1(rd)) == '\n')
				{
					c = '\n';
				}
				else
				{
					binunread = d;
				}
EOF
[ -z "$READSLOW" ] && cat << EOF
			}
			else
			{
				__Logprint("Read end-of-file");
			}
EOF
[ -z "$READSLEEP" ] || [ $READSLEEP -lt 0 ] || slp="System.Threading.Thread.Sleep($READSLEEP);"
[ -z "$READSLOW" ] || cat << EOF
			}
			else
			{
				$slp
				continue;
			}
EOF
cat << EOF
			return c;
		}
	}

	void UNGET($CTYPE c)
	{
		unread = c;
		__Logprint("Set unread: ", c);
	}
EOF

[ -n "$ENABLE_LOG" ] && cat << EOF

	private void __Logprint(string s, $CTYPE c)
	{
	}

	private void __Logopen()
	{
	}

	private void __Logprint(string s)
	{
	}

	private void __Logclose()
	{
	}

	private void __Puttrace()
	{
	}

EOF
[ -n "$ENABLE_LOG" ] || cat << EOF

	private void __Logprint(string s, $CTYPE c)
	{
	}

	private void __Logopen()
	{
	}

	private void __Logprint(string s)
	{
	}

	private void __Logclose()
	{
	}

	private void __Puttrace()
	{
	}

EOF

if [ -n "$ENABLE_LOOKAHEAD" ]
then
  cat << EOF
	void LOOKAHEAD($CTYPE c)
	{
		$CTYPE[] a;

		if(__lookaheadw == null)
		{
			__lookahead_state = STATE;
			__lookaheadw = new $CTYPE[72];
			__lookaheadw_ptr = 0;
			__lookaheadw[__lookaheadw_ptr++] = c;
		}
		else if(__lookaheadw_ptr < __lookaheadw.Length)
		{
			__lookaheadw[__lookaheadw_ptr++] = c;
		}
		else
		{
			a = new $CTYPE[__lookaheadw.Length * 2];
			System.Array.Copy(__lookaheadw, a, __lookaheadw.Length);
			__lookaheadw = a;
			__lookaheadw[__lookaheadw_ptr++] = c;
		}
	}

	private void __Copy_lookahead(int p)
	{
		$CTYPE[] a;
		$CTYPE[] lookaheadOrg = __lookahead;
		int lookaheadLength = __lookahead != null ? __lookahead.Length : __lookahead_ptr;

		if(__lookahead_ptr > 0)
		{
			a = new $CTYPE[__lookahead.Length - __lookahead_ptr];
			System.Array.Copy(__lookahead, __lookahead_ptr, a, 0, a.Length);
			__lookahead = a;
		}

		a = new $CTYPE[__lookaheadw_ptr + (lookaheadLength - __lookahead_ptr)];
		System.Array.Copy(__lookaheadw, a, __lookaheadw_ptr);
		if(lookaheadOrg != null) {
			System.Array.Copy(lookaheadOrg,
					__lookahead_ptr,
					a,
					__lookaheadw_ptr,
					lookaheadLength - __lookahead_ptr);
		}
		__lookahead = a;
		__lookahead_ptr = p;
		__lookaheadw = null;
		__lookaheadw_ptr = -1;
	}

	void LOOKAHEAD_COMMIT()
	{
		if(__lookahead_mark < 0)
		{
			__lookaheadw = null;
			__lookaheadw_ptr = -1;
		}
		else
		{
			__Copy_lookahead(__lookahead_mark);
		}
		__lookahead_mark = -1;
		__Logprint("Commit Lookahead");
	}

	void LOOKAHEAD_RB()
	{
		__Copy_lookahead(0);
		STATE = __lookahead_state;
		__lookahead_ok = false;
		__lookahead_mark = -1;
		__Logprint("Rollback Lookahead");
	}

	void LOOKAHEAD_MARK()
	{
		__lookahead_mark = __lookaheadw_ptr;
	}

	void LOOKAHEAD_MARK_INIT()
	{
		__lookahead_mark = 0;
	}

EOF
fi

if [ -n "$ENABLE_BACKTRACK" ]
then
  [ -z "$TYPE" ] && bkt='__backtrack_sym != c'
  [ -z "$TYPE" ] || bkt='!c.equals(__backtrack_sym)'
  cat << EOF
	void SET_BACKTRACK($CTYPE c)
	{
		$CTYPE[] a;
		int[] b;

		if(${bkt})
		{
			if(__backtrack_ptr < 0)
			{
				__backtrack = new $CTYPE[1024];
				__backtrack_wptr = 0;
			}
			else
			{
				__backtrack_wptr = __backtrack_ptr;
			}

			if(__backtrack_wsym == null)
			{
				__backtrack_state = new int[72];
				__backtrack_wsym = new $CTYPE[72];
				__backtrack_ptrs = new int[72];
				__backtrack_cont = new Continuation[72];
				__backtrack_sptr = 0;
			}
			else if(__backtrack_sptr >= __backtrack_wsym.Length)
			{
				a = __backtrack_wsym;
				b = __backtrack_ptrs;
				__backtrack_wsym = new $CTYPE[a.Length];
				__backtrack_ptrs = new int[b.Length];
				System.Array.Copy(a, __backtrack_wsym, a.Length);
				System.Array.Copy(b, __backtrack_ptrs, b.Length);
			}
			__backtrack_state[__backtrack_sptr] = STATE;
			__backtrack_wsym[__backtrack_sptr] = c;
			__backtrack_ptrs[__backtrack_sptr] = __backtrack_wptr;
			__backtrack_cont[__backtrack_sptr] = GETCC();
			__backtrack_sptr++;
			__backtrack_flg = true;
			__Logprint("Set Backtrack: ", c);
		}
	}

	private void __Write_backtrack($CTYPE c)
	{
		$CTYPE[] a;

		if(__backtrack_wptr < 0)
		{
			// do nothing
		}
		else if(__backtrack_wptr < __backtrack.Length)
		{
			__backtrack[__backtrack_wptr++] = c;
		}
		else
		{
			a = new $CTYPE[__backtrack.Length * 2];
			System.Array.Copy(__backtrack, a, __backtrack.Length);
			__backtrack = a;
			__backtrack[__backtrack_wptr++] = c;
		}
	}

	void BACKTRACK_COMMIT()
	{
		if(--__backtrack_sptr <= 0)
		{
			__backtrack_state = null;
			__backtrack_wsym = null;
			__backtrack_ptrs = null;
			__backtrack_cont = null;
			__backtrack_sptr = -1;
			__backtrack_wptr = -1;
			__Logprint("Commit Backtracking");
		}
	}

	bool BACKTRACK($CTYPE c)
	{
		if(__backtrack_wptr >= 0)
		{
			__backtrack_len = __backtrack_wptr;
			__backtrack_wptr = -1;
			__backtrack_sptr--;
			STATE = __backtrack_state[__backtrack_sptr];
			__backtrack_ptr = __backtrack_ptrs[__backtrack_sptr];
			__backtrack_sym = __backtrack_wsym[__backtrack_sptr];
			SETCC(__backtrack_cont[__backtrack_sptr]);
			__Logprint("Rollback Backtracking");
			return true;
		}
		else
		{
			return false;
		}
	}

	Continuation GETCC()
	{
		return new Continuation(STATE, __sts, __stk, __stv, __slen);
	}

	void SETCC(Continuation c)
	{
		int l;

		STATE = c.STATE;
		l = c.__stk.Length;
		l = __stk.Length > l ? __stk.Length : l * 2;
		__sts = new int[l];
		__stk = new Engine[l];
		System.Array.Copy(c.__sts, __sts, c.__sts.Length);
		System.Array.Copy(c.__stk, __stk, c.__stk.Length);
		__slen = c.__sts.Length;
	}

EOF
fi

for i in $SUBAUTOMATA
do
  ch1=`replace_strange_char $i`
  echo
  echo "	class _Engine_${ch1} : Engine"
  echo "	{"
  echo
  echo "	${CLASSNAME}${TEMPLATE} __this__;"
  echo "	public _Engine_${ch1}(${CLASSNAME}${TEMPLATE} o)"
  echo "	{"
  echo "		__this__ = o;"
  echo "	}"
  echo
  echo "	public int Step($streamsym __rd, $CTYPE __c__)"
  echo '	{'
  [ -n "$ENABLE_LOOKAHEAD" ] && echo '		bool __l__ = __this__.__lookahead_ok;'
  [ -n "$ENABLE_LOOKAHEAD" ] && echo
  [ -n "$DYNAMICAUTOMATA" ]  && echo '		if((__this__.STATE & NinaDiscardstate) != 0)  return 1;'
  [ -n "$ENABLE_LOOKAHEAD" ] && echo '		__this__.__lookahead_ok = true;'
  echo '		switch(__this__.STATE)'
  echo '		{'
  print_states $i
  echo '		}'
  echo '		return 0;'
  echo '	}'
  echo
  echo "	public bool Accepted()"
  echo "	{"
  print_accepts $i
  echo '	}'
  echo
  echo "	public int Execaction($CTYPE __c__)"
  echo '	{'
  [ -n "$DYNAMICAUTOMATA" ]  && echo '		if((__this__.STATE & NinaDiscardstate) != 0) {'
  [ -n "$DYNAMICAUTOMATA" ]  && echo '			if(__c__ >= 0) {'
  [ -n "$DYNAMICAUTOMATA" ]  && echo '				__this__.STATE = __this__.STATE & ~NinaDiscardstate;'
  [ -n "$DYNAMICAUTOMATA" ]  && echo '				__this__.__lookahead_ok = false;'
  [ -n "$DYNAMICAUTOMATA" ]  && echo '			}'
  [ -n "$DYNAMICAUTOMATA" ]  && echo '			return 1;'
  [ -n "$DYNAMICAUTOMATA" ]  && echo '		}'
  [ -n "$DYNAMICAUTOMATA" ]  && echo
  echo '		switch(__this__.STATE) {'
  print_actions $i
  echo '		}'
  echo '		return 1;'
  echo '	}'
  echo
  echo "	public bool Isend()"
  echo "	{"
  print_isend $i
  echo '	}'
  cat << EOF
		public int Recover(System.Exception e)
		{
EOF
    print_recover $i
    cat << EOF
		}

		public int DeadState()
		{
EOF
    print_deadstate $i
    cat << EOF
		}

		public int StateSize()
		{
EOF
    print_statesize $i
    cat << EOF
		}

		public int FinallyState()
		{
EOF
    print_finallystate $i
    cat << EOF
		}

		public bool Dead()
		{
EOF
    print_deads $i
    cat << EOF
		}

		public bool EmptyTransition()
		{
EOF
    print_empty_transitions $i
    cat << EOF
		}

		public override string ToString()
		{
			return "${ch1}";
		}

	}
EOF
done

for i in $LRPARSERS
do
  y.tab.cs.sh $i
done

c='$c'
[ -n "$DYNAMICAUTOMATA" ] && cat << EOF

	bool __startWith(char[] a, int c)
	{
		return a.Length > 0 && a[0] == c;
	}

	bool __startWith(string a, int c)
	{
		return a.Length > 0 && a[0] == c;
	}

	bool __startWith(System.Text.StringBuilder a, int c)
	{
		return a.Length > 0 && a[0] == c;
	}

	class DynamicEngine : Engine
	{

		private ${CLASSNAME}${TEMPLATE} __this__;
		private int ptr = 0;
		private int oldst;
		private char[] a;

		public DynamicEngine(${CLASSNAME}${TEMPLATE} __t, char[] a, int oldst)
		{
			this.__this__ = __t;
			this.oldst = oldst;
			this.a = a;
		}

		public DynamicEngine(${CLASSNAME}${TEMPLATE} __t, string a, int ost)
			: this(__t, a.ToCharArray(), ost)
		{
		}

		public DynamicEngine(${CLASSNAME}${TEMPLATE} __t, System.Text.StringBuilder a, int ost)
			: this(__t, a.ToString().ToCharArray(), ost)
		{
		}

		public int Step($streamsym __rd, $CTYPE __c__)
		{
			if(ptr >= a.Length)
			{
				__this__.LOOKAHEAD_COMMIT();
				return 0;
			}
			else if(a[ptr] == __c__)
			{
				__this__.LOOKAHEAD(__c__);
				ptr++;
				return 1;
			}
			else
			{
				__this__.LOOKAHEAD(__c__);
				__this__.LOOKAHEAD_RB();
				__this__.__sts[__this__.__slen - 1] = NinaDiscardstate | oldst;
				return 0;
			}
		}

		public bool Accepted()
		{
			return true;
		}

		public bool Dead()
		{
			return false;
		}

		public bool EmptyTransition()
		{
			return false;
		}

		public int Execaction($CTYPE c)
		{
			return 1;
		}

		public bool Isend()
		{
			return ptr >= a.Length;
		}

		public int Recover(System.Exception e)
		{
			return -1;
		}

		public int DeadState()
		{
			return -1;
		}

		public int StateSize()
		{
			return a.Length;
		}

		public int FinallyState()
		{
			return -1;
		}

		public string ToString()
		{
			return "dynamic:" + new System.String(a);
		}

	}
EOF

cat << EOF

	void __Stkpush(int st, Engine en)
	{
		object[][] c;
		Engine[] b;
		int[] a;

		if(__slen >= __sts.Length)
		{
			a = new int[__sts.Length * 2];
			b = new Engine[__stk.Length * 2];
			c = new object[__stk.Length * 2][];
			System.Array.Copy(__sts, a, __sts.Length);
			System.Array.Copy(__stk, b, __stk.Length);
			System.Array.Copy(__stv, c, __stv.Length);
			__sts = a;
			__stk = b;
			__stv = c;
		}
		__sts[__slen] = st;
		__stk[__slen] = en;
		__stv[__slen++] = new object[en.StateSize()];
	}
EOF

ch1=`replace_strange_char ${MAINNAME}`
echo
cat << EOF
	private $CTYPE _Parse($streamsym rd, $CTYPE x, bool? rt, bool skip, ref int st)
	{
		bool b = false, p = skip;
		$CTYPE c = x;
		Engine en;
		int a;

		b = __stk[__slen - 1].Accepted();
		if(rd == null)
		{
			throw new System.Exception("can not recurse");
		}
		else if((bool)rt)
		{
			switch(__stk[__slen - 1].Execaction(NinaBegin))
			{
			case NinaAccept:
				__Logprint("accept " + __stk[__slen - 1]);
				st = NinaAccept;  return $nullsym;
			case NinaFail:
				__Logprint("match failed: begin");
				__Puttrace();
				st = NinaFail;  return $nullsym;
			case NinaHaltAccept:
				__Logprint("machine halted: begin");
				st = NinaHaltAccept;  return $nullsym;
			case NinaHaltReject:
				__Logprint("machine halted: begin");
				st = NinaHaltReject;  return $nullsym;
			case NinaYield:
				__Logprint("machine halted: begin");
				st = NinaYield;  return $nullsym;
			}
		}

		try
		{
			do
			{
				en = __stk[__slen - 1];
				if(p)
				{
					p = false;
				}
				else if((a = en.Step(rd, c)) > 0)
				{
					__Logprint("transit to state " + STATE + ": ", c);
					b = en.Accepted();
					switch(en.Execaction(c))
					{
					case NinaAccept:
						__Logprint("accept " + __stk[__slen - 1]);
						UNGET(c);
						st = NinaAccept;  return $nullsym;
					case NinaFail:
						__Logprint("match failed: ", c);
						__Puttrace();
						UNGET(c);
						st = NinaFail;  return $nullsym;
					case NinaHaltAccept:
						__Logprint("machine halted: ", c);
						st = NinaHaltAccept;  return $nullsym;
					case NinaHaltReject:
						__Logprint("machine halted: ", c);
						st = NinaHaltReject;  return $nullsym;
					case NinaYield:
						__Logprint("machine halted: ", c);
						st = NinaYield;  return $nullsym;
					}
EOF
  [ -n "$ENABLE_BACKTRACK" ] && cat << EOF
					if(__backtrack_flg)
					{
						__Write_backtrack(c);
						__backtrack_flg = false;
					}
EOF
  cat << EOF
				}
				else if(a < 0)
				{
					__Logprint("entering " + __stk[__slen - 1]);
					return c;
				}
				else if(b)
				{
					__Logprint("accept " + __stk[__slen - 1]);
					UNGET(c);
					st = NinaAccept;  return $nullsym;
EOF
  [ -n "$ENABLE_LOOKAHEAD" ] && cat << EOF
				}
				else if(__lookaheadw_ptr >= 0)
				{
					__Logprint("match failed: try lookahead: ", c);
					LOOKAHEAD(c);
					LOOKAHEAD_RB();
					b = en.Accepted();
EOF
  [ -n "$ENABLE_BACKTRACK" ] && cat << EOF
				}
				else if(BACKTRACK(c))
				{
					__Logprint("match failed: try backtracking: ", c);
EOF
  cat << EOF
				}
				else if(c == $nullsym)
				{
EOF
  [ -n "$MATCHER" ] || echo "					if(!b)  throw new ${TOKENERROR}();"
  [ -n "$MATCHER" ] && cat << EOF
					if(!b)
					{
						st = NinaFail;
						return $nullsym;
					}
EOF
  cat << EOF
					st = NinaAccept;
					return $nullsym;
				}
				else
				{
					__Logprint("match failed: ", c);
					__Puttrace();
					UNGET(c);
					st = NinaFail;  return $nullsym;
				}

				if(__stk[__slen - 1].EmptyTransition()) {
					// do nothing
				}
				else if(!__stk[__slen - 1].Dead()) {
					c = _Read(rd);
				}
				else if(b)
				{
					__Logprint("accept " + __stk[__slen - 1]);
					st = NinaAccept;  return $nullsym;
EOF
  [ -n "$ENABLE_LOOKAHEAD" ] && cat << EOF
				}
				else if(__lookaheadw_ptr >= 0)
				{
					__Logprint("match failed: try lookahead: ", c);
					LOOKAHEAD_RB();
					b = en.Accepted();
EOF
  [ -n "$ENABLE_BACKTRACK" ] && cat << EOF
				}
				else if(BACKTRACK(c))
				{
					__Logprint("match failed: try backtracking: ", c);
EOF
  cat << EOF
				}
				else if(c == $nullsym)
				{
					if(!b)  throw new ${TOKENERROR}();
					st = NinaAccept;  return $nullsym;
				}
				else
				{
					__Logprint("match failed: ", c);
					__Puttrace();
					st = NinaFail;  return $nullsym;
				}
			} while(true);
		} catch(System.Exception e) {
			UNGET(c);
			throw e;
		}
	}

	private bool? Execfinally()
	{
		int a, b;

		if((a = __stk[__slen - 1].FinallyState()) >= 0)
		{
			b = STATE;  STATE = a;
			switch(__stk[__slen - 1].Execaction(NinaBegin))
			{
			case NinaHaltAccept:
				__slen = 0;
				return true;
			case NinaHaltReject:
				__slen = 0;
				return false;
			}
			STATE = b;
		}
		return null;
	}

	private int Getdeadstate()
	{
		return __stk[__slen - 1].DeadState();
	}

	private int Getrecover(System.Exception e)
	{
		return __stk[__slen - 1].Recover(e);
	}

	${API_ACCESS_MODIFIER} bool Parse($streamsym rd, Engine entry)
	{
		$CTYPE c = 0;
		bool? b = false;
		bool skip = true;
		int a = 0;

		__Logopen();
		try
		{
			if(__slen == 0) {
				b = true;
				__Stkpush(0, entry);
			}

			while(true)
			{
				try
				{
					if((c = _Parse(rd, c, b, skip, ref a)) != $nullsym)
					{
						skip = false;
					}
					else if(a == NinaFail)
					{
						while((STATE = Getdeadstate()) < 0)
						{
							if((b = Execfinally()) != null)
							{
								if(!((bool)b))  throw new ${TOKENERROR}();
								return (bool)b;
							}

							if(__slen-- <= 1)
							{
EOF
  [ -n "$MATCHER" ] || echo "								throw new ${TOKENERROR}();"
  [ -n "$MATCHER" ] && echo '								return false;'
  cat << EOF
							}
						}
						skip = true;
					}
					else if(a == NinaHaltAccept)
					{
						if((b = Execfinally()) != null)  break;
						__slen = 0;
						b = true;  break;
					}
					else if(a == NinaHaltReject)
					{
						if((b = Execfinally()) != null)  break;
						__slen = 0;
						b = false;  break;
					}
					else if(a == NinaYield)
					{
						return false;
					}
					else if(__slen > 1)
					{
						if((b = Execfinally()) != null)  break;
						STATE = __sts[--__slen];
						skip = true;
					}
					else
					{
						if((b = Execfinally()) != null)  break;
						b = __stk[--__slen].Accepted();  break;
					}
				}
				catch(System.Exception e)
				{
					exception = e;
					if(__slen <= 0)  throw e;
					while((STATE = Getrecover(e)) < 0)
					{
						if((b = Execfinally()) != null)  break;
						if(__slen-- <= 1)  throw e;
					}
				}
				b = true;
			}
EOF
  [ -n "$MATCHER" ] || echo "			if(!((bool)b))  throw new ${TOKENERROR}();"
  cat << EOF
			return (bool)b;
		}
		finally
		{
			__Logclose();
		}
	}

	${API_ACCESS_MODIFIER} bool Parse($streamsym rd)
	{
		return Parse(rd, ENGINE_${ch1});
	}

	${API_ACCESS_MODIFIER} void SetStream($streamsym rd) {
		if(befstream != null)
		{
			throw new System.Exception();
		}
		yieldObject = befstream = rd;
	}

	${API_ACCESS_MODIFIER} object ParseNext() {
		object o;

		if(befstream == null)
		{
			throw new System.Exception();
		}
		else if(yieldObject == null)
		{
			return null;
		}
		else if(Parse(befstream, ENGINE_${ch1}))
		{
			if(yieldObject == null)  throw new System.Exception();
			o = yieldObject;  yieldObject = null;
			return o;
		}
		else
		{
			if(yieldObject == null)  throw new System.Exception();
			return yieldObject;
		}
	}

	${API_ACCESS_MODIFIER} static bool ParseAll($streamsym rd)
	{
		${CLASSNAME} o = new ${CLASSNAME}();

		return o.Parse(rd);
	}

	static void puts(string s)
	{
		System.Console.WriteLine(s);
	}

EOF

[ -z "$TYPE" -o -z "$LTYPE" ] && [ -z "$NEWLINEMODE" ] && cat << EOF
	${API_ACCESS_MODIFIER} bool Parse(System.IO.Stream rd)
	{
		return Parse(new System.IO.StreamReader(rd));
	}

	${API_ACCESS_MODIFIER} static bool ParseAll(System.IO.Stream rd)
	{
		return ParseAll(new System.IO.StreamReader(rd));
	}

EOF

for i in $SUBAUTOMATA
do
  print_constants $i
done
echo '	/* @@@-PARSER-CODE-END-@@@ */'

cat fragment
#cat fragment | replace_action

[ -n "$PUTMAIN" ] && cat << EOF
	static void Main() {
		ParseAll(System.Console.In);
	}
EOF
[ -n "$PUTPROMPT" ] && cat << EOF
	static void Main() {
		string s;

		System.Console.Write("> ");
		while((s = System.Console.ReadLine()) != null) {
			try {
				ParseAll(new System.IO.StringReader(s));
				System.Console.Write("> ");
			} catch(System.Exception) {
				System.Console.WriteLine("syntax error");
			}
		}
	}
EOF

echo '}'
[ -z "$PACKAGE" ] || echo "}"
