Syntactic Markup Using TXL

Software Transformation Systems
TXL solution to TIL Chairmarks #4.7: Syntactic markup - Marking up program statements or expressions with some structural property.

This example demonstrates the use of agile parsing to mark up statements with a specified structural property, in this case embedded output. This is a specialization of the generalized markup technique described in the IWPC 2003 paper, "Generalized Selective XML Markup of Source Code using Agile Parsing".

-- JamesCordy - 06 Jan 2008

File "TILmarkup.Txl"

% TXL transformation to mark up statements of a TIL program with some syntactic property 
% Jim Cordy, January 2008

% This program marks up with XML tags all statements in a TIL program
% matching some property specified using a syntactic pattern.

% Based on the TIL base grammar
include "TIL.Grm"

% Preserve commenting, since we may want to display or maintain the result
include "TILCommentOverrides.Grm"


% Grammar overrides to allow for XML tags on TIL statements.
% The same paradigm can be used for any other nonterminal type.

redefine statement
        ...
    |   [marked_statement]
end redefine

define marked_statement
        [xml_tag]         [NL][IN]    % [NL] etc specify pretty tag printing
            [statement]   [EX]
        [xml_endtag]      [NL]
end redefine


% Simple grammar for basic XML markup tags.
% [SPOFF] and [SPON] ("spacing off" and "spacing on") allow for local precise 
% control of TXL output spacing, in this case no spacing % between < and >.

define xml_tag
        '< [SPOFF] [id] '> [SPON]
end define

define xml_endtag
        '< [SPOFF] '/ [id] '> [SPON]
end define


% Our main function just gathers the steps of the transformation -
% in this case only one rule so far

function main
    replace [program]
        P [program]
    % We need a dummy statement to seed the markup
    construct NullStmt [statement]
        '// dummy 
    by
        P [markupMatchingStatements NullStmt]
end function

% Condition function to specifiy the property we're interested in
% For this simple example, it's just statements with embedded output statements

function matchesMarkupCriterion
    % We're interested in statements
    match [statement]
        Stmt [statement]
    % That are not themselves output statements
    deconstruct not Stmt
        _ [write_statement]
    % But have embedded output
    deconstruct * Stmt
        _ [write_statement]
end function

% Generic markup rule for statements matching the criterion -
% uses the general paradigm from the IWPC 2003 paper
% "Generalized Selective XML Markup of Source Code using Agile Parsing"
%
% The $ means a one-pass traversal of the code, the "skipping" prevents
% the traversal from reconsidering the same statement after markup.
% The recursive call forces markup of cadidate statements at all levels,
% and the "deconstruct not" ensures we don't recursively re-mark the same statement

rule markupMatchingStatements ThisStmt [statement]
    % Don't mark already marked statements
    skipping [marked_statement]

    % Make a one pass traversal over the statements of the program
    replace $ [statement]
        Stmt [statement]

    % Don't recursively re-mark the same statement 
    deconstruct not Stmt
        ThisStmt

    % Make sure it has the property we're interested in ...
    where 
        Stmt [matchesMarkupCriterion]

    % ... and if so, mark it
    by
        <matches>
            Stmt [markupMatchingStatements Stmt] 
        </matches>
end rule

Example run:

"factors.til" is one of the TIL example programs.

<linux> cat factors.til
// Factor an input number
var n;
write "Input n please";
read n;
write "The factors of n are";
var f;
f := 2;
while n != 1 do
    while (n / f) * f = n do
        write f;
        n := n / f;
    end
    f := f + 1;
end

<linux> txl factors.til TILmarkup.Txl
TXL v10.5 (11.12.07) (c)1988-2007 Queen's University at Kingston
Compiling TILmarkup.Txl ... 
Parsing factors.til ...
Transforming ...

// Factor an input number
var n;
write "Input n please";
read n;
write "The factors of n are";
var f;
f := 2;
<matches>
    while n != 1 do
        <matches>
            while (n / f) * f = n do
                write f;
                n := n / f;
            end
        </matches>
        f := f + 1;
    end
</matches>

<linux> 

-- JamesCordy - 06 Jan 2008