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