#
# 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.
#
sed "s/@@YEAR@@/$YEAR/g
s/@@OWNER@@/$OWNER/g
s/@@ORGANIZATION@@/$ORGANIZATION/g" /license/$LICENSE

cat definition
[ -z "$READER" ] && readr='(*(b->read))'
[ -n "$READER" ] && readr=$READER

[ -z "$READSLOW" ] || echo '#include <unistd.h>'
cat << EOF
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/uio.h>
#include <unistd.h>
#include "${FILENAME}.h"

#define ENDMARKER ((void *)1)
#define STATE (__this__->state)
#define INITIAL 0
#define THROW_CODE_ACCEPT 91
#define THROW_CODE_REJECT 85
#define THROW_CODE_ERROR  72
#define NEW_NINA_STREAM_FILE(f)   ((nina_stream_t)(&(f)))
#define NEW_NINA_STREAM_STRING(s) ((nina_stream_t)(&(s)))
#define NINA_ACCEPT -1
#define NINA_BEGIN -2
#define NINA_SIGNAL -10
#define NINA_HALT_ACCEPT -91
#define NINA_HALT_REJECT -72

#define UNGET_C(o, c)    (nina__unread((struct ${FILENAME}_tag *)(o), (c)))
#define UNGET(c)         (nina__unread((struct ${FILENAME}_tag *)(__this__), (c)))
#define GOTOSYMBOL(c)    (nina__gotoSymbol((struct ${FILENAME}_tag *)(__this__), (c)))
#define THROWERROR_C(o)  longjmp((o)->ex, THROW_CODE_ERROR);
#define THROWERROR       longjmp((__this__)->ex, THROW_CODE_ERROR);

#define __stk_accepted_C(o) (((o)->__stk_accepted[(o)->__slen - 1])(o))
#define __stk_step_C(o, rd, c) (((o)->__stk_step[(o)->__slen - 1])(o, rd, c))
#define __stk_execaction_C(o, c) (((o)->__stk_execaction[(o)->__slen - 1])(o, c))
#define __stk_deadState_C(o) (((o)->__stk_deadState[(o)->__slen - 1])(o))
#define __stk_finallyState_C(o) (((o)->__stk_finallyState[(o)->__slen - 1])(o))
#define __stk_signal_C(o) (((o)->__stk_signal[(o)->__slen - 1])(o, (o)->__trapped_signal))
#define __stv_C(o) ((o)->__stv[(o)->__slen - 1])
#define __stk_string_C(o) ((o)->__stk_string[(o)->__slen - 1])
#define __stk_push_C(o, st, tok) {\
	if((o)->__slen >= NINA_STACKSIZE)  THROWERROR_C(o);\
	(o)->__stk_step[(o)->__slen]         = ${FILENAME}_ ## tok ## __step;\
	(o)->__stk_accepted[(o)->__slen]     = ${FILENAME}_ ## tok ## __accepted;\
	(o)->__stk_execaction[(o)->__slen]   = ${FILENAME}_ ## tok ## __execaction;\
	(o)->__stk_deadState[(o)->__slen]    = ${FILENAME}_ ## tok ## __deadState;\
	(o)->__stk_finallyState[(o)->__slen] = ${FILENAME}_ ## tok ## __finallyState;\
	(o)->__stk_signal[(o)->__slen]       = ${FILENAME}_ ## tok ## __signal;\
	(o)->__stk_string[(o)->__slen] = #tok;\
	(o)->__sts[(o)->__slen++] = (st);\
}

#define LOOKAHEAD(c)        nina__LOOKAHEAD(__this__, c)
#define LOOKAHEAD_COMMIT()  nina__LOOKAHEAD_COMMIT(__this__)
#define LOOKAHEAD_MARK()    nina__LOOKAHEAD_MARK(__this__)

static void nina__unread(struct ${FILENAME}_tag *b, int c);
static void nina__gotoSymbol(struct ${FILENAME}_tag *b, int c);
EOF

for i in $SUBAUTOMATA
do
  ch1=`replace_strange_char $i`
  echo "static void ${FILENAME}_${ch1}__parse_int(struct ${FILENAME}_tag *__this__,"
  echo "		nina_stream_t rd, int x);"
  echo "static int ${FILENAME}_${ch1}__step(struct ${FILENAME}_tag *__this__,"
  echo "		nina_stream_t __rd, int __c__);"
  echo "static int ${FILENAME}_${ch1}__accepted(struct ${FILENAME}_tag *__this__);"
  echo "static int ${FILENAME}_${ch1}__execaction(struct ${FILENAME}_tag *__this__, int __c__);"
  echo "static int ${FILENAME}_${ch1}__isend(struct ${FILENAME}_tag *__this__);"
  echo "static int ${FILENAME}_${ch1}__deadState(struct ${FILENAME}_tag *__this__);"
  echo "static int ${FILENAME}_${ch1}__finallyState(struct ${FILENAME}_tag *__this__);"
  echo "static int ${FILENAME}_${ch1}__signal(struct ${FILENAME}_tag *__this__, int e);"
done

#cat fragment
cat fragment | replace_action
cat << EOF
#ifdef NINA_DEBUG
#include <time.h>

#define __logopen()  nina__logopen()
#define __logprint(s, c)  nina__logprint(s, c)
#define __logprints(s, c)  nina__logprints(s, c)
#define __logputs(s)  nina__logputs(s)
#define __logclose()  nina__logclose()
#define __fputtrace(s, c)  nina__fputtrace(s, c)
#define __puttrace(s)  nina__puttrace(s)
#else
#define __logopen()
#define __logprint(s, c)
#define __logprints(s, c)
#define __logputs(s)
#define __logclose()
#define __fputtrace(s, c)
#define __puttrace(s)
#endif

static void nina__LOOKAHEAD(struct ${FILENAME}_tag *b, int c);
static void nina__LOOKAHEAD_COMMIT(struct ${FILENAME}_tag *b);
static void nina__LOOKAHEAD_MARK(struct ${FILENAME}_tag *b);

static int __readf(struct ${FILENAME}_tag *b, nina_stream_t f) {
	return fgetc(*((FILE **)f));
}

static int __reads(struct ${FILENAME}_tag *b, nina_stream_t f) {
	char **s = (char **)f;

	return **s ? *((*s)++) : -1;
}

static int __readsys(struct ${FILENAME}_tag *b, nina_stream_t f) {
	char c[1];
	int r;

	if((r = read(**(int **)f, c, 1)) > 0) {
		return c[0];
	} else if(r == 0) {
		return -1;
	} else {
		longjmp(b->ex, THROW_CODE_ERROR);
	}
}

#ifdef NINA_DEBUG
static FILE *nina__log = NULL;
static void nina__logopen() {
	char fname[128], ftime[20];
	time_t t;
	struct tm *v;

	if(nina__log == NULL) {
		t = time(NULL);
		if((v = localtime(&t)) == NULL)  abort();
		strftime(ftime, sizeof(ftime) - 1, "%Y%m%d%H%M%S", v);
		snprintf(fname, sizeof(fname) - 1, "${FILENAME}.%s.log", ftime);
		nina__log = fopen(fname, "w");
	}
}

static void nina__logprint(char *s, int c) {
	if(nina__log == NULL) {
		/* do nothing */
	} else if(c == '\n') {
		fprintf(nina__log, "%s\\n\n", s);
		fflush(nina__log);
	} else if(c == '\t') {
		fprintf(nina__log, "%s\\t\n", s);
		fflush(nina__log);
	} else if(c == '\r') {
		fprintf(nina__log, "%s\\r\n", s);
		fflush(nina__log);
	} else if(c >= 0 && c <= 0x1f) {
		fprintf(nina__log, "%s\\x%d\n", s, c);
		fflush(nina__log);
	} else if(c >= 0x7f && c <= 0x9f) {
		fprintf(nina__log, "%s\\x%d\n", s, c);
		fflush(nina__log);
	} else {
		fprintf(nina__log, "%s%c\n", s, c);
		fflush(nina__log);
	}
}

static void nina__logprints(char *s, char *t) {
	if(nina__log == NULL) {
		/* do nothing */
	} else {
		fprintf(nina__log, "%s%s\n", s, t);
		fflush(nina__log);
	}
}

static void nina__logputs(char *s) {
	if(nina__log == NULL) {
		/* do nothing */
	} else {
		fprintf(nina__log, "%s\n", s);
		fflush(nina__log);
	}
}

static void nina__logclose() {
	if(nina__log != NULL) {
		fclose(nina__log);
		nina__log = NULL;
	}
}

static void nina__fputtrace(struct ${FILENAME}_tag *b, FILE *p) {
	int s = b->state, k;
	char *g;

	fprintf(p, "Stack trace:\n");
	for(k = b->__slen - 1; k >= 0; k--) {
		g = b->__stk_string[k];
		fprintf(p, "\tAutomaton: %s, state: %d\n", g, s);
		s = b->__sts[k];
	}
	fflush(p);
}

static void nina__puttrace(struct ${FILENAME}_tag *b) {
	nina__fputtrace(b, stderr);
	if(nina__log != NULL)  nina__fputtrace(b, nina__log);
}
#endif

static void nina__GETCC(struct ${FILENAME}_tag *c, ${FILENAME}_continuation *b) {
	b->state = c->state;
	memcpy(b->__sts, c->__sts, sizeof(b->__sts));
	memcpy(b->__stk_step, c->__stk_step, sizeof(b->__stk_step));
	memcpy(b->__stk_accepted, c->__stk_accepted, sizeof(b->__stk_accepted));
	memcpy(b->__stk_execaction, c->__stk_execaction, sizeof(b->__stk_execaction));
	memcpy(b->__stk_deadState, c->__stk_deadState, sizeof(b->__stk_deadState));
	memcpy(b->__stk_finallyState, c->__stk_finallyState, sizeof(b->__stk_finallyState));
	memcpy(b->__stk_signal, c->__stk_signal, sizeof(b->__stk_signal));
	memcpy(b->__stv, c->__stv, sizeof(b->__stv));
	b->__slen = c->__slen;
}

static void nina__SETCC(struct ${FILENAME}_tag *b, ${FILENAME}_continuation *c) {
	b->state = c->state;
	memcpy(b->__sts, c->__sts, sizeof(b->__sts));
	memcpy(b->__stk_step, c->__stk_step, sizeof(b->__stk_step));
	memcpy(b->__stk_accepted, c->__stk_accepted, sizeof(b->__stk_accepted));
	memcpy(b->__stk_execaction, c->__stk_execaction, sizeof(b->__stk_execaction));
	memcpy(b->__stk_deadState, c->__stk_deadState, sizeof(b->__stk_deadState));
	memcpy(b->__stk_finallyState, c->__stk_finallyState, sizeof(b->__stk_finallyState));
	memcpy(b->__stk_signal, c->__stk_signal, sizeof(b->__stk_signal));
	memcpy(b->__stv, c->__stv, sizeof(b->__stv));
	b->__slen = c->__slen;
}

static void nina__write_backtrack(struct ${FILENAME}_tag *b, $CTYPE c) {
	if(b->__backtrack_wptr < 0) {
		/* do nothing */
	} else if(b->__backtrack_wptr < MAX_BACKTRACK) {
		b->__backtrack[b->__backtrack_wptr++] = c;
	} else {
		THROWERROR_C(b);
	}
}

static void nina__BACKTRACK_COMMIT(struct ${FILENAME}_tag *b) {
	if(--b->__backtrack_sptr <= 0) {
		b->__backtrack_state = NULL;
		b->__backtrack_wsym = NULL;
		b->__backtrack_ptrs = NULL;
		b->__backtrack_cont = NULL;
		b->__backtrack_sptr = -1;
		b->__backtrack_wptr = -1;
		__logputs("Commit Backtracking");
	}
}

static int nina__BACKTRACK(struct ${FILENAME}_tag *b, $CTYPE c) {
	if(b->__backtrack_wptr >= 0) {
		b->__backtrack_len = b->__backtrack_wptr;
		b->__backtrack_wptr = -1;
		b->__backtrack_sptr--;
		b->state = b->__backtrack_state[b->__backtrack_sptr];
		b->__backtrack_ptr = b->__backtrack_ptrs[b->__backtrack_sptr];
		b->__backtrack_sym = b->__backtrack_wsym[b->__backtrack_sptr];
		nina__SETCC(b, b->__backtrack_cont + b->__backtrack_sptr);
		__logputs("Rollback Backtracking");
		return NINA_TRUE;
	} else {
		return NINA_FALSE;
	}
}

static void nina__LOOKAHEAD(struct ${FILENAME}_tag *b, $CTYPE c) {
	if(b->__lookaheadw == NULL) {
		b->__lookahead_state = b->state;
		b->__lookaheadw = b->__lookaheadw_buf;
		b->__lookaheadw_ptr = 0;
		b->__lookaheadw[b->__lookaheadw_ptr++] = c;
	} else if(b->__lookaheadw_ptr < MAX_BACKTRACK) {
		b->__lookaheadw[b->__lookaheadw_ptr++] = c;
	} else {
		THROWERROR_C(b);
	}
}

static void nina__copy_lookahead(struct ${FILENAME}_tag *b, int p) {
	if(b->__lookahead == NULL) {
		b->__lookahead = b->__lookahead_buf;
		b->__lookahead_length = b->__lookaheadw_ptr;
	} else if(b->__lookaheadw_ptr < b->__lookahead_length) {
		/* do nothing */
	} else {
		b->__lookahead = b->__lookahead_buf;
		b->__lookahead_length = b->__lookaheadw_ptr;
	}
	memcpy(b->__lookahead, b->__lookaheadw, b->__lookaheadw_ptr);
	b->__lookahead_ptr = p;
	b->__lookaheadw = NULL;
	b->__lookaheadw_ptr = -1;
}

static void nina__LOOKAHEAD_COMMIT(struct ${FILENAME}_tag *b) {
	if(b->__lookahead_mark < 0) {
		b->__lookaheadw = NULL;
		b->__lookaheadw_ptr = -1;
	} else {
		nina__copy_lookahead(b, b->__lookahead_mark);
	}
	b->__lookahead_mark = -1;
	__logputs("Commit Lookahead");
}

static void nina__LOOKAHEAD_RB(struct ${FILENAME}_tag *b) {
	nina__copy_lookahead(b, 0);
	b->state = b->__lookahead_state;
	b->__lookahead_ok = NINA_FALSE;
	b->__lookahead_mark = -1;
	__logputs("Rollback Lookahead");
}

static void nina__LOOKAHEAD_MARK(struct ${FILENAME}_tag *b) {
	b->__lookahead_mark = b->__lookaheadw_ptr;
}

static int nina__read(struct ${FILENAME}_tag *b, nina_stream_t f) {
	int c;

	while(1) {
		if(b->__backtrack_sym >= 0) {
			c = b->__backtrack_sym;
			b->__backtrack_sym = -1;
			__logprint("Read Backtracking: ", c);
		} else if(b->gotoSymbol >= 0) {
			c = b->gotoSymbol;
			b->gotoSymbol = -1;
			__logprint("Read GOTOSYMBOL: ", c);
		} else if(b->unread >= 0) {
			c = b->unread;
			b->unread = -1;
			__logprint("Read unread: ", c);
		} else if(b->__lookahead_ptr >= 0) {
			if(b->__lookahead_ptr < b->__lookahead_length) {
				c = b->__lookahead[b->__lookahead_ptr++];
			} else {
				b->__lookahead = NULL;
				b->__lookahead_ptr = -1;
				c = nina__read(b, f);
			}
			__logprint("Read Lookahead: ", c);
		} else if(b->__backtrack_ptr >= 0) {
			if(b->__backtrack_ptr <b-> __backtrack_len) {
				c = b->__backtrack[b->__backtrack_ptr++];
			} else {
				b->__backtrack = NULL;
				b->__backtrack_ptr = b->__backtrack_wptr = -1;
				c = nina__read(b, f);
			}
			__logprint("Read Backtracking: ", c);
EOF
[ -z "$NEWLINEMODE" ] && cat << EOF
		} else if(b->binunread >= 0) {
			c = b->binunread;
			b->binunread = -1;
EOF
echo "		} else if((c = ${readr}(b, f)) >= 0) {"
[ -z "$NEWLINEMODE" ] && echo "		int d;"
echo "			nina__write_backtrack(b, c);"
echo "			__logprint("Read: ", c);"
[ -z "$NEWLINEMODE" ] && cat << EOF
			if(c != '\r') {
			} else if((d = ${readr}(b, f)) == '\n') {
				c = '\n';
			} else {
				b->binunread = d;
			}
EOF
[ -z "$READSLOW" ] && cat << EOF
		} else {
			b->iseof = ENDMARKER;
			__logputs("Read end-of-file");
		}
EOF
[ -z "$READSLEEP" ] || [ $READSLEEP -lt 0 ] || slp="sleep($READSLEEP);"
[ -z "$READSLOW" ] || cat << EOF
		} else {
			$slp
			continue;
		}
EOF
cat << EOF
		return c;
	}
}

static void nina__unread(struct ${FILENAME}_tag *b, int c) {
	b->unread = c;
	__logprint("Set unread: ", c);
}

static void nina__gotoSymbol(struct ${FILENAME}_tag *b, int c) {
	b->gotoSymbol = c;
	__logprint("Set GOTOSYMBOL: ", c);
}

static void nina__SET_BACKTRACK(struct ${FILENAME}_tag *b, int c) {
	if(b->__backtrack_sym != c) {
		if(b->__backtrack_ptr < 0) {
			b->__backtrack = b->__backtrack_buf;
			b->__backtrack_wptr = 0;
		} else {
			b->__backtrack_wptr = b->__backtrack_ptr;
		}

		if(b->__backtrack_wsym == NULL) {
			b->__backtrack_state = b->__backtrack_state_buf;
			b->__backtrack_wsym = b->__backtrack_wsym_buf;
			b->__backtrack_ptrs = b->__backtrack_ptrs_buf;
			b->__backtrack_cont = b->__backtrack_cont_buf;
			b->__backtrack_sptr = 0;
		} else if(b->__backtrack_sptr >= MAX_BACKTRACK) {
			THROWERROR_C(b);
		}
		b->__backtrack_state[b->__backtrack_sptr] = b->state;
		b->__backtrack_wsym[b->__backtrack_sptr] = c;
		b->__backtrack_ptrs[b->__backtrack_sptr] = b->__backtrack_wptr;
		nina__GETCC(b, b->__backtrack_cont + b->__backtrack_sptr);
		b->__backtrack_sptr++;
		b->__backtrack_flg = NINA_TRUE;
		__logprint("Set Backtrack: ", c);
	}
}
EOF

for i in $SUBAUTOMATA
do
  ch1=`replace_strange_char $i`
  echo
  echo "static int ${FILENAME}_${ch1}__step(struct ${FILENAME}_tag *__this__,"
  echo "		nina_stream_t __rd, int __c__) {"
  echo '	int __l__ = __this__->__lookahead_ok;'
  echo
  echo '	__this__->__lookahead_ok = NINA_TRUE;'
  echo '	switch(__this__->state) {'
  print_states $i
  echo '	}'
  echo '	return 0;'
  echo '}'
  echo

  echo "static int ${FILENAME}_${ch1}__accepted(struct ${FILENAME}_tag *__this__) {"
  print_accepts $i
  echo '}'
  echo

  echo "static int ${FILENAME}_${ch1}__execaction(struct ${FILENAME}_tag *__this__, int __c__) {"
  echo '	switch(__this__->state) {'
  print_actions $i
  echo '	}'
  echo '	return 1;'
  echo '}'
  echo

  echo "static int ${FILENAME}_${ch1}__isend(struct ${FILENAME}_tag *__this__) {"
  print_isend $i
  echo '}'
  echo

  echo "static int ${FILENAME}_${ch1}__deadState(struct ${FILENAME}_tag *__this__) {"
  print_deadstate $i
  echo '}'
  echo

  echo "static int ${FILENAME}_${ch1}__finallyState(struct ${FILENAME}_tag *__this__) {"
  print_finallystate $i
  echo '}'
  echo

  echo "static int ${FILENAME}_${ch1}__signal(struct ${FILENAME}_tag *__this__, int e) {"
  print_recover $i
  echo '}'
  echo
done

ch1=`replace_strange_char ${MAINNAME}`
cat << EOF

int ${FILENAME}_matches(const char *s) {
	struct ${FILENAME}_tag b;
	const char *n;

	memset(&b, 0, sizeof(b));
	for(n = s; *n != 0; n++) {
		if(!${FILENAME}_${ch1}__step((struct ${FILENAME}_tag *)&b, NULL, *n)) {
			return 0;
		}
	}
	return ${FILENAME}_${ch1}__accepted((struct ${FILENAME}_tag *)&b);
}

static int ${FILENAME}_lookingAt(struct ${FILENAME}_tag *o, const char *s) {
	struct ${FILENAME}_tag *b = (struct ${FILENAME}_tag *)o;
	const char *n;
	char *p, *q;

	p = b->buf;  q = NULL;
	memset(b->buf, 0, sizeof(b->buf));
	for(n = s; *n != 0; *(p++) = *(n++)) {
		if(${FILENAME}_${ch1}__accepted(b)) {
			q = p;
		}

		if(p - b->buf >= sizeof(b->buf) - 1 ||
				!${FILENAME}_${ch1}__step(b, NULL, *n)) {
			if(q != NULL) {
				*q = 0;
				return 1;
			} else {
				return 0;
			}
		}
	}

	if(${FILENAME}_${ch1}__accepted(b)) {
		*p = 0;
		return 1;
	} else if(q != NULL) {
		*q = 0;
		return 1;
	} else {
		return 0;
	}
}

static int ${FILENAME}_find(struct ${FILENAME}_tag *o, const char *s) {
	struct ${FILENAME}_tag *b = (struct ${FILENAME}_tag *)o;
	const char *n, *k;
	char *p, *q;
	int x = 0;

	p = b->buf;  q = NULL;
	memset(b->buf, 0, sizeof(b->buf));
	for(k = s; *k != 0; k++) {
		for(n = k; *n != 0; *(p++) = *(n++)) {
			if(${FILENAME}_${ch1}__accepted(b)) {
				q = p;
			}

			if(p - b->buf >= sizeof(b->buf) - 1) {
				if(q != NULL) {
					*q = 0;
					return 1;
				} else {
					return 0;
				}
			} else if(!${FILENAME}_${ch1}__step(b, NULL, *n)) {
				if(q != NULL) {
					*q = 0;
					return 1;
				} else {
					b->state = 0;
					p = b->buf;  *p = 0;
					break;
				}
			}
		}

		if(${FILENAME}_${ch1}__accepted(b)) {
			*p = 0;
			return 1;
		} else if(q != NULL) {
			*q = 0;
			return 1;
		}
	}
	return 0;
}

static int ${FILENAME}_parse_int(struct ${FILENAME}_tag *o,
		nina_stream_t rd, int x, int rt) {
	int b = 0;
	int c = x, a;

	b = __stk_accepted_C(o);
	if(rd == NULL) {
		abort();
	} else if(rt && !__stk_execaction_C(o, NINA_BEGIN)) {
		if(!b)  THROWERROR_C(o);
	}

	do {
		if(c < 0) {
			// do nothing
		} else if(o->__trapped_signal > 0) {
			__logprint("trapped a signal: ", o->__trapped_signal);
			return NINA_SIGNAL;
		} else if((a = __stk_step_C(o, rd, c)) > 0) {
			__logprint("transit: ", c);
			b = __stk_accepted_C(o);
			switch(__stk_execaction_C(o, c)) {
			case NINA_ACCEPT:
				__logprints("accept ", __stk_string_C(o));
				UNGET_C(o, c);
				return NINA_ACCEPT;
			case NINA_FAIL:
				__logprint("match failed: ", c);
				__puttrace();
				UNGET_C(o, c);
				return NINA_FAIL;
			case NINA_HALT_ACCEPT:
				__logprint("machine halted: ", c);
				return NINA_HALT_ACCEPT;
			case NINA_HALT_REJECT:
				__logprint("machine halted: ", c);
				return NINA_HALT_REJECT;
			case NINA_YIELD:
				__logprint("machine yielded: ", c);
				return NINA_YIELD;
			}
			if(o->__backtrack_flg) {
				nina__write_backtrack(o, c);
				o->__backtrack_flg = NINA_FALSE;
			}
		} else if(a < 0) {
			__logprints("entering ", __stk_string_C(o));
			return c;
		} else if(b) {
			__logprints("accept ", __stk_string_C(o));
			UNGET_C(o, c);
			return NINA_ACCEPT;
		} else if(o->__lookaheadw_ptr >= 0) {
			__logprint("match failed: try lookahead: ", c);
			nina__LOOKAHEAD(o, c);
			nina__LOOKAHEAD_RB(o);
			b = __stk_accepted_C(o);
		} else if(nina__BACKTRACK(o, c)) {
			__logprint("match failed: try backtracking: ", c);
		} else {
			__logprint("match failed: ", c);
			__puttrace();
			UNGET_C(o, c);
			o->failchar = c;
			return NINA_FAIL;
		}
	} while((c = nina__read(o, rd)) >= 0);
	if(!b)  THROWERROR_C(o);
	return NINA_ACCEPT;
}

static int ${FILENAME}_execfinally(struct ${FILENAME}_tag *o) {
	int a, b;

	if((a = __stk_finallyState_C(o)) >= 0) {
		b = o->state;  o->state = a;
		switch(__stk_execaction_C(o, NINA_BEGIN)) {
		case NINA_HALT_ACCEPT:
			o->__slen = 0;
			return NINA_TRUE;
		case NINA_HALT_REJECT:
			o->__slen = 0;
			return NINA_FALSE;
		}
		o->state = b;
	}
	return NINA_FAIL;
}

#define EXECFINALLY if((x = ${FILENAME}_execfinally(b)) != NINA_FAIL)  return x
static int ${FILENAME}_parse_generic(struct ${FILENAME}_tag *b, nina_stream_t f) {
	int c = -1, z, x = NINA_FALSE;
	char *s;

	if((z = setjmp(b->ex)) == THROW_CODE_ERROR) {
		fprintf(stderr, "${FILENAME}:error\n");
		return NINA_FALSE;
	} else if(z == THROW_CODE_ACCEPT) {
		return NINA_TRUE;
	} else if(z == THROW_CODE_REJECT) {
		return NINA_FALSE;
	} else if(z) {
		abort();
	}

	__logopen();
	if(b->__slen == 0) {
		x = NINA_TRUE;
		__stk_push_C(b, 0, ${ch1});
	}

	while(1) {
		if((c = ${FILENAME}_parse_int(b, f, c, x)) >= 0) {
			// do nothing
		} else if(c == NINA_SIGNAL) {
			s = __stk_string_C(b);
			while((b->state = __stk_signal_C(b)) < 0) {
				if(b->__slen-- <= 1) {
					EXECFINALLY;
					fprintf(stderr, "${FILENAME}: state %s: signal trapped: %d\n",
							s, b->__trapped_signal);
					b->__trapped_signal = 0;
					__logclose();  return NINA_FALSE;
				}
			}
			b->__trapped_signal = 0;
		} else if(c == NINA_FAIL) {
			s = __stk_string_C(b);
			while((b->state = __stk_deadState_C(b)) < 0) {
				if(b->__slen-- <= 1) {
					EXECFINALLY;
					fprintf(stderr,
							"${FILENAME}:error: state %s: character %c(0x%x)\n",
							s, b->failchar, b->failchar);
					__logclose();  return NINA_FALSE;
				}
			}
		} else if(c == NINA_HALT_ACCEPT) {
			EXECFINALLY;
			b->__slen = 0;  __logclose();  return NINA_TRUE;
		} else if(c == NINA_HALT_REJECT) {
			EXECFINALLY;
			b->__slen = 0;  __logclose();  return NINA_FALSE;
		} else if(c == NINA_YIELD) {
			return NINA_YIELD;
		} else if(b->__slen > 1) {
			EXECFINALLY;
			b->state = b->__sts[--b->__slen];
		} else {
			EXECFINALLY;
			x = __stk_accepted_C(b);
			b->__slen = 0;  __logclose();  return x;
		}
		x = NINA_TRUE;
	}
}

static int ${FILENAME}_setfile(struct ${FILENAME}_tag *b, FILE *rd) {
	if(b->befstream != NULL)  return NINA_FAIL;
	b->read = __readf;
	b->yieldobject = b->befstream = (void *)rd;
	return 0;
}

static int ${FILENAME}_setstring(struct ${FILENAME}_tag *b, const char *rd) {
	if(b->befstream != NULL)  return NINA_FAIL;
	b->read = __reads;
	b->yieldobject = b->befstream = (void *)rd;
	return 0;
}

static int ${FILENAME}_setdescriptor(struct ${FILENAME}_tag *b, int d) {
	if(b->befstream != NULL)  return NINA_FAIL;
	b->read = __readsys;
	b->sys_descriptor = d;
	b->yieldobject = b->befstream = &(b->sys_descriptor);
	return 0;
}

static void *${FILENAME}_parsenext(struct ${FILENAME}_tag *b) {
	void *o;

	if(b->befstream == NULL) {
		return NULL;
	} else if(b->yieldobject == NULL) {
		return NULL;
	} else if(${FILENAME}_parse_generic(b, &(b->befstream)) != NINA_YIELD) {
		if(b->yieldobject == NULL)  return NULL;
		o = b->yieldobject;  b->yieldobject = NULL;
		return o;
	} else {
		if(b->yieldobject == NULL)  return NULL;
		return b->yieldobject;
	}
}

static int ${FILENAME}_parse(struct ${FILENAME}_tag *b, FILE *f) {
	b->read = __readf;
	return ${FILENAME}_parse_generic(b, NEW_NINA_STREAM_FILE(f));
}

static int ${FILENAME}_parse_string(struct ${FILENAME}_tag *b, const char *s) {
	b->read = __reads;
	return ${FILENAME}_parse_generic(b, NEW_NINA_STREAM_STRING(s));
}

static int ${FILENAME}_parse_descriptor(struct ${FILENAME}_tag *b, int d) {
	b->read = __readsys;
	b->sys_descriptor = d;
	b->befstream = &(b->sys_descriptor);
	return ${FILENAME}_parse_generic(b, &(b->befstream));
}

static struct ${FILENAME}_tag *__nina_signal_automaton;
static void __nina_signal(int signo) {
	if(__nina_signal_automaton->__trapped_signal == 0) {
		__nina_signal_automaton->__trapped_signal = signo;
	}
}

void ${FILENAME}_init(struct ${FILENAME}_tag *b) {
	memset(b, 0, sizeof(struct ${FILENAME}_tag));
	b->lookingAt        = ${FILENAME}_lookingAt;
	b->find             = ${FILENAME}_find;
	b->parse            = ${FILENAME}_parse;
	b->parse_string     = ${FILENAME}_parse_string;
	b->parse_descriptor = ${FILENAME}_parse_descriptor;
	b->setfile          = ${FILENAME}_setfile;
	b->setstring        = ${FILENAME}_setstring;
	b->setdescriptor    = ${FILENAME}_setdescriptor;
	b->parsenext        = ${FILENAME}_parsenext;
	b->unread = b->binunread = -1;
	b->gotoSymbol = -1;
	b->__backtrack_ptr  = -1;
	b->__backtrack_len  = -1;
	b->__backtrack_wptr = -1;
	b->__backtrack_sym  = -1;
	b->__backtrack_sptr = -1;
	b->__backtrack_flg  = NINA_FALSE;
	b->__lookahead_mark = -1;
	b->__lookahead_ptr  = -1;
	b->__lookaheadw_ptr = -1;
	b->__lookahead_ok   = NINA_TRUE;
}

void ${FILENAME}_init_signal(struct ${FILENAME}_tag *b) {
	__nina_signal_automaton = b;
EOF
print_inittrap
echo '}'

#
# print header file
#
hfile="/output/${OUTPUT_FILENAME}.h"
cat header > $hfile
sed "s/@@YEAR@@/$YEAR/g
s/@@OWNER@@/$OWNER/g
s/@@ORGANIZATION@@/$ORGANIZATION/g" /license/$LICENSE >> $hfile

cat >> $hfile << EOF
#ifndef DEFINED_NINA_COMMON
#define DEFINED_NINA_COMMON
#include <stdio.h>
#include <setjmp.h>

#define NINA_TRUE 1
#define NINA_FALSE 0
#define NINA_FAIL -9
#define NINA_YIELD -85

#define BACKTRACK_BUFSIZE 1024
#define MAX_BACKTRACK 72
#define MAX_LOOKAHEAD 512
#define NINA_STACKSIZE 91

EOF

cat >> $hfile << EOF
typedef void **nina_stream_t;
#endif

#ifndef DEFINED_${FILENAME}
#define DEFINED_${FILENAME}
EOF

echo "union ${FILENAME}_attrs {" >> $hfile
for i in $SUBAUTOMATA
do
  ch1=`replace_strange_char $i`
  echo "	struct {" >> $hfile
  print_attrs $i >> $hfile
  echo "	} ${ch1};" >> $hfile
done
echo "};" >> $hfile

cat >> $hfile << EOF

struct ${FILENAME}_tag;
typedef struct ${FILENAME}_continuation_tag {
	int state;
	int __sts[NINA_STACKSIZE];
	int ((*__stk_step[NINA_STACKSIZE])(struct ${FILENAME}_tag *, nina_stream_t, int));
	int ((*__stk_accepted[NINA_STACKSIZE])(struct ${FILENAME}_tag *));
	int ((*__stk_execaction[NINA_STACKSIZE])(struct ${FILENAME}_tag *, int));
	int ((*__stk_deadState[NINA_STACKSIZE])(struct ${FILENAME}_tag *));
	int ((*__stk_finallyState[NINA_STACKSIZE])(struct ${FILENAME}_tag *));
	int ((*__stk_signal[NINA_STACKSIZE])(struct ${FILENAME}_tag *, int));
	union ${FILENAME}_attrs __stv[NINA_STACKSIZE];
	int __slen;
} ${FILENAME}_continuation;

struct ${FILENAME}_tag {
	int state;
	int unread;
	int binunread;
	void *iseof;
	char buf[${BUFSIZE}];

	int gotoSymbol;
	int (*read)(struct ${FILENAME}_tag *, nina_stream_t);
	void *befstream;
	int sys_descriptor;
	void *yieldobject;
	jmp_buf ex;
	$CTYPE failchar;

	int __sts[NINA_STACKSIZE];
	int ((*__stk_step[NINA_STACKSIZE])(struct ${FILENAME}_tag *, nina_stream_t, int));
	int ((*__stk_accepted[NINA_STACKSIZE])(struct ${FILENAME}_tag *));
	int ((*__stk_execaction[NINA_STACKSIZE])(struct ${FILENAME}_tag *, int));
	int ((*__stk_deadState[NINA_STACKSIZE])(struct ${FILENAME}_tag *));
	int ((*__stk_finallyState[NINA_STACKSIZE])(struct ${FILENAME}_tag *));
	int ((*__stk_signal[NINA_STACKSIZE])(struct ${FILENAME}_tag *, int));
	char *__stk_string[NINA_STACKSIZE];
	int __slen;

	char __backtrack_buf[BACKTRACK_BUFSIZE];
	char *__backtrack;
	int __backtrack_ptr;
	int __backtrack_len;
	int __backtrack_wptr;
	int __backtrack_sym;

	int __backtrack_state_buf[MAX_BACKTRACK];
	char __backtrack_wsym_buf[MAX_BACKTRACK];
	int __backtrack_ptrs_buf[MAX_BACKTRACK];
	${FILENAME}_continuation __backtrack_cont_buf[MAX_BACKTRACK];
	int *__backtrack_state;
	char *__backtrack_wsym;
	int *__backtrack_ptrs;
	${FILENAME}_continuation *__backtrack_cont;
	int __backtrack_sptr;
	int __backtrack_flg;

	int __lookahead_state;
	int __lookahead_mark;
	char __lookahead_buf[MAX_LOOKAHEAD];
	char *__lookahead;
	int __lookahead_length;
	int __lookahead_ptr;
	char __lookaheadw_buf[MAX_LOOKAHEAD];
	char *__lookaheadw;
	int __lookaheadw_ptr;
	int __lookahead_ok;

	int __trapped_signal;

	int (*lookingAt)(struct ${FILENAME}_tag *b, const char *s);
	int (*find)(struct ${FILENAME}_tag *b, const char *s);
	int (*parse)(struct ${FILENAME}_tag *s, FILE *f);
	int (*parse_string)(struct ${FILENAME}_tag *s, const char *f);
	int (*parse_descriptor)(struct ${FILENAME}_tag *s, int d);
	int (*setfile)(struct ${FILENAME}_tag *b, FILE *rd);
	int (*setstring)(struct ${FILENAME}_tag *b, const char *rd);
	int (*setdescriptor)(struct ${FILENAME}_tag *b, int d);
	void *(*parsenext)(struct ${FILENAME}_tag *b);

	union ${FILENAME}_attrs __stv[NINA_STACKSIZE];
	struct {
EOF
if [ -s field ]
then
  cat field
else
  echo "char dummy;"
fi >> $hfile
cat >> $hfile << EOF
	} __user_fields;
};

#ifdef __cplusplus
extern "C" {
	int ${FILENAME}_matches(const char *s);
	void ${FILENAME}_init(struct ${FILENAME}_tag *s);
	void ${FILENAME}_init_signal(struct ${FILENAME}_tag *s);
}

class ${FILENAME} {
private:
	struct ${FILENAME}_tag ccls;
public:
	${FILENAME}() {
		${FILENAME}_init(&ccls);
	}

	int lookingAt(const char *s) {
		return ccls.lookingAt(&ccls, s);
	}

	int find(const char *s) {
		return ccls.find(&ccls, s);
	}

	int parse(FILE *f) {
		return ccls.parse(&ccls, f);
	}

	int parse_string(const char *s) {
		return ccls.parse_string(&ccls, s);
	}

	int parse_descriptor(int s) {
		return ccls.parse_descriptor(&ccls, s);
	}

	int setfile(FILE *s) {
		return ccls.setfile(&ccls, s);
	}

	int setstring(const char *s) {
		return ccls.setstring(&ccls, s);
	}

	int setdescriptor(int s) {
		return ccls.setdescriptor(&ccls, s);
	}

	void *parsenext() {
		return ccls.parsenext(&ccls);
	}
};
#else
typedef struct ${FILENAME}_tag ${FILENAME};
extern int ${FILENAME}_matches(const char *s);
extern void ${FILENAME}_init(struct ${FILENAME}_tag *s);
extern void ${FILENAME}_init_signal(struct ${FILENAME}_tag *s);
#endif
#endif
EOF
