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