diff options
-rw-r--r-- | regress/roff/if/real0.in | 30 | ||||
-rw-r--r-- | roff.7 | 15 | ||||
-rw-r--r-- | roff.c | 121 |
3 files changed, 131 insertions, 35 deletions
diff --git a/regress/roff/if/real0.in b/regress/roff/if/real0.in new file mode 100644 index 00000000..28f4aee4 --- /dev/null +++ b/regress/roff/if/real0.in @@ -0,0 +1,30 @@ +.Dd June 9, 2010 +.Dt TITLE 1 +.Os +.Sh NAME +.Nm test +.Nd test +.Sh SYNOPSIS +foo +.Sh DESCRIPTION +to polar +.if n\ +(r,theta) +.if t\ +(r,\(*h) +coordinates +.if n\ +r\(**cos theta +.if t\ +r\(**cos\(*h +and y = +.if n\ +r\(**sin theta. +.if t\ +r\(**sin\(*h. +These +.if n \ +(r=0,theta=0). +.if t \ +(r=0,\(*h=0). +In @@ -173,8 +173,19 @@ BODY... BODY .Ed .Pp -COND is a conditional (for the time being, this always evaluates to -false). +COND is a conditional statement. +roff allows for complicated conditionals; mandoc is much simpler. +At this time, mandoc supports only +.Sq n , +evaluating to true; +and +.Sq t , +.Sq e , +and +.Sq o , +evaluating to false. +All other invocations are read up to the next end of line or space and +evaluate as false. .Pp If the BODY section is begun by an escaped brace .Sq \e{ , @@ -32,6 +32,14 @@ #define ROFF_CTL(c) \ ('.' == (c) || '\'' == (c)) +#if 1 +#define ROFF_DEBUG(fmt, args...) \ + do { /* Nothing. */ } while (/*CONSTCOND*/ 0) +#else +#define ROFF_DEBUG(fmt, args...) \ + do { fprintf(stderr, fmt , ##args); } while (/*CONSTCOND*/ 0) +#endif + enum rofft { ROFF_am, ROFF_ami, @@ -103,6 +111,7 @@ static enum rofferr roff_ccond(ROFF_ARGS); static enum rofferr roff_cond(ROFF_ARGS); static enum rofferr roff_cond_text(ROFF_ARGS); static enum rofferr roff_cond_sub(ROFF_ARGS); +static enum roffrule roff_evalcond(const char *, int *); static enum rofferr roff_line(ROFF_ARGS); /* See roff_hash_find() */ @@ -306,10 +315,15 @@ roff_parseln(struct roff *r, int ln, if (r->last && ! ROFF_CTL((*bufp)[pos])) { t = r->last->tok; assert(roffs[t].text); + ROFF_DEBUG("roff: intercept scoped text: %s, [%s]\n", + roffs[t].name, &(*bufp)[pos]); return((*roffs[t].text) (r, t, bufp, szp, ln, pos, pos, offs)); - } else if ( ! ROFF_CTL((*bufp)[pos])) + } else if ( ! ROFF_CTL((*bufp)[pos])) { + ROFF_DEBUG("roff: pass non-scoped text: [%s]\n", + &(*bufp)[pos]); return(ROFF_CONT); + } /* * If a scope is open, go to the child handler for that macro, @@ -319,6 +333,8 @@ roff_parseln(struct roff *r, int ln, if (r->last) { t = r->last->tok; assert(roffs[t].sub); + ROFF_DEBUG("roff: intercept scoped context: %s\n", + roffs[t].name); return((*roffs[t].sub) (r, t, bufp, szp, ln, pos, pos, offs)); } @@ -330,9 +346,14 @@ roff_parseln(struct roff *r, int ln, */ ppos = pos; - if (ROFF_MAX == (t = roff_parse(*bufp, &pos))) + if (ROFF_MAX == (t = roff_parse(*bufp, &pos))) { + ROFF_DEBUG("roff: pass non-scoped non-macro: [%s]\n", + &(*bufp)[pos]); return(ROFF_CONT); + } + ROFF_DEBUG("roff: intercept new-scope: %s, [%s]\n", + roffs[t].name, &(*bufp)[pos]); assert(roffs[t].proc); return((*roffs[t].proc) (r, t, bufp, szp, ln, ppos, pos, offs)); @@ -684,12 +705,37 @@ roff_cond_text(ROFF_ARGS) } +static enum roffrule +roff_evalcond(const char *v, int *pos) +{ + + switch (v[*pos]) { + case ('n'): + (*pos)++; + return(ROFFRULE_ALLOW); + case ('e'): + /* FALLTHROUGH */ + case ('o'): + /* FALLTHROUGH */ + case ('t'): + (*pos)++; + return(ROFFRULE_DENY); + default: + break; + } + + while (v[*pos] && ' ' != v[*pos]) + (*pos)++; + return(ROFFRULE_DENY); +} + + /* ARGSUSED */ static enum rofferr roff_cond(ROFF_ARGS) { - int cpos; /* position of the condition */ int sv; + enum roffrule rule; /* Stack overflow! */ @@ -698,20 +744,22 @@ roff_cond(ROFF_ARGS) return(ROFF_ERR); } - cpos = pos; + /* First, evaluate the conditional. */ - if (ROFF_if == tok || ROFF_ie == tok) { - /* - * Read ahead past the conditional. FIXME: this does - * not work, as conditionals don't end on whitespace, - * but are parsed according to a formal grammar. It's - * good enough for now, however. - */ - while ((*bufp)[pos] && ' ' != (*bufp)[pos]) - pos++; - } + if (ROFF_el == tok) { + /* + * An `.el' will get the value of the current rstack + * entry set in prior `ie' calls or defaults to DENY. + */ + if (r->rstackpos < 0) + rule = ROFFRULE_DENY; + else + rule = r->rstack[r->rstackpos]; + } else + rule = roff_evalcond(*bufp, &pos); sv = pos; + while (' ' == (*bufp)[pos]) pos++; @@ -721,30 +769,21 @@ roff_cond(ROFF_ARGS) * really doing anything. Warn about this. It's probably * wrong. */ + if ('\0' == (*bufp)[pos] && sv != pos) { - if ( ! (*r->msg)(MANDOCERR_NOARGS, r->data, ln, ppos, NULL)) - return(ROFF_ERR); - return(ROFF_IGN); + if ((*r->msg)(MANDOCERR_NOARGS, r->data, ln, ppos, NULL)) + return(ROFF_IGN); + return(ROFF_ERR); } if ( ! roffnode_push(r, tok, ln, ppos)) return(ROFF_ERR); - /* XXX: Implement more conditionals. */ + r->last->rule = rule; + + ROFF_DEBUG("roff: cond: %s -> %s\n", roffs[tok].name, + ROFFRULE_ALLOW == rule ? "allow" : "deny"); - if (ROFF_if == tok || ROFF_ie == tok) - r->last->rule = 'n' == (*bufp)[cpos] ? - ROFFRULE_ALLOW : ROFFRULE_DENY; - else if (ROFF_el == tok) { - /* - * An `.el' will get the value of the current rstack - * entry set in prior `ie' calls or defaults to DENY. - */ - if (r->rstackpos < 0) - r->last->rule = ROFFRULE_DENY; - else - r->last->rule = r->rstack[r->rstackpos]; - } if (ROFF_ie == tok) { /* * An if-else will put the NEGATION of the current @@ -756,15 +795,31 @@ roff_cond(ROFF_ARGS) else r->rstack[r->rstackpos] = ROFFRULE_DENY; } - if (r->last->parent && ROFFRULE_DENY == r->last->parent->rule) + + /* If the parent has false as its rule, then so do we. */ + + if (r->last->parent && ROFFRULE_DENY == r->last->parent->rule) { r->last->rule = ROFFRULE_DENY; + ROFF_DEBUG("roff: cond override: %s -> deny\n", + roffs[tok].name); + } + + /* + * Determine scope. If we're invoked with "\{" trailing the + * conditional, then we're in a multiline scope. Else our scope + * expires on the next line. + */ r->last->endspan = 1; if ('\\' == (*bufp)[pos] && '{' == (*bufp)[pos + 1]) { r->last->endspan = -1; pos += 2; - } + ROFF_DEBUG("roff: cond-scope: %s, multi-line\n", + roffs[tok].name); + } else + ROFF_DEBUG("roff: cond-scope: %s, one-line\n", + roffs[tok].name); /* * If there are no arguments on the line, the next-line scope is |