tttm

git clone https://orangeshoelaces.net/git/tttm.git

a25411526ea1b265dacd3556627084568608b8d7

Author: Vasily Kolobkov on 05/06/2016

Committer: Vasily Kolobkov on 05/06/2016

Save the extra bytes for a better use

Stats

parse.c   | 1775 --------
parse.h   |  139 -
parser.c  | 1775 ++++++++
parser.h  |  139 +
pshades.c |   16 +-
5 files changed, 1922 insertions(+), 1922 deletions(-)

Patch

diff --git a/parse.c b/parse.c
deleted file mode 100644
index 801ff23..0000000
--- a/parse.c
+++ /dev/null
@@ -1,1775 +0,0 @@
-/*
-   Be warned! Most internal parser functions bear unconventional call
-   semantics returning 1 on success and 0 otherwise. Where applicable
-   specific error code or 0 is dispensed to the parse context.
-*/
-
-#include <stdint.h>
-#include <stdlib.h>
-#include <string.h>
-#include <strings.h>
-
-#include "parse.h"
-
-#define LEN(a) (sizeof(a) / sizeof(a)[0])
-
-static struct literal {
-	int    val;
-	char  *srep;
-	size_t slen;
-} literals[] = {
-	{ IL_7BIT,              "7BIT",              4  },
-	{ IL_8BIT,              "8BIT",              4  },
-	{ IL_ALERT,             "ALERT",             5  },
-	{ IL_APP,               "APPLICATION",       11 },
-	{ IL_APR,               "Apr",               3  },
-	{ IL_ASTERISK,          "*",                 1  },
-	{ IL_AUDIO,             "AUDIO",             5  },
-	{ IL_AUG,               "Aug",               3  },
-	{ IL_AUTHEQ,            "AUTH=",             5  },
-	{ IL_B64,               "BASE64",            6  },
-	{ IL_BAD,               "BAD",               3  },
-	{ IL_BADCS,             "BADCHARSET",        10 },
-	{ IL_BIN,               "BINARY",            6  },
-	{ IL_BODY,              "BODY",              4  },
-	{ IL_BSLASH,            "\\",                1  },
-	{ IL_BYE,               "BYE",               3  },
-	{ IL_CAP,               "CAPABILITY",        10 },
-	{ IL_CBRACE,            "}",                 1  },
-	{ IL_CBRACK,            "]",                 1  },
-	{ IL_COLON,             ":",                 1  },
-	{ IL_CPAR,              ")",                 1  },
-	{ IL_DEC,               "Dec",               3  },
-	{ IL_DHDR,              ".HEADER",           7  },
-	{ IL_DNOT,              ".NOT",              4  },
-	{ IL_DOT,               ".",                 1  },
-	{ IL_DQUOTE,            "\"",                1  },
-	{ IL_DTXT,              ".TEXT",             5  },
-	{ IL_ENVELOPE,          "ENVELOPE",          8  },
-	{ IL_EOL,               "\r\n",              2  },
-	{ IL_EXISTS,            "EXISTS",            6  },
-	{ IL_EXPUNGE,           "EXPUNGE",           7  },
-	{ IL_FEB,               "Feb",               3  },
-	{ IL_FETCH,             "FETCH",             5  },
-	{ IL_FLAGS,             "FLAGS",             5  },
-	{ IL_FLANSWERED,        "\\Answered",        9  },
-	{ IL_FLANY,             "\\*",               2  },
-	{ IL_FLDELETED,         "\\Deleted",         8  },
-	{ IL_FLDRAFT,           "\\Draft",           6  },
-	{ IL_FLFLAGGED,         "\\Flagged",         8  },
-	{ IL_FLMARKED,          "\\Marked",          7  },
-	{ IL_FLNOINFERIORS,     "\\Noinferiors",     12 },
-	{ IL_FLNOSEL,           "\\Noselect",        9  },
-	{ IL_FLRECENT,          "\\Recent",          7  },
-	{ IL_FLSEEN,            "\\Seen",            5  },
-	{ IL_FLUNMARKED,        "\\Unmarked",        9  },
-	{ IL_GT,                ">",                 1  },
-	{ IL_HDR,               "HEADER",            6  },
-	{ IL_HDRFIELDS,         "HEADER.FIELDS",     13 },
-	{ IL_IMG,               "IMAGE",             5  },
-	{ IL_INBOX,             "INBOX",             5  },
-	{ IL_INTDATE,           "INTERNALDATE",      12 },
-	{ IL_JAN,               "Jan",               3  },
-	{ IL_JUL,               "Jul",               3  },
-	{ IL_JUN,               "Jun",               3  },
-	{ IL_LIST,              "LIST",              4  },
-	{ IL_LSUB,              "LSUB",              4  },
-	{ IL_LT,                "<",                 1  },
-	{ IL_MAR,               "Mar",               3  },
-	{ IL_MAY,               "May",               3  },
-	{ IL_MIME,              "MIME",              4  },
-	{ IL_MINUS,             "-",                 1  },
-	{ IL_MSG,               "MESSAGE",           7  },
-	{ IL_MSGS,              "MESSAGES",          8  },
-	{ IL_NIL,               "NIL",               3  },
-	{ IL_NO,                "NO",                2  },
-	{ IL_NOV,               "Nov",               3  },
-	{ IL_OBRACE,            "{",                 1  },
-	{ IL_OBRACK,            "[",                 1  },
-	{ IL_OCT,               "Oct",               3  },
-	{ IL_OK,                "OK",                2  },
-	{ IL_OPAR,              "(",                 1  },
-	{ IL_PARSE,             "PARSE",             5  },
-	{ IL_PERMFL,            "PERMANENTFLAGS",    14 },
-	{ IL_PLUS,              "+",                 1  },
-	{ IL_QPRN,              "QUOTED-PRINTABLE",  16 },
-	{ IL_RECENT,            "RECENT",            6  },
-	{ IL_RFC822,            "RFC822",            6  },
-	{ IL_RFC822SIZE,        "RFC822.SIZE",       11 },
-	{ IL_RO,                "READ-ONLY",         9  },
-	{ IL_RW,                "READ-WRITE",        10 },
-	{ IL_SEARCH,            "SEARCH",            6  },
-	{ IL_SEP,               "Sep",               3  },
-	{ IL_SP,                " ",                 1  },
-	{ IL_STATUS,            "STATUS",            6  },
-	{ IL_STRUCT,            "STRUCTURE",         9  },
-	{ IL_TRYC,              "TRYCREATE",         9  },
-	{ IL_TXT,               "TEXT",              4  },
-	{ IL_UID,               "UID",               3  },
-	{ IL_UIDNEXT,           "UIDNEXT",           7  },
-	{ IL_UIDVAL,            "UIDVALIDITY",       11 },
-	{ IL_UNSEEN,            "UNSEEN",            6  },
-	{ IL_VIDEO,             "VIDEO",             5  },
-};
-
-static const char astr_specials[] = ""
-	"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
-	"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"
-	" \"%()*\\{\x7f";
-
-static const char atom_specials[] = ""
-	"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
-	"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"
-	" \"%()*\\]{\x7f";
-
-static const char tag_specials[] = ""
-	"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
-	"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"
-	" \"%()*+\\{\x7f";
-
-struct parse_cur {
-	const char *tok;
-	union parse_node *pt;
-};
-
-struct parse_ctx {
-	struct parse_cur  cur;
-	const char       *tok;
-	const char       *tokend;
-	size_t            toklen;
-	union parse_node *pt;
-	union parse_node *ptend;
-	size_t            ptlen;
-	int               e;
-	size_t            oblth;
-};
-
-typedef int parsefn(struct parse_ctx *);
-
-int parse_respln(const char *, size_t, union parse_node *, size_t, size_t);
-
-static int cmpchr(const void *, const void *);
-static int contains(const char *, size_t, char);
-
-static int p_chk(struct parse_ctx *, struct parse_cur *);
-static int p_insint(struct parse_ctx *, int, size_t);
-static int p_inslit(struct parse_ctx *, int);
-static int p_insnum(struct parse_ctx *, uint32_t);
-static int p_insoblstr(struct parse_ctx *, uint32_t);
-static int p_insstr(struct parse_ctx *, int, const char *, uint32_t);
-static int p_beg(struct parse_ctx *, struct parse_cur *, int);
-static int p_end(struct parse_ctx *, struct parse_cur *);
-static int p_rwd(struct parse_ctx *, struct parse_cur *);
-static int p_opt(struct parse_ctx *);
-static int p_list(struct parse_ctx *, parsefn *);
-static int p_listsep(struct parse_ctx *, parsefn *, int);
-static int p_rep(struct parse_ctx *, parsefn *);
-static int p_repchr(struct parse_ctx *, const char *, size_t, int);
-static int p_2xcombo(struct parse_ctx *, int, parsefn *);
-static int p_3xcombo(struct parse_ctx *, int, int, parsefn *);
-static int p_r3xcombo(struct parse_ctx *, parsefn *, int, int);
-static int p_sss(struct parse_ctx *);
-
-static int p_addr(struct parse_ctx *);
-static int p_astr(struct parse_ctx *);
-static int p_atom(struct parse_ctx *);
-static int p_authtype(struct parse_ctx *);
-static int p_badcscode(struct parse_ctx *);
-static int p_badcsopt(struct parse_ctx *);
-static int p_base64(struct parse_ctx *);
-static int p_body(struct parse_ctx *);
-static int p_body1pt(struct parse_ctx *);
-static int p_bodybas(struct parse_ctx *);
-static int p_bodyext(struct parse_ctx *);
-static int p_bodyf(struct parse_ctx *);
-static int p_bodyfdes(struct parse_ctx *);
-static int p_bodyfdsp(struct parse_ctx *);
-static int p_bodyfenc(struct parse_ctx *);
-static int p_bodyfid(struct parse_ctx *);
-static int p_bodyflan(struct parse_ctx *);
-static int p_bodyflin(struct parse_ctx *);
-static int p_bodyfloc(struct parse_ctx *);
-static int p_bodyfmd5(struct parse_ctx *);
-static int p_bodyfoct(struct parse_ctx *);
-static int p_bodyfpar(struct parse_ctx *);
-static int p_bodympt(struct parse_ctx *);
-static int p_bodymsg(struct parse_ctx *);
-static int p_bodytxt(struct parse_ctx *);
-static int p_bodyx1pt(struct parse_ctx *);
-static int p_bodyxcmn(struct parse_ctx *);
-static int p_bodyxmpt(struct parse_ctx *);
-static int p_cap(struct parse_ctx *);
-static int p_capdata(struct parse_ctx *);
-static int p_contreq(struct parse_ctx *);
-static int p_datetime(struct parse_ctx *);
-static int p_dayfix(struct parse_ctx *);
-static int p_dig(struct parse_ctx *, size_t);
-static int p_dquotedchar(struct parse_ctx *);
-static int p_env(struct parse_ctx *);
-static int p_envaddr(struct parse_ctx *, int);
-static int p_envbcc(struct parse_ctx *);
-static int p_envcc(struct parse_ctx *);
-static int p_envdate(struct parse_ctx *);
-static int p_envfrom(struct parse_ctx *);
-static int p_envinrepto(struct parse_ctx *);
-static int p_envmsgid(struct parse_ctx *);
-static int p_envrepto(struct parse_ctx *);
-static int p_envsender(struct parse_ctx *);
-static int p_envsubj(struct parse_ctx *);
-static int p_envto(struct parse_ctx *);
-static int p_fetchrec(struct parse_ctx *);
-static int p_flag(struct parse_ctx *);
-static int p_flext(struct parse_ctx *);
-static int p_flfetch(struct parse_ctx *);
-static int p_flkeyword(struct parse_ctx *);
-static int p_gencode(struct parse_ctx *);
-static int p_genctext(struct parse_ctx *);
-static int p_hdrfname(struct parse_ctx *);
-static int p_hdrlist(struct parse_ctx *);
-static int p_lit(struct parse_ctx *, int);
-static int p_lstr(struct parse_ctx *);
-static int p_mailbox(struct parse_ctx *);
-static int p_matbody(struct parse_ctx *);
-static int p_matbsect(struct parse_ctx *);
-static int p_matenv(struct parse_ctx *);
-static int p_mathdrotxt(struct parse_ctx *);
-static int p_matintdate(struct parse_ctx *);
-static int p_matsize(struct parse_ctx *);
-static int p_matuid(struct parse_ctx *);
-static int p_mbdata(struct parse_ctx *);
-static int p_mbexists(struct parse_ctx *);
-static int p_mbflags(struct parse_ctx *);
-static int p_mblist(struct parse_ctx *);
-static int p_mblistdata(struct parse_ctx *);
-static int p_mblistfl(struct parse_ctx *);
-static int p_mblistofl(struct parse_ctx *);
-static int p_mblistosfl(struct parse_ctx *);
-static int p_mblistsfl(struct parse_ctx *);
-static int p_mblsub(struct parse_ctx *);
-static int p_mbrecent(struct parse_ctx *);
-static int p_mbsearch(struct parse_ctx *);
-static int p_mbstatus(struct parse_ctx *);
-static int p_medbas(struct parse_ctx *);
-static int p_medmsg(struct parse_ctx *);
-static int p_medsubt(struct parse_ctx *);
-static int p_medtxt(struct parse_ctx *);
-static int p_month(struct parse_ctx *);
-static int p_msgdata(struct parse_ctx *);
-static int p_msgatt(struct parse_ctx *);
-static int p_msgattdyn(struct parse_ctx *);
-static int p_msgattstat(struct parse_ctx *);
-static int p_nstr(struct parse_ctx *);
-static int p_num(struct parse_ctx *);
-static int p_nznum(struct parse_ctx *);
-static int p_permfl(struct parse_ctx *);
-static int p_permflcode(struct parse_ctx *);
-static int p_qchar(struct parse_ctx *);
-static int p_qchars(struct parse_ctx *);
-static int p_qstr(struct parse_ctx *);
-static int p_respbye(struct parse_ctx *);
-static int p_respdata(struct parse_ctx *);
-static int p_respln(struct parse_ctx *);
-static int p_respstate(struct parse_ctx *);
-static int p_resptext(struct parse_ctx *);
-static int p_resptextcode(struct parse_ctx *);
-static int p_secmsgtxt(struct parse_ctx *);
-static int p_secpt(struct parse_ctx *);
-static int p_secspec(struct parse_ctx *);
-static int p_section(struct parse_ctx *);
-static int p_sectxt(struct parse_ctx *);
-static int p_statt(struct parse_ctx *);
-static int p_stattrec(struct parse_ctx *);
-static int p_str(struct parse_ctx *);
-static int p_tag(struct parse_ctx *);
-static int p_taggedresp(struct parse_ctx *);
-static int p_text(struct parse_ctx *);
-static int p_time(struct parse_ctx *);
-static int p_uid(struct parse_ctx *);
-static int p_uidncode(struct parse_ctx *);
-static int p_uidvcode(struct parse_ctx *);
-static int p_unseencode(struct parse_ctx *);
-static int p_year(struct parse_ctx *);
-static int p_zone(struct parse_ctx *);
-
-static int p_cpar(struct parse_ctx *);
-static int p_dquote(struct parse_ctx *);
-static int p_opar(struct parse_ctx *);
-static int p_sp(struct parse_ctx *);
-
-int
-parse_respln(const char *tok, size_t toklen, union parse_node *pt,
-    size_t ptlen, size_t oblth)
-{
-	struct parse_ctx p = { { tok, pt}, tok, tok + toklen, toklen,
-	    pt, pt + ptlen, ptlen, 0, oblth };
-
-	p_respln(&p);
-	return p.e;
-}
-
-int
-cmpchr(const void *a, const void *b)
-{
-	return *(char *)a - *(char *)b;
-}
-
-int
-contains(const char *s, size_t slen, char c)
-{
-	return bsearch(&c, s, slen, sizeof(char), cmpchr) != 0;
-}
-
-/*
-  Combinators and misc meta critters
-*/
-
-int
-p_chk(struct parse_ctx *p, struct parse_cur *cp)
-{
-	*cp = p->cur;
-	return 1;
-}
-
-int
-p_insint(struct parse_ctx *p, int prod, size_t len)
-{
-	union parse_node *cur;
-
-	cur = p->cur.pt;
-	if (cur == p->ptend) {
-		p->e = PE_NOTENNODES;
-		return 0;
-	}
-	cur->inter.type = PN_INTER;
-	cur->inter.prod = prod;
-	cur->inter.len = len;
-	p->e = PE_OK;
-	p->cur.pt++;
-	return 1;
-}
-
-int
-p_inslit(struct parse_ctx *p, int val)
-{
-	union parse_node *cur;
-
-	cur = p->cur.pt;
-	if (cur == p->ptend) {
-		p->e = PE_NOTENNODES;
-		return 0;
-	}
-	cur->lit.type = PN_LIT;
-	cur->lit.val = val;
-	p->e = PE_OK;
-	p->cur.pt++;
-	return 1;
-}
-
-int
-p_insnum(struct parse_ctx *p, uint32_t val)
-{
-	union parse_node *cur;
-
-	cur = p->cur.pt;
-	if (cur == p->ptend) {
-		p->e = PE_NOTENNODES;
-		return 0;
-	}
-	cur->lit.type = PN_NUM;
-	cur->lit.val = val;
-	p->e = PE_OK;
-	p->cur.pt++;
-	return 1;
-}
-
-int
-p_insoblstr(struct parse_ctx *p, uint32_t len)
-{
-	union parse_node *cur;
-
-	cur = p->cur.pt;
-	if (cur == p->ptend) {
-		p->e = PE_NOTENNODES;
-		return 0;
-	}
-	cur->str.type = PN_OBLSTR;
-	cur->str.len = len;
-	cur->str.iob = 0;
-	p->e = PE_OK;
-	p->cur.pt++;
-	return 1;
-}
-
-int
-p_insstr(struct parse_ctx *p, int type, const char *tok, uint32_t len)
-{
-	union parse_node *cur;
-
-	cur = p->cur.pt;
-	if (cur == p->ptend) {
-		p->e = PE_NOTENNODES;
-		return 0;
-	}
-	cur->str.type = type;
-	cur->str.len = len;
-	cur->str.tok = tok;
-	p->e = PE_OK;
-	p->cur.pt++;
-	return 1;
-}
-
-int
-p_beg(struct parse_ctx *p, struct parse_cur *beg, int prod)
-{
-	return p_chk(p, beg) && p_insint(p, prod, 0);
-}
-
-int
-p_end(struct parse_ctx *p, struct parse_cur *beg)
-{
-	beg->pt->inter.len = p->cur.pt - beg->pt - 1;
-	p->e = PE_OK;
-	return 1;
-}
-
-int
-p_rwd(struct parse_ctx *p, struct parse_cur *cp)
-{
-	p->cur = *cp;
-	if (!p->e)
-		p->e = PE_PARSE;
-
-	return 0;
-}
-
-int
-p_opt(struct parse_ctx *p)
-{
-	if (p->e == PE_PARSE)
-		p->e = PE_OK;
-
-	return !p->e;
-}
-
-/* prod *(SP prod) */
-int
-p_list(struct parse_ctx *p, parsefn *prod)
-{
-	int res;
-
-	for (res = prod(p); res && p_2xcombo(p, IL_SP, prod);)
-		;
-	return res && p_opt(p);
-}
-
-int
-p_listsep(struct parse_ctx *p, parsefn *prod, int sep)
-{
-	int res;
-
-	for(res = prod(p); res && p_2xcombo(p, sep, prod);)
-		;
-	return res && p_opt(p);
-}
-
-/* 1*prod */
-int
-p_rep(struct parse_ctx *p, parsefn *prod)
-{
-	int res;
-
-	for (res = prod(p); res && prod(p);)
-		;
-	return res && p_opt(p);
-}
-
-/* 1*<any char but those in `except'> */
-int
-p_repchr(struct parse_ctx *p, const char *except, size_t elen, int strtype)
-{
-	const char *t;
-	size_t len;
-
-	t = p->cur.tok;
-	while (t != p->tokend && !contains(except, elen, *t))
-		t++;
-
-	len = t - p->cur.tok;
-	if (len == 0) {
-		p->e = PE_PARSE;
-		goto exit;
-	} else if (len > UINT32_MAX) {
-		p->e = PE_STRTOOBIG;
-		goto exit;
-	}
-	if (!p_insstr(p, strtype, p->cur.tok, (uint32_t)len))
-		goto exit;
-
-	p->cur.tok = t;
-	p->e = PE_OK;
-
- exit:
-	return !p->e;
-}
-
-int
-p_2xcombo(struct parse_ctx *p, int lit, parsefn *prod)
-{
-	struct parse_cur b;
-
-	return p_chk(p, &b) && p_lit(p, lit) && prod(p) || p_rwd(p, &b);
-}
-
-int
-p_3xcombo(struct parse_ctx *p, int lit1, int lit2, parsefn *prod)
-{
-	struct parse_cur b;
-
-	return p_chk(p, &b) && p_lit(p, lit1) &&
-	    p_lit(p, lit2) && prod(p) || p_rwd(p, &b);
-}
-
-int
-p_r3xcombo(struct parse_ctx *p, parsefn *prod, int lit1, int lit2)
-{
-	struct parse_cur b;
-
-	return p_chk(p, &b) && prod(p) && p_lit(p, lit1) &&
-	    p_lit(p, lit2) || p_rwd(p, &b);
-}
-
-int
-p_sss(struct parse_ctx *p)
-{
-	struct parse_cur b;
-
-	return p_chk(p, &b) && p_str(p) && p_sp(p) && p_str(p) ||
-	    p_rwd(p, &b);
-}
-
-/*
-  IMAP parsers
-*/
-
-int
-p_addr(struct parse_ctx *p)
-{
-	struct parse_cur b;
-
-	return p_chk(p, &b) && p_opar(p) && p_nstr(p) && p_sp(p) &&
-	    p_nstr(p) && p_sp(p) && p_nstr(p) && p_sp(p) &&
-	    p_nstr(p) && p_cpar(p) || p_rwd(p, &b);
-}
-
-int
-p_astr(struct parse_ctx *p)
-{
-	struct parse_cur b;
-
-	return p_beg(p, &b, IP_ASTR) &&
-	    (p_repchr(p, astr_specials, LEN(astr_specials), PN_STR) ||
-	    p_str(p)) && p_end(p, &b) || p_rwd(p, &b);
-}
-
-int
-p_atom(struct parse_ctx *p)
-{
-	struct parse_cur b;
-
-	return p_beg(p, &b, IP_ATOM) &&
-	    p_repchr(p, atom_specials, LEN(atom_specials), PN_STR) &&
-	    p_end(p, &b) || p_rwd(p, &b);
-}
-
-int
-p_authtype(struct parse_ctx *p)
-{
-	return p_atom(p);
-}
-
-int
-p_badcscode(struct parse_ctx *p)
-{
-	struct parse_cur b;
-
-	return p_chk(p, &b) && p_lit(p, IL_BADCS) &&
-	    (p_badcsopt(p) || p_opt(p)) || p_rwd(p, &b);
-}
-
-int
-p_badcsopt(struct parse_ctx *p)
-{
-	struct parse_cur b;
-
-	return p_chk(p, &b) && p_sp(p) && p_opar(p) &&
-	    p_list(p, p_astr) && p_cpar(p) || p_rwd(p, &b);
-}
-
-int
-p_base64(struct parse_ctx *p)
-{
-	/* you won't get far w/o b64 */
-}
-
-int
-p_body(struct parse_ctx *p)
-{
-	struct parse_cur b;
-
-	return p_chk(p, &b) && p_opar(p) && (p_body1pt(p) ||
-	    p_bodympt(p)) && p_cpar(p) || p_rwd(p, &b);
-}
-
-int
-p_body1pt(struct parse_ctx *p)
-{
-	struct parse_cur b, o;
-
-	return p_chk(p, &b) &&
-	    (p_bodybas(p) || p_bodymsg(p) || p_bodytxt(p)) &&
-	    (p_chk(p, &o) && p_sp(p) && p_bodyx1pt(p) ||
-	    p_rwd(p, &o) || p_opt(p)) || p_rwd(p, &b);
-}
-
-int
-p_bodybas(struct parse_ctx *p)
-{
-	struct parse_cur b;
-
-	return p_chk(p, &b) && p_medbas(p) && p_sp(p) &&
-	    p_bodyf(p) || p_rwd(p, &b);
-}
-
-int
-p_bodyext(struct parse_ctx *p)
-{
-	struct parse_cur b;
-
-	return p_chk(p, &b) && p_nstr(p) || p_num(p) ||
-	    (p_opar(p) && p_list(p, p_bodyext) && p_cpar(p)) ||
-	    p_rwd(p, &b);
-}
-
-int
-p_bodyf(struct parse_ctx *p)
-{
-	struct parse_cur b;
-
-	return p_chk(p, &b) && p_bodyfpar(p) && p_sp(p) &&
-	    p_bodyfid(p) && p_sp(p) && p_bodyfdes(p) && p_sp(p) &&
-	    p_bodyfenc(p) && p_sp(p) && p_bodyfoct(p) || p_rwd(p, &b);
-}
-
-int
-p_bodyfdes(struct parse_ctx *p)
-{
-	return p_nstr(p);
-}
-
-int
-p_bodyfdsp(struct parse_ctx *p)
-{
-	struct parse_cur b;
-
-	return p_chk(p, &b) && (p_opar(p) && p_str(p) && p_sp(p) &&
-	    p_bodyfpar(p) && p_cpar(p) || p_rwd(p, &b)) || p_lit(p, IL_NIL);
-}
-
-int
-p_bodyfenc(struct parse_ctx *p)
-{
-	struct parse_cur b;
-
-	return p_chk(p, &b) && (p_dquote(p) && (p_lit(p, IL_7BIT) ||
-	    p_lit(p, IL_8BIT) || p_lit(p, IL_BIN) || p_lit(p, IL_B64) ||
-	    p_lit(p, IL_QPRN)) && p_dquote(p) || p_rwd(p, &b)) ||
-	    p_str(p);
-}
-
-int
-p_bodyfid(struct parse_ctx *p)
-{
-	return p_nstr(p);
-}
-
-int
-p_bodyflan(struct parse_ctx *p)
-{
-	struct parse_cur b;
-
-	return p_chk(p, &b) && p_nstr(p) || (p_opar(p) &&
-	    p_list(p, p_str) && p_cpar(p) || p_rwd(p, &b));
-}
-
-int
-p_bodyflin(struct parse_ctx *p)
-{
-	return p_num(p);
-}
-
-int
-p_bodyfloc(struct parse_ctx *p)
-{
-	return p_nstr(p);
-}
-
-int
-p_bodyfmd5(struct parse_ctx *p)
-{
-	return p_nstr(p);
-}
-
-int
-p_bodyfoct(struct parse_ctx *p)
-{
-	return p_num(p);
-}
-
-int
-p_bodyfpar(struct parse_ctx *p)
-{
-	struct parse_cur b;
-
-	return p_chk(p, &b) && (p_opar(p) && p_list(p, p_sss) &&
-	    p_cpar(p) || p_rwd(p, &b)) || p_lit(p, IL_NIL);
-}
-
-int
-p_bodympt(struct parse_ctx *p)
-{
-	struct parse_cur b, o;
-
-	return p_chk(p, &b) && p_rep(p, p_body) && p_sp(p) &&
-	    p_medsubt(p) && (p_chk(p, &o) && p_sp(p) && p_bodyxmpt(p) ||
-	    p_rwd(p, &o) || p_opt(p)) || p_rwd(p, &b);
-}
-
-int
-p_bodymsg(struct parse_ctx *p)
-{
-	struct parse_cur b;
-
-	return p_chk(p, &b) && p_medmsg(p) && p_sp(p) && p_bodyf(p) &&
-	    p_sp(p) && p_env(p) && p_sp(p) && p_body(p) && p_sp(p) &&
-	    p_bodyflin(p) || p_rwd(p, &b);
-}
-
-int
-p_bodytxt(struct parse_ctx *p)
-{
-	struct parse_cur b;
-
-	return p_chk(p, &b) && p_medtxt(p) && p_sp(p) && p_bodyf(p) &&
-	    p_sp(p) && p_bodyflin(p) || p_rwd(p, &b);
-}
-
-int
-p_bodyx1pt(struct parse_ctx *p)
-{
-	struct parse_cur b;
-
-	return p_chk(p, &b) && p_bodyfmd5(p) &&
-	    p_bodyxcmn(p) || p_rwd(p, &b);
-}
-
-/* TODO: this one's extra gross, prob needs a good factoring */
-int
-p_bodyxcmn(struct parse_ctx *p)
-{
-	struct parse_cur o1, o2, o3, o4;
-
-	return p_chk(p, &o1) && p_sp(p) && p_bodyfdsp(p) &&
-	    (p_chk(p, &o2) && p_sp(p) && p_bodyflan(p) &&
-	    (p_chk(p, &o3) && p_sp(p) && p_bodyfloc(p) &&
-	    (p_chk(p, &o4) && p_sp(p) && p_list(p, p_bodyext) ||
-	    p_rwd(p, &o4) || p_opt(p)) ||
-	    p_rwd(p, &o3) || p_opt(p)) ||
-	    p_rwd(p, &o2) || p_opt(p)) ||
-	    p_rwd(p, &o1) || p_opt(p);
-}
-
-int
-p_bodyxmpt(struct parse_ctx *p)
-{
-	struct parse_cur b;
-
-	return p_chk(p, &b) && p_bodyfpar(p) &&
-	    p_bodyxcmn(p) || p_rwd(p, &b);
-}
-
-int
-p_cap(struct parse_ctx *p)
-{
-	struct parse_cur b;
-
-	return p_beg(p, &b, IP_CAP) && p_sp(p) &&
-	    (p_2xcombo(p, IL_AUTHEQ, p_authtype) || p_atom(p)) &&
-	    p_end(p, &b) || p_rwd(p, &b);
-}
-
-int
-p_capdata(struct parse_ctx *p)
-{
-	struct parse_cur b;
-
-	return p_chk(p, &b) && p_lit(p, IL_CAP) &&
-	    p_rep(p, p_cap) || p_rwd(p, &b);
-}
-
-int
-p_contreq(struct parse_ctx *p)
-{
-	struct parse_cur b;
-
-	return p_chk(p, &b) &&
-	    p_lit(p, IL_PLUS) && p_sp(p) &&
-	    (p_resptext(p) || p_base64(p)) &&
-	    p_lit(p, IL_EOL) || p_rwd(p, &b);
-}
-
-int
-p_datetime(struct parse_ctx *p)
-{
-	struct parse_cur b;
-
-	return p_chk(p, &b) && p_dquote(p) && p_dayfix(p) &&
-	    p_lit(p, IL_MINUS) && p_month(p) && p_lit(p, IL_MINUS) &&
-	    p_year(p) && p_sp(p) && p_time(p) && p_sp(p) && p_zone(p) &&
-	    p_dquote(p) || p_rwd(p, &b);
-}
-
-int
-p_dayfix(struct parse_ctx *p)
-{
-	struct parse_cur b;
-
-	return p_chk(p, &b) && p_sp(p) && p_dig(p, 1) ||
-	    p_rwd(p, &b) || p_dig(p, 2);
-}
-
-int
-p_dig(struct parse_ctx *p, size_t count)
-{
-	uint32_t n, prev;
-	const char *t;
-
-	prev = n = 0;
-	t = p->cur.tok;
-
-	while (t != p->tokend && count && *t >= '0' && *t <= '9') {
-		prev = n;
-		n = UINT32_MAX & (10 * n + (*t - 48));
-		if (prev > n) {
-			p->e = PE_PARSE;
-			goto exit;
-		}
-		t++;
-		count--;
-	}
-	if (t == p->cur.tok || count != 0) {
-		p->e = PE_PARSE;
-	} else if (p_insnum(p, n)) {
-		p->cur.tok = t;
-		p->e = PE_OK;
-	}
- exit:
-	return !p->e;
-}
-
-int
-p_dquotedchar(struct parse_ctx *p)
-{
-	struct parse_cur b;
-
-	return p_chk(p, &b) && p_dquote(p) && p_qchar(p) && p_dquote(p) ||
-	    p_rwd(p, &b);
-}
-
-int
-p_env(struct parse_ctx *p)
-{
-	struct parse_cur b;
-
-	return p_chk(p, &b) && p_opar(p) && p_envdate(p) && p_sp(p) &&
-	    p_envsubj(p) && p_sp(p) && p_envfrom(p) && p_sp(p) &&
-	    p_envsender(p) && p_sp(p) && p_envrepto(p) && p_sp(p) &&
-	    p_envto(p) && p_sp(p) && p_envcc(p) && p_sp(p) &&
-	    p_envbcc(p) && p_sp(p) && p_envinrepto(p) && p_sp(p) &&
-	    p_envmsgid(p) && p_cpar(p) || p_rwd(p, &b);
-}
-
-int
-p_envaddr(struct parse_ctx *p, int prod)
-{
-	struct parse_cur b;
-
-	return p_beg(p, &b, prod) &&
-	    (p_opar(p) && p_rep(p, p_addr) && p_cpar(p) ||
-	    p_rwd(p, &b) || p_lit(p, IL_NIL)) && p_end(p, &b);
-}
-
-int
-p_envbcc(struct parse_ctx *p)
-{
-	return p_envaddr(p, IP_ENVBCC);
-}
-
-int
-p_envcc(struct parse_ctx *p)
-{
-	return p_envaddr(p, IP_ENVCC);
-}
-
-int
-p_envdate(struct parse_ctx *p)
-{
-	return p_nstr(p);
-}
-
-int
-p_envfrom(struct parse_ctx *p)
-{
-	return p_envaddr(p, IP_ENVFROM);
-}
-
-int
-p_envinrepto(struct parse_ctx *p)
-{
-	return p_nstr(p);
-}
-
-int
-p_envmsgid(struct parse_ctx *p)
-{
-	return p_nstr(p);
-}
-
-int
-p_envrepto(struct parse_ctx *p)
-{
-	return p_envaddr(p, IP_ENVREPTO);
-}
-
-int
-p_envsender(struct parse_ctx *p)
-{
-	return p_envaddr(p, IP_ENVSENDER);
-}
-
-int
-p_envsubj(struct parse_ctx *p)
-{
-	return p_nstr(p);
-}
-
-int
-p_envto(struct parse_ctx *p)
-{
-	return p_envaddr(p, IP_ENVTO);
-}
-
-int
-p_fetchrec(struct parse_ctx *p)
-{
-	struct parse_cur b;
-
-	return p_chk(p, &b) && p_lit(p, IL_FETCH) && p_sp(p) &&
-	    p_opar(p) && p_list(p, p_msgatt) && p_cpar(p) || p_rwd(p, &b);
-}
-
-int
-p_flag(struct parse_ctx *p)
-{
-	return p_lit(p, IL_FLANSWERED) || p_lit(p, IL_FLFLAGGED) ||
-	    p_lit(p, IL_FLDELETED) || p_lit(p, IL_FLSEEN) ||
-	    p_lit(p, IL_FLDRAFT) || p_flkeyword(p) ||
-	    p_flext(p);
-}
-
-int
-p_flext(struct parse_ctx *p)
-{
-	struct parse_cur b;
-
-	return p_chk(p, &b) && p_lit(p, IL_BSLASH) &&
-	    p_atom(p) || p_rwd(p, &b);
-}
-
-int
-p_flfetch(struct parse_ctx *p)
-{
-	return p_flag(p) || p_lit(p, IL_FLRECENT);
-}
-
-int
-p_flkeyword(struct parse_ctx *p)
-{
-	return p_atom(p);
-}
-
-int
-p_gencode(struct parse_ctx *p)
-{
-	struct parse_cur opt;
-
-	return p_atom(p) && (p_chk(p, &opt) &&
-	    p_sp(p) && p_genctext(p) ||
-	    p_rwd(p, &opt) || p_opt(p));
-}
-
-int
-p_genctext(struct parse_ctx *p)
-{
-	int res;
-	const char *t;
-
-	t = p->cur.tok;
-
-	while (t != p->tokend && *t >= '\1' && *t <= '\x7f' &&
-	    *t != ']' && *t != '\r' && *t != '\n')
-		t++;
-
-	res = t > p->cur.tok;
-	if (res)
-		p->cur.tok = t;
-
-	p->e = !res;
-	return res;
-}
-
-int
-p_hdrfname(struct parse_ctx *p)
-{
-	return p_astr(p);
-}
-
-int
-p_hdrlist(struct parse_ctx *p)
-{
-	struct parse_cur b;
-
-	return p_chk(p, &b) && p_opar(p) && p_list(p, p_hdrfname) &&
-	    p_cpar(p) || p_rwd(p, &b);
-}
-
-int
-p_lit(struct parse_ctx *p, int val)
-{
-	size_t left;
-	struct literal *lit;
-
-	left = p->tokend - p->cur.tok;
-	lit = literals + val;
-
-	if (left < lit->slen) {
-		p->e = PE_PARSE;
-		goto exit;
-	}
-	if (strncasecmp(p->cur.tok, lit->srep, lit->slen) == 0) {
-		if (p_inslit(p, val)) {
-			p->cur.tok += lit->slen;
-			p->e = PE_OK;
-		}
-	} else {
-		p->e = PE_PARSE;
-	}
- exit:
-	return !p->e;
-}
-
-int
-p_lstr(struct parse_ctx *p)
-{
-	int res;
-	size_t len;
-	struct parse_cur b, n;
-
-	res = p_chk(p, &b) && p_lit(p, IL_OBRACE) &&
-	    p_chk(p, &n) && p_num(p) && p_lit(p, IL_CBRACE) &&
-	    p_lit(p, IL_EOL) || p_rwd(p, &b);
-
-	if (res) {
-		len = n.pt->num.val;
-		if (len > UINT32_MAX) {
-			p->e = PE_STRTOOBIG;
-			res = 0;
-		} else if (len < p->oblth) {
-			res = p_insstr(p, PN_LSTR, p->cur.tok, (uint32_t)len);
-			if (res)
-				p->cur.tok += len;
-		} else {
-			res = p_insoblstr(p, (uint32_t)len);
-		}
-	}
-	return res;
-}
-
-int
-p_mailbox(struct parse_ctx *p)
-{
-	return p_lit(p, IL_INBOX) || p_astr(p);
-}
-
-int
-p_matbody(struct parse_ctx *p)
-{
-	struct parse_cur b;
-
-	return p_chk(p, &b) && p_lit(p, IL_BODY) &&
-	    (p_lit(p, IL_STRUCT) || p_opt(p)) && p_sp(p) &&
-	    p_body(p) || p_rwd(p, &b);
-}
-
-int
-p_matbsect(struct parse_ctx *p)
-{
-	struct parse_cur b, o;
-
-	return p_chk(p, &b) && p_lit(p, IL_BODY) && p_section(p) &&
-	    (p_chk(p, &o) && p_lit(p, IL_LT) && p_num(p) && p_lit(p, IL_GT) ||
-	    p_rwd(p, &o) || p_opt(p)) && p_sp(p) && p_nstr(p) || p_rwd(p, &b);
-}
-
-int
-p_matenv(struct parse_ctx *p)
-{
-	return p_3xcombo(p, IL_ENVELOPE, IL_SP, p_env);
-}
-
-int
-p_mathdrotxt(struct parse_ctx *p)
-{
-	struct parse_cur b, o;
-
-	return p_chk(p, &b) && p_lit(p, IL_RFC822) &&
-	    (p_chk(p, &o) && p_lit(p, IL_DHDR) || p_lit(p, IL_DTXT) ||
-	    p_rwd(p, &o) || p_opt(p)) && p_sp(p) && p_nstr(p) ||
-	    p_rwd(p, &b);
-}
-
-int
-p_matintdate(struct parse_ctx *p)
-{
-	return p_3xcombo(p, IL_INTDATE, IL_SP, p_datetime);
-}
-
-int
-p_matsize(struct parse_ctx *p)
-{
-	return p_3xcombo(p, IL_RFC822SIZE, IL_SP, p_num);
-}
-
-int
-p_matuid(struct parse_ctx *p)
-{
-	return p_3xcombo(p, IL_UID, IL_SP, p_uid);
-}
-
-int
-p_mbdata(struct parse_ctx *p)
-{
-	return p_mbflags(p) || p_mblist(p) ||
-	    p_mblsub(p) || p_mbsearch(p) ||
-	    p_mbstatus(p) || p_mbexists(p) ||
-	    p_mbrecent(p);
-}
-
-int
-p_mbexists(struct parse_ctx *p)
-{
-	return p_r3xcombo(p, p_num, IL_SP, IL_EXISTS);
-}
-
-int
-p_mbflags(struct parse_ctx *p)
-{
-	struct parse_cur b;
-
-	return p_chk(p, &b) && p_lit(p, IL_FLAGS) &&
-	    p_sp(p) && p_opar(p) &&
-	    (p_list(p, p_flag) || p_opt(p)) &&
-	    p_cpar(p) || p_rwd(p, &b);
-}
-
-int
-p_mblist(struct parse_ctx *p)
-{
-	struct parse_cur b;
-
-	return p_chk(p, &b) && p_lit(p, IL_LIST) &&
-	    p_sp(p) && p_mblistdata(p) ||
-	    p_rwd(p, &b);
-}
-
-int
-p_mblistdata(struct parse_ctx *p)
-{
-	struct parse_cur b;
-
-	return p_chk(p, &b) && p_opar(p) &&
-	    (p_list(p, p_mblistfl) || p_opt(p)) &&
-	    p_cpar(p) && p_sp(p) &&
-	    (p_dquotedchar(p) || p_lit(p, IL_NIL)) &&
-	    p_sp(p) && p_mailbox(p) || p_rwd(p, &b);
-}
-
-/*
-   TODO: will 1*(SFL|OFL) with a soundness check afterwards
-   be simpler and more readable?
-*/
-int
-p_mblistfl(struct parse_ctx *p)
-{
-	return p_mblistosfl(p) || p_list(p, p_mblistofl);
-}
-
-int
-p_mblistofl(struct parse_ctx *p)
-{
-	return p_lit(p, IL_FLNOINFERIORS) || p_flext(p);
-}
-
-int
-p_mblistosfl(struct parse_ctx *p)
-{
-	int res;
-	struct parse_cur b;
-
-	p_chk(p, &b);
-
-	res = p_list(p, p_mblistofl) &&
-	    p_sp(p) || p_rwd(p, &b) || p_opt(p);
-
-	res = res && p_mblistsfl(p);
-
-	res = res && p_chk(p, &b) && p_sp(p) &&
-	    p_list(p, p_mblistofl) || p_rwd(p, &b) || p_opt(p);
-
-	return res || p_rwd(p, &b);
-}
-
-int
-p_mblistsfl(struct parse_ctx *p)
-{
-	return p_lit(p, IL_FLNOSEL) || p_lit(p, IL_FLMARKED) ||
-	    p_lit(p, IL_FLUNMARKED);
-}
-
-int
-p_mblsub(struct parse_ctx *p)
-{
-	struct parse_cur b;
-
-	return p_chk(p, &b) && p_lit(p, IL_LSUB) &&
-	    p_sp(p) && p_mblistdata(p) ||
-	    p_rwd(p, &b);
-}
-
-int
-p_mbrecent(struct parse_ctx *p)
-{
-	return p_r3xcombo(p, p_num, IL_SP, IL_RECENT);
-}
-
-int
-p_mbsearch(struct parse_ctx *p)
-{
-	struct parse_cur b, o;
-
-	return p_chk(p, &b) && p_lit(p, IL_SEARCH) &&
-	    (p_chk(p, &o) && p_sp(p) &&
-	    p_list(p, p_nznum) || p_rwd(p, &o) || p_opt(p)) ||
-	    p_rwd(p, &b);
-}
-
-int
-p_mbstatus(struct parse_ctx *p)
-{
-	struct parse_cur b;
-
-	return p_chk(p, &b) && p_lit(p, IL_STATUS) && p_sp(p) &&
-	    p_mailbox(p) && p_sp(p) && p_opar(p) &&
-	    (p_list(p, p_stattrec) || p_opt(p)) && p_cpar(p) ||
-	    p_rwd(p, &b);
-}
-
-int
-p_medbas(struct parse_ctx *p)
-{
-	struct parse_cur b;
-
-	return p_chk(p, &b) && (p_dquote(p) &&
-	    (p_lit(p, IL_APP) || p_lit(p, IL_AUDIO) || p_lit(p, IL_IMG) ||
-	    p_lit(p, IL_MSG) || p_lit(p, IL_VIDEO)) && p_dquote(p) ||
-	    (p_rwd(p, &b) || p_str(p))) &&
-	    p_sp(p) && p_medsubt(p) || p_rwd(p, &b);
-}
-
-int
-p_medmsg(struct parse_ctx *p)
-{
-	struct parse_cur b;
-
-	return p_chk(p, &b) &&
-	    p_dquote(p) && p_lit(p, IL_MSG) && p_dquote(p) && p_sp(p) &&
-	    p_dquote(p) && p_lit(p, IL_RFC822) && p_dquote(p) || p_rwd(p, &b);
-}
-
-int
-p_medsubt(struct parse_ctx *p)
-{
-	return p_str(p);
-}
-
-int
-p_medtxt(struct parse_ctx *p)
-{
-	struct parse_cur b;
-
-	return p_chk(p, &b) && p_dquote(p) && p_lit(p, IL_TXT) && p_dquote(p) &&
-	    p_sp(p) && p_medsubt(p) || p_rwd(p, &b);
-}
-
-int
-p_month(struct parse_ctx *p)
-{
-	return p_lit(p, IL_JAN) || p_lit(p, IL_FEB) || p_lit(p, IL_MAR) ||
-	    p_lit(p, IL_APR) || p_lit(p, IL_MAY) || p_lit(p, IL_JUN) ||
-	    p_lit(p, IL_JUL) || p_lit(p, IL_AUG) || p_lit(p, IL_SEP) ||
-	    p_lit(p, IL_OCT) || p_lit(p, IL_NOV) || p_lit(p, IL_DEC);
-}
-
-int
-p_msgdata(struct parse_ctx *p)
-{
-	struct parse_cur b;
-
-	return p_chk(p, &b) && p_nznum(p) && p_sp(p) &&
-	    (p_lit(p, IL_EXPUNGE) || p_fetchrec(p)) || p_rwd(p, &b);
-}
-
-int
-p_msgatt(struct parse_ctx *p)
-{
-	return p_msgattstat(p) || p_msgattdyn(p);
-}
-
-int
-p_msgattdyn(struct parse_ctx *p)
-{
-	struct parse_cur b;
-
-	return p_chk(p, &b) && p_lit(p, IL_FLAGS) && p_sp(p) && p_opar(p) &&
-	    (p_list(p, p_flfetch) || p_opt(p)) && p_cpar(p) || p_rwd(p, &b);
-}
-
-int
-p_msgattstat(struct parse_ctx *p)
-{
-	return p_matenv(p) || p_matintdate(p) || p_mathdrotxt(p) ||
-	    p_matsize(p) || p_matbody(p) || p_matbsect(p) || p_matuid(p);
-}
-
-int
-p_nstr(struct parse_ctx *p)
-{
-	return p_str(p) || p_lit(p, IL_NIL);
-}
-
-int
-p_num(struct parse_ctx *p)
-{
-	uint32_t n, prev;
-	const char *t;
-
-	prev = n = 0;
-	t = p->cur.tok;
-
-	while (t != p->tokend && *t >= '0' && *t <= '9') {
-		prev = n;
-		n = UINT32_MAX & (10 * n + (*t - 48));
-		if (prev > n) {
-			p->e = PE_PARSE;
-			goto exit;
-		}
-		t++;
-	}
-	if (t == p->cur.tok) {
-		p->e = PE_PARSE;
-	} else if (p_insnum(p, n)) {
-		p->cur.tok = t;
-		p->e = PE_OK;
-	}
- exit:
-	return !p->e;
-}
-
-int
-p_nznum(struct parse_ctx *p)
-{
-	const char *t;
-
-	t = p->cur.tok;
-
-	if (t == p->tokend || *t < '1' || *t > '9') {
-		p->e = PE_PARSE;
-		goto exit;
-	}
-	p_num(p);
- exit:
-	return !p->e;
-}
-
-int
-p_permfl(struct parse_ctx *p)
-{
-	return p_flag(p) || p_lit(p, IL_FLANY);
-}
-
-int
-p_permflcode(struct parse_ctx *p)
-{
-	struct parse_cur b;
-
-	return p_chk(p, &b) && p_lit(p, IL_PERMFL) &&
-	    p_sp(p) && p_opar(p) &&
-	    (p_list(p, p_permfl) || p_opt(p)) &&
-	    p_cpar(p) || p_rwd(p, &b);
-}
-
-int
-p_qchar(struct parse_ctx *p)
-{
-	const char *t;
-	int len;
-	size_t left;
-
-	t = p->cur.tok;
-	left = p->tokend - p->cur.tok;
-
-	if (t == p->tokend) {
-		p->e = PE_PARSE;
-		goto exit;
-	}
-	if (*t >= '\1' && *t <= '\x7f' && *t != '\r' &&
-	    *t != '\n' && *t != '"' && *t != '\\') {
-		len = 1;
-	} else if (left >= 2 &&
-	    (strncmp(t, "\\\"", 2) == 0 || strncmp(t, "\\\\", 2) == 0)) {
-		len = 2;
-	} else {
-		p->e = PE_PARSE;
-		goto exit;
-	}
-
-	if (!p_insstr(p, PN_QSTR, p->cur.tok, len)) {
-		p->e = PE_PARSE;
-		goto exit;
-	}
-	p->cur.tok += len;
-	p->e = PE_OK;
-
- exit:
-	return !p->e;
-}
-
-int
-p_qchars(struct parse_ctx *p)
-{
-	const char *t;
-	size_t len;
-	int esc;
-
-	t = p->cur.tok;
-	esc = 0;
-	while (t != p->tokend) {
-		if (esc) {
-			if (*t == '"' || *t == '\\') {
-				t++;
-				esc = 0;
-			} else {
-				p->e = PE_PARSE;
-				goto exit;
-			}
-		} else if (*t == '\\') {
-			t++;
-			esc = 1;
-		} else if (*t >= '\1' && *t <= '\x7f' && *t != '\r' &&
-		    *t != '\n' && *t != '"' && *t != '\\') {
-			t++;
-		} else {
-			p->e = PE_PARSE;
-			goto exit;
-		}
-	}
-	len = t - p->cur.tok;
-	if (len == 0) {
-		p->e = PE_PARSE;
-		goto exit;
-	} else if (len > UINT32_MAX) {
-		p->e = PE_STRTOOBIG;
-		goto exit;
-	} else if (!p_insstr(p, PN_QSTR, p->cur.tok, (uint32_t)len))
-		goto exit;
-
-	p->cur.tok = t;
-	p->e = PE_OK;
-
- exit:
-	return !p->e;
-}
-
-int
-p_qstr(struct parse_ctx *p)
-{
-	struct parse_cur b;
-
-	return p_chk(p, &b) && p_dquote(p) && (p_qchars(p) || p_opt(p)) &&
-	    p_dquote(p) || p_rwd(p, &b);
-}
-
-int
-p_respbye(struct parse_ctx *p)
-{
-	struct parse_cur b;
-
-	return p_chk(p, &b) && p_lit(p, IL_BYE) && p_sp(p) &&
-	    p_resptext(p) || p_rwd(p, &b);
-}
-
-int
-p_respdata(struct parse_ctx *p)
-{
-	struct parse_cur b;
-
-	return p_chk(p, &b) && p_lit(p, IL_ASTERISK) &&
-	    p_sp(p) && (p_respstate(p) ||
-	    p_respbye(p) || p_mbdata(p) || p_msgdata(p) ||
-	    p_capdata(p)) && p_lit(p, IL_EOL) || p_rwd(p, &b);
-}
-
-int
-p_respln(struct parse_ctx *p)
-{
-	return p_contreq(p) || p_respdata(p) || p_taggedresp(p);
-}
-
-int
-p_respstate(struct parse_ctx *p)
-{
-	struct parse_cur b;
-
-	return p_chk(p, &b) &&
-	    (p_lit(p, IL_OK) || p_lit(p, IL_NO) || p_lit(p, IL_BAD)) &&
-	    p_sp(p) && p_resptext(p) || p_rwd(p, &b);
-}
-
-int
-p_resptext(struct parse_ctx *p)
-{
-	int res;
-	struct parse_cur b;
-
-	res = p_chk(p, &b) && p_lit(p, IL_OBRACK) &&
-	    p_resptextcode(p) && p_lit(p, IL_CBRACK) &&
-	    p_sp(p) || p_rwd(p, &b) || p_opt(p);
-
-	return res && p_text(p);
-}
-
-int
-p_resptextcode(struct parse_ctx *p)
-{
-	return p_lit(p, IL_ALERT) || p_badcscode(p) ||
-	    p_capdata(p) || p_lit(p, IL_PARSE) ||
-	    p_permflcode(p) || p_lit(p, IL_RO) ||
-	    p_lit(p, IL_RW) || p_lit(p, IL_TRYC) ||
-	    p_uidncode(p) || p_uidvcode(p) ||
-	    p_unseencode(p) || p_gencode(p);
-}
-
-int
-p_secmsgtxt(struct parse_ctx *p)
-{
-	struct parse_cur b;
-
-	return p_chk(p, &b) && p_lit(p, IL_HDR) ||
-	    (p_lit(p, IL_HDRFIELDS) && (p_lit(p, IL_DNOT) || p_opt(p)) &&
-	    p_sp(p) && p_hdrlist(p) || p_rwd(p, &b)) || p_lit(p, IL_TXT);
-}
-
-int
-p_secpt(struct parse_ctx *p)
-{
-	return p_listsep(p, p_nznum, IL_DOT);
-}
-
-int
-p_secspec(struct parse_ctx *p)
-{
-	struct parse_cur b, o;
-
-	return p_chk(p, &b) && p_secmsgtxt(p) || (p_secpt(p) &&
-	    (p_chk(p, &o) && p_lit(p, IL_DOT) && p_sectxt(p) ||
-	    p_rwd(p, &o) || p_opt(p))) || p_rwd(p, &b);
-}
-
-int
-p_section(struct parse_ctx *p)
-{
-	struct parse_cur b;
-
-	return p_chk(p, &b) && p_lit(p, IL_OBRACK) &&
-	    (p_secspec(p) || p_opt(p)) &&
-	    p_lit(p, IL_CBRACK) || p_rwd(p, &b);
-}
-
-int
-p_sectxt(struct parse_ctx *p)
-{
-	return p_secmsgtxt(p) || p_lit(p, IL_MIME);
-}
-
-int
-p_statt(struct parse_ctx *p)
-{
-	return p_lit(p, IL_MSGS) || p_lit(p, IL_RECENT) ||
-	    p_lit(p, IL_UIDNEXT) || p_lit(p, IL_UIDVAL) ||
-	    p_lit(p, IL_UNSEEN);
-}
-
-int
-p_stattrec(struct parse_ctx *p)
-{
-	struct parse_cur b;
-
-	return p_chk(p, &b) && p_statt(p) && p_sp(p) &&
-	    p_num(p) || p_rwd(p, &b);
-}
-
-int
-p_str(struct parse_ctx *p)
-{
-	return p_qstr(p) || p_lstr(p);
-}
-
-int
-p_tag(struct parse_ctx *p)
-{
-	return p_repchr(p, tag_specials, LEN(tag_specials), PN_STR);
-}
-
-int
-p_taggedresp(struct parse_ctx *p)
-{
-	struct parse_cur b;
-
-	return p_beg(p, &b, IP_TAGGEDRESP) && (p_tag(p) && p_sp(p) &&
-	    p_respstate(p) && p_lit(p, IL_EOL) || p_rwd(p, &b)) &&
-	    p_end(p, &b);
-}
-
-int
-p_text(struct parse_ctx *p)
-{
-	const char *t;
-	size_t len;
-
-	t = p->cur.tok;
-	while (t != p->tokend && *t >= '\1' && *t <= '\x7f' &&
-	    *t != '\r' && *t != '\n')
-		t++;
-
-	len = t - p->cur.tok;
-	if (len == 0) {
-		p->e = PE_PARSE;
-		goto exit;
-	} else if (len > UINT32_MAX) {
-		p->e = PE_STRTOOBIG;
-		goto exit;
-	}
-	if (!p_insstr(p, PN_STR, p->cur.tok, (uint32_t)len))
-		goto exit;
-
-	p->cur.tok = t;
-	p->e = PE_OK;
-
- exit:
-	return !p->e;
-}
-
-int
-p_time(struct parse_ctx *p)
-{
-	struct parse_cur b;
-
-	return p_chk(p, &b) && p_dig(p, 2) && p_lit(p, IL_COLON) &&
-	    p_dig(p, 2) && p_lit(p, IL_COLON) && p_dig(p, 2) || p_rwd(p, &b);
-}
-
-int
-p_uid(struct parse_ctx *p)
-{
-	return p_nznum(p);
-}
-
-int
-p_uidncode(struct parse_ctx *p)
-{
-	return p_3xcombo(p, IL_UIDNEXT, IL_SP, p_nznum);
-}
-
-int
-p_uidvcode(struct parse_ctx *p)
-{
-	return p_3xcombo(p, IL_UIDVAL, IL_SP, p_nznum);
-}
-
-int
-p_unseencode(struct parse_ctx *p)
-{
-	return p_3xcombo(p, IL_UNSEEN, IL_SP, p_nznum);
-}
-
-int
-p_year(struct parse_ctx *p)
-{
-	return p_dig(p, 4);
-}
-
-int
-p_zone(struct parse_ctx *p)
-{
-	struct parse_cur b;
-
-	return p_chk(p, &b) &&
-	    (p_lit(p, IL_PLUS) || p_lit(p, IL_MINUS)) &&
-	    p_dig(p, 4) || p_rwd(p, &b);
-}
-
-/* shortcuts for some common literals and means
-   of imrpoving legibility of bulky productions */
-
-int
-p_cpar(struct parse_ctx *p)
-{
-	return p_lit(p, IL_CPAR);
-}
-
-int
-p_dquote(struct parse_ctx *p)
-{
-	return p_lit(p, IL_DQUOTE);
-}
-
-int
-p_opar(struct parse_ctx *p)
-{
-	return p_lit(p, IL_OPAR);
-}
-
-int
-p_sp(struct parse_ctx *p)
-{
-	return p_lit(p, IL_SP);
-}
diff --git a/parse.h b/parse.h
deleted file mode 100644
index c83ee61..0000000
--- a/parse.h
+++ /dev/null
@@ -1,139 +0,0 @@
-enum {
-	IL_7BIT,
-	IL_8BIT,
-	IL_ALERT,
-	IL_APP,
-	IL_APR,
-	IL_ASTERISK,
-	IL_AUDIO,
-	IL_AUG,
-	IL_AUTHEQ,
-	IL_B64,
-	IL_BAD,
-	IL_BADCS,
-	IL_BIN,
-	IL_BODY,
-	IL_BSLASH,
-	IL_BYE,
-	IL_CAP,
-	IL_CBRACE,
-	IL_CBRACK,
-	IL_COLON,
-	IL_CPAR,
-	IL_DEC,
-	IL_DHDR,
-	IL_DNOT,
-	IL_DOT,
-	IL_DQUOTE,
-	IL_DTXT,
-	IL_ENVELOPE,
-	IL_EOL,
-	IL_EXISTS,
-	IL_EXPUNGE,
-	IL_FEB,
-	IL_FETCH,
-	IL_FLAGS,
-	IL_FLANSWERED,
-	IL_FLANY,
-	IL_FLDELETED,
-	IL_FLDRAFT,
-	IL_FLFLAGGED,
-	IL_FLMARKED,
-	IL_FLNOINFERIORS,
-	IL_FLNOSEL,
-	IL_FLRECENT,
-	IL_FLSEEN,
-	IL_FLUNMARKED,
-	IL_GT,
-	IL_HDR,
-	IL_HDRFIELDS,
-	IL_IMG,
-	IL_INBOX,
-	IL_INTDATE,
-	IL_JAN,
-	IL_JUL,
-	IL_JUN,
-	IL_LIST,
-	IL_LSUB,
-	IL_LT,
-	IL_MAR,
-	IL_MAY,
-	IL_MIME,
-	IL_MINUS,
-	IL_MSG,
-	IL_MSGS,
-	IL_NIL,
-	IL_NO,
-	IL_NOV,
-	IL_OBRACE,
-	IL_OBRACK,
-	IL_OCT,
-	IL_OK,
-	IL_OPAR,
-	IL_PARSE,
-	IL_PERMFL,
-	IL_PLUS,
-	IL_QPRN,
-	IL_RECENT,
-	IL_RFC822,
-	IL_RFC822SIZE,
-	IL_RO,
-	IL_RW,
-	IL_SEARCH,
-	IL_SEP,
-	IL_SP,
-	IL_STATUS,
-	IL_STRUCT,
-	IL_TRYC,
-	IL_TXT,
-	IL_UID,
-	IL_UIDNEXT,
-	IL_UIDVAL,
-	IL_UNSEEN,
-	IL_VIDEO,
-};
-
-enum {
-	IP_ASTR,
-	IP_ATOM,
-	IP_CAP,
-	IP_ENVBCC,
-	IP_ENVCC,
-	IP_ENVFROM,
-	IP_ENVREPTO,
-	IP_ENVSENDER,
-	IP_ENVTO,
-	IP_TAGGEDRESP,
-};
-
-enum { PN_INTER, PN_LIT, PN_NUM, PN_STR, PN_QSTR, PN_LSTR, PN_OBLSTR };
-
-enum { PE_OK, PE_PARSE, PE_NOTENNODES, PE_STRTOOBIG };
-
-union parse_node {
-	int type;
-	struct {
-		int type;
-		int prod;
-		size_t len;
-	} inter;
-	struct {
-		int type;
-		int val;
-	} lit;
-	struct {
-		int type;
-		uint32_t val;
-	} num;
-	struct {
-		int type;
-		uint32_t len;
-		union {
-			const char *tok;
-			size_t iob;
-		};
-	} str;
-};
-
-int parse_respln(const char *tok, size_t toklen, union parse_node *pt,
-    size_t ptlen, size_t oblth);
diff --git a/parser.c b/parser.c
new file mode 100644
index 0000000..0208efc
--- /dev/null
+++ b/parser.c
@@ -0,0 +1,1775 @@
+/*
+   Be warned! Most internal parser functions bear unconventional call
+   semantics returning 1 on success and 0 otherwise. Where applicable
+   specific error code or 0 is dispensed to the parse context.
+*/
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+
+#include "parser.h"
+
+#define LEN(a) (sizeof(a) / sizeof(a)[0])
+
+static struct literal {
+	int    val;
+	char  *srep;
+	size_t slen;
+} literals[] = {
+	{ IL_7BIT,              "7BIT",              4  },
+	{ IL_8BIT,              "8BIT",              4  },
+	{ IL_ALERT,             "ALERT",             5  },
+	{ IL_APP,               "APPLICATION",       11 },
+	{ IL_APR,               "Apr",               3  },
+	{ IL_ASTERISK,          "*",                 1  },
+	{ IL_AUDIO,             "AUDIO",             5  },
+	{ IL_AUG,               "Aug",               3  },
+	{ IL_AUTHEQ,            "AUTH=",             5  },
+	{ IL_B64,               "BASE64",            6  },
+	{ IL_BAD,               "BAD",               3  },
+	{ IL_BADCS,             "BADCHARSET",        10 },
+	{ IL_BIN,               "BINARY",            6  },
+	{ IL_BODY,              "BODY",              4  },
+	{ IL_BSLASH,            "\\",                1  },
+	{ IL_BYE,               "BYE",               3  },
+	{ IL_CAP,               "CAPABILITY",        10 },
+	{ IL_CBRACE,            "}",                 1  },
+	{ IL_CBRACK,            "]",                 1  },
+	{ IL_COLON,             ":",                 1  },
+	{ IL_CPAR,              ")",                 1  },
+	{ IL_DEC,               "Dec",               3  },
+	{ IL_DHDR,              ".HEADER",           7  },
+	{ IL_DNOT,              ".NOT",              4  },
+	{ IL_DOT,               ".",                 1  },
+	{ IL_DQUOTE,            "\"",                1  },
+	{ IL_DTXT,              ".TEXT",             5  },
+	{ IL_ENVELOPE,          "ENVELOPE",          8  },
+	{ IL_EOL,               "\r\n",              2  },
+	{ IL_EXISTS,            "EXISTS",            6  },
+	{ IL_EXPUNGE,           "EXPUNGE",           7  },
+	{ IL_FEB,               "Feb",               3  },
+	{ IL_FETCH,             "FETCH",             5  },
+	{ IL_FLAGS,             "FLAGS",             5  },
+	{ IL_FLANSWERED,        "\\Answered",        9  },
+	{ IL_FLANY,             "\\*",               2  },
+	{ IL_FLDELETED,         "\\Deleted",         8  },
+	{ IL_FLDRAFT,           "\\Draft",           6  },
+	{ IL_FLFLAGGED,         "\\Flagged",         8  },
+	{ IL_FLMARKED,          "\\Marked",          7  },
+	{ IL_FLNOINFERIORS,     "\\Noinferiors",     12 },
+	{ IL_FLNOSEL,           "\\Noselect",        9  },
+	{ IL_FLRECENT,          "\\Recent",          7  },
+	{ IL_FLSEEN,            "\\Seen",            5  },
+	{ IL_FLUNMARKED,        "\\Unmarked",        9  },
+	{ IL_GT,                ">",                 1  },
+	{ IL_HDR,               "HEADER",            6  },
+	{ IL_HDRFIELDS,         "HEADER.FIELDS",     13 },
+	{ IL_IMG,               "IMAGE",             5  },
+	{ IL_INBOX,             "INBOX",             5  },
+	{ IL_INTDATE,           "INTERNALDATE",      12 },
+	{ IL_JAN,               "Jan",               3  },
+	{ IL_JUL,               "Jul",               3  },
+	{ IL_JUN,               "Jun",               3  },
+	{ IL_LIST,              "LIST",              4  },
+	{ IL_LSUB,              "LSUB",              4  },
+	{ IL_LT,                "<",                 1  },
+	{ IL_MAR,               "Mar",               3  },
+	{ IL_MAY,               "May",               3  },
+	{ IL_MIME,              "MIME",              4  },
+	{ IL_MINUS,             "-",                 1  },
+	{ IL_MSG,               "MESSAGE",           7  },
+	{ IL_MSGS,              "MESSAGES",          8  },
+	{ IL_NIL,               "NIL",               3  },
+	{ IL_NO,                "NO",                2  },
+	{ IL_NOV,               "Nov",               3  },
+	{ IL_OBRACE,            "{",                 1  },
+	{ IL_OBRACK,            "[",                 1  },
+	{ IL_OCT,               "Oct",               3  },
+	{ IL_OK,                "OK",                2  },
+	{ IL_OPAR,              "(",                 1  },
+	{ IL_PARSE,             "PARSE",             5  },
+	{ IL_PERMFL,            "PERMANENTFLAGS",    14 },
+	{ IL_PLUS,              "+",                 1  },
+	{ IL_QPRN,              "QUOTED-PRINTABLE",  16 },
+	{ IL_RECENT,            "RECENT",            6  },
+	{ IL_RFC822,            "RFC822",            6  },
+	{ IL_RFC822SIZE,        "RFC822.SIZE",       11 },
+	{ IL_RO,                "READ-ONLY",         9  },
+	{ IL_RW,                "READ-WRITE",        10 },
+	{ IL_SEARCH,            "SEARCH",            6  },
+	{ IL_SEP,               "Sep",               3  },
+	{ IL_SP,                " ",                 1  },
+	{ IL_STATUS,            "STATUS",            6  },
+	{ IL_STRUCT,            "STRUCTURE",         9  },
+	{ IL_TRYC,              "TRYCREATE",         9  },
+	{ IL_TXT,               "TEXT",              4  },
+	{ IL_UID,               "UID",               3  },
+	{ IL_UIDNEXT,           "UIDNEXT",           7  },
+	{ IL_UIDVAL,            "UIDVALIDITY",       11 },
+	{ IL_UNSEEN,            "UNSEEN",            6  },
+	{ IL_VIDEO,             "VIDEO",             5  },
+};
+
+static const char astr_specials[] = ""
+	"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+	"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"
+	" \"%()*\\{\x7f";
+
+static const char atom_specials[] = ""
+	"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+	"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"
+	" \"%()*\\]{\x7f";
+
+static const char tag_specials[] = ""
+	"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+	"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"
+	" \"%()*+\\{\x7f";
+
+struct parcur {
+	const char *tok;
+	union parnode *pt;
+};
+
+struct parctx {
+	struct parcur  cur;
+	const char    *tok;
+	const char    *tokend;
+	size_t         toklen;
+	union parnode *pt;
+	union parnode *ptend;
+	size_t         ptlen;
+	int            e;
+	size_t         oblth;
+};
+
+typedef int parfn(struct parctx *);
+
+int par_respln(const char *, size_t, union parnode *, size_t, size_t);
+
+static int cmpchr(const void *, const void *);
+static int contains(const char *, size_t, char);
+
+static int p_chk(struct parctx *, struct parcur *);
+static int p_insint(struct parctx *, int, size_t);
+static int p_inslit(struct parctx *, int);
+static int p_insnum(struct parctx *, uint32_t);
+static int p_insoblstr(struct parctx *, uint32_t);
+static int p_insstr(struct parctx *, int, const char *, uint32_t);
+static int p_beg(struct parctx *, struct parcur *, int);
+static int p_end(struct parctx *, struct parcur *);
+static int p_rwd(struct parctx *, struct parcur *);
+static int p_opt(struct parctx *);
+static int p_list(struct parctx *, parfn *);
+static int p_listsep(struct parctx *, parfn *, int);
+static int p_rep(struct parctx *, parfn *);
+static int p_repchr(struct parctx *, const char *, size_t, int);
+static int p_2xcombo(struct parctx *, int, parfn *);
+static int p_3xcombo(struct parctx *, int, int, parfn *);
+static int p_r3xcombo(struct parctx *, parfn *, int, int);
+static int p_sss(struct parctx *);
+
+static int p_addr(struct parctx *);
+static int p_astr(struct parctx *);
+static int p_atom(struct parctx *);
+static int p_authtype(struct parctx *);
+static int p_badcscode(struct parctx *);
+static int p_badcsopt(struct parctx *);
+static int p_base64(struct parctx *);
+static int p_body(struct parctx *);
+static int p_body1pt(struct parctx *);
+static int p_bodybas(struct parctx *);
+static int p_bodyext(struct parctx *);
+static int p_bodyf(struct parctx *);
+static int p_bodyfdes(struct parctx *);
+static int p_bodyfdsp(struct parctx *);
+static int p_bodyfenc(struct parctx *);
+static int p_bodyfid(struct parctx *);
+static int p_bodyflan(struct parctx *);
+static int p_bodyflin(struct parctx *);
+static int p_bodyfloc(struct parctx *);
+static int p_bodyfmd5(struct parctx *);
+static int p_bodyfoct(struct parctx *);
+static int p_bodyfpar(struct parctx *);
+static int p_bodympt(struct parctx *);
+static int p_bodymsg(struct parctx *);
+static int p_bodytxt(struct parctx *);
+static int p_bodyx1pt(struct parctx *);
+static int p_bodyxcmn(struct parctx *);
+static int p_bodyxmpt(struct parctx *);
+static int p_cap(struct parctx *);
+static int p_capdata(struct parctx *);
+static int p_contreq(struct parctx *);
+static int p_datetime(struct parctx *);
+static int p_dayfix(struct parctx *);
+static int p_dig(struct parctx *, size_t);
+static int p_dquotedchar(struct parctx *);
+static int p_env(struct parctx *);
+static int p_envaddr(struct parctx *, int);
+static int p_envbcc(struct parctx *);
+static int p_envcc(struct parctx *);
+static int p_envdate(struct parctx *);
+static int p_envfrom(struct parctx *);
+static int p_envinrepto(struct parctx *);
+static int p_envmsgid(struct parctx *);
+static int p_envrepto(struct parctx *);
+static int p_envsender(struct parctx *);
+static int p_envsubj(struct parctx *);
+static int p_envto(struct parctx *);
+static int p_fetchrec(struct parctx *);
+static int p_flag(struct parctx *);
+static int p_flext(struct parctx *);
+static int p_flfetch(struct parctx *);
+static int p_flkeyword(struct parctx *);
+static int p_gencode(struct parctx *);
+static int p_genctext(struct parctx *);
+static int p_hdrfname(struct parctx *);
+static int p_hdrlist(struct parctx *);
+static int p_lit(struct parctx *, int);
+static int p_lstr(struct parctx *);
+static int p_mailbox(struct parctx *);
+static int p_matbody(struct parctx *);
+static int p_matbsect(struct parctx *);
+static int p_matenv(struct parctx *);
+static int p_mathdrotxt(struct parctx *);
+static int p_matintdate(struct parctx *);
+static int p_matsize(struct parctx *);
+static int p_matuid(struct parctx *);
+static int p_mbdata(struct parctx *);
+static int p_mbexists(struct parctx *);
+static int p_mbflags(struct parctx *);
+static int p_mblist(struct parctx *);
+static int p_mblistdata(struct parctx *);
+static int p_mblistfl(struct parctx *);
+static int p_mblistofl(struct parctx *);
+static int p_mblistosfl(struct parctx *);
+static int p_mblistsfl(struct parctx *);
+static int p_mblsub(struct parctx *);
+static int p_mbrecent(struct parctx *);
+static int p_mbsearch(struct parctx *);
+static int p_mbstatus(struct parctx *);
+static int p_medbas(struct parctx *);
+static int p_medmsg(struct parctx *);
+static int p_medsubt(struct parctx *);
+static int p_medtxt(struct parctx *);
+static int p_month(struct parctx *);
+static int p_msgdata(struct parctx *);
+static int p_msgatt(struct parctx *);
+static int p_msgattdyn(struct parctx *);
+static int p_msgattstat(struct parctx *);
+static int p_nstr(struct parctx *);
+static int p_num(struct parctx *);
+static int p_nznum(struct parctx *);
+static int p_permfl(struct parctx *);
+static int p_permflcode(struct parctx *);
+static int p_qchar(struct parctx *);
+static int p_qchars(struct parctx *);
+static int p_qstr(struct parctx *);
+static int p_respbye(struct parctx *);
+static int p_respdata(struct parctx *);
+static int p_respln(struct parctx *);
+static int p_respstate(struct parctx *);
+static int p_resptext(struct parctx *);
+static int p_resptextcode(struct parctx *);
+static int p_secmsgtxt(struct parctx *);
+static int p_secpt(struct parctx *);
+static int p_secspec(struct parctx *);
+static int p_section(struct parctx *);
+static int p_sectxt(struct parctx *);
+static int p_statt(struct parctx *);
+static int p_stattrec(struct parctx *);
+static int p_str(struct parctx *);
+static int p_tag(struct parctx *);
+static int p_taggedresp(struct parctx *);
+static int p_text(struct parctx *);
+static int p_time(struct parctx *);
+static int p_uid(struct parctx *);
+static int p_uidncode(struct parctx *);
+static int p_uidvcode(struct parctx *);
+static int p_unseencode(struct parctx *);
+static int p_year(struct parctx *);
+static int p_zone(struct parctx *);
+
+static int p_cpar(struct parctx *);
+static int p_dquote(struct parctx *);
+static int p_opar(struct parctx *);
+static int p_sp(struct parctx *);
+
+int
+par_respln(const char *tok, size_t toklen, union parnode *pt,
+    size_t ptlen, size_t oblth)
+{
+	struct parctx p = { { tok, pt}, tok, tok + toklen, toklen,
+	    pt, pt + ptlen, ptlen, 0, oblth };
+
+	p_respln(&p);
+	return p.e;
+}
+
+int
+cmpchr(const void *a, const void *b)
+{
+	return *(char *)a - *(char *)b;
+}
+
+int
+contains(const char *s, size_t slen, char c)
+{
+	return bsearch(&c, s, slen, sizeof(char), cmpchr) != 0;
+}
+
+/*
+  Combinators and misc meta critters
+*/
+
+int
+p_chk(struct parctx *p, struct parcur *cp)
+{
+	*cp = p->cur;
+	return 1;
+}
+
+int
+p_insint(struct parctx *p, int prod, size_t len)
+{
+	union parnode *cur;
+
+	cur = p->cur.pt;
+	if (cur == p->ptend) {
+		p->e = PE_NOTENNODES;
+		return 0;
+	}
+	cur->inter.type = PN_INTER;
+	cur->inter.prod = prod;
+	cur->inter.len = len;
+	p->e = PE_OK;
+	p->cur.pt++;
+	return 1;
+}
+
+int
+p_inslit(struct parctx *p, int val)
+{
+	union parnode *cur;
+
+	cur = p->cur.pt;
+	if (cur == p->ptend) {
+		p->e = PE_NOTENNODES;
+		return 0;
+	}
+	cur->lit.type = PN_LIT;
+	cur->lit.val = val;
+	p->e = PE_OK;
+	p->cur.pt++;
+	return 1;
+}
+
+int
+p_insnum(struct parctx *p, uint32_t val)
+{
+	union parnode *cur;
+
+	cur = p->cur.pt;
+	if (cur == p->ptend) {
+		p->e = PE_NOTENNODES;
+		return 0;
+	}
+	cur->lit.type = PN_NUM;
+	cur->lit.val = val;
+	p->e = PE_OK;
+	p->cur.pt++;
+	return 1;
+}
+
+int
+p_insoblstr(struct parctx *p, uint32_t len)
+{
+	union parnode *cur;
+
+	cur = p->cur.pt;
+	if (cur == p->ptend) {
+		p->e = PE_NOTENNODES;
+		return 0;
+	}
+	cur->str.type = PN_OBLSTR;
+	cur->str.len = len;
+	cur->str.iob = 0;
+	p->e = PE_OK;
+	p->cur.pt++;
+	return 1;
+}
+
+int
+p_insstr(struct parctx *p, int type, const char *tok, uint32_t len)
+{
+	union parnode *cur;
+
+	cur = p->cur.pt;
+	if (cur == p->ptend) {
+		p->e = PE_NOTENNODES;
+		return 0;
+	}
+	cur->str.type = type;
+	cur->str.len = len;
+	cur->str.tok = tok;
+	p->e = PE_OK;
+	p->cur.pt++;
+	return 1;
+}
+
+int
+p_beg(struct parctx *p, struct parcur *beg, int prod)
+{
+	return p_chk(p, beg) && p_insint(p, prod, 0);
+}
+
+int
+p_end(struct parctx *p, struct parcur *beg)
+{
+	beg->pt->inter.len = p->cur.pt - beg->pt - 1;
+	p->e = PE_OK;
+	return 1;
+}
+
+int
+p_rwd(struct parctx *p, struct parcur *cp)
+{
+	p->cur = *cp;
+	if (!p->e)
+		p->e = PE_PARSE;
+
+	return 0;
+}
+
+int
+p_opt(struct parctx *p)
+{
+	if (p->e == PE_PARSE)
+		p->e = PE_OK;
+
+	return !p->e;
+}
+
+/* prod *(SP prod) */
+int
+p_list(struct parctx *p, parfn *prod)
+{
+	int res;
+
+	for (res = prod(p); res && p_2xcombo(p, IL_SP, prod);)
+		;
+	return res && p_opt(p);
+}
+
+int
+p_listsep(struct parctx *p, parfn *prod, int sep)
+{
+	int res;
+
+	for(res = prod(p); res && p_2xcombo(p, sep, prod);)
+		;
+	return res && p_opt(p);
+}
+
+/* 1*prod */
+int
+p_rep(struct parctx *p, parfn *prod)
+{
+	int res;
+
+	for (res = prod(p); res && prod(p);)
+		;
+	return res && p_opt(p);
+}
+
+/* 1*<any char but those in `except'> */
+int
+p_repchr(struct parctx *p, const char *except, size_t elen, int strtype)
+{
+	const char *t;
+	size_t len;
+
+	t = p->cur.tok;
+	while (t != p->tokend && !contains(except, elen, *t))
+		t++;
+
+	len = t - p->cur.tok;
+	if (len == 0) {
+		p->e = PE_PARSE;
+		goto exit;
+	} else if (len > UINT32_MAX) {
+		p->e = PE_STRTOOBIG;
+		goto exit;
+	}
+	if (!p_insstr(p, strtype, p->cur.tok, (uint32_t)len))
+		goto exit;
+
+	p->cur.tok = t;
+	p->e = PE_OK;
+
+ exit:
+	return !p->e;
+}
+
+int
+p_2xcombo(struct parctx *p, int lit, parfn *prod)
+{
+	struct parcur b;
+
+	return p_chk(p, &b) && p_lit(p, lit) && prod(p) || p_rwd(p, &b);
+}
+
+int
+p_3xcombo(struct parctx *p, int lit1, int lit2, parfn *prod)
+{
+	struct parcur b;
+
+	return p_chk(p, &b) && p_lit(p, lit1) &&
+	    p_lit(p, lit2) && prod(p) || p_rwd(p, &b);
+}
+
+int
+p_r3xcombo(struct parctx *p, parfn *prod, int lit1, int lit2)
+{
+	struct parcur b;
+
+	return p_chk(p, &b) && prod(p) && p_lit(p, lit1) &&
+	    p_lit(p, lit2) || p_rwd(p, &b);
+}
+
+int
+p_sss(struct parctx *p)
+{
+	struct parcur b;
+
+	return p_chk(p, &b) && p_str(p) && p_sp(p) && p_str(p) ||
+	    p_rwd(p, &b);
+}
+
+/*
+  IMAP parsers
+*/
+
+int
+p_addr(struct parctx *p)
+{
+	struct parcur b;
+
+	return p_chk(p, &b) && p_opar(p) && p_nstr(p) && p_sp(p) &&
+	    p_nstr(p) && p_sp(p) && p_nstr(p) && p_sp(p) &&
+	    p_nstr(p) && p_cpar(p) || p_rwd(p, &b);
+}
+
+int
+p_astr(struct parctx *p)
+{
+	struct parcur b;
+
+	return p_beg(p, &b, IP_ASTR) &&
+	    (p_repchr(p, astr_specials, LEN(astr_specials), PN_STR) ||
+	    p_str(p)) && p_end(p, &b) || p_rwd(p, &b);
+}
+
+int
+p_atom(struct parctx *p)
+{
+	struct parcur b;
+
+	return p_beg(p, &b, IP_ATOM) &&
+	    p_repchr(p, atom_specials, LEN(atom_specials), PN_STR) &&
+	    p_end(p, &b) || p_rwd(p, &b);
+}
+
+int
+p_authtype(struct parctx *p)
+{
+	return p_atom(p);
+}
+
+int
+p_badcscode(struct parctx *p)
+{
+	struct parcur b;
+
+	return p_chk(p, &b) && p_lit(p, IL_BADCS) &&
+	    (p_badcsopt(p) || p_opt(p)) || p_rwd(p, &b);
+}
+
+int
+p_badcsopt(struct parctx *p)
+{
+	struct parcur b;
+
+	return p_chk(p, &b) && p_sp(p) && p_opar(p) &&
+	    p_list(p, p_astr) && p_cpar(p) || p_rwd(p, &b);
+}
+
+int
+p_base64(struct parctx *p)
+{
+	/* you won't get far w/o b64 */
+}
+
+int
+p_body(struct parctx *p)
+{
+	struct parcur b;
+
+	return p_chk(p, &b) && p_opar(p) && (p_body1pt(p) ||
+	    p_bodympt(p)) && p_cpar(p) || p_rwd(p, &b);
+}
+
+int
+p_body1pt(struct parctx *p)
+{
+	struct parcur b, o;
+
+	return p_chk(p, &b) &&
+	    (p_bodybas(p) || p_bodymsg(p) || p_bodytxt(p)) &&
+	    (p_chk(p, &o) && p_sp(p) && p_bodyx1pt(p) ||
+	    p_rwd(p, &o) || p_opt(p)) || p_rwd(p, &b);
+}
+
+int
+p_bodybas(struct parctx *p)
+{
+	struct parcur b;
+
+	return p_chk(p, &b) && p_medbas(p) && p_sp(p) &&
+	    p_bodyf(p) || p_rwd(p, &b);
+}
+
+int
+p_bodyext(struct parctx *p)
+{
+	struct parcur b;
+
+	return p_chk(p, &b) && p_nstr(p) || p_num(p) ||
+	    (p_opar(p) && p_list(p, p_bodyext) && p_cpar(p)) ||
+	    p_rwd(p, &b);
+}
+
+int
+p_bodyf(struct parctx *p)
+{
+	struct parcur b;
+
+	return p_chk(p, &b) && p_bodyfpar(p) && p_sp(p) &&
+	    p_bodyfid(p) && p_sp(p) && p_bodyfdes(p) && p_sp(p) &&
+	    p_bodyfenc(p) && p_sp(p) && p_bodyfoct(p) || p_rwd(p, &b);
+}
+
+int
+p_bodyfdes(struct parctx *p)
+{
+	return p_nstr(p);
+}
+
+int
+p_bodyfdsp(struct parctx *p)
+{
+	struct parcur b;
+
+	return p_chk(p, &b) && (p_opar(p) && p_str(p) && p_sp(p) &&
+	    p_bodyfpar(p) && p_cpar(p) || p_rwd(p, &b)) || p_lit(p, IL_NIL);
+}
+
+int
+p_bodyfenc(struct parctx *p)
+{
+	struct parcur b;
+
+	return p_chk(p, &b) && (p_dquote(p) && (p_lit(p, IL_7BIT) ||
+	    p_lit(p, IL_8BIT) || p_lit(p, IL_BIN) || p_lit(p, IL_B64) ||
+	    p_lit(p, IL_QPRN)) && p_dquote(p) || p_rwd(p, &b)) ||
+	    p_str(p);
+}
+
+int
+p_bodyfid(struct parctx *p)
+{
+	return p_nstr(p);
+}
+
+int
+p_bodyflan(struct parctx *p)
+{
+	struct parcur b;
+
+	return p_chk(p, &b) && p_nstr(p) || (p_opar(p) &&
+	    p_list(p, p_str) && p_cpar(p) || p_rwd(p, &b));
+}
+
+int
+p_bodyflin(struct parctx *p)
+{
+	return p_num(p);
+}
+
+int
+p_bodyfloc(struct parctx *p)
+{
+	return p_nstr(p);
+}
+
+int
+p_bodyfmd5(struct parctx *p)
+{
+	return p_nstr(p);
+}
+
+int
+p_bodyfoct(struct parctx *p)
+{
+	return p_num(p);
+}
+
+int
+p_bodyfpar(struct parctx *p)
+{
+	struct parcur b;
+
+	return p_chk(p, &b) && (p_opar(p) && p_list(p, p_sss) &&
+	    p_cpar(p) || p_rwd(p, &b)) || p_lit(p, IL_NIL);
+}
+
+int
+p_bodympt(struct parctx *p)
+{
+	struct parcur b, o;
+
+	return p_chk(p, &b) && p_rep(p, p_body) && p_sp(p) &&
+	    p_medsubt(p) && (p_chk(p, &o) && p_sp(p) && p_bodyxmpt(p) ||
+	    p_rwd(p, &o) || p_opt(p)) || p_rwd(p, &b);
+}
+
+int
+p_bodymsg(struct parctx *p)
+{
+	struct parcur b;
+
+	return p_chk(p, &b) && p_medmsg(p) && p_sp(p) && p_bodyf(p) &&
+	    p_sp(p) && p_env(p) && p_sp(p) && p_body(p) && p_sp(p) &&
+	    p_bodyflin(p) || p_rwd(p, &b);
+}
+
+int
+p_bodytxt(struct parctx *p)
+{
+	struct parcur b;
+
+	return p_chk(p, &b) && p_medtxt(p) && p_sp(p) && p_bodyf(p) &&
+	    p_sp(p) && p_bodyflin(p) || p_rwd(p, &b);
+}
+
+int
+p_bodyx1pt(struct parctx *p)
+{
+	struct parcur b;
+
+	return p_chk(p, &b) && p_bodyfmd5(p) &&
+	    p_bodyxcmn(p) || p_rwd(p, &b);
+}
+
+/* TODO: this one's extra gross, prob needs a good factoring */
+int
+p_bodyxcmn(struct parctx *p)
+{
+	struct parcur o1, o2, o3, o4;
+
+	return p_chk(p, &o1) && p_sp(p) && p_bodyfdsp(p) &&
+	    (p_chk(p, &o2) && p_sp(p) && p_bodyflan(p) &&
+	    (p_chk(p, &o3) && p_sp(p) && p_bodyfloc(p) &&
+	    (p_chk(p, &o4) && p_sp(p) && p_list(p, p_bodyext) ||
+	    p_rwd(p, &o4) || p_opt(p)) ||
+	    p_rwd(p, &o3) || p_opt(p)) ||
+	    p_rwd(p, &o2) || p_opt(p)) ||
+	    p_rwd(p, &o1) || p_opt(p);
+}
+
+int
+p_bodyxmpt(struct parctx *p)
+{
+	struct parcur b;
+
+	return p_chk(p, &b) && p_bodyfpar(p) &&
+	    p_bodyxcmn(p) || p_rwd(p, &b);
+}
+
+int
+p_cap(struct parctx *p)
+{
+	struct parcur b;
+
+	return p_beg(p, &b, IP_CAP) && p_sp(p) &&
+	    (p_2xcombo(p, IL_AUTHEQ, p_authtype) || p_atom(p)) &&
+	    p_end(p, &b) || p_rwd(p, &b);
+}
+
+int
+p_capdata(struct parctx *p)
+{
+	struct parcur b;
+
+	return p_chk(p, &b) && p_lit(p, IL_CAP) &&
+	    p_rep(p, p_cap) || p_rwd(p, &b);
+}
+
+int
+p_contreq(struct parctx *p)
+{
+	struct parcur b;
+
+	return p_chk(p, &b) &&
+	    p_lit(p, IL_PLUS) && p_sp(p) &&
+	    (p_resptext(p) || p_base64(p)) &&
+	    p_lit(p, IL_EOL) || p_rwd(p, &b);
+}
+
+int
+p_datetime(struct parctx *p)
+{
+	struct parcur b;
+
+	return p_chk(p, &b) && p_dquote(p) && p_dayfix(p) &&
+	    p_lit(p, IL_MINUS) && p_month(p) && p_lit(p, IL_MINUS) &&
+	    p_year(p) && p_sp(p) && p_time(p) && p_sp(p) && p_zone(p) &&
+	    p_dquote(p) || p_rwd(p, &b);
+}
+
+int
+p_dayfix(struct parctx *p)
+{
+	struct parcur b;
+
+	return p_chk(p, &b) && p_sp(p) && p_dig(p, 1) ||
+	    p_rwd(p, &b) || p_dig(p, 2);
+}
+
+int
+p_dig(struct parctx *p, size_t count)
+{
+	uint32_t n, prev;
+	const char *t;
+
+	prev = n = 0;
+	t = p->cur.tok;
+
+	while (t != p->tokend && count && *t >= '0' && *t <= '9') {
+		prev = n;
+		n = UINT32_MAX & (10 * n + (*t - 48));
+		if (prev > n) {
+			p->e = PE_PARSE;
+			goto exit;
+		}
+		t++;
+		count--;
+	}
+	if (t == p->cur.tok || count != 0) {
+		p->e = PE_PARSE;
+	} else if (p_insnum(p, n)) {
+		p->cur.tok = t;
+		p->e = PE_OK;
+	}
+ exit:
+	return !p->e;
+}
+
+int
+p_dquotedchar(struct parctx *p)
+{
+	struct parcur b;
+
+	return p_chk(p, &b) && p_dquote(p) && p_qchar(p) && p_dquote(p) ||
+	    p_rwd(p, &b);
+}
+
+int
+p_env(struct parctx *p)
+{
+	struct parcur b;
+
+	return p_chk(p, &b) && p_opar(p) && p_envdate(p) && p_sp(p) &&
+	    p_envsubj(p) && p_sp(p) && p_envfrom(p) && p_sp(p) &&
+	    p_envsender(p) && p_sp(p) && p_envrepto(p) && p_sp(p) &&
+	    p_envto(p) && p_sp(p) && p_envcc(p) && p_sp(p) &&
+	    p_envbcc(p) && p_sp(p) && p_envinrepto(p) && p_sp(p) &&
+	    p_envmsgid(p) && p_cpar(p) || p_rwd(p, &b);
+}
+
+int
+p_envaddr(struct parctx *p, int prod)
+{
+	struct parcur b;
+
+	return p_beg(p, &b, prod) &&
+	    (p_opar(p) && p_rep(p, p_addr) && p_cpar(p) ||
+	    p_rwd(p, &b) || p_lit(p, IL_NIL)) && p_end(p, &b);
+}
+
+int
+p_envbcc(struct parctx *p)
+{
+	return p_envaddr(p, IP_ENVBCC);
+}
+
+int
+p_envcc(struct parctx *p)
+{
+	return p_envaddr(p, IP_ENVCC);
+}
+
+int
+p_envdate(struct parctx *p)
+{
+	return p_nstr(p);
+}
+
+int
+p_envfrom(struct parctx *p)
+{
+	return p_envaddr(p, IP_ENVFROM);
+}
+
+int
+p_envinrepto(struct parctx *p)
+{
+	return p_nstr(p);
+}
+
+int
+p_envmsgid(struct parctx *p)
+{
+	return p_nstr(p);
+}
+
+int
+p_envrepto(struct parctx *p)
+{
+	return p_envaddr(p, IP_ENVREPTO);
+}
+
+int
+p_envsender(struct parctx *p)
+{
+	return p_envaddr(p, IP_ENVSENDER);
+}
+
+int
+p_envsubj(struct parctx *p)
+{
+	return p_nstr(p);
+}
+
+int
+p_envto(struct parctx *p)
+{
+	return p_envaddr(p, IP_ENVTO);
+}
+
+int
+p_fetchrec(struct parctx *p)
+{
+	struct parcur b;
+
+	return p_chk(p, &b) && p_lit(p, IL_FETCH) && p_sp(p) &&
+	    p_opar(p) && p_list(p, p_msgatt) && p_cpar(p) || p_rwd(p, &b);
+}
+
+int
+p_flag(struct parctx *p)
+{
+	return p_lit(p, IL_FLANSWERED) || p_lit(p, IL_FLFLAGGED) ||
+	    p_lit(p, IL_FLDELETED) || p_lit(p, IL_FLSEEN) ||
+	    p_lit(p, IL_FLDRAFT) || p_flkeyword(p) ||
+	    p_flext(p);
+}
+
+int
+p_flext(struct parctx *p)
+{
+	struct parcur b;
+
+	return p_chk(p, &b) && p_lit(p, IL_BSLASH) &&
+	    p_atom(p) || p_rwd(p, &b);
+}
+
+int
+p_flfetch(struct parctx *p)
+{
+	return p_flag(p) || p_lit(p, IL_FLRECENT);
+}
+
+int
+p_flkeyword(struct parctx *p)
+{
+	return p_atom(p);
+}
+
+int
+p_gencode(struct parctx *p)
+{
+	struct parcur opt;
+
+	return p_atom(p) && (p_chk(p, &opt) &&
+	    p_sp(p) && p_genctext(p) ||
+	    p_rwd(p, &opt) || p_opt(p));
+}
+
+int
+p_genctext(struct parctx *p)
+{
+	int res;
+	const char *t;
+
+	t = p->cur.tok;
+
+	while (t != p->tokend && *t >= '\1' && *t <= '\x7f' &&
+	    *t != ']' && *t != '\r' && *t != '\n')
+		t++;
+
+	res = t > p->cur.tok;
+	if (res)
+		p->cur.tok = t;
+
+	p->e = !res;
+	return res;
+}
+
+int
+p_hdrfname(struct parctx *p)
+{
+	return p_astr(p);
+}
+
+int
+p_hdrlist(struct parctx *p)
+{
+	struct parcur b;
+
+	return p_chk(p, &b) && p_opar(p) && p_list(p, p_hdrfname) &&
+	    p_cpar(p) || p_rwd(p, &b);
+}
+
+int
+p_lit(struct parctx *p, int val)
+{
+	size_t left;
+	struct literal *lit;
+
+	left = p->tokend - p->cur.tok;
+	lit = literals + val;
+
+	if (left < lit->slen) {
+		p->e = PE_PARSE;
+		goto exit;
+	}
+	if (strncasecmp(p->cur.tok, lit->srep, lit->slen) == 0) {
+		if (p_inslit(p, val)) {
+			p->cur.tok += lit->slen;
+			p->e = PE_OK;
+		}
+	} else {
+		p->e = PE_PARSE;
+	}
+ exit:
+	return !p->e;
+}
+
+int
+p_lstr(struct parctx *p)
+{
+	int res;
+	size_t len;
+	struct parcur b, n;
+
+	res = p_chk(p, &b) && p_lit(p, IL_OBRACE) &&
+	    p_chk(p, &n) && p_num(p) && p_lit(p, IL_CBRACE) &&
+	    p_lit(p, IL_EOL) || p_rwd(p, &b);
+
+	if (res) {
+		len = n.pt->num.val;
+		if (len > UINT32_MAX) {
+			p->e = PE_STRTOOBIG;
+			res = 0;
+		} else if (len < p->oblth) {
+			res = p_insstr(p, PN_LSTR, p->cur.tok, (uint32_t)len);
+			if (res)
+				p->cur.tok += len;
+		} else {
+			res = p_insoblstr(p, (uint32_t)len);
+		}
+	}
+	return res;
+}
+
+int
+p_mailbox(struct parctx *p)
+{
+	return p_lit(p, IL_INBOX) || p_astr(p);
+}
+
+int
+p_matbody(struct parctx *p)
+{
+	struct parcur b;
+
+	return p_chk(p, &b) && p_lit(p, IL_BODY) &&
+	    (p_lit(p, IL_STRUCT) || p_opt(p)) && p_sp(p) &&
+	    p_body(p) || p_rwd(p, &b);
+}
+
+int
+p_matbsect(struct parctx *p)
+{
+	struct parcur b, o;
+
+	return p_chk(p, &b) && p_lit(p, IL_BODY) && p_section(p) &&
+	    (p_chk(p, &o) && p_lit(p, IL_LT) && p_num(p) && p_lit(p, IL_GT) ||
+	    p_rwd(p, &o) || p_opt(p)) && p_sp(p) && p_nstr(p) || p_rwd(p, &b);
+}
+
+int
+p_matenv(struct parctx *p)
+{
+	return p_3xcombo(p, IL_ENVELOPE, IL_SP, p_env);
+}
+
+int
+p_mathdrotxt(struct parctx *p)
+{
+	struct parcur b, o;
+
+	return p_chk(p, &b) && p_lit(p, IL_RFC822) &&
+	    (p_chk(p, &o) && p_lit(p, IL_DHDR) || p_lit(p, IL_DTXT) ||
+	    p_rwd(p, &o) || p_opt(p)) && p_sp(p) && p_nstr(p) ||
+	    p_rwd(p, &b);
+}
+
+int
+p_matintdate(struct parctx *p)
+{
+	return p_3xcombo(p, IL_INTDATE, IL_SP, p_datetime);
+}
+
+int
+p_matsize(struct parctx *p)
+{
+	return p_3xcombo(p, IL_RFC822SIZE, IL_SP, p_num);
+}
+
+int
+p_matuid(struct parctx *p)
+{
+	return p_3xcombo(p, IL_UID, IL_SP, p_uid);
+}
+
+int
+p_mbdata(struct parctx *p)
+{
+	return p_mbflags(p) || p_mblist(p) ||
+	    p_mblsub(p) || p_mbsearch(p) ||
+	    p_mbstatus(p) || p_mbexists(p) ||
+	    p_mbrecent(p);
+}
+
+int
+p_mbexists(struct parctx *p)
+{
+	return p_r3xcombo(p, p_num, IL_SP, IL_EXISTS);
+}
+
+int
+p_mbflags(struct parctx *p)
+{
+	struct parcur b;
+
+	return p_chk(p, &b) && p_lit(p, IL_FLAGS) &&
+	    p_sp(p) && p_opar(p) &&
+	    (p_list(p, p_flag) || p_opt(p)) &&
+	    p_cpar(p) || p_rwd(p, &b);
+}
+
+int
+p_mblist(struct parctx *p)
+{
+	struct parcur b;
+
+	return p_chk(p, &b) && p_lit(p, IL_LIST) &&
+	    p_sp(p) && p_mblistdata(p) ||
+	    p_rwd(p, &b);
+}
+
+int
+p_mblistdata(struct parctx *p)
+{
+	struct parcur b;
+
+	return p_chk(p, &b) && p_opar(p) &&
+	    (p_list(p, p_mblistfl) || p_opt(p)) &&
+	    p_cpar(p) && p_sp(p) &&
+	    (p_dquotedchar(p) || p_lit(p, IL_NIL)) &&
+	    p_sp(p) && p_mailbox(p) || p_rwd(p, &b);
+}
+
+/*
+   TODO: will 1*(SFL|OFL) with a soundness check afterwards
+   be simpler and more readable?
+*/
+int
+p_mblistfl(struct parctx *p)
+{
+	return p_mblistosfl(p) || p_list(p, p_mblistofl);
+}
+
+int
+p_mblistofl(struct parctx *p)
+{
+	return p_lit(p, IL_FLNOINFERIORS) || p_flext(p);
+}
+
+int
+p_mblistosfl(struct parctx *p)
+{
+	int res;
+	struct parcur b;
+
+	p_chk(p, &b);
+
+	res = p_list(p, p_mblistofl) &&
+	    p_sp(p) || p_rwd(p, &b) || p_opt(p);
+
+	res = res && p_mblistsfl(p);
+
+	res = res && p_chk(p, &b) && p_sp(p) &&
+	    p_list(p, p_mblistofl) || p_rwd(p, &b) || p_opt(p);
+
+	return res || p_rwd(p, &b);
+}
+
+int
+p_mblistsfl(struct parctx *p)
+{
+	return p_lit(p, IL_FLNOSEL) || p_lit(p, IL_FLMARKED) ||
+	    p_lit(p, IL_FLUNMARKED);
+}
+
+int
+p_mblsub(struct parctx *p)
+{
+	struct parcur b;
+
+	return p_chk(p, &b) && p_lit(p, IL_LSUB) &&
+	    p_sp(p) && p_mblistdata(p) ||
+	    p_rwd(p, &b);
+}
+
+int
+p_mbrecent(struct parctx *p)
+{
+	return p_r3xcombo(p, p_num, IL_SP, IL_RECENT);
+}
+
+int
+p_mbsearch(struct parctx *p)
+{
+	struct parcur b, o;
+
+	return p_chk(p, &b) && p_lit(p, IL_SEARCH) &&
+	    (p_chk(p, &o) && p_sp(p) &&
+	    p_list(p, p_nznum) || p_rwd(p, &o) || p_opt(p)) ||
+	    p_rwd(p, &b);
+}
+
+int
+p_mbstatus(struct parctx *p)
+{
+	struct parcur b;
+
+	return p_chk(p, &b) && p_lit(p, IL_STATUS) && p_sp(p) &&
+	    p_mailbox(p) && p_sp(p) && p_opar(p) &&
+	    (p_list(p, p_stattrec) || p_opt(p)) && p_cpar(p) ||
+	    p_rwd(p, &b);
+}
+
+int
+p_medbas(struct parctx *p)
+{
+	struct parcur b;
+
+	return p_chk(p, &b) && (p_dquote(p) &&
+	    (p_lit(p, IL_APP) || p_lit(p, IL_AUDIO) || p_lit(p, IL_IMG) ||
+	    p_lit(p, IL_MSG) || p_lit(p, IL_VIDEO)) && p_dquote(p) ||
+	    (p_rwd(p, &b) || p_str(p))) &&
+	    p_sp(p) && p_medsubt(p) || p_rwd(p, &b);
+}
+
+int
+p_medmsg(struct parctx *p)
+{
+	struct parcur b;
+
+	return p_chk(p, &b) &&
+	    p_dquote(p) && p_lit(p, IL_MSG) && p_dquote(p) && p_sp(p) &&
+	    p_dquote(p) && p_lit(p, IL_RFC822) && p_dquote(p) || p_rwd(p, &b);
+}
+
+int
+p_medsubt(struct parctx *p)
+{
+	return p_str(p);
+}
+
+int
+p_medtxt(struct parctx *p)
+{
+	struct parcur b;
+
+	return p_chk(p, &b) && p_dquote(p) && p_lit(p, IL_TXT) && p_dquote(p) &&
+	    p_sp(p) && p_medsubt(p) || p_rwd(p, &b);
+}
+
+int
+p_month(struct parctx *p)
+{
+	return p_lit(p, IL_JAN) || p_lit(p, IL_FEB) || p_lit(p, IL_MAR) ||
+	    p_lit(p, IL_APR) || p_lit(p, IL_MAY) || p_lit(p, IL_JUN) ||
+	    p_lit(p, IL_JUL) || p_lit(p, IL_AUG) || p_lit(p, IL_SEP) ||
+	    p_lit(p, IL_OCT) || p_lit(p, IL_NOV) || p_lit(p, IL_DEC);
+}
+
+int
+p_msgdata(struct parctx *p)
+{
+	struct parcur b;
+
+	return p_chk(p, &b) && p_nznum(p) && p_sp(p) &&
+	    (p_lit(p, IL_EXPUNGE) || p_fetchrec(p)) || p_rwd(p, &b);
+}
+
+int
+p_msgatt(struct parctx *p)
+{
+	return p_msgattstat(p) || p_msgattdyn(p);
+}
+
+int
+p_msgattdyn(struct parctx *p)
+{
+	struct parcur b;
+
+	return p_chk(p, &b) && p_lit(p, IL_FLAGS) && p_sp(p) && p_opar(p) &&
+	    (p_list(p, p_flfetch) || p_opt(p)) && p_cpar(p) || p_rwd(p, &b);
+}
+
+int
+p_msgattstat(struct parctx *p)
+{
+	return p_matenv(p) || p_matintdate(p) || p_mathdrotxt(p) ||
+	    p_matsize(p) || p_matbody(p) || p_matbsect(p) || p_matuid(p);
+}
+
+int
+p_nstr(struct parctx *p)
+{
+	return p_str(p) || p_lit(p, IL_NIL);
+}
+
+int
+p_num(struct parctx *p)
+{
+	uint32_t n, prev;
+	const char *t;
+
+	prev = n = 0;
+	t = p->cur.tok;
+
+	while (t != p->tokend && *t >= '0' && *t <= '9') {
+		prev = n;
+		n = UINT32_MAX & (10 * n + (*t - 48));
+		if (prev > n) {
+			p->e = PE_PARSE;
+			goto exit;
+		}
+		t++;
+	}
+	if (t == p->cur.tok) {
+		p->e = PE_PARSE;
+	} else if (p_insnum(p, n)) {
+		p->cur.tok = t;
+		p->e = PE_OK;
+	}
+ exit:
+	return !p->e;
+}
+
+int
+p_nznum(struct parctx *p)
+{
+	const char *t;
+
+	t = p->cur.tok;
+
+	if (t == p->tokend || *t < '1' || *t > '9') {
+		p->e = PE_PARSE;
+		goto exit;
+	}
+	p_num(p);
+ exit:
+	return !p->e;
+}
+
+int
+p_permfl(struct parctx *p)
+{
+	return p_flag(p) || p_lit(p, IL_FLANY);
+}
+
+int
+p_permflcode(struct parctx *p)
+{
+	struct parcur b;
+
+	return p_chk(p, &b) && p_lit(p, IL_PERMFL) &&
+	    p_sp(p) && p_opar(p) &&
+	    (p_list(p, p_permfl) || p_opt(p)) &&
+	    p_cpar(p) || p_rwd(p, &b);
+}
+
+int
+p_qchar(struct parctx *p)
+{
+	const char *t;
+	int len;
+	size_t left;
+
+	t = p->cur.tok;
+	left = p->tokend - p->cur.tok;
+
+	if (t == p->tokend) {
+		p->e = PE_PARSE;
+		goto exit;
+	}
+	if (*t >= '\1' && *t <= '\x7f' && *t != '\r' &&
+	    *t != '\n' && *t != '"' && *t != '\\') {
+		len = 1;
+	} else if (left >= 2 &&
+	    (strncmp(t, "\\\"", 2) == 0 || strncmp(t, "\\\\", 2) == 0)) {
+		len = 2;
+	} else {
+		p->e = PE_PARSE;
+		goto exit;
+	}
+
+	if (!p_insstr(p, PN_QSTR, p->cur.tok, len)) {
+		p->e = PE_PARSE;
+		goto exit;
+	}
+	p->cur.tok += len;
+	p->e = PE_OK;
+
+ exit:
+	return !p->e;
+}
+
+int
+p_qchars(struct parctx *p)
+{
+	const char *t;
+	size_t len;
+	int esc;
+
+	t = p->cur.tok;
+	esc = 0;
+	while (t != p->tokend) {
+		if (esc) {
+			if (*t == '"' || *t == '\\') {
+				t++;
+				esc = 0;
+			} else {
+				p->e = PE_PARSE;
+				goto exit;
+			}
+		} else if (*t == '\\') {
+			t++;
+			esc = 1;
+		} else if (*t >= '\1' && *t <= '\x7f' && *t != '\r' &&
+		    *t != '\n' && *t != '"' && *t != '\\') {
+			t++;
+		} else {
+			p->e = PE_PARSE;
+			goto exit;
+		}
+	}
+	len = t - p->cur.tok;
+	if (len == 0) {
+		p->e = PE_PARSE;
+		goto exit;
+	} else if (len > UINT32_MAX) {
+		p->e = PE_STRTOOBIG;
+		goto exit;
+	} else if (!p_insstr(p, PN_QSTR, p->cur.tok, (uint32_t)len))
+		goto exit;
+
+	p->cur.tok = t;
+	p->e = PE_OK;
+
+ exit:
+	return !p->e;
+}
+
+int
+p_qstr(struct parctx *p)
+{
+	struct parcur b;
+
+	return p_chk(p, &b) && p_dquote(p) && (p_qchars(p) || p_opt(p)) &&
+	    p_dquote(p) || p_rwd(p, &b);
+}
+
+int
+p_respbye(struct parctx *p)
+{
+	struct parcur b;
+
+	return p_chk(p, &b) && p_lit(p, IL_BYE) && p_sp(p) &&
+	    p_resptext(p) || p_rwd(p, &b);
+}
+
+int
+p_respdata(struct parctx *p)
+{
+	struct parcur b;
+
+	return p_chk(p, &b) && p_lit(p, IL_ASTERISK) &&
+	    p_sp(p) && (p_respstate(p) ||
+	    p_respbye(p) || p_mbdata(p) || p_msgdata(p) ||
+	    p_capdata(p)) && p_lit(p, IL_EOL) || p_rwd(p, &b);
+}
+
+int
+p_respln(struct parctx *p)
+{
+	return p_contreq(p) || p_respdata(p) || p_taggedresp(p);
+}
+
+int
+p_respstate(struct parctx *p)
+{
+	struct parcur b;
+
+	return p_chk(p, &b) &&
+	    (p_lit(p, IL_OK) || p_lit(p, IL_NO) || p_lit(p, IL_BAD)) &&
+	    p_sp(p) && p_resptext(p) || p_rwd(p, &b);
+}
+
+int
+p_resptext(struct parctx *p)
+{
+	int res;
+	struct parcur b;
+
+	res = p_chk(p, &b) && p_lit(p, IL_OBRACK) &&
+	    p_resptextcode(p) && p_lit(p, IL_CBRACK) &&
+	    p_sp(p) || p_rwd(p, &b) || p_opt(p);
+
+	return res && p_text(p);
+}
+
+int
+p_resptextcode(struct parctx *p)
+{
+	return p_lit(p, IL_ALERT) || p_badcscode(p) ||
+	    p_capdata(p) || p_lit(p, IL_PARSE) ||
+	    p_permflcode(p) || p_lit(p, IL_RO) ||
+	    p_lit(p, IL_RW) || p_lit(p, IL_TRYC) ||
+	    p_uidncode(p) || p_uidvcode(p) ||
+	    p_unseencode(p) || p_gencode(p);
+}
+
+int
+p_secmsgtxt(struct parctx *p)
+{
+	struct parcur b;
+
+	return p_chk(p, &b) && p_lit(p, IL_HDR) ||
+	    (p_lit(p, IL_HDRFIELDS) && (p_lit(p, IL_DNOT) || p_opt(p)) &&
+	    p_sp(p) && p_hdrlist(p) || p_rwd(p, &b)) || p_lit(p, IL_TXT);
+}
+
+int
+p_secpt(struct parctx *p)
+{
+	return p_listsep(p, p_nznum, IL_DOT);
+}
+
+int
+p_secspec(struct parctx *p)
+{
+	struct parcur b, o;
+
+	return p_chk(p, &b) && p_secmsgtxt(p) || (p_secpt(p) &&
+	    (p_chk(p, &o) && p_lit(p, IL_DOT) && p_sectxt(p) ||
+	    p_rwd(p, &o) || p_opt(p))) || p_rwd(p, &b);
+}
+
+int
+p_section(struct parctx *p)
+{
+	struct parcur b;
+
+	return p_chk(p, &b) && p_lit(p, IL_OBRACK) &&
+	    (p_secspec(p) || p_opt(p)) &&
+	    p_lit(p, IL_CBRACK) || p_rwd(p, &b);
+}
+
+int
+p_sectxt(struct parctx *p)
+{
+	return p_secmsgtxt(p) || p_lit(p, IL_MIME);
+}
+
+int
+p_statt(struct parctx *p)
+{
+	return p_lit(p, IL_MSGS) || p_lit(p, IL_RECENT) ||
+	    p_lit(p, IL_UIDNEXT) || p_lit(p, IL_UIDVAL) ||
+	    p_lit(p, IL_UNSEEN);
+}
+
+int
+p_stattrec(struct parctx *p)
+{
+	struct parcur b;
+
+	return p_chk(p, &b) && p_statt(p) && p_sp(p) &&
+	    p_num(p) || p_rwd(p, &b);
+}
+
+int
+p_str(struct parctx *p)
+{
+	return p_qstr(p) || p_lstr(p);
+}
+
+int
+p_tag(struct parctx *p)
+{
+	return p_repchr(p, tag_specials, LEN(tag_specials), PN_STR);
+}
+
+int
+p_taggedresp(struct parctx *p)
+{
+	struct parcur b;
+
+	return p_beg(p, &b, IP_TAGGEDRESP) && (p_tag(p) && p_sp(p) &&
+	    p_respstate(p) && p_lit(p, IL_EOL) || p_rwd(p, &b)) &&
+	    p_end(p, &b);
+}
+
+int
+p_text(struct parctx *p)
+{
+	const char *t;
+	size_t len;
+
+	t = p->cur.tok;
+	while (t != p->tokend && *t >= '\1' && *t <= '\x7f' &&
+	    *t != '\r' && *t != '\n')
+		t++;
+
+	len = t - p->cur.tok;
+	if (len == 0) {
+		p->e = PE_PARSE;
+		goto exit;
+	} else if (len > UINT32_MAX) {
+		p->e = PE_STRTOOBIG;
+		goto exit;
+	}
+	if (!p_insstr(p, PN_STR, p->cur.tok, (uint32_t)len))
+		goto exit;
+
+	p->cur.tok = t;
+	p->e = PE_OK;
+
+ exit:
+	return !p->e;
+}
+
+int
+p_time(struct parctx *p)
+{
+	struct parcur b;
+
+	return p_chk(p, &b) && p_dig(p, 2) && p_lit(p, IL_COLON) &&
+	    p_dig(p, 2) && p_lit(p, IL_COLON) && p_dig(p, 2) || p_rwd(p, &b);
+}
+
+int
+p_uid(struct parctx *p)
+{
+	return p_nznum(p);
+}
+
+int
+p_uidncode(struct parctx *p)
+{
+	return p_3xcombo(p, IL_UIDNEXT, IL_SP, p_nznum);
+}
+
+int
+p_uidvcode(struct parctx *p)
+{
+	return p_3xcombo(p, IL_UIDVAL, IL_SP, p_nznum);
+}
+
+int
+p_unseencode(struct parctx *p)
+{
+	return p_3xcombo(p, IL_UNSEEN, IL_SP, p_nznum);
+}
+
+int
+p_year(struct parctx *p)
+{
+	return p_dig(p, 4);
+}
+
+int
+p_zone(struct parctx *p)
+{
+	struct parcur b;
+
+	return p_chk(p, &b) &&
+	    (p_lit(p, IL_PLUS) || p_lit(p, IL_MINUS)) &&
+	    p_dig(p, 4) || p_rwd(p, &b);
+}
+
+/* shortcuts for some common literals and means
+   of imrpoving legibility of bulky productions */
+
+int
+p_cpar(struct parctx *p)
+{
+	return p_lit(p, IL_CPAR);
+}
+
+int
+p_dquote(struct parctx *p)
+{
+	return p_lit(p, IL_DQUOTE);
+}
+
+int
+p_opar(struct parctx *p)
+{
+	return p_lit(p, IL_OPAR);
+}
+
+int
+p_sp(struct parctx *p)
+{
+	return p_lit(p, IL_SP);
+}
diff --git a/parser.h b/parser.h
new file mode 100644
index 0000000..edd74ac
--- /dev/null
+++ b/parser.h
@@ -0,0 +1,139 @@
+enum {
+	IL_7BIT,
+	IL_8BIT,
+	IL_ALERT,
+	IL_APP,
+	IL_APR,
+	IL_ASTERISK,
+	IL_AUDIO,
+	IL_AUG,
+	IL_AUTHEQ,
+	IL_B64,
+	IL_BAD,
+	IL_BADCS,
+	IL_BIN,
+	IL_BODY,
+	IL_BSLASH,
+	IL_BYE,
+	IL_CAP,
+	IL_CBRACE,
+	IL_CBRACK,
+	IL_COLON,
+	IL_CPAR,
+	IL_DEC,
+	IL_DHDR,
+	IL_DNOT,
+	IL_DOT,
+	IL_DQUOTE,
+	IL_DTXT,
+	IL_ENVELOPE,
+	IL_EOL,
+	IL_EXISTS,
+	IL_EXPUNGE,
+	IL_FEB,
+	IL_FETCH,
+	IL_FLAGS,
+	IL_FLANSWERED,
+	IL_FLANY,
+	IL_FLDELETED,
+	IL_FLDRAFT,
+	IL_FLFLAGGED,
+	IL_FLMARKED,
+	IL_FLNOINFERIORS,
+	IL_FLNOSEL,
+	IL_FLRECENT,
+	IL_FLSEEN,
+	IL_FLUNMARKED,
+	IL_GT,
+	IL_HDR,
+	IL_HDRFIELDS,
+	IL_IMG,
+	IL_INBOX,
+	IL_INTDATE,
+	IL_JAN,
+	IL_JUL,
+	IL_JUN,
+	IL_LIST,
+	IL_LSUB,
+	IL_LT,
+	IL_MAR,
+	IL_MAY,
+	IL_MIME,
+	IL_MINUS,
+	IL_MSG,
+	IL_MSGS,
+	IL_NIL,
+	IL_NO,
+	IL_NOV,
+	IL_OBRACE,
+	IL_OBRACK,
+	IL_OCT,
+	IL_OK,
+	IL_OPAR,
+	IL_PARSE,
+	IL_PERMFL,
+	IL_PLUS,
+	IL_QPRN,
+	IL_RECENT,
+	IL_RFC822,
+	IL_RFC822SIZE,
+	IL_RO,
+	IL_RW,
+	IL_SEARCH,
+	IL_SEP,
+	IL_SP,
+	IL_STATUS,
+	IL_STRUCT,
+	IL_TRYC,
+	IL_TXT,
+	IL_UID,
+	IL_UIDNEXT,
+	IL_UIDVAL,
+	IL_UNSEEN,
+	IL_VIDEO,
+};
+
+enum {
+	IP_ASTR,
+	IP_ATOM,
+	IP_CAP,
+	IP_ENVBCC,
+	IP_ENVCC,
+	IP_ENVFROM,
+	IP_ENVREPTO,
+	IP_ENVSENDER,
+	IP_ENVTO,
+	IP_TAGGEDRESP,
+};
+
+enum { PN_INTER, PN_LIT, PN_NUM, PN_STR, PN_QSTR, PN_LSTR, PN_OBLSTR };
+
+enum { PE_OK, PE_PARSE, PE_NOTENNODES, PE_STRTOOBIG };
+
+union parnode {
+	int type;
+	struct {
+		int type;
+		int prod;
+		size_t len;
+	} inter;
+	struct {
+		int type;
+		int val;
+	} lit;
+	struct {
+		int type;
+		uint32_t val;
+	} num;
+	struct {
+		int type;
+		uint32_t len;
+		union {
+			const char *tok;
+			size_t iob;
+		};
+	} str;
+};
+
+int par_respln(const char *tok, size_t toklen, union parnode *pt,
+    size_t ptlen, size_t oblth);
diff --git a/pshades.c b/pshades.c
index 8c667b1..40873e2 100644
--- a/pshades.c
+++ b/pshades.c
@@ -4,7 +4,7 @@
 #include <stdio.h>
 #include <unistd.h>
 
-#include "parse.h"
+#include "parser.h"
 
 #define LEN(a) (sizeof(a) / sizeof(a)[0])
 
@@ -43,8 +43,8 @@ char *literals[] = {
 	"UIDVAL", "UNSEEN", "VIDEO"
 };
 
-void ptprint(union parse_node *, size_t);
-union parse_node *ptnext(union parse_node *);
+void ptprint(union parnode *, size_t);
+union parnode *ptnext(union parnode *);
 
 int
 main(int argc, char **argv)
@@ -52,7 +52,7 @@ main(int argc, char **argv)
 	size_t l, inlen;
 	ssize_t n;
 	char input[1024], *p;
-	union parse_node pt[1024];
+	union parnode pt[1024];
 	int e;
 
 	p = input;
@@ -74,15 +74,15 @@ main(int argc, char **argv)
 
 	inlen = p - input;
 
-	if ((e = parse_respln(input, inlen, pt, LEN(pt), 1024)))
+	if ((e = par_respln(input, inlen, pt, LEN(pt), 1024)))
 		errx(1, "error parsing input: %s",  perr[e]);
 
 	ptprint(pt, 0);
 	return 0;
 }
 
-union parse_node *
-ptnext(union parse_node *n)
+union parnode *
+ptnext(union parnode *n)
 {
 	if (n->type == PN_INTER)
 	    n += n->inter.len;
@@ -91,7 +91,7 @@ ptnext(union parse_node *n)
 }
 
 void
-ptprint(union parse_node *n, size_t depth)
+ptprint(union parnode *n, size_t depth)
 {
 	static char *prefix = "               >";
 	size_t nend;