1*260e9a87SYuri Pankov /* $Id: eqn.c,v 1.58 2015/03/04 12:19:49 schwarze Exp $ */
295c635efSGarrett D'Amore /*
3*260e9a87SYuri Pankov * Copyright (c) 2011, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
4*260e9a87SYuri Pankov * Copyright (c) 2014, 2015 Ingo Schwarze <schwarze@openbsd.org>
595c635efSGarrett D'Amore *
695c635efSGarrett D'Amore * Permission to use, copy, modify, and distribute this software for any
795c635efSGarrett D'Amore * purpose with or without fee is hereby granted, provided that the above
895c635efSGarrett D'Amore * copyright notice and this permission notice appear in all copies.
995c635efSGarrett D'Amore *
1095c635efSGarrett D'Amore * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1195c635efSGarrett D'Amore * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1295c635efSGarrett D'Amore * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1395c635efSGarrett D'Amore * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1495c635efSGarrett D'Amore * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1595c635efSGarrett D'Amore * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1695c635efSGarrett D'Amore * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1795c635efSGarrett D'Amore */
1895c635efSGarrett D'Amore #include "config.h"
19*260e9a87SYuri Pankov
20*260e9a87SYuri Pankov #include <sys/types.h>
2195c635efSGarrett D'Amore
2295c635efSGarrett D'Amore #include <assert.h>
2395c635efSGarrett D'Amore #include <limits.h>
2495c635efSGarrett D'Amore #include <stdio.h>
2595c635efSGarrett D'Amore #include <stdlib.h>
2695c635efSGarrett D'Amore #include <string.h>
2795c635efSGarrett D'Amore #include <time.h>
2895c635efSGarrett D'Amore
2995c635efSGarrett D'Amore #include "mandoc.h"
30*260e9a87SYuri Pankov #include "mandoc_aux.h"
3195c635efSGarrett D'Amore #include "libmandoc.h"
3295c635efSGarrett D'Amore #include "libroff.h"
3395c635efSGarrett D'Amore
3495c635efSGarrett D'Amore #define EQN_NEST_MAX 128 /* maximum nesting of defines */
35*260e9a87SYuri Pankov #define STRNEQ(p1, sz1, p2, sz2) \
36*260e9a87SYuri Pankov ((sz1) == (sz2) && 0 == strncmp((p1), (p2), (sz1)))
3795c635efSGarrett D'Amore
38*260e9a87SYuri Pankov enum eqn_tok {
39*260e9a87SYuri Pankov EQN_TOK_DYAD = 0,
40*260e9a87SYuri Pankov EQN_TOK_VEC,
41*260e9a87SYuri Pankov EQN_TOK_UNDER,
42*260e9a87SYuri Pankov EQN_TOK_BAR,
43*260e9a87SYuri Pankov EQN_TOK_TILDE,
44*260e9a87SYuri Pankov EQN_TOK_HAT,
45*260e9a87SYuri Pankov EQN_TOK_DOT,
46*260e9a87SYuri Pankov EQN_TOK_DOTDOT,
47*260e9a87SYuri Pankov EQN_TOK_FWD,
48*260e9a87SYuri Pankov EQN_TOK_BACK,
49*260e9a87SYuri Pankov EQN_TOK_DOWN,
50*260e9a87SYuri Pankov EQN_TOK_UP,
51*260e9a87SYuri Pankov EQN_TOK_FAT,
52*260e9a87SYuri Pankov EQN_TOK_ROMAN,
53*260e9a87SYuri Pankov EQN_TOK_ITALIC,
54*260e9a87SYuri Pankov EQN_TOK_BOLD,
55*260e9a87SYuri Pankov EQN_TOK_SIZE,
56*260e9a87SYuri Pankov EQN_TOK_SUB,
57*260e9a87SYuri Pankov EQN_TOK_SUP,
58*260e9a87SYuri Pankov EQN_TOK_SQRT,
59*260e9a87SYuri Pankov EQN_TOK_OVER,
60*260e9a87SYuri Pankov EQN_TOK_FROM,
61*260e9a87SYuri Pankov EQN_TOK_TO,
62*260e9a87SYuri Pankov EQN_TOK_BRACE_OPEN,
63*260e9a87SYuri Pankov EQN_TOK_BRACE_CLOSE,
64*260e9a87SYuri Pankov EQN_TOK_GSIZE,
65*260e9a87SYuri Pankov EQN_TOK_GFONT,
66*260e9a87SYuri Pankov EQN_TOK_MARK,
67*260e9a87SYuri Pankov EQN_TOK_LINEUP,
68*260e9a87SYuri Pankov EQN_TOK_LEFT,
69*260e9a87SYuri Pankov EQN_TOK_RIGHT,
70*260e9a87SYuri Pankov EQN_TOK_PILE,
71*260e9a87SYuri Pankov EQN_TOK_LPILE,
72*260e9a87SYuri Pankov EQN_TOK_RPILE,
73*260e9a87SYuri Pankov EQN_TOK_CPILE,
74*260e9a87SYuri Pankov EQN_TOK_MATRIX,
75*260e9a87SYuri Pankov EQN_TOK_CCOL,
76*260e9a87SYuri Pankov EQN_TOK_LCOL,
77*260e9a87SYuri Pankov EQN_TOK_RCOL,
78*260e9a87SYuri Pankov EQN_TOK_DELIM,
79*260e9a87SYuri Pankov EQN_TOK_DEFINE,
80*260e9a87SYuri Pankov EQN_TOK_TDEFINE,
81*260e9a87SYuri Pankov EQN_TOK_NDEFINE,
82*260e9a87SYuri Pankov EQN_TOK_UNDEF,
83*260e9a87SYuri Pankov EQN_TOK_EOF,
84*260e9a87SYuri Pankov EQN_TOK_ABOVE,
85*260e9a87SYuri Pankov EQN_TOK__MAX
86*260e9a87SYuri Pankov };
87*260e9a87SYuri Pankov
88*260e9a87SYuri Pankov static const char *eqn_toks[EQN_TOK__MAX] = {
89*260e9a87SYuri Pankov "dyad", /* EQN_TOK_DYAD */
90*260e9a87SYuri Pankov "vec", /* EQN_TOK_VEC */
91*260e9a87SYuri Pankov "under", /* EQN_TOK_UNDER */
92*260e9a87SYuri Pankov "bar", /* EQN_TOK_BAR */
93*260e9a87SYuri Pankov "tilde", /* EQN_TOK_TILDE */
94*260e9a87SYuri Pankov "hat", /* EQN_TOK_HAT */
95*260e9a87SYuri Pankov "dot", /* EQN_TOK_DOT */
96*260e9a87SYuri Pankov "dotdot", /* EQN_TOK_DOTDOT */
97*260e9a87SYuri Pankov "fwd", /* EQN_TOK_FWD * */
98*260e9a87SYuri Pankov "back", /* EQN_TOK_BACK */
99*260e9a87SYuri Pankov "down", /* EQN_TOK_DOWN */
100*260e9a87SYuri Pankov "up", /* EQN_TOK_UP */
101*260e9a87SYuri Pankov "fat", /* EQN_TOK_FAT */
102*260e9a87SYuri Pankov "roman", /* EQN_TOK_ROMAN */
103*260e9a87SYuri Pankov "italic", /* EQN_TOK_ITALIC */
104*260e9a87SYuri Pankov "bold", /* EQN_TOK_BOLD */
105*260e9a87SYuri Pankov "size", /* EQN_TOK_SIZE */
106*260e9a87SYuri Pankov "sub", /* EQN_TOK_SUB */
107*260e9a87SYuri Pankov "sup", /* EQN_TOK_SUP */
108*260e9a87SYuri Pankov "sqrt", /* EQN_TOK_SQRT */
109*260e9a87SYuri Pankov "over", /* EQN_TOK_OVER */
110*260e9a87SYuri Pankov "from", /* EQN_TOK_FROM */
111*260e9a87SYuri Pankov "to", /* EQN_TOK_TO */
112*260e9a87SYuri Pankov "{", /* EQN_TOK_BRACE_OPEN */
113*260e9a87SYuri Pankov "}", /* EQN_TOK_BRACE_CLOSE */
114*260e9a87SYuri Pankov "gsize", /* EQN_TOK_GSIZE */
115*260e9a87SYuri Pankov "gfont", /* EQN_TOK_GFONT */
116*260e9a87SYuri Pankov "mark", /* EQN_TOK_MARK */
117*260e9a87SYuri Pankov "lineup", /* EQN_TOK_LINEUP */
118*260e9a87SYuri Pankov "left", /* EQN_TOK_LEFT */
119*260e9a87SYuri Pankov "right", /* EQN_TOK_RIGHT */
120*260e9a87SYuri Pankov "pile", /* EQN_TOK_PILE */
121*260e9a87SYuri Pankov "lpile", /* EQN_TOK_LPILE */
122*260e9a87SYuri Pankov "rpile", /* EQN_TOK_RPILE */
123*260e9a87SYuri Pankov "cpile", /* EQN_TOK_CPILE */
124*260e9a87SYuri Pankov "matrix", /* EQN_TOK_MATRIX */
125*260e9a87SYuri Pankov "ccol", /* EQN_TOK_CCOL */
126*260e9a87SYuri Pankov "lcol", /* EQN_TOK_LCOL */
127*260e9a87SYuri Pankov "rcol", /* EQN_TOK_RCOL */
128*260e9a87SYuri Pankov "delim", /* EQN_TOK_DELIM */
129*260e9a87SYuri Pankov "define", /* EQN_TOK_DEFINE */
130*260e9a87SYuri Pankov "tdefine", /* EQN_TOK_TDEFINE */
131*260e9a87SYuri Pankov "ndefine", /* EQN_TOK_NDEFINE */
132*260e9a87SYuri Pankov "undef", /* EQN_TOK_UNDEF */
133*260e9a87SYuri Pankov NULL, /* EQN_TOK_EOF */
134*260e9a87SYuri Pankov "above", /* EQN_TOK_ABOVE */
13595c635efSGarrett D'Amore };
13695c635efSGarrett D'Amore
13795c635efSGarrett D'Amore enum eqn_symt {
13895c635efSGarrett D'Amore EQNSYM_alpha,
13995c635efSGarrett D'Amore EQNSYM_beta,
14095c635efSGarrett D'Amore EQNSYM_chi,
14195c635efSGarrett D'Amore EQNSYM_delta,
14295c635efSGarrett D'Amore EQNSYM_epsilon,
14395c635efSGarrett D'Amore EQNSYM_eta,
14495c635efSGarrett D'Amore EQNSYM_gamma,
14595c635efSGarrett D'Amore EQNSYM_iota,
14695c635efSGarrett D'Amore EQNSYM_kappa,
14795c635efSGarrett D'Amore EQNSYM_lambda,
14895c635efSGarrett D'Amore EQNSYM_mu,
14995c635efSGarrett D'Amore EQNSYM_nu,
15095c635efSGarrett D'Amore EQNSYM_omega,
15195c635efSGarrett D'Amore EQNSYM_omicron,
15295c635efSGarrett D'Amore EQNSYM_phi,
15395c635efSGarrett D'Amore EQNSYM_pi,
15495c635efSGarrett D'Amore EQNSYM_ps,
15595c635efSGarrett D'Amore EQNSYM_rho,
15695c635efSGarrett D'Amore EQNSYM_sigma,
15795c635efSGarrett D'Amore EQNSYM_tau,
15895c635efSGarrett D'Amore EQNSYM_theta,
15995c635efSGarrett D'Amore EQNSYM_upsilon,
16095c635efSGarrett D'Amore EQNSYM_xi,
16195c635efSGarrett D'Amore EQNSYM_zeta,
16295c635efSGarrett D'Amore EQNSYM_DELTA,
16395c635efSGarrett D'Amore EQNSYM_GAMMA,
16495c635efSGarrett D'Amore EQNSYM_LAMBDA,
16595c635efSGarrett D'Amore EQNSYM_OMEGA,
16695c635efSGarrett D'Amore EQNSYM_PHI,
16795c635efSGarrett D'Amore EQNSYM_PI,
16895c635efSGarrett D'Amore EQNSYM_PSI,
16995c635efSGarrett D'Amore EQNSYM_SIGMA,
17095c635efSGarrett D'Amore EQNSYM_THETA,
17195c635efSGarrett D'Amore EQNSYM_UPSILON,
17295c635efSGarrett D'Amore EQNSYM_XI,
17395c635efSGarrett D'Amore EQNSYM_inter,
17495c635efSGarrett D'Amore EQNSYM_union,
17595c635efSGarrett D'Amore EQNSYM_prod,
17695c635efSGarrett D'Amore EQNSYM_int,
17795c635efSGarrett D'Amore EQNSYM_sum,
17895c635efSGarrett D'Amore EQNSYM_grad,
17995c635efSGarrett D'Amore EQNSYM_del,
18095c635efSGarrett D'Amore EQNSYM_times,
18195c635efSGarrett D'Amore EQNSYM_cdot,
18295c635efSGarrett D'Amore EQNSYM_nothing,
18395c635efSGarrett D'Amore EQNSYM_approx,
18495c635efSGarrett D'Amore EQNSYM_prime,
18595c635efSGarrett D'Amore EQNSYM_half,
18695c635efSGarrett D'Amore EQNSYM_partial,
18795c635efSGarrett D'Amore EQNSYM_inf,
18895c635efSGarrett D'Amore EQNSYM_muchgreat,
18995c635efSGarrett D'Amore EQNSYM_muchless,
19095c635efSGarrett D'Amore EQNSYM_larrow,
19195c635efSGarrett D'Amore EQNSYM_rarrow,
19295c635efSGarrett D'Amore EQNSYM_pm,
19395c635efSGarrett D'Amore EQNSYM_nequal,
19495c635efSGarrett D'Amore EQNSYM_equiv,
19595c635efSGarrett D'Amore EQNSYM_lessequal,
19695c635efSGarrett D'Amore EQNSYM_moreequal,
197*260e9a87SYuri Pankov EQNSYM_minus,
19895c635efSGarrett D'Amore EQNSYM__MAX
19995c635efSGarrett D'Amore };
20095c635efSGarrett D'Amore
20195c635efSGarrett D'Amore struct eqnsym {
202*260e9a87SYuri Pankov const char *str;
20395c635efSGarrett D'Amore const char *sym;
20495c635efSGarrett D'Amore };
20595c635efSGarrett D'Amore
20695c635efSGarrett D'Amore static const struct eqnsym eqnsyms[EQNSYM__MAX] = {
207*260e9a87SYuri Pankov { "alpha", "*a" }, /* EQNSYM_alpha */
208*260e9a87SYuri Pankov { "beta", "*b" }, /* EQNSYM_beta */
209*260e9a87SYuri Pankov { "chi", "*x" }, /* EQNSYM_chi */
210*260e9a87SYuri Pankov { "delta", "*d" }, /* EQNSYM_delta */
211*260e9a87SYuri Pankov { "epsilon", "*e" }, /* EQNSYM_epsilon */
212*260e9a87SYuri Pankov { "eta", "*y" }, /* EQNSYM_eta */
213*260e9a87SYuri Pankov { "gamma", "*g" }, /* EQNSYM_gamma */
214*260e9a87SYuri Pankov { "iota", "*i" }, /* EQNSYM_iota */
215*260e9a87SYuri Pankov { "kappa", "*k" }, /* EQNSYM_kappa */
216*260e9a87SYuri Pankov { "lambda", "*l" }, /* EQNSYM_lambda */
217*260e9a87SYuri Pankov { "mu", "*m" }, /* EQNSYM_mu */
218*260e9a87SYuri Pankov { "nu", "*n" }, /* EQNSYM_nu */
219*260e9a87SYuri Pankov { "omega", "*w" }, /* EQNSYM_omega */
220*260e9a87SYuri Pankov { "omicron", "*o" }, /* EQNSYM_omicron */
221*260e9a87SYuri Pankov { "phi", "*f" }, /* EQNSYM_phi */
222*260e9a87SYuri Pankov { "pi", "*p" }, /* EQNSYM_pi */
223*260e9a87SYuri Pankov { "psi", "*q" }, /* EQNSYM_psi */
224*260e9a87SYuri Pankov { "rho", "*r" }, /* EQNSYM_rho */
225*260e9a87SYuri Pankov { "sigma", "*s" }, /* EQNSYM_sigma */
226*260e9a87SYuri Pankov { "tau", "*t" }, /* EQNSYM_tau */
227*260e9a87SYuri Pankov { "theta", "*h" }, /* EQNSYM_theta */
228*260e9a87SYuri Pankov { "upsilon", "*u" }, /* EQNSYM_upsilon */
229*260e9a87SYuri Pankov { "xi", "*c" }, /* EQNSYM_xi */
230*260e9a87SYuri Pankov { "zeta", "*z" }, /* EQNSYM_zeta */
231*260e9a87SYuri Pankov { "DELTA", "*D" }, /* EQNSYM_DELTA */
232*260e9a87SYuri Pankov { "GAMMA", "*G" }, /* EQNSYM_GAMMA */
233*260e9a87SYuri Pankov { "LAMBDA", "*L" }, /* EQNSYM_LAMBDA */
234*260e9a87SYuri Pankov { "OMEGA", "*W" }, /* EQNSYM_OMEGA */
235*260e9a87SYuri Pankov { "PHI", "*F" }, /* EQNSYM_PHI */
236*260e9a87SYuri Pankov { "PI", "*P" }, /* EQNSYM_PI */
237*260e9a87SYuri Pankov { "PSI", "*Q" }, /* EQNSYM_PSI */
238*260e9a87SYuri Pankov { "SIGMA", "*S" }, /* EQNSYM_SIGMA */
239*260e9a87SYuri Pankov { "THETA", "*H" }, /* EQNSYM_THETA */
240*260e9a87SYuri Pankov { "UPSILON", "*U" }, /* EQNSYM_UPSILON */
241*260e9a87SYuri Pankov { "XI", "*C" }, /* EQNSYM_XI */
242*260e9a87SYuri Pankov { "inter", "ca" }, /* EQNSYM_inter */
243*260e9a87SYuri Pankov { "union", "cu" }, /* EQNSYM_union */
244*260e9a87SYuri Pankov { "prod", "product" }, /* EQNSYM_prod */
245*260e9a87SYuri Pankov { "int", "integral" }, /* EQNSYM_int */
246*260e9a87SYuri Pankov { "sum", "sum" }, /* EQNSYM_sum */
247*260e9a87SYuri Pankov { "grad", "gr" }, /* EQNSYM_grad */
248*260e9a87SYuri Pankov { "del", "gr" }, /* EQNSYM_del */
249*260e9a87SYuri Pankov { "times", "mu" }, /* EQNSYM_times */
250*260e9a87SYuri Pankov { "cdot", "pc" }, /* EQNSYM_cdot */
251*260e9a87SYuri Pankov { "nothing", "&" }, /* EQNSYM_nothing */
252*260e9a87SYuri Pankov { "approx", "~~" }, /* EQNSYM_approx */
253*260e9a87SYuri Pankov { "prime", "fm" }, /* EQNSYM_prime */
254*260e9a87SYuri Pankov { "half", "12" }, /* EQNSYM_half */
255*260e9a87SYuri Pankov { "partial", "pd" }, /* EQNSYM_partial */
256*260e9a87SYuri Pankov { "inf", "if" }, /* EQNSYM_inf */
257*260e9a87SYuri Pankov { ">>", ">>" }, /* EQNSYM_muchgreat */
258*260e9a87SYuri Pankov { "<<", "<<" }, /* EQNSYM_muchless */
259*260e9a87SYuri Pankov { "<-", "<-" }, /* EQNSYM_larrow */
260*260e9a87SYuri Pankov { "->", "->" }, /* EQNSYM_rarrow */
261*260e9a87SYuri Pankov { "+-", "+-" }, /* EQNSYM_pm */
262*260e9a87SYuri Pankov { "!=", "!=" }, /* EQNSYM_nequal */
263*260e9a87SYuri Pankov { "==", "==" }, /* EQNSYM_equiv */
264*260e9a87SYuri Pankov { "<=", "<=" }, /* EQNSYM_lessequal */
265*260e9a87SYuri Pankov { ">=", ">=" }, /* EQNSYM_moreequal */
266*260e9a87SYuri Pankov { "-", "mi" }, /* EQNSYM_minus */
26795c635efSGarrett D'Amore };
26895c635efSGarrett D'Amore
269*260e9a87SYuri Pankov static struct eqn_box *eqn_box_alloc(struct eqn_node *, struct eqn_box *);
270*260e9a87SYuri Pankov static void eqn_box_free(struct eqn_box *);
271*260e9a87SYuri Pankov static struct eqn_box *eqn_box_makebinary(struct eqn_node *,
272*260e9a87SYuri Pankov enum eqn_post, struct eqn_box *);
273*260e9a87SYuri Pankov static void eqn_def(struct eqn_node *);
274*260e9a87SYuri Pankov static struct eqn_def *eqn_def_find(struct eqn_node *, const char *, size_t);
275*260e9a87SYuri Pankov static void eqn_delim(struct eqn_node *);
276*260e9a87SYuri Pankov static const char *eqn_next(struct eqn_node *, char, size_t *, int);
277*260e9a87SYuri Pankov static const char *eqn_nextrawtok(struct eqn_node *, size_t *);
278*260e9a87SYuri Pankov static const char *eqn_nexttok(struct eqn_node *, size_t *);
279*260e9a87SYuri Pankov static enum rofferr eqn_parse(struct eqn_node *, struct eqn_box *);
280*260e9a87SYuri Pankov static enum eqn_tok eqn_tok_parse(struct eqn_node *, char **);
281*260e9a87SYuri Pankov static void eqn_undef(struct eqn_node *);
282*260e9a87SYuri Pankov
283*260e9a87SYuri Pankov
28495c635efSGarrett D'Amore enum rofferr
eqn_read(struct eqn_node ** epp,int ln,const char * p,int pos,int * offs)28595c635efSGarrett D'Amore eqn_read(struct eqn_node **epp, int ln,
28695c635efSGarrett D'Amore const char *p, int pos, int *offs)
28795c635efSGarrett D'Amore {
28895c635efSGarrett D'Amore size_t sz;
28995c635efSGarrett D'Amore struct eqn_node *ep;
29095c635efSGarrett D'Amore enum rofferr er;
29195c635efSGarrett D'Amore
29295c635efSGarrett D'Amore ep = *epp;
29395c635efSGarrett D'Amore
29495c635efSGarrett D'Amore /*
29595c635efSGarrett D'Amore * If we're the terminating mark, unset our equation status and
29695c635efSGarrett D'Amore * validate the full equation.
29795c635efSGarrett D'Amore */
29895c635efSGarrett D'Amore
29995c635efSGarrett D'Amore if (0 == strncmp(p, ".EN", 3)) {
30095c635efSGarrett D'Amore er = eqn_end(epp);
30195c635efSGarrett D'Amore p += 3;
30295c635efSGarrett D'Amore while (' ' == *p || '\t' == *p)
30395c635efSGarrett D'Amore p++;
30495c635efSGarrett D'Amore if ('\0' == *p)
30595c635efSGarrett D'Amore return(er);
306*260e9a87SYuri Pankov mandoc_vmsg(MANDOCERR_ARG_SKIP, ep->parse,
307*260e9a87SYuri Pankov ln, pos, "EN %s", p);
30895c635efSGarrett D'Amore return(er);
30995c635efSGarrett D'Amore }
31095c635efSGarrett D'Amore
31195c635efSGarrett D'Amore /*
31295c635efSGarrett D'Amore * Build up the full string, replacing all newlines with regular
31395c635efSGarrett D'Amore * whitespace.
31495c635efSGarrett D'Amore */
31595c635efSGarrett D'Amore
31695c635efSGarrett D'Amore sz = strlen(p + pos) + 1;
31795c635efSGarrett D'Amore ep->data = mandoc_realloc(ep->data, ep->sz + sz + 1);
31895c635efSGarrett D'Amore
31995c635efSGarrett D'Amore /* First invocation: nil terminate the string. */
32095c635efSGarrett D'Amore
32195c635efSGarrett D'Amore if (0 == ep->sz)
32295c635efSGarrett D'Amore *ep->data = '\0';
32395c635efSGarrett D'Amore
32495c635efSGarrett D'Amore ep->sz += sz;
32595c635efSGarrett D'Amore strlcat(ep->data, p + pos, ep->sz + 1);
32695c635efSGarrett D'Amore strlcat(ep->data, " ", ep->sz + 1);
32795c635efSGarrett D'Amore return(ROFF_IGN);
32895c635efSGarrett D'Amore }
32995c635efSGarrett D'Amore
33095c635efSGarrett D'Amore struct eqn_node *
eqn_alloc(int pos,int line,struct mparse * parse)331*260e9a87SYuri Pankov eqn_alloc(int pos, int line, struct mparse *parse)
33295c635efSGarrett D'Amore {
33395c635efSGarrett D'Amore struct eqn_node *p;
33495c635efSGarrett D'Amore
33595c635efSGarrett D'Amore p = mandoc_calloc(1, sizeof(struct eqn_node));
33695c635efSGarrett D'Amore
33795c635efSGarrett D'Amore p->parse = parse;
33895c635efSGarrett D'Amore p->eqn.ln = line;
33995c635efSGarrett D'Amore p->eqn.pos = pos;
34095c635efSGarrett D'Amore p->gsize = EQN_DEFSIZE;
34195c635efSGarrett D'Amore
34295c635efSGarrett D'Amore return(p);
34395c635efSGarrett D'Amore }
34495c635efSGarrett D'Amore
345*260e9a87SYuri Pankov /*
346*260e9a87SYuri Pankov * Find the key "key" of the give size within our eqn-defined values.
347*260e9a87SYuri Pankov */
348*260e9a87SYuri Pankov static struct eqn_def *
eqn_def_find(struct eqn_node * ep,const char * key,size_t sz)349*260e9a87SYuri Pankov eqn_def_find(struct eqn_node *ep, const char *key, size_t sz)
35095c635efSGarrett D'Amore {
35195c635efSGarrett D'Amore int i;
35295c635efSGarrett D'Amore
353*260e9a87SYuri Pankov for (i = 0; i < (int)ep->defsz; i++)
354*260e9a87SYuri Pankov if (ep->defs[i].keysz && STRNEQ(ep->defs[i].key,
355*260e9a87SYuri Pankov ep->defs[i].keysz, key, sz))
356*260e9a87SYuri Pankov return(&ep->defs[i]);
35795c635efSGarrett D'Amore
358*260e9a87SYuri Pankov return(NULL);
35995c635efSGarrett D'Amore }
36095c635efSGarrett D'Amore
361*260e9a87SYuri Pankov /*
362*260e9a87SYuri Pankov * Get the next token from the input stream using the given quote
363*260e9a87SYuri Pankov * character.
364*260e9a87SYuri Pankov * Optionally make any replacements.
365*260e9a87SYuri Pankov */
36695c635efSGarrett D'Amore static const char *
eqn_next(struct eqn_node * ep,char quote,size_t * sz,int repl)36795c635efSGarrett D'Amore eqn_next(struct eqn_node *ep, char quote, size_t *sz, int repl)
36895c635efSGarrett D'Amore {
36995c635efSGarrett D'Amore char *start, *next;
37095c635efSGarrett D'Amore int q, diff, lim;
37195c635efSGarrett D'Amore size_t ssz, dummy;
37295c635efSGarrett D'Amore struct eqn_def *def;
37395c635efSGarrett D'Amore
37495c635efSGarrett D'Amore if (NULL == sz)
37595c635efSGarrett D'Amore sz = &dummy;
37695c635efSGarrett D'Amore
37795c635efSGarrett D'Amore lim = 0;
37895c635efSGarrett D'Amore ep->rew = ep->cur;
37995c635efSGarrett D'Amore again:
38095c635efSGarrett D'Amore /* Prevent self-definitions. */
38195c635efSGarrett D'Amore
38295c635efSGarrett D'Amore if (lim >= EQN_NEST_MAX) {
383*260e9a87SYuri Pankov mandoc_msg(MANDOCERR_ROFFLOOP, ep->parse,
384*260e9a87SYuri Pankov ep->eqn.ln, ep->eqn.pos, NULL);
38595c635efSGarrett D'Amore return(NULL);
38695c635efSGarrett D'Amore }
38795c635efSGarrett D'Amore
38895c635efSGarrett D'Amore ep->cur = ep->rew;
38995c635efSGarrett D'Amore start = &ep->data[(int)ep->cur];
39095c635efSGarrett D'Amore q = 0;
39195c635efSGarrett D'Amore
39295c635efSGarrett D'Amore if ('\0' == *start)
39395c635efSGarrett D'Amore return(NULL);
39495c635efSGarrett D'Amore
39595c635efSGarrett D'Amore if (quote == *start) {
39695c635efSGarrett D'Amore ep->cur++;
39795c635efSGarrett D'Amore q = 1;
39895c635efSGarrett D'Amore }
39995c635efSGarrett D'Amore
40095c635efSGarrett D'Amore start = &ep->data[(int)ep->cur];
40195c635efSGarrett D'Amore
40295c635efSGarrett D'Amore if ( ! q) {
40395c635efSGarrett D'Amore if ('{' == *start || '}' == *start)
40495c635efSGarrett D'Amore ssz = 1;
40595c635efSGarrett D'Amore else
40695c635efSGarrett D'Amore ssz = strcspn(start + 1, " ^~\"{}\t") + 1;
40795c635efSGarrett D'Amore next = start + (int)ssz;
40895c635efSGarrett D'Amore if ('\0' == *next)
40995c635efSGarrett D'Amore next = NULL;
41095c635efSGarrett D'Amore } else
41195c635efSGarrett D'Amore next = strchr(start, quote);
41295c635efSGarrett D'Amore
41395c635efSGarrett D'Amore if (NULL != next) {
41495c635efSGarrett D'Amore *sz = (size_t)(next - start);
41595c635efSGarrett D'Amore ep->cur += *sz;
41695c635efSGarrett D'Amore if (q)
41795c635efSGarrett D'Amore ep->cur++;
41895c635efSGarrett D'Amore while (' ' == ep->data[(int)ep->cur] ||
41995c635efSGarrett D'Amore '\t' == ep->data[(int)ep->cur] ||
42095c635efSGarrett D'Amore '^' == ep->data[(int)ep->cur] ||
42195c635efSGarrett D'Amore '~' == ep->data[(int)ep->cur])
42295c635efSGarrett D'Amore ep->cur++;
42395c635efSGarrett D'Amore } else {
42495c635efSGarrett D'Amore if (q)
425*260e9a87SYuri Pankov mandoc_msg(MANDOCERR_ARG_QUOTE, ep->parse,
426*260e9a87SYuri Pankov ep->eqn.ln, ep->eqn.pos, NULL);
42795c635efSGarrett D'Amore next = strchr(start, '\0');
42895c635efSGarrett D'Amore *sz = (size_t)(next - start);
42995c635efSGarrett D'Amore ep->cur += *sz;
43095c635efSGarrett D'Amore }
43195c635efSGarrett D'Amore
43295c635efSGarrett D'Amore /* Quotes aren't expanded for values. */
43395c635efSGarrett D'Amore
43495c635efSGarrett D'Amore if (q || ! repl)
43595c635efSGarrett D'Amore return(start);
43695c635efSGarrett D'Amore
43795c635efSGarrett D'Amore if (NULL != (def = eqn_def_find(ep, start, *sz))) {
43895c635efSGarrett D'Amore diff = def->valsz - *sz;
43995c635efSGarrett D'Amore
44095c635efSGarrett D'Amore if (def->valsz > *sz) {
44195c635efSGarrett D'Amore ep->sz += diff;
44295c635efSGarrett D'Amore ep->data = mandoc_realloc(ep->data, ep->sz + 1);
44395c635efSGarrett D'Amore ep->data[ep->sz] = '\0';
44495c635efSGarrett D'Amore start = &ep->data[(int)ep->rew];
44595c635efSGarrett D'Amore }
44695c635efSGarrett D'Amore
44795c635efSGarrett D'Amore diff = def->valsz - *sz;
44895c635efSGarrett D'Amore memmove(start + *sz + diff, start + *sz,
44995c635efSGarrett D'Amore (strlen(start) - *sz) + 1);
45095c635efSGarrett D'Amore memcpy(start, def->val, def->valsz);
45195c635efSGarrett D'Amore goto again;
45295c635efSGarrett D'Amore }
45395c635efSGarrett D'Amore
45495c635efSGarrett D'Amore return(start);
45595c635efSGarrett D'Amore }
45695c635efSGarrett D'Amore
457*260e9a87SYuri Pankov /*
458*260e9a87SYuri Pankov * Get the next delimited token using the default current quote
459*260e9a87SYuri Pankov * character.
460*260e9a87SYuri Pankov */
461*260e9a87SYuri Pankov static const char *
eqn_nexttok(struct eqn_node * ep,size_t * sz)462*260e9a87SYuri Pankov eqn_nexttok(struct eqn_node *ep, size_t *sz)
46395c635efSGarrett D'Amore {
46495c635efSGarrett D'Amore
465*260e9a87SYuri Pankov return(eqn_next(ep, '"', sz, 1));
46695c635efSGarrett D'Amore }
46795c635efSGarrett D'Amore
468*260e9a87SYuri Pankov /*
469*260e9a87SYuri Pankov * Get next token without replacement.
470*260e9a87SYuri Pankov */
471*260e9a87SYuri Pankov static const char *
eqn_nextrawtok(struct eqn_node * ep,size_t * sz)472*260e9a87SYuri Pankov eqn_nextrawtok(struct eqn_node *ep, size_t *sz)
47395c635efSGarrett D'Amore {
47495c635efSGarrett D'Amore
475*260e9a87SYuri Pankov return(eqn_next(ep, '"', sz, 0));
47695c635efSGarrett D'Amore }
47795c635efSGarrett D'Amore
478*260e9a87SYuri Pankov /*
479*260e9a87SYuri Pankov * Parse a token from the stream of text.
480*260e9a87SYuri Pankov * A token consists of one of the recognised eqn(7) strings.
481*260e9a87SYuri Pankov * Strings are separated by delimiting marks.
482*260e9a87SYuri Pankov * This returns EQN_TOK_EOF when there are no more tokens.
483*260e9a87SYuri Pankov * If the token is an unrecognised string literal, then it returns
484*260e9a87SYuri Pankov * EQN_TOK__MAX and sets the "p" pointer to an allocated, nil-terminated
485*260e9a87SYuri Pankov * string.
486*260e9a87SYuri Pankov * This must be later freed with free(3).
487*260e9a87SYuri Pankov */
488*260e9a87SYuri Pankov static enum eqn_tok
eqn_tok_parse(struct eqn_node * ep,char ** p)489*260e9a87SYuri Pankov eqn_tok_parse(struct eqn_node *ep, char **p)
490*260e9a87SYuri Pankov {
491*260e9a87SYuri Pankov const char *start;
492*260e9a87SYuri Pankov size_t i, sz;
493*260e9a87SYuri Pankov int quoted;
494*260e9a87SYuri Pankov
495*260e9a87SYuri Pankov if (NULL != p)
496*260e9a87SYuri Pankov *p = NULL;
497*260e9a87SYuri Pankov
498*260e9a87SYuri Pankov quoted = ep->data[ep->cur] == '"';
499*260e9a87SYuri Pankov
500*260e9a87SYuri Pankov if (NULL == (start = eqn_nexttok(ep, &sz)))
501*260e9a87SYuri Pankov return(EQN_TOK_EOF);
502*260e9a87SYuri Pankov
503*260e9a87SYuri Pankov if (quoted) {
504*260e9a87SYuri Pankov if (p != NULL)
505*260e9a87SYuri Pankov *p = mandoc_strndup(start, sz);
506*260e9a87SYuri Pankov return(EQN_TOK__MAX);
507*260e9a87SYuri Pankov }
508*260e9a87SYuri Pankov
509*260e9a87SYuri Pankov for (i = 0; i < EQN_TOK__MAX; i++) {
510*260e9a87SYuri Pankov if (NULL == eqn_toks[i])
511*260e9a87SYuri Pankov continue;
512*260e9a87SYuri Pankov if (STRNEQ(start, sz, eqn_toks[i], strlen(eqn_toks[i])))
513*260e9a87SYuri Pankov break;
514*260e9a87SYuri Pankov }
515*260e9a87SYuri Pankov
516*260e9a87SYuri Pankov if (i == EQN_TOK__MAX && NULL != p)
517*260e9a87SYuri Pankov *p = mandoc_strndup(start, sz);
518*260e9a87SYuri Pankov
519*260e9a87SYuri Pankov return(i);
520*260e9a87SYuri Pankov }
521*260e9a87SYuri Pankov
522*260e9a87SYuri Pankov static void
eqn_box_free(struct eqn_box * bp)523*260e9a87SYuri Pankov eqn_box_free(struct eqn_box *bp)
52495c635efSGarrett D'Amore {
52595c635efSGarrett D'Amore
526*260e9a87SYuri Pankov if (bp->first)
527*260e9a87SYuri Pankov eqn_box_free(bp->first);
528*260e9a87SYuri Pankov if (bp->next)
529*260e9a87SYuri Pankov eqn_box_free(bp->next);
53095c635efSGarrett D'Amore
531*260e9a87SYuri Pankov free(bp->text);
532*260e9a87SYuri Pankov free(bp->left);
533*260e9a87SYuri Pankov free(bp->right);
534*260e9a87SYuri Pankov free(bp->top);
535*260e9a87SYuri Pankov free(bp->bottom);
536*260e9a87SYuri Pankov free(bp);
53795c635efSGarrett D'Amore }
53895c635efSGarrett D'Amore
539*260e9a87SYuri Pankov /*
540*260e9a87SYuri Pankov * Allocate a box as the last child of the parent node.
541*260e9a87SYuri Pankov */
542*260e9a87SYuri Pankov static struct eqn_box *
eqn_box_alloc(struct eqn_node * ep,struct eqn_box * parent)543*260e9a87SYuri Pankov eqn_box_alloc(struct eqn_node *ep, struct eqn_box *parent)
544*260e9a87SYuri Pankov {
545*260e9a87SYuri Pankov struct eqn_box *bp;
546*260e9a87SYuri Pankov
547*260e9a87SYuri Pankov bp = mandoc_calloc(1, sizeof(struct eqn_box));
548*260e9a87SYuri Pankov bp->parent = parent;
549*260e9a87SYuri Pankov bp->parent->args++;
550*260e9a87SYuri Pankov bp->expectargs = UINT_MAX;
551*260e9a87SYuri Pankov bp->size = ep->gsize;
552*260e9a87SYuri Pankov
553*260e9a87SYuri Pankov if (NULL != parent->first) {
554*260e9a87SYuri Pankov parent->last->next = bp;
555*260e9a87SYuri Pankov bp->prev = parent->last;
556*260e9a87SYuri Pankov } else
557*260e9a87SYuri Pankov parent->first = bp;
558*260e9a87SYuri Pankov
559*260e9a87SYuri Pankov parent->last = bp;
560*260e9a87SYuri Pankov return(bp);
561*260e9a87SYuri Pankov }
562*260e9a87SYuri Pankov
563*260e9a87SYuri Pankov /*
564*260e9a87SYuri Pankov * Reparent the current last node (of the current parent) under a new
565*260e9a87SYuri Pankov * EQN_SUBEXPR as the first element.
566*260e9a87SYuri Pankov * Then return the new parent.
567*260e9a87SYuri Pankov * The new EQN_SUBEXPR will have a two-child limit.
568*260e9a87SYuri Pankov */
569*260e9a87SYuri Pankov static struct eqn_box *
eqn_box_makebinary(struct eqn_node * ep,enum eqn_post pos,struct eqn_box * parent)570*260e9a87SYuri Pankov eqn_box_makebinary(struct eqn_node *ep,
571*260e9a87SYuri Pankov enum eqn_post pos, struct eqn_box *parent)
572*260e9a87SYuri Pankov {
573*260e9a87SYuri Pankov struct eqn_box *b, *newb;
574*260e9a87SYuri Pankov
575*260e9a87SYuri Pankov assert(NULL != parent->last);
576*260e9a87SYuri Pankov b = parent->last;
577*260e9a87SYuri Pankov if (parent->last == parent->first)
578*260e9a87SYuri Pankov parent->first = NULL;
579*260e9a87SYuri Pankov parent->args--;
580*260e9a87SYuri Pankov parent->last = b->prev;
581*260e9a87SYuri Pankov b->prev = NULL;
582*260e9a87SYuri Pankov newb = eqn_box_alloc(ep, parent);
583*260e9a87SYuri Pankov newb->pos = pos;
584*260e9a87SYuri Pankov newb->type = EQN_SUBEXPR;
585*260e9a87SYuri Pankov newb->expectargs = 2;
586*260e9a87SYuri Pankov newb->args = 1;
587*260e9a87SYuri Pankov newb->first = newb->last = b;
588*260e9a87SYuri Pankov newb->first->next = NULL;
589*260e9a87SYuri Pankov b->parent = newb;
590*260e9a87SYuri Pankov return(newb);
591*260e9a87SYuri Pankov }
592*260e9a87SYuri Pankov
593*260e9a87SYuri Pankov /*
594*260e9a87SYuri Pankov * Parse the "delim" control statement.
595*260e9a87SYuri Pankov */
596*260e9a87SYuri Pankov static void
eqn_delim(struct eqn_node * ep)597*260e9a87SYuri Pankov eqn_delim(struct eqn_node *ep)
598*260e9a87SYuri Pankov {
599*260e9a87SYuri Pankov const char *start;
600*260e9a87SYuri Pankov size_t sz;
601*260e9a87SYuri Pankov
602*260e9a87SYuri Pankov if ((start = eqn_nextrawtok(ep, &sz)) == NULL)
603*260e9a87SYuri Pankov mandoc_msg(MANDOCERR_REQ_EMPTY, ep->parse,
604*260e9a87SYuri Pankov ep->eqn.ln, ep->eqn.pos, "delim");
605*260e9a87SYuri Pankov else if (strncmp(start, "off", 3) == 0)
606*260e9a87SYuri Pankov ep->delim = 0;
607*260e9a87SYuri Pankov else if (strncmp(start, "on", 2) == 0) {
608*260e9a87SYuri Pankov if (ep->odelim && ep->cdelim)
609*260e9a87SYuri Pankov ep->delim = 1;
610*260e9a87SYuri Pankov } else if (start[1] != '\0') {
611*260e9a87SYuri Pankov ep->odelim = start[0];
612*260e9a87SYuri Pankov ep->cdelim = start[1];
613*260e9a87SYuri Pankov ep->delim = 1;
614*260e9a87SYuri Pankov }
615*260e9a87SYuri Pankov }
616*260e9a87SYuri Pankov
617*260e9a87SYuri Pankov /*
618*260e9a87SYuri Pankov * Undefine a previously-defined string.
619*260e9a87SYuri Pankov */
620*260e9a87SYuri Pankov static void
eqn_undef(struct eqn_node * ep)621*260e9a87SYuri Pankov eqn_undef(struct eqn_node *ep)
622*260e9a87SYuri Pankov {
623*260e9a87SYuri Pankov const char *start;
624*260e9a87SYuri Pankov struct eqn_def *def;
625*260e9a87SYuri Pankov size_t sz;
626*260e9a87SYuri Pankov
627*260e9a87SYuri Pankov if ((start = eqn_nextrawtok(ep, &sz)) == NULL) {
628*260e9a87SYuri Pankov mandoc_msg(MANDOCERR_REQ_EMPTY, ep->parse,
629*260e9a87SYuri Pankov ep->eqn.ln, ep->eqn.pos, "undef");
630*260e9a87SYuri Pankov return;
631*260e9a87SYuri Pankov }
632*260e9a87SYuri Pankov if ((def = eqn_def_find(ep, start, sz)) == NULL)
633*260e9a87SYuri Pankov return;
634*260e9a87SYuri Pankov free(def->key);
635*260e9a87SYuri Pankov free(def->val);
636*260e9a87SYuri Pankov def->key = def->val = NULL;
637*260e9a87SYuri Pankov def->keysz = def->valsz = 0;
638*260e9a87SYuri Pankov }
639*260e9a87SYuri Pankov
640*260e9a87SYuri Pankov static void
eqn_def(struct eqn_node * ep)641*260e9a87SYuri Pankov eqn_def(struct eqn_node *ep)
64295c635efSGarrett D'Amore {
64395c635efSGarrett D'Amore const char *start;
64495c635efSGarrett D'Amore size_t sz;
64595c635efSGarrett D'Amore struct eqn_def *def;
64695c635efSGarrett D'Amore int i;
64795c635efSGarrett D'Amore
648*260e9a87SYuri Pankov if ((start = eqn_nextrawtok(ep, &sz)) == NULL) {
649*260e9a87SYuri Pankov mandoc_msg(MANDOCERR_REQ_EMPTY, ep->parse,
650*260e9a87SYuri Pankov ep->eqn.ln, ep->eqn.pos, "define");
651*260e9a87SYuri Pankov return;
65295c635efSGarrett D'Amore }
65395c635efSGarrett D'Amore
65495c635efSGarrett D'Amore /*
65595c635efSGarrett D'Amore * Search for a key that already exists.
65695c635efSGarrett D'Amore * Create a new key if none is found.
65795c635efSGarrett D'Amore */
65895c635efSGarrett D'Amore if (NULL == (def = eqn_def_find(ep, start, sz))) {
65995c635efSGarrett D'Amore /* Find holes in string array. */
66095c635efSGarrett D'Amore for (i = 0; i < (int)ep->defsz; i++)
66195c635efSGarrett D'Amore if (0 == ep->defs[i].keysz)
66295c635efSGarrett D'Amore break;
66395c635efSGarrett D'Amore
66495c635efSGarrett D'Amore if (i == (int)ep->defsz) {
66595c635efSGarrett D'Amore ep->defsz++;
666*260e9a87SYuri Pankov ep->defs = mandoc_reallocarray(ep->defs,
667*260e9a87SYuri Pankov ep->defsz, sizeof(struct eqn_def));
66895c635efSGarrett D'Amore ep->defs[i].key = ep->defs[i].val = NULL;
66995c635efSGarrett D'Amore }
67095c635efSGarrett D'Amore
671*260e9a87SYuri Pankov def = ep->defs + i;
672*260e9a87SYuri Pankov free(def->key);
673*260e9a87SYuri Pankov def->key = mandoc_strndup(start, sz);
674*260e9a87SYuri Pankov def->keysz = sz;
67595c635efSGarrett D'Amore }
67695c635efSGarrett D'Amore
67795c635efSGarrett D'Amore start = eqn_next(ep, ep->data[(int)ep->cur], &sz, 0);
678*260e9a87SYuri Pankov if (start == NULL) {
679*260e9a87SYuri Pankov mandoc_vmsg(MANDOCERR_REQ_EMPTY, ep->parse,
680*260e9a87SYuri Pankov ep->eqn.ln, ep->eqn.pos, "define %s", def->key);
681*260e9a87SYuri Pankov free(def->key);
682*260e9a87SYuri Pankov free(def->val);
683*260e9a87SYuri Pankov def->key = def->val = NULL;
684*260e9a87SYuri Pankov def->keysz = def->valsz = 0;
685*260e9a87SYuri Pankov return;
68695c635efSGarrett D'Amore }
687*260e9a87SYuri Pankov free(def->val);
688*260e9a87SYuri Pankov def->val = mandoc_strndup(start, sz);
68995c635efSGarrett D'Amore def->valsz = sz;
69095c635efSGarrett D'Amore }
69195c635efSGarrett D'Amore
692*260e9a87SYuri Pankov /*
693*260e9a87SYuri Pankov * Recursively parse an eqn(7) expression.
694*260e9a87SYuri Pankov */
695*260e9a87SYuri Pankov static enum rofferr
eqn_parse(struct eqn_node * ep,struct eqn_box * parent)696*260e9a87SYuri Pankov eqn_parse(struct eqn_node *ep, struct eqn_box *parent)
69795c635efSGarrett D'Amore {
698*260e9a87SYuri Pankov char sym[64];
699*260e9a87SYuri Pankov struct eqn_box *cur;
70095c635efSGarrett D'Amore const char *start;
701*260e9a87SYuri Pankov char *p;
702*260e9a87SYuri Pankov size_t i, sz;
703*260e9a87SYuri Pankov enum eqn_tok tok, subtok;
704*260e9a87SYuri Pankov enum eqn_post pos;
705*260e9a87SYuri Pankov int size;
70695c635efSGarrett D'Amore
707*260e9a87SYuri Pankov assert(parent != NULL);
708*260e9a87SYuri Pankov
709*260e9a87SYuri Pankov /*
710*260e9a87SYuri Pankov * Empty equation.
711*260e9a87SYuri Pankov * Do not add it to the high-level syntax tree.
712*260e9a87SYuri Pankov */
713*260e9a87SYuri Pankov
714*260e9a87SYuri Pankov if (ep->data == NULL)
715*260e9a87SYuri Pankov return(ROFF_IGN);
716*260e9a87SYuri Pankov
717*260e9a87SYuri Pankov next_tok:
718*260e9a87SYuri Pankov tok = eqn_tok_parse(ep, &p);
719*260e9a87SYuri Pankov
720*260e9a87SYuri Pankov this_tok:
721*260e9a87SYuri Pankov switch (tok) {
722*260e9a87SYuri Pankov case (EQN_TOK_UNDEF):
723*260e9a87SYuri Pankov eqn_undef(ep);
724*260e9a87SYuri Pankov break;
725*260e9a87SYuri Pankov case (EQN_TOK_NDEFINE):
726*260e9a87SYuri Pankov case (EQN_TOK_DEFINE):
727*260e9a87SYuri Pankov eqn_def(ep);
728*260e9a87SYuri Pankov break;
729*260e9a87SYuri Pankov case (EQN_TOK_TDEFINE):
730*260e9a87SYuri Pankov if (eqn_nextrawtok(ep, NULL) == NULL ||
731*260e9a87SYuri Pankov eqn_next(ep, ep->data[(int)ep->cur], NULL, 0) == NULL)
732*260e9a87SYuri Pankov mandoc_msg(MANDOCERR_REQ_EMPTY, ep->parse,
733*260e9a87SYuri Pankov ep->eqn.ln, ep->eqn.pos, "tdefine");
734*260e9a87SYuri Pankov break;
735*260e9a87SYuri Pankov case (EQN_TOK_DELIM):
736*260e9a87SYuri Pankov eqn_delim(ep);
737*260e9a87SYuri Pankov break;
738*260e9a87SYuri Pankov case (EQN_TOK_GFONT):
739*260e9a87SYuri Pankov if (eqn_nextrawtok(ep, NULL) == NULL)
740*260e9a87SYuri Pankov mandoc_msg(MANDOCERR_REQ_EMPTY, ep->parse,
741*260e9a87SYuri Pankov ep->eqn.ln, ep->eqn.pos, eqn_toks[tok]);
742*260e9a87SYuri Pankov break;
743*260e9a87SYuri Pankov case (EQN_TOK_MARK):
744*260e9a87SYuri Pankov case (EQN_TOK_LINEUP):
745*260e9a87SYuri Pankov /* Ignore these. */
746*260e9a87SYuri Pankov break;
747*260e9a87SYuri Pankov case (EQN_TOK_DYAD):
748*260e9a87SYuri Pankov case (EQN_TOK_VEC):
749*260e9a87SYuri Pankov case (EQN_TOK_UNDER):
750*260e9a87SYuri Pankov case (EQN_TOK_BAR):
751*260e9a87SYuri Pankov case (EQN_TOK_TILDE):
752*260e9a87SYuri Pankov case (EQN_TOK_HAT):
753*260e9a87SYuri Pankov case (EQN_TOK_DOT):
754*260e9a87SYuri Pankov case (EQN_TOK_DOTDOT):
755*260e9a87SYuri Pankov if (parent->last == NULL) {
756*260e9a87SYuri Pankov mandoc_msg(MANDOCERR_EQN_NOBOX, ep->parse,
757*260e9a87SYuri Pankov ep->eqn.ln, ep->eqn.pos, eqn_toks[tok]);
758*260e9a87SYuri Pankov cur = eqn_box_alloc(ep, parent);
759*260e9a87SYuri Pankov cur->type = EQN_TEXT;
760*260e9a87SYuri Pankov cur->text = mandoc_strdup("");
76195c635efSGarrett D'Amore }
762*260e9a87SYuri Pankov parent = eqn_box_makebinary(ep, EQNPOS_NONE, parent);
763*260e9a87SYuri Pankov parent->type = EQN_LISTONE;
764*260e9a87SYuri Pankov parent->expectargs = 1;
765*260e9a87SYuri Pankov switch (tok) {
766*260e9a87SYuri Pankov case (EQN_TOK_DOTDOT):
767*260e9a87SYuri Pankov strlcpy(sym, "\\[ad]", sizeof(sym));
768*260e9a87SYuri Pankov break;
769*260e9a87SYuri Pankov case (EQN_TOK_VEC):
770*260e9a87SYuri Pankov strlcpy(sym, "\\[->]", sizeof(sym));
771*260e9a87SYuri Pankov break;
772*260e9a87SYuri Pankov case (EQN_TOK_DYAD):
773*260e9a87SYuri Pankov strlcpy(sym, "\\[<>]", sizeof(sym));
774*260e9a87SYuri Pankov break;
775*260e9a87SYuri Pankov case (EQN_TOK_TILDE):
776*260e9a87SYuri Pankov strlcpy(sym, "\\[a~]", sizeof(sym));
777*260e9a87SYuri Pankov break;
778*260e9a87SYuri Pankov case (EQN_TOK_UNDER):
779*260e9a87SYuri Pankov strlcpy(sym, "\\[ul]", sizeof(sym));
780*260e9a87SYuri Pankov break;
781*260e9a87SYuri Pankov case (EQN_TOK_BAR):
782*260e9a87SYuri Pankov strlcpy(sym, "\\[rl]", sizeof(sym));
783*260e9a87SYuri Pankov break;
784*260e9a87SYuri Pankov case (EQN_TOK_DOT):
785*260e9a87SYuri Pankov strlcpy(sym, "\\[a.]", sizeof(sym));
786*260e9a87SYuri Pankov break;
787*260e9a87SYuri Pankov case (EQN_TOK_HAT):
788*260e9a87SYuri Pankov strlcpy(sym, "\\[ha]", sizeof(sym));
789*260e9a87SYuri Pankov break;
790*260e9a87SYuri Pankov default:
791*260e9a87SYuri Pankov abort();
79295c635efSGarrett D'Amore }
79395c635efSGarrett D'Amore
794*260e9a87SYuri Pankov switch (tok) {
795*260e9a87SYuri Pankov case (EQN_TOK_DOTDOT):
796*260e9a87SYuri Pankov case (EQN_TOK_VEC):
797*260e9a87SYuri Pankov case (EQN_TOK_DYAD):
798*260e9a87SYuri Pankov case (EQN_TOK_TILDE):
799*260e9a87SYuri Pankov case (EQN_TOK_BAR):
800*260e9a87SYuri Pankov case (EQN_TOK_DOT):
801*260e9a87SYuri Pankov case (EQN_TOK_HAT):
802*260e9a87SYuri Pankov parent->top = mandoc_strdup(sym);
803*260e9a87SYuri Pankov break;
804*260e9a87SYuri Pankov case (EQN_TOK_UNDER):
805*260e9a87SYuri Pankov parent->bottom = mandoc_strdup(sym);
806*260e9a87SYuri Pankov break;
807*260e9a87SYuri Pankov default:
808*260e9a87SYuri Pankov abort();
809*260e9a87SYuri Pankov }
810*260e9a87SYuri Pankov parent = parent->parent;
811*260e9a87SYuri Pankov break;
812*260e9a87SYuri Pankov case (EQN_TOK_FWD):
813*260e9a87SYuri Pankov case (EQN_TOK_BACK):
814*260e9a87SYuri Pankov case (EQN_TOK_DOWN):
815*260e9a87SYuri Pankov case (EQN_TOK_UP):
816*260e9a87SYuri Pankov subtok = eqn_tok_parse(ep, NULL);
817*260e9a87SYuri Pankov if (subtok != EQN_TOK__MAX) {
818*260e9a87SYuri Pankov mandoc_msg(MANDOCERR_REQ_EMPTY, ep->parse,
819*260e9a87SYuri Pankov ep->eqn.ln, ep->eqn.pos, eqn_toks[tok]);
820*260e9a87SYuri Pankov tok = subtok;
821*260e9a87SYuri Pankov goto this_tok;
822*260e9a87SYuri Pankov }
823*260e9a87SYuri Pankov break;
824*260e9a87SYuri Pankov case (EQN_TOK_FAT):
825*260e9a87SYuri Pankov case (EQN_TOK_ROMAN):
826*260e9a87SYuri Pankov case (EQN_TOK_ITALIC):
827*260e9a87SYuri Pankov case (EQN_TOK_BOLD):
828*260e9a87SYuri Pankov while (parent->args == parent->expectargs)
829*260e9a87SYuri Pankov parent = parent->parent;
830*260e9a87SYuri Pankov /*
831*260e9a87SYuri Pankov * These values apply to the next word or sequence of
832*260e9a87SYuri Pankov * words; thus, we mark that we'll have a child with
833*260e9a87SYuri Pankov * exactly one of those.
834*260e9a87SYuri Pankov */
835*260e9a87SYuri Pankov parent = eqn_box_alloc(ep, parent);
836*260e9a87SYuri Pankov parent->type = EQN_LISTONE;
837*260e9a87SYuri Pankov parent->expectargs = 1;
838*260e9a87SYuri Pankov switch (tok) {
839*260e9a87SYuri Pankov case (EQN_TOK_FAT):
840*260e9a87SYuri Pankov parent->font = EQNFONT_FAT;
841*260e9a87SYuri Pankov break;
842*260e9a87SYuri Pankov case (EQN_TOK_ROMAN):
843*260e9a87SYuri Pankov parent->font = EQNFONT_ROMAN;
844*260e9a87SYuri Pankov break;
845*260e9a87SYuri Pankov case (EQN_TOK_ITALIC):
846*260e9a87SYuri Pankov parent->font = EQNFONT_ITALIC;
847*260e9a87SYuri Pankov break;
848*260e9a87SYuri Pankov case (EQN_TOK_BOLD):
849*260e9a87SYuri Pankov parent->font = EQNFONT_BOLD;
850*260e9a87SYuri Pankov break;
851*260e9a87SYuri Pankov default:
852*260e9a87SYuri Pankov abort();
853*260e9a87SYuri Pankov }
854*260e9a87SYuri Pankov break;
855*260e9a87SYuri Pankov case (EQN_TOK_SIZE):
856*260e9a87SYuri Pankov case (EQN_TOK_GSIZE):
857*260e9a87SYuri Pankov /* Accept two values: integral size and a single. */
858*260e9a87SYuri Pankov if (NULL == (start = eqn_nexttok(ep, &sz))) {
859*260e9a87SYuri Pankov mandoc_msg(MANDOCERR_REQ_EMPTY, ep->parse,
860*260e9a87SYuri Pankov ep->eqn.ln, ep->eqn.pos, eqn_toks[tok]);
861*260e9a87SYuri Pankov break;
862*260e9a87SYuri Pankov }
863*260e9a87SYuri Pankov size = mandoc_strntoi(start, sz, 10);
864*260e9a87SYuri Pankov if (-1 == size) {
865*260e9a87SYuri Pankov mandoc_msg(MANDOCERR_IT_NONUM, ep->parse,
866*260e9a87SYuri Pankov ep->eqn.ln, ep->eqn.pos, eqn_toks[tok]);
867*260e9a87SYuri Pankov break;
868*260e9a87SYuri Pankov }
869*260e9a87SYuri Pankov if (EQN_TOK_GSIZE == tok) {
870*260e9a87SYuri Pankov ep->gsize = size;
871*260e9a87SYuri Pankov break;
872*260e9a87SYuri Pankov }
873*260e9a87SYuri Pankov parent = eqn_box_alloc(ep, parent);
874*260e9a87SYuri Pankov parent->type = EQN_LISTONE;
875*260e9a87SYuri Pankov parent->expectargs = 1;
876*260e9a87SYuri Pankov parent->size = size;
877*260e9a87SYuri Pankov break;
878*260e9a87SYuri Pankov case (EQN_TOK_FROM):
879*260e9a87SYuri Pankov case (EQN_TOK_TO):
880*260e9a87SYuri Pankov case (EQN_TOK_SUB):
881*260e9a87SYuri Pankov case (EQN_TOK_SUP):
882*260e9a87SYuri Pankov /*
883*260e9a87SYuri Pankov * We have a left-right-associative expression.
884*260e9a87SYuri Pankov * Repivot under a positional node, open a child scope
885*260e9a87SYuri Pankov * and keep on reading.
886*260e9a87SYuri Pankov */
887*260e9a87SYuri Pankov if (parent->last == NULL) {
888*260e9a87SYuri Pankov mandoc_msg(MANDOCERR_EQN_NOBOX, ep->parse,
889*260e9a87SYuri Pankov ep->eqn.ln, ep->eqn.pos, eqn_toks[tok]);
890*260e9a87SYuri Pankov cur = eqn_box_alloc(ep, parent);
891*260e9a87SYuri Pankov cur->type = EQN_TEXT;
892*260e9a87SYuri Pankov cur->text = mandoc_strdup("");
893*260e9a87SYuri Pankov }
894*260e9a87SYuri Pankov /* Handle the "subsup" and "fromto" positions. */
895*260e9a87SYuri Pankov if (EQN_TOK_SUP == tok && parent->pos == EQNPOS_SUB) {
896*260e9a87SYuri Pankov parent->expectargs = 3;
897*260e9a87SYuri Pankov parent->pos = EQNPOS_SUBSUP;
898*260e9a87SYuri Pankov break;
899*260e9a87SYuri Pankov }
900*260e9a87SYuri Pankov if (EQN_TOK_TO == tok && parent->pos == EQNPOS_FROM) {
901*260e9a87SYuri Pankov parent->expectargs = 3;
902*260e9a87SYuri Pankov parent->pos = EQNPOS_FROMTO;
903*260e9a87SYuri Pankov break;
904*260e9a87SYuri Pankov }
905*260e9a87SYuri Pankov switch (tok) {
906*260e9a87SYuri Pankov case (EQN_TOK_FROM):
907*260e9a87SYuri Pankov pos = EQNPOS_FROM;
908*260e9a87SYuri Pankov break;
909*260e9a87SYuri Pankov case (EQN_TOK_TO):
910*260e9a87SYuri Pankov pos = EQNPOS_TO;
911*260e9a87SYuri Pankov break;
912*260e9a87SYuri Pankov case (EQN_TOK_SUP):
913*260e9a87SYuri Pankov pos = EQNPOS_SUP;
914*260e9a87SYuri Pankov break;
915*260e9a87SYuri Pankov case (EQN_TOK_SUB):
916*260e9a87SYuri Pankov pos = EQNPOS_SUB;
917*260e9a87SYuri Pankov break;
918*260e9a87SYuri Pankov default:
919*260e9a87SYuri Pankov abort();
920*260e9a87SYuri Pankov }
921*260e9a87SYuri Pankov parent = eqn_box_makebinary(ep, pos, parent);
922*260e9a87SYuri Pankov break;
923*260e9a87SYuri Pankov case (EQN_TOK_SQRT):
924*260e9a87SYuri Pankov while (parent->args == parent->expectargs)
925*260e9a87SYuri Pankov parent = parent->parent;
926*260e9a87SYuri Pankov /*
927*260e9a87SYuri Pankov * Accept a left-right-associative set of arguments just
928*260e9a87SYuri Pankov * like sub and sup and friends but without rebalancing
929*260e9a87SYuri Pankov * under a pivot.
930*260e9a87SYuri Pankov */
931*260e9a87SYuri Pankov parent = eqn_box_alloc(ep, parent);
932*260e9a87SYuri Pankov parent->type = EQN_SUBEXPR;
933*260e9a87SYuri Pankov parent->pos = EQNPOS_SQRT;
934*260e9a87SYuri Pankov parent->expectargs = 1;
935*260e9a87SYuri Pankov break;
936*260e9a87SYuri Pankov case (EQN_TOK_OVER):
937*260e9a87SYuri Pankov /*
938*260e9a87SYuri Pankov * We have a right-left-associative fraction.
939*260e9a87SYuri Pankov * Close out anything that's currently open, then
940*260e9a87SYuri Pankov * rebalance and continue reading.
941*260e9a87SYuri Pankov */
942*260e9a87SYuri Pankov if (parent->last == NULL) {
943*260e9a87SYuri Pankov mandoc_msg(MANDOCERR_EQN_NOBOX, ep->parse,
944*260e9a87SYuri Pankov ep->eqn.ln, ep->eqn.pos, eqn_toks[tok]);
945*260e9a87SYuri Pankov cur = eqn_box_alloc(ep, parent);
946*260e9a87SYuri Pankov cur->type = EQN_TEXT;
947*260e9a87SYuri Pankov cur->text = mandoc_strdup("");
948*260e9a87SYuri Pankov }
949*260e9a87SYuri Pankov while (EQN_SUBEXPR == parent->type)
950*260e9a87SYuri Pankov parent = parent->parent;
951*260e9a87SYuri Pankov parent = eqn_box_makebinary(ep, EQNPOS_OVER, parent);
952*260e9a87SYuri Pankov break;
953*260e9a87SYuri Pankov case (EQN_TOK_RIGHT):
954*260e9a87SYuri Pankov case (EQN_TOK_BRACE_CLOSE):
955*260e9a87SYuri Pankov /*
956*260e9a87SYuri Pankov * Close out the existing brace.
957*260e9a87SYuri Pankov * FIXME: this is a shitty sentinel: we should really
958*260e9a87SYuri Pankov * have a native EQN_BRACE type or whatnot.
959*260e9a87SYuri Pankov */
960*260e9a87SYuri Pankov for (cur = parent; cur != NULL; cur = cur->parent)
961*260e9a87SYuri Pankov if (cur->type == EQN_LIST &&
962*260e9a87SYuri Pankov (tok == EQN_TOK_BRACE_CLOSE ||
963*260e9a87SYuri Pankov cur->left != NULL))
964*260e9a87SYuri Pankov break;
965*260e9a87SYuri Pankov if (cur == NULL) {
966*260e9a87SYuri Pankov mandoc_msg(MANDOCERR_BLK_NOTOPEN, ep->parse,
967*260e9a87SYuri Pankov ep->eqn.ln, ep->eqn.pos, eqn_toks[tok]);
968*260e9a87SYuri Pankov break;
969*260e9a87SYuri Pankov }
970*260e9a87SYuri Pankov parent = cur;
971*260e9a87SYuri Pankov if (EQN_TOK_RIGHT == tok) {
972*260e9a87SYuri Pankov if (NULL == (start = eqn_nexttok(ep, &sz))) {
973*260e9a87SYuri Pankov mandoc_msg(MANDOCERR_REQ_EMPTY,
974*260e9a87SYuri Pankov ep->parse, ep->eqn.ln,
975*260e9a87SYuri Pankov ep->eqn.pos, eqn_toks[tok]);
976*260e9a87SYuri Pankov break;
977*260e9a87SYuri Pankov }
978*260e9a87SYuri Pankov /* Handling depends on right/left. */
979*260e9a87SYuri Pankov if (STRNEQ(start, sz, "ceiling", 7)) {
980*260e9a87SYuri Pankov strlcpy(sym, "\\[rc]", sizeof(sym));
981*260e9a87SYuri Pankov parent->right = mandoc_strdup(sym);
982*260e9a87SYuri Pankov } else if (STRNEQ(start, sz, "floor", 5)) {
983*260e9a87SYuri Pankov strlcpy(sym, "\\[rf]", sizeof(sym));
984*260e9a87SYuri Pankov parent->right = mandoc_strdup(sym);
985*260e9a87SYuri Pankov } else
986*260e9a87SYuri Pankov parent->right = mandoc_strndup(start, sz);
987*260e9a87SYuri Pankov }
988*260e9a87SYuri Pankov parent = parent->parent;
989*260e9a87SYuri Pankov if (EQN_TOK_BRACE_CLOSE == tok && parent &&
990*260e9a87SYuri Pankov (parent->type == EQN_PILE ||
991*260e9a87SYuri Pankov parent->type == EQN_MATRIX))
992*260e9a87SYuri Pankov parent = parent->parent;
993*260e9a87SYuri Pankov /* Close out any "singleton" lists. */
994*260e9a87SYuri Pankov while (parent->type == EQN_LISTONE &&
995*260e9a87SYuri Pankov parent->args == parent->expectargs)
996*260e9a87SYuri Pankov parent = parent->parent;
997*260e9a87SYuri Pankov break;
998*260e9a87SYuri Pankov case (EQN_TOK_BRACE_OPEN):
999*260e9a87SYuri Pankov case (EQN_TOK_LEFT):
1000*260e9a87SYuri Pankov /*
1001*260e9a87SYuri Pankov * If we already have something in the stack and we're
1002*260e9a87SYuri Pankov * in an expression, then rewind til we're not any more
1003*260e9a87SYuri Pankov * (just like with the text node).
1004*260e9a87SYuri Pankov */
1005*260e9a87SYuri Pankov while (parent->args == parent->expectargs)
1006*260e9a87SYuri Pankov parent = parent->parent;
1007*260e9a87SYuri Pankov if (EQN_TOK_LEFT == tok &&
1008*260e9a87SYuri Pankov (start = eqn_nexttok(ep, &sz)) == NULL) {
1009*260e9a87SYuri Pankov mandoc_msg(MANDOCERR_REQ_EMPTY, ep->parse,
1010*260e9a87SYuri Pankov ep->eqn.ln, ep->eqn.pos, eqn_toks[tok]);
1011*260e9a87SYuri Pankov break;
1012*260e9a87SYuri Pankov }
1013*260e9a87SYuri Pankov parent = eqn_box_alloc(ep, parent);
1014*260e9a87SYuri Pankov parent->type = EQN_LIST;
1015*260e9a87SYuri Pankov if (EQN_TOK_LEFT == tok) {
1016*260e9a87SYuri Pankov if (STRNEQ(start, sz, "ceiling", 7)) {
1017*260e9a87SYuri Pankov strlcpy(sym, "\\[lc]", sizeof(sym));
1018*260e9a87SYuri Pankov parent->left = mandoc_strdup(sym);
1019*260e9a87SYuri Pankov } else if (STRNEQ(start, sz, "floor", 5)) {
1020*260e9a87SYuri Pankov strlcpy(sym, "\\[lf]", sizeof(sym));
1021*260e9a87SYuri Pankov parent->left = mandoc_strdup(sym);
1022*260e9a87SYuri Pankov } else
1023*260e9a87SYuri Pankov parent->left = mandoc_strndup(start, sz);
1024*260e9a87SYuri Pankov }
1025*260e9a87SYuri Pankov break;
1026*260e9a87SYuri Pankov case (EQN_TOK_PILE):
1027*260e9a87SYuri Pankov case (EQN_TOK_LPILE):
1028*260e9a87SYuri Pankov case (EQN_TOK_RPILE):
1029*260e9a87SYuri Pankov case (EQN_TOK_CPILE):
1030*260e9a87SYuri Pankov case (EQN_TOK_CCOL):
1031*260e9a87SYuri Pankov case (EQN_TOK_LCOL):
1032*260e9a87SYuri Pankov case (EQN_TOK_RCOL):
1033*260e9a87SYuri Pankov while (parent->args == parent->expectargs)
1034*260e9a87SYuri Pankov parent = parent->parent;
1035*260e9a87SYuri Pankov parent = eqn_box_alloc(ep, parent);
1036*260e9a87SYuri Pankov parent->type = EQN_PILE;
1037*260e9a87SYuri Pankov parent->expectargs = 1;
1038*260e9a87SYuri Pankov break;
1039*260e9a87SYuri Pankov case (EQN_TOK_ABOVE):
1040*260e9a87SYuri Pankov for (cur = parent; cur != NULL; cur = cur->parent)
1041*260e9a87SYuri Pankov if (cur->type == EQN_PILE)
1042*260e9a87SYuri Pankov break;
1043*260e9a87SYuri Pankov if (cur == NULL) {
1044*260e9a87SYuri Pankov mandoc_msg(MANDOCERR_IT_STRAY, ep->parse,
1045*260e9a87SYuri Pankov ep->eqn.ln, ep->eqn.pos, eqn_toks[tok]);
1046*260e9a87SYuri Pankov break;
1047*260e9a87SYuri Pankov }
1048*260e9a87SYuri Pankov parent = eqn_box_alloc(ep, cur);
1049*260e9a87SYuri Pankov parent->type = EQN_LIST;
1050*260e9a87SYuri Pankov break;
1051*260e9a87SYuri Pankov case (EQN_TOK_MATRIX):
1052*260e9a87SYuri Pankov while (parent->args == parent->expectargs)
1053*260e9a87SYuri Pankov parent = parent->parent;
1054*260e9a87SYuri Pankov parent = eqn_box_alloc(ep, parent);
1055*260e9a87SYuri Pankov parent->type = EQN_MATRIX;
1056*260e9a87SYuri Pankov parent->expectargs = 1;
1057*260e9a87SYuri Pankov break;
1058*260e9a87SYuri Pankov case (EQN_TOK_EOF):
1059*260e9a87SYuri Pankov /*
1060*260e9a87SYuri Pankov * End of file!
1061*260e9a87SYuri Pankov * TODO: make sure we're not in an open subexpression.
1062*260e9a87SYuri Pankov */
1063*260e9a87SYuri Pankov return(ROFF_EQN);
1064*260e9a87SYuri Pankov default:
1065*260e9a87SYuri Pankov assert(tok == EQN_TOK__MAX);
1066*260e9a87SYuri Pankov assert(NULL != p);
1067*260e9a87SYuri Pankov /*
1068*260e9a87SYuri Pankov * If we already have something in the stack and we're
1069*260e9a87SYuri Pankov * in an expression, then rewind til we're not any more.
1070*260e9a87SYuri Pankov */
1071*260e9a87SYuri Pankov while (parent->args == parent->expectargs)
1072*260e9a87SYuri Pankov parent = parent->parent;
1073*260e9a87SYuri Pankov cur = eqn_box_alloc(ep, parent);
1074*260e9a87SYuri Pankov cur->type = EQN_TEXT;
1075*260e9a87SYuri Pankov for (i = 0; i < EQNSYM__MAX; i++)
1076*260e9a87SYuri Pankov if (0 == strcmp(eqnsyms[i].str, p)) {
1077*260e9a87SYuri Pankov (void)snprintf(sym, sizeof(sym),
1078*260e9a87SYuri Pankov "\\[%s]", eqnsyms[i].sym);
1079*260e9a87SYuri Pankov cur->text = mandoc_strdup(sym);
1080*260e9a87SYuri Pankov free(p);
1081*260e9a87SYuri Pankov break;
1082*260e9a87SYuri Pankov }
1083*260e9a87SYuri Pankov
1084*260e9a87SYuri Pankov if (i == EQNSYM__MAX)
1085*260e9a87SYuri Pankov cur->text = p;
1086*260e9a87SYuri Pankov /*
1087*260e9a87SYuri Pankov * Post-process list status.
1088*260e9a87SYuri Pankov */
1089*260e9a87SYuri Pankov while (parent->type == EQN_LISTONE &&
1090*260e9a87SYuri Pankov parent->args == parent->expectargs)
1091*260e9a87SYuri Pankov parent = parent->parent;
1092*260e9a87SYuri Pankov break;
1093*260e9a87SYuri Pankov }
1094*260e9a87SYuri Pankov goto next_tok;
1095*260e9a87SYuri Pankov }
1096*260e9a87SYuri Pankov
1097*260e9a87SYuri Pankov enum rofferr
eqn_end(struct eqn_node ** epp)1098*260e9a87SYuri Pankov eqn_end(struct eqn_node **epp)
109995c635efSGarrett D'Amore {
1100*260e9a87SYuri Pankov struct eqn_node *ep;
110195c635efSGarrett D'Amore
1102*260e9a87SYuri Pankov ep = *epp;
1103*260e9a87SYuri Pankov *epp = NULL;
110495c635efSGarrett D'Amore
1105*260e9a87SYuri Pankov ep->eqn.root = mandoc_calloc(1, sizeof(struct eqn_box));
1106*260e9a87SYuri Pankov ep->eqn.root->expectargs = UINT_MAX;
1107*260e9a87SYuri Pankov return(eqn_parse(ep, ep->eqn.root));
110895c635efSGarrett D'Amore }
110995c635efSGarrett D'Amore
1110*260e9a87SYuri Pankov void
eqn_free(struct eqn_node * p)1111*260e9a87SYuri Pankov eqn_free(struct eqn_node *p)
111295c635efSGarrett D'Amore {
111395c635efSGarrett D'Amore int i;
111495c635efSGarrett D'Amore
1115*260e9a87SYuri Pankov eqn_box_free(p->eqn.root);
111695c635efSGarrett D'Amore
1117*260e9a87SYuri Pankov for (i = 0; i < (int)p->defsz; i++) {
1118*260e9a87SYuri Pankov free(p->defs[i].key);
1119*260e9a87SYuri Pankov free(p->defs[i].val);
1120*260e9a87SYuri Pankov }
1121*260e9a87SYuri Pankov
1122*260e9a87SYuri Pankov free(p->data);
1123*260e9a87SYuri Pankov free(p->defs);
1124*260e9a87SYuri Pankov free(p);
112595c635efSGarrett D'Amore }
1126