=================================================================== RCS file: /cvs/mandoc/eqn.c,v retrieving revision 1.49 retrieving revision 1.55 diff -u -p -r1.49 -r1.55 --- mandoc/eqn.c 2014/10/10 09:12:44 1.49 +++ mandoc/eqn.c 2014/10/25 14:35:37 1.55 @@ -1,6 +1,7 @@ -/* $Id: eqn.c,v 1.49 2014/10/10 09:12:44 kristaps Exp $ */ +/* $Id: eqn.c,v 1.55 2014/10/25 14:35:37 schwarze Exp $ */ /* - * Copyright (c) 2011 Kristaps Dzonsons + * Copyright (c) 2011, 2014 Kristaps Dzonsons + * Copyright (c) 2014 Ingo Schwarze * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -35,8 +36,6 @@ #define EQN_NEST_MAX 128 /* maximum nesting of defines */ #define STRNEQ(p1, sz1, p2, sz2) \ ((sz1) == (sz2) && 0 == strncmp((p1), (p2), (sz1))) -#define EQNSTREQ(x, p, sz) \ - STRNEQ((x)->name, (x)->sz, (p), (sz)) enum eqn_tok { EQN_TOK_DYAD = 0, @@ -314,24 +313,12 @@ eqn_read(struct eqn_node **epp, int ln, } struct eqn_node * -eqn_alloc(const char *name, int pos, int line, struct mparse *parse) +eqn_alloc(int pos, int line, struct mparse *parse) { struct eqn_node *p; - size_t sz; - const char *end; p = mandoc_calloc(1, sizeof(struct eqn_node)); - if (name && '\0' != *name) { - sz = strlen(name); - assert(sz); - do { - sz--; - end = name + (int)sz; - } while (' ' == *end || '\t' == *end); - p->eqn.name = mandoc_strndup(name, sz + 1); - } - p->parse = parse; p->eqn.ln = line; p->eqn.pos = pos; @@ -486,13 +473,22 @@ eqn_tok_parse(struct eqn_node *ep, char **p) { const char *start; size_t i, sz; + int quoted; if (NULL != p) *p = NULL; + quoted = ep->data[ep->cur] == '"'; + if (NULL == (start = eqn_nexttok(ep, &sz))) return(EQN_TOK_EOF); + if (quoted) { + if (p != NULL) + *p = mandoc_strndup(start, sz); + return(EQN_TOK__MAX); + } + for (i = 0; i < EQN_TOK__MAX; i++) { if (NULL == eqn_toks[i]) continue; @@ -537,10 +533,7 @@ eqn_box_alloc(struct eqn_node *ep, struct eqn_box *par bp->expectargs = UINT_MAX; bp->size = ep->gsize; - assert(NULL != parent); - if (NULL != parent->first) { - assert(NULL != parent->last); parent->last->next = bp; bp->prev = parent->last; } else @@ -557,7 +550,7 @@ eqn_box_alloc(struct eqn_node *ep, struct eqn_box *par * The new EQN_SUBEXPR will have a two-child limit. */ static struct eqn_box * -eqn_box_makebinary(struct eqn_node *ep, +eqn_box_makebinary(struct eqn_node *ep, enum eqn_post pos, struct eqn_box *parent) { struct eqn_box *b, *newb; @@ -581,6 +574,30 @@ eqn_box_makebinary(struct eqn_node *ep, } /* + * Parse the "delim" control statement. + */ +static void +eqn_delim(struct eqn_node *ep) +{ + const char *start; + size_t sz; + + if ((start = eqn_nextrawtok(ep, &sz)) == NULL) + mandoc_msg(MANDOCERR_REQ_EMPTY, ep->parse, + ep->eqn.ln, ep->eqn.pos, "delim"); + else if (strncmp(start, "off", 3) == 0) + ep->delim = 0; + else if (strncmp(start, "on", 2) == 0) { + if (ep->odelim && ep->cdelim) + ep->delim = 1; + } else if (start[1] != '\0') { + ep->odelim = start[0]; + ep->cdelim = start[1]; + ep->delim = 1; + } +} + +/* * Undefine a previously-defined string. */ static int @@ -659,7 +676,7 @@ static int eqn_parse(struct eqn_node *ep, struct eqn_box *parent) { char *p; - enum eqn_tok tok; + enum eqn_tok tok, subtok; enum eqn_post pos; struct eqn_box *cur; int rc, size; @@ -668,9 +685,12 @@ eqn_parse(struct eqn_node *ep, struct eqn_box *parent) const char *start; assert(NULL != parent); -again: - - switch ((tok = eqn_tok_parse(ep, &p))) { + +next_tok: + tok = eqn_tok_parse(ep, &p); + +this_tok: + switch (tok) { case (EQN_TOK_UNDEF): if ((rc = eqn_undef(ep)) <= 0) return(rc); @@ -683,16 +703,17 @@ again: case (EQN_TOK_TDEFINE): if (NULL == eqn_nextrawtok(ep, NULL)) EQN_MSG(MANDOCERR_EQNEOF, ep); - else if (NULL == eqn_next(ep, + else if (NULL == eqn_next(ep, ep->data[(int)ep->cur], NULL, 0)) EQN_MSG(MANDOCERR_EQNEOF, ep); break; case (EQN_TOK_DELIM): + eqn_delim(ep); + break; case (EQN_TOK_GFONT): - if (NULL == eqn_nextrawtok(ep, NULL)) { - EQN_MSG(MANDOCERR_EQNSYNT, ep); - return(-1); - } + 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): @@ -706,12 +727,14 @@ again: case (EQN_TOK_HAT): case (EQN_TOK_DOT): case (EQN_TOK_DOTDOT): - if (NULL == parent->last) { - EQN_MSG(MANDOCERR_EQNSYNT, ep); - return(-1); + 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 = eqn_box_makebinary(ep, EQNPOS_NONE, parent); parent->type = EQN_LISTONE; parent->expectargs = 1; switch (tok) { @@ -765,10 +788,12 @@ again: case (EQN_TOK_BACK): case (EQN_TOK_DOWN): case (EQN_TOK_UP): - tok = eqn_tok_parse(ep, NULL); - if (EQN_TOK__MAX != tok) { - EQN_MSG(MANDOCERR_EQNSYNT, ep); - return(-1); + 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): @@ -776,10 +801,7 @@ again: case (EQN_TOK_ITALIC): case (EQN_TOK_BOLD): while (parent->args == parent->expectargs) - if (NULL == (parent = parent->parent)) { - EQN_MSG(MANDOCERR_EQNSYNT, ep); - return(-1); - } + parent = parent->parent; /* * These values apply to the next word or sequence of * words; thus, we mark that we'll have a child with @@ -809,13 +831,15 @@ again: case (EQN_TOK_GSIZE): /* Accept two values: integral size and a single. */ if (NULL == (start = eqn_nexttok(ep, &sz))) { - EQN_MSG(MANDOCERR_EQNSYNT, ep); - return(-1); + 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) { - EQN_MSG(MANDOCERR_EQNSYNT, ep); - return(-1); + 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; @@ -835,9 +859,12 @@ again: * Repivot under a positional node, open a child scope * and keep on reading. */ - if (NULL == parent->last) { - EQN_MSG(MANDOCERR_EQNSYNT, ep); - return(-1); + 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) { @@ -870,11 +897,8 @@ again: break; case (EQN_TOK_SQRT): while (parent->args == parent->expectargs) - if (NULL == (parent = parent->parent)) { - EQN_MSG(MANDOCERR_EQNSYNT, ep); - return(-1); - } - /* + parent = parent->parent; + /* * Accept a left-right-associative set of arguments just * like sub and sup and friends but without rebalancing * under a pivot. @@ -890,15 +914,15 @@ again: * Close out anything that's currently open, then * rebalance and continue reading. */ - if (NULL == parent->last) { - EQN_MSG(MANDOCERR_EQNSYNT, ep); - return(-1); + 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) - if (NULL == (parent = parent->parent)) { - EQN_MSG(MANDOCERR_EQNSYNT, ep); - return(-1); - } + parent = parent->parent; parent = eqn_box_makebinary(ep, EQNPOS_OVER, parent); break; case (EQN_TOK_RIGHT): @@ -908,19 +932,23 @@ again: * FIXME: this is a shitty sentinel: we should really * have a native EQN_BRACE type or whatnot. */ - while (parent->type != EQN_LIST) - if (NULL == (parent = parent->parent)) { - EQN_MSG(MANDOCERR_EQNSYNT, ep); - return(-1); - } + 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 == parent->left) { - EQN_MSG(MANDOCERR_EQNSYNT, ep); - return(-1); - } if (NULL == (start = eqn_nexttok(ep, &sz))) { - EQN_MSG(MANDOCERR_EQNSYNT, ep); - return(-1); + 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)) { @@ -929,24 +957,18 @@ again: } else if (STRNEQ(start, sz, "floor", 5)) { strlcpy(sym, "\\[rf]", sizeof(sym)); parent->right = mandoc_strdup(sym); - } else + } else parent->right = mandoc_strndup(start, sz); } - if (NULL == (parent = parent->parent)) { - EQN_MSG(MANDOCERR_EQNSYNT, ep); - return(-1); - } - if (EQN_TOK_BRACE_CLOSE == tok && parent && - (parent->type == EQN_PILE || - parent->type == EQN_MATRIX)) + 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->type == EQN_LISTONE && - parent->args == parent->expectargs) - if (NULL == (parent = parent->parent)) { - EQN_MSG(MANDOCERR_EQNSYNT, ep); - return(-1); - } + while (parent->type == EQN_LISTONE && + parent->args == parent->expectargs) + parent = parent->parent; break; case (EQN_TOK_BRACE_OPEN): case (EQN_TOK_LEFT): @@ -956,25 +978,23 @@ again: * (just like with the text node). */ while (parent->args == parent->expectargs) - if (NULL == (parent = parent->parent)) { - EQN_MSG(MANDOCERR_EQNSYNT, ep); - return(-1); - } + 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 (NULL == (start = eqn_nexttok(ep, &sz))) { - EQN_MSG(MANDOCERR_EQNSYNT, ep); - return(-1); - } - /* Handling depends on right/left. */ 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 + } else parent->left = mandoc_strndup(start, sz); } break; @@ -986,46 +1006,33 @@ again: case (EQN_TOK_LCOL): case (EQN_TOK_RCOL): while (parent->args == parent->expectargs) - if (NULL == (parent = parent->parent)) { - EQN_MSG(MANDOCERR_EQNSYNT, ep); - return(-1); - } - if (EQN_TOK_BRACE_OPEN != eqn_tok_parse(ep, NULL)) { - EQN_MSG(MANDOCERR_EQNSYNT, ep); - return(-1); - } + parent = parent->parent; parent = eqn_box_alloc(ep, parent); parent->type = EQN_PILE; - parent = eqn_box_alloc(ep, parent); - parent->type = EQN_LIST; + parent->expectargs = 1; break; case (EQN_TOK_ABOVE): - while (parent->type != EQN_PILE) - if (NULL == (parent = parent->parent)) { - EQN_MSG(MANDOCERR_EQNSYNT, ep); - return(-1); - } - parent = eqn_box_alloc(ep, parent); + 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) - if (NULL == (parent = parent->parent)) { - EQN_MSG(MANDOCERR_EQNSYNT, ep); - return(-1); - } - if (EQN_TOK_BRACE_OPEN != eqn_tok_parse(ep, NULL)) { - EQN_MSG(MANDOCERR_EQNSYNT, ep); - return(-1); - } + parent = parent->parent; parent = eqn_box_alloc(ep, parent); parent->type = EQN_MATRIX; - parent = eqn_box_alloc(ep, parent); - parent->type = EQN_LIST; + parent->expectargs = 1; break; case (EQN_TOK_EOF): /* - * End of file! + * End of file! * TODO: make sure we're not in an open subexpression. */ return(0); @@ -1037,16 +1044,12 @@ again: * in an expression, then rewind til we're not any more. */ while (parent->args == parent->expectargs) - if (NULL == (parent = parent->parent)) { - EQN_MSG(MANDOCERR_EQNSYNT, ep); - free(p); - return(-1); - } + 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), + (void)snprintf(sym, sizeof(sym), "\\[%s]", eqnsyms[i].sym); cur->text = mandoc_strdup(sym); free(p); @@ -1058,19 +1061,16 @@ again: /* * Post-process list status. */ - while (parent->type == EQN_LISTONE && - parent->args == parent->expectargs) - if (NULL == (parent = parent->parent)) { - EQN_MSG(MANDOCERR_EQNSYNT, ep); - return(-1); - } + while (parent->type == EQN_LISTONE && + parent->args == parent->expectargs) + parent = parent->parent; break; } - goto again; + goto next_tok; } enum rofferr -eqn_end(struct eqn_node **epp) +eqn_end(struct eqn_node **epp) { struct eqn_node *ep; @@ -1094,7 +1094,6 @@ eqn_free(struct eqn_node *p) free(p->defs[i].val); } - free(p->eqn.name); free(p->data); free(p->defs); free(p);