
/********************************************
rexp.c

libmawk changes (C) 2009-2010, Tibor 'Igor2' Palinkas;
based on mawk code coming with the below copyright:

copyright 1991, Michael D. Brennan

This is a source file for mawk, an implementation of
the AWK programming language.

Mawk is distributed without warranty under the terms of
the GNU General Public License, version 2, 1991.
********************************************/

/*  op precedence  parser for regular expressions  */

#include  "rexp.h"


/*  DATA   */
const char *mawk_REerrlist[] = { (const char *) 0,
	/* 1  */ "missing '('",
	/* 2  */ "missing ')'",
	/* 3  */ "bad class -- [], [^] or [",
	/* 4  */ "missing operand",
	/* 5  */ "resource exhaustion -- regular expression too large",
	/* 6  */ "syntax error ^* or ^+"
};

/* E5 is very unlikely to occur */


/* This table drives the operator precedence parser */
static const short table[8][8] = {

/*        0   |   CAT   *   +   ?   (   )   */
/* 0 */ { 0,  L,   L,   L,  L,  L,  L,  E1},
/* | */ { G,  G,   L,   L,  L,  L,  L,  G},
/* CAT*/{ G,  G,   G,   L,  L,  L,  L,  G},
/* * */ { G,  G,   G,   G,  G,  G,  E7, G},
/* + */ { G,  G,   G,   G,  G,  G,  E7, G},
/* ? */ { G,  G,   G,   G,  G,  G,  E7, G},
/* ( */ { E2, L,   L,   L,  L,  L,  L,  EQ},
/* ) */ { G,  G,   G,   G,  G,  G,  E7, G}
};


#define	 STACKSZ   64


PTR mawk_REcompile(mawk_state_t *MAWK, char *re)
{
	MACHINE m_stack[STACKSZ];
	struct op {
		int token;
		int prec;
	} op_stack[STACKSZ];
	register MACHINE *m_ptr;
	register struct op *op_ptr;
	register int t;
	int ern;

	/* do this first because it also checks if we have a
	   run time stack */
	t = mawk_RE_lex_init(MAWK, re);
	if (t < 0) {
		MAWK->REerrno = -t;
		return NULL;
	}

	if (*re == 0) {
		mawk_RESTATE *p = (mawk_RESTATE *) mawk_RE_malloc(MAWK, sizeof(mawk_RESTATE));
		if (p == NULL) {
			MAWK->REerrno = -MEMORY_FAILURE;
			return NULL;
		}
		p->type = M_ACCEPT;
		return (PTR) p;
	}

	/* initialize the stacks  */
	m_ptr = m_stack - 1;
	op_ptr = op_stack;
	op_ptr->token = 0;

	t = mawk_RE_lex(MAWK, m_stack);
	if (t < 0) {
		MAWK->REerrno = -t;
		return  NULL;
	}

	while (1) {
		switch (t) {
		case T_STR:
		case T_ANY:
		case T_U:
		case T_START:
		case T_END:
		case T_CLASS:
			m_ptr++;
			break;

		case 0:										/*  end of reg expr   */
			if (op_ptr->token == 0) {
				/*  done   */
				if (m_ptr == m_stack)
					return (PTR) m_ptr->start;
				else {
					/* machines still on the stack  */
					mawk_RE_panic("values still on machine stack");
				}
			}

			/*  otherwise  fall  thru to default
			   which is operator case  */

		default:

			if ((op_ptr->prec = table[op_ptr->token][t]) == G) {
				do {										/* op_pop   */

					if (op_ptr->token <= T_CAT)	/*binary op */
						m_ptr--;
					/* if not enough values on machine stack
					   then we have a missing operand */
					if (m_ptr < m_stack) {
						MAWK->REerrno = -E4;
						return NULL;
					}

					switch (op_ptr->token) {
					case T_CAT:
						ern = mawk_RE_cat(MAWK, m_ptr, m_ptr + 1);
						if (ern < 0) {
							MAWK->REerrno = -ern;
							return NULL;
						}
						break;

					case T_OR:
						ern = mawk_RE_or(MAWK, m_ptr, m_ptr + 1);
						if (ern < 0) {
							MAWK->REerrno = -ern;
							return NULL;
						}
						break;

					case T_STAR:
						ern = mawk_RE_close(MAWK, m_ptr);
						if (ern < 0) {
							MAWK->REerrno = -ern;
							return NULL;
						}
						break;

					case T_PLUS:
						ern = mawk_RE_poscl(MAWK, m_ptr);
						if (ern < 0) {
							MAWK->REerrno = -ern;
							return NULL;
						}
						break;

					case T_Q:
						ern = mawk_RE_01(MAWK, m_ptr);
						if (ern < 0) {
							MAWK->REerrno = -ern;
							return NULL;
						}
						break;

					default:
						/*nothing on ( or ) */
						break;
					}

					op_ptr--;
				}
				while (op_ptr->prec != L);

				continue;								/* back thru switch at top */
			}

			if (op_ptr->prec < 0) {
				if (op_ptr->prec == E7)
					mawk_RE_panic("parser returns E7");
				else {
					MAWK->REerrno = -op_ptr->prec;
					return NULL;
				}
			}

			if (++op_ptr == op_stack + STACKSZ) {
				/* stack overflow */
				MAWK->REerrno = -E5;
				return NULL;
			}

			op_ptr->token = t;
		}														/* end of switch */

		if (m_ptr == m_stack + (STACKSZ - 1)) {
			/*overflow */
			MAWK->REerrno = -E5;
			return NULL;
		}

		t = mawk_RE_lex(MAWK, m_ptr + 1);
		if (t < 0) {
			MAWK->REerrno = -t;
			return  NULL;
		}
	}
}


/* getting here means a logic flaw or unforeseen case */
void mawk_RE_panic(char *s)
{
	fprintf(stderr, "mawk_REcompile() - panic:  %s\n", s);
	exit(100);
}
