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.w460
1 files changed, 240 insertions, 220 deletions
diff --git a/web/c_cpp/cweb/ctangle.w b/web/c_cpp/cweb/ctangle.w
index e7e2d311fe..1a9e8065af 100644
--- a/web/c_cpp/cweb/ctangle.w
+++ b/web/c_cpp/cweb/ctangle.w
@@ -2,7 +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 4.2 --- February 2021
+% Version 4.6 --- December 2021
% Copyright (C) 1987,1990,1993,2000 Silvio Levy and Donald E. Knuth
@@ -27,11 +27,11 @@
\mathchardef\RA="3221 % right arrow
\mathchardef\BA="3224 % double arrow
-\def\title{CTANGLE (Version 4.2)}
+\def\title{CTANGLE (Version 4.6)}
\def\topofcontents{\null\vfill
\centerline{\titlefont The {\ttitlefont CTANGLE} processor}
\vskip 15pt
- \centerline{(Version 4.2)}
+ \centerline{(Version 4.6)}
\vfill}
\def\botofcontents{\vfill
\noindent
@@ -61,7 +61,7 @@ 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)"
+@d banner "This is CTANGLE (Version 4.6)"
@c
@<Include files@>@/
@@ -75,7 +75,7 @@ is modified.
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
+Please read the documentation for \.{COMMON}, the set of routines common
to \.{CTANGLE} and \.{CWEAVE}, before proceeding further.
@c
@@ -126,7 +126,9 @@ typedef struct {
} text;
typedef text *text_pointer;
-@ @<Private...@>=
+@ @d max_texts 2500 /* number of replacement texts, must be less than 10240 */
+@d max_toks 270000 /* number of bytes in compressed \CEE/ code */
+@<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| */
@@ -151,14 +153,13 @@ init_node(name_dir); /* the undefined section has no replacement text */
starting at position |first| equals the identifier pointed to by |p|:
@c
-boolean names_match(@t\1\1@>
+boolean names_match(
name_pointer p, /* points to the proposed match */
const char *first, /* position of first character of string */
size_t l, /* length of identifier */
-eight_bits t@t\2\2@>) /* not used by \.{TANGLE} */
-{@+(void)t;
- if (length(p)!=l) return false;
- return !strncmp(first,p->byte_start,l);
+eight_bits t) /* not used by \.{TANGLE} */
+{@+(void)t;@/
+ return length(p)==l && strncmp(first,p->byte_start,l)==0;
}
@ The common lookup routine refers to separate routines |init_node| and
@@ -193,12 +194,13 @@ 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 macro 0
@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;
+@ @<Set init...@>= last_unnamed=text_info; text_info->text_link=macro;
@ 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
@@ -214,16 +216,19 @@ 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}).
+\yskip \hang |string| denotes the beginning or end of a string
+or a verbatim construction.
+
+\hang |constant| denotes a numerical constant.
-\hang |string| denotes the beginning or end of a string, verbatim
-construction or numerical constant.
+\hang |join| denotes the concatenation of adjacent items with no space
+or line breaks allowed between them (the \.{@@\&} operation of \.{CWEB}).
@^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)
+@d string 02 /* takes the place of ASCII \.{STX} */
+@d constant 03 /* takes the place of ASCII \.{ETX} */
+@d join 0177 /* takes the place of ASCII \.{DEL} */
+@d output_defs_flag (2*024000-1) /* |024000==(0250-0200)*0400| */
@ The following procedure is used to enter a two-byte value into
|tok_mem| when a replacement text is being generated.
@@ -276,7 +281,8 @@ typedef struct {
} output_state;
typedef output_state *stack_pointer;
-@ @d cur_end cur_state.end_field /* current ending location in |tok_mem| */
+@ @d stack_size 50 /* number of simultaneous levels of macro expansion */
+@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 */
@@ -308,8 +314,8 @@ We assume that the \CEE/ compiler can copy structures.
@c
static void
-push_level(@t\1\1@> /* suspends the current level */
-name_pointer p@t\2\2@>)
+push_level( /* suspends the current level */
+name_pointer p)
{
if (stack_ptr==stack_end) overflow("stack");
*stack_ptr=cur_state;
@@ -331,8 +337,8 @@ 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| */
+pop_level( /* do this when |cur_byte| reaches |cur_end| */
+boolean flag) /* |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 */
@@ -350,7 +356,7 @@ 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.)
+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.
@@ -384,11 +390,12 @@ get_output(void) /* sends next token to |out_char| */
else {
a=(a-0200)*0400+*cur_byte++;
switch (a/024000) { /* |024000==(0250-0200)*0400| */
- case 0: cur_val=a; out_char(identifier); break;
+ case 0: cur_val=(int)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;
+ default: cur_val=(int)a-050000;
+ if (cur_val>0) cur_section=(sixteen_bits)cur_val;
out_char(section_number);
}
}
@@ -463,7 +470,7 @@ flush_buffer(void) /* writes one line to output file */
{
C_putc('\n');
if (cur_line % 100 == 0 && show_progress) {
- printf(".");
+ putchar('.');
if (cur_line % 500 == 0) printf("%d",cur_line);
update_terminal; /* progress report */
}
@@ -502,9 +509,7 @@ complain we're out of room@>=
if (an_output_file==end_output_files) {
if (cur_out_file>output_files)
*--cur_out_file=cur_section_name;
- else {
- overflow("output files");
- }
+ else overflow("output files");
}
}
@@ -514,18 +519,21 @@ output.
@c
static void
phase_two (void) {
+ phase=2;
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) {
+ if (text_info->text_link==macro && 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)
+ if (cur_out_file==end_output_files) {
+ if (show_progress) {
printf("\nWriting the output file (%s):",C_file_name);
+ update_terminal;
+ }
}
else {
if (show_progress) {
@@ -534,7 +542,7 @@ phase_two (void) {
printf(" (%s)",C_file_name);
update_terminal;
}
- if (text_info->text_link==0) goto writeloop;
+ if (text_info->text_link==macro) goto writeloop;
}
while (stack_ptr>stack) get_output();
flush_buffer();
@@ -557,14 +565,14 @@ 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);
+ if ((C_file=fopen(output_file_name,"wb"))==NULL)
+ 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_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();
@@ -586,14 +594,17 @@ static boolean output_defs_seen=false;
static void output_defs(void);@/
static void out_char(eight_bits);
-@ @c
+@ @d C_printf(c,a) fprintf(C_file,c,a)
+@d C_putc(c) putc((int)(c),C_file) /* isn't \CEE/ wonderfully consistent? */
+
+@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 */
+ if (cur_text->text_link==macro) { /* |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 ");
@@ -609,11 +620,12 @@ output_defs(void)
else {
a=(a-0200)*0400+*cur_byte++;
if (a<024000) { /* |024000==(0250-0200)*0400| */
- cur_val=a; out_char(identifier);
+ cur_val=(int)a; out_char(identifier);
}
- else if (a<050000) { confusion("macro defs have strange char");}
+ else if (a<050000) confusion("macro defs have strange char");
else {
- cur_val=a-050000; cur_section=cur_val; out_char(section_number);
+ cur_val=(int)a-050000; cur_section=(sixteen_bits)cur_val;
+ out_char(section_number);
}
/* no other cases */
}
@@ -643,7 +655,7 @@ restart:
@/@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(' ');
+ case '=': case '>': C_putc(cur_char);@+C_putc(' ');
out_state=normal; break;
case join: out_state=unbreakable; break;
case constant: if (out_state==verbatim) {
@@ -659,7 +671,7 @@ restart:
}
}
-@ @<Cases like \.{!=}@>=
+@ @<Cases like \.{!=}@>=@t\1\quad@>
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;
@@ -697,41 +709,38 @@ static char translit[128][translit_length];
for (i=0;i<128;i++) sprintf(translit[i],"X%02X",(unsigned int)(128+i));
}
-@ @<Case of an identifier@>=
+@ @<Case of an identifier@>=@t\1\quad@>
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) {
+ for (j=(cur_val+name_dir)->byte_start, k=(cur_val+name_dir+1)->byte_start;
+ j<k; j++)
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 of a sec...@>=@t\1\quad@>
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';
+ cur_char = (eight_bits)'\n';
goto restart;
} else {
sixteen_bits a;
- a=0400* *cur_byte++;
+ a=*cur_byte++ *0400;
a+=*cur_byte++; /* gets the line number */
- C_printf("\n#line %d \"",a);
+ C_printf("\n#line %d \"",(int)a);
@:line}{\.{\#line}@>
- cur_val=*cur_byte++;
- cur_val=0400*(cur_val-0200)+ *cur_byte++; /* points to the file name */
+ cur_val=(int)(*cur_byte++-0200)*0400;
+ cur_val+=*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");
+ C_putc('"');@+C_putc('\n');
}
break;
@@ -756,7 +765,7 @@ 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 ignore 00 /* 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}' */
@@ -773,20 +782,20 @@ 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;
}
+ccode[' ']=ccode['\t']=ccode['\n']=ccode['\v']=ccode['\r']=ccode['\f']
+ =ccode['*']=new_section;
+ccode['@@']=(eight_bits)'@@'; 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.
@@ -817,7 +826,7 @@ 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}
+\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
@@ -831,15 +840,15 @@ No comment, long or short, is allowed to contain `\.{@@\ }' or `\.{@@*}'.
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@>)
+static boolean skip_comment( /* skips over comments */
+boolean is_long_comment)
{
char c; /* current character */
while (true) {
if (loc>limit) {
if (is_long_comment) {
- if(get_line()) return comment_continues=true;
- else{
+ if (get_line()) return comment_continues=true;
+ else {
err_print("! Input ended in mid-comment");
@.Input ended in mid-comment@>
return comment_continues=false;
@@ -864,8 +873,6 @@ boolean is_long_comment@t\2\2@>)
@* 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|? */
@@ -873,32 +880,26 @@ 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;
+ static boolean preprocessing=false;
eight_bits c; /* the current character */
while (true) {
if (loc>limit) {
- if (preprocessing && *(limit-1)!='\\') preprocessing=0;
+ if (preprocessing && *(limit-1)!='\\') preprocessing=false;
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';
+ else return (eight_bits)'\n';
}
- c=*loc;
+ c=(eight_bits)*loc;
if (comment_continues || (c=='/' && (*(loc+1)=='*' || *(loc+1)=='/'))) {
- skip_comment(comment_continues||*(loc+1)=='*');
+ if (skip_comment(comment_continues||*(loc+1)=='*')) return '\n';
/* scan to end of comment or newline */
- if (comment_continues) return '\n';
else continue;
}
loc++;
@@ -907,15 +908,16 @@ get_next(void) /* produces the next input token */
|| ((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))
+ else if (isalpha((int)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 return (eight_bits)' ';
+ /* ignore spaces and tabs, unless |preprocessing| */
}
- else if (c=='#' && loc==buffer+1) preprocessing=1;
+ else if (c=='#' && loc==buffer+1) preprocessing=true;
mistake: @<Compress two-symbol operator@>@;
return c;
}
@@ -924,30 +926,29 @@ get_next(void) /* produces the next input token */
@ @<Predecl...@>=@+static eight_bits get_next(void);
@ The following code assigns values to the combinations \.{++},
-\.{--}, \.{->}, \.{>=}, \.{<=}, \.{==}, \.{<<}, \.{>>}, \.{!=}, \.{||} and
-\.{\&\&}, and to the \CPLUSPLUS/
+\.{--}, \.{->}, \.{>=}, \.{<=}, \.{==}, \.{<<}, \.{>>}, \.{!=}, %\.{||}
+\.{\v\v} and~\.{\&\&}, and to the \CPLUSPLUS/
combinations \.{...}, \.{::}, \.{.*} and \.{->*}.
The compound assignment operators (e.g., \.{+=}) are
treated as separate tokens.
-@d compress(c) if (loc++<=limit) return c
-
@<Compress tw...@>=
switch(c) {
case '+': if (*loc=='+') compress(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);}
+ 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;
+ 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);}
+ case '>': if (*loc=='=') {@+compress(gt_eq);@+}
else if (*loc=='>') compress(gt_gt); break;
- case '<': if (*loc=='=') {compress(lt_eq);}
+ 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;
@@ -956,30 +957,41 @@ switch(c) {
@ @<Get an identifier@>= {
id_first=--loc;
- while (isalpha((eight_bits)*++loc) || isdigit((eight_bits)*loc) @|
- || isxalpha((eight_bits)*loc) || ishigh((eight_bits)*loc));
+ do
+ ++loc;
+ while (isalpha((int)*loc) || isdigit((int)*loc) @|
+ || isxalpha(*loc) || ishigh(*loc));
id_loc=loc; return identifier;
}
@ @<Get a constant@>= {
+ boolean hex_flag = false; /* are we reading a hexadecimal literal? */
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;
+ hex_flag = true;
+ loc++; while (xisxdigit(*loc) || *loc=='\'') loc++;
+ }
+ else if (*loc=='b' || *loc=='B') { /* binary constant */
+ loc++; while (*loc=='0' || *loc=='1' || *loc=='\'') loc++; goto found;
}
}
- while (xisdigit(*loc)) loc++;
+ while (xisdigit(*loc) || *loc=='\'') loc++;
if (*loc=='.') {
- loc++;
- while (xisdigit(*loc)) loc++;
+ loc++;
+ while ((hex_flag && xisxdigit(*loc)) || xisdigit(*loc) || *loc=='\'') loc++;
}
if (*loc=='e' || *loc=='E') { /* float constant */
if (*++loc=='+' || *loc=='-') loc++;
- while (xisdigit(*loc)) loc++;
+ while (xisdigit(*loc) || *loc=='\'') loc++;
}
- found: while (*loc=='u' || *loc=='U' || *loc=='l' || *loc=='L'
- || *loc=='f' || *loc=='F') loc++;
+ else if (hex_flag && (*loc=='p' || *loc=='P')) { /* hex float constant */
+ if (*++loc=='+' || *loc=='-') loc++;
+ while (xisxdigit(*loc) || *loc=='\'') loc++;
+ }
+found: while (*loc=='u' || *loc=='U' || *loc=='l' || *loc=='L'
+ || *loc=='f' || *loc=='F') loc++;
id_loc=loc;
return constant;
}
@@ -990,11 +1002,11 @@ 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 */
+ char delim = (char)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++; }
+ if (delim=='u' && *loc=='8') *++id_loc=*loc++;
delim=*loc++; *++id_loc=delim;
}
while (true) {
@@ -1010,16 +1022,16 @@ convention, but do not allow the string to be longer than |longest_name|.
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;
+ if ((c=(eight_bits)*loc++)==delim) {
+ if (++id_loc<=section_text_end) *id_loc=(char)c;
break;
}
if (c=='\\') {
if (loc>=limit) continue;
if (++id_loc<=section_text_end) *id_loc = '\\';
- c=*loc++;
+ c=(eight_bits)*loc++;
}
- if (++id_loc<=section_text_end) *id_loc=c;
+ if (++id_loc<=section_text_end) *id_loc=(char)c;
}
if (id_loc>=section_text_end) {
fputs("\n! String too long: ",stdout);
@@ -1034,25 +1046,23 @@ convention, but do not allow the string to be longer than |longest_name|.
@ 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;
+@<Get control code and possible section name@>=
+switch(c=ccode[(eight_bits)*loc++]) {
+ 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");
+ 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;
- }
+ 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
@@ -1063,9 +1073,8 @@ thus, \.{@@'\\nopq'} gives the same result as \.{@@'\\n'}.
@<Scan an ASCII constant@>=
id_first=loc;
- if (*loc=='\\') {
+ if (*loc=='\\')
if (*++loc=='\'') loc++;
- }
while (*loc!='\'') {
if (*loc=='@@') {
if (*(loc+1)!='@@')
@@ -1083,11 +1092,13 @@ thus, \.{@@'\\nopq'} gives the same result as \.{@@'\\n'}.
return ord;
@ @<Scan the section name...@>= {
- char *k; /* pointer into |section_text| */
+ char *k=section_text; /* 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);
+ cur_section_name=section_lookup(section_text+1,k-3,true);
+ /* |true| means it's a prefix */
+ else cur_section_name=section_lookup(section_text+1,k,false);
+ /* |false| means it's not */
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@>@;
@@ -1103,20 +1114,19 @@ 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;
+ c=(eight_bits)*loc;
@<If end of name or erroneous nesting, |break|@>@;
loc++; if (k<section_text_end) k++;
if (xisspace(c)) {
- c=' '; if (*(k-1)==' ') k--;
+ c=(eight_bits)' '; if (*(k-1)==' ') k--;
}
-*k=c;
+*k=(char)c;
}
if (k>=section_text_end) {
fputs("\n! Section name too long: ",stdout);
@@ -1128,7 +1138,7 @@ if (*k==' ' && k>section_text) k--;
@ @<If end of name or erroneous nesting,...@>=
if (c=='@@') {
- c=*(loc+1);
+ c=(eight_bits)*(loc+1);
if (c=='>') {
loc+=2; break;
}
@@ -1148,14 +1158,13 @@ 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");
+@<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;
-}
+id_loc=loc; loc+=2;
+return string;
@* Scanning a macro definition.
The rules for generating the replacement texts corresponding to macros and
@@ -1176,8 +1185,10 @@ ANSI \CEE/ preprocessor sometimes requires it.
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;}
+@d app_repl(c) {
+ if (tok_ptr==tok_mem_end) overflow("token");
+ else *(tok_ptr++)=(eight_bits)c;
+}
@<Private...@>=
static text_pointer cur_text; /* replacement text formed by |scan_repl| */
@@ -1185,13 +1196,13 @@ static eight_bits next_control;
@ @c
static void
-scan_repl(@t\1\1@> /* creates a replacement text */
-eight_bits t@t\2\2@>)
+scan_repl( /* creates a replacement text */
+eight_bits t)
{
sixteen_bits a; /* the current token */
- if (t==section_name) {@<Insert the line number into |tok_mem|@>@;}
+ 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|,
+ @/@t\4@>@<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@>@;
@@ -1211,31 +1222,36 @@ eight_bits t@t\2\2@>)
to |0150000|; then the numeric line number; then a pointer to the
file name.
+@d store_id(a) a=id_lookup(id_first,id_loc,'\0')-name_dir;@/
+ app_repl((a / 0400)+0200);
+ app_repl(a % 0400)
+
@<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);
+{
+ eight_bits a; /* shadow variable |a| */
+ 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);
+ store_id(a);
}
-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;
+@ @<In cases that |a| is...@>=@t\1\quad@>
+case identifier: store_id(a); 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;
+ @<Insert the line number into |tok_mem|@>@;
}
+ break;
case output_defs_code: if (t!=section_name) err_print("! Misplaced @@h");
@.Misplaced @@h@>
else {
@@ -1245,11 +1261,13 @@ case output_defs_code: if (t!=section_name) err_print("! Misplaced @@h");
app_repl(a % 0400);
@<Insert the line number into |tok_mem|@>@;
}
- break;
+ break;
case constant: case string:
@<Copy a string or verbatim construction or numerical constant@>@;
+ break;
case ord:
@<Copy an ASCII constant@>@;
+ break;
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 +1286,13 @@ case new_section: goto done;
as explained in the manual */
}
-@ @<Copy a string...@>=
+@ By default, \.{CTANGLE} purges single-quote characters from \CPLUSPLUS/-style
+literals, e.g., \.{1'000'000}, so that you can use this notation also in \CEE/
+code. The \.{+k} switch will `keep' the single quotes in the output.
+
+@d keep_digit_separators flags['k']
+
+@<Copy a string...@>=
app_repl(a); /* |string| or |constant| */
while (id_first < id_loc) { /* simplify \.{@@@@} pairs */
if (*id_first=='@@') {
@@ -1276,18 +1300,20 @@ case new_section: goto done;
else err_print("! Double @@ should be used in string");
@.Double @@ should be used...@>
}
+ else if (a==constant && *id_first=='\'' && !keep_digit_separators)
+ id_first++;
app_repl(*id_first++);
}
- app_repl(a); break;
+ app_repl(a);
@ 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;
+ int c=(int)((eight_bits) *id_first);
if (c=='\\') {
- c=*++id_first;
+ c=(int)((eight_bits) *++id_first);
if (c>='0' && c<='7') {
c-='0';
if (*(id_first+1)>='0' && *(id_first+1)<='7') {
@@ -1306,15 +1332,15 @@ code internally.
case 'a':c='\7';@+break;
case '?':c='?';@+break;
case 'x':
- if (xisdigit(*(id_first+1))) c=*(++id_first)-'0';
+ if (xisdigit(*(id_first+1))) c=(int)(*(++id_first)-'0');
else if (xisxdigit(*(id_first+1))) {
++id_first;
- c=toupper((eight_bits)*id_first)-'A'+10;
+ c=toupper((int)*id_first)-'A'+10;
}
- if (xisdigit(*(id_first+1))) c=16*c+*(++id_first)-'0';
+ if (xisdigit(*(id_first+1))) c=16*c+(int)(*(++id_first)-'0');
else if (xisxdigit(*(id_first+1))) {
++id_first;
- c=16*c+toupper((eight_bits)*id_first)-'A'+10;
+ c=16*c+toupper((int)*id_first)-(int)'A'+10;
}
break;
case '\\':c='\\';@+break;
@@ -1326,12 +1352,11 @@ code internally.
}@/
/* 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);
+ if (c>=100) app_repl((int)'0'+c/100);
+ if (c>=10) app_repl((int)'0'+(c/10)%10);
+ app_repl((int)'0'+c%10);
app_repl(constant);
}
-break;
@* Scanning a section.
The |scan_section| procedure starts when `\.{@@\ }' or `\.{@@*}' has been
@@ -1352,17 +1377,17 @@ scan_section(void)
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;
+ printf("*%d",(int)section_count); update_terminal;
}
- next_control=0;
+ next_control=ignore;
while (true) {
@<Skip ahead until |next_control| corresponds to \.{@@d}, \.{@@<},
\.{@@\ } or the like@>@;
- if (next_control == definition) { /* \.{@@d} */
+ if (next_control == definition) { /* \.{@@d} */
@<Scan a definition@>@;
continue;
}
- if (next_control == begin_C) { /* \.{@@c} or \.{@@p} */
+ if (next_control == begin_C) { /* \.{@@c} or \.{@@p} */
p=name_dir; break;
}
if (next_control == section_name) { /* \.{@@<} or \.{@@(} */
@@ -1391,22 +1416,19 @@ while (next_control<definition)
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");
+@ @<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;
+ continue;
}
+store_id(a); /* append the lhs */
+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
@@ -1431,8 +1453,8 @@ 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;
+if (p==name_dir||p==NULL) { /* 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 */
@@ -1454,7 +1476,6 @@ phase_one(void) {
skip_limbo();
while (!input_has_ended) scan_section();
check_complete();
- phase=2;
}
@ @<Predec...@>=@+static void phase_one(void);
@@ -1466,19 +1487,18 @@ processing is straightforward.
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;
+ char c=*loc++;
switch (ccode[(eight_bits)c]) {
+ case new_section: return;
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())=='@@');
+ while ((c=(char)skip_ahead())=='@@');
if (*(loc-1)!='>')
err_print("! Double @@ should be used in control text");
@.Double @@ should be used...@>
@@ -1517,19 +1537,19 @@ skip_limbo(void)
}
@ Because on some systems the difference between two pointers is a |ptrdiff_t|
-but not an |int|, we use \.{\%ld} to print these quantities.
+but not an |int|, we use \.{\%td} to print these quantities.
@c
void
print_stats(void) {
puts("\nMemory usage statistics:");
- printf("%ld names (out of %ld)\n",
+ printf("%td names (out of %ld)\n",
(ptrdiff_t)(name_ptr-name_dir),(long)max_names);
- printf("%ld replacement texts (out of %ld)\n",
+ printf("%td replacement texts (out of %ld)\n",
(ptrdiff_t)(text_ptr-text_info),(long)max_texts);
- printf("%ld bytes (out of %ld)\n",
+ printf("%td bytes (out of %ld)\n",
(ptrdiff_t)(byte_ptr-byte_mem),(long)max_bytes);
- printf("%ld tokens (out of %ld)\n",
+ printf("%td tokens (out of %ld)\n",
(ptrdiff_t)(tok_ptr-tok_mem),(long)max_toks);
}