Annotation of mandoc/macro.c, Revision 1.66
1.66 ! kristaps 1: /* $Id: macro.c,v 1.65 2009/03/10 15:01:54 kristaps Exp $ */
1.1 kristaps 2: /*
3: * Copyright (c) 2008 Kristaps Dzonsons <kristaps@kth.se>
4: *
5: * Permission to use, copy, modify, and distribute this software for any
6: * purpose with or without fee is hereby granted, provided that the
7: * above copyright notice and this permission notice appear in all
8: * copies.
9: *
10: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
11: * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
12: * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
13: * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
14: * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
15: * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
16: * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17: * PERFORMANCE OF THIS SOFTWARE.
18: */
1.2 kristaps 19: #include <assert.h>
20: #include <ctype.h>
1.1 kristaps 21: #include <stdlib.h>
1.2 kristaps 22: #include <stdio.h>
1.5 kristaps 23: #include <string.h>
1.63 kristaps 24:
25: #include "private.h"
1.2 kristaps 26:
1.44 kristaps 27: /*
28: * This has scanning/parsing routines, each of which extract a macro and
29: * its arguments and parameters, then know how to progress to the next
1.51 kristaps 30: * macro.
1.44 kristaps 31: */
32:
1.65 kristaps 33: /* FIXME: .Fl, .Ar, .Cd handling of `|'. */
34:
1.51 kristaps 35: static int macro_obsolete(MACRO_PROT_ARGS);
36: static int macro_constant(MACRO_PROT_ARGS);
37: static int macro_constant_scoped(MACRO_PROT_ARGS);
38: static int macro_constant_delimited(MACRO_PROT_ARGS);
39: static int macro_text(MACRO_PROT_ARGS);
40: static int macro_scoped(MACRO_PROT_ARGS);
41: static int macro_scoped_close(MACRO_PROT_ARGS);
42: static int macro_scoped_line(MACRO_PROT_ARGS);
43:
1.35 kristaps 44: #define REWIND_REWIND (1 << 0)
45: #define REWIND_NOHALT (1 << 1)
46: #define REWIND_HALT (1 << 2)
1.49 kristaps 47:
1.44 kristaps 48: static int rewind_dohalt(int, enum mdoc_type,
49: const struct mdoc_node *);
50: static int rewind_alt(int);
1.41 kristaps 51: static int rewind_dobreak(int, const struct mdoc_node *);
1.28 kristaps 52: static int rewind_elem(struct mdoc *, int);
1.38 kristaps 53: static int rewind_impblock(struct mdoc *, int, int, int);
54: static int rewind_expblock(struct mdoc *, int, int, int);
1.41 kristaps 55: static int rewind_subblock(enum mdoc_type,
56: struct mdoc *, int, int, int);
57: static int rewind_last(struct mdoc *, struct mdoc_node *);
58: static int append_delims(struct mdoc *, int, int *, char *);
1.30 kristaps 59: static int lookup(struct mdoc *, int, int, int, const char *);
1.49 kristaps 60: static int pwarn(struct mdoc *, int, int, int);
61: static int perr(struct mdoc *, int, int, int);
1.59 kristaps 62: static int scopewarn(struct mdoc *, enum mdoc_type, int, int,
63: const struct mdoc_node *);
1.49 kristaps 64:
65: #define WMACPARM (1)
66: #define WOBS (2)
67:
68: #define ENOCTX (1)
69: #define ENOPARMS (2)
70:
1.51 kristaps 71: /* Central table of library: who gets parsed how. */
72:
73: const struct mdoc_macro __mdoc_macros[MDOC_MAX] = {
74: { NULL, 0 }, /* \" */
75: { macro_constant, MDOC_PROLOGUE }, /* Dd */
76: { macro_constant, MDOC_PROLOGUE }, /* Dt */
77: { macro_constant, MDOC_PROLOGUE }, /* Os */
78: { macro_scoped, 0 }, /* Sh */
79: { macro_scoped, 0 }, /* Ss */
80: { macro_text, 0 }, /* Pp */
81: { macro_scoped_line, MDOC_PARSED }, /* D1 */
82: { macro_scoped_line, MDOC_PARSED }, /* Dl */
83: { macro_scoped, MDOC_EXPLICIT }, /* Bd */
84: { macro_scoped_close, MDOC_EXPLICIT }, /* Ed */
85: { macro_scoped, MDOC_EXPLICIT }, /* Bl */
86: { macro_scoped_close, MDOC_EXPLICIT }, /* El */
87: { macro_scoped, MDOC_PARSED }, /* It */
88: { macro_text, MDOC_CALLABLE | MDOC_PARSED }, /* Ad */
89: { macro_text, MDOC_PARSED }, /* An */
90: { macro_text, MDOC_CALLABLE | MDOC_PARSED }, /* Ar */
91: { macro_constant, 0 }, /* Cd */
92: { macro_text, MDOC_CALLABLE | MDOC_PARSED }, /* Cm */
93: { macro_text, MDOC_CALLABLE | MDOC_PARSED }, /* Dv */
94: { macro_text, MDOC_CALLABLE | MDOC_PARSED }, /* Er */
95: { macro_text, MDOC_CALLABLE | MDOC_PARSED }, /* Ev */
96: { macro_constant, 0 }, /* Ex */
97: { macro_text, MDOC_CALLABLE | MDOC_PARSED }, /* Fa */
98: { macro_constant, 0 }, /* Fd */
99: { macro_text, MDOC_CALLABLE | MDOC_PARSED }, /* Fl */
100: { macro_text, MDOC_CALLABLE | MDOC_PARSED }, /* Fn */
101: { macro_text, MDOC_PARSED }, /* Ft */
102: { macro_text, MDOC_CALLABLE | MDOC_PARSED }, /* Ic */
103: { macro_constant, 0 }, /* In */
104: { macro_text, MDOC_CALLABLE | MDOC_PARSED }, /* Li */
105: { macro_constant, 0 }, /* Nd */
106: { macro_text, MDOC_CALLABLE | MDOC_PARSED }, /* Nm */
107: { macro_scoped_line, MDOC_CALLABLE | MDOC_PARSED }, /* Op */
108: { macro_obsolete, 0 }, /* Ot */
109: { macro_text, MDOC_CALLABLE | MDOC_PARSED }, /* Pa */
110: { macro_constant, 0 }, /* Rv */
111: /* XXX - .St supposed to be (but isn't) callable. */
112: { macro_constant_delimited, MDOC_PARSED }, /* St */
113: { macro_text, MDOC_CALLABLE | MDOC_PARSED }, /* Va */
114: { macro_text, MDOC_CALLABLE | MDOC_PARSED }, /* Vt */
115: { macro_text, MDOC_CALLABLE | MDOC_PARSED }, /* Xr */
116: { macro_constant, 0 }, /* %A */
117: { macro_constant, 0 }, /* %B */
118: { macro_constant, 0 }, /* %D */
119: { macro_constant, 0 }, /* %I */
120: { macro_constant, 0 }, /* %J */
121: { macro_constant, 0 }, /* %N */
122: { macro_constant, 0 }, /* %O */
123: { macro_constant, 0 }, /* %P */
124: { macro_constant, 0 }, /* %R */
125: { macro_constant, 0 }, /* %T */
126: { macro_constant, 0 }, /* %V */
127: { macro_scoped_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Ac */
128: { macro_constant_scoped, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* Ao */
129: { macro_scoped_line, MDOC_CALLABLE | MDOC_PARSED }, /* Aq */
130: { macro_constant_delimited, 0 }, /* At */
131: { macro_scoped_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Bc */
132: { macro_scoped, MDOC_EXPLICIT }, /* Bf */
133: { macro_constant_scoped, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* Bo */
134: { macro_scoped_line, MDOC_CALLABLE | MDOC_PARSED }, /* Bq */
135: { macro_constant_delimited, MDOC_PARSED }, /* Bsx */
136: { macro_constant_delimited, MDOC_PARSED }, /* Bx */
137: { macro_constant, 0 }, /* Db */
138: { macro_scoped_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Dc */
139: { macro_constant_scoped, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* Do */
140: { macro_scoped_line, MDOC_CALLABLE | MDOC_PARSED }, /* Dq */
141: { macro_scoped_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Ec */
142: { macro_scoped_close, MDOC_EXPLICIT }, /* Ef */
143: { macro_text, MDOC_CALLABLE | MDOC_PARSED }, /* Em */
144: { macro_constant_scoped, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* Eo */
145: { macro_constant_delimited, MDOC_PARSED }, /* Fx */
146: { macro_text, MDOC_PARSED }, /* Ms */
147: { macro_constant_delimited, MDOC_CALLABLE | MDOC_PARSED }, /* No */
148: { macro_constant_delimited, MDOC_CALLABLE | MDOC_PARSED }, /* Ns */
149: { macro_constant_delimited, MDOC_PARSED }, /* Nx */
150: { macro_constant_delimited, MDOC_PARSED }, /* Ox */
151: { macro_scoped_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Pc */
152: { macro_constant_delimited, MDOC_PARSED }, /* Pf */
153: { macro_constant_scoped, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* Po */
154: { macro_scoped_line, MDOC_CALLABLE | MDOC_PARSED }, /* Pq */
155: { macro_scoped_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Qc */
156: { macro_scoped_line, MDOC_CALLABLE | MDOC_PARSED }, /* Ql */
157: { macro_constant_scoped, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* Qo */
158: { macro_scoped_line, MDOC_CALLABLE | MDOC_PARSED }, /* Qq */
159: { macro_scoped_close, MDOC_EXPLICIT }, /* Re */
160: { macro_scoped, MDOC_EXPLICIT }, /* Rs */
161: { macro_scoped_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Sc */
162: { macro_constant_scoped, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* So */
163: { macro_scoped_line, MDOC_CALLABLE | MDOC_PARSED }, /* Sq */
164: { macro_constant, 0 }, /* Sm */
165: { macro_text, MDOC_CALLABLE | MDOC_PARSED }, /* Sx */
166: { macro_text, MDOC_CALLABLE | MDOC_PARSED }, /* Sy */
167: { macro_text, MDOC_CALLABLE | MDOC_PARSED }, /* Tn */
168: { macro_constant_delimited, MDOC_PARSED }, /* Ux */
169: { macro_scoped_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Xc */
170: { macro_constant_scoped, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* Xo */
171: /* XXX - .Fo supposed to be (but isn't) callable. */
172: { macro_scoped, MDOC_EXPLICIT }, /* Fo */
1.52 kristaps 173: { macro_scoped_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Fc */
1.51 kristaps 174: { macro_constant_scoped, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* Oo */
175: { macro_scoped_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Oc */
176: { macro_scoped, MDOC_EXPLICIT }, /* Bk */
177: { macro_scoped_close, MDOC_EXPLICIT }, /* Ek */
178: { macro_constant, 0 }, /* Bt */
179: { macro_constant, 0 }, /* Hf */
180: { macro_obsolete, 0 }, /* Fr */
181: { macro_constant, 0 }, /* Ud */
1.57 kristaps 182: { macro_constant, 0 }, /* Lb */
1.61 kristaps 183: { macro_constant_delimited, MDOC_CALLABLE | MDOC_PARSED }, /* Ap */
1.62 kristaps 184: { macro_text, 0 }, /* Lp */
1.64 kristaps 185: { macro_text, MDOC_PARSED }, /* Lk */
186: { macro_text, MDOC_PARSED }, /* Mt */
1.66 ! kristaps 187: { macro_scoped_line, MDOC_CALLABLE | MDOC_PARSED }, /* Brq */
! 188: { macro_constant_scoped, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* Bro */
! 189: { macro_scoped_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Brc */
1.51 kristaps 190: };
191:
192: const struct mdoc_macro * const mdoc_macros = __mdoc_macros;
193:
1.49 kristaps 194:
195: static int
196: perr(struct mdoc *mdoc, int line, int pos, int type)
197: {
198: int c;
199:
200: switch (type) {
201: case (ENOCTX):
202: c = mdoc_perr(mdoc, line, pos,
1.59 kristaps 203: "closing macro has no prior context");
1.49 kristaps 204: break;
205: case (ENOPARMS):
206: c = mdoc_perr(mdoc, line, pos,
207: "macro doesn't expect parameters");
208: break;
209: default:
210: abort();
211: /* NOTREACHED */
212: }
213: return(c);
214: }
215:
216: static int
217: pwarn(struct mdoc *mdoc, int line, int pos, int type)
218: {
219: int c;
220:
221: switch (type) {
222: case (WMACPARM):
223: c = mdoc_pwarn(mdoc, line, pos, WARN_SYNTAX,
224: "macro-like parameter");
225: break;
226: case (WOBS):
227: c = mdoc_pwarn(mdoc, line, pos, WARN_SYNTAX,
228: "macro is marked obsolete");
229: break;
230: default:
231: abort();
232: /* NOTREACHED */
233: }
234: return(c);
235: }
1.24 kristaps 236:
237:
238: static int
1.59 kristaps 239: scopewarn(struct mdoc *mdoc, enum mdoc_type type,
240: int line, int pos, const struct mdoc_node *p)
241: {
242: const char *n, *t, *tt;
243:
244: n = t = "<root>";
245: tt = "block";
246:
1.60 kristaps 247: switch (type) {
1.59 kristaps 248: case (MDOC_BODY):
249: tt = "multi-line";
250: break;
251: case (MDOC_HEAD):
252: tt = "line";
253: break;
254: default:
255: break;
256: }
257:
258: switch (p->type) {
259: case (MDOC_BLOCK):
260: n = mdoc_macronames[p->tok];
261: t = "block";
262: break;
263: case (MDOC_BODY):
264: n = mdoc_macronames[p->tok];
265: t = "multi-line";
266: break;
267: case (MDOC_HEAD):
268: n = mdoc_macronames[p->tok];
269: t = "line";
270: break;
271: default:
272: break;
273: }
274:
275: if ( ! (MDOC_IGN_SCOPE & mdoc->pflags))
276: return(mdoc_perr(mdoc, line, pos,
277: "%s scope breaks %s scope of %s",
278: tt, t, n));
279: return(mdoc_pwarn(mdoc, line, pos, WARN_SYNTAX,
280: "%s scope breaks %s scope of %s",
281: tt, t, n));
282: }
283:
284:
285: static int
1.30 kristaps 286: lookup(struct mdoc *mdoc, int line, int pos, int from, const char *p)
1.24 kristaps 287: {
1.30 kristaps 288: int res;
1.24 kristaps 289:
1.58 kristaps 290: res = mdoc_tokhash_find(mdoc->htab, p);
1.30 kristaps 291: if (MDOC_PARSED & mdoc_macros[from].flags)
292: return(res);
293: if (MDOC_MAX == res)
294: return(res);
1.49 kristaps 295: if ( ! pwarn(mdoc, line, pos, WMACPARM))
1.30 kristaps 296: return(-1);
297: return(MDOC_MAX);
1.24 kristaps 298: }
1.19 kristaps 299:
300:
301: static int
1.41 kristaps 302: rewind_last(struct mdoc *mdoc, struct mdoc_node *to)
1.25 kristaps 303: {
304:
305: assert(to);
1.30 kristaps 306: mdoc->next = MDOC_NEXT_SIBLING;
1.42 kristaps 307:
1.49 kristaps 308: /* LINTED */
1.42 kristaps 309: while (mdoc->last != to) {
1.30 kristaps 310: if ( ! mdoc_valid_post(mdoc))
311: return(0);
312: if ( ! mdoc_action_post(mdoc))
313: return(0);
1.29 kristaps 314: mdoc->last = mdoc->last->parent;
315: assert(mdoc->last);
1.42 kristaps 316: }
1.28 kristaps 317:
1.42 kristaps 318: if ( ! mdoc_valid_post(mdoc))
319: return(0);
320: return(mdoc_action_post(mdoc));
1.25 kristaps 321: }
322:
323:
324: static int
1.35 kristaps 325: rewind_alt(int tok)
326: {
327: switch (tok) {
328: case (MDOC_Ac):
329: return(MDOC_Ao);
330: case (MDOC_Bc):
331: return(MDOC_Bo);
1.66 ! kristaps 332: case (MDOC_Brc):
! 333: return(MDOC_Bro);
1.35 kristaps 334: case (MDOC_Dc):
335: return(MDOC_Do);
336: case (MDOC_Ec):
337: return(MDOC_Eo);
338: case (MDOC_Ed):
339: return(MDOC_Bd);
340: case (MDOC_Ef):
341: return(MDOC_Bf);
342: case (MDOC_Ek):
343: return(MDOC_Bk);
344: case (MDOC_El):
345: return(MDOC_Bl);
346: case (MDOC_Fc):
347: return(MDOC_Fo);
348: case (MDOC_Oc):
349: return(MDOC_Oo);
350: case (MDOC_Pc):
351: return(MDOC_Po);
352: case (MDOC_Qc):
353: return(MDOC_Qo);
354: case (MDOC_Re):
355: return(MDOC_Rs);
356: case (MDOC_Sc):
357: return(MDOC_So);
358: case (MDOC_Xc):
359: return(MDOC_Xo);
360: default:
361: break;
362: }
363: abort();
364: /* NOTREACHED */
365: }
366:
367:
368: static int
369: rewind_dohalt(int tok, enum mdoc_type type, const struct mdoc_node *p)
370: {
371:
372: if (MDOC_ROOT == p->type)
373: return(REWIND_HALT);
1.42 kristaps 374: if (MDOC_VALID & p->flags)
1.35 kristaps 375: return(REWIND_NOHALT);
376:
377: switch (tok) {
378: /* One-liner implicit-scope. */
379: case (MDOC_Aq):
380: /* FALLTHROUGH */
381: case (MDOC_Bq):
382: /* FALLTHROUGH */
1.66 ! kristaps 383: case (MDOC_Brq):
! 384: /* FALLTHROUGH */
1.35 kristaps 385: case (MDOC_D1):
386: /* FALLTHROUGH */
387: case (MDOC_Dl):
388: /* FALLTHROUGH */
389: case (MDOC_Dq):
390: /* FALLTHROUGH */
391: case (MDOC_Op):
392: /* FALLTHROUGH */
393: case (MDOC_Pq):
394: /* FALLTHROUGH */
395: case (MDOC_Ql):
396: /* FALLTHROUGH */
397: case (MDOC_Qq):
398: /* FALLTHROUGH */
399: case (MDOC_Sq):
1.44 kristaps 400: assert(MDOC_HEAD != type);
1.35 kristaps 401: assert(MDOC_TAIL != type);
402: if (type == p->type && tok == p->tok)
403: return(REWIND_REWIND);
404: break;
405:
406: /* Multi-line implicit-scope. */
407: case (MDOC_It):
408: assert(MDOC_TAIL != type);
409: if (type == p->type && tok == p->tok)
410: return(REWIND_REWIND);
1.36 kristaps 411: if (MDOC_BODY == p->type && MDOC_Bl == p->tok)
1.35 kristaps 412: return(REWIND_HALT);
413: break;
414: case (MDOC_Sh):
1.36 kristaps 415: if (type == p->type && tok == p->tok)
416: return(REWIND_REWIND);
417: break;
1.35 kristaps 418: case (MDOC_Ss):
1.36 kristaps 419: assert(MDOC_TAIL != type);
1.35 kristaps 420: if (type == p->type && tok == p->tok)
421: return(REWIND_REWIND);
1.36 kristaps 422: if (MDOC_BODY == p->type && MDOC_Sh == p->tok)
423: return(REWIND_HALT);
1.35 kristaps 424: break;
425:
426: /* Multi-line explicit scope start. */
427: case (MDOC_Ao):
428: /* FALLTHROUGH */
429: case (MDOC_Bd):
430: /* FALLTHROUGH */
431: case (MDOC_Bf):
432: /* FALLTHROUGH */
433: case (MDOC_Bk):
434: /* FALLTHROUGH */
435: case (MDOC_Bl):
436: /* FALLTHROUGH */
437: case (MDOC_Bo):
438: /* FALLTHROUGH */
1.66 ! kristaps 439: case (MDOC_Bro):
! 440: /* FALLTHROUGH */
1.35 kristaps 441: case (MDOC_Do):
442: /* FALLTHROUGH */
443: case (MDOC_Eo):
444: /* FALLTHROUGH */
445: case (MDOC_Fo):
446: /* FALLTHROUGH */
447: case (MDOC_Oo):
448: /* FALLTHROUGH */
449: case (MDOC_Po):
450: /* FALLTHROUGH */
451: case (MDOC_Qo):
452: /* FALLTHROUGH */
453: case (MDOC_Rs):
454: /* FALLTHROUGH */
455: case (MDOC_So):
456: /* FALLTHROUGH */
457: case (MDOC_Xo):
458: if (type == p->type && tok == p->tok)
459: return(REWIND_REWIND);
460: break;
461:
462: /* Multi-line explicit scope close. */
463: case (MDOC_Ac):
464: /* FALLTHROUGH */
465: case (MDOC_Bc):
466: /* FALLTHROUGH */
1.66 ! kristaps 467: case (MDOC_Brc):
! 468: /* FALLTHROUGH */
1.35 kristaps 469: case (MDOC_Dc):
470: /* FALLTHROUGH */
471: case (MDOC_Ec):
472: /* FALLTHROUGH */
473: case (MDOC_Ed):
474: /* FALLTHROUGH */
475: case (MDOC_Ek):
476: /* FALLTHROUGH */
477: case (MDOC_El):
478: /* FALLTHROUGH */
479: case (MDOC_Fc):
480: /* FALLTHROUGH */
481: case (MDOC_Ef):
482: /* FALLTHROUGH */
483: case (MDOC_Oc):
484: /* FALLTHROUGH */
485: case (MDOC_Pc):
486: /* FALLTHROUGH */
487: case (MDOC_Qc):
488: /* FALLTHROUGH */
489: case (MDOC_Re):
490: /* FALLTHROUGH */
491: case (MDOC_Sc):
492: /* FALLTHROUGH */
493: case (MDOC_Xc):
494: if (type == p->type && rewind_alt(tok) == p->tok)
495: return(REWIND_REWIND);
496: break;
497: default:
498: abort();
499: /* NOTREACHED */
500: }
501:
502: return(REWIND_NOHALT);
503: }
504:
505:
506: static int
1.41 kristaps 507: rewind_dobreak(int tok, const struct mdoc_node *p)
1.35 kristaps 508: {
509:
510: assert(MDOC_ROOT != p->type);
511: if (MDOC_ELEM == p->type)
512: return(1);
513: if (MDOC_TEXT == p->type)
514: return(1);
1.42 kristaps 515: if (MDOC_VALID & p->flags)
516: return(1);
1.35 kristaps 517:
518: switch (tok) {
1.36 kristaps 519: /* Implicit rules. */
1.35 kristaps 520: case (MDOC_It):
521: return(MDOC_It == p->tok);
522: case (MDOC_Ss):
523: return(MDOC_Ss == p->tok);
524: case (MDOC_Sh):
525: if (MDOC_Ss == p->tok)
526: return(1);
527: return(MDOC_Sh == p->tok);
1.36 kristaps 528:
529: /* Extra scope rules. */
530: case (MDOC_El):
531: if (MDOC_It == p->tok)
532: return(1);
533: break;
534: default:
535: break;
1.35 kristaps 536: }
537:
538: if (MDOC_EXPLICIT & mdoc_macros[tok].flags)
539: return(p->tok == rewind_alt(tok));
540: else if (MDOC_BLOCK == p->type)
541: return(1);
542:
543: return(tok == p->tok);
544: }
545:
546:
547: static int
1.28 kristaps 548: rewind_elem(struct mdoc *mdoc, int tok)
1.19 kristaps 549: {
550: struct mdoc_node *n;
1.2 kristaps 551:
1.19 kristaps 552: n = mdoc->last;
553: if (MDOC_ELEM != n->type)
554: n = n->parent;
555: assert(MDOC_ELEM == n->type);
1.32 kristaps 556: assert(tok == n->tok);
1.19 kristaps 557:
1.41 kristaps 558: return(rewind_last(mdoc, n));
1.19 kristaps 559: }
1.6 kristaps 560:
561:
562: static int
1.41 kristaps 563: rewind_subblock(enum mdoc_type type, struct mdoc *mdoc,
564: int tok, int line, int ppos)
1.22 kristaps 565: {
566: struct mdoc_node *n;
1.35 kristaps 567: int c;
1.28 kristaps 568:
1.6 kristaps 569: /* LINTED */
1.42 kristaps 570: for (n = mdoc->last; n; n = n->parent) {
1.36 kristaps 571: c = rewind_dohalt(tok, type, n);
1.35 kristaps 572: if (REWIND_HALT == c)
573: return(1);
574: if (REWIND_REWIND == c)
1.6 kristaps 575: break;
1.41 kristaps 576: else if (rewind_dobreak(tok, n))
1.7 kristaps 577: continue;
1.59 kristaps 578: if ( ! scopewarn(mdoc, type, line, ppos, n))
579: return(0);
1.6 kristaps 580: }
581:
1.25 kristaps 582: assert(n);
1.41 kristaps 583: return(rewind_last(mdoc, n));
1.6 kristaps 584: }
585:
586:
587: static int
1.38 kristaps 588: rewind_expblock(struct mdoc *mdoc, int tok, int line, int ppos)
1.6 kristaps 589: {
1.7 kristaps 590: struct mdoc_node *n;
1.35 kristaps 591: int c;
1.6 kristaps 592:
1.7 kristaps 593: /* LINTED */
1.42 kristaps 594: for (n = mdoc->last; n; n = n->parent) {
1.35 kristaps 595: c = rewind_dohalt(tok, MDOC_BLOCK, n);
596: if (REWIND_HALT == c)
1.49 kristaps 597: return(perr(mdoc, line, ppos, ENOCTX));
1.35 kristaps 598: if (REWIND_REWIND == c)
1.16 kristaps 599: break;
1.41 kristaps 600: else if (rewind_dobreak(tok, n))
1.22 kristaps 601: continue;
1.59 kristaps 602: if ( ! scopewarn(mdoc, MDOC_BLOCK, line, ppos, n))
603: return(0);
1.16 kristaps 604: }
605:
1.28 kristaps 606: assert(n);
1.41 kristaps 607: return(rewind_last(mdoc, n));
1.21 kristaps 608: }
609:
610:
611: static int
1.38 kristaps 612: rewind_impblock(struct mdoc *mdoc, int tok, int line, int ppos)
1.21 kristaps 613: {
614: struct mdoc_node *n;
1.35 kristaps 615: int c;
1.21 kristaps 616:
617: /* LINTED */
1.42 kristaps 618: for (n = mdoc->last; n; n = n->parent) {
1.35 kristaps 619: c = rewind_dohalt(tok, MDOC_BLOCK, n);
620: if (REWIND_HALT == c)
621: return(1);
622: else if (REWIND_REWIND == c)
1.21 kristaps 623: break;
1.41 kristaps 624: else if (rewind_dobreak(tok, n))
1.21 kristaps 625: continue;
1.59 kristaps 626: if ( ! scopewarn(mdoc, MDOC_BLOCK, line, ppos, n))
627: return(0);
1.21 kristaps 628: }
629:
1.35 kristaps 630: assert(n);
1.41 kristaps 631: return(rewind_last(mdoc, n));
1.16 kristaps 632: }
633:
634:
1.22 kristaps 635: static int
1.41 kristaps 636: append_delims(struct mdoc *mdoc, int line, int *pos, char *buf)
1.22 kristaps 637: {
638: int c, lastarg;
639: char *p;
640:
641: if (0 == buf[*pos])
642: return(1);
643:
644: for (;;) {
645: lastarg = *pos;
1.28 kristaps 646: c = mdoc_args(mdoc, line, pos, buf, 0, &p);
1.49 kristaps 647: assert(ARGS_PHRASE != c);
648:
1.22 kristaps 649: if (ARGS_ERROR == c)
650: return(0);
651: else if (ARGS_EOLN == c)
652: break;
653: assert(mdoc_isdelim(p));
1.28 kristaps 654: if ( ! mdoc_word_alloc(mdoc, line, lastarg, p))
655: return(0);
1.22 kristaps 656: mdoc->next = MDOC_NEXT_SIBLING;
657: }
658:
659: return(1);
660: }
661:
662:
1.44 kristaps 663: /*
664: * Close out an explicit scope. This optionally parses a TAIL type with
665: * a set number of TEXT children.
666: */
1.51 kristaps 667: static int
1.35 kristaps 668: macro_scoped_close(MACRO_PROT_ARGS)
1.19 kristaps 669: {
1.28 kristaps 670: int tt, j, c, lastarg, maxargs, flushed;
1.22 kristaps 671: char *p;
1.19 kristaps 672:
673: switch (tok) {
1.22 kristaps 674: case (MDOC_Ec):
675: maxargs = 1;
676: break;
677: default:
678: maxargs = 0;
679: break;
680: }
681:
1.35 kristaps 682: tt = rewind_alt(tok);
683:
1.41 kristaps 684: mdoc_msg(mdoc, "parse: %s closing %s",
1.36 kristaps 685: mdoc_macronames[tok], mdoc_macronames[tt]);
686:
1.22 kristaps 687: if ( ! (MDOC_CALLABLE & mdoc_macros[tok].flags)) {
1.35 kristaps 688: if (0 == buf[*pos]) {
1.51 kristaps 689: if ( ! rewind_subblock(MDOC_BODY, mdoc,
690: tok, line, ppos))
1.35 kristaps 691: return(0);
1.38 kristaps 692: return(rewind_expblock(mdoc, tok, line, ppos));
1.35 kristaps 693: }
1.49 kristaps 694: return(perr(mdoc, line, ppos, ENOPARMS));
1.22 kristaps 695: }
1.19 kristaps 696:
1.41 kristaps 697: if ( ! rewind_subblock(MDOC_BODY, mdoc, tok, line, ppos))
1.22 kristaps 698: return(0);
1.19 kristaps 699:
1.22 kristaps 700: lastarg = ppos;
701: flushed = 0;
1.15 kristaps 702:
1.22 kristaps 703: if (maxargs > 0) {
1.28 kristaps 704: if ( ! mdoc_tail_alloc(mdoc, line, ppos, tt))
705: return(0);
1.22 kristaps 706: mdoc->next = MDOC_NEXT_CHILD;
707: }
1.15 kristaps 708:
1.41 kristaps 709: for (j = 0; /* No sentinel. */; j++) {
1.15 kristaps 710: lastarg = *pos;
1.22 kristaps 711:
712: if (j == maxargs && ! flushed) {
1.38 kristaps 713: if ( ! rewind_expblock(mdoc, tok, line, ppos))
1.22 kristaps 714: return(0);
715: flushed = 1;
716: }
717:
1.48 kristaps 718: c = mdoc_args(mdoc, line, pos, buf, tok, &p);
1.49 kristaps 719: assert(ARGS_PHRASE != c);
720:
1.15 kristaps 721: if (ARGS_ERROR == c)
722: return(0);
1.22 kristaps 723: if (ARGS_PUNCT == c)
724: break;
725: if (ARGS_EOLN == c)
726: break;
727:
1.30 kristaps 728: if (-1 == (c = lookup(mdoc, line, lastarg, tok, p)))
729: return(0);
730: else if (MDOC_MAX != c) {
1.22 kristaps 731: if ( ! flushed) {
1.51 kristaps 732: if ( ! rewind_expblock(mdoc, tok,
733: line, ppos))
1.22 kristaps 734: return(0);
735: flushed = 1;
736: }
1.26 kristaps 737: if ( ! mdoc_macro(mdoc, c, line, lastarg, pos, buf))
1.22 kristaps 738: return(0);
1.15 kristaps 739: break;
1.30 kristaps 740: }
1.22 kristaps 741:
1.28 kristaps 742: if ( ! mdoc_word_alloc(mdoc, line, lastarg, p))
743: return(0);
1.16 kristaps 744: mdoc->next = MDOC_NEXT_SIBLING;
1.15 kristaps 745: }
1.2 kristaps 746:
1.38 kristaps 747: if ( ! flushed && ! rewind_expblock(mdoc, tok, line, ppos))
1.28 kristaps 748: return(0);
1.22 kristaps 749:
750: if (ppos > 1)
751: return(1);
1.41 kristaps 752: return(append_delims(mdoc, line, pos, buf));
1.1 kristaps 753: }
754:
1.2 kristaps 755:
1.44 kristaps 756: /*
757: * A general text macro. This is a complex case because of punctuation.
758: * If a text macro is followed by words, then punctuation, the macro is
759: * "stopped" and "reopened" following the punctuation. Thus, the
760: * following arises:
761: *
762: * .Fl a ; b
763: *
764: * ELEMENT (.Fl)
765: * TEXT (`a')
766: * TEXT (`;')
767: * ELEMENT (.Fl)
768: * TEXT (`b')
769: *
770: * This must handle the following situations:
771: *
772: * .Fl Ar b ; ;
773: *
774: * ELEMENT (.Fl)
775: * ELEMENT (.Ar)
776: * TEXT (`b')
777: * TEXT (`;')
778: * TEXT (`;')
779: */
1.51 kristaps 780: static int
1.19 kristaps 781: macro_text(MACRO_PROT_ARGS)
1.13 kristaps 782: {
1.58 kristaps 783: int la, lastpunct, c, w;
784: struct mdoc_arg *arg;
1.19 kristaps 785: char *p;
1.13 kristaps 786:
1.28 kristaps 787: la = ppos;
1.19 kristaps 788: lastpunct = 0;
1.58 kristaps 789: arg = NULL;
1.17 kristaps 790:
1.58 kristaps 791: for (;;) {
1.28 kristaps 792: la = *pos;
1.58 kristaps 793: c = mdoc_argv(mdoc, line, tok, &arg, pos, buf);
1.38 kristaps 794: if (ARGV_EOLN == c)
1.19 kristaps 795: break;
1.38 kristaps 796: if (ARGV_WORD == c) {
797: *pos = la;
798: break;
799: } else if (ARGV_ARG == c)
1.19 kristaps 800: continue;
1.58 kristaps 801: mdoc_argv_free(arg);
1.14 kristaps 802: return(0);
1.10 kristaps 803: }
804:
1.58 kristaps 805: if ( ! mdoc_elem_alloc(mdoc, line, ppos, tok, arg))
1.19 kristaps 806: return(0);
1.7 kristaps 807:
1.28 kristaps 808: mdoc->next = MDOC_NEXT_CHILD;
809:
1.41 kristaps 810: lastpunct = 0;
811: for (;;) {
1.28 kristaps 812: la = *pos;
1.48 kristaps 813: w = mdoc_args(mdoc, line, pos, buf, tok, &p);
1.65 kristaps 814: assert(ARGS_PHRASE != w);
1.49 kristaps 815:
1.58 kristaps 816: if (ARGS_ERROR == w)
1.7 kristaps 817: return(0);
1.45 kristaps 818: if (ARGS_EOLN == w)
1.19 kristaps 819: break;
1.45 kristaps 820: if (ARGS_PUNCT == w)
1.19 kristaps 821: break;
1.2 kristaps 822:
1.65 kristaps 823: /* Quoted words shouldn't be looked-up. */
824:
1.45 kristaps 825: c = ARGS_QWORD == w ? MDOC_MAX :
826: lookup(mdoc, line, la, tok, p);
827:
1.65 kristaps 828: /* MDOC_MAX (not a macro) or -1 (error). */
829:
1.45 kristaps 830: if (MDOC_MAX != c && -1 != c) {
1.58 kristaps 831: if (0 == lastpunct && ! rewind_elem(mdoc, tok))
1.19 kristaps 832: return(0);
1.28 kristaps 833: c = mdoc_macro(mdoc, c, line, la, pos, buf);
834: if (0 == c)
1.19 kristaps 835: return(0);
836: if (ppos > 1)
837: return(1);
1.41 kristaps 838: return(append_delims(mdoc, line, pos, buf));
1.58 kristaps 839: } else if (-1 == c)
1.45 kristaps 840: return(0);
1.2 kristaps 841:
1.65 kristaps 842: /* Non-quote-enclosed punctuation. */
1.55 kristaps 843:
1.45 kristaps 844: if (ARGS_QWORD != w && mdoc_isdelim(p)) {
1.58 kristaps 845: if (0 == lastpunct && ! rewind_elem(mdoc, tok))
1.19 kristaps 846: return(0);
847: lastpunct = 1;
1.36 kristaps 848: } else if (lastpunct) {
1.58 kristaps 849: c = mdoc_elem_alloc(mdoc, line, ppos, tok, arg);
850:
851: if (0 == c)
1.36 kristaps 852: return(0);
1.58 kristaps 853:
1.36 kristaps 854: mdoc->next = MDOC_NEXT_CHILD;
855: lastpunct = 0;
1.19 kristaps 856: }
1.36 kristaps 857:
1.28 kristaps 858: if ( ! mdoc_word_alloc(mdoc, line, la, p))
859: return(0);
1.19 kristaps 860: mdoc->next = MDOC_NEXT_SIBLING;
1.2 kristaps 861: }
862:
1.36 kristaps 863: if (0 == lastpunct && ! rewind_elem(mdoc, tok))
1.7 kristaps 864: return(0);
1.19 kristaps 865: if (ppos > 1)
866: return(1);
1.41 kristaps 867: return(append_delims(mdoc, line, pos, buf));
1.5 kristaps 868: }
869:
870:
1.44 kristaps 871: /*
872: * Handle explicit-scope (having a different closure token) and implicit
873: * scope (closing out prior scopes when re-invoked) macros. These
874: * constitute the BLOCK type and usually span multiple lines. These
875: * always have HEAD and sometimes have BODY types. In the multi-line
876: * case:
877: *
878: * .Bd -ragged
879: * Text.
880: * .Fl macro
881: * Another.
882: * .Ed
883: *
884: * BLOCK (.Bd)
885: * HEAD
886: * BODY
887: * TEXT (`Text.')
888: * ELEMENT (.Fl)
889: * TEXT (`macro')
890: * TEXT (`Another.')
891: *
892: * Note that the `.It' macro, possibly the most difficult (as it has
893: * embedded scope, etc.) is handled by this routine.
894: */
1.51 kristaps 895: static int
1.16 kristaps 896: macro_scoped(MACRO_PROT_ARGS)
1.6 kristaps 897: {
1.58 kristaps 898: int c, lastarg;
899: struct mdoc_arg *arg;
1.24 kristaps 900: char *p;
1.6 kristaps 901:
1.16 kristaps 902: assert ( ! (MDOC_CALLABLE & mdoc_macros[tok].flags));
1.6 kristaps 903:
1.47 kristaps 904: /* First rewind extant implicit scope. */
905:
1.35 kristaps 906: if ( ! (MDOC_EXPLICIT & mdoc_macros[tok].flags)) {
1.41 kristaps 907: if ( ! rewind_subblock(MDOC_BODY, mdoc, tok, line, ppos))
1.35 kristaps 908: return(0);
1.38 kristaps 909: if ( ! rewind_impblock(mdoc, tok, line, ppos))
1.16 kristaps 910: return(0);
1.35 kristaps 911: }
1.2 kristaps 912:
1.47 kristaps 913: /* Parse arguments. */
1.58 kristaps 914:
915: arg = NULL;
1.47 kristaps 916:
1.58 kristaps 917: for (;;) {
1.16 kristaps 918: lastarg = *pos;
1.58 kristaps 919: c = mdoc_argv(mdoc, line, tok, &arg, pos, buf);
1.38 kristaps 920: if (ARGV_EOLN == c)
921: break;
922: if (ARGV_WORD == c) {
923: *pos = lastarg;
1.16 kristaps 924: break;
1.38 kristaps 925: } else if (ARGV_ARG == c)
1.16 kristaps 926: continue;
1.58 kristaps 927: mdoc_argv_free(arg);
1.8 kristaps 928: return(0);
1.16 kristaps 929: }
1.2 kristaps 930:
1.58 kristaps 931: if ( ! mdoc_block_alloc(mdoc, line, ppos, tok, arg))
1.16 kristaps 932: return(0);
1.8 kristaps 933:
1.19 kristaps 934: mdoc->next = MDOC_NEXT_CHILD;
935:
1.24 kristaps 936: if (0 == buf[*pos]) {
1.28 kristaps 937: if ( ! mdoc_head_alloc(mdoc, line, ppos, tok))
938: return(0);
1.51 kristaps 939: if ( ! rewind_subblock(MDOC_HEAD, mdoc,
940: tok, line, ppos))
1.28 kristaps 941: return(0);
942: if ( ! mdoc_body_alloc(mdoc, line, ppos, tok))
1.25 kristaps 943: return(0);
1.19 kristaps 944: mdoc->next = MDOC_NEXT_CHILD;
1.24 kristaps 945: return(1);
946: }
1.19 kristaps 947:
1.28 kristaps 948: if ( ! mdoc_head_alloc(mdoc, line, ppos, tok))
949: return(0);
1.24 kristaps 950: mdoc->next = MDOC_NEXT_CHILD;
1.7 kristaps 951:
1.41 kristaps 952: for (;;) {
1.24 kristaps 953: lastarg = *pos;
1.48 kristaps 954: c = mdoc_args(mdoc, line, pos, buf, tok, &p);
1.49 kristaps 955:
1.24 kristaps 956: if (ARGS_ERROR == c)
1.19 kristaps 957: return(0);
1.24 kristaps 958: if (ARGS_EOLN == c)
959: break;
1.49 kristaps 960: if (ARGS_PHRASE == c) {
961: /*
962: if ( ! mdoc_phrase(mdoc, line, lastarg, buf))
963: return(0);
964: */
965: continue;
966: }
967:
1.48 kristaps 968: /* FIXME: if .It -column, the lookup must be for a
969: * sub-line component. BLAH. */
1.24 kristaps 970:
1.30 kristaps 971: if (-1 == (c = lookup(mdoc, line, lastarg, tok, p)))
972: return(0);
1.48 kristaps 973:
974: if (MDOC_MAX == c) {
1.28 kristaps 975: if ( ! mdoc_word_alloc(mdoc, line, lastarg, p))
976: return(0);
1.24 kristaps 977: mdoc->next = MDOC_NEXT_SIBLING;
978: continue;
1.30 kristaps 979: }
1.2 kristaps 980:
1.26 kristaps 981: if ( ! mdoc_macro(mdoc, c, line, lastarg, pos, buf))
1.24 kristaps 982: return(0);
983: break;
1.7 kristaps 984: }
1.48 kristaps 985:
1.53 kristaps 986: if (1 == ppos && ! append_delims(mdoc, line, pos, buf))
987: return(0);
1.41 kristaps 988: if ( ! rewind_subblock(MDOC_HEAD, mdoc, tok, line, ppos))
1.24 kristaps 989: return(0);
990:
1.28 kristaps 991: if ( ! mdoc_body_alloc(mdoc, line, ppos, tok))
992: return(0);
1.16 kristaps 993: mdoc->next = MDOC_NEXT_CHILD;
1.8 kristaps 994:
1.16 kristaps 995: return(1);
1.1 kristaps 996: }
1.5 kristaps 997:
1.7 kristaps 998:
1.44 kristaps 999: /*
1000: * This handles a case of implicitly-scoped macro (BLOCK) limited to a
1001: * single line. Instead of being closed out by a subsequent call to
1002: * another macro, the scope is closed at the end of line. These don't
1003: * have BODY or TAIL types. Notice that the punctuation falls outside
1004: * of the HEAD type.
1005: *
1006: * .Qq a Fl b Ar d ; ;
1007: *
1008: * BLOCK (Qq)
1009: * HEAD
1010: * TEXT (`a')
1011: * ELEMENT (.Fl)
1012: * TEXT (`b')
1013: * ELEMENT (.Ar)
1014: * TEXT (`d')
1015: * TEXT (`;')
1016: * TEXT (`;')
1017: */
1.51 kristaps 1018: static int
1.16 kristaps 1019: macro_scoped_line(MACRO_PROT_ARGS)
1.7 kristaps 1020: {
1.41 kristaps 1021: int lastarg, c;
1.8 kristaps 1022: char *p;
1.7 kristaps 1023:
1.58 kristaps 1024: if ( ! mdoc_block_alloc(mdoc, line, ppos, tok, NULL))
1.28 kristaps 1025: return(0);
1.16 kristaps 1026: mdoc->next = MDOC_NEXT_CHILD;
1.8 kristaps 1027:
1.28 kristaps 1028: if ( ! mdoc_head_alloc(mdoc, line, ppos, tok))
1029: return(0);
1.44 kristaps 1030: mdoc->next = MDOC_NEXT_SIBLING;
1031: if ( ! mdoc_body_alloc(mdoc, line, ppos, tok))
1032: return(0);
1.16 kristaps 1033: mdoc->next = MDOC_NEXT_CHILD;
1.8 kristaps 1034:
1.19 kristaps 1035: /* XXX - no known argument macros. */
1036:
1.41 kristaps 1037: lastarg = ppos;
1038: for (;;) {
1.19 kristaps 1039: lastarg = *pos;
1.48 kristaps 1040: c = mdoc_args(mdoc, line, pos, buf, tok, &p);
1.49 kristaps 1041: assert(ARGS_PHRASE != c);
1.8 kristaps 1042:
1.19 kristaps 1043: if (ARGS_ERROR == c)
1044: return(0);
1045: if (ARGS_PUNCT == c)
1046: break;
1047: if (ARGS_EOLN == c)
1048: break;
1.8 kristaps 1049:
1.30 kristaps 1050: if (-1 == (c = lookup(mdoc, line, lastarg, tok, p)))
1051: return(0);
1052: else if (MDOC_MAX == c) {
1.28 kristaps 1053: if ( ! mdoc_word_alloc(mdoc, line, lastarg, p))
1054: return(0);
1.19 kristaps 1055: mdoc->next = MDOC_NEXT_SIBLING;
1056: continue;
1.30 kristaps 1057: }
1.8 kristaps 1058:
1.26 kristaps 1059: if ( ! mdoc_macro(mdoc, c, line, lastarg, pos, buf))
1.19 kristaps 1060: return(0);
1.8 kristaps 1061: break;
1062: }
1063:
1.19 kristaps 1064: if (1 == ppos) {
1.44 kristaps 1065: if ( ! rewind_subblock(MDOC_BODY, mdoc, tok, line, ppos))
1.16 kristaps 1066: return(0);
1.41 kristaps 1067: if ( ! append_delims(mdoc, line, pos, buf))
1.8 kristaps 1068: return(0);
1.44 kristaps 1069: } else if ( ! rewind_subblock(MDOC_BODY, mdoc, tok, line, ppos))
1.35 kristaps 1070: return(0);
1.38 kristaps 1071: return(rewind_impblock(mdoc, tok, line, ppos));
1.22 kristaps 1072: }
1073:
1074:
1.44 kristaps 1075: /*
1076: * A constant-scoped macro is like a simple-scoped macro (mdoc_scoped)
1077: * except that it doesn't handle implicit scopes and explicit ones have
1078: * a fixed number of TEXT children to the BODY.
1079: *
1080: * .Fl a So b Sc ;
1081: *
1082: * ELEMENT (.Fl)
1083: * TEXT (`a')
1084: * BLOCK (.So)
1085: * HEAD
1086: * BODY
1087: * TEXT (`b')
1088: * TEXT (';')
1089: */
1.51 kristaps 1090: static int
1.22 kristaps 1091: macro_constant_scoped(MACRO_PROT_ARGS)
1092: {
1093: int lastarg, flushed, j, c, maxargs;
1094: char *p;
1095:
1096: lastarg = ppos;
1097: flushed = 0;
1098:
1099: switch (tok) {
1100: case (MDOC_Eo):
1101: maxargs = 1;
1102: break;
1103: default:
1104: maxargs = 0;
1105: break;
1106: }
1107:
1.58 kristaps 1108: if ( ! mdoc_block_alloc(mdoc, line, ppos, tok, NULL))
1.28 kristaps 1109: return(0);
1.22 kristaps 1110: mdoc->next = MDOC_NEXT_CHILD;
1111:
1112: if (0 == maxargs) {
1.28 kristaps 1113: if ( ! mdoc_head_alloc(mdoc, line, ppos, tok))
1114: return(0);
1.41 kristaps 1115: if ( ! rewind_subblock(MDOC_HEAD, mdoc, tok, line, ppos))
1.28 kristaps 1116: return(0);
1117: if ( ! mdoc_body_alloc(mdoc, line, ppos, tok))
1.25 kristaps 1118: return(0);
1.22 kristaps 1119: flushed = 1;
1.28 kristaps 1120: } else if ( ! mdoc_head_alloc(mdoc, line, ppos, tok))
1121: return(0);
1.22 kristaps 1122:
1123: mdoc->next = MDOC_NEXT_CHILD;
1124:
1.41 kristaps 1125: for (j = 0; /* No sentinel. */; j++) {
1.22 kristaps 1126: lastarg = *pos;
1127:
1128: if (j == maxargs && ! flushed) {
1.41 kristaps 1129: if ( ! rewind_subblock(MDOC_HEAD, mdoc, tok, line, ppos))
1.22 kristaps 1130: return(0);
1131: flushed = 1;
1.28 kristaps 1132: if ( ! mdoc_body_alloc(mdoc, line, ppos, tok))
1133: return(0);
1.22 kristaps 1134: mdoc->next = MDOC_NEXT_CHILD;
1135: }
1136:
1.48 kristaps 1137: c = mdoc_args(mdoc, line, pos, buf, tok, &p);
1.49 kristaps 1138: assert(ARGS_PHRASE != c);
1139:
1.22 kristaps 1140: if (ARGS_ERROR == c)
1141: return(0);
1142: if (ARGS_PUNCT == c)
1143: break;
1144: if (ARGS_EOLN == c)
1145: break;
1146:
1.30 kristaps 1147: if (-1 == (c = lookup(mdoc, line, lastarg, tok, p)))
1148: return(0);
1149: else if (MDOC_MAX != c) {
1.22 kristaps 1150: if ( ! flushed) {
1.51 kristaps 1151: if ( ! rewind_subblock(MDOC_HEAD, mdoc,
1152: tok, line, ppos))
1.22 kristaps 1153: return(0);
1154: flushed = 1;
1.51 kristaps 1155: if ( ! mdoc_body_alloc(mdoc, line,
1156: ppos, tok))
1.28 kristaps 1157: return(0);
1.22 kristaps 1158: mdoc->next = MDOC_NEXT_CHILD;
1159: }
1.51 kristaps 1160: if ( ! mdoc_macro(mdoc, c, line, lastarg,
1161: pos, buf))
1.22 kristaps 1162: return(0);
1163: break;
1164: }
1165:
1166: if ( ! flushed && mdoc_isdelim(p)) {
1.51 kristaps 1167: if ( ! rewind_subblock(MDOC_HEAD, mdoc,
1168: tok, line, ppos))
1.22 kristaps 1169: return(0);
1170: flushed = 1;
1.28 kristaps 1171: if ( ! mdoc_body_alloc(mdoc, line, ppos, tok))
1172: return(0);
1.22 kristaps 1173: mdoc->next = MDOC_NEXT_CHILD;
1174: }
1175:
1.28 kristaps 1176: if ( ! mdoc_word_alloc(mdoc, line, lastarg, p))
1177: return(0);
1.22 kristaps 1178: mdoc->next = MDOC_NEXT_SIBLING;
1179: }
1180:
1181: if ( ! flushed) {
1.41 kristaps 1182: if ( ! rewind_subblock(MDOC_HEAD, mdoc, tok, line, ppos))
1.28 kristaps 1183: return(0);
1184: if ( ! mdoc_body_alloc(mdoc, line, ppos, tok))
1.22 kristaps 1185: return(0);
1186: mdoc->next = MDOC_NEXT_CHILD;
1187: }
1188:
1189: if (ppos > 1)
1190: return(1);
1.41 kristaps 1191: return(append_delims(mdoc, line, pos, buf));
1.7 kristaps 1192: }
1.8 kristaps 1193:
1.10 kristaps 1194:
1.44 kristaps 1195: /*
1196: * A delimited constant is very similar to the macros parsed by
1197: * macro_text except that, in the event of punctuation, the macro isn't
1198: * "re-opened" as it is in macro_text. Also, these macros have a fixed
1199: * number of parameters.
1200: *
1201: * .Fl a No b
1202: *
1203: * ELEMENT (.Fl)
1204: * TEXT (`a')
1205: * ELEMENT (.No)
1206: * TEXT (`b')
1207: */
1.51 kristaps 1208: static int
1.10 kristaps 1209: macro_constant_delimited(MACRO_PROT_ARGS)
1210: {
1.58 kristaps 1211: int lastarg, flushed, j, c, maxargs,
1.57 kristaps 1212: igndelim, ignargs;
1.58 kristaps 1213: struct mdoc_arg *arg;
1.13 kristaps 1214: char *p;
1.10 kristaps 1215:
1216: lastarg = ppos;
1217: flushed = 0;
1.57 kristaps 1218:
1219: /*
1220: * Maximum arguments per macro. Some of these have none and
1221: * exit as soon as they're parsed.
1222: */
1223:
1.10 kristaps 1224: switch (tok) {
1.61 kristaps 1225: case (MDOC_Ap):
1226: /* FALLTHROUGH */
1.16 kristaps 1227: case (MDOC_No):
1228: /* FALLTHROUGH */
1229: case (MDOC_Ns):
1230: /* FALLTHROUGH */
1.10 kristaps 1231: case (MDOC_Ux):
1232: maxargs = 0;
1233: break;
1234: default:
1235: maxargs = 1;
1236: break;
1237: }
1238:
1.57 kristaps 1239: /*
1240: * Whether to ignore delimiter characters. `Pf' accepts its
1241: * first token as a parameter no matter what it looks like (if
1242: * it's text).
1243: */
1244:
1.50 kristaps 1245: switch (tok) {
1246: case (MDOC_Pf):
1247: igndelim = 1;
1248: break;
1249: default:
1250: igndelim = 0;
1251: break;
1252: }
1253:
1.57 kristaps 1254: /*
1255: * Whether to ignore arguments: `St', for example, handles its
1256: * argument-like parameters as regular parameters.
1257: */
1258:
1259: switch (tok) {
1260: case (MDOC_St):
1261: ignargs = 1;
1262: break;
1263: default:
1264: ignargs = 0;
1265: break;
1.24 kristaps 1266: }
1267:
1.58 kristaps 1268: arg = NULL;
1.57 kristaps 1269:
1270: if ( ! ignargs)
1.58 kristaps 1271: for (;;) {
1.57 kristaps 1272: lastarg = *pos;
1.58 kristaps 1273: c = mdoc_argv(mdoc, line, tok, &arg, pos, buf);
1.57 kristaps 1274: if (ARGV_EOLN == c)
1275: break;
1276: if (ARGV_WORD == c) {
1277: *pos = lastarg;
1278: break;
1279: } else if (ARGV_ARG == c)
1280: continue;
1.58 kristaps 1281: mdoc_argv_free(arg);
1.57 kristaps 1282: return(0);
1283: }
1284:
1.58 kristaps 1285: if ( ! mdoc_elem_alloc(mdoc, line, ppos, tok, arg))
1.24 kristaps 1286: return(0);
1287:
1.19 kristaps 1288: mdoc->next = MDOC_NEXT_CHILD;
1.10 kristaps 1289:
1.41 kristaps 1290: for (j = 0; /* No sentinel. */; j++) {
1.19 kristaps 1291: lastarg = *pos;
1.10 kristaps 1292:
1.19 kristaps 1293: if (j == maxargs && ! flushed) {
1.28 kristaps 1294: if ( ! rewind_elem(mdoc, tok))
1.19 kristaps 1295: return(0);
1296: flushed = 1;
1297: }
1.11 kristaps 1298:
1.48 kristaps 1299: c = mdoc_args(mdoc, line, pos, buf, tok, &p);
1.49 kristaps 1300: assert(ARGS_PHRASE != c);
1301:
1.19 kristaps 1302: if (ARGS_ERROR == c)
1.10 kristaps 1303: return(0);
1.19 kristaps 1304: if (ARGS_PUNCT == c)
1305: break;
1306: if (ARGS_EOLN == c)
1307: break;
1308:
1.30 kristaps 1309: if (-1 == (c = lookup(mdoc, line, lastarg, tok, p)))
1310: return(0);
1311: else if (MDOC_MAX != c) {
1.28 kristaps 1312: if ( ! flushed && ! rewind_elem(mdoc, tok))
1.19 kristaps 1313: return(0);
1314: flushed = 1;
1.26 kristaps 1315: if ( ! mdoc_macro(mdoc, c, line, lastarg, pos, buf))
1.19 kristaps 1316: return(0);
1317: break;
1318: }
1.10 kristaps 1319:
1.50 kristaps 1320: if ( ! flushed && mdoc_isdelim(p) && ! igndelim) {
1.28 kristaps 1321: if ( ! rewind_elem(mdoc, tok))
1.19 kristaps 1322: return(0);
1323: flushed = 1;
1324: }
1325:
1.28 kristaps 1326: if ( ! mdoc_word_alloc(mdoc, line, lastarg, p))
1327: return(0);
1.19 kristaps 1328: mdoc->next = MDOC_NEXT_SIBLING;
1.10 kristaps 1329: }
1330:
1.42 kristaps 1331: if ( ! flushed && ! rewind_elem(mdoc, tok))
1.19 kristaps 1332: return(0);
1.11 kristaps 1333:
1.19 kristaps 1334: if (ppos > 1)
1335: return(1);
1.41 kristaps 1336: return(append_delims(mdoc, line, pos, buf));
1.10 kristaps 1337: }
1.11 kristaps 1338:
1339:
1.44 kristaps 1340: /*
1341: * A constant macro is the simplest classification. It spans an entire
1342: * line.
1343: */
1.51 kristaps 1344: static int
1.11 kristaps 1345: macro_constant(MACRO_PROT_ARGS)
1346: {
1.58 kristaps 1347: int c, w, la;
1348: struct mdoc_arg *arg;
1.43 kristaps 1349: char *p;
1.44 kristaps 1350:
1351: assert( ! (MDOC_CALLABLE & mdoc_macros[tok].flags));
1.11 kristaps 1352:
1.58 kristaps 1353: arg = NULL;
1354:
1355: for (;;) {
1.45 kristaps 1356: la = *pos;
1.58 kristaps 1357: c = mdoc_argv(mdoc, line, tok, &arg, pos, buf);
1.16 kristaps 1358: if (ARGV_EOLN == c)
1359: break;
1.38 kristaps 1360: if (ARGV_WORD == c) {
1.45 kristaps 1361: *pos = la;
1.38 kristaps 1362: break;
1363: } else if (ARGV_ARG == c)
1.16 kristaps 1364: continue;
1.58 kristaps 1365: mdoc_argv_free(arg);
1.11 kristaps 1366: return(0);
1367: }
1368:
1.58 kristaps 1369: if ( ! mdoc_elem_alloc(mdoc, line, ppos, tok, arg))
1.28 kristaps 1370: return(0);
1.11 kristaps 1371:
1.19 kristaps 1372: mdoc->next = MDOC_NEXT_CHILD;
1373:
1.41 kristaps 1374: for (;;) {
1.45 kristaps 1375: la = *pos;
1.48 kristaps 1376: w = mdoc_args(mdoc, line, pos, buf, tok, &p);
1.49 kristaps 1377: assert(ARGS_PHRASE != c);
1378:
1.45 kristaps 1379: if (ARGS_ERROR == w)
1.16 kristaps 1380: return(0);
1.45 kristaps 1381: if (ARGS_EOLN == w)
1.13 kristaps 1382: break;
1.19 kristaps 1383:
1.45 kristaps 1384: c = ARGS_QWORD == w ? MDOC_MAX :
1385: lookup(mdoc, line, la, tok, p);
1386:
1387: if (MDOC_MAX != c && -1 != c) {
1.39 kristaps 1388: if ( ! rewind_elem(mdoc, tok))
1389: return(0);
1.45 kristaps 1390: return(mdoc_macro(mdoc, c, line, la, pos, buf));
1391: } else if (-1 == c)
1392: return(0);
1.39 kristaps 1393:
1.45 kristaps 1394: if ( ! mdoc_word_alloc(mdoc, line, la, p))
1.28 kristaps 1395: return(0);
1.21 kristaps 1396: mdoc->next = MDOC_NEXT_SIBLING;
1.13 kristaps 1397: }
1398:
1.44 kristaps 1399: return(rewind_elem(mdoc, tok));
1.13 kristaps 1400: }
1.15 kristaps 1401:
1402:
1.16 kristaps 1403: /* ARGSUSED */
1.51 kristaps 1404: static int
1.15 kristaps 1405: macro_obsolete(MACRO_PROT_ARGS)
1406: {
1407:
1.49 kristaps 1408: return(pwarn(mdoc, line, ppos, WOBS));
1.15 kristaps 1409: }
1.25 kristaps 1410:
1411:
1.44 kristaps 1412: /*
1413: * This is called at the end of parsing. It must traverse up the tree,
1414: * closing out open [implicit] scopes. Obviously, open explicit scopes
1415: * are errors.
1416: */
1.25 kristaps 1417: int
1418: macro_end(struct mdoc *mdoc)
1419: {
1.42 kristaps 1420: struct mdoc_node *n;
1.25 kristaps 1421:
1422: assert(mdoc->first);
1423: assert(mdoc->last);
1.42 kristaps 1424:
1425: /* Scan for open explicit scopes. */
1426:
1427: n = MDOC_VALID & mdoc->last->flags ?
1428: mdoc->last->parent : mdoc->last;
1429:
1430: for ( ; n; n = n->parent) {
1431: if (MDOC_BLOCK != n->type)
1432: continue;
1433: if ( ! (MDOC_EXPLICIT & mdoc_macros[n->tok].flags))
1434: continue;
1.51 kristaps 1435: return(mdoc_nerr(mdoc, n,
1436: "macro scope still open on exit"));
1.42 kristaps 1437: }
1438:
1.41 kristaps 1439: return(rewind_last(mdoc, mdoc->first));
1.25 kristaps 1440: }
CVSweb