source@mandoc.bsd.lv
 help / color / mirror / Atom feed
* mdocml: Support a decent subset of eqn(7) in MathML.
@ 2014-09-28 13:34 kristaps
  0 siblings, 0 replies; only message in thread
From: kristaps @ 2014-09-28 13:34 UTC (permalink / raw)
  To: source

Log Message:
-----------
Support a decent subset of eqn(7) in MathML.
This has basic support for positions (under, sup, sub, sub/sup) and piles.
It *does not* support right-left grouping (among many other things), e.g.,

  a sub b over c sub d

Which it will interpret, for the time being, as

  a sub { b over { c sub d } }

instead of

  { a sub b } over { c sub d }

However, left-right grouping works fine.

Modified Files:
--------------
    mdocml:
        eqn_html.c

Revision Data
-------------
Index: eqn_html.c
===================================================================
RCS file: /usr/vhosts/mdocml.bsd.lv/cvs/mdocml/eqn_html.c,v
retrieving revision 1.4
retrieving revision 1.5
diff -Leqn_html.c -Leqn_html.c -u -p -r1.4 -r1.5
--- eqn_html.c
+++ eqn_html.c
@@ -35,7 +35,8 @@ static	const enum htmltag fontmap[EQNFON
 	TAG_I /* EQNFONT_ITALIC */
 };
 
-static void	eqn_box(struct html *, const struct eqn_box *);
+static const struct eqn_box *
+	eqn_box(struct html *, const struct eqn_box *, int);
 
 
 void
@@ -45,37 +46,164 @@ print_eqn(struct html *p, const struct e
 	struct tag	*t;
 
 	PAIR_CLASS_INIT(&tag, "eqn");
-	t = print_otag(p, TAG_SPAN, 1, &tag);
+	t = print_otag(p, TAG_MATH, 1, &tag);
 
 	p->flags |= HTML_NONOSPACE;
-	eqn_box(p, ep->root);
+	eqn_box(p, ep->root, 1);
 	p->flags &= ~HTML_NONOSPACE;
 
 	print_tagq(p, t);
 }
 
-static void
-eqn_box(struct html *p, const struct eqn_box *bp)
+/*
+ * This function is fairly brittle.
+ * This is because the eqn syntax doesn't play so nicely with recusive
+ * formats, e.g.,
+ *     foo sub bar sub baz
+ * ...needs to resolve into
+ *     <msub> foo <msub> bar, baz </msub> </msub>
+ * In other words, we need to embed some recursive work.
+ * FIXME: this does NOT handle right-left associativity or precedence!
+ */
+static const struct eqn_box *
+eqn_box(struct html *p, const struct eqn_box *bp, int next)
 {
-	struct tag	*t;
-
-	t = EQNFONT_NONE == bp->font ? NULL :
-	    print_otag(p, fontmap[(int)bp->font], 0, NULL);
-
-	if (bp->left)
-		print_text(p, bp->left);
-
-	if (bp->text)
-		print_text(p, bp->text);
-
-	if (bp->first)
-		eqn_box(p, bp->first);
-
-	if (NULL != t)
-		print_tagq(p, t);
-	if (bp->right)
-		print_text(p, bp->right);
-
-	if (bp->next)
-		eqn_box(p, bp->next);
+	struct tag	*post, *pilet, *tmp;
+	struct htmlpair	 tag[2];
+	int		 skiptwo;
+
+	if (NULL == bp)
+		return(NULL);
+
+	post = pilet = NULL;
+	skiptwo = 0;
+
+	/*
+	 * If we're a "row" under a pile, then open up the piling
+	 * context here.
+	 * We do this first because the pile surrounds the content of
+	 * the contained expression.
+	 */
+	if (NULL != bp->parent && bp->parent->pile != EQNPILE_NONE) {
+		pilet = print_otag(p, TAG_MTR, 0, NULL);
+		print_otag(p, TAG_MTD, 0, NULL);
+	}
+
+	/*
+	 * If we're establishing a pile, start the table mode now.
+	 * If we've already in a pile row, then don't override "pilet",
+	 * because we'll be closed out anyway.
+	 */
+	if (bp->pile != EQNPILE_NONE) {
+		tmp = print_otag(p, TAG_MTABLE, 0, NULL);
+		pilet = (NULL == pilet) ? tmp : pilet;
+	}
+
+	/*
+	 * Positioning.
+	 * This is the most complicated part, and actually doesn't quite
+	 * work (FIXME) because it doesn't account for associativity.
+	 * Setting "post" will mean that we're only going to process a
+	 * single or double following expression.
+	 */
+	switch (bp->pos) {
+	case (EQNPOS_SUP):
+		post = print_otag(p, TAG_MSUP, 0, NULL);
+		break;
+	case (EQNPOS_FROM):
+		/* FALLTHROUGH */
+	case (EQNPOS_SUB):
+		post = print_otag(p, TAG_MSUB, 0, NULL);
+		break;
+	case (EQNPOS_OVER):
+		post = print_otag(p, TAG_MFRAC, 0, NULL);
+		break;
+	case (EQNPOS_SUBSUP):
+		/* This requires two elements. */
+		post = print_otag(p, TAG_MSUBSUP, 0, NULL);
+		skiptwo = 1;
+		break;
+	default:
+		break;
+	}
+
+	/*t = EQNFONT_NONE == bp->font ? NULL :
+	    print_otag(p, fontmap[(int)bp->font], 0, NULL);*/
+
+	if (NULL != bp->text) {
+		assert(NULL == bp->first);
+		/*
+		 * We have text.
+		 * This can be a number, a function, a variable, or
+		 * pretty much anything else.
+		 * First, check for some known functions.
+		 * If we're going to create a structural node (e.g.,
+		 * sqrt), then set the "post" variable only if it's not
+		 * already set.
+		 */
+		if (0 == strcmp(bp->text, "sqrt")) {
+			tmp = print_otag(p, TAG_MSQRT, 0, NULL);
+			post = (NULL == post) ? tmp : post;
+		} else if (0 == strcmp(bp->text, "+") ||
+			   0 == strcmp(bp->text, "-") ||
+			   0 == strcmp(bp->text, "=") ||
+			   0 == strcmp(bp->text, "(") ||
+			   0 == strcmp(bp->text, ")") ||
+			   0 == strcmp(bp->text, "/")) {
+			tmp = print_otag(p, TAG_MO, 0, NULL);
+			print_text(p, bp->text);
+			print_tagq(p, tmp);
+		} else {
+			tmp = print_otag(p, TAG_MI, 0, NULL);
+			print_text(p, bp->text);
+			print_tagq(p, tmp);
+		}
+	} else if (NULL != bp->first) {
+		assert(NULL == bp->text);
+		/* 
+		 * If we're a "fenced" component (i.e., having
+		 * brackets), then process those brackets now.
+		 * Otherwise, introduce a dummy row (if we're not
+		 * already in a table context).
+		 */
+		tmp = NULL;
+		if (NULL != bp->left || NULL != bp->right) {
+			PAIR_INIT(&tag[0], ATTR_OPEN,
+				NULL != bp->left ? bp->left : "");
+			PAIR_INIT(&tag[1], ATTR_CLOSE,
+				NULL != bp->right ? bp->right : "");
+			tmp = print_otag(p, TAG_MFENCED, 2, tag);
+			print_otag(p, TAG_MROW, 0, NULL);
+		} else if (NULL == pilet)
+			tmp = print_otag(p, TAG_MROW, 0, NULL);
+		eqn_box(p, bp->first, 1);
+		if (NULL != tmp)
+			print_tagq(p, tmp);
+	}
+
+	/*
+	 * If a positional context, invoke the "next" context.
+	 * This is recursive and will return the end of the recursive
+	 * chain of "next" contexts.
+	 */
+	if (NULL != post) {
+		bp = eqn_box(p, bp->next, 0);
+		if (skiptwo)
+			bp = eqn_box(p, bp->next, 0);
+		print_tagq(p, post);
+	}
+
+	/* 
+	 * If we're being piled (either directly, in the table, or
+	 * indirectly in a table row), then close that out.
+	 */
+	if (NULL != pilet)
+		print_tagq(p, pilet);
+
+	/*
+	 * If we're normally processing, then grab the next node.
+	 * If we're in a recursive context, then don't seek to the next
+	 * node; further recursion has already been handled.
+	 */
+	return(next ? eqn_box(p, bp->next, 1) : bp);
 }
--
 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:[~2014-09-28 13:34 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-09-28 13:34 mdocml: Support a decent subset of eqn(7) in MathML 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).