]> git.cameronkatri.com Git - mandoc.git/commitdiff
*** empty log message ***
authorKristaps Dzonsons <kristaps@bsd.lv>
Mon, 12 Jan 2009 12:52:21 +0000 (12:52 +0000)
committerKristaps Dzonsons <kristaps@bsd.lv>
Mon, 12 Jan 2009 12:52:21 +0000 (12:52 +0000)
action.c
macro.c
mdoc.c
mdoc.h
mdocml.c
validate.c

index e11c7124d914aa4288b64b72a596aff21b3902a2..7f09a571f521add5ed33b2a37c64acb0091c9fa2 100644 (file)
--- a/action.c
+++ b/action.c
@@ -1,4 +1,4 @@
-/* $Id: action.c,v 1.6 2009/01/09 14:45:44 kristaps Exp $ */
+/* $Id: action.c,v 1.7 2009/01/12 12:52:21 kristaps Exp $ */
 /*
  * Copyright (c) 2008 Kristaps Dzonsons <kristaps@kth.se>
  *
@@ -159,7 +159,7 @@ post_sh(struct mdoc *mdoc)
        if (MDOC_HEAD != mdoc->last->type)
                return(1);
        
-       assert(MDOC_Sh == mdoc->last->data.head.tok);
+       assert(MDOC_Sh == mdoc->last->tok);
 
        n = mdoc->last->child;
        assert(n);
@@ -189,7 +189,7 @@ post_dt(struct mdoc *mdoc)
        struct mdoc_node *n;
 
        assert(MDOC_ELEM == mdoc->last->type);
-       assert(MDOC_Dt == mdoc->last->data.elem.tok);
+       assert(MDOC_Dt == mdoc->last->tok);
        assert(0 == mdoc->meta.title[0]);
 
        sz = META_TITLE_SZ;
@@ -236,7 +236,7 @@ post_os(struct mdoc *mdoc)
        struct mdoc_node *n;
 
        assert(MDOC_ELEM == mdoc->last->type);
-       assert(MDOC_Os == mdoc->last->data.elem.tok);
+       assert(MDOC_Os == mdoc->last->tok);
        assert(0 == mdoc->meta.os[0]);
 
        sz = META_OS_SZ;
@@ -269,7 +269,7 @@ post_dd(struct mdoc *mdoc)
        struct mdoc_node *n;
 
        assert(MDOC_ELEM == mdoc->last->type);
-       assert(MDOC_Dd == mdoc->last->data.elem.tok);
+       assert(MDOC_Dd == mdoc->last->tok);
 
        n = mdoc->last->child; 
        assert(0 == mdoc->meta.date);
@@ -281,7 +281,7 @@ post_dd(struct mdoc *mdoc)
                assert(MDOC_TEXT == n->type);
                p = n->data.text.string;
 
-               if (xstrcmp(p, "$Mdocdate: January 9 2009 $")) {
+               if (xstrcmp(p, "$Mdocdate: January 12 2009 $")) {
                        mdoc->meta.date = time(NULL);
                        continue;
                } else if (xstrcmp(p, "$")) {
@@ -317,27 +317,14 @@ mdoc_action_pre(struct mdoc *mdoc, struct mdoc_node *node)
 int
 mdoc_action_post(struct mdoc *mdoc)
 {
-       int              t;
-
-       switch (mdoc->last->type) {
-       case (MDOC_BODY):
-               t = mdoc->last->data.body.tok;
-               break;
-       case (MDOC_ELEM):
-               t = mdoc->last->data.elem.tok;
-               break;
-       case (MDOC_BLOCK):
-               t = mdoc->last->data.block.tok;
-               break;
-       case (MDOC_HEAD):
-               t = mdoc->last->data.head.tok;
-               break;
-       default:
+
+       if (MDOC_TEXT == mdoc->last->type)
+               return(1);
+       if (MDOC_ROOT == mdoc->last->type)
                return(1);
-       }
 
-       if (NULL == mdoc_actions[t].post)
+       if (NULL == mdoc_actions[mdoc->last->tok].post)
                return(1);
        /* TODO: MDOC_Nm... ? */
-       return((*mdoc_actions[t].post)(mdoc));
+       return((*mdoc_actions[mdoc->last->tok].post)(mdoc));
 }
diff --git a/macro.c b/macro.c
index 56da7aacb2e260f0e9197e351dd060302cd4e1ab..56d8bc83d4b5d47c271923cde9f3ec450e4e3a8f 100644 (file)
--- a/macro.c
+++ b/macro.c
@@ -1,4 +1,4 @@
-/* $Id: macro.c,v 1.31 2009/01/12 10:31:53 kristaps Exp $ */
+/* $Id: macro.c,v 1.32 2009/01/12 12:52:21 kristaps Exp $ */
 /*
  * Copyright (c) 2008 Kristaps Dzonsons <kristaps@kth.se>
  *
@@ -93,7 +93,7 @@ rewind_elem(struct mdoc *mdoc, int tok)
        if (MDOC_ELEM != n->type)
                n = n->parent;
        assert(MDOC_ELEM == n->type);
-       assert(tok == n->data.elem.tok);
+       assert(tok == n->tok);
 
        return(rewind_last(mdoc, n));
 }
@@ -111,7 +111,7 @@ rewind_body(struct mdoc *mdoc, int tok)
        for (n = mdoc->last; n; n = n->parent) {
                if (MDOC_BODY != n->type) 
                        continue;
-               if (tok == (t = n->data.head.tok))
+               if (tok == (t = n->tok))
                        break;
                if ( ! (MDOC_EXPLICIT & mdoc_macros[t].flags))
                        continue;
@@ -135,7 +135,7 @@ rewind_head(struct mdoc *mdoc, int tok)
        for (n = mdoc->last; n; n = n->parent) {
                if (MDOC_HEAD != n->type) 
                        continue;
-               if (tok == (t = n->data.head.tok))
+               if (tok == (t = n->tok))
                        break;
                if ( ! (MDOC_EXPLICIT & mdoc_macros[t].flags))
                        continue;
@@ -159,7 +159,7 @@ rewind_expblock(struct mdoc *mdoc, int tok)
        for ( ; n; n = n->parent) {
                if (MDOC_BLOCK != n->type)
                        continue;
-               if (tok == (t = n->data.block.tok))
+               if (tok == (t = n->tok))
                        break;
                if (MDOC_NESTED & mdoc_macros[t].flags)
                        continue;
@@ -183,7 +183,7 @@ rewind_impblock(struct mdoc *mdoc, int tok)
        for ( ; n; n = n->parent) {
                if (MDOC_BLOCK != n->type) 
                        continue;
-               if (tok == (t = n->data.block.tok))
+               if (tok == (t = n->tok))
                        break;
                if ( ! (MDOC_EXPLICIT & mdoc_macros[t].flags))
                        continue;
diff --git a/mdoc.c b/mdoc.c
index 166f5293c1f48caf130ababf6a308d99cb0cc41d..71e5514bbc8e0708e0ed5cf62663337aeb9e086b 100644 (file)
--- a/mdoc.c
+++ b/mdoc.c
@@ -1,4 +1,4 @@
-/* $Id: mdoc.c,v 1.26 2009/01/12 10:31:53 kristaps Exp $ */
+/* $Id: mdoc.c,v 1.27 2009/01/12 12:52:21 kristaps Exp $ */
 /*
  * Copyright (c) 2008 Kristaps Dzonsons <kristaps@kth.se>
  *
@@ -399,33 +399,34 @@ mdoc_node_append(struct mdoc *mdoc, struct mdoc_node *p)
        assert(mdoc->first);
        assert(MDOC_ROOT != p->type);
 
+       if (MDOC_TEXT == mdoc->last->type)
+               on = "<text>";
+       else if (MDOC_ROOT == mdoc->last->type)
+               on = "<root>";
+       else
+               on = mdoc_macronames[mdoc->last->tok];
+
+       /* FIXME: put this into util.c. */
        switch (mdoc->last->type) {
        case (MDOC_TEXT):
-               on = "<text>";
                ot = "text";
                break;
        case (MDOC_BODY):
-               on = mdoc_macronames[mdoc->last->data.body.tok];
                ot = "body";
                break;
        case (MDOC_ELEM):
-               on = mdoc_macronames[mdoc->last->data.elem.tok];
                ot = "elem";
                break;
        case (MDOC_HEAD):
-               on = mdoc_macronames[mdoc->last->data.head.tok];
                ot = "head";
                break;
        case (MDOC_TAIL):
-               on = mdoc_macronames[mdoc->last->data.tail.tok];
                ot = "tail";
                break;
        case (MDOC_BLOCK):
-               on = mdoc_macronames[mdoc->last->data.block.tok];
                ot = "block";
                break;
        case (MDOC_ROOT):
-               on = "root";
                ot = "root";
                break;
        default:
@@ -454,6 +455,24 @@ mdoc_node_append(struct mdoc *mdoc, struct mdoc_node *p)
                return(0);
        if ( ! mdoc_action_pre(mdoc, p))
                return(0);
+
+       switch (p->type) {
+       case (MDOC_HEAD):
+               assert(MDOC_BLOCK == p->parent->type);
+               p->parent->data.block.head = p;
+               break;
+       case (MDOC_TAIL):
+               assert(MDOC_BLOCK == p->parent->type);
+               p->parent->data.block.tail = p;
+               break;
+       case (MDOC_BODY):
+               assert(MDOC_BLOCK == p->parent->type);
+               p->parent->data.block.body = p;
+               break;
+       default:
+               break;
+       }
+
        mdoc->last = p;
        mdoc_msg(mdoc, "parse: %s of %s `%s'", act, ot, on);
        return(1);
@@ -473,7 +492,7 @@ mdoc_tail_alloc(struct mdoc *mdoc, int line, int pos, int tok)
        p->line = line;
        p->pos = pos;
        p->type = MDOC_TAIL;
-       p->data.tail.tok = tok;
+       p->tok = tok;
 
        return(mdoc_node_append(mdoc, p));
 }
@@ -492,7 +511,7 @@ mdoc_head_alloc(struct mdoc *mdoc, int line, int pos, int tok)
        p->line = line;
        p->pos = pos;
        p->type = MDOC_HEAD;
-       p->data.head.tok = tok;
+       p->tok = tok;
 
        return(mdoc_node_append(mdoc, p));
 }
@@ -511,7 +530,7 @@ mdoc_body_alloc(struct mdoc *mdoc, int line, int pos, int tok)
        p->line = line;
        p->pos = pos;
        p->type = MDOC_BODY;
-       p->data.body.tok = tok;
+       p->tok = tok;
 
        return(mdoc_node_append(mdoc, p));
 }
@@ -541,7 +560,7 @@ mdoc_block_alloc(struct mdoc *mdoc, int line, int pos,
        p->pos = pos;
        p->line = line;
        p->type = MDOC_BLOCK;
-       p->data.block.tok = tok;
+       p->tok = tok;
        p->data.block.argc = argsz;
        p->data.block.argv = argdup(argsz, args);
 
@@ -560,7 +579,7 @@ mdoc_elem_alloc(struct mdoc *mdoc, int line, int pos,
        p->line = line;
        p->pos = pos;
        p->type = MDOC_ELEM;
-       p->data.elem.tok = tok;
+       p->tok = tok;
        p->data.elem.argc = argsz;
        p->data.elem.argv = argdup(argsz, args);
 
diff --git a/mdoc.h b/mdoc.h
index 8ccd961af1162942c01966527f04b2a2ca2324cc..2344461263a92373849167d6c9f26f84d80c8702 100644 (file)
--- a/mdoc.h
+++ b/mdoc.h
@@ -1,4 +1,4 @@
-/* $Id: mdoc.h,v 1.19 2009/01/12 10:31:53 kristaps Exp $ */
+/* $Id: mdoc.h,v 1.20 2009/01/12 12:52:21 kristaps Exp $ */
 /*
  * Copyright (c) 2008 Kristaps Dzonsons <kristaps@kth.se>
  *
@@ -221,6 +221,7 @@ enum        mdoc_err {
        ERR_ARGS_LE8,
        ERR_ARGS_MANY,
        ERR_SYNTAX_CHILDBAD,
+       ERR_SYNTAX_PARENTBAD,
        ERR_SYNTAX_CHILDHEAD,
        ERR_SYNTAX_CHILDBODY,
        ERR_SYNTAX_EMPTYBODY,
@@ -249,7 +250,9 @@ enum        mdoc_warn {
        WARN_SYNTAX_MACLIKE,
        WARN_SYNTAX_ARGLIKE,
        WARN_SYNTAX_QUOTED,
+       WARN_SYNTAX_EMPTYHEAD,
        WARN_SYNTAX_EMPTYBODY,
+       WARN_SYNTAX_NOBODY,
        WARN_IGN_AFTER_BLK,
        WARN_IGN_BEFORE_BLK,
        WARN_IGN_OBSOLETE,
@@ -379,27 +382,16 @@ struct    mdoc_text {
 };
 
 struct mdoc_block {
-       int               tok;
        size_t            argc;
        struct mdoc_arg  *argv;
-};
-
-struct mdoc_head {
-       int               tok;
-};
-
-struct mdoc_tail {
-       int               tok;
-};
-
-struct mdoc_body {
-       int               tok;
+       struct mdoc_node *head;
+       struct mdoc_node *body;
+       struct mdoc_node *tail;
 };
 
 struct mdoc_elem {
        size_t            sz;
        char            **args;
-       int               tok;
        size_t            argc;
        struct mdoc_arg  *argv;
 };
@@ -407,9 +399,6 @@ struct      mdoc_elem {
 union  mdoc_data {
        struct mdoc_text  text;
        struct mdoc_elem  elem;
-       struct mdoc_body  body;
-       struct mdoc_head  head;
-       struct mdoc_tail  tail;
        struct mdoc_block block;
 };
 
@@ -420,6 +409,7 @@ struct      mdoc_node {
        struct mdoc_node *prev;
        int               line;
        int               pos;
+       int               tok;
        enum mdoc_type    type;
        union mdoc_data   data;
 };
index 1f29809d381582027acbfdef583c51427568d8fa..ec53aa10b328542e64131b672d75fbb2a940b2ec 100644 (file)
--- a/mdocml.c
+++ b/mdocml.c
@@ -1,4 +1,4 @@
-/* $Id: mdocml.c,v 1.39 2009/01/12 10:31:53 kristaps Exp $ */
+/* $Id: mdocml.c,v 1.40 2009/01/12 12:52:21 kristaps Exp $ */
 /*
  * Copyright (c) 2008 Kristaps Dzonsons <kristaps@kth.se>
  *
@@ -192,6 +192,7 @@ print_node(const struct mdoc_node *n, int indent)
        params = NULL;
        sz = 0;
 
+       /* FIXME: put parts of this in util.c. */
        switch (n->type) {
        case (MDOC_TEXT):
                assert(NULL == n->child);
@@ -199,25 +200,25 @@ print_node(const struct mdoc_node *n, int indent)
                t = "text";
                break;
        case (MDOC_BODY):
-               p = mdoc_macronames[n->data.body.tok];
+               p = mdoc_macronames[n->tok];
                t = "block-body";
                break;
        case (MDOC_HEAD):
-               p = mdoc_macronames[n->data.head.tok];
+               p = mdoc_macronames[n->tok];
                t = "block-head";
                break;
        case (MDOC_TAIL):
-               p = mdoc_macronames[n->data.tail.tok];
+               p = mdoc_macronames[n->tok];
                t = "block-tail";
                break;
        case (MDOC_ELEM):
-               p = mdoc_macronames[n->data.elem.tok];
+               p = mdoc_macronames[n->tok];
                t = "element";
                argv = n->data.elem.argv;
                argc = n->data.elem.argc;
                break;
        case (MDOC_BLOCK):
-               p = mdoc_macronames[n->data.block.tok];
+               p = mdoc_macronames[n->tok];
                t = "block";
                argv = n->data.block.argv;
                argc = n->data.block.argc;
@@ -419,6 +420,9 @@ msg_err(void *arg, int line, int col, enum mdoc_err type)
        case (ERR_SYNTAX_CHILDBAD):
                lit = "syntax: invalid child for parent macro";
                break;
+       case (ERR_SYNTAX_PARENTBAD):
+               lit = "syntax: invalid parent for macro";
+               break;
        case (ERR_SYNTAX_CHILDHEAD):
                lit = "syntax: expected only block-header section";
                break;
@@ -485,7 +489,13 @@ msg_warn(void *arg, int line, int col, enum mdoc_warn type)
                lit = "syntax: argument-like value";
                break;
        case (WARN_SYNTAX_EMPTYBODY):
-               lit = "syntax: empty block-body section";
+               lit = "syntax: macro suggests non-empty block-body section";
+               break;
+       case (WARN_SYNTAX_EMPTYHEAD):
+               lit = "syntax: macro suggests non-empty block-head section";
+               break;
+       case (WARN_SYNTAX_NOBODY):
+               lit = "syntax: macro suggests empty block-body section";
                break;
        case (WARN_SEC_OO):
                lit = "section is out of conventional order";
index 8fddae18cb15ce5830529a9277033797eac48d63..1242676b4fbfc03594dbe7aa5a34787ef347fa7b 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: validate.c,v 1.24 2009/01/12 10:31:53 kristaps Exp $ */
+/* $Id: validate.c,v 1.25 2009/01/12 12:52:21 kristaps Exp $ */
 /*
  * Copyright (c) 2008 Kristaps Dzonsons <kristaps@kth.se>
  *
@@ -35,6 +35,7 @@ struct        valids {
 static int     pre_display(struct mdoc *, struct mdoc_node *);
 static int     pre_bd(struct mdoc *, struct mdoc_node *);
 static int     pre_bl(struct mdoc *, struct mdoc_node *);
+static int     pre_it(struct mdoc *, struct mdoc_node *);
 static int     pre_prologue(struct mdoc *, struct mdoc_node *);
 static int     pre_prologue(struct mdoc *, struct mdoc_node *);
 static int     pre_prologue(struct mdoc *, struct mdoc_node *);
@@ -46,11 +47,13 @@ static      int     elemchild_warn_eq0(struct mdoc *);
 static int     bodychild_warn_ge1(struct mdoc *);
 static int     post_sh(struct mdoc *);
 static int     post_bl(struct mdoc *);
+static int     post_it(struct mdoc *);
 
 static v_pre   pres_prologue[] = { pre_prologue, NULL };
 static v_pre   pres_d1[] = { pre_display, NULL };
 static v_pre   pres_bd[] = { pre_display, pre_bd, NULL };
 static v_pre   pres_bl[] = { pre_bl, NULL };
+static v_pre   pres_it[] = { pre_it, NULL };
 static v_post  posts_bd[] = { headchild_err_eq0, 
                        bodychild_warn_ge1, NULL };
 
@@ -58,6 +61,7 @@ static        v_post  posts_sh[] = { headchild_err_ge1,
                        bodychild_warn_ge1, post_sh, NULL };
 static v_post  posts_bl[] = { headchild_err_eq0, 
                        bodychild_warn_ge1, post_bl, NULL };
+static v_post  posts_it[] = { post_it, NULL };
 static v_post  posts_ss[] = { headchild_err_ge1, NULL };
 static v_post  posts_pp[] = { elemchild_warn_eq0, NULL };
 static v_post  posts_dd[] = { elemchild_err_ge1, NULL };
@@ -78,7 +82,7 @@ const struct valids mdoc_valids[MDOC_MAX] = {
        { NULL, NULL }, /* Ed */
        { pres_bl, posts_bl }, /* Bl */ /* FIXME: preceding Pp. */
        { NULL, NULL }, /* El */
-       { NULL, NULL }, /* It */
+       { pres_it, posts_it }, /* It */
        { NULL, NULL }, /* Ad */ 
        { NULL, NULL }, /* An */
        { NULL, NULL }, /* Ar */
@@ -244,7 +248,7 @@ pre_display(struct mdoc *mdoc, struct mdoc_node *node)
 
        for (n = mdoc->last; n; n = n->parent) 
                if (MDOC_BLOCK == n->type)
-                       if (MDOC_Bd == n->data.block.tok)
+                       if (MDOC_Bd == n->tok)
                                break;
        if (NULL == n)
                return(1);
@@ -261,7 +265,7 @@ pre_bl(struct mdoc *mdoc, struct mdoc_node *node)
 
        if (MDOC_BLOCK != node->type)
                return(1);
-       assert(MDOC_Bl == node->data.block.tok);
+       assert(MDOC_Bl == node->tok);
 
        argv = NULL;
        argc = node->data.block.argc; 
@@ -316,7 +320,7 @@ pre_bd(struct mdoc *mdoc, struct mdoc_node *node)
 
        if (MDOC_BLOCK != node->type)
                return(1);
-       assert(MDOC_Bd == node->data.block.tok);
+       assert(MDOC_Bd == node->tok);
 
        argv = NULL;
        argc = node->data.block.argc;
@@ -350,6 +354,23 @@ pre_bd(struct mdoc *mdoc, struct mdoc_node *node)
 }
 
 
+static int
+pre_it(struct mdoc *mdoc, struct mdoc_node *node)
+{
+
+       if (MDOC_BLOCK != mdoc->last->type)
+               return(1);
+       assert(MDOC_It == mdoc->last->tok);
+
+       if (MDOC_BODY != mdoc->last->parent->type) 
+               return(mdoc_verr(mdoc, node, ERR_SYNTAX_PARENTBAD));
+       if (MDOC_Bl != mdoc->last->parent->tok)
+               return(mdoc_verr(mdoc, node, ERR_SYNTAX_PARENTBAD));
+
+       return(1);
+}
+
+
 static int
 pre_prologue(struct mdoc *mdoc, struct mdoc_node *node)
 {
@@ -360,7 +381,7 @@ pre_prologue(struct mdoc *mdoc, struct mdoc_node *node)
 
        /* Check for ordering. */
 
-       switch (node->data.elem.tok) {
+       switch (node->tok) {
        case (MDOC_Os):
                if (mdoc->meta.title[0] && mdoc->meta.date)
                        break;
@@ -380,7 +401,7 @@ pre_prologue(struct mdoc *mdoc, struct mdoc_node *node)
 
        /* Check for repetition. */
 
-       switch (node->data.elem.tok) {
+       switch (node->tok) {
        case (MDOC_Os):
                if (0 == mdoc->meta.os[0])
                        return(1);
@@ -402,6 +423,108 @@ pre_prologue(struct mdoc *mdoc, struct mdoc_node *node)
 }
 
 
+/* Warn if `Bl' type-specific syntax isn't reflected in items. */
+static int
+post_it(struct mdoc *mdoc)
+{
+       int               type, sv;
+#define        TYPE_NONE        (0)
+#define        TYPE_BODY        (1)
+#define        TYPE_HEAD        (2)
+       size_t            i, argc;
+       struct mdoc_node *n;
+
+       if (MDOC_BLOCK != mdoc->last->type)
+               return(1);
+
+       assert(MDOC_It == mdoc->last->tok);
+
+       n = mdoc->last->parent;
+       assert(n);
+       assert(MDOC_Bl == n->tok);
+
+       n = n->parent;
+       assert(MDOC_BLOCK == n->type);
+       assert(MDOC_Bl == n->tok);
+
+       argc = n->data.block.argc;
+       type = TYPE_NONE;
+
+       for (i = 0; TYPE_NONE == type && i < argc; i++)
+               switch (n->data.block.argv[(int)i].arg) {
+               case (MDOC_Tag):
+                       /* FALLTHROUGH */
+               case (MDOC_Diag):
+                       /* FALLTHROUGH */
+               case (MDOC_Hang):
+                       /* FALLTHROUGH */
+               case (MDOC_Ohang):
+                       /* FALLTHROUGH */
+               case (MDOC_Inset):
+                       type = TYPE_HEAD;
+                       sv = n->data.block.argv[(int)i].arg;
+                       break;
+               case (MDOC_Bullet):
+                       /* FALLTHROUGH */
+               case (MDOC_Dash):
+                       /* FALLTHROUGH */
+               case (MDOC_Enum):
+                       /* FALLTHROUGH */
+               case (MDOC_Hyphen):
+                       /* FALLTHROUGH */
+               case (MDOC_Item):
+                       /* FALLTHROUGH */
+               case (MDOC_Column):
+                       type = TYPE_BODY;
+                       sv = n->data.block.argv[(int)i].arg;
+                       break;
+               default:
+                       break;
+               }
+
+       assert(TYPE_NONE != type);
+
+       if (TYPE_HEAD == type) {
+               if (NULL == (n = mdoc->last->data.block.head)) {
+                       if ( ! mdoc_warn(mdoc, WARN_SYNTAX_EMPTYHEAD))
+                               return(0);
+               } else if (NULL == n->child)
+                       if ( ! mdoc_warn(mdoc, WARN_SYNTAX_EMPTYHEAD))
+                               return(0);
+
+               if (NULL == (n = mdoc->last->data.block.body)) {
+                       if ( ! mdoc_warn(mdoc, WARN_SYNTAX_EMPTYBODY))
+                               return(0);
+               } else if (NULL == n->child)
+                       if ( ! mdoc_warn(mdoc, WARN_SYNTAX_EMPTYBODY))
+                               return(0);
+
+               return(1);
+       }
+
+       if (NULL == (n = mdoc->last->data.block.head)) {
+               if ( ! mdoc_warn(mdoc, WARN_SYNTAX_EMPTYHEAD))
+                       return(0);
+       } else if (NULL == n->child)
+               if ( ! mdoc_warn(mdoc, WARN_SYNTAX_EMPTYHEAD))
+                       return(0);
+
+       if ((n = mdoc->last->data.block.body) && n->child)
+               if ( ! mdoc_warn(mdoc, WARN_SYNTAX_NOBODY))
+                       return(0);
+
+       /* TODO: make sure columns are aligned. */
+       assert(MDOC_Column != sv);
+
+       return(1);
+
+#undef TYPE_NONE
+#undef TYPE_BODY
+#undef TYPE_HEAD
+}
+
+
+/* Make sure that only `It' macros are our body-children. */
 static int
 post_bl(struct mdoc *mdoc)
 {
@@ -409,11 +532,11 @@ post_bl(struct mdoc *mdoc)
 
        if (MDOC_BODY != mdoc->last->type)
                return(1);
-       assert(MDOC_Bl == mdoc->last->data.body.tok);
+       assert(MDOC_Bl == mdoc->last->tok);
 
        for (n = mdoc->last->child; n; n = n->next) {
                if (MDOC_BLOCK == n->type) 
-                       if (MDOC_It == n->data.block.tok)
+                       if (MDOC_It == n->tok)
                                continue;
                break;
        }
@@ -423,10 +546,7 @@ post_bl(struct mdoc *mdoc)
 }
 
 
-/*
- * Warn if sections (those that are with a known title, such as NAME,
- * DESCRIPTION, and so forth) are out of the conventional order.
- */
+/* Warn if conventional sections are out of order. */
 static int
 post_sh(struct mdoc *mdoc)
 {
@@ -438,7 +558,7 @@ post_sh(struct mdoc *mdoc)
        if (MDOC_HEAD != mdoc->last->type)
                return(1);
        
-       assert(MDOC_Sh == mdoc->last->data.head.tok);
+       assert(MDOC_Sh == mdoc->last->tok);
 
        n = mdoc->last->child;
        assert(n);
@@ -466,28 +586,16 @@ int
 mdoc_valid_pre(struct mdoc *mdoc, struct mdoc_node *node)
 {
        v_pre           *p;
-       int              t;
 
-       switch (node->type) {
-       case (MDOC_BODY):
-               t = node->data.body.tok;
-               break;
-       case (MDOC_ELEM):
-               t = node->data.elem.tok;
-               break;
-       case (MDOC_BLOCK):
-               t = node->data.block.tok;
-               break;
-       case (MDOC_HEAD):
-               t = node->data.head.tok;
-               break;
-       default:
+       /* TODO: character-escape checks. */
+
+       if (MDOC_TEXT == node->type)
                return(1);
-       }
+       assert(MDOC_ROOT != node->type);
 
-       if (NULL == mdoc_valids[t].pre)
+       if (NULL == mdoc_valids[node->tok].pre)
                return(1);
-       for (p = mdoc_valids[t].pre; *p; p++)
+       for (p = mdoc_valids[node->tok].pre; *p; p++)
                if ( ! (*p)(mdoc, node)) 
                        return(0);
        return(1);
@@ -498,28 +606,15 @@ int
 mdoc_valid_post(struct mdoc *mdoc)
 {
        v_post          *p;
-       int              t;
 
-       switch (mdoc->last->type) {
-       case (MDOC_BODY):
-               t = mdoc->last->data.body.tok;
-               break;
-       case (MDOC_ELEM):
-               t = mdoc->last->data.elem.tok;
-               break;
-       case (MDOC_BLOCK):
-               t = mdoc->last->data.block.tok;
-               break;
-       case (MDOC_HEAD):
-               t = mdoc->last->data.head.tok;
-               break;
-       default:
+       if (MDOC_TEXT == mdoc->last->type)
+               return(1);
+       if (MDOC_ROOT == mdoc->last->type)
                return(1);
-       }
 
-       if (NULL == mdoc_valids[t].post)
+       if (NULL == mdoc_valids[mdoc->last->tok].post)
                return(1);
-       for (p = mdoc_valids[t].post; *p; p++)
+       for (p = mdoc_valids[mdoc->last->tok].post; *p; p++)
                if ( ! (*p)(mdoc)) 
                        return(0);