source@mandoc.bsd.lv
 help / color / mirror / Atom feed
* mdocml: Fix adding some minimal intelligence to conditional parser.
@ 2010-06-10 21:42 kristaps
  0 siblings, 0 replies; only message in thread
From: kristaps @ 2010-06-10 21:42 UTC (permalink / raw)
  To: source

Log Message:
-----------
Fix adding some minimal intelligence to conditional parser.  See roff.7
for what's supported.  This simplified the roff_cond() function quite
nicely.  From a bug report by uqs@.

Added regression test based on bug-report example by uqs@.

Also added ROFF_DEBUG to see what the hell the parser is actually doing.
Obviously turned off by default.

Modified Files:
--------------
    mdocml:
        roff.7
        roff.c

Added Files:
-----------
    mdocml/regress/roff/if:
        real0.in

Revision Data
-------------
Index: roff.7
===================================================================
RCS file: /usr/vhosts/mdocml.bsd.lv/cvs/mdocml/roff.7,v
retrieving revision 1.8
retrieving revision 1.9
diff -Lroff.7 -Lroff.7 -u -p -r1.8 -r1.9
--- roff.7
+++ roff.7
@@ -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{ ,
Index: roff.c
===================================================================
RCS file: /usr/vhosts/mdocml.bsd.lv/cvs/mdocml/roff.c,v
retrieving revision 1.87
retrieving revision 1.88
diff -Lroff.c -Lroff.c -u -p -r1.87 -r1.88
--- roff.c
+++ roff.c
@@ -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_ARG
 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
--- /dev/null
+++ 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 
--
 To unsubscribe send an email to source+unsubscribe@mdocml.bsd.lv

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2010-06-10 21:42 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2010-06-10 21:42 mdocml: Fix adding some minimal intelligence to conditional parser kristaps

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).