Tuesday, March 9, 2010

Grammar-centric programming

Let's look at a small Grogix example. Grogix stands for "GRammar-Operated General information computing system"

Again, the notion is to keep the entire system coherent through a single, central grammar.

Around the grammar is an interface to the world. The interface allows the recursive traversal procedure, the one that interprets the grammar, to drive action outside, and receive state-change information from the outside.

This particular interface is a Python program, acting as both a Grogix interpreter, and as a liaison with the Google App Engine framework.

Here's a Grogix grammar for a simple wiki:

. start ... start ... {{default_page}}
. default_page ... default ... {{page_contents}}

. page_contents ... name_value(page) ... {{content_section}}
. page_contents ... name_value(site) ... {{page_section}}
. page_contents ... default ... {{site_section}}

. site_section ... no_item(site) ... {{site_cycle}}
. site_section ... default ... List of Sites: {{sites}}{{br}}{{site_cycle}}{{br}}{{br}}{{br}}{{hr}}{{br}}

. sites ... default ... {{sites:site}} {{br}} <a href="/site={{site.name}}"> {{site.name}}</a> : {{site.value}}
. site_cycle ... post ... {{site_cycle_post_response}}
. site_cycle_post_response ... name_value(add) ... success
. site_cycle ... get ... {{site_cycle_get_response}}
. site_cycle_get_response ... name_value(action) ... {{standard_form}}
. site_cycle_get_response ... default ... <a href="/action=add&item=site">Add a site</a>

. page_section ... no_item(page) ... Site: {{*site}}{{br}}{{page_cycle}}
. page_section ... default ... <a href="/">Back to site overview</a>{{br}}Pages:{{pages}}{{br}}{{page_cycle}}{{br}}{{br}}{{br}}{{hr}}{{br}}

. pages ... default ... {{pages:page}} {{br}} -> <a href="/site={{*site}}&page={{page.name}}">{{page.name}}</a> : {{page.value}}
. page_cycle ... post ... {{page_cycle_post_response}}
. page_cycle_post_response ... name_value(add) ... success
. page_cycle ... get ... {{page_cycle_get_response}}
. page_cycle_get_response ... name_value(action) ... {{standard_form}}
. page_cycle_get_response ... default ... <a href="/site={{*site}}&action=add&item=page">Add a page</a>

. content_section ... no_item(content) ... Page: {{*page}}{{br}}{{content_cycle}}'
. content_section ... default ... <a href="/">Back to site overview</a>{{br}}Content:{{contents}}{{br}}{{content_cycle}}{{br}}{{br}}{{br}}{{hr}}{{br}}

. contents ... default ... {{contents:content}} {{br}} {{content.name}} {{br}} <b>{{content.value}}</b>
. content_cycle ... post ... {{content_cycle_post_response}}
. content_cycle_post_response ... name_value(add) ... success
. content_cycle ... get ... {{content_cycle_get_response}}
. content_cycle_get_response ... name_value(action) ... {{standard_form}}
. content_cycle_get_response ... default ... <a href="/site={{*site}}&page={{*page}}&action=add&item=content">Add content</a>

. standard_form ... default ... <form action="{{form_target}}" method="post"> {{form_name_textarea}}{{form_value_textarea}}{{standard_form_button}}{{form_hiddens}}</form>

. form_name_textarea ... default ... name: <textarea style="height:30px;width:300px;background:#eeee00;" name="name"></textarea>{{br}}

. form_value_textarea ... default ... value: <textarea style="height:30px;width:300px;background:#eeee00;" name="value"></textarea>{{br}}

. standard_form_button ... default ... <span align="left"><input type="Submit" name="button" value="{{standard_form_button_text}}"></span>

. form_target ... add(site) ... /action=add&item=site
. form_target ... add(page) ... /site={{*site}}&action=add&item=page
. form_target ... add(content) ... /site={{*site}}&page={{*page}}&action=add&item=content

. form_hiddens ... default ... {{fh::"landing_site",*site}} {{fh::"next_start","start"}} {{fh::"landing_page",*page}}

. fh ... default ... <input type="hidden" name="{{$1}}" value="{{$2}}">

. standard_form_button_text ... add(site) ... Add Site
. standard_form_button_text ... add(page) ... Add Page
. standard_form_button_text ... add(content) ... Add Content

. br ... default ... <br />

. hr ... default ... <hr />



So, what are you looking at here?

It's a grammar. You can see the "start" non-terminal at the beginning.

It's an ordered set of non-terminal productions. You can see the non-terminal on the left is defined by the phrase on the right ... and the phrase on the right is clearly a text-based template ... the production is 'guarded' by a conditional clause between the non-terminal and the template-like phrase:

. [non-terminal] ... [conditional] ... [defining phrase]

The reason I precede each production with a "dot", is that I like to have free comments, to explain what is going on. This is a nod to Donald Knuth's important observations regarding Literate Programming.

The ordered conditionals determine which productions are followed at run-time.

The defining production itself has further non-terminal references in {{ braces }}.

The productions can also inherit attributes passed from (or bequeathed by) its parent production, which uses this construction: {{ nt :: 'literal', *interface_value, $[inherited_value] }}.

The productions can use information directly from the interface, and can modify interface values, including where the interface should "start" in the grammar on various occasions.

There's an assumed general data-type which associates with a non-terminal, and can be assigned values. It is wound and unraveled with the {{sites:site}} recursive construction, with constraints selected in this way {{contents : content [site,page] }}, where site and page are in this case constraints on the data by those values, passed from the interface.

Note that this was my first working version ... the program itself can obviously be shortened considerably to achieve the same end (there's a repetition I was using while debugging some properties of the interpreter ... discovering this is perhaps a useful exercise for the reader). In any case, in my next installment, I'll show a better grogix grammar for a wiki closer in definition to the original, and deploy the grammar-driven Google App Engine online, so people can try it for themselves.

No comments:

Post a Comment