summaryrefslogtreecommitdiff
path: root/web/noweb/src/awk/totex.nw.bad
blob: aa99ff290cefb28a7613c15415ffe4c72e18e6a6 (plain)
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
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
\section{Converting {\tt noweb} markup to {\TeX} markup}
The copyright applies both to the {\tt noweb} source and to the
generated shell script.
<<copyright notice>>=
# Copyright 1991 by Norman Ramsey.  All rights reserved.
# See file COPYRIGHT for more information.
<<totex>>=
#!/bin/sh
<<copyright notice>>
# Don't try to understand this file!  Look at lib/totex.nw in the noweb source!
delay=0 noindex=0
for i do
  case $i in
    -delay)   delay=1   ;;
    -noindex) noindex=1 ;;
    *) echo "This can't happen -- $i passed to totex" 1>&2 ; exit 1 ;;
  esac
done
<<invoke awk program using parameter>>
@
On a forgiving system, we make the awk program an argument:
<<invoke awk program using parameter>>=
nawk '<<awk program for conversion to {\TeX}>>' delay=$delay noindex=$noindex
@
On an ugly system, we have to put it in a file.
<<invoke awk program using file>>=
awkfile=/tmp/totex$$.awk
trap 'rm -f $awkfile; exit 1' 0 1 2 15	# clean up files
cat > $awkfile << 'EOF'
<<awk program for conversion to {\TeX}>>
EOF
nawk -f $awkfile delay=$delay noindex=$noindex
@ 
The markup carefully adds no newlines not already present in the input,
so that the line numbers of the {\TeX} file will be the same as the
numbers of the corresponding {\tt noweb} file.
The variables are:
\begin{description}
\item[\tt code] Nonzero if converting a code chunk.
\item[\tt quoting] Nonzero if quoting code in documentation.
\item[\tt text] Number of characters written since start of
		documentation chunk.
\end{description}
[[text]] is used to write [[\par]] if a newline appears at the
beginning of a documentation chunk without any intervening text.
This subtle trick preserves new-paragraph semantics without requiring
the insertion of a blank line that would throw off the line count.
<<awk program for conversion to {\TeX}>>=
BEGIN		   { code=0 ; quoting=0 ; text=1; <<initialization>> }
/^@begin code/     { code=1 ; printf "\\nwbegincode{%s}", substr($0, 13) }
/^@end code/       { code=0 ; printf "\\nwendcode{}"; lastdefnlabel = "" }
<<special patterns for document chunk 0>>
/^@begin docs/ 	   { text=0 ; printf "\\nwbegindocs{%s}", substr($0, 13) }
/^@end docs/       {          printf "\\nwenddocs{}" }
/^@text /          { line = substr($0, 7) ; text += length - 6
                     if (code)         printf "%s", escape_brace_bslash(line) 
                     else if (quoting) printf "%s", TeXliteral(line)
                     else              printf "%s", line
                   }
/^@nl$/            { if (!code) {<<print [[\nwdocspar]] if no text>>}
                     if (quoting) printf "\\nwnewline"
                     printf "\n" 
                   }
/^@defn /          { name = substr($0, 7); <<defn of [[name]], with cross-reference>> }
/^@use /           { <<set [[optreftag]]>>
                     printf "\\LA{}%s%s\\RA{}", \
                         convquotes(substr($0, 6)), optreftag
                   }
/^@quote$/         { quoting = 1 ; printf "{\\tt{}" }
/^@endquote$/      { quoting = 0 ; printf "}" }
/^@file /          { filename = substr($0, 7); <<clear [[lastxref*]]>>
                     if (!delay) printf "\\nwfilename{%s}", filename 
                   }
/^@literal /       { printf "%s", substr($0, 10) }
/^@header latex /  { <<write {\LaTeX} header>> }
/^@header tex /    { printf "\\input nwmac " }
/^@trailer latex$/ { print "\\end{document}" }
/^@trailer tex$/   { print "\\bye" }
<<xref patterns>>
<<index patterns>>
END		   { printf "\n" }
<<functions>>
@
<<print [[\nwdocspar]] if no text>>=
if (text==0) printf "\\nwdocspar"
text=1
@
Delaying markup is handled by special patterns for the first document chunk.
Because several {\tt noweb} files can be marked up at once, there can be
several document chunks numbered 0.
The later ones are given no special treatment by the simple expedient of
turning [[delay]] off after the first one.
<<special patterns for document chunk 0>>=
/^@begin docs 0$/ { if (delay) next }
/^@end docs 0$/   { if (delay) { 
                      printf "\\nwfilename{%s}", filename; delay=0; next
                    } }
@
<<defn of [[name]], with cross-reference>>=
if (lastxreflabel != "") {
  printf "\\sublabel{%s}", lastxreflabel
  printf "\\nwmargintag{%s}", label2tag(lastxreflabel)
}

<<set [[optreftag]]>>
printf "\\moddef{%s%s}\\%sendmoddef", convquotes(name), optreftag, defns[name]
lastdefnlabel = lastxreflabel
<<clear [[lastxref*]]>>
defns[name] = "plus"
<<set [[optreftag]]>>=
if (lastxrefref != "")
  optreftag = "~" label2tag(lastxrefref)
else
  optreftag = ""
<<functions>>=
function label2tag(label) {
  return "{\\nwtagstyle{}\\subpageref{" label "}}"
}
<<initialization>>=
defns[0] = 0
@ 
<<write {\LaTeX} header>>=
printf "\\documentclass{article}\\usepackage{noweb}\\pagestyle{noweb}\\noweboptions{%s}%s", substr($0, 15),  "\\begin{document}"
@
\subsection{Cross-reference and index support}
<<xref patterns>>=
/^@xref label /     { lastxreflabel = substr($0, 13) }
/^@xref ref /       { lastxrefref   = substr($0, 11) }
/^@xref begindefs$/ { printf "\\nwalsodefined{" }
/^@xref defitem /   { printf "\\\\{%s}", substr($0, 15) }
/^@xref enddefs$/   { printf "}" }
/^@xref beginuses$/ { printf "\\nwused{" }
/^@xref useitem /   { printf "\\\\{%s}", substr($0, 15) }
/^@xref enduses$/   { printf "}" }
/^@xref notused /   { printf "\\nwnotused{%s}", TeXliteral(substr($0, 15)) }
/^@xref nextdef /   { } 
/^@xref prevdef /   { } 
<<clear [[lastxref*]]>>=
lastxreflabel = lastxrefref = ""
<<index patterns>>=
/^@index nl$/               { if (code) print "\\eatline"
                              else print "%" }
/^@index defn / {
         if (!noindex) { arg = substr($0, 13); <<handle index defn of [[arg]]>> } }
/^@index localdefn / {
         if (!noindex) { arg = substr($0, 18); <<handle index defn of [[arg]]>> } }
/^@index use /  {
         if (!noindex) { arg = substr($0, 12); <<handle index use of [[arg]]>> } }
@
Nothing is involved in handling definitions and uses unless there are cross-reference
labels pending.
An index definition or use has its own [[@xref label]] only if it's in documentation;
if it's in code, we use the anchor label of the definition.
(You don't have to know that to understand what happens here, but I thought you
might like to.)
<<handle index defn of [[arg]]>>=
if (lastxreflabel != "") printf "\\nosublabel{%s}", lastxreflabel
if (lastxrefref != "")
  printf "\\nwindexdefn{%s}{%s}{%s}", TeXliteral(arg), indexlabel(arg), lastxrefref
<<clear [[lastxref*]]>>
@
The {\LaTeX} back end ignores uses in code; they get bundled up by a previous filter
(the cross-referencer) and handled elsewhere.
<<handle index use of [[arg]]>>=
if (!code) {
  if (lastxreflabel != "") printf "\\protect\\nosublabel{%s}", lastxreflabel
  if (lastxrefref != "")
    printf "\\protect\\nwindexuse{%s}{%s}{%s}", \
                TeXliteral(arg), indexlabel(arg), lastxrefref
}
<<clear [[lastxref*]]>>
@
Here's the local identifier cross-reference that appears at the end of a code chunk.
We guard everything with \LA{}SI\RA, as before.
<<index patterns>>=
/^@index begindefs$/ { if (!noindex) { printf "\\nwidentdefs{" } }
/^@index isused /    { if (!noindex) { } } # handled by latex
/^@index defitem /   { if (!noindex) { i = substr($0,16); <<write [[i]] with [[\\]]>> } }
/^@index enddefs$/   { if (!noindex) { printf "}" } }
/^@index beginuses$/ { if (!noindex) { printf "\\nwidentuses{"; ucount = 0 } }
/^@index isdefined / { if (!noindex) { } } # latex finds the definitions
/^@index useitem /   { if (!noindex) { i = substr($0, 16); <<write [[i]] with [[\\]]>> 
                                   ulist[ucount++] = i
                                 } }
/^@index enduses$/   { if (!noindex) { printf "}"; <<write [[ulist]]>> } }
<<initialization>>=
ulist[0] = 0
<<write [[i]] with [[\\]]>>=
printf "\\\\{{%s}{%s}}", TeXliteral(i), indexlabel(i)
<<write [[ulist]]>>=
if (lastdefnlabel != "") {
  for (j = 0; j < ucount; j++)
    printf "\\nwindexuse{%s}{%s}{%s}", \
		TeXliteral(ulist[j]), indexlabel(ulist[j]), lastdefnlabel
}
@
\subsubsection{The list of chunks and the index}
The treatments of the list of chunks and the index are similar.
Both use [[\nwixlogsorted]], which writes magic goo into the {\tt .aux} file.
The real cross-referencing is done by the underlying {\LaTeX} code.
<<xref patterns>>=
/^@xref beginchunks$/             { }
/^@xref chunkbegin /              { label = $3; name = substr($0, 19 + length(label)) 
                                    printf "\\nwixlogsorted{c}{{%s}{%s}{", \
				       convquotes(name), label
				  }
/^@xref chunkuse /                { printf "\\nwixu{%s}", substr($0, 16) }
/^@xref chunkdefn /               { printf "\\nwixd{%s}", substr($0, 17) }
/^@xref chunkend$/                { print "}}%" }
/^@xref endchunks$/               { }
<<index patterns>>=
/^@index beginindex$/ { if (!noindex) { } }
/^@index entrybegin / { if (!noindex) { label = $3; name = substr($0, 20 + length(label)) 
                                    printf "\\nwixlogsorted{i}{{%s}{%s}}%%\n", \
                                      TeXliteral(name), indexlabel(name)
                                  } }
/^@index entryuse /   { if (!noindex) { } } # handled by latex
/^@index entrydefn /  { if (!noindex) { } } # handled by latex
/^@index entryend$/   { if (!noindex) { } }
/^@index endindex$/   { if (!noindex) { } }

@
\subsection{Miscellany}
I first insert a newline before the special characters, then change the 
newline to a backslash.  I can't do the backslash directly because
[[\&]] means a literal ampersand.
<<functions>>=
function escape_brace_bslash(line) {
  gsub(/[\\{}]/, "\n&", line)
  gsub(/\n/, "\\", line)
  return line
}
@
A special function is used to implement {\tt noweb}'s quoting 
convention within chunk names.
<<functions>>=
function convquotes(s, r, i) {
  r = ""
  while (i = index(s, "[[")) {
    r = r substr(s, 1, i-1) "\\code{}"
    s = substr(s, i+2)
    if (i = match(s, "\\]\\]+")) {
      r = r TeXliteral(substr(s, 1, i-1+RLENGTH-2)) "\\edoc{}"
      s = substr(s, i+RLENGTH)
    } else {
      r = r s "\\edoc{}"
      s = ""
    }
  }
  return r s
}
<<functions>>=
function indexlabel(ident, l) {
  l = ident
  gsub(/:/,  ":col", l)		# must be first  (colon)
  gsub(/ /,  ":sp",  l)      # space
  gsub(/#/,  ":has", l)     # hash
  gsub(/\$/, ":do",  l)      # dollar
  gsub(/%/,  ":pe",  l)      # percent
  gsub(/&/,  ":am",  l)      # ampersand
  gsub(/,/,  ":com", l)     # commad
  gsub(/\\/, ":bs",  l)      # backslash
  gsub(/\^/, ":hat", l)     # hat
  gsub(/_/,  ":un",  l)      # underscore
  gsub(/{/,  ":lb",  l)      # left brace
  gsub(/}/,  ":rb",  l)      # right brace
  gsub(/~/,  ":ti",  l)      # tilde
  return l
}
@ %def indexlabel
@
Because latex2e uses [[`]] as an active character, I have to use 
decimal character codes for the specials.
<<functions>>=
function TeXliteral(arg) {
  gsub(/\\/, "<\\char92>",  arg)
  gsub(/}/,  "<\\char125}", arg)
  gsub(/{/,  "{\\char123}", arg)
  gsub(/<\\char/, "{\\char", arg)
  gsub(/{\\char92>/, "{\\char92}", arg)
  gsub(/\$/, "{\\char36}",  arg)
  gsub(/&/,  "{\\char38}",  arg)
  gsub(/#/,  "{\\char35}",  arg)
  gsub(/\^/, "{\\char94}",  arg)
  gsub(/_/,  "{\\char95}",  arg)
  gsub(/%/,  "{\\char37}",  arg)
  gsub(/~/,  "{\\char126}", arg)
  gsub(/ /,  "\\ ",         arg)
  return arg
}
@ %def TeXliteral