diff --git a/.gitattributes b/.gitattributes index ceeed23..4fcb02b 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,3 +1,6 @@ [Git-archive] .gitattributes export-ignore README.md export-ignore +my-changes.md export-ignore +testthings.w export-ignore +indentation.w export-ignore diff --git a/Makefile b/Makefile index 0c20d83..5859421 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ # This file is part of CWEB. # It is distributed WITHOUT ANY WARRANTY, express or implied. -# Version 4.2 --- February 2021 +# Version 4.3 --- May 2021 # Copyright (C) 1987,1990,1993,2000 Silvio Levy and Donald E. Knuth @@ -74,14 +74,14 @@ CWEAVE = ./cweave CTANGLE = ./ctangle SOURCES = cweave.w common.w ctangle.w ALL = common.w ctangle.w cweave.w prod.w \ - Makefile common.c common.h ctangle.c \ + Makefile README common.c common.h ctangle.c \ cwebman.tex cwebmac.tex comm-vms.ch ctang-vms.ch \ cweav-vms.ch comm-man.ch ctang-man.ch cweav-man.ch \ comm-pc.ch ctang-pc.ch cweav-pc.ch comm-amiga.ch \ comm-bs.ch ctang-bs.ch cweav-bs.ch makefile.bs \ comm-ql.ch ctang-ql.ch cweav-ql.ch readme.ql \ comm-w32.ch ctang-w32.ch cweav-w32.ch \ - comm-os2.ch comm-mac.ch cweb.1 cweb.el c++lib.w README + comm-os2.ch comm-mac.ch cweb.1 cweb.el c++lib.w iso_types.w .SUFFIXES: .dvi .tex .w .pdf @@ -183,6 +183,8 @@ install: all - mkdir $(CWEBINPUTS) $(CP) c++lib.w $(CWEBINPUTS) chmod 644 $(CWEBINPUTS)/c++lib.w + $(CP) iso_types.w $(CWEBINPUTS) + chmod 644 $(CWEBINPUTS)/iso_types.w floppy: $(ALL) examples bar cvhf /dev/rfd0 $(ALL) examples diff --git a/README b/README index 081dc5a..e2caca4 100644 --- a/README +++ b/README @@ -1,7 +1,7 @@ % This file is part of CWEB. % The CWEB programs by Silvio Levy are based on programs by D. E. Knuth. % They are distributed WITHOUT ANY WARRANTY, express or implied. -% This README file last updated February 2021 by Andreas Scherer +% This README file last updated May 2021 by Andreas Scherer % Copyright (C) 1987,1990,1993,2000,2016 Silvio Levy and Donald E. Knuth @@ -66,14 +66,16 @@ makefile.bs prod.w readme.ql c++lib.w +iso_types.w The file cwebman.tex is the user manual. The examples directory contains additional examples of the use of CWEB. The files common.c and ctangle.c are used for bootstrapping. The file cweb.1 is a manual page. The file cweb.el is suggested for GNU-Emacs users. -The file c++lib.w is for C++ users (say `@i c++lib.w' at beginning of program). -The files *-man.ch are used if you want to make the full 240-page CWEB manual. +The files c++lib.w and iso_types.w are for C++ users (say `@i c++lib.w' +and/or `@i iso_types.w' at beginning of program). +The files *-man.ch are used if you want to make the full 243-page CWEB manual. The files *-bs.ch are used instead of *-pc.ch if you are doing BIG programs. You can use makefile.bs to make CWEB with *-bs.ch. The files *-ql.ch are for QDOS/SMSQ systems; see readme.ql for further info. diff --git a/README.md b/README.md index 7b8177e..fa56c6e 100644 --- a/README.md +++ b/README.md @@ -1,22 +1,25 @@ -# cweb 4.2 +# cweb 4.3 people have been accumulating several decades of experience with [cweb](http://www-cs-faculty.stanford.edu/~uno/cweb.html), and we know that ctangle and cweave work reasonably well on numerous platforms. in general those programs are now entirely stable: don knuth won't be changing them any more, because they've proved their value in extensive use. (henceforth he must -devote full time to the art of computer programming!) +devote full time to +[the art of computer programming](https://www-cs-faculty.stanford.edu/~knuth/taocp.html)!) however, further significant developments, including versions that don himself does not maintain, are ongoing. all of the really current news about cweb is, -in fact, now to be found in this cweb development project. +in fact, now to be found in this cweb development project. Check out the +details in the +[releases description](https://github.com/ascherer/cweb/releases). # software archæology besides for further development, this ‘project’ is used as an – obviously incomplete – repository of original release versions of levy/knuth [cweb](http://www-cs-faculty.stanford.edu/~uno/cweb.html). you can either -compile these sources directly or stick the recent version “cweb-4.2” into my +compile these sources directly or stick the recent version “cweb-4.3” into my [cwebbin](https://github.com/ascherer/cwebbin), which introduces convenient extensions and prepares cweb for inclusion in the “tex live” distribution. diff --git a/comm-amiga.ch b/comm-amiga.ch index f17c2d3..fecfc94 100644 --- a/comm-amiga.ch +++ b/comm-amiga.ch @@ -10,7 +10,7 @@ An omitted change file argument means that |"/dev/null"| should be used, An omitted change file argument means that |"nil:"| should be used, @z -@x section 76 +@x section 75 strcpy(change_file_name,"/dev/null"); @y strcpy(change_file_name,"nil:"); diff --git a/comm-bs.ch b/comm-bs.ch index b01b867..d121e3d 100644 --- a/comm-bs.ch +++ b/comm-bs.ch @@ -15,7 +15,7 @@ by using "huge" pointers. (Update attempt by Andreas Scherer, 31 Jan 2021. Good luck!) -@x Section 6. +@x Section 9. for section names */ @= @@ -50,7 +50,7 @@ typedef struct name_info { union { void huge* equiv_member; void huge* xref_member; - } ptr_union; /* info corresponding to names */ + } ptr_union; /* info corresponding to names */ } name_info; /* contains information about an identifier or section name */ typedef name_info *name_pointer; /* pointer into array of \&{name\_info}s */ typedef name_pointer *hash_pointer; @@ -136,23 +136,23 @@ name_pointer p) @x Section 57. static name_pointer -add_section_name(@t\1\1@> /* install a new node in the tree */ +add_section_name( /* install a new node in the tree */ name_pointer par, /* parent of new node */ int c, /* right or left? */ char *first, /* first character of section name */ char *last, /* last character of section name, plus one */ -int ispref@t\2\2@>) /* are we adding a prefix or a full name? */ +boolean ispref) /* are we adding a prefix or a full name? */ { name_pointer p=name_ptr; /* new node */ char *s=first_chunk(p); @y static name_pointer -add_section_name(@t\1\1@> /* install a new node in the tree */ +add_section_name( /* install a new node in the tree */ name_pointer par, /* parent of new node */ int c, /* right or left? */ char huge* first, /* first character of section name */ char huge* last, /* last character of section name, plus one */ -int ispref@t\2\2@>) /* are we adding a prefix or a full name? */ +boolean ispref) /* are we adding a prefix or a full name? */ { name_pointer p=name_ptr; /* new node */ char huge* s=first_chunk(p); @@ -161,39 +161,39 @@ int ispref@t\2\2@>) /* are we adding a prefix or a full name? */ @x Section 58. static void -extend_section_name(@t\1\1@> +extend_section_name( name_pointer p, /* name to be extended */ char *first, /* beginning of extension text */ char *last, /* one beyond end of extension text */ -int ispref@t\2\2@>) /* are we adding a prefix or a full name? */ +boolean ispref) /* are we adding a prefix or a full name? */ { char *s; @y static void -extend_section_name(@t\1\1@> +extend_section_name( name_pointer p, /* name to be extended */ char huge* first, /* beginning of extension text */ char huge* last, /* one beyond end of extension text */ -int ispref@t\2\2@>) /* are we adding a prefix or a full name? */ +boolean ispref) /* are we adding a prefix or a full name? */ { char huge* s; @z -@x Section 64. -static int section_name_cmp(@t\1\1@> +@x Section 63. +static int section_name_cmp( char **pfirst, /* pointer to beginning of comparison string */ int len, /* length of string */ -name_pointer r@t\2\2@>) /* section name being compared */ +name_pointer r) /* section name being compared */ { char *first=*pfirst; /* beginning of comparison string */ name_pointer q=r+1; /* access to subsequent chunks */ char *ss, *s=first_chunk(r); @y -static int section_name_cmp(@t\1\1@> +static int section_name_cmp( char huge** pfirst, /* pointer to beginning of comparison string */ int len, /* length of string */ -name_pointer r@t\2\2@>) /* section name being compared */ +name_pointer r) /* section name being compared */ { char huge* first=*pfirst; /* beginning of comparison string */ name_pointer q=r+1; /* access to subsequent chunks */ @@ -208,14 +208,14 @@ An omitted change file argument means that |"NUL"| should be used, @z -@x Section 76. +@x Section 75. strcpy(change_file_name,"/dev/null"); @y strcpy(change_file_name,"NUL"); @z -@x Section 76. +@x Section 75. else if (*s=='/') dot_pos=NULL,name_pos=++s; @y else if (*s == ':' || *s == '\\' || *s == '/') diff --git a/comm-mac.ch b/comm-mac.ch index aa3a77f..895566d 100644 --- a/comm-mac.ch +++ b/comm-mac.ch @@ -4,27 +4,24 @@ No changes to CTANGLE or CWEAVE are needed. (Contributed 13 Oct 2000 by AndPio@aol.com; slightly edited by Don Knuth) @x in limbo, change the title page document to specify Mac version - \centerline{(Version 4.2)} + \centerline{(Version 4.3)} @y - \centerline{(Version 4.2 for MacOS)} + \centerline{(Version 4.3 for MacOS)} @z -@x sections 23/24: Make input_ln accept \n, \r, \n\r, or \r\n as line endings +@x section 23: Make input_ln accept \n, \r, \n\r, or \r\n as line endings @ In the unlikely event that your standard I/O library does not support |feof|, |getc|, and |ungetc| you may have to change things here. @^system dependencies@> -@= -static boolean input_ln(FILE *);@/ - -@ @c -static boolean input_ln(@t\1\1@> /* copies a line into |buffer| or returns |false| */ -FILE *fp@t\2\2@>) /* what file to read from */ +@c +static boolean input_ln( /* copies a line into |buffer| or returns |false| */ +FILE *fp) /* what file to read from */ { - register int c=EOF; /* character read; initialized so some compilers won't complain */ - register char *k; /* where next character goes */ - if (feof(fp)) return false; /* we have hit end-of-file */ - limit = k = buffer; /* beginning of buffer */ + register int c=EOF; /* character read; initialized so some compilers won't complain */ + register char *k; /* where next character goes */ + if (feof(fp)) return false; /* we have hit end-of-file */ + limit = k = buffer; /* beginning of buffer */ while (k<=buffer_end && (c=getc(fp)) != EOF && c!='\n') if ((*(k++) = c) != ' ') limit = k; if (k>buffer_end) @@ -32,7 +29,7 @@ FILE *fp@t\2\2@>) /* what file to read from */ ungetc(c,fp); loc=buffer; err_print("! Input line too long"); @.Input line too long@> } - if (c==EOF && limit==buffer) return false; /* there was nothing after + if (c==EOF && limit==buffer) return false; /* there was nothing after the last newline */ return true; } @@ -45,17 +42,14 @@ line endings, so that \.{CWEB} will works with ASCII files stored in \UNIX/, {\mc DOS} or {\mc MAC} format. @^system dependencies@> -@= -static boolean input_ln(FILE *);@/ - -@ @c -static boolean input_ln(@t\1\1@> /* copies a line into |buffer| or returns |false| */ -FILE *fp@t\2\2@>) /* what file to read from */ +@c +static boolean input_ln( /* copies a line into |buffer| or returns |false| */ +FILE *fp) /* what file to read from */ { register int c=EOF; /* character read; initialized so some compilers won't complain */ - register char *k; /* where next character goes */ - if (feof(fp)) return false; /* we have hit end-of-file */ - limit = k = buffer; /* beginning of buffer */ + register char *k; /* where next character goes */ + if (feof(fp)) return false; /* we have hit end-of-file */ + limit = k = buffer; /* beginning of buffer */ while (true) { c = getc(fp); if (c==EOF) return limit!=buffer; /* |false|, if there was nothing after @@ -77,7 +71,7 @@ FILE *fp@t\2\2@>) /* what file to read from */ } @z -@x section 28, simply return if no change file was specified +@x section 27, simply return if no change file was specified change_limit=change_buffer; /* this value is used if the change file ends */ @@; @y @@ -121,20 +115,19 @@ An omitted change file argument means that |"/dev/null"| should be used, @y An omitted change file argument means that no change file should be used, @z - -@x section 76, make change file name empty when it is unspecified +@x section 75, make change file name empty when it is unspecified strcpy(change_file_name,"/dev/null"); @y change_file_name[0]='\0'; /* empty string */ @z -@x section 76, use the Metrowerks |ccommand| to access command lines +@x section 75, use the Metrowerks |ccommand| to access command lines while (--argc > 0) { @y argc = ccommand (&argv); /* use Mac interface to command line */ @^system dependencies@> while (--argc > 0) { @z -@x section 76, use the path separator constant +@x section 75, use the path separator constant else if (*s=='/') dot_pos=NULL,name_pos=++s; @y else if (*s==PATH_SEP) dot_pos=NULL,name_pos=++s; diff --git a/comm-os2.ch b/comm-os2.ch index 2b85f8b..d818863 100644 --- a/comm-os2.ch +++ b/comm-os2.ch @@ -10,13 +10,13 @@ An omitted change file argument means that |"/dev/null"| should be used, An omitted change file argument means that |"NUL"| should be used, @z -@x section 76 +@x section 75 strcpy(change_file_name,"/dev/null"); @y strcpy(change_file_name,"NUL"); @z -@x section 76 (this change copied from comm-pc.ch) +@x section 75 (this change copied from comm-pc.ch) else if (*s=='/') dot_pos=NULL,name_pos=++s; @y else if (*s == ':' || *s == '\\' || *s == '/') diff --git a/comm-pc.ch b/comm-pc.ch index 5f7d9c4..9e156ad 100644 --- a/comm-pc.ch +++ b/comm-pc.ch @@ -19,13 +19,13 @@ An omitted change file argument means that |"/dev/null"| should be used, An omitted change file argument means that |"NUL"| should be used, @z -@x section 76 +@x section 75 strcpy(change_file_name,"/dev/null"); @y strcpy(change_file_name,"NUL"); @z -@x section 76 (this change copied from comm-bs.ch, July 94) +@x section 75 (this change copied from comm-bs.ch, July 94) else if (*s=='/') dot_pos=NULL,name_pos=++s; @y else if (*s == ':' || *s == '\\' || *s == '/') diff --git a/comm-ql.ch b/comm-ql.ch index c03b918..bde4a1a 100644 --- a/comm-ql.ch +++ b/comm-ql.ch @@ -10,24 +10,24 @@ ex cc;'-v -h -c -=500000 -DCWEBINPUTS=flp2_ common_c' @x \def\v{\char'174} % vertical (|) in typewriter font -\def\title{Common code for CTANGLE and CWEAVE (Version 4.2)} +\def\title{Common code for CTANGLE and CWEAVE (Version 4.3)} \def\topofcontents{\null\vfill \centerline{\titlefont Common code for {\ttitlefont CTANGLE} and {\ttitlefont CWEAVE}} \vskip 15pt - \centerline{(Version 4.2)} + \centerline{(Version 4.3)} \vfill} \def\botofcontents{\vfill \noindent @y \def\v{\char'174} % vertical (|) in typewriter font -\def\title{Common code for CTANGLE and CWEAVE (QL Version 4.2)} +\def\title{Common code for CTANGLE and CWEAVE (QL Version 4.3)} \def\topofcontents{\null\vfill \centerline{\titlefont Common code for {\ttitlefont CTANGLE} and {\ttitlefont CWEAVE}} \vskip 15pt - \centerline{(Version 4.2)} + \centerline{(Version 4.3)} \vfill} \def\botofcontents{\vfill \noindent diff --git a/comm-vms.ch b/comm-vms.ch index caf8ece..9be9b2b 100644 --- a/comm-vms.ch +++ b/comm-vms.ch @@ -34,7 +34,7 @@ modified: @x section 68 (01-FEB-1992 ST) programs are started. Here, for instance, we pass the operating system -a status of 0 if and only if only harmless messages were printed. +a status of |EXIT_SUCCESS| if and only if only harmless messages were printed. @y programs are started. Here, for instance, we pass VAX/VMS a status of |SS$_NORMAL| if and only if only harmless @@ -67,7 +67,7 @@ An omitted change file argument means that the null device |"NL:"| should be used, when no changes are desired. @z -@x section 76 (1987 BL) (01-FEB-1992 ST) (05-APR-1992 DEK) +@x section 75 (1987 BL) (01-FEB-1992 ST) (05-APR-1992 DEK) strcpy(change_file_name,"/dev/null"); @y strcpy(change_file_name,"NL:"); diff --git a/comm-w32.ch b/comm-w32.ch index d256ced..38c2099 100644 --- a/comm-w32.ch +++ b/comm-w32.ch @@ -52,13 +52,13 @@ An omitted change file argument means that |"/dev/null"| should be used, An omitted change file argument means that |"NUL"| should be used, @z -@x section 76 +@x section 75 strcpy(change_file_name,"/dev/null"); @y strcpy(change_file_name,"NUL"); @z -@x section 76 (this change copied from comm-bs.ch, July 94) +@x section 75 (this change copied from comm-bs.ch, July 94) else if (*s=='/') dot_pos=NULL,name_pos=++s; @y else if (*s == ':' || *s == '\\' || *s == '/') diff --git a/common.c b/common.c index 7dd0f0c..3480c86 100644 --- a/common.c +++ b/common.c @@ -1,8 +1,8 @@ /*1:*/ -#line 66 "common.w" +#line 62 "common.w" /*3:*/ -#line 46 "common.h" +#line 44 "common.h" #include #include @@ -13,7 +13,7 @@ #include /*:3*/ -#line 67 "common.w" +#line 63 "common.w" #define ctangle false #define cweave true \ @@ -34,12 +34,18 @@ #define period_ast 026 #define minus_gt_ast 027 \ -#define xisalpha(c) (isalpha((eight_bits) c) &&((eight_bits) c<0200) ) -#define xisdigit(c) (isdigit((eight_bits) c) &&((eight_bits) c<0200) ) -#define xisspace(c) (isspace((eight_bits) c) &&((eight_bits) c<0200) ) -#define xislower(c) (islower((eight_bits) c) &&((eight_bits) c<0200) ) -#define xisupper(c) (isupper((eight_bits) c) &&((eight_bits) c<0200) ) -#define xisxdigit(c) (isxdigit((eight_bits) c) &&((eight_bits) c<0200) ) \ +#define compress(c) if(loc++<=limit) return c \ + +#define xisalpha(c) (isalpha((eight_bits) (c) ) &&((eight_bits) (c) <0200) ) +#define xisdigit(c) (isdigit((eight_bits) (c) ) &&((eight_bits) (c) <0200) ) +#define xisspace(c) (isspace((eight_bits) (c) ) &&((eight_bits) (c) <0200) ) +#define xislower(c) (islower((eight_bits) (c) ) &&((eight_bits) (c) <0200) ) +#define xisupper(c) (isupper((eight_bits) (c) ) &&((eight_bits) (c) <0200) ) +#define xisxdigit(c) (isxdigit((eight_bits) (c) ) &&((eight_bits) (c) <0200) ) +#define isxalpha(c) ((c) =='_'||(c) =='$') \ + +#define ishigh(c) ((eight_bits) (c) > 0177) \ + \ #define max_include_depth 10 \ @@ -61,23 +67,20 @@ #define harmless_message 1 #define error_message 2 #define fatal_message 3 -#define mark_harmless {if(history==spotless) history= harmless_message;} +#define mark_harmless if(history==spotless) history= harmless_message #define mark_error history= error_message #define confusion(s) fatal("! This can't happen: ",s) \ \ #define show_banner flags['b'] #define show_progress flags['p'] -#define show_stats flags['s'] #define show_happiness flags['h'] +#define show_stats flags['s'] #define make_xrefs flags['x'] \ #define update_terminal fflush(stdout) #define new_line putchar('\n') -#define putxchar putchar -#define term_write(a,b) fflush(stdout) ,fwrite(a,sizeof(char) ,b,stdout) -#define C_printf(c,a) fprintf(C_file,c,a) -#define C_putc(c) putc(c,C_file) \ +#define term_write(a,b) fflush(stdout) ,fwrite(a,sizeof(char) ,b,stdout) \ #define max_bytes 1000000 \ @@ -94,7 +97,8 @@ #define lines_dont_match (change_limit-change_buffer!=limit-buffer|| \ strncmp(buffer,change_buffer,(size_t) (limit-buffer) ) ) \ -#define if_section_start_make_pending(b) {*limit= '!'; \ +#define if_section_start_make_pending(b) { \ +*limit= '!'; \ for(loc= buffer;xisspace(*loc) ;loc++) ; \ *limit= ' '; \ if(*loc=='@'&&(xisspace(*(loc+1) ) ||*(loc+1) =='*') ) change_pending= b; \ @@ -121,10 +125,10 @@ err_print("! Include file name too long") ;goto restart;} \ #define flag_change (**argv!='-') -#line 68 "common.w" +#line 64 "common.w" /*2:*/ -#line 37 "common.h" +#line 35 "common.h" typedef bool boolean; typedef uint8_t eight_bits; @@ -141,7 +145,7 @@ extern char*id_first; extern char*id_loc; /*:4*//*5:*/ -#line 88 "common.h" +#line 92 "common.h" extern char buffer[]; extern char*buffer_end; @@ -149,7 +153,7 @@ extern char*loc; extern char*limit; /*:5*//*6:*/ -#line 105 "common.h" +#line 109 "common.h" extern int include_depth; extern FILE*file[]; @@ -165,7 +169,7 @@ extern boolean changing; extern boolean web_file_open; /*:6*//*8:*/ -#line 125 "common.h" +#line 129 "common.h" extern sixteen_bits section_count; extern boolean changed_section[]; @@ -173,7 +177,7 @@ extern boolean change_pending; extern boolean print_where; /*:8*//*9:*/ -#line 139 "common.h" +#line 143 "common.h" typedef struct name_info{ char*byte_start; @@ -198,12 +202,12 @@ extern hash_pointer hash_end; extern hash_pointer h; /*:9*//*11:*/ -#line 183 "common.h" +#line 187 "common.h" extern int history; /*:11*//*13:*/ -#line 199 "common.h" +#line 203 "common.h" extern int argc; extern char**argv; @@ -214,7 +218,7 @@ extern char scn_file_name[]; extern boolean flags[]; /*:13*//*14:*/ -#line 215 "common.h" +#line 217 "common.h" extern FILE*C_file; extern FILE*tex_file; @@ -223,20 +227,20 @@ extern FILE*scn_file; extern FILE*active_file; /*:14*/ -#line 69 "common.w" +#line 65 "common.w" /*18:*/ -#line 83 "common.w" +#line 79 "common.w" boolean program; /*:18*//*19:*/ -#line 92 "common.w" +#line 88 "common.w" int phase; /*:19*//*21:*/ -#line 130 "common.w" +#line 126 "common.w" char section_text[longest_name+1]; char*section_text_end= section_text+longest_name; @@ -244,7 +248,7 @@ char*id_first; char*id_loc; /*:21*//*22:*/ -#line 150 "common.w" +#line 146 "common.w" char buffer[long_buf_size]; char*buffer_end= buffer+buf_size-2; @@ -252,7 +256,7 @@ char*loc= buffer; char*limit= buffer; /*:22*//*25:*/ -#line 194 "common.w" +#line 190 "common.w" int include_depth; FILE*file[max_include_depth]; @@ -269,13 +273,13 @@ boolean changing; boolean web_file_open= false; /*:25*//*26:*/ -#line 220 "common.w" +#line 216 "common.w" static char change_buffer[buf_size]; static char*change_limit; /*:26*//*37:*/ -#line 399 "common.w" +#line 396 "common.w" sixteen_bits section_count; boolean changed_section[max_sections]; @@ -284,7 +288,7 @@ boolean change_pending; boolean print_where= false; /*:37*//*43:*/ -#line 596 "common.w" +#line 593 "common.w" char byte_mem[max_bytes]; char*byte_mem_end= byte_mem+max_bytes-1; @@ -292,25 +296,25 @@ name_info name_dir[max_names]; name_pointer name_dir_end= name_dir+max_names-1; /*:43*//*44:*/ -#line 607 "common.w" +#line 604 "common.w" char*byte_ptr; name_pointer name_ptr; /*:44*//*46:*/ -#line 627 "common.w" +#line 624 "common.w" name_pointer hash[hash_size]; hash_pointer hash_end= hash+hash_size-1; hash_pointer h; /*:46*//*65:*/ -#line 1014 "common.w" +#line 1006 "common.w" int history= spotless; /*:65*//*73:*/ -#line 1135 "common.w" +#line 1129 "common.w" int argc; char**argv; @@ -321,7 +325,7 @@ char scn_file_name[max_file_name_length]; boolean flags[128]; /*:73*//*83:*/ -#line 1282 "common.w" +#line 1272 "common.w" FILE*C_file; FILE*tex_file; @@ -330,22 +334,22 @@ FILE*scn_file; FILE*active_file; /*:83*/ -#line 70 "common.w" +#line 66 "common.w" /*7:*/ -#line 119 "common.h" +#line 123 "common.h" extern boolean get_line(void); extern void check_complete(void); extern void reset_input(void); /*:7*//*10:*/ -#line 162 "common.h" +#line 166 "common.h" extern boolean names_match(name_pointer,const char*,size_t,eight_bits); extern name_pointer id_lookup(const char*,const char*,char); -extern name_pointer section_lookup(char*,char*,int); +extern name_pointer section_lookup(char*,char*,boolean); extern void init_node(name_pointer); extern void init_p(name_pointer,eight_bits); extern void print_prefix_name(name_pointer); @@ -353,7 +357,7 @@ extern void print_section_name(name_pointer); extern void sprint_section_name(char*,name_pointer); /*:10*//*12:*/ -#line 186 "common.h" +#line 190 "common.h" extern int wrap_up(void); extern void err_print(const char*); @@ -361,50 +365,50 @@ extern void fatal(const char*,const char*); extern void overflow(const char*); /*:12*//*15:*/ -#line 223 "common.h" +#line 225 "common.h" extern void common_init(void); extern void print_stats(void); /*:15*//*24:*/ -#line 180 "common.w" +#line 176 "common.w" static boolean input_ln(FILE*); /*:24*//*28:*/ -#line 241 "common.w" +#line 237 "common.w" static void prime_the_change_buffer(void); /*:28*//*33:*/ -#line 340 "common.w" +#line 337 "common.w" static void check_change(void); /*:33*//*55:*/ -#line 774 "common.w" +#line 767 "common.w" static int web_strcmp(char*,int,char*,int); -static name_pointer add_section_name(name_pointer,int,char*,char*,int); -static void extend_section_name(name_pointer,char*,char*,int); +static name_pointer add_section_name(name_pointer,int,char*,char*,boolean); +static void extend_section_name(name_pointer,char*,char*,boolean); /*:55*//*64:*/ -#line 1002 "common.w" +#line 994 "common.w" static int section_name_cmp(char**,int,name_pointer); /*:64*//*76:*/ -#line 1197 "common.w" +#line 1189 "common.w" static void scan_args(void); /*:76*/ -#line 71 "common.w" +#line 67 "common.w" /*:1*//*20:*/ -#line 99 "common.w" +#line 95 "common.w" void common_init(void) { /*45:*/ -#line 611 "common.w" +#line 608 "common.w" name_dir->byte_start= byte_ptr= byte_mem; name_ptr= name_dir+1; @@ -412,24 +416,23 @@ name_ptr->byte_start= byte_mem; root= NULL; /*:45*//*47:*/ -#line 634 "common.w" +#line 631 "common.w" for(h= hash;h<=hash_end;*h++= NULL); /*:47*/ -#line 103 "common.w" +#line 99 "common.w" /*74:*/ -#line 1148 "common.w" +#line 1142 "common.w" show_banner= show_happiness= show_progress= make_xrefs= true; -show_stats= false; /*:74*/ -#line 104 "common.w" +#line 100 "common.w" /*84:*/ -#line 1289 "common.w" +#line 1279 "common.w" scan_args(); if(program==ctangle){ @@ -443,12 +446,12 @@ fatal("! Cannot open output file ",tex_file_name); } /*:84*/ -#line 105 "common.w" +#line 101 "common.w" } /*:20*//*23:*/ -#line 160 "common.w" +#line 156 "common.w" static boolean input_ln( FILE*fp) @@ -470,14 +473,14 @@ return true; } /*:23*//*27:*/ -#line 231 "common.w" +#line 227 "common.w" static void prime_the_change_buffer(void) { change_limit= change_buffer; /*29:*/ -#line 247 "common.w" +#line 243 "common.w" while(true){ change_line++; @@ -494,10 +497,10 @@ err_print("! Missing @x in change file"); } /*:29*/ -#line 236 "common.w" +#line 232 "common.w" /*30:*/ -#line 264 "common.w" +#line 260 "common.w" do{ change_line++; @@ -509,10 +512,10 @@ return; }while(limit==buffer); /*:30*/ -#line 237 "common.w" +#line 233 "common.w" /*31:*/ -#line 274 "common.w" +#line 270 "common.w" { change_limit= change_buffer+(ptrdiff_t)(limit-buffer); @@ -520,12 +523,12 @@ strncpy(change_buffer,buffer,(size_t)(limit-buffer+1)); } /*:31*/ -#line 238 "common.w" +#line 234 "common.w" } /*:27*//*32:*/ -#line 302 "common.w" +#line 299 "common.w" static void check_change(void) @@ -538,7 +541,7 @@ if_section_start_make_pending(true); if(!change_pending)changed_section[section_count]= true; } while(true){ -changing= true;print_where= true;change_line++; +changing= print_where= true;change_line++; if(!input_ln(change_file)){ err_print("! Change file ended before @y"); @@ -548,7 +551,7 @@ return; if(limit> buffer+1&&buffer[0]=='@'){ char xyz_code= xisupper(buffer[1])?tolower((eight_bits)buffer[1]):buffer[1]; /*34:*/ -#line 342 "common.w" +#line 339 "common.w" if(xyz_code=='x'||xyz_code=='z'){ loc= buffer+2;err_print("! Where is the matching @y?"); @@ -566,11 +569,11 @@ return; } /*:34*/ -#line 324 "common.w" +#line 321 "common.w" } /*31:*/ -#line 274 "common.w" +#line 270 "common.w" { change_limit= change_buffer+(ptrdiff_t)(limit-buffer); @@ -578,7 +581,7 @@ strncpy(change_buffer,buffer,(size_t)(limit-buffer+1)); } /*:31*/ -#line 326 "common.w" +#line 323 "common.w" changing= false;cur_line++; while(!input_ln(cur_file)){ @@ -594,14 +597,14 @@ if(lines_dont_match)n++; } /*:32*//*35:*/ -#line 362 "common.w" +#line 359 "common.w" void reset_input(void) { limit= buffer;loc= buffer+1;buffer[0]= ' '; /*36:*/ -#line 377 "common.w" +#line 374 "common.w" if((web_file= fopen(web_file_name,"r"))==NULL){ strcpy(web_file_name,alt_web_file_name); @@ -615,23 +618,23 @@ if((change_file= fopen(change_file_name,"r"))==NULL) fatal("! Cannot open change file ",change_file_name); /*:36*/ -#line 367 "common.w" +#line 364 "common.w" -include_depth= 0;cur_line= 0;change_line= 0; +include_depth= cur_line= change_line= 0; change_depth= include_depth; -changing= 1;prime_the_change_buffer();changing= !changing; +changing= true;prime_the_change_buffer();changing= !changing; limit= buffer;loc= buffer+1;buffer[0]= ' ';input_has_ended= false; } /*:35*//*38:*/ -#line 406 "common.w" +#line 403 "common.w" boolean get_line(void) { restart: if(changing&&include_depth==change_depth) /*41:*/ -#line 514 "common.w" +#line 511 "common.w" { change_line++; if(!input_ln(change_file)){ @@ -662,11 +665,11 @@ prime_the_change_buffer();changing= !changing;print_where= true; } /*:41*/ -#line 411 "common.w" +#line 408 "common.w" if(!changing||include_depth> change_depth){ /*40:*/ -#line 497 "common.w" +#line 494 "common.w" { cur_line++; while(!input_ln(cur_file)){ @@ -685,7 +688,7 @@ if(change_limit> change_buffer)check_change(); } /*:40*/ -#line 413 "common.w" +#line 410 "common.w" if(changing&&include_depth==change_depth)goto restart; } @@ -706,11 +709,11 @@ goto restart; } include_depth++; /*39:*/ -#line 451 "common.w" +#line 448 "common.w" { char temp_file_name[max_file_name_length]; char*cur_file_name_end= cur_file_name+max_file_name_length-1; -char*k= cur_file_name,*kk; +char*kk,*k= cur_file_name; int l; if(*loc=='"'){ @@ -726,8 +729,8 @@ if((cur_file= fopen(cur_file_name,"r"))!=NULL){ cur_line= 0;print_where= true; goto restart; } -kk= getenv("CWEBINPUTS"); -if(kk!=NULL){ +if((kk= getenv("CWEBINPUTS"))!=NULL){ + if((l= strlen(kk))> max_file_name_length-2)too_long(); strcpy(temp_file_name,kk); } @@ -754,14 +757,14 @@ include_depth--;err_print("! Cannot open include file");goto restart; } /*:39*/ -#line 432 "common.w" +#line 429 "common.w" } return true; } /*:38*//*42:*/ -#line 546 "common.w" +#line 543 "common.w" void check_complete(void){ @@ -775,7 +778,7 @@ err_print("! Change file entry did not match"); } /*:42*//*48:*/ -#line 639 "common.w" +#line 636 "common.w" name_pointer id_lookup( @@ -790,17 +793,17 @@ name_pointer p; if(last==NULL)for(last= first;*last!='\0';last++); l= (int)(last-first); /*49:*/ -#line 662 "common.w" +#line 659 "common.w" h= (eight_bits)*i; while(++ilink; @@ -810,10 +813,10 @@ p->link= hash[h];hash[h]= p; } /*:50*/ -#line 653 "common.w" +#line 650 "common.w" if(p==name_ptr)/*51:*/ -#line 681 "common.w" +#line 679 "common.w" { if(byte_ptr+l> byte_mem_end)overflow("byte memory"); if(name_ptr>=name_dir_end)overflow("name"); @@ -823,13 +826,13 @@ init_p(p,t); } /*:51*/ -#line 654 "common.w" +#line 651 "common.w" return p; } /*:48*//*52:*/ -#line 713 "common.w" +#line 711 "common.w" void print_section_name( @@ -839,18 +842,16 @@ char*ss,*s= first_chunk(p); name_pointer q= p+1; while(p!=name_dir){ ss= (p+1)->byte_start-1; -if(*ss==' '&&ss>=s){ -term_write(s,(size_t)(ss-s));p= q->link;q= p; -}else{ -term_write(s,(size_t)(ss+1-s));p= name_dir;q= NULL; -} +if(*ss==' '&&ss>=s)p= q->link,q= p; +else ss++,p= name_dir,q= NULL; +term_write(s,(size_t)(ss-s)); s= p->byte_start; } if(q)term_write("...",3); } /*:52*//*53:*/ -#line 732 "common.w" +#line 728 "common.w" void sprint_section_name( @@ -861,11 +862,8 @@ char*ss,*s= first_chunk(p); name_pointer q= p+1; while(p!=name_dir){ ss= (p+1)->byte_start-1; -if(*ss==' '&&ss>=s){ -p= q->link;q= p; -}else{ -ss++;p= name_dir; -} +if(*ss==' '&&ss>=s)p= q->link,q= p; +else ss++,p= name_dir; strncpy(dest,s,(size_t)(ss-s)),dest+= ss-s; s= p->byte_start; } @@ -873,7 +871,7 @@ s= p->byte_start; } /*:53*//*54:*/ -#line 753 "common.w" +#line 746 "common.w" void print_prefix_name( @@ -886,7 +884,7 @@ if(s+l<(p+1)->byte_start)term_write("...",3); } /*:54*//*56:*/ -#line 779 "common.w" +#line 772 "common.w" static int web_strcmp( char*j, @@ -904,7 +902,7 @@ else return greater; } /*:56*//*57:*/ -#line 808 "common.w" +#line 801 "common.w" static name_pointer add_section_name( @@ -912,7 +910,7 @@ name_pointer par, int c, char*first, char*last, -int ispref) +boolean ispref) { name_pointer p= name_ptr; char*s= first_chunk(p); @@ -928,21 +926,20 @@ name_ptr->link= name_dir; } set_prefix_length(p,name_len); strncpy(s,first,name_len); -p->llink= NULL; -p->rlink= NULL; +p->llink= p->rlink= NULL; init_node(p); return par==NULL?(root= p):c==less?(par->llink= p):(par->rlink= p); } /*:57*//*58:*/ -#line 837 "common.w" +#line 829 "common.w" static void extend_section_name( name_pointer p, char*first, char*last, -int ispref) +boolean ispref) { char*s; name_pointer q= p+1; @@ -959,14 +956,14 @@ if(ispref)*(byte_ptr-1)= ' '; } /*:58*//*59:*/ -#line 865 "common.w" +#line 857 "common.w" name_pointer section_lookup( char*first,char*last, -int ispref) +boolean ispref) { -int c= 0; +int c= less; name_pointer p= root; name_pointer q= NULL; name_pointer r= NULL; @@ -974,7 +971,7 @@ name_pointer par= NULL; int name_len= (int)(last-first)+1; /*60:*/ -#line 889 "common.w" +#line 881 "common.w" while(p){ c= web_strcmp(first,name_len,first_chunk(p),prefix_length(p)); @@ -1001,19 +998,19 @@ p= q,q= NULL; } /*:60*/ -#line 879 "common.w" +#line 871 "common.w" /*61:*/ -#line 914 "common.w" +#line 906 "common.w" if(r==NULL) return add_section_name(par,c,first,last+1,ispref); /*:61*/ -#line 880 "common.w" +#line 872 "common.w" /*62:*/ -#line 922 "common.w" +#line 914 "common.w" switch(section_name_cmp(&first,name_len,r)){ @@ -1026,16 +1023,16 @@ err_print(">"); } else if(name_len"); -return r; +break; default: fputs("\n! Section name incompatible with <",stdout); @@ -1043,16 +1040,16 @@ print_prefix_name(r); fputs(">,\n which abbreviates <",stdout); print_section_name(r); err_print(">"); -return r; } +return r; /*:62*/ -#line 881 "common.w" +#line 873 "common.w" } /*:59*//*63:*/ -#line 970 "common.w" +#line 962 "common.w" static int section_name_cmp( char**pfirst, @@ -1062,12 +1059,12 @@ name_pointer r) char*first= *pfirst; name_pointer q= r+1; char*ss,*s= first_chunk(r); -int c; -int ispref; +int c= less; +boolean ispref; while(true){ ss= (r+1)->byte_start-1; -if(*ss==' '&&ss>=r->byte_start)ispref= 1,q= q->link; -else ispref= 0,ss++,q= name_dir; +if(*ss==' '&&ss>=r->byte_start)ispref= true,q= q->link; +else ispref= false,ss++,q= name_dir; switch(c= web_strcmp(first,len,s,ss-s)){ case equal:if(q==name_dir) if(ispref){ @@ -1086,7 +1083,7 @@ default:return c; } /*:63*//*66:*/ -#line 1024 "common.w" +#line 1016 "common.w" void err_print( @@ -1095,7 +1092,7 @@ const char*s) char*k,*l; printf(*s=='!'?"\n%s":"%s",s); if(web_file_open)/*67:*/ -#line 1044 "common.w" +#line 1036 "common.w" {if(changing&&include_depth==change_depth) printf(". (l. %d of change file)\n",change_line); @@ -1106,7 +1103,7 @@ if(l> buffer){ for(k= buffer;k harmless_message)return EXIT_FAILURE; else return EXIT_SUCCESS; } /*:68*//*70:*/ -#line 1102 "common.w" +#line 1096 "common.w" void fatal( const char*s,const char*t) @@ -1158,7 +1157,7 @@ history= fatal_message;exit(wrap_up()); } /*:70*//*71:*/ -#line 1113 "common.w" +#line 1107 "common.w" void overflow( const char*t) @@ -1168,7 +1167,7 @@ printf("\n! Sorry, %s capacity exceeded",t);fatal("",""); /*:71*//*75:*/ -#line 1167 "common.w" +#line 1160 "common.w" static void scan_args(void) @@ -1182,35 +1181,32 @@ boolean found_web= false,found_change= false,found_out= false; strcpy(change_file_name,"/dev/null"); while(--argc> 0){ if((**(++argv)=='-'||**argv=='+')&&*(*argv+1))/*80:*/ -#line 1258 "common.w" +#line 1250 "common.w" -{ for(dot_pos= *argv+1;*dot_pos> '\0';dot_pos++) flags[(eight_bits)*dot_pos]= flag_change; -} /*:80*/ -#line 1179 "common.w" +#line 1172 "common.w" else{ s= name_pos= *argv;dot_pos= NULL; -while(*s){ +while(*s) if(*s=='.')dot_pos= s++; else if(*s=='/')dot_pos= NULL,name_pos= ++s; else s++; -} if(!found_web)/*77:*/ -#line 1206 "common.w" +#line 1198 "common.w" { if(s-*argv> max_file_name_length-5) /*82:*/ -#line 1276 "common.w" +#line 1266 "common.w" fatal("! Filename too long\n",*argv); /*:82*/ -#line 1209 "common.w" +#line 1201 "common.w" if(dot_pos==NULL) sprintf(web_file_name,"%s.w",*argv); @@ -1227,21 +1223,21 @@ found_web= true; } /*:77*/ -#line 1188 "common.w" +#line 1180 "common.w" else if(!found_change)/*78:*/ -#line 1224 "common.w" +#line 1216 "common.w" { if(strcmp(*argv,"-")!=0){ if(s-*argv> max_file_name_length-4) /*82:*/ -#line 1276 "common.w" +#line 1266 "common.w" fatal("! Filename too long\n",*argv); /*:82*/ -#line 1228 "common.w" +#line 1220 "common.w" if(dot_pos==NULL) sprintf(change_file_name,"%s.ch",*argv); @@ -1251,20 +1247,20 @@ found_change= true; } /*:78*/ -#line 1189 "common.w" +#line 1181 "common.w" else if(!found_out)/*79:*/ -#line 1236 "common.w" +#line 1228 "common.w" { if(s-*argv> max_file_name_length-5) /*82:*/ -#line 1276 "common.w" +#line 1266 "common.w" fatal("! Filename too long\n",*argv); /*:82*/ -#line 1239 "common.w" +#line 1231 "common.w" if(dot_pos==NULL){ sprintf(tex_file_name,"%s.tex",*argv); @@ -1284,10 +1280,10 @@ found_out= true; } /*:79*/ -#line 1190 "common.w" +#line 1182 "common.w" else/*81:*/ -#line 1264 "common.w" +#line 1254 "common.w" { if(program==ctangle) @@ -1301,12 +1297,12 @@ else fatal( } /*:81*/ -#line 1191 "common.w" +#line 1183 "common.w" } } if(!found_web)/*81:*/ -#line 1264 "common.w" +#line 1254 "common.w" { if(program==ctangle) @@ -1320,7 +1316,7 @@ else fatal( } /*:81*/ -#line 1194 "common.w" +#line 1186 "common.w" } diff --git a/common.h b/common.h index 425239f..0f8ec18 100644 --- a/common.h +++ b/common.h @@ -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 (works also with later versions) +% Version 4.3 --- May 2021 (works also with later versions) % Copyright (C) 1987,1990,1993 Silvio Levy and Donald E. Knuth @@ -27,9 +27,7 @@ First comes general stuff: -@s boolean int -@s uint8_t int -@s uint16_t int +@i iso_types.w @d ctangle false @d cweave true @@ -56,20 +54,22 @@ extern int phase; /* which phase are we in? */ @^ASCII code dependencies@> @d and_and 04 /* `\.{\&\&}'\,; corresponds to MIT's {\tentex\char'4} */ -@d lt_lt 020 /* `\.{<<}'\,; corresponds to MIT's {\tentex\char'20} */ -@d gt_gt 021 /* `\.{>>}'\,; corresponds to MIT's {\tentex\char'21} */ -@d plus_plus 013 /* `\.{++}'\,; corresponds to MIT's {\tentex\char'13} */ -@d minus_minus 01 /* `\.{--}'\,; corresponds to MIT's {\tentex\char'1} */ -@d minus_gt 031 /* `\.{->}'\,; corresponds to MIT's {\tentex\char'31} */ -@d non_eq 032 /* `\.{!=}'\,; corresponds to MIT's {\tentex\char'32} */ -@d lt_eq 034 /* `\.{<=}'\,; corresponds to MIT's {\tentex\char'34} */ -@d gt_eq 035 /* `\.{>=}'\,; corresponds to MIT's {\tentex\char'35} */ -@d eq_eq 036 /* `\.{==}'\,; corresponds to MIT's {\tentex\char'36} */ -@d or_or 037 /* `\.{\v\v}'\,; corresponds to MIT's {\tentex\char'37} */ -@d dot_dot_dot 016 /* `\.{...}'\,; corresponds to MIT's {\tentex\char'16} */ -@d colon_colon 06 /* `\.{::}'\,; corresponds to MIT's {\tentex\char'6} */ -@d period_ast 026 /* `\.{.*}'\,; corresponds to MIT's {\tentex\char'26} */ -@d minus_gt_ast 027 /* `\.{->*}'\,; corresponds to MIT's {\tentex\char'27} */ +@d lt_lt 020 /* `\.{<<}'\,; corresponds to MIT's {\tentex\char'20} */ +@d gt_gt 021 /* `\.{>>}'\,; corresponds to MIT's {\tentex\char'21} */ +@d plus_plus 013 /* `\.{++}'\,; corresponds to MIT's {\tentex\char'13} */ +@d minus_minus 01 /* `\.{--}'\,; corresponds to MIT's {\tentex\char'1} */ +@d minus_gt 031 /* `\.{->}'\,; corresponds to MIT's {\tentex\char'31} */ +@d non_eq 032 /* `\.{!=}'\,; corresponds to MIT's {\tentex\char'32} */ +@d lt_eq 034 /* `\.{<=}'\,; corresponds to MIT's {\tentex\char'34} */ +@d gt_eq 035 /* `\.{>=}'\,; corresponds to MIT's {\tentex\char'35} */ +@d eq_eq 036 /* `\.{==}'\,; corresponds to MIT's {\tentex\char'36} */ +@d or_or 037 /* `\.{\v\v}'\,; corresponds to MIT's {\tentex\char'37} */ +@d dot_dot_dot 016 /* `\.{...}'\,; corresponds to MIT's {\tentex\char'16} */ +@d colon_colon 06 /* `\.{::}'\,; corresponds to MIT's {\tentex\char'6} */ +@d period_ast 026 /* `\.{.*}'\,; corresponds to MIT's {\tentex\char'26} */ +@d minus_gt_ast 027 /* `\.{->*}'\,; corresponds to MIT's {\tentex\char'27} */ +@# +@d compress(c) if (loc++<=limit) return c @= extern char section_text[]; /* text being sought for */ @@ -78,12 +78,16 @@ extern char *id_first; /* where the current identifier begins in the buffer */ extern char *id_loc; /* just after the current identifier in the buffer */ @ Code related to input routines: -@d xisalpha(c) (isalpha((eight_bits)c)&&((eight_bits)c<0200)) -@d xisdigit(c) (isdigit((eight_bits)c)&&((eight_bits)c<0200)) -@d xisspace(c) (isspace((eight_bits)c)&&((eight_bits)c<0200)) -@d xislower(c) (islower((eight_bits)c)&&((eight_bits)c<0200)) -@d xisupper(c) (isupper((eight_bits)c)&&((eight_bits)c<0200)) -@d xisxdigit(c) (isxdigit((eight_bits)c)&&((eight_bits)c<0200)) +@d xisalpha(c) (isalpha((eight_bits)(c))&&((eight_bits)(c)<0200)) +@d xisdigit(c) (isdigit((eight_bits)(c))&&((eight_bits)(c)<0200)) +@d xisspace(c) (isspace((eight_bits)(c))&&((eight_bits)(c)<0200)) +@d xislower(c) (islower((eight_bits)(c))&&((eight_bits)(c)<0200)) +@d xisupper(c) (isupper((eight_bits)(c))&&((eight_bits)(c)<0200)) +@d xisxdigit(c) (isxdigit((eight_bits)(c))&&((eight_bits)(c)<0200)) +@d isxalpha(c) ((c)=='_' || (c)=='$') + /* non-alpha characters allowed in identifier */ +@d ishigh(c) ((eight_bits)(c)>0177) +@^high-bit character handling@> @= extern char buffer[]; /* where each line of input goes */ @@ -163,7 +167,7 @@ extern hash_pointer h; /* index into hash-head array */ extern boolean names_match(name_pointer,const char *,size_t,eight_bits);@/ extern name_pointer id_lookup(const char *,const char *,char); /* looks up a string in the identifier table */ -extern name_pointer section_lookup(char *,char *,int); /* finds section name */ +extern name_pointer section_lookup(char *,char *,boolean); /* finds section name */ extern void init_node(name_pointer);@/ extern void init_p(name_pointer,eight_bits);@/ extern void print_prefix_name(name_pointer);@/ @@ -175,7 +179,7 @@ extern void sprint_section_name(char *,name_pointer); @d harmless_message 1 /* |history| value when non-serious info was printed */ @d error_message 2 /* |history| value when an error was noted */ @d fatal_message 3 /* |history| value when we had to stop prematurely */ -@d mark_harmless {if (history==spotless) history=harmless_message;} +@d mark_harmless if (history==spotless) history=harmless_message @d mark_error history=error_message @d confusion(s) fatal("! This can't happen: ",s) @.This can't happen@> @@ -192,8 +196,8 @@ extern void overflow(const char *); /* succumb because a table has overflowed */ @ Code related to command line arguments: @d show_banner flags['b'] /* should the banner line be printed? */ @d show_progress flags['p'] /* should progress reports be printed? */ -@d show_stats flags['s'] /* should statistics be printed at end of run? */ @d show_happiness flags['h'] /* should lack of errors be announced? */ +@d show_stats flags['s'] /* should statistics be printed at end of run? */ @d make_xrefs flags['x'] /* should cross references be output? */ @= @@ -207,10 +211,8 @@ extern boolean flags[]; /* an option for each 7-bit code */ @ Code related to output: @d update_terminal fflush(stdout) /* empty the terminal output buffer */ -@d new_line putchar('\n') @d putxchar putchar +@d new_line putchar('\n') @d term_write(a,b) fflush(stdout),fwrite(a,sizeof(char),b,stdout) -@d C_printf(c,a) fprintf(C_file,c,a) -@d C_putc(c) putc(c,C_file) /* isn't \CEE/ wonderfully consistent? */ @= extern FILE *C_file; /* where output of \.{CTANGLE} goes */ diff --git a/common.w b/common.w index 15e93c2..d6e0702 100644 --- a/common.w +++ b/common.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.3 --- May 2021 % Copyright (C) 1987,1990,1993,2000 Silvio Levy and Donald E. Knuth @@ -22,12 +22,12 @@ \def\v{\char'174} % vertical (|) in typewriter font -\def\title{Common code for CTANGLE and CWEAVE (Version 4.2)} +\def\title{Common code for CTANGLE and CWEAVE (Version 4.3)} \def\topofcontents{\null\vfill \centerline{\titlefont Common code for {\ttitlefont CTANGLE} and {\ttitlefont CWEAVE}} \vskip 15pt - \centerline{(Version 4.2)} + \centerline{(Version 4.3)} \vfill} \def\botofcontents{\vfill \noindent @@ -47,10 +47,6 @@ under the terms of a permission notice identical to this one. \pageno=\contentspagenumber \advance\pageno by 1 \let\maybe=\iftrue -@s boolean int -@s uint8_t int -@s uint16_t int - @** Introduction. This file contains code common to both \.{CTANGLE} and \.{CWEAVE}, which roughly concerns the following problems: character uniformity, input routines, error handling and @@ -158,13 +154,13 @@ support |feof|, |getc|, and |ungetc| you may have to change things here. @^system dependencies@> @c -static boolean input_ln(@t\1\1@> /* copies a line into |buffer| or returns |false| */ -FILE *fp@t\2\2@>) /* what file to read from */ +static boolean input_ln( /* copies a line into |buffer| or returns |false| */ +FILE *fp) /* what file to read from */ { - register int c=EOF; /* character read; initialized so some compilers won't complain */ - register char *k; /* where next character goes */ - if (feof(fp)) return false; /* we have hit end-of-file */ - limit = k = buffer; /* beginning of buffer */ + register int c=EOF; /* character read; initialized so some compilers won't complain */ + register char *k; /* where next character goes */ + if (feof(fp)) return false; /* we have hit end-of-file */ + limit = k = buffer; /* beginning of buffer */ while (k<=buffer_end && (c=getc(fp)) != EOF && c!='\n') if ((*(k++) = c) != ' ') limit = k; if (k>buffer_end) @@ -172,7 +168,7 @@ FILE *fp@t\2\2@>) /* what file to read from */ ungetc(c,fp); loc=buffer; err_print("! Input line too long"); @.Input line too long@> } - if (c==EOF && limit==buffer) return false; /* there was nothing after + if (c==EOF && limit==buffer) return false; /* there was nothing after the last newline */ return true; } @@ -214,7 +210,7 @@ so that no further matches will be made. Here's a shorthand expression for inequality between the two lines: -@d lines_dont_match (change_limit-change_buffer != limit-buffer || @| +@d lines_dont_match (change_limit-change_buffer != limit-buffer @| || strncmp(buffer, change_buffer, (size_t)(limit-buffer))) @= @@ -293,8 +289,9 @@ either `\.{@@*}' or `\.{@@\ }' (possibly preceded by whitespace). This procedure is called only when |buffer @@ -365,9 +362,9 @@ reset_input(void) { limit=buffer; loc=buffer+1; buffer[0]=' '; @@; - include_depth=0; cur_line=0; change_line=0; + include_depth=cur_line=change_line=0; change_depth=include_depth; - changing=1; prime_the_change_buffer(); changing=!changing; + changing=true; prime_the_change_buffer(); changing=!changing; limit=buffer; loc=buffer+1; buffer[0]=' '; input_has_ended=false; } @@ -408,7 +405,7 @@ boolean get_line(void) /* inputs the next line */ { restart: if (changing && include_depth==change_depth) - @@; + @@; if (! changing || include_depth>change_depth) { @@; if (changing && include_depth==change_depth) goto restart; @@ -448,10 +445,10 @@ The remainder of the \.{@@i} line after the file name is ignored. @d too_long() {include_depth--; err_print("! Include file name too long"); goto restart;} -@.CWEBINPUTS@>@= { +@= { char temp_file_name[max_file_name_length]; char *cur_file_name_end=cur_file_name+max_file_name_length-1; - char *k=cur_file_name, *kk; + char *kk, *k=cur_file_name; int l; /* length of file name */ if (*loc=='"') { @@ -467,8 +464,8 @@ The remainder of the \.{@@i} line after the file name is ignored. cur_line=0; print_where=true; goto restart; /* success */ } - kk=getenv("CWEBINPUTS"); - if (kk!=NULL) { + if ((kk=getenv("CWEBINPUTS"))!=NULL) { +@.CWEBINPUTS@> if ((l=strlen(kk))>max_file_name_length-2) too_long(); strcpy(temp_file_name,kk); } @@ -483,7 +480,7 @@ The remainder of the \.{@@i} line after the file name is ignored. if (l>0) { if (k+l+2>=cur_file_name_end) too_long(); @.Include file name ...@> - for (; k>= cur_file_name; k--) *(k+l+1)=*k; + for (; k>=cur_file_name; k--) *(k+l+1)=*k; strcpy(cur_file_name,temp_file_name); cur_file_name[l]='/'; /* \UNIX/ pathname separator */ if ((cur_file=fopen(cur_file_name,"r"))!=NULL) { @@ -638,10 +635,10 @@ for (h=hash; h<=hash_end; *h++=NULL) ; @c name_pointer -id_lookup(@t\1\1@> /* looks up a string in the identifier table */ +id_lookup( /* looks up a string in the identifier table */ const char *first, /* first character of string */ const char *last, /* last character of string plus one */ -char t@t\2\2@>) /* the |ilk|; used by \.{CWEAVE} only */ +char t) /* the |ilk|; used by \.{CWEAVE} only */ { const char *i=first; /* position in |buffer| */ int h; /* hash code */ @@ -678,6 +675,7 @@ if (p==NULL) { @ The information associated with a new identifier must be initialized in a slightly different way in \.{CWEAVE} than in \.{CTANGLE}; hence the |init_p| procedure. + @= { if (byte_ptr+l>byte_mem_end) overflow("byte memory"); if (name_ptr>=name_dir_end) overflow("name"); @@ -704,7 +702,7 @@ and if it too is a prefix (ending with blank) its |link| will point to additional chunks in the same way. Null links are represented by |name_dir|. -@d first_chunk(p) ((p)->byte_start+2) +@d first_chunk(p) ((p)->byte_start+2) @d prefix_length(p) (int)((eight_bits)*((p)->byte_start)*256 + (eight_bits)*((p)->byte_start+1)) @d set_prefix_length(p,m) (*((p)->byte_start)=(m)/256, @@ -719,11 +717,9 @@ name_pointer p) name_pointer q = p+1; while (p!=name_dir) { ss = (p+1)->byte_start-1; - if (*ss==' ' && ss>=s) { - term_write(s,(size_t)(ss-s)); p=q->link; q=p; - } else { - term_write(s,(size_t)(ss+1-s)); p=name_dir; q=NULL; - } + if (*ss==' ' && ss>=s) p=q->link,q=p; + else ss++,p=name_dir,q=NULL; + term_write(s,(size_t)(ss-s)); s = p->byte_start; } if (q) term_write("...",3); /* complete name not yet known */ @@ -739,11 +735,8 @@ sprint_section_name( name_pointer q = p+1; while (p!=name_dir) { ss = (p+1)->byte_start-1; - if (*ss==' ' && ss>=s) { - p=q->link; q=p; - } else { - ss++; p=name_dir; - } + if (*ss==' ' && ss>=s) p=q->link,q=p; + else ss++,p=name_dir; strncpy(dest,s,(size_t)(ss-s)), dest+=ss-s; s = p->byte_start; } @@ -773,15 +766,15 @@ are null-terminated, and we keep an eye open for prefixes and extensions. @= static int web_strcmp(char *,int,char *,int);@/ -static name_pointer add_section_name(name_pointer,int,char *,char *,int);@/ -static void extend_section_name(name_pointer,char *,char *,int); +static name_pointer add_section_name(name_pointer,int,char *,char *,boolean);@/ +static void extend_section_name(name_pointer,char *,char *,boolean); @ @c -static int web_strcmp(@t\1\1@> /* fuller comparison than |strcmp| */ +static int web_strcmp( /* fuller comparison than |strcmp| */ char *j, /* beginning of first string */ int j_len, /* length of first string */ char *k, /* beginning of second string */ - int k_len@t\2\2@>) /* length of second string */ + int k_len) /* length of second string */ { char *j1=j+j_len, *k1=k+k_len; while (k /* install a new node in the tree */ +add_section_name( /* install a new node in the tree */ name_pointer par, /* parent of new node */ int c, /* right or left? */ char *first, /* first character of section name */ char *last, /* last character of section name, plus one */ -int ispref@t\2\2@>) /* are we adding a prefix or a full name? */ +boolean ispref) /* are we adding a prefix or a full name? */ { name_pointer p=name_ptr; /* new node */ char *s=first_chunk(p); @@ -828,19 +821,18 @@ int ispref@t\2\2@>) /* are we adding a prefix or a full name? */ } set_prefix_length(p,name_len); strncpy(s,first,name_len); - p->llink=NULL; - p->rlink=NULL; + p->llink=p->rlink=NULL; init_node(p); return par==NULL ? (root=p) : c==less ? (par->llink=p) : (par->rlink=p); } @ @c static void -extend_section_name(@t\1\1@> +extend_section_name( name_pointer p, /* name to be extended */ char *first, /* beginning of extension text */ char *last, /* one beyond end of extension text */ -int ispref@t\2\2@>) /* are we adding a prefix or a full name? */ +boolean ispref) /* are we adding a prefix or a full name? */ { char *s; name_pointer q=p+1; @@ -864,11 +856,11 @@ exactly equals or is a prefix or extension of a name in the tree. @c name_pointer -section_lookup(@t\1\1@> /* find or install section name in tree */ +section_lookup( /* find or install section name in tree */ char *first,char *last, /* first and last characters of new name */ -int ispref@t\2\2@>) /* is the new name a prefix or a full name? */ +boolean ispref) /* is the new name a prefix or a full name? */ { - int c=0; /* comparison between two names; initialized so some compilers won't complain */ + int c=less; /* comparison between two names; initialized so some compilers won't complain */ name_pointer p=root; /* current node of the search tree */ name_pointer q=NULL; /* another place to look in the tree */ name_pointer r=NULL; /* where a match has been found */ @@ -931,16 +923,16 @@ switch(section_name_cmp(&first,name_len,r)) { } else if (name_len print_section_name(r); err_print(">"); - return r; + break; default: /* no match: illegal */ fputs("\n! Section name incompatible with <",stdout); @.Section name incompatible...@> @@ -948,8 +940,8 @@ switch(section_name_cmp(&first,name_len,r)) { fputs(">,\n which abbreviates <",stdout); print_section_name(r); err_print(">"); - return r; } +return r; @ The return codes of |section_name_cmp|, which compares a string with the full name of a section, are those of |web_strcmp| plus @@ -968,20 +960,20 @@ us to regard \.{@@} as an ``extension'' of itself. @d bad_extension 5 @c -static int section_name_cmp(@t\1\1@> +static int section_name_cmp( char **pfirst, /* pointer to beginning of comparison string */ int len, /* length of string */ -name_pointer r@t\2\2@>) /* section name being compared */ +name_pointer r) /* section name being compared */ { char *first=*pfirst; /* beginning of comparison string */ name_pointer q=r+1; /* access to subsequent chunks */ char *ss, *s=first_chunk(r); - int c; /* comparison */ - int ispref; /* is chunk |r| a prefix? */ + int c=less; /* comparison */ + boolean ispref; /* is chunk |r| a prefix? */ while (true) { ss=(r+1)->byte_start-1; - if (*ss==' ' && ss>=r->byte_start) ispref=1,q=q->link; - else ispref=0,ss++,q=name_dir; + if (*ss==' ' && ss>=r->byte_start) ispref=true,q=q->link; + else ispref=false,ss++,q=name_dir; switch(c=web_strcmp(first,len,s,ss-s)) { case equal: if (q==name_dir) if (ispref) { @@ -1023,12 +1015,12 @@ if the string begins with |"!"|. @c void -err_print(@t\1\1@> /* prints `\..' and location of error message */ -const char *s@t\2\2@>) +err_print( /* prints `\..' and location of error message */ +const char *s) { char *k,*l; /* pointers into |buffer| */ printf(*s=='!'? "\n%s" : "%s",s); - if(web_file_open) @@; + if (web_file_open) @@; update_terminal; mark_error; } @@ -1051,7 +1043,7 @@ if (l>buffer) { for (k=buffer; k @c @@ -1085,13 +1077,15 @@ int wrap_up(void) { @ @= switch (history) { -case spotless: if (show_happiness) puts("(No errors were found.)"); break; +case spotless: + if (show_happiness) puts("(No errors were found.)"); break; case harmless_message: puts("(Did you see the warning message above?)"); break; case error_message: puts("(Pardon me, but I think I spotted something wrong.)"); break; -case fatal_message: puts("(That was a fatal error, my friend.)"); -} /* there are no other cases */ +case fatal_message: default: + puts("(That was a fatal error, my friend.)"); +} @ When there is no way to recover from an error, the |fatal| subroutine is invoked. This happens most often when |overflow| occurs. @@ -1146,8 +1140,7 @@ scanning the arguments; if additional flags are |true| by default they should be set before calling |common_init|. @= -show_banner=show_happiness=show_progress=make_xrefs=true;@/ -show_stats=false; +show_banner=show_happiness=show_progress=make_xrefs=true; @ We now must look at the command line arguments and set the file names accordingly. At least one file name must be present: the \.{CWEB} @@ -1179,14 +1172,13 @@ scan_args(void) if ((**(++argv)=='-'||**argv=='+')&&*(*argv+1)) @@; else { s=name_pos=*argv;@+dot_pos=NULL; - while (*s) { + while (*s) if (*s=='.') dot_pos=s++; else if (*s=='/') dot_pos=NULL,name_pos=++s; else s++; - } if (!found_web) @@; - else if (!found_change) @@; + |web_file_name|, |tex_file_name|, and |C_file_name|@>@; + else if (!found_change) @@; else if (!found_out) @@; else @@; } @@ -1256,10 +1248,8 @@ after the dot. We must check that there is enough room in @ @d flag_change (**argv!='-') @= -{ - for(dot_pos=*argv+1;*dot_pos>'\0';dot_pos++) - flags[(eight_bits)*dot_pos]=flag_change; -} +for(dot_pos=*argv+1;*dot_pos>'\0';dot_pos++) + flags[(eight_bits)*dot_pos]=flag_change; @ @= { diff --git a/ctang-bs.ch b/ctang-bs.ch index 55cc27c..fcd2706 100644 --- a/ctang-bs.ch +++ b/ctang-bs.ch @@ -17,16 +17,16 @@ by using "huge" pointers. 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.3)" @y The ``banner line'' defined here should be changed whenever \.{CTANGLE} is modified. -@d banner "This is CTANGLE (Version 4.2pc/big)" +@d banner "This is CTANGLE (Version 4.3pc/big)" @z -@x Section 9. +@x Section 10. for section names */ @= @@ -127,7 +127,7 @@ to run \.{CTANGLE} from a makefile.) @z -@x Section 16. +@x Section 19. eight_bits *tok_start; /* pointer into |tok_mem| */ sixteen_bits text_link; /* relates replacement texts */ } text; @@ -140,7 +140,7 @@ typedef text *text_pointer; @z -@x Section 17. +@x Section 20. 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| */ @@ -151,7 +151,7 @@ static eight_bits huge* tok_ptr; /* first unused position in |tok_mem| */ @z -@x Section 18. +@x Section 21. 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 */ @@ -163,14 +163,14 @@ text_ptr=text_info+1; text_ptr->tok_start=tok_mem; @z -@x Section 19. +@x Section 22. @d equiv equiv_or_xref /* info corresponding to names */ @y @d equiv ptr_union.equiv_member /* info corresponding to names */ @z -@x Section 27. +@x Section 31. eight_bits *end_field; /* ending location of replacement text */ eight_bits *byte_field; /* present location within replacement text */ @y @@ -179,7 +179,7 @@ text_ptr=text_info+1; text_ptr->tok_start=tok_mem; @z -@x Section 49. +@x Section 55. out_char( eight_bits cur_char) { diff --git a/ctang-man.ch b/ctang-man.ch index 5b4d06c..f90d536 100644 --- a/ctang-man.ch +++ b/ctang-man.ch @@ -16,7 +16,7 @@ under the terms of a permission notice identical to this one. } @y \def\botofcontents{\vfill\titlefalse} -\def\contentspagenumber{66} +\def\contentspagenumber{64} \def\title{APPENDIX E: CTANGLE} \let\K=\leftarrow @z diff --git a/ctang-pc.ch b/ctang-pc.ch index ddf281b..025790e 100644 --- a/ctang-pc.ch +++ b/ctang-pc.ch @@ -9,11 +9,11 @@ that allows >64K arrays. If you need lots of bytes and toks, try the alternate change files with -bs suffix instead of -pc. @x section 1 -@d banner "This is CTANGLE (Version 4.2)" +@d banner "This is CTANGLE (Version 4.3)" @y -@d banner "This is CTANGLE (Version 4.2pc)" +@d banner "This is CTANGLE (Version 4.3pc)" @z -@x section 4 +@x section 17 @d max_bytes 1000000 /* the number of bytes in identifiers, index entries, and section names */ @d max_toks 1000000 /* number of bytes in compressed \CEE/ code */ diff --git a/ctang-ql.ch b/ctang-ql.ch index 64f0e81..6d5fe6b 100644 --- a/ctang-ql.ch +++ b/ctang-ql.ch @@ -7,15 +7,15 @@ ex cc;"-v -h -c -=500000 ctangle_c" @x -\def\title{CTANGLE (Version 4.2)} +\def\title{CTANGLE (Version 4.3)} @y -\def\title{CTANGLE (QL Version 4.2)} +\def\title{CTANGLE (QL Version 4.3)} @z @x section 1 -@d banner "This is CTANGLE (Version 4.2)" +@d banner "This is CTANGLE (Version 4.3)" @y -@d banner "This is CTANGLE (QL Version 4.2)" +@d banner "This is CTANGLE (QL Version 4.3)" @z @x diff --git a/ctang-vms.ch b/ctang-vms.ch index 5686c66..753e8d9 100644 --- a/ctang-vms.ch +++ b/ctang-vms.ch @@ -10,12 +10,12 @@ created: (these changes not necessary for initial bootstrapping) @x section 1 (01-FEB-1992 ST) -@d banner "This is CTANGLE (Version 4.2)" +@d banner "This is CTANGLE (Version 4.3)" @y -@d banner "This is CTANGLE (VAX/VMS Version 4.2)" +@d banner "This is CTANGLE (VAX/VMS Version 4.3)" @z -@x section 3 (01-FEB-1992 ST) +@x section 4 (01-FEB-1992 ST) #include /* definition of |@!isalpha|, |@!isdigit| and so on */ #include /* definition of |@!bool|, |@!true| and |@!false| */ #include /* definition of |@!ptrdiff_t| */ diff --git a/ctang-w32.ch b/ctang-w32.ch index 1c687e5..9d9be12 100644 --- a/ctang-w32.ch +++ b/ctang-w32.ch @@ -4,23 +4,23 @@ This is the change file for CWEB's CTANGLE under Win32 Changes necessary for compiling with Borland C/C++ @x section 1 -@d banner "This is CTANGLE (Version 4.2)" +@d banner "This is CTANGLE (Version 4.3)" @y -@d banner "This is CTANGLE (Version 4.2win32)" +@d banner "This is CTANGLE (Version 4.3win32)" @z @x -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} */ +eight_bits t) /* not used by \.{TANGLE} */ @y -boolean __cdecl names_match(@t\1\1@> +boolean __cdecl 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} */ +eight_bits t) /* not used by \.{TANGLE} */ @z @x diff --git a/ctangle.c b/ctangle.c index d955da9..26407b4 100644 --- a/ctangle.c +++ b/ctangle.c @@ -2,7 +2,7 @@ #line 66 "ctangle.w" /*4:*/ -#line 46 "common.h" +#line 44 "common.h" #include #include @@ -15,7 +15,7 @@ /*:4*/ #line 67 "ctangle.w" -#define banner "This is CTANGLE (Version 4.2)" \ +#define banner "This is CTANGLE (Version 4.3)" \ #define ctangle false #define cweave true \ @@ -36,12 +36,18 @@ #define period_ast 026 #define minus_gt_ast 027 \ -#define xisalpha(c) (isalpha((eight_bits) c) &&((eight_bits) c<0200) ) -#define xisdigit(c) (isdigit((eight_bits) c) &&((eight_bits) c<0200) ) -#define xisspace(c) (isspace((eight_bits) c) &&((eight_bits) c<0200) ) -#define xislower(c) (islower((eight_bits) c) &&((eight_bits) c<0200) ) -#define xisupper(c) (isupper((eight_bits) c) &&((eight_bits) c<0200) ) -#define xisxdigit(c) (isxdigit((eight_bits) c) &&((eight_bits) c<0200) ) \ +#define compress(c) if(loc++<=limit) return c \ + +#define xisalpha(c) (isalpha((eight_bits) (c) ) &&((eight_bits) (c) <0200) ) +#define xisdigit(c) (isdigit((eight_bits) (c) ) &&((eight_bits) (c) <0200) ) +#define xisspace(c) (isspace((eight_bits) (c) ) &&((eight_bits) (c) <0200) ) +#define xislower(c) (islower((eight_bits) (c) ) &&((eight_bits) (c) <0200) ) +#define xisupper(c) (isupper((eight_bits) (c) ) &&((eight_bits) (c) <0200) ) +#define xisxdigit(c) (isxdigit((eight_bits) (c) ) &&((eight_bits) (c) <0200) ) +#define isxalpha(c) ((c) =='_'||(c) =='$') \ + +#define ishigh(c) ((eight_bits) (c) > 0177) \ + \ #define max_include_depth 10 \ @@ -63,23 +69,20 @@ #define harmless_message 1 #define error_message 2 #define fatal_message 3 -#define mark_harmless {if(history==spotless) history= harmless_message;} +#define mark_harmless if(history==spotless) history= harmless_message #define mark_error history= error_message #define confusion(s) fatal("! This can't happen: ",s) \ \ #define show_banner flags['b'] #define show_progress flags['p'] -#define show_stats flags['s'] #define show_happiness flags['h'] +#define show_stats flags['s'] #define make_xrefs flags['x'] \ #define update_terminal fflush(stdout) #define new_line putchar('\n') -#define putxchar putchar -#define term_write(a,b) fflush(stdout) ,fwrite(a,sizeof(char) ,b,stdout) -#define C_printf(c,a) fprintf(C_file,c,a) -#define C_putc(c) putc(c,C_file) \ +#define term_write(a,b) fflush(stdout) ,fwrite(a,sizeof(char) ,b,stdout) \ #define max_bytes 1000000 \ @@ -95,9 +98,11 @@ #define equiv equiv_or_xref \ +#define macro 0 #define section_flag max_texts \ #define string 02 +#define constant 03 #define join 0177 #define output_defs_flag (2*024000-1) \ @@ -117,9 +122,12 @@ #define verbatim 4 \ #define max_files 256 +#define C_printf(c,a) fprintf(C_file,c,a) +#define C_putc(c) putc(c,C_file) \ + #define translit_length 10 \ -#define ignore 0 +#define ignore 00 #define ord 0302 #define control_text 0303 #define translit_code 0304 @@ -130,23 +138,15 @@ #define section_name 0311 #define new_section 0312 \ -#define constant 03 \ - -#define isxalpha(c) ((c) =='_'||(c) =='$') \ - -#define ishigh(c) ((eight_bits) (c) > 0177) \ - \ - -#define compress(c) if(loc++<=limit) return c \ - -#define macro 0 #define app_repl(c) {if(tok_ptr==tok_mem_end) overflow("token") ;*tok_ptr++= c;} \ +#define keep_digit_separators flags['k'] \ + #line 68 "ctangle.w" /*3:*/ -#line 37 "common.h" +#line 35 "common.h" typedef bool boolean; typedef uint8_t eight_bits; @@ -163,7 +163,7 @@ extern char*id_first; extern char*id_loc; /*:5*//*6:*/ -#line 88 "common.h" +#line 92 "common.h" extern char buffer[]; extern char*buffer_end; @@ -171,7 +171,7 @@ extern char*loc; extern char*limit; /*:6*//*7:*/ -#line 105 "common.h" +#line 109 "common.h" extern int include_depth; extern FILE*file[]; @@ -187,7 +187,7 @@ extern boolean changing; extern boolean web_file_open; /*:7*//*9:*/ -#line 125 "common.h" +#line 129 "common.h" extern sixteen_bits section_count; extern boolean changed_section[]; @@ -195,7 +195,7 @@ extern boolean change_pending; extern boolean print_where; /*:9*//*10:*/ -#line 139 "common.h" +#line 143 "common.h" typedef struct name_info{ char*byte_start; @@ -220,12 +220,12 @@ extern hash_pointer hash_end; extern hash_pointer h; /*:10*//*12:*/ -#line 183 "common.h" +#line 187 "common.h" extern int history; /*:12*//*14:*/ -#line 199 "common.h" +#line 203 "common.h" extern int argc; extern char**argv; @@ -236,7 +236,7 @@ extern char scn_file_name[]; extern boolean flags[]; /*:14*//*15:*/ -#line 215 "common.h" +#line 217 "common.h" extern FILE*C_file; extern FILE*tex_file; @@ -257,7 +257,7 @@ sixteen_bits text_link; typedef text*text_pointer; /*:19*//*31:*/ -#line 269 "ctangle.w" +#line 273 "ctangle.w" typedef struct{ eight_bits*end_field; @@ -282,12 +282,12 @@ static eight_bits*tok_mem_end= tok_mem+max_toks-1; static eight_bits*tok_ptr; /*:20*//*26:*/ -#line 198 "ctangle.w" +#line 199 "ctangle.w" static text_pointer last_unnamed; /*:26*//*32:*/ -#line 285 "ctangle.w" +#line 289 "ctangle.w" static output_state cur_state; @@ -296,18 +296,18 @@ static stack_pointer stack_end= stack+stack_size; static stack_pointer stack_ptr; /*:32*//*37:*/ -#line 361 "ctangle.w" +#line 365 "ctangle.w" static int cur_val; /*:37*//*42:*/ -#line 452 "ctangle.w" +#line 456 "ctangle.w" static eight_bits out_state; static boolean protect; /*:42*//*45:*/ -#line 483 "ctangle.w" +#line 487 "ctangle.w" static name_pointer output_files[max_files]; static name_pointer*cur_out_file,*end_output_files,*an_output_file; @@ -315,33 +315,33 @@ static char cur_section_name_char; static char output_file_name[longest_name+1]; /*:45*//*52:*/ -#line 582 "ctangle.w" +#line 584 "ctangle.w" static boolean output_defs_seen= false; /*:52*//*57:*/ -#line 691 "ctangle.w" +#line 696 "ctangle.w" static char translit[128][translit_length]; /*:57*//*62:*/ -#line 770 "ctangle.w" +#line 775 "ctangle.w" static eight_bits ccode[256]; /*:62*//*66:*/ -#line 830 "ctangle.w" +#line 835 "ctangle.w" static boolean comment_continues= false; /*:66*//*68:*/ -#line 869 "ctangle.w" +#line 872 "ctangle.w" static name_pointer cur_section_name; static boolean no_where; /*:68*//*82:*/ -#line 1182 "ctangle.w" +#line 1189 "ctangle.w" static text_pointer cur_text; static eight_bits next_control; @@ -350,19 +350,19 @@ static eight_bits next_control; #line 71 "ctangle.w" /*8:*/ -#line 119 "common.h" +#line 123 "common.h" extern boolean get_line(void); extern void check_complete(void); extern void reset_input(void); /*:8*//*11:*/ -#line 162 "common.h" +#line 166 "common.h" extern boolean names_match(name_pointer,const char*,size_t,eight_bits); extern name_pointer id_lookup(const char*,const char*,char); -extern name_pointer section_lookup(char*,char*,int); +extern name_pointer section_lookup(char*,char*,boolean); extern void init_node(name_pointer); extern void init_p(name_pointer,eight_bits); extern void print_prefix_name(name_pointer); @@ -370,7 +370,7 @@ extern void print_section_name(name_pointer); extern void sprint_section_name(char*,name_pointer); /*:11*//*13:*/ -#line 186 "common.h" +#line 190 "common.h" extern int wrap_up(void); extern void err_print(const char*); @@ -378,63 +378,63 @@ extern void fatal(const char*,const char*); extern void overflow(const char*); /*:13*//*16:*/ -#line 223 "common.h" +#line 225 "common.h" extern void common_init(void); extern void print_stats(void); /*:16*//*30:*/ -#line 241 "ctangle.w" +#line 245 "ctangle.w" static void store_two_bytes(sixteen_bits); /*:30*//*35:*/ -#line 324 "ctangle.w" +#line 328 "ctangle.w" static void push_level(name_pointer); static void pop_level(boolean); /*:35*//*39:*/ -#line 397 "ctangle.w" +#line 401 "ctangle.w" static void get_output(void); /*:39*//*44:*/ -#line 473 "ctangle.w" +#line 477 "ctangle.w" static void flush_buffer(void); /*:44*//*49:*/ -#line 549 "ctangle.w" +#line 551 "ctangle.w" static void phase_two(void); /*:49*//*53:*/ -#line 585 "ctangle.w" +#line 587 "ctangle.w" static void output_defs(void); static void out_char(eight_bits); /*:53*//*65:*/ -#line 810 "ctangle.w" +#line 815 "ctangle.w" static eight_bits skip_ahead(void); static boolean skip_comment(boolean); /*:65*//*70:*/ -#line 924 "ctangle.w" +#line 922 "ctangle.w" static eight_bits get_next(void); /*:70*//*84:*/ -#line 1208 "ctangle.w" +#line 1215 "ctangle.w" static void scan_repl(eight_bits); /*:84*//*91:*/ -#line 1379 "ctangle.w" +#line 1396 "ctangle.w" static void scan_section(void); /*:91*//*99:*/ -#line 1460 "ctangle.w" +#line 1477 "ctangle.w" static void phase_one(void); /*:99*//*101:*/ -#line 1494 "ctangle.w" +#line 1511 "ctangle.w" static void skip_limbo(void); /*:101*/ @@ -463,16 +463,16 @@ text_ptr= text_info+1;text_ptr->tok_start= tok_mem; init_node(name_dir); /*:23*//*27:*/ -#line 201 "ctangle.w" -last_unnamed= text_info;text_info->text_link= 0; +#line 202 "ctangle.w" +last_unnamed= text_info;text_info->text_link= macro; /*:27*//*46:*/ -#line 493 "ctangle.w" +#line 497 "ctangle.w" cur_out_file= end_output_files= output_files+max_files; /*:46*//*58:*/ -#line 694 "ctangle.w" +#line 699 "ctangle.w" { int i; @@ -480,10 +480,11 @@ for(i= 0;i<128;i++)sprintf(translit[i],"X%02X",(unsigned int)(128+i)); } /*:58*//*63:*/ -#line 773 "ctangle.w" +#line 778 "ctangle.w" { int c; 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; @@ -497,10 +498,9 @@ ccode['l']= ccode['L']= translit_code; ccode['&']= join; ccode['<']= ccode['(']= section_name; ccode['\'']= ord; -} /*:63*//*78:*/ -#line 1103 "ctangle.w" +#line 1111 "ctangle.w" section_text[0]= ' '; /*:78*/ @@ -539,7 +539,7 @@ void init_p(name_pointer p,eight_bits t){(void)p;(void)t;} /*:25*//*29:*/ -#line 231 "ctangle.w" +#line 235 "ctangle.w" static void store_two_bytes( @@ -551,7 +551,7 @@ if(tok_ptr+2> tok_mem_end)overflow("token"); } /*:29*//*34:*/ -#line 309 "ctangle.w" +#line 313 "ctangle.w" static void push_level( @@ -568,7 +568,7 @@ cur_section= 0; } /*:34*//*36:*/ -#line 332 "ctangle.w" +#line 336 "ctangle.w" static void pop_level( @@ -584,7 +584,7 @@ if(stack_ptr> stack)cur_state= *stack_ptr; } /*:36*//*38:*/ -#line 368 "ctangle.w" +#line 372 "ctangle.w" static void get_output(void) @@ -607,7 +607,7 @@ switch(a/024000){ case 0:cur_val= a;out_char(identifier);break; case 1:if(a==output_defs_flag)output_defs(); else/*40:*/ -#line 402 "ctangle.w" +#line 406 "ctangle.w" { a-= 024000; @@ -621,7 +621,7 @@ goto restart; } /*:40*/ -#line 389 "ctangle.w" +#line 393 "ctangle.w" break; default:cur_val= a-050000;if(cur_val> 0)cur_section= cur_val; @@ -631,14 +631,14 @@ out_char(section_number); } /*:38*//*43:*/ -#line 460 "ctangle.w" +#line 464 "ctangle.w" static void flush_buffer(void) { C_putc('\n'); if(cur_line%100==0&&show_progress){ -printf("."); +putchar('.'); if(cur_line%500==0)printf("%d",cur_line); update_terminal; } @@ -646,31 +646,31 @@ cur_line++; } /*:43*//*48:*/ -#line 514 "ctangle.w" +#line 516 "ctangle.w" static void phase_two(void){ web_file_open= false; cur_line= 1; /*33:*/ -#line 298 "ctangle.w" +#line 302 "ctangle.w" 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; /*:33*/ -#line 519 "ctangle.w" +#line 521 "ctangle.w" /*51:*/ -#line 578 "ctangle.w" +#line 580 "ctangle.w" if(!output_defs_seen) output_defs(); /*:51*/ -#line 520 "ctangle.w" +#line 522 "ctangle.w" -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; } @@ -686,19 +686,19 @@ fputs("\nWriting the output files:",stdout); 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(); writeloop:/*50:*/ -#line 555 "ctangle.w" +#line 557 "ctangle.w" 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); if(show_progress){printf("\n(%s)",output_file_name);update_terminal;} cur_line= 1; @@ -712,7 +712,7 @@ flush_buffer(); } /*:50*/ -#line 541 "ctangle.w" +#line 543 "ctangle.w" if(show_happiness){ if(show_progress)new_line; @@ -722,7 +722,7 @@ fputs("Done.",stdout); } /*:48*//*54:*/ -#line 589 "ctangle.w" +#line 594 "ctangle.w" static void output_defs(void) @@ -730,7 +730,7 @@ output_defs(void) sixteen_bits a; push_level(NULL); for(cur_text= text_info+1;cur_texttext_link==0){ +if(cur_text->text_link==macro){ cur_byte= cur_text->tok_start; cur_end= (cur_text+1)->tok_start; C_printf("%s","#define "); @@ -748,7 +748,7 @@ a= (a-0200)*0400+*cur_byte++; if(a<024000){ cur_val= 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); } @@ -762,7 +762,7 @@ pop_level(false); } /*:54*//*55:*/ -#line 632 "ctangle.w" +#line 637 "ctangle.w" static void out_char( @@ -775,7 +775,7 @@ 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; /*59:*/ -#line 700 "ctangle.w" +#line 705 "ctangle.w" case identifier: if(out_state==num_or_id)C_putc(' '); @@ -790,10 +790,10 @@ j++; out_state= num_or_id;break; /*:59*/ -#line 643 "ctangle.w" +#line 648 "ctangle.w" /*60:*/ -#line 713 "ctangle.w" +#line 718 "ctangle.w" case section_number: if(cur_val> 0)C_printf("/*%d:*/",cur_val); @@ -815,15 +815,15 @@ j');C_putc('*');out_state= normal; break; /*:56*/ -#line 645 "ctangle.w" +#line 650 "ctangle.w" case'=':case'>':C_putc(cur_char);C_putc(' '); out_state= normal;break; @@ -863,7 +863,7 @@ default:C_putc(cur_char);out_state= normal;break; } /*:55*//*64:*/ -#line 794 "ctangle.w" +#line 799 "ctangle.w" static eight_bits skip_ahead(void) @@ -881,7 +881,7 @@ if(c!=ignore||*(loc-1)=='>')return c; } /*:64*//*67:*/ -#line 833 "ctangle.w" +#line 838 "ctangle.w" static boolean skip_comment( boolean is_long_comment) @@ -915,22 +915,23 @@ else loc++; } /*:67*//*69:*/ -#line 881 "ctangle.w" +#line 879 "ctangle.w" static eight_bits get_next(void) { -static int preprocessing= 0; +static boolean preprocessing= false; eight_bits c; 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; /*85:*/ -#line 1214 "ctangle.w" +#line 1221 "ctangle.w" +{ store_two_bytes(0150000); if(changing&&include_depth==change_depth){ id_first= change_file_name; @@ -942,9 +943,10 @@ 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);} +} /*:85*/ -#line 893 "ctangle.w" +#line 891 "ctangle.w" } else return'\n'; @@ -958,23 +960,32 @@ else continue; } loc++; if(xisdigit(c)||c=='.')/*73:*/ -#line 964 "ctangle.w" +#line 963 "ctangle.w" { +boolean hex_flag= false; id_first= loc-1; if(*id_first=='.'&&!xisdigit(*loc))goto mistake; if(*id_first=='0'){ if(*loc=='x'||*loc=='X'){ -loc++;while(xisxdigit(*loc))loc++;goto found; +hex_flag= true; +loc++;while(xisxdigit(*loc)||*loc=='\'')loc++; +} +else if(*loc=='b'||*loc=='B'){ +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++; +while((hex_flag&&xisxdigit(*loc))||xisdigit(*loc)||*loc=='\'')loc++; } if(*loc=='e'||*loc=='E'){ if(*++loc=='+'||*loc=='-')loc++; -while(xisdigit(*loc))loc++; +while(xisdigit(*loc)||*loc=='\'')loc++; +} +else if(hex_flag&&(*loc=='p'||*loc=='P')){ +if(*++loc=='+'||*loc=='-')loc++; +while(xisxdigit(*loc)||*loc=='\'')loc++; } found:while(*loc=='u'||*loc=='U'||*loc=='l'||*loc=='L' ||*loc=='f'||*loc=='F')loc++; @@ -983,19 +994,19 @@ return constant; } /*:73*/ -#line 905 "ctangle.w" +#line 903 "ctangle.w" else if(c=='\''||c=='"' ||((c=='L'||c=='u'||c=='U')&&(*loc=='\''||*loc=='"')) ||((c=='u'&&*loc=='8')&&(*(loc+1)=='\''||*(loc+1)=='"'))) /*74:*/ -#line 992 "ctangle.w" +#line 1000 "ctangle.w" { char delim= c; id_first= section_text+1; id_loc= section_text;*++id_loc= delim; if(delim=='L'||delim=='u'||delim=='U'){ -if(delim=='u'&&*loc=='8'){*++id_loc= *loc++;} +if(delim=='u'&&*loc=='8')*++id_loc= *loc++; delim= *loc++;*++id_loc= delim; } while(true){ @@ -1033,26 +1044,27 @@ return string; } /*:74*/ -#line 909 "ctangle.w" +#line 907 "ctangle.w" else if(isalpha(c)||isxalpha(c)||ishigh(c)) /*72:*/ -#line 957 "ctangle.w" +#line 954 "ctangle.w" { id_first= --loc; -while(isalpha((eight_bits)*++loc)||isdigit((eight_bits)*loc) +do +++loc; +while(isalpha((eight_bits)*loc)||isdigit((eight_bits)*loc) ||isxalpha((eight_bits)*loc)||ishigh((eight_bits)*loc)); id_loc= loc;return identifier; } /*:72*/ -#line 911 "ctangle.w" +#line 909 "ctangle.w" else if(c=='@')/*75:*/ -#line 1037 "ctangle.w" +#line 1045 "ctangle.w" { -c= ccode[(eight_bits)*loc++]; -switch(c){ +switch(c= ccode[(eight_bits)*loc++]){ case ignore:continue; case translit_code:err_print("! Use @l in limbo only");continue; @@ -1065,11 +1077,11 @@ continue; case section_name: cur_section_name_char= *(loc-1); /*77:*/ -#line 1085 "ctangle.w" +#line 1091 "ctangle.w" { char*k; /*79:*/ -#line 1105 "ctangle.w" +#line 1113 "ctangle.w" k= section_text; while(true){ @@ -1080,7 +1092,7 @@ loc= buffer+1;break; } c= *loc; /*80:*/ -#line 1129 "ctangle.w" +#line 1137 "ctangle.w" if(c=='@'){ c= *(loc+1); @@ -1099,7 +1111,7 @@ err_print("! Nesting of section names not allowed");break; } /*:80*/ -#line 1114 "ctangle.w" +#line 1122 "ctangle.w" loc++;if(k section_text)k--; /*:79*/ -#line 1087 "ctangle.w" +#line 1093 "ctangle.w" if(k-section_text> 3&&strncmp(k-2,"...",3)==0) -cur_section_name= section_lookup(section_text+1,k-3,1); -else cur_section_name= section_lookup(section_text+1,k,0); +cur_section_name= section_lookup(section_text+1,k-3,true); + +else cur_section_name= section_lookup(section_text+1,k,false); + if(cur_section_name_char=='(') /*47:*/ -#line 497 "ctangle.w" +#line 501 "ctangle.w" { for(an_output_file= cur_out_file; @@ -1132,23 +1146,21 @@ 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"); -} +else overflow("output files"); } } /*:47*/ -#line 1093 "ctangle.w" +#line 1101 "ctangle.w" return section_name; } /*:77*/ -#line 1051 "ctangle.w" +#line 1058 "ctangle.w" case string:/*81:*/ -#line 1151 "ctangle.w" +#line 1159 "ctangle.w" { id_first= loc++;*(limit+1)= '@';*(limit+2)= '>'; while(*loc!='@'||*(loc+1)!='>')loc++; @@ -1159,15 +1171,14 @@ return string; } /*:81*/ -#line 1052 "ctangle.w" +#line 1059 "ctangle.w" case ord:/*76:*/ -#line 1064 "ctangle.w" +#line 1071 "ctangle.w" id_first= loc; -if(*loc=='\\'){ +if(*loc=='\\') if(*++loc=='\'')loc++; -} while(*loc!='\''){ if(*loc=='@'){ if(*(loc+1)!='@') @@ -1185,34 +1196,35 @@ loc++; return ord; /*:76*/ -#line 1053 "ctangle.w" +#line 1060 "ctangle.w" default:return c; } } /*:75*/ -#line 912 "ctangle.w" +#line 910 "ctangle.w" else if(xisspace(c)){ if(!preprocessing||loc> limit)continue; else return' '; } -else if(c=='#'&&loc==buffer+1)preprocessing= 1; +else if(c=='#'&&loc==buffer+1)preprocessing= true; mistake:/*71:*/ -#line 935 "ctangle.w" +#line 931 "ctangle.w" 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); -} -break; +}break; case':':if(*loc==':')compress(colon_colon);break; case'=':if(*loc=='=')compress(eq_eq);break; case'>':if(*loc=='='){compress(gt_eq);} @@ -1225,23 +1237,24 @@ case'!':if(*loc=='=')compress(non_eq);break; } /*:71*/ -#line 919 "ctangle.w" +#line 917 "ctangle.w" return c; } } /*:69*//*83:*/ -#line 1186 "ctangle.w" +#line 1193 "ctangle.w" static void scan_repl( eight_bits t) { sixteen_bits a; -if(t==section_name){/*85:*/ -#line 1214 "ctangle.w" +if(t==section_name)/*85:*/ +#line 1221 "ctangle.w" +{ store_two_bytes(0150000); if(changing&&include_depth==change_depth){ id_first= change_file_name; @@ -1253,13 +1266,14 @@ 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);} +} /*:85*/ -#line 1192 "ctangle.w" -} +#line 1199 "ctangle.w" + while(true)switch(a= get_next()){ /*86:*/ -#line 1227 "ctangle.w" +#line 1236 "ctangle.w" case identifier:a= id_lookup(id_first,id_loc,0)-name_dir; app_repl((a/0400)+0200); @@ -1267,7 +1281,7 @@ app_repl(a%0400);break; case section_name:if(t!=section_name)goto done; else{ /*87:*/ -#line 1260 "ctangle.w" +#line 1269 "ctangle.w" { char*try_loc= loc; while(*try_loc==' '&&try_loctok_start= tok_ptr; } /*:83*//*90:*/ -#line 1346 "ctangle.w" +#line 1363 "ctangle.w" static void scan_section(void) @@ -1437,10 +1457,10 @@ section_count++;no_where= true; if(*(loc-1)=='*'&&show_progress){ printf("*%d",section_count);update_terminal; } -next_control= 0; +next_control= ignore; while(true){ /*92:*/ -#line 1387 "ctangle.w" +#line 1404 "ctangle.w" while(next_controltext_link= macro; } /*:93*/ -#line 1362 "ctangle.w" +#line 1379 "ctangle.w" continue; } @@ -1482,14 +1502,14 @@ p= name_dir;break; if(next_control==section_name){ p= cur_section_name; /*94:*/ -#line 1419 "ctangle.w" +#line 1436 "ctangle.w" while((next_control= get_next())=='+'); if(next_control!='='&&next_control!=eq_eq) continue; /*:94*/ -#line 1370 "ctangle.w" +#line 1387 "ctangle.w" break; } @@ -1497,22 +1517,22 @@ return; } no_where= print_where= false; /*95:*/ -#line 1424 "ctangle.w" +#line 1441 "ctangle.w" /*96:*/ -#line 1429 "ctangle.w" +#line 1446 "ctangle.w" store_two_bytes((sixteen_bits)(0150000+section_count)); /*:96*/ -#line 1425 "ctangle.w" +#line 1442 "ctangle.w" scan_repl(section_name); /*97:*/ -#line 1433 "ctangle.w" +#line 1450 "ctangle.w" -if(p==name_dir||p==0){ +if(p==name_dir||p==NULL){ (last_unnamed)->text_link= cur_text-text_info;last_unnamed= cur_text; } else if(p->equiv==(void*)text_info)p->equiv= (void*)cur_text; @@ -1527,16 +1547,16 @@ cur_text->text_link= section_flag; /*:97*/ -#line 1427 "ctangle.w" +#line 1444 "ctangle.w" /*:95*/ -#line 1376 "ctangle.w" +#line 1393 "ctangle.w" } /*:90*//*98:*/ -#line 1448 "ctangle.w" +#line 1465 "ctangle.w" static void phase_one(void){ @@ -1550,7 +1570,7 @@ phase= 2; } /*:98*//*100:*/ -#line 1465 "ctangle.w" +#line 1482 "ctangle.w" static void skip_limbo(void) @@ -1565,7 +1585,7 @@ c= *loc++; if(ccode[(eight_bits)c]==new_section)break; switch(ccode[(eight_bits)c]){ case translit_code:/*102:*/ -#line 1496 "ctangle.w" +#line 1513 "ctangle.w" while(xisspace(*loc)&&loc@/ @@ -151,11 +151,11 @@ 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} */ +eight_bits t) /* not used by \.{TANGLE} */ {@+(void)t; if (length(p)!=l) return false; return !strncmp(first,p->byte_start,l); @@ -193,12 +193,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 */ @= static text_pointer last_unnamed; /* most recent replacement text of unnamed section */ -@ @= last_unnamed=text_info; text_info->text_link=0; +@ @= 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,15 +215,18 @@ 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 |string| denotes the beginning or end of a string, verbatim -construction or numerical constant. +\hang |constant| denotes a 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 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) @ The following procedure is used to enter a two-byte value into @@ -308,8 +312,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 +335,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_linktext_link+text_info; /* stay on the same level */ @@ -350,7 +354,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. @@ -463,7 +467,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 +506,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"); } } @@ -518,7 +520,7 @@ phase_two (void) { cur_line=1; @@; @@; - 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...@> } @@ -534,7 +536,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 +559,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 +588,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(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_texttext_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 "); @@ -611,7 +616,7 @@ output_defs(void) if (a<024000) { /* |024000==(0250-0200)*0400| */ cur_val=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); } @@ -643,7 +648,7 @@ restart: @/@t\4@>@@; @/@t\4@>@@; @/@t\4@>@@; - 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 +664,7 @@ restart: } } -@ @= +@ @=@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,7 +702,7 @@ static char translit[128][translit_length]; for (i=0;i<128;i++) sprintf(translit[i],"X%02X",(unsigned int)(128+i)); } -@ @= +@ @=@t\1\quad@> case identifier: if (out_state==num_or_id) C_putc(' '); j=(cur_val+name_dir)->byte_start; @@ -710,7 +715,7 @@ case identifier: } out_state=num_or_id; break; -@ @= +@ @=@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); @@ -731,7 +736,7 @@ case section_number: if (*j=='\\' || *j=='"') C_putc('\\'); C_putc(*j); } - C_printf("%s","\"\n"); + C_putc('"');@+C_putc('\n'); } break; @@ -756,7 +761,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 +778,20 @@ static eight_bits ccode[256]; /* meaning of a char following \.{@@} */ @ @= { 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['@@']='@@'; 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 +822,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 +836,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 +869,6 @@ boolean is_long_comment@t\2\2@>) @* Inputting the next token. -@d constant 03 - @= static name_pointer cur_section_name; /* name of section just scanned */ static boolean no_where; /* suppress |print_where|? */ @@ -873,20 +876,15 @@ 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; @@ -913,9 +911,9 @@ get_next(void) /* 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; + else if (c=='#' && loc==buffer+1) preprocessing=true; mistake: @@; return c; } @@ -930,24 +928,23 @@ combinations \.{...}, \.{::}, \.{.*} and \.{->*}. The compound assignment operators (e.g., \.{+=}) are treated as separate tokens. -@d compress(c) if (loc++<=limit) return c - @= 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 +953,41 @@ switch(c) { @ @= { id_first=--loc; - while (isalpha((eight_bits)*++loc) || isdigit((eight_bits)*loc) @| + do + ++loc; + while (isalpha((eight_bits)*loc) || isdigit((eight_bits)*loc) @| || isxalpha((eight_bits)*loc) || ishigh((eight_bits)*loc)); id_loc=loc; return identifier; } @ @= { + 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++; + } + 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++; +found: while (*loc=='u' || *loc=='U' || *loc=='l' || *loc=='L' + || *loc=='f' || *loc=='F') loc++; id_loc=loc; return constant; } @@ -994,7 +1002,7 @@ convention, but do not allow the string to be longer than |longest_name|. 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) { @@ -1035,8 +1043,7 @@ convention, but do not allow the string to be longer than |longest_name|. whether there is more work to do. @= { - c=ccode[(eight_bits)*loc++]; - switch(c) { + switch(c=ccode[(eight_bits)*loc++]) { case ignore: continue; case translit_code: err_print("! Use @@l in limbo only"); continue; @.Use @@l in limbo...@> @@ -1063,9 +1070,8 @@ thus, \.{@@'\\nopq'} gives the same result as \.{@@'\\n'}. @= id_first=loc; - if (*loc=='\\') { + if (*loc=='\\') if (*++loc=='\'') loc++; - } while (*loc!='\'') { if (*loc=='@@') { if (*(loc+1)!='@@') @@ -1086,8 +1092,10 @@ thus, \.{@@'\\nopq'} gives the same result as \.{@@'\\n'}. char *k; /* pointer 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=='(') @@; @@ -1176,7 +1184,6 @@ 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;} @= @@ -1185,11 +1192,11 @@ 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) {@@;} + if (t==section_name) @@; while (true) switch (a=get_next()) { @= -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); +{ + 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);} } -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);} -@ @= +@ @=@t\1\quad@> case identifier: a=id_lookup(id_first,id_loc,0)-name_dir; app_repl((a / 0400)+0200); app_repl(a % 0400); break; @@ -1268,7 +1277,13 @@ case new_section: goto done; as explained in the manual */ } -@ @= +@ 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'] + +@= app_repl(a); /* |string| or |constant| */ while (id_first < id_loc) { /* simplify \.{@@@@} pairs */ if (*id_first=='@@') { @@ -1276,6 +1291,8 @@ 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; @@ -1354,7 +1371,7 @@ scan_section(void) if (*(loc-1)=='*' && show_progress) { /* starred section */ printf("*%d",section_count); update_terminal; } - next_control=0; + next_control=ignore; while (true) { @@; @@ -1431,7 +1448,7 @@ store_two_bytes((sixteen_bits)(0150000+section_count)); /* |0150000==0320*0400| */ @ @= -if (p==name_dir||p==0) { /* unnamed section, or bad section name */ +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; diff --git a/cweav-bs.ch b/cweav-bs.ch index bf27528..ee919d7 100644 --- a/cweav-bs.ch +++ b/cweav-bs.ch @@ -20,16 +20,16 @@ This file contributed by Barry Schwartz, trashman@crud.mn.org, 28 Jun 94. The ``banner line'' defined here should be changed whenever \.{CWEAVE} is modified. -@d banner "This is CWEAVE (Version 4.2)" +@d banner "This is CWEAVE (Version 4.3)" @y The ``banner line'' defined here should be changed whenever \.{CWEAVE} is modified. -@d banner "This is CWEAVE (Version 4.2pc/big)" +@d banner "This is CWEAVE (Version 4.3pc/big)" @z -@x Section 7. +@x Section 10. for section names */ @= @@ -119,11 +119,11 @@ static xref_pointer xmem_end; @x Section 24. -xref_ptr=xmem; init_node(name_dir); xref_switch=0; section_xref_switch=0; +xref_ptr=xmem; init_node(name_dir); xref_switch=section_xref_switch=0; xmem->num=0; /* sentinel value */ @y xmem_end = xmem + max_refs - 1; -xref_ptr=xmem; init_node(name_dir); xref_switch=0; section_xref_switch=0; +xref_ptr=xmem; init_node(name_dir); xref_switch=section_xref_switch=0; xmem->num=0; /* sentinel value */ @z @@ -165,7 +165,7 @@ max_tok_ptr=tok_mem+1; max_text_ptr=tok_start+1; @z -@x Section 74. +@x Section 78. if (unindexed(lhs)) { /* retain only underlined entries */ xref_pointer q,r=NULL; for (q=(xref_pointer)lhs->xref;q>xmem;q=q->xlink) @@ -186,7 +186,7 @@ max_tok_ptr=tok_mem+1; max_text_ptr=tok_start+1; @z -@x Section 93. +@x Section 97. char *k, *k_end=(p+1)->byte_start; /* pointers into |byte_mem| */ out('{'); for (k=p->byte_start; kxref!=(void *)xmem) { @y if (cur_name->xref!=(void huge*)xmem) { @z -@x Section 246. +@x Section 255. static char *cur_byte; /* index into |byte_mem| */ @y static char huge* cur_byte; /* index into |byte_mem| */ @z -@x Section 255. -switch (cur_name->ilk) { - case normal: case func_template: if (is_tiny(cur_name)) out_str("\\|"); - else {char *j; -@y -switch (cur_name->ilk) { - case normal: case func_template: if (is_tiny(cur_name)) out_str("\\|"); - else {char huge* j; -@z - - -@x Section 255. - case custom: {char *j; out_str("$\\"); +@x Section 264. +switch (cur_name->ilk) {@+char *j; @y - case custom: {char huge* j; out_str("$\\"); +switch (cur_name->ilk) {@+char huge* j; @z diff --git a/cweav-man.ch b/cweav-man.ch index b723609..6cfcc8f 100644 --- a/cweav-man.ch +++ b/cweav-man.ch @@ -16,7 +16,7 @@ under the terms of a permission notice identical to this one. } @y \def\botofcontents{\vfill\titlefalse} -\def\contentspagenumber{111} +\def\contentspagenumber{109} \def\title{APPENDIX F: CWEAVE} \let\K=\leftarrow @z diff --git a/cweav-pc.ch b/cweav-pc.ch index b37f9f2..f0f7770 100644 --- a/cweav-pc.ch +++ b/cweav-pc.ch @@ -11,12 +11,12 @@ that allows >64K arrays. (If you need lots more bytes, try the alternate change files that have -bs in their name instead of -pc.) @x section 1 -@d banner "This is CWEAVE (Version 4.2)" +@d banner "This is CWEAVE (Version 4.3)" @y -@d banner "This is CWEAVE (Version 4.2pc)" +@d banner "This is CWEAVE (Version 4.3pc)" @z -@x section 4 +@x section 17 @d max_bytes 1000000 /* the number of bytes in identifiers, @y @d max_bytes (unsigned)60000 /* the number of bytes in identifiers, diff --git a/cweav-ql.ch b/cweav-ql.ch index 28053eb..fa809a5 100644 --- a/cweav-ql.ch +++ b/cweav-ql.ch @@ -7,15 +7,15 @@ ex cc;"-v -h -c =500000 cweave_c" @x -\def\title{CWEAVE (Version 4.2)} +\def\title{CWEAVE (Version 4.3)} @y -\def\title{CWEAVE (QL Version 4.2)} +\def\title{CWEAVE (QL Version 4.3)} @z @x section 1 -@d banner "This is CWEAVE (Version 4.2)" +@d banner "This is CWEAVE (Version 4.3)" @y -@d banner "This is CWEAVE (QL Version 4.2)" +@d banner "This is CWEAVE (QL Version 4.3)" @z @x diff --git a/cweav-vms.ch b/cweav-vms.ch index 7d80d57..a4416a7 100644 --- a/cweav-vms.ch +++ b/cweav-vms.ch @@ -13,12 +13,12 @@ modified: (also modified by Don Knuth to keep version numbers uptodate) @x section 1 (01-FEB-1992 ST) -@d banner "This is CWEAVE (Version 4.2)" +@d banner "This is CWEAVE (Version 4.3)" @y -@d banner "This is CWEAVE (VAX/VMS Version 4.2)" +@d banner "This is CWEAVE (VAX/VMS Version 4.3)" @z -@x section 3 (01-FEB-1992 ST) +@x section 4 (01-FEB-1992 ST) #include /* definition of |@!isalpha|, |@!isdigit| and so on */ #include /* definition of |@!bool|, |@!true| and |@!false| */ #include /* definition of |@!ptrdiff_t| */ diff --git a/cweav-w32.ch b/cweav-w32.ch index 346d007..2fec067 100644 --- a/cweav-w32.ch +++ b/cweav-w32.ch @@ -2,23 +2,23 @@ This is the change file for CWEB's CWEAVE under Win32 (Contributed by Fabrice Popineau, February 2002) @x section 1 -@d banner "This is CWEAVE (Version 4.2)" +@d banner "This is CWEAVE (Version 4.3)" @y -@d banner "This is CWEAVE (Version 4.2win32)" +@d banner "This is CWEAVE (Version 4.3win32)" @z @x -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@>) /* desired |ilk| */ +eight_bits t) /* desired |ilk| */ @y -boolean __cdecl names_match(@t\1\1@> +boolean __cdecl 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@>) /* desired |ilk| */ +eight_bits t) /* desired |ilk| */ @z @x diff --git a/cweave.w b/cweave.w index a8e3105..30bcedb 100644 --- a/cweave.w +++ b/cweave.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.3 --- May 2021 % Copyright (C) 1987,1990,1993,2000 Silvio Levy and Donald E. Knuth @@ -32,11 +32,11 @@ \def\skipxTeX{\\{skip\_\TEX/}} \def\copyxTeX{\\{copy\_\TEX/}} -\def\title{CWEAVE (Version 4.2)} +\def\title{CWEAVE (Version 4.3)} \def\topofcontents{\null\vfill \centerline{\titlefont The {\ttitlefont CWEAVE} processor} \vskip 15pt - \centerline{(Version 4.2)} + \centerline{(Version 4.3)} \vfill} \def\botofcontents{\vfill \noindent @@ -67,9 +67,10 @@ Crusius, and others who have contributed improvements. The ``banner line'' defined here should be changed whenever \.{CWEAVE} is modified. -@d banner "This is CWEAVE (Version 4.2)" +@d banner "This is CWEAVE (Version 4.3)" -@c @@/ +@c +@@/ @h @@/ @@/ @@ -85,9 +86,9 @@ Please read the documentation for \.{common}, the set of routines common to \.{CTANGLE} and \.{CWEAVE}, before proceeding further. @c -int main (@t\1\1@> +int main ( int ac, /* argument count */ -char **av@t\2\2@>) /* argument values */ +char **av) /* argument values */ { argc=ac; argv=av; program=cweave; @@ -99,7 +100,7 @@ char **av@t\2\2@>) /* argument values */ phase_one(); /* read all the user's text and store the cross-references */ phase_two(); /* read all the text again and translate it to \TEX/ form */ phase_three(); /* output the cross-reference index */ - if (tracing==2 && !show_progress) new_line; + if (tracing==fully && !show_progress) new_line; return wrap_up(); /* and exit gracefully */ } @@ -116,8 +117,6 @@ handle \TEX/, so they should be sufficient for most applications of \.{CWEAVE}. @d line_length 80 /* lines of \TEX/ output have at most this many characters; should be less than 256 */ @d max_refs 65535 /* number of cross-references; must be less than 65536 */ -@d max_texts 10239 /* number of phrases in \CEE/ texts being parsed; - must be less than 10240 */ @d max_scraps 10000 /* number of tokens in \CEE/ texts being parsed */ @* Data structures exclusive to {\tt CWEAVE}. @@ -143,7 +142,7 @@ will be typeset in special ways. \yskip\hang |typewriter| identifiers are index entries that appear after \.{@@.} in the \.{CWEB} file. -\yskip\hang |alfop|, \dots, |template_like| +\yskip\hang |alfop|, \dots, |attr| identifiers are \CEE/ or \CPLUSPLUS/ reserved words whose |ilk| explains how they are to be treated when \CEE/ code is being formatted. @@ -176,6 +175,10 @@ formatted. @d typedef_like 56 /* \&{typedef} */ @d define_like 57 /* \&{define} */ @d template_like 58 /* \&{template} */ +@d alignas_like 59 /* \&{alignas} */ +@d using_like 60 /* \&{using} */ +@d default_like 61 /* \&{default} */ +@d attr 62 /* \&{noexcept} and attributes */ @ We keep track of the current section number in |section_count|, which is the total number of sections that have started. Sections which have @@ -229,7 +232,7 @@ has a special first cross-reference whose |num| field is |file_flag|. @d xref equiv_or_xref @= -xref_ptr=xmem; init_node(name_dir); xref_switch=0; section_xref_switch=0; +xref_ptr=xmem; init_node(name_dir); xref_switch=section_xref_switch=0; xmem->num=0; /* sentinel value */ @ A new cross-reference for an identifier is formed by calling |new_xref|, @@ -239,12 +242,12 @@ to one-letter identifiers or \CEE/'s reserved words. If the user has sent the |no_xref| flag (the \.{-x} option of the command line), it is unnecessary to keep track of cross-references for identifiers. If one were careful, one could probably make more changes around section -100 to avoid a lot of identifier looking up. +115 to avoid a lot of identifier looking up. @d append_xref(c) if (xref_ptr==xmem_end) overflow("cross-reference"); else (++xref_ptr)->num=c; @d no_xref (!make_xrefs) -@d is_tiny(p) ((p+1)->byte_start==(p)->byte_start+1) +@d is_tiny(p) (length(p)==1) @d unindexed(a) (ailk>=custom) /* tells if uses of a name are to be indexed */ @@ -289,9 +292,9 @@ static void new_section_xref( name_pointer p) { - xref_pointer q,r; /* pointers to previous cross-references */ - q=(xref_pointer)p->xref; r=xmem; - if (q>xmem) + xref_pointer q=(xref_pointer)p->xref; + xref_pointer r=xmem; /* pointers to previous cross-references */ + if (q>r) while (q->num>section_xref_switch) {r=q; q=q->xlink;} if (r->num==section_count+section_xref_switch) return; /* don't duplicate entries */ @@ -309,8 +312,7 @@ static void set_file_flag( name_pointer p) { - xref_pointer q; - q=(xref_pointer)p->xref; + xref_pointer q=(xref_pointer)p->xref; if (q->num==file_flag) return; append_xref(file_flag); xref_ptr->xlink = q; @@ -350,11 +352,11 @@ text_ptr=max_text_ptr=tok_start+1; @ Here are the three procedures needed to complete |id_lookup|: @c -boolean names_match(@t\1\1@> +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@>) /* desired |ilk| */ +eight_bits t) /* desired |ilk| */ { if (length(p)!=l) return false; if (p->ilk!=t && !(t==normal && abnormal(p))) return false; @@ -385,14 +387,18 @@ name_pointer p) @ @=@+static void update_node(name_pointer p); -@ We have to get \CEE/'s +@ We have to get \CEE/'s and \CPLUSPLUS/'s reserved words into the hash table, and the simplest way to do this is to insert them every time \.{CWEAVE} is run. Fortunately there are relatively few reserved words. (Some of these are not strictly ``reserved,'' but -are defined in header files of the ISO Standard \CEE/ Library.) +are defined in header files of the ISO Standard \CEE/ Library. +An ever growing list of \CPLUSPLUS/ keywords can be found here: +\.{https://en.cppreference.com/w/cpp/keyword}.) @^reserved words@> @= +id_lookup("alignas",NULL,alignas_like); +id_lookup("alignof",NULL,sizeof_like); id_lookup("and",NULL,alfop); id_lookup("and_eq",NULL,alfop); id_lookup("asm",NULL,sizeof_like); @@ -404,13 +410,24 @@ id_lookup("break",NULL,case_like); id_lookup("case",NULL,case_like); id_lookup("catch",NULL,catch_like); id_lookup("char",NULL,raw_int); +id_lookup("char8_t",NULL,raw_int); +id_lookup("char16_t",NULL,raw_int); +id_lookup("char32_t",NULL,raw_int); id_lookup("class",NULL,struct_like); id_lookup("clock_t",NULL,raw_int); id_lookup("compl",NULL,alfop); +id_lookup("concept",NULL,int_like); id_lookup("const",NULL,const_like); +id_lookup("consteval",NULL,const_like); +id_lookup("constexpr",NULL,const_like); +id_lookup("constinit",NULL,const_like); id_lookup("const_cast",NULL,raw_int); id_lookup("continue",NULL,case_like); -id_lookup("default",NULL,case_like); +id_lookup("co_await",NULL,case_like); +id_lookup("co_return",NULL,case_like); +id_lookup("co_yield",NULL,case_like); +id_lookup("decltype",NULL,sizeof_like); +id_lookup("default",NULL,default_like); id_lookup("define",NULL,define_like); id_lookup("defined",NULL,sizeof_like); id_lookup("delete",NULL,delete_like); @@ -427,6 +444,7 @@ id_lookup("explicit",NULL,int_like); id_lookup("export",NULL,int_like); id_lookup("extern",NULL,int_like); id_lookup("FILE",NULL,raw_int); +id_lookup("false",NULL,normal); id_lookup("float",NULL,raw_int); id_lookup("for",NULL,for_like); id_lookup("fpos_t",NULL,raw_int); @@ -445,9 +463,11 @@ id_lookup("long",NULL,raw_int); id_lookup("mutable",NULL,int_like); id_lookup("namespace",NULL,struct_like); id_lookup("new",NULL,new_like); +id_lookup("noexcept",NULL,attr); id_lookup("not",NULL,alfop); id_lookup("not_eq",NULL,alfop); id_lookup("NULL",NULL,custom); +id_lookup("nullptr",NULL,custom); id_lookup("offsetof",NULL,raw_int); id_lookup("operator",NULL,operator_like); id_lookup("or",NULL,alfop); @@ -459,6 +479,8 @@ id_lookup("ptrdiff_t",NULL,raw_int); id_lookup("public",NULL,public_like); id_lookup("register",NULL,int_like); id_lookup("reinterpret_cast",NULL,raw_int); +id_lookup("requires",NULL,int_like); +id_lookup("restrict",NULL,int_like); id_lookup("return",NULL,case_like); id_lookup("short",NULL,raw_int); id_lookup("sig_atomic_t",NULL,raw_int); @@ -466,21 +488,24 @@ id_lookup("signed",NULL,raw_int); id_lookup("size_t",NULL,raw_int); id_lookup("sizeof",NULL,sizeof_like); id_lookup("static",NULL,int_like); +id_lookup("static_assert",NULL,sizeof_like); id_lookup("static_cast",NULL,raw_int); id_lookup("struct",NULL,struct_like); id_lookup("switch",NULL,for_like); id_lookup("template",NULL,template_like); id_lookup("this",NULL,custom); +id_lookup("thread_local",NULL,raw_int); id_lookup("throw",NULL,case_like); id_lookup("time_t",NULL,raw_int); +id_lookup("true",NULL,normal); id_lookup("try",NULL,else_like); id_lookup("typedef",NULL,typedef_like); -id_lookup("typeid",NULL,raw_int); +id_lookup("typeid",NULL,sizeof_like); id_lookup("typename",NULL,struct_like); id_lookup("undef",NULL,if_like); id_lookup("union",NULL,struct_like); id_lookup("unsigned",NULL,raw_int); -id_lookup("using",NULL,int_like); +id_lookup("using",NULL,using_like); id_lookup("va_dcl",NULL,decl); /* Berkeley's variable-arg-list convention */ id_lookup("va_list",NULL,raw_int); /* ditto */ id_lookup("virtual",NULL,int_like); @@ -491,6 +516,8 @@ id_lookup("while",NULL,for_like); id_lookup("xor",NULL,alfop); id_lookup("xor_eq",NULL,alfop);@+ res_wd_end=name_ptr; id_lookup("TeX",NULL,custom); +id_lookup("complex",NULL,int_like); +id_lookup("imaginary",NULL,int_like); id_lookup("make_pair",NULL,func_template); @* Lexical scanning. @@ -513,11 +540,11 @@ scanning routines. @^ASCII code dependencies@> @d ignore 00 /* control code of no interest to \.{CWEAVE} */ -@d verbatim 02 /* takes the place of extended ASCII \.{\char2} */ +@d verbatim 02 /* takes the place of ASCII \.{STX} */ @d begin_short_comment 03 /* \CPLUSPLUS/ short comment */ @d begin_comment '\t' /* tab marks will not appear */ @d underline '\n' /* this code will be intercepted without confusion */ -@d noop 0177 /* takes the place of ASCII delete */ +@d noop 0177 /* takes the place of ASCII \.{DEL} */ @d xref_roman 0203 /* control code for `\.{@@\^}' */ @d xref_wildcard 0204 /* control code for `\.{@@:}' */ @d xref_typewriter 0205 /* control code for `\.{@@.}' */ @@ -548,10 +575,12 @@ representation by means of the table |ccode|. @= static eight_bits ccode[256]; /* meaning of a char following \.{@@} */ -@ @= -{int c; for (c=0; c<256; c++) ccode[c]=0;} +@ @= { + 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['*']=new_section; ccode['@@']='@@'; /* `quoted' at sign */ ccode['=']=verbatim; ccode['d']=ccode['D']=definition; @@ -671,13 +700,6 @@ static char cur_section_char; /* the character just before that name */ @ As one might expect, |get_next| consists mostly of a big switch that branches to the various special cases that can arise. -\CEE/ allows underscores to appear in identifiers, and some \CEE/ -compilers even allow the dollar sign. - -@d isxalpha(c) ((c)=='_' || (c)=='$') - /* non-alpha characters allowed in identifier */ -@d ishigh(c) ((eight_bits)(c)>0177) -@^high-bit character handling@> @c static eight_bits @@ -694,7 +716,7 @@ get_next(void) /* produces the next input token */ || ((c=='u' && *loc=='8')&&(*(loc+1)=='\'' || *(loc+1)=='"'))@| || (c=='<' && sharp_include_line==true)) @@; - else if (xisalpha(c) || isxalpha(c) || ishigh(c)) + else if (isalpha(c) || isxalpha(c) || ishigh(c)) @@; else if (c=='@@') @@; else if (xisspace(c)) continue; /* ignore spaces and tabs */ @@ -733,7 +755,8 @@ a file name in lines that start with \.{\#include}. We must treat this file name as a string. @= -static boolean sharp_include_line=false; /* are we scanning a \&{\#include} line? */ +static boolean sharp_include_line=false; + /* are we scanning a \#\&{include} line? */ @ @= while (loc<=buffer_end-7 && xisspace(*loc)) loc++; @@ -758,26 +781,25 @@ combinations \.{...}, \.{::}, \.{.*} and \.{->*}. The compound assignment operators (e.g., \.{+=}) are treated as separate tokens. -@d compress(c) if (loc++<=limit) return c - @= switch(c) { - case '/': if (*loc=='*') {compress(begin_comment);} + case '/': if (*loc=='*') {@+compress(begin_comment);@+} else if (*loc=='/') compress(begin_short_comment); break; case '+': if (*loc=='+') compress(plus_plus); break; - case '-': if (*loc=='-') {compress(minus_minus);} - else { if (*loc=='>') { if (*(loc+1)=='*') {loc++; compress(minus_gt_ast);} - else compress(minus_gt); } } break; - case '.': if (*loc=='*') {compress(period_ast);} + 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; @@ -786,7 +808,9 @@ switch(c) { @ @= { id_first=--loc; - while (isalpha((eight_bits)*++loc) || isdigit((eight_bits)*loc) @| + do + ++loc; + while (isalpha((eight_bits)*loc) || isdigit((eight_bits)*loc) @| || isxalpha((eight_bits)*loc) || ishigh((eight_bits)*loc)); id_loc=loc; return identifier; } @@ -798,28 +822,38 @@ introduced by \.0 and hexadecimals by \.{0x}, but \.{CWEAVE} will print with \TEX/ macros that the user can redefine to fit the context. In order to simplify such macros, we replace some of the characters. +On output, the \.{\ } that replaces \.{'} in \CPLUSPLUS/ literals will become +``\.{\\\ }''. + Notice that in this section and the next, |id_first| and |id_loc| are pointers into the array |section_text|, not into |buffer|. +@d gather_digits_while(t) while (t || *loc=='\'') + if (*loc=='\'') { /* \CPLUSPLUS/-style digit separator */ + *id_loc++=' '; loc++; /* insert a little bit of space */ + }@+else *id_loc++=*loc++; + @= { id_first=id_loc=section_text+1; + if (*(loc-1)=='.' && !xisdigit(*loc)) goto mistake; /* not a constant */ if (*(loc-1)=='0') { - if (*loc=='x' || *loc=='X') {*id_loc++='^'; loc++; - while (xisxdigit(*loc)) *id_loc++=*loc++;} /* hex constant */ - else if (xisdigit(*loc)) {*id_loc++='~'; - while (xisdigit(*loc)) *id_loc++=*loc++;} /* octal constant */ - else goto dec; /* decimal constant */ - } - else { /* decimal constant */ - if (*(loc-1)=='.' && !xisdigit(*loc)) goto mistake; /* not a constant */ - dec: *id_loc++=*(loc-1); - while (xisdigit(*loc) || *loc=='.') *id_loc++=*loc++; - if (*loc=='e' || *loc=='E') { /* float constant */ - *id_loc++='_'; loc++; - if (*loc=='+' || *loc=='-') *id_loc++=*loc++; - while (xisdigit(*loc)) *id_loc++=*loc++; - } + if (*loc=='x' || *loc=='X') @@; + else if (*loc=='b' || *loc=='B') @@; + else if (xisdigit(*loc)) @@; } + *id_loc++=*(loc-1); /* decimal constant */ + gather_digits_while(xisdigit(*loc) || *loc=='.'); +get_exponent: + if (*loc=='e' || *loc=='E') + *id_loc++='_'; + else if (*loc=='p' || *loc=='P') + *id_loc++='%'; + else + goto digit_suffix; + loc++; + if (*loc=='+' || *loc=='-') *id_loc++=*loc++; + gather_digits_while(xisdigit(*loc)); +digit_suffix: while (*loc=='u' || *loc=='U' || *loc=='l' || *loc=='L' || *loc=='f' || *loc=='F') { *id_loc++='$'; *id_loc++=toupper((eight_bits)*loc); loc++; @@ -827,22 +861,37 @@ are pointers into the array |section_text|, not into |buffer|. return constant; } +@ @={ + *id_loc++='^'; loc++; + gather_digits_while(xisxdigit(*loc) || *loc=='.'); + *id_loc++='/'; goto get_exponent; +} + +@ @={ + *id_loc++='\\'; loc++; + gather_digits_while(*loc=='0' || *loc=='1'); + *id_loc++='/'; goto digit_suffix; +} + +@ @={ + *id_loc++='~'; gather_digits_while(xisdigit(*loc)); + *id_loc++='/'; goto digit_suffix; +} + @ \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|. -@= { +@= {@+ char delim = c; /* what started the string */ id_first = section_text+1; id_loc = section_text; if (delim=='\'' && *(loc-2)=='@@') {*++id_loc='@@'; *++id_loc='@@';} *++id_loc=delim; - if (delim=='L' || delim=='u' || delim=='U') { /* wide character constant */ - if (delim=='u' && *loc=='8') { *++id_loc=*loc++; } - delim=*loc++; *++id_loc=delim; - } - if (delim=='<') delim='>'; /* for file names in \&{\#include} lines */ + if (delim=='L' || delim=='u' || delim=='U') + @@; + if (delim=='<') delim='>'; /* for file names in \#\&{include} lines */ while (true) { if (loc>=limit) { if(*(limit-1)!='\\') { @@ -858,10 +907,14 @@ convention, but do not allow the string to be longer than |longest_name|. if (++id_loc<=section_text_end) *id_loc=c; break; } - if (c=='\\') { if (loc>=limit) continue; - else { if (++id_loc<=section_text_end) { - *id_loc = '\\'; c=*loc++; - } } } + if (c=='\\') { + if (loc>=limit) continue; + else { + if (++id_loc<=section_text_end) { + *id_loc = '\\'; c=*loc++; + } + } + } if (++id_loc<=section_text_end) *id_loc=c; } if (id_loc>=section_text_end) { @@ -874,6 +927,11 @@ convention, but do not allow the string to be longer than |longest_name|. return string; } +@ @={ + if (delim=='u' && *loc=='8') *++id_loc=*loc++; + delim=*loc++; *++id_loc=delim; +} + @ After an \.{@@} sign has been scanned, the next character tells us whether there is more work to do. @@ -885,7 +943,7 @@ whether there is more work to do. case underline: xref_switch=def_flag; continue; case trace: tracing=c-'0'; continue; case xref_roman: case xref_wildcard: case xref_typewriter: case noop: - case TeX_string: c=ccode[(eight_bits)c]; skip_restricted(); return c; + case TeX_string: skip_restricted(); return ccode[(eight_bits)c]; case section_name: @@; case verbatim: @@; @@ -902,8 +960,9 @@ because the section name might (for example) follow \&{int}. cur_section_char=*(loc-1); @@; if (k-section_text>3 && strncmp(k-2,"...",3)==0) - cur_section=section_lookup(section_text+1,k-3,1); /* 1 indicates a prefix */ - else cur_section=section_lookup(section_text+1,k,0); + cur_section=section_lookup(section_text+1,k-3,true); + /* |true| indicates a prefix */ + else cur_section=section_lookup(section_text+1,k,false); xref_switch=0; return section_name; } @@ -969,8 +1028,7 @@ false_alarm: if (loc++>limit) { err_print("! Control text didn't end"); loc=limit; @.Control text didn't end@> - } - else { + } else { if (*loc=='@@'&&loc<=limit) {loc++; goto false_alarm;} if (*loc++!='>') err_print("! Control codes are forbidden in control text"); @@ -1067,8 +1125,8 @@ static void outer_xref(void); @ @c static void -C_xref(@t\1\1@> /* makes cross-references for \CEE/ identifiers */ - eight_bits spec_ctrl@t\2\2@>) +C_xref( /* makes cross-references for \CEE/ identifiers */ + eight_bits spec_ctrl) { name_pointer p; /* a referenced name */ while (next_control +flush_buffer( char *b, /* outputs from |out_buf+1| to |b|, where |b<=out_ptr| */ -boolean per_cent,boolean carryover@t\2\2@>) +boolean per_cent,boolean carryover) { - char *j; j=b; /* pointer into |out_buf| */ + char *j=b; /* pointer into |out_buf| */ if (! per_cent) /* remove trailing blanks */ while (j>out_buf && *j==' ') j--; c_line_write(j-out_buf); @@ -1378,8 +1436,8 @@ static void break_out(void); @ @c static void -out_str(@t\1\1@> /* output characters from |s| to end of string */ -const char*s@t\2\2@>) +out_str( /* output characters from |s| to end of string */ +const char*s) { while (*s) out(*s++); } @@ -1546,9 +1604,9 @@ one further token without overflow. @d app_tok(c) {if (tok_ptr+2>tok_mem_end) overflow("token"); *(tok_ptr++)=c;} @c -static int copy_comment(@t\1\1@> /* copies \TeX\ code in comments */ +static int copy_comment( /* copies \TeX\ code in comments */ boolean is_long_comment, /* is this a traditional \CEE/ comment? */ -int bal@t\2\2@>) /* brace balance */ +int bal) /* brace balance */ { char c; /* current character being copied */ while (true) { @@ -1559,8 +1617,7 @@ int bal@t\2\2@>) /* brace balance */ @.Input ended in mid-comment@> loc=buffer+1; goto done; } - } - else { + } else { if (bal>1) err_print("! Missing } in comment"); @.Missing \} in comment@> goto done; @@ -1583,7 +1640,7 @@ int bal@t\2\2@>) /* brace balance */ } } } -done:@@; +done: @@; } @ @= @@ -1601,9 +1658,11 @@ if (c=='@@') { @.Illegal use of @@...@> loc-=2; if (phase==2) *(tok_ptr-1)=' '; goto done; } +} else { + if (c=='\\' && *loc!='@@') { + if (phase==2) app_tok(*(loc++))@; else loc++; + } } -else { if (c=='\\' && *loc!='@@') { - if (phase==2) app_tok(*(loc++))@; else loc++; } } @ We output enough right braces to keep \TEX/ happy. @@ -1683,8 +1742,8 @@ same initial letter; these subscripts are assigned from left to right. @d rbrace 8 /* denotes a right brace */ @d decl_head 9 /* denotes an incomplete declaration */ @d comma 10 /* denotes a comma */ -@d lpar 11 /* denotes a left parenthesis or left bracket */ -@d rpar 12 /* denotes a right parenthesis or right bracket */ +@d lpar 11 /* denotes a left parenthesis */ +@d rpar 12 /* denotes a right parenthesis */ @d prelangle 13 /* denotes `$<$' before we know what it is */ @d prerangle 14 /* denotes `$>$' before we know what it is */ @d langle 15 /* denotes `$<$' when it's used as angle bracket in a template */ @@ -1706,10 +1765,13 @@ same initial letter; these subscripts are assigned from left to right. @d insert 37 /* a scrap that gets combined with its neighbor */ @d section_scrap 38 /* section name */ @d dead 39 /* scrap that won't combine */ -@d ftemplate 59 /* \\{make\_pair} */ -@d new_exp 60 /* \&{new} and a following type identifier */ -@d begin_arg 61 /* \.{@@[} */ -@d end_arg 62 /* \.{@@]} */ +@d ftemplate 63 /* \\{make\_pair} */ +@d new_exp 64 /* \&{new} and a following type identifier */ +@d begin_arg 65 /* \.{@@[} */ +@d end_arg 66 /* \.{@@]} */ +@d lbrack 67 /* denotes a left bracket */ +@d rbrack 68 /* denotes a right bracket */ +@d attr_head 69 /* denotes beginning of attribute */ @= static char cat_name[256][12]; @@ -1774,14 +1836,21 @@ static char cat_name[256][12]; strcpy(cat_name[new_exp],"new_exp"); strcpy(cat_name[begin_arg],"@@["@q]@>); strcpy(cat_name[end_arg],@q[@>"@@]"); + strcpy(cat_name[lbrack],"["); + strcpy(cat_name[rbrack],"]"); + strcpy(cat_name[attr_head],"attr_head"); + strcpy(cat_name[attr],"attr"); + strcpy(cat_name[alignas_like],"alignas"); + strcpy(cat_name[using_like],"using"); + strcpy(cat_name[default_like],"default"); strcpy(cat_name[0],"zero"); @ This code allows \.{CWEAVE} to display its parsing steps. @c static void -print_cat(@t\1\1@> /* symbolic printout of a category */ -eight_bits c@t\2\2@>) +print_cat( /* symbolic printout of a category */ +eight_bits c) { fputs(cat_name[c],stdout); } @@ -1813,7 +1882,9 @@ $10n$; \yskip\hang |indent| causes future lines to be indented one more em; -\yskip\hang |outdent| causes future lines to be indented one less em. +\yskip\hang |outdent| causes future lines to be indented one less em; + +\yskip\hang |dindent| causes future lines to be indented two more ems. \yskip\noindent All of these tokens are removed from the \TEX/ output that comes from \CEE/ text between \pb\ signs; |break_space| and |force| and @@ -1827,6 +1898,10 @@ However, a sequence of consecutive `\.\ ', |break_space|, |force|, and/or |big_force| tokens is first replaced by a single token (the maximum of the given ones). +A |dindent| token becomes \.{\\1\\1}. It is equivalent to a pair of |indent| +tokens. However, if |dindent| immediately precedes |big_force|, the two tokens +are swapped, so that the indentation happens after the line break. + The token |math_rel| will be translated into \.{\\MRL\{}, and it will get a matching \.\} later. Other control sequences in the \TEX/ output will be @@ -1854,6 +1929,7 @@ reserved words, `\.{\\.\{}$\,\ldots\,$\.\}' surrounding strings, @d end_translation 0223 /* special sentinel token at end of list */ @d inserted 0224 /* sentinel to mark translations of inserts */ @d qualifier 0225 /* introduces an explicit namespace qualifier */ +@d dindent 0226 /* two more tabs (\.{\\1\\1}) */ @ The raw input is converted into scraps according to the following table, which gives category codes followed by the translations. @@ -1892,11 +1968,14 @@ with discretionary breaks in between. \.{@@=}string\.{@@>}&|exp|: \.{\\vb\{}string with special characters quoted\.\}&maybe\cr \.{@@'7'}&|exp|: \.{\\.\{@@'7'\}}&maybe\cr -\.{077} or \.{\\77}&|exp|: \.{\\T\{\\\~77\}}&maybe\cr -\.{0x7f}&|exp|: \.{\\T\{\\\^7f\}}&maybe\cr +\.{077} or \.{\\77}&|exp|: \.{\\T\{\\\~77/\}}&maybe\cr +\.{0x7f}&|exp|: \.{\\T\{\\\^7f/\}}&maybe\cr +\.{0b10111}&|exp|: \.{\\T\{\\\\10111/\}}&maybe\cr \.{77}&|exp|: \.{\\T\{77\}}&maybe\cr \.{77L}&|exp|: \.{\\T\{77\\\$L\}}&maybe\cr \.{0.1E5}&|exp|: \.{\\T\{0.1\\\_5\}}&maybe\cr +\.{0x10p3}&|exp|: \.{\\T\{\\\^10/\\\%3\}}&maybe\cr +\.{1'000'000}&|exp|: \.{\\T\{1\\\ 000\\\ 000\}}&maybe\cr \.+&|ubinop|: \.+&yes\cr \.-&|ubinop|: \.-&yes\cr \.*&|raw_ubin|: \.*&yes\cr @@ -1913,9 +1992,9 @@ with discretionary breaks in between. \.\~&|unop|: \.{\\CM}&yes\cr \.\&&|raw_ubin|: \.{\\AND}&yes\cr \.(&|lpar|: \.(&maybe\cr -\.[&|lpar|: \.[&maybe\cr \.)&|rpar|: \.)&maybe\cr -\.]&|rpar|: \.]&maybe\cr +\.[&|lbrack|: \.[&maybe\cr +\.]&|rbrack|: \.]&maybe\cr \.\{&|lbrace|: \.\{&yes\cr \.\}&|lbrace|: \.\}&yes\cr \.,&|comma|: \.,&yes\cr @@ -1926,6 +2005,8 @@ with discretionary breaks in between. end of \.\# line&|rproc|: |force|&no\cr identifier&|exp|: \.{\\\\\{}identifier with underlines and dollar signs quoted\.\}&maybe\cr +\.{alignas}&|alignas_like|: \stars&maybe\cr +\.{alignof}&|sizeof_like|: \stars&maybe\cr \.{and}&|alfop|: \stars&yes\cr \.{and\_eq}&|alfop|: \stars&yes\cr \.{asm}&|sizeof_like|: \stars&maybe\cr @@ -1937,13 +2018,25 @@ identifier&|exp|: \.{\\\\\{}identifier with underlines and \.{case}&|case_like|: \stars&maybe\cr \.{catch}&|catch_like|: \stars&maybe\cr \.{char}&|raw_int|: \stars&maybe\cr +\.{char8\_t}&|raw_int|: \stars&maybe\cr +\.{char16\_t}&|raw_int|: \stars&maybe\cr +\.{char32\_t}&|raw_int|: \stars&maybe\cr \.{class}&|struct_like|: \stars&maybe\cr \.{clock\_t}&|raw_int|: \stars&maybe\cr \.{compl}&|alfop|: \stars&yes\cr +\.{complex}&|int_like|: \stars&yes\cr +\.{concept}&|int_like|: \stars&maybe\cr \.{const}&|const_like|: \stars&maybe\cr +\.{consteval}&|const_like|: \stars&maybe\cr +\.{constexpr}&|const_like|: \stars&maybe\cr +\.{constinit}&|const_like|: \stars&maybe\cr \.{const\_cast}&|raw_int|: \stars&maybe\cr \.{continue}&|case_like|: \stars&maybe\cr -\.{default}&|case_like|: \stars&maybe\cr +\.{co\_await}&|case_like|: \stars&maybe\cr +\.{co\_return}&|case_like|: \stars&maybe\cr +\.{co\_yield}&|case_like|: \stars&maybe\cr +\.{decltype}&|sizeof_like|: \stars&maybe\cr +\.{default}&|default_like|: \stars&maybe\cr \.{define}&|define_like|: \stars&maybe\cr \.{defined}&|sizeof_like|: \stars&maybe\cr \.{delete}&|delete_like|: \stars&maybe\cr @@ -1960,6 +2053,7 @@ identifier&|exp|: \.{\\\\\{}identifier with underlines and \.{export}&|int_like|: \stars&maybe\cr \.{extern}&|int_like|: \stars&maybe\cr \.{FILE}&|raw_int|: \stars&maybe\cr +\.{false}&|normal|: \stars&maybe\cr \.{float}&|raw_int|: \stars&maybe\cr \.{for}&|for_like|: \stars&maybe\cr \.{fpos\_t}&|raw_int|: \stars&maybe\cr @@ -1968,6 +2062,7 @@ identifier&|exp|: \.{\\\\\{}identifier with underlines and \.{if}&|if_like|: \stars&maybe\cr \.{ifdef}&|if_like|: \stars&maybe\cr \.{ifndef}&|if_like|: \stars&maybe\cr +\.{imaginary}&|int_like|: \stars&maybe\cr \.{include}&|if_like|: \stars&maybe\cr \.{inline}&|int_like|: \stars&maybe\cr \.{int}&|raw_int|: \stars&maybe\cr @@ -1979,9 +2074,11 @@ identifier&|exp|: \.{\\\\\{}identifier with underlines and \.{mutable}&|int_like|: \stars&maybe\cr \.{namespace}&|struct_like|: \stars&maybe\cr \.{new}&|new_like|: \stars&maybe\cr +\.{noexcept}&|attr|: \stars&maybe\cr \.{not}&|alfop|: \stars&yes\cr \.{not\_eq}&|alfop|: \stars&yes\cr \.{NULL}&|exp|: \.{\\NULL}&yes\cr +\.{nullptr}&|exp|: \.{\\NULL}&yes\cr \.{offsetof}&|raw_int|: \stars&maybe\cr \.{operator}&|operator_like|: \stars&maybe\cr \.{or}&|alfop|: \stars&yes\cr @@ -1993,6 +2090,8 @@ identifier&|exp|: \.{\\\\\{}identifier with underlines and \.{public}&|public_like|: \stars&maybe\cr \.{register}&|int_like|: \stars&maybe\cr \.{reinterpret\_cast}&|raw_int|: \stars&maybe\cr +\.{requires}&|int_like|: \stars&maybe\cr +\.{restrict}&|int_like|: \stars&maybe\cr \.{return}&|case_like|: \stars&maybe\cr \.{short}&|raw_int|: \stars&maybe\cr \.{sig\_atomic\_t}&|raw_int|: \stars&maybe\cr @@ -2000,22 +2099,24 @@ identifier&|exp|: \.{\\\\\{}identifier with underlines and \.{size\_t}&|raw_int|: \stars&maybe\cr \.{sizeof}&|sizeof_like|: \stars&maybe\cr \.{static}&|int_like|: \stars&maybe\cr +\.{static\_assert}&|sizeof_like|: \stars&maybe\cr \.{static\_cast}&|raw_int|: \stars&maybe\cr \.{struct}&|struct_like|: \stars&maybe\cr \.{switch}&|for_like|: \stars&maybe\cr \.{template}&|template_like|: \stars&maybe\cr \.{TeX}&|exp|: \.{\\TeX}&yes\cr \.{this}&|exp|: \.{\\this}&yes\cr +\.{thread\_local}&|raw_int|: \stars&maybe\cr \.{throw}&|case_like|: \stars&maybe\cr \.{time\_t}&|raw_int|: \stars&maybe\cr \.{try}&|else_like|: \stars&maybe\cr \.{typedef}&|typedef_like|: \stars&maybe\cr -\.{typeid}&|raw_int|: \stars&maybe\cr +\.{typeid}&|sizeof_like|: \stars&maybe\cr \.{typename}&|struct_like|: \stars&maybe\cr \.{undef}&|if_like|: \stars&maybe\cr \.{union}&|struct_like|: \stars&maybe\cr \.{unsigned}&|raw_int|: \stars&maybe\cr -\.{using}&|int_like|: \stars&maybe\cr +\.{using}&|using_like|: \stars&maybe\cr \.{va\_dcl}&|decl|: \stars&maybe\cr \.{va\_list}&|raw_int|: \stars&maybe\cr \.{virtual}&|int_like|: \stars&maybe\cr @@ -2137,23 +2238,26 @@ translated without line-break controls. @c static void -print_text(@t\1\1@> /* prints a token list for debugging; not used in |main| */ -text_pointer p@t\2\2@>) +print_text( /* prints a token list for debugging; not used in |main| */ +text_pointer p) { token_pointer j; /* index into |tok_mem| */ sixteen_bits r; /* remainder of token after the flag has been stripped off */ if (p>=text_ptr) printf("BAD"); else for (j=*p; j<*(p+1); j++) { r=*j%id_flag; - switch (*j/id_flag) { - case 1: printf("\\\\{"@q}@>); print_id((name_dir+r)); printf(@q{@>"}"); - break; /* |id_flag| */ - case 2: printf("\\&{"@q}@>); print_id((name_dir+r)); printf(@q{@>"}"); - break; /* |res_flag| */ - case 3: printf("<"); print_section_name((name_dir+r)); printf(">"); - break; /* |section_flag| */ - case 4: printf("[[%d]]",r); break; /* |tok_flag| */ - case 5: printf("|[[%d]]|",r); break; /* |inner_tok_flag| */ + switch (*j) { + case id_flag: + printf("\\\\{"@q}@>); print_id((name_dir+r)); putchar(@q{@>'}'); + break; + case res_flag: + printf("\\&{"@q}@>); print_id((name_dir+r)); putchar(@q{@>'}'); + break; + case section_flag: + putchar('<'); print_section_name((name_dir+r)); putchar('>'); + break; + case tok_flag: printf("[[%d]]",r); break; + case inner_tok_flag: printf("|[[%d]]|",r); break; default: @@; } } @@ -2169,6 +2273,7 @@ switch (r) { case cancel: printf("[cancel]"); break; case indent: printf("[indent]"); break; case outdent: printf("[outdent]"); break; + case dindent: printf("[dindent]"); break; case backup: printf("[backup]"); break; case opt: printf("[opt]"); break; case break_space: printf("[break]"); break; @@ -2178,7 +2283,7 @@ switch (r) { case quoted_char: j++; printf("[%o]",(unsigned int)*j); break; case end_translation: printf("[quit]"); break; case inserted: printf("[inserted]"); break; - default: putxchar(r); + default: putchar(r); } @ The production rules listed above are embedded directly into \.{CWEAVE}, @@ -2253,8 +2358,9 @@ productions as they were listed earlier. @d no_math 2 /* should be in horizontal mode */ @d yes_math 1 /* should be in math mode */ @d maybe_math 0 /* works in either horizontal or math mode */ -@d big_app2(a) big_app1(a);big_app1(a+1) -@d big_app3(a) big_app2(a);big_app1(a+2) +@d big_app2(a) big_app1(a);@+big_app1(a+1) +@d big_app3(a) big_app2(a);@+big_app1(a+2) +@d big_app1_insert(p,c) big_app1(p);@+big_app(c);@+big_app1(p+1) @d app(a) *(tok_ptr++)=(token)(a) @d app1(a) *(tok_ptr++)=(token)(tok_flag+(int)((a)->trans-tok_start)) @@ -2278,12 +2384,12 @@ static void big_app( token a) { - if (a==' ' || (a>=big_cancel && a<=big_force)) /* non-math token */ { + if (a==' ' || (a>=big_cancel && a<=big_force) || a==dindent) + /* non-math token */ { if (cur_mathness==maybe_math) init_mathness=no_math; else if (cur_mathness==yes_math) app_str("{}$"); cur_mathness=no_math; - } - else { + } else { if (cur_mathness==maybe_math) init_mathness=yes_math; else if (cur_mathness==no_math) app_str("${}"); cur_mathness=yes_math; @@ -2320,7 +2426,7 @@ code needs to be provided with a proper environment. @d cat2 (pp+2)->cat @d cat3 (pp+3)->cat @d lhs_not_simple (pp->cat!=public_like - && pp->cat!=semi + && pp->cat!=semi && pp->cat!=prelangle && pp->cat!=prerangle @| && pp->cat!=template_like @@ -2337,6 +2443,8 @@ code needs to be provided with a proper environment. if (cat1==end_arg && lhs_not_simple) if (pp->cat==begin_arg) squash(pp,2,exp,-2,124); else squash(pp,2,end_arg,-1,125); + else if (pp->cat==rbrack) squash(pp,1,rpar,-3,130); + else if (pp->cat==using_like) squash(pp,1,int_like,-3,140); else if (cat1==insert) squash(pp,2,pp->cat,-2,0); else if (cat2==insert) squash(pp+1,2,(pp+1)->cat,-1,0); else if (cat3==insert) squash(pp+2,2,(pp+2)->cat,0,0); @@ -2389,6 +2497,11 @@ code needs to be provided with a proper environment. case typedef_like: @@; @+break; case delete_like: @@; @+break; case question: @@; @+break; + case alignas_like: @@; @+break; + case lbrack: @@; @+break; + case attr_head: @@; @+break; + case attr: @@; @+break; + case default_like: @@; @+break; } pp++; /* if no match was found, we move to the right */ } @@ -2457,8 +2570,8 @@ the |for| loop below. @c static void -make_reserved(@t\1\1@> /* make the first identifier in |p->trans| like |int| */ -scrap_pointer p@t\2\2@>) +make_reserved( /* make the first identifier in |p->trans| like |int| */ +scrap_pointer p) { sixteen_bits tok_value; /* the name of this identifier, plus its flag */ token_pointer tok_loc; /* pointer to |tok_value| */ @@ -2488,9 +2601,9 @@ it has been swallowed up by an |exp|. @c static void -make_underlined(@t\1\1@> +make_underlined( /* underline the entry for the first identifier in |p->trans| */ -scrap_pointer p@t\2\2@>) +scrap_pointer p) { token_pointer tok_loc; /* where the first identifier appears */ if ((tok_loc=find_first_ident(p->trans))<=operator_found) @@ -2535,11 +2648,11 @@ to insert the new cross-reference not at the beginning of the list (namely, at |p->xref|), but rather right before |q|. @= - append_xref(0); /* this number doesn't matter */ - xref_ptr->xlink=(xref_pointer)p->xref; r=xref_ptr; - update_node(p); - while (r->xlink!=q) {r->num=r->xlink->num; r=r->xlink;} - r->num=m; /* everything from |q| on is left undisturbed */ +append_xref(0); /* this number doesn't matter */ +xref_ptr->xlink=(xref_pointer)p->xref; r=xref_ptr; +update_node(p); +while (r->xlink!=q) {r->num=r->xlink->num; r=r->xlink;} +r->num=m; /* everything from |q| on is left undisturbed */ @ Now comes the code that tries to match each production starting with a particular type of scrap. Whenever a match is discovered, @@ -2548,7 +2661,7 @@ to be performed, followed by |goto found|. @= if (cat1==lbrace || cat1==int_like || cat1==decl) { - make_underlined(pp); big_app1(pp); big_app(indent); app(indent); + make_underlined(pp); big_app(dindent); big_app1(pp); reduce(pp,1,fn_decl,0,1); } else if (cat1==unop) squash(pp,2,exp,-2,2); @@ -2562,16 +2675,20 @@ else if (cat1==lpar && cat2==rpar && cat3==colon) squash(pp+3,1,base,0,5); else if (cat1==cast && cat2==colon) squash(pp+2,1,base,0,5); else if (cat1==semi) squash(pp,2,stmt,-1,6); else if (cat1==colon) { - make_underlined (pp); squash(pp,2,tag,-1,7); + make_underlined (pp); squash(pp,2,tag,-1,7); } else if (cat1==rbrace) squash(pp,1,stmt,-1,8); else if (cat1==lpar && cat2==rpar && (cat3==const_like || cat3==case_like)) { - big_app1(pp+2); big_app(' '); big_app1(pp+3); reduce(pp+2,2,rpar,0,9); + big_app1_insert(pp+2,' '); reduce(pp+2,2,rpar,0,9); } else if (cat1==cast && (cat2==const_like || cat2==case_like)) { - big_app1(pp+1); big_app(' '); big_app1(pp+2); reduce(pp+1,2,cast,0,9); + big_app1_insert(pp+1,' '); reduce(pp+1,2,cast,0,9); } else if (cat1==exp || cat1==cast) squash(pp,2,exp,-2,10); +else if (cat1==attr) { + big_app1_insert(pp,' '); reduce(pp,2,exp,-2,142); +} +else if (cat1==colcol && cat2==int_like) squash(pp,3,int_like,-2,152); @ @= if ((cat1==exp||cat1==ubinop) && cat2==rpar) squash(pp,3,exp,-2,11); @@ -2594,15 +2711,13 @@ if (cat1==exp || cat1==int_like) squash(pp,2,exp,-2,16); @ @= if (cat1==cast && cat2==rpar) { - big_app('{'); big_app1(pp); big_app('}'); big_app1(pp+1); - reduce(pp,2,cast,-2,17); + big_app('{'); big_app1_insert(pp,'}'); reduce(pp,2,cast,-2,17); } else if (cat1==exp || cat1==int_like) { - big_app('{'); big_app1(pp); big_app('}'); big_app1(pp+1); - reduce(pp,2,cat1,-2,18); + big_app('{'); big_app1_insert(pp,'}'); reduce(pp,2,cat1,-2,18); } else if (cat1==binop) { - big_app(math_rel); big_app1(pp); big_app('{'); big_app1(pp+1); big_app('}'); + big_app(math_rel); big_app1_insert(pp,'{'); big_app('}'); big_app('}'); reduce(pp,2,binop,-1,19); } @@ -2616,19 +2731,19 @@ if (cat1==binop) { @ @= if (cat1==lpar) squash(pp,2,lpar,-1,21); else if (cat1==exp) { - big_app1(pp); big_app(' '); big_app1(pp+1); reduce(pp,2,exp,-2,21); + big_app1_insert(pp,' '); reduce(pp,2,exp,-2,21); } else if (cat1==semi) squash(pp,1,exp,-2,22); @ @= if (cat1==cast) squash(pp,2,exp,-2,23); else if (cat1==exp) { - big_app1(pp); big_app(' '); big_app1(pp+1); reduce(pp,2,exp,-2,24); + big_app1_insert(pp,' '); reduce(pp,2,exp,-2,24); } @ @= if (cat1==int_like|| cat1==struct_like) { - big_app1(pp); big_app(' '); big_app1(pp+1); reduce(pp,2,cat1,-2,25); + big_app1_insert(pp,' '); reduce(pp,2,cat1,-2,25); } else if (cat1==exp && (cat2==raw_int||cat2==struct_like)) squash(pp,2,int_like,-2,26); @@ -2644,17 +2759,17 @@ else squash(pp,1,int_like,-2,30); @ @= if (cat1==exp||cat1==int_like) { app(qualifier); squash(pp,2,cat1,-2,31); -}@+else if (cat1==colcol) squash(pp,2,colcol,-1,32); +} +else if (cat1==colcol) squash(pp,2,colcol,-1,32); @ @= if (cat1==comma) { big_app2(pp); big_app(' '); reduce(pp,2,decl_head,-1,33); } else if (cat1==ubinop) { - big_app1(pp); big_app('{'); big_app1(pp+1); big_app('}'); - reduce(pp,2,decl_head,-1,34); + big_app1_insert(pp,'{'); big_app('}'); reduce(pp,2,decl_head,-1,34); } -else if (cat1==exp && cat2!=lpar && cat2!=exp && cat2!=cast) { +else if (cat1==exp && cat2!=lpar && cat2!=lbrack && cat2!=exp && cat2!=cast) { make_underlined(pp+1); squash(pp,2,decl_head,-1,35); } else if ((cat1==binop||cat1==colon) && cat2==exp && (cat3==comma || @@ -2662,18 +2777,19 @@ else if ((cat1==binop||cat1==colon) && cat2==exp && (cat3==comma || squash(pp,3,decl_head,-1,36); else if (cat1==cast) squash(pp,2,decl_head,-1,37); else if (cat1==lbrace || cat1==int_like || cat1==decl) { - big_app1(pp); big_app(indent); app(indent); reduce(pp,1,fn_decl,0,38); + big_app(dindent); big_app1(pp); reduce(pp,1,fn_decl,0,38); } else if (cat1==semi) squash(pp,2,decl,-1,39); +else if (cat1==attr) { + big_app1_insert(pp,' '); reduce(pp,2,decl_head,-1,139); +} @ @= if (cat1==decl) { - big_app1(pp); big_app(force); big_app1(pp+1); - reduce(pp,2,decl,-1,40); + big_app1_insert(pp,force); reduce(pp,2,decl,-1,40); } else if (cat1==stmt || cat1==function) { - big_app1(pp); big_app(big_force); - big_app1(pp+1); reduce(pp,2,cat1,-1,41); + big_app1_insert(pp,big_force); reduce(pp,2,cat1,-1,41); } @ @= @@ -2683,19 +2799,19 @@ if (cat1==int_like || cat1==exp) { app(opt); app('9'); reduce(pp,3,base,0,42); } else if (cat2==lbrace) { - big_app1(pp); big_app(' '); big_app1(pp+1); big_app(' '); big_app1(pp+2); + big_app1_insert(pp,' '); big_app(' '); big_app1(pp+2); reduce(pp,3,lbrace,-2,43); } } @ @= if (cat1==lbrace) { - big_app1(pp); big_app(' '); big_app1(pp+1); reduce(pp,2,struct_head,0,44); + big_app1_insert(pp,' '); reduce(pp,2,struct_head,0,44); } else if (cat1==exp||cat1==int_like) { if (cat2==lbrace || cat2==semi) { make_underlined(pp+1); make_reserved(pp+1); - big_app1(pp); big_app(' '); big_app1(pp+1); + big_app1_insert(pp,' '); if (cat2==semi) reduce(pp,2,decl_head,0,45); else { big_app(' '); big_app1(pp+2);reduce(pp,3,struct_head,0,46); @@ -2703,14 +2819,20 @@ else if (cat1==exp||cat1==int_like) { } else if (cat2==colon) squash(pp+2,1,base,2,47); else if (cat2!=base) { - big_app1(pp); big_app(' '); big_app1(pp+1); reduce(pp,2,int_like,-2,48); + big_app1_insert(pp,' '); reduce(pp,2,int_like,-2,48); } } +else if (cat1==attr) { + big_app1_insert(pp,' '); reduce(pp,2,struct_like,-3,141); +} +else if (cat1==struct_like) { + big_app1_insert(pp,' '); reduce(pp,2,struct_like,-3,151); +} @ @= if ((cat1==decl || cat1==stmt || cat1==function) && cat2==rbrace) { big_app1(pp); big_app(indent); big_app(force); big_app1(pp+1); - big_app(outdent); big_app(force); big_app1(pp+2); + big_app(outdent); big_app(force); big_app1(pp+2); reduce(pp,3,int_like,-2,49); } else if (cat1==rbrace) { @@ -2721,16 +2843,19 @@ else if (cat1==rbrace) { @ @= if (cat1==decl) { - big_app1(pp); big_app(force); big_app1(pp+1); reduce(pp,2,fn_decl,0,51); + big_app1_insert(pp,force); reduce(pp,2,fn_decl,0,51); } else if (cat1==stmt) { big_app1(pp); app(outdent); app(outdent); big_app(force); big_app1(pp+1); reduce(pp,2,function,-1,52); } +else if (cat1==attr) { + big_app1_insert(pp,' '); reduce(pp,2,fn_decl,0,157); +} @ @= if (cat1==function || cat1==decl || cat1==stmt) { - big_app1(pp); big_app(big_force); big_app1(pp+1); reduce(pp,2,cat1,-1,53); + big_app1_insert(pp,big_force); reduce(pp,2,cat1,-1,53); } @ @= @@ -2740,8 +2865,8 @@ if (cat1==rbrace) { reduce(pp,2,stmt,-1,54); } else if ((cat1==stmt||cat1==decl||cat1==function) && cat2==rbrace) { - big_app(force); big_app1(pp); big_app(indent); big_app(force); - big_app1(pp+1); big_app(force); big_app(backup); big_app1(pp+2); + big_app(force); big_app1(pp); big_app(indent); big_app(force); + big_app1(pp+1); big_app(force); big_app(backup); big_app1(pp+2); big_app(outdent); big_app(force); reduce(pp,3,stmt,-1,55); } else if (cat1==exp) { @@ -2751,7 +2876,7 @@ else if (cat1==exp) { @ @= if (cat1==exp) { - big_app1(pp); big_app(' '); big_app1(pp+1); reduce(pp,2,if_clause,0,57); + big_app1_insert(pp,' '); reduce(pp,2,if_clause,0,57); } @ @= @@ -2778,19 +2903,24 @@ else if (cat1==stmt) { big_app1(pp+1); big_app(outdent); big_app(force); big_app1(pp+2); if (cat3==if_like) { big_app(' '); big_app1(pp+3); reduce(pp,4,if_like,0,63); - }@+else reduce(pp,3,else_like,0,64); + } + else reduce(pp,3,else_like,0,64); } else squash(pp,1,else_like,0,65); } +else if (cat1==attr) { + big_app1_insert(pp,' '); reduce(pp,2,if_head,0,146); +} @ @= if (cat1==stmt || cat1==exp) { if (cat2==else_like) { big_app(force); big_app1(pp); big_app(break_space); app(noop); - big_app(cancel); big_app1(pp+1); big_app(force); big_app1(pp+2); + big_app(cancel); big_app1_insert(pp+1,force); if (cat3==if_like) { big_app(' '); big_app1(pp+3); reduce(pp,4,if_like,0,66); - }@+else reduce(pp,3,else_like,0,67); + } + else reduce(pp,3,else_like,0,67); } else squash(pp,1,else_head,0,68); } @@ -2806,22 +2936,23 @@ if (cat1==stmt && cat2==else_like && cat3==semi) { if (cat1==semi) squash(pp,2,stmt,-1,70); else if (cat1==colon) squash(pp,2,tag,-1,71); else if (cat1==exp) { - big_app1(pp); big_app(' '); big_app1(pp+1); reduce(pp,2,exp,-2,72); + big_app1_insert(pp,' '); reduce(pp,2,exp,-2,72); } @ @= if (cat1==cast || cat1==exp) { - big_app2(pp); big_app(indent); big_app(indent); reduce(pp,2,fn_decl,0,73); + big_app1_insert(pp,dindent); reduce(pp,2,fn_decl,0,73); } @ @= if (cat1==tag) { - big_app1(pp); big_app(break_space); big_app1(pp+1); reduce(pp,2,tag,-1,74); + big_app1_insert(pp,break_space); reduce(pp,2,tag,-1,74); } else if (cat1==stmt||cat1==decl||cat1==function) { - big_app(force); big_app(backup); big_app1(pp); big_app(break_space); - big_app1(pp+1); reduce(pp,2,cat1,-1,75); + big_app(force); big_app(backup); big_app1_insert(pp,break_space); + reduce(pp,2,cat1,-1,75); } +else if (cat1==rbrace) squash(pp,1,decl,-1,156); @ The user can decide at run-time whether short statements should be grouped together on the same line. @@ -2833,12 +2964,8 @@ force_lines=true; @ @= if (cat1==stmt||cat1==decl||cat1==function) { - big_app1(pp); - if (cat1==function) big_app(big_force); - else if (cat1==decl) big_app(big_force); - else if (force_lines) big_app(force); - else big_app(break_space); - big_app1(pp+1); reduce(pp,2,cat1,-1,76); + big_app1_insert(pp, (cat1==function || cat1==decl) ? big_force : + force_lines ? force : break_space); reduce(pp,2,cat1,-1,76); } @ @= @@ -2846,7 +2973,7 @@ big_app(' '); big_app1(pp); reduce(pp,1,stmt,-1,77); @ @= if (cat1==define_like) make_underlined(pp+2); -if (cat1==else_like || cat1==if_like ||cat1==define_like) +if (cat1==else_like || cat1==if_like || cat1==define_like) squash(pp,2,lproc,0,78); else if (cat1==rproc) { app(inserted); big_app2(pp); reduce(pp,2,insert,-1,79); @@ -2856,7 +2983,7 @@ else if (cat1==rproc) { reduce(pp,3,insert,-1,80); } else if (cat2==exp && cat3==rproc && cat1==exp) { - app(inserted); big_app1(pp); big_app(' '); big_app1(pp+1); app_str(" \\5"); + app(inserted); big_app1_insert(pp,' '); app_str("\\5"); @.\\5@> big_app2(pp+2); reduce(pp,4,insert,-1,80); } @@ -2880,7 +3007,10 @@ app('<'); reduce(pp,1,binop,-2,84); init_mathness=cur_mathness=yes_math; app('>'); reduce(pp,1,binop,-2,85); -@ @= +@ @d reserve_typenames flags['t'] + /* should we treat \&{typename} in a template like \&{typedef}? */ + +@= if (cat1==prerangle) { big_app1(pp); app('\\'); app(','); big_app1(pp+1); @.\\,@> @@ -2892,31 +3022,42 @@ else if (cat1==decl_head || cat1==int_like || cat1==exp) { big_app3(pp); app(opt); app('9'); reduce(pp,3,langle,0,88); } } +else if (cat1==struct_like) { + if ((cat2==exp || cat2==int_like) && (cat3==comma || cat3==prerangle)) { + make_underlined(pp+2); if (reserve_typenames) make_reserved(pp+2); + big_app2(pp); big_app(' '); big_app2(pp+2); + if (cat3==comma) reduce(pp,4,langle,0,153); + else reduce(pp,4,cast,-1,154); + } +} @ @= if (cat1==exp && cat2==prelangle) squash(pp+2,1,langle,2,89); else if (cat1==exp || cat1==raw_int) { - big_app1(pp); big_app(' '); big_app1(pp+1); reduce(pp,2,cat1,-2,90); -}@+ else squash(pp,1,raw_int,0,91); + big_app1_insert(pp,' '); reduce(pp,2,cat1,-2,90); +} +else if (cat1==cast && cat2==struct_like) { + big_app1_insert(pp,' '); reduce(pp,2,struct_like,0,155); +} +else squash(pp,1,raw_int,0,91); @ @= if (cat1==lpar && cat2==exp && cat3==rpar) squash(pp,4,new_like,0,92); else if (cat1==cast) { - big_app1(pp); big_app(' '); big_app1(pp+1); reduce(pp,2,exp,-2,93); + big_app1_insert(pp,' '); reduce(pp,2,exp,-2,93); } else if (cat1!=lpar) squash(pp,1,new_exp,0,94); @ @= if (cat1==int_like || cat1==const_like) { - big_app1(pp); big_app(' '); big_app1(pp+1); reduce(pp,2,new_exp,0,95); + big_app1_insert(pp,' '); reduce(pp,2,new_exp,0,95); } else if (cat1==struct_like && (cat2==exp || cat2==int_like)) { - big_app1(pp); big_app(' '); big_app1(pp+1); big_app(' '); + big_app1_insert(pp,' '); big_app(' '); big_app1(pp+2); reduce(pp,3,new_exp,0,96); } else if (cat1==raw_ubin) { - big_app1(pp); big_app('{'); big_app1(pp+1); big_app('}'); - reduce(pp,2,new_exp,0,97); + big_app1_insert(pp,'{'); big_app('}'); reduce(pp,2,new_exp,0,97); } else if (cat1==lpar) squash(pp,1,exp,-2,98); else if (cat1==exp) { @@ -2931,14 +3072,15 @@ else squash(pp,1,exp,-2,101); @ @= if (cat1==exp) { - big_app1(pp); big_app(' '); big_app1(pp+1); reduce(pp,2,else_like,-2,102); + big_app1_insert(pp,' '); reduce(pp,2,else_like,-2,102); } @ @= if (cat1==const_like) { big_app2(pp); app_str("\\ "); reduce(pp,2,raw_ubin,0,103); @.\\\ @> -} else squash(pp,1,ubinop,-2,104); +} +else squash(pp,1,ubinop,-2,104); @ @= squash(pp,1,int_like,-2,105); @@ -2948,16 +3090,16 @@ if (cat1==prelangle) squash(pp+1,1,langle,1,106); else if (cat1==colcol) squash(pp,2,colcol,-1,107); else if (cat1==cast) squash(pp,2,raw_int,0,108); else if (cat1==lpar) squash(pp,1,exp,-2,109); +else if (cat1==lbrack) squash(pp,1,exp,-2,144); else if (cat1!=langle) squash(pp,1,int_like,-3,110); @ @= if (cat1==binop || cat1==unop || cat1==ubinop) { if (cat2==binop) break; - big_app1(pp); big_app('{'); big_app1(pp+1); big_app('}'); - reduce(pp,2,exp,-2,111); + big_app1_insert(pp,'{'); big_app('}'); reduce(pp,2,exp,-2,111); } else if (cat1==new_like || cat1==delete_like) { - big_app1(pp); big_app(' '); big_app1(pp+1); reduce(pp,2,exp,-2,112); + big_app1_insert(pp,' '); reduce(pp,2,exp,-2,112); } else if (cat1==comma) squash(pp,2,exp,-2,113); else if (cat1!=raw_ubin) squash(pp,1,new_exp,0,114); @@ -2966,19 +3108,18 @@ else if (cat1!=raw_ubin) squash(pp,1,new_exp,0,114); if ((cat1==int_like || cat1==cast) && (cat2==comma || cat2==semi)) squash(pp+1,1,exp,-1,115); else if (cat1==int_like) { - big_app1(pp); big_app(' '); big_app1(pp+1); reduce(pp,2,typedef_like,0,116); + big_app1_insert(pp,' '); reduce(pp,2,typedef_like,0,116); } else if (cat1==exp && cat2!=lpar && cat2!=exp && cat2!=cast) { make_underlined(pp+1); make_reserved(pp+1); - big_app1(pp); big_app(' '); big_app1(pp+1); reduce(pp,2,typedef_like,0,117); + big_app1_insert(pp,' '); reduce(pp,2,typedef_like,0,117); } else if (cat1==comma) { big_app2(pp); big_app(' '); reduce(pp,2,typedef_like,0,118); } else if (cat1==semi) squash(pp,2,decl,-1,119); else if (cat1==ubinop && (cat2==ubinop || cat2==cast)) { - big_app('{'); big_app1(pp+1); big_app('}'); big_app1(pp+2); - reduce(pp+1,2,cat2,0,120); + big_app('{'); big_app1_insert(pp+1,'}'); reduce(pp+1,2,cat2,0,120); } @ @= @@ -2988,7 +3129,7 @@ if (cat1==lpar && cat2==rpar) { reduce(pp,3,delete_like,0,121); } else if (cat1==exp) { - big_app1(pp); big_app(' '); big_app1(pp+1); reduce(pp,2,exp,-2,122); + big_app1_insert(pp,' '); reduce(pp,2,exp,-2,122); } @ @= @@ -2997,6 +3138,51 @@ if (cat1==exp && (cat2==colon || cat2==base)) { squash(pp,3,binop,-2,123); } +@ @= +if (cat1==decl_head) squash(pp,2,attr,-1,126); +else if (cat1==exp) squash(pp,2,attr,-1,127); +else if (cat1==cast) squash(pp,2,attr,-1,158); + +@ @= +if (cat1==lbrack) + if (cat2==rbrack && cat3==rbrack) squash(pp,4,exp,-2,147); + else squash(pp,2,attr_head,-1,128); +else squash(pp,1,lpar,-1,129); + +@ @= +if (cat1==rbrack && cat2==rbrack) squash(pp,3,attr,-1,131); +else if (cat1==exp) squash(pp,2,attr_head,0,132); +else if (cat1==using_like && cat2==exp && cat3==colon) { + big_app2(pp); big_app(' '); big_app2(pp+2); big_app(' '); + reduce(pp,4,attr_head,0,133); +} +else if (cat1==comma) squash(pp,2,attr_head,0,145); + +@ @= +if (cat1==lbrace || cat1==stmt) { + big_app1_insert(pp,' '); reduce(pp,2,cat1,-2,134); +} +else if (cat1==tag) { + big_app1_insert(pp,' '); reduce(pp,2,tag,-1,135); +} +else if (cat1==semi) squash(pp,2,stmt,-2,136); +else if (cat1==attr) { + big_app1_insert(pp,' '); reduce(pp,2,attr,-1,137); +} +else if (cat1==decl_head) { + big_app1_insert(pp,' '); reduce(pp,2,decl_head,-1,138); +} +else if (cat1==typedef_like) { + big_app1_insert(pp,' '); reduce(pp,2,typedef_like,0,143); +} +else if (cat1==function) { + big_app1_insert(pp,' '); reduce(pp,2,function,-1,148); +} + +@ @= +if (cat1==colon) squash(pp,1,case_like,-3,149); +else squash(pp,1,exp,-2,150); + @ Now here's the |reduce| procedure used in our code for productions. The `|freeze_text|' macro is used to give official status to a token list. @@ -3103,27 +3289,30 @@ if (lo_ptr= -static int tracing; /* can be used to show parsing details */ +static int tracing=off; /* can be used to show parsing details */ @ @= -{ scrap_pointer k_l; /* pointer into |scrap_info| */ - if (tracing==2) { - printf("\n%d:",n); - for (k_l=scrap_base; k_l<=lo_ptr; k_l++) { - if (k_l==pp) putxchar('*'); else putxchar(' '); - if (k_l->mathness %4 == yes_math) putchar('+'); - else if (k_l->mathness %4 == no_math) putchar('-'); - print_cat(k_l->cat); - if (k_l->mathness /4 == yes_math) putchar('+'); - else if (k_l->mathness /4 == no_math) putchar('-'); - } - if (hi_ptr<=scrap_ptr) fputs("...",stdout); /* indicate that more is coming */ +if (tracing==fully) { + scrap_pointer k_l; /* pointer into |scrap_info| */ + printf("\n%d:",n); + for (k_l=scrap_base; k_l<=lo_ptr; k_l++) { + if (k_l==pp) putchar('*'); else putchar(' '); + if (k_l->mathness %4 == yes_math) putchar('+'); + else if (k_l->mathness %4 == no_math) putchar('-'); + print_cat(k_l->cat); + if (k_l->mathness /4 == yes_math) putchar('+'); + else if (k_l->mathness /4 == no_math) putchar('-'); } + if (hi_ptr<=scrap_ptr) printf("..."); /* indicate that more is coming */ } @ The |translate| function assumes that scraps have been stored in @@ -3143,8 +3332,8 @@ for overflow. static text_pointer translate(void) /* converts a sequence of scraps */ { - scrap_pointer i, /* index into |cat| */ - j; /* runs through final scraps */ + scrap_pointer i; /* index into |cat| */ + scrap_pointer j; /* runs through final scraps */ pp=scrap_base; lo_ptr=pp-1; hi_ptr=pp; @@; @@; @@ -3171,17 +3360,17 @@ where appropriate. } @ @= -if (lo_ptr>scrap_base && tracing==1) { +if (lo_ptr>scrap_base && tracing==partly) { printf("\nIrreducible scrap sequence in section %d:",section_count); @.Irreducible scrap sequence...@> mark_harmless; for (j=scrap_base; j<=lo_ptr; j++) { - printf(" "); print_cat(j->cat); + putchar(' '); print_cat(j->cat); } } @ @= -if (tracing==2) { +if (tracing==fully) { printf("\nTracing after l. %d:\n",cur_line); mark_harmless; @.Tracing after...@> if (loc>buffer+50) { @@ -3208,10 +3397,9 @@ is advanced. @c static void -C_parse(@t\1\1@> /* creates scraps from \CEE/ tokens */ - eight_bits spec_ctrl@t\2\2@>) +C_parse( /* creates scraps from \CEE/ tokens */ + eight_bits spec_ctrl) { - int count; /* characters remaining before string break */ while (next_control@; next_control=get_next(); @@ -3236,7 +3424,7 @@ been appended: switch (next_control) { case section_name: app(section_flag+(int)(cur_section-name_dir)); - app_scrap(section_scrap,maybe_math); + app_scrap(section_scrap,maybe_math);@+ app_scrap(exp,yes_math);@+break; case string: case constant: case verbatim: @@;@+break; @@ -3271,8 +3459,10 @@ switch (next_control) { @.\\\#@> case ignore: case xref_roman: case xref_wildcard: case xref_typewriter: case noop:@+break; - case '(': case '[': app(next_control);@+app_scrap(lpar,maybe_math);@+break; - case ')': case ']': app(next_control);@+app_scrap(rpar,maybe_math);@+break; + case '(': app(next_control);@+app_scrap(lpar,maybe_math);@+break; + case ')': app(next_control);@+app_scrap(rpar,maybe_math);@+break; + case '[': app(next_control);@+app_scrap(lbrack,maybe_math);@+break; + case ']': app(next_control);@+app_scrap(rbrack,maybe_math);@+break; case '{': app_str("\\{"@q}@>);@+app_scrap(lbrace,yes_math);@+break; @.\\\{@>@q}@> case '}': app_str(@q{@>"\\}");@+app_scrap(rbrace,yes_math);@+break; @@ -3320,7 +3510,7 @@ if (scrap_ptr+safe_scrap_incr>scrap_info_end || standard ones. They are converted to \TEX/ control sequences so that it is possible to keep \.{CWEAVE} from outputting unusual |char| codes. -@= +@=@t\1\quad@> case non_eq: app_str("\\I");@+app_scrap(binop,yes_math);@+break; @.\\I@> case lt_eq: app_str("\\Z");@+app_scrap(binop,yes_math);@+break; @@ -3362,8 +3552,7 @@ Many of the special characters in a string must be prefixed by `\.\\' so that \TEX/ will print them properly. @^special string characters@> -@= -count= -1; +@={@+ int count=-1; /* characters remaining before string break */ if (next_control==constant) app_str("\\T{"@q}@>); @.\\T@> else if (next_control==string) { @@ -3407,6 +3596,7 @@ while (id_first'}'); app_scrap(exp,maybe_math); +} @ We do not make the \TEX/ string into a scrap, because there is no telling what the user will be putting into it; instead we leave it @@ -3447,8 +3637,8 @@ static void outer_parse(void); @ @c static void -app_cur_id(@t\1\1@> -boolean scrapping@t\2\2@>) /* are we making this into a scrap? */ +app_cur_id( +boolean scrapping) /* are we making this into a scrap? */ { name_pointer p=id_lookup(id_first,id_loc,normal); if (p->ilk<=custom) { /* not a reserved word */ @@ -3475,8 +3665,8 @@ static text_pointer C_translate(void) { text_pointer p; /* points to the translation */ - scrap_pointer save_base; /* holds original value of |scrap_base| */ - save_base=scrap_base; scrap_base=scrap_ptr+1; + scrap_pointer save_base=scrap_base; /* holds original value of |scrap_base| */ + scrap_base=scrap_ptr+1; C_parse(section_name); /* get the scraps together */ if (next_control!='|') err_print("! Missing '|' after C text"); @.Missing '|'...@> @@ -3493,8 +3683,7 @@ is to |C_xref|: It constructs a sequence of scraps for \CEE/ text until |next_control>=format_code|. Thus, it takes care of embedded comments. The token list created from within `\pb' brackets is output as an argument -to \.{\\PB}, if the user has invoked \.{CWEAVE} with the \.{+e} flag. -Although \.{cwebmac} ignores \.{\\PB}, other macro packages +to \.{\\PB}. Although \.{cwebmac} ignores \.{\\PB}, other macro packages might use it to localize the special meaning of the macros that mark up program text. @@ -3615,8 +3804,8 @@ static void pop_level(void); @ @c static void -push_level(@t\1\1@> /* suspends the current level */ -text_pointer p@t\2\2@>) +push_level( /* suspends the current level */ +text_pointer p) { if (stack_ptr==stack_end) overflow("stack"); if (stack_ptr>stack) { /* save current state */ @@ -3701,12 +3890,11 @@ while outputting the name of a section. static void output_C(void) /* outputs the current token list */ { - token_pointer save_tok_ptr; - text_pointer save_text_ptr; - sixteen_bits save_next_control; /* values to be restored */ + token_pointer save_tok_ptr=tok_ptr; + text_pointer save_text_ptr=text_ptr; + sixteen_bits save_next_control=next_control; /* values to be restored */ text_pointer p; /* translation of the \CEE/ text */ - save_tok_ptr=tok_ptr; save_text_ptr=text_ptr; - save_next_control=next_control; next_control=ignore; p=C_translate(); + next_control=ignore; p=C_translate(); app(inner_tok_flag+(int)(p-tok_start)); if (make_pb) { out_str("\\PB{"); make_output(); out('}'); @@ -3724,8 +3912,8 @@ output_C(void) /* outputs the current token list */ static void make_output(void) /* outputs the equivalents of tokens */ { - eight_bits a=0, /* current output byte */ - b; /* next output byte */ + eight_bits a=0; /* current output byte */ + eight_bits b; /* next output byte */ int c; /* count of |indent| and |outdent| tokens */ char scratch[longest_name+1]; /* scratch area for section names */ char *k, *k_limit; /* indices into |scratch| */ @@ -3735,6 +3923,7 @@ make_output(void) /* outputs the equivalents of tokens */ char *save_loc, *save_limit; /* |loc| and |limit| to be restored */ name_pointer cur_section_name; /* name of section being output */ boolean save_mode; /* value of |cur_mode| before a sequence of breaks */ + boolean dindent_pending=false; /* should a |dindent| be output? */ app(end_translation); /* append a sentinel */ freeze_text; push_level(text_ptr-1); while (true) { @@ -3751,11 +3940,17 @@ make_output(void) /* outputs the equivalents of tokens */ a=get_output(); if (a==inserted) continue; if ((abig_force) break; - if (a==indent) c++; else if (a==outdent) c--; - else if (a==opt) a=get_output(); + if (a==indent) c++; + else if (a==outdent) c--; + else if (a==opt) a=get_output(); } @@; goto reswitch; + case dindent: a=get_output(); + if (a!=big_force) { + out_str("\\1\\1"); goto reswitch; + } + else dindent_pending=true; /* fall through */ case indent: case outdent: case opt: case backup: case break_space: case force: case big_force: case preproc_line: @@; break; @@ -3779,7 +3974,8 @@ if (a==identifier) { for (p=cur_name->byte_start;p<(cur_name+1)->byte_start;p++) out(*p=='_'? 'x': *p=='$'? 'X': *p); break; - } else if (is_tiny(cur_name)) out('|')@; + } + else if (is_tiny(cur_name)) out('|')@; @.\\|@> else { delim='.'; for (p=cur_name->byte_start;p<(cur_name+1)->byte_start;p++) @@ -3790,10 +3986,12 @@ if (a==identifier) { } @.\\\\@> @.\\.@> -}@+else if (cur_name->ilk==alfop) { +} +else if (cur_name->ilk==alfop) { out('X'); goto custom_out; -}@+else out('&'); /* |a==res_word| */ +} +else out('&'); /* |a==res_word| */ @.\\\&@> if (is_tiny(cur_name)) { if (isxalpha((cur_name->byte_start)[0])) @@ -3820,7 +4018,7 @@ if (a @ If several of the tokens |break_space|, |force|, |big_force| occur in a @@ -3830,7 +4028,10 @@ except at the very end of the translation. The very first line break is suppressed (i.e., a line break that follows `\.{\\Y\\B}'). @= { - b=a; save_mode=cur_mode; c=0; + b=a; save_mode=cur_mode; + if (dindent_pending) { + c=2; dindent_pending=false; + } else c=0; while (true) { a=get_output(); if (a==inserted) continue; @@ -3908,9 +4109,9 @@ while (k@; if (an_output) switch (b) { - case ' ':case '\\':case '#':case '%':case '$':case '^': - case '{': case '}': case '~': case '&': case '_': - out('\\'); /* falls through */ + case ' ': case '\\': case '#': case '%': case '$': case '^': + case '{': case '}': case '~': case '&': case '_': + out('\\'); /* falls through */ @.\\\ @> @.\\\\@> @.\\\#@> @@ -3922,15 +4123,16 @@ while (k @.\\\&@> @.\\\_@> - default: out(b); + default: out(b); + } + else + if (b!='|') out(b)@; + else { + @@; + save_loc=loc; save_limit=limit; loc=limit+2; limit=j+1; + *limit='|'; output_C(); + loc=save_loc; limit=save_limit; } - else { if (b!='|') out(b)@; - else { - @@; - save_loc=loc; save_limit=limit; loc=limit+2; limit=j+1; - *limit='|'; output_C(); - loc=save_loc; limit=save_limit; - } } } @ @= @@ -4055,14 +4257,13 @@ else { if (show_progress) printf("*%d",section_count); update_terminal; /* print a progress report */ } -out_str("{");out_section(section_count); out_str("}"); +out('{'); out_section(section_count); out('}'); @ In the \TEX/ part of a section, we simply copy the source text, except that index entries are not copied and \CEE/ text within \pb\ is translated. @= do { - next_control=copy_TeX(); - switch (next_control) { + switch (next_control=copy_TeX()) { case '|': init_stack; output_C(); break; case '@@': out('@@'); break; case TeX_string: case noop: @@ -4105,8 +4306,8 @@ takes place, so that the translation will normally end with \.{\\6} or @c static void -finish_C(@t\1\1@> /* finishes a definition or a \CEE/ part */ - boolean visible@t\2\2@>) /* nonzero if we should produce \TeX\ output */ +finish_C( /* finishes a definition or a \CEE/ part */ + boolean visible) /* |true| if we should produce \TeX\ output */ { text_pointer p; /* translation of the scraps */ if (visible) { @@ -4114,7 +4315,7 @@ finish_C(@t\1\1@> /* finishes a definition or a \CEE/ part */ p=translate(); @.\\B@> app(tok_flag+(int)(p-tok_start)); make_output(); /* output the list */ - if (out_ptr>out_buf+1) { + if (out_ptr>out_buf+1) if (*(out_ptr-1)=='\\') { @.\\6@> @.\\7@> @@ -4122,7 +4323,6 @@ finish_C(@t\1\1@> /* finishes a definition or a \CEE/ part */ if (*out_ptr=='6') out_ptr-=2; else if (*out_ptr=='7') *out_ptr='Y'; } - } out_str("\\par"); finish_line(); } if (text_ptr>max_text_ptr) max_text_ptr=text_ptr; @@ -4145,22 +4345,30 @@ it starts after we scan the matching `\.)'. @= { if (save_line!=out_line || save_place!=out_ptr || space_checked) app(backup); if(!space_checked){emit_space_if_needed;save_position;} - app_str("\\D"); /* this will produce `\&{define }' */ + app_str("\\D"); /* this will produce `\#\&{define }' */ @.\\D@> if ((next_control=get_next())!=identifier) err_print("! Improper macro definition"); @.Improper macro definition@> else { - app('$'); app_cur_id(false); - if (*loc=='(') + app_cur_id(false); + if (*loc=='(') { + app('$'); reswitch: switch (next_control=get_next()) { case '(': case ',': app(next_control); goto reswitch; case identifier: app_cur_id(false); goto reswitch; case ')': app(next_control); next_control=get_next(); break; + case dot_dot_dot: app_str("\\,\\ldots\\,"); @.\\,@> @.\\ldots@> + app_scrap(raw_int,no_math); + if ((next_control=get_next())==')') { + app(next_control); next_control=get_next(); break; + } /* otherwise fall through */ default: err_print("! Improper macro definition"); break; + } + app('$'); } else next_control=get_next(); - app_str("$ "); app(break_space); + app(break_space); app_scrap(dead,no_math); /* scrap won't take part in the parsing */ } } @@ -4174,7 +4382,6 @@ it starts after we scan the matching `\.)'. next_control=get_next(); if (next_control==identifier) { app(id_flag+(int)(id_lookup(id_first, id_loc,normal)-name_dir)); - app(' '); app(break_space); /* this is syntactically separate from what follows */ next_control=get_next(); if (next_control==identifier) { @@ -4220,7 +4427,7 @@ do next_control=get_next(); if (next_control!='=' && next_control!=eq_eq) err_print("! You need an = sign after the section name"); @.You need an = sign...@> - else next_control=get_next(); +else next_control=get_next(); if (out_ptr>out_buf+1 && *out_ptr=='Y' && *(out_ptr-1)=='\\') app(backup); /* the section name will be flush left */ @.\\Y@> @@ -4277,11 +4484,11 @@ supply new definitions for the macros \.{\\A}, \.{\\As}, etc. @c static void -footnote(@t\1\1@> /* outputs section cross-references */ -sixteen_bits flag@t\2\2@>) +footnote( /* outputs section cross-references */ +sixteen_bits flag) { - xref_pointer q; /* cross-reference pointer variable */ - if (cur_xref->num<=flag) return; + xref_pointer q=cur_xref; /* cross-reference pointer variable */ + if (q->num<=flag) return; finish_line(); out('\\'); @.\\A@> @.\\Q@> @@ -4298,7 +4505,7 @@ of cross-references is one, two, or more than two. Variable |q| points to the first cross-reference, and the last link is a zero. @= -q=cur_xref; if (q->xlink->num>flag) out('s'); /* plural */ +if (q->xlink->num>flag) out('s'); /* plural */ while (true) { out_section(cur_xref->num-flag); cur_xref=cur_xref->xlink; /* point to the next cross-reference to output */ @@ -4443,7 +4650,6 @@ name_pointer Head; @f sort_pointer int @d sort_pointer scrap_pointer /* ditto */ @d sort_ptr scrap_ptr /* ditto */ -@d max_sorts max_scraps /* ditto */ @= static eight_bits cur_depth; /* depth of current buckets */ @@ -4519,8 +4725,8 @@ regarded as identical. @c static void -unbucket(@t\1\1@> /* empties buckets having depth |d| */ -eight_bits d@t\2\2@>) +unbucket( /* empties buckets having depth |d| */ +eight_bits d) { int c; /* index into |bucket|; cannot be a simple |char| because of sign comparison below */ @@ -4575,15 +4781,16 @@ while (sort_ptr>scrap_info) { } @ @= -switch (cur_name->ilk) { - case normal: case func_template: if (is_tiny(cur_name)) out_str("\\|"); - else {char *j; +switch (cur_name->ilk) {@+char *j; + case normal: case func_template: + if (is_tiny(cur_name)) out_str("\\|"); + else { for (j=cur_name->byte_start;j<(cur_name+1)->byte_start;j++) if (xislower(*j)) goto lowcase; out_str("\\."); break; lowcase: out_str("\\\\"); } - break; + break; @.\\|@> @.\\.@> @.\\\\@> @@ -4592,12 +4799,12 @@ lowcase: out_str("\\\\"); case typewriter: out_str("\\."); @.\\.@> case roman: not_an_identifier: out_name(cur_name,false); goto name_done; - case custom: {char *j; out_str("$\\"); + case custom: + out_str("$\\"); for (j=cur_name->byte_start;j<(cur_name+1)->byte_start;j++) out(*j=='_'? 'x': *j=='$'? 'X': *j); out('$'); goto name_done; - } default: out_str("\\&"); @.\\\&@> } @@ -4621,6 +4828,7 @@ out('.'); finish_line(); @ List inversion is best thought of as popping elements off one stack and pushing them onto another. In this case |cur_xref| will be the head of the stack that we push things onto. + @= static xref_pointer next_xref, this_xref; /* pointer variables for rearranging a list */ @@ -4638,8 +4846,8 @@ prints them. @c static void -section_print(@t\1\1@> /* print all section names in subtree |p| */ -name_pointer p@t\2\2@>) +section_print( /* print all section names in subtree |p| */ +name_pointer p) { if (p) { section_print(p->llink); out_str("\\I"); diff --git a/cweb.1 b/cweb.1 index a9aa69b..4c35edb 100644 --- a/cweb.1 +++ b/cweb.1 @@ -1,4 +1,4 @@ -.TH CWEB 1 2018-Dec-16 +.TH CWEB 1 2021-Apr-24 . .SH NAME ctangle, cweave \- translate CWEB to C and/or TeX @@ -9,14 +9,14 @@ ctangle, cweave \- translate CWEB to C and/or TeX [ .B \-bhp ] [ -.B +s +.B +ks ] webfile[.w] [{changefile[.ch]|-} [outputfile[.c]]] .br .B cweave [ .B \-befhpx ] [ -.B +s +.B +st ] webfile[.w] [{changefile[.ch]|-} [outputfile[.tex]]] .ad . @@ -80,7 +80,13 @@ The .B +s option prints statistics about memory usage at the end of a run. .PP -There are three other options applicable to +There is one other option applicable to +.I ctangle +only: +.B +k +means keep '-separators in numeric literals in the C/C++\ output. +.PP +There are four other options applicable to .I cweave only: .B \-f @@ -89,13 +95,15 @@ means do not force a newline after every statement in the formatted output. inhibits the enclosure of C\ material formatted by .I cweave in brackets -\ePB{...}. -Such brackets are normally inserted so that special hooks +\ePB{...}; +such brackets are normally inserted so that special hooks can be used by .I cweb-latex and similar programs. .B \-x -means omit the index and table of contents. +means omit the index, the names of the sections, and the table of contents. +.B +t +means treat 'typename' in templates like 'typedef'. . .SH FILES The location of the files mentioned below varies from system to system. @@ -129,4 +137,5 @@ Silvio Levy designed and developed CWEB by adapting the WEB conventions to\ C and by recoding everything in CWEB. Knuth began using CWEB and made further refinements. Many other helpers are acknowledged in the CWEB manual. +Contemporary development on https://github.com/ascherer/cweb. diff --git a/cwebmac.tex b/cwebmac.tex index 385dc47..a4686ad 100644 --- a/cwebmac.tex +++ b/cwebmac.tex @@ -1,7 +1,7 @@ % standard macros for CWEB listings (in addition to plain.tex) -% Version 4.2 --- February 2021 +% Version 4.3 --- May 2021 \ifx\renewenvironment\undefined\else\endinput\fi % LaTeX will use other macros -\xdef\fmtversion{\fmtversion+CWEB4.2} +\xdef\fmtversion{\fmtversion+CWEB4.3} \chardef\cwebversion=4 \chardef\cwebrevision=1 \newif\ifpdf \ifx\pdf+\pdftrue\fi @@ -31,6 +31,7 @@ \def\TEX/{\TeX} \def\CPLUSPLUS/{{\mc C\PP\spacefactor1000}} \def\Cee{\CEE/} % for backward compatibility +\def\Cpp{\CPLUSPLUS/} % for backward compatibility \def\9#1{} % with this definition of \9 you can say @:sort key}{TeX code@> % to alphabetize an index entry by the sort key but format with the TeX code @@ -124,6 +125,7 @@ \newskip\intersecskip \intersecskip=12pt minus 3pt % space between sections \let\yskip=\smallskip \def\?{\mathrel?} +\def\,{\relax\ifmmode\mskip\thinmuskip\else\thinspace\fi} \def\note#1#2.{\Y\noindent{\hangindent2em% \baselineskip10pt\eightrm#1~\ifacro{\pdfnote#2.}\else#2\fi.\par}} @@ -287,7 +289,7 @@ \else \special{pdf: dest (\romannumeral\secstar) [ @thispage /FitH @ypos ]}\fi}}\fi} \let\startsection=\stsec -\def\defin#1{\global\advance\ind by 2 \1\&{#1 } } % begin `define' or `format' +\def\defin#1{\global\advance\ind by 2 \1\&{#1 }} % begin `define' or `format' \def\A{\note{See also section}} % xref for doubly defined section name \def\As{\note{See also sections}} % xref for multiply defined section name \def\B{\rightskip=0pt plus 100pt minus 10pt % go into C mode @@ -300,7 +302,7 @@ \let\SHC\C % "// short comments" treated like "/* ordinary comments */" %\def\C#1{\5\5\quad$\triangleright\,${\cmntfont#1}$\,\triangleleft$} %\def\SHC#1{\5\5\quad$\diamond\,${\cmntfont#1}} -\def\D{\defin{\#define}} % macro definition +\def\D{\defin{{\rm\#}define}} % macro definition \let\E=\equiv % equivalence sign \def\ET{ and~} % conjunction between two section numbers \def\ETs{, and~} % conjunction between the last two of several section numbers @@ -341,12 +343,15 @@ \def\Qs{\note{This code is cited in sections}} % xref for mentions of a section \let\R=\lnot % logical not % \S is section sign +\def\digitseparator{\,} % a bit of extra space \def\T#1{\leavevmode % octal, hex or decimal constant \hbox{$\def\?{\kern.2em}% + \let\ \digitseparator% % \def\$##1{\egroup_{\,\rm##1}\bgroup}% suffix to constant % versions < 3.67 \def\$##1{\egroup_{\rm##1}\bgroup}% suffix to constant % in version 3.67 \def\_{\cdot 10^{\aftergroup}}% power of ten (via dirty trick) - \let\~=\oct \let\^=\hex {#1}$}} + \def\%{\cdot 16^{\aftergroup}}% power of sixteen (via dirty trick) + \let\~=\oct \let\^=\hex \let\\=\bin {#1}$}} \def\U{\note{This code is used in section}} % xref for use of a section \def\Us{\note{This code is used in sections}} % xref for uses of a section \let\V=\lor % logical or @@ -365,8 +370,12 @@ %\def\oct{\hbox{\rm\char'23\kern-.2em\it\aftergroup\?\aftergroup}} % WEB style %\def\hex{\hbox{\rm\char"7D\tt\aftergroup}} % WEB style -\def\oct{\hbox{$^\circ$\kern-.1em\it\aftergroup\?\aftergroup}}% CWEB style -\def\hex{\hbox{$^{\scriptscriptstyle\#}$\tt\aftergroup}} % CWEB style +\def\oct{\hbox{$^\circ$\kern-.1em}\Od}% CWEB style +\def\hex{\hbox{$^{\scriptscriptstyle\#}$}\Hd} % CWEB style +\def\bin{\hbox{$^{\scriptscriptstyle b}$}\Bd} +\def\Od#1/{{\it#1}} % octal digit +\def\Hd#1/{{\tt#1}} % hexadecimal digit +\def\Bd#1/{{\tt#1}} % binary digit \def\vb#1{\leavevmode\hbox{\kern2pt\vrule\vtop{\vbox{\hrule \hbox{\strut\kern2pt\.{#1}\kern2pt}} \hrule}\vrule\kern2pt}} % verbatim string @@ -482,14 +491,13 @@ \def\X##1:##2\X{\Xpdf##1:##2\X \firstsecno##1.% {\toksF={}\makeoutlinetoks##2\outlinedone\outlinedone}% \pdfoutline goto num \the\toksA \expandafter{\the\toksE}} - \else\ifpdf - \special{pdf: outline -1 << /Title (\outsecname) + \else \special{pdf: outline -1 << /Title (\outsecname) /Dest [ @thispage /FitH @ypos ] >>} \def\X##1:##2\X{\Xpdf##1:##2\X \firstsecno##1.% {\toksF={}\makeoutlinetoks##2\outlinedone\outlinedone}% \special{pdf: outline 0 << /Title (\the\toksE) /A << /S /GoTo /D (\romannumeral\the\toksA) >> >>}} - \fi\fi\fi + \fi\fi \readsections} \def\makebookmarks{\let\ZZ=\writebookmarkline \readcontents\relax} \def\expnumber#1{\expandafter\ifx\csname#1\endcsname\relax 0% @@ -536,9 +544,6 @@ \def\printtwodigits{\advance\twodigits100 \expandafter\gobbleone\number\twodigits \advance\twodigits-100 } -\def\TeX{{\ifmmode\it\fi - \leavevmode\hbox{T\kern-.1667em\lower.424ex\hbox{E}\hskip-.125em X}}} -\def\,{\relax\ifmmode\mskip\thinmuskip\else\thinspace\fi} \def\datethis{\def\startsection{\leftline{\sc\today\ at \hours}\bigskip \let\startsection=\stsec\stsec}} % say `\datethis' in limbo, to get your listing timestamped before section 1 diff --git a/cwebman.tex b/cwebman.tex index df65223..4d4206e 100644 --- a/cwebman.tex +++ b/cwebman.tex @@ -1,5 +1,4 @@ % This file generates the user manual; TeX it, don't read it! -% update 14 Nov 2016 by DEK: corrected obsolete remarks re debugging info \def\tangref{3} % where the main explanation of CTANGLing is given \input cwebmac @@ -36,7 +35,7 @@ \def\lheader{\mainfont\the\pageno\hfill\sc\runninghead\hfill} \def\rheader{\hfill\sc\runninghead\hfill\mainfont\the\pageno} -\def\runninghead{{\tentt CWEB} USER MANUAL (VERSION 4.2)} +\def\runninghead{{\tentt CWEB} USER MANUAL (VERSION 4.3)} % This verbatim mode assumes that ! marks are !! in the text being copied. \def\verbatim{\begingroup @@ -50,7 +49,7 @@ \null\vfill \centerline{\titlefont The {\ttitlefont CWEB} System of Structured Documentation} -\vskip 18pt\centerline{(Version 4.2 --- February 2021)} +\vskip 18pt\centerline{(Version 4.3 --- May 2021)} \vskip 24pt \centerline{\authorfont Donald E. Knuth and Silvio Levy} \vfill @@ -394,9 +393,9 @@ \CEE/ editing within \TEX/ text, if you place `\.|' marks before and after the \CEE/ material. For example, suppose you want to say something like this: -$$\hbox{ If \\{pa} is declared as `\&{int} ${}{*}\\{pa}$', -the assignment $\\{pa}\K{\AND}\|a[\T{0}]$ makes \\{pa} -point to the zeroth element of \|a.}$$ +$$\hbox{If \PB{\\{pa}} is declared as `\PB{\&{int} ${}{*}\\{pa}$}', +the assignment \PB{$\\{pa}\K{\AND}\|a[\T{0}]$} makes \PB{\\{pa}} +point to the zeroth element of \PB{\|a}.}$$ The \TEX/ text would look like this in your \.{CWEB} file: $$\lpile{\.{If |pa| is declared as `|int *pa|', the assignment}\cr \.{|pa=\&a[0]| makes |pa| point to the zeroth element of |a|.}\cr}$$ @@ -477,13 +476,16 @@ or \.{0x}. In \.{CWEB} it seems reasonable to let each convention hold in its respective realm; so in \CEE/ text you get $40_8$ by typing `\.{040}', which \.{CTANGLE} faithfully copies into the \CEE/ file (for -the compiler's benefit) and which \.{CWEAVE} prints as $\T{\~40}$. +the compiler's benefit) and which \.{CWEAVE} prints as $\T{\~40/}$. Similarly, \.{CWEAVE} prints the hexadecimal \CEE/ constant `\.{0x20}' -as \T{\^20}. The use of italic font for octal digits and typewriter font +as \T{\^20/}. The use of italic font for octal digits and typewriter font for hexadecimal digits makes the meaning of such constants clearer in -a document. For consistency, then, you -should type `\.{|040|}' or `\.{|0x20|}' -in the \TEX/ part of the section. +a document. For consistency, then, you should type `\.{|040|}' or +`\.{|0x20|}' in the \TEX/ part of the section. + +And if you type a binary constant like `\.{0b00101010}', \.{CWEAVE} prints +it as $\T{\\00101010/}$. In all numeric literals you may add \.' separators +for improved readability. \section Control codes. A \.{CWEB} {\sl control code\/} @@ -761,11 +763,11 @@ them by standard ASCII alphanumeric characters or \.{\_}, in order to generate legal \CEE/ code. It does this by means of a transliteration table, which by default associates the string -\.{Xab} to the character with ASCII code \T{\^}$ab$ (where $a$ and $b$ are +\.{Xab} to the character with ASCII code \T{\^/}$ab$ (where $a$ and $b$ are hexadecimal digits, and $a\ge8$). By placing the construction \.{@l\ ab\ newstring} in limbo, you are telling \.{CTANGLE} to replace this character by \.{newstring} instead. -For example, the ISO Latin-1 code for the letter `\"u' is \T{\^FC} +For example, the ISO Latin-1 code for the letter `\"u' is \T{\^FC/} (or \.{'\char`\\374'}), and \.{CTANGLE} will normally change this code to the three-character sequence \.{XFC} if it @@ -1042,7 +1044,7 @@ \option e Enclose \CEE/ material formatted by \.{CWEAVE} in brackets \.{\\PB\{...\}}, so that special hooks can be used. -(On by default; has no effect on \.{CTANGLE}.) +(On by default.) (Has no effect on \.{CTANGLE}.) \option f Force line breaks after each \CEE/ statement formatted by \.{CWEAVE}. (On by default; \.{-f} saves paper but looks less \CEE/-like @@ -1051,13 +1053,18 @@ \option h Print a happy message at the conclusion of a successful run. (On by default.) +\option k Keep single quotes (\.') in numeric literals in the +\CEE//\CPLUSPLUS/ output. (Off by default.) (\.{CTANGLE} only.) + \option p Give progress reports as the program runs. (On by default.) \option s Show statistics about memory usage after the program runs to completion. (Off by default.) -If you -have large \.{CWEB} files or sections, you may need to see -how close you come to exceeding the capacity of \.{CTANGLE} and/or \.{CWEAVE}. +If you have large \.{CWEB} files or sections, you may need to see how close +you come to exceeding the capacity of \.{CTANGLE} and/or \.{CWEAVE}. + +\option t Treat \&{typename} in a template like \&{typedef}. +(Off by default.) (Has no effect on \.{CTANGLE}.) \option x Include indexes and a table of contents in the \TEX/ file output by \.{CWEAVE}. (On by default.) (Has no effect on \.{CTANGLE}.) @@ -1155,7 +1162,7 @@ Alternatively, thanks to H\`an Th\^e\kern-.3em\raise.3ex\hbox{\'{}} Th\`anh and Andreas Scherer, you can generate \.{cob.pdf} in one step by simply saying `\.{pdftex}~\.{cob}'. -A third way to create PDF output from \.{CWEB} input is to say +And a third way to create PDF output from \.{CWEB} input is to say `\.{xetex}~\.{cob}'. A more elaborate system called \.{CTWILL}, which extends the usual cross @@ -1211,10 +1218,7 @@ the change file is exhausted. This procedure is called only when |changing| is |true|; hence error messages will be reported correctly. -@= -static void prime_the_change_buffer(void);@/ - -@ @c +@c static void prime_the_change_buffer(void) { @@ -1224,6 +1228,8 @@ @@; } +@ @=@+static void prime_the_change_buffer(void); + @ While looking for a line that begins with \.{@@x} in the change file, we allow lines that begin with \.{@@}, as long as they don't begin with \.{@@y}, \.{@@z}, or \.{@@i} (which would probably mean that the change file is fouled up). @@ -1268,20 +1274,20 @@ Here's the portion of the \CEE/ code generated by \.{CTANGLE} that corresponds to the source on the preceding page. Notice that sections~29, 30 and~31 -have been tangled into section~28. +have been tangled into section~27. \vskip6pt \begingroup \def\tt{\eighttt} \baselineskip9pt \verbatim -/*:24*//*28:*/ -#line 234 "common.w" +/*:23*//*27:*/ +#line 227 "common.w" static void prime_the_change_buffer(void) { change_limit= change_buffer; /*29:*/ -#line 248 "common.w" +#line 243 "common.w" while(true){ change_line++; @@ -1298,10 +1304,10 @@ } /*:29*/ -#line 239 "common.w" +#line 232 "common.w" /*30:*/ -#line 265 "common.w" +#line 260 "common.w" do{ change_line++; @@ -1313,10 +1319,10 @@ }while(limit==buffer); /*:30*/ -#line 240 "common.w" +#line 233 "common.w" /*31:*/ -#line 275 "common.w" +#line 270 "common.w" { change_limit= change_buffer+(ptrdiff_t)(limit-buffer); @@ -1324,11 +1330,11 @@ } /*:31*/ -#line 241 "common.w" +#line 234 "common.w" } -/*:28*//*33:*/ +/*:27*//*32:*/ !endgroup \endgroup \vfill\eject @@ -1349,11 +1355,7 @@ \PB{\\{changing}} is \PB{\\{true}}; hence error messages will be reported correctly. -\Y\B\4\X7:Predeclaration of procedures\X${}\mathrel+\E{}$\6 -\&{static} \&{void} \\{prime\_the\_change\_buffer}(\&{void});\par -\fi - -\M{28}\B\&{static} \&{void} \\{prime\_the\_change\_buffer}(\&{void})\1\1\2\2\6 +\Y\B\1\1\&{static} \&{void} \\{prime\_the\_change\_buffer}(\&{void})\2\2\6 ${}\{{}$\1\6 ${}\\{change\_limit}\K\\{change\_buffer}{}$;\C{ this value is used if the change file ends }\6 @@ -1365,6 +1367,10 @@ \4${}\}{}$\2\par \fi +\M{28}\B\X7:Predeclaration of procedures\X${}\mathrel+\E{}$\5 +\&{static} \&{void} \\{prime\_the\_change\_buffer}(\&{void});\par +\fi + \M{29}While looking for a line that begins with \.{@x} in the change file, we allow lines that begin with \.{@}, as long as they don't begin with \.{@y}, \.{@z}, or \.{@i} (which would probably mean that the change file is fouled @@ -1392,7 +1398,7 @@ \\{err\_print}(\.{"!!\ Missing\ @x\ in\ cha}\)\.{nge\ file"});\6 \4${}\}{}$\2\6 \4${}\}{}$\2\par -\U28.\fi +\U27.\fi \M{30}Here we are looking at lines following the \.{@x}. @@ -1408,7 +1414,7 @@ \4${}\}{}$\2\6 \4${}\}{}$\2\5 \&{while} ${}(\\{limit}\E\\{buffer}){}$;\par -\U28.\fi +\U27.\fi !endgroup \endgroup \vfil\eject @@ -1427,11 +1433,7 @@ \PB{\\{changing}} is \PB{\\{true}}; hence error messages will be reported correctly. -\Y\B\4\X7:Predeclaration of procedures\X${}\mathrel+\E{}$\6 -\&{static} \&{void} \\{prime\_the\_change\_buffer}(\&{void});\par -\fi - -\M{28}\B\&{static} \&{void} \\{prime\_the\_change\_buffer}(\&{void})\1\1\2\2\6 +\Y\B\1\1\&{static} \&{void} \\{prime\_the\_change\_buffer}(\&{void})\2\2\6 ${}\{{}$\1\6 ${}\\{change\_limit}\K\\{change\_buffer}{}$;\C{ this value is used if the change file ends }\6 @@ -1443,6 +1445,10 @@ \4${}\}{}$\2\par \fi +\M{28}\B\X7:Predeclaration of procedures\X${}\mathrel+\E{}$\5 +\&{static} \&{void} \\{prime\_the\_change\_buffer}(\&{void});\par +\fi + \M{29}While looking for a line that begins with \.{@x} in the change file, we allow lines that begin with \.{@}, as long as they don't begin with \.{@y}, \.{@z}, or \.{@i} (which would probably mean that the change file is fouled @@ -1470,7 +1476,7 @@ \\{err\_print}(\.{"!\ Missing\ @x\ in\ cha}\)\.{nge\ file"});\6 \4${}\}{}$\2\6 \4${}\}{}$\2\par -\U28.\fi +\U27.\fi \M{30}Here we are looking at lines following the \.{@x}. @@ -1486,7 +1492,7 @@ \4${}\}{}$\2\6 \4${}\}{}$\2\5 \&{while} ${}(\\{limit}\E\\{buffer}){}$;\par -\U28.\fi +\U27.\fi \M{31}\B\X31:Move \PB{\\{buffer}} and \PB{\\{limit}} to \PB{\\{change\_buffer}} and \PB{\\{change\_limit}}\X${}\E{}$\6 @@ -1496,7 +1502,7 @@ ${}\\{strncpy}(\\{change\_buffer},\39\\{buffer},\39(\&{size\_t})(\\{limit}-% \\{buffer}+\T{1}));{}$\6 \4${}\}{}$\2\par -\Us28\ET33.\fi +\Us27\ET32.\fi \vfil\eject\titletrue \rightskip=0pt % get out of C mode (cf. \B) \sfcode`;=1500 \pretolerance 200 \hyphenpenalty 50 \exhyphenpenalty 50 @@ -1591,7 +1597,7 @@ \.{ { }\\titlefalse \% include headline on the contents page}\cr \.{ { }\\def\\rheader\{\\mainfont The \{\\tt CWEAVE\}{ }processor\\hfil\}}\cr \.{ { }\\centerline\{\\titlefont The \{\\ttitlefont CWEAVE\}{ }processor\}}\cr - \.{ { }\\vskip 15pt \\centerline\{(Version 4.2)\}{ }\\vfill\}}\cr}$$ + \.{ { }\\vskip 15pt \\centerline\{(Version 4.3)\}{ }\\vfill\}}\cr}$$ Redefining \.{\\rheader}, which is the headline for right-hand pages, suffices in this case to put the desired information at the top of the contents page. diff --git a/indentation.w b/indentation.w new file mode 100644 index 0000000..c07e4e7 --- /dev/null +++ b/indentation.w @@ -0,0 +1,37 @@ +@* Indentation. ``Classic'' and ``modern'' function headers have a similar +layout with regards to the indentation of parameters. You can suppress +parameter indentation with \.{cweave -i}. + +@c +int main() /* No parameter */ +{} + +@ @c +int main2(void) /* No parameter */ +{} + +@ @c +int func1(para1) /* One parameter */ + int para1; /* First parameter */ +{} + +@ @c +int func2(para1,para2) /* Two parameters */ + int para1; /* First parameter */ + int para2; /* Second parameter */ +{ +} + +@ @c +int proc1( /* One parameter */ + int para1) /* First parameter */ +{} + +@ @c +int proc2( /* Two parameters */ + int para1, /* First parameter */ + int para2) /* Second parameter */ +{ +} + +@* Index. diff --git a/iso_types.w b/iso_types.w new file mode 100644 index 0000000..c88e76b --- /dev/null +++ b/iso_types.w @@ -0,0 +1,95 @@ +@q This file defines type names introduced in modern dialects @> +@q of C and C++ as special entities for TeX formatting @> + +@q C99 and C11 underscore keywords @> +@q http://en.cppreference.com/w/c/keyword @> + +@s _Alignas alignas +@s _Alignof alignof +@s _Atomic int +@s _Bool bool +@s _Complex complex +@s _Generic class +@s _Imaginary imaginary +@s _Noreturn noreturn +@s _Static_assert static_assert +@s _Thread_local thread_local + +@q C99 and C11 core language atomic types @> +@q http://en.cppreference.com/w/c/atomic @> + +@s atomic_bool bool +@s atomic_char char +@s atomic_schar char +@s atomic_uchar char +@s atomic_short short +@s atomic_ushort short +@s atomic_int int +@s atomic_uint int +@s atomic_long long +@s atomic_ulong long +@s atomic_llong long +@s atomic_ullong long +@s atomic_char8_t char8_t +@s atomic_char16_t char16_t +@s atomic_char32_t char32_t +@s atomic_wchar_t wchar_t +@s atomic_int_least8_t int +@s atomic_uint_least8_t int +@s atomic_int_least16_t int +@s atomic_uint_least16_t int +@s atomic_int_least32_t int +@s atomic_uint_least32_t int +@s atomic_int_least64_t int +@s atomic_uint_least64_t int +@s atomic_int_fast8_t int +@s atomic_uint_fast8_t int +@s atomic_int_fast16_t int +@s atomic_uint_fast16_t int +@s atomic_int_fast32_t int +@s atomic_uint_fast32_t int +@s atomic_int_fast64_t int +@s atomic_uint_fast64_t int +@s atomic_intptr_t int +@s atomic_uintptr_t int +@s atomic_ptrdiff_t ptrdiff_t +@s atomic_size_t size_t +@s atomic_intmax_t int +@s atomic_uintmax_t int + +@q C99 preprocessor @> + +@s _Pragma pragma + +@q Integral types of C99 and C++, see @> +@q http://en.cppreference.com/w/c/types/integer and @> +@q http://en.cppreference.com/w/cpp/types/integer @> + +@s int8_t int +@s int16_t int +@s int32_t int +@s int64_t int +@s int_fast8_t int +@s int_fast16_t int +@s int_fast32_t int +@s int_fast64_t int +@s int_least8_t int +@s int_least16_t int +@s int_least32_t int +@s int_least64_t int +@s intmax_t int +@s intptr_t int +@s uint8_t int +@s uint16_t int +@s uint32_t int +@s uint64_t int +@s uint_fast8_t int +@s uint_fast16_t int +@s uint_fast32_t int +@s uint_fast64_t int +@s uint_least8_t int +@s uint_least16_t int +@s uint_least32_t int +@s uint_least64_t int +@s uintmax_t int +@s uintptr_t int diff --git a/my-changes.md b/my-changes.md new file mode 100644 index 0000000..f38f14e --- /dev/null +++ b/my-changes.md @@ -0,0 +1,36 @@ +Added support for new C++ numeric literals. Note: The TeX side of this is rather +jank. Currently, binary literals are formatted just like hexadecimal literals +except with a superscript “b” instead of “#”, and the `'` digit separator +becomes a thin space (`\,` in TeX). If you run `CTANGLE` with the option `+k`, +it will omit the separator in output, so that you can use it in C code as well +as in C++ code. + +Added support for C and C++ attributes. + +Allowed “`default;`” as a function body. + +Added more reserved words: `alignas`, `_Alignas`, `alignof`, `_Alignof`, +`_Atomic`, `_Bool`, `char8_t`, `char16_t`, `char32_t`, `co_await`, `_Complex`, +`consteval`, `constexpr`, `constinit`, `co_return`, `co_yield`, `_Decimal128`, +`_Decimal32`, `_Decimal64`, `decltype`, `_Generic`, `_Imaginary`, `noexcept`, +`_Noreturn`, `nullptr`, `static_assert`, `_Static_assert`, `thread_local`, +`_Thread_local`. + +Made `typeid` act like `sizeof`. + +Added support for `enum class`, `enum struct`. + +Altered handling of `template` and `typename`. If you supply the option `+t`, +the identifier `N` in + +```C++ +template class C { … }; +``` + +will be made a reserved word so that it acts like a type name. + +Quite a few new productions have been added to `prod.w`; they are all at the +end, even though many of them would belong more logically earlier in the file. +There are new kinds of scrap as well, mostly for handling attributes. + +To test the major additions, run `CWEAVE` on `testthings.w`. \ No newline at end of file diff --git a/prod.w b/prod.w index 5f76a19..f7994a1 100644 --- a/prod.w +++ b/prod.w @@ -26,9 +26,8 @@ identifier's ilk becomes |raw_int|. A dagger \dag\ before the production number refers to the notes at the end of this section, which deal with various exceptional cases. -We use \\{in}, \\{out}, \\{back} and -\\{bsp} as shorthands for |indent|, |outdent|, |backup| and -|break_space|, respectively. +We use \\{in}, \\{out}, \\{back}, \\{bsp}, and \\{din} as shorthands for +|indent|, |outdent|, |backup|, |break_space|, and |dindent|, respectively. \begingroup \lineskip=4pt \def\alt #1 #2 @@ -38,9 +37,9 @@ We use \\{in}, \\{out}, \\{back} and {$\displaystyle\Biggl\{\!\matrix{\strut\hbox{#1}\cr\hbox{#2}\cr \strut\hbox{#3}\cr}\!\Biggr\}$ } \def\malt #1 #2 -{$\displaystyle\matrix{\strut\hbox{#1}\hfill\cr\strut\hbox{#2}\hfill\cr}$} +{$\displaystyle\!\matrix{\strut\hbox{#1}\hfill\cr\strut\hbox{#2}\hfill\cr}$} \def\maltt #1 #2 #3 -{$\displaystyle\matrix{\strut\hbox{#1}\hfill\cr\hbox{#2}\hfill\cr +{$\displaystyle\!\matrix{\strut\hbox{#1}\hfill\cr\hbox{#2}\hfill\cr \strut\hbox{#3}\hfill\cr}$} \yskip \prodno=0 \midcol=2.5in @@ -58,14 +57,14 @@ We use \\{in}, \\{out}, \\{back} and & stmt; \ /$\ast\,$comment$\,*$/\cr \+& |exp| \altt|lbrace| |int_like| |decl| & |fn_decl| \altt|lbrace| |int_like| |decl| - \hfill $F=E^*\,|in|\,|in|$ & \malt {\\{main}()$\{$} + \hfill $F=E^*\,\\{din}$ & \malt {\\{main}()$\{$} {\\{main}$(\\{ac},\\{av})$ \&{int} \\{ac};} \cr \+& |exp| |unop| & |exp| & |x++|\cr \+& |exp| \alt |binop| |ubinop| |exp| & |exp| & \malt {|x/y|} {|x+y|} \cr \+& |exp| |comma| |exp| & |exp| \hfill $EC\,|opt|9\,E$& |f(x,y)|\cr \+& |exp| \alt {|lpar| |rpar|} |cast| |colon| & |exp| \alt {|lpar| |rpar|} |cast| |base| & - \malt \&C|()|: {\&C|int i)|:} \cr + \malt \&C|()|: {\&C|(int i)|:} \cr \+& |exp| |semi| & |stmt| & |x=0;|\cr \+& |exp| |colon| & |tag| \hfill $E^*C$ & |found:|\cr \+& |exp| |rbrace| & |stmt| |rbrace| & end of \&{enum} list\cr @@ -118,7 +117,7 @@ We use \\{in}, \\{out}, \\{back} and $D=D$\alt $B$ $C$ \unskip$E$ & \malt {\&{int} $f(\&{int}\ x=2)$} |int b:1| \cr \+& |decl_head| |cast| & |decl_head| & |int f(int)|\cr \+& |decl_head| \altt|int_like| |lbrace| |decl| & |fn_decl| - \altt|int_like| |lbrace| |decl| \hfill $F=D\,|in|\,|in|$ + \altt|int_like| |lbrace| |decl| \hfill $F=D\,\\{din}$ & |long time () {|\cr \+& |decl_head| |semi| & |decl| & |int n;|\cr \+& |decl| |decl| & |decl| \hfill $D_1\,|force|\,D_2$ & |int n;double x;|\cr @@ -161,24 +160,24 @@ We use \\{in}, \\{out}, \\{back} and \+& |else_like| |colon| & |else_like| |base| & \&{try} :\cr \+& |else_like| |lbrace| & |else_head| |lbrace| & \&{else} $\{$\cr \+& |else_like| |stmt| & |stmt| \hfill - $|force|\,E\,\\{in}\,\\{bsp}\,S\,\\{out}\,|force|$ & |else x=0;|\cr + $|force|\,E\,\\{in}\,\\{bsp}\,S\,\\{out}\,|force|$ & $\!\!$|else x=0;|\cr \+& |else_head| \alt|stmt| |exp| & |stmt| \hfill - $|force|\,E\,\\{bsp}\,|noop|\,|cancel|\,S\,\\{bsp}$ & |else{x=0;}|\cr + $|force|\,E\,\\{bsp}\,|noop|\,|cancel|\,S\,\\{bsp}$ & $\!\!$|else{x=0;}|\cr \+& |if_clause| |lbrace| & |if_head| |lbrace| & |if (x) {|\cr \+& |if_clause| |stmt| |else_like| |if_like| & |if_like| \hfill $|force|\,I\,\\{in}\,\\{bsp}\,S\,\\{out}\,|force|\,E\,\.\ I$ & - |if (x) y; else if|\cr + $\!\!$|if (x) y; else if|\cr \+& |if_clause| |stmt| |else_like| & |else_like| \hfill $|force|\,I\,\\{in}\,\\{bsp}\,S\,\\{out}\,|force|\,E$ & - |if (x) y; else|\cr + $\!\!$|if (x) y; else|\cr \+& |if_clause| |stmt| & |else_like| |stmt| & |if (x)|\cr \+& |if_head| \alt|stmt| |exp| |else_like| |if_like| & |if_like| \hfill $|force|\,I\,\\{bsp}\,|noop|\,|cancel|\,S\,|force|\,E\,\.\ I$ & - |if (x){y;}else if|\cr + $\!\!$|if (x){y;}else if|\cr \+& |if_head| \alt|stmt| |exp| |else_like| & |else_like| \hfill $|force|\,I\,\\{bsp}\,|noop|\,|cancel|\,S\,|force|\,E$ & - |if (x){y;}else|\cr -\+& |if_head| \alt|stmt| |exp| & |else_head| \alt|stmt| |exp| & |if (x){y;}|\cr + $\!\!$|if (x){y;}else|\cr +\+& |if_head| \alt|stmt| |exp| & |else_head| \alt|stmt| |exp| & $\!\!$|if (x){y;}|\cr \advance\midcol20pt \+& |do_like| |stmt| |else_like| |semi| & |stmt| \hfill $D\,\\{bsp}\,|noop|\,|cancel|\,S\,|cancel|\,|noop|\,\\{bsp}\,ES$% @@ -191,18 +190,18 @@ We use \\{in}, \\{out}, \\{back} and $C$\alt $C$ $E$ \\{in}\,\\{in} & |catch (...)|\cr \+& |tag| |tag| & |tag| \hfill $T_1\,\\{bsp}\,T_2$ & |case 0: case 1:|\cr \+& |tag| \altt|stmt| |decl| |function| & \altt|stmt| |decl| |function| - \hfill $|force|\,\\{back}\,T\,\\{bsp}\,S$ & |case 0: z=0;|\cr + \hfill $|force|\,\\{back}\,T\,\\{bsp}\,S$ & $\!\!$|case 0: z=0;|\cr \+\dagit& |stmt| \altt|stmt| |decl| |function| & \altt|stmt| |decl| |function| \hfill $S\,$\altt$|force|\,S$ $|big_force|\,D$ $|big_force|\,F$ & |x=1;y=2;|\cr \+& |semi| & |stmt| \hfill \.\ $S$& empty statement\cr \+\dagit& |lproc| \altt |if_like| |else_like| |define_like| & |lproc| & - \maltt {{\bf \#include}} {\bf\#else} {\bf\#define} \cr -\+& |lproc| |rproc| & |insert| & {\bf\#endif} \cr + \maltt {\#\&{include}} \#\&{else} \#\&{define} \cr +\+& |lproc| |rproc| & |insert| & \#\&{endif} \cr \+& |lproc| \alt {|exp| [|exp|]} |function| |rproc| & |insert| \hfill $I$\.\ \alt {$E{[\.{\ \\5}E]}$} {$F$} & - \malt{{\bf\#define} $a$\enspace 1} {{\bf\#define} $a$\enspace$\{\,b;\,\}$} \cr + \malt{\#\&{define} $a$\enspace 1} {\#\&{define} $a$\enspace$\{\,b;\,\}$} \cr \+& |section_scrap| |semi| & |stmt|\hfill $MS$ |force| &$\langle\,$section name$\,\rangle$;\cr \+& |section_scrap| & |exp| &$\langle\,$section name$\,\rangle$\cr @@ -270,14 +269,63 @@ We use \\{in}, \\{out}, \\{back} and \malt |?x:| |?f():| \cr \+& |begin_arg| |end_arg| & |exp| & \.{@@[}\&{char}$*$\.{@@]}\cr \+& |any_other| |end_arg| & |end_arg| & \&{char}$*$\.{@@]}\cr +\+& |alignas_like| |decl_head| & |attr| & |alignas(struct s *)| \cr +\+& |alignas_like| |exp| & |attr| & |alignas(8)| \cr +\+& |lbrack| |lbrack| & |attr_head| & attribute begins \cr +\+& |lbrack| & |lpar| & |[| elsewhere \cr +\+& |rbrack| & |rpar| & |]| elsewhere \cr +\+& |attr_head| |rbrack| |rbrack| & |attr| & $[[\ldots]]$ \cr +\+& |attr_head| |exp| & |attr_head| & $[[$|deprecated| \cr +\+& |attr_head| |using_like| |exp| |colon| & |attr_head| & $[[$|using NS:| \cr +\+& |attr| \alt|lbrace| |stmt| & \alt|lbrace| |stmt| \hfill $A\.\ $ \alt $S$ $L$ & + |[[likely]] {|\cr +\+& |attr| |tag| & |tag| \hfill $A\.\ T$ & |[[likely]] case 0:| \cr +\+& |attr| |semi| & |stmt| & |[[fallthrough]];| \cr +\+& |attr| |attr| & |attr| \hfill $A\.\ A$ & |alignas(x)| $[[\ldots]]$ \cr +\+& |attr| |decl_head| & |decl_head| & |[[nodiscard]] f()| \cr +\+& |decl_head| |attr| & |decl_head| & |(int x [[deprecated]])|\cr +\+& |using_like| & |int_like| & \&{using} not in attributes \cr +\+& |struct_like| |attr| & |struct_like| \hfill $S\.\ A$ & + |struct [[deprecated]]|\cr +\+& |exp| |attr| & |attr| \hfill $E\.\ A$ & \&{enum} $\{x\ [[\ldots]]\}$ \cr +\+& |attr| |typedef_like| & |typedef_like| \hfill $A\.\ T$ & + |[[deprecated]] typedef| \cr +\+& |raw_int| |lbrack| & |exp| & |int[3]| \cr +\+& |attr_head| |comma| & |attr_head| & $[[$|x, y| \cr +\+& |if_head| |attr| & |if_head| \hfill $I\.\ A$ & |if (x) [[unlikely]] {| \cr +\+& |lbrack| |lbrack| |rbrack| |rbrack| & |exp| & |[[]]| \cr +\+& |attr| |function| & |function| \hfill $A\.\ F$ & + attribute and function \cr +\+& |default_like| |colon| & |case_like| |colon| & |default:| \cr +\+& |default_like| & |exp| & |f()=default;| \cr +\+& |struct_like| |struct_like| & |struct_like| \hfill $S\.\ S$ & + |enum class| \cr +\+& |exp| |colcol| |int_like| & |int_like| & $\\{std}\DC\&{atomic}$ \cr +\advance\midcol-60pt +\+\dagit& |langle| |struct_like| \alt |exp| |int_like| |comma| & + |langle| \hfill $LS$\alt $E^{**}$ $I^{**}$ $C$ & $\langle$\&{typename} $t,$\cr +\+\dagit& |langle| |struct_like| \alt |exp| |int_like| |prerangle| & + |cast| \hfill $LS$\alt $E^{**}$ $I^{**}$ $P$ & + \hbox{$\langle$\&{typename} $t\rangle$} \hss \cr +\advance\midcol60pt +\+& |template_like| |cast| |struct_like| & |struct_like| \hfill $T\.\ CS$ & + |template<@t\dots@>> class| \cr +\+& |tag| |rbrace| & |decl| |rbrace| & @q{@>|public: }| \cr +\+& |fn_decl| |attr| & |fn_decl| \hfill $F\.\ A$ & |void f() noexcept| \cr +\+& |alignas_like| |cast| & |attr| & |alignas(int)| \cr +\yskip +\yskip +\yskip +\yskip +\yskip \yskip \yskip \yskip \parindent=0pt \dag{\bf Notes} \yskip -Rule 35: The |exp| must not be immediately followed by |lpar|, |exp|, - or~|cast|. +Rule 35: The |exp| must not be immediately followed by |lpar|, |lbrack|, +|exp|, or~|cast|. Rule 48: The |exp| or |int_like| must not be immediately followed by |base|. @@ -304,4 +352,7 @@ or |cast|. Rule 123: The mathness of the |colon| or |base| changes to `yes'. +Rules 153, 154: |make_reserved| is called only if the \.{+t} option is given +to \.{CWEAVE}. + \endgroup diff --git a/testthings.w b/testthings.w new file mode 100644 index 0000000..f927438 --- /dev/null +++ b/testthings.w @@ -0,0 +1,242 @@ +@s atomic int + +@* Attributes. This is just all of the examples from the sections about +attributes in the \CEE/ and \CPLUSPLUS/ standards collected together, with most +comments removed. + +@c +[[using CC: opt(1), debug]] + void f() {} +[[using CC: opt(1)]] [[CC::debug]] + void g() {} +[[using CC: CC::opt(1)]] + void h() {} + +int p[10]; +void f() { + int x = 42, y[5]; + int i [[vendor::attr([[]])]]; +} + +alignas(double) unsigned char c[sizeof(double)]; +extern unsigned char c[sizeof(double)]; + +struct foo { int* a; int* b; }; +std::atomic foo_head[10]; + +int foo_array[10][10]; + +[[carries_dependency]] struct foo* f(int i) { + return foo_head[i].load(memory_order::consume); +} + +int g(int* x, int* y [[carries_dependency]]) { + return kill_dependency(foo_array[*x][*y]); +} + +[[carries_dependency]] struct foo* f(int i); +int g(int* x, int* y [[carries_dependency]]); + +int c = 3; + +void h(int i) { + struct foo* p; + + p = f(i); + do_something_with(g(&c, p->a)); + do_something_with(g(p->a, &c)); +} + +void f(int n) { + void g(), h(), i(); + switch (n) { + case 1: + case 2: + g(); + [[fallthrough]]; + case 3: + do { + [[fallthrough]]; + } while (false); + case 6: + do { + [[fallthrough]]; + } while (n--); + case 7: + while (false) { + [[fallthrough]]; + } + case 5: + h(); + case 4: + i(); + [[fallthrough]]; + } +} + +void g(int); +int f(int n) { + if (n > 5) [[unlikely]] { + g(0); + return n * 2 + 1; + } + + switch (n) { + case 1: + g(1); + [[fallthrough]]; + + [[likely]] case 2: + g(2); + break; + } + return 3; +} + +[[maybe_unused]] void f([[maybe_unused]] bool thing1, + [[maybe_unused]] bool thing2) { + [[maybe_unused]] bool b = thing1 && thing2; + assert(b); +} + +struct [[nodiscard]] my_scopeguard { int x; }; +struct my_unique { + my_unique() = default; + [[nodiscard]] my_unique(int fd) { /* \dots */ } + ~my_unique() noexcept { /* \dots */ } + /* \dots */ +}; +struct [[nodiscard]] error_info { /* \dots */ }; +error_info enable_missile_safety_mode(); +void launch_missiles(); +void test_missiles() { + my_scopeguard(); + (void)my_scopeguard(), + launch_missiles(); + my_unique(42); + my_unique(); + enable_missile_safety_mode(); + launch_missiles(); +} +error_info &foo(); +void f() { foo(); } + + +[[ noreturn ]] void f() { + throw "error"; +} + +[[ noreturn ]] void q(int i) { + if (i > 0) + throw "positive"; +} + +template +class hash_map { + [[no_unique_address]] Hash hasher; + [[no_unique_address]] Pred pred; + [[no_unique_address]] Allocator alloc; + Bucket *buckets; + +public: + +}; + +[[deprecated, hal::daisy]] double nine1000(double); +[[deprecated]] [[hal::daisy]] double nine1000(double); +[[deprecated]] double nine1000 [[hal::daisy]] (double); + +[[__deprecated__, __hal__::__daisy__]] double nine1000(double); +[[__deprecated__]] [[__hal__::__daisy__]] double nine1000(double); +[[__deprecated__]] double nine1000 [[__hal__::__daisy__]] (double); +[[hal::daisy, hal::rosie]] double nine999(double); +[[hal::rosie, hal::daisy]] double nine999(double); + +[[hal::daisy]] [[hal::rosie]] double nine999(double); +[[hal::rosie]] [[hal::daisy]] double nine999(double); + +struct [[nodiscard]] error_info { /*\dots*/ }; +struct error_info enable_missile_safety_mode(void); +void launch_missiles(void); +void test_missiles(void) { +enable_missile_safety_mode(); +launch_missiles(); +} + +[[nodiscard]] int important_func(void); +void call(void) { +int i = important_func(); +} + +[[nodiscard("must check armed state")]] +bool arm_detonator(int); +void call(void) { +arm_detonator(3); +detonate(); +} + +[[maybe_unused]] void f([[maybe_unused]] int i) { +[[maybe_unused]] int j = i + 100; +assert(j); +} + +struct [[deprecated]] S { +int a; +}; +enum [[deprecated]] E1 { +one +}; +enum E2 { +two [[deprecated("use ’three’ instead")]], +three +}; +[[deprecated]] typedef int Foo; +void f1(struct S s) { +int i = one; +int j = two; +int k = three; +Foo f; +} +[[deprecated]] void f2(struct S s) { +int i = one; +int j = two; +int k = three; +Foo f; +} +struct [[deprecated]] T { +Foo f; +struct S s; +}; + +void f(int n) { +void g(void), h(void), i(void); +switch (n) { +case 1: /* diagnostic on fallthrough discouraged */ +case 2: +g(); +[[fallthrough]]; +case 3: /* diagnostic on fallthrough discouraged */ +h(); +case 4: /* fallthrough diagnostic encouraged */ +i(); +[[fallthrough]]; /* constraint violation */ +} +} + +@* Numbers. Here are new numbers. + +@c + +int main(void) +{ + int decimal_integer = 100; + int octal_integer = 0240; + int binary_integer = 0b10101011; + int separated_integer = 100'000'000; + float binary_exponent = 0x1FFFFp10; + float separated_float = 123.456'789'000e2; + int normal_exponent = 123'456e789; +} + +@* Index. \ No newline at end of file