summaryrefslogtreecommitdiff
path: root/Build/source/texk/web2c/cwebdir/ctangle.w
diff options
context:
space:
mode:
Diffstat (limited to 'Build/source/texk/web2c/cwebdir/ctangle.w')
-rw-r--r--Build/source/texk/web2c/cwebdir/ctangle.w1543
1 files changed, 0 insertions, 1543 deletions
diff --git a/Build/source/texk/web2c/cwebdir/ctangle.w b/Build/source/texk/web2c/cwebdir/ctangle.w
deleted file mode 100644
index e7e2d311fe5..00000000000
--- a/Build/source/texk/web2c/cwebdir/ctangle.w
+++ /dev/null
@@ -1,1543 +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 'ctangle.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
-\mathchardef\RA="3221 % right arrow
-\mathchardef\BA="3224 % double arrow
-
-\def\title{CTANGLE (Version 4.2)}
-\def\topofcontents{\null\vfill
- \centerline{\titlefont The {\ttitlefont CTANGLE} 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 \.{CTANGLE} program by Silvio Levy and Donald E. Knuth,
-based on \.{TANGLE} by Knuth.
-We are thankful to
-Nelson Beebe, Hans-Hermann Bode (to whom the \CPLUSPLUS/ adaptation is due),
-Klaus Guntermann, Norman Ramsey, Tomas Rokicki, Joachim Schnitter,
-Joachim Schrod, Lee Wittenberg, and others who have contributed improvements.
-
-The ``banner line'' defined here should be changed whenever \.{CTANGLE}
-is modified.
-
-@d banner "This is CTANGLE (Version 4.2)"
-
-@c
-@<Include files@>@/
-@h
-@<Common code for \.{CWEAVE} and \.{CTANGLE}@>@/
-@<Typedef declarations@>@/
-@<Private variables@>@/
-@<Predeclaration of procedures@>
-
-@ \.{CTANGLE} has a fairly straightforward outline. It operates in
-two phases: First it reads the source file, saving the \CEE/ code in
-compressed form; then it shuffles and outputs the code.
-
-Please read the documentation for \.{common}, the set of routines common
-to \.{CTANGLE} and \.{CWEAVE}, before proceeding further.
-
-@c
-int main (
-int ac,
-char **av)
-{
- argc=ac; argv=av;
- program=ctangle;
- @<Set initial values@>@;
- common_init();
- if (show_banner) puts(banner); /* print a ``banner line'' */
- phase_one(); /* read all the user's text and compress it into |tok_mem| */
- phase_two(); /* output the contents of the compressed tables */
- 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
-
-@* Data structures exclusive to {\tt CTANGLE}.
-We've already seen that the |byte_mem| array holds the names of identifiers,
-strings, and sections;
-the |tok_mem| array holds the replacement texts
-for sections. Allocation is sequential, since things are deleted only
-during Phase II, and only in a last-in-first-out manner.
-
-A \&{text} variable is a structure containing a pointer into
-|tok_mem|, which tells where the corresponding text starts, and an
-integer |text_link|, which, as we shall see later, is used to connect
-pieces of text that have the same name. All the \&{text}s are stored in
-the array |text_info|, and we use a \&{text\_pointer} variable to refer
-to them.
-
-The first position of |tok_mem| that is unoccupied by
-replacement text is called |tok_ptr|, and the first unused location of
-|text_info| is called |text_ptr|. Thus we usually have the identity
-|text_ptr->tok_start==tok_ptr|.
-
-@<Typed...@>=
-typedef struct {
- eight_bits *tok_start; /* pointer into |tok_mem| */
- sixteen_bits text_link; /* relates replacement texts */
-} text;
-typedef text *text_pointer;
-
-@ @<Private...@>=
-static text text_info[max_texts];
-static text_pointer text_info_end=text_info+max_texts-1;
-static text_pointer text_ptr; /* first unused position in |text_info| */
-static eight_bits tok_mem[max_toks];
-static eight_bits *tok_mem_end=tok_mem+max_toks-1;
-static eight_bits *tok_ptr; /* first unused position in |tok_mem| */
-
-@ @<Set init...@>=
-text_info->tok_start=tok_ptr=tok_mem;
-text_ptr=text_info+1; text_ptr->tok_start=tok_mem;
- /* this makes replacement text 0 of length zero */
-
-@ If |p| is a pointer to a section name, |p->equiv| is a pointer to its
-replacement text, an element of the array |text_info|.
-
-@d equiv equiv_or_xref /* info corresponding to names */
-
-@ @<Set init...@>=
-init_node(name_dir); /* the undefined section has no replacement text */
-
-@ Here's the procedure that decides whether a name of length |l|
-starting at position |first| equals the identifier pointed to by |p|:
-
-@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@>) /* not used by \.{TANGLE} */
-{@+(void)t;
- if (length(p)!=l) return false;
- return !strncmp(first,p->byte_start,l);
-}
-
-@ The common lookup routine refers to separate routines |init_node| and
-|init_p| when the data structure grows. Actually |init_p| is called only by
-\.{CWEAVE}, but we need to declare a dummy version so that
-the loader won't complain of its absence.
-
-@c
-void
-init_node(
-name_pointer node)
-{
- node->equiv=(void *)text_info;
-}
-void
-init_p(name_pointer p,eight_bits t) {@+(void)p;@+(void)t;@+}
-
-@* Tokens.
-Replacement texts, which represent \CEE/ code in a compressed format,
-appear in |tok_mem| as mentioned above. The codes in
-these texts are called `tokens'; some tokens occupy two consecutive
-eight-bit byte positions, and the others take just one byte.
-
-If $p$ points to a replacement text, |p->tok_start| is the |tok_mem| position
-of the first eight-bit code of that text. If |p->text_link==0|,
-this is the replacement text for a macro, otherwise it is the replacement
-text for a section. In the latter case |p->text_link| is either equal to
-|section_flag|, which means that there is no further text for this section, or
-|p->text_link| points to a continuation of this replacement text; such
-links are created when several sections have \CEE/ texts with the same
-name, and they also tie together all the \CEE/ texts of unnamed sections.
-The replacement text pointer for the first unnamed section appears in
-|text_info->text_link|, and the most recent such pointer is |last_unnamed|.
-
-@d section_flag max_texts /* final |text_link| in section replacement texts */
-
-@<Private...@>=
-static text_pointer last_unnamed; /* most recent replacement text of unnamed section */
-
-@ @<Set init...@>= last_unnamed=text_info; text_info->text_link=0;
-
-@ If the first byte of a token is less than |0200|, the token occupies a
-single byte. Otherwise we make a sixteen-bit token by combining two consecutive
-bytes |a| and |b|. If |0200<=a<0250|, then |(a-0200)@t${}\times2^8$@>+b|
-points to an identifier; if |0250<=a<0320|, then
-|(a-0250)@t${}\times2^8$@>+b| points to a section name
-(or, if it has the special value |output_defs_flag|,
-to the area where the preprocessor definitions are stored); and if
-|0320<=a<0400|, then |(a-0320)@t${}\times2^8$@>+b| is the number of the section
-in which the current replacement text appears.
-
-Codes less than |0200| are 7-bit |char| codes that represent themselves.
-Some of the 7-bit codes will not be present, however, so we can
-use them for special purposes. The following symbolic names are used:
-
-\yskip \hang |join| denotes the concatenation of adjacent items with no
-space or line breaks allowed between them (the \.{@@\&} operation of \.{CWEB}).
-
-\hang |string| denotes the beginning or end of a string, verbatim
-construction or numerical constant.
-@^ASCII code dependencies@>
-
-@d string 02 /* takes the place of extended ASCII \.{\char2} */
-@d join 0177 /* takes the place of ASCII delete */
-@d output_defs_flag (2*024000-1)
-
-@ The following procedure is used to enter a two-byte value into
-|tok_mem| when a replacement text is being generated.
-
-@c
-static void
-store_two_bytes(
-sixteen_bits x)
-{
- if (tok_ptr+2>tok_mem_end) overflow("token");
- *tok_ptr++=x>>8; /* store high byte */
- *tok_ptr++=x&0377; /* store low byte */
-}
-
-@ @<Predecl...@>=@+static void store_two_bytes(sixteen_bits);
-
-@** Stacks for output. The output process uses a stack to keep track
-of what is going on at different ``levels'' as the sections are being
-written out. Entries on this stack have five parts:
-
-\yskip\hang |end_field| is the |tok_mem| location where the replacement
-text of a particular level will end;
-
-\hang |byte_field| is the |tok_mem| location from which the next token
-on a particular level will be read;
-
-\hang |name_field| points to the name corresponding to a particular level;
-
-\hang |repl_field| points to the replacement text currently being read
-at a particular level;
-
-\hang |section_field| is the section number, or zero if this is a macro.
-
-\yskip\noindent The current values of these five 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_byte|,
-|cur_name|, |cur_repl|, and |cur_section|.
-
-The global variable |stack_ptr| tells how many levels of output are
-currently in progress. The end of all output occurs when the stack is
-empty, i.e., when |stack_ptr==stack|.
-
-@<Typed...@>=
-typedef struct {
- eight_bits *end_field; /* ending location of replacement text */
- eight_bits *byte_field; /* present location within replacement text */
- name_pointer name_field; /* |byte_start| index for text being output */
- text_pointer repl_field; /* |tok_start| index for text being output */
- sixteen_bits section_field; /* section number or zero if not a section */
-} output_state;
-typedef output_state *stack_pointer;
-
-@ @d cur_end cur_state.end_field /* current ending location in |tok_mem| */
-@d cur_byte cur_state.byte_field /* location of next output byte in |tok_mem|*/
-@d cur_name cur_state.name_field /* pointer to current name being expanded */
-@d cur_repl cur_state.repl_field /* pointer to current replacement text */
-@d cur_section cur_state.section_field /* current section number being expanded */
-
-@<Private...@>=
-static output_state cur_state; /* |cur_end|, |cur_byte|, |cur_name|, |cur_repl|,
- and |cur_section| */
-static output_state stack[stack_size+1]; /* info for non-current levels */
-static stack_pointer stack_end=stack+stack_size; /* end of |stack| */
-static stack_pointer stack_ptr; /* first unused location in the output state stack */
-
-@ To get the output process started, we will perform the following
-initialization steps. We may assume that |text_info->text_link| is nonzero,
-since it points to the \CEE/ text in the first unnamed section that generates
-code; if there are no such sections, there is nothing to output, and an
-error message will have been generated before we do any of the initialization.
-
-@<Initialize the output stacks@>=
-stack_ptr=stack+1; cur_name=name_dir; cur_repl=text_info->text_link+text_info;
-cur_byte=cur_repl->tok_start; cur_end=(cur_repl+1)->tok_start; cur_section=0;
-
-@ When the replacement text for name |p| is to be inserted into the output,
-the following subroutine is called to save the old level of output and get
-the new one going.
-
-We assume that the \CEE/ compiler can copy structures.
-@^system dependencies@>
-
-@c
-static void
-push_level(@t\1\1@> /* suspends the current level */
-name_pointer p@t\2\2@>)
-{
- if (stack_ptr==stack_end) overflow("stack");
- *stack_ptr=cur_state;
- stack_ptr++;
- if (p!=NULL) { /* |p==NULL| means we are in |output_defs| */
- cur_name=p; cur_repl=(text_pointer)p->equiv;
- cur_byte=cur_repl->tok_start; cur_end=(cur_repl+1)->tok_start;
- cur_section=0;
- }
-}
-
-@ @<Predecl...@>=
-static void push_level(name_pointer);@/
-static void pop_level(boolean);
-
-@ When we come to the end of a replacement text, the |pop_level| subroutine
-does the right thing: It either moves to the continuation of this replacement
-text or returns the state to the most recently stacked level.
-
-@c
-static void
-pop_level(@t\1\1@> /* do this when |cur_byte| reaches |cur_end| */
-boolean flag@t\2\2@>) /* |flag==false| means we are in |output_defs| */
-{
- if (flag && cur_repl->text_link<section_flag) { /* link to a continuation */
- cur_repl=cur_repl->text_link+text_info; /* stay on the same level */
- cur_byte=cur_repl->tok_start; cur_end=(cur_repl+1)->tok_start;
- return;
- }
- stack_ptr--; /* go down to the previous level */
- if (stack_ptr>stack) cur_state=*stack_ptr;
-}
-
-@ The heart of the output procedure is the function |get_output|,
-which produces the next token of output and sends it on to the lower-level
-function |out_char|. The main purpose of |get_output| is to handle the
-necessary stacking and unstacking. It sends the value |section_number|
-if the next output begins or ends the replacement text of some section,
-in which case |cur_val| is that section's number (if beginning) or the
-negative of that value (if ending). (A section number of 0 indicates
-not the beginning or ending of a section, but a \&{\#line} command.)
-And it sends the value |identifier|
-if the next output is an identifier, in which case
-|cur_val| points to that identifier name.
-
-@d section_number 0201 /* code returned by |get_output| for section numbers */
-@d identifier 0202 /* code returned by |get_output| for identifiers */
-
-@<Private...@>=
-static int cur_val; /* additional information corresponding to output token */
-
-@ If |get_output| finds that no more output remains, it returns with
-|stack_ptr==stack|.
-@^high-bit character handling@>
-
-@c
-static void
-get_output(void) /* sends next token to |out_char| */
-{
- sixteen_bits a; /* value of current byte */
- restart: if (stack_ptr==stack) return;
- if (cur_byte==cur_end) {
- cur_val=-((int)cur_section); /* cast needed because of sign extension */
- pop_level(true);
- if (cur_val==0) goto restart;
- out_char(section_number); return;
- }
- a=*cur_byte++;
- if (out_state==verbatim && a!=string && a!=constant && a!='\n')
- C_putc(a); /* a high-bit character can occur in a string */
- else if (a<0200) out_char(a); /* one-byte token */
- else {
- a=(a-0200)*0400+*cur_byte++;
- switch (a/024000) { /* |024000==(0250-0200)*0400| */
- case 0: cur_val=a; out_char(identifier); break;
- case 1: if (a==output_defs_flag) output_defs();
- else @<Expand section |a-024000|, |goto restart|@>@;
- break;
- default: cur_val=a-050000; if (cur_val>0) cur_section=cur_val;
- out_char(section_number);
- }
- }
-}
-
-@ @<Predecl...@>=@+static void get_output(void);
-
-@ The user may have forgotten to give any \CEE/ text for a section name,
-or the \CEE/ text may have been associated with a different name by mistake.
-
-@<Expand section |a-...@>=
-{
- a-=024000;
- if ((a+name_dir)->equiv!=(void *)text_info) push_level(a+name_dir);
- else if (a!=0) {
- fputs("\n! Not present: <",stdout);
- print_section_name(a+name_dir); err_print(">");
-@.Not present: <section name>@>
- }
- goto restart;
-}
-
-@* Producing the output.
-The |get_output| routine above handles most of the complexity of output
-generation, but there are two further considerations that have a nontrivial
-effect on \.{CTANGLE}'s algorithms.
-
-@ First,
-we want to make sure that the output has spaces and line breaks in
-the right places (e.g., not in the middle of a string or a constant or an
-identifier, not at a `\.{@@\&}' position
-where quantities are being joined together, and certainly after an \.=
-because the \CEE/ compiler thinks \.{=-} is ambiguous).
-
-The output process can be in one of following states:
-
-\yskip\hang |num_or_id| means that the last item in the buffer is a number or
-identifier, hence a blank space or line break must be inserted if the next
-item is also a number or identifier.
-
-\yskip\hang |unbreakable| means that the last item in the buffer was followed
-by the \.{@@\&} operation that inhibits spaces between it and the next item.
-
-\yskip\hang |verbatim| means we're copying only character tokens, and
-that they are to be output exactly as stored. This is the case during
-strings, verbatim constructions and numerical constants.
-
-\yskip\hang |post_slash| means we've just output a slash.
-
-\yskip\hang |normal| means none of the above.
-
-\yskip\noindent Furthermore, if the variable |protect| is |true|, newlines
-are preceded by a `\.\\'.
-
-@d normal 0 /* non-unusual state */
-@d num_or_id 1 /* state associated with numbers and identifiers */
-@d post_slash 2 /* state following a \./ */
-@d unbreakable 3 /* state associated with \.{@@\&} */
-@d verbatim 4 /* state in the middle of a string */
-
-@<Private...@>=
-static eight_bits out_state; /* current status of partial output */
-static boolean protect; /* should newline characters be quoted? */
-
-@ Here is a routine that is invoked when we want to output the current line.
-During the output process, |cur_line| equals the number of the next line
-to be output.
-
-@c
-static void
-flush_buffer(void) /* writes one line to output file */
-{
- C_putc('\n');
- if (cur_line % 100 == 0 && show_progress) {
- printf(".");
- if (cur_line % 500 == 0) printf("%d",cur_line);
- update_terminal; /* progress report */
- }
- cur_line++;
-}
-
-@ @<Predecl...@>=@+static void flush_buffer(void);
-
-@ Second, we have modified the original \.{TANGLE} so that it will write output
-on multiple files.
-If a section name is introduced in at least one place by \.{@@(}
-instead of \.{@@<}, we treat it as the name of a file.
-All these special sections are saved on a stack, |output_files|.
-We write them out after we've done the unnamed section.
-
-@d max_files 256
-@<Private...@>=
-static name_pointer output_files[max_files];
-static name_pointer *cur_out_file, *end_output_files, *an_output_file;
-static char cur_section_name_char; /* is it |'<'| or |'('| */
-static char output_file_name[longest_name+1]; /* name of the file */
-
-@ We make |end_output_files| point just beyond the end of
-|output_files|. The stack pointer
-|cur_out_file| starts out there. Every time we see a new file, we
-decrement |cur_out_file| and then write it in.
-@<Set initial...@>=
-cur_out_file=end_output_files=output_files+max_files;
-
-@ @<If it's not there, add |cur_section_name| to the output file stack, or
-complain we're out of room@>=
-{
- for (an_output_file=cur_out_file;
- an_output_file<end_output_files; an_output_file++)
- if (*an_output_file==cur_section_name) break;
- if (an_output_file==end_output_files) {
- if (cur_out_file>output_files)
- *--cur_out_file=cur_section_name;
- else {
- overflow("output files");
- }
- }
-}
-
-@* The big output switch. Here then is the routine that does the
-output.
-
-@c
-static void
-phase_two (void) {
- web_file_open=false;
- cur_line=1;
- @<Initialize the output stacks@>@;
- @<Output macro definitions if appropriate@>@;
- if (text_info->text_link==0 && cur_out_file==end_output_files) {
- fputs("\n! No program text was specified.",stdout); mark_harmless;
-@.No program text...@>
- }
- else {
- if(cur_out_file==end_output_files) {
- if(show_progress)
- printf("\nWriting the output file (%s):",C_file_name);
- }
- else {
- if (show_progress) {
- fputs("\nWriting the output files:",stdout);
-@.Writing the output...@>
- printf(" (%s)",C_file_name);
- update_terminal;
- }
- if (text_info->text_link==0) goto writeloop;
- }
- while (stack_ptr>stack) get_output();
- flush_buffer();
-writeloop: @<Write all the named output files@>@;
- if (show_happiness) {
- if (show_progress) new_line;
- fputs("Done.",stdout);
- }
- }
-}
-
-@ @<Predecl...@>=@+static void phase_two(void);
-
-@ To write the named output files, we proceed as for the unnamed
-section.
-The only subtlety is that we have to open each one.
-
-@<Write all the named output files@>=
-for (an_output_file=end_output_files; an_output_file>cur_out_file;) {
- an_output_file--;
- sprint_section_name(output_file_name,*an_output_file);
- fclose(C_file);
- C_file=fopen(output_file_name,"wb");
- if (C_file ==0) fatal("! Cannot open output file ",output_file_name);
-@.Cannot open output file@>
- if (show_progress) { printf("\n(%s)",output_file_name); update_terminal; }
- cur_line=1;
- stack_ptr=stack+1;
- cur_name= (*an_output_file);
- cur_repl= (text_pointer)cur_name->equiv;
- cur_byte=cur_repl->tok_start;
- cur_end=(cur_repl+1)->tok_start;
- while (stack_ptr > stack) get_output();
- flush_buffer();
-}
-
-@ If a \.{@@h} was not encountered in the input,
-we go through the list of replacement texts and copy the ones
-that refer to macros, preceded by the \.{\#define} preprocessor command.
-
-@<Output macro definitions if appropriate@>=
- if (!output_defs_seen)
- output_defs();
-
-@ @<Private...@>=
-static boolean output_defs_seen=false;
-
-@ @<Predecl...@>=
-static void output_defs(void);@/
-static void out_char(eight_bits);
-
-@ @c
-static void
-output_defs(void)
-{
- sixteen_bits a;
- push_level(NULL);
- for (cur_text=text_info+1; cur_text<text_ptr; cur_text++)
- if (cur_text->text_link==0) { /* |cur_text| is the text for a macro */
- cur_byte=cur_text->tok_start;
- cur_end=(cur_text+1)->tok_start;
- C_printf("%s","#define ");
- out_state=normal;
- protect=true; /* newlines should be preceded by |'\\'| */
- while (cur_byte<cur_end) {
- a=*cur_byte++;
- if (cur_byte==cur_end && a=='\n') break; /* disregard a final newline */
- if (out_state==verbatim && a!=string && a!=constant && a!='\n')
- C_putc(a); /* a high-bit character can occur in a string */
-@^high-bit character handling@>
- else if (a<0200) out_char(a); /* one-byte token */
- else {
- a=(a-0200)*0400+*cur_byte++;
- if (a<024000) { /* |024000==(0250-0200)*0400| */
- cur_val=a; out_char(identifier);
- }
- else if (a<050000) { confusion("macro defs have strange char");}
- else {
- cur_val=a-050000; cur_section=cur_val; out_char(section_number);
- }
- /* no other cases */
- }
- }
- protect=false;
- flush_buffer();
- }
- pop_level(false);
-}
-
-@ A many-way switch is used to send the output. Note that this function
-is not called if |out_state==verbatim|, except perhaps with arguments
-|'\n'| (protect the newline), |string| (end the string), or |constant|
-(end the constant).
-
-@c
-static void
-out_char(
-eight_bits cur_char)
-{
- char *j, *k; /* pointer into |byte_mem| */
-restart:
- switch (cur_char) {
- case '\n': if (protect && out_state!=verbatim) C_putc(' ');
- if (protect || out_state==verbatim) C_putc('\\');
- flush_buffer(); if (out_state!=verbatim) out_state=normal; break;
- @/@t\4@>@<Case of an identifier@>@;
- @/@t\4@>@<Case of a section number@>@;
- @/@t\4@>@<Cases like \.{!=}@>@;
- case '=': case '>': C_putc(cur_char); C_putc(' ');
- out_state=normal; break;
- case join: out_state=unbreakable; break;
- case constant: if (out_state==verbatim) {
- out_state=num_or_id; break;
- }
- if(out_state==num_or_id) C_putc(' '); out_state=verbatim; break;
- case string: if (out_state==verbatim) out_state=normal;
- else out_state=verbatim; break;
- case '/': C_putc('/'); out_state=post_slash; break;
- case '*': if (out_state==post_slash) C_putc(' ');
- /* fall through */
- default: C_putc(cur_char); out_state=normal; break;
- }
-}
-
-@ @<Cases like \.{!=}@>=
-case plus_plus: C_putc('+');@+C_putc('+'); out_state=normal; break;
-case minus_minus: C_putc('-');@+C_putc('-'); out_state=normal; break;
-case minus_gt: C_putc('-');@+C_putc('>'); out_state=normal; break;
-case gt_gt: C_putc('>');@+C_putc('>'); out_state=normal; break;
-case eq_eq: C_putc('=');@+C_putc('='); out_state=normal; break;
-case lt_lt: C_putc('<');@+C_putc('<'); out_state=normal; break;
-case gt_eq: C_putc('>');@+C_putc('='); out_state=normal; break;
-case lt_eq: C_putc('<');@+C_putc('='); out_state=normal; break;
-case non_eq: C_putc('!');@+C_putc('='); out_state=normal; break;
-case and_and: C_putc('&');@+C_putc('&'); out_state=normal; break;
-case or_or: C_putc('|');@+C_putc('|'); out_state=normal; break;
-case dot_dot_dot: C_putc('.');@+C_putc('.');@+C_putc('.'); out_state=normal;
- break;
-case colon_colon: C_putc(':');@+C_putc(':'); out_state=normal; break;
-case period_ast: C_putc('.');@+C_putc('*'); out_state=normal; break;
-case minus_gt_ast: C_putc('-');@+C_putc('>');@+C_putc('*'); out_state=normal;
- break;
-
-@ When an identifier is output to the \CEE/ file, characters in the
-range 128--255 must be changed into something else, so the \CEE/
-compiler won't complain. By default, \.{CTANGLE} converts the
-character with code $16 x+y$ to the three characters `\.X$xy$', but
-a different transliteration table can be specified. Thus a German
-might want {\it gr\"un\/} to appear as a still readable \.{gruen}.
-This makes debugging a lot less confusing.
-
-@d translit_length 10
-
-@<Private...@>=
-static char translit[128][translit_length];
-
-@ @<Set init...@>=
-{
- int i;
- for (i=0;i<128;i++) sprintf(translit[i],"X%02X",(unsigned int)(128+i));
-}
-
-@ @<Case of an identifier@>=
-case identifier:
- if (out_state==num_or_id) C_putc(' ');
- j=(cur_val+name_dir)->byte_start;
- k=(cur_val+name_dir+1)->byte_start;
- while (j<k) {
- if ((eight_bits)(*j)<0200) C_putc(*j);
-@^high-bit character handling@>
- else C_printf("%s",translit[(eight_bits)(*j)-0200]);
- j++;
- }
- out_state=num_or_id; break;
-
-@ @<Case of a sec...@>=
-case section_number:
- if (cur_val>0) C_printf("/*%d:*/",cur_val);
- else if(cur_val<0) C_printf("/*:%d*/",-cur_val);
- else if (protect) {
- cur_byte +=4; /* skip line number and file name */
- cur_char = '\n';
- goto restart;
- } else {
- sixteen_bits a;
- a=0400* *cur_byte++;
- a+=*cur_byte++; /* gets the line number */
- C_printf("\n#line %d \"",a);
-@:line}{\.{\#line}@>
- cur_val=*cur_byte++;
- cur_val=0400*(cur_val-0200)+ *cur_byte++; /* points to the file name */
- for (j=(cur_val+name_dir)->byte_start, k=(cur_val+name_dir+1)->byte_start;
- j<k; j++) {
- if (*j=='\\' || *j=='"') C_putc('\\');
- C_putc(*j);
- }
- C_printf("%s","\"\n");
- }
- break;
-
-@** Introduction to the input phase.
-We have now seen that \.{CTANGLE} will be able to output the full
-\CEE/ program, if we can only get that program into the byte memory in
-the proper format. The input process is something like the output process
-in reverse, since we compress the text as we read it in and we expand it
-as we write it out.
-
-There are three main input routines. The most interesting is the one that gets
-the next token of a \CEE/ text; the other two are used to scan rapidly past
-\TEX/ text in the \.{CWEB} source code. One of the latter routines will jump to
-the next token that starts with `\.{@@}', and the other skips to the end
-of a \CEE/ comment.
-
-@ Control codes in \.{CWEB} begin with `\.{@@}', and the next character
-identifies the code. Some of these are of interest only to \.{CWEAVE},
-so \.{CTANGLE} ignores them; the others are converted by \.{CTANGLE} into
-internal code numbers by the |ccode| table below. The ordering
-of these internal code numbers has been chosen to simplify the program logic;
-larger numbers are given to the control codes that denote more significant
-milestones.
-
-@d ignore 0 /* control code of no interest to \.{CTANGLE} */
-@d ord 0302 /* control code for `\.{@@'}' */
-@d control_text 0303 /* control code for `\.{@@t}', `\.{@@\^}', etc. */
-@d translit_code 0304 /* control code for `\.{@@l}' */
-@d output_defs_code 0305 /* control code for `\.{@@h}' */
-@d format_code 0306 /* control code for `\.{@@f}' */
-@d definition 0307 /* control code for `\.{@@d}' */
-@d begin_C 0310 /* control code for `\.{@@c}' */
-@d section_name 0311 /* control code for `\.{@@<}' */
-@d new_section 0312 /* control code for `\.{@@\ }' and `\.{@@*}' */
-
-@<Private...@>=
-static eight_bits ccode[256]; /* meaning of a char following \.{@@} */
-
-@ @<Set ini...@>= {
- int c; /* must be |int| so the |for| loop will end */
- for (c=0; c<256; c++) ccode[c]=ignore;
- ccode[' ']=ccode['\t']=ccode['\n']=ccode['\v']=ccode['\r']=ccode['\f']
- =ccode['*']=new_section;
- ccode['@@']='@@'; ccode['=']=string;
- 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['^']=ccode[':']=ccode['.']=ccode['t']=ccode['T']=
- ccode['q']=ccode['Q']=control_text;
- ccode['h']=ccode['H']=output_defs_code;
- ccode['l']=ccode['L']=translit_code;
- ccode['&']=join;
- ccode['<']=ccode['(']=section_name;
- ccode['\'']=ord;
-}
-
-@ The |skip_ahead| procedure reads through the input at fairly high speed
-until finding the next non-ignorable control code, which it returns.
-
-@c
-static eight_bits
-skip_ahead(void) /* skip to next control code */
-{
- eight_bits c; /* control code found */
- while (true) {
- if (loc>limit && (get_line()==false)) return new_section;
- *(limit+1)='@@';
- while (*loc!='@@') loc++;
- if (loc<=limit) {
- loc++; c=ccode[(eight_bits)*loc]; loc++;
- if (c!=ignore || *(loc-1)=='>') return c;
- }
- }
-}
-
-@ @<Predecl...@>=
-static eight_bits skip_ahead(void);@/
-static boolean skip_comment(boolean);
-
-@ The |skip_comment| procedure reads through the input at somewhat high
-speed in order to pass over comments, which \.{CTANGLE} does not transmit
-to the output. If the comment is introduced by \.{/*}, |skip_comment|
-proceeds until finding the end-comment token \.{*/} or a newline; in the
-latter case |skip_comment| will be called again by |get_next|, since the
-comment is not finished. This is done so that each newline in the
-\CEE/ part of a section is copied to the output; otherwise the \&{\#line}
-commands inserted into the \CEE/ file by the output routines become useless.
-On the other hand, if the comment is introduced by \.{//} (i.e., if it
-is a \CPLUSPLUS/ ``short comment''), it always is simply delimited by the next
-newline. The boolean argument |is_long_comment| distinguishes between
-the two types of comments.
-
-If |skip_comment| comes to the end of the section, it prints an error message.
-No comment, long or short, is allowed to contain `\.{@@\ }' or `\.{@@*}'.
-
-@<Private...@>=
-static boolean comment_continues=false; /* are we scanning a comment? */
-
-@ @c
-static boolean skip_comment(@t\1\1@> /* skips over comments */
-boolean is_long_comment@t\2\2@>)
-{
- char c; /* current character */
- while (true) {
- if (loc>limit) {
- if (is_long_comment) {
- if(get_line()) return comment_continues=true;
- else{
- err_print("! Input ended in mid-comment");
-@.Input ended in mid-comment@>
- return comment_continues=false;
- }
- }
- else return comment_continues=false;
- }
- c=*(loc++);
- if (is_long_comment && c=='*' && *loc=='/') {
- loc++; return comment_continues=false;
- }
- if (c=='@@') {
- if (ccode[(eight_bits)*loc]==new_section) {
- err_print("! Section name ended in mid-comment"); loc--;
-@.Section name ended in mid-comment@>
- return comment_continues=false;
- }
- else loc++;
- }
- }
-}
-
-@* Inputting the next token.
-
-@d constant 03
-
-@<Private...@>=
-static name_pointer cur_section_name; /* name of section just scanned */
-static boolean no_where; /* suppress |print_where|? */
-
-@ As one might expect, |get_next| consists mostly of a big switch
-that branches to the various special cases that can arise.
-
-@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 */
-{
- static int preprocessing=0;
- eight_bits c; /* the current character */
- while (true) {
- if (loc>limit) {
- if (preprocessing && *(limit-1)!='\\') preprocessing=0;
- if (get_line()==false) return new_section;
- else if (print_where && !no_where) {
- print_where=false;
- @<Insert the line number into |tok_mem|@>@;
- }
- else return '\n';
- }
- c=*loc;
- if (comment_continues || (c=='/' && (*(loc+1)=='*' || *(loc+1)=='/'))) {
- skip_comment(comment_continues||*(loc+1)=='*');
- /* scan to end of comment or newline */
- if (comment_continues) return '\n';
- else continue;
- }
- 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)=='"')))
- @<Get a string@>@;
- else if (isalpha(c) || isxalpha(c) || ishigh(c))
- @<Get an identifier@>@;
- else if (c=='@@') @<Get control code and possible section name@>@;
- else if (xisspace(c)) {
- if (!preprocessing || loc>limit) continue;
- /* we don't want a blank after a final backslash */
- else return ' '; /* ignore spaces and tabs, unless preprocessing */
- }
- else if (c=='#' && loc==buffer+1) preprocessing=1;
- mistake: @<Compress two-symbol operator@>@;
- return c;
- }
-}
-
-@ @<Predecl...@>=@+static eight_bits get_next(void);
-
-@ The following code assigns values to the combinations \.{++},
-\.{--}, \.{->}, \.{>=}, \.{<=}, \.{==}, \.{<<}, \.{>>}, \.{!=}, \.{||} 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(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;
-}
-
-@ @<Get a constant@>= {
- id_first=loc-1;
- if (*id_first=='.' && !xisdigit(*loc)) goto mistake; /* not a constant */
- if (*id_first=='0') {
- if (*loc=='x' || *loc=='X') { /* hex constant */
- loc++; while (xisxdigit(*loc)) loc++; goto found;
- }
- }
- while (xisdigit(*loc)) loc++;
- if (*loc=='.') {
- loc++;
- while (xisdigit(*loc)) loc++;
- }
- if (*loc=='e' || *loc=='E') { /* float constant */
- if (*++loc=='+' || *loc=='-') loc++;
- while (xisdigit(*loc)) loc++;
- }
- found: while (*loc=='u' || *loc=='U' || *loc=='l' || *loc=='L'
- || *loc=='f' || *loc=='F') loc++;
- id_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; *++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;
- }
- 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@>
- }
- else if (++id_loc<=section_text_end) *id_loc='\n'; /* will print as
- \.{"\\\\\\n"} */
- }
- if ((c=*loc++)==delim) {
- if (++id_loc<=section_text_end) *id_loc=c;
- break;
- }
- if (c=='\\') {
- if (loc>=limit) continue;
- 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);
- err_print("...");
- }
- 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=ccode[(eight_bits)*loc++];
- switch(c) {
- case ignore: continue;
- case translit_code: err_print("! Use @@l in limbo only"); continue;
-@.Use @@l in limbo...@>
- case control_text: while ((c=skip_ahead())=='@@');
- /* only \.{@@@@} and \.{@@>} are expected */
- if (*(loc-1)!='>')
- err_print("! Double @@ should be used in control text");
-@.Double @@ should be used...@>
- continue;
- case section_name:
- cur_section_name_char=*(loc-1);
- @<Scan the section name and make |cur_section_name| point to it@>@;
- case string: @<Scan a verbatim string@>@;
- case ord: @<Scan an ASCII constant@>@;
- default: return c;
- }
-}
-
-@ After scanning a valid ASCII constant that follows
-\.{@@'}, this code plows ahead until it finds the next single quote.
-(Special care is taken if the quote is part of the constant.)
-Anything after a valid ASCII constant is ignored;
-thus, \.{@@'\\nopq'} gives the same result as \.{@@'\\n'}.
-
-@<Scan an ASCII constant@>=
- id_first=loc;
- if (*loc=='\\') {
- if (*++loc=='\'') loc++;
- }
- while (*loc!='\'') {
- if (*loc=='@@') {
- if (*(loc+1)!='@@')
- err_print("! Double @@ should be used in ASCII constant");
-@.Double @@ should be used...@>
- else loc++;
- }
- loc++;
- if (loc>limit) {
- err_print("! String didn't end"); loc=limit-1; break;
-@.String didn't end@>
- }
- }
- loc++;
- return ord;
-
-@ @<Scan the section name...@>= {
- char *k; /* pointer into |section_text| */
- @<Put section name into |section_text|@>@;
- if (k-section_text>3 && strncmp(k-2,"...",3)==0)
- cur_section_name=section_lookup(section_text+1,k-3,1); /* 1 means is a prefix */
- else cur_section_name=section_lookup(section_text+1,k,0);
- if (cur_section_name_char=='(')
- @<If it's not there, add |cur_section_name| to the output file stack, or
- complain we're out of room@>@;
- 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 nesting, |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 or erroneous nesting,...@>=
-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 (ccode[(eight_bits)c]==section_name) {
- err_print("! Nesting of section names not allowed"); break;
-@.Nesting of section names...@>
- }
- *(++k)='@@'; loc++; /* now |c==*loc| again */
-}
-
-@ At the present point in the program we
-have |*(loc-1)==string|; 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 string;
-}
-
-@* Scanning a macro definition.
-The rules for generating the replacement texts corresponding to macros and
-\CEE/ texts of a section are almost identical; the only differences are that
-
-\yskip \item{a)}Section names are not allowed in macros;
-in fact, the appearance of a section name terminates such macros and denotes
-the name of the current section.
-
-\item{b)}The symbols \.{@@d} and \.{@@f} and \.{@@c} are not allowed after
-section names, while they terminate macro definitions.
-
-\item{c)}Spaces are inserted after right parentheses in macros, because the
-ANSI \CEE/ preprocessor sometimes requires it.
-
-\yskip Therefore there is a single procedure |scan_repl| whose parameter
-|t| specifies either |macro| or |section_name|. After |scan_repl| has
-acted, |cur_text| will point to the replacement text just generated, and
-|next_control| will contain the control code that terminated the activity.
-
-@d macro 0
-@d app_repl(c) {if (tok_ptr==tok_mem_end) overflow("token"); *tok_ptr++=c;}
-
-@<Private...@>=
-static text_pointer cur_text; /* replacement text formed by |scan_repl| */
-static eight_bits next_control;
-
-@ @c
-static void
-scan_repl(@t\1\1@> /* creates a replacement text */
-eight_bits t@t\2\2@>)
-{
- sixteen_bits a; /* the current token */
- if (t==section_name) {@<Insert the line number into |tok_mem|@>@;}
- while (true) switch (a=get_next()) {
- @<In cases that |a| is a non-|char| token (|identifier|,
- |section_name|, etc.), either process it and change |a| to a byte
- that should be stored, or |continue| if |a| should be ignored,
- or |goto done| if |a| signals the end of this replacement text@>@;
- case ')': app_repl(a);
- if (t==macro) app_repl(' ');
- break;
- default: app_repl(a); /* store |a| in |tok_mem| */
- }
- done: next_control=(eight_bits) a;
- if (text_ptr>text_info_end) overflow("text");
- cur_text=text_ptr; (++text_ptr)->tok_start=tok_ptr;
-}
-
-@ @<Predecl...@>=@+static void scan_repl(eight_bits);
-
-@ Here is the code for the line number: first a |sixteen_bits| equal
-to |0150000|; then the numeric line number; then a pointer to the
-file name.
-
-@<Insert the line...@>=
-store_two_bytes(0150000);
-if (changing && include_depth==change_depth) { /* correction made Feb 2017 */
- id_first=change_file_name;
- store_two_bytes((sixteen_bits)change_line);
-}@+else {
- id_first=cur_file_name;
- store_two_bytes((sixteen_bits)cur_line);
-}
-id_loc=id_first+strlen(id_first);
-{int a_l=id_lookup(id_first,id_loc,0)-name_dir; app_repl((a_l / 0400)+0200);
- app_repl(a_l % 0400);}
-
-@ @<In cases that |a| is...@>=
-case identifier: a=id_lookup(id_first,id_loc,0)-name_dir;
- app_repl((a / 0400)+0200);
- app_repl(a % 0400); break;
-case section_name: if (t!=section_name) goto done;
- else {
- @<Was an `\.{@@}' missed here?@>@;
- a=cur_section_name-name_dir;
- app_repl((a / 0400)+0250);
- app_repl(a % 0400);
- @<Insert the line number into |tok_mem|@>@; break;
- }
-case output_defs_code: if (t!=section_name) err_print("! Misplaced @@h");
-@.Misplaced @@h@>
- else {
- output_defs_seen=true;
- a=output_defs_flag;
- app_repl((a / 0400)+0200);
- app_repl(a % 0400);
- @<Insert the line number into |tok_mem|@>@;
- }
- break;
-case constant: case string:
- @<Copy a string or verbatim construction or numerical constant@>@;
-case ord:
- @<Copy an ASCII constant@>@;
-case definition: case format_code: case begin_C: if (t!=section_name) goto done;
- else {
- err_print("! @@d, @@f and @@c are ignored in C text"); continue;
-@.@@d, @@f and @@c are ignored in C text@>
- }
-case new_section: goto done;
-
-@ @<Was an `\.{@@}'...@>= {
- char *try_loc=loc;
- while (*try_loc==' ' && try_loc<limit) try_loc++;
- if (*try_loc=='+' && try_loc<limit) try_loc++;
- while (*try_loc==' ' && try_loc<limit) try_loc++;
- if (*try_loc=='=') err_print ("! Missing `@@ ' before a named section");
-@.Missing `@@ '...@>
- /* user who isn't defining a section should put newline after the name,
- as explained in the manual */
-}
-
-@ @<Copy a string...@>=
- app_repl(a); /* |string| or |constant| */
- while (id_first < id_loc) { /* simplify \.{@@@@} pairs */
- if (*id_first=='@@') {
- if (*(id_first+1)=='@@') id_first++;
- else err_print("! Double @@ should be used in string");
-@.Double @@ should be used...@>
- }
- app_repl(*id_first++);
- }
- app_repl(a); break;
-
-@ This section should be rewritten on machines that don't use ASCII
-code internally.
-@^ASCII code dependencies@>
-
-@<Copy an ASCII constant@>= {
- int c=(eight_bits) *id_first;
- if (c=='\\') {
- c=*++id_first;
- if (c>='0' && c<='7') {
- c-='0';
- if (*(id_first+1)>='0' && *(id_first+1)<='7') {
- c=8*c+*(++id_first) - '0';
- if (*(id_first+1)>='0' && *(id_first+1)<='7' && c<32)
- c=8*c+*(++id_first)- '0';
- }
- }
- else switch (c) {
- case 't':c='\t';@+break;
- case 'n':c='\n';@+break;
- case 'b':c='\b';@+break;
- case 'f':c='\f';@+break;
- case 'v':c='\v';@+break;
- case 'r':c='\r';@+break;
- case 'a':c='\7';@+break;
- case '?':c='?';@+break;
- case 'x':
- if (xisdigit(*(id_first+1))) c=*(++id_first)-'0';
- else if (xisxdigit(*(id_first+1))) {
- ++id_first;
- c=toupper((eight_bits)*id_first)-'A'+10;
- }
- if (xisdigit(*(id_first+1))) c=16*c+*(++id_first)-'0';
- else if (xisxdigit(*(id_first+1))) {
- ++id_first;
- c=16*c+toupper((eight_bits)*id_first)-'A'+10;
- }
- break;
- case '\\':c='\\';@+break;
- case '\'':c='\'';@+break;
- case '\"':c='\"';@+break;
- default: err_print("! Unrecognized escape sequence");
-@.Unrecognized escape sequence@>
- }
- }@/
- /* at this point |c| should have been converted to its ASCII code number */
- app_repl(constant);
- if (c>=100) app_repl('0'+c/100);
- if (c>=10) app_repl('0'+(c/10)%10);
- app_repl('0'+c%10);
- app_repl(constant);
-}
-break;
-
-@* Scanning a section.
-The |scan_section| procedure starts when `\.{@@\ }' or `\.{@@*}' has been
-sensed in the input, and it proceeds until the end of that section. It
-uses |section_count| to keep track of the current section number; with luck,
-\.{CWEAVE} and \.{CTANGLE} will both assign the same numbers to sections.
-
-The body of |scan_section| is a loop where we look for control codes
-that are significant to \.{CTANGLE}: those
-that delimit a definition, the \CEE/ part of a module, or a new module.
-
-@c
-static void
-scan_section(void)
-{
- name_pointer p; /* section name for the current section */
- text_pointer q; /* text for the current section */
- sixteen_bits a; /* token for left-hand side of definition */
- section_count++; @+ no_where=true;
- if (*(loc-1)=='*' && show_progress) { /* starred section */
- printf("*%d",section_count); update_terminal;
- }
- next_control=0;
- while (true) {
- @<Skip ahead until |next_control| corresponds to \.{@@d}, \.{@@<},
- \.{@@\ } or the like@>@;
- if (next_control == definition) { /* \.{@@d} */
- @<Scan a definition@>@;
- continue;
- }
- if (next_control == begin_C) { /* \.{@@c} or \.{@@p} */
- p=name_dir; break;
- }
- if (next_control == section_name) { /* \.{@@<} or \.{@@(} */
- p=cur_section_name;
- @<If section is not being defined, |continue| @>@;
- break;
- }
- return; /* \.{@@\ } or \.{@@*} */
- }
- no_where=print_where=false;
- @<Scan the \CEE/ part of the current section@>@;
-}
-
-@ @<Predecl...@>=@+static void scan_section(void);
-
-@ At the top of this loop, if |next_control==section_name|, the
-section name has already been scanned (see |@<Get control code
-and...@>|). Thus, if we encounter |next_control==section_name| in the
-skip-ahead process, we should likewise scan the section name, so later
-processing will be the same in both cases.
-
-@<Skip ahead until |next_control| ...@>=
-while (next_control<definition)
- /* |definition| is the lowest of the ``significant'' codes */
- if((next_control=skip_ahead())==section_name){
- loc-=2; next_control=get_next();
- }
-
-@ @<Scan a definition@>= {
- while ((next_control=get_next())=='\n'); /* allow newline before definition */
- if (next_control!=identifier) {
- err_print("! Definition flushed, must start with identifier");
-@.Definition flushed...@>
- continue;
- }
- app_repl(((a=id_lookup(id_first,id_loc,0)-name_dir) / 0400)+0200);
- /* append the lhs */
- app_repl(a % 0400);
- if (*loc!='(') { /* identifier must be separated from replacement text */
- app_repl(string); app_repl(' '); app_repl(string);
- }
- scan_repl(macro);
- cur_text->text_link=macro;
-}
-
-@ If the section name is not followed by \.{=} or \.{+=}, no \CEE/
-code is forthcoming: the section is being cited, not being
-defined. This use is illegal after the definition part of the
-current section has started, except inside a comment, but
-\.{CTANGLE} does not enforce this rule; it simply ignores the offending
-section name and everything following it, up to the next significant
-control code.
-
-@<If section is not being defined, |continue| @>=
-while ((next_control=get_next())=='+'); /* allow optional \.{+=} */
-if (next_control!='=' && next_control!=eq_eq)
- continue;
-
-@ @<Scan the \CEE/...@>=
-@<Insert the section number into |tok_mem|@>@;
-scan_repl(section_name); /* now |cur_text| points to the replacement text */
-@<Update the data structure so that the replacement text is accessible@>@;
-
-@ @<Insert the section number...@>=
-store_two_bytes((sixteen_bits)(0150000+section_count));
- /* |0150000==0320*0400| */
-
-@ @<Update the data...@>=
-if (p==name_dir||p==0) { /* unnamed section, or bad section name */
- (last_unnamed)->text_link=cur_text-text_info; last_unnamed=cur_text;
-}
-else if (p->equiv==(void *)text_info) p->equiv=(void *)cur_text;
- /* first section of this name */
-else {
- q=(text_pointer)p->equiv;
- while (q->text_link<section_flag)
- q=q->text_link+text_info; /* find end of list */
- q->text_link=cur_text-text_info;
-}
-cur_text->text_link=section_flag;
- /* mark this replacement text as a nonmacro */
-
-@ @c
-static void
-phase_one(void) {
- phase=1;
- section_count=0;
- reset_input();
- skip_limbo();
- while (!input_has_ended) scan_section();
- check_complete();
- phase=2;
-}
-
-@ @<Predec...@>=@+static void phase_one(void);
-
-@ Only a small subset of the control codes is legal in limbo, so limbo
-processing is straightforward.
-
-@c
-static void
-skip_limbo(void)
-{
- char c;
- while (true) {
- if (loc>limit && get_line()==false) return;
- *(limit+1)='@@';
- while (*loc!='@@') loc++;
- if (loc++<=limit) {
- c=*loc++;
- if (ccode[(eight_bits)c]==new_section) break;
- switch (ccode[(eight_bits)c]) {
- case translit_code: @<Read in transliteration of a character@>@; break;
- case format_code: case '@@': break;
- case control_text: if (c=='q' || c=='Q') {
- while ((c=skip_ahead())=='@@');
- if (*(loc-1)!='>')
- err_print("! Double @@ should be used in control text");
-@.Double @@ should be used...@>
- break;
- } /* otherwise fall through */
- default: err_print("! Double @@ should be used in limbo");
-@.Double @@ should be used...@>
- }
- }
- }
-}
-
-@ @<Predecl...@>=@+static void skip_limbo(void);
-
-@ @<Read in transliteration of a character@>=
- while(xisspace(*loc)&&loc<limit) loc++;
- loc+=3;
- if (loc>limit || !xisxdigit(*(loc-3)) || !xisxdigit(*(loc-2)) @|
- || (*(loc-3)>='0' && *(loc-3)<='7') || !xisspace(*(loc-1)))
- err_print("! Improper hex number following @@l");
-@.Improper hex number...@>
- else {
- unsigned int i;
- char *beg;
- sscanf(loc-3,"%x",&i);
- while(xisspace(*loc)&&loc<limit) loc++;
- beg=loc;
- while(loc<limit&&(xisalpha(*loc)||xisdigit(*loc)||*loc=='_')) loc++;
- if (loc-beg>=translit_length)
- err_print("! Replacement string in @@l too long");
-@.Replacement string in @@l...@>
- else{
- strncpy(translit[i-0200],beg,(size_t)(loc-beg));
- translit[i-0200][loc-beg]='\0';
- }
- }
-
-@ Because on some systems the difference between two pointers is a |ptrdiff_t|
-but not an |int|, we use \.{\%ld} to print these quantities.
-
-@c
-void
-print_stats(void) {
- puts("\nMemory usage statistics:");
- printf("%ld names (out of %ld)\n",
- (ptrdiff_t)(name_ptr-name_dir),(long)max_names);
- printf("%ld replacement texts (out of %ld)\n",
- (ptrdiff_t)(text_ptr-text_info),(long)max_texts);
- printf("%ld bytes (out of %ld)\n",
- (ptrdiff_t)(byte_ptr-byte_mem),(long)max_bytes);
- printf("%ld tokens (out of %ld)\n",
- (ptrdiff_t)(tok_ptr-tok_mem),(long)max_toks);
-}
-
-@** Index.
-Here is a cross-reference table for \.{CTANGLE}.
-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 and
-a few other things like ``ASCII code dependencies'' are indexed here too.