Blame src/tokscan/tbnf_scan_token.c

ae7810
/**************************************************************/
ae7810
/*  treebnf: a tree oriented bnf library                      */
ae7810
/*  Copyright (C) 2024  SysDeer Technologies, LLC             */
ae7810
/*  Released under GPLv2 and GPLv3; see COPYING.TREEBNF.      */
ae7810
/**************************************************************/
ae7810
ae7810
#include <treebnf/treebnf.h>
ae7810
ae7810
#define TBNF_STATE_STACK_SIZE   (512)
ae7810
ae7810
/* single token, read-only context */
ae7810
int tbnf_scan_token(const struct tbnf_scan_ctx * sctx, struct tbnf_token * tok)
ae7810
{
ae7810
	int ret  = 0;
ae7810
	int len  = 0;
ae7810
	int type = 0;
ae7810
ae7810
	int tidx = 0;
ae7810
	int sidx = sctx->tok_scan_state;
ae7810
ae7810
	for (; tidx < sctx->tok_scan_nents; ) {
ae7810
		if (sctx->tok_scan_tbls[sidx][tidx].tok_scan_fn)
ae7810
			ret = sctx->tok_scan_tbls[sidx][tidx].tok_scan_fn(sctx);
ae7810
ae7810
		if (ret > len) {
ae7810
			len  = ret;
ae7810
			type = tidx;
ae7810
		}
ae7810
ae7810
		tidx++;
ae7810
	}
ae7810
ae7810
	tok->tok_type = type;
ae7810
	tok->tok_len  = len;
ae7810
	tok->tok_off  = sctx->tok_scan_mark - sctx->tok_scan_base;
ae7810
ae7810
	return (len > 0) ? 0 : -1;
ae7810
}
ae7810
ae7810
/* scan up to ntoks tokens, read-write context */
ae7810
int tbnf_scan_tokens(struct tbnf_scan_ctx * sctx, size_t ntoks, struct tbnf_token * tokv, int any)
ae7810
{
ae7810
	int                     ret;
ae7810
	int *                   state;
ae7810
	int *                   stcap;
ae7810
	int                     ststk[TBNF_STATE_STACK_SIZE];
ae7810
	struct tbnf_scan_tbl *  pentry;
ae7810
ae7810
	ret      = 0;
ae7810
	ntoks    = (ntoks > INT32_MAX) ? INT32_MAX : ntoks;
ae7810
ae7810
	state    = ststk;
ae7810
	state[0] = sctx->tok_scan_state;
ae7810
ae7810
	stcap    = &state[TBNF_STATE_STACK_SIZE];
ae7810
	stcap--;
ae7810
ae7810
	/*******************************************************************/
ae7810
	/* a positive return value that's smaller than the original ntoks, */
ae7810
	/* in combination with mark < cap, indicates an error while trying */
ae7810
	/* to obtain the next token.                                       */
ae7810
	/*******************************************************************/
ae7810
ae7810
	for (; ntoks && (sctx->tok_scan_mark < sctx->tok_scan_cap); ) {
ae7810
		if (tbnf_scan_token(sctx,tokv) < 0)
ae7810
			return (ret > 0) ? ret : (-1);
ae7810
ae7810
		pentry = &sctx->tok_scan_tbls[*state][tokv->tok_type];
ae7810
ae7810
		switch (pentry->tok_state_op) {
ae7810
			case TBNF_STATE_POP:
ae7810
				if (state == ststk)
ae7810
					return (-1);
ae7810
ae7810
				state--;
ae7810
				sctx->tok_scan_state = *state;
ae7810
				break;
ae7810
ae7810
			case TBNF_STATE_KEEP:
ae7810
				break;
ae7810
ae7810
			case TBNF_STATE_PUSH:
ae7810
				if (state == stcap)
ae7810
					return (-1);
ae7810
ae7810
				sctx->tok_scan_state = pentry->tok_state_next;
ae7810
				*++state             = sctx->tok_scan_state;
ae7810
				break;
ae7810
		}
ae7810
ae7810
		sctx->tok_scan_type  = tokv->tok_type;
ae7810
		sctx->tok_scan_mark += tokv->tok_len;
ae7810
ae7810
		tokv->tok_any = any;
ae7810
		tokv++;
ae7810
ae7810
		ntoks--;
ae7810
		ret++;
ae7810
	}
ae7810
ae7810
	return ret;
ae7810
}