1 #LyX 1.4.0cvs created this file. For more info see http://www.lyx.org/
5 \textclass literate-article
8 % This relaxes the noweb constraint that chunks are
9 % never broken across pages.
11 % This is from the noweb FAQ
13 \def\nwendcode{\endtrivlist \endgroup}
14 \let\nwdocspar=\smallbreak
17 \inputencoding default
20 \paperfontsize default
27 \paperorientation portrait
30 \paragraph_separation indent
32 \quotes_language english
36 \paperpagestyle default
37 \tracking_changes false
53 Sylvan <kayvan@sylvan.com>
61 \begin_layout Abstract
63 This document describes and implements a perl script for importing noweb
67 \begin_layout Standard
70 \begin_inset LatexCommand \tableofcontents{}
77 \begin_layout Standard
90 \begin_layout Standard
92 Since version 1.0.1, LyX now supports Literate Programming using
97 This addition to LyX made it very pleasant to write programs in the literate
98 style (like this one).
99 In addition to being able to write new literate programs, it would be quite
104 code could be imported into LyX in some fashion.
105 That's where this program comes in.
108 \begin_layout Standard
129 # Copyright (C) 1999 Kayvan A.
130 Sylvan <kayvan@sylvan.com>
132 # You are free to use and modify this code under the terms of
134 # the GNU General Public Licence version 2 or later.
138 # Written with assistance from:
140 # Edmar Wienskoski Jr.
141 <edmar-w-jr@technologist.com>
143 # Amir Karger <karger@post.harvard.edu>
147 # $Id: noweb2lyx.lyx,v 1.5 2005/07/18 09:42:27 jamatos Exp $
151 # NOTE: This file was automatically generated from noweb2lyx.lyx using noweb.
155 <<Setup variables from user supplied args>>
159 <<Convert noweb to LyX>>
164 \begin_layout Section
166 The Noweb file defined
169 \begin_layout Standard
175 file is a collection of documentation and code chunks.
176 Documentation chunks simply start with an ``@'' and have no name:
179 \begin_layout LyX-Code
181 @ Here is some documentation.
183 We can do arbitrary LaTeX code here.
189 \begin_layout Standard
191 Code chunks look like this:
194 \begin_layout LyX-Code
200 \begin_layout Standard
210 \begin_layout Standard
219 code for the chunk goes here ...}
224 \begin_layout Standard
226 The ``@'' is a necessary delimiter to end the code chunk.
227 The other form that the ``@'' line takes is as follows:
230 \begin_layout LyX-Code
236 \begin_layout Standard
246 \begin_layout Standard
255 code for the chunk ...}
257 @ %def identifier1 identifier2
260 \begin_layout Standard
262 In the latter form, we are declaring to
266 that this code chunk defines identifier1, identifier2, etc.
269 \begin_layout Standard
271 When first tackling this problem, I spoke with members of the LyX team that
272 knew about the literate programming extensions and reLyX (the LaTeX importing
276 \begin_layout Standard
278 One of the first ideas was to extend the reLyX code to understand the
283 This proved to be too hard and presents other problems
287 \begin_layout Standard
289 Not the least of these problems is the fact that << is a quote in French.
295 On the other hand, it turns out that reLyX contains a very useful literal
297 If the input file contains the construct
300 \begin_layout LyX-Code
314 \begin_layout Standard
316 then reLyX will copy the surrounded code to the output file verbatim.
317 Given this, the first part of the translation is easy; we simply have to
318 copy the code chunks into an intermediate file that surrounds them with
334 \begin_layout Standard
336 Once reLyX is done with the input file, the problem is reduced to changing
337 the code chunks from LyX's LaTeX layout to the Scrap layout.
340 \begin_layout Standard
342 There is one final constraint on
347 We want to be able to run it as a simple pre-processor and post-processor
349 We can accomplish this by setting the flags
362 \begin_layout Standard
390 \begin_layout Standard
405 before we reach the main conversion code.
408 \begin_layout Standard
410 With all that preamble out of the way, we now have the basic high-level
411 outline for our code:
416 <<Convert noweb to LyX>>=
420 <<Transform noweb for reLyX>>
424 if ((!$pre_only) && (!$post_only)) {
426 <<Run reLyX on intermediate file>>
441 \begin_layout Section
443 Making a file that reLyX can process
446 \begin_layout Standard
448 In this section, we present the code that performs the task of creating
449 the intermediate file that reLyX can process, using the algorithm that
451 This algorithm is outlined in the code that follows:
456 <<Transform noweb for reLyX>>=
458 <<Setup INPUT and OUTPUT>>
460 inputline: while(<INPUT>)
474 >=/) { # Beginning of a noweb scrap
476 <<Read in and output the noweb code chunk>>
480 s+(.*)/) { # Beginning of a documentation chunk
482 print OUTPUT $1; # We do not need the ``@'' part
492 ]/) { # noweb quoted code
494 <<Perform special input quoting of [[var]]>>
498 print OUTPUT; # Just let the line pass through
504 <<Close INPUT and OUTPUT>>
509 \begin_layout Standard
511 In the code above, we do some pre-processing of the noweb ``[[...]]'' construct.
512 This avoids some problems with reLyX confusing lists composed of ``[[...]]''
518 <<Perform special input quoting of [[var]]>>=
533 \begin_layout Standard
548 \begin_layout Standard
563 file, once we have identified a
567 code chunk, we transform it into a form that is usable by reLyX.
572 <<Read in and output the noweb code chunk>>=
574 <<Save the beginning of the scrap to savedScrap>>
576 <<Concatenate the rest of the scrap>>
578 <<print out the scrap in a reLyXskip block>>
583 \begin_layout Subsection
585 File input and output for the pre-processing step
588 \begin_layout Standard
607 \begin_layout Standard
635 \begin_layout Standard
650 to read and write files.
651 In the code fragment above, we need to read from the input file and write
652 to a file that will be later transformed by reLyX.
653 If we are being called only to pre-process the input file, then there is
654 no need to create a temporary file.
659 <<Setup INPUT and OUTPUT>>=
663 &setup_files($input_file, $output_file);
667 $relyx_file = "temp$$";
669 &setup_files($input_file, $relyx_file);
676 \begin_layout Standard
678 This code uses a small perl subroutine,
691 \begin_layout Standard
706 , which we define below:
717 open(INPUT, "<$in") || die "Can not read $in: $!
721 open(OUTPUT, ">$out") || die "Can not write $out: $!
730 \begin_layout Subsection
739 \begin_layout Standard
741 After we see the beginning of the scrap, we need to read in and save the
742 rest of the scrap for output.
747 <<Save the beginning of the scrap to savedScrap>>=
758 <<Concatenate the rest of the scrap>>=
760 scrapline: while (<INPUT>) {
762 last scrapline if /^@
774 s+$/) {$savedScrap .= $_; last switch; }
778 s+%def.*$/) {$savedScrap .= $_; last switch; }
782 s+(.*)$/) {$savedScrap .= "@
793 \begin_layout Subsection
795 Printing out the scrap
798 \begin_layout Standard
800 The final piece of the first pass of the conversion is done by this code.
805 <<print out the scrap in a reLyXskip block>>=
815 print OUTPUT $savedScrap;
827 print OUTPUT "$endLine";
832 \begin_layout Standard
834 Finally, we need to close the
847 \begin_layout Standard
875 \begin_layout Standard
895 <<Close INPUT and OUTPUT>>=
904 \begin_layout Section
909 \begin_layout Standard
911 In this section, we describe and implement the code that runs reLyX on the
925 \begin_layout Standard
944 \begin_layout Subsection
946 Selecting the document class
949 \begin_layout Standard
951 In order to run reLyX, we need to know the article class of the input document
952 (to choose the corresponding literate document layout).
953 For this, we need to parse the intermediate file.
958 <<Run reLyX on intermediate file>>=
960 <<Parse for document class>>
962 <<Run reLyX with document class>>
967 \begin_layout Standard
969 In the code below, you'll see a strange regular expression to search for
971 The reason for this kludge is that without it, we can't run
979 file that is generated by LyX
983 \begin_layout Standard
1002 \begin_layout Standard
1030 \begin_layout Standard
1045 class and gets confused, so we have to obfuscate it slightly.
1051 With the regular expression as it is, we can actually run
1055 on itself and a produce a quite reasonable LyX file.
1060 <<Parse for document class>>=
1062 open(INPUT, "<$relyx_file") ||
1064 die "Can not read $relyx_file: $!
1068 $class = "article"; # default if none found
1070 parse: while(<INPUT>) {
1076 docu[m]entclass{(.*)}/) {
1091 \begin_layout Subsection
1093 Running reLyX with the corresponding literate document layout
1096 \begin_layout Standard
1098 Now that we know what the document class ought to be, we do:
1103 <<Run reLyX with document class>>=
1105 $doc_class = "literate-" .
1108 die "reLyX returned non-zero: $!
1112 if (system("reLyX -c $doc_class $relyx_file"));
1117 \begin_layout Standard
1119 reLyX performs the main bulk of the translation work.
1120 Note that if the ``literate-
1124 '' document layout is not found, then reLyX will fail with an error.
1125 In that case, you may need to modify your
1129 input file to a supported document type.
1132 \begin_layout Section
1134 Fixing the reLyX output
1137 \begin_layout Standard
1139 We need to perform some post-processing of what reLyX produces in order
1140 to have the best output for our literate document.
1141 The outline of the post-processing steps are:
1146 <<Fix up LyX file>>=
1148 <<Setup INPUT and OUTPUT for the final output>>
1150 line: while(<INPUT>)
1154 <<Fix code chunks in latex layout>>
1156 <<Fix [[var]] noweb construct>>
1158 print OUTPUT; # default
1162 <<Close INPUT and OUTPUT>>
1167 \begin_layout Standard
1169 Note that in the perl code that is contained in the
1182 \begin_layout Standard
1197 loop above, the perl construct
1210 \begin_layout Standard
1225 is sufficient to restart the loop.
1226 We can use this construct to do some relatively complex parsing of the
1227 reLyX generated file.
1230 \begin_layout Subsection
1232 File input and output for the post-processing
1235 \begin_layout Standard
1250 \begin_layout Standard
1278 \begin_layout Standard
1293 is taken care of by this code:
1298 <<Setup INPUT and OUTPUT for the final output>>=
1302 &setup_files("$input_file", "$output_file");
1306 &setup_files("$relyx_file.lyx", "$output_file");
1313 \begin_layout Subsection
1315 Making sure the code chunks are in the Scrap layout
1318 \begin_layout Standard
1320 Now, as we outlined before, the final step is transforming the code-chunks
1321 which have been put into a LaTeX layout by LyX into the scrap layout.
1326 <<Fix code chunks in latex layout>>=
1332 latex latex/) { # Beginning of some latex code
1334 if (($line = <INPUT>) =~ /^
1336 s*<</) { # code scrap
1338 <<Transform this chunk into layout scrap>>
1344 latex latex line + next line
1346 print OUTPUT "$_$line";
1357 \begin_layout Standard
1359 When we are sure that we are in a code chunk, we must read in the rest of
1360 the code chunk and output a scrap layout for it:
1365 <<Transform this chunk into layout scrap>>=
1377 codeline: while (<INPUT>) {
1381 last codeline if /^@
1387 print OUTPUT $savedScrap;
1389 <<Slurp up to the end of the latex layout>>
1394 \begin_layout Standard
1396 Okay, now we just need to eat the rest of the latex layout.
1397 There should only be a few different types of lines for us to match:
1402 <<Slurp up to the end of the latex layout>>=
1404 slurp: while (<INPUT>) {
1422 warn "confused by line: $_";
1429 \begin_layout Subsection
1442 \begin_layout Standard
1448 allows the user to use a special code quoting mechanism in documentation
1450 Fixing this ``[[quoted-code]]''
1454 syntax means putting the ``[[quoted-code]]'' in a LaTeX layout in the LyX
1456 Otherwise, LyX will backslash-quote the brackets, creating ugly output.
1457 The quoted-code is transformed by
1461 when it generates the final LaTeX code.
1466 <<Fix [[var]] noweb construct>>=
1476 ]/) { # special code for [[var]]
1511 \begin_layout Section
1513 Cleaning up intermediate files
1516 \begin_layout Standard
1518 The cleanup code is very simple:
1525 system("rm -f $relyx_file*") unless ($post_only || $pre_only);
1530 \begin_layout Section
1532 User supplied arguments
1535 \begin_layout Standard
1541 script understands two arguments, input-file and output-file.
1542 It is also set up to be used internally by reLyX to pre-process or postprocess
1543 files in the import pipeline.
1548 <<Setup variables from user supplied args>>=
1550 &usage() if ($#ARGV < 1); # zero or one argument
1552 if ($ARGV[0] eq "-pre") {
1554 &usage unless ($#ARGV == 2);
1556 $input_file = $ARGV[1]; $output_file = $ARGV[2]; $pre_only = 1;
1558 } elsif ($ARGV[0] eq "-post") {
1560 &usage unless ($#ARGV == 2);
1562 $input_file = $ARGV[1]; $output_file = $ARGV[2]; $post_only = 1;
1566 &usage unless ($#ARGV == 1);
1568 $input_file = $ARGV[0]; $output_file = $ARGV[1];
1570 $pre_only = 0; $post_only = 0;
1574 @ %def input_file output_file pre_only post_only
1583 print "Usage: noweb2lyx [-pre | -post] input-file output-file
1587 If -pre is specified, only pre-processes the input-file for reLyX.
1589 Similarly, in the case of -post, post-processes reLyX output.
1591 In case of bugs, Email Kayvan Sylvan <kayvan
1604 \begin_layout Section
1613 \begin_layout Standard
1615 The noweb2lyx script can be tangled from LyX if you set
1621 to call a generic script that always extracts a scrap named
1626 Here is an example of such a script:
1629 \begin_layout LyX-Code
1633 notangle -Rbuild-script $1 | sh
1642 notangle -Rnoweb2lyx.in noweb2lyx.nw > noweb2lyx.in
1644 sed -e "s=@PERL@=$PREFIX/bin/perl=" noweb2lyx.in > noweb2lyx
1652 \begin_layout Standard
1659 \begin_layout Section*
1664 \begin_layout Standard
1679 \begin_layout Standard
1690 \begin_layout Section*
1695 \begin_layout Standard
1710 \begin_layout Standard