summaryrefslogtreecommitdiff
path: root/web/c_cpp/cweb/ctangle.w
diff options
context:
space:
mode:
Diffstat (limited to 'web/c_cpp/cweb/ctangle.w')
-rw-r--r--web/c_cpp/cweb/ctangle.w536
1 files changed, 261 insertions, 275 deletions
diff --git a/web/c_cpp/cweb/ctangle.w b/web/c_cpp/cweb/ctangle.w
index 130800210e..e7e2d311fe 100644
--- a/web/c_cpp/cweb/ctangle.w
+++ b/web/c_cpp/cweb/ctangle.w
@@ -2,9 +2,7 @@
% 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 3.64 --- February 2002
-% (same as Version 3.5 except for minor corrections)
-% (also quotes backslashes in file names of #line directives)
+% Version 4.2 --- February 2021
% Copyright (C) 1987,1990,1993,2000 Silvio Levy and Donald E. Knuth
@@ -17,6 +15,11 @@
% 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 (|...|)
@@ -24,11 +27,11 @@
\mathchardef\RA="3221 % right arrow
\mathchardef\BA="3224 % double arrow
-\def\title{CTANGLE (Version 3.64)}
+\def\title{CTANGLE (Version 4.2)}
\def\topofcontents{\null\vfill
\centerline{\titlefont The {\ttitlefont CTANGLE} processor}
\vskip 15pt
- \centerline{(Version 3.64)}
+ \centerline{(Version 4.2)}
\vfill}
\def\botofcontents{\vfill
\noindent
@@ -46,7 +49,6 @@ under the terms of a permission notice identical to this one.
}
\pageno=\contentspagenumber \advance\pageno by 1
\let\maybe=\iftrue
-@s not_eq normal @q unreserve a C++ keyword @>
@** Introduction.
This is the \.{CTANGLE} program by Silvio Levy and Donald E. Knuth,
@@ -59,27 +61,15 @@ 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 3.64)\n"
+@d banner "This is CTANGLE (Version 4.2)"
@c
@<Include files@>@/
@h
@<Common code for \.{CWEAVE} and \.{CTANGLE}@>@/
@<Typedef declarations@>@/
-@<Global variables@>@/
-@<Predeclaration of procedures@>@/
-
-@ We predeclare several standard system functions here instead of including
-their system header files, because the names of the header files are not as
-standard as the names of the functions. (For example, some \CEE/ environments
-have \.{<string.h>} where others have \.{<strings.h>}.)
-
-@<Predecl...@>=
-extern int strlen(); /* length of string */
-extern int strcmp(); /* compare strings lexicographically */
-extern char* strcpy(); /* copy one string to another */
-extern int strncmp(); /* compare up to $n$ string characters */
-extern char* strncpy(); /* copy up to $n$ string characters */
+@<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
@@ -89,40 +79,24 @@ Please read the documentation for \.{common}, the set of routines common
to \.{CTANGLE} and \.{CWEAVE}, before proceeding further.
@c
-int main (ac, av)
-int ac;
-char **av;
+int main (
+int ac,
+char **av)
{
argc=ac; argv=av;
program=ctangle;
- @<Set initial values@>;
+ @<Set initial values@>@;
common_init();
- if (show_banner) printf(banner); /* print a ``banner line'' */
+ 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 following parameters were sufficient in the original \.{TANGLE} to
-handle \TEX/,
-so they should be sufficient for most applications of \.{CTANGLE}.
-If you change |max_bytes|, |max_names|, or |hash_size| you should also
-change them in the file |"common.w"|.
-
-@d max_bytes 90000 /* the number of bytes in identifiers,
- index entries, and section names; used in |"common.w"| */
-@d max_toks 270000 /* number of bytes in compressed \CEE/ code */
-@d max_names 4000 /* number of identifiers, strings, section names;
- must be less than 10240; used in |"common.w"| */
-@d max_texts 2500 /* number of replacement texts, must be less than 10240 */
-@d hash_size 353 /* should be prime; used in |"common.w"| */
-@d longest_name 10000 /* section names and strings shouldn't be longer than this */
-@d stack_size 50 /* number of simultaneous levels of macro expansion */
-@d buf_size 100 /* for \.{CWEAVE} and \.{CTANGLE} */
-
@ 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 needs to be updated when |"common.w"| changes.
+file |"common.h"|, which is also included in |"common.w"| to propagate
+possible changes from this \.{COMMON} interface consistently.
@i common.h
@@ -137,7 +111,7 @@ 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
+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
@@ -145,10 +119,6 @@ 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|.
-If your machine does not support |unsigned char| you should change
-the definition of \&{eight\_bits} to |unsigned short|.
-@^system dependencies@>
-
@<Typed...@>=
typedef struct {
eight_bits *tok_start; /* pointer into |tok_mem| */
@@ -156,13 +126,13 @@ typedef struct {
} text;
typedef text *text_pointer;
-@ @<Glob...@>=
-text text_info[max_texts];
-text_pointer text_info_end=text_info+max_texts-1;
-text_pointer text_ptr; /* first unused position in |text_info| */
-eight_bits tok_mem[max_toks];
-eight_bits *tok_mem_end=tok_mem+max_toks-1;
-eight_bits *tok_ptr; /* first unused position in |tok_mem| */
+@ @<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;
@@ -175,18 +145,19 @@ replacement text, an element of the array |text_info|.
@d equiv equiv_or_xref /* info corresponding to names */
@ @<Set init...@>=
-name_dir->equiv=(char *)text_info; /* the undefined section has no replacement text */
+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
-int names_match(p,first,l)
-name_pointer p; /* points to the proposed match */
-char *first; /* position of first character of string */
-int l; /* length of identifier */
-{
- if (length(p)!=l) return 0;
+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);
}
@@ -197,13 +168,13 @@ the loader won't complain of its absence.
@c
void
-init_node(node)
-name_pointer node;
+init_node(
+name_pointer node)
{
- node->equiv=(char *)text_info;
+ node->equiv=(void *)text_info;
}
void
-init_p() {}
+init_p(name_pointer p,eight_bits t) {@+(void)p;@+(void)t;@+}
@* Tokens.
Replacement texts, which represent \CEE/ code in a compressed format,
@@ -224,8 +195,8 @@ The replacement text pointer for the first unnamed section appears in
@d section_flag max_texts /* final |text_link| in section replacement texts */
-@<Glob...@>=
-text_pointer last_unnamed; /* most recent replacement text of unnamed section */
+@<Private...@>=
+static text_pointer last_unnamed; /* most recent replacement text of unnamed section */
@ @<Set init...@>= last_unnamed=text_info; text_info->text_link=0;
@@ -258,15 +229,17 @@ construction or numerical constant.
|tok_mem| when a replacement text is being generated.
@c
-void
-store_two_bytes(x)
-sixteen_bits x;
+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:
@@ -309,12 +282,12 @@ typedef output_state *stack_pointer;
@d cur_repl cur_state.repl_field /* pointer to current replacement text */
@d cur_section cur_state.section_field /* current section number being expanded */
-@<Global...@>=
-output_state cur_state; /* |cur_end|, |cur_byte|, |cur_name|, |cur_repl|,
+@<Private...@>=
+static output_state cur_state; /* |cur_end|, |cur_byte|, |cur_name|, |cur_repl|,
and |cur_section| */
-output_state stack[stack_size+1]; /* info for non-current levels */
-stack_pointer stack_ptr; /* first unused location in the output state stack */
-stack_pointer stack_end=stack+stack_size; /* end of |stack| */
+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,
@@ -334,9 +307,9 @@ We assume that the \CEE/ compiler can copy structures.
@^system dependencies@>
@c
-void
-push_level(p) /* suspends the current level */
-name_pointer p;
+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;
@@ -348,14 +321,18 @@ name_pointer p;
}
}
+@ @<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
-void
-pop_level(flag) /* do this when |cur_byte| reaches |cur_end| */
-int flag; /* |flag==0| means we are in |output_defs| */
+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 */
@@ -381,22 +358,22 @@ if the next output is an identifier, in which case
@d section_number 0201 /* code returned by |get_output| for section numbers */
@d identifier 0202 /* code returned by |get_output| for identifiers */
-@<Global...@>=
-int cur_val; /* additional information corresponding to output token */
+@<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
-void
-get_output() /* sends next token to |out_char| */
+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(1);
+ pop_level(true);
if (cur_val==0) goto restart;
out_char(section_number); return;
}
@@ -409,7 +386,7 @@ get_output() /* sends next token to |out_char| */
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|@>;
+ 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);
@@ -417,15 +394,17 @@ get_output() /* sends next token to |out_char| */
}
}
+@ @<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!=(char *)text_info) push_level(a+name_dir);
+ if ((a+name_dir)->equiv!=(void *)text_info) push_level(a+name_dir);
else if (a!=0) {
- printf("\n! Not present: <");
+ fputs("\n! Not present: <",stdout);
print_section_name(a+name_dir); err_print(">");
@.Not present: <section name>@>
}
@@ -461,7 +440,7 @@ strings, verbatim constructions and numerical constants.
\yskip\hang |normal| means none of the above.
-\yskip\noindent Furthermore, if the variable |protect| is positive, newlines
+\yskip\noindent Furthermore, if the variable |protect| is |true|, newlines
are preceded by a `\.\\'.
@d normal 0 /* non-unusual state */
@@ -470,17 +449,17 @@ are preceded by a `\.\\'.
@d unbreakable 3 /* state associated with \.{@@\&} */
@d verbatim 4 /* state in the middle of a string */
-@<Global...@>=
-eight_bits out_state; /* current status of partial output */
-boolean protect; /* should newline characters be quoted? */
+@<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
-void
-flush_buffer() /* writes one line to output file */
+static void
+flush_buffer(void) /* writes one line to output file */
{
C_putc('\n');
if (cur_line % 100 == 0 && show_progress) {
@@ -491,6 +470,8 @@ flush_buffer() /* writes one line to output file */
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 \.{@@(}
@@ -499,11 +480,11 @@ 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
-@<Glob...@>=
-name_pointer output_files[max_files];
-name_pointer *cur_out_file, *end_output_files, *an_output_file;
-char cur_section_name_char; /* is it |'<'| or |'('| */
-char output_file_name[longest_name]; /* name of the file */
+@<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
@@ -530,18 +511,15 @@ complain we're out of room@>=
@* The big output switch. Here then is the routine that does the
output.
-@<Predecl...@>=
-void phase_two();
-
-@ @c
-void
-phase_two () {
- web_file_open=0;
+@c
+static void
+phase_two (void) {
+ web_file_open=false;
cur_line=1;
- @<Initialize the output stacks@>;
- @<Output macro definitions if appropriate@>;
+ @<Initialize the output stacks@>@;
+ @<Output macro definitions if appropriate@>@;
if (text_info->text_link==0 && cur_out_file==end_output_files) {
- printf("\n! No program text was specified."); mark_harmless;
+ fputs("\n! No program text was specified.",stdout); mark_harmless;
@.No program text...@>
}
else {
@@ -551,7 +529,7 @@ phase_two () {
}
else {
if (show_progress) {
- printf("\nWriting the output files:");
+ fputs("\nWriting the output files:",stdout);
@.Writing the output...@>
printf(" (%s)",C_file_name);
update_terminal;
@@ -560,11 +538,16 @@ phase_two () {
}
while (stack_ptr>stack) get_output();
flush_buffer();
-writeloop: @<Write all the named output files@>;
- if(show_happiness) printf("\nDone.");
+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.
@@ -574,10 +557,10 @@ 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,"w");
- if (C_file ==0) fatal("! Cannot open output file:",output_file_name);
+ C_file=fopen(output_file_name,"wb");
+ if (C_file ==0) fatal("! Cannot open output file ",output_file_name);
@.Cannot open output file@>
- printf("\n(%s)",output_file_name); update_terminal;
+ if (show_progress) { printf("\n(%s)",output_file_name); update_terminal; }
cur_line=1;
stack_ptr=stack+1;
cur_name= (*an_output_file);
@@ -596,15 +579,16 @@ that refer to macros, preceded by the \.{\#define} preprocessor command.
if (!output_defs_seen)
output_defs();
-@ @<Glob...@>=
-boolean output_defs_seen=0;
+@ @<Private...@>=
+static boolean output_defs_seen=false;
@ @<Predecl...@>=
-void output_defs();
+static void output_defs(void);@/
+static void out_char(eight_bits);
@ @c
-void
-output_defs()
+static void
+output_defs(void)
{
sixteen_bits a;
push_level(NULL);
@@ -614,7 +598,7 @@ output_defs()
cur_end=(cur_text+1)->tok_start;
C_printf("%s","#define ");
out_state=normal;
- protect=1; /* newlines should be preceded by |'\\'| */
+ 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 */
@@ -634,10 +618,10 @@ output_defs()
/* no other cases */
}
}
- protect=0;
+ protect=false;
flush_buffer();
}
- pop_level(0);
+ pop_level(false);
}
@ A many-way switch is used to send the output. Note that this function
@@ -645,13 +629,10 @@ is not called if |out_state==verbatim|, except perhaps with arguments
|'\n'| (protect the newline), |string| (end the string), or |constant|
(end the constant).
-@<Predecl...@>=
-static void out_char();
-
-@ @c
+@c
static void
-out_char(cur_char)
-eight_bits cur_char;
+out_char(
+eight_bits cur_char)
{
char *j, *k; /* pointer into |byte_mem| */
restart:
@@ -659,9 +640,9 @@ restart:
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 \.{!=}@>;
+ @/@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;
@@ -679,22 +660,22 @@ restart:
}
@ @<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 not_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;
+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;
+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
@@ -707,13 +688,13 @@ This makes debugging a lot less confusing.
@d translit_length 10
-@<Glo...@>=
-char translit[128][translit_length];
+@<Private...@>=
+static char translit[128][translit_length];
@ @<Set init...@>=
{
int i;
- for (i=0;i<128;i++) sprintf(translit[i],"X%02X",(unsigned)(128+i));
+ for (i=0;i<128;i++) sprintf(translit[i],"X%02X",(unsigned int)(128+i));
}
@ @<Case of an identifier@>=
@@ -722,9 +703,9 @@ case identifier:
j=(cur_val+name_dir)->byte_start;
k=(cur_val+name_dir+1)->byte_start;
while (j<k) {
- if ((unsigned char)(*j)<0200) C_putc(*j);
+ if ((eight_bits)(*j)<0200) C_putc(*j);
@^high-bit character handling@>
- else C_printf("%s",translit[(unsigned char)(*j)-0200]);
+ else C_printf("%s",translit[(eight_bits)(*j)-0200]);
j++;
}
out_state=num_or_id; break;
@@ -786,8 +767,8 @@ milestones.
@d section_name 0311 /* control code for `\.{@@<}' */
@d new_section 0312 /* control code for `\.{@@\ }' and `\.{@@*}' */
-@<Global...@>=
-eight_bits ccode[256]; /* meaning of a char following \.{@@} */
+@<Private...@>=
+static eight_bits ccode[256]; /* meaning of a char following \.{@@} */
@ @<Set ini...@>= {
int c; /* must be |int| so the |for| loop will end */
@@ -811,21 +792,25 @@ eight_bits ccode[256]; /* meaning of a char following \.{@@} */
until finding the next non-ignorable control code, which it returns.
@c
-eight_bits
-skip_ahead() /* skip to next control code */
+static eight_bits
+skip_ahead(void) /* skip to next control code */
{
eight_bits c; /* control code found */
- while (1) {
- if (loc>limit && (get_line()==0)) return(new_section);
+ 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);
+ 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|
@@ -842,35 +827,35 @@ 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 `\.{@@*}'.
-@<Global...@>=
-boolean comment_continues=0; /* are we scanning a comment? */
+@<Private...@>=
+static boolean comment_continues=false; /* are we scanning a comment? */
@ @c
-int skip_comment(is_long_comment) /* skips over comments */
-boolean is_long_comment;
+static boolean skip_comment(@t\1\1@> /* skips over comments */
+boolean is_long_comment@t\2\2@>)
{
char c; /* current character */
- while (1) {
+ while (true) {
if (loc>limit) {
if (is_long_comment) {
- if(get_line()) return(comment_continues=1);
+ if(get_line()) return comment_continues=true;
else{
err_print("! Input ended in mid-comment");
@.Input ended in mid-comment@>
- return(comment_continues=0);
+ return comment_continues=false;
}
}
- else return(comment_continues=0);
+ else return comment_continues=false;
}
c=*(loc++);
if (is_long_comment && c=='*' && *loc=='/') {
- loc++; return(comment_continues=0);
+ 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=0);
+ return comment_continues=false;
}
else loc++;
}
@@ -881,48 +866,46 @@ boolean is_long_comment;
@d constant 03
-@<Global...@>=
-name_pointer cur_section_name; /* name of section just scanned */
-int no_where; /* suppress |print_where|? */
-
-@ @<Include...@>=
-#include <ctype.h> /* definition of |isalpha|, |isdigit| and so on */
-#include <stdlib.h> /* definition of |exit| */
+@<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) ((unsigned char)(c)>0177)
+@d ishigh(c) ((eight_bits)(c)>0177)
@^high-bit character handling@>
@c
-eight_bits
-get_next() /* produces the next input token */
+static eight_bits
+get_next(void) /* produces the next input token */
{
static int preprocessing=0;
eight_bits c; /* the current character */
- while (1) {
+ while (true) {
if (loc>limit) {
if (preprocessing && *(limit-1)!='\\') preprocessing=0;
- if (get_line()==0) return(new_section);
+ if (get_line()==false) return new_section;
else if (print_where && !no_where) {
- print_where=0;
- @<Insert the line number into |tok_mem|@>;
+ print_where=false;
+ @<Insert the line number into |tok_mem|@>@;
}
- else return ('\n');
+ 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');
+ if (comment_continues) return '\n';
else continue;
}
loc++;
if (xisdigit(c) || c=='.') @<Get a constant@>@;
- else if (c=='\'' || c=='"' || (c=='L'&&(*loc=='\'' || *loc=='"')))
+ 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@>@;
@@ -930,14 +913,16 @@ get_next() /* produces the next input token */
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 return ' '; /* ignore spaces and tabs, unless preprocessing */
}
else if (c=='#' && loc==buffer+1) preprocessing=1;
mistake: @<Compress two-symbol operator@>@;
- return(c);
+ return c;
}
}
+@ @<Predecl...@>=@+static eight_bits get_next(void);
+
@ The following code assigns values to the combinations \.{++},
\.{--}, \.{->}, \.{>=}, \.{<=}, \.{==}, \.{<<}, \.{>>}, \.{!=}, \.{||} and
\.{\&\&}, and to the \CPLUSPLUS/
@@ -945,14 +930,14 @@ combinations \.{...}, \.{::}, \.{.*} and \.{->*}.
The compound assignment operators (e.g., \.{+=}) are
treated as separate tokens.
-@d compress(c) if (loc++<=limit) return(c)
+@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;
+ 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);
@@ -966,13 +951,14 @@ switch(c) {
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(not_eq); break;
+ case '!': if (*loc=='=') compress(non_eq); break;
}
@ @<Get an identifier@>= {
id_first=--loc;
- while (isalpha(*++loc) || isdigit(*loc) || isxalpha(*loc) || ishigh(*loc));
- id_loc=loc; return(identifier);
+ 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@>= {
@@ -995,7 +981,7 @@ switch(c) {
found: while (*loc=='u' || *loc=='U' || *loc=='l' || *loc=='L'
|| *loc=='f' || *loc=='F') loc++;
id_loc=loc;
- return(constant);
+ return constant;
}
@ \CEE/ strings and character constants, delimited by double and single
@@ -1007,16 +993,17 @@ convention, but do not allow the string to be longer than |longest_name|.
char delim = c; /* what started the string */
id_first = section_text+1;
id_loc = section_text; *++id_loc=delim;
- if (delim=='L') { /* wide character constant */
+ if (delim=='L' || delim=='u' || delim=='U') { /* wide character constant */
+ if (delim=='u' && *loc=='8') { *++id_loc=*loc++; }
delim=*loc++; *++id_loc=delim;
}
- while (1) {
+ while (true) {
if (loc>=limit) {
if(*(limit-1)!='\\') {
err_print("! String didn't end"); loc=limit; break;
@.String didn't end@>
}
- if(get_line()==0) {
+ if(get_line()==false) {
err_print("! Input ended in middle of string"); loc=buffer; break;
@.Input ended in middle of string@>
}
@@ -1035,13 +1022,13 @@ convention, but do not allow the string to be longer than |longest_name|.
if (++id_loc<=section_text_end) *id_loc=c;
}
if (id_loc>=section_text_end) {
- printf("\n! String too long: ");
+ fputs("\n! String too long: ",stdout);
@.String too long@>
term_write(section_text+1,25);
err_print("...");
}
id_loc++;
- return(string);
+ return string;
}
@ After an \.{@@} sign has been scanned, the next character tells us
@@ -1061,10 +1048,10 @@ whether there is more work to do.
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);
+ @<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;
}
}
@@ -1093,18 +1080,18 @@ thus, \.{@@'\\nopq'} gives the same result as \.{@@'\\n'}.
}
}
loc++;
- return(ord);
+ return ord;
@ @<Scan the section name...@>= {
char *k; /* pointer into |section_text| */
- @<Put section name 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);
+ complain we're out of room@>@;
+ return section_name;
}
@ Section names are placed into the |section_text| array with consecutive spaces,
@@ -1117,14 +1104,14 @@ character of the name.)
@ @<Put section name...@>=
k=section_text;
-while (1) {
- if (loc>limit && get_line()==0) {
+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|@>;
+ @<If end of name or erroneous nesting, |break|@>@;
loc++; if (k<section_text_end) k++;
if (xisspace(c)) {
c=' '; if (*(k-1)==' ') k--;
@@ -1132,7 +1119,7 @@ while (1) {
*k=c;
}
if (k>=section_text_end) {
- printf("\n! Section name too long: ");
+ fputs("\n! Section name too long: ",stdout);
@.Section name too long@>
term_write(section_text+1,25);
printf("..."); mark_harmless;
@@ -1167,7 +1154,7 @@ buffer. We also set |loc| to the position just after the ending delimiter.
if (loc>=limit) err_print("! Verbatim string didn't end");
@.Verbatim string didn't end@>
id_loc=loc; loc+=2;
- return(string);
+ return string;
}
@* Scanning a macro definition.
@@ -1192,18 +1179,18 @@ acted, |cur_text| will point to the replacement text just generated, and
@d macro 0
@d app_repl(c) {if (tok_ptr==tok_mem_end) overflow("token"); *tok_ptr++=c;}
-@<Global...@>=
-text_pointer cur_text; /* replacement text formed by |scan_repl| */
-eight_bits next_control;
+@<Private...@>=
+static text_pointer cur_text; /* replacement text formed by |scan_repl| */
+static eight_bits next_control;
@ @c
-void
-scan_repl(t) /* creates a replacement text */
-eight_bits t;
+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 (1) switch (a=get_next()) {
+ 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,
@@ -1218,6 +1205,8 @@ eight_bits t;
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.
@@ -1232,8 +1221,8 @@ if (changing && include_depth==change_depth) { /* correction made Feb 2017 */
store_two_bytes((sixteen_bits)cur_line);
}
id_loc=id_first+strlen(id_first);
-{int a=id_lookup(id_first,id_loc,0)-name_dir; app_repl((a / 0400)+0200);
- app_repl(a % 0400);}
+{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;
@@ -1241,26 +1230,26 @@ case identifier: a=id_lookup(id_first,id_loc,0)-name_dir;
app_repl(a % 0400); break;
case section_name: if (t!=section_name) goto done;
else {
- @<Was an `@@' missed here?@>;
+ @<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;
+ @<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=1;
+ output_defs_seen=true;
a=output_defs_flag;
app_repl((a / 0400)+0200);
app_repl(a % 0400);
- @<Insert the line number into |tok_mem|@>;
+ @<Insert the line number into |tok_mem|@>@;
}
break;
case constant: case string:
- @<Copy a string or verbatim construction or numerical constant@>;
+ @<Copy a string or verbatim construction or numerical constant@>@;
case ord:
- @<Copy an ASCII constant@>;
+ @<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;
@@ -1268,7 +1257,7 @@ case definition: case format_code: case begin_C: if (t!=section_name) goto done;
}
case new_section: goto done;
-@ @<Was an `@@'...@>= {
+@ @<Was an `\.{@@}'...@>= {
char *try_loc=loc;
while (*try_loc==' ' && try_loc<limit) try_loc++;
if (*try_loc=='+' && try_loc<limit) try_loc++;
@@ -1320,12 +1309,12 @@ code internally.
if (xisdigit(*(id_first+1))) c=*(++id_first)-'0';
else if (xisxdigit(*(id_first+1))) {
++id_first;
- c=toupper(*id_first)-'A'+10;
+ 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(*id_first)-'A'+10;
+ c=16*c+toupper((eight_bits)*id_first)-'A'+10;
}
break;
case '\\':c='\\';@+break;
@@ -1350,28 +1339,25 @@ 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.
-@<Global...@>=
-extern sixteen_bits section_count; /* the current section number */
-
-@ The body of |scan_section| is a loop where we look for control codes
+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
-void
-scan_section()
+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=1;
+ section_count++; @+ no_where=true;
if (*(loc-1)=='*' && show_progress) { /* starred section */
printf("*%d",section_count); update_terminal;
}
next_control=0;
- while (1) {
+ while (true) {
@<Skip ahead until |next_control| corresponds to \.{@@d}, \.{@@<},
- \.{@@\ } or the like@>;
+ \.{@@\ } or the like@>@;
if (next_control == definition) { /* \.{@@d} */
@<Scan a definition@>@;
continue;
@@ -1381,15 +1367,17 @@ scan_section()
}
if (next_control == section_name) { /* \.{@@<} or \.{@@(} */
p=cur_section_name;
- @<If section is not being defined, |continue| @>;
+ @<If section is not being defined, |continue| @>@;
break;
}
return; /* \.{@@\ } or \.{@@*} */
}
- no_where=print_where=0;
- @<Scan the \CEE/ part of the current section@>;
+ 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
@@ -1404,7 +1392,7 @@ while (next_control<definition)
}
@ @<Scan a definition@>= {
- while ((next_control=get_next())=='\n'); /*allow newline before 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...@>
@@ -1417,7 +1405,7 @@ while (next_control<definition)
app_repl(string); app_repl(' '); app_repl(string);
}
scan_repl(macro);
- cur_text->text_link=0; /* |text_link==0| characterizes a macro */
+ cur_text->text_link=macro;
}
@ If the section name is not followed by \.{=} or \.{+=}, no \CEE/
@@ -1434,9 +1422,9 @@ if (next_control!='=' && next_control!=eq_eq)
continue;
@ @<Scan the \CEE/...@>=
-@<Insert the section number into |tok_mem|@>;
+@<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@>;
+@<Update the data structure so that the replacement text is accessible@>@;
@ @<Insert the section number...@>=
store_two_bytes((sixteen_bits)(0150000+section_count));
@@ -1446,7 +1434,7 @@ store_two_bytes((sixteen_bits)(0150000+section_count));
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==(char *)text_info) p->equiv=(char *)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;
@@ -1457,12 +1445,9 @@ else {
cur_text->text_link=section_flag;
/* mark this replacement text as a nonmacro */
-@ @<Predec...@>=
-void phase_one();
-
@ @c
-void
-phase_one() {
+static void
+phase_one(void) {
phase=1;
section_count=0;
reset_input();
@@ -1472,26 +1457,25 @@ phase_one() {
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.
-@<Predecl...@>=
-void skip_limbo();
-
-@ @c
-void
-skip_limbo()
+@c
+static void
+skip_limbo(void)
{
char c;
- while (1) {
- if (loc>limit && get_line()==0) return;
+ 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 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())=='@@');
@@ -1507,6 +1491,8 @@ skip_limbo()
}
}
+@ @<Predecl...@>=@+static void skip_limbo(void);
+
@ @<Read in transliteration of a character@>=
while(xisspace(*loc)&&loc<limit) loc++;
loc+=3;
@@ -1515,7 +1501,7 @@ skip_limbo()
err_print("! Improper hex number following @@l");
@.Improper hex number...@>
else {
- unsigned i;
+ unsigned int i;
char *beg;
sscanf(loc-3,"%x",&i);
while(xisspace(*loc)&&loc<limit) loc++;
@@ -1525,26 +1511,26 @@ skip_limbo()
err_print("! Replacement string in @@l too long");
@.Replacement string in @@l...@>
else{
- strncpy(translit[i-0200],beg,loc-beg);
+ 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 |long|
+@ 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() {
- printf("\nMemory usage statistics:\n");
+print_stats(void) {
+ puts("\nMemory usage statistics:");
printf("%ld names (out of %ld)\n",
- (long)(name_ptr-name_dir),(long)max_names);
+ (ptrdiff_t)(name_ptr-name_dir),(long)max_names);
printf("%ld replacement texts (out of %ld)\n",
- (long)(text_ptr-text_info),(long)max_texts);
+ (ptrdiff_t)(text_ptr-text_info),(long)max_texts);
printf("%ld bytes (out of %ld)\n",
- (long)(byte_ptr-byte_mem),(long)max_bytes);
+ (ptrdiff_t)(byte_ptr-byte_mem),(long)max_bytes);
printf("%ld tokens (out of %ld)\n",
- (long)(tok_ptr-tok_mem),(long)max_toks);
+ (ptrdiff_t)(tok_ptr-tok_mem),(long)max_toks);
}
@** Index.