1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134
|
<?xml version="1.0"?>
<!DOCTYPE literate SYSTEM "literate.dtd" [
<!ENTITY % forS "INCLUDE">
<!ENTITY % forR "IGNORE">
]>
<literate>
<doc>
This document is a very early attempt to illustrate how we might use
XML for "literate programming" with the S language. The idea is that
we write code to be read by ahuman rather than the machine, but that
in the process, we also generate the code. The goal is to develop
more readable, understandable and hence maintainable and useful code.
The topic was pionereed by Donald Knuth and there are various
pieces of software that do it in different format. XML is
a rather natural form. See also
<a href="http://www.oasis-open.org/cover/xmlLitProg.html">Oasis-open</a>
<P />
There are numerous practical benefits associated with using literate
programming techniques. For one, it is easy to comment out code while
still leaving it in the source. It is also easy to have two pieces of
similar code and swap them when experimenting with some modifications.
Also, it is easy to reuse a block of code without having to play
pre-processor tricks.
<P/>
In this example, we are going to mix programming languages within the
same file. We will write an S-language (meaning both SPlus and R and
from here on, simply referred to as S) function which calls a C
routine to perform the computation. The function is uninteresting and
simply computes the process identifier of the R session.
It calls the C function <croutine>getpid</croutine>
to do this.
</doc>
<function language="R">
<doc>
The function takes no arguments and returns
a numeric vector of length 1.
</doc>
<![CDATA[
getpid <-
function() {
.Call("RS_getpid")
}
]]>
</function>
<code language="C">
<a href="includes" />
<a href="RS_getpid" />
</code>
<doc>
The <croutine>getpid</croutine>
is declared in the <file>unistd.h</file>
header file. So we include it here.
</doc>
<code name="includes">
<![CDATA[
#include <unistd.h>
]]>
</code>
<code name="includes">
<![CDATA[
#include <Rinternals.h>
]]>
</code>
<code language="C">
USER_OBJECT_
RS_getpid()
{
USER_OBEJCT_ ans;
pid_t id;
id = getpid();
NEW_NUMERIC(1);
NUMERIC_DATA(ans)[0] = id;
return(id);
}
</code>
<function language="R">
<doc>
This is gratuitous text.
</doc>
while(T) {
<a href="iterate" />
}
</function>
<doc>
Note how we use the <b>sgets</b> entity here to avoid having to use a
CDATA construct to escape the text.
</doc>
<code id="iterate">
if(x > 10)
break
else
x %sgets; rnorm(9)
</code>
<doc>
What we are trying to do here is produce elements
that are processed conditionally.
It appears that INCLUDE and
IGNORE directives have to be within DTDs. (Is this true?)
Hence we escape them here.
</doc>
<code>
<![CDATA[
<![ %forS [
x = y@slot
] ]>
<![ %forR [
x <- y$slot
] ]>
]]>
</code>
</literate>
|