summaryrefslogtreecommitdiff
path: root/Build/source/texk/web2c/cwebdir/cweave.w
diff options
context:
space:
mode:
authorDenis Bitouzé <dbitouze@wanadoo.fr>2021-02-25 18:23:07 +0000
committerDenis Bitouzé <dbitouze@wanadoo.fr>2021-02-25 18:23:07 +0000
commitc6101f91d071883b48b1b4b51e5eba0f36d9a78d (patch)
tree1bf7f5a881d7a4f5c5bf59d0b2821943dd822372 /Build/source/texk/web2c/cwebdir/cweave.w
parent07ee7222e389b0777456b427a55c22d0e6ffd267 (diff)
French translation for tlmgr updated
git-svn-id: svn://tug.org/texlive/trunk@57912 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Build/source/texk/web2c/cwebdir/cweave.w')
-rw-r--r--Build/source/texk/web2c/cwebdir/cweave.w4696
1 files changed, 0 insertions, 4696 deletions
diff --git a/Build/source/texk/web2c/cwebdir/cweave.w b/Build/source/texk/web2c/cwebdir/cweave.w
deleted file mode 100644
index a8e31055b23..00000000000
--- a/Build/source/texk/web2c/cwebdir/cweave.w
+++ /dev/null
@@ -1,4696 +0,0 @@
-% 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.2 --- February 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.2)}
-\def\topofcontents{\null\vfill
- \centerline{\titlefont The {\ttitlefont CWEAVE} processor}
- \vskip 15pt
- \centerline{(Version 4.2)}
- \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.2)"
-
-@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 (@t\1\1@>
-int ac, /* argument count */
-char **av@t\2\2@>) /* 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==2 && !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_texts 10239 /* number of phrases in \CEE/ texts being parsed;
- must be less than 10240 */
-@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, |template_like|
-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} */
-
-@ 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=0; 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
-100 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) ((p+1)->byte_start==(p)->byte_start+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,r; /* pointers to previous cross-references */
- q=(xref_pointer)p->xref; r=xmem;
- if (q>xmem)
- 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;
- 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(@t\1\1@>
-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@t\2\2@>) /* 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
-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.)
-@^reserved words@>
-
-@<Store all the reserved words@>=
-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("class",NULL,struct_like);
-id_lookup("clock_t",NULL,raw_int);
-id_lookup("compl",NULL,alfop);
-id_lookup("const",NULL,const_like);
-id_lookup("const_cast",NULL,raw_int);
-id_lookup("continue",NULL,case_like);
-id_lookup("default",NULL,case_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("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("not",NULL,alfop);
-id_lookup("not_eq",NULL,alfop);
-id_lookup("NULL",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("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_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("throw",NULL,case_like);
-id_lookup("time_t",NULL,raw_int);
-id_lookup("try",NULL,else_like);
-id_lookup("typedef",NULL,typedef_like);
-id_lookup("typeid",NULL,raw_int);
-id_lookup("typename",NULL,struct_like);
-id_lookup("undef",NULL,if_like);
-id_lookup("union",NULL,struct_like);
-id_lookup("unsigned",NULL,raw_int);
-id_lookup("using",NULL,int_like);
-id_lookup("va_dcl",NULL,decl); /* Berkeley's variable-arg-list convention */
-id_lookup("va_list",NULL,raw_int); /* ditto */
-id_lookup("virtual",NULL,int_like);
-id_lookup("void",NULL,raw_int);
-id_lookup("volatile",NULL,const_like);
-id_lookup("wchar_t",NULL,raw_int);
-id_lookup("while",NULL,for_like);
-id_lookup("xor",NULL,alfop);
-id_lookup("xor_eq",NULL,alfop);@+ res_wd_end=name_ptr;
-id_lookup("TeX",NULL,custom);
-id_lookup("make_pair",NULL,func_template);
-
-@* Lexical scanning.
-Let us now consider the subroutines that read the \.{CWEB} source file
-and break it into meaningful units. There are four such procedures:
-One simply skips to the next `\.{@@\ }' or `\.{@@*}' that begins a
-section; another passes over the \TEX/ text at the beginning of a
-section; the third passes over the \TEX/ text in a \CEE/ comment;
-and the last, which is the most interesting, gets the next token of
-a \CEE/ text. They all use the pointers |limit| and |loc| into
-the line of input currently being studied.
-
-@ Control codes in \.{CWEB}, which begin with `\.{@@}', are converted
-into a numeric code designed to simplify \.{CWEAVE}'s logic; for example,
-larger numbers are given to the control codes that denote more significant
-milestones, and the code of |new_section| should be the largest of
-all. Some of these numeric control codes take the place of |char|
-control codes that will not otherwise appear in the output of the
-scanning routines.
-@^ASCII code dependencies@>
-
-@d ignore 00 /* control code of no interest to \.{CWEAVE} */
-@d verbatim 02 /* takes the place of extended ASCII \.{\char2} */
-@d begin_short_comment 03 /* \CPLUSPLUS/ short comment */
-@d begin_comment '\t' /* tab marks will not appear */
-@d underline '\n' /* this code will be intercepted without confusion */
-@d noop 0177 /* takes the place of ASCII delete */
-@d xref_roman 0203 /* control code for `\.{@@\^}' */
-@d xref_wildcard 0204 /* control code for `\.{@@:}' */
-@d xref_typewriter 0205 /* control code for `\.{@@.}' */
-@d TeX_string 0206 /* control code for `\.{@@t}' */
-@f TeX_string TeX
-@d ord 0207 /* control code for `\.{@@'}' */
-@d join 0210 /* control code for `\.{@@\&}' */
-@d thin_space 0211 /* control code for `\.{@@,}' */
-@d math_break 0212 /* control code for `\.{@@\v}' */
-@d line_break 0213 /* control code for `\.{@@/}' */
-@d big_line_break 0214 /* control code for `\.{@@\#}' */
-@d no_line_break 0215 /* control code for `\.{@@+}' */
-@d pseudo_semi 0216 /* control code for `\.{@@;}' */
-@d macro_arg_open 0220 /* control code for `\.{@@[}' */
-@d macro_arg_close 0221 /* control code for `\.{@@]}' */
-@d trace 0222 /* control code for `\.{@@0}', `\.{@@1}' and `\.{@@2}' */
-@d translit_code 0223 /* control code for `\.{@@l}' */
-@d output_defs_code 0224 /* control code for `\.{@@h}' */
-@d format_code 0225 /* control code for `\.{@@f}' and `\.{@@s}' */
-@d definition 0226 /* control code for `\.{@@d}' */
-@d begin_C 0227 /* control code for `\.{@@c}' */
-@d section_name 0230 /* control code for `\.{@@<}' */
-@d new_section 0231 /* control code for `\.{@@\ }' and `\.{@@*}' */
-
-@ Control codes are converted to \.{CWEAVE}'s internal
-representation by means of the table |ccode|.
-
-@<Private...@>=
-static eight_bits ccode[256]; /* meaning of a char following \.{@@} */
-
-@ @<Set ini...@>=
-{int c; for (c=0; c<256; c++) ccode[c]=0;}
-ccode[' ']=ccode['\t']=ccode['\n']=ccode['\v']=ccode['\r']=ccode['\f']
- =ccode['*']=new_section;
-ccode['@@']='@@'; /* `quoted' at sign */
-ccode['=']=verbatim;
-ccode['d']=ccode['D']=definition;
-ccode['f']=ccode['F']=ccode['s']=ccode['S']=format_code;
-ccode['c']=ccode['C']=ccode['p']=ccode['P']=begin_C;
-ccode['t']=ccode['T']=TeX_string;
-ccode['l']=ccode['L']=translit_code;
-ccode['q']=ccode['Q']=noop;
-ccode['h']=ccode['H']=output_defs_code;
-ccode['&']=join; ccode['<']=ccode['(']=section_name;
-ccode['!']=underline; ccode['^']=xref_roman;
-ccode[':']=xref_wildcard; ccode['.']=xref_typewriter; ccode[',']=thin_space;
-ccode['|']=math_break; ccode['/']=line_break; ccode['#']=big_line_break;
-ccode['+']=no_line_break; ccode[';']=pseudo_semi;
-ccode['[']=macro_arg_open; ccode[']']=macro_arg_close;
-ccode['\'']=ord;
-@<Special control codes for debugging@>@;
-
-@ Users can write
-\.{@@2}, \.{@@1}, and \.{@@0} to turn tracing fully on, partly on,
-and off, respectively.
-
-@<Special control codes...@>=
-ccode['0']=ccode['1']=ccode['2']=trace;
-
-@ The |skip_limbo| routine is used on the first pass to skip through
-portions of the input that are not in any sections, i.e., that precede
-the first section. After this procedure has been called, the value of
-|input_has_ended| will tell whether or not a section has actually been found.
-
-There's a complication that we will postpone until later: If the \.{@@s}
-operation appears in limbo, we want to use it to adjust the default
-interpretation of identifiers.
-
-@<Predec...@>=
-static void skip_limbo(void);@/
-static eight_bits skip_TeX(void);
-
-@ @c
-static void
-skip_limbo(void) {
- while(true) {
- if (loc>limit && get_line()==false) return;
- *(limit+1)='@@';
- while (*loc!='@@') loc++; /* look for `\.{@@}', then skip two chars */
- if (loc++ <=limit) { int c=ccode[(eight_bits)*loc++];
- if (c==new_section) return;
- if (c==noop) skip_restricted();
- else if (c==format_code) @<Process simple format in limbo@>@;
- }
- }
-}
-
-@ The |skip_TeX| routine is used on the first pass to skip through
-the \TEX/ code at the beginning of a section. It returns the next
-control code or `\.{\v}' found in the input. A |new_section| is
-assumed to exist at the very end of the file.
-
-@f skip_TeX TeX
-
-@c
-static eight_bits
-skip_TeX(void) /* skip past pure \TEX/ code */
-{
- while (true) {
- if (loc>limit && get_line()==false) return new_section;
- *(limit+1)='@@';
- while (*loc!='@@' && *loc!='|') loc++;
- if (*loc++ =='|') return '|';
- if (loc<=limit) return ccode[(eight_bits)*(loc++)];
- }
-}
-
-@*1 Inputting the next token.
-As stated above, \.{CWEAVE}'s most interesting lexical scanning routine is the
-|get_next| function that inputs the next token of \CEE/ input. However,
-|get_next| is not especially complicated.
-
-The result of |get_next| is either a |char| code for some special character,
-or it is a special code representing a pair of characters (e.g., `\.{!=}'),
-or it is the numeric value computed by the |ccode|
-table, or it is one of the following special codes:
-
-\yskip\hang |identifier|: In this case the global variables |id_first| and
-|id_loc| will have been set to the beginning and ending-plus-one locations
-in the buffer, as required by the |id_lookup| routine.
-
-\yskip\hang |string|: The string will have been copied into the array
-|section_text|; |id_first| and |id_loc| are set as above (now they are
-pointers into |section_text|).
-
-\yskip\hang |constant|: The constant is copied into |section_text|, with
-slight modifications; |id_first| and |id_loc| are set.
-
-\yskip\noindent Furthermore, some of the control codes cause
-|get_next| to take additional actions:
-
-\yskip\hang |xref_roman|, |xref_wildcard|, |xref_typewriter|, |TeX_string|,
-|verbatim|: The values of |id_first| and |id_loc| will have been set to
-the beginning and ending-plus-one locations in the buffer.
-
-\yskip\hang |section_name|: In this case the global variable |cur_section| will
-point to the |byte_start| entry for the section name that has just been scanned.
-The value of |cur_section_char| will be |'('| if the section name was
-preceded by \.{@@(} instead of \.{@@<}.
-
-\yskip\noindent If |get_next| sees `\.{@@!}'
-it sets |xref_switch| to |def_flag| and goes on to the next token.
-
-@d constant 0200 /* \CEE/ constant */
-@d string 0201 /* \CEE/ string */
-@d identifier 0202 /* \CEE/ identifier or reserved word */
-
-@<Private...@>=
-static name_pointer cur_section; /* name of section just scanned */
-static char cur_section_char; /* the character just before that name */
-
-@ As one might expect, |get_next| consists mostly of a big switch
-that branches to the various special cases that can arise.
-\CEE/ allows underscores to appear in identifiers, and some \CEE/
-compilers even allow the dollar sign.
-
-@d isxalpha(c) ((c)=='_' || (c)=='$')
- /* non-alpha characters allowed in identifier */
-@d ishigh(c) ((eight_bits)(c)>0177)
-@^high-bit character handling@>
-
-@c
-static eight_bits
-get_next(void) /* produces the next input token */
-{
- eight_bits c; /* the current character */
- while (true) {
- @<Check if we're at the end of a preprocessor command@>@;
- if (loc>limit && get_line()==false) return new_section;
- c=*(loc++);
- if (xisdigit(c) || c=='.') @<Get a constant@>@;
- else if (c=='\'' || c=='"'@|
- || ((c=='L' || c=='u' || c=='U')&&(*loc=='\'' || *loc=='"'))@|
- || ((c=='u' && *loc=='8')&&(*(loc+1)=='\'' || *(loc+1)=='"'))@|
- || (c=='<' && sharp_include_line==true))
- @<Get a string@>@;
- else if (xisalpha(c) || isxalpha(c) || ishigh(c))
- @<Get an identifier@>@;
- else if (c=='@@') @<Get control code and possible section name@>@;
- else if (xisspace(c)) continue; /* ignore spaces and tabs */
- if (c=='#' && loc==buffer+1) @<Raise preprocessor flag@>@;
- mistake: @<Compress two-symbol operator@>@;
- return c;
- }
-}
-
-@ @<Predecl...@>=@+static eight_bits get_next(void);
-
-@ Because preprocessor commands do not fit in with the rest of the syntax
-of \CEE/,
-we have to deal with them separately. One solution is to enclose such
-commands between special markers. Thus, when a \.\# is seen as the
-first character of a line, |get_next| returns a special code
-|left_preproc| and raises a flag |preprocessing|.
-
-We can use the same internal code number for |left_preproc| as we do
-for |ord|, since |get_next| changes |ord| into a string.
-
-@d left_preproc ord /* begins a preprocessor command */
-@d right_preproc 0217 /* ends a preprocessor command */
-
-@<Private...@>=
-static boolean preprocessing=false; /* are we scanning a preprocessor command? */
-
-@ @<Raise prep...@>= {
- preprocessing=true;
- @<Check if next token is |include|@>@;
- return left_preproc;
-}
-
-@ An additional complication is the freakish use of \.< and \.> to delimit
-a file name in lines that start with \.{\#include}. We must treat this file
-name as a string.
-
-@<Private...@>=
-static boolean sharp_include_line=false; /* are we scanning a \&{\#include} line? */
-
-@ @<Check if next token is |include|@>=
-while (loc<=buffer_end-7 && xisspace(*loc)) loc++;
-if (loc<=buffer_end-6 && strncmp(loc,"include",7)==0) sharp_include_line=true;
-
-@ When we get to the end of a preprocessor line,
-we lower the flag and send a code |right_preproc|, unless
-the last character was a \.\\.
-
-@<Check if we're at...@>=
- while (loc==limit-1 && preprocessing && *loc=='\\')
- if (get_line()==false) return new_section; /* still in preprocessor mode */
- if (loc>=limit && preprocessing) {
- preprocessing=sharp_include_line=false;
- return right_preproc;
- }
-
-@ The following code assigns values to the combinations \.{++},
-\.{--}, \.{->}, \.{>=}, \.{<=}, \.{==}, \.{<<}, \.{>>}, \.{!=}, \.{\v\v}, and
-\.{\&\&}, and to the \CPLUSPLUS/
-combinations \.{...}, \.{::}, \.{.*} and \.{->*}.
-The compound assignment operators (e.g., \.{+=}) are
-treated as separate tokens.
-
-@d compress(c) if (loc++<=limit) return c
-
-@<Compress tw...@>=
-switch(c) {
- case '/': if (*loc=='*') {compress(begin_comment);}
- else if (*loc=='/') compress(begin_short_comment); break;
- case '+': if (*loc=='+') compress(plus_plus); break;
- case '-': if (*loc=='-') {compress(minus_minus);}
- else { if (*loc=='>') { if (*(loc+1)=='*') {loc++; compress(minus_gt_ast);}
- else compress(minus_gt); } } break;
- case '.': if (*loc=='*') {compress(period_ast);}
- else if (*loc=='.' && *(loc+1)=='.') {
- loc++; compress(dot_dot_dot);
- }
- break;
- case ':': if (*loc==':') compress(colon_colon); break;
- case '=': if (*loc=='=') compress(eq_eq); break;
- case '>': if (*loc=='=') {compress(gt_eq);}
- else if (*loc=='>') compress(gt_gt); break;
- case '<': if (*loc=='=') {compress(lt_eq);}
- else if (*loc=='<') compress(lt_lt); break;
- case '&': if (*loc=='&') compress(and_and); break;
- case '|': if (*loc=='|') compress(or_or); break;
- case '!': if (*loc=='=') compress(non_eq); break;
-}
-
-@ @<Get an identifier@>= {
- id_first=--loc;
- while (isalpha((eight_bits)*++loc) || isdigit((eight_bits)*loc) @|
- || isxalpha((eight_bits)*loc) || ishigh((eight_bits)*loc));
- id_loc=loc; return identifier;
-}
-
-@ Different conventions are followed by \TEX/ and \CEE/ to express octal
-and hexadecimal numbers; it is reasonable to stick to each convention
-within its realm. Thus the \CEE/ part of a \.{CWEB} file has octals
-introduced by \.0 and hexadecimals by \.{0x}, but \.{CWEAVE} will print
-with \TEX/ macros that the user can redefine to fit the context.
-In order to simplify such macros, we replace some of the characters.
-
-Notice that in this section and the next, |id_first| and |id_loc|
-are pointers into the array |section_text|, not into |buffer|.
-
-@<Get a constant@>= {
- id_first=id_loc=section_text+1;
- if (*(loc-1)=='0') {
- if (*loc=='x' || *loc=='X') {*id_loc++='^'; loc++;
- while (xisxdigit(*loc)) *id_loc++=*loc++;} /* hex constant */
- else if (xisdigit(*loc)) {*id_loc++='~';
- while (xisdigit(*loc)) *id_loc++=*loc++;} /* octal constant */
- else goto dec; /* decimal constant */
- }
- else { /* decimal constant */
- if (*(loc-1)=='.' && !xisdigit(*loc)) goto mistake; /* not a constant */
- dec: *id_loc++=*(loc-1);
- while (xisdigit(*loc) || *loc=='.') *id_loc++=*loc++;
- if (*loc=='e' || *loc=='E') { /* float constant */
- *id_loc++='_'; loc++;
- if (*loc=='+' || *loc=='-') *id_loc++=*loc++;
- while (xisdigit(*loc)) *id_loc++=*loc++;
- }
- }
- while (*loc=='u' || *loc=='U' || *loc=='l' || *loc=='L'
- || *loc=='f' || *loc=='F') {
- *id_loc++='$'; *id_loc++=toupper((eight_bits)*loc); loc++;
- }
- return constant;
-}
-
-@ \CEE/ strings and character constants, delimited by double and single
-quotes, respectively, can contain newlines or instances of their own
-delimiters if they are protected by a backslash. We follow this
-convention, but do not allow the string to be longer than |longest_name|.
-
-@<Get a string@>= {
- char delim = c; /* what started the string */
- id_first = section_text+1;
- id_loc = section_text;
- if (delim=='\'' && *(loc-2)=='@@') {*++id_loc='@@'; *++id_loc='@@';}
- *++id_loc=delim;
- if (delim=='L' || delim=='u' || delim=='U') { /* wide character constant */
- if (delim=='u' && *loc=='8') { *++id_loc=*loc++; }
- delim=*loc++; *++id_loc=delim;
- }
- if (delim=='<') delim='>'; /* for file names in \&{\#include} lines */
- while (true) {
- if (loc>=limit) {
- if(*(limit-1)!='\\') {
- err_print("! String didn't end"); loc=limit; break;
-@.String didn't end@>
- }
- if(get_line()==false) {
- err_print("! Input ended in middle of string"); loc=buffer; break;
-@.Input ended in middle of string@>
- }
- }
- if ((c=*loc++)==delim) {
- if (++id_loc<=section_text_end) *id_loc=c;
- break;
- }
- if (c=='\\') { if (loc>=limit) continue;
- else { if (++id_loc<=section_text_end) {
- *id_loc = '\\'; c=*loc++;
- } } }
- if (++id_loc<=section_text_end) *id_loc=c;
- }
- if (id_loc>=section_text_end) {
- fputs("\n! String too long: ",stdout);
-@.String too long@>
- term_write(section_text+1,25);
- printf("..."); mark_error;
- }
- id_loc++;
- return string;
-}
-
-@ After an \.{@@} sign has been scanned, the next character tells us
-whether there is more work to do.
-
-@<Get control code and possible section name@>= {
- c=*loc++;
- switch(ccode[(eight_bits)c]) {
- 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=c-'0'; continue;
- case xref_roman: case xref_wildcard: case xref_typewriter: case noop:
- case TeX_string: c=ccode[(eight_bits)c]; skip_restricted(); return c;
- case section_name:
- @<Scan the section name and make |cur_section| point to it@>@;
- case verbatim: @<Scan a verbatim string@>@;
- case ord: @<Get a string@>@;
- default: return ccode[(eight_bits)c];
- }
-}
-
-@ The occurrence of a section name sets |xref_switch| to zero,
-because the section name might (for example) follow \&{int}.
-
-@<Scan the section name...@>= {
- char *k; /* pointer into |section_text| */
- cur_section_char=*(loc-1);
- @<Put section name into |section_text|@>@;
- if (k-section_text>3 && strncmp(k-2,"...",3)==0)
- cur_section=section_lookup(section_text+1,k-3,1); /* 1 indicates a prefix */
- else cur_section=section_lookup(section_text+1,k,0);
- xref_switch=0; return section_name;
-}
-
-@ Section names are placed into the |section_text| array with consecutive spaces,
-tabs, and carriage-returns replaced by single spaces. There will be no
-spaces at the beginning or the end. (We set |section_text[0]=' '| to facilitate
-this, since the |section_lookup| routine uses |section_text[1]| as the first
-character of the name.)
-
-@<Set init...@>=section_text[0]=' ';
-
-@ @<Put section name...@>=
-k=section_text;
-while (true) {
- if (loc>limit && get_line()==false) {
- err_print("! Input ended in section name");
-@.Input ended in section name@>
- loc=buffer+1; break;
- }
- c=*loc;
- @<If end of name or erroneous control code, |break|@>@;
- loc++; if (k<section_text_end) k++;
- if (xisspace(c)) {
- c=' '; if (*(k-1)==' ') k--;
- }
-*k=c;
-}
-if (k>=section_text_end) {
- fputs("\n! Section name too long: ",stdout);
-@.Section name too long@>
- term_write(section_text+1,25);
- printf("..."); mark_harmless;
-}
-if (*k==' ' && k>section_text) k--;
-
-@ @<If end of name...@>=
-if (c=='@@') {
- c=*(loc+1);
- if (c=='>') {
- loc+=2; break;
- }
- if (ccode[(eight_bits)c]==new_section) {
- err_print("! Section name didn't end"); break;
-@.Section name didn't end@>
- }
- if (c!='@@') {
- err_print("! Control codes are forbidden in section name"); break;
-@.Control codes are forbidden...@>
- }
- *(++k)='@@'; loc++; /* now |c==*loc| again */
-}
-
-@ This function skips over a restricted context at relatively high speed.
-
-@c
-static void
-skip_restricted(void)
-{
- id_first=loc; *(limit+1)='@@';
-false_alarm:
- while (*loc!='@@') loc++;
- id_loc=loc;
- if (loc++>limit) {
- err_print("! Control text didn't end"); loc=limit;
-@.Control text didn't end@>
- }
- else {
- if (*loc=='@@'&&loc<=limit) {loc++; goto false_alarm;}
- if (*loc++!='>')
- err_print("! Control codes are forbidden in control text");
-@.Control codes are forbidden...@>
- }
-}
-
-@ @<Predecl...@>=@+static void skip_restricted(void);
-
-@ At the present point in the program we
-have |*(loc-1)==verbatim|; we set |id_first| to the beginning
-of the string itself, and |id_loc| to its ending-plus-one location in the
-buffer. We also set |loc| to the position just after the ending delimiter.
-
-@<Scan a verbatim string@>= {
- id_first=loc++; *(limit+1)='@@'; *(limit+2)='>';
- while (*loc!='@@' || *(loc+1)!='>') loc++;
- if (loc>=limit) err_print("! Verbatim string didn't end");
-@.Verbatim string didn't end@>
- id_loc=loc; loc+=2;
- return verbatim;
-}
-
-@** Phase one processing.
-We now have accumulated enough subroutines to make it possible to carry out
-\.{CWEAVE}'s first pass over the source file. If everything works right,
-both phase one and phase two of \.{CWEAVE} will assign the same numbers to
-sections, and these numbers will agree with what \.{CTANGLE} does.
-
-The global variable |next_control| often contains the most recent output of
-|get_next|; in interesting cases, this will be the control code that
-ended a section or part of a section.
-
-@<Private...@>=
-static eight_bits next_control; /* control code waiting to be acting upon */
-
-@ The overall processing strategy in phase one has the following
-straightforward outline.
-
-@c
-static void
-phase_one(void) {
- phase=1; reset_input(); section_count=0;
- skip_limbo(); change_exists=false;
- while (!input_has_ended)
- @<Store cross-reference data for the current section@>@;
- changed_section[section_count]=change_exists;
- /* the index changes if anything does */
- phase=2; /* prepare for second phase */
- @<Print error messages about unused or undefined section names@>@;
-}
-
-@ @<Predecl...@>=@+static void phase_one(void);
-
-@ @<Store cross-reference data...@>=
-{
- if (++section_count==max_sections) overflow("section number");
- changed_section[section_count]=changing;
- /* it will become |true| if any line changes */
- if (*(loc-1)=='*' && show_progress) {
- printf("*%d",section_count);
- update_terminal; /* print a progress report */
- }
- @<Store cross-references in the \TEX/ part of a section@>@;
- @<Store cross-references in the definition part of a section@>@;
- @<Store cross-references in the \CEE/ part of a section@>@;
- if (changed_section[section_count]) change_exists=true;
-}
-
-@ The |C_xref| subroutine stores references to identifiers in
-\CEE/ text material beginning with the current value of |next_control|
-and continuing until |next_control| is `\.\{' or `\.{\v}', or until the next
-``milestone'' is passed (i.e., |next_control>=format_code|). If
-|next_control>=format_code| when |C_xref| is called, nothing will happen;
-but if |next_control=='|'| upon entry, the procedure assumes that this is
-the `\.{\v}' preceding \CEE/ text that is to be processed.
-
-The parameter |spec_ctrl| is used to change this behavior. In most cases
-|C_xref| is called with |spec_ctrl==ignore|, which triggers the default
-processing described above. If |spec_ctrl==section_name|, section names will
-be gobbled. This is used when \CEE/ text in the \TEX/ part or inside comments
-is parsed: It allows for section names to appear in \pb, but these
-strings will not be entered into the cross reference lists since they are not
-definitions of section names.
-
-The program uses the fact that our internal code numbers satisfy
-the relations |xref_roman==identifier+roman| and |xref_wildcard==identifier
-+wildcard| and |xref_typewriter==identifier+typewriter|,
-as well as |normal==0|.
-
-@<Predecl...@>=
-static void C_xref(eight_bits);@/
-static void outer_xref(void);
-
-@ @c
-static void
-C_xref(@t\1\1@> /* makes cross-references for \CEE/ identifiers */
- eight_bits spec_ctrl@t\2\2@>)
-{
- 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 begins
-with |next_control!='|'| and ends with |next_control>=format_code|. Thus, it
-handles \CEE/ text with embedded comments.
-
-@c
-static void
-outer_xref(void) /* 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 for
-the identifiers in \CEE/ texts enclosed in \pb, or for control texts
-enclosed in \.{@@\^}$\,\ldots\,$\.{@@>} or \.{@@.}$\,\ldots\,$\.{@@>}
-or \.{@@:}$\,\ldots\,$\.{@@>}.
-
-@<Store cross-references in the \T...@>=
-while (true) {
- 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-references
-are made for all identifiers except reserved words. However, the right
-identifier in a format definition is not referenced, and the left
-identifier is referenced only if it has been explicitly
-underlined (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 skipped
-entirely, even if it contains \pb\ constructions.
-
-The variables |lhs| and |rhs| point to the respective identifiers involved
-in a format definition.
-
-@<Private...@>=
-static name_pointer lhs, rhs; /* pointers to |byte_start| for format identifiers */
-static 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 phase
-two. Our job in phase one is to define the |ilk| of a properly formatted
-identifier, and to remove cross-references to identifiers that we now
-discover 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=(void *)q->xlink;
- else r=q;
- }
- next_control=get_next();
- }
- }
-}
-
-@ A much simpler processing of format definitions occurs when the
-definition 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 each
-section name was both defined and used. The variable |cur_xref| will point
-to cross-references for the current section name of interest.
-
-@<Private...@>=
-static xref_pointer cur_xref; /* temporary cross-reference pointer */
-static boolean an_output; /* did |file_flag| precede |cur_xref|? */
-
-@ The following recursive procedure
-walks through the tree of section names and prints out anomalies.
-@^recursion@>
-
-@c
-static void
-section_check(
-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=true; cur_xref=cur_xref->xlink;}
- else an_output=false;
- if (cur_xref->num <def_flag) {
- fputs("\n! Never defined: <",stdout);
- 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) {
- fputs("\n! Never used: <",stdout);
- print_section_name(p); putchar('>'); mark_harmless;
-@.Never used: <section name>@>
- }
- section_check(p->rlink);
- }
-}
-
-@ @<Predecl...@>=@+static void section_check(name_pointer);
-
-@ @<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 output
-process, |out_line| will hold the current line number of the line about to
-be output.
-
-@<Private...@>=
-static char out_buf[line_length+1]; /* assembled characters */
-static char *out_buf_end = out_buf+line_length; /* end of |out_buf| */
-static char *out_ptr; /* last character in |out_buf| */
-static 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 |true|, a |'%'| is appended to the line
-that is being output; in this case the breakpoint |b| should be strictly
-less than |out_buf_end|. If the |per_cent| parameter is |false|,
-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 be
-carried over to the next line (so that \TEX/ will ignore the completion
-of 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,"%s",c)
-@d tex_puts(c) fputs(c,active_file)
-
-@<Predecl...@>=
-static void flush_buffer(char *,boolean,boolean);@/
-static void finish_line(void);
-
-@ @c
-static void
-flush_buffer(@t\1\1@>
-char *b, /* outputs from |out_buf+1| to |b|, where |b<=out_ptr| */
-boolean per_cent,boolean carryover@t\2\2@>)
-{
- 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) memcpy(out_buf+1,b+1,(size_t)(out_ptr-b));
- out_ptr-=b-out_buf;
-}
-
-@ When we are copying \TEX/ source material, we retain line breaks
-that occur in the input, except that an empty line is not
-output when the \TEX/ source line was nonempty. For example, a line
-of the \TEX/ file that contains only an index cross-reference entry
-will not be copied. The |finish_line| routine is called just before
-|get_line| inputs a new line, and just after a line break token has
-been emitted during the output of translated \CEE/ text.
-
-@c
-static void
-finish_line(void) /* do this at the end of a line */
-{
- char *k; /* pointer into |buffer| */
- if (out_ptr>out_buf) flush_buffer(out_ptr,false,false);
- else {
- for (k=buffer; k<=limit; k++)
- if (!(xisspace(*k))) return;
- flush_buffer(out_buf,false,false);
- }
-}
-
-@ In particular, the |finish_line| procedure is called near the very
-beginning of phase two. We initialize the output variables in a slightly
-tricky way so that the first line of the output file will be
-`\.{\\input cwebmac}'.
-
-@<Start \TEX/...@>=
-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 already
-full. 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;}
-
-@<Predecl...@>=
-static void out_str(const char *);@/
-static void break_out(void);
-
-@ @c
-static void
-out_str(@t\1\1@> /* output characters from |s| to end of string */
-const char*s@t\2\2@>)
-{
- while (*s) out(*s++);
-}
-
-@ The |break_out| routine is called just before the output buffer is about
-to overflow. To make this routine a little faster, we initialize position
-0 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't
-preceded by another backslash. In the latter case, a |'%'| is output at
-the break.
-
-@c
-static void
-break_out(void) /* finds a way to break the output line */
-{
- char *k=out_ptr; /* pointer into |out_buf| */
- while (true) {
- if (k==out_buf) @<Print warning message, break the line, |return|@>@;
- if (*k==' ') {
- flush_buffer(k,false,true); return;
- }
- if (*(k--)=='\\' && *k!='\\') { /* we've decreased |k| */
- flush_buffer(k,true,true); return;
- }
- }
-}
-
-@ We get to this section only in the unusual case that the entire output line
-consists of a string of backslashes followed by a string of nonblank
-non-backslashes. In such cases it is almost always safe to break the
-line by putting a |'%'| just before the last character.
-
-@<Print warning message...@>=
-{
- printf("\n! Line had to be broken (output l. %d):\n",out_line);
-@.Line had to be broken@>
- term_write(out_buf+1, out_ptr-out_buf-1);
- new_line; mark_harmless;
- flush_buffer(out_ptr-1,true,true); return;
-}
-
-@ Here is a macro that outputs a section number in decimal notation.
-The number to be converted by |out_section| is known to be less than
-|def_flag|, so it cannot have more than five decimal digits. If
-the section is changed, we output `\.{\\*}' just after the number.
-
-@<Predecl...@>=
-static void out_section(sixteen_bits);@/
-static void out_name(name_pointer,boolean);
-
-@ @c
-static void
-out_section(
-sixteen_bits n)
-{
- char s[6];
- sprintf(s,"%d",n); out_str(s);
- if(changed_section[n]) out_str ("\\*");
-@.\\*@>
-}
-
-@ The |out_name| procedure is used to output an identifier or index
-entry, enclosing it in braces.
-
-@c
-static void
-out_name(
-name_pointer p,
-boolean quote_xalpha)
-{
- char *k, *k_end=(p+1)->byte_start; /* pointers into |byte_mem| */
- out('{');
- for (k=p->byte_start; k<k_end; k++) {
- if (isxalpha(*k) && quote_xalpha) out('\\');
-@.\\\$@>
-@.\\\_@>
- out(*k);
- }
- out('}');
-}
-
-@* Routines that copy \TEX/ material.
-During phase two, we use the subroutines |copy_limbo| and |copy_TeX| (and
-|copy_comment|) in place of the analogous |skip_limbo| and |skip_TeX|
-that were used in phase one.
-
-The |copy_limbo| routine, for example, takes \TEX/ material that is not
-part of any section and transcribes it almost verbatim to the output file.
-The use of `\.{@@}' signs is severely restricted in such material:
-`\.{@@@@}' pairs are replaced by singletons; `\.{@@l}' and `\.{@@q}' and
-`\.{@@s}' are interpreted.
-
-@<Predecl...@>=
-static void copy_limbo(void);@/
-static eight_bits copy_TeX(void);@/
-static int copy_comment(boolean,int);
-
-@ @c
-static void
-copy_limbo(void)
-{
- char c;
- while (true) {
- if (loc>limit && (finish_line(), get_line()==false)) return;
- *(limit+1)='@@';
- while (*loc!='@@') out(*(loc++));
- if (loc++<=limit) {
- c=*loc++;
- if (ccode[(eight_bits)c]==new_section) break;
- switch (ccode[(eight_bits)c]) {
- case translit_code: out_str("\\ATL"); break;
-@.\\ATL@>
- case '@@': out('@@'); break;
- case noop: skip_restricted(); break;
- case format_code: if (get_next()==identifier) get_next();
- if (loc>=limit) get_line(); /* avoid blank lines in output */
- break; /* the operands of \.{@@s} are ignored on this pass */
- default: err_print("! Double @@ should be used in limbo");
-@.Double @@ should be used...@>
- out('@@');
- }
- }
- }
-}
-
-@ The |copy_TeX| routine processes the \TEX/ code at the beginning of a
-section; for example, the words you are now reading were copied in this
-way. It returns the next control code or `\.{\v}' found in the input.
-We don't copy spaces or tab marks into the beginning of a line. This
-makes the test for empty lines in |finish_line| work.
-
-@f copy_TeX TeX
-@c
-static eight_bits
-copy_TeX(void)
-{
- char c; /* current character being copied */
- while (true) {
- if (loc>limit && (finish_line(), get_line()==false)) return new_section;
- *(limit+1)='@@';
- while ((c=*(loc++))!='|' && c!='@@') {
- out(c);
- if (out_ptr==out_buf+1 && (xisspace(c))) out_ptr--;
- }
- if (c=='|') return '|';
- if (loc<=limit) return ccode[(eight_bits)*(loc++)];
- }
-}
-
-@ The |copy_comment| function issues a warning if more braces are opened than
-closed, and in the case of a more serious error it supplies enough
-braces to keep \TEX/ from complaining about unbalanced braces.
-Instead of copying the \TEX/ material
-into the output buffer, this function copies it into the token memory
-(in phase two only).
-The abbreviation |app_tok(t)| is used to append token |t| to the current
-token list, and it also makes sure that it is possible to append at least
-one further token without overflow.
-
-@d app_tok(c) {if (tok_ptr+2>tok_mem_end) overflow("token"); *(tok_ptr++)=c;}
-
-@c
-static int copy_comment(@t\1\1@> /* copies \TeX\ code in comments */
-boolean is_long_comment, /* is this a traditional \CEE/ comment? */
-int bal@t\2\2@>) /* brace balance */
-{
- char c; /* current character being copied */
- while (true) {
- if (loc>limit) {
- if (is_long_comment) {
- if (get_line()==false) {
- err_print("! Input ended in mid-comment");
-@.Input ended in mid-comment@>
- loc=buffer+1; goto done;
- }
- }
- else {
- if (bal>1) err_print("! Missing } in comment");
-@.Missing \} in comment@>
- goto done;
- }
- }
- c=*(loc++);
- if (c=='|') return bal;
- if (is_long_comment) @<Check for end of comment@>@;
- if (phase==2) {
- if (ishigh(c)) app_tok(quoted_char);
- app_tok(c);
- }
- @<Copy special things when |c=='@@', '\\'|@>@;
- if (c=='{') bal++;
- else if (c=='}') {
- if(bal>1) bal--;
- else {err_print("! Extra } in comment");
-@.Extra \} in comment@>
- if (phase==2) tok_ptr--;
- }
- }
- }
-done:@<Clear |bal| and |return|@>@;
-}
-
-@ @<Check for end of comment@>=
-if (c=='*' && *loc=='/') {
- loc++;
- if (bal>1) err_print("! Missing } in comment");
-@.Missing \} in comment@>
- goto done;
-}
-
-@ @<Copy special things when |c=='@@'...@>=
-if (c=='@@') {
- if (*(loc++)!='@@') {
- err_print("! Illegal use of @@ in comment");
-@.Illegal use of @@...@>
- loc-=2; if (phase==2) *(tok_ptr-1)=' '; goto done;
- }
-}
-else { if (c=='\\' && *loc!='@@') {
- if (phase==2) app_tok(*(loc++))@; else loc++; } }
-
-@ We output
-enough right braces to keep \TEX/ happy.
-
-@<Clear |bal|...@>=
-if (phase==2) while (bal-- >0) app_tok('}');
-return 0;
-
-@** Parsing.
-The most intricate part of \.{CWEAVE} is its mechanism for converting
-\CEE/-like code into \TEX/ code, and we might as well plunge into this
-aspect of the program now. A ``bottom up'' approach is used to parse the
-\CEE/-like material, since \.{CWEAVE} must deal with fragmentary
-constructions whose overall ``part of speech'' is not known.
-
-At the lowest level, the input is represented as a sequence of entities
-that we shall call {\it scraps}, where each scrap of information consists
-of two parts, its {\it category} and its {\it translation}. The category
-is essentially a syntactic class, and the translation is a token list that
-represents \TEX/ code. Rules of syntax and semantics tell us how to
-combine adjacent scraps into larger ones, and if we are lucky an entire
-\CEE/ text that starts out as hundreds of small scraps will join
-together into one gigantic scrap whose translation is the desired \TEX/
-code. If we are unlucky, we will be left with several scraps that don't
-combine; their translations will simply be output, one by one.
-
-The combination rules are given as context-sensitive productions that are
-applied from left to right. Suppose that we are currently working on the
-sequence of scraps $s_1\,s_2\ldots s_n$. We try first to find the longest
-production that applies to an initial substring $s_1\,s_2\ldots\,$; but if
-no such productions exist, we try to find the longest production
-applicable to the next substring $s_2\,s_3\ldots\,$; and if that fails, we
-try to match $s_3\,s_4\ldots\,$, etc.
-
-A production applies if the category codes have a given pattern. For
-example, one of the productions (see rule~3) is
-$$\hbox{|exp| }\left\{\matrix{\hbox{|binop|}\cr\hbox{|ubinop|}}\right\}
-\hbox{ |exp| }\RA\hbox{ |exp|}$$
-and it means that three consecutive scraps whose respective categories are
-|exp|, |binop| (or |ubinop|),
-and |exp| are converted to one scrap whose category
-is |exp|. The translations of the original
-scraps are simply concatenated. The case of
-$$\hbox{|exp| |comma| |exp| $\RA$ |exp|} \hskip4emE_1C\,\\{opt}9\,E_2$$
-(rule 4) is only slightly more complicated:
-Here the resulting |exp| translation
-consists not only of the three original translations, but also of the
-tokens |opt| and 9 between the translations of the
-|comma| and the following |exp|.
-In the \TEX/ file, this will specify an optional line break after the
-comma, with penalty 90.
-
-At each opportunity the longest possible production is applied. For
-example, if the current sequence of scraps is |if_clause| |stmt|
-|else_like| |if_like|, rule 63 is applied; but if the sequence is
-|if_clause| |stmt| |else_like| followed by anything other than
-|if_like|, rule 64 takes effect; and if the sequence is |if_clause|
-|stmt| followed by anything other than |else_like|, rule 65 takes
-effect.
-
-Translation rules such as `$E_1C\,\\{opt}9\,E_2$' above use subscripts
-to distinguish between translations of scraps whose categories have the
-same initial letter; these subscripts are assigned from left to right.
-
-@ Here is a list of the category codes that scraps can have.
-(A few others, like |int_like|, have already been defined; the
-|cat_name| array contains a complete list.)
-
-@d exp 1 /* denotes an expression, including perhaps a single identifier */
-@d unop 2 /* denotes a unary operator */
-@d binop 3 /* denotes a binary operator */
-@d ubinop 4
- /* denotes an operator that can be unary or binary, depending on context */
-@d cast 5 /* denotes a cast */
-@d question 6 /* denotes a question mark and possibly the expressions flanking it */
-@d lbrace 7 /* denotes a left brace */
-@d rbrace 8 /* denotes a right brace */
-@d decl_head 9 /* denotes an incomplete declaration */
-@d comma 10 /* denotes a comma */
-@d lpar 11 /* denotes a left parenthesis or left bracket */
-@d rpar 12 /* denotes a right parenthesis or right bracket */
-@d prelangle 13 /* denotes `$<$' before we know what it is */
-@d prerangle 14 /* denotes `$>$' before we know what it is */
-@d langle 15 /* denotes `$<$' when it's used as angle bracket in a template */
-@d colcol 18 /* denotes `::' */
-@d base 19 /* denotes a colon that introduces a base specifier */
-@d decl 20 /* denotes a complete declaration */
-@d struct_head 21 /* denotes the beginning of a structure specifier */
-@d stmt 23 /* denotes a complete statement */
-@d function 24 /* denotes a complete function */
-@d fn_decl 25 /* denotes a function declarator */
-@d semi 27 /* denotes a semicolon */
-@d colon 28 /* denotes a colon */
-@d tag 29 /* denotes a statement label */
-@d if_head 30 /* denotes the beginning of a compound conditional */
-@d else_head 31 /* denotes a prefix for a compound statement */
-@d if_clause 32 /* pending \.{if} together with a condition */
-@d lproc 35 /* begins a preprocessor command */
-@d rproc 36 /* ends a preprocessor command */
-@d insert 37 /* a scrap that gets combined with its neighbor */
-@d section_scrap 38 /* section name */
-@d dead 39 /* scrap that won't combine */
-@d ftemplate 59 /* \\{make\_pair} */
-@d new_exp 60 /* \&{new} and a following type identifier */
-@d begin_arg 61 /* \.{@@[} */
-@d end_arg 62 /* \.{@@]} */
-
-@<Private...@>=
-static char cat_name[256][12];
-
-@ @<Set in...@>=
-{int c; for (c=0;c<256;c++) strcpy(cat_name[c],"UNKNOWN");}
-@.UNKNOWN@>
- strcpy(cat_name[exp],"exp");
- strcpy(cat_name[unop],"unop");
- strcpy(cat_name[binop],"binop");
- strcpy(cat_name[ubinop],"ubinop");
- strcpy(cat_name[cast],"cast");
- strcpy(cat_name[question],"?");
- strcpy(cat_name[lbrace],"{"@q}@>);
- strcpy(cat_name[rbrace],@q{@>"}");
- strcpy(cat_name[decl_head],"decl_head");
- strcpy(cat_name[comma],",");
- strcpy(cat_name[lpar],"(");
- strcpy(cat_name[rpar],")");
- strcpy(cat_name[prelangle],"<");
- strcpy(cat_name[prerangle],">");
- strcpy(cat_name[langle],"\\<");
- strcpy(cat_name[colcol],"::");
- strcpy(cat_name[base],"\\:");
- strcpy(cat_name[decl],"decl");
- strcpy(cat_name[struct_head],"struct_head");
- strcpy(cat_name[alfop],"alfop");
- strcpy(cat_name[stmt],"stmt");
- strcpy(cat_name[function],"function");
- strcpy(cat_name[fn_decl],"fn_decl");
- strcpy(cat_name[else_like],"else_like");
- strcpy(cat_name[semi],";");
- strcpy(cat_name[colon],":");
- strcpy(cat_name[tag],"tag");
- strcpy(cat_name[if_head],"if_head");
- strcpy(cat_name[else_head],"else_head");
- strcpy(cat_name[if_clause],"if()");
- strcpy(cat_name[lproc],"#{"@q}@>);
- strcpy(cat_name[rproc],@q{@>"#}");
- strcpy(cat_name[insert],"insert");
- strcpy(cat_name[section_scrap],"section");
- strcpy(cat_name[dead],"@@d");
- strcpy(cat_name[public_like],"public");
- strcpy(cat_name[operator_like],"operator");
- strcpy(cat_name[new_like],"new");
- strcpy(cat_name[catch_like],"catch");
- strcpy(cat_name[for_like],"for");
- strcpy(cat_name[do_like],"do");
- strcpy(cat_name[if_like],"if");
- strcpy(cat_name[delete_like],"delete");
- strcpy(cat_name[raw_ubin],"ubinop?");
- strcpy(cat_name[const_like],"const");
- strcpy(cat_name[raw_int],"raw");
- strcpy(cat_name[int_like],"int");
- strcpy(cat_name[case_like],"case");
- strcpy(cat_name[sizeof_like],"sizeof");
- strcpy(cat_name[struct_like],"struct");
- strcpy(cat_name[typedef_like],"typedef");
- strcpy(cat_name[define_like],"define");
- strcpy(cat_name[template_like],"template");
- strcpy(cat_name[ftemplate],"ftemplate");
- strcpy(cat_name[new_exp],"new_exp");
- strcpy(cat_name[begin_arg],"@@["@q]@>);
- strcpy(cat_name[end_arg],@q[@>"@@]");
- strcpy(cat_name[0],"zero");
-
-@ This code allows \.{CWEAVE} to display its parsing steps.
-
-@c
-static void
-print_cat(@t\1\1@> /* symbolic printout of a category */
-eight_bits c@t\2\2@>)
-{
- fputs(cat_name[c],stdout);
-}
-
-@ @<Predecl...@>=@+static void print_cat(eight_bits);
-
-@ The token lists for translated \TEX/ output contain some special control
-symbols as well as ordinary characters. These control symbols are
-interpreted by \.{CWEAVE} before they are written to the output file.
-
-\yskip\hang |break_space| denotes an optional line break or an en space;
-
-\yskip\hang |force| denotes a line break;
-
-\yskip\hang |big_force| denotes a line break with additional vertical space;
-
-\yskip\hang |preproc_line| denotes that the line will be printed flush left;
-
-\yskip\hang |opt| denotes an optional line break (with the continuation
-line indented two ems with respect to the normal starting position)---this
-code is followed by an integer |n|, and the break will occur with penalty
-$10n$;
-
-\yskip\hang |backup| denotes a backspace of one em;
-
-\yskip\hang |cancel| obliterates any |break_space|, |opt|, |force|, or
-|big_force| tokens that immediately precede or follow it and also cancels any
-|backup| tokens that follow it;
-
-\yskip\hang |indent| causes future lines to be indented one more em;
-
-\yskip\hang |outdent| causes future lines to be indented one less em.
-
-\yskip\noindent All of these tokens are removed from the \TEX/ output that
-comes from \CEE/ text between \pb\ signs; |break_space| and |force| and
-|big_force| become single spaces in this mode. The translation of other
-\CEE/ texts results in \TEX/ control sequences \.{\\1}, \.{\\2},
-\.{\\3}, \.{\\4}, \.{\\5}, \.{\\6}, \.{\\7}, \.{\\8}
-corresponding respectively to
-|indent|, |outdent|, |opt|, |backup|, |break_space|, |force|,
-|big_force| and |preproc_line|.
-However, a sequence of consecutive `\.\ ', |break_space|,
-|force|, and/or |big_force| tokens is first replaced by a single token
-(the maximum of the given ones).
-
-The token |math_rel| will be translated into
-\.{\\MRL\{}, and it will get a matching \.\} later.
-Other control sequences in the \TEX/ output will be
-`\.{\\\\\{}$\,\ldots\,$\.\}'
-surrounding identifiers, `\.{\\\&\{}$\,\ldots\,$\.\}' surrounding
-reserved words, `\.{\\.\{}$\,\ldots\,$\.\}' surrounding strings,
-`\.{\\C\{}$\,\ldots\,$\.\}$\,$|force|' surrounding comments, and
-`\.{\\X$n$:}$\,\ldots\,$\.{\\X}' surrounding section names, where
-|n| is the section number.
-
-@d math_rel 0206
-@d big_cancel 0210 /* like |cancel|, also overrides spaces */
-@d cancel 0211 /* overrides |backup|, |break_space|, |force|, |big_force| */
-@d indent 0212 /* one more tab (\.{\\1}) */
-@d outdent 0213 /* one less tab (\.{\\2}) */
-@d opt 0214 /* optional break in mid-statement (\.{\\3}) */
-@d backup 0215 /* stick out one unit to the left (\.{\\4}) */
-@d break_space 0216 /* optional break between statements (\.{\\5}) */
-@d force 0217 /* forced break between statements (\.{\\6}) */
-@d big_force 0220 /* forced break with additional space (\.{\\7}) */
-@d preproc_line 0221 /* begin line without indentation (\.{\\8}) */
-@^high-bit character handling@>
-@d quoted_char 0222
- /* introduces a character token in the range |0200|--|0377| */
-@d end_translation 0223 /* special sentinel token at end of list */
-@d inserted 0224 /* sentinel to mark translations of inserts */
-@d qualifier 0225 /* introduces an explicit namespace qualifier */
-
-@ The raw input is converted into scraps according to the following table,
-which gives category codes followed by the translations.
-\def\stars {\.{**}}%
-The symbol `\stars' stands for `\.{\\\&\{{\rm identifier}\}}',
-i.e., the identifier itself treated as a reserved word.
-The right-hand column is the so-called |mathness|, which is explained
-further below.
-
-An identifier |c| of length 1 is translated as \.{\\\v c} instead of
-as \.{\\\\\{c\}}. An identifier \.{CAPS} in all caps is translated as
-\.{\\.\{CAPS\}} instead of as \.{\\\\\{CAPS\}}. An identifier that has
-become a reserved word via |typedef| is translated with \.{\\\&} replacing
-\.{\\\\} and |raw_int| replacing |exp|.
-
-A string of length greater than 20 is broken into pieces of size at most~20
-with discretionary breaks in between.
-
-\yskip\halign{\quad#\hfil&\quad#\hfil&\quad\hfil#\hfil\cr
-\.{!=}&|binop|: \.{\\I}&yes\cr
-\.{<=}&|binop|: \.{\\Z}&yes\cr
-\.{>=}&|binop|: \.{\\G}&yes\cr
-\.{==}&|binop|: \.{\\E}&yes\cr
-\.{\&\&}&|binop|: \.{\\W}&yes\cr
-\.{\v\v}&|binop|: \.{\\V}&yes\cr
-\.{++}&|unop|: \.{\\PP}&yes\cr
-\.{--}&|unop|: \.{\\MM}&yes\cr
-\.{->}&|binop|: \.{\\MG}&yes\cr
-\.{>>}&|binop|: \.{\\GG}&yes\cr
-\.{<<}&|binop|: \.{\\LL}&yes\cr
-\.{::}&|colcol|: \.{\\DC}&maybe\cr
-\.{.*}&|binop|: \.{\\PA}&yes\cr
-\.{->*}&|binop|: \.{\\MGA}&yes\cr
-\.{...}&|raw_int|: \.{\\,\\ldots\\,}&yes\cr
-\."string\."&|exp|: \.{\\.\{}string with special characters quoted\.\}&maybe\cr
-\.{@@=}string\.{@@>}&|exp|: \.{\\vb\{}string with special characters
- quoted\.\}&maybe\cr
-\.{@@'7'}&|exp|: \.{\\.\{@@'7'\}}&maybe\cr
-\.{077} or \.{\\77}&|exp|: \.{\\T\{\\\~77\}}&maybe\cr
-\.{0x7f}&|exp|: \.{\\T\{\\\^7f\}}&maybe\cr
-\.{77}&|exp|: \.{\\T\{77\}}&maybe\cr
-\.{77L}&|exp|: \.{\\T\{77\\\$L\}}&maybe\cr
-\.{0.1E5}&|exp|: \.{\\T\{0.1\\\_5\}}&maybe\cr
-\.+&|ubinop|: \.+&yes\cr
-\.-&|ubinop|: \.-&yes\cr
-\.*&|raw_ubin|: \.*&yes\cr
-\./&|binop|: \./&yes\cr
-\.<&|prelangle|: \.{\\langle}&yes\cr
-\.=&|binop|: \.{\\K}&yes\cr
-\.>&|prerangle|: \.{\\rangle}&yes\cr
-\..&|binop|: \..&yes\cr
-\.{\v}&|binop|: \.{\\OR}&yes\cr
-\.\^&|binop|: \.{\\XOR}&yes\cr
-\.\%&|binop|: \.{\\MOD}&yes\cr
-\.?&|question|: \.{\\?}&yes\cr
-\.!&|unop|: \.{\\R}&yes\cr
-\.\~&|unop|: \.{\\CM}&yes\cr
-\.\&&|raw_ubin|: \.{\\AND}&yes\cr
-\.(&|lpar|: \.(&maybe\cr
-\.[&|lpar|: \.[&maybe\cr
-\.)&|rpar|: \.)&maybe\cr
-\.]&|rpar|: \.]&maybe\cr
-\.\{&|lbrace|: \.\{&yes\cr
-\.\}&|lbrace|: \.\}&yes\cr
-\.,&|comma|: \.,&yes\cr
-\.;&|semi|: \.;&maybe\cr
-\.:&|colon|: \.:&no\cr
-\.\# (within line)&|ubinop|: \.{\\\#}&yes\cr
-\.\# (at beginning)&|lproc|: |force| |preproc_line| \.{\\\#}&no\cr
-end of \.\# line&|rproc|: |force|&no\cr
-identifier&|exp|: \.{\\\\\{}identifier with underlines and
- dollar signs quoted\.\}&maybe\cr
-\.{and}&|alfop|: \stars&yes\cr
-\.{and\_eq}&|alfop|: \stars&yes\cr
-\.{asm}&|sizeof_like|: \stars&maybe\cr
-\.{auto}&|int_like|: \stars&maybe\cr
-\.{bitand}&|alfop|: \stars&yes\cr
-\.{bitor}&|alfop|: \stars&yes\cr
-\.{bool}&|raw_int|: \stars&maybe\cr
-\.{break}&|case_like|: \stars&maybe\cr
-\.{case}&|case_like|: \stars&maybe\cr
-\.{catch}&|catch_like|: \stars&maybe\cr
-\.{char}&|raw_int|: \stars&maybe\cr
-\.{class}&|struct_like|: \stars&maybe\cr
-\.{clock\_t}&|raw_int|: \stars&maybe\cr
-\.{compl}&|alfop|: \stars&yes\cr
-\.{const}&|const_like|: \stars&maybe\cr
-\.{const\_cast}&|raw_int|: \stars&maybe\cr
-\.{continue}&|case_like|: \stars&maybe\cr
-\.{default}&|case_like|: \stars&maybe\cr
-\.{define}&|define_like|: \stars&maybe\cr
-\.{defined}&|sizeof_like|: \stars&maybe\cr
-\.{delete}&|delete_like|: \stars&maybe\cr
-\.{div\_t}&|raw_int|: \stars&maybe\cr
-\.{do}&|do_like|: \stars&maybe\cr
-\.{double}&|raw_int|: \stars&maybe\cr
-\.{dynamic\_cast}&|raw_int|: \stars&maybe\cr
-\.{elif}&|if_like|: \stars&maybe\cr
-\.{else}&|else_like|: \stars&maybe\cr
-\.{endif}&|if_like|: \stars&maybe\cr
-\.{enum}&|struct_like|: \stars&maybe\cr
-\.{error}&|if_like|: \stars&maybe\cr
-\.{explicit}&|int_like|: \stars&maybe\cr
-\.{export}&|int_like|: \stars&maybe\cr
-\.{extern}&|int_like|: \stars&maybe\cr
-\.{FILE}&|raw_int|: \stars&maybe\cr
-\.{float}&|raw_int|: \stars&maybe\cr
-\.{for}&|for_like|: \stars&maybe\cr
-\.{fpos\_t}&|raw_int|: \stars&maybe\cr
-\.{friend}&|int_like|: \stars&maybe\cr
-\.{goto}&|case_like|: \stars&maybe\cr
-\.{if}&|if_like|: \stars&maybe\cr
-\.{ifdef}&|if_like|: \stars&maybe\cr
-\.{ifndef}&|if_like|: \stars&maybe\cr
-\.{include}&|if_like|: \stars&maybe\cr
-\.{inline}&|int_like|: \stars&maybe\cr
-\.{int}&|raw_int|: \stars&maybe\cr
-\.{jmp\_buf}&|raw_int|: \stars&maybe\cr
-\.{ldiv\_t}&|raw_int|: \stars&maybe\cr
-\.{line}&|if_like|: \stars&maybe\cr
-\.{long}&|raw_int|: \stars&maybe\cr
-\.{make\_pair}&|ftemplate|: \.{\\\\\{make\\\_pair\}}&maybe\cr
-\.{mutable}&|int_like|: \stars&maybe\cr
-\.{namespace}&|struct_like|: \stars&maybe\cr
-\.{new}&|new_like|: \stars&maybe\cr
-\.{not}&|alfop|: \stars&yes\cr
-\.{not\_eq}&|alfop|: \stars&yes\cr
-\.{NULL}&|exp|: \.{\\NULL}&yes\cr
-\.{offsetof}&|raw_int|: \stars&maybe\cr
-\.{operator}&|operator_like|: \stars&maybe\cr
-\.{or}&|alfop|: \stars&yes\cr
-\.{or\_eq}&|alfop|: \stars&yes\cr
-\.{pragma}&|if_like|: \stars&maybe\cr
-\.{private}&|public_like|: \stars&maybe\cr
-\.{protected}&|public_like|: \stars&maybe\cr
-\.{ptrdiff\_t}&|raw_int|: \stars&maybe\cr
-\.{public}&|public_like|: \stars&maybe\cr
-\.{register}&|int_like|: \stars&maybe\cr
-\.{reinterpret\_cast}&|raw_int|: \stars&maybe\cr
-\.{return}&|case_like|: \stars&maybe\cr
-\.{short}&|raw_int|: \stars&maybe\cr
-\.{sig\_atomic\_t}&|raw_int|: \stars&maybe\cr
-\.{signed}&|raw_int|: \stars&maybe\cr
-\.{size\_t}&|raw_int|: \stars&maybe\cr
-\.{sizeof}&|sizeof_like|: \stars&maybe\cr
-\.{static}&|int_like|: \stars&maybe\cr
-\.{static\_cast}&|raw_int|: \stars&maybe\cr
-\.{struct}&|struct_like|: \stars&maybe\cr
-\.{switch}&|for_like|: \stars&maybe\cr
-\.{template}&|template_like|: \stars&maybe\cr
-\.{TeX}&|exp|: \.{\\TeX}&yes\cr
-\.{this}&|exp|: \.{\\this}&yes\cr
-\.{throw}&|case_like|: \stars&maybe\cr
-\.{time\_t}&|raw_int|: \stars&maybe\cr
-\.{try}&|else_like|: \stars&maybe\cr
-\.{typedef}&|typedef_like|: \stars&maybe\cr
-\.{typeid}&|raw_int|: \stars&maybe\cr
-\.{typename}&|struct_like|: \stars&maybe\cr
-\.{undef}&|if_like|: \stars&maybe\cr
-\.{union}&|struct_like|: \stars&maybe\cr
-\.{unsigned}&|raw_int|: \stars&maybe\cr
-\.{using}&|int_like|: \stars&maybe\cr
-\.{va\_dcl}&|decl|: \stars&maybe\cr
-\.{va\_list}&|raw_int|: \stars&maybe\cr
-\.{virtual}&|int_like|: \stars&maybe\cr
-\.{void}&|raw_int|: \stars&maybe\cr
-\.{volatile}&|const_like|: \stars&maybe\cr
-\.{wchar\_t}&|raw_int|: \stars&maybe\cr
-\.{while}&|for_like|: \stars&maybe\cr
-\.{xor}&|alfop|: \stars&yes\cr
-\.{xor\_eq}&|alfop|: \stars&yes\cr
-\.{@@,}&|insert|: \.{\\,}&maybe\cr
-\.{@@\v}&|insert|: |opt| \.0&maybe\cr
-\.{@@/}&|insert|: |force|&no\cr
-\.{@@\#}&|insert|: |big_force|&no\cr
-\.{@@+}&|insert|: |big_cancel| \.{\{\}} |break_space|
- \.{\{\}} |big_cancel|&no\cr
-\.{@@;}&|semi|: &maybe\cr
-\.{@@[@q]@>}&|begin_arg|: &maybe\cr
-\.{@q[@>@@]}&|end_arg|: &maybe\cr
-\.{@@\&}&|insert|: \.{\\J}&maybe\cr
-\.{@@h}&|insert|: |force| \.{\\ATH} |force|&no\cr
-\.{@@<}\thinspace section name\thinspace\.{@@>}&|section_scrap|:
- \.{\\X}$n$\.:translated section name\.{\\X}&maybe\cr
-\.{@@(@q)@>}\thinspace section name\thinspace\.{@@>}&|section_scrap|:
- \.{\\X}$n$\.{:\\.\{}section name with special characters
- quoted\.{\ \}\\X}&maybe\cr
-\.{/*}comment\.{*/}&|insert|: |cancel|
- \.{\\C\{}translated comment\.\} |force|&no\cr
-\.{//}comment&|insert|: |cancel|
- \.{\\SHC\{}translated comment\.\} |force|&no\cr
-}
-
-\smallskip
-The construction \.{@@t}\thinspace stuff\/\thinspace\.{@@>} contributes
-\.{\\hbox\{}\thinspace stuff\/\thinspace\.\} to the following scrap.
-
-@i prod.w
-
-@* Implementing the productions.
-More specifically, a scrap is a structure consisting of a category
-|cat| and a |text_pointer| |trans|, which points to the translation in
-|tok_start|. When \CEE/ text is to be processed with the grammar above,
-we form an array |scrap_info| containing the initial scraps.
-Our production rules have the nice property that the right-hand side is never
-longer than the left-hand side. Therefore it is convenient to use sequential
-allocation for the current sequence of scraps. Five pointers are used to
-manage the parsing:
-
-\yskip\hang |pp| is a pointer into |scrap_info|. We will try to match
-the category codes |pp->cat,@,@,(pp+1)->cat|$,\,\,\ldots\,$
-to the left-hand sides of productions.
-
-\yskip\hang |scrap_base|, |lo_ptr|, |hi_ptr|, and |scrap_ptr| are such that
-the current sequence of scraps appears in positions |scrap_base| through
-|lo_ptr| and |hi_ptr| through |scrap_ptr|, inclusive, in the |cat| and
-|trans| arrays. Scraps located between |scrap_base| and |lo_ptr| have
-been examined, while those in positions |>=hi_ptr| have not yet been
-looked at by the parsing process.
-
-\yskip\noindent Initially |scrap_ptr| is set to the position of the final
-scrap to be parsed, and it doesn't change its value. The parsing process
-makes sure that |lo_ptr>=pp+3|, since productions have as many as four terms,
-by moving scraps from |hi_ptr| to |lo_ptr|. If there are
-fewer than |pp+3| scraps left, the positions up to |pp+3| are filled with
-blanks that will not match in any productions. Parsing stops when
-|pp==lo_ptr+1| and |hi_ptr==scrap_ptr+1|.
-
-Since the |scrap| structure will later be used for other purposes, we
-declare its second element as a union.
-
-@<Type...@>=
-typedef struct {
- eight_bits cat;
- eight_bits mathness;
- union {
- text_pointer Trans;
- @<Rest of |trans_plus| union@>@;
- } trans_plus;
-} scrap;
-typedef scrap *scrap_pointer;
-
-@ @d trans trans_plus.Trans /* translation texts of scraps */
-
-@<Private...@>=
-static scrap scrap_info[max_scraps]; /* memory array for scraps */
-static scrap_pointer scrap_info_end=scrap_info+max_scraps-1; /* end of |scrap_info| */
-static scrap_pointer scrap_base; /* beginning of the current scrap sequence */
-static scrap_pointer scrap_ptr; /* ending of the current scrap sequence */
-static scrap_pointer max_scr_ptr; /* largest value assumed by |scrap_ptr| */
-static scrap_pointer pp; /* current position for reducing productions */
-static scrap_pointer lo_ptr; /* last scrap that has been examined */
-static scrap_pointer hi_ptr; /* first scrap that has not been examined */
-
-@ @<Set init...@>=
-scrap_base=scrap_info+1;
-max_scr_ptr=scrap_ptr=scrap_info;
-
-@ Token lists in |@!tok_mem| are composed of the following kinds of
-items for \TEX/ output.
-
-\yskip\item{$\bullet$}Character codes and special codes like |force| and
-|math_rel| represent themselves;
-
-\item{$\bullet$}|id_flag+p| represents \.{\\\\\{{\rm identifier $p$}\}};
-
-\item{$\bullet$}|res_flag+p| represents \.{\\\&\{{\rm identifier $p$}\}};
-
-\item{$\bullet$}|section_flag+p| represents section name |p|;
-
-\item{$\bullet$}|tok_flag+p| represents token list number |p|;
-
-\item{$\bullet$}|inner_tok_flag+p| represents token list number |p|, to be
-translated without line-break controls.
-
-@d id_flag 10240 /* signifies an identifier */
-@d res_flag 2*id_flag /* signifies a reserved word */
-@d section_flag 3*id_flag /* signifies a section name */
-@d tok_flag 4*id_flag /* signifies a token list */
-@d inner_tok_flag 5*id_flag /* signifies a token list in `\pb' */
-
-@c
-static void
-print_text(@t\1\1@> /* prints a token list for debugging; not used in |main| */
-text_pointer p@t\2\2@>)
-{
- token_pointer j; /* index into |tok_mem| */
- sixteen_bits r; /* remainder of token after the flag has been stripped off */
- if (p>=text_ptr) printf("BAD");
- else for (j=*p; j<*(p+1); j++) {
- r=*j%id_flag;
- switch (*j/id_flag) {
- case 1: printf("\\\\{"@q}@>); print_id((name_dir+r)); printf(@q{@>"}");
- break; /* |id_flag| */
- case 2: printf("\\&{"@q}@>); print_id((name_dir+r)); printf(@q{@>"}");
- break; /* |res_flag| */
- case 3: printf("<"); print_section_name((name_dir+r)); printf(">");
- break; /* |section_flag| */
- case 4: printf("[[%d]]",r); break; /* |tok_flag| */
- case 5: printf("|[[%d]]|",r); break; /* |inner_tok_flag| */
- default: @<Print token |r| in symbolic form@>@;
- }
- }
- update_terminal;
-}
-
-@ @<Predecl...@>=@+static void print_text(text_pointer p);
-
-@ @<Print token |r|...@>=
-switch (r) {
- case math_rel: printf("\\mathrel{"@q}@>); break;
- case big_cancel: printf("[ccancel]"); break;
- case cancel: printf("[cancel]"); break;
- case indent: printf("[indent]"); break;
- case outdent: printf("[outdent]"); break;
- case backup: printf("[backup]"); break;
- case opt: printf("[opt]"); break;
- case break_space: printf("[break]"); break;
- case force: printf("[force]"); break;
- case big_force: printf("[fforce]"); break;
- case preproc_line: printf("[preproc]"); break;
- case quoted_char: j++; printf("[%o]",(unsigned int)*j); break;
- case end_translation: printf("[quit]"); break;
- case inserted: printf("[inserted]"); break;
- default: putxchar(r);
-}
-
-@ The production rules listed above are embedded directly into \.{CWEAVE},
-since it is easier to do this than to write an interpretive system
-that would handle production systems in general. Several macros are defined
-here so that the program for each production is fairly short.
-
-All of our productions conform to the general notion that some |k|
-consecutive scraps starting at some position |j| are to be replaced by a
-single scrap of some category |c| whose translation is composed from the
-translations of the disappearing scraps. After this production has been
-applied, the production pointer |pp| should change by an amount |d|. Such
-a production can be represented by the quadruple |(j,k,c,d)|. For example,
-the production `|exp@,comma@,exp| $\RA$ |exp|' would be represented by
-`|(pp,3,exp,-2)|'; in this case the pointer |pp| should decrease by 2
-after the production has been applied, because some productions with
-|exp| in their second or third positions might now match,
-but no productions have
-|exp| in the fourth position of their left-hand sides. Note that
-the value of |d| is determined by the whole collection of productions, not
-by an individual one.
-The determination of |d| has been
-done by hand in each case, based on the full set of productions but not on
-the grammar of \CEE/ or on the rules for constructing the initial
-scraps.
-
-We also attach a serial number to each production, so that additional
-information is available when debugging. For example, the program below
-contains the statement `|reduce(pp,3,exp,-2,4)|' when it implements
-the production just mentioned.
-
-Before calling |reduce|, the program should have appended the tokens of
-the new translation to the |tok_mem| array. We commonly want to append
-copies of several existing translations, and macros are defined to
-simplify these common cases. For example, \\{app2}|(pp)| will append the
-translations of two consecutive scraps, |pp->trans| and |(pp+1)->trans|, to
-the current token list. If the entire new translation is formed in this
-way, we write `|squash(j,k,c,d,n)|' instead of `|reduce(j,k,c,d,n)|'. For
-example, `|squash(pp,3,exp,-2,3)|' is an abbreviation for `\\{app3}|(pp);
-reduce(pp,3,exp,-2,3)|'.
-
-A couple more words of explanation:
-Both |big_app| and |app| append a token (while |big_app1| to |big_app3|
-append the specified number of scrap translations) to the current token list.
-The difference between |big_app| and |app| is simply that |big_app|
-checks whether there can be a conflict between math and non-math
-tokens, and intercalates a `\.{\$}' token if necessary. When in
-doubt what to use, use |big_app|.
-
-The |mathness| is an attribute of scraps that says whether they are
-to be printed in a math mode context or not. It is separate from the
-``part of speech'' (the |cat|) because to make each |cat| have
-a fixed |mathness| (as in the original \.{WEAVE}) would multiply the
-number of necessary production rules.
-
-The low two bits (i.e. |mathness % 4|) control the left boundary.
-(We need two bits because we allow cases |yes_math|, |no_math| and
-|maybe_math|, which can go either way.)
-The next two bits (i.e. |mathness / 4|) control the right boundary.
-If we combine two scraps and the right boundary of the first has
-a different mathness from the left boundary of the second, we
-insert a \.{\$} in between. Similarly, if at printing time some
-irreducible scrap has a |yes_math| boundary the scrap gets preceded
-or followed by a \.{\$}. The left boundary is |maybe_math| if and
-only if the right boundary is.
-
-The code below is an exact translation of the production rules into
-\CEE/, using such macros, and the reader should have no difficulty
-understanding the format by comparing the code with the symbolic
-productions as they were listed earlier.
-
-@d no_math 2 /* should be in horizontal mode */
-@d yes_math 1 /* should be in math mode */
-@d maybe_math 0 /* works in either horizontal or math mode */
-@d big_app2(a) big_app1(a);big_app1(a+1)
-@d big_app3(a) big_app2(a);big_app1(a+2)
-@d app(a) *(tok_ptr++)=(token)(a)
-@d app1(a) *(tok_ptr++)=(token)(tok_flag+(int)((a)->trans-tok_start))
-
-@<Private...@>=
-static int cur_mathness, init_mathness;
-
-@ @<Predecl...@>=
-static void app_str(const char *);@/
-static void big_app(token);@/
-static void big_app1(scrap_pointer);
-
-@ @c
-static void
-app_str(
-const char *s)
-{
- while (*s) app_tok(*(s++));
-}
-
-static void
-big_app(
-token a)
-{
- if (a==' ' || (a>=big_cancel && a<=big_force)) /* non-math token */ {
- if (cur_mathness==maybe_math) init_mathness=no_math;
- else if (cur_mathness==yes_math) app_str("{}$");
- cur_mathness=no_math;
- }
- else {
- if (cur_mathness==maybe_math) init_mathness=yes_math;
- else if (cur_mathness==no_math) app_str("${}");
- cur_mathness=yes_math;
- }
- app(a);
-}
-
-static void
-big_app1(
-scrap_pointer a)
-{
- switch (a->mathness % 4) { /* left boundary */
- case (no_math):
- if (cur_mathness==maybe_math) init_mathness=no_math;
- else if (cur_mathness==yes_math) app_str("{}$");
- cur_mathness=a->mathness / 4; /* right boundary */
- break;
- case (yes_math):
- if (cur_mathness==maybe_math) init_mathness=yes_math;
- else if (cur_mathness==no_math) app_str("${}");
- cur_mathness=a->mathness / 4; /* right boundary */
- break;
- case (maybe_math): /* no changes */ break;
- }
- app(tok_flag+(int)((a)->trans-tok_start));
-}
-
-@ Let us consider the big switch for productions now, before looking
-at its context. We want to design the program so that this switch
-works, so we might as well not keep ourselves in suspense about exactly what
-code needs to be provided with a proper environment.
-
-@d cat1 (pp+1)->cat
-@d cat2 (pp+2)->cat
-@d cat3 (pp+3)->cat
-@d lhs_not_simple (pp->cat!=public_like
- && pp->cat!=semi
- && pp->cat!=prelangle
- && pp->cat!=prerangle @|
- && pp->cat!=template_like
- && pp->cat!=new_like
- && pp->cat!=new_exp
- && pp->cat!=ftemplate @|
- && pp->cat!=raw_ubin
- && pp->cat!=const_like
- && pp->cat!=raw_int
- && pp->cat!=operator_like)
- /* not a production with left side length 1 */
-
-@<Match a production at |pp|, or increase |pp| if there is no match@>= {
- if (cat1==end_arg && lhs_not_simple)
- if (pp->cat==begin_arg) squash(pp,2,exp,-2,124);
- else squash(pp,2,end_arg,-1,125);
- else if (cat1==insert) squash(pp,2,pp->cat,-2,0);
- else if (cat2==insert) squash(pp+1,2,(pp+1)->cat,-1,0);
- else if (cat3==insert) squash(pp+2,2,(pp+2)->cat,0,0);
- else
- switch (pp->cat) {
- case exp: @<Cases for |exp|@>@; @+break;
- case lpar: @<Cases for |lpar|@>@; @+break;
- case unop: @<Cases for |unop|@>@; @+break;
- case ubinop: @<Cases for |ubinop|@>@; @+break;
- case binop: @<Cases for |binop|@>@; @+break;
- case cast: @<Cases for |cast|@>@; @+break;
- case sizeof_like: @<Cases for |sizeof_like|@>@; @+break;
- case int_like: @<Cases for |int_like|@>@; @+break;
- case public_like: @<Cases for |public_like|@>@; @+break;
- case colcol: @<Cases for |colcol|@>@; @+break;
- case decl_head: @<Cases for |decl_head|@>@; @+break;
- case decl: @<Cases for |decl|@>@; @+break;
- case base: @<Cases for |base|@>@; @+break;
- case struct_like: @<Cases for |struct_like|@>@; @+break;
- case struct_head: @<Cases for |struct_head|@>@; @+break;
- case fn_decl: @<Cases for |fn_decl|@>@; @+break;
- case function: @<Cases for |function|@>@; @+break;
- case lbrace: @<Cases for |lbrace|@>@; @+break;
- case if_like: @<Cases for |if_like|@>@; @+break;
- case else_like: @<Cases for |else_like|@>@; @+break;
- case else_head: @<Cases for |else_head|@>@; @+break;
- case if_clause: @<Cases for |if_clause|@>@; @+break;
- case if_head: @<Cases for |if_head|@>@; @+break;
- case do_like: @<Cases for |do_like|@>@; @+break;
- case case_like: @<Cases for |case_like|@>@; @+break;
- case catch_like: @<Cases for |catch_like|@>@; @+break;
- case tag: @<Cases for |tag|@>@; @+break;
- case stmt: @<Cases for |stmt|@>@; @+break;
- case semi: @<Cases for |semi|@>@; @+break;
- case lproc: @<Cases for |lproc|@>@; @+break;
- case section_scrap: @<Cases for |section_scrap|@>@; @+break;
- case insert: @<Cases for |insert|@>@; @+break;
- case prelangle: @<Cases for |prelangle|@>@; @+break;
- case prerangle: @<Cases for |prerangle|@>@; @+break;
- case langle: @<Cases for |langle|@>@; @+break;
- case template_like: @<Cases for |template_like|@>@; @+break;
- case new_like: @<Cases for |new_like|@>@; @+break;
- case new_exp: @<Cases for |new_exp|@>@; @+break;
- case ftemplate: @<Cases for |ftemplate|@>@; @+break;
- case for_like: @<Cases for |for_like|@>@; @+break;
- case raw_ubin: @<Cases for |raw_ubin|@>@; @+break;
- case const_like: @<Cases for |const_like|@>@; @+break;
- case raw_int: @<Cases for |raw_int|@>@; @+break;
- case operator_like: @<Cases for |operator_like|@>@; @+break;
- case typedef_like: @<Cases for |typedef_like|@>@; @+break;
- case delete_like: @<Cases for |delete_like|@>@; @+break;
- case question: @<Cases for |question|@>@; @+break;
- }
- pp++; /* if no match was found, we move to the right */
-}
-
-@ In \CEE/, new specifier names can be defined via |typedef|, and we want
-to make the parser recognize future occurrences of the identifier thus
-defined as specifiers. This is done by the procedure |make_reserved|,
-which changes the |ilk| of the relevant identifier.
-
-We first need a procedure to recursively seek the first
-identifier in a token list, because the identifier might
-be enclosed in parentheses, as when one defines a function
-returning a pointer.
-
-If the first identifier found is a keyword like `\&{case}', we
-return the special value |case_found|; this prevents underlining
-of identifiers in case labels.
-
-If the first identifier is the keyword `\&{operator}', we give up;
-users who want to index definitions of overloaded \CPLUSPLUS/ operators
-should say, for example, `\.{@@!@@\^\\\&\{operator\} \$+\{=\}\$@@>}' (or,
-more properly alpha\-betized,
-`\.{@@!@@:operator+=\}\{\\\&\{operator\} \$+\{=\}\$@@>}').
-
-@d no_ident_found (token_pointer)0 /* distinct from any identifier token */
-@d case_found (token_pointer)1 /* likewise */
-@d operator_found (token_pointer)2 /* likewise */
-
-@<Predecl...@>=
-static token_pointer find_first_ident(text_pointer);@/
-static void make_reserved(scrap_pointer);@/
-static void make_underlined(scrap_pointer);@/
-static void underline_xref(name_pointer);
-
-@ @c
-static token_pointer
-find_first_ident(
-text_pointer p)
-{
- token_pointer q; /* token to be returned */
- token_pointer j; /* token being looked at */
- sixteen_bits r; /* remainder of token after the flag has been stripped off */
- if (p>=text_ptr) confusion("find_first_ident");
- for (j=*p; j<*(p+1); j++) {
- r=*j%id_flag;
- switch (*j/id_flag) {
- case 2: /* |res_flag| */
- if (name_dir[r].ilk==case_like) return case_found;
- if (name_dir[r].ilk==operator_like) return operator_found;
- if (name_dir[r].ilk!=raw_int) break;
- case 1: return j;
- case 4: case 5: /* |tok_flag| or |inner_tok_flag| */
- if ((q=find_first_ident(tok_start+r))!=no_ident_found)
- return q;
- default: ; /* char, |section_flag|, fall thru: move on to next token */
- if (*j==inserted) return no_ident_found; /* ignore inserts */
- else if (*j==qualifier) j++; /* bypass namespace qualifier */
- }
- }
- return no_ident_found;
-}
-
-@ The scraps currently being parsed must be inspected for any
-occurrence of the identifier that we're making reserved; hence
-the |for| loop below.
-
-@c
-static void
-make_reserved(@t\1\1@> /* make the first identifier in |p->trans| like |int| */
-scrap_pointer p@t\2\2@>)
-{
- sixteen_bits tok_value; /* the name of this identifier, plus its flag */
- token_pointer tok_loc; /* pointer to |tok_value| */
- if ((tok_loc=find_first_ident(p->trans))<=operator_found)
- return; /* this should not happen */
- tok_value=*tok_loc;
- for (;p<=scrap_ptr; p==lo_ptr? p=hi_ptr: p++) {
- if (p->cat==exp) {
- if (**(p->trans)==tok_value) {
- p->cat=raw_int;
- **(p->trans)=tok_value%id_flag+res_flag;
- }
- }
- }
- (name_dir+(sixteen_bits)(tok_value%id_flag))->ilk=raw_int;
- *tok_loc=tok_value%id_flag+res_flag;
-}
-
-@ In the following situations we want to mark the occurrence of
-an identifier as a definition: when |make_reserved| is just about to be
-used; after a specifier, as in |char **argv|;
-before a colon, as in \\{found}:; and in the declaration of a function,
-as in \\{main}()$\{\ldots;\}$. This is accomplished by the invocation
-of |make_underlined| at appropriate times. Notice that, in the declaration
-of a function, we find out that the identifier is being defined only after
-it has been swallowed up by an |exp|.
-
-@c
-static void
-make_underlined(@t\1\1@>
-/* underline the entry for the first identifier in |p->trans| */
-scrap_pointer p@t\2\2@>)
-{
- token_pointer tok_loc; /* where the first identifier appears */
- if ((tok_loc=find_first_ident(p->trans))<=operator_found)
- return; /* this happens, for example, in |case found:| */
- xref_switch=def_flag;
- underline_xref(*tok_loc%id_flag+name_dir);
-}
-
-@ We cannot use |new_xref| to underline a cross-reference at this point
-because this would just make a new cross-reference at the end of the list.
-We actually have to search through the list for the existing
-cross-reference.
-
-@c
-static void
-underline_xref(
-name_pointer p)
-{
- xref_pointer q=(xref_pointer)p->xref; /* pointer to cross-reference being examined */
- xref_pointer r; /* temporary pointer for permuting cross-references */
- sixteen_bits m; /* cross-reference value to be installed */
- sixteen_bits n; /* cross-reference value being examined */
- if (no_xref) return;
- m=section_count+xref_switch;
- while (q != xmem) {
- n=q->num;
- if (n==m) return;
- else if (m==n+def_flag) {
- q->num=m; return;
- }
- else if (n>=def_flag && n<m) break;
- q=q->xlink;
- }
- @<Insert new cross-reference at |q|, not at beginning of list@>@;
-}
-
-@ We get to this section only when the identifier is one letter long,
-so it didn't get a non-underlined entry during phase one. But it may
-have got some explicitly underlined entries in later sections, so in order
-to preserve the numerical order of the entries in the index, we have
-to insert the new cross-reference not at the beginning of the list
-(namely, at |p->xref|), but rather right before |q|.
-
-@<Insert new cross-reference at |q|...@>=
- append_xref(0); /* this number doesn't matter */
- xref_ptr->xlink=(xref_pointer)p->xref; r=xref_ptr;
- update_node(p);
- while (r->xlink!=q) {r->num=r->xlink->num; r=r->xlink;}
- r->num=m; /* everything from |q| on is left undisturbed */
-
-@ Now comes the code that tries to match each production starting
-with a particular type of scrap. Whenever a match is discovered,
-the |squash| or |reduce| macro will cause the appropriate action
-to be performed, followed by |goto found|.
-
-@<Cases for |exp|@>=
-if (cat1==lbrace || cat1==int_like || cat1==decl) {
- make_underlined(pp); big_app1(pp); big_app(indent); app(indent);
- reduce(pp,1,fn_decl,0,1);
-}
-else if (cat1==unop) squash(pp,2,exp,-2,2);
-else if ((cat1==binop || cat1==ubinop) && cat2==exp)
- squash(pp,3,exp,-2,3);
-else if (cat1==comma && cat2==exp) {
- big_app2(pp);
- app(opt); app('9'); big_app1(pp+2); reduce(pp,3,exp,-2,4);
-}
-else if (cat1==lpar && cat2==rpar && cat3==colon) squash(pp+3,1,base,0,5);
-else if (cat1==cast && cat2==colon) squash(pp+2,1,base,0,5);
-else if (cat1==semi) squash(pp,2,stmt,-1,6);
-else if (cat1==colon) {
- make_underlined (pp); squash(pp,2,tag,-1,7);
-}
-else if (cat1==rbrace) squash(pp,1,stmt,-1,8);
-else if (cat1==lpar && cat2==rpar && (cat3==const_like || cat3==case_like)) {
- big_app1(pp+2); big_app(' '); big_app1(pp+3); reduce(pp+2,2,rpar,0,9);
-}
-else if (cat1==cast && (cat2==const_like || cat2==case_like)) {
- big_app1(pp+1); big_app(' '); big_app1(pp+2); reduce(pp+1,2,cast,0,9);
-}
-else if (cat1==exp || cat1==cast) squash(pp,2,exp,-2,10);
-
-@ @<Cases for |lpar|@>=
-if ((cat1==exp||cat1==ubinop) && cat2==rpar) squash(pp,3,exp,-2,11);
-else if (cat1==rpar) {
- big_app1(pp); app('\\'); app(','); big_app1(pp+1);
-@.\\,@>
- reduce(pp,2,exp,-2,12);
-}
-else if ((cat1==decl_head || cat1==int_like || cat1==cast) && cat2==rpar)
- squash(pp,3,cast,-2,13);
-else if ((cat1==decl_head || cat1==int_like || cat1==exp) && cat2==comma) {
- big_app3(pp); app(opt); app('9'); reduce(pp,3,lpar,-1,14);
-}
-else if (cat1==stmt || cat1==decl) {
- big_app2(pp); big_app(' '); reduce(pp,2,lpar,-1,15);
-}
-
-@ @<Cases for |unop|@>=
-if (cat1==exp || cat1==int_like) squash(pp,2,exp,-2,16);
-
-@ @<Cases for |ubinop|@>=
-if (cat1==cast && cat2==rpar) {
- big_app('{'); big_app1(pp); big_app('}'); big_app1(pp+1);
- reduce(pp,2,cast,-2,17);
-}
-else if (cat1==exp || cat1==int_like) {
- big_app('{'); big_app1(pp); big_app('}'); big_app1(pp+1);
- reduce(pp,2,cat1,-2,18);
-}
-else if (cat1==binop) {
- big_app(math_rel); big_app1(pp); big_app('{'); big_app1(pp+1); big_app('}');
- big_app('}'); reduce(pp,2,binop,-1,19);
-}
-
-@ @<Cases for |binop|@>=
-if (cat1==binop) {
- big_app(math_rel); big_app('{'); big_app1(pp); big_app('}');
- big_app('{'); big_app1(pp+1); big_app('}');
- big_app('}'); reduce(pp,2,binop,-1,20);
-}
-
-@ @<Cases for |cast|@>=
-if (cat1==lpar) squash(pp,2,lpar,-1,21);
-else if (cat1==exp) {
- big_app1(pp); big_app(' '); big_app1(pp+1); reduce(pp,2,exp,-2,21);
-}
-else if (cat1==semi) squash(pp,1,exp,-2,22);
-
-@ @<Cases for |sizeof_like|@>=
-if (cat1==cast) squash(pp,2,exp,-2,23);
-else if (cat1==exp) {
- big_app1(pp); big_app(' '); big_app1(pp+1); reduce(pp,2,exp,-2,24);
-}
-
-@ @<Cases for |int_like|@>=
-if (cat1==int_like|| cat1==struct_like) {
- big_app1(pp); big_app(' '); big_app1(pp+1); reduce(pp,2,cat1,-2,25);
-}
-else if (cat1==exp && (cat2==raw_int||cat2==struct_like))
- squash(pp,2,int_like,-2,26);
-else if (cat1==exp || cat1==ubinop || cat1==colon) {
- big_app1(pp); big_app(' '); reduce(pp,1,decl_head,-1,27);
-}
-else if (cat1==semi || cat1==binop) squash(pp,1,decl_head,0,28);
-
-@ @<Cases for |public_like|@>=
-if (cat1==colon) squash(pp,2,tag,-1,29);
-else squash(pp,1,int_like,-2,30);
-
-@ @<Cases for |colcol|@>=
-if (cat1==exp||cat1==int_like) {
- app(qualifier); squash(pp,2,cat1,-2,31);
-}@+else if (cat1==colcol) squash(pp,2,colcol,-1,32);
-
-@ @<Cases for |decl_head|@>=
-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);
-}
-else if (cat1==exp && cat2!=lpar && 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 ||
- cat3==semi || cat3==rpar))
- 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);
-}
-else if (cat1==semi) squash(pp,2,decl,-1,39);
-
-@ @<Cases for |decl|@>=
-if (cat1==decl) {
- big_app1(pp); big_app(force); big_app1(pp+1);
- 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);
-}
-
-@ @<Cases for |base|@>=
-if (cat1==int_like || cat1==exp) {
- if (cat2==comma) {
- big_app1(pp); big_app(' '); big_app2(pp+1);
- app(opt); app('9'); reduce(pp,3,base,0,42);
- }
- else if (cat2==lbrace) {
- big_app1(pp); big_app(' '); big_app1(pp+1); big_app(' '); big_app1(pp+2);
- reduce(pp,3,lbrace,-2,43);
- }
-}
-
-@ @<Cases for |struct_like|@>=
-if (cat1==lbrace) {
- big_app1(pp); big_app(' '); big_app1(pp+1); reduce(pp,2,struct_head,0,44);
-}
-else if (cat1==exp||cat1==int_like) {
- if (cat2==lbrace || cat2==semi) {
- make_underlined(pp+1); make_reserved(pp+1);
- big_app1(pp); big_app(' '); big_app1(pp+1);
- if (cat2==semi) reduce(pp,2,decl_head,0,45);
- else {
- big_app(' '); big_app1(pp+2);reduce(pp,3,struct_head,0,46);
- }
- }
- else if (cat2==colon) squash(pp+2,1,base,2,47);
- else if (cat2!=base) {
- big_app1(pp); big_app(' '); big_app1(pp+1); reduce(pp,2,int_like,-2,48);
- }
-}
-
-@ @<Cases for |struct_head|@>=
-if ((cat1==decl || cat1==stmt || cat1==function) && cat2==rbrace) {
- big_app1(pp); big_app(indent); big_app(force); big_app1(pp+1);
- big_app(outdent); big_app(force); big_app1(pp+2);
- reduce(pp,3,int_like,-2,49);
-}
-else if (cat1==rbrace) {
- big_app1(pp); app_str("\\,"); big_app1(pp+1);
-@.\\,@>
- reduce(pp,2,int_like,-2,50);
-}
-
-@ @<Cases for |fn_decl|@>=
-if (cat1==decl) {
- big_app1(pp); big_app(force); big_app1(pp+1); reduce(pp,2,fn_decl,0,51);
-}
-else if (cat1==stmt) {
- big_app1(pp); app(outdent); app(outdent); big_app(force);
- big_app1(pp+1); reduce(pp,2,function,-1,52);
-}
-
-@ @<Cases for |function|@>=
-if (cat1==function || cat1==decl || cat1==stmt) {
- big_app1(pp); big_app(big_force); big_app1(pp+1); reduce(pp,2,cat1,-1,53);
-}
-
-@ @<Cases for |lbrace|@>=
-if (cat1==rbrace) {
- big_app1(pp); app('\\'); app(','); big_app1(pp+1);
-@.\\,@>
- reduce(pp,2,stmt,-1,54);
-}
-else if ((cat1==stmt||cat1==decl||cat1==function) && cat2==rbrace) {
- big_app(force); big_app1(pp); big_app(indent); big_app(force);
- big_app1(pp+1); big_app(force); big_app(backup); big_app1(pp+2);
- big_app(outdent); big_app(force); reduce(pp,3,stmt,-1,55);
-}
-else if (cat1==exp) {
- if (cat2==rbrace) squash(pp,3,exp,-2,56);
- else if (cat2==comma && cat3==rbrace) squash(pp,4,exp,-2,56);
-}
-
-@ @<Cases for |if_like|@>=
-if (cat1==exp) {
- big_app1(pp); big_app(' '); big_app1(pp+1); reduce(pp,2,if_clause,0,57);
-}
-
-@ @<Cases for |else_like|@>=
-if (cat1==colon) squash(pp+1,1,base,1,58);
-else if (cat1==lbrace) squash(pp,1,else_head,0,59);
-else if (cat1==stmt) {
- big_app(force); big_app1(pp); big_app(indent); big_app(break_space);
- big_app1(pp+1); big_app(outdent); big_app(force);
- reduce(pp,2,stmt,-1,60);
-}
-
-@ @<Cases for |else_head|@>=
-if (cat1==stmt || cat1==exp) {
- big_app(force); big_app1(pp); big_app(break_space); app(noop);
- big_app(cancel); big_app1(pp+1); big_app(force);
- reduce(pp,2,stmt,-1,61);
-}
-
-@ @<Cases for |if_clause|@>=
-if (cat1==lbrace) squash(pp,1,if_head,0,62);
-else if (cat1==stmt) {
- if (cat2==else_like) {
- big_app(force); big_app1(pp); big_app(indent); big_app(break_space);
- big_app1(pp+1); big_app(outdent); big_app(force); big_app1(pp+2);
- if (cat3==if_like) {
- big_app(' '); big_app1(pp+3); reduce(pp,4,if_like,0,63);
- }@+else reduce(pp,3,else_like,0,64);
- }
- else squash(pp,1,else_like,0,65);
-}
-
-@ @<Cases for |if_head|@>=
-if (cat1==stmt || cat1==exp) {
- if (cat2==else_like) {
- big_app(force); big_app1(pp); big_app(break_space); app(noop);
- big_app(cancel); big_app1(pp+1); big_app(force); big_app1(pp+2);
- if (cat3==if_like) {
- big_app(' '); big_app1(pp+3); reduce(pp,4,if_like,0,66);
- }@+else reduce(pp,3,else_like,0,67);
- }
- else squash(pp,1,else_head,0,68);
-}
-
-@ @<Cases for |do_like|@>=
-if (cat1==stmt && cat2==else_like && cat3==semi) {
- big_app1(pp); big_app(break_space); app(noop); big_app(cancel);
- big_app1(pp+1); big_app(cancel); app(noop); big_app(break_space);
- big_app2(pp+2); reduce(pp,4,stmt,-1,69);
-}
-
-@ @<Cases for |case_like|@>=
-if (cat1==semi) squash(pp,2,stmt,-1,70);
-else if (cat1==colon) squash(pp,2,tag,-1,71);
-else if (cat1==exp) {
- big_app1(pp); big_app(' '); big_app1(pp+1); reduce(pp,2,exp,-2,72);
-}
-
-@ @<Cases for |catch_like|@>=
-if (cat1==cast || cat1==exp) {
- big_app2(pp); big_app(indent); big_app(indent); reduce(pp,2,fn_decl,0,73);
-}
-
-@ @<Cases for |tag|@>=
-if (cat1==tag) {
- big_app1(pp); big_app(break_space); big_app1(pp+1); reduce(pp,2,tag,-1,74);
-}
-else if (cat1==stmt||cat1==decl||cat1==function) {
- big_app(force); big_app(backup); big_app1(pp); big_app(break_space);
- big_app1(pp+1); reduce(pp,2,cat1,-1,75);
-}
-
-@ The user can decide at run-time whether short statements should be
-grouped together on the same line.
-
-@d force_lines flags['f'] /* should each statement be on its own line? */
-
-@<Set init...@>=
-force_lines=true;
-
-@ @<Cases for |stmt|@>=
-if (cat1==stmt||cat1==decl||cat1==function) {
- big_app1(pp);
- if (cat1==function) big_app(big_force);
- else if (cat1==decl) big_app(big_force);
- else if (force_lines) big_app(force);
- else big_app(break_space);
- big_app1(pp+1); reduce(pp,2,cat1,-1,76);
-}
-
-@ @<Cases for |semi|@>=
-big_app(' '); big_app1(pp); reduce(pp,1,stmt,-1,77);
-
-@ @<Cases for |lproc|@>=
-if (cat1==define_like) make_underlined(pp+2);
-if (cat1==else_like || cat1==if_like ||cat1==define_like)
- squash(pp,2,lproc,0,78);
-else if (cat1==rproc) {
- app(inserted); big_app2(pp); reduce(pp,2,insert,-1,79);
-} else if (cat1==exp || cat1==function) {
- if (cat2==rproc) {
- app(inserted); big_app1(pp); big_app(' '); big_app2(pp+1);
- reduce(pp,3,insert,-1,80);
- }
- else if (cat2==exp && cat3==rproc && cat1==exp) {
- app(inserted); big_app1(pp); big_app(' '); big_app1(pp+1); app_str(" \\5");
-@.\\5@>
- big_app2(pp+2); reduce(pp,4,insert,-1,80);
- }
-}
-
-@ @<Cases for |section_scrap|@>=
-if (cat1==semi) {
- big_app2(pp); big_app(force); reduce(pp,2,stmt,-2,81);
-}
-else squash(pp,1,exp,-2,82);
-
-@ @<Cases for |insert|@>=
-if (cat1)
- squash(pp,2,cat1,0,83);
-
-@ @<Cases for |prelangle|@>=
-init_mathness=cur_mathness=yes_math;
-app('<'); reduce(pp,1,binop,-2,84);
-
-@ @<Cases for |prerangle|@>=
-init_mathness=cur_mathness=yes_math;
-app('>'); reduce(pp,1,binop,-2,85);
-
-@ @<Cases for |langle|@>=
-if (cat1==prerangle) {
- big_app1(pp); app('\\'); app(','); big_app1(pp+1);
-@.\\,@>
- reduce(pp,2,cast,-1,86);
-}
-else if (cat1==decl_head || cat1==int_like || cat1==exp) {
- if (cat2==prerangle) squash(pp,3,cast,-1,87);
- else if (cat2==comma) {
- big_app3(pp); app(opt); app('9'); reduce(pp,3,langle,0,88);
- }
-}
-
-@ @<Cases for |template_like|@>=
-if (cat1==exp && cat2==prelangle) squash(pp+2,1,langle,2,89);
-else if (cat1==exp || cat1==raw_int) {
- big_app1(pp); big_app(' '); big_app1(pp+1); reduce(pp,2,cat1,-2,90);
-}@+ else squash(pp,1,raw_int,0,91);
-
-@ @<Cases for |new_like|@>=
-if (cat1==lpar && cat2==exp && cat3==rpar) squash(pp,4,new_like,0,92);
-else if (cat1==cast) {
- big_app1(pp); big_app(' '); big_app1(pp+1); reduce(pp,2,exp,-2,93);
-}
-else if (cat1!=lpar) squash(pp,1,new_exp,0,94);
-
-@ @<Cases for |new_exp|@>=
-if (cat1==int_like || cat1==const_like) {
- big_app1(pp); big_app(' '); big_app1(pp+1); reduce(pp,2,new_exp,0,95);
-}
-else if (cat1==struct_like && (cat2==exp || cat2==int_like)) {
- big_app1(pp); big_app(' '); big_app1(pp+1); big_app(' ');
- big_app1(pp+2); reduce(pp,3,new_exp,0,96);
-}
-else if (cat1==raw_ubin) {
- big_app1(pp); big_app('{'); big_app1(pp+1); big_app('}');
- reduce(pp,2,new_exp,0,97);
-}
-else if (cat1==lpar) squash(pp,1,exp,-2,98);
-else if (cat1==exp) {
- big_app1(pp); big_app(' '); reduce(pp,1,exp,-2,98);
-}
-else if (cat1!=raw_int && cat1!=struct_like && cat1!=colcol)
- squash(pp,1,exp,-2,99);
-
-@ @<Cases for |ftemplate|@>=
-if (cat1==prelangle) squash(pp+1,1,langle,1,100);
-else squash(pp,1,exp,-2,101);
-
-@ @<Cases for |for_like|@>=
-if (cat1==exp) {
- big_app1(pp); big_app(' '); big_app1(pp+1); reduce(pp,2,else_like,-2,102);
-}
-
-@ @<Cases for |raw_ubin|@>=
-if (cat1==const_like) {
- big_app2(pp); app_str("\\ "); reduce(pp,2,raw_ubin,0,103);
-@.\\\ @>
-} else squash(pp,1,ubinop,-2,104);
-
-@ @<Cases for |const_like|@>=
-squash(pp,1,int_like,-2,105);
-
-@ @<Cases for |raw_int|@>=
-if (cat1==prelangle) squash(pp+1,1,langle,1,106);
-else if (cat1==colcol) squash(pp,2,colcol,-1,107);
-else if (cat1==cast) squash(pp,2,raw_int,0,108);
-else if (cat1==lpar) squash(pp,1,exp,-2,109);
-else if (cat1!=langle) squash(pp,1,int_like,-3,110);
-
-@ @<Cases for |operator_like|@>=
-if (cat1==binop || cat1==unop || cat1==ubinop) {
- if (cat2==binop) break;
- big_app1(pp); big_app('{'); big_app1(pp+1); big_app('}');
- reduce(pp,2,exp,-2,111);
-}
-else if (cat1==new_like || cat1==delete_like) {
- big_app1(pp); big_app(' '); big_app1(pp+1); reduce(pp,2,exp,-2,112);
-}
-else if (cat1==comma) squash(pp,2,exp,-2,113);
-else if (cat1!=raw_ubin) squash(pp,1,new_exp,0,114);
-
-@ @<Cases for |typedef_like|@>=
-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);
-}
-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);
-}
-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);
-}
-
-@ @<Cases for |delete_like|@>=
-if (cat1==lpar && cat2==rpar) {
- big_app2(pp); app('\\'); app(','); big_app1(pp+2);
-@.\\,@>
- reduce(pp,3,delete_like,0,121);
-}
-else if (cat1==exp) {
- big_app1(pp); big_app(' '); big_app1(pp+1); reduce(pp,2,exp,-2,122);
-}
-
-@ @<Cases for |question|@>=
-if (cat1==exp && (cat2==colon || cat2==base)) {
- (pp+2)->mathness=5*yes_math; /* this colon should be in math mode */
- squash(pp,3,binop,-2,123);
-}
-
-@ Now here's the |reduce| procedure used in our code for productions.
-
-The `|freeze_text|' macro is used to give official status to a token list.
-Before saying |freeze_text|, items are appended to the current token list,
-and we know that the eventual number of this token list will be the current
-value of |text_ptr|. But no list of that number really exists as yet,
-because no ending point for the current list has been
-stored in the |tok_start| array. After saying |freeze_text|, the
-old current token list becomes legitimate, and its number is the current
-value of |text_ptr-1| since |text_ptr| has been increased. The new
-current token list is empty and ready to be appended to.
-Note that |freeze_text| does not check to see that |text_ptr| hasn't gotten
-too large, since it is assumed that this test was done beforehand.
-
-@d freeze_text *(++text_ptr)=tok_ptr
-
-@<Predecl...@>=
-static void reduce(scrap_pointer,short,eight_bits,short,short);@/
-static void squash(scrap_pointer,short,eight_bits,short,short);
-
-@ @c
-static void
-reduce(
-scrap_pointer j, short k,
-eight_bits c,
-short d, short n)
-{
- scrap_pointer i, i1; /* pointers into scrap memory */
- j->cat=c; j->trans=text_ptr;
- j->mathness=4*cur_mathness+init_mathness;
- freeze_text;
- if (k>1) {
- for (i=j+k, i1=j+1; i<=lo_ptr; i++, i1++) {
- i1->cat=i->cat; i1->trans=i->trans;
- i1->mathness=i->mathness;
- }
- lo_ptr=lo_ptr-k+1;
- }
- pp=(pp+d<scrap_base? scrap_base: pp+d);
- @<Print a snapshot of the scrap list if debugging @>@;
- pp--; /* we next say |pp++| */
-}
-
-@ Here's the |squash| procedure, which
-takes advantage of the simplification that occurs when |k==1|.
-
-@c
-static void
-squash(
-scrap_pointer j, short k,
-eight_bits c,
-short d, short n)
-{
- scrap_pointer i; /* pointers into scrap memory */
- if (k==1) {
- j->cat=c; pp=(pp+d<scrap_base? scrap_base: pp+d);
- @<Print a snapshot...@>@;
- pp--; /* we next say |pp++| */
- return;
- }
- for (i=j; i<j+k; i++) big_app1(i);
- reduce(j,k,c,d,n);
-}
-
-@ And here now is the code that applies productions as long as possible.
-Before applying the production mechanism, we must make sure
-it has good input (at least four scraps, the length of the lhs of the
-longest rules), and that there is enough room in the memory arrays
-to hold the appended tokens and texts. Here we use a very
-conservative test; it's more important to make sure the program
-will still work if we change the production rules (within reason)
-than to squeeze the last bit of space from the memory arrays.
-
-@d safe_tok_incr 20
-@d safe_text_incr 10
-@d safe_scrap_incr 10
-
-@<Reduce the scraps using the productions until no more rules apply@>=
-while (true) {
- @<Make sure the entries |pp| through |pp+3| of |cat| are defined@>@;
- if (tok_ptr+safe_tok_incr>tok_mem_end) {
- if (tok_ptr>max_tok_ptr) max_tok_ptr=tok_ptr;
- overflow("token");
- }
- if (text_ptr+safe_text_incr>tok_start_end) {
- if (text_ptr>max_text_ptr) max_text_ptr=text_ptr;
- overflow("text");
- }
- if (pp>lo_ptr) break;
- init_mathness=cur_mathness=maybe_math;
- @<Match a production...@>@;
-}
-
-@ If we get to the end of the scrap list, category codes equal to zero are
-stored, since zero does not match anything in a production.
-
-@<Make sure the entries...@>=
-if (lo_ptr<pp+3) {
- while (hi_ptr<=scrap_ptr && lo_ptr!=pp+3) {
- (++lo_ptr)->cat=hi_ptr->cat; lo_ptr->mathness=(hi_ptr)->mathness;
- lo_ptr->trans=(hi_ptr++)->trans;
- }
- for (i=lo_ptr+1;i<=pp+3;i++) i->cat=0;
-}
-
-@ If \.{CWEAVE} is being run in debugging mode, the production numbers and
-current stack categories will be printed out when |tracing| is set to 2;
-a sequence of two or more irreducible scraps will be printed out when
-|tracing| is set to 1.
-
-@<Private...@>=
-static int tracing; /* can be used to show parsing details */
-
-@ @<Print a snapsh...@>=
-{ scrap_pointer k_l; /* pointer into |scrap_info| */
- if (tracing==2) {
- printf("\n%d:",n);
- for (k_l=scrap_base; k_l<=lo_ptr; k_l++) {
- if (k_l==pp) putxchar('*'); else putxchar(' ');
- if (k_l->mathness %4 == yes_math) putchar('+');
- else if (k_l->mathness %4 == no_math) putchar('-');
- print_cat(k_l->cat);
- if (k_l->mathness /4 == yes_math) putchar('+');
- else if (k_l->mathness /4 == no_math) putchar('-');
- }
- if (hi_ptr<=scrap_ptr) fputs("...",stdout); /* indicate that more is coming */
- }
-}
-
-@ The |translate| function assumes that scraps have been stored in
-positions |scrap_base| through |scrap_ptr| of |cat| and |trans|. It
-applies productions as much as
-possible. The result is a token list containing the translation of
-the given sequence of scraps.
-
-After calling |translate|, we will have |text_ptr+3<=max_texts| and
-|tok_ptr+6<=max_toks|, so it will be possible to create up to three token
-lists with up to six tokens without checking for overflow. Before calling
-|translate|, we should have |text_ptr<max_texts| and |scrap_ptr<max_scraps|,
-since |translate| might add a new text and a new scrap before it checks
-for overflow.
-
-@c
-static text_pointer
-translate(void) /* converts a sequence of scraps */
-{
- scrap_pointer i, /* index into |cat| */
- j; /* runs through final scraps */
- pp=scrap_base; lo_ptr=pp-1; hi_ptr=pp;
- @<If tracing, print an indication of where we are@>@;
- @<Reduce the scraps...@>@;
- @<Combine the irreducible scraps that remain@>@;
-}
-
-@ @<Predecl...@>=@+static text_pointer translate(void);
-
-@ If the initial sequence of scraps does not reduce to a single scrap,
-we concatenate the translations of all remaining scraps, separated by
-blank spaces, with dollar signs surrounding the translations of scraps
-where appropriate.
-
-@<Combine the irreducible...@>= {
- @<If semi-tracing, show the irreducible scraps@>@;
- for (j=scrap_base; j<=lo_ptr; j++) {
- if (j!=scrap_base) app(' ');
- if (j->mathness % 4 == yes_math) app('$');
- app1(j);
- if (j->mathness / 4 == yes_math) app('$');
- if (tok_ptr+6>tok_mem_end) overflow("token");
- }
- freeze_text; return text_ptr-1;
-}
-
-@ @<If semi-tracing, show the irreducible scraps@>=
-if (lo_ptr>scrap_base && tracing==1) {
- printf("\nIrreducible scrap sequence in section %d:",section_count);
-@.Irreducible scrap sequence...@>
- mark_harmless;
- for (j=scrap_base; j<=lo_ptr; j++) {
- printf(" "); print_cat(j->cat);
- }
-}
-
-@ @<If tracing,...@>=
-if (tracing==2) {
- printf("\nTracing after l. %d:\n",cur_line); mark_harmless;
-@.Tracing after...@>
- if (loc>buffer+50) {
- printf("...");
- term_write(loc-51,51);
- }
- else term_write(buffer,loc-buffer);
-}
-
-@* Initializing the scraps.
-If we are going to use the powerful production mechanism just developed, we
-must get the scraps set up in the first place, given a \CEE/ text. A table
-of the initial scraps corresponding to \CEE/ tokens appeared above in the
-section on parsing; our goal now is to implement that table. We shall do this
-by implementing a subroutine called |C_parse| that is analogous to the
-|C_xref| routine used during phase one.
-
-Like |C_xref|, the |C_parse| procedure starts with the current
-value of |next_control| and it uses the operation |next_control=get_next()|
-repeatedly to read \CEE/ text until encountering the next `\.{\v}' or
-`\.{/*}', or until |next_control>=format_code|. The scraps corresponding to
-what it reads are appended into the |cat| and |trans| arrays, and |scrap_ptr|
-is advanced.
-
-@c
-static void
-C_parse(@t\1\1@> /* creates scraps from \CEE/ tokens */
- eight_bits spec_ctrl@t\2\2@>)
-{
- int count; /* characters remaining before string break */
- while (next_control<format_code || next_control==spec_ctrl) {
- @<Append the scrap appropriate to |next_control|@>@;
- next_control=get_next();
- if (next_control=='|' || next_control==begin_comment ||
- next_control==begin_short_comment) return;
- }
-}
-
-@ @<Predecl...@>=@+static void C_parse(eight_bits);
-
-@ The following macro is used to append a scrap whose tokens have just
-been appended:
-
-@d app_scrap(c,b) {
- (++scrap_ptr)->cat=(c); scrap_ptr->trans=text_ptr;
- scrap_ptr->mathness=5*(b); /* no no, yes yes, or maybe maybe */
- freeze_text;
-}
-
-@ @<Append the scr...@>=
-@<Make sure that there is room for the new scraps, tokens, and texts@>@;
-switch (next_control) {
- case section_name:
- app(section_flag+(int)(cur_section-name_dir));
- app_scrap(section_scrap,maybe_math);
- app_scrap(exp,yes_math);@+break;
- case string: case constant: case verbatim:
- @<Append a string or constant@>@;@+break;
- case identifier: app_cur_id(true);@+break;
- case TeX_string:
- @<Append a \TEX/ string, without forming a scrap@>@;@+break;
- case '/': case '.':
- app(next_control);@+app_scrap(binop,yes_math);@+break;
- case '<': app_str("\\langle");@+app_scrap(prelangle,yes_math);@+break;
-@.\\langle@>
- case '>': app_str("\\rangle");@+app_scrap(prerangle,yes_math);@+break;
-@.\\rangle@>
- case '=': app_str("\\K");@+app_scrap(binop,yes_math);@+break;
-@.\\K@>
- case '|': app_str("\\OR");@+app_scrap(binop,yes_math);@+break;
-@.\\OR@>
- case '^': app_str("\\XOR");@+app_scrap(binop,yes_math);@+break;
-@.\\XOR@>
- case '%': app_str("\\MOD");@+app_scrap(binop,yes_math);@+break;
-@.\\MOD@>
- case '!': app_str("\\R");@+app_scrap(unop,yes_math);@+break;
-@.\\R@>
- case '~': app_str("\\CM");@+app_scrap(unop,yes_math);@+break;
-@.\\CM@>
- case '+': case '-': app(next_control);@+app_scrap(ubinop,yes_math);@+break;
- case '*': app(next_control);@+app_scrap(raw_ubin,yes_math);@+break;
- case '&': app_str("\\AND");@+app_scrap(raw_ubin,yes_math);@+break;
-@.\\AND@>
- case '?': app_str("\\?");@+app_scrap(question,yes_math);@+break;
-@.\\?@>
- case '#': app_str("\\#");@+app_scrap(ubinop,yes_math);@+break;
-@.\\\#@>
- case ignore: case xref_roman: case xref_wildcard:
- case xref_typewriter: case noop:@+break;
- case '(': case '[': app(next_control);@+app_scrap(lpar,maybe_math);@+break;
- case ')': case ']': app(next_control);@+app_scrap(rpar,maybe_math);@+break;
- case '{': app_str("\\{"@q}@>);@+app_scrap(lbrace,yes_math);@+break;
-@.\\\{@>@q}@>
- case '}': app_str(@q{@>"\\}");@+app_scrap(rbrace,yes_math);@+break;
-@q{@>@.\\\}@>
- case ',': app(',');@+app_scrap(comma,yes_math);@+break;
- case ';': app(';');@+app_scrap(semi,maybe_math);@+break;
- case ':': app(':');@+app_scrap(colon,no_math);@+break;@/
- @t\4@> @<Cases involving nonstandard characters@>@;
- case thin_space: app_str("\\,");@+app_scrap(insert,maybe_math);@+break;
-@.\\,@>
- case math_break: app(opt);@+app_str("0");@+
- app_scrap(insert,maybe_math);@+break;
- case line_break: app(force);@+app_scrap(insert,no_math);@+break;
- case left_preproc: app(force);@+app(preproc_line);@+app_str("\\#");
- app_scrap(lproc,no_math);@+break;
-@.\\\#@>
- case right_preproc: app(force);@+app_scrap(rproc,no_math);@+break;
- case big_line_break: app(big_force);@+app_scrap(insert,no_math);@+break;
- case no_line_break: app(big_cancel);@+app(noop);@+app(break_space);@+
- app(noop);@+app(big_cancel);
- app_scrap(insert,no_math);@+break;
- case pseudo_semi: app_scrap(semi,maybe_math);@+break;
- case macro_arg_open: app_scrap(begin_arg,maybe_math);@+break;
- case macro_arg_close: app_scrap(end_arg,maybe_math);@+break;
- case join: app_str("\\J");@+app_scrap(insert,no_math);@+break;
-@.\\J@>
- case output_defs_code: app(force);@+app_str("\\ATH");@+app(force);
- app_scrap(insert,no_math);@+break;
-@.\\ATH@>
- default: app(inserted);@+app(next_control);
- app_scrap(insert,maybe_math);@+break;
-}
-
-@ @<Make sure that there is room for the new...@>=
-if (scrap_ptr+safe_scrap_incr>scrap_info_end ||
- tok_ptr+safe_tok_incr>tok_mem_end @| ||
- text_ptr+safe_text_incr>tok_start_end) {
- if (scrap_ptr>max_scr_ptr) max_scr_ptr=scrap_ptr;
- if (tok_ptr>max_tok_ptr) max_tok_ptr=tok_ptr;
- if (text_ptr>max_text_ptr) max_text_ptr=text_ptr;
- overflow("scrap/token/text");
-}
-
-@ Some nonstandard characters may have entered \.{CWEAVE} by means of
-standard ones. They are converted to \TEX/ control sequences so that it is
-possible to keep \.{CWEAVE} from outputting unusual |char| codes.
-
-@<Cases involving nonstandard...@>=
-case non_eq: app_str("\\I");@+app_scrap(binop,yes_math);@+break;
-@.\\I@>
-case lt_eq: app_str("\\Z");@+app_scrap(binop,yes_math);@+break;
-@.\\Z@>
-case gt_eq: app_str("\\G");@+app_scrap(binop,yes_math);@+break;
-@.\\G@>
-case eq_eq: app_str("\\E");@+app_scrap(binop,yes_math);@+break;
-@.\\E@>
-case and_and: app_str("\\W");@+app_scrap(binop,yes_math);@+break;
-@.\\W@>
-case or_or: app_str("\\V");@+app_scrap(binop,yes_math);@+break;
-@.\\V@>
-case plus_plus: app_str("\\PP");@+app_scrap(unop,yes_math);@+break;
-@.\\PP@>
-case minus_minus: app_str("\\MM");@+app_scrap(unop,yes_math);@+break;
-@.\\MM@>
-case minus_gt: app_str("\\MG");@+app_scrap(binop,yes_math);@+break;
-@.\\MG@>
-case gt_gt: app_str("\\GG");@+app_scrap(binop,yes_math);@+break;
-@.\\GG@>
-case lt_lt: app_str("\\LL");@+app_scrap(binop,yes_math);@+break;
-@.\\LL@>
-case dot_dot_dot: app_str("\\,\\ldots\\,");@+app_scrap(raw_int,yes_math);
- @+break;
-@.\\,@>
-@.\\ldots@>
-case colon_colon: app_str("\\DC");@+app_scrap(colcol,maybe_math);@+break;
-@.\\DC@>
-case period_ast: app_str("\\PA");@+app_scrap(binop,yes_math);@+break;
-@.\\PA@>
-case minus_gt_ast: app_str("\\MGA");@+app_scrap(binop,yes_math);@+break;
-@.\\MGA@>
-
-@ The following code must use |app_tok| instead of |app| in order to
-protect against overflow. Note that |tok_ptr+1<=max_toks| after |app_tok|
-has been used, so another |app| is legitimate before testing again.
-
-Many of the special characters in a string must be prefixed by `\.\\' so that
-\TEX/ will print them properly.
-@^special string characters@>
-
-@<Append a string or...@>=
-count= -1;
-if (next_control==constant) app_str("\\T{"@q}@>);
-@.\\T@>
-else if (next_control==string) {
- count=20; app_str("\\.{"@q}@>);
-}
-@.\\.@>
-else app_str("\\vb{"@q}@>);
-@.\\vb@>
-while (id_first<id_loc) {
- if (count==0) { /* insert a discretionary break in a long string */
- app_str(@q(@>@q{@>"}\\)\\.{"@q}@>); count=20;
-@q(@>@.\\)@>
- }
-@^high-bit character handling@>
- if((eight_bits)(*id_first)>0177) {
- app_tok(quoted_char);
- app_tok((eight_bits)(*id_first++));
- }
- else {
- switch (*id_first) {
- case ' ':case '\\':case '#':case '%':case '$':case '^':
- case '{': case '}': case '~': case '&': case '_': app('\\'); break;
-@.\\\ @>
-@.\\\\@>
-@.\\\#@>
-@.\\\%@>
-@.\\\$@>
-@.\\\^@>
-@.\\\{@>@q}@>
-@q{@>@.\\\}@>
-@.\\\~@>
-@.\\\&@>
-@.\\\_@>
- case '@@': if (*(id_first+1)=='@@') id_first++;
- else err_print("! Double @@ should be used in strings");
-@.Double @@ should be used...@>
- }
- app_tok(*id_first++);
- }
- count--;
-}
-app(@q{@>'}');
-app_scrap(exp,maybe_math);
-
-@ We do not make the \TEX/ string into a scrap, because there is no
-telling what the user will be putting into it; instead we leave it
-open, to be picked up by the next scrap. If it comes at the end of a
-section, it will be made into a scrap when |finish_C| is called.
-
-There's a known bug here, in cases where an adjacent scrap is
-|prelangle| or |prerangle|. Then the \TEX/ string can disappear
-when the \.{\\langle} or \.{\\rangle} becomes \.{<} or \.{>}.
-For example, if the user writes \.{\v x<@@ty@@>\v}, the \TEX/ string
-\.{\\hbox\{y\}} eventually becomes part of an |insert| scrap, which is combined
-with a |prelangle| scrap and eventually lost. The best way to work around
-this bug is probably to enclose the \.{@@t...@@>} in \.{@@[...@@]} so that
-the \TEX/ string is treated as an expression.
-@^bug, known@>
-
-@<Append a \TEX/ string, without forming a scrap@>=
-app_str("\\hbox{"@q}@>);
-@^high-bit character handling@>
-while (id_first<id_loc)
- if((eight_bits)(*id_first)>0177) {
- app_tok(quoted_char);
- app_tok((eight_bits)(*id_first++));
- }
- else {
- if (*id_first=='@@') id_first++;
- app_tok(*id_first++);
- }
-app(@q{@>'}');
-
-@ The function |app_cur_id| appends the current identifier to the
-token list; it also builds a new scrap if |scrapping==true|.
-
-@<Predec...@>=
-static void app_cur_id(boolean);@/
-static text_pointer C_translate(void);@/
-static void outer_parse(void);
-
-@ @c
-static void
-app_cur_id(@t\1\1@>
-boolean scrapping@t\2\2@>) /* are we making this into a scrap? */
-{
- name_pointer p=id_lookup(id_first,id_loc,normal);
- if (p->ilk<=custom) { /* not a reserved word */
- app(id_flag+(int)(p-name_dir));
- if (scrapping) app_scrap(p->ilk==func_template? ftemplate: exp,
- p->ilk==custom? yes_math: maybe_math);
-@.\\NULL@>
- } else {
- app(res_flag+(int)(p-name_dir));
- if (scrapping) {
- if (p->ilk==alfop) app_scrap(ubinop,yes_math)@;
- else app_scrap(p->ilk,maybe_math);
- }
- }
-}
-
-@ When the `\.{\v}' that introduces \CEE/ text is sensed, a call on
-|C_translate| will return a pointer to the \TEX/ translation of
-that text. If scraps exist in |scrap_info|, they are
-unaffected by this translation process.
-
-@c
-static text_pointer
-C_translate(void)
-{
- text_pointer p; /* points to the translation */
- scrap_pointer save_base; /* holds original value of |scrap_base| */
- save_base=scrap_base; scrap_base=scrap_ptr+1;
- C_parse(section_name); /* get the scraps together */
- if (next_control!='|') err_print("! Missing '|' after C text");
-@.Missing '|'...@>
- app_tok(cancel); app_scrap(insert,maybe_math);
- /* place a |cancel| token as a final ``comment'' */
- p=translate(); /* make the translation */
- if (scrap_ptr>max_scr_ptr) max_scr_ptr=scrap_ptr;
- scrap_ptr=scrap_base-1; scrap_base=save_base; /* scrap the scraps */
- return p;
-}
-
-@ The |outer_parse| routine is to |C_parse| as |outer_xref|
-is to |C_xref|: It constructs a sequence of scraps for \CEE/ text
-until |next_control>=format_code|. Thus, it takes care of embedded comments.
-
-The token list created from within `\pb' brackets is output as an argument
-to \.{\\PB}, if the user has invoked \.{CWEAVE} with the \.{+e} flag.
-Although \.{cwebmac} ignores \.{\\PB}, other macro packages
-might use it to localize the special meaning of the macros that mark up
-program text.
-
-@d make_pb flags['e']
-
-@<Set init...@>=
-make_pb=true;
-
-@ @c
-static void
-outer_parse(void) /* makes scraps from \CEE/ tokens and comments */
-{
- int bal; /* brace level in comment */
- text_pointer p, q; /* partial comments */
- while (next_control<format_code)
- if (next_control!=begin_comment && next_control!=begin_short_comment)
- C_parse(ignore);
- else {
- boolean is_long_comment=(next_control==begin_comment);
- @<Make sure that there is room for the new...@>@;
- app(cancel); app(inserted);
- if (is_long_comment) app_str("\\C{"@q}@>);
-@.\\C@>
- else app_str("\\SHC{"@q}@>);
-@.\\SHC@>
- bal=copy_comment(is_long_comment,1); next_control=ignore;
- while (bal>0) {
- p=text_ptr; freeze_text; q=C_translate();
- /* at this point we have |tok_ptr+6<=max_toks| */
- app(tok_flag+(int)(p-tok_start));
- if (make_pb) app_str("\\PB{");
-@.\\PB@>
- app(inner_tok_flag+(int)(q-tok_start));
- if (make_pb) app_tok('}');
- if (next_control=='|') {
- bal=copy_comment(is_long_comment,bal);
- next_control=ignore;
- }
- else bal=0; /* an error has been reported */
- }
- app(force); app_scrap(insert,no_math);
- /* the full comment becomes a scrap */
- }
-}
-
-@* Output of tokens.
-So far our programs have only built up multi-layered token lists in
-\.{CWEAVE}'s internal memory; we have to figure out how to get them into
-the desired final form. The job of converting token lists to characters in
-the \TEX/ output file is not difficult, although it is an implicitly
-recursive process. Four main considerations had to be kept in mind when
-this part of \.{CWEAVE} was designed. (a) There are two modes of output:
-|outer| mode, which translates tokens like |force| into line-breaking
-control sequences, and |inner| mode, which ignores them except that blank
-spaces take the place of line breaks. (b) The |cancel| instruction applies
-to adjacent token or tokens that are output, and this cuts across levels
-of recursion since `|cancel|' occurs at the beginning or end of a token
-list on one level. (c) The \TEX/ output file will be semi-readable if line
-breaks are inserted after the result of tokens like |break_space| and
-|force|. (d) The final line break should be suppressed, and there should
-be no |force| token output immediately after `\.{\\Y\\B}'.
-
-@ The output process uses a stack to keep track of what is going on at
-different ``levels'' as the token lists are being written out. Entries on
-this stack have three parts:
-
-\yskip\hang |end_field| is the |tok_mem| location where the token list of a
-particular level will end;
-
-\yskip\hang |tok_field| is the |tok_mem| location from which the next token
-on a particular level will be read;
-
-\yskip\hang |mode_field| is the current mode, either |inner| or |outer|.
-
-\yskip\noindent The current values of these quantities are referred to
-quite frequently, so they are stored in a separate place instead of in the
-|stack| array. We call the current values |cur_end|, |cur_tok|, and
-|cur_mode|.
-
-The global variable |stack_ptr| tells how many levels of output are
-currently in progress. The end of output occurs when an |end_translation|
-token is found, so the stack is never empty except when we first begin the
-output process.
-
-@d inner 0 /* value of |mode| for \CEE/ texts within \TEX/ texts */
-@d outer 1 /* value of |mode| for \CEE/ texts in sections */
-
-@<Typed...@>= typedef int mode;
-typedef struct {
- token_pointer end_field; /* ending location of token list */
- token_pointer tok_field; /* present location within token list */
- boolean mode_field; /* interpretation of control tokens */
-} output_state;
-typedef output_state *stack_pointer;
-
-@ @d cur_end cur_state.end_field /* current ending location in |tok_mem| */
-@d cur_tok cur_state.tok_field /* location of next output token in |tok_mem| */
-@d cur_mode cur_state.mode_field /* current mode of interpretation */
-@d init_stack stack_ptr=stack;cur_mode=outer /* initialize the stack */
-
-@<Private...@>=
-static output_state cur_state; /* |cur_end|, |cur_tok|, |cur_mode| */
-static output_state stack[stack_size]; /* info for non-current levels */
-static stack_pointer stack_end=stack+stack_size-1; /* end of |stack| */
-static stack_pointer stack_ptr; /* first unused location in the output state stack */
-static stack_pointer max_stack_ptr; /* largest value assumed by |stack_ptr| */
-
-@ @<Set init...@>=
-max_stack_ptr=stack;
-
-@ To insert token-list |p| into the output, the |push_level| subroutine
-is called; it saves the old level of output and gets a new one going.
-The value of |cur_mode| is not changed.
-
-@<Predecl...@>=
-static void push_level(text_pointer);@/
-static void pop_level(void);
-
-@ @c
-static void
-push_level(@t\1\1@> /* suspends the current level */
-text_pointer p@t\2\2@>)
-{
- if (stack_ptr==stack_end) overflow("stack");
- if (stack_ptr>stack) { /* save current state */
- stack_ptr->end_field=cur_end;
- stack_ptr->tok_field=cur_tok;
- stack_ptr->mode_field=cur_mode;
- }
- stack_ptr++;
- if (stack_ptr>max_stack_ptr) max_stack_ptr=stack_ptr;
- cur_tok=*p; cur_end=*(p+1);
-}
-
-@ Conversely, the |pop_level| routine restores the conditions that were in
-force when the current level was begun. This subroutine will never be
-called when |stack_ptr==1|.
-
-@c
-static void
-pop_level(void)
-{
- cur_end=(--stack_ptr)->end_field;
- cur_tok=stack_ptr->tok_field; cur_mode=stack_ptr->mode_field;
-}
-
-@ The |get_output| function returns the next byte of output that is not a
-reference to a token list. It returns the values |identifier| or |res_word|
-or |section_code| if the next token is to be an identifier (typeset in
-italics), a reserved word (typeset in boldface), or a section name (typeset
-by a complex routine that might generate additional levels of output).
-In these cases |cur_name| points to the identifier or section name in
-question.
-
-@<Private...@>=
-static name_pointer cur_name;
-
-@ @d res_word 0201 /* returned by |get_output| for reserved words */
-@d section_code 0200 /* returned by |get_output| for section names */
-
-@<Predecl...@>=
-static eight_bits get_output(void);@/
-static void output_C(void);@/
-static void make_output(void);
-
-@ @c
-static eight_bits
-get_output(void) /* returns the next token of output */
-{
- sixteen_bits a; /* current item read from |tok_mem| */
- restart: while (cur_tok==cur_end) pop_level();
- a=*(cur_tok++);
- if (a>=0400) {
- cur_name=a % id_flag + name_dir;
- switch (a / id_flag) {
- case 2: return res_word ; /* |a==res_flag+cur_name| */
- case 3: return section_code ; /* |a==section_flag+cur_name| */
- case 4: push_level(a % id_flag + tok_start); goto restart;
- /* |a==tok_flag+cur_name| */
- case 5: push_level(a % id_flag + tok_start); cur_mode=inner; goto restart;
- /* |a==inner_tok_flag+cur_name| */
- default: return identifier; /* |a==id_flag+cur_name| */
- }
- }
- return (eight_bits)a;
-}
-
-@ The real work associated with token output is done by |make_output|.
-This procedure appends an |end_translation| token to the current token list,
-and then it repeatedly calls |get_output| and feeds characters to the output
-buffer until reaching the |end_translation| sentinel. It is possible for
-|make_output| to be called recursively, since a section name may include
-embedded \CEE/ text; however, the depth of recursion never exceeds one
-level, since section names cannot be inside of section names.
-
-A procedure called |output_C| does the scanning, translation, and
-output of \CEE/ text within `\pb' brackets, and this procedure uses
-|make_output| to output the current token list. Thus, the recursive call
-of |make_output| actually occurs when |make_output| calls |output_C|
-while outputting the name of a section.
-@^recursion@>
-
-@c
-static void
-output_C(void) /* outputs the current token list */
-{
- token_pointer save_tok_ptr;
- text_pointer save_text_ptr;
- sixteen_bits save_next_control; /* values to be restored */
- text_pointer p; /* translation of the \CEE/ text */
- save_tok_ptr=tok_ptr; save_text_ptr=text_ptr;
- save_next_control=next_control; next_control=ignore; p=C_translate();
- app(inner_tok_flag+(int)(p-tok_start));
- if (make_pb) {
- out_str("\\PB{"); make_output(); out('}');
-@.\\PB@>
- }@+else make_output(); /* output the list */
- if (text_ptr>max_text_ptr) max_text_ptr=text_ptr;
- if (tok_ptr>max_tok_ptr) max_tok_ptr=tok_ptr;
- text_ptr=save_text_ptr; tok_ptr=save_tok_ptr; /* forget the tokens */
- next_control=save_next_control; /* restore |next_control| to original state */
-}
-
-@ Here is \.{CWEAVE}'s major output handler.
-
-@c
-static void
-make_output(void) /* outputs the equivalents of tokens */
-{
- eight_bits a=0, /* current output byte */
- b; /* next output byte */
- int c; /* count of |indent| and |outdent| tokens */
- char scratch[longest_name+1]; /* scratch area for section names */
- char *k, *k_limit; /* indices into |scratch| */
- char *j; /* index into |buffer| */
- char *p; /* index into |byte_mem| */
- char delim; /* first and last character of string being copied */
- char *save_loc, *save_limit; /* |loc| and |limit| to be restored */
- name_pointer cur_section_name; /* name of section being output */
- boolean save_mode; /* value of |cur_mode| before a sequence of breaks */
- app(end_translation); /* append a sentinel */
- freeze_text; push_level(text_ptr-1);
- while (true) {
- a=get_output();
- reswitch: switch(a) {
- case end_translation: return;
- case identifier: case res_word: @<Output an identifier@>@; break;
- case section_code: @<Output a section name@>@; break;
- case math_rel: out_str("\\MRL{"@q}@>);
-@.\\MRL@>
- case noop: case inserted: break;
- case cancel: case big_cancel: c=0; b=a;
- while (true) {
- a=get_output();
- if (a==inserted) continue;
- if ((a<indent && !(b==big_cancel&&a==' ')) || a>big_force) break;
- if (a==indent) c++; else if (a==outdent) c--;
- else if (a==opt) a=get_output();
- }
- @<Output saved |indent| or |outdent| tokens@>@;
- goto reswitch;
- case indent: case outdent: case opt: case backup: case break_space:
- case force: case big_force: case preproc_line: @<Output a control,
- look ahead in case of line breaks, possibly |goto reswitch|@>@; break;
- case quoted_char: out(*(cur_tok++));
- case qualifier: break;
- default: out(a); /* otherwise |a| is an ordinary character */
- }
- }
-}
-
-@ An identifier of length one does not have to be enclosed in braces, and it
-looks slightly better if set in a math-italic font instead of a (slightly
-narrower) text-italic font. Thus we output `\.{\\\v}\.{a}' but
-`\.{\\\\\{aa\}}'.
-
-@<Output an identifier@>=
-out('\\');
-if (a==identifier) {
- if (cur_name->ilk==custom && !doing_format) {
- custom_out:
- for (p=cur_name->byte_start;p<(cur_name+1)->byte_start;p++)
- out(*p=='_'? 'x': *p=='$'? 'X': *p);
- break;
- } else if (is_tiny(cur_name)) out('|')@;
-@.\\|@>
- else { delim='.';
- for (p=cur_name->byte_start;p<(cur_name+1)->byte_start;p++)
- if (xislower(*p)) { /* not entirely uppercase */
- delim='\\'; break;
- }
- out(delim);
- }
-@.\\\\@>
-@.\\.@>
-}@+else if (cur_name->ilk==alfop) {
- out('X');
- goto custom_out;
-}@+else out('&'); /* |a==res_word| */
-@.\\\&@>
-if (is_tiny(cur_name)) {
- if (isxalpha((cur_name->byte_start)[0]))
- out('\\');
- out((cur_name->byte_start)[0]);
-}
-else out_name(cur_name,true);
-
-@ The current mode does not affect the behavior of \.{CWEAVE}'s output routine
-except when we are outputting control tokens.
-
-@<Output a control...@>=
-if (a<break_space || a==preproc_line) {
- if (cur_mode==outer) {
- out('\\'); out(a-cancel+'0');
-@.\\1@>
-@.\\2@>
-@.\\3@>
-@.\\4@>
-@.\\8@>
- if (a==opt) {
- b=get_output(); /* |opt| is followed by a digit */
- if (b!='0' || force_lines==false) out(b)@;
- else out_str("{-1}"); /* |force_lines| encourages more \.{@@\v} breaks */
- }
- } else if (a==opt) b=get_output(); /* ignore digit following |opt| */
- }
-else @<Look ahead for strongest line break, |goto reswitch|@>
-
-@ If several of the tokens |break_space|, |force|, |big_force| occur in a
-row, possibly mixed with blank spaces (which are ignored),
-the largest one is used. A line break also occurs in the output file,
-except at the very end of the translation. The very first line break
-is suppressed (i.e., a line break that follows `\.{\\Y\\B}').
-
-@<Look ahead for st...@>= {
- b=a; save_mode=cur_mode; c=0;
- while (true) {
- a=get_output();
- if (a==inserted) continue;
- if (a==cancel || a==big_cancel) {
- @<Output saved |indent| or |outdent| tokens@>@;
- goto reswitch; /* |cancel| overrides everything */
- }
- if ((a!=' ' && a<indent) || a==backup || a>big_force) {
- if (save_mode==outer) {
- if (out_ptr>out_buf+3 && strncmp(out_ptr-3,"\\Y\\B",4)==0)
- goto reswitch;
- @<Output saved |indent| or |outdent| tokens@>@;
- out('\\'); out(b-cancel+'0');
-@.\\5@>
-@.\\6@>
-@.\\7@>
- if (a!=end_translation) finish_line();
- }
- else if (a!=end_translation && cur_mode==inner) out(' ');
- goto reswitch;
- }
- if (a==indent) c++;
- else if (a==outdent) c--;
- else if (a==opt) a=get_output();
- else if (a>b) b=a; /* if |a==' '| we have |a<b| */
- }
-}
-
-@ @<Output saved...@>=
- for (;c>0;c--) out_str("\\1");
-@.\\1@>
- for (;c<0;c++) out_str("\\2");
-@.\\2@>
-
-@ The remaining part of |make_output| is somewhat more complicated. When we
-output a section name, we may need to enter the parsing and translation
-routines, since the name may contain \CEE/ code embedded in
-\pb\ constructions. This \CEE/ code is placed at the end of the active
-input buffer and the translation process uses the end of the active
-|tok_mem| area.
-
-@<Output a section name@>= {
- out_str("\\X");
-@.\\X@>
- cur_xref=(xref_pointer)cur_name->xref;
- if (cur_xref->num==file_flag) {an_output=true; cur_xref=cur_xref->xlink;}
- else an_output=false;
- if (cur_xref->num>=def_flag) {
- out_section(cur_xref->num-def_flag);
- if (phase==3) {
- cur_xref=cur_xref->xlink;
- while (cur_xref->num>=def_flag) {
- out_str(", ");
- out_section(cur_xref->num-def_flag);
- cur_xref=cur_xref->xlink;
- }
- }
- }
- else out('0'); /* output the section number, or zero if it was undefined */
- out(':');
- if (an_output) out_str("\\.{"@q}@>);
-@.\\.@>
- @<Output the text of the section name@>@;
- if (an_output) out_str(@q{@>" }");
- out_str("\\X");
-}
-
-@ @<Output the text...@>=
-sprint_section_name(scratch,cur_name);
-k=scratch;
-k_limit=scratch+strlen(scratch);
-cur_section_name=cur_name;
-while (k<k_limit) {
- b=*(k++);
- if (b=='@@') @<Skip next character, give error if not `\.{@@}'@>@;
- if (an_output)
- switch (b) {
- case ' ':case '\\':case '#':case '%':case '$':case '^':
- case '{': case '}': case '~': case '&': case '_':
- out('\\'); /* falls through */
-@.\\\ @>
-@.\\\\@>
-@.\\\#@>
-@.\\\%@>
-@.\\\$@>
-@.\\\^@>
-@.\\\{@>@q}@>
-@q{@>@.\\\}@>
-@.\\\~@>
-@.\\\&@>
-@.\\\_@>
- default: out(b);
- }
- else { if (b!='|') out(b)@;
- else {
- @<Copy the \CEE/ text into the |buffer| array@>@;
- save_loc=loc; save_limit=limit; loc=limit+2; limit=j+1;
- *limit='|'; output_C();
- loc=save_loc; limit=save_limit;
- } }
-}
-
-@ @<Skip next char...@>=
-if (*k++!='@@') {
- fputs("\n! Illegal control code in section name: <",stdout);
-@.Illegal control code...@>
- print_section_name(cur_section_name); printf("> "); mark_error;
-}
-
-@ The \CEE/ text enclosed in \pb\ should not contain `\.{\v}' characters,
-except within strings. We put a `\.{\v}' at the front of the buffer, so that an
-error message that displays the whole buffer will look a little bit sensible.
-The variable |delim| is zero outside of strings, otherwise it
-equals the delimiter that began the string being copied.
-
-@<Copy the \CEE/ text into...@>=
-j=limit+1; *j='|'; delim=0;
-while (true) {
- if (k>=k_limit) {
- fputs("\n! C text in section name didn't end: <",stdout);
-@.C text...didn't end@>
- print_section_name(cur_section_name); printf("> "); mark_error; break;
- }
- b=*(k++);
- if (b=='@@' || (b=='\\' && delim!=0))
- @<Copy a quoted character into the buffer@>@;
- else {
- if (b=='\'' || b=='"') {
- if (delim==0) delim=b;
- else if (delim==b) delim=0; }
- if (b!='|' || delim!=0) {
- if (j>buffer+long_buf_size-3) overflow("buffer");
- *(++j)=b;
- }
- else break;
- }
-}
-
-@ @<Copy a quoted char...@>= {
- if (j>buffer+long_buf_size-4) overflow("buffer");
- *(++j)=b; *(++j)=*(k++);
-}
-
-@** Phase two processing.
-We have assembled enough pieces of the puzzle in order to be ready to specify
-the processing in \.{CWEAVE}'s main pass over the source file. Phase two
-is analogous to phase one, except that more work is involved because we must
-actually output the \TEX/ material instead of merely looking at the
-\.{CWEB} specifications.
-
-@c
-static void
-phase_two(void) {
-reset_input(); if (show_progress) fputs("\nWriting the output file...",stdout);
-@.Writing the output file...@>
-section_count=0; format_visible=true; copy_limbo();
-finish_line(); flush_buffer(out_buf,false,false); /* insert a blank line, it looks nice */
-while (!input_has_ended) @<Translate the current section@>@;
-}
-
-@ @<Predecl...@>=@+static void phase_two(void);
-
-@ The output file will contain the control sequence \.{\\Y} between non-null
-sections of a section, e.g., between the \TEX/ and definition parts if both
-are nonempty. This puts a little white space between the parts when they are
-printed. However, we don't want \.{\\Y} to occur between two definitions
-within a single section. The variables |out_line| or |out_ptr| will
-change if a section is non-null, so the following macros `|save_position|'
-and `|emit_space_if_needed|' are able to handle the situation:
-
-@d save_position save_line=out_line; save_place=out_ptr
-@d emit_space_if_needed if (save_line!=out_line || save_place!=out_ptr)
- out_str("\\Y");
- space_checked=true;
-@.\\Y@>
-
-@<Private...@>=
-static int save_line; /* former value of |out_line| */
-static char *save_place; /* former value of |out_ptr| */
-static int sec_depth; /* the integer, if any, following \.{@@*} */
-static boolean space_checked; /* have we done |emit_space_if_needed|? */
-static boolean format_visible; /* should the next format declaration be output? */
-static boolean doing_format=false; /* are we outputting a format declaration? */
-static boolean group_found=false; /* has a starred section occurred? */
-
-@ @<Translate the current section@>= {
- section_count++;
- @<Output the code for the beginning of a new section@>@;
- save_position;
- @<Translate the \TEX/ part of the current section@>@;
- @<Translate the definition part of the current section@>@;
- @<Translate the \CEE/ part of the current section@>@;
- @<Show cross-references to this section@>@;
- @<Output the code for the end of a section@>@;
-}
-
-@ Sections beginning with the \.{CWEB} control sequence `\.{@@\ }' start in the
-output with the \TEX/ control sequence `\.{\\M}', followed by the section
-number. Similarly, `\.{@@*}' sections lead to the control sequence `\.{\\N}'.
-In this case there's an additional parameter, representing one plus the
-specified depth, immediately after the \.{\\N}.
-If the section has changed, we put \.{\\*} just after the section number.
-
-@<Output the code for the beginning...@>=
-if (*(loc-1)!='*') out_str("\\M");
-@.\\M@>
-else {
- while (*loc == ' ') loc++;
- if (*loc=='*') { /* ``top'' level */
- sec_depth = -1;
- loc++;
- }
- else {
- for (sec_depth=0; xisdigit(*loc);loc++)
- sec_depth = sec_depth*10 + (*loc) -'0';
- }
- while (*loc == ' ') loc++; /* remove spaces before group title */
- group_found=true;
- out_str("\\N");
-@.\\N@>
- {@+ char s[32];@+sprintf(s,"{%d}",sec_depth+1);@+out_str(s);@+}
- if (show_progress)
- printf("*%d",section_count); update_terminal; /* print a progress report */
-}
-out_str("{");out_section(section_count); out_str("}");
-
-@ In the \TEX/ part of a section, we simply copy the source text, except that
-index entries are not copied and \CEE/ text within \pb\ is translated.
-
-@<Translate the \T...@>= do {
- next_control=copy_TeX();
- switch (next_control) {
- case '|': init_stack; output_C(); break;
- case '@@': out('@@'); break;
- case TeX_string: case noop:
- case xref_roman: case xref_wildcard: case xref_typewriter:
- case section_name: loc-=2; next_control=get_next(); /* skip to \.{@@>} */
- if (next_control==TeX_string)
- err_print("! TeX string should be in C text only"); break;
-@.TeX string should be...@>
- case thin_space: case math_break: case ord:
- case line_break: case big_line_break: case no_line_break: case join:
- case pseudo_semi: case macro_arg_open: case macro_arg_close:
- case output_defs_code:
- err_print("! You can't do that in TeX text"); break;
-@.You can't do that...@>
- }
-} while (next_control<format_code);
-
-@ When we get to the following code we have |next_control>=format_code|, and
-the token memory is in its initial empty state.
-
-@<Translate the d...@>=
-space_checked=false;
-while (next_control<=definition) { /* |format_code| or |definition| */
- init_stack;
- if (next_control==definition) @<Start a macro definition@>@;
- else @<Start a format definition@>@;
- outer_parse(); finish_C(format_visible); format_visible=true;
- doing_format=false;
-}
-
-@ The |finish_C| procedure outputs the translation of the current
-scraps, preceded by the control sequence `\.{\\B}' and followed by the
-control sequence `\.{\\par}'. It also restores the token and scrap
-memories to their initial empty state.
-
-A |force| token is appended to the current scraps before translation
-takes place, so that the translation will normally end with \.{\\6} or
-\.{\\7} (the \TEX/ macros for |force| and |big_force|). This \.{\\6} or
-\.{\\7} is replaced by the concluding \.{\\par} or by \.{\\Y\\par}.
-
-@c
-static void
-finish_C(@t\1\1@> /* finishes a definition or a \CEE/ part */
- boolean visible@t\2\2@>) /* nonzero if we should produce \TeX\ output */
-{
- text_pointer p; /* translation of the scraps */
- if (visible) {
- out_str("\\B"); app_tok(force); app_scrap(insert,no_math);
- p=translate();
-@.\\B@>
- app(tok_flag+(int)(p-tok_start)); make_output(); /* output the list */
- if (out_ptr>out_buf+1) {
- if (*(out_ptr-1)=='\\') {
-@.\\6@>
-@.\\7@>
-@.\\Y@>
- if (*out_ptr=='6') out_ptr-=2;
- else if (*out_ptr=='7') *out_ptr='Y';
- }
- }
- out_str("\\par"); finish_line();
- }
- if (text_ptr>max_text_ptr) max_text_ptr=text_ptr;
- if (tok_ptr>max_tok_ptr) max_tok_ptr=tok_ptr;
- if (scrap_ptr>max_scr_ptr) max_scr_ptr=scrap_ptr;
- tok_ptr=tok_mem+1; text_ptr=tok_start+1; scrap_ptr=scrap_info;
- /* forget the tokens and the scraps */
-}
-
-@ @<Predecl...@>=@+static void finish_C(boolean);
-
-@ Keeping in line with the conventions of the \CEE/ preprocessor (and
-otherwise contrary to the rules of \.{CWEB}) we distinguish here
-between the case that `\.(' immediately follows an identifier and the
-case that the two are separated by a space. In the latter case, and
-if the identifier is not followed by `\.(' at all, the replacement
-text starts immediately after the identifier. In the former case,
-it starts after we scan the matching `\.)'.
-
-@<Start a macro...@>= {
- if (save_line!=out_line || save_place!=out_ptr || space_checked) app(backup);
- if(!space_checked){emit_space_if_needed;save_position;}
- app_str("\\D"); /* this will produce `\&{define }' */
-@.\\D@>
- if ((next_control=get_next())!=identifier)
- err_print("! Improper macro definition");
-@.Improper macro definition@>
- else {
- app('$'); app_cur_id(false);
- if (*loc=='(')
- reswitch: switch (next_control=get_next()) {
- case '(': case ',': app(next_control); goto reswitch;
- case identifier: app_cur_id(false); goto reswitch;
- case ')': app(next_control); next_control=get_next(); break;
- default: err_print("! Improper macro definition"); break;
- }
- else next_control=get_next();
- app_str("$ "); app(break_space);
- app_scrap(dead,no_math); /* scrap won't take part in the parsing */
- }
-}
-
-@ @<Start a format...@>= {
- doing_format=true;
- if(*(loc-1)=='s' || *(loc-1)=='S') format_visible=false;
- if(!space_checked){emit_space_if_needed;save_position;}
- app_str("\\F"); /* this will produce `\&{format }' */
-@.\\F@>
- next_control=get_next();
- if (next_control==identifier) {
- app(id_flag+(int)(id_lookup(id_first, id_loc,normal)-name_dir));
- app(' ');
- app(break_space); /* this is syntactically separate from what follows */
- next_control=get_next();
- if (next_control==identifier) {
- app(id_flag+(int)(id_lookup(id_first, id_loc,normal)-name_dir));
- app_scrap(exp,maybe_math); app_scrap(semi,maybe_math);
- next_control=get_next();
- }
- }
- if (scrap_ptr!=scrap_info+2) err_print("! Improper format definition");
-@.Improper format definition@>
-}
-
-@ Finally, when the \TEX/ and definition parts have been treated, we have
-|next_control>=begin_C|. We will make the global variable |this_section|
-point to the current section name, if it has a name.
-
-@<Private...@>=
-static name_pointer this_section; /* the current section name, or zero */
-
-@ @<Translate the \CEE/...@>=
-this_section=name_dir;
-if (next_control<=section_name) {
- emit_space_if_needed; init_stack;
- if (next_control==begin_C) next_control=get_next();
- else {
- this_section=cur_section;
- @<Check that '=' or '==' follows this section name, and
- emit the scraps to start the section definition@>@;
- }
- while (next_control<=section_name) {
- outer_parse();
- @<Emit the scrap for a section name if present@>@;
- }
- finish_C(true);
-}
-
-@ The title of the section and an $\E$ or $\mathrel+\E$ are made
-into a scrap that should not take part in the parsing.
-
-@<Check that '='...@>=
-do next_control=get_next();
- while (next_control=='+'); /* allow optional `\.{+=}' */
-if (next_control!='=' && next_control!=eq_eq)
- err_print("! You need an = sign after the section name");
-@.You need an = sign...@>
- else next_control=get_next();
-if (out_ptr>out_buf+1 && *out_ptr=='Y' && *(out_ptr-1)=='\\') app(backup);
- /* the section name will be flush left */
-@.\\Y@>
-app(section_flag+(int)(this_section-name_dir));
-cur_xref=(xref_pointer)this_section->xref;
-if(cur_xref->num==file_flag) cur_xref=cur_xref->xlink;
-app_str("${}");
-if (cur_xref->num!=section_count+def_flag) {
- app_str("\\mathrel+"); /* section name is multiply defined */
- this_section=name_dir; /* so we won't give cross-reference info here */
-}
-app_str("\\E"); /* output an equivalence sign */
-@.\\E@>
-app_str("{}$");
-app(force); app_scrap(dead,no_math);
- /* this forces a line break unless `\.{@@+}' follows */
-
-@ @<Emit the scrap...@>=
-if (next_control<section_name) {
- err_print("! You can't do that in C text");
-@.You can't do that...@>
- next_control=get_next();
-}
-else if (next_control==section_name) {
- app(section_flag+(int)(cur_section-name_dir));
- app_scrap(section_scrap,maybe_math);
- next_control=get_next();
-}
-
-@ Cross references relating to a named section are given
-after the section ends.
-
-@<Show cross...@>=
-if (this_section>name_dir) {
- cur_xref=(xref_pointer)this_section->xref;
- if (cur_xref->num==file_flag){an_output=true;cur_xref=cur_xref->xlink;}
- else an_output=false;
- if (cur_xref->num>def_flag)
- cur_xref=cur_xref->xlink; /* bypass current section number */
- footnote(def_flag); footnote(cite_flag); footnote(0);
-}
-
-@ The |footnote| procedure gives cross-reference information about
-multiply defined section names (if the |flag| parameter is
-|def_flag|), or about references to a section name
-(if |flag==cite_flag|), or to its uses (if |flag==0|). It assumes that
-|cur_xref| points to the first cross-reference entry of interest, and it
-leaves |cur_xref| pointing to the first element not printed. Typical outputs:
-`\.{\\A101.}'; `\.{\\Us 370\\ET1009.}';
-`\.{\\As 8, 27\\*\\ETs64.}'.
-
-Note that the output of \.{CWEAVE} is not English-specific; users may
-supply new definitions for the macros \.{\\A}, \.{\\As}, etc.
-
-@c
-static void
-footnote(@t\1\1@> /* outputs section cross-references */
-sixteen_bits flag@t\2\2@>)
-{
- xref_pointer q; /* cross-reference pointer variable */
- if (cur_xref->num<=flag) return;
- finish_line(); out('\\');
-@.\\A@>
-@.\\Q@>
-@.\\U@>
- out(flag==0? 'U': flag==cite_flag? 'Q': 'A');
- @<Output all the section numbers on the reference list |cur_xref|@>@;
- out('.');
-}
-
-@ @<Predecl...@>=@+static void footnote(sixteen_bits);
-
-@ The following code distinguishes three cases, according as the number
-of cross-references is one, two, or more than two. Variable |q| points
-to the first cross-reference, and the last link is a zero.
-
-@<Output all the section numbers...@>=
-q=cur_xref; if (q->xlink->num>flag) out('s'); /* plural */
-while (true) {
- out_section(cur_xref->num-flag);
- cur_xref=cur_xref->xlink; /* point to the next cross-reference to output */
- if (cur_xref->num<=flag) break;
- if (cur_xref->xlink->num>flag) out_str(", "); /* not the last */
- else {out_str("\\ET"); /* the last */
-@.\\ET@>
- if (cur_xref != q->xlink) out('s'); /* the last of more than two */
- }
-}
-
-@ @<Output the code for the end of a section@>=
-out_str("\\fi"); finish_line();
-@.\\fi@>
-flush_buffer(out_buf,false,false); /* insert a blank line, it looks nice */
-
-@** Phase three processing.
-We are nearly finished! \.{CWEAVE}'s only remaining task is to write out the
-index, after sorting the identifiers and index entries.
-
-If the user has set the |no_xref| flag (the \.{-x} option on the command line),
-just finish off the page, omitting the index, section name list, and table of
-contents.
-
-@c
-static void
-phase_three(void) {
-if (no_xref) {
- finish_line();
- out_str("\\end");
-@.\\end@>
- finish_line();
-}
-else {
- phase=3; if (show_progress) fputs("\nWriting the index...",stdout);
-@.Writing the index...@>
- finish_line();
- if ((idx_file=fopen(idx_file_name,"wb"))==NULL)
- fatal("! Cannot open index file ",idx_file_name);
-@.Cannot open index file@>
- if (change_exists) {
- @<Tell about changed sections@>@; finish_line(); finish_line();
- }
- out_str("\\inx"); finish_line();
-@.\\inx@>
- active_file=idx_file; /* change active file to the index file */
- @<Do the first pass of sorting@>@;
- @<Sort and output the index@>@;
- finish_line(); fclose(active_file); /* finished with |idx_file| */
- active_file=tex_file; /* switch back to |tex_file| for a tic */
- out_str("\\fin"); finish_line();
-@.\\fin@>
- if ((scn_file=fopen(scn_file_name,"wb"))==NULL)
- fatal("! Cannot open section file ",scn_file_name);
-@.Cannot open section file@>
- active_file=scn_file; /* change active file to section listing file */
- @<Output all the section names@>@;
- finish_line(); fclose(active_file); /* finished with |scn_file| */
- active_file=tex_file;
- if (group_found) out_str("\\con");@+else out_str("\\end");
-@.\\con@>
-@.\\end@>
- finish_line();
- fclose(active_file);
-}
-if (show_happiness) {
- if (show_progress) new_line;
- fputs("Done.",stdout);
-}
-check_complete(); /* was all of the change file used? */
-}
-
-@ @<Predecl...@>=@+static void phase_three(void);
-
-@ Just before the index comes a list of all the changed sections, including
-the index section itself.
-
-@<Private...@>=
-static sixteen_bits k_section; /* runs through the sections */
-
-@ @<Tell about changed sections@>= {
- /* remember that the index is already marked as changed */
- k_section=0;
- while (!changed_section[++k_section]);
- out_str("\\ch ");
-@.\\ch@>
- out_section(k_section);
- while (k_section<section_count) {
- while (!changed_section[++k_section]);
- out_str(", "); out_section(k_section);
- }
- out('.');
-}
-
-@ A left-to-right radix sorting method is used, since this makes it easy to
-adjust the collating sequence and since the running time will be at worst
-proportional to the total length of all entries in the index. We put the
-identifiers into different lists based on their first characters.
-(Uppercase letters are put into the same list as the corresponding lowercase
-letters, since we want to have `$t<\\{TeX}<\&{to}$'.) The
-list for character |c| begins at location |bucket[c]| and continues through
-the |blink| array.
-
-@<Private...@>=
-static name_pointer bucket[256];
-static name_pointer next_name; /* successor of |cur_name| when sorting */
-static name_pointer blink[max_names]; /* links in the buckets */
-
-@ To begin the sorting, we go through all the hash lists and put each entry
-having a nonempty cross-reference list into the proper bucket.
-
-@<Do the first pass...@>= {
-int c;
-for (c=0; c<256; c++) bucket[c]=NULL;
-for (h=hash; h<=hash_end; h++) {
- next_name=*h;
- while (next_name) {
- cur_name=next_name; next_name=cur_name->link;
- if (cur_name->xref!=(void *)xmem) {
- c=(eight_bits)((cur_name->byte_start)[0]);
- if (xisupper(c)) c=tolower(c);
- blink[cur_name-name_dir]=bucket[c]; bucket[c]=cur_name;
- }
- }
-}
-}
-
-@ During the sorting phase we shall use the |cat| and |trans| arrays from
-\.{CWEAVE}'s parsing algorithm and rename them |depth| and |head|. They now
-represent a stack of identifier lists for all the index entries that have
-not yet been output. The variable |sort_ptr| tells how many such lists are
-present; the lists are output in reverse order (first |sort_ptr|, then
-|sort_ptr-1|, etc.). The |j|th list starts at |head[j]|, and if the first
-|k| characters of all entries on this list are known to be equal we have
-|depth[j]==k|.
-
-@<Rest of |trans_plus| union@>=
-name_pointer Head;
-
-@ @d depth cat /* reclaims memory that is no longer needed for parsing */
-@d head trans_plus.Head /* ditto */
-@f sort_pointer int
-@d sort_pointer scrap_pointer /* ditto */
-@d sort_ptr scrap_ptr /* ditto */
-@d max_sorts max_scraps /* ditto */
-
-@<Private...@>=
-static eight_bits cur_depth; /* depth of current buckets */
-static char *cur_byte; /* index into |byte_mem| */
-static sixteen_bits cur_val; /* current cross-reference number */
-static sort_pointer max_sort_ptr; /* largest value of |sort_ptr| */
-
-@ @<Set init...@>=
-max_sort_ptr=scrap_info;
-
-@ The desired alphabetic order is specified by the |collate| array; namely,
-$|collate|[0]<|collate|[1]<\cdots<|collate|[100]$.
-
-@<Private...@>=
-static eight_bits collate[101+128]; /* collation order */
-@^high-bit character handling@>
-
-@ We use the order $\hbox{null}<\.\ <\hbox{other characters}<{}$\.\_${}<
-\.A=\.a<\cdots<\.Z=\.z<\.0<\cdots<\.9.$ Warning: The collation mapping
-needs to be changed if ASCII code is not being used.
-@^ASCII code dependencies@>
-@^high-bit character handling@>
-
-We initialize |collate| by copying a few characters at a time, because
-some \CEE/ compilers choke on long strings.
-
-@<Set init...@>=
-collate[0]=0;
-memcpy((char *)collate+1,
- " \1\2\3\4\5\6\7\10\11\12\13\14\15\16\17",16);
-/* 16 characters + 1 = 17 */
-memcpy((char *)collate+17,
- "\20\21\22\23\24\25\26\27\30\31\32\33\34\35\36\37",16);
-/* 16 characters + 17 = 33 */
-memcpy((char *)collate+33,
- "!\42#$%&'()*+,-./:;<=>?@@[\\]^`{|}~_",32);
-/* 32 characters + 33 = 65 */
-memcpy((char *)collate+65,
- "abcdefghijklmnopqrstuvwxyz0123456789",36);
-/* (26 + 10) characters + 65 = 101 */
-memcpy((char *)collate+101,
- "\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217",16);
-/* 16 characters + 101 = 117 */
-memcpy((char *)collate+117,
- "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237",16);
-/* 16 characters + 117 = 133 */
-memcpy((char *)collate+133,
- "\240\241\242\243\244\245\246\247\250\251\252\253\254\255\256\257",16);
-/* 16 characters + 133 = 149 */
-memcpy((char *)collate+149,
- "\260\261\262\263\264\265\266\267\270\271\272\273\274\275\276\277",16);
-/* 16 characters + 149 = 165 */
-memcpy((char *)collate+165,
- "\300\301\302\303\304\305\306\307\310\311\312\313\314\315\316\317",16);
-/* 16 characters + 165 = 181 */
-memcpy((char *)collate+181,
- "\320\321\322\323\324\325\326\327\330\331\332\333\334\335\336\337",16);
-/* 16 characters + 181 = 197 */
-memcpy((char *)collate+197,
- "\340\341\342\343\344\345\346\347\350\351\352\353\354\355\356\357",16);
-/* 16 characters + 197 = 213 */
-memcpy((char *)collate+213,
- "\360\361\362\363\364\365\366\367\370\371\372\373\374\375\376\377",16);
-/* 16 characters + 213 = 229 */
-
-@ Procedure |unbucket| goes through the buckets and adds nonempty lists
-to the stack, using the collating sequence specified in the |collate| array.
-The parameter to |unbucket| tells the current depth in the buckets.
-Any two sequences that agree in their first 255 character positions are
-regarded as identical.
-
-@d infinity 255 /* $\infty$ (approximately) */
-
-@c
-static void
-unbucket(@t\1\1@> /* empties buckets having depth |d| */
-eight_bits d@t\2\2@>)
-{
- int c; /* index into |bucket|; cannot be a simple |char| because of sign
- comparison below */
- for (c=100+128; c>= 0; c--) if (bucket[collate[c]]) {
-@^high-bit character handling@>
- if (sort_ptr>=scrap_info_end) overflow("sorting");
- sort_ptr++;
- if (sort_ptr>max_sort_ptr) max_sort_ptr=sort_ptr;
- if (c==0) sort_ptr->depth=infinity;
- else sort_ptr->depth=d;
- sort_ptr->head=bucket[collate[c]]; bucket[collate[c]]=NULL;
- }
-}
-
-@ @<Predecl...@>=@+static void unbucket(eight_bits);
-
-@ @<Sort and output...@>=
-sort_ptr=scrap_info; unbucket(1);
-while (sort_ptr>scrap_info) {
- cur_depth=sort_ptr->depth;
- if (blink[sort_ptr->head-name_dir]==0 || cur_depth==infinity)
- @<Output index entries for the list at |sort_ptr|@>@;
- else @<Split the list at |sort_ptr| into further lists@>@;
-}
-
-@ @<Split the list...@>= {
- eight_bits c;
- next_name=sort_ptr->head;
- do {
- cur_name=next_name; next_name=blink[cur_name-name_dir];
- cur_byte=cur_name->byte_start+cur_depth;
- if (cur_byte==(cur_name+1)->byte_start) c=0; /* hit end of the name */
- else {
- c=(eight_bits) *cur_byte;
- if (xisupper(c)) c=tolower(c);
- }
- blink[cur_name-name_dir]=bucket[c]; bucket[c]=cur_name;
- } while (next_name);
- --sort_ptr; unbucket(cur_depth+1);
-}
-
-@ @<Output index...@>= {
- cur_name=sort_ptr->head;
- do {
- out_str("\\I");
-@.\\I@>
- @<Output the name at |cur_name|@>@;
- @<Output the cross-references at |cur_name|@>@;
- cur_name=blink[cur_name-name_dir];
- } while (cur_name);
- --sort_ptr;
-}
-
-@ @<Output the name...@>=
-switch (cur_name->ilk) {
- case normal: case func_template: if (is_tiny(cur_name)) 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 wildcard: out_str("\\9");@+ goto not_an_identifier;
-@.\\9@>
- case typewriter: out_str("\\.");
-@.\\.@>
- case roman: not_an_identifier: out_name(cur_name,false); goto name_done;
- 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:@;
-
-@ Section numbers that are to be underlined are enclosed in
-`\.{\\[}$\,\ldots\,$\.]'.
-
-@<Output the cross-references...@>=
-@<Invert the cross-reference list at |cur_name|, making |cur_xref| the head@>@;
-do {
- out_str(", "); cur_val=cur_xref->num;
- if (cur_val<def_flag) out_section(cur_val);
- else {out_str("\\["); out_section(cur_val-def_flag); out(']');}
-@.\\[@>
- cur_xref=cur_xref->xlink;
-} while (cur_xref!=xmem);
-out('.'); finish_line();
-
-@ List inversion is best thought of as popping elements off one stack and
-pushing them onto another. In this case |cur_xref| will be the head of
-the stack that we push things onto.
-@<Private...@>=
-static xref_pointer next_xref, this_xref;
- /* pointer variables for rearranging a list */
-
-@ @<Invert the cross-reference list at |cur_name|, making |cur_xref| the head@>=
-this_xref=(xref_pointer)cur_name->xref; cur_xref=xmem;
-do {
- next_xref=this_xref->xlink; this_xref->xlink=cur_xref;
- cur_xref=this_xref; this_xref=next_xref;
-} while (this_xref!=xmem);
-
-@ The following recursive procedure walks through the tree of section names and
-prints them.
-@^recursion@>
-
-@c
-static void
-section_print(@t\1\1@> /* print all section names in subtree |p| */
-name_pointer p@t\2\2@>)
-{
- if (p) {
- section_print(p->llink); out_str("\\I");
-@.\\I@>
- tok_ptr=tok_mem+1; text_ptr=tok_start+1; scrap_ptr=scrap_info; init_stack;
- app(p-name_dir+section_flag); make_output();
- footnote(cite_flag);
- footnote(0); /* |cur_xref| was set by |make_output| */
- finish_line();@/
- section_print(p->rlink);
- }
-}
-
-@ @<Predecl...@>=@+static void section_print(name_pointer);
-
-@ @<Output all the section names@>=section_print(root);
-
-@ Because on some systems the difference between two pointers is a |ptrdiff_t|
-rather than an |int|, we use \.{\%ld} to print these quantities.
-
-@c
-void
-print_stats(void) {
- puts("\nMemory usage statistics:");
-@.Memory usage statistics:@>
- printf("%ld names (out of %ld)\n",
- (ptrdiff_t)(name_ptr-name_dir),(long)max_names);
- printf("%ld cross-references (out of %ld)\n",
- (ptrdiff_t)(xref_ptr-xmem),(long)max_refs);
- printf("%ld bytes (out of %ld)\n",
- (ptrdiff_t)(byte_ptr-byte_mem),(long)max_bytes);
- puts("Parsing:");
- printf("%ld scraps (out of %ld)\n",
- (ptrdiff_t)(max_scr_ptr-scrap_info),(long)max_scraps);
- printf("%ld texts (out of %ld)\n",
- (ptrdiff_t)(max_text_ptr-tok_start),(long)max_texts);
- printf("%ld tokens (out of %ld)\n",
- (ptrdiff_t)(max_tok_ptr-tok_mem),(long)max_toks);
- printf("%ld levels (out of %ld)\n",
- (ptrdiff_t)(max_stack_ptr-stack),(long)stack_size);
- puts("Sorting:");
- printf("%ld levels (out of %ld)\n",
- (ptrdiff_t)(max_sort_ptr-scrap_info),(long)max_scraps);
-}
-
-@** Index.
-If you have read and understood the code for Phase III above, you know what
-is in this index and how it got here. All sections in which an identifier is
-used are listed with that identifier, except that reserved words are
-indexed only when they appear in format definitions, and the appearances
-of identifiers in section names are not indexed. Underlined entries
-correspond to where the identifier was declared. Error messages, control
-sequences put into the output, and a few
-other things like ``recursion'' are indexed here too.