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