% This file is part of CWEB.% This program by Silvio Levy and Donald E. Knuth% is based on a program by Knuth.% It is distributed WITHOUT ANY WARRANTY, express or implied.% Version 4.3 --- May 2021 % Copyright (C) 1987,1990,1993,2000 Silvio Levy and Donald E. Knuth % Permission is granted to make and distribute verbatim copies of this% document provided that the copyright notice and this permission notice% are preserved on all copies. % Permission is granted to copy and distribute modified versions of this% document under the conditions for verbatim copying, provided that the% entire resulting derived work is given a different name and distributed% under the terms of a permission notice identical to this one. % Amendments to 'cweave.w' resulting in this updated version were created% by numerous collaborators over the course of many years. % Please send comments, suggestions, etc. to tex-k@@tug.org. % Here is TeX material that gets inserted after \input cwebmac\def\hang{\hangindent 3em\indent\ignorespaces}\def\pb{$\.|\ldots\.|$} % C brackets (|...|)\def\v{\char'174} % vertical (|) in typewriter font\def\dleft{[\![} \def\dright{]\!]} % double brackets\mathchardef\RA="3221 % right arrow\mathchardef\BA="3224 % double arrow\def\({} % ) kludge for alphabetizing certain section names\def\TeXxstring{\\{\TEX/\_string}}\def\skipxTeX{\\{skip\_\TEX/}}\def\copyxTeX{\\{copy\_\TEX/}} \def\title{CWEAVE (Version 4.3)}\def\topofcontents{\null\vfill \centerline{\titlefont The {\ttitlefont CWEAVE} processor} \vskip 15pt \centerline{(Version 4.3)} \vfill}\def\botofcontents{\vfill\noindentCopyright \copyright\ 1987, 1990, 1993, 2000 Silvio Levy and Donald E. Knuth\bigskip\noindentPermission is granted to make and distribute verbatim copies of thisdocument provided that the copyright notice and this permission noticeare preserved on all copies. \smallskip\noindentPermission is granted to copy and distribute modified versions of thisdocument under the conditions for verbatim copying, provided that theentire resulting derived work is given a different name and distributedunder the terms of a permission notice identical to this one.}\pageno=\contentspagenumber \advance\pageno by 1\let\maybe=\iftrue @** Introduction.This is the \.{CWEAVE} program by Silvio Levy and Donald E. Knuth,based on \.{WEAVE} by Knuth.We are thankful to Steve Avery,Nelson Beebe, Hans-Hermann Bode (to whom the original \CPLUSPLUS/ adaptationis due), Klaus Guntermann, Norman Ramsey, Tomas Rokicki, Joachim Schnitter,Joachim Schrod, Lee Wittenberg, Saroj Mahapatra, Cesar Augusto RoratoCrusius, 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.3)" @c@<Include files@>@/@h@<Common code for \.{CWEAVE} and \.{CTANGLE}@>@/@<Typedef declarations@>@/@<Private variables@>@/@<Predeclaration of procedures@> @ \.{CWEAVE} has a fairly straightforward outline. It operates inthree phases: First it inputs the source file and stores cross-referencedata, then it inputs the source once again and produces the \TEX/ outputfile, finally it sorts and outputs the index. Please read the documentation for \.{common}, the set of routines commonto \.{CTANGLE} and \.{CWEAVE}, before proceeding further. @cint main (int ac, /* argument count */char **av) /* argument values */{ argc=ac; argv=av; program=cweave; @<Set initial values@>@; common_init(); @<Start \TEX/ output@>@; if (show_banner) puts(banner); /* print a ``banner line'' */ @<Store all the reserved words@>@; phase_one(); /* read all the user's text and store the cross-references */ phase_two(); /* read all the text again and translate it to \TEX/ form */ phase_three(); /* output the cross-reference index */ if (tracing==fully && !show_progress) new_line; return wrap_up(); /* and exit gracefully */} @ The next few sections contain stuff from the file |"common.w"| that mustbe included in both |"ctangle.w"| and |"cweave.w"|. It appears infile |"common.h"|, which is also included in |"common.w"| to propagatepossible changes from this \.{COMMON} interface consistently. @i common.h @ The following parameters were sufficient in the original \.{WEAVE} tohandle \TEX/, so they should be sufficient for most applications of \.{CWEAVE}. @d line_length 80 /* lines of \TEX/ output have at most this many characters; should be less than 256 */@d max_refs 65535 /* number of cross-references; must be less than 65536 */@d max_scraps 10000 /* number of tokens in \CEE/ texts being parsed */ @* Data structures exclusive to {\tt CWEAVE}.As explained in \.{common.w}, the field of a |name_info| structurethat contains the |rlink| of a section name is used for a completelydifferent purpose in the case of identifiers. It is then called the|ilk| of the identifier, and it is used todistinguish between various types of identifiers, as follows: \yskip\hang |normal| and |func_template| identifiers are part of the\CEE/ program that will appear in italic type (or in typewriter typeif all uppercase). \yskip\hang |custom| identifiers are part of the \CEE/ program thatwill be typeset in special ways. \yskip\hang |roman| identifiers are index entries that appear after\.{@@\^} in the \.{CWEB} file. \yskip\hang |wildcard| identifiers are index entries that appear after\.{@@:} in the \.{CWEB} file. \yskip\hang |typewriter| identifiers are index entries that appear after\.{@@.} in the \.{CWEB} file. \yskip\hang |alfop|, \dots, |attr|identifiers are \CEE/ or \CPLUSPLUS/ reserved words whose |ilk|explains how they are to be treated when \CEE/ code is beingformatted. @d ilk dummy.Ilk@d normal 0 /* ordinary identifiers have |normal| ilk */@d roman 1 /* normal index entries have |roman| ilk */@d wildcard 2 /* user-formatted index entries have |wildcard| ilk */@d typewriter 3 /* `typewriter type' entries have |typewriter| ilk */@d abnormal(a) (a->ilk>typewriter) /* tells if a name is special */@d func_template 4 /* identifiers that can be followed by optional template */@d custom 5 /* identifiers with user-given control sequence */@d alfop 22 /* alphabetic operators like \&{and} or \&{not\_eq} */@d else_like 26 /* \&{else} */@d public_like 40 /* \&{public}, \&{private}, \&{protected} */@d operator_like 41 /* \&{operator} */@d new_like 42 /* \&{new} */@d catch_like 43 /* \&{catch} */@d for_like 45 /* \&{for}, \&{switch}, \&{while} */@d do_like 46 /* \&{do} */@d if_like 47 /* \&{if}, \&{ifdef}, \&{endif}, \&{pragma}, \dots */@d delete_like 48 /* \&{delete} */@d raw_ubin 49 /* `\.\&' or `\.*' when looking for \&{const} following */@d const_like 50 /* \&{const}, \&{volatile} */@d raw_int 51 /* \&{int}, \&{char}, \dots; also structure and class names */@d int_like 52 /* same, when not followed by left parenthesis or \DC\ */@d case_like 53 /* \&{case}, \&{return}, \&{goto}, \&{break}, \&{continue} */@d sizeof_like 54 /* \&{sizeof} */@d struct_like 55 /* \&{struct}, \&{union}, \&{enum}, \&{class} */@d typedef_like 56 /* \&{typedef} */@d define_like 57 /* \&{define} */@d template_like 58 /* \&{template} */@d alignas_like 59 /* \&{alignas} */@d using_like 60 /* \&{using} */@d default_like 61 /* \&{default} */@d attr 62 /* \&{noexcept} and attributes */ @ We keep track of the current section number in |section_count|, whichis the total number of sections that have started. Sections which havebeen altered by a change file entry have their |changed_section| flagturned on during the first phase. @<Private...@>=static boolean change_exists; /* has any section changed? */ @ The other large memory area in \.{CWEAVE} keeps the cross-reference data.All uses of the name |p| are recorded in a linked list beginning at|p->xref|, which points into the |xmem| array. The elements of |xmem|are structures consisting of an integer, |num|, and a pointer |xlink|to another element of |xmem|. If |x=p->xref| is a pointer into |xmem|,the value of |x->num| is either a section number where |p| is used,or |cite_flag| plus a section number where |p| is mentioned,or |def_flag| plus a section number where |p| is defined;and |x->xlink| points to the next such cross-reference for |p|,if any. This list of cross-references is in decreasing order bysection number. The next unused slot in |xmem| is |xref_ptr|.The linked list ends at |&xmem[0]|. The global variable |xref_switch| is set either to |def_flag| or to zero,depending on whether the next cross-reference to an identifier is to beunderlined or not in the index. This switch is set to |def_flag| when\.{@@!} or \.{@@d} is scanned, and it is cleared to zero whenthe next identifier or index entry cross-reference has been made.Similarly, the global variable |section_xref_switch| is either|def_flag| or |cite_flag| or zero, dependingon whether a section name is being defined, cited or used in \CEE/ text. @<Type...@>=typedef struct xref_info { sixteen_bits num; /* section number plus zero or |def_flag| */ struct xref_info *xlink; /* pointer to the previous cross-reference */} xref_info;typedef xref_info *xref_pointer; @ @<Private...@>=static xref_info xmem[max_refs]; /* contains cross-reference information */static xref_pointer xmem_end = xmem+max_refs-1;static xref_pointer xref_ptr; /* the largest occupied position in |xmem| */static sixteen_bits xref_switch,section_xref_switch; /* either zero or |def_flag| */ @ A section that is used for multi-file output (with the \.{@@(} feature)has a special first cross-reference whose |num| field is |file_flag|. @d file_flag (3*cite_flag)@d def_flag (2*cite_flag)@d cite_flag 10240 /* must be strictly larger than |max_sections| */@d xref equiv_or_xref @<Set init...@>=xref_ptr=xmem; init_node(name_dir); xref_switch=section_xref_switch=0;xmem->num=0; /* sentinel value */ @ A new cross-reference for an identifier is formed by calling |new_xref|,which discards duplicate entries and ignores non-underlined referencesto one-letter identifiers or \CEE/'s reserved words. If the user has sent the |no_xref| flag (the \.{-x} option of the command line),it is unnecessary to keep track of cross-references for identifiers.If one were careful, one could probably make more changes around section115 to avoid a lot of identifier looking up. @d append_xref(c) if (xref_ptr==xmem_end) overflow("cross-reference"); else (++xref_ptr)->num=c;@d no_xref (!make_xrefs)@d is_tiny(p) (length(p)==1)@d unindexed(a) (a<res_wd_end && a->ilk>=custom) /* tells if uses of a name are to be indexed */ @<Predecl...@>=static void new_xref(name_pointer);@/static void new_section_xref(name_pointer);@/static void set_file_flag(name_pointer); @ @cstatic voidnew_xref(name_pointer p){ xref_pointer q; /* pointer to previous cross-reference */ sixteen_bits m, n; /* new and previous cross-reference value */ if (no_xref) return; if ((unindexed(p) || is_tiny(p)) && xref_switch==0) return; m=section_count+xref_switch; xref_switch=0; q=(xref_pointer)p->xref; if (q != xmem) { n=q->num; if (n==m || n==m+def_flag) return; else if (m==n+def_flag) { q->num=m; return; } } append_xref(m); xref_ptr->xlink=q; update_node(p);} @ The cross-reference lists for section names are slightly different.Suppose that a section name is defined in sections $m_1$, \dots,$m_k$, cited in sections $n_1$, \dots, $n_l$, and used in sections$p_1$, \dots, $p_j$. Then its list will contain $m_1+|def_flag|$,\dots, $m_k+|def_flag|$, $n_1+|cite_flag|$, \dots,$n_l+|cite_flag|$, $p_1$, \dots, $p_j$, in this order. Although this method of storage takes quadratic time with respect tothe length of the list, under foreseeable uses of \.{CWEAVE} this inefficiencyis insignificant. @cstatic voidnew_section_xref(name_pointer p){ xref_pointer q=(xref_pointer)p->xref; xref_pointer r=xmem; /* pointers to previous cross-references */ if (q>r) while (q->num>section_xref_switch) {r=q; q=q->xlink;} if (r->num==section_count+section_xref_switch) return; /* don't duplicate entries */ append_xref(section_count+section_xref_switch); xref_ptr->xlink=q; section_xref_switch=0; if (r==xmem) update_node(p); else r->xlink=xref_ptr;} @ The cross-reference list for a section name may also begin with|file_flag|. Here's how that flag gets put~in. @cstatic voidset_file_flag(name_pointer p){ xref_pointer q=(xref_pointer)p->xref; if (q->num==file_flag) return; append_xref(file_flag); xref_ptr->xlink = q; update_node(p);} @ A third large area of memory is used for sixteen-bit `tokens', which appearin short lists similar to the strings of characters in |byte_mem|. Token listsare used to contain the result of \CEE/ code translated into \TEX/ form;further details about them will be explained later. A \&{text\_pointer}variable is an index into |tok_start|. @<Typed...@>=typedef sixteen_bits token;typedef token *token_pointer;typedef token_pointer *text_pointer; @ The first position of |tok_mem|that is unoccupied by replacement text is called |tok_ptr|, and the firstunused location of |tok_start| is called |text_ptr|.Thus, we usually have |*text_ptr==tok_ptr|. @<Private...@>=static token tok_mem[max_toks]; /* tokens */static token_pointer tok_mem_end = tok_mem+max_toks-1; /* end of |tok_mem| */static token_pointer tok_ptr; /* first unused position in |tok_mem| */static token_pointer max_tok_ptr; /* largest value of |tok_ptr| */static token_pointer tok_start[max_texts]; /* directory into |tok_mem| */static text_pointer tok_start_end = tok_start+max_texts-1; /* end of |tok_start| */static text_pointer text_ptr; /* first unused position in |tok_start| */static text_pointer max_text_ptr; /* largest value of |text_ptr| */ @ @<Set init...@>=tok_ptr=max_tok_ptr=tok_mem+1;@/tok_start[0]=tok_start[1]=tok_mem+1;@/text_ptr=max_text_ptr=tok_start+1; @ Here are the three procedures needed to complete |id_lookup|:@cboolean names_match(name_pointer p, /* points to the proposed match */const char *first, /* position of first character of string */size_t l, /* length of identifier */eight_bits t) /* desired |ilk| */{ if (length(p)!=l) return false; if (p->ilk!=t && !(t==normal && abnormal(p))) return false; return !strncmp(first,p->byte_start,l);} voidinit_p(name_pointer p,eight_bits t){ p->ilk=t; init_node(p);} voidinit_node(name_pointer p){ p->xref=(void *)xmem;} static voidupdate_node(name_pointer p){ p->xref=(void *)xref_ptr;} @ @<Predecl...@>=@+static void update_node(name_pointer p); @ We have to get \CEE/'s and \CPLUSPLUS/'sreserved words into the hash table, and the simplest way to do this isto insert them every time \.{CWEAVE} is run. Fortunately there are relativelyfew reserved words. (Some of these are not strictly ``reserved,'' butare defined in header files of the ISO Standard \CEE/ Library.An ever growing list of \CPLUSPLUS/ keywords can be found here:\.{https://en.cppreference.com/w/cpp/keyword}.)@^reserved words@> @<Store all the reserved words@>=id_lookup("alignas",NULL,alignas_like);id_lookup("alignof",NULL,sizeof_like);id_lookup("and",NULL,alfop);id_lookup("and_eq",NULL,alfop);id_lookup("asm",NULL,sizeof_like);id_lookup("auto",NULL,int_like);id_lookup("bitand",NULL,alfop);id_lookup("bitor",NULL,alfop);id_lookup("bool",NULL,raw_int);id_lookup("break",NULL,case_like);id_lookup("case",NULL,case_like);id_lookup("catch",NULL,catch_like);id_lookup("char",NULL,raw_int);id_lookup("char8_t",NULL,raw_int);id_lookup("char16_t",NULL,raw_int);id_lookup("char32_t",NULL,raw_int);id_lookup("class",NULL,struct_like);id_lookup("clock_t",NULL,raw_int);id_lookup("compl",NULL,alfop);id_lookup("concept",NULL,int_like);id_lookup("const",NULL,const_like);id_lookup("consteval",NULL,const_like);id_lookup("constexpr",NULL,const_like);id_lookup("constinit",NULL,const_like);id_lookup("const_cast",NULL,raw_int);id_lookup("continue",NULL,case_like);id_lookup("co_await",NULL,case_like);id_lookup("co_return",NULL,case_like);id_lookup("co_yield",NULL,case_like);id_lookup("decltype",NULL,sizeof_like);id_lookup("default",NULL,default_like);id_lookup("define",NULL,define_like);id_lookup("defined",NULL,sizeof_like);id_lookup("delete",NULL,delete_like);id_lookup("div_t",NULL,raw_int);id_lookup("do",NULL,do_like);id_lookup("double",NULL,raw_int);id_lookup("dynamic_cast",NULL,raw_int);id_lookup("elif",NULL,if_like);id_lookup("else",NULL,else_like);id_lookup("endif",NULL,if_like);id_lookup("enum",NULL,struct_like);id_lookup("error",NULL,if_like);id_lookup("explicit",NULL,int_like);id_lookup("export",NULL,int_like);id_lookup("extern",NULL,int_like);id_lookup("FILE",NULL,raw_int);id_lookup("false",NULL,normal);id_lookup("float",NULL,raw_int);id_lookup("for",NULL,for_like);id_lookup("fpos_t",NULL,raw_int);id_lookup("friend",NULL,int_like);id_lookup("goto",NULL,case_like);id_lookup("if",NULL,if_like);id_lookup("ifdef",NULL,if_like);id_lookup("ifndef",NULL,if_like);id_lookup("include",NULL,if_like);id_lookup("inline",NULL,int_like);id_lookup("int",NULL,raw_int);id_lookup("jmp_buf",NULL,raw_int);id_lookup("ldiv_t",NULL,raw_int);id_lookup("line",NULL,if_like);id_lookup("long",NULL,raw_int);id_lookup("mutable",NULL,int_like);id_lookup("namespace",NULL,struct_like);id_lookup("new",NULL,new_like);id_lookup("noexcept",NULL,attr);id_lookup("not",NULL,alfop);id_lookup("not_eq",NULL,alfop);id_lookup("NULL",NULL,custom);id_lookup("nullptr",NULL,custom);id_lookup("offsetof",NULL,raw_int);id_lookup("operator",NULL,operator_like);id_lookup("or",NULL,alfop);id_lookup("or_eq",NULL,alfop);id_lookup("pragma",NULL,if_like);id_lookup("private",NULL,public_like);id_lookup("protected",NULL,public_like);id_lookup("ptrdiff_t",NULL,raw_int);id_lookup("public",NULL,public_like);id_lookup("register",NULL,int_like);id_lookup("reinterpret_cast",NULL,raw_int);id_lookup("requires",NULL,int_like);id_lookup("restrict",NULL,int_like);id_lookup("return",NULL,case_like);id_lookup("short",NULL,raw_int);id_lookup("sig_atomic_t",NULL,raw_int);id_lookup("signed",NULL,raw_int);id_lookup("size_t",NULL,raw_int);id_lookup("sizeof",NULL,sizeof_like);id_lookup("static",NULL,int_like);id_lookup("static_assert",NULL,sizeof_like);id_lookup("static_cast",NULL,raw_int);id_lookup("struct",NULL,struct_like);id_lookup("switch",NULL,for_like);id_lookup("template",NULL,template_like);id_lookup("this",NULL,custom);id_lookup("thread_local",NULL,raw_int);id_lookup("throw",NULL,case_like);id_lookup("time_t",NULL,raw_int);id_lookup("true",NULL,normal);Lines 1–500 of 4904. Load more
% This file is part of CWEB. % This program by Silvio Levy and Donald E. Knuth % is based on a program by Knuth. % It is distributed WITHOUT ANY WARRANTY, express or implied. % Version 4.3 --- May 2021 % Copyright (C) 1987,1990,1993,2000 Silvio Levy and Donald E. Knuth % Permission is granted to make and distribute verbatim copies of this % document provided that the copyright notice and this permission notice % are preserved on all copies. % Permission is granted to copy and distribute modified versions of this % document under the conditions for verbatim copying, provided that the % entire resulting derived work is given a different name and distributed % under the terms of a permission notice identical to this one. % Amendments to 'cweave.w' resulting in this updated version were created % by numerous collaborators over the course of many years. % Please send comments, suggestions, etc. to tex-k@@tug.org. % Here is TeX material that gets inserted after \input cwebmac \def\hang{\hangindent 3em\indent\ignorespaces} \def\pb{$\.|\ldots\.|$} % C brackets (|...|) \def\v{\char'174} % vertical (|) in typewriter font \def\dleft{[\![} \def\dright{]\!]} % double brackets \mathchardef\RA="3221 % right arrow \mathchardef\BA="3224 % double arrow \def\({} % ) kludge for alphabetizing certain section names \def\TeXxstring{\\{\TEX/\_string}} \def\skipxTeX{\\{skip\_\TEX/}} \def\copyxTeX{\\{copy\_\TEX/}} \def\title{CWEAVE (Version 4.3)} \def\topofcontents{\null\vfill \centerline{\titlefont The {\ttitlefont CWEAVE} processor} \vskip 15pt \centerline{(Version 4.3)} \vfill} \def\botofcontents{\vfill \noindent Copyright \copyright\ 1987, 1990, 1993, 2000 Silvio Levy and Donald E. Knuth \bigskip\noindent Permission is granted to make and distribute verbatim copies of this document provided that the copyright notice and this permission notice are preserved on all copies. \smallskip\noindent Permission is granted to copy and distribute modified versions of this document under the conditions for verbatim copying, provided that the entire resulting derived work is given a different name and distributed under the terms of a permission notice identical to this one. } \pageno=\contentspagenumber \advance\pageno by 1 \let\maybe=\iftrue @** Introduction. This is the \.{CWEAVE} program by Silvio Levy and Donald E. Knuth, based on \.{WEAVE} by Knuth. We are thankful to Steve Avery, Nelson Beebe, Hans-Hermann Bode (to whom the original \CPLUSPLUS/ adaptation is due), Klaus Guntermann, Norman Ramsey, Tomas Rokicki, Joachim Schnitter, Joachim Schrod, Lee Wittenberg, Saroj Mahapatra, Cesar Augusto Rorato 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.3)" @c @<Include files@>@/ @h @<Common code for \.{CWEAVE} and \.{CTANGLE}@>@/ @<Typedef declarations@>@/ @<Private variables@>@/ @<Predeclaration of procedures@> @ \.{CWEAVE} has a fairly straightforward outline. It operates in three phases: First it inputs the source file and stores cross-reference data, then it inputs the source once again and produces the \TEX/ output file, finally it sorts and outputs the index. Please read the documentation for \.{common}, the set of routines common to \.{CTANGLE} and \.{CWEAVE}, before proceeding further. @c int main ( int ac, /* argument count */ char **av) /* argument values */ { argc=ac; argv=av; program=cweave; @<Set initial values@>@; common_init(); @<Start \TEX/ output@>@; if (show_banner) puts(banner); /* print a ``banner line'' */ @<Store all the reserved words@>@; phase_one(); /* read all the user's text and store the cross-references */ phase_two(); /* read all the text again and translate it to \TEX/ form */ phase_three(); /* output the cross-reference index */ if (tracing==fully && !show_progress) new_line; return wrap_up(); /* and exit gracefully */ } @ The next few sections contain stuff from the file |"common.w"| that must be included in both |"ctangle.w"| and |"cweave.w"|. It appears in file |"common.h"|, which is also included in |"common.w"| to propagate possible changes from this \.{COMMON} interface consistently. @i common.h @ The following parameters were sufficient in the original \.{WEAVE} to handle \TEX/, so they should be sufficient for most applications of \.{CWEAVE}. @d line_length 80 /* lines of \TEX/ output have at most this many characters; should be less than 256 */ @d max_refs 65535 /* number of cross-references; must be less than 65536 */ @d max_scraps 10000 /* number of tokens in \CEE/ texts being parsed */ @* Data structures exclusive to {\tt CWEAVE}. As explained in \.{common.w}, the field of a |name_info| structure that contains the |rlink| of a section name is used for a completely different purpose in the case of identifiers. It is then called the |ilk| of the identifier, and it is used to distinguish between various types of identifiers, as follows: \yskip\hang |normal| and |func_template| identifiers are part of the \CEE/ program that will appear in italic type (or in typewriter type if all uppercase). \yskip\hang |custom| identifiers are part of the \CEE/ program that will be typeset in special ways. \yskip\hang |roman| identifiers are index entries that appear after \.{@@\^} in the \.{CWEB} file. \yskip\hang |wildcard| identifiers are index entries that appear after \.{@@:} in the \.{CWEB} file. \yskip\hang |typewriter| identifiers are index entries that appear after \.{@@.} in the \.{CWEB} file. \yskip\hang |alfop|, \dots, |attr| identifiers are \CEE/ or \CPLUSPLUS/ reserved words whose |ilk| explains how they are to be treated when \CEE/ code is being formatted. @d ilk dummy.Ilk @d normal 0 /* ordinary identifiers have |normal| ilk */ @d roman 1 /* normal index entries have |roman| ilk */ @d wildcard 2 /* user-formatted index entries have |wildcard| ilk */ @d typewriter 3 /* `typewriter type' entries have |typewriter| ilk */ @d abnormal(a) (a->ilk>typewriter) /* tells if a name is special */ @d func_template 4 /* identifiers that can be followed by optional template */ @d custom 5 /* identifiers with user-given control sequence */ @d alfop 22 /* alphabetic operators like \&{and} or \&{not\_eq} */ @d else_like 26 /* \&{else} */ @d public_like 40 /* \&{public}, \&{private}, \&{protected} */ @d operator_like 41 /* \&{operator} */ @d new_like 42 /* \&{new} */ @d catch_like 43 /* \&{catch} */ @d for_like 45 /* \&{for}, \&{switch}, \&{while} */ @d do_like 46 /* \&{do} */ @d if_like 47 /* \&{if}, \&{ifdef}, \&{endif}, \&{pragma}, \dots */ @d delete_like 48 /* \&{delete} */ @d raw_ubin 49 /* `\.\&' or `\.*' when looking for \&{const} following */ @d const_like 50 /* \&{const}, \&{volatile} */ @d raw_int 51 /* \&{int}, \&{char}, \dots; also structure and class names */ @d int_like 52 /* same, when not followed by left parenthesis or \DC\ */ @d case_like 53 /* \&{case}, \&{return}, \&{goto}, \&{break}, \&{continue} */ @d sizeof_like 54 /* \&{sizeof} */ @d struct_like 55 /* \&{struct}, \&{union}, \&{enum}, \&{class} */ @d typedef_like 56 /* \&{typedef} */ @d define_like 57 /* \&{define} */ @d template_like 58 /* \&{template} */ @d alignas_like 59 /* \&{alignas} */ @d using_like 60 /* \&{using} */ @d default_like 61 /* \&{default} */ @d attr 62 /* \&{noexcept} and attributes */ @ We keep track of the current section number in |section_count|, which is the total number of sections that have started. Sections which have been altered by a change file entry have their |changed_section| flag turned on during the first phase. @<Private...@>= static boolean change_exists; /* has any section changed? */ @ The other large memory area in \.{CWEAVE} keeps the cross-reference data. All uses of the name |p| are recorded in a linked list beginning at |p->xref|, which points into the |xmem| array. The elements of |xmem| are structures consisting of an integer, |num|, and a pointer |xlink| to another element of |xmem|. If |x=p->xref| is a pointer into |xmem|, the value of |x->num| is either a section number where |p| is used, or |cite_flag| plus a section number where |p| is mentioned, or |def_flag| plus a section number where |p| is defined; and |x->xlink| points to the next such cross-reference for |p|, if any. This list of cross-references is in decreasing order by section number. The next unused slot in |xmem| is |xref_ptr|. The linked list ends at |&xmem[0]|. The global variable |xref_switch| is set either to |def_flag| or to zero, depending on whether the next cross-reference to an identifier is to be underlined or not in the index. This switch is set to |def_flag| when \.{@@!} or \.{@@d} is scanned, and it is cleared to zero when the next identifier or index entry cross-reference has been made. Similarly, the global variable |section_xref_switch| is either |def_flag| or |cite_flag| or zero, depending on whether a section name is being defined, cited or used in \CEE/ text. @<Type...@>= typedef struct xref_info { sixteen_bits num; /* section number plus zero or |def_flag| */ struct xref_info *xlink; /* pointer to the previous cross-reference */ } xref_info; typedef xref_info *xref_pointer; @ @<Private...@>= static xref_info xmem[max_refs]; /* contains cross-reference information */ static xref_pointer xmem_end = xmem+max_refs-1; static xref_pointer xref_ptr; /* the largest occupied position in |xmem| */ static sixteen_bits xref_switch,section_xref_switch; /* either zero or |def_flag| */ @ A section that is used for multi-file output (with the \.{@@(} feature) has a special first cross-reference whose |num| field is |file_flag|. @d file_flag (3*cite_flag) @d def_flag (2*cite_flag) @d cite_flag 10240 /* must be strictly larger than |max_sections| */ @d xref equiv_or_xref @<Set init...@>= xref_ptr=xmem; init_node(name_dir); xref_switch=section_xref_switch=0; xmem->num=0; /* sentinel value */ @ A new cross-reference for an identifier is formed by calling |new_xref|, which discards duplicate entries and ignores non-underlined references to one-letter identifiers or \CEE/'s reserved words. If the user has sent the |no_xref| flag (the \.{-x} option of the command line), it is unnecessary to keep track of cross-references for identifiers. If one were careful, one could probably make more changes around section 115 to avoid a lot of identifier looking up. @d append_xref(c) if (xref_ptr==xmem_end) overflow("cross-reference"); else (++xref_ptr)->num=c; @d no_xref (!make_xrefs) @d is_tiny(p) (length(p)==1) @d unindexed(a) (a<res_wd_end && a->ilk>=custom) /* tells if uses of a name are to be indexed */ @<Predecl...@>= static void new_xref(name_pointer);@/ static void new_section_xref(name_pointer);@/ static void set_file_flag(name_pointer); @ @c static void new_xref( name_pointer p) { xref_pointer q; /* pointer to previous cross-reference */ sixteen_bits m, n; /* new and previous cross-reference value */ if (no_xref) return; if ((unindexed(p) || is_tiny(p)) && xref_switch==0) return; m=section_count+xref_switch; xref_switch=0; q=(xref_pointer)p->xref; if (q != xmem) { n=q->num; if (n==m || n==m+def_flag) return; else if (m==n+def_flag) { q->num=m; return; } } append_xref(m); xref_ptr->xlink=q; update_node(p); } @ The cross-reference lists for section names are slightly different. Suppose that a section name is defined in sections $m_1$, \dots, $m_k$, cited in sections $n_1$, \dots, $n_l$, and used in sections $p_1$, \dots, $p_j$. Then its list will contain $m_1+|def_flag|$, \dots, $m_k+|def_flag|$, $n_1+|cite_flag|$, \dots, $n_l+|cite_flag|$, $p_1$, \dots, $p_j$, in this order. Although this method of storage takes quadratic time with respect to the length of the list, under foreseeable uses of \.{CWEAVE} this inefficiency is insignificant. @c static void new_section_xref( name_pointer p) { xref_pointer q=(xref_pointer)p->xref; xref_pointer r=xmem; /* pointers to previous cross-references */ if (q>r) while (q->num>section_xref_switch) {r=q; q=q->xlink;} if (r->num==section_count+section_xref_switch) return; /* don't duplicate entries */ append_xref(section_count+section_xref_switch); xref_ptr->xlink=q; section_xref_switch=0; if (r==xmem) update_node(p); else r->xlink=xref_ptr; } @ The cross-reference list for a section name may also begin with |file_flag|. Here's how that flag gets put~in. @c static void set_file_flag( name_pointer p) { xref_pointer q=(xref_pointer)p->xref; if (q->num==file_flag) return; append_xref(file_flag); xref_ptr->xlink = q; update_node(p); } @ A third large area of memory is used for sixteen-bit `tokens', which appear in short lists similar to the strings of characters in |byte_mem|. Token lists are used to contain the result of \CEE/ code translated into \TEX/ form; further details about them will be explained later. A \&{text\_pointer} variable is an index into |tok_start|. @<Typed...@>= typedef sixteen_bits token; typedef token *token_pointer; typedef token_pointer *text_pointer; @ The first position of |tok_mem| that is unoccupied by replacement text is called |tok_ptr|, and the first unused location of |tok_start| is called |text_ptr|. Thus, we usually have |*text_ptr==tok_ptr|. @<Private...@>= static token tok_mem[max_toks]; /* tokens */ static token_pointer tok_mem_end = tok_mem+max_toks-1; /* end of |tok_mem| */ static token_pointer tok_ptr; /* first unused position in |tok_mem| */ static token_pointer max_tok_ptr; /* largest value of |tok_ptr| */ static token_pointer tok_start[max_texts]; /* directory into |tok_mem| */ static text_pointer tok_start_end = tok_start+max_texts-1; /* end of |tok_start| */ static text_pointer text_ptr; /* first unused position in |tok_start| */ static text_pointer max_text_ptr; /* largest value of |text_ptr| */ @ @<Set init...@>= tok_ptr=max_tok_ptr=tok_mem+1;@/ tok_start[0]=tok_start[1]=tok_mem+1;@/ text_ptr=max_text_ptr=tok_start+1; @ Here are the three procedures needed to complete |id_lookup|: @c boolean names_match( name_pointer p, /* points to the proposed match */ const char *first, /* position of first character of string */ size_t l, /* length of identifier */ eight_bits t) /* desired |ilk| */ { if (length(p)!=l) return false; if (p->ilk!=t && !(t==normal && abnormal(p))) return false; return !strncmp(first,p->byte_start,l); } void init_p( name_pointer p, eight_bits t) { p->ilk=t; init_node(p); } void init_node( name_pointer p) { p->xref=(void *)xmem; } static void update_node( name_pointer p) { p->xref=(void *)xref_ptr; } @ @<Predecl...@>=@+static void update_node(name_pointer p); @ We have to get \CEE/'s and \CPLUSPLUS/'s reserved words into the hash table, and the simplest way to do this is to insert them every time \.{CWEAVE} is run. Fortunately there are relatively few reserved words. (Some of these are not strictly ``reserved,'' but are defined in header files of the ISO Standard \CEE/ Library. An ever growing list of \CPLUSPLUS/ keywords can be found here: \.{https://en.cppreference.com/w/cpp/keyword}.) @^reserved words@> @<Store all the reserved words@>= id_lookup("alignas",NULL,alignas_like); id_lookup("alignof",NULL,sizeof_like); id_lookup("and",NULL,alfop); id_lookup("and_eq",NULL,alfop); id_lookup("asm",NULL,sizeof_like); id_lookup("auto",NULL,int_like); id_lookup("bitand",NULL,alfop); id_lookup("bitor",NULL,alfop); id_lookup("bool",NULL,raw_int); id_lookup("break",NULL,case_like); id_lookup("case",NULL,case_like); id_lookup("catch",NULL,catch_like); id_lookup("char",NULL,raw_int); id_lookup("char8_t",NULL,raw_int); id_lookup("char16_t",NULL,raw_int); id_lookup("char32_t",NULL,raw_int); id_lookup("class",NULL,struct_like); id_lookup("clock_t",NULL,raw_int); id_lookup("compl",NULL,alfop); id_lookup("concept",NULL,int_like); id_lookup("const",NULL,const_like); id_lookup("consteval",NULL,const_like); id_lookup("constexpr",NULL,const_like); id_lookup("constinit",NULL,const_like); id_lookup("const_cast",NULL,raw_int); id_lookup("continue",NULL,case_like); id_lookup("co_await",NULL,case_like); id_lookup("co_return",NULL,case_like); id_lookup("co_yield",NULL,case_like); id_lookup("decltype",NULL,sizeof_like); id_lookup("default",NULL,default_like); id_lookup("define",NULL,define_like); id_lookup("defined",NULL,sizeof_like); id_lookup("delete",NULL,delete_like); id_lookup("div_t",NULL,raw_int); id_lookup("do",NULL,do_like); id_lookup("double",NULL,raw_int); id_lookup("dynamic_cast",NULL,raw_int); id_lookup("elif",NULL,if_like); id_lookup("else",NULL,else_like); id_lookup("endif",NULL,if_like); id_lookup("enum",NULL,struct_like); id_lookup("error",NULL,if_like); id_lookup("explicit",NULL,int_like); id_lookup("export",NULL,int_like); id_lookup("extern",NULL,int_like); id_lookup("FILE",NULL,raw_int); id_lookup("false",NULL,normal); id_lookup("float",NULL,raw_int); id_lookup("for",NULL,for_like); id_lookup("fpos_t",NULL,raw_int); id_lookup("friend",NULL,int_like); id_lookup("goto",NULL,case_like); id_lookup("if",NULL,if_like); id_lookup("ifdef",NULL,if_like); id_lookup("ifndef",NULL,if_like); id_lookup("include",NULL,if_like); id_lookup("inline",NULL,int_like); id_lookup("int",NULL,raw_int); id_lookup("jmp_buf",NULL,raw_int); id_lookup("ldiv_t",NULL,raw_int); id_lookup("line",NULL,if_like); id_lookup("long",NULL,raw_int); id_lookup("mutable",NULL,int_like); id_lookup("namespace",NULL,struct_like); id_lookup("new",NULL,new_like); id_lookup("noexcept",NULL,attr); id_lookup("not",NULL,alfop); id_lookup("not_eq",NULL,alfop); id_lookup("NULL",NULL,custom); id_lookup("nullptr",NULL,custom); id_lookup("offsetof",NULL,raw_int); id_lookup("operator",NULL,operator_like); id_lookup("or",NULL,alfop); id_lookup("or_eq",NULL,alfop); id_lookup("pragma",NULL,if_like); id_lookup("private",NULL,public_like); id_lookup("protected",NULL,public_like); id_lookup("ptrdiff_t",NULL,raw_int); id_lookup("public",NULL,public_like); id_lookup("register",NULL,int_like); id_lookup("reinterpret_cast",NULL,raw_int); id_lookup("requires",NULL,int_like); id_lookup("restrict",NULL,int_like); id_lookup("return",NULL,case_like); id_lookup("short",NULL,raw_int); id_lookup("sig_atomic_t",NULL,raw_int); id_lookup("signed",NULL,raw_int); id_lookup("size_t",NULL,raw_int); id_lookup("sizeof",NULL,sizeof_like); id_lookup("static",NULL,int_like); id_lookup("static_assert",NULL,sizeof_like); id_lookup("static_cast",NULL,raw_int); id_lookup("struct",NULL,struct_like); id_lookup("switch",NULL,for_like); id_lookup("template",NULL,template_like); id_lookup("this",NULL,custom); id_lookup("thread_local",NULL,raw_int); id_lookup("throw",NULL,case_like); id_lookup("time_t",NULL,raw_int); id_lookup("true",NULL,normal);