diff options
author | Denis Bitouzé <dbitouze@wanadoo.fr> | 2021-02-25 18:23:07 +0000 |
---|---|---|
committer | Denis Bitouzé <dbitouze@wanadoo.fr> | 2021-02-25 18:23:07 +0000 |
commit | c6101f91d071883b48b1b4b51e5eba0f36d9a78d (patch) | |
tree | 1bf7f5a881d7a4f5c5bf59d0b2821943dd822372 /Build/source/texk/web2c/cwebdir/cweave.w | |
parent | 07ee7222e389b0777456b427a55c22d0e6ffd267 (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.w | 4696 |
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. |