diff options
Diffstat (limited to 'Build/source/texk/web2c/cwebdir/ctwill-w2c.ch')
-rw-r--r-- | Build/source/texk/web2c/cwebdir/ctwill-w2c.ch | 1418 |
1 files changed, 713 insertions, 705 deletions
diff --git a/Build/source/texk/web2c/cwebdir/ctwill-w2c.ch b/Build/source/texk/web2c/cwebdir/ctwill-w2c.ch index 777c3c28484..f194af2c139 100644 --- a/Build/source/texk/web2c/cwebdir/ctwill-w2c.ch +++ b/Build/source/texk/web2c/cwebdir/ctwill-w2c.ch @@ -31,12 +31,13 @@ @y % Here is TeX material that gets inserted after \input ctwimac \def\contentspagenumber{0} % default page number for table of contents +\datethis % Put timestamp before section 1 @z @x -\def\title{CWEAVE (Version 4.2)} +\def\title{CWEAVE (Version 4.3)} @y -\def\title{CTWILL (Version 4.2 [\TeX~Live])} +\def\title{CTWILL (Version 4.3 [\TeX~Live])} @z @x @@ -46,9 +47,9 @@ @z @x - \centerline{(Version 4.2)} + \centerline{(Version 4.3)} @y - \centerline{(Version 4.2 [\TeX~Live])} + \centerline{(Version 4.3 [\TeX~Live])} @z @x @@ -75,7 +76,7 @@ Crusius, and others who have contributed improvements. The ``banner line'' defined here should be changed whenever \.{CWEAVE} is modified. -@d banner "This is CWEAVE (Version 4.2)" +@d banner "This is CWEAVE (Version 4.3)" @y This is the \.{CTWILL} program by D. E. Knuth, based on \.{CWEAVE} by Silvio Levy and D.~E. Knuth. It is also based on @@ -91,180 +92,19 @@ were made only to maintain compatibility with \.{CWEAVE}. Further information can be found in Knuth's article ``Mini-indexes for literate programs,'' reprinted in {\sl Digital Typography\/} (1999), 225--245. +A kind of ``user manual'' for \.{CTWILL} can be found in the appendix +{\bf 272.~Mogrify \.{CWEAVE} into \.{CTWILL}} and beyond, together +with additional material specific to \.{CTWILL}. % FIXME +Until then, \.{CWEAVE}'s sequence of sections will be preserved. + The ``banner line'' defined here should be changed whenever \.{CTWILL} is modified. The version number parallels the corresponding version of \.{CWEAVE}. -@d banner "This is CTWILL, Version 4.2" +@d banner "This is CTWILL, Version 4.3" /* will be extended by the \TeX~Live |versionstring| */ @z @x -@<Predeclaration of procedures@> -@y -@<Predeclaration of procedures@> - -@ Here is a sort of user manual for \.{CTWILL}---which is exactly like -\.{CWEAVE} except that it produces much better documentation, for which you -must work harder. As with \.{CWEAVE}, input comes from a source file -\.{foo.w} and from an optional (but now almost mandatory) change file -\.{foo.ch}; output goes to \.{foo.tex}, \.{foo.idx}, and \.{foo.scn}. -Unlike \.{CWEAVE}, there is an additional output file, \.{foo.aux}, -which records all nonexternal definitions. The \.{.aux} file also -serves as an input file on subsequent runs. You should run \.{CTWILL} -twice, once to prime the pump and once to get decent answers. - -Moreover, you must run the output twice through \TeX. (This double duplicity -suggested the original name \.{TWILL}.) After `\.{tex} \.{foo}' you -will have output that looks like final pages except that the entries -of mini-indexes won't be alphabetized. \TeX\ will say `This is the first -pass', and it will produce a weird file called \.{foo.ref}. Say -$$\.{refsort < foo.ref > foo.sref}$$ -and then another `\.{tex} \.{foo}' will produce alphabetized output. -While \TeX\ runs it emits messages filled with numeric data, indicating how -much space is consumed by each program section. If you can decipher these -numbers (see \.{ctwimac.tex}), you can use them to fine-tune the page -layout. You might be tempted to do fine tuning by editing \.{foo.tex} -directly, but it's better to incorporate all changes into \.{foo.ch}. - -The mini-indexes list identifiers that are used but not defined on -each two-page spread. At the end of each section, \.{CTWILL} gives -\TeX\ a list of identifiers used in that section and information -about where they are defined. The macros in \.{ctwimac.tex} figure out -which identifiers should go in each mini-index, based on how the pages -break. (Yes, those macros are pretty hairy.) - -The information that \.{CTWILL} concocts from \.{foo.w} is not always -correct. Sometimes you'll use an identifier that you don't want -indexed; for example, your exposition might talk about |f(x)| when you -don't mean to refer to program variables |f| or |x|. Sometimes you'll -use an identifier that's defined in a header file, unknown to -\.{CTWILL}. Sometimes you'll define a single identifier in several -different places, and \.{CTWILL} won't know which definition to choose. -But all is not lost. \.{CTWILL} guesses right most of the time, and you can -give it the necessary hints in other places via your change file. - -If you think it's easy to write a completely automatic system that doesn't -make \.{CTWILL}'s mistakes and doesn't depend so much on change files, -please do so. - -\.{CTWILL} uses a very simple method to generate mini-index info. By -understanding this method, you will understand how to fix it when things -go wrong. Every identifier has a current ``meaning,'' consisting of its -abstract type and the number of the section in which it was most recently -defined. For example, if your \Cee\ program says `|char *s|' in section~3, -the meaning of~|s| gets changed to `\&{char} $*$, \S3' while \.{CTWILL} -is processing that section. If you refer to~|s| in section~10, and if -|s|~hasn't been redefined in the meantime, and if section~10 doesn't -wind up on the same two-page spread as section~3, the mini-index generated -by section~10 will say ``|s|: \&{char}~$*$, \S3.'' - -The current meaning of every identifier is initially `\.{\\uninitialized}'. -Then \.{CTWILL} reads the \.{.aux} file for your job, if any; this -\.{.aux} file contains all definitions of new meanings in the previous -run, so it tells \.{CTWILL} about definitions that will be occurring -in the future. If all identifiers have a unique definition, they will -have a unique and appropriate meaning in the mini-indexes. - -But some identifiers, like parameters to procedures, may be defined -several times. Others may not be defined at all, because they are -defined elsewhere and mentioned in header files included by the \Cee\ -preprocessor. To solve this problem, \.{CTWILL} provides mechanisms by which -the current meaning of an identifier can be temporarily or permanently -changed. - -For example, the operation -$$\.{@@\$s \{FOO\}3 \\\&\{char\} \$*\$@@>}$$ -changes the current meaning of |s| to the \TeX\ output of `\.{\\\&\{char\}} -\.{\$*\$}' in section~3 of program {\sc FOO}. All entries in the \.{.aux} -file are expressed in the form of this \.{@@\$} operator; therefore you -can use a text editor to paste such entries into a \.{.ch} file, whenever -you want to tell \.{CTWILL} about definitions that are out of order -or from other programs. - -Before reading the \.{.aux} file, \.{CTWILL} actually looks for a file -called \.{system.bux}, which will be read if present. And after -\.{foo.aux}, a third possibility is \.{foo.bux}. The general -convention is to put definitions of system procedures such as |printf| -into \.{system.bux}, and to put definitions found in specifically -foo-ish header files into \.{foo.bux}. Like the \.{.aux} -files, \.{.bux} files should contain only \.{@@\$} specifications; -this rule corresponds to the fact that `bux' is the plural of `\$'. -The \.{.bux} files may also contain \.{@@i} includes. - -A companion operation \.{@@\%} signifies that all \.{@@\$} -specifications from the present point to the beginning of the next -section will define {\it temporary\/} meanings instead of permanent -ones. Temporary meanings are placed into the -mini-index of the current section; the permanent (current) meaning of -the identifier will not be changed, nor will it appear in the -mini-index of the section. If several temporary meanings are assigned -to the same identifier in a section, all will appear in the mini-index. -Each \.{@@\%} toggles the temporary/permanent convention; thus, after -an even number of \.{@@\%} operations in a section, meanings specified -by \.{@@\$} are permanent. - -The operation \.{@@-} followed by an identifier followed by \.{@@>} -specifies that the identifier should not generate a mini-index entry -in the current section (unless, of course, a temporary meaning is assigned). - -If \.{@@-foo@@>} appears in a section where a new permanent meaning is -later defined by the semantics of~\Cee, the current meaning of \\{foo} -will not be redefined; moreover, this current meaning, which may have -been changed by \.{@@\$foo ...@@>}, will also be written to the -\.{.aux} file. Therefore you can control what \.{CTWILL} outputs; you -can keep it from repeatedly contaminating the \.{.aux} file with -things you don't like. - -The meaning specified by \.{@@\$...@@>} generally has four components: -an identifier (followed by space), a program name (enclosed in braces), -a section number (followed by space), and a \TeX\ part. The \TeX\ part -must have fewer than 50 characters. If the \TeX\ part starts -with `\.=', the mini-index entry will contain an equals sign instead -of a colon; for example, -$$\.{@@\$buf\_size \{PROG\}10 =\\T\{200\}@@>}$$ -generates either `$\\{buf\_size}=200$, \S10' or -`$\\{buf\_size}=200$, {\sc PROG}\S10', depending on whether -`{\sc PROG}' is or isn't the title of the current program. If the -\TeX\ part is `\.{\\zip}', the mini-index entry will contain neither -colon nor equals, just a comma. The program name and section number -can also be replaced by a string. For example, -$$\.{@@\$printf "<stdio.h>" \\zip@@>}$$ -will generate a mini-index entry like `\\{printf}, \.{<stdio.h>}.'. - -A special ``proofmode'' is provided so that you can check \.{CTWILL}'s -conclusions about cross-references. Run \.{CTWILL} with the -flag \.{+P}, and \TeX\ will produce a specially formatted document -({\it without\/} mini-indexes) -in which you can check that your specifications are correct. -You should always do this before generating mini-indexes, because -mini-indexes can mask errors if page breaks are favorable but the -errors might reveal themselves later after your program has changed. -The proofmode output is much easier to check than the mini-indexes themselves. - -The control code \.{@@r} or \.{@@R} causes \.{CTWILL} to emit -the \TeX\ macro `\.{\\shortpage}' just before starting the next -section of the program. This causes the section to appear at the top of -a right-hand page, if it would ordinarily have appeared near the bottom -of a left-hand page and split across the pages. (The \.{\\shortpage} macro -is fragile and should be used only in cases where it will not mess up -the output; insert it only when fine-tuning a set of pages.) If the -next section is a starred section, the behavior is slightly different -(but still fragile): The starred section will either be postponed to -a left-hand page, if it normally would begin on a right-hand page, -or vice versa. In other words, \.{@@r@@*} inverts the left/right logic. - -\.{CTANGLE} does not recognize the operations \.{@@\$}, \.{@@\%}, \.{@@-}, -and \.{@@r}, which are unique to \.{CTWILL}. But that is no problem, -since you use them only in change files set up for book publishing, -which are quite different from the change files you set up for tangling. - -(End of user manual. We now resume the program for \.{CWEAVE}, with occasional -outbursts of new code.) - -@d max_tex_chars 50 /* limit on the \TeX\ part of a meaning */ -@z - -@x program=cweave; @y program=ctwill; @@ -292,126 +132,16 @@ turned on during the first phase---NOT! @z @x -static sixteen_bits xref_switch,section_xref_switch; /* either zero or |def_flag| */ +@d append_xref(c) if (xref_ptr==xmem_end) overflow("cross-reference"); @y -static sixteen_bits xref_switch,section_xref_switch; /* either zero or |def_flag| */ - -@ \.{CTWILL} also has special data structures to keep track of current -and temporary meanings. These structures were not designed for maximum -efficiency; they were designed to be easily grafted into \.{CWEAVE}'s -existing code without major surgery. - -@d max_meanings 100 /* max temporary meanings per section */ -@d max_titles 100 /* max distinct program or header names in meanings */ - -@<Type...@>= -typedef struct { - name_pointer id; /* identifier whose meaning is being recorded */ - sixteen_bits prog_no; /* title of program or header in which defined */ - sixteen_bits sec_no; /* section number in which defined */ - char tex_part[max_tex_chars]; /* \TeX\ part of meaning */ -} meaning_struct; - -@ @<Private...@>= -struct perm_meaning { - meaning_struct perm; /* current meaning of an identifier */ - int stamp; /* last section number in which further output suppressed */ - struct perm_meaning *link; /* another meaning to output in this section */ -} cur_meaning[max_names]; /* the current ``permanent'' meanings */ -static struct perm_meaning *top_usage; /* first meaning to output in this section */ -static meaning_struct temp_meaning_stack[max_meanings]; /* the current ``temporary'' meanings */ -static meaning_struct *temp_meaning_ptr; /* first available slot in |temp_meaning_stack| */ -static meaning_struct *max_temp_meaning_ptr; /* its maximum value so far */ -static name_pointer title_code[max_titles]; /* program names seen so far */ -static name_pointer *title_code_ptr; /* first available slot in |title_code| */ -static char ministring_buf[max_tex_chars]; /* \TeX\ code being generated */ -static char *ministring_ptr; /* first available slot in |ministring_buf| */ -static boolean ms_mode; /* are we outputting to |ministring_buf|? */ - -@ @<Set init...@>= -max_temp_meaning_ptr=temp_meaning_stack; -title_code_ptr=title_code; -ms_mode=false; - -@ Here's a routine that converts a program title from the buffer -into an internal number for the |prog_no| field of a meaning. -It advances |loc| past the title found. - -@c static sixteen_bits title_lookup(void) -{ - char *first,*last; /* boundaries */ - int balance; /* excess of left over right */ - register name_pointer *p; - first=loc; - if (*loc=='"') { - while (++loc<=limit && *loc!='"') if (*loc=='\\') loc++; - } else if (*loc=='{') { - balance=1; - while (++loc<=limit) { - if (*loc=='}' && --balance==0) break; - if (*loc=='{') balance++; - } - } else err_print(_("! Title should be enclosed in braces or doublequotes")); - last=++loc; - if (last>limit) err_print(_("! Title name didn't end")); - if (title_code_ptr==&title_code[max_titles]) overflow(_("titles")); - *title_code_ptr=id_lookup(first,last,title); - for (p=title_code;;p++) if (*p==*title_code_ptr) break; - if (p==title_code_ptr) title_code_ptr++; - return p-title_code; -} - -@ @<Give a default title to the program, if necessary@>= -if (title_code_ptr==title_code) { /* no \.{\\def\\title} found in limbo */ - char *saveloc=loc,*savelimit=limit; - loc=limit+1; limit=loc; - *limit++='{'; - memcpy(limit,tex_file_name,strlen(tex_file_name)-4); - limit+=strlen(tex_file_name)-4; - *limit++='}'; - title_lookup(); - loc=saveloc; limit=savelimit; -} - -@ The |new_meaning| routine changes the current ``permanent meaning'' -when an identifier is redeclared. It gets the |tex_part| from -|ministring_buf|. - -@c -static void -new_meaning( - name_pointer p) -{ - struct perm_meaning *q=p-name_dir+cur_meaning; - ms_mode=false; - if (q->stamp!=section_count) { - if (*(ministring_ptr-1)==' ') ministring_ptr--; - if (ministring_ptr>=&ministring_buf[max_tex_chars]) - strcpy(ministring_buf,"\\zip"); /* ignore |tex_part| if too long */ -@.\\zip@> - else *ministring_ptr='\0'; - q->perm.prog_no=0; /* |q->perm.id=p| */ - q->perm.sec_no=section_count; - strcpy(q->perm.tex_part,ministring_buf); - } - @<Write the new meaning to the \.{.aux} file@>; -} - -@ @<Write the new meaning to the \.{.aux} file@>= -{@+int n=q->perm.prog_no; - fprintf(aux_file,"@@$%.*s %.*s",@| - (int)((p+1)->byte_start-p->byte_start),p->byte_start,@| - (int)((title_code[n]+1)->byte_start-title_code[n]->byte_start), - title_code[n]->byte_start); - if (*(title_code[n]->byte_start)=='{') fprintf(aux_file,"%d",q->perm.sec_no); - fprintf(aux_file," %s@@>\n",q->perm.tex_part); -} +@d append_xref(c) if (xref_ptr==xmem_end) overflow(_("cross-reference")); @z @x -@d append_xref(c) if (xref_ptr==xmem_end) overflow("cross-reference"); +@ Here are the three procedures needed to complete |id_lookup|: @y -@d append_xref(c) if (xref_ptr==xmem_end) overflow(_("cross-reference")); +@ Here are the three procedures needed to complete |id_lookup|: +@s perm_meaning int @z @x @@ -439,15 +169,6 @@ int_loc=id_lookup("int",NULL,raw_int)-name_dir; @z @x -id_lookup("make_pair",NULL,func_template); -@y -id_lookup("make_pair",NULL,func_template); - -@ @<Private...@>= -static sixteen_bits int_loc, ext_loc; /* locations of special reserved words */ -@z - -@x @d ord 0207 /* control code for `\.{@@'}' */ @d join 0210 /* control code for `\.{@@\&}' */ @d thin_space 0211 /* control code for `\.{@@,}' */ @@ -631,58 +352,7 @@ skip_restricted(void) @y @.Control codes are forbidden...@> if (c==meaning && phase==2) @<Process a user-generated meaning@>@; - else if (c==suppress && phase==2) @<Suppress mini-index entry@>; - } -} - -@ @<Suppress mini-index entry@>= -{ char *first=id_first,*last=id_loc; - while (xisspace(*first)) first++; - while (xisspace(*(last-1))) last--; - if (first<last) { - struct perm_meaning *q=id_lookup(first,last,normal)-name_dir+cur_meaning; - q->stamp=section_count; /* this is what actually suppresses output */ - } -} - -@ @<Process a user-generated meaning@>= -{ char *first=id_first; - while (xisspace(*first)) first++; - loc=first; - while (xisalpha(*loc)||xisdigit(*loc)||*loc=='_') loc++; - if (*loc++!=' ') - err_print(_("! Identifier in meaning should be followed by space")); - else { name_pointer p=id_lookup(first,loc-1,normal); - sixteen_bits t; int n=0; - t=title_lookup(); - if (*(loc-1)=='}') - while (xisdigit(*loc)) n=10*n+(*loc++)-'0'; - if (*loc++!=' ') - err_print(_("! Location in meaning should be followed by space")); - else @<Digest the meaning of |p|, |t|, |n|@>; - } - loc=id_loc+2; -} - -@ @<Digest...@>= -{ meaning_struct *m; - struct perm_meaning *q=p-name_dir+cur_meaning; - if (temp_switch) { - m=temp_meaning_ptr++; - if (temp_meaning_ptr>max_temp_meaning_ptr) { - if (temp_meaning_ptr>&temp_meaning_stack[max_meanings]) - overflow(_("temp meanings")); - max_temp_meaning_ptr=temp_meaning_ptr; - } - } else m=&(q->perm); - m->id=p; - m->prog_no=t; - m->sec_no=n; - if (id_loc-loc>=max_tex_chars) strcpy(m->tex_part,"\\zip"); -@.\\zip@> - else { char *q=m->tex_part; - while (loc<id_loc) *q++=*loc++; - *q='\0'; + else if (c==suppress && phase==2) @<Suppress mini-index entry@>@; @z @x @@ -695,7 +365,7 @@ skip_restricted(void) skip_limbo(); change_exists=false; @y skip_limbo(); - @<Give a default title to the program, if necessary@>; + @<Give a default title to the program, if necessary@>@; @z @x @@ -872,10 +542,10 @@ the section is changed, we output `\.{\\*}' just after the number. @z @x -@d end_arg 62 /* \.{@@]} */ +@d attr_head 69 /* denotes beginning of attribute */ @y -@d end_arg 62 /* \.{@@]} */ -@d title 63 /* program name or header name in a ``meaning'' */ +@d attr_head 69 /* denotes beginning of attribute */ +@d title 70 /* program name or header name in a ``meaning'' */ @z @x @@ -903,20 +573,25 @@ null_scrap.trans=&tok_start[0]; @c static void -print_text(@t\1\1@> /* prints a token list for debugging; not used in |main| */ +print_text( /* prints a token list for debugging; not used in |main| */ @y @d inner_tok_flag 5*id_flag /* signifies a token list in `\pb' */ -@c +@<Predecl...@>= #if 0 -static void -print_text(@t\1\1@> /* prints a token list for debugging; not used in |main| */ +static void print_text(text_pointer p); +#endif + +@ @c +#if 0 +@t\4\4@>static void +print_text( /* prints a token list for debugging; not used in |main| */ @z @x update_terminal; @y - printf("|\n"); update_terminal; + puts("|"); update_terminal; @z @x @@ -929,10 +604,6 @@ print_text(@t\1\1@> /* prints a token list for debugging; not used in |main| */ @x @ @<Predecl...@>=@+static void print_text(text_pointer p); @y -@ @<Predecl...@>= -#if 0 -static void print_text(text_pointer p); -#endif @z @x @@ -964,132 +635,9 @@ static token_pointer tok_loc; /* where the first identifier appears */ @z @x - r->num=m; /* everything from |q| on is left undisturbed */ -@y - r->num=m; /* everything from |q| on is left undisturbed */ - -@ \.{CTWILL} needs the following procedure, which appends tokens of a -translated text until coming to |tok_loc|, then suppresses text that may -appear between parentheses or brackets. The calling routine should set -|ident_seen=false| first. (This is admittedly tricky.) - -@c boolean ident_seen; -static boolean app_supp( - text_pointer p) -{ token_pointer j; - text_pointer q; - if (ident_seen && **p>=tok_flag) { - q=**p-tok_flag+tok_start; - if (**q=='(') { - app('(');@+app('\\');@+app(',');@+app(')'); goto catch14; - } - if (**q=='[') { - app('[');@+app('\\');@+app(',');@+app(']'); goto catch14; - } - } - for (j=*p;j<*(p+1);j++) { - if (*j<tok_flag) { - if (*j==inserted) return false; - if (j==tok_loc) ident_seen=true; - else app(*j); - } else if (*j>=inner_tok_flag) confusion(_("inner")); - else if (app_supp(*j-tok_flag+tok_start)) goto catch14;; - } - return false; -catch14: if (*(*(p+1)-1)=='9') return true; /* production 14 was used */ - else return false; -} - -@ The trickiest part of \.{CTWILL} is the procedure |make_ministring(l)|, -which tries to figure out a symbolic form of definition after -|make_underlined(pp+l)| has been called. We rely heavily on the -existing productions, which force the translated texts to have a -structure that's decodable even though the underlying |cat| and |mathness| -codes have disappeared. - -@c static void -make_ministring( - int l) /* 0, 1, or 2 */ -{ - text_pointer q,r; - name_pointer cn; - token t; - int ast_count; /* asterisks preceding the expression */ - boolean non_ast_seen; /* have we seen a non-asterisk? */ - if (tok_loc<=operator_found) return; - cn=((*tok_loc)%id_flag)+name_dir; - @<Append the type of the declaree; |return| if it begins with \&{extern}@>; - null_scrap.mathness=(((pp+l)->mathness)%4)*5; big_app1(&null_scrap); - /* now we're ready for the mathness that follows (I think) */ - /* (without the mod 4 times 5, comments posed a problem) */ - /* (namely in cases like |int a(b,c)| followed by comment) */ - ident_seen=false;@+app_supp((pp+l)->trans); - null_scrap.mathness=10; big_app1(&null_scrap); - /* now |cur_mathness==no_math| */ - ms_mode=true; ministring_ptr=ministring_buf; - if (l==2) *ministring_ptr++='='; - make_output(); /* translate the current text into a ministring */ - tok_ptr=*(--text_ptr); /* delete that text */ - new_meaning(cn); - cur_mathness=maybe_math; /* restore it */ -} - -@ Here we use the fact that a |decl_head| comes from |int_like| only in -production~27, whose translation is fairly easy to recognize. (Well, -production 28 has been added for \CPLUSPLUS/, but we hope that doesn't -mess us up.) And we also use other similar facts. - -If an identifier is given an \&{extern} definition, we don't change -its current meaning, but we do suppress mini-index entries to its -current meaning in other sections. - -@<Append the type of the declaree; |return| if it begins with \&{extern}@>= -if (l==0) { app(int_loc+res_flag); app(' '); cur_mathness=no_math; } -else { - q=(pp+l-1)->trans; - ast_count=0; - non_ast_seen=false; - while (true) { - if (*(q+1)==*q+1) { - r=q;@+break; /* e.g. \&{struct}; we're doing production 45 or 46 */ - } - if (**q<tok_flag) confusion(_("find type")); - r=**q-tok_flag+tok_start; - if ((t=*(*(q+1)-2))>=tok_flag && **(t-tok_flag+tok_start)=='*') { - /* production 34 */ - if (!non_ast_seen) ast_count++; /* count immediately preceding |*|'s */ - } else non_ast_seen=true; - if (*(*q+1)==' ' && *(q+1)==*q+2) break; /* production 27 */ - if (*(*q+1)=='{' && *(*q+2)=='}' && *(*q+3)=='$' && *(*q+4)==' '@| - && *(q+1)==*q+5) break; /* production 27 in disguise */ - q=r; - } - while (**r>=tok_flag) { - if (*(r+1)>*r+9 && *(*r+1)=='{' && *(*r+2)=='}' && *(*r+3)=='$' @| - && *(*r+4)==indent) q=**r-tok_flag+tok_start; /* production 49 */ - r=**r-tok_flag+tok_start; - } - if (**r==ext_loc+res_flag) return; /* \&{extern} gives no definition */ - @<Append tokens for type |q|@>; -} - -@ @<Append tokens for type |q|@>= -cur_mathness=no_math; /* it was |maybe_math| */ -if (*(q+1)==*q+8 && *(*q+1)==' ' && *(*q+3)==' ') { - app(**q);@+app(' ');@+app(*(*q+2)); /* production 46 */ -} else if ((t=*(*(q+1)-1))>=tok_flag && **(r=t-tok_flag+tok_start)=='\\' - && *(*r+1)=='{') app(**q); /* |struct_like| identifier */ -else app((q-tok_start)+tok_flag); -while (ast_count) { - big_app('{');@+app('*');@+app('}');@+ast_count--; -} - -@z - -@x @<Cases for |exp|@>= if (cat1==lbrace || cat1==int_like || cat1==decl) { - make_underlined(pp); big_app1(pp); big_app(indent); app(indent); + make_underlined(pp); big_app(dindent); big_app1(pp); reduce(pp,1,fn_decl,0,1); } @y @@ -1097,16 +645,13 @@ if (cat1==lbrace || cat1==int_like || cat1==decl) { if(cat1==lbrace || cat1==int_like || cat1==decl) { make_underlined(pp); make_ministring(0); - big_app1(pp); - if (indent_param_decl) { - big_app(indent); app(indent); - } + if (indent_param_decl) big_app(dindent); big_app1(pp); reduce(pp,1,fn_decl,0,1); } @z @x - make_underlined (pp); squash(pp,2,tag,-1,7); + make_underlined (pp); squash(pp,2,tag,-1,7); @y make_underlined (pp); if (tok_loc>operator_found) { @@ -1123,10 +668,9 @@ if (cat1==comma) { big_app2(pp); big_app(' '); reduce(pp,2,decl_head,-1,33); } else if (cat1==ubinop) { - big_app1(pp); big_app('{'); big_app1(pp+1); big_app('}'); - reduce(pp,2,decl_head,-1,34); + big_app1_insert(pp,'{'); big_app('}'); reduce(pp,2,decl_head,-1,34); } -else if (cat1==exp && cat2!=lpar && cat2!=exp && cat2!=cast) { +else if (cat1==exp && cat2!=lpar && cat2!=lbrack && cat2!=exp && cat2!=cast) { make_underlined(pp+1); squash(pp,2,decl_head,-1,35); } else if ((cat1==binop||cat1==colon) && cat2==exp && (cat3==comma || @@ -1134,7 +678,7 @@ else if ((cat1==binop||cat1==colon) && cat2==exp && (cat3==comma || squash(pp,3,decl_head,-1,36); else if (cat1==cast) squash(pp,2,decl_head,-1,37); else if (cat1==lbrace || cat1==int_like || cat1==decl) { - big_app1(pp); big_app(indent); app(indent); reduce(pp,1,fn_decl,0,38); + big_app(dindent); big_app1(pp); reduce(pp,1,fn_decl,0,38); } else if (cat1==semi) squash(pp,2,decl,-1,39); @y @@ -1143,10 +687,10 @@ if (cat1==comma) { big_app2(pp); big_app(' '); reduce(pp,2,decl_head,-1,33); } else if (cat1==ubinop) { - big_app1(pp); big_app('{'); big_app1(pp+1); big_app('}'); + big_app1_insert(pp,'{'); big_app('}'); reduce(pp,2,decl_head,-1,34); } -else if (cat1==exp && cat2!=lpar && cat2!=exp && cat2!=cast) { +else if (cat1==exp && cat2!=lpar && cat2!=lbrack && cat2!=exp && cat2!=cast) { make_underlined(pp+1); make_ministring(1); squash(pp,2,decl_head,-1,35); @@ -1156,10 +700,7 @@ else if ((cat1==binop||cat1==colon) && cat2==exp && (cat3==comma || squash(pp,3,decl_head,-1,36); else if (cat1==cast) squash(pp,2,decl_head,-1,37); else if (cat1==lbrace || cat1==int_like || cat1==decl) { - big_app1(pp); - if (indent_param_decl) { - big_app(indent); app(indent); - } + if (indent_param_decl) big_app(dindent); big_app1(pp); reduce(pp,1,fn_decl,0,38); } else if (cat1==semi) squash(pp,2,decl,-1,39); @@ -1168,24 +709,19 @@ else if (cat1==semi) squash(pp,2,decl,-1,39); @x @ @<Cases for |decl|@>= if (cat1==decl) { - big_app1(pp); big_app(force); big_app1(pp+1); - reduce(pp,2,decl,-1,40); + big_app1_insert(pp,force); reduce(pp,2,decl,-1,40); } else if (cat1==stmt || cat1==function) { - big_app1(pp); big_app(big_force); - big_app1(pp+1); reduce(pp,2,cat1,-1,41); + big_app1_insert(pp,big_force); reduce(pp,2,cat1,-1,41); } @y @ @<Cases for |decl|@>= if (cat1==decl) { - big_app1(pp); big_app(force); big_app1(pp+1); - reduce(pp,2,decl,-1,40); + big_app1_insert(pp,force); reduce(pp,2,decl,-1,40); } else if (cat1==stmt || cat1==function) { - big_app1(pp); - if(order_decl_stmt) big_app(big_force); - else big_app(force); - big_app1(pp+1); reduce(pp,2,cat1,-1,41); + big_app1_insert(pp,order_decl_stmt ? big_force : force); + reduce(pp,2,cat1,-1,41); } @z @@ -1199,7 +735,7 @@ else if (cat1==stmt || cat1==function) { @x @ @<Cases for |fn_decl|@>= if (cat1==decl) { - big_app1(pp); big_app(force); big_app1(pp+1); reduce(pp,2,fn_decl,0,51); + big_app1_insert(pp,force); reduce(pp,2,fn_decl,0,51); } else if (cat1==stmt) { big_app1(pp); app(outdent); app(outdent); big_app(force); @@ -1208,25 +744,31 @@ else if (cat1==stmt) { @y @ @<Cases for |fn_decl|@>= if (cat1==decl) { - big_app1(pp); big_app(force); big_app1(pp+1); reduce(pp,2,fn_decl,0,51); + big_app1_insert(pp,force); reduce(pp,2,fn_decl,0,51); } else if (cat1==stmt) { big_app1(pp); if (indent_param_decl) { app(outdent); app(outdent); } - big_app(force); - big_app1(pp+1); reduce(pp,2,function,-1,52); + big_app(force); big_app1(pp+1); reduce(pp,2,function,-1,52); } @z @x + big_app1_insert(pp,dindent); reduce(pp,2,fn_decl,0,73); +@y + big_app1(pp); if (indent_param_decl) big_app(dindent); + big_app1(pp+1); reduce(pp,2,fn_decl,0,73); +@z + +@x if (cat1==define_like) make_underlined(pp+2); @y -if (cat1==define_like) { /* \.{\#define} is analogous to \&{extern} */ +if (cat1==define_like) { /* \#\&{define} is analogous to \&{extern} */ make_underlined(pp+2); if (tok_loc>operator_found) { - /* no time to work out this case; I'll handle defines by brute force + /* no time to work out this case; I'll handle \&{define}s by brute force in the \.{aux} file, since they usually don't go in mini-index */ } } @@ -1241,9 +783,9 @@ else squash(pp,1,exp,-2,122); @z @x - big_app1(pp); big_app(' '); big_app1(pp+1); reduce(pp,2,else_like,-2,102); + big_app1_insert(pp,' '); reduce(pp,2,else_like,-2,102); @y - big_app1(pp); big_app(' '); big_app1(pp+1); reduce(pp,2,else_like,-2,123); + big_app1_insert(pp,' '); reduce(pp,2,else_like,-2,123); @z @x @@ -1251,19 +793,18 @@ else squash(pp,1,exp,-2,122); if ((cat1==int_like || cat1==cast) && (cat2==comma || cat2==semi)) squash(pp+1,1,exp,-1,115); else if (cat1==int_like) { - big_app1(pp); big_app(' '); big_app1(pp+1); reduce(pp,2,typedef_like,0,116); + big_app1_insert(pp,' '); reduce(pp,2,typedef_like,0,116); } else if (cat1==exp && cat2!=lpar && cat2!=exp && cat2!=cast) { make_underlined(pp+1); make_reserved(pp+1); - big_app1(pp); big_app(' '); big_app1(pp+1); reduce(pp,2,typedef_like,0,117); + big_app1_insert(pp,' '); reduce(pp,2,typedef_like,0,117); } else if (cat1==comma) { big_app2(pp); big_app(' '); reduce(pp,2,typedef_like,0,118); } else if (cat1==semi) squash(pp,2,decl,-1,119); else if (cat1==ubinop && (cat2==ubinop || cat2==cast)) { - big_app('{'); big_app1(pp+1); big_app('}'); big_app1(pp+2); - reduce(pp+1,2,cat2,0,120); + big_app('{'); big_app1_insert(pp+1,'}'); reduce(pp+1,2,cat2,0,120); } @y @ Here \.{CTWILL} deviates from the normal productions introduced in @@ -1343,7 +884,7 @@ if (cat1==decl_head) { else app_scrap(p->ilk,maybe_math); } } - @<Flag the usage of this identifier, for the mini-index@>; + @<Flag the usage of this identifier, for the mini-index@>@; @z @x @@ -1353,11 +894,9 @@ if (cat1==decl_head) { @z @x -to \.{\\PB}, if the user has invoked \.{CWEAVE} with the \.{+e} flag. -Although \.{cwebmac} ignores \.{\\PB}, other macro packages +to \.{\\PB}. Although \.{cwebmac} ignores \.{\\PB}, other macro packages @y -to \.{\\PB}, if the user has invoked \.{CTWILL} with the \.{+e} flag. -Although \.{ctwimac} ignores \.{\\PB}, other macro packages +to \.{\\PB}. Although \.{ctwimac} ignores \.{\\PB}, other macro packages @z @x @@ -1407,45 +946,11 @@ reset_input(); if (show_progress) fputs(_("\nWriting the output file..."),stdout section_count=0; format_visible=true; copy_limbo(); @y temp_switch=false; temp_meaning_ptr=temp_meaning_stack; -@<Read the \.{.aux} file, if present; then open it for output@>; +@<Read the \.{.aux} file, if present; then open it for output@>@; section_count=0; format_visible=true; right_start_switch=false; copy_limbo(); @z @x -while (!input_has_ended) @<Translate the current section@>@; -} - -@y -while (!input_has_ended) @<Translate the current section@>@; -} - -@ @<Private...@>= -static FILE *aux_file; -static char aux_file_name[max_file_name_length]; /* name of \.{.aux} file */ - -@ @<Read the \.{.aux} file, if present; then open it for output@>= -memcpy(aux_file_name,tex_file_name,strlen(tex_file_name)-4); -strcat(aux_file_name,".bux"); -include_depth=1; /* we simulate \.{@@i} */ -strcpy(cur_file_name,aux_file_name); /* first in, third out */ -if ((cur_file=fopen(cur_file_name,"r"))) { cur_line=0; include_depth++; } -strcpy(aux_file_name+strlen(aux_file_name)-4,".aux"); -strcpy(cur_file_name,aux_file_name); /* second in, second out */ -if ((cur_file=fopen(cur_file_name,"r"))) { cur_line=0; include_depth++; } -strcpy(cur_file_name,"system.bux"); /* third in, first out */ -if ((cur_file=fopen(cur_file_name,"r"))) cur_line=0; -else include_depth--; -if (include_depth) { /* at least one new file was opened */ - while (get_next()==meaning) ; /* new meaning is digested */ - if (include_depth) err_print(_("! Only @@$ is allowed in aux and bux files")); - finish_line(); loc=buffer; /* now reading beginning of line 1 */ -} -if ((aux_file=fopen(aux_file_name,"wb"))==NULL) - fatal(_("! Cannot open aux output file "),aux_file_name); - -@z - -@x static boolean group_found=false; /* has a starred section occurred? */ @ @<Translate the current section@>= { @@ -1479,15 +984,15 @@ if (*(loc-1)!='*') { @y @.\\N@> if (right_start_switch) { - out_str("N"); right_start_switch=false; + out('N'); right_start_switch=false; @.\\NN@> } @z @x -out_str("{");out_section(section_count); out_str("}"); +out('{'); out_section(section_count); out('}'); @y -out_str("{");out_section(section_count); out_str("}"); +out('{'); out_section(section_count); out('}'); flush_buffer(out_ptr,false,false); @z @@ -1524,15 +1029,10 @@ flush_buffer(out_ptr,false,false); } @y outer_parse(); - if (is_macro) @<Make ministring for a new macro@>; + if (is_macro) @<Make ministring for a new macro@>@; finish_C(format_visible); format_visible=true; doing_format=false; } - -@ @<Private...@>= -static boolean is_macro; /* it's a macro def, not a format def */ -static int def_diff; /* 0 iff the current macro has parameters */ -static name_pointer id_being_defined; /* the definee */ @z @x @@ -1551,13 +1051,13 @@ static name_pointer id_being_defined; /* the definee */ @x @.Improper macro definition@> else { - app('$'); app_cur_id(false); + app_cur_id(false); @y @.Improper macro definition@> else { id_being_defined=id_lookup(id_first,id_loc,normal); - app('$'); app_cur_id(false); - def_diff=*loc-'('; + app_cur_id(false); + def_diff=(*loc!='('); @z @x @@ -1570,22 +1070,6 @@ static name_pointer id_being_defined; /* the definee */ @ @<Start a format...@>= { doing_format=true; @y -@ @<Make ministring for a new macro@>= -{ - ms_mode=true; ministring_ptr=ministring_buf; - *ministring_ptr++='='; - if (def_diff) { /* parameterless */ - scrap_pointer s=scrap_ptr; - text_pointer t; - token_pointer j; - while (s->cat==insert) s--; - if ((s-1)->cat==dead && s->cat==exp && **(t=s->trans)=='\\' - && *(*t+1)=='T') /* it's just a constant */ - for (j=*t;j<*(t+1);j++) *ministring_ptr++=*j; - else out_str("macro"); - } else out_str("macro (\\,)"); - new_meaning(id_being_defined); -} @ @<Start a format...@>= { doing_format=true; @@ -1617,94 +1101,10 @@ flush_buffer(out_buf,false,false); /* insert a blank line, it looks nice */ @y finish_line(); out_str("\\mini"); finish_line(); @.\\mini@> -@<Output information about usage of id's defined in other sections@>; +@<Output information about usage of id's defined in other sections@>@; out_str("}\\FI"); finish_line(); @.\\FI@> flush_buffer(out_buf,false,false); /* insert a blank line, it looks nice */ - -@ The following code is performed for each identifier parsed during -a section. Variable |top_usage| is always nonzero; it has the sentinel -value~1 initially, then it points to each variable scheduled for -possible citation. A variable is on this list if and only if its -|link| field is nonzero. All variables mentioned in the section are -placed on the list, unless they are reserved and their current -\TeX\ meaning is uninitialized. - -@<Flag the usage of this identifier, for the mini-index@>= -{ struct perm_meaning *q=p-name_dir+cur_meaning; - if (!(abnormal(p)) || strcmp(q->perm.tex_part,"\\uninitialized")!=0) - if (q->link==0) { - q->link=top_usage; - top_usage=q; - } -} - -@ @<Output information about usage of id's defined in other sections@>= -{ struct perm_meaning *q; - while (temp_meaning_ptr>temp_meaning_stack) { - out_mini(--temp_meaning_ptr); - q=temp_meaning_ptr->id-name_dir+cur_meaning; - q->stamp=section_count; /* suppress output from ``permanent'' data */ - } - while (top_usage!=usage_sentinel) { - q=top_usage; - top_usage=q->link; - q->link=NULL; - if (q->stamp!=section_count) out_mini(&(q->perm)); - } -} - -@ @c static void -out_mini( - meaning_struct *m) -{ char s[60]; - name_pointer cur_name=m->id; - if (m->prog_no==0) { /* reference within current program */ - if (m->sec_no==section_count) return; /* defined in current section */ - sprintf(s,"\\[%d",m->sec_no); - } else { name_pointer n=title_code[m->prog_no]; - if (*(n->byte_start)=='{') - sprintf(s,"\\]%.*s%d",(int)((n+1)->byte_start-n->byte_start),n->byte_start, - m->sec_no); - else sprintf(s,"\\]%.*s",(int)((n+1)->byte_start-n->byte_start),n->byte_start); - } - out_str(s); out(' '); - @<Mini-output the name at |cur_name|@>; - out(' '); out_str(m->tex_part); finish_line(); -} - -@ @<Predec...@>=@+static void out_mini(meaning_struct *); - -@ @<Mini-output...@>= -switch (cur_name->ilk) { - case normal: case func_template: if (length(cur_name)==1) out_str("\\|"); - else {char *j; - for (j=cur_name->byte_start;j<(cur_name+1)->byte_start;j++) - if (xislower(*j)) goto lowcase; - out_str("\\."); break; -lowcase: out_str("\\\\"); - } - break; -@.\\|@> -@.\\.@> -@.\\\\@> - case roman: break; - case wildcard: out_str("\\9"); break; -@.\\9@> - case typewriter: out_str("\\."); break; -@.\\.@> - case custom: {char *j; out_str("$\\"); - for (j=cur_name->byte_start;j<(cur_name+1)->byte_start;j++) - out(*j=='_'? 'x': *j=='$'? 'X': *j); - out('$'); - goto name_done; - } - default: out_str("\\&"); -@.\\\&@> -} -out_name(cur_name,true); -name_done: - @z @x @@ -1789,8 +1189,8 @@ the index section itself---NOT! } out('.'); } - @y +@ No need to tell about changed sections. @z @x @@ -1809,26 +1209,26 @@ rest of the job. @z @x - case normal: case func_template: if (is_tiny(cur_name)) out_str("\\|"); + case normal: case func_template: @y - case normal: if (is_tiny(cur_name)) out_str("\\|"); + case normal: @z @x case wildcard: out_str("\\9");@+ goto not_an_identifier; @y - case roman: out_str(" "); goto not_an_identifier; - case wildcard: out_str("\\9"); goto not_an_identifier; + case roman: out_str(" ");@+ goto not_an_identifier; + case wildcard: out_str("\\9");@+ goto not_an_identifier; @z @x case roman: not_an_identifier: out_name(cur_name,false); goto name_done; - case custom: {char *j; out_str("$\\"); + case custom: + out_str("$\\"); for (j=cur_name->byte_start;j<(cur_name+1)->byte_start;j++) out(*j=='_'? 'x': *j=='$'? 'X': *j); out('$'); goto name_done; - } @y not_an_identifier: out_name(cur_name,false); goto name_done; case custom: out_str("\\$"); break; @@ -1839,11 +1239,9 @@ not_an_identifier: out_name(cur_name,false); goto name_done; out_name(cur_name,true); @y if (proofing) out_name(cur_name,true); -else { +else {@+char *j; out('{'); - {char *j; - for (j=cur_name->byte_start;j<(cur_name+1)->byte_start;j++) out(*j); - } + for (j=cur_name->byte_start;j<(cur_name+1)->byte_start;j++) out(*j); out('}'); } @z @@ -1900,20 +1298,631 @@ else { @x @** Index. @y -@** Extensions to \.{CWEB}. The following sections introduce new or improved -features that have been created by numerous contributors over the course of a -quarter century. +@q Section 272. @> +@** Mogrify {\tentex CWEAVE} into {\tentex CTWILL}. The following sections +introduce material that is specific to \.{CTWILL}. + +Care has been taken to keep the original section numbering of \.{CWEAVE} +up to this point intact, so this new material should nicely integrate +with the original ``\&{272.~Index}.'' + +@q Section 2->273. @> +@* {\tentex CTWILL} user manual. +Here is a sort of user manual for \.{CTWILL}---which is exactly like +\.{CWEAVE} except that it produces much better documentation, for which you +must work harder. As with \.{CWEAVE}, input comes from a source file +\.{foo.w} and from an optional (but now almost mandatory) change file +\.{foo.ch}; output goes to \.{foo.tex}, \.{foo.idx}, and \.{foo.scn}. +Unlike \.{CWEAVE}, there is an additional output file, \.{foo.aux}, +which records all nonexternal definitions. The \.{.aux} file also +serves as an input file on subsequent runs. You should run \.{CTWILL} +twice, once to prime the pump and once to get decent answers. + +Moreover, you must run the output twice through \TeX. (This double duplicity +suggested the original name \.{TWILL}.) After `\.{tex} \.{foo}' you +will have output that looks like final pages except that the entries +of mini-indexes won't be alphabetized. \TeX\ will say `This is the first +pass', and it will produce a weird file called \.{foo.ref}. Say +$$\.{refsort < foo.ref > foo.sref}$$ +and then another `\.{tex} \.{foo}' will produce alphabetized output. +While \TeX\ runs it emits messages filled with numeric data, indicating how +much space is consumed by each program section. If you can decipher these +numbers (see \.{ctwimac.tex}), you can use them to fine-tune the page +layout. You might be tempted to do fine tuning by editing \.{foo.tex} +directly, but it's better to incorporate all changes into \.{foo.ch}. + +The mini-indexes list identifiers that are used but not defined on +each two-page spread. At the end of each section, \.{CTWILL} gives +\TeX\ a list of identifiers used in that section and information +about where they are defined. The macros in \.{ctwimac.tex} figure out +which identifiers should go in each mini-index, based on how the pages +break. (Yes, those macros are pretty hairy.) + +The information that \.{CTWILL} concocts from \.{foo.w} is not always +correct. Sometimes you'll use an identifier that you don't want +indexed; for example, your exposition might talk about |f(x)| when you +don't mean to refer to program variables |f| or |x|. Sometimes you'll +use an identifier that's defined in a header file, unknown to +\.{CTWILL}. Sometimes you'll define a single identifier in several +different places, and \.{CTWILL} won't know which definition to choose. +But all is not lost. \.{CTWILL} guesses right most of the time, and you can +give it the necessary hints in other places via your change file. + +If you think it's easy to write a completely automatic system that doesn't +make \.{CTWILL}'s mistakes and doesn't depend so much on change files, +please do so. + +\.{CTWILL} uses a very simple method to generate mini-index info. By +understanding this method, you will understand how to fix it when things +go wrong. Every identifier has a current ``meaning,'' consisting of its +abstract type and the number of the section in which it was most recently +defined. For example, if your \Cee\ program says `|char *s|' in section~3, +the meaning of~|s| gets changed to `\&{char} $*$, \S3' while \.{CTWILL} +is processing that section. If you refer to~|s| in section~10, and if +|s|~hasn't been redefined in the meantime, and if section~10 doesn't +wind up on the same two-page spread as section~3, the mini-index generated +by section~10 will say ``|s|: \&{char}~$*$, \S3.'' + +The current meaning of every identifier is initially `\.{\\uninitialized}'. +Then \.{CTWILL} reads the \.{.aux} file for your job, if any; this +\.{.aux} file contains all definitions of new meanings in the previous +run, so it tells \.{CTWILL} about definitions that will be occurring +in the future. If all identifiers have a unique definition, they will +have a unique and appropriate meaning in the mini-indexes. + +But some identifiers, like parameters to procedures, may be defined +several times. Others may not be defined at all, because they are +defined elsewhere and mentioned in header files included by the \Cee\ +preprocessor. To solve this problem, \.{CTWILL} provides mechanisms by which +the current meaning of an identifier can be temporarily or permanently +changed. + +For example, the operation +$$\.{@@\$s \{FOO\}3 \\\&\{char\} \$*\$@@>}$$ +changes the current meaning of |s| to the \TeX\ output of `\.{\\\&\{char\}} +\.{\$*\$}' in section~3 of program {\sc FOO}. All entries in the \.{.aux} +file are expressed in the form of this \.{@@\$} operator; therefore you +can use a text editor to paste such entries into a \.{.ch} file, whenever +you want to tell \.{CTWILL} about definitions that are out of order +or from other programs. + +Before reading the \.{.aux} file, \.{CTWILL} actually looks for a file +called \.{system.bux}, which will be read if present. And after +\.{foo.aux}, a third possibility is \.{foo.bux}. The general +convention is to put definitions of system procedures such as |printf| +into \.{system.bux}, and to put definitions found in specifically +foo-ish header files into \.{foo.bux}. Like the \.{.aux} +files, \.{.bux} files should contain only \.{@@\$} specifications; +this rule corresponds to the fact that `bux' is the plural of `\$'. +The \.{.bux} files may also contain \.{@@i} includes. + +A companion operation \.{@@\%} signifies that all \.{@@\$} +specifications from the present point to the beginning of the next +section will define {\it temporary\/} meanings instead of permanent +ones. Temporary meanings are placed into the +mini-index of the current section; the permanent (current) meaning of +the identifier will not be changed, nor will it appear in the +mini-index of the section. If several temporary meanings are assigned +to the same identifier in a section, all will appear in the mini-index. +Each \.{@@\%} toggles the temporary/permanent convention; thus, after +an even number of \.{@@\%} operations in a section, meanings specified +by \.{@@\$} are permanent. + +The operation \.{@@-} followed by an identifier followed by \.{@@>} +specifies that the identifier should not generate a mini-index entry +in the current section (unless, of course, a temporary meaning is assigned). + +If \.{@@-foo@@>} appears in a section where a new permanent meaning is +later defined by the semantics of~\Cee, the current meaning of \\{foo} +will not be redefined; moreover, this current meaning, which may have +been changed by \.{@@\$foo ...@@>}, will also be written to the +\.{.aux} file. Therefore you can control what \.{CTWILL} outputs; you +can keep it from repeatedly contaminating the \.{.aux} file with +things you don't like. + +The meaning specified by \.{@@\$...@@>} generally has four components: +an identifier (followed by space), a program name (enclosed in braces), +a section number (followed by space), and a \TeX\ part. The \TeX\ part +must have fewer than 50 characters. If the \TeX\ part starts +with `\.=', the mini-index entry will contain an equals sign instead +of a colon; for example, +$$\.{@@\$buf\_size \{PROG\}10 =\\T\{200\}@@>}$$ +generates either `$\\{buf\_size}=200$, \S10' or +`$\\{buf\_size}=200$, {\sc PROG}\S10', depending on whether +`{\sc PROG}' is or isn't the title of the current program. If the +\TeX\ part is `\.{\\zip}', the mini-index entry will contain neither +colon nor equals, just a comma. The program name and section number +can also be replaced by a string. For example, +$$\.{@@\$printf "<stdio.h>" \\zip@@>}$$ +will generate a mini-index entry like `\\{printf}, \.{<stdio.h>}.'. + +A special ``proofmode'' is provided so that you can check \.{CTWILL}'s +conclusions about cross-references. Run \.{CTWILL} with the +flag \.{+P}, and \TeX\ will produce a specially formatted document +({\it without\/} mini-indexes) +in which you can check that your specifications are correct. +You should always do this before generating mini-indexes, because +mini-indexes can mask errors if page breaks are favorable but the +errors might reveal themselves later after your program has changed. +The proofmode output is much easier to check than the mini-indexes themselves. + +The control code \.{@@r} or \.{@@R} causes \.{CTWILL} to emit +the \TeX\ macro `\.{\\shortpage}' just before starting the next +section of the program. This causes the section to appear at the top of +a right-hand page, if it would ordinarily have appeared near the bottom +of a left-hand page and split across the pages. (The \.{\\shortpage} macro +is fragile and should be used only in cases where it will not mess up +the output; insert it only when fine-tuning a set of pages.) If the +next section is a starred section, the behavior is slightly different +(but still fragile): The starred section will either be postponed to +a left-hand page, if it normally would begin on a right-hand page, +or vice versa. In other words, \.{@@r@@*} inverts the left/right logic. + +\.{CTANGLE} does not recognize the operations \.{@@\$}, \.{@@\%}, \.{@@-}, +and \.{@@r}, which are unique to \.{CTWILL}. But that is no problem, +since you use them only in change files set up for book publishing, +which are quite different from the change files you set up for tangling. + +(End of user manual.) + +@d max_tex_chars 50 /* limit on the \TeX\ part of a meaning */ + +@q Section 25->274. @> +@* Temporary and permanent meanings. +\.{CTWILL} has special data structures to keep track of current +and temporary meanings. These structures were not designed for maximum +efficiency; they were designed to be easily grafted into \.{CWEAVE}'s +existing code without major surgery. + +@d max_meanings 100 /* max temporary meanings per section */ +@d max_titles 100 /* max distinct program or header names in meanings */ + +@<Type...@>= +typedef struct { + name_pointer id; /* identifier whose meaning is being recorded */ + sixteen_bits prog_no; /* title of program or header in which defined */ + sixteen_bits sec_no; /* section number in which defined */ + char tex_part[max_tex_chars]; /* \TeX\ part of meaning */ +} meaning_struct; + +@q Section 26->275. @> +@ @<Private...@>= +struct perm_meaning { + meaning_struct perm; /* current meaning of an identifier */ + int stamp; /* last section number in which further output suppressed */ + struct perm_meaning *link; /* another meaning to output in this section */ +} cur_meaning[max_names]; /* the current ``permanent'' meanings */ +static struct perm_meaning *top_usage; /* first meaning to output in this section */ +static meaning_struct temp_meaning_stack[max_meanings]; /* the current ``temporary'' meanings */ +static meaning_struct *temp_meaning_ptr; /* first available slot in |temp_meaning_stack| */ +static meaning_struct *max_temp_meaning_ptr; /* its maximum value so far */ +static name_pointer title_code[max_titles]; /* program names seen so far */ +static name_pointer *title_code_ptr; /* first available slot in |title_code| */ +static char ministring_buf[max_tex_chars]; /* \TeX\ code being generated */ +static char *ministring_ptr; /* first available slot in |ministring_buf| */ +static boolean ms_mode; /* are we outputting to |ministring_buf|? */ + +@q Section 27->276. @> +@ @<Set init...@>= +max_temp_meaning_ptr=temp_meaning_stack; +title_code_ptr=title_code; +ms_mode=false; + +@q Section 277. @> +@ @<Predec...@>=@+static void new_meaning(name_pointer); + +@q Section 30->278. @> +@ The |new_meaning| routine changes the current ``permanent meaning'' +when an identifier is redeclared. It gets the |tex_part| from +|ministring_buf|. + +@c +static void +new_meaning( + name_pointer p) +{ + struct perm_meaning *q=p-name_dir+cur_meaning; + ms_mode=false; + if (q->stamp!=section_count) { + if (*(ministring_ptr-1)==' ') ministring_ptr--; + if (ministring_ptr>=&ministring_buf[max_tex_chars]) + strcpy(ministring_buf,"\\zip"); /* ignore |tex_part| if too long */ +@.\\zip@> + else *ministring_ptr='\0'; + q->perm.prog_no=0; /* |q->perm.id=p| */ + q->perm.sec_no=section_count; + strcpy(q->perm.tex_part,ministring_buf); + } + @<Write the new meaning to the \.{.aux} file@>@; +} + +@q Section 75->279. @> +@ @<Process a user-generated meaning@>= +{ char *first=id_first; + while (xisspace(*first)) first++; + loc=first; + while (xisalpha(*loc)||xisdigit(*loc)||*loc=='_') loc++; + if (*loc++!=' ') + err_print(_("! Identifier in meaning should be followed by space")); + else {@+ int n=0; + name_pointer p=id_lookup(first,loc-1,normal); + sixteen_bits t=title_lookup(); + if (*(loc-1)=='}') + while (xisdigit(*loc)) n=10*n+(*loc++)-'0'; + if (*loc++!=' ') + err_print(_("! Location in meaning should be followed by space")); + else @<Digest the meaning of |p|, |t|, |n|@>@; + } + loc=id_loc+2; +} + +@q Section 76->280. @> +@ @<Suppress mini-index entry@>= +{ char *first=id_first,*last=id_loc; + while (xisspace(*first)) first++; + while (xisspace(*(last-1))) last--; + if (first<last) { + struct perm_meaning *q=id_lookup(first,last,normal)-name_dir+cur_meaning; + q->stamp=section_count; /* this is what actually suppresses output */ + } +} + +@q Section 77->281. @> +@ @<Digest...@>= +{ meaning_struct *m; + struct perm_meaning *q=p-name_dir+cur_meaning; + if (temp_switch) { + m=temp_meaning_ptr++; + if (temp_meaning_ptr>max_temp_meaning_ptr) { + if (temp_meaning_ptr>&temp_meaning_stack[max_meanings]) + overflow(_("temp meanings")); + max_temp_meaning_ptr=temp_meaning_ptr; + } + } else m=&(q->perm); + m->id=p; + m->prog_no=t; + m->sec_no=n; + if (id_loc-loc>=max_tex_chars) strcpy(m->tex_part,"\\zip"); +@.\\zip@> + else { char *q=m->tex_part; + while (loc<id_loc) *q++=*loc++; + *q='\0'; + } +} + +@q Section 141->282/3. @> +@* Make ministrings. + \.{CTWILL} needs the following procedure, which appends tokens of a +translated text until coming to |tok_loc|, then suppresses text that may +appear between parentheses or brackets. The calling routine |make_ministring| +should set |ident_seen=false| first. (This is admittedly tricky.) + +@<Private var...@>= +static boolean ident_seen; + +@ @c +static boolean app_supp( + text_pointer p) +{ token_pointer j; + if (ident_seen && **p>=tok_flag) + switch (**(**p-tok_flag+tok_start)) { + case '(': app('(');@+app('\\');@+app(',');@+app(')'); goto catch14; + case '[': app('[');@+app('\\');@+app(',');@+app(']'); goto catch14; + } + for (j=*p;j<*(p+1);j++) { + if (*j<tok_flag) { + if (*j==inserted) break; + if (j==tok_loc) ident_seen=true; + else app(*j); + } else if (*j>=inner_tok_flag) confusion(_("inner")); + else if (app_supp(*j-tok_flag+tok_start)) goto catch14; + } + return false; +catch14: return *(*(p+1)-1)=='9'; /* was production 14 used? */ +} + +@q Section 284. @> +@ @<Predec...@>=@+static boolean app_supp(text_pointer); + +@q Section 142->285. @> +@ The trickiest part of \.{CTWILL} is the procedure |make_ministring(l)|, +which tries to figure out a symbolic form of definition after +|make_underlined(pp+l)| has been called. We rely heavily on the +existing productions, which force the translated texts to have a +structure that's decodable even though the underlying |cat| and |mathness| +codes have disappeared. + +@c static void +make_ministring( + int l) /* 0, 1, or 2 */ +{ + name_pointer cn; + if (tok_loc<=operator_found) return; + cn=((*tok_loc)%id_flag)+name_dir; + @<Append the type of the declaree; |return| if it begins with \&{extern}@>@; + null_scrap.mathness=(((pp+l)->mathness)%4)*5; big_app1(&null_scrap); + /* now we're ready for the mathness that follows (I think); + (without the mod 4 times 5, comments posed a problem, + namely in cases like |int a(b,c)| followed by comment) */ + ident_seen=false;@+app_supp((pp+l)->trans); + null_scrap.mathness=10; big_app1(&null_scrap); + /* now |cur_mathness==no_math| */ + ms_mode=true; ministring_ptr=ministring_buf; + if (l==2) *ministring_ptr++='='; + make_output(); /* translate the current text into a ministring */ + tok_ptr=*(--text_ptr); /* delete that text */ + new_meaning(cn); + cur_mathness=maybe_math; /* restore it */ +} + +@q Section 286. @> +@ @<Predec...@>=@+static void make_ministring(int); + +@q Section 43->287. @> +@ @<Private...@>= +static sixteen_bits int_loc, ext_loc; /* locations of special reserved words */ + +@q Section 143->288. @> +@ Here we use the fact that a |decl_head| comes from |int_like| only in +production~27, whose translation is fairly easy to recognize. (Well, +production 28 has been added for \CPLUSPLUS/, but we hope that doesn't +mess us up.) And we also use other similar facts. + +If an identifier is given an \&{extern} definition, we don't change +its current meaning, but we do suppress mini-index entries to its +current meaning in other sections. + +@<Append the type of the declaree; |return| if it begins with \&{extern}@>= +if (l==0) { app(int_loc+res_flag); app(' '); cur_mathness=no_math; } +else { + text_pointer q=(pp+l-1)->trans, r; + token t; + int ast_count=0; /* asterisks preceding the expression */ + boolean non_ast_seen=false; /* have we seen a non-asterisk? */ + while (true) { + if (*(q+1)==*q+1) { + r=q;@+break; /* e.g. \&{struct}; we're doing production 45 or 46 */ + } + if (**q<tok_flag) confusion(_("find type")); + r=**q-tok_flag+tok_start; + if ((t=*(*(q+1)-2))>=tok_flag && **(t-tok_flag+tok_start)=='*') { + /* production 34 */ + if (!non_ast_seen) ast_count++; /* count immediately preceding |*|'s */ + } else non_ast_seen=true; + if (*(*q+1)==' ' && *(q+1)==*q+2) break; /* production 27 */ + if (*(*q+1)=='{' && *(*q+2)=='}' && *(*q+3)=='$' && *(*q+4)==' '@| + && *(q+1)==*q+5) break; /* production 27 in disguise */ + q=r; + } + while (**r>=tok_flag) { + if (*(r+1)>*r+9 && *(*r+1)=='{' && *(*r+2)=='}' && *(*r+3)=='$' @| + && *(*r+4)==indent) q=**r-tok_flag+tok_start; /* production 49 */ + r=**r-tok_flag+tok_start; + } + if (**r==ext_loc+res_flag) return; /* \&{extern} gives no definition */ + @<Append tokens for type |q|@>@; +} + +@q Section 144->289. @> +@ @<Append tokens for type |q|@>= +cur_mathness=no_math; /* it was |maybe_math| */ +if (*(q+1)==*q+8 && *(*q+1)==' ' && *(*q+3)==' ') { + app(**q);@+app(' ');@+app(*(*q+2)); /* production 46 */ +} else if ((t=*(*(q+1)-1))>=tok_flag && **(r=t-tok_flag+tok_start)=='\\' + && *(*r+1)=='{') app(**q); /* |struct_like| identifier */ +else app((q-tok_start)+tok_flag); +while (ast_count) { + big_app('{');@+app('*');@+app('}');@+ast_count--; +} + +@q Section 253->290. @> +@ @<Private...@>= +static boolean is_macro; /* it's a macro def, not a format def */ +static boolean def_diff; /* |false| iff the current macro has parameters */ +static name_pointer id_being_defined; /* the definee */ + +@q Section 257->291. @> +@ @<Make ministring for a new macro@>= +{ + ms_mode=true; ministring_ptr=ministring_buf; + *ministring_ptr++='='; + if (def_diff) { /* parameterless */ + scrap_pointer s=scrap_ptr; + text_pointer t; + token_pointer j; + while (s->cat==insert) s--; + if ((s-1)->cat==dead && s->cat==exp && **(t=s->trans)=='\\' + && *(*t+1)=='T') /* it's just a constant */ + for (j=*t;j<*(t+1);j++) *ministring_ptr++=*j; + else out_str("macro"); + } else out_str("macro (\\,)"); + new_meaning(id_being_defined); +} -\bigskip -\font\itt=cmitt10 -{\noindent \it Although \.{\itt CTWILL} is based on \.{\itt cweave.w}, new and -modified material is incorporated all over the place, without taking special -care for keeping the original section numbering intact.} +@q Section 246->292. @> +@* Process {\tentex .aux} files. + +@<Private...@>= +static FILE *aux_file; +static char aux_file_name[max_file_name_length]; /* name of \.{.aux} file */ + +@q Section 247->293. @> +@ @<Read the \.{.aux} file, if present; then open it for output@>= +memcpy(aux_file_name,tex_file_name,strlen(tex_file_name)-4); +strcat(aux_file_name,".bux"); +include_depth=1; /* we simulate \.{@@i} */ +strcpy(cur_file_name,aux_file_name); /* first in, third out */ +if ((cur_file=fopen(cur_file_name,"r"))) { cur_line=0; include_depth++; } +strcpy(aux_file_name+strlen(aux_file_name)-4,".aux");@/ +strcpy(cur_file_name,aux_file_name); /* second in, second out */ +if ((cur_file=fopen(cur_file_name,"r"))) { cur_line=0; include_depth++; } +strcpy(cur_file_name,"system.bux"); /* third in, first out */ +if ((cur_file=fopen(cur_file_name,"r"))) cur_line=0; +else include_depth--; +if (include_depth) { /* at least one new file was opened */ + while (get_next()==meaning) ; /* new meaning is digested */ + if (include_depth) err_print(_("! Only @@$ is allowed in aux and bux files")); + finish_line(); loc=buffer; /* now reading beginning of line 1 */ +} +if ((aux_file=fopen(aux_file_name,"wb"))==NULL) + fatal(_("! Cannot open aux output file "),aux_file_name); + +@q Section 31->294. @> +@ @<Write the new meaning to the \.{.aux} file@>= +{@+int n=q->perm.prog_no; + fprintf(aux_file,"@@$%.*s %.*s",@| + (int)length(p),p->byte_start,@| + (int)length(title_code[n]),title_code[n]->byte_start); + if (*(title_code[n]->byte_start)=='{') fprintf(aux_file,"%d",q->perm.sec_no); + fprintf(aux_file," %s@@>\n",q->perm.tex_part); +} + +@q Section 268->295. @> +@* Usage of identifiers. +The following code is performed for each identifier parsed during +a section. Variable |top_usage| is always nonzero; it has the sentinel +value~1 initially, then it points to each variable scheduled for +possible citation. A variable is on this list if and only if its +|link| field is nonzero. All variables mentioned in the section are +placed on the list, unless they are reserved and their current +\TeX\ meaning is uninitialized. + +@<Flag the usage of this identifier, for the mini-index@>= +{ struct perm_meaning *q=p-name_dir+cur_meaning; + if (!(abnormal(p)) || strcmp(q->perm.tex_part,"\\uninitialized")!=0) + if (q->link==NULL) { + q->link=top_usage; + top_usage=q; + } +} + +@q Section 269->296. @> +@ @<Output information about usage of id's defined in other sections@>= +{ struct perm_meaning *q; + while (temp_meaning_ptr>temp_meaning_stack) { + out_mini(--temp_meaning_ptr); + q=temp_meaning_ptr->id-name_dir+cur_meaning; + q->stamp=section_count; /* suppress output from ``permanent'' data */ + } + while (top_usage!=usage_sentinel) { + q=top_usage; + top_usage=q->link; + q->link=NULL; + if (q->stamp!=section_count) out_mini(&(q->perm)); + } +} + +@q Section 270->297. @> +@ @c static void +out_mini( + meaning_struct *m) +{ char s[60]; + name_pointer cur_name=m->id; + if (m->prog_no==0) { /* reference within current program */ + if (m->sec_no==section_count) return; /* defined in current section */ + sprintf(s,"\\[%d",m->sec_no); + } else { name_pointer n=title_code[m->prog_no]; + if (*(n->byte_start)=='{') + sprintf(s,"\\]%.*s%d",(int)length(n),n->byte_start,m->sec_no); + else sprintf(s,"\\]%.*s",(int)length(n),n->byte_start); + } + out_str(s); out(' '); + @<Mini-output the name at |cur_name|@>@; + out(' '); out_str(m->tex_part); finish_line(); +} + +@q Section 271->298. @> +@ @<Predec...@>=@+static void out_mini(meaning_struct *); + +@q Section 272->299. @> +@ Compare this code with section |@<Output the name...@>|. + +@<Mini-output...@>= +switch (cur_name->ilk) {@+char *j; + case normal: case func_template: + if (is_tiny(cur_name)) out_str("\\|"); + else { + for (j=cur_name->byte_start;j<(cur_name+1)->byte_start;j++) + if (xislower(*j)) goto lowcase; + out_str("\\."); break; +lowcase: out_str("\\\\"); + } + break; +@.\\|@> +@.\\.@> +@.\\\\@> + case wildcard: out_str("\\9"); break; +@.\\9@> + case typewriter: out_str("\\."); +@.\\.@> + case roman: break; + case custom: + out_str("$\\"); + for (j=cur_name->byte_start;j<(cur_name+1)->byte_start;j++) + out(*j=='_'? 'x': *j=='$'? 'X': *j); + out('$'); + goto name_done; + default: out_str("\\&"); +@.\\\&@> +} +out_name(cur_name,true); +name_done:@; + +@q Section 28->300. @> +@* Handle program title. +Here's a routine that converts a program title from the buffer +into an internal number for the |prog_no| field of a meaning. +It advances |loc| past the title found. + +@c static sixteen_bits title_lookup(void) +{ + char *first=loc,*last; /* boundaries */ + register name_pointer *p; + if (*loc=='"') { + while (++loc<=limit && *loc!='"') if (*loc=='\\') loc++; + } else if (*loc=='{') { + int balance=1; /* excess of left over right */ + while (++loc<=limit) { + if (*loc==' ' && balance==1) + *loc='}'; /* Skip ``version'' after module name and fall through */ + if (*loc=='}' && --balance==0) break; + if (*loc=='{') balance++; + } + } else err_print(_("! Title should be enclosed in braces or doublequotes")); + last=++loc; + if (last>limit) err_print(_("! Title name didn't end")); + if (title_code_ptr==&title_code[max_titles]) overflow(_("titles")); + *title_code_ptr=id_lookup(first,last,title); + for (p=title_code;true;p++) if (*p==*title_code_ptr) break; + if (p==title_code_ptr) title_code_ptr++; + return p-title_code; +} + +@q Section 301. @> +@ @<Predec...@>=@+static sixteen_bits title_lookup(void); + +@q Section 29->302. @> +@ @<Give a default title to the program, if necessary@>= +if (title_code_ptr==title_code) { /* no \.{\\def\\title} found in limbo */ + char *saveloc=loc,*savelimit=limit; /* save */ + loc=limit+1; limit=loc; + *limit++='{'; + memcpy(limit,tex_file_name,strlen(tex_file_name)-4); + limit+=strlen(tex_file_name)-4; + *limit++='}'; + title_lookup();@/ + loc=saveloc; limit=savelimit; /* restore */ +} + +@q Section 303. @> +@** Extensions to {\tentex CWEB}. The following sections introduce new or +improved features that have been created by numerous contributors over the +course of a quarter century. @* Formatting alternatives. -\.{CWEAVE} indents declarations after old-style function definitions. -With the \.{-i} option they will come out flush left. You won't see -any difference if you use ANSI-style function definitions. +\.{CWEAVE} indents declarations after old-style function definitions and +long parameter lists of modern function definitions. +With the \.{-i} option they will come out flush left. @d indent_param_decl flags['i'] /* should formal parameter declarations be indented? */ @@ -1940,14 +1949,13 @@ be found in the program \.{NUWEB} by Preston Briggs, to whom credit is due. @<Update the result...@>= if((tex_file=fopen(tex_file_name,"r"))!=NULL) { - char x[BUFSIZ],y[BUFSIZ]; - int x_size,y_size,comparison=false; + boolean comparison=false; if((check_file=fopen(check_file_name,"r"))==NULL) fatal(_("! Cannot open output file "),check_file_name); @.Cannot open output file@> - if (temporary_output) @<Compare the temporary output...@>@; + if (check_for_change) @<Compare the temporary output...@>@; fclose(tex_file); tex_file=NULL; fclose(check_file); check_file=NULL; @@ -1962,10 +1970,10 @@ strcpy(check_file_name,""); /* We want to get rid of the temporary file */ @<Compare the temporary output to the previous output@>= do { - x_size = fread(x,1,BUFSIZ,tex_file); - y_size = fread(y,1,BUFSIZ,check_file); - comparison = (x_size == y_size); /* Do not merge these statements! */ - if(comparison) comparison = !memcmp(x,y,x_size); + char x[BUFSIZ],y[BUFSIZ]; + int x_size = fread(x,sizeof(char),BUFSIZ,tex_file); + int y_size = fread(y,sizeof(char),BUFSIZ,check_file); + comparison = (x_size == y_size) && !memcmp(x,y,x_size); } while(comparison && !feof(tex_file) && !feof(check_file)); @ Note the superfluous call to |remove| before |rename|. We're using it to @@ -1979,7 +1987,7 @@ else { rename(check_file_name,tex_file_name); } -@* Put ``version'' information in \.{COMMON}. +@* Print ``version'' information. Don't do this at home, kids! Push our local macro to the variable in \.{COMMON} for printing the |banner| and the |versionstring| from there. |