]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/mandoc/eqn.c
readelf: add newline after dumping dynamic FLAGS / FLAGS_1
[FreeBSD/FreeBSD.git] / contrib / mandoc / eqn.c
1 /*      $Id: eqn.c,v 1.78 2017/07/15 16:26:17 schwarze Exp $ */
2 /*
3  * Copyright (c) 2011, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
4  * Copyright (c) 2014, 2015, 2017 Ingo Schwarze <schwarze@openbsd.org>
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 #include "config.h"
19
20 #include <sys/types.h>
21
22 #include <assert.h>
23 #include <ctype.h>
24 #include <limits.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <time.h>
29
30 #include "mandoc_aux.h"
31 #include "mandoc.h"
32 #include "roff.h"
33 #include "libmandoc.h"
34 #include "libroff.h"
35
36 #define EQN_NEST_MAX     128 /* maximum nesting of defines */
37 #define STRNEQ(p1, sz1, p2, sz2) \
38         ((sz1) == (sz2) && 0 == strncmp((p1), (p2), (sz1)))
39
40 enum    eqn_tok {
41         EQN_TOK_DYAD = 0,
42         EQN_TOK_VEC,
43         EQN_TOK_UNDER,
44         EQN_TOK_BAR,
45         EQN_TOK_TILDE,
46         EQN_TOK_HAT,
47         EQN_TOK_DOT,
48         EQN_TOK_DOTDOT,
49         EQN_TOK_FWD,
50         EQN_TOK_BACK,
51         EQN_TOK_DOWN,
52         EQN_TOK_UP,
53         EQN_TOK_FAT,
54         EQN_TOK_ROMAN,
55         EQN_TOK_ITALIC,
56         EQN_TOK_BOLD,
57         EQN_TOK_SIZE,
58         EQN_TOK_SUB,
59         EQN_TOK_SUP,
60         EQN_TOK_SQRT,
61         EQN_TOK_OVER,
62         EQN_TOK_FROM,
63         EQN_TOK_TO,
64         EQN_TOK_BRACE_OPEN,
65         EQN_TOK_BRACE_CLOSE,
66         EQN_TOK_GSIZE,
67         EQN_TOK_GFONT,
68         EQN_TOK_MARK,
69         EQN_TOK_LINEUP,
70         EQN_TOK_LEFT,
71         EQN_TOK_RIGHT,
72         EQN_TOK_PILE,
73         EQN_TOK_LPILE,
74         EQN_TOK_RPILE,
75         EQN_TOK_CPILE,
76         EQN_TOK_MATRIX,
77         EQN_TOK_CCOL,
78         EQN_TOK_LCOL,
79         EQN_TOK_RCOL,
80         EQN_TOK_DELIM,
81         EQN_TOK_DEFINE,
82         EQN_TOK_TDEFINE,
83         EQN_TOK_NDEFINE,
84         EQN_TOK_UNDEF,
85         EQN_TOK_ABOVE,
86         EQN_TOK__MAX,
87         EQN_TOK_FUNC,
88         EQN_TOK_QUOTED,
89         EQN_TOK_SYM,
90         EQN_TOK_EOF
91 };
92
93 static  const char *eqn_toks[EQN_TOK__MAX] = {
94         "dyad", /* EQN_TOK_DYAD */
95         "vec", /* EQN_TOK_VEC */
96         "under", /* EQN_TOK_UNDER */
97         "bar", /* EQN_TOK_BAR */
98         "tilde", /* EQN_TOK_TILDE */
99         "hat", /* EQN_TOK_HAT */
100         "dot", /* EQN_TOK_DOT */
101         "dotdot", /* EQN_TOK_DOTDOT */
102         "fwd", /* EQN_TOK_FWD * */
103         "back", /* EQN_TOK_BACK */
104         "down", /* EQN_TOK_DOWN */
105         "up", /* EQN_TOK_UP */
106         "fat", /* EQN_TOK_FAT */
107         "roman", /* EQN_TOK_ROMAN */
108         "italic", /* EQN_TOK_ITALIC */
109         "bold", /* EQN_TOK_BOLD */
110         "size", /* EQN_TOK_SIZE */
111         "sub", /* EQN_TOK_SUB */
112         "sup", /* EQN_TOK_SUP */
113         "sqrt", /* EQN_TOK_SQRT */
114         "over", /* EQN_TOK_OVER */
115         "from", /* EQN_TOK_FROM */
116         "to", /* EQN_TOK_TO */
117         "{", /* EQN_TOK_BRACE_OPEN */
118         "}", /* EQN_TOK_BRACE_CLOSE */
119         "gsize", /* EQN_TOK_GSIZE */
120         "gfont", /* EQN_TOK_GFONT */
121         "mark", /* EQN_TOK_MARK */
122         "lineup", /* EQN_TOK_LINEUP */
123         "left", /* EQN_TOK_LEFT */
124         "right", /* EQN_TOK_RIGHT */
125         "pile", /* EQN_TOK_PILE */
126         "lpile", /* EQN_TOK_LPILE */
127         "rpile", /* EQN_TOK_RPILE */
128         "cpile", /* EQN_TOK_CPILE */
129         "matrix", /* EQN_TOK_MATRIX */
130         "ccol", /* EQN_TOK_CCOL */
131         "lcol", /* EQN_TOK_LCOL */
132         "rcol", /* EQN_TOK_RCOL */
133         "delim", /* EQN_TOK_DELIM */
134         "define", /* EQN_TOK_DEFINE */
135         "tdefine", /* EQN_TOK_TDEFINE */
136         "ndefine", /* EQN_TOK_NDEFINE */
137         "undef", /* EQN_TOK_UNDEF */
138         "above", /* EQN_TOK_ABOVE */
139 };
140
141 static  const char *const eqn_func[] = {
142         "acos", "acsc", "and",  "arc",  "asec", "asin", "atan",
143         "cos",  "cosh", "coth", "csc",  "det",  "exp",  "for",
144         "if",   "lim",  "ln",   "log",  "max",  "min",
145         "sec",  "sin",  "sinh", "tan",  "tanh", "Im",   "Re",
146 };
147
148 enum    eqn_symt {
149         EQNSYM_alpha = 0,
150         EQNSYM_beta,
151         EQNSYM_chi,
152         EQNSYM_delta,
153         EQNSYM_epsilon,
154         EQNSYM_eta,
155         EQNSYM_gamma,
156         EQNSYM_iota,
157         EQNSYM_kappa,
158         EQNSYM_lambda,
159         EQNSYM_mu,
160         EQNSYM_nu,
161         EQNSYM_omega,
162         EQNSYM_omicron,
163         EQNSYM_phi,
164         EQNSYM_pi,
165         EQNSYM_ps,
166         EQNSYM_rho,
167         EQNSYM_sigma,
168         EQNSYM_tau,
169         EQNSYM_theta,
170         EQNSYM_upsilon,
171         EQNSYM_xi,
172         EQNSYM_zeta,
173         EQNSYM_DELTA,
174         EQNSYM_GAMMA,
175         EQNSYM_LAMBDA,
176         EQNSYM_OMEGA,
177         EQNSYM_PHI,
178         EQNSYM_PI,
179         EQNSYM_PSI,
180         EQNSYM_SIGMA,
181         EQNSYM_THETA,
182         EQNSYM_UPSILON,
183         EQNSYM_XI,
184         EQNSYM_inter,
185         EQNSYM_union,
186         EQNSYM_prod,
187         EQNSYM_int,
188         EQNSYM_sum,
189         EQNSYM_grad,
190         EQNSYM_del,
191         EQNSYM_times,
192         EQNSYM_cdot,
193         EQNSYM_nothing,
194         EQNSYM_approx,
195         EQNSYM_prime,
196         EQNSYM_half,
197         EQNSYM_partial,
198         EQNSYM_inf,
199         EQNSYM_muchgreat,
200         EQNSYM_muchless,
201         EQNSYM_larrow,
202         EQNSYM_rarrow,
203         EQNSYM_pm,
204         EQNSYM_nequal,
205         EQNSYM_equiv,
206         EQNSYM_lessequal,
207         EQNSYM_moreequal,
208         EQNSYM_minus,
209         EQNSYM__MAX
210 };
211
212 struct  eqnsym {
213         const char      *str;
214         const char      *sym;
215 };
216
217 static  const struct eqnsym eqnsyms[EQNSYM__MAX] = {
218         { "alpha", "*a" }, /* EQNSYM_alpha */
219         { "beta", "*b" }, /* EQNSYM_beta */
220         { "chi", "*x" }, /* EQNSYM_chi */
221         { "delta", "*d" }, /* EQNSYM_delta */
222         { "epsilon", "*e" }, /* EQNSYM_epsilon */
223         { "eta", "*y" }, /* EQNSYM_eta */
224         { "gamma", "*g" }, /* EQNSYM_gamma */
225         { "iota", "*i" }, /* EQNSYM_iota */
226         { "kappa", "*k" }, /* EQNSYM_kappa */
227         { "lambda", "*l" }, /* EQNSYM_lambda */
228         { "mu", "*m" }, /* EQNSYM_mu */
229         { "nu", "*n" }, /* EQNSYM_nu */
230         { "omega", "*w" }, /* EQNSYM_omega */
231         { "omicron", "*o" }, /* EQNSYM_omicron */
232         { "phi", "*f" }, /* EQNSYM_phi */
233         { "pi", "*p" }, /* EQNSYM_pi */
234         { "psi", "*q" }, /* EQNSYM_psi */
235         { "rho", "*r" }, /* EQNSYM_rho */
236         { "sigma", "*s" }, /* EQNSYM_sigma */
237         { "tau", "*t" }, /* EQNSYM_tau */
238         { "theta", "*h" }, /* EQNSYM_theta */
239         { "upsilon", "*u" }, /* EQNSYM_upsilon */
240         { "xi", "*c" }, /* EQNSYM_xi */
241         { "zeta", "*z" }, /* EQNSYM_zeta */
242         { "DELTA", "*D" }, /* EQNSYM_DELTA */
243         { "GAMMA", "*G" }, /* EQNSYM_GAMMA */
244         { "LAMBDA", "*L" }, /* EQNSYM_LAMBDA */
245         { "OMEGA", "*W" }, /* EQNSYM_OMEGA */
246         { "PHI", "*F" }, /* EQNSYM_PHI */
247         { "PI", "*P" }, /* EQNSYM_PI */
248         { "PSI", "*Q" }, /* EQNSYM_PSI */
249         { "SIGMA", "*S" }, /* EQNSYM_SIGMA */
250         { "THETA", "*H" }, /* EQNSYM_THETA */
251         { "UPSILON", "*U" }, /* EQNSYM_UPSILON */
252         { "XI", "*C" }, /* EQNSYM_XI */
253         { "inter", "ca" }, /* EQNSYM_inter */
254         { "union", "cu" }, /* EQNSYM_union */
255         { "prod", "product" }, /* EQNSYM_prod */
256         { "int", "integral" }, /* EQNSYM_int */
257         { "sum", "sum" }, /* EQNSYM_sum */
258         { "grad", "gr" }, /* EQNSYM_grad */
259         { "del", "gr" }, /* EQNSYM_del */
260         { "times", "mu" }, /* EQNSYM_times */
261         { "cdot", "pc" }, /* EQNSYM_cdot */
262         { "nothing", "&" }, /* EQNSYM_nothing */
263         { "approx", "~~" }, /* EQNSYM_approx */
264         { "prime", "fm" }, /* EQNSYM_prime */
265         { "half", "12" }, /* EQNSYM_half */
266         { "partial", "pd" }, /* EQNSYM_partial */
267         { "inf", "if" }, /* EQNSYM_inf */
268         { ">>", ">>" }, /* EQNSYM_muchgreat */
269         { "<<", "<<" }, /* EQNSYM_muchless */
270         { "<-", "<-" }, /* EQNSYM_larrow */
271         { "->", "->" }, /* EQNSYM_rarrow */
272         { "+-", "+-" }, /* EQNSYM_pm */
273         { "!=", "!=" }, /* EQNSYM_nequal */
274         { "==", "==" }, /* EQNSYM_equiv */
275         { "<=", "<=" }, /* EQNSYM_lessequal */
276         { ">=", ">=" }, /* EQNSYM_moreequal */
277         { "-", "mi" }, /* EQNSYM_minus */
278 };
279
280 enum    parse_mode {
281         MODE_QUOTED,
282         MODE_NOSUB,
283         MODE_SUB,
284         MODE_TOK
285 };
286
287 static  struct eqn_box  *eqn_box_alloc(struct eqn_node *, struct eqn_box *);
288 static  struct eqn_box  *eqn_box_makebinary(struct eqn_node *,
289                                 struct eqn_box *);
290 static  void             eqn_def(struct eqn_node *);
291 static  struct eqn_def  *eqn_def_find(struct eqn_node *);
292 static  void             eqn_delim(struct eqn_node *);
293 static  enum eqn_tok     eqn_next(struct eqn_node *, enum parse_mode);
294 static  void             eqn_undef(struct eqn_node *);
295
296
297 struct eqn_node *
298 eqn_alloc(struct mparse *parse)
299 {
300         struct eqn_node *ep;
301
302         ep = mandoc_calloc(1, sizeof(*ep));
303         ep->parse = parse;
304         ep->gsize = EQN_DEFSIZE;
305         return ep;
306 }
307
308 void
309 eqn_reset(struct eqn_node *ep)
310 {
311         free(ep->data);
312         ep->data = ep->start = ep->end = NULL;
313         ep->sz = ep->toksz = 0;
314 }
315
316 void
317 eqn_read(struct eqn_node *ep, const char *p)
318 {
319         char            *cp;
320
321         if (ep->data == NULL) {
322                 ep->sz = strlen(p);
323                 ep->data = mandoc_strdup(p);
324         } else {
325                 ep->sz = mandoc_asprintf(&cp, "%s %s", ep->data, p);
326                 free(ep->data);
327                 ep->data = cp;
328         }
329         ep->sz += 1;
330 }
331
332 /*
333  * Find the key "key" of the give size within our eqn-defined values.
334  */
335 static struct eqn_def *
336 eqn_def_find(struct eqn_node *ep)
337 {
338         int              i;
339
340         for (i = 0; i < (int)ep->defsz; i++)
341                 if (ep->defs[i].keysz && STRNEQ(ep->defs[i].key,
342                     ep->defs[i].keysz, ep->start, ep->toksz))
343                         return &ep->defs[i];
344
345         return NULL;
346 }
347
348 /*
349  * Parse a token from the input text.  The modes are:
350  * MODE_QUOTED: Use *ep->start as the delimiter; the token ends
351  *   before its next occurence.  Do not interpret the token in any
352  *   way and return EQN_TOK_QUOTED.  All other modes behave like
353  *   MODE_QUOTED when *ep->start is '"'.
354  * MODE_NOSUB: If *ep->start is a curly brace, the token ends after it;
355  *   otherwise, it ends before the next whitespace or brace.
356  *   Do not interpret the token and return EQN_TOK__MAX.
357  * MODE_SUB: Like MODE_NOSUB, but try to interpret the token as an
358  *   alias created with define.  If it is an alias, replace it with
359  *   its string value and reparse.
360  * MODE_TOK: Like MODE_SUB, but also check the token against the list
361  *   of tokens, and if there is a match, return that token.  Otherwise,
362  *   if the token matches a symbol, return EQN_TOK_SYM; if it matches
363  *   a function name, EQN_TOK_FUNC, or else EQN_TOK__MAX.  Except for
364  *   a token match, *ep->start is set to an allocated string that the
365  *   caller is expected to free.
366  * All modes skip whitespace following the end of the token.
367  */
368 static enum eqn_tok
369 eqn_next(struct eqn_node *ep, enum parse_mode mode)
370 {
371         static int       last_len, lim;
372
373         struct eqn_def  *def;
374         size_t           start;
375         int              diff, i, quoted;
376         enum eqn_tok     tok;
377
378         /*
379          * Reset the recursion counter after advancing
380          * beyond the end of the previous substitution.
381          */
382         if (ep->end - ep->data >= last_len)
383                 lim = 0;
384
385         ep->start = ep->end;
386         quoted = mode == MODE_QUOTED;
387         for (;;) {
388                 switch (*ep->start) {
389                 case '\0':
390                         ep->toksz = 0;
391                         return EQN_TOK_EOF;
392                 case '"':
393                         quoted = 1;
394                         break;
395                 default:
396                         break;
397                 }
398                 if (quoted) {
399                         ep->end = strchr(ep->start + 1, *ep->start);
400                         ep->start++;  /* Skip opening quote. */
401                         if (ep->end == NULL) {
402                                 mandoc_msg(MANDOCERR_ARG_QUOTE, ep->parse,
403                                     ep->node->line, ep->node->pos, NULL);
404                                 ep->end = strchr(ep->start, '\0');
405                         }
406                 } else {
407                         ep->end = ep->start + 1;
408                         if (*ep->start != '{' && *ep->start != '}')
409                                 ep->end += strcspn(ep->end, " ^~\"{}\t");
410                 }
411                 ep->toksz = ep->end - ep->start;
412                 if (quoted && *ep->end != '\0')
413                         ep->end++;  /* Skip closing quote. */
414                 while (*ep->end != '\0' && strchr(" \t^~", *ep->end) != NULL)
415                         ep->end++;
416                 if (quoted)  /* Cannot return, may have to strndup. */
417                         break;
418                 if (mode == MODE_NOSUB)
419                         return EQN_TOK__MAX;
420                 if ((def = eqn_def_find(ep)) == NULL)
421                         break;
422                 if (++lim > EQN_NEST_MAX) {
423                         mandoc_msg(MANDOCERR_ROFFLOOP, ep->parse,
424                             ep->node->line, ep->node->pos, NULL);
425                         return EQN_TOK_EOF;
426                 }
427
428                 /* Replace a defined name with its string value. */
429                 if ((diff = def->valsz - ep->toksz) > 0) {
430                         start = ep->start - ep->data;
431                         ep->sz += diff;
432                         ep->data = mandoc_realloc(ep->data, ep->sz + 1);
433                         ep->start = ep->data + start;
434                 }
435                 if (diff)
436                         memmove(ep->start + def->valsz, ep->start + ep->toksz,
437                             strlen(ep->start + ep->toksz) + 1);
438                 memcpy(ep->start, def->val, def->valsz);
439                 last_len = ep->start - ep->data + def->valsz;
440         }
441         if (mode != MODE_TOK)
442                 return quoted ? EQN_TOK_QUOTED : EQN_TOK__MAX;
443         if (quoted) {
444                 ep->start = mandoc_strndup(ep->start, ep->toksz);
445                 return EQN_TOK_QUOTED;
446         }
447         for (tok = 0; tok < EQN_TOK__MAX; tok++)
448                 if (STRNEQ(ep->start, ep->toksz,
449                     eqn_toks[tok], strlen(eqn_toks[tok])))
450                         return tok;
451
452         for (i = 0; i < EQNSYM__MAX; i++) {
453                 if (STRNEQ(ep->start, ep->toksz,
454                     eqnsyms[i].str, strlen(eqnsyms[i].str))) {
455                         mandoc_asprintf(&ep->start,
456                             "\\[%s]", eqnsyms[i].sym);
457                         return EQN_TOK_SYM;
458                 }
459         }
460         ep->start = mandoc_strndup(ep->start, ep->toksz);
461         for (i = 0; i < (int)(sizeof(eqn_func)/sizeof(*eqn_func)); i++)
462                 if (STRNEQ(ep->start, ep->toksz,
463                     eqn_func[i], strlen(eqn_func[i])))
464                         return EQN_TOK_FUNC;
465         return EQN_TOK__MAX;
466 }
467
468 void
469 eqn_box_free(struct eqn_box *bp)
470 {
471
472         if (bp->first)
473                 eqn_box_free(bp->first);
474         if (bp->next)
475                 eqn_box_free(bp->next);
476
477         free(bp->text);
478         free(bp->left);
479         free(bp->right);
480         free(bp->top);
481         free(bp->bottom);
482         free(bp);
483 }
484
485 /*
486  * Allocate a box as the last child of the parent node.
487  */
488 static struct eqn_box *
489 eqn_box_alloc(struct eqn_node *ep, struct eqn_box *parent)
490 {
491         struct eqn_box  *bp;
492
493         bp = mandoc_calloc(1, sizeof(struct eqn_box));
494         bp->parent = parent;
495         bp->parent->args++;
496         bp->expectargs = UINT_MAX;
497         bp->font = bp->parent->font;
498         bp->size = ep->gsize;
499
500         if (NULL != parent->first) {
501                 parent->last->next = bp;
502                 bp->prev = parent->last;
503         } else
504                 parent->first = bp;
505
506         parent->last = bp;
507         return bp;
508 }
509
510 /*
511  * Reparent the current last node (of the current parent) under a new
512  * EQN_SUBEXPR as the first element.
513  * Then return the new parent.
514  * The new EQN_SUBEXPR will have a two-child limit.
515  */
516 static struct eqn_box *
517 eqn_box_makebinary(struct eqn_node *ep, struct eqn_box *parent)
518 {
519         struct eqn_box  *b, *newb;
520
521         assert(NULL != parent->last);
522         b = parent->last;
523         if (parent->last == parent->first)
524                 parent->first = NULL;
525         parent->args--;
526         parent->last = b->prev;
527         b->prev = NULL;
528         newb = eqn_box_alloc(ep, parent);
529         newb->type = EQN_SUBEXPR;
530         newb->expectargs = 2;
531         newb->args = 1;
532         newb->first = newb->last = b;
533         newb->first->next = NULL;
534         b->parent = newb;
535         return newb;
536 }
537
538 /*
539  * Parse the "delim" control statement.
540  */
541 static void
542 eqn_delim(struct eqn_node *ep)
543 {
544         if (ep->end[0] == '\0' || ep->end[1] == '\0') {
545                 mandoc_msg(MANDOCERR_REQ_EMPTY, ep->parse,
546                     ep->node->line, ep->node->pos, "delim");
547                 if (ep->end[0] != '\0')
548                         ep->end++;
549         } else if (strncmp(ep->end, "off", 3) == 0) {
550                 ep->delim = 0;
551                 ep->end += 3;
552         } else if (strncmp(ep->end, "on", 2) == 0) {
553                 if (ep->odelim && ep->cdelim)
554                         ep->delim = 1;
555                 ep->end += 2;
556         } else {
557                 ep->odelim = *ep->end++;
558                 ep->cdelim = *ep->end++;
559                 ep->delim = 1;
560         }
561 }
562
563 /*
564  * Undefine a previously-defined string.
565  */
566 static void
567 eqn_undef(struct eqn_node *ep)
568 {
569         struct eqn_def  *def;
570
571         if (eqn_next(ep, MODE_NOSUB) == EQN_TOK_EOF) {
572                 mandoc_msg(MANDOCERR_REQ_EMPTY, ep->parse,
573                     ep->node->line, ep->node->pos, "undef");
574                 return;
575         }
576         if ((def = eqn_def_find(ep)) == NULL)
577                 return;
578         free(def->key);
579         free(def->val);
580         def->key = def->val = NULL;
581         def->keysz = def->valsz = 0;
582 }
583
584 static void
585 eqn_def(struct eqn_node *ep)
586 {
587         struct eqn_def  *def;
588         int              i;
589
590         if (eqn_next(ep, MODE_NOSUB) == EQN_TOK_EOF) {
591                 mandoc_msg(MANDOCERR_REQ_EMPTY, ep->parse,
592                     ep->node->line, ep->node->pos, "define");
593                 return;
594         }
595
596         /*
597          * Search for a key that already exists.
598          * Create a new key if none is found.
599          */
600         if ((def = eqn_def_find(ep)) == NULL) {
601                 /* Find holes in string array. */
602                 for (i = 0; i < (int)ep->defsz; i++)
603                         if (0 == ep->defs[i].keysz)
604                                 break;
605
606                 if (i == (int)ep->defsz) {
607                         ep->defsz++;
608                         ep->defs = mandoc_reallocarray(ep->defs,
609                             ep->defsz, sizeof(struct eqn_def));
610                         ep->defs[i].key = ep->defs[i].val = NULL;
611                 }
612
613                 def = ep->defs + i;
614                 free(def->key);
615                 def->key = mandoc_strndup(ep->start, ep->toksz);
616                 def->keysz = ep->toksz;
617         }
618
619         if (eqn_next(ep, MODE_QUOTED) == EQN_TOK_EOF) {
620                 mandoc_vmsg(MANDOCERR_REQ_EMPTY, ep->parse,
621                     ep->node->line, ep->node->pos, "define %s", def->key);
622                 free(def->key);
623                 free(def->val);
624                 def->key = def->val = NULL;
625                 def->keysz = def->valsz = 0;
626                 return;
627         }
628         free(def->val);
629         def->val = mandoc_strndup(ep->start, ep->toksz);
630         def->valsz = ep->toksz;
631 }
632
633 void
634 eqn_parse(struct eqn_node *ep)
635 {
636         struct eqn_box  *cur, *nbox, *parent, *split;
637         const char      *cp, *cpn;
638         char            *p;
639         enum eqn_tok     tok;
640         enum { CCL_LET, CCL_DIG, CCL_PUN } ccl, ccln;
641         int              size;
642
643         parent = ep->node->eqn;
644         assert(parent != NULL);
645
646         /*
647          * Empty equation.
648          * Do not add it to the high-level syntax tree.
649          */
650
651         if (ep->data == NULL)
652                 return;
653
654         ep->start = ep->end = ep->data + strspn(ep->data, " ^~");
655
656 next_tok:
657         tok = eqn_next(ep, MODE_TOK);
658         switch (tok) {
659         case EQN_TOK_UNDEF:
660                 eqn_undef(ep);
661                 break;
662         case EQN_TOK_NDEFINE:
663         case EQN_TOK_DEFINE:
664                 eqn_def(ep);
665                 break;
666         case EQN_TOK_TDEFINE:
667                 if (eqn_next(ep, MODE_NOSUB) == EQN_TOK_EOF ||
668                     eqn_next(ep, MODE_QUOTED) == EQN_TOK_EOF)
669                         mandoc_msg(MANDOCERR_REQ_EMPTY, ep->parse,
670                             ep->node->line, ep->node->pos, "tdefine");
671                 break;
672         case EQN_TOK_DELIM:
673                 eqn_delim(ep);
674                 break;
675         case EQN_TOK_GFONT:
676                 if (eqn_next(ep, MODE_SUB) == EQN_TOK_EOF)
677                         mandoc_msg(MANDOCERR_REQ_EMPTY, ep->parse,
678                             ep->node->line, ep->node->pos, eqn_toks[tok]);
679                 break;
680         case EQN_TOK_MARK:
681         case EQN_TOK_LINEUP:
682                 /* Ignore these. */
683                 break;
684         case EQN_TOK_DYAD:
685         case EQN_TOK_VEC:
686         case EQN_TOK_UNDER:
687         case EQN_TOK_BAR:
688         case EQN_TOK_TILDE:
689         case EQN_TOK_HAT:
690         case EQN_TOK_DOT:
691         case EQN_TOK_DOTDOT:
692                 if (parent->last == NULL) {
693                         mandoc_msg(MANDOCERR_EQN_NOBOX, ep->parse,
694                             ep->node->line, ep->node->pos, eqn_toks[tok]);
695                         cur = eqn_box_alloc(ep, parent);
696                         cur->type = EQN_TEXT;
697                         cur->text = mandoc_strdup("");
698                 }
699                 parent = eqn_box_makebinary(ep, parent);
700                 parent->type = EQN_LIST;
701                 parent->expectargs = 1;
702                 parent->font = EQNFONT_ROMAN;
703                 switch (tok) {
704                 case EQN_TOK_DOTDOT:
705                         parent->top = mandoc_strdup("\\[ad]");
706                         break;
707                 case EQN_TOK_VEC:
708                         parent->top = mandoc_strdup("\\[->]");
709                         break;
710                 case EQN_TOK_DYAD:
711                         parent->top = mandoc_strdup("\\[<>]");
712                         break;
713                 case EQN_TOK_TILDE:
714                         parent->top = mandoc_strdup("\\[a~]");
715                         break;
716                 case EQN_TOK_UNDER:
717                         parent->bottom = mandoc_strdup("\\[ul]");
718                         break;
719                 case EQN_TOK_BAR:
720                         parent->top = mandoc_strdup("\\[rn]");
721                         break;
722                 case EQN_TOK_DOT:
723                         parent->top = mandoc_strdup("\\[a.]");
724                         break;
725                 case EQN_TOK_HAT:
726                         parent->top = mandoc_strdup("\\[ha]");
727                         break;
728                 default:
729                         abort();
730                 }
731                 parent = parent->parent;
732                 break;
733         case EQN_TOK_FWD:
734         case EQN_TOK_BACK:
735         case EQN_TOK_DOWN:
736         case EQN_TOK_UP:
737                 if (eqn_next(ep, MODE_SUB) == EQN_TOK_EOF)
738                         mandoc_msg(MANDOCERR_REQ_EMPTY, ep->parse,
739                             ep->node->line, ep->node->pos, eqn_toks[tok]);
740                 break;
741         case EQN_TOK_FAT:
742         case EQN_TOK_ROMAN:
743         case EQN_TOK_ITALIC:
744         case EQN_TOK_BOLD:
745                 while (parent->args == parent->expectargs)
746                         parent = parent->parent;
747                 /*
748                  * These values apply to the next word or sequence of
749                  * words; thus, we mark that we'll have a child with
750                  * exactly one of those.
751                  */
752                 parent = eqn_box_alloc(ep, parent);
753                 parent->type = EQN_LIST;
754                 parent->expectargs = 1;
755                 switch (tok) {
756                 case EQN_TOK_FAT:
757                         parent->font = EQNFONT_FAT;
758                         break;
759                 case EQN_TOK_ROMAN:
760                         parent->font = EQNFONT_ROMAN;
761                         break;
762                 case EQN_TOK_ITALIC:
763                         parent->font = EQNFONT_ITALIC;
764                         break;
765                 case EQN_TOK_BOLD:
766                         parent->font = EQNFONT_BOLD;
767                         break;
768                 default:
769                         abort();
770                 }
771                 break;
772         case EQN_TOK_SIZE:
773         case EQN_TOK_GSIZE:
774                 /* Accept two values: integral size and a single. */
775                 if (eqn_next(ep, MODE_SUB) == EQN_TOK_EOF) {
776                         mandoc_msg(MANDOCERR_REQ_EMPTY, ep->parse,
777                             ep->node->line, ep->node->pos, eqn_toks[tok]);
778                         break;
779                 }
780                 size = mandoc_strntoi(ep->start, ep->toksz, 10);
781                 if (-1 == size) {
782                         mandoc_msg(MANDOCERR_IT_NONUM, ep->parse,
783                             ep->node->line, ep->node->pos, eqn_toks[tok]);
784                         break;
785                 }
786                 if (EQN_TOK_GSIZE == tok) {
787                         ep->gsize = size;
788                         break;
789                 }
790                 while (parent->args == parent->expectargs)
791                         parent = parent->parent;
792                 parent = eqn_box_alloc(ep, parent);
793                 parent->type = EQN_LIST;
794                 parent->expectargs = 1;
795                 parent->size = size;
796                 break;
797         case EQN_TOK_FROM:
798         case EQN_TOK_TO:
799         case EQN_TOK_SUB:
800         case EQN_TOK_SUP:
801                 /*
802                  * We have a left-right-associative expression.
803                  * Repivot under a positional node, open a child scope
804                  * and keep on reading.
805                  */
806                 if (parent->last == NULL) {
807                         mandoc_msg(MANDOCERR_EQN_NOBOX, ep->parse,
808                             ep->node->line, ep->node->pos, eqn_toks[tok]);
809                         cur = eqn_box_alloc(ep, parent);
810                         cur->type = EQN_TEXT;
811                         cur->text = mandoc_strdup("");
812                 }
813                 while (parent->expectargs == 1 && parent->args == 1)
814                         parent = parent->parent;
815                 if (tok == EQN_TOK_FROM || tok == EQN_TOK_TO)  {
816                         for (cur = parent; cur != NULL; cur = cur->parent)
817                                 if (cur->pos == EQNPOS_SUB ||
818                                     cur->pos == EQNPOS_SUP ||
819                                     cur->pos == EQNPOS_SUBSUP ||
820                                     cur->pos == EQNPOS_SQRT ||
821                                     cur->pos == EQNPOS_OVER)
822                                         break;
823                         if (cur != NULL)
824                                 parent = cur->parent;
825                 }
826                 if (tok == EQN_TOK_SUP && parent->pos == EQNPOS_SUB) {
827                         parent->expectargs = 3;
828                         parent->pos = EQNPOS_SUBSUP;
829                         break;
830                 }
831                 if (tok == EQN_TOK_TO && parent->pos == EQNPOS_FROM) {
832                         parent->expectargs = 3;
833                         parent->pos = EQNPOS_FROMTO;
834                         break;
835                 }
836                 parent = eqn_box_makebinary(ep, parent);
837                 switch (tok) {
838                 case EQN_TOK_FROM:
839                         parent->pos = EQNPOS_FROM;
840                         break;
841                 case EQN_TOK_TO:
842                         parent->pos = EQNPOS_TO;
843                         break;
844                 case EQN_TOK_SUP:
845                         parent->pos = EQNPOS_SUP;
846                         break;
847                 case EQN_TOK_SUB:
848                         parent->pos = EQNPOS_SUB;
849                         break;
850                 default:
851                         abort();
852                 }
853                 break;
854         case EQN_TOK_SQRT:
855                 while (parent->args == parent->expectargs)
856                         parent = parent->parent;
857                 /*
858                  * Accept a left-right-associative set of arguments just
859                  * like sub and sup and friends but without rebalancing
860                  * under a pivot.
861                  */
862                 parent = eqn_box_alloc(ep, parent);
863                 parent->type = EQN_SUBEXPR;
864                 parent->pos = EQNPOS_SQRT;
865                 parent->expectargs = 1;
866                 break;
867         case EQN_TOK_OVER:
868                 /*
869                  * We have a right-left-associative fraction.
870                  * Close out anything that's currently open, then
871                  * rebalance and continue reading.
872                  */
873                 if (parent->last == NULL) {
874                         mandoc_msg(MANDOCERR_EQN_NOBOX, ep->parse,
875                             ep->node->line, ep->node->pos, eqn_toks[tok]);
876                         cur = eqn_box_alloc(ep, parent);
877                         cur->type = EQN_TEXT;
878                         cur->text = mandoc_strdup("");
879                 }
880                 while (parent->args == parent->expectargs)
881                         parent = parent->parent;
882                 while (EQN_SUBEXPR == parent->type)
883                         parent = parent->parent;
884                 parent = eqn_box_makebinary(ep, parent);
885                 parent->pos = EQNPOS_OVER;
886                 break;
887         case EQN_TOK_RIGHT:
888         case EQN_TOK_BRACE_CLOSE:
889                 /*
890                  * Close out the existing brace.
891                  * FIXME: this is a shitty sentinel: we should really
892                  * have a native EQN_BRACE type or whatnot.
893                  */
894                 for (cur = parent; cur != NULL; cur = cur->parent)
895                         if (cur->type == EQN_LIST &&
896                             cur->expectargs > 1 &&
897                             (tok == EQN_TOK_BRACE_CLOSE ||
898                              cur->left != NULL))
899                                 break;
900                 if (cur == NULL) {
901                         mandoc_msg(MANDOCERR_BLK_NOTOPEN, ep->parse,
902                             ep->node->line, ep->node->pos, eqn_toks[tok]);
903                         break;
904                 }
905                 parent = cur;
906                 if (EQN_TOK_RIGHT == tok) {
907                         if (eqn_next(ep, MODE_SUB) == EQN_TOK_EOF) {
908                                 mandoc_msg(MANDOCERR_REQ_EMPTY,
909                                     ep->parse, ep->node->line,
910                                     ep->node->pos, eqn_toks[tok]);
911                                 break;
912                         }
913                         /* Handling depends on right/left. */
914                         if (STRNEQ(ep->start, ep->toksz, "ceiling", 7))
915                                 parent->right = mandoc_strdup("\\[rc]");
916                         else if (STRNEQ(ep->start, ep->toksz, "floor", 5))
917                                 parent->right = mandoc_strdup("\\[rf]");
918                         else
919                                 parent->right =
920                                     mandoc_strndup(ep->start, ep->toksz);
921                 }
922                 parent = parent->parent;
923                 if (tok == EQN_TOK_BRACE_CLOSE &&
924                     (parent->type == EQN_PILE ||
925                      parent->type == EQN_MATRIX))
926                         parent = parent->parent;
927                 /* Close out any "singleton" lists. */
928                 while (parent->type == EQN_LIST &&
929                     parent->expectargs == 1 &&
930                     parent->args == 1)
931                         parent = parent->parent;
932                 break;
933         case EQN_TOK_BRACE_OPEN:
934         case EQN_TOK_LEFT:
935                 /*
936                  * If we already have something in the stack and we're
937                  * in an expression, then rewind til we're not any more
938                  * (just like with the text node).
939                  */
940                 while (parent->args == parent->expectargs)
941                         parent = parent->parent;
942                 if (EQN_TOK_LEFT == tok &&
943                     eqn_next(ep, MODE_SUB) == EQN_TOK_EOF) {
944                         mandoc_msg(MANDOCERR_REQ_EMPTY, ep->parse,
945                             ep->node->line, ep->node->pos, eqn_toks[tok]);
946                         break;
947                 }
948                 parent = eqn_box_alloc(ep, parent);
949                 parent->type = EQN_LIST;
950                 if (EQN_TOK_LEFT == tok) {
951                         if (STRNEQ(ep->start, ep->toksz, "ceiling", 7))
952                                 parent->left = mandoc_strdup("\\[lc]");
953                         else if (STRNEQ(ep->start, ep->toksz, "floor", 5))
954                                 parent->left = mandoc_strdup("\\[lf]");
955                         else
956                                 parent->left =
957                                     mandoc_strndup(ep->start, ep->toksz);
958                 }
959                 break;
960         case EQN_TOK_PILE:
961         case EQN_TOK_LPILE:
962         case EQN_TOK_RPILE:
963         case EQN_TOK_CPILE:
964         case EQN_TOK_CCOL:
965         case EQN_TOK_LCOL:
966         case EQN_TOK_RCOL:
967                 while (parent->args == parent->expectargs)
968                         parent = parent->parent;
969                 parent = eqn_box_alloc(ep, parent);
970                 parent->type = EQN_PILE;
971                 parent->expectargs = 1;
972                 break;
973         case EQN_TOK_ABOVE:
974                 for (cur = parent; cur != NULL; cur = cur->parent)
975                         if (cur->type == EQN_PILE)
976                                 break;
977                 if (cur == NULL) {
978                         mandoc_msg(MANDOCERR_IT_STRAY, ep->parse,
979                             ep->node->line, ep->node->pos, eqn_toks[tok]);
980                         break;
981                 }
982                 parent = eqn_box_alloc(ep, cur);
983                 parent->type = EQN_LIST;
984                 break;
985         case EQN_TOK_MATRIX:
986                 while (parent->args == parent->expectargs)
987                         parent = parent->parent;
988                 parent = eqn_box_alloc(ep, parent);
989                 parent->type = EQN_MATRIX;
990                 parent->expectargs = 1;
991                 break;
992         case EQN_TOK_EOF:
993                 return;
994         case EQN_TOK__MAX:
995         case EQN_TOK_FUNC:
996         case EQN_TOK_QUOTED:
997         case EQN_TOK_SYM:
998                 p = ep->start;
999                 assert(p != NULL);
1000                 /*
1001                  * If we already have something in the stack and we're
1002                  * in an expression, then rewind til we're not any more.
1003                  */
1004                 while (parent->args == parent->expectargs)
1005                         parent = parent->parent;
1006                 cur = eqn_box_alloc(ep, parent);
1007                 cur->type = EQN_TEXT;
1008                 cur->text = p;
1009                 switch (tok) {
1010                 case EQN_TOK_FUNC:
1011                         cur->font = EQNFONT_ROMAN;
1012                         break;
1013                 case EQN_TOK_QUOTED:
1014                         if (cur->font == EQNFONT_NONE)
1015                                 cur->font = EQNFONT_ITALIC;
1016                         break;
1017                 case EQN_TOK_SYM:
1018                         break;
1019                 default:
1020                         if (cur->font != EQNFONT_NONE || *p == '\0')
1021                                 break;
1022                         cpn = p - 1;
1023                         ccln = CCL_LET;
1024                         split = NULL;
1025                         for (;;) {
1026                                 /* Advance to next character. */
1027                                 cp = cpn++;
1028                                 ccl = ccln;
1029                                 ccln = isalpha((unsigned char)*cpn) ? CCL_LET :
1030                                     isdigit((unsigned char)*cpn) ||
1031                                     (*cpn == '.' && (ccl == CCL_DIG ||
1032                                      isdigit((unsigned char)cpn[1]))) ?
1033                                     CCL_DIG : CCL_PUN;
1034                                 /* No boundary before first character. */
1035                                 if (cp < p)
1036                                         continue;
1037                                 cur->font = ccl == CCL_LET ?
1038                                     EQNFONT_ITALIC : EQNFONT_ROMAN;
1039                                 if (*cp == '\\')
1040                                         mandoc_escape(&cpn, NULL, NULL);
1041                                 /* No boundary after last character. */
1042                                 if (*cpn == '\0')
1043                                         break;
1044                                 if (ccln == ccl && *cp != ',' && *cpn != ',')
1045                                         continue;
1046                                 /* Boundary found, split the text. */
1047                                 if (parent->args == parent->expectargs) {
1048                                         /* Remove the text from the tree. */
1049                                         if (cur->prev == NULL)
1050                                                 parent->first = cur->next;
1051                                         else
1052                                                 cur->prev->next = NULL;
1053                                         parent->last = cur->prev;
1054                                         parent->args--;
1055                                         /* Set up a list instead. */
1056                                         split = eqn_box_alloc(ep, parent);
1057                                         split->type = EQN_LIST;
1058                                         /* Insert the word into the list. */
1059                                         split->first = split->last = cur;
1060                                         cur->parent = split;
1061                                         cur->prev = NULL;
1062                                         parent = split;
1063                                 }
1064                                 /* Append a new text box. */
1065                                 nbox = eqn_box_alloc(ep, parent);
1066                                 nbox->type = EQN_TEXT;
1067                                 nbox->text = mandoc_strdup(cpn);
1068                                 /* Truncate the old box. */
1069                                 p = mandoc_strndup(cur->text,
1070                                     cpn - cur->text);
1071                                 free(cur->text);
1072                                 cur->text = p;
1073                                 /* Setup to process the new box. */
1074                                 cur = nbox;
1075                                 p = nbox->text;
1076                                 cpn = p - 1;
1077                                 ccln = CCL_LET;
1078                         }
1079                         if (split != NULL)
1080                                 parent = split->parent;
1081                         break;
1082                 }
1083                 break;
1084         default:
1085                 abort();
1086         }
1087         goto next_tok;
1088 }
1089
1090 void
1091 eqn_free(struct eqn_node *p)
1092 {
1093         int              i;
1094
1095         for (i = 0; i < (int)p->defsz; i++) {
1096                 free(p->defs[i].key);
1097                 free(p->defs[i].val);
1098         }
1099
1100         free(p->data);
1101         free(p->defs);
1102         free(p);
1103 }