]> git.cameronkatri.com Git - mandoc.git/blobdiff - eqn.c
The .Dd and .TH macros must interrupt .ce, too;
[mandoc.git] / eqn.c
diff --git a/eqn.c b/eqn.c
index 4806b933155fe136bd0d13d625cbb96e9565e43a..f371be5b9e53e3bdbc8193c97bbb828d81a1496c 100644 (file)
--- a/eqn.c
+++ b/eqn.c
@@ -1,4 +1,4 @@
-/*     $Id: eqn.c,v 1.73 2017/07/05 15:03:27 schwarze Exp $ */
+/*     $Id: eqn.c,v 1.76 2017/07/08 14:51:04 schwarze Exp $ */
 /*
  * Copyright (c) 2011, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
  * Copyright (c) 2014, 2015, 2017 Ingo Schwarze <schwarze@openbsd.org>
@@ -27,8 +27,9 @@
 #include <string.h>
 #include <time.h>
 
-#include "mandoc.h"
 #include "mandoc_aux.h"
+#include "mandoc.h"
+#include "roff.h"
 #include "libmandoc.h"
 #include "libroff.h"
 
@@ -284,76 +285,48 @@ enum      parse_mode {
 };
 
 static struct eqn_box  *eqn_box_alloc(struct eqn_node *, struct eqn_box *);
-static void             eqn_box_free(struct eqn_box *);
 static struct eqn_box  *eqn_box_makebinary(struct eqn_node *,
-                               enum eqn_post, struct eqn_box *);
+                               struct eqn_box *);
 static void             eqn_def(struct eqn_node *);
 static struct eqn_def  *eqn_def_find(struct eqn_node *);
 static void             eqn_delim(struct eqn_node *);
 static enum eqn_tok     eqn_next(struct eqn_node *, enum parse_mode);
-static enum rofferr     eqn_parse(struct eqn_node *, struct eqn_box *);
 static void             eqn_undef(struct eqn_node *);
 
 
-enum rofferr
-eqn_read(struct eqn_node **epp, int ln,
-               const char *p, int pos, int *offs)
+struct eqn_node *
+eqn_alloc(struct mparse *parse)
 {
-       size_t           sz;
-       struct eqn_node *ep;
-       enum rofferr     er;
-
-       ep = *epp;
-
-       /*
-        * If we're the terminating mark, unset our equation status and
-        * validate the full equation.
-        */
-
-       if (0 == strncmp(p, ".EN", 3)) {
-               er = eqn_end(epp);
-               p += 3;
-               while (' ' == *p || '\t' == *p)
-                       p++;
-               if ('\0' == *p)
-                       return er;
-               mandoc_vmsg(MANDOCERR_ARG_SKIP, ep->parse,
-                   ln, pos, "EN %s", p);
-               return er;
-       }
-
-       /*
-        * Build up the full string, replacing all newlines with regular
-        * whitespace.
-        */
-
-       sz = strlen(p + pos) + 1;
-       ep->data = mandoc_realloc(ep->data, ep->sz + sz + 1);
+       struct eqn_node *ep;
 
-       /* First invocation: nil terminate the string. */
-
-       if (0 == ep->sz)
-               *ep->data = '\0';
-
-       ep->sz += sz;
-       strlcat(ep->data, p + pos, ep->sz + 1);
-       strlcat(ep->data, " ", ep->sz + 1);
-       return ROFF_IGN;
+       ep = mandoc_calloc(1, sizeof(*ep));
+       ep->parse = parse;
+       ep->gsize = EQN_DEFSIZE;
+       return ep;
 }
 
-struct eqn_node *
-eqn_alloc(int pos, int line, struct mparse *parse)
+void
+eqn_reset(struct eqn_node *ep)
 {
-       struct eqn_node *p;
-
-       p = mandoc_calloc(1, sizeof(struct eqn_node));
+       free(ep->data);
+       ep->data = ep->start = ep->end = NULL;
+       ep->sz = ep->toksz = 0;
+}
 
-       p->parse = parse;
-       p->eqn.ln = line;
-       p->eqn.pos = pos;
-       p->gsize = EQN_DEFSIZE;
+void
+eqn_read(struct eqn_node *ep, const char *p)
+{
+       char            *cp;
 
-       return p;
+       if (ep->data == NULL) {
+               ep->sz = strlen(p);
+               ep->data = mandoc_strdup(p);
+       } else {
+               ep->sz = mandoc_asprintf(&cp, "%s %s", ep->data, p);
+               free(ep->data);
+               ep->data = cp;
+       }
+       ep->sz += 1;
 }
 
 /*
@@ -427,7 +400,7 @@ eqn_next(struct eqn_node *ep, enum parse_mode mode)
                        ep->start++;  /* Skip opening quote. */
                        if (ep->end == NULL) {
                                mandoc_msg(MANDOCERR_ARG_QUOTE, ep->parse,
-                                   ep->eqn.ln, ep->eqn.pos, NULL);
+                                   ep->node->line, ep->node->pos, NULL);
                                ep->end = strchr(ep->start, '\0');
                        }
                } else {
@@ -448,7 +421,7 @@ eqn_next(struct eqn_node *ep, enum parse_mode mode)
                        break;
                if (++lim > EQN_NEST_MAX) {
                        mandoc_msg(MANDOCERR_ROFFLOOP, ep->parse,
-                           ep->eqn.ln, ep->eqn.pos, NULL);
+                           ep->node->line, ep->node->pos, NULL);
                        return EQN_TOK_EOF;
                }
 
@@ -492,7 +465,7 @@ eqn_next(struct eqn_node *ep, enum parse_mode mode)
        return EQN_TOK__MAX;
 }
 
-static void
+void
 eqn_box_free(struct eqn_box *bp)
 {
 
@@ -541,8 +514,7 @@ eqn_box_alloc(struct eqn_node *ep, struct eqn_box *parent)
  * The new EQN_SUBEXPR will have a two-child limit.
  */
 static struct eqn_box *
-eqn_box_makebinary(struct eqn_node *ep,
-       enum eqn_post pos, struct eqn_box *parent)
+eqn_box_makebinary(struct eqn_node *ep, struct eqn_box *parent)
 {
        struct eqn_box  *b, *newb;
 
@@ -554,7 +526,6 @@ eqn_box_makebinary(struct eqn_node *ep,
        parent->last = b->prev;
        b->prev = NULL;
        newb = eqn_box_alloc(ep, parent);
-       newb->pos = pos;
        newb->type = EQN_SUBEXPR;
        newb->expectargs = 2;
        newb->args = 1;
@@ -572,7 +543,7 @@ eqn_delim(struct eqn_node *ep)
 {
        if (ep->end[0] == '\0' || ep->end[1] == '\0') {
                mandoc_msg(MANDOCERR_REQ_EMPTY, ep->parse,
-                   ep->eqn.ln, ep->eqn.pos, "delim");
+                   ep->node->line, ep->node->pos, "delim");
                if (ep->end[0] != '\0')
                        ep->end++;
        } else if (strncmp(ep->end, "off", 3) == 0) {
@@ -599,7 +570,7 @@ eqn_undef(struct eqn_node *ep)
 
        if (eqn_next(ep, MODE_NOSUB) == EQN_TOK_EOF) {
                mandoc_msg(MANDOCERR_REQ_EMPTY, ep->parse,
-                   ep->eqn.ln, ep->eqn.pos, "undef");
+                   ep->node->line, ep->node->pos, "undef");
                return;
        }
        if ((def = eqn_def_find(ep)) == NULL)
@@ -618,7 +589,7 @@ eqn_def(struct eqn_node *ep)
 
        if (eqn_next(ep, MODE_NOSUB) == EQN_TOK_EOF) {
                mandoc_msg(MANDOCERR_REQ_EMPTY, ep->parse,
-                   ep->eqn.ln, ep->eqn.pos, "define");
+                   ep->node->line, ep->node->pos, "define");
                return;
        }
 
@@ -647,7 +618,7 @@ eqn_def(struct eqn_node *ep)
 
        if (eqn_next(ep, MODE_QUOTED) == EQN_TOK_EOF) {
                mandoc_vmsg(MANDOCERR_REQ_EMPTY, ep->parse,
-                   ep->eqn.ln, ep->eqn.pos, "define %s", def->key);
+                   ep->node->line, ep->node->pos, "define %s", def->key);
                free(def->key);
                free(def->val);
                def->key = def->val = NULL;
@@ -659,20 +630,17 @@ eqn_def(struct eqn_node *ep)
        def->valsz = ep->toksz;
 }
 
-/*
- * Recursively parse an eqn(7) expression.
- */
-static enum rofferr
-eqn_parse(struct eqn_node *ep, struct eqn_box *parent)
+void
+eqn_parse(struct eqn_node *ep)
 {
-       struct eqn_box  *cur, *nbox, *split;
+       struct eqn_box  *cur, *nbox, *parent, *split;
        const char      *cp, *cpn;
        char            *p;
        enum eqn_tok     tok;
-       enum eqn_post    pos;
        enum { CCL_LET, CCL_DIG, CCL_PUN } ccl, ccln;
        int              size;
 
+       parent = ep->node->eqn;
        assert(parent != NULL);
 
        /*
@@ -681,7 +649,7 @@ eqn_parse(struct eqn_node *ep, struct eqn_box *parent)
         */
 
        if (ep->data == NULL)
-               return ROFF_IGN;
+               return;
 
        ep->start = ep->end = ep->data + strspn(ep->data, " ^~");
 
@@ -699,7 +667,7 @@ next_tok:
                if (eqn_next(ep, MODE_NOSUB) == EQN_TOK_EOF ||
                    eqn_next(ep, MODE_QUOTED) == EQN_TOK_EOF)
                        mandoc_msg(MANDOCERR_REQ_EMPTY, ep->parse,
-                           ep->eqn.ln, ep->eqn.pos, "tdefine");
+                           ep->node->line, ep->node->pos, "tdefine");
                break;
        case EQN_TOK_DELIM:
                eqn_delim(ep);
@@ -707,7 +675,7 @@ next_tok:
        case EQN_TOK_GFONT:
                if (eqn_next(ep, MODE_SUB) == EQN_TOK_EOF)
                        mandoc_msg(MANDOCERR_REQ_EMPTY, ep->parse,
-                           ep->eqn.ln, ep->eqn.pos, eqn_toks[tok]);
+                           ep->node->line, ep->node->pos, eqn_toks[tok]);
                break;
        case EQN_TOK_MARK:
        case EQN_TOK_LINEUP:
@@ -723,12 +691,12 @@ next_tok:
        case EQN_TOK_DOTDOT:
                if (parent->last == NULL) {
                        mandoc_msg(MANDOCERR_EQN_NOBOX, ep->parse,
-                           ep->eqn.ln, ep->eqn.pos, eqn_toks[tok]);
+                           ep->node->line, ep->node->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, parent);
                parent->type = EQN_LIST;
                parent->expectargs = 1;
                parent->font = EQNFONT_ROMAN;
@@ -768,7 +736,7 @@ next_tok:
        case EQN_TOK_UP:
                if (eqn_next(ep, MODE_SUB) == EQN_TOK_EOF)
                        mandoc_msg(MANDOCERR_REQ_EMPTY, ep->parse,
-                           ep->eqn.ln, ep->eqn.pos, eqn_toks[tok]);
+                           ep->node->line, ep->node->pos, eqn_toks[tok]);
                break;
        case EQN_TOK_FAT:
        case EQN_TOK_ROMAN:
@@ -806,19 +774,21 @@ next_tok:
                /* Accept two values: integral size and a single. */
                if (eqn_next(ep, MODE_SUB) == EQN_TOK_EOF) {
                        mandoc_msg(MANDOCERR_REQ_EMPTY, ep->parse,
-                           ep->eqn.ln, ep->eqn.pos, eqn_toks[tok]);
+                           ep->node->line, ep->node->pos, eqn_toks[tok]);
                        break;
                }
                size = mandoc_strntoi(ep->start, ep->toksz, 10);
                if (-1 == size) {
                        mandoc_msg(MANDOCERR_IT_NONUM, ep->parse,
-                           ep->eqn.ln, ep->eqn.pos, eqn_toks[tok]);
+                           ep->node->line, ep->node->pos, eqn_toks[tok]);
                        break;
                }
                if (EQN_TOK_GSIZE == tok) {
                        ep->gsize = size;
                        break;
                }
+               while (parent->args == parent->expectargs)
+                       parent = parent->parent;
                parent = eqn_box_alloc(ep, parent);
                parent->type = EQN_LIST;
                parent->expectargs = 1;
@@ -835,39 +805,51 @@ next_tok:
                 */
                if (parent->last == NULL) {
                        mandoc_msg(MANDOCERR_EQN_NOBOX, ep->parse,
-                           ep->eqn.ln, ep->eqn.pos, eqn_toks[tok]);
+                           ep->node->line, ep->node->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) {
+               while (parent->expectargs == 1 && parent->args == 1)
+                       parent = parent->parent;
+               if (tok == EQN_TOK_FROM || tok == EQN_TOK_TO)  {
+                       for (cur = parent; cur != NULL; cur = cur->parent)
+                               if (cur->pos == EQNPOS_SUB ||
+                                   cur->pos == EQNPOS_SUP ||
+                                   cur->pos == EQNPOS_SUBSUP ||
+                                   cur->pos == EQNPOS_SQRT ||
+                                   cur->pos == EQNPOS_OVER)
+                                       break;
+                       if (cur != NULL)
+                               parent = cur->parent;
+               }
+               if (tok == EQN_TOK_SUP && parent->pos == EQNPOS_SUB) {
                        parent->expectargs = 3;
                        parent->pos = EQNPOS_SUBSUP;
                        break;
                }
-               if (EQN_TOK_TO == tok && parent->pos == EQNPOS_FROM) {
+               if (tok == EQN_TOK_TO && parent->pos == EQNPOS_FROM) {
                        parent->expectargs = 3;
                        parent->pos = EQNPOS_FROMTO;
                        break;
                }
+               parent = eqn_box_makebinary(ep, parent);
                switch (tok) {
                case EQN_TOK_FROM:
-                       pos = EQNPOS_FROM;
+                       parent->pos = EQNPOS_FROM;
                        break;
                case EQN_TOK_TO:
-                       pos = EQNPOS_TO;
+                       parent->pos = EQNPOS_TO;
                        break;
                case EQN_TOK_SUP:
-                       pos = EQNPOS_SUP;
+                       parent->pos = EQNPOS_SUP;
                        break;
                case EQN_TOK_SUB:
-                       pos = EQNPOS_SUB;
+                       parent->pos = EQNPOS_SUB;
                        break;
                default:
                        abort();
                }
-               parent = eqn_box_makebinary(ep, pos, parent);
                break;
        case EQN_TOK_SQRT:
                while (parent->args == parent->expectargs)
@@ -890,14 +872,17 @@ next_tok:
                 */
                if (parent->last == NULL) {
                        mandoc_msg(MANDOCERR_EQN_NOBOX, ep->parse,
-                           ep->eqn.ln, ep->eqn.pos, eqn_toks[tok]);
+                           ep->node->line, ep->node->pos, eqn_toks[tok]);
                        cur = eqn_box_alloc(ep, parent);
                        cur->type = EQN_TEXT;
                        cur->text = mandoc_strdup("");
                }
+               while (parent->args == parent->expectargs)
+                       parent = parent->parent;
                while (EQN_SUBEXPR == parent->type)
                        parent = parent->parent;
-               parent = eqn_box_makebinary(ep, EQNPOS_OVER, parent);
+               parent = eqn_box_makebinary(ep, parent);
+               parent->pos = EQNPOS_OVER;
                break;
        case EQN_TOK_RIGHT:
        case EQN_TOK_BRACE_CLOSE:
@@ -914,15 +899,15 @@ next_tok:
                                break;
                if (cur == NULL) {
                        mandoc_msg(MANDOCERR_BLK_NOTOPEN, ep->parse,
-                           ep->eqn.ln, ep->eqn.pos, eqn_toks[tok]);
+                           ep->node->line, ep->node->pos, eqn_toks[tok]);
                        break;
                }
                parent = cur;
                if (EQN_TOK_RIGHT == tok) {
                        if (eqn_next(ep, MODE_SUB) == EQN_TOK_EOF) {
                                mandoc_msg(MANDOCERR_REQ_EMPTY,
-                                   ep->parse, ep->eqn.ln,
-                                   ep->eqn.pos, eqn_toks[tok]);
+                                   ep->parse, ep->node->line,
+                                   ep->node->pos, eqn_toks[tok]);
                                break;
                        }
                        /* Handling depends on right/left. */
@@ -957,7 +942,7 @@ next_tok:
                if (EQN_TOK_LEFT == tok &&
                    eqn_next(ep, MODE_SUB) == EQN_TOK_EOF) {
                        mandoc_msg(MANDOCERR_REQ_EMPTY, ep->parse,
-                           ep->eqn.ln, ep->eqn.pos, eqn_toks[tok]);
+                           ep->node->line, ep->node->pos, eqn_toks[tok]);
                        break;
                }
                parent = eqn_box_alloc(ep, parent);
@@ -991,7 +976,7 @@ next_tok:
                                break;
                if (cur == NULL) {
                        mandoc_msg(MANDOCERR_IT_STRAY, ep->parse,
-                           ep->eqn.ln, ep->eqn.pos, eqn_toks[tok]);
+                           ep->node->line, ep->node->pos, eqn_toks[tok]);
                        break;
                }
                parent = eqn_box_alloc(ep, cur);
@@ -1005,11 +990,7 @@ next_tok:
                parent->expectargs = 1;
                break;
        case EQN_TOK_EOF:
-               /*
-                * End of file!
-                * TODO: make sure we're not in an open subexpression.
-                */
-               return ROFF_EQN;
+               return;
        case EQN_TOK__MAX:
        case EQN_TOK_FUNC:
        case EQN_TOK_QUOTED:
@@ -1099,13 +1080,6 @@ next_tok:
                                parent = split->parent;
                        break;
                }
-               /*
-                * Post-process list status.
-                */
-               while (parent->type == EQN_LIST &&
-                   parent->expectargs == 1 &&
-                   parent->args == 1)
-                       parent = parent->parent;
                break;
        default:
                abort();
@@ -1113,26 +1087,11 @@ next_tok:
        goto next_tok;
 }
 
-enum rofferr
-eqn_end(struct eqn_node **epp)
-{
-       struct eqn_node *ep;
-
-       ep = *epp;
-       *epp = NULL;
-
-       ep->eqn.root = mandoc_calloc(1, sizeof(struct eqn_box));
-       ep->eqn.root->expectargs = UINT_MAX;
-       return eqn_parse(ep, ep->eqn.root);
-}
-
 void
 eqn_free(struct eqn_node *p)
 {
        int              i;
 
-       eqn_box_free(p->eqn.root);
-
        for (i = 0; i < (int)p->defsz; i++) {
                free(p->defs[i].key);
                free(p->defs[i].val);