Exemplo n.º 1
0
static int
eqn_do_define(struct eqn_node *ep)
{
	const char	*start;
	size_t		 sz;
	struct eqn_def	*def;
	int		 i;

	if (NULL == (start = eqn_nextrawtok(ep, &sz))) {
		EQN_MSG(MANDOCERR_EQNEOF, ep);
		return(0);
	}

	/* 
	 * Search for a key that already exists. 
	 * Create a new key if none is found.
	 */

	if (NULL == (def = eqn_def_find(ep, start, sz))) {
		/* Find holes in string array. */
		for (i = 0; i < (int)ep->defsz; i++)
			if (0 == ep->defs[i].keysz)
				break;

		if (i == (int)ep->defsz) {
			ep->defsz++;
			ep->defs = mandoc_realloc
				(ep->defs, ep->defsz * 
				 sizeof(struct eqn_def));
			ep->defs[i].key = ep->defs[i].val = NULL;
		}

		ep->defs[i].keysz = sz;
		ep->defs[i].key = mandoc_realloc
			(ep->defs[i].key, sz + 1);

		memcpy(ep->defs[i].key, start, sz);
		ep->defs[i].key[(int)sz] = '\0';
		def = &ep->defs[i];
	}

	start = eqn_next(ep, ep->data[(int)ep->cur], &sz, 0);

	if (NULL == start) {
		EQN_MSG(MANDOCERR_EQNEOF, ep);
		return(0);
	}

	def->valsz = sz;
	def->val = mandoc_realloc(def->val, sz + 1);
	memcpy(def->val, start, sz);
	def->val[(int)sz] = '\0';
	return(1);
}
Exemplo n.º 2
0
static int
eqn_do_tdefine(struct eqn_node *ep)
{

	if (NULL == eqn_nextrawtok(ep, NULL))
		EQN_MSG(MANDOCERR_EQNEOF, ep);
	else if (NULL == eqn_next(ep, ep->data[(int)ep->cur], NULL, 0))
		EQN_MSG(MANDOCERR_EQNEOF, ep);
	else
		return(1);

	return(0);
}
Exemplo n.º 3
0
static void
eqn_def(struct eqn_node *ep)
{
	const char	*start;
	size_t		 sz;
	struct eqn_def	*def;
	int		 i;

	if ((start = eqn_nextrawtok(ep, &sz)) == NULL) {
		mandoc_msg(MANDOCERR_REQ_EMPTY, ep->parse,
		    ep->eqn.ln, ep->eqn.pos, "define");
		return;
	}

	/*
	 * Search for a key that already exists.
	 * Create a new key if none is found.
	 */
	if (NULL == (def = eqn_def_find(ep, start, sz))) {
		/* Find holes in string array. */
		for (i = 0; i < (int)ep->defsz; i++)
			if (0 == ep->defs[i].keysz)
				break;

		if (i == (int)ep->defsz) {
			ep->defsz++;
			ep->defs = mandoc_reallocarray(ep->defs,
			    ep->defsz, sizeof(struct eqn_def));
			ep->defs[i].key = ep->defs[i].val = NULL;
		}

		def = ep->defs + i;
		free(def->key);
		def->key = mandoc_strndup(start, sz);
		def->keysz = sz;
	}

	start = eqn_next(ep, ep->data[(int)ep->cur], &sz, 0);
	if (start == NULL) {
		mandoc_vmsg(MANDOCERR_REQ_EMPTY, ep->parse,
		    ep->eqn.ln, ep->eqn.pos, "define %s", def->key);
		free(def->key);
		free(def->val);
		def->key = def->val = NULL;
		def->keysz = def->valsz = 0;
		return;
	}
	free(def->val);
	def->val = mandoc_strndup(start, sz);
	def->valsz = sz;
}
Exemplo n.º 4
0
/*
 * Recursively parse an eqn(7) expression.
 */
static enum rofferr
eqn_parse(struct eqn_node *ep, struct eqn_box *parent)
{
	char		 sym[64];
	struct eqn_box	*cur;
	const char	*start;
	char		*p;
	size_t		 i, sz;
	enum eqn_tok	 tok, subtok;
	enum eqn_post	 pos;
	int		 size;

	assert(parent != NULL);

	/*
	 * Empty equation.
	 * Do not add it to the high-level syntax tree.
	 */

	if (ep->data == NULL)
		return(ROFF_IGN);

next_tok:
	tok = eqn_tok_parse(ep, &p);

this_tok:
	switch (tok) {
	case (EQN_TOK_UNDEF):
		eqn_undef(ep);
		break;
	case (EQN_TOK_NDEFINE):
	case (EQN_TOK_DEFINE):
		eqn_def(ep);
		break;
	case (EQN_TOK_TDEFINE):
		if (eqn_nextrawtok(ep, NULL) == NULL ||
		    eqn_next(ep, ep->data[(int)ep->cur], NULL, 0) == NULL)
			mandoc_msg(MANDOCERR_REQ_EMPTY, ep->parse,
			    ep->eqn.ln, ep->eqn.pos, "tdefine");
		break;
	case (EQN_TOK_DELIM):
		eqn_delim(ep);
		break;
	case (EQN_TOK_GFONT):
		if (eqn_nextrawtok(ep, NULL) == NULL)
			mandoc_msg(MANDOCERR_REQ_EMPTY, ep->parse,
			    ep->eqn.ln, ep->eqn.pos, eqn_toks[tok]);
		break;
	case (EQN_TOK_MARK):
	case (EQN_TOK_LINEUP):
		/* Ignore these. */
		break;
	case (EQN_TOK_DYAD):
	case (EQN_TOK_VEC):
	case (EQN_TOK_UNDER):
	case (EQN_TOK_BAR):
	case (EQN_TOK_TILDE):
	case (EQN_TOK_HAT):
	case (EQN_TOK_DOT):
	case (EQN_TOK_DOTDOT):
		if (parent->last == NULL) {
			mandoc_msg(MANDOCERR_EQN_NOBOX, ep->parse,
			    ep->eqn.ln, ep->eqn.pos, eqn_toks[tok]);
			cur = eqn_box_alloc(ep, parent);
			cur->type = EQN_TEXT;
			cur->text = mandoc_strdup("");
		}
		parent = eqn_box_makebinary(ep, EQNPOS_NONE, parent);
		parent->type = EQN_LISTONE;
		parent->expectargs = 1;
		switch (tok) {
		case (EQN_TOK_DOTDOT):
			strlcpy(sym, "\\[ad]", sizeof(sym));
			break;
		case (EQN_TOK_VEC):
			strlcpy(sym, "\\[->]", sizeof(sym));
			break;
		case (EQN_TOK_DYAD):
			strlcpy(sym, "\\[<>]", sizeof(sym));
			break;
		case (EQN_TOK_TILDE):
			strlcpy(sym, "\\[a~]", sizeof(sym));
			break;
		case (EQN_TOK_UNDER):
			strlcpy(sym, "\\[ul]", sizeof(sym));
			break;
		case (EQN_TOK_BAR):
			strlcpy(sym, "\\[rl]", sizeof(sym));
			break;
		case (EQN_TOK_DOT):
			strlcpy(sym, "\\[a.]", sizeof(sym));
			break;
		case (EQN_TOK_HAT):
			strlcpy(sym, "\\[ha]", sizeof(sym));
			break;
		default:
			abort();
		}

		switch (tok) {
		case (EQN_TOK_DOTDOT):
		case (EQN_TOK_VEC):
		case (EQN_TOK_DYAD):
		case (EQN_TOK_TILDE):
		case (EQN_TOK_BAR):
		case (EQN_TOK_DOT):
		case (EQN_TOK_HAT):
			parent->top = mandoc_strdup(sym);
			break;
		case (EQN_TOK_UNDER):
			parent->bottom = mandoc_strdup(sym);
			break;
		default:
			abort();
		}
		parent = parent->parent;
		break;
	case (EQN_TOK_FWD):
	case (EQN_TOK_BACK):
	case (EQN_TOK_DOWN):
	case (EQN_TOK_UP):
		subtok = eqn_tok_parse(ep, NULL);
		if (subtok != EQN_TOK__MAX) {
			mandoc_msg(MANDOCERR_REQ_EMPTY, ep->parse,
			    ep->eqn.ln, ep->eqn.pos, eqn_toks[tok]);
			tok = subtok;
			goto this_tok;
		}
		break;
	case (EQN_TOK_FAT):
	case (EQN_TOK_ROMAN):
	case (EQN_TOK_ITALIC):
	case (EQN_TOK_BOLD):
		while (parent->args == parent->expectargs)
			parent = parent->parent;
		/*
		 * These values apply to the next word or sequence of
		 * words; thus, we mark that we'll have a child with
		 * exactly one of those.
		 */
		parent = eqn_box_alloc(ep, parent);
		parent->type = EQN_LISTONE;
		parent->expectargs = 1;
		switch (tok) {
		case (EQN_TOK_FAT):
			parent->font = EQNFONT_FAT;
			break;
		case (EQN_TOK_ROMAN):
			parent->font = EQNFONT_ROMAN;
			break;
		case (EQN_TOK_ITALIC):
			parent->font = EQNFONT_ITALIC;
			break;
		case (EQN_TOK_BOLD):
			parent->font = EQNFONT_BOLD;
			break;
		default:
			abort();
		}
		break;
	case (EQN_TOK_SIZE):
	case (EQN_TOK_GSIZE):
		/* Accept two values: integral size and a single. */
		if (NULL == (start = eqn_nexttok(ep, &sz))) {
			mandoc_msg(MANDOCERR_REQ_EMPTY, ep->parse,
			    ep->eqn.ln, ep->eqn.pos, eqn_toks[tok]);
			break;
		}
		size = mandoc_strntoi(start, sz, 10);
		if (-1 == size) {
			mandoc_msg(MANDOCERR_IT_NONUM, ep->parse,
			    ep->eqn.ln, ep->eqn.pos, eqn_toks[tok]);
			break;
		}
		if (EQN_TOK_GSIZE == tok) {
			ep->gsize = size;
			break;
		}
		parent = eqn_box_alloc(ep, parent);
		parent->type = EQN_LISTONE;
		parent->expectargs = 1;
		parent->size = size;
		break;
	case (EQN_TOK_FROM):
	case (EQN_TOK_TO):
	case (EQN_TOK_SUB):
	case (EQN_TOK_SUP):
		/*
		 * We have a left-right-associative expression.
		 * Repivot under a positional node, open a child scope
		 * and keep on reading.
		 */
		if (parent->last == NULL) {
			mandoc_msg(MANDOCERR_EQN_NOBOX, ep->parse,
			    ep->eqn.ln, ep->eqn.pos, eqn_toks[tok]);
			cur = eqn_box_alloc(ep, parent);
			cur->type = EQN_TEXT;
			cur->text = mandoc_strdup("");
		}
		/* Handle the "subsup" and "fromto" positions. */
		if (EQN_TOK_SUP == tok && parent->pos == EQNPOS_SUB) {
			parent->expectargs = 3;
			parent->pos = EQNPOS_SUBSUP;
			break;
		}
		if (EQN_TOK_TO == tok && parent->pos == EQNPOS_FROM) {
			parent->expectargs = 3;
			parent->pos = EQNPOS_FROMTO;
			break;
		}
		switch (tok) {
		case (EQN_TOK_FROM):
			pos = EQNPOS_FROM;
			break;
		case (EQN_TOK_TO):
			pos = EQNPOS_TO;
			break;
		case (EQN_TOK_SUP):
			pos = EQNPOS_SUP;
			break;
		case (EQN_TOK_SUB):
			pos = EQNPOS_SUB;
			break;
		default:
			abort();
		}
		parent = eqn_box_makebinary(ep, pos, parent);
		break;
	case (EQN_TOK_SQRT):
		while (parent->args == parent->expectargs)
			parent = parent->parent;
		/*
		 * Accept a left-right-associative set of arguments just
		 * like sub and sup and friends but without rebalancing
		 * under a pivot.
		 */
		parent = eqn_box_alloc(ep, parent);
		parent->type = EQN_SUBEXPR;
		parent->pos = EQNPOS_SQRT;
		parent->expectargs = 1;
		break;
	case (EQN_TOK_OVER):
		/*
		 * We have a right-left-associative fraction.
		 * Close out anything that's currently open, then
		 * rebalance and continue reading.
		 */
		if (parent->last == NULL) {
			mandoc_msg(MANDOCERR_EQN_NOBOX, ep->parse,
			    ep->eqn.ln, ep->eqn.pos, eqn_toks[tok]);
			cur = eqn_box_alloc(ep, parent);
			cur->type = EQN_TEXT;
			cur->text = mandoc_strdup("");
		}
		while (EQN_SUBEXPR == parent->type)
			parent = parent->parent;
		parent = eqn_box_makebinary(ep, EQNPOS_OVER, parent);
		break;
	case (EQN_TOK_RIGHT):
	case (EQN_TOK_BRACE_CLOSE):
		/*
		 * Close out the existing brace.
		 * FIXME: this is a shitty sentinel: we should really
		 * have a native EQN_BRACE type or whatnot.
		 */
		for (cur = parent; cur != NULL; cur = cur->parent)
			if (cur->type == EQN_LIST &&
			    (tok == EQN_TOK_BRACE_CLOSE ||
			     cur->left != NULL))
				break;
		if (cur == NULL) {
			mandoc_msg(MANDOCERR_BLK_NOTOPEN, ep->parse,
			    ep->eqn.ln, ep->eqn.pos, eqn_toks[tok]);
			break;
		}
		parent = cur;
		if (EQN_TOK_RIGHT == tok) {
			if (NULL == (start = eqn_nexttok(ep, &sz))) {
				mandoc_msg(MANDOCERR_REQ_EMPTY,
				    ep->parse, ep->eqn.ln,
				    ep->eqn.pos, eqn_toks[tok]);
				break;
			}
			/* Handling depends on right/left. */
			if (STRNEQ(start, sz, "ceiling", 7)) {
				strlcpy(sym, "\\[rc]", sizeof(sym));
				parent->right = mandoc_strdup(sym);
			} else if (STRNEQ(start, sz, "floor", 5)) {
				strlcpy(sym, "\\[rf]", sizeof(sym));
				parent->right = mandoc_strdup(sym);
			} else
				parent->right = mandoc_strndup(start, sz);
		}
		parent = parent->parent;
		if (EQN_TOK_BRACE_CLOSE == tok && parent &&
		    (parent->type == EQN_PILE ||
		     parent->type == EQN_MATRIX))
			parent = parent->parent;
		/* Close out any "singleton" lists. */
		while (parent && parent->type == EQN_LISTONE &&
		    parent->args == parent->expectargs)
			parent = parent->parent;
		break;
	case (EQN_TOK_BRACE_OPEN):
	case (EQN_TOK_LEFT):
		/*
		 * If we already have something in the stack and we're
		 * in an expression, then rewind til we're not any more
		 * (just like with the text node).
		 */
		while (parent->args == parent->expectargs)
			parent = parent->parent;
		if (EQN_TOK_LEFT == tok &&
		    (start = eqn_nexttok(ep, &sz)) == NULL) {
			mandoc_msg(MANDOCERR_REQ_EMPTY, ep->parse,
			    ep->eqn.ln, ep->eqn.pos, eqn_toks[tok]);
			break;
		}
		parent = eqn_box_alloc(ep, parent);
		parent->type = EQN_LIST;
		if (EQN_TOK_LEFT == tok) {
			if (STRNEQ(start, sz, "ceiling", 7)) {
				strlcpy(sym, "\\[lc]", sizeof(sym));
				parent->left = mandoc_strdup(sym);
			} else if (STRNEQ(start, sz, "floor", 5)) {
				strlcpy(sym, "\\[lf]", sizeof(sym));
				parent->left = mandoc_strdup(sym);
			} else
				parent->left = mandoc_strndup(start, sz);
		}
		break;
	case (EQN_TOK_PILE):
	case (EQN_TOK_LPILE):
	case (EQN_TOK_RPILE):
	case (EQN_TOK_CPILE):
	case (EQN_TOK_CCOL):
	case (EQN_TOK_LCOL):
	case (EQN_TOK_RCOL):
		while (parent->args == parent->expectargs)
			parent = parent->parent;
		parent = eqn_box_alloc(ep, parent);
		parent->type = EQN_PILE;
		parent->expectargs = 1;
		break;
	case (EQN_TOK_ABOVE):
		for (cur = parent; cur != NULL; cur = cur->parent)
			if (cur->type == EQN_PILE)
				break;
		if (cur == NULL) {
			mandoc_msg(MANDOCERR_IT_STRAY, ep->parse,
			    ep->eqn.ln, ep->eqn.pos, eqn_toks[tok]);
			break;
		}
		parent = eqn_box_alloc(ep, cur);
		parent->type = EQN_LIST;
		break;
	case (EQN_TOK_MATRIX):
		while (parent->args == parent->expectargs)
			parent = parent->parent;
		parent = eqn_box_alloc(ep, parent);
		parent->type = EQN_MATRIX;
		parent->expectargs = 1;
		break;
	case (EQN_TOK_EOF):
		/*
		 * End of file!
		 * TODO: make sure we're not in an open subexpression.
		 */
		return(ROFF_EQN);
	default:
		assert(tok == EQN_TOK__MAX);
		assert(NULL != p);
		/*
		 * If we already have something in the stack and we're
		 * in an expression, then rewind til we're not any more.
		 */
		while (parent->args == parent->expectargs)
			parent = parent->parent;
		cur = eqn_box_alloc(ep, parent);
		cur->type = EQN_TEXT;
		for (i = 0; i < EQNSYM__MAX; i++)
			if (0 == strcmp(eqnsyms[i].str, p)) {
				(void)snprintf(sym, sizeof(sym),
					"\\[%s]", eqnsyms[i].sym);
				cur->text = mandoc_strdup(sym);
				free(p);
				break;
			}

		if (i == EQNSYM__MAX)
			cur->text = p;
		/*
		 * Post-process list status.
		 */
		while (parent->type == EQN_LISTONE &&
		    parent->args == parent->expectargs)
			parent = parent->parent;
		break;
	}
	goto next_tok;
}
Exemplo n.º 5
0
/*
 * Get next token without replacement.
 */
static const char *
eqn_nextrawtok(struct eqn_node *ep, size_t *sz)
{

	return(eqn_next(ep, '"', sz, 0));
}
Exemplo n.º 6
0
Arquivo: eqn.c Projeto: 2asoft/freebsd
/*
 * Get the next delimited token using the default current quote
 * character.
 */
static const char *
eqn_nexttok(struct eqn_node *ep, size_t *sz)
{

	return eqn_next(ep, '"', sz, 1);
}