#! /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.
#
if [ -z "$TYPE" ]
then
  nullsym='-1'
  streamsym='java.io.Reader'
  rdt='java.io.Reader'
  tre='throws java.io.IOException'
else
  nullsym='null'
  rdt="Iterable<$CTYPE>"
  streamsym='java.util.Iterator'
  tre=''
fi

cat << EOF
#ifndef ACCEPTSTATE
#define INITSIZE 765
#define ACCEPTSTATE 0x40000001
#define LRSTATEMASK  0x3fff0000
#define LRSTATESHIFT 16
#define FASTATEMASK  0x0000ffff
#endif
EOF
put_token_const $1
cat_definition $1
lex=`echo_lexer $1`
if [ -z "$lex" ]
then
  echo
elif [ -n "$TYPE" ]
then
  raiseerror 'mustcharacter'
else
  nina_template.nfa.c.sh $lex "LR${1}Lexer" "${FILENAME}"
  cat << EOF

static int LR${1}Engine_stepLex(struct ${FILENAME}_tag *__this__, int state, int a) {
	int s = __this__->state;
	int r;

	__this__->state = state;
	r = LR${1}Lexer__step(__this__, a) != 0 ? __this__->state : -1;
	__this__->state = s;
	return r;
}

static int LR${1}Engine_isAcceptedLex(struct ${FILENAME}_tag *__this__, int state) {
	int s = __this__->state;
	int r;

	__this__->state = state;
	r = LR${1}Lexer__accepted(__this__);
	__this__->state = s;
	return r;
}

static int LR${1}Engine_isDeadLex(struct ${FILENAME}_tag *__this__, int state) {
	int s = __this__->state;
	int r;

	__this__->state = state;
	r = LR${1}Lexer__isdead(__this__);
	__this__->state = s;
	return r;
}

static int LR${1}Engine_getTokenLex(struct ${FILENAME}_tag *__this__, int state, char *b) {
	int s = __this__->state;
	int r;

	__this__->state = state;
	r = LR${1}Lexer__gettoken(__this__, b);
	__this__->state = s;
	return r;
}
EOF
fi

cat << EOF

static int LR${1}Engine__eq(int o, int p) {
	return o == p;
}

static int LR${1}Engine__end(int o) {
	return LR${1}Engine__eq(o, '\n');
}

static void LR${1}Engine__push(struct ${FILENAME}_tag *b, int k, YYSTYPE s) {
	if(b->__synptr - b->__synbuffer >= NINA_LRSTACKSIZE) {
		fprintf(stderr, "LR stack overflow\n");
		THROWERROR_C(b);
	}
	(b->__synptr++)->val   = s;
	(b->__synptr++)->state = k;
}

static void LR${1}Engine__pop(struct ${FILENAME}_tag *b, int num) {
	b->__synptr -= num * 2;
}

static int LR${1}Engine__refsyn(struct ${FILENAME}_tag *b) {
	return (b->__synptr - 1)->state;
}

static YYSTYPE LR${1}Engine__refv(struct ${FILENAME}_tag *b, int n) {
	return (b->__synptr - n * 2)->val;
}

static int LR${1}Engine_getGoto(struct ${FILENAME}_tag *b, int __stateID, int __n) {
	switch(__stateID >> LRSTATESHIFT) {
EOF
put_goto $1
cat << EOF
	}
	THROWERROR_C(b);  return 0;
}

static int LR${1}Engine_getShift(struct ${FILENAME}_tag *__this__, int __t) {
	switch(__this__->state >> LRSTATESHIFT) {
EOF
put_shift $1
cat << EOF
	}
	return -1;
}

static int LR${1}Engine_getReduce(struct ${FILENAME}_tag *__this__, int __t) {
	YYSTYPE __b__;
	int __k;

	switch(__this__->state >> LRSTATESHIFT) {
EOF
put_reduce $1
cat << EOF
	}
	return -1;
}

static int LR${1}Engine_isAccept(struct ${FILENAME}_tag *__this__, int __t) {
	switch(__this__->state >> LRSTATESHIFT) {
EOF
put_accept $1
cat << EOF
	}
	return NINA_FALSE;
}

EOF

[ -z "$lex" ] && cat << EOF
static int ${FILENAME}__LR_${1}__step(struct ${FILENAME}_tag *__this__,
		nina_stream_t __rd, $CTYPE a) {
	int k;

	if(STATE == ACCEPTSTATE) {
		return 0;
	} else if(LR${1}Engine_isAccept(__this__, a)) {
		UNGET(a);
		STATE = ACCEPTSTATE;
		return 1;
	} else if((k = LR${1}Engine_getShift(__this__, a)) >= 0) {
		LR${1}Engine__push(__this__, k << LRSTATESHIFT, a);
		STATE = k << LRSTATESHIFT;
		return 1;
	} else if((k = LR${1}Engine_getReduce(__this__, a)) >= 0) {
		UNGET(a);
		STATE = k << LRSTATESHIFT;
		return 1;
	} else {
		return 0;
	}
}
EOF
[ -z "$lex" ] || cat << EOF
static int LR${1}Engine__steptoken(struct ${FILENAME}_tag *__this__) {
	int k;

	if(LR${1}Engine_isAccept(__this__, __this__->__token)) {
		STATE = ACCEPTSTATE;
		__this__->__token = NILTOKEN;
		return 1;
	} else if((k = LR${1}Engine_getShift(__this__, __this__->__token)) >= 0) {
		LR${1}Engine__push(__this__, k << LRSTATESHIFT, __this__->__token);
		STATE = k << LRSTATESHIFT;
		__this__->__token = NILTOKEN;
		return 1;
	} else if(k < -1) {
		LR${1}Engine__push(__this__, (-k - 2) << LRSTATESHIFT, __this__->__token);
		STATE = 0;
		__this__->__token = NILTOKEN;
		return NINA_ACCEPT;
	} else if((k = LR${1}Engine_getReduce(__this__, __this__->__token)) >= 0) {
		STATE = k << LRSTATESHIFT;
		return 1;
	} else {
		__this__->__token = NILTOKEN;
		return 0;
	}
}

static int ${FILENAME}__LR_${1}__step(struct ${FILENAME}_tag *__this__,
		nina_stream_t __rd, $CTYPE a) {
	int k;

	if(STATE == ACCEPTSTATE) {
		return 0;
	} else if(__this__->__token != NILTOKEN) {
		UNGET(a);
		return LR${1}Engine__steptoken(__this__);
	} else if((k = LR${1}Engine_stepLex(__this__, STATE & FASTATEMASK, a)) < 0) {
		if(__this__->__lexok) {
			UNGET(a);
			*(__this__->__lexptr) = 0;
			__this__->__token = LR${1}Engine_getTokenLex(
					__this__, STATE & FASTATEMASK, __this__->__lexbuf);
			STATE = STATE & LRSTATEMASK;
			__this__->__lexptr = __this__->__lexbuf;
			__this__->__lexok = LR${1}Engine_isAcceptedLex(__this__, 0);
			return 1;
		} else {
			return 0;
		}
	} else if(__this__->__lexptr - __this__->__lexbuf < sizeof(__this__->__lexbuf) - 1) {
		STATE = (STATE & LRSTATEMASK) | k;
		*(__this__->__lexptr++) = a;
		__this__->__lexok = LR${1}Engine_isAcceptedLex(__this__, STATE & FASTATEMASK);
		if(__this__->__lexok) {
			if(LR${1}Engine_isDeadLex(__this__, STATE & FASTATEMASK)) {
				*(__this__->__lexptr) = 0;
				__this__->__token = LR${1}Engine_getTokenLex(
						__this__, STATE & FASTATEMASK, __this__->__lexbuf);
				STATE = STATE & LRSTATEMASK;
				__this__->__lexptr = __this__->__lexbuf;
				__this__->__lexok = LR${1}Engine_isAcceptedLex(__this__, 0);
				return LR${1}Engine__steptoken(__this__);
			}
		} else if(LR${1}Engine_isDeadLex(__this__, STATE & FASTATEMASK)) {
			return 0;
		}
		return 1;
	} else {
		return 0;
	}
}
EOF

cat << EOF

static int ${FILENAME}__LR_${1}__accepted(struct ${FILENAME}_tag *__this__) {
	return STATE == ACCEPTSTATE;
}

static int ${FILENAME}__LR_${1}__execaction(struct ${FILENAME}_tag *__this__, $CTYPE c) {
	if(c == NINA_BEGIN && __this__->__synptr == NULL) {
		__this__->__synptr = __this__->__synbuffer;
EOF
put_grammar_initial $1
cat << EOF
		__this__->__synptr++;
	}
	return 1;
}

static int ${FILENAME}__LR_${1}__isend(struct ${FILENAME}_tag *__this__) {
	return NINA_FALSE;
}

static int ${FILENAME}__LR_${1}__deadState(struct ${FILENAME}_tag *__this__) {
	return -1;
}

static int ${FILENAME}__LR_${1}__stateSize(struct ${FILENAME}_tag *__this__) {
	return 1;
}

static int ${FILENAME}__LR_${1}__finallyState(struct ${FILENAME}_tag *__this__) {
	return -1;
}

static int ${FILENAME}__LR_${1}__signal(struct ${FILENAME}_tag *__this__, int e) {
	return -1;
}
EOF
