📄 cweave.w
字号:
strings will not be entered into the cross reference lists since they are notdefinitions of section names.The program uses the fact that our internal code numbers satisfythe relations |xref_roman==identifier+roman| and |xref_wildcard==identifier+wildcard| and |xref_typewriter==identifier+typewriter|,as well as |normal==0|.@<Predecl...@>=void C_xref();@ @cvoidC_xref( spec_ctrl ) /* makes cross-references for \CEE/ identifiers */ eight_bits spec_ctrl;{ name_pointer p; /* a referenced name */ while (next_control<format_code || next_control==spec_ctrl) { if (next_control>=identifier && next_control<=xref_typewriter) { if (next_control>identifier) @<Replace |"@@@@"| by |"@@"| @>@; p=id_lookup(id_first, id_loc,next_control-identifier); new_xref(p); } if (next_control==section_name) { section_xref_switch=cite_flag; new_section_xref(cur_section); } next_control=get_next(); if (next_control=='|' || next_control==begin_comment || next_control==begin_short_comment) return; }}@ The |outer_xref| subroutine is like |C_xref| except that it beginswith |next_control!='|'| and ends with |next_control>=format_code|. Thus, ithandles \CEE/ text with embedded comments.@<Predecl...@>=void outer_xref();@ @cvoidouter_xref() /* extension of |C_xref| */{ int bal; /* brace level in comment */ while (next_control<format_code) if (next_control!=begin_comment && next_control!=begin_short_comment) C_xref(ignore); else { boolean is_long_comment=(next_control==begin_comment); bal=copy_comment(is_long_comment,1); next_control='|'; while (bal>0) { C_xref(section_name); /* do not reference section names in comments */ if (next_control=='|') bal=copy_comment(is_long_comment,bal); else bal=0; /* an error message will occur in phase two */ } }}@ In the \TEX/ part of a section, cross-reference entries are made only forthe identifiers in \CEE/ texts enclosed in \pb, or for control textsenclosed in \.{@@\^}$\,\ldots\,$\.{@@>} or \.{@@.}$\,\ldots\,$\.{@@>}or \.{@@:}$\,\ldots\,$\.{@@>}.@<Store cross-references in the \T...@>=while (1) { switch (next_control=skip_TeX()) { case translit_code: err_print("! Use @@l in limbo only"); continue;@.Use @@l in limbo...@> case underline: xref_switch=def_flag; continue; case trace: tracing=*(loc-1)-'0'; continue; case '|': C_xref(section_name); break; case xref_roman: case xref_wildcard: case xref_typewriter: case noop: case section_name: loc-=2; next_control=get_next(); /* scan to \.{@@>} */ if (next_control>=xref_roman && next_control<=xref_typewriter) { @<Replace |"@@@@"| by |"@@"| @>@; new_xref(id_lookup(id_first, id_loc,next_control-identifier)); } break; } if (next_control>=format_code) break;}@ @<Replace |"@@@@"| by |"@@"| @>={ char *src=id_first,*dst=id_first; while(src<id_loc){ if(*src=='@@') src++; *dst++=*src++; } id_loc=dst; while (dst<src) *dst++=' '; /* clean up in case of error message display */}@ During the definition and \CEE/ parts of a section, cross-referencesare made for all identifiers except reserved words. However, the rightidentifier in a format definition is not referenced, and the leftidentifier is referenced only if it has been explicitlyunderlined (preceded by \.{@@!}).The \TEX/ code in comments is, of course, ignored, except for\CEE/ portions enclosed in \pb; the text of a section name is skippedentirely, even if it contains \pb\ constructions.The variables |lhs| and |rhs| point to the respective identifiers involvedin a format definition.@<Global...@>=name_pointer lhs, rhs; /* pointers to |byte_start| for format identifiers */name_pointer res_wd_end; /* pointer to the first nonreserved identifier */@ When we get to the following code we have |next_control>=format_code|.@<Store cross-references in the d...@>=while (next_control<=definition) { /* |format_code| or |definition| */ if (next_control==definition) { xref_switch=def_flag; /* implied \.{@@!} */ next_control=get_next(); } else @<Process a format definition@>; outer_xref();}@ Error messages for improper format definitions will be issued in phasetwo. Our job in phase one is to define the |ilk| of a properly formattedidentifier, and to remove cross-references to identifiers that we nowdiscover should be unindexed.@<Process a form...@>= { next_control=get_next(); if (next_control==identifier) { lhs=id_lookup(id_first, id_loc,normal); lhs->ilk=normal; if (xref_switch) new_xref(lhs); next_control=get_next(); if (next_control==identifier) { rhs=id_lookup(id_first, id_loc,normal); lhs->ilk=rhs->ilk; if (unindexed(lhs)) { /* retain only underlined entries */ xref_pointer q,r=NULL; for (q=(xref_pointer)lhs->xref;q>xmem;q=q->xlink) if (q->num<def_flag) if (r) r->xlink=q->xlink; else lhs->xref=(char*)q->xlink; else r=q; } next_control=get_next(); } }}@ A much simpler processing of format definitions occurs when thedefinition is found in limbo.@<Process simple format in limbo@>={ if (get_next()!=identifier) err_print("! Missing left identifier of @@s");@.Missing left identifier...@> else { lhs=id_lookup(id_first,id_loc,normal); if (get_next()!=identifier) err_print("! Missing right identifier of @@s");@.Missing right identifier...@> else { rhs=id_lookup(id_first,id_loc,normal); lhs->ilk=rhs->ilk; } }}@ Finally, when the \TEX/ and definition parts have been treated, we have|next_control>=begin_C|.@<Store cross-references in the \CEE/...@>=if (next_control<=section_name) { /* |begin_C| or |section_name| */ if (next_control==begin_C) section_xref_switch=0; else { section_xref_switch=def_flag; if(cur_section_char=='(' && cur_section!=name_dir) set_file_flag(cur_section); } do { if (next_control==section_name && cur_section!=name_dir) new_section_xref(cur_section); next_control=get_next(); outer_xref(); } while ( next_control<=section_name);}@ After phase one has looked at everything, we want to check that eachsection name was both defined and used. The variable |cur_xref| will pointto cross-references for the current section name of interest.@<Global...@>=xref_pointer cur_xref; /* temporary cross-reference pointer */boolean an_output; /* did |file_flag| precede |cur_xref|? */@ The following recursive procedurewalks through the tree of section names and prints out anomalies.@^recursion@>@<Predecl...@>=void section_check();@ @cvoidsection_check(p)name_pointer p; /* print anomalies in subtree |p| */{ if (p) { section_check(p->llink); cur_xref=(xref_pointer)p->xref; if (cur_xref->num==file_flag) {an_output=1; cur_xref=cur_xref->xlink;} else an_output=0; if (cur_xref->num <def_flag) { printf("\n! Never defined: <"); print_section_name(p); putchar('>'); mark_harmless;@.Never defined: <section name>@> } while (cur_xref->num >=cite_flag) cur_xref=cur_xref->xlink; if (cur_xref==xmem && !an_output) { printf("\n! Never used: <"); print_section_name(p); putchar('>'); mark_harmless;@.Never used: <section name>@> } section_check(p->rlink); }}@ @<Print error messages about un...@>=section_check(root)@* Low-level output routines.The \TEX/ output is supposed to appear in lines at most |line_length|characters long, so we place it into an output buffer. During the outputprocess, |out_line| will hold the current line number of the line about tobe output.@<Global...@>=char out_buf[line_length+1]; /* assembled characters */char *out_ptr; /* just after last character in |out_buf| */char *out_buf_end = out_buf+line_length; /* end of |out_buf| */int out_line; /* number of next line to be output */@ The |flush_buffer| routine empties the buffer up to a given breakpoint,and moves any remaining characters to the beginning of the next line.If the |per_cent| parameter is 1 a |'%'| is appended to the linethat is being output; in this case the breakpoint |b| should be strictlyless than |out_buf_end|. If the |per_cent| parameter is |0|,trailing blanks are suppressed.The characters emptied from the buffer form a new line of output;if the |carryover| parameter is true, a |"%"| in that line will becarried over to the next line (so that \TEX/ will ignore the completionof commented-out text).@d c_line_write(c) fflush(active_file),fwrite(out_buf+1,sizeof(char),c,active_file)@d tex_putc(c) putc(c,active_file)@d tex_new_line putc('\n',active_file)@d tex_printf(c) fprintf(active_file,c)@cvoidflush_buffer(b,per_cent,carryover)char *b; /* outputs from |out_buf+1| to |b|,where |b<=out_ptr| */boolean per_cent,carryover;{ char *j; j=b; /* pointer into |out_buf| */ if (! per_cent) /* remove trailing blanks */ while (j>out_buf && *j==' ') j--; c_line_write(j-out_buf); if (per_cent) tex_putc('%'); tex_new_line; out_line++; if (carryover) while (j>out_buf) if (*j--=='%' && (j==out_buf || *j!='\\')) { *b--='%'; break; } if (b<out_ptr) strncpy(out_buf+1,b+1,out_ptr-b); out_ptr-=b-out_buf;}@ When we are copying \TEX/ source material, we retain line breaksthat occur in the input, except that an empty line is notoutput when the \TEX/ source line was nonempty. For example, a lineof the \TEX/ file that contains only an index cross-reference entrywill not be copied. The |finish_line| routine is called just before|get_line| inputs a new line, and just after a line break token hasbeen emitted during the output of translated \CEE/ text.@cvoidfinish_line() /* do this at the end of a line */{ char *k; /* pointer into |buffer| */ if (out_ptr>out_buf) flush_buffer(out_ptr,0,0); else { for (k=buffer; k<=limit; k++) if (!(xisspace(*k))) return; flush_buffer(out_buf,0,0); }}@ In particular, the |finish_line| procedure is called near the verybeginning of phase two. We initialize the output variables in a slightlytricky way so that the first line of the output file will be`\.{\\input cwebmac}'.@<Set init...@>=out_ptr=out_buf+1; out_line=1; active_file=tex_file;*out_ptr='c'; tex_printf("\\input cwebma");@ When we wish to append one character |c| to the output buffer, we write`|out(c)|'; this will cause the buffer to be emptied if it was alreadyfull. If we want to append more than one character at once, we say|out_str(s)|, where |s| is a string containing the characters.A line break will occur at a space or after a single-nonletter\TEX/ control sequence.@d out(c) {if (out_ptr>=out_buf_end) break_out(); *(++out_ptr)=c;}@cvoidout_str(s) /* output characters from |s| to end of string */char *s;{ while (*s) out(*s++);}@ The |break_out| routine is called just before the output buffer is aboutto overflow. To make this routine a little faster, we initialize position0 of the output buffer to `\.\\'; this character isn't really output.@<Set init...@>=out_buf[0]='\\';@ A long line is broken at a blank space or just before a backslash that isn'tpreceded by another backslash. In the latter case, a |'%'| is output atthe break.@<Predecl...@>=void break_out();@ @cvoidbreak_out() /* finds a way to break the output line */{ char *k=out_ptr; /* pointer into |out_buf| */ while (1) { if (k==out_buf) @<Print warning message, break the line, |return|@>; if (*k==' ') { flush_buffer(k,0,1); return; } if (*(k--)=='\\' && *k!='\\') { /* we've decreased |k| */ flush_buffer(k,1,1); return; } }}@ We get to this section only in the unusual case that the entire output lineconsists of a string of backslashes followed by a string of nonblanknon-backslashes. In such cases it is almost always safe to break the
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -