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