Markup Macro Processor [1300 views]

by Bill Wadge

Screen Shot 2020-09-29 at 6.48.03 PMThe Markup Macro Processor (MMP) is a text based macro system that uses a markup-like syntax, similar to (but much simpler than) XML.

Markup? Who uses markup?

Not many people any more, Markdown being a small exception. Although you can also count Latex with its macros as a kind of markup.

Originally, markup seemed like a great idea. It allowed ordinary people with only a word processor to post Web pages. However those days are gone. Now if you want a snazzy looking Web page you have to know a lot of Javascript and CSS and this is beyond all but the experts. Or you can use some  godawful GUI like Dreamweaver – I myself have never been able to master it.

The main reason that Good Old Fashioned Markup (GOFM) has been abandoned is that traditional systems have no abstraction mechanism. There’s nothing corresponding to functions (in a functional language) or methods (in an OO language). You can’t bundle up boilerplate and introduce new user defined tags that generate the boilerplate.

Well not quite nothing. There’s XSLT and other proposals but they’re so complex they’re not suitable for non-techies, in my opinion.

What I’m proposing is to revive GOFM and give the little guy/gal the  possibility of creating sophisticated pages with a simple text editor.

I propose doing this with a stripped-down, super simple, XML independent,  general purpose macro processor. MMP (Markup Macro Processor) and has been implemented (in a few thousand lines of Java) by Dr Paul Swoboda and myself.

MMP syntax is inspired by two sources: XML/HTML and groff (originally, troff) macros. MMP uses tags (opening, closing, and clopening) and tags can have arguments (arbitrary strings, possibly quoted). That’s it.

Here’s a typical MMP macro call

{page “Introducing Wadge Degrees”}
The {wiki “Wadge hierarchy” Wadge_hierarchy/} was discovered by {me/}.
{/page}

which (given the macro definitions given below) expands to

<html>
<title>Introducing Wadge Degrees</title>
<body>
The <a href=”https://en.wikipedia.org/wiki/Wadge_hierarchy”>Wadge Hierarchy</a> was invented by Bill Wadge.
</body>
</html>

There are three MMP macros in the original source, namely page, wiki, and me. The calls to wiki and me occur inside the ‘body’ of the page macro – the body being the part between the opening and closing tags. Macro expansion is done inside out. The macros wiki and me are first expanded, then page is invoked with the new body.

Here is the definition of the me macro:

{de me}Bill Wadge{/de}

The de macro defines its first argument to be the body of its call.

Here is the definition of the wiki macro:

{de wiki}<a href=”https//en.wikipedia.org/wiki/$2″>$1</a>{/de}

Here $1 and $2 stand for the first and second arguments of the call to wiki.

Finally, here is the definition of the page macro

{de page>
<html>
<title>$1</title>
<body>
$_
</body>
</html>
{/de}

As before, $1 stands for the first argument, and here $_ stands for the body.

In a sense, that’s about it. I’ve told you how macros are called, how they are expanded, and how they are defined. Those are the main three things you have to know about a macro processor.

As a non-trivial example, consider the droptext macro defined below. Droptext is hidden text (or other content) that drops into view when sensitive content is clicked. Our macro is especially simple, the sensitive content is a headline. So for example you may see

How to contact us

and when you  click “How to contact us” you immediately see

How to contact us
   call 1-800-123-4567
   email info@bleen.com

and clicking on “How to contact us” causes the contact information to disappear again.

The droptext macro takes arguments which together form the headline, and a body containing the text that drops up and down. A call to the macro looks like this:

{droptext How to contact us}
call 1-800-123-4567
email info@bleen.com
{/droptext}

and the definition and associated Javascript is as follows

{de droptext}
<div>
<div style=”color:blue”
onMouseOver=”this.style.cursor=’hand'”
onClick=”dt_toggle(this);”>$*</div>
<div style=”display:none; margin-left:5px”>
<p>
$_
</div>
</div>
{/de}
<script>
function dt_toggle(t)
{ if ( t.parentNode.childNodes[3].style.display==’block’ )
{ t.parentNode.childNodes[3].style.display=’none’;
t.style.color = ‘blue’; }
else {
 t.parentNode.childNodes[3].style.display=’block’;
t.style.color = ‘red’; }
 }
</script>

The cleverness is all in the (non obvious) Javascript (which colors the headline blue when the text is hidden, red when it’s showing). But you (or me) has to figure it out only once, and enter it only once. Then to use it you put it in a file – say, droptext.i – and in your source have the macro call {import droptext.i/}. The import macro will include it with your source, unless it’s already been imported  – import will not include multiple copies.

People can use droptext without knowing anything about Javascript. Incidentally, the droptext can be any content including nested calls to droptext.

The script above might seem a problem because MMP treats curly parentheses specially. There is, however, an easy way around this. MMP does not give special attention to open curly parentheses followed by a blank, nor to closed curly parentheses preceded by a blank. The Javascript above has been padded with blanks to avoid such special attention.

But of course there’s a lot more to know about MMP if you want to author macros, not just use them. For a start, there’s built-in ‘system’ macros that don’t work by string substitution. An example is the  + macro which adds its arguments, so for example {+ 3 5 7} evaluates to 15. Especially useful is the replacement macro r which applies regular-expression based substitutions to its body (using Java’s conventions). Thus

{r William Bill}I’m William Wadge{/r}

expands to

I’m Bill Wadge

Another complication is the definition macro: de is not the basic system macro, it has a definition, but treats $ specially. The system definition macro : does not do this, it uses pseudo macros for the arguments (e.g.{1/}) and body ({/_}). The page macro definition becomes

{” : page}
{html}
<title>{1/}</title>
<body>
{_/}
</body>
</html>
{/”}

One subject which is touchy with all macro processors is quoting – blocking expansion temporarily. The above definition is a call to the quote macro, which calls its first argument with the body quoted. We don’t want to try to expand {1/} and {_/} until we have an actual argument and body.

Another complication is scripting. MMP does not have an escape to a conventional scripting language. Possibly a mistake. Instead, it has macros with side effects that can be combined into scripts. This is not as bad as it sounds because MMP allows macros with multiple bodies that are evaluated in sequence. And one can define macros for conditionals, loops, switch statements etc.

There is, however, one source of trouble that I can’t fix, one that is found in any system that introduces layers of abstraction. The trouble is with error handling. What if you’re using a lot of high-level macro calls and you make a mistake? MMP is good at detecting errors but it handles them at the lowest level. What we need to do is intercept them and convert them to messages that make sense at a higher level. I still don’t know of any conventions for doing that.

There’s also some good news. MMP integrates the intensional approach to versioning we applied to web sites. Macros can have separate versions defined separately. As a super simple example, suppose we define

{de greet}Hello{/greet}

and suppose we also have French and Spanish versions of our website. Then we can separately (but in the same file) define French and Spanish versions of our greet macro:

{de greet lang:fr}Salut{/greet}
{de greet lang:sp}Hola{/greet}

Then the call {greet/} evaluated in a context where lang:fr holds produces Salut, and in a context where lang:sp we get Hola. If lang has some other value, or has no value, we default to Hello. Notice that when we call greet we don’t have to specify the versions, the macro picks that up from the ‘atmosphere’.

As I said, MMP has been implemented by Paul Swoboda and myself in a few thousand lines of Java. Although it has been implemented using mindless string copying it’s fast enough to use as a web language. My Uvic colleague Dr Alex Thomo installed it in a Java servlet. Demands come in for .mmp files, the macros are expanded, and the resulting html text generated is sent back as the response.

I haven’t put it on github yet so if you want to try out MMP, mail me at wwadge@me.com.

About Bill Wadge

I am a retired Professor in Computer Science at UVic.
This entry was posted in Uncategorized. Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.