diff options
Diffstat (limited to 'web/c_cpp/c2cweb/cweb')
-rw-r--r-- | web/c_cpp/c2cweb/cweb/Makefile | 106 | ||||
-rw-r--r-- | web/c_cpp/c2cweb/cweb/common.c | 1280 | ||||
-rw-r--r-- | web/c_cpp/c2cweb/cweb/common.ch | 83 | ||||
-rw-r--r-- | web/c_cpp/c2cweb/cweb/common.h | 201 | ||||
-rw-r--r-- | web/c_cpp/c2cweb/cweb/common.w | 1415 | ||||
-rw-r--r-- | web/c_cpp/c2cweb/cweb/cweave.c | 4543 | ||||
-rw-r--r-- | web/c_cpp/c2cweb/cweb/cweave.ch | 1095 | ||||
-rw-r--r-- | web/c_cpp/c2cweb/cweb/cweave.def | 3 | ||||
-rw-r--r-- | web/c_cpp/c2cweb/cweb/cweave.w | 4505 | ||||
-rw-r--r-- | web/c_cpp/c2cweb/cweb/cwebmac.ori | 346 | ||||
-rw-r--r-- | web/c_cpp/c2cweb/cweb/cwebmac.tex | 375 | ||||
-rw-r--r-- | web/c_cpp/c2cweb/cweb/cwebmaca.tex | 381 | ||||
-rw-r--r-- | web/c_cpp/c2cweb/cweb/prod-alt.w | 303 |
13 files changed, 14636 insertions, 0 deletions
diff --git a/web/c_cpp/c2cweb/cweb/Makefile b/web/c_cpp/c2cweb/cweb/Makefile new file mode 100644 index 0000000000..68d0ca8e18 --- /dev/null +++ b/web/c_cpp/c2cweb/cweb/Makefile @@ -0,0 +1,106 @@ +# This file is part of the c2cweb package Version 1.5 (10-Nov-1996) + +# GNU Makefile for c2cweb's version of CWEAVE + + +.PHONY: default all debug clean \ + cweb +.CAUTIOUS: common.c cweave.c + + +default: + @echo " say " + @echo ". " + @echo " make <TARGET> OS=<SYSTEM> " + @echo ". " + @echo " SYSTEM can be one of the following: " + @echo ". " + @echo " unix (gcc) " + @echo " os2 bound (emx) " + @echo " dos (djgpp) " + @echo ". " + @echo " TARGET can be one of the following: " + @echo ". " + @echo " all debug clean " + + +ifdef OS + + ifeq ($(OS),unix) + CC = gcc -Wall -O + O = .o + LIB = + EXE = + RM = rm -f + endif + + ifeq ($(OS),os2) + CC = gcc -Wall -Zomf -Zmtd -O + O = .obj + LIB = cweave.def + EXE = .exe + RM = del + endif + + ifeq ($(OS),dos) + CC = gcc -Wall -O + O = .o + LIB = + EXE = .exe + RM = del + endif + + ifeq ($(OS),bound) + CC = gcc -Wall -O + O = .o + LIB = + EXE = .exe + RM = del + endif + + + OBJ = common$O cweave$O + + + %$O: %.c + $(CC) $(CFLAGS) -c -o $@ $< + + %.c: %.w %.ch + $(CTANGLE) $^ $@ + %.c: %.w + $(CTANGLE) $< + + + all: + $(MAKE) cweb CFLAGS=-s + + debug: + $(MAKE) cweb CFLAGS=-g + + # remove the unnecessary files. + clean: + -$(RM) *$O + + + cweb: cweave$(EXE) + + cweave$(EXE): $(OBJ) + ifeq ($(OS),dos) + $(CC) $(CFLAGS) -o $(basename $@) $^ + strip $(basename $@) + coff2exe $(basename $@) + -$(RM) $(basename $@) + else + $(CC) $(CFLAGS) -o $@ $^ $(LIB) + endif + + cweave.w: common.h + cweave.ch: prod-alt.w + +else # ifdef OS + + all debug clean: default + +endif + +# end of Makefile diff --git a/web/c_cpp/c2cweb/cweb/common.c b/web/c_cpp/c2cweb/cweb/common.c new file mode 100644 index 0000000000..963a20d9c1 --- /dev/null +++ b/web/c_cpp/c2cweb/cweb/common.c @@ -0,0 +1,1280 @@ +/*1:*/ +#line 57 "common.w" + +/*5:*/ +#line 101 "common.w" + +#include <ctype.h> + +/*:5*//*8:*/ +#line 163 "common.w" + +#include <stdio.h> + +/*:8*//*22:*/ +#line 468 "common.w" + +#include <stdlib.h> + +/*:22*/ +#line 58 "common.w" + +#define ctangle 0 +#define cweave 1 \ + +#define and_and 04 +#define lt_lt 020 +#define gt_gt 021 +#define plus_plus 013 +#define minus_minus 01 +#define minus_gt 031 +#define not_eq 032 +#define lt_eq 034 +#define gt_eq 035 +#define eq_eq 036 +#define or_or 037 +#define dot_dot_dot 016 +#define colon_colon 06 +#define period_ast 026 +#define minus_gt_ast 027 \ + +#define buf_size 400 +#define long_buf_size 500 +#define xisspace(c) (isspace(c) &&((unsigned char) c<0200) ) +#define xisupper(c) (isupper(c) &&((unsigned char) c<0200) ) \ + +#define max_include_depth 10 \ + +#define max_file_name_length 60 +#define cur_file file[include_depth] +#define cur_file_name file_name[include_depth] +#define cur_line line[include_depth] +#define web_file file[0] +#define web_file_name file_name[0] \ + +#define lines_dont_match (change_limit-change_buffer!=limit-buffer|| \ +strncmp(buffer,change_buffer,limit-buffer) ) \ + +#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; \ +} \ + +#define max_sections 2000 \ + \ + +#define too_long() {include_depth--; \ +err_print("! Include file name too long") ;goto restart;} \ + +#define max_bytes 225000 \ + +#define max_names 10000 \ + \ + +#define length(c) (c+1) ->byte_start-(c) ->byte_start +#define print_id(c) term_write((c) ->byte_start,length((c) ) ) \ + +#define hash_size 353 \ + +#define llink link +#define rlink dummy.Rlink +#define root name_dir->rlink \ + \ + +#define first_chunk(p) ((p) ->byte_start+2) +#define prefix_length(p) (int) ((unsigned char) *((p) ->byte_start) *256+ \ +(unsigned char) *((p) ->byte_start+1) ) +#define set_prefix_length(p,m) (*((p) ->byte_start) = (m) /256, \ +*((p) ->byte_start+1) = (m) %256) \ + +#define less 0 +#define equal 1 +#define greater 2 +#define prefix 3 +#define extension 4 \ + +#define bad_extension 5 \ + +#define spotless 0 +#define harmless_message 1 +#define error_message 2 +#define fatal_message 3 +#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 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) \ + + +#line 59 "common.w" + +/*2:*/ +#line 72 "common.w" + +typedef short boolean; +boolean program; + +/*:2*//*7:*/ +#line 157 "common.w" + +char buffer[long_buf_size]; +char*buffer_end= buffer+buf_size-2; +char*limit= buffer; +char*loc= buffer; + +/*:7*//*10:*/ +#line 212 "common.w" + +int include_depth; +FILE*file[max_include_depth]; +FILE*change_file; +char file_name[max_include_depth][max_file_name_length]; + +char change_file_name[max_file_name_length]; +char alt_web_file_name[max_file_name_length]; +int line[max_include_depth]; +int change_line; +int change_depth; +boolean input_has_ended; +boolean changing; +boolean web_file_open= 0; + +/*:10*//*20:*/ +#line 416 "common.w" + +typedef unsigned short sixteen_bits; +sixteen_bits section_count; +boolean changed_section[max_sections]; +boolean change_pending; + +boolean print_where= 0; + +/*:20*//*27:*/ +#line 586 "common.w" + +typedef struct name_info{ +char*byte_start; +/*31:*/ +#line 623 "common.w" + +struct name_info*link; + +/*:31*//*40:*/ +#line 722 "common.w" + +union{ +struct name_info*Rlink; + +#line 31 "common.ch" +struct{ +char Ilk; +boolean Func_flag;}dummy1; +}dummy; +#line 728 "common.w" + +/*:40*//*55:*/ +#line 1054 "common.w" + +char*equiv_or_xref; + +/*:55*/ +#line 589 "common.w" + +}name_info; +typedef name_info*name_pointer; +char byte_mem[max_bytes]; +char*byte_mem_end= byte_mem+max_bytes-1; +name_info name_dir[max_names]; +name_pointer name_dir_end= name_dir+max_names-1; + +/*:27*//*29:*/ +#line 609 "common.w" + +name_pointer name_ptr; +char*byte_ptr; + +/*:29*//*32:*/ +#line 636 "common.w" + +typedef name_pointer*hash_pointer; +name_pointer hash[hash_size]; +hash_pointer hash_end= hash+hash_size-1; +hash_pointer h; + +/*:32*//*56:*/ +#line 1074 "common.w" + +int history= spotless; + +/*:56*//*67:*/ +#line 1212 "common.w" + +int argc; +char**argv; +char C_file_name[max_file_name_length]; +char tex_file_name[max_file_name_length]; +char idx_file_name[max_file_name_length]; +char scn_file_name[max_file_name_length]; +boolean flags[128]; + +/*:67*//*77:*/ +#line 1366 "common.w" + +FILE*C_file; +FILE*tex_file; +FILE*idx_file; +FILE*scn_file; +FILE*active_file; + +/*:77*/ +#line 60 "common.w" + +/*3:*/ +#line 82 "common.w" +int phase; + +/*:3*//*11:*/ +#line 238 "common.w" + +char change_buffer[buf_size]; +char*change_limit; + +/*:11*/ +#line 61 "common.w" + +/*33:*/ +#line 642 "common.w" + +extern int names_match(); + +/*:33*//*38:*/ +#line 695 "common.w" + +void init_p(); + +/*:38*//*46:*/ +#line 844 "common.w" + +extern void init_node(); + +/*:46*//*53:*/ +#line 1009 "common.w" + +int section_name_cmp(); + +/*:53*//*57:*/ +#line 1084 "common.w" + +void err_print(); + +/*:57*//*60:*/ +#line 1132 "common.w" + +int wrap_up(); +extern void print_stats(); + +/*:60*//*63:*/ +#line 1165 "common.w" + +void fatal(),overflow(); + +/*:63*//*69:*/ +#line 1243 "common.w" + +void scan_args(); + +/*:69*//*81:*/ +#line 1407 "common.w" + +extern int strlen(); +extern int strcmp(); +extern char*strcpy(); +extern int strncmp(); +extern char*strncpy(); + +/*:81*/ +#line 62 "common.w" + + +/*:1*//*4:*/ +#line 88 "common.w" + +void +common_init() +{ +/*30:*/ +#line 613 "common.w" + +name_dir->byte_start= byte_ptr= byte_mem; +name_ptr= name_dir+1; +name_ptr->byte_start= byte_mem; + +/*:30*//*34:*/ +#line 647 "common.w" + +for(h= hash;h<=hash_end;*h++= NULL); + +/*:34*//*41:*/ +#line 729 "common.w" + +root= NULL; + +/*:41*/ +#line 92 "common.w" +; +/*68:*/ +#line 1225 "common.w" + +show_banner= show_happiness= show_progress= 1; + +/*:68*/ +#line 93 "common.w" +; +/*78:*/ +#line 1373 "common.w" + +scan_args(); +if(program==ctangle){ +if((C_file= fopen(C_file_name,"w"))==NULL) +fatal("! Cannot open output file ",C_file_name); + +} +else{ +if((tex_file= fopen(tex_file_name,"w"))==NULL) +fatal("! Cannot open output file ",tex_file_name); +} + +/*:78*/ +#line 94 "common.w" +; +} + +/*:4*//*9:*/ +#line 170 "common.w" + +int input_ln(fp) +FILE*fp; +{ +register int c= EOF; +register char*k; +if(feof(fp))return(0); +limit= k= buffer; +while(k<=buffer_end&&(c= getc(fp))!=EOF&&c!='\n') +if((*(k++)= c)!=' ')limit= k; +if(k>buffer_end) +if((c= getc(fp))!=EOF&&c!='\n'){ +ungetc(c,fp);loc= buffer;err_print("! Input line too long"); + +} +if(c==EOF&&limit==buffer)return(0); + +return(1); +} + +/*:9*//*12:*/ +#line 249 "common.w" + +void +prime_the_change_buffer() +{ +change_limit= change_buffer; +/*13:*/ +#line 263 "common.w" + +while(1){ +change_line++; +if(!input_ln(change_file))return; +if(limit<buffer+2)continue; +if(buffer[0]!='@')continue; +if(xisupper(buffer[1]))buffer[1]= tolower(buffer[1]); +if(buffer[1]=='x')break; +if(buffer[1]=='y'||buffer[1]=='z'||buffer[1]=='i'){ +loc= buffer+2; +err_print("! Missing @x in change file"); + +} +} + +/*:13*/ +#line 254 "common.w" +; +/*14:*/ +#line 280 "common.w" + +do{ +change_line++; +if(!input_ln(change_file)){ +err_print("! Change file ended after @x"); + +return; +} +}while(limit==buffer); + +/*:14*/ +#line 255 "common.w" +; +/*15:*/ +#line 290 "common.w" + +{ +change_limit= change_buffer-buffer+limit; +strncpy(change_buffer,buffer,limit-buffer+1); +} + +/*:15*/ +#line 256 "common.w" +; +} + +/*:12*//*16:*/ +#line 318 "common.w" + +void +check_change() +{ +int n= 0; +if(lines_dont_match)return; +change_pending= 0; +if(!changed_section[section_count]){ +if_section_start_make_pending(1); +if(!change_pending)changed_section[section_count]= 1; +} +while(1){ +changing= 1;print_where= 1;change_line++; +if(!input_ln(change_file)){ +err_print("! Change file ended before @y"); + +change_limit= change_buffer;changing= 0; +return; +} +if(limit>buffer+1&&buffer[0]=='@'){ +if(xisupper(buffer[1]))buffer[1]= tolower(buffer[1]); +/*17:*/ +#line 356 "common.w" + +if(buffer[1]=='x'||buffer[1]=='z'){ +loc= buffer+2;err_print("! Where is the matching @y?"); + +} +else if(buffer[1]=='y'){ +if(n>0){ +loc= buffer+2; +printf("\n! Hmm... %d ",n); +err_print("of the preceding lines failed to match"); + +} +change_depth= include_depth; +return; +} + +/*:17*/ +#line 340 "common.w" +; +} +/*15:*/ +#line 290 "common.w" + +{ +change_limit= change_buffer-buffer+limit; +strncpy(change_buffer,buffer,limit-buffer+1); +} + +/*:15*/ +#line 342 "common.w" +; +changing= 0;cur_line++; +while(!input_ln(cur_file)){ +if(include_depth==0){ +err_print("! CWEB file ended during a change"); + +input_has_ended= 1;return; +} +include_depth--;cur_line++; +} +if(lines_dont_match)n++; +} +} + +/*:16*//*18:*/ +#line 376 "common.w" + +void +reset_input() +{ +limit= buffer;loc= buffer+1;buffer[0]= ' '; +/*19:*/ +#line 391 "common.w" + +if((web_file= fopen(web_file_name,"r"))==NULL){ +strcpy(web_file_name,alt_web_file_name); +if((web_file= fopen(web_file_name,"r"))==NULL) +fatal("! Cannot open input file ",web_file_name); +} + + +web_file_open= 1; +if((change_file= fopen(change_file_name,"r"))==NULL) +fatal("! Cannot open change file ",change_file_name); + +/*:19*/ +#line 381 "common.w" +; +include_depth= 0;cur_line= 0;change_line= 0; +change_depth= include_depth; +changing= 1;prime_the_change_buffer();changing= !changing; +limit= buffer;loc= buffer+1;buffer[0]= ' ';input_has_ended= 0; +} + +/*:18*//*21:*/ +#line 424 "common.w" + +int get_line() +{ +restart: +if(changing&&include_depth==change_depth) +/*25:*/ +#line 529 "common.w" +{ +change_line++; +if(!input_ln(change_file)){ +err_print("! Change file ended without @z"); + +buffer[0]= '@';buffer[1]= 'z';limit= buffer+2; +} +if(limit>buffer){ +if(change_pending){ +if_section_start_make_pending(0); +if(change_pending){ +changed_section[section_count]= 1;change_pending= 0; +} +} +*limit= ' '; +if(buffer[0]=='@'){ +if(xisupper(buffer[1]))buffer[1]= tolower(buffer[1]); +if(buffer[1]=='x'||buffer[1]=='y'){ +loc= buffer+2; +err_print("! Where is the matching @z?"); + +} +else if(buffer[1]=='z'){ +prime_the_change_buffer();changing= !changing;print_where= 1; +} +} +} +} + +/*:25*/ +#line 429 "common.w" +; +if(!changing||include_depth>change_depth){ +/*24:*/ +#line 512 "common.w" +{ +cur_line++; +while(!input_ln(cur_file)){ +print_where= 1; +if(include_depth==0){input_has_ended= 1;break;} +else{ +fclose(cur_file);include_depth--; +if(changing&&include_depth==change_depth)break; +cur_line++; +} +} +if(!changing&&!input_has_ended) +if(limit-buffer==change_limit-change_buffer) +if(buffer[0]==change_buffer[0]) +if(change_limit>change_buffer)check_change(); +} + +/*:24*/ +#line 431 "common.w" +; +if(changing&&include_depth==change_depth)goto restart; +} +loc= buffer;*limit= ' '; +if(*buffer=='@'&&(*(buffer+1)=='i'||*(buffer+1)=='I')){ +loc= buffer+2; +while(loc<=limit&&(*loc==' '||*loc=='\t'||*loc=='"'))loc++; +if(loc>=limit){ +err_print("! Include file name not given"); + +goto restart; +} +if(include_depth>=max_include_depth-1){ +err_print("! Too many nested includes"); + +goto restart; +} +include_depth++; +/*23:*/ +#line 471 "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; +int l; + +while(*loc!=' '&&*loc!='\t'&&*loc!='"'&&k<=cur_file_name_end)*k++= *loc++; +if(k>cur_file_name_end)too_long(); + +*k= '\0'; +if((cur_file= fopen(cur_file_name,"r"))!=NULL){ +cur_line= 0;print_where= 1; +goto restart; +} +kk= getenv("CWEBINPUTS"); +if(kk!=NULL){ +if((l= strlen(kk))>max_file_name_length-2)too_long(); +strcpy(temp_file_name,kk); +} +else{ +#ifdef CWEBINPUTS +if((l= strlen(CWEBINPUTS))>max_file_name_length-2)too_long(); +strcpy(temp_file_name,CWEBINPUTS); +#else +l= 0; +#endif +} +if(l>0){ +if(k+l+2>=cur_file_name_end)too_long(); + +for(;k>=cur_file_name;k--)*(k+l+1)= *k; +strcpy(cur_file_name,temp_file_name); +cur_file_name[l]= '/'; +if((cur_file= fopen(cur_file_name,"r"))!=NULL){ +cur_line= 0;print_where= 1; +goto restart; +} +} +include_depth--;err_print("! Cannot open include file");goto restart; +} + +/*:23*/ +#line 449 "common.w" +; +} +return(!input_has_ended); +} + +/*:21*//*26:*/ +#line 561 "common.w" + +void +check_complete(){ +if(change_limit!=change_buffer){ +strncpy(buffer,change_buffer,change_limit-change_buffer+1); +limit= buffer+(int)(change_limit-change_buffer); +changing= 1;change_depth= include_depth;loc= buffer; +err_print("! Change file entry did not match"); + +} +} + +/*:26*//*35:*/ +#line 652 "common.w" + +name_pointer +id_lookup(first,last,t) +char*first; +char*last; +char t; +{ +char*i= first; +int h; +int l; +name_pointer p; +if(last==NULL)for(last= first;*last!='\0';last++); +l= last-first; +/*36:*/ +#line 675 "common.w" + +h= (unsigned char)*i; +while(++i<last)h= (h+h+(int)((unsigned char)*i))%hash_size; + + +/*:36*/ +#line 665 "common.w" +; +/*37:*/ +#line 683 "common.w" + +p= hash[h]; +while(p&&!names_match(p,first,l,t))p= p->link; +if(p==NULL){ +p= name_ptr; +p->link= hash[h];hash[h]= p; +} + +/*:37*/ +#line 666 "common.w" +; +if(p==name_ptr)/*39:*/ +#line 698 "common.w" +{ +if(byte_ptr+l>byte_mem_end)overflow("byte memory"); +if(name_ptr>=name_dir_end)overflow("name"); +strncpy(byte_ptr,first,l); +(++name_ptr)->byte_start= byte_ptr+= l; +if(program==cweave)init_p(p,t); +} + +/*:39*/ +#line 667 "common.w" +; +return(p); +} + +/*:35*//*42:*/ +#line 756 "common.w" + +void +print_section_name(p) +name_pointer p; +{ +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,ss-s);p= q->link;q= p; +}else{ +term_write(s,ss+1-s);p= name_dir;q= NULL; +} +s= p->byte_start; +} +if(q)term_write("...",3); +} + +/*:42*//*43:*/ +#line 775 "common.w" + +void +sprint_section_name(dest,p) +char*dest; +name_pointer p; +{ +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; +} +strncpy(dest,s,ss-s),dest+= ss-s; +s= p->byte_start; +} +*dest= '\0'; +} + +/*:43*//*44:*/ +#line 796 "common.w" + +void +print_prefix_name(p) +name_pointer p; +{ +char*s= first_chunk(p); +int l= prefix_length(p); +term_write(s,l); +if(s+l<(p+1)->byte_start)term_write("...",3); +} + +/*:44*//*45:*/ +#line 817 "common.w" + +int web_strcmp(j,j_len,k,k_len) +char*j,*k; +int j_len,k_len; +{ +char*j1= j+j_len,*k1= k+k_len; +while(k<k1&&j<j1&&*j==*k)k++,j++; +if(k==k1)if(j==j1)return equal; +else return extension; +else if(j==j1)return prefix; +else if(*j<*k)return less; +else return greater; +} + +/*:45*//*47:*/ +#line 847 "common.w" + +name_pointer +add_section_name(par,c,first,last,ispref) +name_pointer par; +int c; +char*first; +char*last; +int ispref; +{ +name_pointer p= name_ptr; +char*s= first_chunk(p); +int name_len= last-first+ispref; +if(s+name_len>byte_mem_end)overflow("byte memory"); +if(name_ptr+1>=name_dir_end)overflow("name"); +(++name_ptr)->byte_start= byte_ptr= s+name_len; +if(ispref){ +*(byte_ptr-1)= ' '; +name_len--; +name_ptr->link= name_dir; +(++name_ptr)->byte_start= byte_ptr; +} +set_prefix_length(p,name_len); +strncpy(s,first,name_len); +p->llink= NULL; +p->rlink= NULL; +init_node(p); +return par==NULL?(root= p):c==less?(par->llink= p):(par->rlink= p); +} + +/*:47*//*48:*/ +#line 876 "common.w" + +void +extend_section_name(p,first,last,ispref) +name_pointer p; +char*first; +char*last; +int ispref; +{ +char*s; +name_pointer q= p+1; +int name_len= last-first+ispref; +if(name_ptr>=name_dir_end)overflow("name"); +while(q->link!=name_dir)q= q->link; +q->link= name_ptr; +s= name_ptr->byte_start; +name_ptr->link= name_dir; +if(s+name_len>byte_mem_end)overflow("byte memory"); +(++name_ptr)->byte_start= byte_ptr= s+name_len; +strncpy(s,first,name_len); +if(ispref)*(byte_ptr-1)= ' '; +} + +/*:48*//*49:*/ +#line 904 "common.w" + +name_pointer +section_lookup(first,last,ispref) +char*first,*last; +int ispref; +{ +int c= 0; +name_pointer p= root; +name_pointer q= NULL; +name_pointer r= NULL; +name_pointer par= NULL; + +int name_len= last-first+1; +/*50:*/ +#line 928 "common.w" + +while(p){ +c= web_strcmp(first,name_len,first_chunk(p),prefix_length(p)); +if(c==less||c==greater){ +if(r==NULL) +par= p; +p= (c==less?p->llink:p->rlink); +}else{ +if(r!=NULL){ +printf("\n! Ambiguous prefix: matches <"); + +print_prefix_name(p); +printf(">\n and <"); +print_prefix_name(r); +err_print(">"); +return name_dir; +} +r= p; +p= p->llink; +q= r->rlink; +} +if(p==NULL) +p= q,q= NULL; +} + +/*:50*/ +#line 918 "common.w" +; +/*51:*/ +#line 953 "common.w" + +if(r==NULL) +return add_section_name(par,c,first,last+1,ispref); + +/*:51*/ +#line 919 "common.w" +; +/*52:*/ +#line 961 "common.w" + +switch(section_name_cmp(&first,name_len,r)){ + +case prefix: +if(!ispref){ +printf("\n! New name is a prefix of <"); + +print_section_name(r); +err_print(">"); +} +else if(name_len<prefix_length(r))set_prefix_length(r,name_len); + +case equal:return r; +case extension:if(!ispref||first<=last) +extend_section_name(r,first,last+1,ispref); +return r; +case bad_extension: +printf("\n! New name extends <"); + +print_section_name(r); +err_print(">"); +return r; +default: +printf("\n! Section name incompatible with <"); + +print_prefix_name(r); +printf(">,\n which abbreviates <"); +print_section_name(r); +err_print(">"); +return r; +} + +/*:52*/ +#line 920 "common.w" +; +} + +/*:49*//*54:*/ +#line 1012 "common.w" + +int section_name_cmp(pfirst,len,r) +char**pfirst; +int len; +name_pointer r; +{ +char*first= *pfirst; +name_pointer q= r+1; +char*ss,*s= first_chunk(r); +int c; +int ispref; +while(1){ +ss= (r+1)->byte_start-1; +if(*ss==' '&&ss>=r->byte_start)ispref= 1,q= q->link; +else ispref= 0,ss++,q= name_dir; +switch(c= web_strcmp(first,len,s,ss-s)){ +case equal:if(q==name_dir) +if(ispref){ +*pfirst= first+(ss-s); +return extension; +}else return equal; +else return(q->byte_start==(q+1)->byte_start)?equal:prefix; +case extension: +if(!ispref)return bad_extension; +first+= ss-s; +if(q!=name_dir){len-= ss-s;s= q->byte_start;r= q;continue;} +*pfirst= first;return extension; +default:return c; +} +} +} + +/*:54*//*58:*/ +#line 1087 "common.w" + +void +err_print(s) +char*s; +{ +char*k,*l; +printf(*s=='!'?"\n%s":"%s",s); +if(web_file_open)/*59:*/ +#line 1107 "common.w" + +{if(changing&&include_depth==change_depth) +printf(". (l. %d of change file)\n",change_line); +else if(include_depth==0)printf(". (l. %d)\n",cur_line); +else printf(". (l. %d of include file %s)\n",cur_line,cur_file_name); +l= (loc>=limit?limit:loc); +if(l>buffer){ +for(k= buffer;k<l;k++) +if(*k=='\t')putchar(' '); +else putchar(*k); +putchar('\n'); +for(k= buffer;k<l;k++)putchar(' '); +} +for(k= l;k<limit;k++)putchar(*k); +if(*limit=='|')putchar('|'); +putchar(' '); +} + +/*:59*/ +#line 1094 "common.w" +; +update_terminal;mark_error; +} + +/*:58*//*61:*/ +#line 1142 "common.w" + +int wrap_up(){ +putchar('\n'); +if(show_stats) +print_stats(); +/*62:*/ +#line 1152 "common.w" + +switch(history){ +case spotless:if(show_happiness)printf("(No errors were found.)\n");break; +case harmless_message: +printf("(Did you see the warning message above?)\n");break; +case error_message: +printf("(Pardon me, but I think I spotted something wrong.)\n");break; +case fatal_message:printf("(That was a fatal error, my friend.)\n"); +} + +/*:62*/ +#line 1147 "common.w" +; +if(history>harmless_message)return(1); +else return(0); +} + +/*:61*//*64:*/ +#line 1171 "common.w" +void +fatal(s,t) +char*s,*t; +{ +if(*s)printf(s); +err_print(t); +history= fatal_message;exit(wrap_up()); +} + +/*:64*//*65:*/ +#line 1182 "common.w" +void +overflow(t) +char*t; +{ +printf("\n! Sorry, %s capacity exceeded",t);fatal("",""); +} + + +/*:65*//*70:*/ +#line 1246 "common.w" + +void +scan_args() +{ +char*dot_pos; +char*name_pos; +register char*s; +boolean found_web= 0,found_change= 0,found_out= 0; + +boolean flag_change; + +while(--argc>0){ +if((**(++argv)=='-'||**argv=='+')&&*(*argv+1))/*74:*/ +#line 1340 "common.w" + +{ +if(**argv=='-')flag_change= 0; +else flag_change= 1; +for(dot_pos= *argv+1;*dot_pos>'\0';dot_pos++) +flags[*dot_pos]= flag_change; +} + +/*:74*/ +#line 1258 "common.w" + +else{ +s= name_pos= *argv;dot_pos= NULL; +while(*s){ +if(*s=='.')dot_pos= s++; +#line 47 "common.ch" +#ifdef __EMX__ +else if(*s==':'||*s=='\\'||*s=='/') +dot_pos= NULL,name_pos= ++s; +#else +else if(*s=='/')dot_pos= NULL,name_pos= ++s; +#endif +#line 1264 "common.w" + else s++; +} +if(!found_web)/*71:*/ +#line 1284 "common.w" + +{ +if(s-*argv>max_file_name_length-5) +/*76:*/ +#line 1360 "common.w" +fatal("! Filename too long\n",*argv); + + +/*:76*/ +#line 1287 "common.w" +; +if(dot_pos==NULL) +sprintf(web_file_name,"%s.w",*argv); +else{ +strcpy(web_file_name,*argv); +*dot_pos= 0; +} +sprintf(alt_web_file_name,"%s.web",*argv); +sprintf(tex_file_name,"%s.tex",name_pos); +sprintf(idx_file_name,"%s.idx",name_pos); +sprintf(scn_file_name,"%s.scn",name_pos); +sprintf(C_file_name,"%s.c",name_pos); +found_web= 1; +} + +/*:71*/ +#line 1267 "common.w" + +else if(!found_change)/*72:*/ +#line 1302 "common.w" + +{ +if(strcmp(*argv,"-")==0)found_change= -1; +else{ +if(s-*argv>max_file_name_length-4) +/*76:*/ +#line 1360 "common.w" +fatal("! Filename too long\n",*argv); + + +/*:76*/ +#line 1307 "common.w" +; +if(dot_pos==NULL) +sprintf(change_file_name,"%s.ch",*argv); +else strcpy(change_file_name,*argv); +found_change= 1; +} +} + +/*:72*/ +#line 1268 "common.w" + +else if(!found_out)/*73:*/ +#line 1315 "common.w" + +{ +if(s-*argv>max_file_name_length-5) +/*76:*/ +#line 1360 "common.w" +fatal("! Filename too long\n",*argv); + + +/*:76*/ +#line 1318 "common.w" +; +if(dot_pos==NULL){ +sprintf(tex_file_name,"%s.tex",*argv); +sprintf(idx_file_name,"%s.idx",*argv); +sprintf(scn_file_name,"%s.scn",*argv); +sprintf(C_file_name,"%s.c",*argv); +}else{ +strcpy(tex_file_name,*argv); +if(flags['x']){ +if(program==cweave&&strcmp(*argv+strlen(*argv)-4,".tex")!=0) +fatal("! Output file name should end with .tex\n",*argv); + +strcpy(idx_file_name,*argv); +strcpy(idx_file_name+strlen(*argv)-4,".idx"); +strcpy(scn_file_name,*argv); +strcpy(scn_file_name+strlen(*argv)-4,".scn"); +} +strcpy(C_file_name,*argv); +} +found_out= 1; +} + +/*:73*/ +#line 1269 "common.w" + +else/*75:*/ +#line 1348 "common.w" + +{ +if(program==ctangle) +fatal( +"! Usage: ctangle [options] webfile[.w] [{changefile[.ch]|-} [outfile[.c]]]\n" +,""); + +else fatal( +#line 69 "common.ch" +"! Usage: cweave [options] webfile[.w] [{changefile[.ch]|-} [outfile[.tex]]]\n" +"\n" +" possible options: (default values shown)\n" +"\n" +" -a alternative output format\n" +" +b show banner\n" +" +f force line breaks after C statements\n" +" +h print happy message if successful\n" +" -i append () after functions in index\n" +" +p give progress reports\n" +" -s show memory statistics\n" +" +x include indices and table of contents\n",""); +#line 1358 "common.w" +} + +/*:75*/ +#line 1270 "common.w" +; +} +} +if(!found_web)/*75:*/ +#line 1348 "common.w" + +{ +if(program==ctangle) +fatal( +"! Usage: ctangle [options] webfile[.w] [{changefile[.ch]|-} [outfile[.c]]]\n" +,""); + +else fatal( +#line 69 "common.ch" +"! Usage: cweave [options] webfile[.w] [{changefile[.ch]|-} [outfile[.tex]]]\n" +"\n" +" possible options: (default values shown)\n" +"\n" +" -a alternative output format\n" +" +b show banner\n" +" +f force line breaks after C statements\n" +" +h print happy message if successful\n" +" -i append () after functions in index\n" +" +p give progress reports\n" +" -s show memory statistics\n" +" +x include indices and table of contents\n",""); +#line 1358 "common.w" +} + +/*:75*/ +#line 1273 "common.w" +; +#line 58 "common.ch" +#ifdef __EMX__ +if(found_change<=0)strcpy(change_file_name,"NUL"); +#else +if(found_change<=0)strcpy(change_file_name,"/dev/null"); +#endif +#line 1275 "common.w" +} + +/*:70*/ diff --git a/web/c_cpp/c2cweb/cweb/common.ch b/web/c_cpp/c2cweb/cweb/common.ch new file mode 100644 index 0000000000..f591d774bf --- /dev/null +++ b/web/c_cpp/c2cweb/cweb/common.ch @@ -0,0 +1,83 @@ +This file is part of the c2cweb package Version 1.5 + +This is the change file for CWEB's COMMON (Ver. 3.2 July 1994) + +modified by Werner Lemberg (a7971428@@unet.univie.ac.at) 10-Nov-1996 + +=============================================================================== + +@x section 7 +@d buf_size 100 /* for \.{CWEAVE} and \.{CTANGLE} */ +@y +@d buf_size 400 /* for \.{CWEAVE} and \.{CTANGLE} */ +@z + +@x section 27 +@d max_bytes 90000 /* the number of bytes in identifiers, + index entries, and section names; must be less than $2^{24}$ */ +@d max_names 4000 /* number of identifiers, strings, section names; + must be less than 10240 */ +@y +@d max_bytes 225000 /* the number of bytes in identifiers, + index entries, and section names; must be less than $2^{24}$ */ +@d max_names 10000 /* number of identifiers, strings, section names; + must be less than 10240 */ +@z + +@x section 40 + char Ilk; /* used by identifiers in \.{CWEAVE} only */ +} dummy; +@y + struct { + char Ilk; /* used by identifiers in \.{CWEAVE} only */ + boolean Func_flag; } dummy1; +} dummy; +@z + +@x section 69 +An omitted change file argument means that |"/dev/null"| should be used, +@y +An omitted change file argument means that |"/dev/null"| (or |"NUL"| under DOS +and OS/2) should be used, +@z + +@x section 70 + else if (*s=='/') dot_pos=NULL,name_pos=++s; +@y +#ifdef __EMX__ + else if (*s == ':' || *s == '\\' || *s == '/') + dot_pos=NULL,name_pos=++s; +#else + else if (*s=='/') dot_pos=NULL,name_pos=++s; +#endif +@z + +@x section 70 + if (found_change<=0) strcpy(change_file_name,"/dev/null"); +@y +#ifdef __EMX__ + if (found_change<=0) strcpy(change_file_name,"NUL"); +#else + if (found_change<=0) strcpy(change_file_name,"/dev/null"); +#endif +@z + +@x section 75 +"! Usage: cweave [options] webfile[.w] [{changefile[.ch]|-} [outfile[.tex]]]\n" + ,""); +@y +"! Usage: cweave [options] webfile[.w] [{changefile[.ch]|-} [outfile[.tex]]]\n" +"\n" +" possible options: (default values shown)\n" +"\n" +" -a alternative output format\n" +" +b show banner\n" +" +f force line breaks after C statements\n" +" +h print happy message if successful\n" +" -i append () after functions in index\n" +" +p give progress reports\n" +" -s show memory statistics\n" +" +x include indices and table of contents\n", ""); +@z + +--- end of common.ch --- diff --git a/web/c_cpp/c2cweb/cweb/common.h b/web/c_cpp/c2cweb/cweb/common.h new file mode 100644 index 0000000000..200ec27358 --- /dev/null +++ b/web/c_cpp/c2cweb/cweb/common.h @@ -0,0 +1,201 @@ +% This file is part of CWEB. +% This program by Silvio Levy and Donald E. Knuth +% is based on a program by Knuth. +% It is distributed WITHOUT ANY WARRANTY, express or implied. +% Version 3.0 --- June 1993 + +% Copyright (C) 1987,1990,1993 Silvio Levy and Donald E. Knuth + +% this file is part of the c2cweb package Version 1.5 +% modified by Werner Lemberg (a7971428@@unet.univie.ac.at) 10-Nov-1996 + +% Permission is granted to make and distribute verbatim copies of this +% document provided that the copyright notice and this permission notice +% are preserved on all copies. + +% Permission is granted to copy and distribute modified versions of this +% document under the conditions for verbatim copying, provided that the +% entire resulting derived work is distributed under the terms of a +% permission notice identical to this one. + +% Please send comments, suggestions, etc. to levy@@geom.umn.edu. + +% The next few sections contain stuff from the file |"common.w"| that has +% to be included in both |"ctangle.w"| and |"cweave.w"|. It appears in this +% file |"common.h"|, which needs to be updated when |"common.w"| changes. + +First comes general stuff: + +@d ctangle 0 +@d cweave 1 + +@<Common code for \.{CWEAVE} and \.{CTANGLE}@>= +typedef short boolean; +typedef char unsigned eight_bits; +extern boolean program; /* \.{CWEAVE} or \.{CTANGLE}? */ +extern int phase; /* which phase are we in? */ + +@ @<Include files@>= +#include <stdio.h> + +@ Code related to the character set: +@^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 not_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} */ + +@<Common code...@>= +char section_text[longest_name+1]; /* name being sought for */ +char *section_text_end = section_text+longest_name; /* end of |section_text| */ +char *id_first; /* where the current identifier begins in the buffer */ +char *id_loc; /* just after the current identifier in the buffer */ + +@ Code related to input routines: + +@d xisalpha(c) (isalpha(c)&&((eight_bits)c<0200)) +@d xisdigit(c) (isdigit(c)&&((eight_bits)c<0200)) +@d xisspace(c) (isspace(c)&&((eight_bits)c<0200)) +@d xislower(c) (islower(c)&&((eight_bits)c<0200)) +@d xisupper(c) (isupper(c)&&((eight_bits)c<0200)) +@d xisxdigit(c) (isxdigit(c)&&((eight_bits)c<0200)) + +@<Common code...@>= +extern char buffer[]; /* where each line of input goes */ +extern char *buffer_end; /* end of |buffer| */ +extern char *loc; /* points to the next character to be read from the buffer*/ +extern char *limit; /* points to the last character in the buffer */ + +@ Code related to identifier and section name storage: +@d length(c) (c+1)->byte_start-(c)->byte_start /* the length of a name */ +@d print_id(c) term_write((c)->byte_start,length((c))) /* print identifier */ +@d llink link /* left link in binary search tree for section names */ +@d rlink dummy.Rlink /* right link in binary search tree for section names */ +@d root name_dir->rlink /* the root of the binary search tree + for section names */ +@d chunk_marker 0 + +@<Common code...@>= +typedef struct name_info { + char *byte_start; /* beginning of the name in |byte_mem| */ + struct name_info *link; + union { + struct name_info *Rlink; /* right link in binary search tree for section + names */ + struct { + char Ilk; /* used by identifiers in \.{CWEAVE} only */ + boolean Func_flag; + } dummy1; + } dummy; + char *equiv_or_xref; /* 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; +extern char byte_mem[]; /* characters of names */ +extern char *byte_mem_end; /* end of |byte_mem| */ +extern name_info name_dir[]; /* information about names */ +extern name_pointer name_dir_end; /* end of |name_dir| */ +extern name_pointer name_ptr; /* first unused position in |byte_start| */ +extern char *byte_ptr; /* first unused position in |byte_mem| */ +extern name_pointer hash[]; /* heads of hash lists */ +extern hash_pointer hash_end; /* end of |hash| */ +extern hash_pointer h; /* index into hash-head array */ +extern name_pointer id_lookup(); /* looks up a string in the identifier table */ +extern name_pointer section_lookup(); /* finds section name */ +extern void print_section_name(), sprint_section_name(); + +@ Code related to error handling: +@d spotless 0 /* |history| value for normal jobs */ +@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_error history=error_message +@d confusion(s) fatal("! This can't happen: ",s) + +@<Common...@>= +extern history; /* indicates how bad this run was */ +extern err_print(); /* print error message and context */ +extern wrap_up(); /* indicate |history| and exit */ +extern void fatal(); /* issue error message and die */ +extern void overflow(); /* succumb because a table has overflowed */ + +@ Code related to file handling: +@f line x /* make |line| an unreserved word */ +@d max_file_name_length 60 +@d cur_file file[include_depth] /* current file */ +@d cur_file_name file_name[include_depth] /* current file name */ +@d web_file_name file_name[0] /* main source file name */ +@d cur_line line[include_depth] /* number of current line in current file */ + +@<Common code...@>= +extern include_depth; /* current level of nesting */ +extern FILE *file[]; /* stack of non-change files */ +extern FILE *change_file; /* change file */ +extern char C_file_name[]; /* name of |C_file| */ +extern char tex_file_name[]; /* name of |tex_file| */ +extern char idx_file_name[]; /* name of |idx_file| */ +extern char scn_file_name[]; /* name of |scn_file| */ +extern char file_name[][max_file_name_length]; + /* stack of non-change file names */ +extern char change_file_name[]; /* name of change file */ +extern line[]; /* number of current line in the stacked files */ +extern change_line; /* number of current line in change file */ +extern boolean input_has_ended; /* if there is no more input */ +extern boolean changing; /* if the current line is from |change_file| */ +extern boolean web_file_open; /* if the web file is being read */ +extern reset_input(); /* initialize to read the web file and change file */ +extern get_line(); /* inputs the next line */ +extern check_complete(); /* checks that all changes were picked up */ + +@ Code related to section numbers: +@<Common code...@>= +typedef unsigned short sixteen_bits; +extern sixteen_bits section_count; /* the current section number */ +extern boolean changed_section[]; /* is the section changed? */ +extern boolean change_pending; /* is a decision about change still unclear? */ +extern boolean print_where; /* tells \.{CTANGLE} to print line and file info */ + +@ 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_happiness flags['h'] /* should lack of errors be announced? */ + +@<Common code...@>= +extern int argc; /* copy of |ac| parameter to |main| */ +extern char **argv; /* copy of |av| parameter to |main| */ +extern boolean flags[]; /* an option for each 7-bit code */ + +@ Code relating to output: +@d update_terminal fflush(stdout) /* empty the terminal output buffer */ +@d new_line putchar('\n') @d putxchar putchar +@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) + +@<Common code...@>= +extern FILE *C_file; /* where output of \.{CTANGLE} goes */ +extern FILE *tex_file; /* where output of \.{CWEAVE} goes */ +extern FILE *idx_file; /* where index from \.{CWEAVE} goes */ +extern FILE *scn_file; /* where list of sections from \.{CWEAVE} goes */ +extern FILE *active_file; /* currently active file for \.{CWEAVE} output */ + +@ The procedure that gets everything rolling: + +@<Common code...@>= +extern void common_init(); + + +@q end of common.h @> diff --git a/web/c_cpp/c2cweb/cweb/common.w b/web/c_cpp/c2cweb/cweb/common.w new file mode 100644 index 0000000000..48caf68e24 --- /dev/null +++ b/web/c_cpp/c2cweb/cweb/common.w @@ -0,0 +1,1415 @@ +% This file is part of CWEB. +% This program by Silvio Levy and Donald E. Knuth +% is based on a program by Knuth. +% It is distributed WITHOUT ANY WARRANTY, express or implied. +% Version 3.3 --- December 1994 (works with later versions too) + +% Copyright (C) 1987,1990,1993 Silvio Levy and Donald E. Knuth + +% Permission is granted to make and distribute verbatim copies of this +% document provided that the copyright notice and this permission notice +% are preserved on all copies. + +% Permission is granted to copy and distribute modified versions of this +% document under the conditions for verbatim copying, provided that the +% entire resulting derived work is given a different name and distributed +% under the terms of a permission notice identical to this one. + +\def\v{\char'174} % vertical (|) in typewriter font + +\def\title{Common code for CTANGLE and CWEAVE (Version 3.3)} +\def\topofcontents{\null\vfill + \centerline{\titlefont Common code for {\ttitlefont CTANGLE} and + {\ttitlefont CWEAVE}} + \vskip 15pt + \centerline{(Version 3.3)} + \vfill} +\def\botofcontents{\vfill +\noindent +Copyright \copyright\ 1987, 1990, 1993 Silvio Levy and Donald E. Knuth +\bigskip\noindent +Permission is granted to make and distribute verbatim copies of this +document provided that the copyright notice and this permission notice +are preserved on all copies. + +\smallskip\noindent +Permission is granted to copy and distribute modified versions of this +document under the conditions for verbatim copying, provided that the +entire resulting derived work is given a different name and distributed +under the terms of a permission notice identical to this one. +} + +\pageno=\contentspagenumber \advance\pageno by 1 +\let\maybe=\iftrue + +@** Introduction. This file contains code common +to both \.{CTANGLE} and \.{CWEAVE}, which roughly concerns the following +problems: character uniformity, input routines, error handling and +parsing of command line. We have tried to concentrate in this file +all the system dependencies, so as to maximize portability. + +In the texts below we will +sometimes use \.{CWEB} to refer to either of the two component +programs, if no confusion can arise. + +The file begins with a few basic definitions. + +@c +@<Include files@>@/ +@h +@<Definitions that should agree with \.{CTANGLE} and \.{CWEAVE}@>@/ +@<Other definitions@>@/ +@<Predeclaration of procedures@>@/ + +@ In certain cases \.{CTANGLE} and \.{CWEAVE} should do almost, but not +quite, the same thing. In these cases we've written common code for +both, differentiating between the two by means of the global variable +|program|. + +@d ctangle 0 +@d cweave 1 + +@<Definitions...@>= +typedef short boolean; +boolean program; /* \.{CWEAVE} or \.{CTANGLE}? */ + +@ \.{CWEAVE} operates in three phases: first it inputs the source +file and stores cross-reference data, then it inputs the source once again and +produces the \TEX/ output file, and finally it sorts and outputs the index. +Similarly, \.{CTANGLE} operates in two phases. +The global variable |phase| tells which phase we are in. + +@<Other...@>= int phase; /* which phase are we in? */ + +@ There's an initialization procedure that gets both \.{CTANGLE} and +\.{CWEAVE} off to a good start. We will fill in the details of this +procedure later. + +@c +void +common_init() +{ + @<Initialize pointers@>; + @<Set the default options common to \.{CTANGLE} and \.{CWEAVE}@>; + @<Scan arguments and open output files@>; +} + +@*1 The character set. +\.{CWEB} uses the conventions of \CEE/ programs found in the standard +\.{ctype.h} header file. + +@<Include files@>= +#include <ctype.h> + +@ A few character pairs are encoded internally as single characters, +using the definitions below. These definitions are consistent with +an extension of ASCII code originally developed at MIT and explained in +Appendix~C of {\sl The \TEX/book\/}; thus, users who have such a +character set can type things like \.{\char'32} and \.{\char'4} instead +of \.{!=} and \.{\&\&}. (However, their files will not be too portable +until more people adopt the extended code.) + +If the character set is not ASCII, the definitions given here may conflict +with existing characters; in such cases, other arbitrary codes should be +substituted. The indexes to \.{CTANGLE} and \.{CWEAVE} mention every +case where similar codes may have to be changed in order to +avoid character conflicts. Look for the entry ``ASCII code dependencies'' +in those indexes. + +@^ASCII code dependencies@> +@^system 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 not_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} */ + +@** Input routines. The lowest level of input to the \.{CWEB} programs +is performed by |input_ln|, which must be told which file to read from. +The return value of |input_ln| is 1 if the read is successful and 0 if +not (generally this means the file has ended). The conventions +of \TEX/ are followed; i.e., the characters of the next line of the file +are copied into the |buffer| array, +and the global variable |limit| is set to the first unoccupied position. +Trailing blanks are ignored. The value of |limit| must be strictly less +than |buf_size|, so that |buffer[buf_size-1]| is never filled. + +Since |buf_size| is strictly less than |long_buf_size|, +some of \.{CWEB}'s routines use the fact that it is safe to refer to +|*(limit+2)| without overstepping the bounds of the array. + +@d buf_size 100 /* for \.{CWEAVE} and \.{CTANGLE} */ +@d longest_name 1000 +@d long_buf_size (buf_size+longest_name) /* for \.{CWEAVE} */ +@d xisspace(c) (isspace(c)&&((unsigned char)c<0200)) +@d xisupper(c) (isupper(c)&&((unsigned char)c<0200)) + +@<Definitions...@>= +char buffer[long_buf_size]; /* where each line of input goes */ +char *buffer_end=buffer+buf_size-2; /* end of |buffer| */ +char *limit=buffer; /* points to the last character in the buffer */ +char *loc=buffer; /* points to the next character to be read from the buffer */ + +@ @<Include files@>= +#include <stdio.h> + +@ 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@> + +@c +int input_ln(fp) /* copies a line into |buffer| or returns 0 */ +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(0); /* 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) + if ((c=getc(fp))!=EOF && c!='\n') { + ungetc(c,fp); loc=buffer; err_print("! Input line too long"); +@.Input line too long@> + } + if (c==EOF && limit==buffer) return(0); /* there was nothing after + the last newline */ + return(1); +} + +@ Now comes the problem of deciding which file to read from next. +Recall that the actual text that \.{CWEB} should process comes from two +streams: a |web_file|, which can contain possibly nested include +commands \.{@@i}, and a |change_file|, which might also contain +includes. The |web_file| together with the currently open include +files form a stack |file|, whose names are stored in a parallel stack +|file_name|. The boolean |changing| tells whether or not we're reading +from the |change_file|. + +The line number of each open file is also kept for error reporting and +for the benefit of \.{CTANGLE}. + +@f line x /* make |line| an unreserved word */ +@d max_include_depth 10 /* maximum number of source files open + simultaneously, not counting the change file */ +@d max_file_name_length 60 +@d cur_file file[include_depth] /* current file */ +@d cur_file_name file_name[include_depth] /* current file name */ +@d cur_line line[include_depth] /* number of current line in current file */ +@d web_file file[0] /* main source file */ +@d web_file_name file_name[0] /* main source file name */ + +@<Definitions...@>= +int include_depth; /* current level of nesting */ +FILE *file[max_include_depth]; /* stack of non-change files */ +FILE *change_file; /* change file */ +char file_name[max_include_depth][max_file_name_length]; + /* stack of non-change file names */ +char change_file_name[max_file_name_length]; /* name of change file */ +char alt_web_file_name[max_file_name_length]; /* alternate name to try */ +int line[max_include_depth]; /* number of current line in the stacked files */ +int change_line; /* number of current line in change file */ +int change_depth; /* where \.{@@y} originated during a change */ +boolean input_has_ended; /* if there is no more input */ +boolean changing; /* if the current line is from |change_file| */ +boolean web_file_open=0; /* if the web file is being read */ + +@ When |changing==0|, the next line of |change_file| is kept in +|change_buffer|, for purposes of comparison with the next +line of |cur_file|. After the change file has been completely input, we +set |change_limit=change_buffer|, +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 || + strncmp(buffer, change_buffer, limit-buffer)) + +@<Other...@>= +char change_buffer[buf_size]; /* next line of |change_file| */ +char *change_limit; /* points to the last character in |change_buffer| */ + +@ Procedure |prime_the_change_buffer| +sets |change_buffer| in preparation for the next matching operation. +Since blank lines in the change file are not used for matching, we have +|(change_limit==change_buffer && !changing)| if and only if +the change file is exhausted. This procedure is called only when +|changing| is 1; hence error messages will be reported correctly. + +@c +void +prime_the_change_buffer() +{ + change_limit=change_buffer; /* this value is used if the change file ends */ + @<Skip over comment lines in the change file; |return| if end of file@>; + @<Skip to the next nonblank line; |return| if end of file@>; + @<Move |buffer| and |limit| to |change_buffer| and |change_limit|@>; +} + +@ 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). + +@<Skip over comment lines in the change file...@>= +while(1) { + change_line++; + if (!input_ln(change_file)) return; + if (limit<buffer+2) continue; + if (buffer[0]!='@@') continue; + if (xisupper(buffer[1])) buffer[1]=tolower(buffer[1]); + if (buffer[1]=='x') break; + if (buffer[1]=='y' || buffer[1]=='z' || buffer[1]=='i') { + loc=buffer+2; + err_print("! Missing @@x in change file"); +@.Missing @@x...@> + } +} + +@ Here we are looking at lines following the \.{@@x}. + +@<Skip to the next nonblank line...@>= +do { + change_line++; + if (!input_ln(change_file)) { + err_print("! Change file ended after @@x"); +@.Change file ended...@> + return; + } +} while (limit==buffer); + +@ @<Move |buffer| and |limit| to |change_buffer| and |change_limit|@>= +{ + change_limit=change_buffer-buffer+limit; + strncpy(change_buffer,buffer,limit-buffer+1); +} + +@ The following procedure is used to see if the next change entry should +go into effect; it is called only when |changing| is 0. +The idea is to test whether or not the current +contents of |buffer| matches the current contents of |change_buffer|. +If not, there's nothing more to do; but if so, a change is called for: +All of the text down to the \.{@@y} is supposed to match. An error +message is issued if any discrepancy is found. Then the procedure +prepares to read the next line from |change_file|. + +When a match is found, the current section is marked as changed unless +the first line after the \.{@@x} and after the \.{@@y} both start with +either |'@@*'| or |'@@ '| (possibly preceded by whitespace). + +This procedure is called only when |buffer<limit|, i.e., when the +current line is nonempty. + +@d if_section_start_make_pending(b) {@+*limit='!'; + for (loc=buffer;xisspace(*loc);loc++) ; + *limit=' '; + if (*loc=='@@' && (xisspace(*(loc+1)) || *(loc+1)=='*')) change_pending=b; +} + +@c +void +check_change() /* switches to |change_file| if the buffers match */ +{ + int n=0; /* the number of discrepancies found */ + if (lines_dont_match) return; + change_pending=0; + if (!changed_section[section_count]) { + if_section_start_make_pending(1); + if (!change_pending) changed_section[section_count]=1; + } + while (1) { + changing=1; print_where=1; change_line++; + if (!input_ln(change_file)) { + err_print("! Change file ended before @@y"); +@.Change file ended...@> + change_limit=change_buffer; changing=0; + return; + } + if (limit>buffer+1 && buffer[0]=='@@') { + if (xisupper(buffer[1])) buffer[1]=tolower(buffer[1]); + @<If the current line starts with \.{@@y}, + report any discrepancies and |return|@>; + } + @<Move |buffer| and |limit|...@>; + changing=0; cur_line++; + while (!input_ln(cur_file)) { /* pop the stack or quit */ + if (include_depth==0) { + err_print("! CWEB file ended during a change"); +@.CWEB file ended...@> + input_has_ended=1; return; + } + include_depth--; cur_line++; + } + if (lines_dont_match) n++; + } +} + +@ @<If the current line starts with \.{@@y}...@>= +if (buffer[1]=='x' || buffer[1]=='z') { + loc=buffer+2; err_print("! Where is the matching @@y?"); +@.Where is the match...@> + } +else if (buffer[1]=='y') { + if (n>0) { + loc=buffer+2; + printf("\n! Hmm... %d ",n); + err_print("of the preceding lines failed to match"); +@.Hmm... n of the preceding...@> + } + change_depth=include_depth; + return; +} + +@ The |reset_input| procedure, which gets \.{CWEB} ready to read the +user's \.{CWEB} input, is used at the beginning of phase one of \.{CTANGLE}, +phases one and two of \.{CWEAVE}. + +@c +void +reset_input() +{ + limit=buffer; loc=buffer+1; buffer[0]=' '; + @<Open input files@>; + include_depth=0; cur_line=0; change_line=0; + change_depth=include_depth; + changing=1; prime_the_change_buffer(); changing=!changing; + limit=buffer; loc=buffer+1; buffer[0]=' '; input_has_ended=0; +} + +@ The following code opens the input files. +@^system dependencies@> + +@<Open input files@>= +if ((web_file=fopen(web_file_name,"r"))==NULL) { + strcpy(web_file_name,alt_web_file_name); + if ((web_file=fopen(web_file_name,"r"))==NULL) + fatal("! Cannot open input file ", web_file_name); +} +@.Cannot open input file@> +@.Cannot open change file@> +web_file_open=1; +if ((change_file=fopen(change_file_name,"r"))==NULL) + fatal("! Cannot open change file ", change_file_name); + +@ The |get_line| procedure is called when |loc>limit|; it puts the next +line of merged input into the buffer and updates the other variables +appropriately. A space is placed at the right end of the line. +This procedure returns |!input_has_ended| because we often want to +check the value of that variable after calling the procedure. + +If we've just changed from the |cur_file| to the |change_file|, or if +the |cur_file| has changed, we tell \.{CTANGLE} to print this +information in the \CEE/ file by means of the |print_where| flag. + +@d max_sections 2000 /* number of identifiers, strings, section names; + must be less than 10240 */ + +@<Defin...@>= +typedef unsigned short sixteen_bits; +sixteen_bits section_count; /* the current section number */ +boolean changed_section[max_sections]; /* is the section changed? */ +boolean change_pending; /* if the current change is not yet recorded in + |changed_section[section_count]| */ +boolean print_where=0; /* should \.{CTANGLE} print line and file info? */ + +@ @c +int get_line() /* inputs the next line */ +{ + restart: + if (changing && include_depth==change_depth) + @<Read from |change_file| and maybe turn off |changing|@>; + if (! changing || include_depth>change_depth) { + @<Read from |cur_file| and maybe turn on |changing|@>; + if (changing && include_depth==change_depth) goto restart; + } + loc=buffer; *limit=' '; + if (*buffer=='@@' && (*(buffer+1)=='i' || *(buffer+1)=='I')) { + loc=buffer+2; + while (loc<=limit && (*loc==' '||*loc=='\t'||*loc=='"')) loc++; + if (loc>=limit) { + err_print("! Include file name not given"); +@.Include file name ...@> + goto restart; + } + if (include_depth>=max_include_depth-1) { + err_print("! Too many nested includes"); +@.Too many nested includes@> + goto restart; + } + include_depth++; /* push input stack */ + @<Try to open include file, abort push if unsuccessful, go to |restart|@>; + } + return (!input_has_ended); +} + +@ When an \.{@@i} line is found in the |cur_file|, we must temporarily +stop reading it and start reading from the named include file. The +\.{@@i} line should give a complete file name with or without +double quotes. +If the environment variable \.{CWEBINPUTS} is set, or if the compiler flag +of the same name was defined at compile time, +\.{CWEB} will look for include files in the directory thus named, if +it cannot find them in the current directory. +(Colon-separated paths are not supported.) +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;} + +@<Include...@>= +#include <stdlib.h> /* declaration of |getenv| and |exit| */ + +@ @<Try to open...@>= { + 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; + int l; /* length of file name */ + + while (*loc!=' '&&*loc!='\t'&&*loc!='"'&&k<=cur_file_name_end) *k++=*loc++; + if (k>cur_file_name_end) too_long(); +@.Include file name ...@> + *k='\0'; + if ((cur_file=fopen(cur_file_name,"r"))!=NULL) { + cur_line=0; print_where=1; + goto restart; /* success */ + } + kk=getenv("CWEBINPUTS"); + if (kk!=NULL) { + if ((l=strlen(kk))>max_file_name_length-2) too_long(); + strcpy(temp_file_name,kk); + } + else { +#ifdef CWEBINPUTS + if ((l=strlen(CWEBINPUTS))>max_file_name_length-2) too_long(); + strcpy(temp_file_name,CWEBINPUTS); +#else + l=0; +#endif /* |CWEBINPUTS| */ + } + 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; + strcpy(cur_file_name,temp_file_name); + cur_file_name[l]='/'; /* \UNIX/ pathname separator */ + if ((cur_file=fopen(cur_file_name,"r"))!=NULL) { + cur_line=0; print_where=1; + goto restart; /* success */ + } + } + include_depth--; err_print("! Cannot open include file"); goto restart; +} + +@ @<Read from |cur_file|...@>= { + cur_line++; + while (!input_ln(cur_file)) { /* pop the stack or quit */ + print_where=1; + if (include_depth==0) {input_has_ended=1; break;} + else { + fclose(cur_file); include_depth--; + if (changing && include_depth==change_depth) break; + cur_line++; + } + } + if (!changing && !input_has_ended) + if (limit-buffer==change_limit-change_buffer) + if (buffer[0]==change_buffer[0]) + if (change_limit>change_buffer) check_change(); +} + +@ @<Read from |change_file|...@>= { + change_line++; + if (!input_ln(change_file)) { + err_print("! Change file ended without @@z"); +@.Change file ended...@> + buffer[0]='@@'; buffer[1]='z'; limit=buffer+2; + } + if (limit>buffer) { /* check if the change has ended */ + if (change_pending) { + if_section_start_make_pending(0); + if (change_pending) { + changed_section[section_count]=1; change_pending=0; + } + } + *limit=' '; + if (buffer[0]=='@@') { + if (xisupper(buffer[1])) buffer[1]=tolower(buffer[1]); + if (buffer[1]=='x' || buffer[1]=='y') { + loc=buffer+2; + err_print("! Where is the matching @@z?"); +@.Where is the match...@> + } + else if (buffer[1]=='z') { + prime_the_change_buffer(); changing=!changing; print_where=1; + } + } + } +} + +@ At the end of the program, we will tell the user if the change file +had a line that didn't match any relevant line in |web_file|. + +@c +void +check_complete(){ + if (change_limit!=change_buffer) { /* |changing| is 0 */ + strncpy(buffer,change_buffer,change_limit-change_buffer+1); + limit=buffer+(int)(change_limit-change_buffer); + changing=1; change_depth=include_depth; loc=buffer; + err_print("! Change file entry did not match"); +@.Change file entry did not match@> + } +} + +@** Storage of names and strings. +Both \.{CWEAVE} and \.{CTANGLE} store identifiers, section names and +other strings in a large array of |char|s, called |byte_mem|. +Information about the names is kept in the array |name_dir|, whose +elements are structures of type |name_info|, containing a pointer into +the |byte_mem| array (the address where the name begins) and other data. +A |name_pointer| variable is a pointer into |name_dir|. + +@d max_bytes 90000 /* the number of bytes in identifiers, + index entries, and section names; must be less than $2^{24}$ */ +@d max_names 4000 /* number of identifiers, strings, section names; + must be less than 10240 */ + +@<Definitions that...@>= +typedef struct name_info { + char *byte_start; /* beginning of the name in |byte_mem| */ + @<More elements of |name_info| structure@>@; +} name_info; /* contains information about an identifier or section name */ +typedef name_info *name_pointer; /* pointer into array of |name_info|s */ +char byte_mem[max_bytes]; /* characters of names */ +char *byte_mem_end = byte_mem+max_bytes-1; /* end of |byte_mem| */ +name_info name_dir[max_names]; /* information about names */ +name_pointer name_dir_end = name_dir+max_names-1; /* end of |name_dir| */ + +@ The actual sequence of characters in the name pointed to by a |name_pointer +p| appears in positions |p->byte_start| to |(p+1)->byte_start-1|, inclusive. +The |print_id| macro prints this text on the user's terminal. + +@d length(c) (c+1)->byte_start-(c)->byte_start /* the length of a name */ +@d print_id(c) term_write((c)->byte_start,length((c))) /* print identifier */ + +@ The first unused position in |byte_mem| and |name_dir| is +kept in |byte_ptr| and |name_ptr|, respectively. Thus we +usually have |name_ptr->byte_start==byte_ptr|, and certainly +we want to keep |name_ptr<=name_dir_end| and |byte_ptr<=byte_mem_end|. + +@<Defini...@>= +name_pointer name_ptr; /* first unused position in |byte_start| */ +char *byte_ptr; /* first unused position in |byte_mem| */ + +@ @<Init...@>= +name_dir->byte_start=byte_ptr=byte_mem; /* position zero in both arrays */ +name_ptr=name_dir+1; /* |name_dir[0]| will be used only for error recovery */ +name_ptr->byte_start=byte_mem; /* this makes name 0 of length zero */ + +@ The names of identifiers are found by computing a hash address |h| and +then looking at strings of bytes signified by the |name_pointer|s +|hash[h]|, |hash[h]->link|, |hash[h]->link->link|, \dots, +until either finding the desired name or encountering the null pointer. + +@<More elements of |name...@>= +struct name_info *link; + +@ The hash table itself +consists of |hash_size| entries of type |name_pointer|, and is +updated by the |id_lookup| procedure, which finds a given identifier +and returns the appropriate |name_pointer|. The matching is done by the +function |names_match|, which is slightly different in +\.{CWEAVE} and \.{CTANGLE}. If there is no match for the identifier, +it is inserted into the table. + +@d hash_size 353 /* should be prime */ + +@<Defini...@>= +typedef name_pointer *hash_pointer; +name_pointer hash[hash_size]; /* heads of hash lists */ +hash_pointer hash_end = hash+hash_size-1; /* end of |hash| */ +hash_pointer h; /* index into hash-head array */ + +@ @<Predec...@>= +extern int names_match(); + +@ Initially all the hash lists are empty. + +@<Init...@>= +for (h=hash; h<=hash_end; *h++=NULL) ; + +@ Here is the main procedure for finding identifiers: + +@c +name_pointer +id_lookup(first,last,t) /* looks up a string in the identifier table */ +char *first; /* first character of string */ +char *last; /* last character of string plus one */ +char t; /* the |ilk|; used by \.{CWEAVE} only */ +{ + char *i=first; /* position in |buffer| */ + int h; /* hash code */ + int l; /* length of the given identifier */ + name_pointer p; /* where the identifier is being sought */ + if (last==NULL) for (last=first; *last!='\0'; last++); + l=last-first; /* compute the length */ + @<Compute the hash code |h|@>; + @<Compute the name location |p|@>; + if (p==name_ptr) @<Enter a new name into the table at position |p|@>; + return(p); +} + +@ A simple hash code is used: If the sequence of +character codes is $c_1c_2\ldots c_n$, its hash value will be +$$(2^{n-1}c_1+2^{n-2}c_2+\cdots+c_n)\,\bmod\,|hash_size|.$$ + +@<Compute the hash...@>= +h=(unsigned char)*i; +while (++i<last) h=(h+h+(int)((unsigned char)*i)) % hash_size; +@^high-bit character handling@> + +@ If the identifier is new, it will be placed in position |p=name_ptr|, +otherwise |p| will point to its existing location. + +@<Compute the name location...@>= +p=hash[h]; +while (p && !names_match(p,first,l,t)) p=p->link; +if (p==NULL) { + p=name_ptr; /* the current identifier is new */ + p->link=hash[h]; hash[h]=p; /* insert |p| at beginning of hash list */ +} + +@ 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. + +@<Pred...@>= +void init_p(); + +@ @<Enter a new name...@>= { + if (byte_ptr+l>byte_mem_end) overflow("byte memory"); + if (name_ptr>=name_dir_end) overflow("name"); + strncpy(byte_ptr,first,l); + (++name_ptr)->byte_start=byte_ptr+=l; + if (program==cweave) init_p(p,t); +} + +@ The names of sections are stored in |byte_mem| together +with the identifier names, but a hash table is not used for them because +\.{CTANGLE} needs to be able to recognize a section name when given a prefix of +that name. A conventional binary search tree is used to retrieve section names, +with fields called |llink| and |rlink| (where |llink| takes the place +of |link|). The root of this tree is stored in |name_dir->rlink|; +this will be the only information in |name_dir[0]|. + +Since the space used by |rlink| has a different function for +identifiers than for section names, we declare it as a |union|. + +@d llink link /* left link in binary search tree for section names */ +@d rlink dummy.Rlink /* right link in binary search tree for section names */ +@d root name_dir->rlink /* the root of the binary search tree + for section names */ + +@<More elements of |name...@>= +union { + struct name_info *Rlink; /* right link in binary search tree for section + names */ + char Ilk; /* used by identifiers in \.{CWEAVE} only */ +} dummy; + +@ @<Init...@>= +root=NULL; /* the binary search tree starts out with nothing in it */ + +@ If |p| is a |name_pointer| variable, as we have seen, +|p->byte_start| is the beginning of the area where the name +corresponding to |p| is stored. However, if |p| refers to a section +name, the name may need to be stored in chunks, because it may +``grow'': a prefix of the section name may be encountered before +the full name. Furthermore we need to know the length of the shortest +prefix of the name that was ever encountered. + +We solve this problem by inserting two extra bytes at |p->byte_start|, +representing the length of the shortest prefix, when |p| is a +section name. Furthermore, the last byte of the name will be a blank +space if |p| is a prefix. In the latter case, the name pointer +|p+1| will allow us to access additional chunks of the name: +The second chunk will begin at the name pointer |(p+1)->link|, +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 prefix_length(p) (int)((unsigned char)*((p)->byte_start)*256 + + (unsigned char)*((p)->byte_start+1)) +@d set_prefix_length(p,m) (*((p)->byte_start)=(m)/256, + *((p)->byte_start+1)=(m)%256) + +@c +void +print_section_name(p) +name_pointer p; +{ + 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,ss-s); p=q->link; q=p; + } else { + term_write(s,ss+1-s); p=name_dir; q=NULL; + } + s = p->byte_start; + } + if (q) term_write("...",3); /* complete name not yet known */ +} + +@ @c +void +sprint_section_name(dest,p) + char*dest; + name_pointer p; +{ + 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; + } + strncpy(dest,s,ss-s), dest+=ss-s; + s = p->byte_start; + } + *dest='\0'; +} + +@ @c +void +print_prefix_name(p) +name_pointer p; +{ + char *s = first_chunk(p); + int l = prefix_length(p); + term_write(s,l); + if (s+l<(p+1)->byte_start) term_write("...",3); +} + +@ When we compare two section names, we'll need a function analogous to +|strcmp|. But we do not assume the strings +are null-terminated, and we keep an eye open for prefixes and extensions. + +@d less 0 /* the first name is lexicographically less than the second */ +@d equal 1 /* the first name is equal to the second */ +@d greater 2 /* the first name is lexicographically greater than the second */ +@d prefix 3 /* the first name is a proper prefix of the second */ +@d extension 4 /* the first name is a proper extension of the second */ + +@c +int web_strcmp(j,j_len,k,k_len) /* fuller comparison than |strcmp| */ + char *j, *k; /* beginning of first and second strings */ + int j_len, k_len; /* length of strings */ +{ + char *j1=j+j_len, *k1=k+k_len; + while (k<k1 && j<j1 && *j==*k) k++, j++; + if (k==k1) if (j==j1) return equal; + else return extension; + else if (j==j1) return prefix; + else if (*j<*k) return less; + else return greater; +} + +@ Adding a section name to the tree is straightforward if we know its +parent and whether it's the |rlink| or |llink| of the parent. As a +special case, when the name is the first section being added, we set the +``parent'' to |NULL|. When a section name is created, it has only one +chunk, which however may be just a prefix: the full name will +hopefully be unveiled later. Obviously, |prefix_length| starts +out as the length of the first chunk, though it may decrease later. + +The information associated with a new node must be initialized +differently in \.{CWEAVE} and \.{CTANGLE}; hence the +|init_node| procedure, which is defined differently in \.{cweave.w} +and \.{ctangle.w}. + +@<Prede...@>= +extern void init_node(); + +@ @c +name_pointer +add_section_name(par,c,first,last,ispref) /* 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; /* are we adding a prefix or a full name? */ +{ + name_pointer p=name_ptr; /* new node */ + char *s=first_chunk(p); + int name_len=last-first+ispref; /* length of section name */ + if (s+name_len>byte_mem_end) overflow("byte memory"); + if (name_ptr+1>=name_dir_end) overflow("name"); + (++name_ptr)->byte_start=byte_ptr=s+name_len; + if (ispref) { + *(byte_ptr-1)=' '; + name_len--; + name_ptr->link=name_dir; + (++name_ptr)->byte_start=byte_ptr; + } + set_prefix_length(p,name_len); + strncpy(s,first,name_len); + p->llink=NULL; + p->rlink=NULL; + init_node(p); + return par==NULL ? (root=p) : c==less ? (par->llink=p) : (par->rlink=p); +} + +@ @c +void +extend_section_name(p,first,last,ispref) +name_pointer p; /* name to be extended */ +char *first; /* beginning of extension text */ +char *last; /* one beyond end of extension text */ +int ispref; /* are we adding a prefix or a full name? */ +{ + char *s; + name_pointer q=p+1; + int name_len=last-first+ispref; + if (name_ptr>=name_dir_end) overflow("name"); + while (q->link!=name_dir) q=q->link; + q->link=name_ptr; + s=name_ptr->byte_start; + name_ptr->link=name_dir; + if (s+name_len>byte_mem_end) overflow("byte memory"); + (++name_ptr)->byte_start=byte_ptr=s+name_len; + strncpy(s,first,name_len); + if (ispref) *(byte_ptr-1)=' '; +} + +@ The |section_lookup| procedure is supposed to find a +section name that matches a new name, installing the new name if +it doesn't match an existing one. The new name is the string +between |first| and |last|; a ``match'' means that the new name +exactly equals or is a prefix or extension of a name in the tree. + +@c +name_pointer +section_lookup(first,last,ispref) /* find or install section name in tree */ +char *first, *last; /* first and last characters of new name */ +int 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 */ + 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 */ + name_pointer par=NULL; /* parent of |p|, if |r| is |NULL|; + otherwise parent of |r| */ + int name_len=last-first+1; + @<Look for matches for new name among shortest prefixes, complaining + if more than one is found@>; + @<If no match found, add new name to tree@>; + @<If one match found, check for compatibility and return match@>; +} + +@ A legal new name matches an existing section name if and only if it +matches the shortest prefix of that section name. Therefore we can +limit our search for matches to shortest prefixes, which eliminates +the need for chunk-chasing at this stage. + +@<Look for matches for new name among...@>= +while (p) { /* compare shortest prefix of |p| with new name */ + c=web_strcmp(first,name_len,first_chunk(p),prefix_length(p)); + if (c==less || c==greater) { /* new name does not match |p| */ + if (r==NULL) /* no previous matches have been found */ + par=p; + p=(c==less?p->llink:p->rlink); + } else { /* new name matches |p| */ + if (r!=NULL) { /* and also |r|: illegal */ + printf("\n! Ambiguous prefix: matches <"); +@.Ambiguous prefix ... @> + print_prefix_name(p); + printf(">\n and <"); + print_prefix_name(r); + err_print(">"); + return name_dir; /* the unsection */ + } + r=p; /* remember match */ + p=p->llink; /* try another */ + q=r->rlink; /* we'll get back here if the new |p| doesn't match */ + } + if (p==NULL) + p=q, q=NULL; /* |q| held the other branch of |r| */ +} + +@ @<If no match ...@>= + if (r==NULL) /* no matches were found */ + return add_section_name(par,c,first,last+1,ispref); + +@ Although error messages are given in anomalous cases, we do return the +unique best match when a discrepancy is found, because users often +change a title in one place while forgetting to change it elsewhere. + +@<If one match found, check for compatibility and return match@>= +switch(section_name_cmp(&first,name_len,r)) { + /* compare all of |r| with new name */ + case prefix: + if (!ispref) { + printf("\n! New name is a prefix of <"); +@.New name is a prefix...@> + print_section_name(r); + err_print(">"); + } + else if (name_len<prefix_length(r)) set_prefix_length(r,name_len); + /* fall through */ + case equal: return r; + case extension: if (!ispref || first<=last) + extend_section_name(r,first,last+1,ispref); + return r; + case bad_extension: + printf("\n! New name extends <"); +@.New name extends...@> + print_section_name(r); + err_print(">"); + return r; + default: /* no match: illegal */ + printf("\n! Section name incompatible with <"); +@.Section name incompatible...@> + print_prefix_name(r); + printf(">,\n which abbreviates <"); + print_section_name(r); + err_print(">"); + 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 +|bad_extension|, used when the string is an extension of a +supposedly already complete section name. This function has a side +effect when the comparison string is an extension: it advances the +address of the first character of the string by an amount equal to +the length of the known part of the section name. + +The name \.{@@<foo...@@>} should be an acceptable ``abbreviation'' +for \.{@@<foo@@>}. If such an abbreviation comes after the complete +name, there's no trouble recognizing it. If it comes before the +complete name, we simply append a null chunk. This logic requires +us to regard \.{@@<foo...@@>} as an ``extension'' of itself. + +@d bad_extension 5 + +@<Predec...@>= +int section_name_cmp(); + +@ @c +int section_name_cmp(pfirst,len,r) +char **pfirst; /* pointer to beginning of comparison string */ +int len; /* length of string */ +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? */ + while (1) { + ss=(r+1)->byte_start-1; + if (*ss==' ' && ss>=r->byte_start) ispref=1,q=q->link; + else ispref=0,ss++,q=name_dir; + switch(c=web_strcmp(first,len,s,ss-s)) { + case equal: if (q==name_dir) + if (ispref) { + *pfirst=first+(ss-s); + return extension; /* null extension */ + } else return equal; + else return (q->byte_start==(q+1)->byte_start)? equal: prefix; + case extension: + if (!ispref) return bad_extension; + first += ss-s; + if (q!=name_dir) {len -= ss-s; s=q->byte_start; r=q; continue;} + *pfirst=first; return extension; + default: return c; + } + } +} + +@ The last component of |name_info| is different for \.{CTANGLE} and +\.{CWEAVE}. In \.{CTANGLE}, if |p| is a pointer to a section name, +|p->equiv| is a pointer to its replacement text, an element of the +array |text_info|. In \.{CWEAVE}, on the other hand, if +|p| points to an identifier, |p->xref| is a pointer to its +list of cross-references, an element of the array |xmem|. The make-up +of |text_info| and |xmem| is discussed in the \.{CTANGLE} and \.{CWEAVE} +source files, respectively; here we just declare a common field +|equiv_or_xref| as a pointer to a |char|. + +@<More elements of |name...@>= +char *equiv_or_xref; /* info corresponding to names */ + +@** Reporting errors to the user. +A global variable called |history| will contain one of four values +at the end of every run: |spotless| means that no unusual messages were +printed; |harmless_message| means that a message of possible interest +was printed but no serious errors were detected; |error_message| means that +at least one error was found; |fatal_message| means that the program +terminated abnormally. The value of |history| does not influence the +behavior of the program; it is simply computed for the convenience +of systems that might want to use such information. + +@d spotless 0 /* |history| value for normal jobs */ +@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_error history=error_message + +@<Definit...@>= +int history=spotless; /* indicates how bad this run was */ + +@ The command `|err_print("! Error message")|' will report a syntax error to +the user, by printing the error message at the beginning of a new line and +then giving an indication of where the error was spotted in the source file. +Note that no period follows the error message, since the error routine +will automatically supply a period. A newline is automatically supplied +if the string begins with |"!"|. + +@<Predecl...@>= +void err_print(); + +@ @c +void +err_print(s) /* prints `\..' and location of error message */ +char *s; +{ + char *k,*l; /* pointers into |buffer| */ + printf(*s=='!'? "\n%s" : "%s",s); + if(web_file_open) @<Print error location based on input buffer@>; + update_terminal; mark_error; +} + +@ The error locations can be indicated by using the global variables +|loc|, |cur_line|, |cur_file_name| and |changing|, +which tell respectively the first +unlooked-at position in |buffer|, the current line number, the current +file, and whether the current line is from |change_file| or |cur_file|. +This routine should be modified on systems whose standard text editor +has special line-numbering conventions. +@^system dependencies@> + +@<Print error location based on input buffer@>= +{if (changing && include_depth==change_depth) + printf(". (l. %d of change file)\n", change_line); +else if (include_depth==0) printf(". (l. %d)\n", cur_line); + else printf(". (l. %d of include file %s)\n", cur_line, cur_file_name); +l= (loc>=limit? limit: loc); +if (l>buffer) { + for (k=buffer; k<l; k++) + if (*k=='\t') putchar(' '); + else putchar(*k); /* print the characters already read */ + putchar('\n'); + for (k=buffer; k<l; k++) putchar(' '); /* space out the next line */ +} +for (k=l; k<limit; k++) putchar(*k); /* print the part not yet read */ +if (*limit=='|') putchar('|'); /* end of \CEE/ text in section names */ +putchar(' '); /* to separate the message from future asterisks */ +} + +@ When no recovery from some error has been provided, we have to wrap +up and quit as graciously as possible. This is done by calling the +function |wrap_up| at the end of the code. + +\.{CTANGLE} and \.{CWEAVE} have their own notions about how to +print the job statistics. + +@<Prede...@>= +int wrap_up(); +extern void print_stats(); + +@ Some implementations may wish to pass the |history| value to the +operating system so that it can be used to govern whether or not other +programs are started. Here, for instance, we pass the operating system +a status of 0 if and only if only harmless messages were printed. +@^system dependencies@> + +@c +int wrap_up() { + putchar('\n'); + if (show_stats) + print_stats(); /* print statistics about memory usage */ + @<Print the job |history|@>; + if (history > harmless_message) return(1); + else return(0); +} + +@ @<Print the job |history|@>= +switch (history) { +case spotless: if (show_happiness) printf("(No errors were found.)\n"); break; +case harmless_message: + printf("(Did you see the warning message above?)\n"); break; +case error_message: + printf("(Pardon me, but I think I spotted something wrong.)\n"); break; +case fatal_message: printf("(That was a fatal error, my friend.)\n"); +} /* there are no other cases */ + +@ When there is no way to recover from an error, the |fatal| subroutine is +invoked. This happens most often when |overflow| occurs. + +@<Predec...@>= +void fatal(), overflow(); + +@ The two parameters to |fatal| are strings that are essentially +concatenated to print the final error message. + +@c void +fatal(s,t) + char *s,*t; +{ + if (*s) printf(s); + err_print(t); + history=fatal_message; exit(wrap_up()); +} + +@ An overflow stop occurs if \.{CWEB}'s tables aren't large enough. + +@c void +overflow(t) + char *t; +{ + printf("\n! Sorry, %s capacity exceeded",t); fatal("",""); +} +@.Sorry, capacity exceeded@> + +@ Sometimes the program's behavior is far different from what it should be, +and \.{CWEB} prints an error message that is really for the \.{CWEB} +maintenance person, not the user. In such cases the program says +|confusion("indication of where we are")|. + +@d confusion(s) fatal("! This can't happen: ",s) +@.This can't happen@> + +@** Command line arguments. +The user calls \.{CWEAVE} and \.{CTANGLE} with arguments on the command line. +These are either file names or flags to be turned off (beginning with |"-"|) +or flags to be turned on (beginning with |"+"|). +The following globals are for communicating the user's desires to the rest +of the program. The various file name variables contain strings with +the names of those files. Most of the 128 flags are undefined but available +for future extensions. + +@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? */ + +@<Defin...@>= +int argc; /* copy of |ac| parameter to |main| */ +char **argv; /* copy of |av| parameter to |main| */ +char C_file_name[max_file_name_length]; /* name of |C_file| */ +char tex_file_name[max_file_name_length]; /* name of |tex_file| */ +char idx_file_name[max_file_name_length]; /* name of |idx_file| */ +char scn_file_name[max_file_name_length]; /* name of |scn_file| */ +boolean flags[128]; /* an option for each 7-bit code */ + +@ The |flags| will be initially zero. Some of them are set to~1 before +scanning the arguments; if additional flags are 1 by default they +should be set before calling |common_init|. + +@<Set the default options common to \.{CTANGLE} and \.{CWEAVE}@>= +show_banner=show_happiness=show_progress=1; + +@ 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} +file. It may have an extension, or it may omit the extension to get |".w"| or +|".web"| added. The \TEX/ output file name is formed by replacing the \.{CWEB} +file name extension by |".tex"|, and the \CEE/ file name by replacing +the extension by |".c"|, after removing the directory name (if any). + +If there is a second file name present among the arguments, it is the +change file, again either with an extension or without one to get |".ch"|. +An omitted change file argument means that |"/dev/null"| should be used, +when no changes are desired. +@^system dependencies@> + +If there's a third file name, it will be the output file. + +@<Pred...@>= +void scan_args(); + +@ @c +void +scan_args() +{ + char *dot_pos; /* position of |'.'| in the argument */ + char *name_pos; /* file name beginning, sans directory */ + register char *s; /* register for scanning strings */ + boolean found_web=0,found_change=0,found_out=0; + /* have these names have been seen? */ + boolean flag_change; + + while (--argc > 0) { + if ((**(++argv)=='-'||**argv=='+')&&*(*argv+1)) @<Handle flag argument@>@; + else { + s=name_pos=*argv;@+dot_pos=NULL; + while (*s) { + if (*s=='.') dot_pos=s++; + else if (*s=='/') dot_pos=NULL,name_pos=++s; + else s++; + } + if (!found_web) @<Make + |web_file_name|, |tex_file_name| and |C_file_name|@>@; + else if (!found_change) @<Make |change_file_name| from |fname|@>@; + else if (!found_out) @<Override |tex_file_name| and |C_file_name|@>@; + else @<Print usage error message and quit@>; + } + } + if (!found_web) @<Print usage error message and quit@>; + if (found_change<=0) strcpy(change_file_name,"/dev/null"); +} + +@ We use all of |*argv| for the |web_file_name| if there is a |'.'| in it, +otherwise we add |".w"|. If this file can't be opened, we prepare an +|alt_web_file_name| by adding |"web"| after the dot. +The other file names come from adding other things +after the dot. We must check that there is enough room in +|web_file_name| and the other arrays for the argument. + +@<Make |web_file_name|...@>= +{ + if (s-*argv > max_file_name_length-5) + @<Complain about argument length@>; + if (dot_pos==NULL) + sprintf(web_file_name,"%s.w",*argv); + else { + strcpy(web_file_name,*argv); + *dot_pos=0; /* string now ends where the dot was */ + } + sprintf(alt_web_file_name,"%s.web",*argv); + sprintf(tex_file_name,"%s.tex",name_pos); /* strip off directory name */ + sprintf(idx_file_name,"%s.idx",name_pos); + sprintf(scn_file_name,"%s.scn",name_pos); + sprintf(C_file_name,"%s.c",name_pos); + found_web=1; +} + +@ @<Make |change_file_name|...@>= +{ + if (strcmp(*argv,"-")==0) found_change=-1; + else { + if (s-*argv > max_file_name_length-4) + @<Complain about argument length@>; + if (dot_pos==NULL) + sprintf(change_file_name,"%s.ch",*argv); + else strcpy(change_file_name,*argv); + found_change=1; + } +} + +@ @<Override...@>= +{ + if (s-*argv > max_file_name_length-5) + @<Complain about argument length@>; + if (dot_pos==NULL) { + sprintf(tex_file_name,"%s.tex",*argv); + sprintf(idx_file_name,"%s.idx",*argv); + sprintf(scn_file_name,"%s.scn",*argv); + sprintf(C_file_name,"%s.c",*argv); + } else { + strcpy(tex_file_name,*argv); + if (flags['x']) { /* indexes will be generated */ + if (program==cweave && strcmp(*argv+strlen(*argv)-4,".tex")!=0) + fatal("! Output file name should end with .tex\n",*argv); +@.Output file name...tex@> + strcpy(idx_file_name,*argv); + strcpy(idx_file_name+strlen(*argv)-4,".idx"); + strcpy(scn_file_name,*argv); + strcpy(scn_file_name+strlen(*argv)-4,".scn"); + } + strcpy(C_file_name,*argv); + } + found_out=1; +} + +@ @<Handle flag...@>= +{ + if (**argv=='-') flag_change=0; + else flag_change=1; + for(dot_pos=*argv+1;*dot_pos>'\0';dot_pos++) + flags[*dot_pos]=flag_change; +} + +@ @<Print usage error message and quit@>= +{ +if (program==ctangle) + fatal( +"! Usage: ctangle [options] webfile[.w] [{changefile[.ch]|-} [outfile[.c]]]\n" + ,""); +@.Usage:@> +else fatal( +"! Usage: cweave [options] webfile[.w] [{changefile[.ch]|-} [outfile[.tex]]]\n" + ,""); +} + +@ @<Complain about arg...@>= fatal("! Filename too long\n", *argv); +@.Filename too long@> + +@** Output. Here is the code that opens the output file: +@^system dependencies@> + +@<Defin...@>= +FILE *C_file; /* where output of \.{CTANGLE} goes */ +FILE *tex_file; /* where output of \.{CWEAVE} goes */ +FILE *idx_file; /* where index from \.{CWEAVE} goes */ +FILE *scn_file; /* where list of sections from \.{CWEAVE} goes */ +FILE *active_file; /* currently active file for \.{CWEAVE} output */ + +@ @<Scan arguments and open output files@>= +scan_args(); +if (program==ctangle) { + if ((C_file=fopen(C_file_name,"w"))==NULL) + fatal("! Cannot open output file ", C_file_name); +@.Cannot open output file@> +} +else { + if ((tex_file=fopen(tex_file_name,"w"))==NULL) + fatal("! Cannot open output file ", tex_file_name); +} + +@ The |update_terminal| procedure is called when we want +to make sure that everything we have output to the terminal so far has +actually left the computer's internal buffers and been sent. +@^system dependencies@> + +@d update_terminal fflush(stdout) /* empty the terminal output buffer */ + +@ Terminal output uses |putchar| and |putc| when we have to +translate from \.{CWEB}'s code into the external character code, +and |printf| when we just want to print strings. +Several macros make other kinds of output convenient. +@^system dependencies@> +@d new_line putchar('\n') @d putxchar putchar +@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? */ + +@ We predeclare several standard system functions here instead of including +their system header files, because the names of the header files are not as +standard as the names of the functions. (For example, some \CEE/ environments +have \.{<string.h>} where others have \.{<strings.h>}.) + +@<Predecl...@>= +extern int strlen(); /* length of string */ +extern int strcmp(); /* compare strings lexicographically */ +extern char* strcpy(); /* copy one string to another */ +extern int strncmp(); /* compare up to $n$ string characters */ +extern char* strncpy(); /* copy up to $n$ string characters */ + +@** Index. diff --git a/web/c_cpp/c2cweb/cweb/cweave.c b/web/c_cpp/c2cweb/cweb/cweave.c new file mode 100644 index 0000000000..bff742feb7 --- /dev/null +++ b/web/c_cpp/c2cweb/cweb/cweave.c @@ -0,0 +1,4543 @@ +/*1:*/ +#line 66 "cweave.w" +/*6:*/ +#line 38 "common.h" + +#include <stdio.h> + +/*:6*//*38:*/ +#line 644 "cweave.w" + +#include <ctype.h> +#include <stdlib.h> + +/*:38*/ +#line 66 "cweave.w" + +#define banner "This is CWEAVE (Version 3.4) modified by Werner Lemberg (V1.5)\n" \ + +#define max_bytes 225000 \ + +#define max_names 10000 \ + +#define max_sections 2000 +#define hash_size 353 +#define buf_size 400 +#define longest_name 1000 +#define long_buf_size (buf_size+longest_name) +#define line_length 100 \ + +#define max_refs 20000 +#define max_toks 65000 \ + +#define max_texts 10200 \ + +#define max_scraps 65000 +#define stack_size 10000 \ + +#define ctangle 0 +#define cweave 1 \ + +#define and_and 04 +#define lt_lt 020 +#define gt_gt 021 +#define plus_plus 013 +#define minus_minus 01 +#define minus_gt 031 +#define not_eq 032 +#define lt_eq 034 +#define gt_eq 035 +#define eq_eq 036 +#define or_or 037 +#define dot_dot_dot 016 +#define colon_colon 06 +#define period_ast 026 +#define minus_gt_ast 027 \ + +#define xisalpha(c) (isalpha(c) &&((eight_bits) c<0200) ) +#define xisdigit(c) (isdigit(c) &&((eight_bits) c<0200) ) +#define xisspace(c) (isspace(c) &&((eight_bits) c<0200) ) +#define xislower(c) (islower(c) &&((eight_bits) c<0200) ) +#define xisupper(c) (isupper(c) &&((eight_bits) c<0200) ) +#define xisxdigit(c) (isxdigit(c) &&((eight_bits) c<0200) ) \ + +#define length(c) (c+1) ->byte_start-(c) ->byte_start +#define print_id(c) term_write((c) ->byte_start,length((c) ) ) +#define llink link +#define rlink dummy.Rlink +#define root name_dir->rlink \ + +#define chunk_marker 0 \ + +#define spotless 0 +#define harmless_message 1 +#define error_message 2 +#define fatal_message 3 +#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 max_file_name_length 60 +#define cur_file file[include_depth] +#define cur_file_name file_name[include_depth] +#define web_file_name file_name[0] +#define cur_line line[include_depth] \ + +#define show_banner flags['b'] +#define show_progress flags['p'] +#define show_happiness flags['h'] \ + +#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 ilk dummy.dummy1.Ilk +#define func_flag dummy.dummy1.Func_flag +#define normal 0 +#define roman 1 +#define wildcard 2 +#define typewriter 3 +#define abnormal(a) (a->ilk>typewriter) +#define custom 4 +#define unindexed(a) (a->ilk>custom) +#define quoted 5 +#define else_like 26 +#define public_like 40 +#define operator_like 41 +#define new_like 42 +#define catch_like 43 +#define for_like 45 +#define do_like 46 +#define if_like 47 +#define raw_rpar 48 +#define raw_unorbin 49 +#define const_like 50 +#define raw_int 51 +#define int_like 52 +#define case_like 53 +#define sizeof_like 54 +#define struct_like 55 +#define typedef_like 56 +#define define_like 57 \ + +#define file_flag (3*cite_flag) +#define def_flag (2*cite_flag) +#define cite_flag 10240 +#define xref equiv_or_xref \ + +#define append_xref(c) if(xref_ptr==xmem_end) overflow("cross-reference") ; \ +else(++xref_ptr) ->num= c; +#define no_xref (flags['x']==0) +#define make_xrefs flags['x'] +#define is_tiny(p) ((p+1) ->byte_start==(p) ->byte_start+1) \ + +#define ignore 00 +#define verbatim 02 +#define begin_short_comment 03 +#define begin_comment '\t' +#define underline '\n' +#define noop 0177 +#define xref_roman 0203 +#define xref_wildcard 0204 +#define xref_typewriter 0205 +#define TeX_string 0206 +#define ord 0207 +#define join 0210 +#define thin_space 0211 +#define math_break 0212 +#define line_break 0213 +#define big_line_break 0214 +#define no_line_break 0215 +#define pseudo_semi 0216 +#define macro_arg_open 0220 +#define macro_arg_close 0221 +#define trace 0222 +#define translit_code 0223 +#define output_defs_code 0224 +#define format_code 0225 +#define definition 0226 +#define begin_C 0227 +#define section_name 0230 +#define new_section 0231 +#define pseudo_lbrace 022 +#define pseudo_rbrace 023 \ + +#define constant 0200 +#define string 0201 +#define identifier 0202 \ + +#define isxalpha(c) ((c) =='_'||(c) =='$') \ + +#define ishigh(c) ((eight_bits) (c) >0177) \ + \ + +#define left_preproc ord +#define right_preproc 0217 +#define preproc_space '\b' +#define numb_numb '\f' \ + +#define compress(c) if(loc++<=limit) return(c) \ + +#define c_line_write(c) fflush(active_file) ,fwrite(out_buf+1,sizeof(char) ,c,active_file) +#define tex_putc(c) putc(c,active_file) +#define tex_new_line putc('\n',active_file) +#define tex_printf(c) fprintf(active_file,c) \ + +#define app_tok(c) {if(tok_ptr+2>tok_mem_end) overflow("token") ;*(tok_ptr++) = c;} \ + +#define exp 1 +#define unop 2 +#define binop 3 +#define unorbinop 4 \ + +#define cast 5 +#define question 6 +#define lbrace 7 +#define rbrace 8 +#define decl_head 9 +#define comma 10 +#define lpar 11 +#define rpar 12 +#define prelangle 13 +#define prerangle 14 +#define langle 15 +#define colcol 18 +#define base 19 +#define decl 20 +#define struct_head 21 +#define stmt 23 +#define function 24 +#define fn_decl 25 +#define semi 27 +#define colon 28 +#define tag 29 \ + +#define if_head 30 +#define else_head 31 +#define if_clause 32 +#define lproc 35 +#define rproc 36 +#define insert 37 +#define section_scrap 38 +#define dead 39 +#define begin_arg 58 +#define end_arg 59 +#define label 60 +#define do_head 61 +#define pp_space 62 \ + +#define math_rel 0206 +#define big_cancel 0210 +#define cancel 0211 +#define indent 0212 +#define outdent 0213 +#define opt 0214 +#define backup 0215 +#define break_space 0216 +#define force 0217 +#define big_force 0220 +#define preproc_line 0221 \ + +#define quoted_char 0222 \ + +#define end_translation 0223 +#define inserted 0224 \ + +#define trans trans_plus.Trans \ + +#define id_flag 10240 +#define res_flag 2*id_flag +#define section_flag 3*id_flag +#define tok_flag 4*id_flag +#define inner_tok_flag 5*id_flag \ + +#define no_math 2 +#define yes_math 1 +#define maybe_math 0 +#define big_app2(a) big_app1(a) ;big_app1(a+1) +#define big_app3(a) big_app2(a) ;big_app1(a+2) +#define big_app4(a) big_app3(a) ;big_app1(a+3) +#define app(a) *(tok_ptr++) = a +#define app1(a) *(tok_ptr++) = tok_flag+(int) ((a) ->trans-tok_start) \ + +#define cat1 (pp+1) ->cat +#define cat2 (pp+2) ->cat +#define cat3 (pp+3) ->cat +#define lhs_not_simple (pp->cat!=semi&&pp->cat!=raw_int&&pp->cat!=raw_unorbin \ +&&pp->cat!=raw_rpar&&pp->cat!=const_like) \ + +#define no_ident_found 0 \ + +#define force_lines flags['f'] +#define freeze_text *(++text_ptr) = tok_ptr \ + +#define safe_tok_incr 20 +#define safe_text_incr 10 +#define safe_scrap_incr 10 \ + +#define app_scrap(c,b) { \ +(++scrap_ptr) ->cat= (c) ;scrap_ptr->trans= text_ptr; \ +scrap_ptr->mathness= 5*(b) ; \ +freeze_text; \ +} \ + +#define alternative flags['a'] +#define func_index flags['i'] \ + \ + +#define inner 0 +#define outer 1 \ + +#define cur_end cur_state.end_field +#define cur_tok cur_state.tok_field +#define cur_mode cur_state.mode_field +#define init_stack stack_ptr= stack;cur_mode= outer \ + +#define res_word 0201 +#define section_code 0200 \ + +#define save_position save_line= out_line;save_place= out_ptr +#define emit_space_if_needed if(save_line!=out_line||save_place!=out_ptr) \ +out_str("\\Y") ; \ +space_checked= 1 \ + \ + +#define depth cat +#define head trans_plus.Head +#define sort_pointer scrap_pointer +#define sort_ptr scrap_ptr +#define max_sorts max_scraps \ + +#define infinity 255 \ + + +#line 67 "cweave.w" + +/*5:*/ +#line 32 "common.h" + +typedef short boolean; +typedef char unsigned eight_bits; +extern boolean program; +extern int phase; + +/*:5*//*7:*/ +#line 60 "common.h" + +char section_text[longest_name+1]; +char*section_text_end= section_text+longest_name; +char*id_first; +char*id_loc; + +/*:7*//*8:*/ +#line 75 "common.h" + +extern char buffer[]; +extern char*buffer_end; +extern char*loc; +extern char*limit; + +/*:8*//*9:*/ +#line 90 "common.h" + +typedef struct name_info{ +char*byte_start; +struct name_info*link; +union{ +struct name_info*Rlink; + +struct{ +char Ilk; +boolean Func_flag; +}dummy1; +}dummy; +char*equiv_or_xref; +}name_info; +typedef name_info*name_pointer; +typedef name_pointer*hash_pointer; +extern char byte_mem[]; +extern char*byte_mem_end; +extern name_info name_dir[]; +extern name_pointer name_dir_end; +extern name_pointer name_ptr; +extern char*byte_ptr; +extern name_pointer hash[]; +extern hash_pointer hash_end; +extern hash_pointer h; +extern name_pointer id_lookup(); +extern name_pointer section_lookup(); +extern void print_section_name(),sprint_section_name(); + +/*:9*//*10:*/ +#line 128 "common.h" + +extern history; +extern err_print(); +extern wrap_up(); +extern void fatal(); +extern void overflow(); + +/*:10*//*11:*/ +#line 143 "common.h" + +extern include_depth; +extern FILE*file[]; +extern FILE*change_file; +extern char C_file_name[]; +extern char tex_file_name[]; +extern char idx_file_name[]; +extern char scn_file_name[]; +extern char file_name[][max_file_name_length]; + +extern char change_file_name[]; +extern line[]; +extern change_line; +extern boolean input_has_ended; +extern boolean changing; +extern boolean web_file_open; +extern reset_input(); +extern get_line(); +extern check_complete(); + +/*:11*//*12:*/ +#line 164 "common.h" + +typedef unsigned short sixteen_bits; +extern sixteen_bits section_count; +extern boolean changed_section[]; +extern boolean change_pending; +extern boolean print_where; + +/*:12*//*13:*/ +#line 176 "common.h" + +extern int argc; +extern char**argv; +extern boolean flags[]; + +/*:13*//*14:*/ +#line 188 "common.h" + +extern FILE*C_file; +extern FILE*tex_file; +extern FILE*idx_file; +extern FILE*scn_file; +extern FILE*active_file; + +/*:14*//*15:*/ +#line 197 "common.h" + +extern void common_init(); + + + +#line 140 "cweave.w" + +/*:15*/ +#line 68 "cweave.w" + +/*18:*/ +#line 222 "cweave.w" + +typedef struct xref_info{ +sixteen_bits num; +struct xref_info*xlink; +}xref_info; +typedef xref_info*xref_pointer; + +/*:18*//*24:*/ +#line 332 "cweave.w" + +typedef sixteen_bits token; +typedef token*token_pointer; +typedef token_pointer*text_pointer; + +/*:24*//*103:*/ +#line 2012 "cweave.w" + +typedef struct{ +eight_bits cat; +eight_bits mathness; +union{ +text_pointer Trans; +/*231:*/ +#line 4257 "cweave.w" + +name_pointer Head; + +/*:231*/ +#line 2018 "cweave.w" + +}trans_plus; +}scrap; +typedef scrap*scrap_pointer; + +/*:103*//*185:*/ +#line 3412 "cweave.w" +typedef int mode; +typedef struct{ +token_pointer end_field; +token_pointer tok_field; +boolean mode_field; +}output_state; +typedef output_state*stack_pointer; + +/*:185*/ +#line 69 "cweave.w" + +/*17:*/ +#line 197 "cweave.w" + +boolean change_exists; + +/*:17*//*19:*/ +#line 229 "cweave.w" + +xref_info xmem[max_refs]; +xref_pointer xmem_end= xmem+max_refs-1; +xref_pointer xref_ptr; +sixteen_bits xref_switch,section_xref_switch; + +/*:19*//*25:*/ +#line 342 "cweave.w" + +token tok_mem[max_toks]; +token_pointer tok_mem_end= tok_mem+max_toks-1; +token_pointer tok_start[max_texts]; +token_pointer tok_ptr; +text_pointer text_ptr; +text_pointer tok_start_end= tok_start+max_texts-1; +token_pointer max_tok_ptr; +text_pointer max_text_ptr; + +/*:25*//*31:*/ +#line 521 "cweave.w" + +eight_bits ccode[256]; + +/*:31*//*37:*/ +#line 640 "cweave.w" + +name_pointer cur_section; +char cur_section_char; + +/*:37*//*41:*/ +#line 214 "cweave.ch" + +boolean preprocessing= 0; +int define_pos= 0; + +#line 695 "cweave.w" + +/*:41*//*43:*/ +#line 706 "cweave.w" + +boolean sharp_include_line= 0; + +/*:43*//*58:*/ +#line 980 "cweave.w" + +eight_bits next_control; + +/*:58*//*68:*/ +#line 1136 "cweave.w" + +name_pointer lhs,rhs; + +/*:68*//*73:*/ +#line 1219 "cweave.w" + +xref_pointer cur_xref; +boolean an_output; + +/*:73*//*77:*/ +#line 1261 "cweave.w" + +char out_buf[line_length+1]; +char*out_ptr; +char*out_buf_end= out_buf+line_length; +#line 268 "cweave.ch" +int out_line; + +boolean in_math= 0; +boolean escape= 0; +int math_brace_count= 0; +#line 1266 "cweave.w" + +/*:77*//*97:*/ +#line 1670 "cweave.w" + +char cat_name[256][12]; +eight_bits cat_index; + +/*:97*//*104:*/ +#line 2025 "cweave.w" + +scrap scrap_info[max_scraps]; +scrap_pointer scrap_info_end= scrap_info+max_scraps-1; +scrap_pointer pp; +scrap_pointer scrap_base; +scrap_pointer scrap_ptr; +scrap_pointer lo_ptr; +scrap_pointer hi_ptr; +scrap_pointer max_scr_ptr; + +/*:104*//*108:*/ +#line 2184 "cweave.w" + +int cur_mathness,init_mathness; + +/*:108*//*167:*/ +#line 2962 "cweave.w" + +int tracing; + +/*:167*//*186:*/ +#line 3425 "cweave.w" + +output_state cur_state; +output_state stack[stack_size]; +stack_pointer stack_ptr; +stack_pointer stack_end= stack+stack_size-1; +stack_pointer max_stack_ptr; + +/*:186*//*190:*/ +#line 3475 "cweave.w" + +name_pointer cur_name; + +/*:190*//*206:*/ +#line 3831 "cweave.w" + +int save_line; +char*save_place; +int sec_depth; +boolean space_checked; +boolean format_visible; +boolean doing_format= 0; +boolean group_found= 0; + +/*:206*//*215:*/ +#line 4014 "cweave.w" + +name_pointer this_section; + +/*:215*//*226:*/ +#line 4198 "cweave.w" + +sixteen_bits k_section; + +/*:226*//*228:*/ +#line 4224 "cweave.w" + +name_pointer bucket[256]; +name_pointer next_name; +name_pointer blink[max_names]; + +/*:228*//*232:*/ +#line 4267 "cweave.w" + +eight_bits cur_depth; +char*cur_byte; +sixteen_bits cur_val; +sort_pointer max_sort_ptr; + +/*:232*//*234:*/ +#line 4279 "cweave.w" + +eight_bits collate[102+128]; + + +/*:234*//*243:*/ +#line 4432 "cweave.w" + +xref_pointer next_xref,this_xref; + + +/*:243*/ +#line 70 "cweave.w" + +/*2:*/ +#line 78 "cweave.w" + +extern int strlen(); +extern int strcmp(); +extern char*strcpy(); +extern int strncmp(); +extern char*strncpy(); + +/*:2*//*34:*/ +#line 562 "cweave.w" + +void skip_limbo(); + +/*:34*//*39:*/ +#line 655 "cweave.w" + +eight_bits get_next(); + +/*:39*//*55:*/ +#line 933 "cweave.w" + +void skip_restricted(); + +/*:55*//*59:*/ +#line 986 "cweave.w" + +void phase_one(); + +/*:59*//*62:*/ +#line 1038 "cweave.w" + +void C_xref(); + +/*:62*//*64:*/ +#line 1066 "cweave.w" + +void outer_xref(); + +/*:64*//*74:*/ +#line 1227 "cweave.w" + +void section_check(); + +/*:74*//*83:*/ +#line 1363 "cweave.w" + +void break_out(); + +/*:83*//*91:*/ +#line 1506 "cweave.w" + +int copy_comment(); + +/*:91*//*114:*/ +#line 2388 "cweave.w" + +void underline_xref(); + +/*:114*//*180:*/ +#line 3289 "cweave.w" + +void app_cur_id(); + +/*:180*//*193:*/ +#line 3544 "cweave.w" + +void make_output(); + +/*:193*//*204:*/ +#line 3804 "cweave.w" + +void phase_two(); + +/*:204*//*211:*/ +#line 3927 "cweave.w" + +void finish_C(); + +/*:211*//*220:*/ +#line 4098 "cweave.w" + +void footnote(); + +/*:220*//*224:*/ +#line 4147 "cweave.w" + +void phase_three(); + +/*:224*//*236:*/ +#line 4327 "cweave.w" + +void unbucket(); + +/*:236*//*245:*/ +#line 4447 "cweave.w" + +void section_print(); + +/*:245*/ +#line 71 "cweave.w" + + +/*:1*//*3:*/ +#line 93 "cweave.w" + +int main(ac,av) +int ac; +char**av; +{ +argc= ac;argv= av; +program= cweave; +make_xrefs= force_lines= 1; +common_init(); +/*20:*/ +#line 243 "cweave.w" + +xref_ptr= xmem;name_dir->xref= (char*)xmem;xref_switch= 0;section_xref_switch= 0; +xmem->num= 0; + +/*:20*//*26:*/ +#line 352 "cweave.w" + +tok_ptr= tok_mem+1;text_ptr= tok_start+1;tok_start[0]= tok_mem+1; +tok_start[1]= tok_mem+1; +max_tok_ptr= tok_mem+1;max_text_ptr= tok_start+1; + +/*:26*//*32:*/ +#line 524 "cweave.w" + +{int c;for(c= 0;c<256;c++)ccode[c]= 0;} +ccode[' ']= ccode['\t']= ccode['\n']= ccode['\v']= ccode['\r']= ccode['\f'] += ccode['*']= new_section; +ccode['@']= '@'; +ccode['=']= verbatim; +ccode['d']= ccode['D']= definition; +ccode['f']= ccode['F']= ccode['s']= ccode['S']= format_code; +ccode['c']= ccode['C']= ccode['p']= ccode['P']= begin_C; +ccode['t']= ccode['T']= TeX_string; +ccode['l']= ccode['L']= translit_code; +ccode['q']= ccode['Q']= noop; +ccode['h']= ccode['H']= output_defs_code; +ccode['&']= join;ccode['<']= ccode['(']= section_name; +ccode['!']= underline;ccode['^']= xref_roman; +ccode[':']= xref_wildcard;ccode['.']= xref_typewriter;ccode[',']= thin_space; +ccode['|']= math_break;ccode['/']= line_break;ccode['#']= big_line_break; +#line 117 "cweave.ch" +ccode['+']= no_line_break;ccode[';']= pseudo_semi; +ccode['{']= pseudo_lbrace;ccode['}']= pseudo_rbrace; +ccode['[']= macro_arg_open;ccode[']']= macro_arg_close; +#line 543 "cweave.w" +ccode['\'']= ord; +/*33:*/ +#line 550 "cweave.w" + +ccode['0']= ccode['1']= ccode['2']= trace; + +/*:33*/ +#line 544 "cweave.w" + + +/*:32*//*52:*/ +#line 888 "cweave.w" +section_text[0]= ' '; + +/*:52*//*80:*/ +#line 1330 "cweave.w" + +#line 281 "cweave.ch" +out_ptr= out_buf+1;out_line= 1;active_file= tex_file; +if(alternative){ +*out_ptr= 'a'; +tex_printf("\\input cwebmac"); +}else{ +*out_ptr= 'c'; +tex_printf("\\input cwebma"); +} +#line 1333 "cweave.w" + +/*:80*//*82:*/ +#line 1356 "cweave.w" + +out_buf[0]= '\\'; + +/*:82*//*98:*/ +#line 1674 "cweave.w" + +for(cat_index= 0;cat_index<255;cat_index++) +strcpy(cat_name[cat_index],"UNKNOWN"); +strcpy(cat_name[exp],"exp"); +strcpy(cat_name[unop],"unop"); +strcpy(cat_name[binop],"binop"); +strcpy(cat_name[unorbinop],"unorbinop"); +strcpy(cat_name[cast],"cast"); +strcpy(cat_name[question],"?"); +strcpy(cat_name[lbrace],"{"); +strcpy(cat_name[rbrace],"}"); +strcpy(cat_name[decl_head],"decl_head"); +strcpy(cat_name[comma],","); +strcpy(cat_name[lpar],"("); +strcpy(cat_name[rpar],")"); +strcpy(cat_name[prelangle],"<"); +strcpy(cat_name[prerangle],">"); +strcpy(cat_name[langle],"\\<"); +strcpy(cat_name[colcol],"::"); +strcpy(cat_name[base],"\\:"); +strcpy(cat_name[decl],"decl"); +strcpy(cat_name[struct_head],"struct_head"); +strcpy(cat_name[stmt],"stmt"); +strcpy(cat_name[function],"function"); +strcpy(cat_name[fn_decl],"fn_decl"); +strcpy(cat_name[else_like],"else_like"); +strcpy(cat_name[semi],";"); +strcpy(cat_name[colon],":"); +strcpy(cat_name[tag],"tag"); +strcpy(cat_name[if_head],"if_head"); +strcpy(cat_name[else_head],"else_head"); +strcpy(cat_name[if_clause],"if()"); +strcpy(cat_name[lproc],"#{"); +strcpy(cat_name[rproc],"#}"); +strcpy(cat_name[insert],"insert"); +strcpy(cat_name[section_scrap],"section"); +strcpy(cat_name[dead],"@d"); +strcpy(cat_name[public_like],"public"); +strcpy(cat_name[operator_like],"operator"); +strcpy(cat_name[new_like],"new"); +strcpy(cat_name[catch_like],"catch"); +strcpy(cat_name[for_like],"for"); +strcpy(cat_name[do_like],"do"); +strcpy(cat_name[if_like],"if"); +strcpy(cat_name[raw_rpar],")?"); +strcpy(cat_name[raw_unorbin],"unorbinop?"); +strcpy(cat_name[const_like],"const"); +strcpy(cat_name[raw_int],"raw"); +strcpy(cat_name[int_like],"int"); +strcpy(cat_name[case_like],"case"); +strcpy(cat_name[sizeof_like],"sizeof"); +strcpy(cat_name[struct_like],"struct"); +strcpy(cat_name[typedef_like],"typedef"); +strcpy(cat_name[define_like],"define"); +strcpy(cat_name[begin_arg],"@["); +#line 362 "cweave.ch" +strcpy(cat_name[end_arg],"@]"); +strcpy(cat_name[label],"label"); +strcpy(cat_name[do_head],"do_head"); +strcpy(cat_name[pp_space],"#_"); +#line 1730 "cweave.w" +strcpy(cat_name[0],"zero"); + +/*:98*//*105:*/ +#line 2035 "cweave.w" + +scrap_base= scrap_info+1; +max_scr_ptr= scrap_ptr= scrap_info; + +/*:105*//*187:*/ +#line 3432 "cweave.w" + +max_stack_ptr= stack; + +/*:187*//*233:*/ +#line 4273 "cweave.w" + +max_sort_ptr= scrap_info; + +/*:233*//*235:*/ +#line 4292 "cweave.w" + +collate[0]= 0; +strcpy(collate+1," \1\2\3\4\5\6\7\10\11\12\13\14\15\16\17"); + +strcpy(collate+17,"\20\21\22\23\24\25\26\27\30\31\32\33\34\35\36\37"); + +strcpy(collate+33,"!\42#$%&'()*+,-./:;<=>?@[\\]^`{|}~_"); + +strcpy(collate+65,"abcdefghijklmnopqrstuvwxyz0123456789"); + +strcpy(collate+101,"\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"); + +strcpy(collate+117,"\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237"); + +strcpy(collate+133,"\240\241\242\243\244\245\246\247\250\251\252\253\254\255\256\257"); + +strcpy(collate+149,"\260\261\262\263\264\265\266\267\270\271\272\273\274\275\276\277"); + +strcpy(collate+165,"\300\301\302\303\304\305\306\307\310\311\312\313\314\315\316\317"); + +strcpy(collate+181,"\320\321\322\323\324\325\326\327\330\331\332\333\334\335\336\337"); + +strcpy(collate+197,"\340\341\342\343\344\345\346\347\350\351\352\353\354\355\356\357"); + +strcpy(collate+213,"\360\361\362\363\364\365\366\367\370\371\372\373\374\375\376\377"); + + +/*:235*/ +#line 102 "cweave.w" +; +if(show_banner)printf(banner); +/*28:*/ +#line 392 "cweave.w" + +id_lookup("asm",NULL,sizeof_like); +id_lookup("auto",NULL,int_like); +id_lookup("break",NULL,case_like); +id_lookup("case",NULL,case_like); +id_lookup("catch",NULL,catch_like); +id_lookup("char",NULL,raw_int); +id_lookup("class",NULL,struct_like); +id_lookup("clock_t",NULL,raw_int); +id_lookup("const",NULL,const_like); +id_lookup("continue",NULL,case_like); +id_lookup("default",NULL,case_like); +id_lookup("define",NULL,define_like); +id_lookup("defined",NULL,sizeof_like); +id_lookup("delete",NULL,sizeof_like); +id_lookup("div_t",NULL,raw_int); +id_lookup("do",NULL,do_like); +id_lookup("double",NULL,raw_int); +id_lookup("elif",NULL,if_like); +id_lookup("else",NULL,else_like); +id_lookup("endif",NULL,if_like); +id_lookup("enum",NULL,struct_like); +id_lookup("error",NULL,if_like); +id_lookup("extern",NULL,int_like); +id_lookup("FILE",NULL,raw_int); +id_lookup("float",NULL,raw_int); +id_lookup("for",NULL,for_like); +id_lookup("fpos_t",NULL,raw_int); +id_lookup("friend",NULL,int_like); +id_lookup("goto",NULL,case_like); +id_lookup("if",NULL,if_like); +id_lookup("ifdef",NULL,if_like); +id_lookup("ifndef",NULL,if_like); +id_lookup("include",NULL,if_like); +id_lookup("inline",NULL,int_like); +id_lookup("int",NULL,raw_int); +id_lookup("jmp_buf",NULL,raw_int); +id_lookup("ldiv_t",NULL,raw_int); +id_lookup("line",NULL,if_like); +id_lookup("long",NULL,raw_int); +id_lookup("new",NULL,new_like); +id_lookup("NULL",NULL,quoted); +id_lookup("offsetof",NULL,sizeof_like); +id_lookup("operator",NULL,operator_like); +id_lookup("pragma",NULL,if_like); +id_lookup("private",NULL,public_like); +id_lookup("protected",NULL,public_like); +id_lookup("ptrdiff_t",NULL,raw_int); +id_lookup("public",NULL,public_like); +id_lookup("register",NULL,int_like); +id_lookup("return",NULL,case_like); +id_lookup("short",NULL,raw_int); +id_lookup("sig_atomic_t",NULL,raw_int); +id_lookup("signed",NULL,raw_int); +id_lookup("size_t",NULL,raw_int); +id_lookup("sizeof",NULL,sizeof_like); +id_lookup("static",NULL,int_like); +id_lookup("struct",NULL,struct_like); +id_lookup("switch",NULL,for_like); +id_lookup("template",NULL,int_like); +id_lookup("TeX",NULL,custom); +id_lookup("this",NULL,quoted); +id_lookup("throw",NULL,case_like); +id_lookup("time_t",NULL,raw_int); +id_lookup("try",NULL,else_like); +id_lookup("typedef",NULL,typedef_like); +id_lookup("undef",NULL,if_like); +id_lookup("union",NULL,struct_like); +id_lookup("unsigned",NULL,raw_int); +id_lookup("va_dcl",NULL,decl); +id_lookup("va_list",NULL,raw_int); +id_lookup("virtual",NULL,int_like); +id_lookup("void",NULL,raw_int); +id_lookup("volatile",NULL,const_like); +id_lookup("wchar_t",NULL,raw_int); +id_lookup("while",NULL,for_like); + +/*:28*/ +#line 104 "cweave.w" +; +phase_one(); +phase_two(); +phase_three(); +return wrap_up(); +} + +/*:3*//*21:*/ +#line 262 "cweave.w" + +void +new_xref(p) +name_pointer p; +{ +xref_pointer q; +sixteen_bits m,n; +if(no_xref)return; +if((unindexed(p)||is_tiny(p))&&xref_switch==0)return; +m= section_count+xref_switch;xref_switch= 0;q= (xref_pointer)p->xref; +if(q!=xmem){ +n= q->num; +if(n==m||n==m+def_flag)return; +else if(m==n+def_flag){ +q->num= m;return; +} +} +append_xref(m);xref_ptr->xlink= q;p->xref= (char*)xref_ptr; +} + +/*:21*//*22:*/ +#line 293 "cweave.w" + +void +new_section_xref(p) +name_pointer p; +{ +xref_pointer q,r; +q= (xref_pointer)p->xref;r= xmem; +if(q>xmem) +while(q->num>section_xref_switch){r= q;q= q->xlink;} +if(r->num==section_count+section_xref_switch) +return; +append_xref(section_count+section_xref_switch); +xref_ptr->xlink= q;section_xref_switch= 0; +if(r==xmem)p->xref= (char*)xref_ptr; +else r->xlink= xref_ptr; +} + +/*:22*//*23:*/ +#line 313 "cweave.w" + +void +set_file_flag(p) +name_pointer p; +{ +xref_pointer q; +q= (xref_pointer)p->xref; +if(q->num==file_flag)return; +append_xref(file_flag); +xref_ptr->xlink= q; +p->xref= (char*)xref_ptr; +} + +/*:23*//*27:*/ +#line 358 "cweave.w" + +int names_match(p,first,l,t) +name_pointer p; +char*first; +int l; +eight_bits t; +{ +if(length(p)!=l)return 0; +if(p->ilk!=t&&!(t==normal&&abnormal(p)))return 0; +return!strncmp(first,p->byte_start,l); +} + +void +init_p(p,t) +name_pointer p; +eight_bits t; +{ +p->ilk= t;p->xref= (char*)xmem; +} + +void +init_node(p) +name_pointer p; +{ +p->xref= (char*)xmem; +} + +/*:27*//*35:*/ +#line 565 "cweave.w" + +void +skip_limbo(){ +while(1){ +if(loc>limit&&get_line()==0)return; +*(limit+1)= '@'; +while(*loc!='@')loc++; +if(loc++<=limit){int c= ccode[(eight_bits)*loc++]; +if(c==new_section)return; +if(c==noop)skip_restricted(); +else if(c==format_code)/*71:*/ +#line 1180 "cweave.w" + +{ +if(get_next()!=identifier) +err_print("! Missing left identifier of @s"); + +else{ +lhs= id_lookup(id_first,id_loc,normal); +if(get_next()!=identifier) +err_print("! Missing right identifier of @s"); + +else{ +rhs= id_lookup(id_first,id_loc,normal); +lhs->ilk= rhs->ilk; +} +} +} + +/*:71*/ +#line 575 "cweave.w" +; +} +} +} + +/*:35*//*36:*/ +#line 587 "cweave.w" + +unsigned +skip_TeX() +{ +while(1){ +if(loc>limit&&get_line()==0)return(new_section); +*(limit+1)= '@'; +while(*loc!='@'&&*loc!='|')loc++; +if(*loc++=='|')return('|'); +if(loc<=limit)return(ccode[(eight_bits)*(loc++)]); +} +} + +/*:36*//*40:*/ +#line 658 "cweave.w" + +#line 155 "cweave.ch" +eight_bits +get_next() +{eight_bits c; +int blank_count= 0; + +if(loc<limit&&preprocessing&&(define_pos==2||define_pos==4)&& +xisspace(*loc)){ +define_pos= 5; +return(preproc_space); +} + +while(1){ +/*45:*/ +#line 717 "cweave.w" + +while(loc==limit-1&&preprocessing&&*loc=='\\') +if(get_line()==0)return(new_section); +#line 228 "cweave.ch" +if(loc>=limit&&preprocessing){ +preprocessing= sharp_include_line= define_pos= 0; +return(right_preproc); +} +#line 724 "cweave.w" + +/*:45*/ +#line 167 "cweave.ch" +; +if(loc>limit&&get_line()==0)return(new_section); + +if(loc==buffer){ +blank_count= 0; +while((*loc==' '||*loc=='\t')&&loc<limit){ +blank_count++;loc++; +} +} + +c= *(loc++); +if(xisdigit(c)||c=='\\'||c=='.')/*48:*/ +#line 775 "cweave.w" +{ +id_first= id_loc= section_text+1; +if(*(loc-1)=='\\'){*id_loc++= '~'; +while(xisdigit(*loc))*id_loc++= *loc++;} +else if(*(loc-1)=='0'){ +if(*loc=='x'||*loc=='X'){*id_loc++= '^';loc++; +while(xisxdigit(*loc))*id_loc++= *loc++;} +else if(xisdigit(*loc)){*id_loc++= '~'; +while(xisdigit(*loc))*id_loc++= *loc++;} +else goto dec; +} +else{ +if(*(loc-1)=='.'&&!xisdigit(*loc))goto mistake; +dec:*id_loc++= *(loc-1); +while(xisdigit(*loc)||*loc=='.')*id_loc++= *loc++; +if(*loc=='e'||*loc=='E'){ +*id_loc++= '_';loc++; +if(*loc=='+'||*loc=='-')*id_loc++= *loc++; +while(xisdigit(*loc))*id_loc++= *loc++; +} +} +while(*loc=='u'||*loc=='U'||*loc=='l'||*loc=='L' +||*loc=='f'||*loc=='F'){ +*id_loc++= '$';*id_loc++= toupper(*loc);loc++; +} +return(constant); +} + +/*:48*/ +#line 178 "cweave.ch" + +else if(c=='\''||c=='"'||(c=='L'&&(*loc=='\''||*loc=='"')) +||(c=='<'&&sharp_include_line==1)) +/*49:*/ +#line 808 "cweave.w" +{ +char delim= c; +id_first= section_text+1; +id_loc= section_text; +if(delim=='\''&&*(loc-2)=='@'){*++id_loc= '@';*++id_loc= '@';} +*++id_loc= delim; +if(delim=='L'){ +delim= *loc++;*++id_loc= delim; +} +if(delim=='<')delim= '>'; +while(1){ +if(loc>=limit){ +if(*(limit-1)!='\\'){ +err_print("! String didn't end");loc= limit;break; + +} +if(get_line()==0){ +err_print("! Input ended in middle of string");loc= buffer;break; + +} +} +if((c= *loc++)==delim){ +if(++id_loc<=section_text_end)*id_loc= c; +break; +} +if(c=='\\')if(loc>=limit)continue; +else if(++id_loc<=section_text_end){ +*id_loc= '\\';c= *loc++; +} +if(++id_loc<=section_text_end)*id_loc= c; +} +if(id_loc>=section_text_end){ +printf("\n! String too long: "); + +term_write(section_text+1,25); +printf("...");mark_error; +} +id_loc++; +return(string); +} + +/*:49*/ +#line 181 "cweave.ch" + +else if(xisalpha(c)||isxalpha(c)||ishigh(c)) +/*47:*/ +#line 758 "cweave.w" +{ +#line 250 "cweave.ch" +id_first= --loc; + +if(preprocessing){ +if(define_pos==1) +define_pos= 2; +else if(strncmp(loc,"define",6)==0&&xisspace(*(loc+6))) +define_pos= 1; +} + +while(isalpha(*++loc)||isdigit(*loc)||isxalpha(*loc)||ishigh(*loc)); +id_loc= loc;return(identifier); +#line 762 "cweave.w" +} + +/*:47*/ +#line 183 "cweave.ch" + +else if(c=='@')/*50:*/ +#line 852 "cweave.w" +{ +c= *loc++; +switch(ccode[(eight_bits)c]){ +case translit_code:err_print("! Use @l in limbo only");continue; + +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[c];skip_restricted();return(c); +case section_name: +/*51:*/ +#line 872 "cweave.w" +{ +char*k; +cur_section_char= *(loc-1); +/*53:*/ +#line 890 "cweave.w" + +k= section_text; +while(1){ +if(loc>limit&&get_line()==0){ +err_print("! Input ended in section name"); + +loc= buffer+1;break; +} +c= *loc; +/*54:*/ +#line 914 "cweave.w" + +if(c=='@'){ +c= *(loc+1); +if(c=='>'){ +loc+= 2;break; +} +if(ccode[(eight_bits)c]==new_section){ +err_print("! Section name didn't end");break; + +} +if(c!='@'){ +err_print("! Control codes are forbidden in section name");break; + +} +*(++k)= '@';loc++; +} + +/*:54*/ +#line 899 "cweave.w" +; +loc++;if(k<section_text_end)k++; +if(xisspace(c)){ +c= ' ';if(*(k-1)==' ')k--; +} +*k= c; +} +if(k>=section_text_end){ +printf("\n! Section name too long: "); + +term_write(section_text+1,25); +printf("...");mark_harmless; +} +if(*k==' '&&k>section_text)k--; + +/*:53*/ +#line 875 "cweave.w" +; +if(k-section_text>3&&strncmp(k-2,"...",3)==0) +cur_section= section_lookup(section_text+1,k-3,1); +else cur_section= section_lookup(section_text+1,k,0); +xref_switch= 0;return(section_name); +} + +/*:51*/ +#line 862 "cweave.w" +; +case verbatim:/*57:*/ +#line 961 "cweave.w" +{ +id_first= loc++;*(limit+1)= '@';*(limit+2)= '>'; +while(*loc!='@'||*(loc+1)!='>')loc++; +if(loc>=limit)err_print("! Verbatim string didn't end"); + +id_loc= loc;loc+= 2; +return(verbatim); +} + +/*:57*/ +#line 863 "cweave.w" +; +case ord:/*49:*/ +#line 808 "cweave.w" +{ +char delim= c; +id_first= section_text+1; +id_loc= section_text; +if(delim=='\''&&*(loc-2)=='@'){*++id_loc= '@';*++id_loc= '@';} +*++id_loc= delim; +if(delim=='L'){ +delim= *loc++;*++id_loc= delim; +} +if(delim=='<')delim= '>'; +while(1){ +if(loc>=limit){ +if(*(limit-1)!='\\'){ +err_print("! String didn't end");loc= limit;break; + +} +if(get_line()==0){ +err_print("! Input ended in middle of string");loc= buffer;break; + +} +} +if((c= *loc++)==delim){ +if(++id_loc<=section_text_end)*id_loc= c; +break; +} +if(c=='\\')if(loc>=limit)continue; +else if(++id_loc<=section_text_end){ +*id_loc= '\\';c= *loc++; +} +if(++id_loc<=section_text_end)*id_loc= c; +} +if(id_loc>=section_text_end){ +printf("\n! String too long: "); + +term_write(section_text+1,25); +printf("...");mark_error; +} +id_loc++; +return(string); +} + +/*:49*/ +#line 864 "cweave.w" +; +default:return(ccode[(eight_bits)c]); +} +} + +/*:50*/ +#line 184 "cweave.ch" + +else if(xisspace(c))continue; +if(c=='#'&&loc==buffer+1+blank_count&&!preprocessing) +/*42:*/ +#line 696 "cweave.w" +{ +preprocessing= 1; +/*44:*/ +#line 709 "cweave.w" + +while(loc<=buffer_end-7&&xisspace(*loc))loc++; +if(loc<=buffer_end-6&&strncmp(loc,"include",7)==0)sharp_include_line= 1; + +/*:44*/ +#line 698 "cweave.w" +; +return(left_preproc); +} + +/*:42*/ +#line 187 "cweave.ch" +; +mistake:/*46:*/ +#line 734 "cweave.w" + +switch(c){ +case'/':if(*loc=='*'){compress(begin_comment);} +else if(*loc=='/')compress(begin_short_comment);break; +case'+':if(*loc=='+')compress(plus_plus);break; +case'-':if(*loc=='-'){compress(minus_minus);} +else if(*loc=='>')if(*(loc+1)=='*'){loc++;compress(minus_gt_ast);} +else compress(minus_gt);break; +case'.':if(*loc=='*'){compress(period_ast);} +else if(*loc=='.'&&*(loc+1)=='.'){ +loc++;compress(dot_dot_dot); +} +break; +case':':if(*loc==':')compress(colon_colon);break; +case'=':if(*loc=='=')compress(eq_eq);break; +case'>':if(*loc=='='){compress(gt_eq);} +else if(*loc=='>')compress(gt_gt);break; +case'<':if(*loc=='='){compress(lt_eq);} +else if(*loc=='<')compress(lt_lt);break; +case'&':if(*loc=='&')compress(and_and);break; +case'|':if(*loc=='|')compress(or_or);break; +#line 239 "cweave.ch" +case'!':if(*loc=='=')compress(not_eq);break; +case'#':if(*loc=='#')compress(numb_numb);break; +#line 756 "cweave.w" +} + +/*:46*/ +#line 188 "cweave.ch" + +if(preprocessing){ +if(c=='('&&define_pos==2&&!xisspace(*(loc-2))) +define_pos= 3; +else if(c==')'&&define_pos==3) +define_pos= 4; +} +return(c); +} +} +#line 679 "cweave.w" + +/*:40*//*56:*/ +#line 936 "cweave.w" + +void +skip_restricted() +{ +id_first= loc;*(limit+1)= '@'; +false_alarm: +while(*loc!='@')loc++; +id_loc= loc; +if(loc++>limit){ +err_print("! Control text didn't end");loc= limit; + +} +else{ +if(*loc=='@'&&loc<=limit){loc++;goto false_alarm;} +if(*loc++!='>') +err_print("! Control codes are forbidden in control text"); + +} +} + +/*:56*//*60:*/ +#line 989 "cweave.w" + +void +phase_one(){ +phase= 1;reset_input();section_count= 0; +skip_limbo();change_exists= 0; +while(!input_has_ended) +/*61:*/ +#line 1002 "cweave.w" + +{ +if(++section_count==max_sections)overflow("section number"); +changed_section[section_count]= changing; + +if(*(loc-1)=='*'&&show_progress){ +printf("*%d",section_count); +update_terminal; +} +/*66:*/ +#line 1093 "cweave.w" + +while(1){ +switch(next_control= skip_TeX()){ +case translit_code:err_print("! Use @l in limbo only");continue; + +case underline:xref_switch= def_flag;continue; +case trace:tracing= *(loc-1)-'0';continue; +case'|':C_xref(section_name);break; +case xref_roman:case xref_wildcard:case xref_typewriter: +case noop:case section_name: +loc-= 2;next_control= get_next(); +if(next_control>=xref_roman&&next_control<=xref_typewriter){ +/*67:*/ +#line 1113 "cweave.w" + +{ +char*src= id_first,*dst= id_first; +while(src<id_loc){ +if(*src=='@')src++; +*dst++= *src++; +} +id_loc= dst; +while(dst<src)*dst++= ' '; +} + +/*:67*/ +#line 1105 "cweave.w" + +new_xref(id_lookup(id_first,id_loc,next_control-identifier)); +} +break; +} +if(next_control>=format_code)break; +} + +/*:66*/ +#line 1011 "cweave.w" +; +/*69:*/ +#line 1141 "cweave.w" + +while(next_control<=definition){ +if(next_control==definition){ +xref_switch= def_flag; +next_control= get_next(); +}else/*70:*/ +#line 1155 "cweave.w" +{ +next_control= get_next(); +if(next_control==identifier){ +lhs= id_lookup(id_first,id_loc,normal);lhs->ilk= normal; +if(xref_switch)new_xref(lhs); +next_control= get_next(); +if(next_control==identifier){ +rhs= id_lookup(id_first,id_loc,normal); +lhs->ilk= rhs->ilk; +if(unindexed(lhs)){ +xref_pointer q,r= NULL; +for(q= (xref_pointer)lhs->xref;q>xmem;q= q->xlink) +if(q->num<def_flag) +if(r)r->xlink= q->xlink; +else lhs->xref= (char*)q->xlink; +else r= q; +} +next_control= get_next(); +} +} +} + +/*:70*/ +#line 1146 "cweave.w" +; +outer_xref(); +} + +/*:69*/ +#line 1012 "cweave.w" +; +/*72:*/ +#line 1200 "cweave.w" + +if(next_control<=section_name){ +if(next_control==begin_C)section_xref_switch= 0; +else{ +section_xref_switch= def_flag; +if(cur_section_char=='('&&cur_section!=name_dir) +set_file_flag(cur_section); +} +do{ +if(next_control==section_name&&cur_section!=name_dir) +new_section_xref(cur_section); +next_control= get_next();outer_xref(); +}while(next_control<=section_name); +} + +/*:72*/ +#line 1013 "cweave.w" +; +if(changed_section[section_count])change_exists= 1; +} + +/*:61*/ +#line 995 "cweave.w" +; +changed_section[section_count]= change_exists; + +phase= 2; +/*76:*/ +#line 1253 "cweave.w" +section_check(root) + +/*:76*/ +#line 999 "cweave.w" +; +} + +/*:60*//*63:*/ +#line 1041 "cweave.w" + +void +C_xref(spec_ctrl) +eight_bits spec_ctrl; +{ +name_pointer p; +while(next_control<format_code||next_control==spec_ctrl){ +if(next_control>=identifier&&next_control<=xref_typewriter){ +if(next_control>identifier)/*67:*/ +#line 1113 "cweave.w" + +{ +char*src= id_first,*dst= id_first; +while(src<id_loc){ +if(*src=='@')src++; +*dst++= *src++; +} +id_loc= dst; +while(dst<src)*dst++= ' '; +} + +/*:67*/ +#line 1049 "cweave.w" + +p= id_lookup(id_first,id_loc,next_control-identifier);new_xref(p); +} +if(next_control==section_name){ +section_xref_switch= cite_flag; +new_section_xref(cur_section); +} +next_control= get_next(); +if(next_control=='|'||next_control==begin_comment|| +next_control==begin_short_comment)return; +} +} + +/*:63*//*65:*/ +#line 1069 "cweave.w" + +void +outer_xref() +{ +int bal; +while(next_control<format_code) +if(next_control!=begin_comment&&next_control!=begin_short_comment) +C_xref(ignore); +else{ +boolean is_long_comment= (next_control==begin_comment); +bal= copy_comment(is_long_comment,1);next_control= '|'; +while(bal>0){ +C_xref(section_name); +if(next_control=='|')bal= copy_comment(is_long_comment,bal); +else bal= 0; +} +} +} + +/*:65*//*75:*/ +#line 1230 "cweave.w" + +void +section_check(p) +name_pointer p; +{ +if(p){ +section_check(p->llink); +cur_xref= (xref_pointer)p->xref; +if(cur_xref->num==file_flag){an_output= 1;cur_xref= cur_xref->xlink;} +else an_output= 0; +if(cur_xref->num<def_flag){ +printf("\n! Never defined: <");print_section_name(p);putchar('>');mark_harmless; + +} +while(cur_xref->num>=cite_flag)cur_xref= cur_xref->xlink; +if(cur_xref==xmem&&!an_output){ +printf("\n! Never used: <");print_section_name(p);putchar('>');mark_harmless; + +} +section_check(p->rlink); +} +} + +/*:75*//*78:*/ +#line 1283 "cweave.w" + +void +flush_buffer(b,per_cent,carryover) +char*b; +boolean per_cent,carryover; +{ +char*j;j= b; +if(!per_cent) +while(j>out_buf&&*j==' ')j--; +c_line_write(j-out_buf); +if(per_cent)tex_putc('%'); +tex_new_line;out_line++; +if(carryover) +while(j>out_buf) +if(*j--=='%'&&(j==out_buf||*j!='\\')){ +*b--= '%';break; +} +if(b<out_ptr)strncpy(out_buf+1,b+1,out_ptr-b); +out_ptr-= b-out_buf; +} + +/*:78*//*79:*/ +#line 1312 "cweave.w" + +void +finish_line() +{ +char*k; +if(out_ptr>out_buf)flush_buffer(out_ptr,0,0); +else{ +for(k= buffer;k<=limit;k++) +if(!(xisspace(*k)))return; +flush_buffer(out_buf,0,0); +} +} + +/*:79*//*81:*/ +#line 298 "cweave.ch" + +void +out(c) +char c; +{ +if(out_ptr>=out_buf_end) +break_out(); + +if(!escape){ +if(in_math){ +if(c=='{') +math_brace_count++; +else if(c=='}'){ +math_brace_count--; +if(math_brace_count<0){ +math_brace_count= 0; +return; +} +} +} +if(c=='$'){ +while(math_brace_count>0){ +*(++out_ptr)= '}'; +math_brace_count--; +} +in_math= 1-in_math; +} +} + +if(c=='\\'&&!escape) +escape= 1; +else +escape= 0; + +*(++out_ptr)= c; +return; +} +#line 1345 "cweave.w" +void +out_str(s) +char*s; +{ +while(*s)out(*s++); +} + +/*:81*//*84:*/ +#line 1366 "cweave.w" + +void +break_out() +{ +char*k= out_ptr; +while(1){ +if(k==out_buf)/*85:*/ +#line 1387 "cweave.w" + +{ +printf("\n! Line had to be broken (output l. %d):\n",out_line); + +term_write(out_buf+1,out_ptr-out_buf-1); +new_line;mark_harmless; +flush_buffer(out_ptr-1,1,1);return; +} + +/*:85*/ +#line 1372 "cweave.w" +; +if(*k==' '){ +flush_buffer(k,0,1);return; +} +if(*(k--)=='\\'&&*k!='\\'){ +flush_buffer(k,1,1);return; +} +} +} + +/*:84*//*86:*/ +#line 1401 "cweave.w" + +void +out_section(n) +sixteen_bits n; +{ +char s[6]; +sprintf(s,"%d",n);out_str(s); +if(changed_section[n])out_str("\\*"); + +} + +/*:86*//*87:*/ +#line 1415 "cweave.w" + +void +out_name(p) +name_pointer p; +{ +char*k,*k_end= (p+1)->byte_start; +out('{'); +for(k= p->byte_start;k<k_end;k++){ +if(isxalpha(*k))out('\\'); +out(*k); +} +out('}'); +} + +/*:87*//*88:*/ +#line 1442 "cweave.w" + +void +copy_limbo() +{ +char c; +while(1){ +if(loc>limit&&(finish_line(),get_line()==0))return; +*(limit+1)= '@'; +while(*loc!='@')out(*(loc++)); +if(loc++<=limit){ +c= *loc++; +if(ccode[(eight_bits)c]==new_section)break; +switch(ccode[(eight_bits)c]){ +case translit_code:out_str("\\ATL");break; + +case'@':out('@');break; +case noop:skip_restricted();break; +case format_code:if(get_next()==identifier)get_next(); +if(loc>=limit)get_line(); +break; +default:err_print("! Double @ should be used in limbo"); + +out('@'); +} +} +} +} + +/*:88*//*90:*/ +#line 1477 "cweave.w" + +eight_bits +copy_TeX() +{ +char c; +while(1){ +if(loc>limit&&(finish_line(),get_line()==0))return(new_section); +*(limit+1)= '@'; +while((c= *(loc++))!='|'&&c!='@'){ +out(c); +if(out_ptr==out_buf+1&&(xisspace(c)))out_ptr--; +} +if(c=='|')return('|'); +if(loc<=limit)return(ccode[(eight_bits)*(loc++)]); +} +} + +/*:90*//*92:*/ +#line 1509 "cweave.w" + +int copy_comment(is_long_comment,bal) +boolean is_long_comment; +int bal; +{ +char c; +while(1){ +if(loc>limit){ +if(is_long_comment){ +if(get_line()==0){ +err_print("! Input ended in mid-comment"); + +loc= buffer+1;goto done; +} +} +else{ +if(bal>1)err_print("! Missing } in comment"); + +goto done; +} +} +c= *(loc++); +if(c=='|')return(bal); +if(is_long_comment)/*93:*/ +#line 1550 "cweave.w" + +if(c=='*'&&*loc=='/'){ +loc++; +if(bal>1)err_print("! Missing } in comment"); + +goto done; +} + +/*:93*/ +#line 1532 "cweave.w" +; +if(phase==2){ +if(ishigh(c))app_tok(quoted_char); +app_tok(c); +} +/*94:*/ +#line 1558 "cweave.w" + +if(c=='@'){ +if(*(loc++)!='@'){ +err_print("! Illegal use of @ in comment"); + +loc-= 2;if(phase==2)*(tok_ptr-1)= ' ';goto done; +} +} +else if(c=='\\'&&*loc!='@') +if(phase==2)app_tok(*(loc++))else loc++; + +/*:94*/ +#line 1537 "cweave.w" +; +if(c=='{')bal++; +else if(c=='}'){ +if(bal>1)bal--; +else{err_print("! Extra } in comment"); + +if(phase==2)tok_ptr--; +} +} +} +done:/*95:*/ +#line 1572 "cweave.w" + +if(phase==2)while(bal-->0)app_tok('}'); +return(0); + +/*:95*/ +#line 1547 "cweave.w" +; +} + +/*:92*//*99:*/ +#line 1734 "cweave.w" + +void +print_cat(c) +eight_bits c; +{ +printf(cat_name[c]); +} + +/*:99*//*106:*/ +#line 2062 "cweave.w" + +void +print_text(p) +text_pointer p; +{ +token_pointer j; +sixteen_bits r; +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("\\\\{");print_id((name_dir+r));printf("}"); +break; +case 2:printf("\\&{");print_id((name_dir+r));printf("}"); +break; +case 3:printf("<");print_section_name((name_dir+r));printf(">"); +break; +case 4:printf("[[%d]]",r);break; +case 5:printf("|[[%d]]|",r);break; +default:/*107:*/ +#line 2087 "cweave.w" + +switch(r){ +case math_rel:printf("\\mathrel{");break; +case big_cancel:printf("[ccancel]");break; +case cancel:printf("[cancel]");break; +case indent:printf("[indent]");break; +case outdent:printf("[outdent]");break; +case backup:printf("[backup]");break; +case opt:printf("[opt]");break; +case break_space:printf("[break]");break; +case force:printf("[force]");break; +case big_force:printf("[fforce]");break; +case preproc_line:printf("[preproc]");break; +case quoted_char:j++;printf("[%o]",(unsigned)*j);break; +case end_translation:printf("[quit]");break; +case inserted:printf("[inserted]");break; +default:putxchar(r); +} + +/*:107*/ +#line 2081 "cweave.w" +; +} +} +fflush(stdout); +} + +/*:106*//*109:*/ +#line 2187 "cweave.w" + +void +app_str(s) +char*s; +{ +while(*s)app_tok(*(s++)); +} + +void +big_app(a) +token a; +{ +if(a==' '||(a>=big_cancel&&a<=big_force)){ +if(cur_mathness==maybe_math)init_mathness= no_math; +else if(cur_mathness==yes_math)app_str("{}$"); +cur_mathness= no_math; +} +else{ +if(cur_mathness==maybe_math)init_mathness= yes_math; +else if(cur_mathness==no_math)app_str("${}"); +cur_mathness= yes_math; +} +app(a); +} + +void +big_app1(a) +scrap_pointer a; +{ +switch(a->mathness%4){ +case(no_math): +if(cur_mathness==maybe_math)init_mathness= no_math; +else if(cur_mathness==yes_math)app_str("{}$"); +cur_mathness= a->mathness/4; +break; +case(yes_math): +if(cur_mathness==maybe_math)init_mathness= yes_math; +else if(cur_mathness==no_math)app_str("${}"); +cur_mathness= a->mathness/4; +break; +case(maybe_math):break; +} +app(tok_flag+(int)((a)->trans-tok_start)); +} + +/*:109*//*111:*/ +#line 2312 "cweave.w" + +token_pointer +find_first_ident(p) +text_pointer p; +{ +token_pointer q; +token_pointer j; +sixteen_bits r; +if(p>=text_ptr)confusion("find_first_ident"); +for(j= *p;j<*(p+1);j++){ +r= *j%id_flag; +switch(*j/id_flag){ +case 1:case 2:return j; +case 4:case 5: +if((q= find_first_ident(tok_start+r))!=no_ident_found) +return q; +default:; +if(*j==inserted)return no_ident_found; +} +} +return no_ident_found; +} + +/*:111*//*112:*/ +#line 2339 "cweave.w" + +#line 421 "cweave.ch" +void +make_reserved(p,cat) +scrap_pointer p; +eight_bits cat; +{ +sixteen_bits tok_value; +token_pointer tok_loc; +if((tok_loc= find_first_ident(p->trans))==no_ident_found) +return; +tok_value= *tok_loc; +for(;p<=scrap_ptr;p==lo_ptr?p= hi_ptr:p++){ +if(p->cat==exp||p->cat==int_like||p->cat==const_like){ +if(**(p->trans)==tok_value){ +p->cat= cat; +**(p->trans)= tok_value%id_flag+res_flag; +} +} +} +(name_dir+(sixteen_bits)(tok_value%id_flag))->ilk= cat; +*tok_loc= tok_value%id_flag+res_flag; +} +#line 2360 "cweave.w" + +/*:112*//*113:*/ +#line 2370 "cweave.w" + +void +make_underlined(p) + +scrap_pointer p; +{ +token_pointer tok_loc; +if((tok_loc= find_first_ident(p->trans))==no_ident_found) +return; +xref_switch= def_flag; +underline_xref(*tok_loc%id_flag+name_dir); +} + +/*:113*//*115:*/ +#line 2391 "cweave.w" + +void +underline_xref(p) +name_pointer p; +{ +xref_pointer q= (xref_pointer)p->xref; +xref_pointer r; +sixteen_bits m; +sixteen_bits n; +if(no_xref)return; +m= section_count+xref_switch; +while(q!=xmem){ +n= q->num; +if(n==m)return; +else if(m==n+def_flag){ +q->num= m;return; +} +else if(n>=def_flag&&n<m)break; +q= q->xlink; +} +/*116:*/ +#line 2421 "cweave.w" + +append_xref(0); +xref_ptr->xlink= (xref_pointer)p->xref;r= xref_ptr; +p->xref= (char*)xref_ptr; +while(r->xlink!=q){r->num= r->xlink->num;r= r->xlink;} +r->num= m; + +/*:116*/ +#line 2411 "cweave.w" +; +} + +/*:115*//*162:*/ +#line 2868 "cweave.w" + +void +reduce(j,k,c,d,n) +scrap_pointer j; +eight_bits c; +short k,d,n; +{ +scrap_pointer i,i1; +j->cat= c;j->trans= text_ptr; +j->mathness= 4*cur_mathness+init_mathness; +freeze_text; +if(k>1){ +for(i= j+k,i1= j+1;i<=lo_ptr;i++,i1++){ +i1->cat= i->cat;i1->trans= i->trans; +i1->mathness= i->mathness; +} +lo_ptr= lo_ptr-k+1; +} +/*163:*/ +#line 2891 "cweave.w" + +if(pp+d>=scrap_base)pp= pp+d; +else pp= scrap_base; + +/*:163*/ +#line 2886 "cweave.w" +; +/*168:*/ +#line 2965 "cweave.w" + +{scrap_pointer k; +#line 806 "cweave.ch" +if(tracing==2){ +printf("\n%3d:",n); +#line 2969 "cweave.w" +for(k= scrap_base;k<=lo_ptr;k++){ +if(k==pp)putxchar('*');else putxchar(' '); +if(k->mathness%4==yes_math)putchar('+'); +else if(k->mathness%4==no_math)putchar('-'); +print_cat(k->cat); +if(k->mathness/4==yes_math)putchar('+'); +else if(k->mathness/4==no_math)putchar('-'); +} +if(hi_ptr<=scrap_ptr)printf("..."); +} +} + +/*:168*/ +#line 2887 "cweave.w" +; +pp--; +} + +/*:162*//*164:*/ +#line 2898 "cweave.w" + +void +squash(j,k,c,d,n) +scrap_pointer j; +eight_bits c; +short k,d,n; +{ +scrap_pointer i; +if(k==1){ +j->cat= c;/*163:*/ +#line 2891 "cweave.w" + +if(pp+d>=scrap_base)pp= pp+d; +else pp= scrap_base; + +/*:163*/ +#line 2907 "cweave.w" +; +/*168:*/ +#line 2965 "cweave.w" + +{scrap_pointer k; +#line 806 "cweave.ch" +if(tracing==2){ +printf("\n%3d:",n); +#line 2969 "cweave.w" +for(k= scrap_base;k<=lo_ptr;k++){ +if(k==pp)putxchar('*');else putxchar(' '); +if(k->mathness%4==yes_math)putchar('+'); +else if(k->mathness%4==no_math)putchar('-'); +print_cat(k->cat); +if(k->mathness/4==yes_math)putchar('+'); +else if(k->mathness/4==no_math)putchar('-'); +} +if(hi_ptr<=scrap_ptr)printf("..."); +} +} + +/*:168*/ +#line 2908 "cweave.w" +; +pp--; +return; +} +for(i= j;i<j+k;i++)big_app1(i); +reduce(j,k,c,d,n); +} + +/*:164*//*169:*/ +#line 2994 "cweave.w" + +text_pointer +translate() +{ +scrap_pointer i, +j; +pp= scrap_base;lo_ptr= pp-1;hi_ptr= pp; +/*172:*/ +#line 3033 "cweave.w" + +if(tracing==2){ +printf("\nTracing after l. %d:\n",cur_line);mark_harmless; + +if(loc>buffer+50){ +printf("..."); +term_write(loc-51,51); +} +else term_write(buffer,loc-buffer); +} + +/*:172*/ +#line 3001 "cweave.w" +; +/*165:*/ +#line 2929 "cweave.w" + +while(1){ +/*166:*/ +#line 2948 "cweave.w" + +if(lo_ptr<pp+3){ +while(hi_ptr<=scrap_ptr&&lo_ptr!=pp+3){ +(++lo_ptr)->cat= hi_ptr->cat;lo_ptr->mathness= (hi_ptr)->mathness; +lo_ptr->trans= (hi_ptr++)->trans; +} +for(i= lo_ptr+1;i<=pp+3;i++)i->cat= 0; +} + +/*:166*/ +#line 2931 "cweave.w" +; +if(tok_ptr+safe_tok_incr>tok_mem_end){ +if(tok_ptr>max_tok_ptr)max_tok_ptr= tok_ptr; +overflow("token"); +} +if(text_ptr+safe_text_incr>tok_start_end){ +if(text_ptr>max_text_ptr)max_text_ptr= text_ptr; +overflow("text"); +} +if(pp>lo_ptr)break; +init_mathness= cur_mathness= maybe_math; +/*110:*/ +#line 2243 "cweave.w" +{ +if(cat1==end_arg&&lhs_not_simple) +if(pp->cat==begin_arg)squash(pp,2,exp,-2,110); +else squash(pp,2,end_arg,-1,111); +else if(cat1==insert)squash(pp,2,pp->cat,-2,0); +else if(cat2==insert)squash(pp+1,2,(pp+1)->cat,-1,0); +else if(cat3==insert)squash(pp+2,2,(pp+2)->cat,0,0); +else +switch(pp->cat){ +case exp:/*117:*/ +#line 2433 "cweave.w" + +if(cat1==lbrace||cat1==int_like||cat1==decl){ +make_underlined(pp);big_app1(pp);big_app(indent);app(indent); +reduce(pp,1,fn_decl,0,1); +} +else if(cat1==unop)squash(pp,2,exp,-2,2); +else if((cat1==binop||cat1==unorbinop)&&cat2==exp) +squash(pp,3,exp,-2,3); +else if(cat1==comma&&cat2==exp){ +big_app2(pp); +app(opt);app('9');big_app1(pp+2);reduce(pp,3,exp,-2,4); +} +else if(cat1==exp||cat1==cast)squash(pp,2,exp,-2,5); +else if(cat1==semi)squash(pp,2,stmt,-1,6); +else if(cat1==colon){ +#line 449 "cweave.ch" +make_underlined(pp); +if(alternative) +squash(pp,2,label,0,7); +else +squash(pp,2,tag,0,7); +#line 2449 "cweave.w" +} +else if(cat1==base){ +if(cat2==int_like&&cat3==comma){ +big_app1(pp+1);big_app(' ');big_app2(pp+2); +app(opt);app('9');reduce(pp+1,3,base,0,8); +} +else if(cat2==int_like&&cat3==lbrace){ +big_app1(pp);big_app(' ');big_app1(pp+1);big_app(' ');big_app1(pp+2); +reduce(pp,3,exp,-1,9); +} +} +else if(cat1==rbrace)squash(pp,1,stmt,-1,10); + +/*:117*/ +#line 2252 "cweave.w" +;break; +case lpar:/*118:*/ +#line 2462 "cweave.w" + +if((cat1==exp||cat1==unorbinop)&&cat2==rpar)squash(pp,3,exp,-2,11); +else if(cat1==rpar){ +big_app1(pp);app('\\');app(',');big_app1(pp+1); + +reduce(pp,2,exp,-2,12); +} +else if(cat1==decl_head||cat1==int_like||cat1==exp){ +if(cat2==rpar)squash(pp,3,cast,-2,13); +else if(cat2==comma){ +big_app3(pp);app(opt);app('9');reduce(pp,3,lpar,0,14); +} +} +else if(cat1==stmt||cat1==decl){ +big_app2(pp);big_app(' ');reduce(pp,2,lpar,0,15); +} + +/*:118*/ +#line 2253 "cweave.w" +;break; +case question:/*119:*/ +#line 2479 "cweave.w" + +if(cat1==exp&&cat2==colon)squash(pp,3,binop,-2,16); + +/*:119*/ +#line 2254 "cweave.w" +;break; +case unop:/*120:*/ +#line 2482 "cweave.w" + +if(cat1==exp||cat1==int_like)squash(pp,2,cat1,-2,17); + +/*:120*/ +#line 2255 "cweave.w" +;break; +case unorbinop:/*121:*/ +#line 2485 "cweave.w" + +if(cat1==exp||cat1==int_like){ +big_app('{');big_app1(pp);big_app('}');big_app1(pp+1); +reduce(pp,2,cat1,-2,18); +} +else if(cat1==binop){ +big_app(math_rel);big_app1(pp);big_app('{');big_app1(pp+1);big_app('}'); +big_app('}');reduce(pp,2,binop,-1,19); +} + +/*:121*/ +#line 2256 "cweave.w" +;break; +case binop:/*122:*/ +#line 2495 "cweave.w" + +if(cat1==binop){ +big_app(math_rel);big_app('{');big_app1(pp);big_app('}'); +big_app('{');big_app1(pp+1);big_app('}'); +big_app('}');reduce(pp,2,binop,-1,20); +} + +/*:122*/ +#line 2257 "cweave.w" +;break; +case cast:/*123:*/ +#line 2502 "cweave.w" + +if(cat1==exp){ +big_app1(pp);big_app(' ');big_app1(pp+1);reduce(pp,2,exp,-2,21); +} +else if(cat1==semi)squash(pp,1,exp,-2,22); + +/*:123*/ +#line 2258 "cweave.w" +;break; +case sizeof_like:/*124:*/ +#line 2508 "cweave.w" + +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); +} + +/*:124*/ +#line 2259 "cweave.w" +;break; +case int_like:/*125:*/ +#line 2514 "cweave.w" + +if(cat1==int_like||cat1==struct_like){ +big_app1(pp);big_app(' ');big_app1(pp+1);reduce(pp,2,cat1,-2,25); +} +else if(cat1==exp&&(cat2==raw_int||cat2==struct_like)) +squash(pp,2,int_like,-2,26); +else if(cat1==exp||cat1==unorbinop||cat1==semi){ +big_app1(pp); +if(cat1!=semi)big_app(' '); +reduce(pp,1,decl_head,-1,27); +} +else if(cat1==colon){ +big_app1(pp);big_app(' ');reduce(pp,1,decl_head,0,28); +} +else if(cat1==prelangle)squash(pp+1,1,langle,1,29); +else if(cat1==colcol&&(cat2==exp||cat2==int_like))squash(pp,3,cat2,-2,30); +else if(cat1==cast){ +if(cat2==lbrace){ +big_app2(pp);big_app(indent);big_app(indent); +reduce(pp,2,fn_decl,1,31); +} +#line 462 "cweave.ch" +else squash(pp,2,int_like,-2,32); +} +else if(cat1==binop&&cat2==exp)squash(pp,3,int_like,-2,117); +#line 2537 "cweave.w" + +/*:125*/ +#line 2260 "cweave.w" +;break; +case decl_head:/*126:*/ +#line 2538 "cweave.w" + +if(cat1==comma){ +big_app2(pp);big_app(' ');reduce(pp,2,decl_head,-1,33); +} +else if(cat1==unorbinop){ +big_app1(pp);big_app('{');big_app1(pp+1);big_app('}'); +reduce(pp,2,decl_head,-1,34); +} +else if(cat1==exp&&cat2!=lpar&&cat2!=exp){ +make_underlined(pp+1);squash(pp,2,decl_head,-1,35); +} +else if((cat1==binop||cat1==colon)&&cat2==exp&&(cat3==comma|| +cat3==semi||cat3==rpar)) +squash(pp,3,decl_head,-1,36); +else if(cat1==cast)squash(pp,2,decl_head,-1,37); +else if(cat1==lbrace||(cat1==int_like&&cat2!=colcol)||cat1==decl){ +big_app1(pp);big_app(indent);app(indent);reduce(pp,1,fn_decl,0,38); +} +else if(cat1==semi)squash(pp,2,decl,-1,39); + +/*:126*/ +#line 2261 "cweave.w" +;break; +case decl:/*127:*/ +#line 2558 "cweave.w" + +if(cat1==decl){ +big_app1(pp);big_app(force);big_app1(pp+1); +reduce(pp,2,decl,-1,40); +} +else if(cat1==stmt||cat1==function){ +big_app1(pp);big_app(big_force); +big_app1(pp+1);reduce(pp,2,cat1,-1,41); +} + +/*:127*/ +#line 2262 "cweave.w" +;break; +case typedef_like:/*128:*/ +#line 2568 "cweave.w" + +#line 479 "cweave.ch" +if(cat1==decl_head){ +if((cat2==exp&&cat3!=lpar&&cat3!=exp)||cat2==int_like){ +make_underlined(pp+2);make_reserved(pp+2,raw_int); +big_app2(pp+1);reduce(pp+1,2,decl_head,0,42); +} +else if(cat2==semi){ +big_app1(pp);big_app(' ');big_app2(pp+1);reduce(pp,3,decl,-1,43); +} +} +else if(cat1==exp&&!preprocessing&&cat2!=lpar){ +make_reserved(pp+1,raw_int); +squash(pp+1,1,raw_int,-2,116); +} +#line 2577 "cweave.w" + +/*:128*/ +#line 2263 "cweave.w" +;break; +case struct_like:/*129:*/ +#line 2578 "cweave.w" + +#line 515 "cweave.ch" +if(cat1==lbrace){ +if(alternative){ +big_app1(pp);big_app(indent);big_app(force);big_app(backup); +big_app1(pp+1);reduce(pp,2,struct_head,0,44); +}else{ +big_app1(pp);big_app(' ');big_app1(pp+1); +reduce(pp,2,struct_head,0,44); +} +} +else if(cat1==exp||cat1==int_like){ +if(cat2==lbrace||cat2==semi){ +make_underlined(pp+1);make_reserved(pp+1,raw_int); +big_app1(pp);big_app(' ');big_app1(pp+1); +if(cat2==semi)reduce(pp,2,decl_head,-1,45); +else{ +if(alternative){ +big_app(indent);big_app(force);big_app(backup);big_app1(pp+2); +reduce(pp,3,struct_head,0,46); +}else{ +big_app(' ');big_app1(pp+2);reduce(pp,3,struct_head,0,46); +} +} +} +else if(cat2==colon)squash(pp+2,1,base,-1,47); +else if(!(cat2==base||cat2==raw_int|| +cat2==int_like||cat2==const_like)){ +big_app1(pp);big_app(' ');big_app1(pp+1);reduce(pp,2,int_like,-2,48); +} +} +#line 2596 "cweave.w" + +/*:129*/ +#line 2264 "cweave.w" +;break; +case struct_head:/*130:*/ +#line 2597 "cweave.w" + +if((cat1==decl||cat1==stmt||cat1==function)&&cat2==rbrace){ +#line 553 "cweave.ch" +if(alternative){ +big_app1(pp);big_app1(pp+1); +big_app(force);big_app(backup);big_app1(pp+2);big_app(' '); +big_app(outdent);reduce(pp,3,int_like,-2,49); +}else{ +big_app1(pp);big_app(indent);big_app(force);big_app1(pp+1); +big_app(outdent);big_app(force);big_app1(pp+2); +reduce(pp,3,int_like,-2,49); +} +#line 2602 "cweave.w" +} +else if(cat1==rbrace){ +big_app1(pp);app_str("\\,");big_app1(pp+1); + +reduce(pp,2,int_like,-2,50); +} + +/*:130*/ +#line 2265 "cweave.w" +;break; +case fn_decl:/*131:*/ +#line 2609 "cweave.w" + +if(cat1==decl){ +big_app1(pp);big_app(force);big_app1(pp+1);reduce(pp,2,fn_decl,0,51); +} +else if(cat1==stmt){ +big_app1(pp);app(outdent);app(outdent);big_app(force); +big_app1(pp+1);reduce(pp,2,function,-1,52); +} + +/*:131*/ +#line 2266 "cweave.w" +;break; +case function:/*132:*/ +#line 2618 "cweave.w" + +if(cat1==function||cat1==decl||cat1==stmt){ +big_app1(pp);big_app(big_force);big_app1(pp+1);reduce(pp,2,cat1,-1,53); +} + +/*:132*/ +#line 2267 "cweave.w" +;break; +case lbrace:/*133:*/ +#line 2623 "cweave.w" + +if(cat1==rbrace){ +big_app1(pp);app('\\');app(',');big_app1(pp+1); + +reduce(pp,2,stmt,-1,54); +} +else if((cat1==stmt||cat1==decl||cat1==function)&&cat2==rbrace){ +#line 571 "cweave.ch" +if(alternative){ +big_app(indent);big_app(force);big_app(backup);big_app1(pp); +app(noop);big_app(cancel);big_app1(pp+1);big_app(force);big_app(backup); +big_app1(pp+2);big_app(outdent);big_app(force);reduce(pp,3,stmt,-2,55); +}else{ +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); +} +#line 2633 "cweave.w" +} +else if(cat1==exp){ +if(cat2==rbrace)squash(pp,3,exp,-2,56); +else if(cat2==comma&&cat3==rbrace)squash(pp,4,exp,-2,56); +} + +/*:133*/ +#line 2268 "cweave.w" +;break; +case do_like:/*140:*/ +#line 2689 "cweave.w" + +#line 669 "cweave.ch" +if(alternative){ +if(cat1==lbrace)squash(pp,1,do_head,0,114); +else if(cat1==stmt&&cat2==else_like&&cat3==semi){ +big_app(force);big_app1(pp);big_app(indent);big_app(force); +big_app1(pp+1);big_app(cancel);app(noop); +big_app(break_space);big_app2(pp+2);big_app(outdent);big_app(force); +reduce(pp,4,stmt,-1,69); +} +}else{ +if(cat1==stmt&&cat2==else_like&&cat3==semi){ +big_app1(pp);big_app(break_space);app(noop);big_app(cancel); +big_app1(pp+1);big_app(cancel);app(noop);big_app(break_space); +big_app2(pp+2);reduce(pp,4,stmt,-1,69); +} +} +#line 2695 "cweave.w" + +/*:140*/ +#line 2269 "cweave.w" +;break; +case if_like:/*134:*/ +#line 2639 "cweave.w" + +if(cat1==exp){ +big_app1(pp);big_app(' ');big_app1(pp+1);reduce(pp,2,if_clause,0,57); +} + +/*:134*/ +#line 2270 "cweave.w" +;break; +case for_like:/*135:*/ +#line 2644 "cweave.w" + +if(cat1==exp){ +big_app1(pp);big_app(' ');big_app1(pp+1);reduce(pp,2,else_like,-2,58); +} + +/*:135*/ +#line 2271 "cweave.w" +;break; +case else_like:/*136:*/ +#line 2649 "cweave.w" + +if(cat1==lbrace)squash(pp,1,else_head,0,59); +else if(cat1==stmt){ +#line 589 "cweave.ch" +if(alternative){ +big_app(force);big_app1(pp);big_app(indent);big_app(force); +big_app1(pp+1);big_app(outdent);big_app(force); +reduce(pp,2,stmt,-1,60); +}else{ +big_app(force);big_app1(pp);big_app(indent);big_app(break_space); +big_app1(pp+1);big_app(outdent);big_app(force); +reduce(pp,2,stmt,-1,60); +} +#line 2655 "cweave.w" +} + +/*:136*/ +#line 2272 "cweave.w" +;break; +case if_clause:/*138:*/ +#line 2664 "cweave.w" + +if(cat1==lbrace)squash(pp,1,if_head,0,62); +else if(cat1==stmt){ +if(cat2==else_like){ +#line 627 "cweave.ch" +if(alternative){ +big_app(force);big_app1(pp);big_app(indent);big_app(force); +big_app1(pp+1);big_app(outdent);big_app(force);big_app1(pp+2); +}else{ +big_app(force);big_app1(pp);big_app(indent);big_app(break_space); +big_app1(pp+1);big_app(outdent);big_app(force);big_app1(pp+2); +} +if(cat3==if_like){ +big_app(' ');big_app1(pp+3);reduce(pp,4,if_like,0,63); +}else reduce(pp,3,else_like,0,64); +#line 2673 "cweave.w" +} +else squash(pp,1,else_like,0,65); +} + +/*:138*/ +#line 2273 "cweave.w" +;break; +case if_head:/*139:*/ +#line 2677 "cweave.w" + +if(cat1==stmt||cat1==exp){ +if(cat2==else_like){ +#line 648 "cweave.ch" +if(alternative){ +big_app(force);big_app1(pp);big_app(break_space); +big_app1(pp+1);big_app(force);big_app1(pp+2); +}else{ +big_app(force);big_app1(pp);big_app(break_space);app(noop); +big_app(cancel);big_app1(pp+1);big_app(force);big_app1(pp+2); +} +if(cat3==if_like){ +big_app(' ');big_app1(pp+3);reduce(pp,4,if_like,0,66); +}else reduce(pp,3,else_like,0,67); +#line 2685 "cweave.w" +} +else squash(pp,1,else_head,0,68); +} + +/*:139*/ +#line 2274 "cweave.w" +;break; +case else_head:/*137:*/ +#line 2657 "cweave.w" + +if(cat1==stmt||cat1==exp){ +#line 607 "cweave.ch" +if(alternative){ +big_app(force);big_app1(pp);big_app(break_space); +big_app1(pp+1);big_app(force); +reduce(pp,2,stmt,-1,61); +}else{ +big_app(force);big_app1(pp);big_app(break_space);app(noop); +big_app(cancel);big_app1(pp+1);big_app(force); +reduce(pp,2,stmt,-1,61); +} +#line 2662 "cweave.w" +} + +/*:137*/ +#line 2275 "cweave.w" +;break; +case case_like:/*141:*/ +#line 2696 "cweave.w" + +#line 692 "cweave.ch" +if(cat1==semi)squash(pp,2,stmt,-3,70); +else if(cat1==colon)squash(pp,2,tag,-2,71); +#line 2699 "cweave.w" +else if(cat1==exp){ +if(cat2==semi){ +big_app1(pp);big_app(' ');big_app1(pp+1);big_app1(pp+2); +reduce(pp,3,stmt,-1,72); +} +else if(cat2==colon){ +big_app1(pp);big_app(' ');big_app1(pp+1);big_app1(pp+2); +#line 701 "cweave.ch" +reduce(pp,3,tag,-2,73); +#line 2707 "cweave.w" +} +} + +/*:141*/ +#line 2276 "cweave.w" +;break; +case stmt:/*143:*/ +#line 2723 "cweave.w" + +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); +} + +/*:143*/ +#line 2277 "cweave.w" +;break; +case tag:/*142:*/ +#line 2710 "cweave.w" + +#line 715 "cweave.ch" +if(alternative){ +if(cat1==tag){ +big_app1(pp);big_app(force);big_app1(pp+1);reduce(pp,2,tag,-1,74); +} +else if((cat1==stmt||cat1==decl||cat1==function)&& +(cat2==rbrace||cat2==tag)){ +big_app(force);big_app1(pp);big_app(indent);big_app(force); +big_app1(pp+1);big_app(outdent);reduce(pp,2,cat1,-1,75); +} +}else{ +if(cat1==tag){ +big_app1(pp);big_app(break_space);big_app1(pp+1);reduce(pp,2,tag,-1,74); +} +else if(cat1==stmt||cat1==decl||cat1==function){ +big_app(force);big_app(backup);big_app1(pp);big_app(break_space); +big_app1(pp+1);reduce(pp,2,cat1,-1,75); +} +} +#line 2718 "cweave.w" + +/*:142*/ +#line 2278 "cweave.w" +;break; +case semi:/*144:*/ +#line 2733 "cweave.w" + +big_app(' ');big_app1(pp);reduce(pp,1,stmt,-1,77); + +/*:144*/ +#line 2279 "cweave.w" +;break; +case lproc:/*145:*/ +#line 2736 "cweave.w" + +if(cat1==define_like)make_underlined(pp+2); +if(cat1==else_like||cat1==if_like||cat1==define_like) +squash(pp,2,lproc,0,78); +else if(cat1==rproc){ +app(inserted);big_app2(pp);reduce(pp,2,insert,-1,79); +#line 750 "cweave.ch" +}else if((cat1==exp||cat1==function||cat1==int_like)&&cat2==rproc){ +app(inserted);big_app1(pp);big_app(' ');big_app2(pp+1); +reduce(pp,3,insert,-1,80); +}else if((cat1==exp||cat1==int_like||cat1==const_like)&& +cat2==pp_space){ +if(cat3==int_like||cat3==const_like||cat3==raw_int) +make_reserved(pp+1,(pp+3)->cat); +big_app1(pp);big_app(' ');big_app1(pp+1);app_str(" \\5"); + +reduce(pp,3,lproc,-1,119); +}else if(cat1==exp&&cat2==exp&&cat3==pp_space){ +big_app1(pp);big_app(' ');big_app2(pp+1);app_str(" \\5"); +reduce(pp,4,lproc,-1,120); +} +#line 2753 "cweave.w" + +/*:145*/ +#line 2280 "cweave.w" +;break; +case section_scrap:/*146:*/ +#line 2754 "cweave.w" + +if(cat1==semi){ +big_app2(pp);big_app(force);reduce(pp,2,stmt,-2,81); +} +else squash(pp,1,exp,-2,82); + +/*:146*/ +#line 2281 "cweave.w" +;break; +case insert:/*147:*/ +#line 2760 "cweave.w" + +if(cat1) +squash(pp,2,cat1,0,83); + +/*:147*/ +#line 2282 "cweave.w" +;break; +case prelangle:/*148:*/ +#line 2764 "cweave.w" + +init_mathness= cur_mathness= yes_math; +app('<');reduce(pp,1,binop,-2,84); + +/*:148*/ +#line 2283 "cweave.w" +;break; +case prerangle:/*149:*/ +#line 2768 "cweave.w" + +init_mathness= cur_mathness= yes_math; +app('>');reduce(pp,1,binop,-2,85); + +/*:149*/ +#line 2284 "cweave.w" +;break; +case langle:/*150:*/ +#line 2772 "cweave.w" + +if(cat1==exp&&cat2==prerangle)squash(pp,3,cast,-1,86); +else if(cat1==prerangle){ +big_app1(pp);app('\\');app(',');big_app1(pp+1); + +reduce(pp,2,cast,-1,87); +} +else if(cat1==decl_head||cat1==int_like){ +if(cat2==prerangle)squash(pp,3,cast,-1,88); +else if(cat2==comma){ +big_app3(pp);app(opt);app('9');reduce(pp,3,langle,0,89); +} +} + +/*:150*/ +#line 2285 "cweave.w" +;break; +case public_like:/*151:*/ +#line 2786 "cweave.w" + +#line 771 "cweave.ch" +if(cat1==colon)squash(pp,2,tag,-2,90); +#line 2788 "cweave.w" +else squash(pp,1,int_like,-2,91); + +/*:151*/ +#line 2286 "cweave.w" +;break; +case colcol:/*152:*/ +#line 2790 "cweave.w" + +if(cat1==exp||cat1==int_like)squash(pp,2,cat1,-2,92); + +/*:152*/ +#line 2287 "cweave.w" +;break; +case new_like:/*153:*/ +#line 2793 "cweave.w" + +if(cat1==exp||(cat1==raw_int&&cat2!=prelangle&&cat2!=langle)){ +big_app1(pp);big_app(' ');big_app1(pp+1);reduce(pp,2,new_like,0,93); +} +else if(cat1==raw_unorbin||cat1==colcol) +squash(pp,2,new_like,0,94); +else if(cat1==cast)squash(pp,2,exp,-2,95); +else if(cat1!=lpar&&cat1!=raw_int&&cat1!=struct_like) +squash(pp,1,exp,-2,96); + +/*:153*/ +#line 2288 "cweave.w" +;break; +case operator_like:/*154:*/ +#line 2803 "cweave.w" + +#line 786 "cweave.ch" +if(cat1==binop||cat1==unop||cat1==unorbinop||cat1==raw_unorbin){ +if(cat2==binop)break; +big_app1(pp);big_app('{');big_app1(pp+1);big_app('}'); +reduce(pp,2,exp,-2,97); +} +else if(cat1==new_like||cat1==sizeof_like){ +big_app1(pp);big_app(' ');big_app1(pp+1);reduce(pp,2,exp,-2,98); +} +else if(cat1==raw_int||cat1==int_like||cat1==const_like){ +big_app1(pp);big_app(' ');big_app1(pp+1); +reduce(pp,2,operator_like,-2,118); +} +#line 2812 "cweave.w" +else squash(pp,1,new_like,0,99); + +/*:154*/ +#line 2289 "cweave.w" +;break; +case catch_like:/*155:*/ +#line 2814 "cweave.w" + +if(cat1==cast||cat1==exp){ +big_app2(pp);big_app(indent);big_app(indent); +reduce(pp,2,fn_decl,0,100); +} + +/*:155*/ +#line 2290 "cweave.w" +;break; +case base:/*156:*/ +#line 2820 "cweave.w" + +if(cat1==public_like&&cat2==exp){ +if(cat3==comma){ +big_app2(pp);big_app(' ');big_app2(pp+2); +reduce(pp,4,base,0,101); +}else{ +big_app1(pp+1);big_app(' ');big_app1(pp+2); +reduce(pp+1,2,int_like,-1,102); +} +} + +/*:156*/ +#line 2291 "cweave.w" +;break; +case raw_rpar:/*157:*/ +#line 2831 "cweave.w" + +if(cat1==const_like&& +(cat2==semi||cat2==lbrace||cat2==comma||cat2==binop +||cat2==const_like)){ +big_app1(pp);big_app(' '); +big_app1(pp+1);reduce(pp,2,raw_rpar,0,103); +}else squash(pp,1,rpar,-3,104); + +/*:157*/ +#line 2292 "cweave.w" +;break; +case raw_unorbin:/*158:*/ +#line 2839 "cweave.w" + +if(cat1==const_like){ +big_app2(pp);app_str("\\ ");reduce(pp,2,raw_unorbin,0,105); + +}else squash(pp,1,unorbinop,-2,106); + +/*:158*/ +#line 2293 "cweave.w" +;break; +case const_like:/*159:*/ +#line 2845 "cweave.w" + +squash(pp,1,int_like,-2,107); + +/*:159*/ +#line 2294 "cweave.w" +;break; +#line 392 "cweave.ch" +case raw_int:/*160:*/ +#line 2848 "cweave.w" + +if(cat1==lpar)squash(pp,1,exp,-2,108); +else squash(pp,1,int_like,-3,109); + +/*:160*/ +#line 392 "cweave.ch" +;break; +case label:/*249:*/ +#line 1075 "cweave.ch" + +if(cat1==label){ +big_app1(pp);big_app(force);big_app1(pp+1);reduce(pp,2,label,-1,112); +} +else if(cat1==stmt||cat1==decl||cat1==function){ +big_app(cancel);app(noop); +big_app(outdent);big_app(outdent);big_app(force); +big_app1(pp);big_app(indent);big_app(indent);big_app(force); +big_app1(pp+1);reduce(pp,2,cat1,-1,113); +} + +/*:249*/ +#line 393 "cweave.ch" +;break; +case do_head:/*250:*/ +#line 1086 "cweave.ch" + +if(cat1==stmt&&cat2==else_like&&cat3==semi){ +big_app1(pp);big_app(break_space);big_app1(pp+1);big_app(cancel); +app(noop);big_app(break_space);big_app2(pp+2);reduce(pp,4,stmt,-1,115); +} + +/*:250*/ +#line 394 "cweave.ch" +;break; +#line 2296 "cweave.w" +} +pp++; +} + +/*:110*/ +#line 2942 "cweave.w" +; +} + +/*:165*/ +#line 3002 "cweave.w" +; +/*170:*/ +#line 3011 "cweave.w" +{ +/*171:*/ +#line 3023 "cweave.w" + +if(lo_ptr>scrap_base&&tracing==1){ +printf("\nIrreducible scrap sequence in section %d:",section_count); + +mark_harmless; +for(j= scrap_base;j<=lo_ptr;j++){ +printf(" ");print_cat(j->cat); +} +} + +/*:171*/ +#line 3012 "cweave.w" +; +for(j= scrap_base;j<=lo_ptr;j++){ +if(j!=scrap_base)app(' '); +if(j->mathness%4==yes_math)app('$'); +app1(j); +if(j->mathness/4==yes_math)app('$'); +if(tok_ptr+6>tok_mem_end)overflow("token"); +} +freeze_text;return(text_ptr-1); +} + +/*:170*/ +#line 3003 "cweave.w" +; +} + +/*:169*//*173:*/ +#line 3059 "cweave.w" + +void +C_parse(spec_ctrl) +eight_bits spec_ctrl; +{ +int count; +while(next_control<format_code||next_control==spec_ctrl){ +/*175:*/ +#line 821 "cweave.ch" + +/*176:*/ +#line 3156 "cweave.w" + +if(scrap_ptr+safe_scrap_incr>scrap_info_end|| +tok_ptr+safe_tok_incr>tok_mem_end|| +text_ptr+safe_text_incr>tok_start_end){ +if(scrap_ptr>max_scr_ptr)max_scr_ptr= scrap_ptr; +if(tok_ptr>max_tok_ptr)max_tok_ptr= tok_ptr; +if(text_ptr>max_text_ptr)max_text_ptr= text_ptr; +overflow("scrap/token/text"); +} + +/*:176*/ +#line 822 "cweave.ch" +; +#line 3084 "cweave.w" +switch(next_control){ +case section_name: +app(section_flag+(int)(cur_section-name_dir)); +app_scrap(section_scrap,maybe_math); +app_scrap(exp,yes_math);break; +case string:case constant:case verbatim:/*178:*/ +#line 3211 "cweave.w" + +count= -1; +if(next_control==constant)app_str("\\T{"); + +else if(next_control==string){ +count= 20;app_str("\\.{"); +} + +else app_str("\\vb{"); + +while(id_first<id_loc){ +if(count==0){ +app_str("}\\)\\.{");count= 20; + +} + +if((eight_bits)(*id_first)>0177){ +app_tok(quoted_char); +app_tok((eight_bits)(*id_first++)); +} +else{ +switch(*id_first){ +case' ':case'\\':case'#':case'%':case'$':case'^': +case'{':case'}':case'~':case'&':case'_':app('\\');break; + + + +#line 913 "cweave.ch" + + + +#line 3241 "cweave.w" + + + + + +case'@':if(*(id_first+1)=='@')id_first++; +else err_print("! Double @ should be used in strings"); + +} +app_tok(*id_first++); +} +count--; +} +app('}'); +app_scrap(exp,maybe_math); + +/*:178*/ +#line 3089 "cweave.w" +; +break; +case identifier:app_cur_id(1);break; +case TeX_string:/*179:*/ +#line 3272 "cweave.w" + +app_str("\\hbox{"); + +while(id_first<id_loc) +if((eight_bits)(*id_first)>0177){ +app_tok(quoted_char); +app_tok((eight_bits)(*id_first++)); +} +else{ +if(*id_first=='@')id_first++; +app_tok(*id_first++); +} +app('}'); + +/*:179*/ +#line 3092 "cweave.w" +;break; +case'/':case'.': +app(next_control);app_scrap(binop,yes_math);break; +case'<':app_str("\\langle");app_scrap(prelangle,yes_math);break; + +case'>':app_str("\\rangle");app_scrap(prerangle,yes_math);break; + +case'=':app_str("\\K");app_scrap(binop,yes_math);break; + +case'|':app_str("\\OR");app_scrap(binop,yes_math);break; + +case'^':app_str("\\XOR");app_scrap(binop,yes_math);break; + +case'%':app_str("\\MOD");app_scrap(binop,yes_math);break; + +case'!':app_str("\\R");app_scrap(unop,yes_math);break; + +case'~':app_str("\\CM");app_scrap(unop,yes_math);break; + +case'+':case'-':app(next_control);app_scrap(unorbinop,yes_math);break; +case'*':app(next_control);app_scrap(raw_unorbin,yes_math);break; +case'&':app_str("\\AND");app_scrap(raw_unorbin,yes_math);break; + +case'?':app_str("\\?");app_scrap(question,yes_math);break; + +case'#':app_str("\\#");app_scrap(unorbinop,yes_math);break; + +case ignore:case xref_roman:case xref_wildcard: +case xref_typewriter:case noop:break; +#line 835 "cweave.ch" +case'(':if(func_index) +if(*(tok_ptr-1)>=id_flag&&*(tok_ptr-1)<res_flag) + +(name_dir+*(tok_ptr-1)%10240)->func_flag= 1; +case'[':app(next_control);app_scrap(lpar,maybe_math);break; +case')':case']':app(next_control);app_scrap(raw_rpar,maybe_math);break; +case'{':if(alternative) +app_str("\\LBR"); +else +app_str("\\{"); +app_scrap(lbrace,yes_math);break; + +case'}':if(alternative) +app_str("\\RBR"); +else +app_str("\\}"); +app_scrap(rbrace,yes_math);break; + +#line 3127 "cweave.w" +case',':app(',');app_scrap(comma,yes_math);break; +case';':app(';');app_scrap(semi,maybe_math);break; +case':':app(':');app_scrap(colon,maybe_math);break; +/*177:*/ +#line 3170 "cweave.w" + +case not_eq:app_str("\\I");app_scrap(binop,yes_math);break; + +case lt_eq:app_str("\\Z");app_scrap(binop,yes_math);break; + +case gt_eq:app_str("\\G");app_scrap(binop,yes_math);break; + +case eq_eq:app_str("\\E");app_scrap(binop,yes_math);break; + +case and_and:app_str("\\W");app_scrap(binop,yes_math);break; + +case or_or:app_str("\\V");app_scrap(binop,yes_math);break; + +case plus_plus:app_str("\\PP");app_scrap(unop,yes_math);break; + +case minus_minus:app_str("\\MM");app_scrap(unop,yes_math);break; + +case minus_gt:app_str("\\MG");app_scrap(binop,yes_math);break; + +case gt_gt:app_str("\\GG");app_scrap(binop,yes_math);break; + +case lt_lt:app_str("\\LL");app_scrap(binop,yes_math);break; + +case dot_dot_dot:app_str("\\,\\ldots\\,");app_scrap(exp,yes_math);break; + + +case colon_colon:app_str("\\DC");app_scrap(colcol,maybe_math);break; + +case period_ast:app_str("\\PA");app_scrap(binop,yes_math);break; + +#line 900 "cweave.ch" +case minus_gt_ast:app_str("\\MGA");app_scrap(binop,yes_math);break; + +case numb_numb:app_str("\\NN");app_scrap(binop,yes_math);break; + +#line 3202 "cweave.w" + +/*:177*/ +#line 3130 "cweave.w" + +case thin_space:app_str("\\,");app_scrap(insert,maybe_math);break; + +case math_break:app(opt);app_str("0"); +app_scrap(insert,maybe_math);break; +case line_break:app(force);app_scrap(insert,no_math);break; +#line 863 "cweave.ch" +case left_preproc:app(force);app(preproc_line); +app_str("\\#");app_scrap(lproc,no_math);break; + +case preproc_space:app(' ');app_scrap(pp_space,maybe_math);break; +case right_preproc:app(force);app_scrap(rproc,no_math);break; +#line 3140 "cweave.w" +case big_line_break:app(big_force);app_scrap(insert,no_math);break; +case no_line_break:app(big_cancel);app(noop);app(break_space); +app(noop);app(big_cancel); +app_scrap(insert,no_math);break; +#line 875 "cweave.ch" +case pseudo_semi:app_scrap(semi,maybe_math);break; +case pseudo_lbrace:app_str("\\phantom{"); +if(alternative) +app_str("\\LBR"); +else +app_str("\\{"); +app_str("}"); +app_scrap(lbrace,yes_math); +break; +case pseudo_rbrace:app_str("\\phantom{"); +if(alternative) +app_str("\\RBR"); +else +app_str("\\}"); +app_str("}"); +app_scrap(rbrace,yes_math); +break; +#line 3145 "cweave.w" +case macro_arg_open:app_scrap(begin_arg,maybe_math);break; +case macro_arg_close:app_scrap(end_arg,maybe_math);break; +case join:app_str("\\J");app_scrap(insert,no_math);break; + +case output_defs_code:app(force);app_str("\\ATH");app(force); +app_scrap(insert,no_math);break; + +default:app(inserted);app(next_control); +app_scrap(insert,maybe_math);break; +} + +/*:175*/ +#line 3066 "cweave.w" +; +next_control= get_next(); +if(next_control=='|'||next_control==begin_comment|| +next_control==begin_short_comment)return; +} +} + +/*:173*//*181:*/ +#line 3292 "cweave.w" + +void +app_cur_id(scrapping) +boolean scrapping; +{ +name_pointer p= id_lookup(id_first,id_loc,normal); +if(p->ilk<=quoted){ +app(id_flag+(int)(p-name_dir)); +if(scrapping)app_scrap(exp,p->ilk>=custom?yes_math:maybe_math); + +}else{ +app(res_flag+(int)(p-name_dir)); +if(scrapping)app_scrap(p->ilk,maybe_math); +} +} + +/*:181*//*182:*/ +#line 3313 "cweave.w" + +text_pointer +C_translate() +{ +text_pointer p; +scrap_pointer save_base; +save_base= scrap_base;scrap_base= scrap_ptr+1; +C_parse(section_name); +if(next_control!='|')err_print("! Missing '|' after C text"); + +app_tok(cancel);app_scrap(insert,maybe_math); + +p= translate(); +if(scrap_ptr>max_scr_ptr)max_scr_ptr= scrap_ptr; +scrap_ptr= scrap_base-1;scrap_base= save_base; +return(p); +} + +/*:182*//*183:*/ +#line 3335 "cweave.w" + +void +outer_parse() +{ +int bal; +text_pointer p,q; +while(next_control<format_code) +if(next_control!=begin_comment&&next_control!=begin_short_comment) +C_parse(ignore); +else{ +boolean is_long_comment= (next_control==begin_comment); +/*176:*/ +#line 3156 "cweave.w" + +if(scrap_ptr+safe_scrap_incr>scrap_info_end|| +tok_ptr+safe_tok_incr>tok_mem_end|| +text_ptr+safe_text_incr>tok_start_end){ +if(scrap_ptr>max_scr_ptr)max_scr_ptr= scrap_ptr; +if(tok_ptr>max_tok_ptr)max_tok_ptr= tok_ptr; +if(text_ptr>max_text_ptr)max_text_ptr= text_ptr; +overflow("scrap/token/text"); +} + +/*:176*/ +#line 3346 "cweave.w" +; +app(cancel);app(inserted); +if(is_long_comment)app_str("\\C{"); + +else app_str("\\SHC{"); + +bal= copy_comment(is_long_comment,1);next_control= ignore; +while(bal>0){ +p= text_ptr;freeze_text;q= C_translate(); + +app(tok_flag+(int)(p-tok_start)); +app_str("\\PB{");app(inner_tok_flag+(int)(q-tok_start));app_tok('}'); + +if(next_control=='|'){ +bal= copy_comment(is_long_comment,bal); +next_control= ignore; +} +else bal= 0; +} +app(force);app_scrap(insert,no_math); + +} +} + +/*:183*//*188:*/ +#line 3439 "cweave.w" + +void +push_level(p) +text_pointer p; +{ +if(stack_ptr==stack_end)overflow("stack"); +if(stack_ptr>stack){ +stack_ptr->end_field= cur_end; +stack_ptr->tok_field= cur_tok; +stack_ptr->mode_field= cur_mode; +} +stack_ptr++; +if(stack_ptr>max_stack_ptr)max_stack_ptr= stack_ptr; +cur_tok= *p;cur_end= *(p+1); +} + +/*:188*//*189:*/ +#line 3459 "cweave.w" + +void +pop_level() +{ +cur_end= (--stack_ptr)->end_field; +cur_tok= stack_ptr->tok_field;cur_mode= stack_ptr->mode_field; +} + +/*:189*//*191:*/ +#line 3481 "cweave.w" + +eight_bits +get_output() +{ +sixteen_bits a; +restart:while(cur_tok==cur_end)pop_level(); +a= *(cur_tok++); +if(a>=0400){ +cur_name= a%id_flag+name_dir; +switch(a/id_flag){ +case 2:return(res_word); +case 3:return(section_code); +case 4:push_level(a%id_flag+tok_start);goto restart; + +case 5:push_level(a%id_flag+tok_start);cur_mode= inner;goto restart; + +default:return(identifier); +} +} +return(a); +} + +/*:191*//*192:*/ +#line 3523 "cweave.w" + +void +output_C() +{ +token_pointer save_tok_ptr; +text_pointer save_text_ptr; +sixteen_bits save_next_control; +text_pointer p; +save_tok_ptr= tok_ptr;save_text_ptr= text_ptr; +save_next_control= next_control;next_control= ignore;p= C_translate(); +app(inner_tok_flag+(int)(p-tok_start)); +out_str("\\PB{");make_output();out('}'); + +if(text_ptr>max_text_ptr)max_text_ptr= text_ptr; +if(tok_ptr>max_tok_ptr)max_tok_ptr= tok_ptr; +text_ptr= save_text_ptr;tok_ptr= save_tok_ptr; +next_control= save_next_control; +} + +/*:192*//*194:*/ +#line 3547 "cweave.w" + +void +make_output() +{ +eight_bits a, +b; +int c; +char scratch[longest_name]; +char*k,*k_limit; +char*j; +char*p; +char delim; +char*save_loc,*save_limit; +name_pointer cur_section_name; +boolean save_mode; +app(end_translation); +freeze_text;push_level(text_ptr-1); +while(1){ +a= get_output(); +reswitch:switch(a){ +case end_translation:return; +case identifier:case res_word:/*195:*/ +#line 3597 "cweave.w" + +out('\\'); +if(a==identifier){ +if(cur_name->ilk>=custom&&cur_name->ilk<=quoted&&!doing_format){ +for(p= cur_name->byte_start;p<(cur_name+1)->byte_start;p++) +out(isxalpha(*p)?'x':*p); +break; +#line 923 "cweave.ch" +}else if(is_tiny(cur_name))out('|'); +#line 3605 "cweave.w" + +else{delim= '.'; +for(p= cur_name->byte_start;p<(cur_name+1)->byte_start;p++) +if(xislower(*p)){ +delim= '\\';break; +} +out(delim); +} + + +} +#line 931 "cweave.ch" +else out('&'); +#line 3617 "cweave.w" + +if(is_tiny(cur_name)){ +if(isxalpha((cur_name->byte_start)[0])) +out('\\'); +out((cur_name->byte_start)[0]); +} +else out_name(cur_name); + +/*:195*/ +#line 3568 "cweave.w" +;break; +case section_code:/*199:*/ +#line 3695 "cweave.w" +{ +out_str("\\X"); + +cur_xref= (xref_pointer)cur_name->xref; +if(cur_xref->num==file_flag){an_output= 1;cur_xref= cur_xref->xlink;} +else an_output= 0; +if(cur_xref->num>=def_flag){ +out_section(cur_xref->num-def_flag); +if(phase==3){ +cur_xref= cur_xref->xlink; +while(cur_xref->num>=def_flag){ +out_str(", "); +out_section(cur_xref->num-def_flag); +cur_xref= cur_xref->xlink; +} +} +} +else out('0'); +out(':'); +if(an_output)out_str("\\.{"); + +/*200:*/ +#line 3721 "cweave.w" + +sprint_section_name(scratch,cur_name); +k= scratch; +k_limit= scratch+strlen(scratch); +cur_section_name= cur_name; +while(k<k_limit){ +b= *(k++); +if(b=='@')/*201:*/ +#line 3756 "cweave.w" + +if(*k++!='@'){ +printf("\n! Illegal control code in section name: <"); + +print_section_name(cur_section_name);printf("> ");mark_error; +} + +/*:201*/ +#line 3728 "cweave.w" +; +if(an_output) +switch(b){ +case' ':case'\\':case'#':case'%':case'$':case'^': +case'{':case'}':case'~':case'&':case'_': +out('\\'); + + + +#line 949 "cweave.ch" + + + +#line 3740 "cweave.w" + + + + + +default:out(b); +} +#line 959 "cweave.ch" +else if(b!='|')out(b); +#line 3748 "cweave.w" +else{ +/*202:*/ +#line 3769 "cweave.w" + +j= limit+1;*j= '|';delim= 0; +while(1){ +if(k>=k_limit){ +printf("\n! C text in section name didn't end: <"); + +print_section_name(cur_section_name);printf("> ");mark_error;break; +} +b= *(k++); +if(b=='@'||(b=='\\'&&delim!=0)) +/*203:*/ +#line 3792 "cweave.w" +{ +if(j>buffer+long_buf_size-4)overflow("buffer"); +*(++j)= b;*(++j)= *(k++); +} + +/*:203*/ +#line 3779 "cweave.w" + +else{ +if(b=='\''||b=='"') +if(delim==0)delim= b; +else if(delim==b)delim= 0; +if(b!='|'||delim!=0){ +if(j>buffer+long_buf_size-3)overflow("buffer"); +*(++j)= b; +} +else break; +} +} + +/*:202*/ +#line 3749 "cweave.w" +; +save_loc= loc;save_limit= limit;loc= limit+2;limit= j+1; +*limit= '|';output_C(); +loc= save_loc;limit= save_limit; +} +} + +/*:200*/ +#line 3716 "cweave.w" +; +if(an_output)out_str(" }"); +out_str("\\X"); +} + +/*:199*/ +#line 3569 "cweave.w" +;break; +case math_rel:out_str("\\MRL{"); + +case noop:case inserted:break; +case cancel:case big_cancel:c= 0;b= a; +while(1){ +a= get_output(); +if(a==inserted)continue; +if((a<indent&&!(b==big_cancel&&a==' '))||a>big_force)break; +if(a==indent)c++;else if(a==outdent)c--; +else if(a==opt)a= get_output(); +} +/*198:*/ +#line 3682 "cweave.w" + +for(;c>0;c--)out_str("\\1"); + +for(;c<0;c++)out_str("\\2"); + + +/*:198*/ +#line 3581 "cweave.w" +; +goto reswitch; +case indent:case outdent:case opt:case backup:case break_space: +case force:case big_force:case preproc_line:/*196:*/ +#line 3628 "cweave.w" + +if(a<break_space||a==preproc_line){ +if(cur_mode==outer){ +out('\\');out(a-cancel+'0'); + + + + + +if(a==opt){ +b= get_output(); +#line 939 "cweave.ch" +if(b!='0'||force_lines==0)out(b); +#line 3640 "cweave.w" +else out_str("{-1}"); +} +}else if(a==opt)b= get_output(); +} +else/*197:*/ +#line 3652 "cweave.w" +{ +b= a;save_mode= cur_mode;c= 0; +while(1){ +a= get_output(); +if(a==inserted)continue; +if(a==cancel||a==big_cancel){ +/*198:*/ +#line 3682 "cweave.w" + +for(;c>0;c--)out_str("\\1"); + +for(;c<0;c++)out_str("\\2"); + + +/*:198*/ +#line 3658 "cweave.w" +; +goto reswitch; +} +if((a!=' '&&a<indent)||a==backup||a>big_force){ +if(save_mode==outer){ +if(out_ptr>out_buf+3&&strncmp(out_ptr-3,"\\Y\\B",4)==0) +goto reswitch; +/*198:*/ +#line 3682 "cweave.w" + +for(;c>0;c--)out_str("\\1"); + +for(;c<0;c++)out_str("\\2"); + + +/*:198*/ +#line 3665 "cweave.w" +; +out('\\');out(b-cancel+'0'); + + + +if(a!=end_translation)finish_line(); +} +else if(a!=end_translation&&cur_mode==inner)out(' '); +goto reswitch; +} +if(a==indent)c++; +else if(a==outdent)c--; +else if(a==opt)a= get_output(); +else if(a>b)b= a; +} +} + +/*:197*/ +#line 3644 "cweave.w" + + +/*:196*/ +#line 3585 "cweave.w" +;break; +case quoted_char:out(*(cur_tok++));break; +default:out(a); +} +} +} + +/*:194*//*205:*/ +#line 3807 "cweave.w" + +void +phase_two(){ +reset_input();if(show_progress)printf("\nWriting the output file..."); + +section_count= 0;format_visible= 1;copy_limbo(); +finish_line();flush_buffer(out_buf,0,0); +while(!input_has_ended)/*207:*/ +#line 3840 "cweave.w" +{ +section_count++; +/*208:*/ +#line 3858 "cweave.w" + +if(*(loc-1)!='*')out_str("\\M"); + +else{ +while(*loc==' ')loc++; +if(*loc=='*'){ +sec_depth= -1; +loc++; +} +else{ +for(sec_depth= 0;xisdigit(*loc);loc++) +sec_depth= sec_depth*10+(*loc)-'0'; +} +while(*loc==' ')loc++; +group_found= 1; +out_str("\\N"); + +{char s[32];sprintf(s,"{%d}",sec_depth+1);out_str(s);} +if(show_progress) +printf("*%d",section_count);update_terminal; +} +out_str("{");out_section(section_count);out_str("}"); + +/*:208*/ +#line 3842 "cweave.w" +; +save_position; +/*209:*/ +#line 3884 "cweave.w" +do{ +next_control= copy_TeX(); +switch(next_control){ +case'|':init_stack;output_C();break; +case'@':out('@');break; +case TeX_string:case noop: +case xref_roman:case xref_wildcard:case xref_typewriter: +case section_name:loc-= 2;next_control= get_next(); +if(next_control==TeX_string) +err_print("! TeX string should be in C text only");break; + +#line 972 "cweave.ch" +case thin_space:case math_break:case ord: +case line_break:case big_line_break:case no_line_break:case join: +case pseudo_semi:case macro_arg_open:case macro_arg_close: +case pseudo_lbrace:case pseudo_rbrace: +case output_defs_code: +err_print("! You can't do that in TeX text");break; + +#line 3901 "cweave.w" +} +}while(next_control<format_code); + +/*:209*/ +#line 3844 "cweave.w" +; +/*210:*/ +#line 3907 "cweave.w" + +space_checked= 0; +while(next_control<=definition){ +init_stack; +if(next_control==definition)/*213:*/ +#line 3965 "cweave.w" +{ +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"); + +if((next_control= get_next())!=identifier) +err_print("! Improper macro definition"); + +else{ +app('$');app_cur_id(0); +#line 992 "cweave.ch" +if(*loc=='('){ +if(func_index) +(name_dir+*(tok_ptr-1)%10240)->func_flag= 1; +reswitch:switch(next_control= get_next()){ +case'(':case',':app(next_control);goto reswitch; +case identifier:app_cur_id(0);goto reswitch; +case')':app(next_control);next_control= get_next();break; +default:err_print("! Improper macro definition");break; +} +} +#line 3982 "cweave.w" +else next_control= get_next(); +app_str("$ ");app(break_space); +app_scrap(dead,no_math); +} +} + +/*:213*/ +#line 3911 "cweave.w" + +else/*214:*/ +#line 3988 "cweave.w" +{ +doing_format= 1; +if(*(loc-1)=='s'||*(loc-1)=='S')format_visible= 0; +if(!space_checked){emit_space_if_needed;save_position;} +app_str("\\F"); + +next_control= get_next(); +if(next_control==identifier){ +app(id_flag+(int)(id_lookup(id_first,id_loc,normal)-name_dir)); +app(' '); +app(break_space); +next_control= get_next(); +if(next_control==identifier){ +app(id_flag+(int)(id_lookup(id_first,id_loc,normal)-name_dir)); +app_scrap(exp,maybe_math);app_scrap(semi,maybe_math); +next_control= get_next(); +} +} +if(scrap_ptr!=scrap_info+2)err_print("! Improper format definition"); + +} + +/*:214*/ +#line 3912 "cweave.w" +; +outer_parse();finish_C(format_visible);format_visible= 1; +doing_format= 0; +} + +/*:210*/ +#line 3845 "cweave.w" +; +/*216:*/ +#line 4017 "cweave.w" + +this_section= name_dir; +if(next_control<=section_name){ +emit_space_if_needed;init_stack; +if(next_control==begin_C)next_control= get_next(); +else{ +this_section= cur_section; +/*217:*/ +#line 4037 "cweave.w" + +do next_control= get_next(); +while(next_control=='+'); +if(next_control!='='&&next_control!=eq_eq) +err_print("! You need an = sign after the section name"); + +else next_control= get_next(); +if(out_ptr>out_buf+1&&*out_ptr=='Y'&&*(out_ptr-1)=='\\')app(backup); + + +app(section_flag+(int)(this_section-name_dir)); +cur_xref= (xref_pointer)this_section->xref; +if(cur_xref->num==file_flag)cur_xref= cur_xref->xlink; +app_str("${}"); +if(cur_xref->num!=section_count+def_flag){ +app_str("\\mathrel+"); +this_section= name_dir; +} +app_str("\\E"); + +app_str("{}$"); +app(force);app_scrap(dead,no_math); + + +/*:217*/ +#line 4025 "cweave.w" +; +} +while(next_control<=section_name){ +outer_parse(); +/*218:*/ +#line 4061 "cweave.w" + +if(next_control<section_name){ +err_print("! You can't do that in C text"); + +next_control= get_next(); +} +else if(next_control==section_name){ +app(section_flag+(int)(cur_section-name_dir)); +app_scrap(section_scrap,maybe_math); +next_control= get_next(); +} + +/*:218*/ +#line 4029 "cweave.w" +; +} +finish_C(1); +} + +/*:216*/ +#line 3846 "cweave.w" +; +/*219:*/ +#line 4076 "cweave.w" + +if(this_section>name_dir){ +cur_xref= (xref_pointer)this_section->xref; +if(cur_xref->num==file_flag){an_output= 1;cur_xref= cur_xref->xlink;} +else an_output= 0; +if(cur_xref->num>def_flag) +cur_xref= cur_xref->xlink; +footnote(def_flag);footnote(cite_flag);footnote(0); +} + +/*:219*/ +#line 3847 "cweave.w" +; +/*223:*/ +#line 4134 "cweave.w" + +out_str("\\fi");finish_line(); + +flush_buffer(out_buf,0,0); + +/*:223*/ +#line 3848 "cweave.w" +; +} + +/*:207*/ +#line 3814 "cweave.w" +; +} + +/*:205*//*212:*/ +#line 3930 "cweave.w" + +void +finish_C(visible) +boolean visible; +{ +text_pointer p; +if(visible){ +out_str("\\B");app_tok(force);app_scrap(insert,no_math); +p= translate(); + +app(tok_flag+(int)(p-tok_start));make_output(); +if(out_ptr>out_buf+1) +if(*(out_ptr-1)=='\\') + + + +if(*out_ptr=='6')out_ptr-= 2; +else if(*out_ptr=='7')*out_ptr= 'Y'; +out_str("\\par");finish_line(); +} +if(text_ptr>max_text_ptr)max_text_ptr= text_ptr; +if(tok_ptr>max_tok_ptr)max_tok_ptr= tok_ptr; +if(scrap_ptr>max_scr_ptr)max_scr_ptr= scrap_ptr; +tok_ptr= tok_mem+1;text_ptr= tok_start+1;scrap_ptr= scrap_info; + +} + +/*:212*//*221:*/ +#line 4101 "cweave.w" + +void +footnote(flag) +sixteen_bits flag; +{ +xref_pointer q; +if(cur_xref->num<=flag)return; +finish_line();out('\\'); + + + +out(flag==0?'U':flag==cite_flag?'Q':'A'); +/*222:*/ +#line 4121 "cweave.w" + +q= cur_xref;if(q->xlink->num>flag)out('s'); +while(1){ +out_section(cur_xref->num-flag); +cur_xref= cur_xref->xlink; +if(cur_xref->num<=flag)break; +if(cur_xref->xlink->num>flag)out_str(", "); +else{out_str("\\ET"); + +if(cur_xref!=q->xlink)out('s'); +} +} + +/*:222*/ +#line 4113 "cweave.w" +; +out('.'); +} + +/*:221*//*225:*/ +#line 4150 "cweave.w" + +void +phase_three(){ +if(no_xref){ +finish_line(); +out_str("\\end"); + +finish_line(); +} +else{ +phase= 3;if(show_progress)printf("\nWriting the index..."); + +finish_line(); +if((idx_file= fopen(idx_file_name,"w"))==NULL) +fatal("! Cannot open index file ",idx_file_name); + +if(change_exists){ +/*227:*/ +#line 4201 "cweave.w" +{ + +k_section= 0; +while(!changed_section[++k_section]); +out_str("\\ch "); + +out_section(k_section); +while(k_section<section_count){ +while(!changed_section[++k_section]); +out_str(", ");out_section(k_section); +} +out('.'); +} + +/*:227*/ +#line 4167 "cweave.w" +;finish_line();finish_line(); +} +out_str("\\inx");finish_line(); + +active_file= idx_file; +/*229:*/ +#line 4232 "cweave.w" +{ +int c; +for(c= 0;c<=255;c++)bucket[c]= NULL; +for(h= hash;h<=hash_end;h++){ +next_name= *h; +while(next_name){ +cur_name= next_name;next_name= cur_name->link; +if(cur_name->xref!=(char*)xmem){ +c= (eight_bits)((cur_name->byte_start)[0]); +if(xisupper(c))c= tolower(c); +blink[cur_name-name_dir]= bucket[c];bucket[c]= cur_name; +} +} +} +} + +/*:229*/ +#line 4172 "cweave.w" +; +/*238:*/ +#line 4348 "cweave.w" + +sort_ptr= scrap_info;unbucket(1); +while(sort_ptr>scrap_info){ +cur_depth= sort_ptr->depth; +if(blink[sort_ptr->head-name_dir]==0||cur_depth==infinity) +/*240:*/ +#line 4373 "cweave.w" +{ +cur_name= sort_ptr->head; +do{ +out_str("\\I"); + +/*241:*/ +#line 4385 "cweave.w" + +#line 1036 "cweave.ch" +switch(cur_name->ilk){ +case normal: +if(is_tiny(cur_name)&&!cur_name->func_flag) +out_str("\\|"); +else{char*j; +for(j= cur_name->byte_start;j<(cur_name+1)->byte_start;j++) +if(xislower(*j))goto lowcase; +out_str("\\.");break; +lowcase:out_str("\\\\"); +} +break; + + + +case roman:break; +case wildcard:out_str("\\9");break; + +case typewriter:out_str("\\.");break; + +case custom:case quoted:{char*j;out_str("$\\"); +for(j= cur_name->byte_start;j<(cur_name+1)->byte_start;j++) +out(isxalpha(*j)?'x':*j); +out('$'); +goto name_done; +} +default:out_str("\\&"); + +} +out_name(cur_name); +name_done: +if(cur_name->func_flag) +out_str("(\\,)"); +#line 4414 "cweave.w" + +/*:241*/ +#line 4378 "cweave.w" +; +/*242:*/ +#line 4418 "cweave.w" + +/*244:*/ +#line 4436 "cweave.w" + +this_xref= (xref_pointer)cur_name->xref;cur_xref= xmem; +do{ +next_xref= this_xref->xlink;this_xref->xlink= cur_xref; +cur_xref= this_xref;this_xref= next_xref; +}while(this_xref!=xmem); + +/*:244*/ +#line 4419 "cweave.w" +; +do{ +out_str(", ");cur_val= cur_xref->num; +if(cur_val<def_flag)out_section(cur_val); +else{out_str("\\[");out_section(cur_val-def_flag);out(']');} + +cur_xref= cur_xref->xlink; +}while(cur_xref!=xmem); +out('.');finish_line(); + +/*:242*/ +#line 4379 "cweave.w" +; +cur_name= blink[cur_name-name_dir]; +}while(cur_name); +--sort_ptr; +} + +/*:240*/ +#line 4353 "cweave.w" + +else/*239:*/ +#line 4357 "cweave.w" +{ +eight_bits c; +next_name= sort_ptr->head; +do{ +cur_name= next_name;next_name= blink[cur_name-name_dir]; +cur_byte= cur_name->byte_start+cur_depth; +if(cur_byte==(cur_name+1)->byte_start)c= 0; +else{ +c= (eight_bits)*cur_byte; +if(xisupper(c))c= tolower(c); +} +blink[cur_name-name_dir]= bucket[c];bucket[c]= cur_name; +}while(next_name); +--sort_ptr;unbucket(cur_depth+1); +} + +/*:239*/ +#line 4354 "cweave.w" +; +} + +/*:238*/ +#line 4173 "cweave.w" +; +finish_line();fclose(active_file); +active_file= tex_file; +out_str("\\fin");finish_line(); + +if((scn_file= fopen(scn_file_name,"w"))==NULL) +fatal("! Cannot open section file ",scn_file_name); + +active_file= scn_file; +/*247:*/ +#line 4467 "cweave.w" +section_print(root) + +/*:247*/ +#line 4182 "cweave.w" +; +finish_line();fclose(active_file); +active_file= tex_file; +if(group_found)out_str("\\con");else out_str("\\end"); + + +finish_line(); +fclose(active_file); +} +if(show_happiness)printf("\nDone."); +check_complete(); +} + +/*:225*//*237:*/ +#line 4330 "cweave.w" + +void +unbucket(d) +eight_bits d; +{ +int c; + +for(c= 100+128;c>=0;c--)if(bucket[collate[c]]){ + +if(sort_ptr>=scrap_info_end)overflow("sorting"); +sort_ptr++; +if(sort_ptr>max_sort_ptr)max_sort_ptr= sort_ptr; +if(c==0)sort_ptr->depth= infinity; +else sort_ptr->depth= d; +sort_ptr->head= bucket[collate[c]];bucket[collate[c]]= NULL; +} +} + +/*:237*//*246:*/ +#line 4450 "cweave.w" + +void +section_print(p) +name_pointer p; +{ +if(p){ +section_print(p->llink);out_str("\\I"); + +tok_ptr= tok_mem+1;text_ptr= tok_start+1;scrap_ptr= scrap_info;init_stack; +app(p-name_dir+section_flag);make_output(); +footnote(cite_flag); +footnote(0); +finish_line(); +section_print(p->rlink); +} +} + +/*:246*//*248:*/ +#line 4472 "cweave.w" + +void +print_stats(){ +printf("\nMemory usage statistics:\n"); + +printf("%ld names (out of %ld)\n", +(long)(name_ptr-name_dir),(long)max_names); +printf("%ld cross-references (out of %ld)\n", +(long)(xref_ptr-xmem),(long)max_refs); +printf("%ld bytes (out of %ld)\n", +(long)(byte_ptr-byte_mem),(long)max_bytes); +printf("Parsing:\n"); +printf("%ld scraps (out of %ld)\n", +(long)(max_scr_ptr-scrap_info),(long)max_scraps); +printf("%ld texts (out of %ld)\n", +(long)(max_text_ptr-tok_start),(long)max_texts); +printf("%ld tokens (out of %ld)\n", +(long)(max_tok_ptr-tok_mem),(long)max_toks); +printf("%ld levels (out of %ld)\n", +(long)(max_stack_ptr-stack),(long)stack_size); +printf("Sorting:\n"); +printf("%ld levels (out of %ld)\n", +(long)(max_sort_ptr-scrap_info),(long)max_scraps); +} + +#line 1075 "cweave.ch" +/*:248*/ diff --git a/web/c_cpp/c2cweb/cweb/cweave.ch b/web/c_cpp/c2cweb/cweb/cweave.ch new file mode 100644 index 0000000000..035de5a5e3 --- /dev/null +++ b/web/c_cpp/c2cweb/cweb/cweave.ch @@ -0,0 +1,1095 @@ +This file is part of the c2cweb package Version 1.5 + +This is a change file for CWEB's CWEAVE (Ver. 3.4g June 1996) + +modified by Werner Lemberg (a7971428@@unet.univie.ac.at) 10-Nov-1996 + +=============================================================================== + +An exclamation mark (!) removes a bug in the original CWEAVE which caused +unbalanced braces sometimes. + +One star (*) marks changes of the productions if switch a is set -- +please look at an output to see what. Additionally cwebmaca.tex will be used +by TeX instead of cwebmac.tex . + +Two stars (**) mark changes to the index routines: function definitions will +now have () after the identifier if the i switch is on (this will work properly +only if you don't have function names identical to names of variables, +structures etc.). + +Three stars (***) change the debugging output slightly. + +A (+) enables the dollar sign `$' in identifiers; some compilers allow it, +and it doesn't harm in the output. + +Two plus (++) improve the processing of #define statements (weird things +like '#define short int'). Two new control codes are introduced: @{ and @} +(i.e. invisible braces). You will need this if you have unbalanced braces due +to #ifdef ... #endif statements. The concatenation operator ## will be now +recognized. + +Three plus (+++) implement exotic cases of C++ (look e.g. for "iostream.h"). + + +These changes are not perfect yet; if you don't like some things, remove the +specified sections. (Or better, improve them and send the new change file(s) +to me :-) + + +@x in limbo +\let\maybe=\iftrue +@y +\let\maybe=\iffalse +@z + +@x section 1 +@d banner "This is CWEAVE (Version 3.4)\n" +@y +@d banner "This is CWEAVE (Version 3.4) modified by Werner Lemberg (V1.5)\n" +@z + +@x section 4 +@d max_bytes 90000 /* the number of bytes in identifiers, + index entries, and section names */ +@d max_names 4000 /* number of identifiers, strings, section names; + must be less than 10240; used in |"common.w"| */ +@d max_sections 2000 /* greater than the total number of sections */ +@d hash_size 353 /* should be prime */ +@d buf_size 100 /* maximum length of input line, plus one */ +@d longest_name 1000 /* section names and strings shouldn't be longer than this */ +@d long_buf_size (buf_size+longest_name) +@d line_length 80 /* lines of \TEX/ output have at most this many characters; + should be less than 256 */ +@d max_refs 20000 /* number of cross-references; must be less than 65536 */ +@d max_toks 20000 /* number of symbols in \CEE/ texts being parsed; + must be less than 65536 */ +@d max_texts 4000 /* number of phrases in \CEE/ texts being parsed; + must be less than 10240 */ +@d max_scraps 2000 /* number of tokens in \CEE/ texts being parsed */ +@d stack_size 400 /* number of simultaneous output levels */ +@y +@d max_bytes 225000 /* the number of bytes in identifiers, + index entries, and section names */ +@d max_names 10000 /* number of identifiers, strings, section names; + must be less than 10240; used in |"common.w"| */ +@d max_sections 2000 /* greater than the total number of sections */ +@d hash_size 353 /* should be prime */ +@d buf_size 400 /* maximum length of input line, plus one */ +@d longest_name 1000 /* section names and strings shouldn't be longer than this */ +@d long_buf_size (buf_size+longest_name) +@d line_length 100 /* lines of \TEX/ output have at most this many characters; + should be less than 256 */ +@d max_refs 20000 /* number of cross-references; must be less than 65536 */ +@d max_toks 65000 /* number of symbols in \CEE/ texts being parsed; + must be less than 65536 */ +@d max_texts 10200 /* number of phrases in \CEE/ texts being parsed; + must be less than 10240 */ +@d max_scraps 65000 /* number of tokens in \CEE/ texts being parsed */ +@d stack_size 10000 /* number of simultaneous output levels */ +@z + +** + +@x section 16 +@d ilk dummy.Ilk +@y +@d ilk dummy.dummy1.Ilk +@d func_flag dummy.dummy1.Func_flag +@z + +++ + +@x section 30 +@d new_section 0231 /* control code for `\.{@@\ }' and `\.{@@*}' */ +@y +@d new_section 0231 /* control code for `\.{@@\ }' and `\.{@@*}' */ +@d pseudo_lbrace 022 /* control code for `\.{@@\{}' */ +@d pseudo_rbrace 023 /* control code for `\.{@@\}}' */ +@z + +++ + +@x section 32 +ccode['+']=no_line_break; ccode[';']=pseudo_semi; +ccode['[']=macro_arg_open; ccode[']']=macro_arg_close; +@y +ccode['+']=no_line_break; ccode[';']=pseudo_semi; +ccode['{']=pseudo_lbrace; ccode['}']=pseudo_rbrace; +ccode['[']=macro_arg_open; ccode[']']=macro_arg_close; +@z + ++ + +@x section 39 +@d isxalpha(c) ((c)=='_') /* non-alpha character allowed in identifier */ +@y +@d isxalpha(c) ((c)=='_' || (c)=='$') + /* non-alpha characters allowed in identifier */ +@z + +++ + +@x section 40 +eight_bits +get_next() /* produces the next input token */ +{@+eight_bits c; /* the current character */ + while (1) { + @<Check if we're at the end of a preprocessor command@>; + if (loc>limit && get_line()==0) return(new_section); + c=*(loc++); + if (xisdigit(c) || c=='\\' || c=='.') @<Get a constant@>@; + else if (c=='\'' || c=='"' || (c=='L'&&(*loc=='\'' || *loc=='"'))@| + || (c=='<' && sharp_include_line==1)) + @<Get a string@>@; + else if (xisalpha(c) || isxalpha(c) || ishigh(c)) + @<Get an identifier@>@; + else if (c=='@@') @<Get control code and possible section name@>@; + else if (xisspace(c)) continue; /* ignore spaces and tabs */ + if (c=='#' && loc==buffer+1) @<Raise preprocessor flag@>; + mistake: @<Compress two-symbol operator@>@; + return(c); + } +} +@y +eight_bits +get_next() /* produces the next input token */ +{@+eight_bits c; /* the current character */ + int blank_count=0; /* number of leading blanks */ + + if (loc<limit && preprocessing && (define_pos==2 || define_pos==4) && + xisspace(*loc)) { + define_pos=5; + return(preproc_space); + } + + while (1) { + @<Check if we're at the end of a preprocessor command@>; + if (loc>limit && get_line()==0) return(new_section); + + if(loc==buffer) { + blank_count=0; + while((*loc==' ' || *loc=='\t') && loc<limit) { + blank_count++; loc++; + } + } + + c=*(loc++); + if (xisdigit(c) || c=='\\' || c=='.') @<Get a constant@>@; + else if (c=='\'' || c=='"' || (c=='L'&&(*loc=='\'' || *loc=='"'))@| + || (c=='<' && sharp_include_line==1)) + @<Get a string@>@; + else if (xisalpha(c) || isxalpha(c) || ishigh(c)) + @<Get an identifier@>@; + else if (c=='@@') @<Get control code and possible section name@>@; + else if (xisspace(c)) continue; /* ignore spaces and tabs */ + if (c=='#' && loc==buffer+1+blank_count && !preprocessing) + @<Raise preprocessor flag@>; + mistake: @<Compress two-symbol operator@>@; + if(preprocessing) { + if (c=='(' && define_pos==2 && !xisspace(*(loc-2))) + define_pos=3; + else if (c==')' && define_pos==3) + define_pos=4; + } + return(c); + } +} +@z + +++ + +@x section 41 +@d left_preproc ord /* begins a preprocessor command */ +@d right_preproc 0217 /* ends a preprocessor command */ + +@<Glob...@>= +boolean preprocessing=0; /* are we scanning a preprocessor command? */ +@y +@d left_preproc ord /* begins a preprocessor command */ +@d right_preproc 0217 /* ends a preprocessor command */ +@d preproc_space '\b' /* emitted before the macro sustitution */ +@d numb_numb '\f' /* `\.{\#\#}'\,; the concatenation operator */ + +@<Glob...@>= +boolean preprocessing=0; /* are we scanning a preprocessor command? */ +int define_pos=0; + /* at which position we are while scanning a macro definition */ +@z + +++ + +@x section 45 + if (loc>=limit && preprocessing) { + preprocessing=sharp_include_line=0; + return(right_preproc); + } +@y + if (loc>=limit && preprocessing) { + preprocessing=sharp_include_line=define_pos=0; + return(right_preproc); + } +@z + +++ + +@x section 46 + case '!': if (*loc=='=') compress(not_eq); break; +@y + case '!': if (*loc=='=') compress(not_eq); break; + case '#': if (*loc=='#') compress(numb_numb); break; +@z + +++ + +@x section 47 + id_first=--loc; + while (isalpha(*++loc) || isdigit(*loc) || isxalpha(*loc) || ishigh(*loc)); + id_loc=loc; return(identifier); +@y + id_first=--loc; + + if (preprocessing) { + if (define_pos==1) + define_pos=2; + else if (strncmp(loc, "define", 6)==0 && xisspace(*(loc+6))) + define_pos=1; + } + + while (isalpha(*++loc) || isdigit(*loc) || isxalpha(*loc) || ishigh(*loc)); + id_loc=loc; return(identifier); +@z + +! + +@x section 77 +int out_line; /* number of next line to be output */ +@y +int out_line; /* number of next line to be output */ + +boolean in_math = 0; +boolean escape = 0; +int math_brace_count = 0; +@z + +* + +@x section 80 +out_ptr=out_buf+1; out_line=1; active_file=tex_file; +*out_ptr='c'; tex_printf("\\input cwebma"); +@y +out_ptr=out_buf+1; out_line=1; active_file=tex_file; +if(alternative) { + *out_ptr='a'; + tex_printf("\\input cwebmac"); +} else { + *out_ptr='c'; + tex_printf("\\input cwebma"); +} +@z + +! + +@x section 81 +@d out(c) {if (out_ptr>=out_buf_end) break_out(); *(++out_ptr)=c;} + +@c +@y +@c +void +out(c) +char c; +{ + if (out_ptr >= out_buf_end) + break_out(); + + if(!escape) { + if(in_math) { + if(c == '{') + math_brace_count++; + else if(c == '}') { + math_brace_count--; + if(math_brace_count < 0) { + math_brace_count = 0; + return; + } + } + } + if(c == '$') { + while(math_brace_count > 0) { + *(++out_ptr) = '}'; + math_brace_count--; + } + in_math = 1 - in_math; + } + } + + if(c == '\\' && !escape) + escape = 1; + else + escape = 0; + + *(++out_ptr) = c; + return; +} +@z + +* + +@x section 97 +@d tag 29 /* denotes a statement label */ +@y +@d tag 29 + /* denotes a statement label (if |alternative| is set, only a case label) */ +@z + +*, ++ + +@x section 97 +@d end_arg 59 /* \.{@@]} */ +@y +@d end_arg 59 /* \.{@@]} */ +@d label 60 /* denotes a label; used if |alternative| is set */ +@d do_head 61 /* used if |alternative| is set */ +@d pp_space 62 /* denotes the start point of a macro replacement text */ +@z + +*, ++ + +@x section 98 + strcpy(cat_name[end_arg],@q[@>"@@]"); +@y + strcpy(cat_name[end_arg],@q[@>"@@]"); + strcpy(cat_name[label],"label"); /* used if |alternative| is set */ + strcpy(cat_name[do_head], "do_head"); /* used if |alternative| is set */ + strcpy(cat_name[pp_space], "#_"); +@z + +++ section 101 + +@x +\.:&|colon|: \.:&maybe\cr +\.\# (within line)&|unorbinop|: \.{\\\#}&yes\cr +@y +\.:&|colon|: \.:&maybe\cr +\.{\#\#}&|binop|: \.{\\NN}&yes\cr +\.\# (within line)&|unorbinop|: \.{\\\#}&yes\cr +@z + +* + +@x section 101 +@i prod.w +@y +@i prod-alt.w +@z + +* + +@x section 110 + case raw_int: @<Cases for |raw_int|@>; @+break; +@y + case raw_int: @<Cases for |raw_int|@>; @+break; + case label: @<Cases for |label|@>; @+break; + case do_head: @<Cases for |do_head|@>; @+break; +@z + +++ + +@x section 112 +void +make_reserved(p) /* 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| */ + if ((tok_loc=find_first_ident(p->trans))==no_ident_found) + return; /* this should not happen */ + tok_value=*tok_loc; + for (;p<=scrap_ptr; p==lo_ptr? p=hi_ptr: p++) { + if (p->cat==exp) { + if (**(p->trans)==tok_value) { + p->cat=raw_int; + **(p->trans)=tok_value%id_flag+res_flag; + } + } + } + (name_dir+(sixteen_bits)(tok_value%id_flag))->ilk=raw_int; + *tok_loc=tok_value%id_flag+res_flag; +} +@y +void +make_reserved(p, cat) /* make the first identifier in |p->trans| like |cat| */ +scrap_pointer p; +eight_bits cat; +{ + sixteen_bits tok_value; /* the name of this identifier, plus its flag*/ + token_pointer tok_loc; /* pointer to |tok_value| */ + if ((tok_loc=find_first_ident(p->trans))==no_ident_found) + return; /* this should not happen */ + tok_value=*tok_loc; + for (;p<=scrap_ptr; p==lo_ptr? p=hi_ptr: p++) { + if (p->cat==exp || p->cat==int_like || p->cat==const_like) { + if (**(p->trans)==tok_value) { + p->cat=cat; + **(p->trans)=tok_value%id_flag+res_flag; + } + } + } + (name_dir+(sixteen_bits)(tok_value%id_flag))->ilk=cat; + *tok_loc=tok_value%id_flag+res_flag; +} +@z + +* + +@x section 117 + make_underlined (pp); squash(pp,2,tag,0,7); +@y + make_underlined (pp); + if(alternative) + squash(pp,2,label,0,7); + else + squash(pp,2,tag,0,7); +@z + ++++ + +@x section 125 + else squash(pp,2,int_like,-2,32); +} +@y + else squash(pp,2,int_like,-2,32); +} +else if (cat1==binop && cat2==exp) squash(pp,3,int_like,-2,117); +@z + +++ + +@x section 128 +if (cat1==decl_head) + if ((cat2==exp&&cat3!=lpar&&cat3!=exp)||cat2==int_like) { + make_underlined(pp+2); make_reserved(pp+2); + big_app2(pp+1); reduce(pp+1,2,decl_head,0,42); + } + else if (cat2==semi) { + big_app1(pp); big_app(' '); big_app2(pp+1); reduce(pp,3,decl,-1,43); + } +@y +if (cat1==decl_head) { + if ((cat2==exp&&cat3!=lpar&&cat3!=exp)||cat2==int_like) { + make_underlined(pp+2); make_reserved(pp+2, raw_int); + big_app2(pp+1); reduce(pp+1,2,decl_head,0,42); + } + else if (cat2==semi) { + big_app1(pp); big_app(' '); big_app2(pp+1); reduce(pp,3,decl,-1,43); + } +} +else if (cat1==exp && !preprocessing && cat2!=lpar) { + make_reserved(pp+1, raw_int); + squash(pp+1,1,raw_int,-2,116); +} +@z + +* + +@x section 129 +if (cat1==lbrace) { + big_app1(pp); big_app(' '); big_app1(pp+1); reduce(pp,2,struct_head,0,44); +} +else if (cat1==exp||cat1==int_like) { + if (cat2==lbrace || cat2==semi) { + make_underlined(pp+1); make_reserved(pp+1); + big_app1(pp); big_app(' '); big_app1(pp+1); + if (cat2==semi) reduce(pp,2,decl_head,0,45); + else { + big_app(' '); big_app1(pp+2);reduce(pp,3,struct_head,0,46); + } + } + else if (cat2==colon) squash(pp+2,1,base,-1,47); + else if (cat2!=base) { + big_app1(pp); big_app(' '); big_app1(pp+1); reduce(pp,2,int_like,-2,48); + } +} +@y +if (cat1==lbrace) { + if(alternative) { + big_app1(pp); big_app(indent); big_app(force); big_app(backup); + big_app1(pp+1); reduce(pp,2,struct_head,0,44); + } else { + big_app1(pp); big_app(' '); big_app1(pp+1); + reduce(pp,2,struct_head,0,44); + } +} +else if (cat1==exp||cat1==int_like) { + if (cat2==lbrace || cat2==semi) { + make_underlined(pp+1); make_reserved(pp+1, raw_int); + big_app1(pp); big_app(' '); big_app1(pp+1); + if (cat2==semi) reduce(pp,2,decl_head,-1,45); + else { + if(alternative) { + big_app(indent); big_app(force); big_app(backup); big_app1(pp+2); + reduce(pp,3,struct_head,0,46); + } else { + big_app(' '); big_app1(pp+2); reduce(pp,3,struct_head,0,46); + } + } + } + else if (cat2==colon) squash(pp+2,1,base,-1,47); + else if (!(cat2==base || cat2==raw_int || + cat2==int_like || cat2==const_like)) { + big_app1(pp); big_app(' '); big_app1(pp+1); reduce(pp,2,int_like,-2,48); + } +} +@z + +* + +@x section 130 + big_app1(pp); big_app(indent); big_app(force); big_app1(pp+1); + big_app(outdent); big_app(force); big_app1(pp+2); + reduce(pp,3,int_like,-2,49); +@y + if(alternative) { + big_app1(pp); big_app1(pp+1); + big_app(force); big_app(backup); big_app1(pp+2); big_app(' '); + big_app(outdent); reduce(pp,3,int_like,-2,49); + } else { + big_app1(pp); big_app(indent); big_app(force); big_app1(pp+1); + big_app(outdent); big_app(force); big_app1(pp+2); + reduce(pp,3,int_like,-2,49); + } +@z + +* + +@x section 133 + 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); +@y + if(alternative) { + big_app(indent); big_app(force); big_app(backup); big_app1(pp); + app(noop); big_app(cancel); big_app1(pp+1); big_app(force); big_app(backup); + big_app1(pp+2); big_app(outdent); big_app(force); reduce(pp,3,stmt,-2,55); + } else { + 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); + } +@z + +* + +@x section 136 + big_app(force); big_app1(pp); big_app(indent); big_app(break_space); + big_app1(pp+1); big_app(outdent); big_app(force); + reduce(pp,2,stmt,-1,60); +@y + if(alternative) { + big_app(force); big_app1(pp); big_app(indent); big_app(force); + big_app1(pp+1); big_app(outdent); big_app(force); + reduce(pp,2,stmt,-1,60); + } else { + big_app(force); big_app1(pp); big_app(indent); big_app(break_space); + big_app1(pp+1); big_app(outdent); big_app(force); + reduce(pp,2,stmt,-1,60); + } +@z + +* + +@x section 137 + big_app(force); big_app1(pp); big_app(break_space); app(noop); + big_app(cancel); big_app1(pp+1); big_app(force); + reduce(pp,2,stmt,-1,61); +@y + if(alternative) { + big_app(force); big_app1(pp); big_app(break_space); + big_app1(pp+1); big_app(force); + reduce(pp,2,stmt,-1,61); + } else { + big_app(force); big_app1(pp); big_app(break_space); app(noop); + big_app(cancel); big_app1(pp+1); big_app(force); + reduce(pp,2,stmt,-1,61); + } +@z + +* + +@x section 138 + big_app(force); big_app1(pp); big_app(indent); big_app(break_space); + big_app1(pp+1); big_app(outdent); big_app(force); big_app1(pp+2); + if (cat3==if_like) { + big_app(' '); big_app1(pp+3); reduce(pp,4,if_like,0,63); + }@+else reduce(pp,3,else_like,0,64); +@y + if(alternative) { + big_app(force); big_app1(pp); big_app(indent); big_app(force); + big_app1(pp+1); big_app(outdent); big_app(force); big_app1(pp+2); + } else { + big_app(force); big_app1(pp); big_app(indent); big_app(break_space); + big_app1(pp+1); big_app(outdent); big_app(force); big_app1(pp+2); + } + if (cat3==if_like) { + big_app(' '); big_app1(pp+3); reduce(pp,4,if_like,0,63); + }@+else reduce(pp,3,else_like,0,64); +@z + +* + +@x section 139 + big_app(force); big_app1(pp); big_app(break_space); app(noop); + big_app(cancel); big_app1(pp+1); big_app(force); big_app1(pp+2); + if (cat3==if_like) { + big_app(' '); big_app1(pp+3); reduce(pp,4,if_like,0,66); + }@+else reduce(pp,3,else_like,0,67); +@y + if(alternative) { + big_app(force); big_app1(pp); big_app(break_space); + big_app1(pp+1); big_app(force); big_app1(pp+2); + } else { + big_app(force); big_app1(pp); big_app(break_space); app(noop); + big_app(cancel); big_app1(pp+1); big_app(force); big_app1(pp+2); + } + if (cat3==if_like) { + big_app(' '); big_app1(pp+3); reduce(pp,4,if_like,0,66); + }@+else reduce(pp,3,else_like,0,67); +@z + +* + +@x section 140 +if (cat1==stmt && cat2==else_like && cat3==semi) { + big_app1(pp); big_app(break_space); app(noop); big_app(cancel); + big_app1(pp+1); big_app(cancel); app(noop); big_app(break_space); + big_app2(pp+2); reduce(pp,4,stmt,-1,69); +} +@y +if(alternative) { + if (cat1==lbrace) squash(pp,1,do_head,0,114); + else if (cat1==stmt && cat2==else_like && cat3==semi) { + big_app(force); big_app1(pp); big_app(indent); big_app(force); + big_app1(pp+1); big_app(cancel); app(noop); + big_app(break_space); big_app2(pp+2); big_app(outdent); big_app(force); + reduce(pp,4,stmt,-1,69); + } +} else { + if (cat1==stmt && cat2==else_like && cat3==semi) { + big_app1(pp); big_app(break_space); app(noop); big_app(cancel); + big_app1(pp+1); big_app(cancel); app(noop); big_app(break_space); + big_app2(pp+2); reduce(pp,4,stmt,-1,69); + } +} +@z + +* + +@x section 141 +if (cat1==semi) squash(pp,2,stmt,-1,70); +else if (cat1==colon) squash(pp,2,tag,-1,71); +@y +if (cat1==semi) squash(pp,2,stmt,-3,70); +else if (cat1==colon) squash(pp,2,tag,-2,71); +@z + +* + +@x section 141 + reduce(pp,3,tag,-1,73); +@y + reduce(pp,3,tag,-2,73); +@z + +* + +@x section 142 +if (cat1==tag) { + big_app1(pp); big_app(break_space); big_app1(pp+1); reduce(pp,2,tag,-1,74); +} +else if (cat1==stmt||cat1==decl||cat1==function) { + big_app(force); big_app(backup); big_app1(pp); big_app(break_space); + big_app1(pp+1); reduce(pp,2,cat1,-1,75); +} +@y +if(alternative) { + if (cat1==tag) { + big_app1(pp); big_app(force); big_app1(pp+1); reduce(pp,2,tag,-1,74); + } + else if ((cat1==stmt||cat1==decl||cat1==function) && + (cat2==rbrace||cat2==tag)) { + big_app(force); big_app1(pp); big_app(indent); big_app(force); + big_app1(pp+1); big_app(outdent); reduce(pp,2,cat1,-1,75); + } +} else { + if (cat1==tag) { + big_app1(pp); big_app(break_space); big_app1(pp+1); reduce(pp,2,tag,-1,74); + } + else if (cat1==stmt||cat1==decl||cat1==function) { + big_app(force); big_app(backup); big_app1(pp); big_app(break_space); + big_app1(pp+1); reduce(pp,2,cat1,-1,75); + } +} +@z + +++ + +@x section 145 +} else if (cat1==exp || cat1==function) { + if (cat2==rproc) { + app(inserted); big_app1(pp); big_app(' '); big_app2(pp+1); + reduce(pp,3,insert,-1,80); + } + else if (cat2==exp && cat3==rproc && cat1==exp) { + app(inserted); big_app1(pp); big_app(' '); big_app1(pp+1); app_str(" \\5"); +@.\\5@> + big_app2(pp+2); reduce(pp,4,insert,-1,80); + } +} +@y +} else if ((cat1==exp || cat1==function || cat1==int_like) && cat2==rproc) { + app(inserted); big_app1(pp); big_app(' '); big_app2(pp+1); + reduce(pp,3,insert,-1,80); +} else if ((cat1==exp || cat1==int_like || cat1==const_like) && + cat2==pp_space) { + if(cat3==int_like || cat3==const_like || cat3==raw_int) + make_reserved(pp+1, (pp+3)->cat); + big_app1(pp); big_app(' '); big_app1(pp+1); app_str(" \\5"); +@.\\5@> + reduce(pp,3,lproc,-1,119); +} else if (cat1==exp && cat2==exp && cat3==pp_space) { + big_app1(pp); big_app(' '); big_app2(pp+1); app_str(" \\5"); + reduce(pp,4,lproc,-1,120); +} +@z + +* + +@x section 151 +if (cat1==colon) squash(pp,2,tag,-1,90); +@y +if (cat1==colon) squash(pp,2,tag,-2,90); +@z + ++++ + +@x section 154 +if (cat1==binop || cat1==unop || cat1==unorbinop) { + if (cat2==binop) break; + big_app1(pp); big_app('{'); big_app1(pp+1); big_app('}'); + reduce(pp,2,exp,-2,97); +} +else if (cat1==new_like || cat1==sizeof_like) { + big_app1(pp); big_app(' '); big_app1(pp+1); reduce(pp,2,exp,-2,98); +} +@y +if (cat1==binop || cat1==unop || cat1==unorbinop || cat1==raw_unorbin) { + if (cat2==binop) break; + big_app1(pp); big_app('{'); big_app1(pp+1); big_app('}'); + reduce(pp,2,exp,-2,97); +} +else if (cat1==new_like || cat1==sizeof_like) { + big_app1(pp); big_app(' '); big_app1(pp+1); reduce(pp,2,exp,-2,98); +} +else if (cat1==raw_int || cat1==int_like || cat1==const_like) { + big_app1(pp); big_app(' '); big_app1(pp+1); + reduce(pp,2,operator_like,-2,118); +} +@z + +*** This makes the tracing info looking smoother + +@x section 168 + if (tracing==2) { + printf("\n%d:",n); +@y + if (tracing==2) { + printf("\n%3d:",n); +@z + +**, ++ + +@x section 175 +@ @<Append the scr...@>= +@<Make sure that there is room for the new scraps, tokens, and texts@>; +@y +@ +@d alternative flags['a'] /* if set, an alternative format is produced */ +@d func_index flags['i'] + /* should functions in the index have |()| appended? */ + +@<Append the scr...@>= +@<Make sure that there is room for the new scraps, tokens, and texts@>; +@z + +*, ** + +@x section 175 + case '(': case '[': app(next_control); app_scrap(lpar,maybe_math);@+break; + case ')': case ']': app(next_control); app_scrap(raw_rpar,maybe_math);@+break; + case '{': app_str("\\{"@q}@>); app_scrap(lbrace,yes_math);@+break; +@.\\\{@>@q}@> + case '}': app_str(@q{@>"\\}"); app_scrap(rbrace,yes_math);@+break; +@q{@>@.\\\}@> +@y + case '(': if(func_index) + if(*(tok_ptr-1)>=id_flag && *(tok_ptr-1)<res_flag) + /* an identifier? */ + (name_dir+ *(tok_ptr-1)%10240)->func_flag=1; + case '[': app(next_control); app_scrap(lpar,maybe_math);@+break; + case ')': case ']': app(next_control); app_scrap(raw_rpar,maybe_math);@+break; + case '{': if(alternative) + app_str("\\LBR"); + else + app_str("\\{"@q}@>); + app_scrap(lbrace,yes_math);@+break; +@.\\\{@>@q}@> + case '}': if(alternative) + app_str("\\RBR"); + else + app_str(@q{@>"\\}"); + app_scrap(rbrace,yes_math);@+break; +@q{@>@.\\\}@> +@z + +++ + +@x section 175 + case left_preproc: app(force); app(preproc_line); + app_str("\\#"); app_scrap(lproc,no_math);@+break; +@.\\\#@> + case right_preproc: app(force); app_scrap(rproc,no_math);@+break; +@y + case left_preproc: app(force); app(preproc_line); + app_str("\\#"); app_scrap(lproc,no_math);@+break; +@.\\\#@> + case preproc_space: app(' '); app_scrap(pp_space, maybe_math);@+break; + case right_preproc: app(force); app_scrap(rproc,no_math);@+break; +@z + +++ + +@x section 175 + case pseudo_semi: app_scrap(semi,maybe_math);@+break; +@y + case pseudo_semi: app_scrap(semi,maybe_math);@+break; + case pseudo_lbrace: app_str("\\phantom{"); + if(alternative) + app_str("\\LBR"); + else + app_str("\\{"@q}@>); + app_str("}"); + app_scrap(lbrace,yes_math); + break; + case pseudo_rbrace: app_str("\\phantom{"); + if(alternative) + app_str("\\RBR"); + else + app_str(@q{@>"\\}"); + app_str("}"); + app_scrap(rbrace,yes_math); + break; +@z + +++ + +@x section 177 +case minus_gt_ast: app_str("\\MGA");@+app_scrap(binop,yes_math);@+break; +@.\\MGA@> +@y +case minus_gt_ast: app_str("\\MGA");@+app_scrap(binop,yes_math);@+break; +@.\\MGA@> +case numb_numb: app_str("\\NN");@+app_scrap(binop,yes_math);@+break; +@.\\NN@> +@z + +** + +@x section 178 +@.\\\%@> +@.\\\$@> +@.\\\^@> +@y +@.\\\%@> +@.\\$@> @q CWEAVE quotes a dollar sign! @> +@.\\\^@> +@z + +! + +@x section 195 + } else if (is_tiny(cur_name)) out('|') +@y + } else if (is_tiny(cur_name)) out('|'); +@z + +! + +@x section 195 +else out('&') /* |a==res_word| */ +@y +else out('&'); /* |a==res_word| */ +@z + +! + +@x section 196 + if (b!='0' || force_lines==0) out(b)@; +@y + if (b!='0' || force_lines==0) out(b); +@z + +** + +@x section 200 +@.\\\%@> +@.\\\$@> +@.\\\^@> +@y +@.\\\%@> +@.\\$@> @q CWEAVE quotes a dollar symbol! @> +@.\\\^@> +@z + +! + +@x section 200 + else if (b!='|') out(b) +@y + else if (b!='|') out(b); +@z + +++ + +@x section 209 + case thin_space: case math_break: case ord: + case line_break: case big_line_break: case no_line_break: case join: + case pseudo_semi: case macro_arg_open: case macro_arg_close: + case output_defs_code: + err_print("! You can't do that in TeX text"); break; +@.You can't do that...@> +@y + case thin_space: case math_break: case ord: + case line_break: case big_line_break: case no_line_break: case join: + case pseudo_semi: case macro_arg_open: case macro_arg_close: + case pseudo_lbrace: case pseudo_rbrace: + case output_defs_code: + err_print("! You can't do that in TeX text"); break; +@.You can't do that...@> +@z + +** + +@x section 213 + if (*loc=='(') + reswitch: switch (next_control=get_next()) { + case '(': case ',': app(next_control); goto reswitch; + case identifier: app_cur_id(0); goto reswitch; + case ')': app(next_control); next_control=get_next(); break; + default: err_print("! Improper macro definition"); break; + } +@y + if (*loc=='(') { + if(func_index) + (name_dir+ *(tok_ptr-1)%10240)->func_flag=1; + reswitch: switch (next_control=get_next()) { + case '(': case ',': app(next_control); goto reswitch; + case identifier: app_cur_id(0); goto reswitch; + case ')': app(next_control); next_control=get_next(); break; + default: err_print("! Improper macro definition"); break; + } + } +@z + +** + +@x section 241 +switch (cur_name->ilk) { + case normal: if (is_tiny(cur_name)) out_str("\\|"); + else {char *j; + for (j=cur_name->byte_start;j<(cur_name+1)->byte_start;j++) + if (xislower(*j)) goto lowcase; + out_str("\\."); break; +lowcase: out_str("\\\\"); + } + break; +@.\\|@> +@.\\.@> +@.\\\\@> + case roman: break; + case wildcard: out_str("\\9"); break; +@.\\9@> + case typewriter: out_str("\\."); break; +@.\\.@> + case custom: case quoted: {char *j; out_str("$\\"); + for (j=cur_name->byte_start;j<(cur_name+1)->byte_start;j++) + out(isxalpha(*j)? 'x' : *j); + out('$'); + goto name_done; + } + default: out_str("\\&"); +@.\\\&@> +} +out_name(cur_name); +name_done: +@y +switch (cur_name->ilk) { + case normal: + if (is_tiny(cur_name) && !cur_name->func_flag) + out_str("\\|"); + else {char *j; + for (j=cur_name->byte_start;j<(cur_name+1)->byte_start;j++) + if (xislower(*j)) goto lowcase; + out_str("\\."); break; +lowcase: out_str("\\\\"); + } + break; +@.\\|@> +@.\\.@> +@.\\\\@> + case roman: break; + case wildcard: out_str("\\9"); break; +@.\\9@> + case typewriter: out_str("\\."); break; +@.\\.@> + case custom: case quoted: {char *j; out_str("$\\"); + for (j=cur_name->byte_start;j<(cur_name+1)->byte_start;j++) + out(isxalpha(*j)? 'x' : *j); + out('$'); + goto name_done; + } + default: out_str("\\&"); +@.\\\&@> +} +out_name(cur_name); +name_done: + if(cur_name->func_flag) + out_str("(\\,)"); +@z + +* + +@x section 249 +@** Index. +@y +@ @<Cases for |label|@>= +if (cat1==label) { + big_app1(pp); big_app(force); big_app1(pp+1); reduce(pp,2,label,-1,112); +} +else if (cat1==stmt||cat1==decl||cat1==function) { + big_app(cancel); app(noop); + big_app(outdent); big_app(outdent); big_app(force); + big_app1(pp); big_app(indent); big_app(indent); big_app(force); + big_app1(pp+1); reduce(pp,2,cat1,-1,113); +} + +@ @<Cases for |do_head|@>= +if (cat1==stmt && cat2==else_like && cat3==semi) { + big_app1(pp); big_app(break_space); big_app1(pp+1); big_app(cancel); + app(noop); big_app(break_space); big_app2(pp+2); reduce(pp,4,stmt,-1,115); +} + +@** Index. +@z + +--- end of cweave.ch --- diff --git a/web/c_cpp/c2cweb/cweb/cweave.def b/web/c_cpp/c2cweb/cweb/cweave.def new file mode 100644 index 0000000000..71fd302fae --- /dev/null +++ b/web/c_cpp/c2cweb/cweb/cweave.def @@ -0,0 +1,3 @@ +NAME CWEAVE WINDOWCOMPAT +DESCRIPTION 'CWEAVE 3.2' +STACKSIZE 0x80000 diff --git a/web/c_cpp/c2cweb/cweb/cweave.w b/web/c_cpp/c2cweb/cweb/cweave.w new file mode 100644 index 0000000000..6c08b6bc80 --- /dev/null +++ b/web/c_cpp/c2cweb/cweb/cweave.w @@ -0,0 +1,4505 @@ +% This file is part of CWEB. +% This program by Silvio Levy and Donald E. Knuth +% is based on a program by Knuth. +% It is distributed WITHOUT ANY WARRANTY, express or implied. +% Version 3.4 --- April 1995 + +% Copyright (C) 1987,1990,1993 Silvio Levy and Donald E. Knuth + +% Permission is granted to make and distribute verbatim copies of this +% document provided that the copyright notice and this permission notice +% are preserved on all copies. + +% Permission is granted to copy and distribute modified versions of this +% document under the conditions for verbatim copying, provided that the +% entire resulting derived work is given a different name and distributed +% under the terms of a permission notice identical to this one. + +% Here is TeX material that gets inserted after \input cwebmac +\def\hang{\hangindent 3em\indent\ignorespaces} +\def\pb{$\.|\ldots\.|$} % C brackets (|...|) +\def\v{\char'174} % vertical (|) in typewriter font +\def\dleft{[\![} \def\dright{]\!]} % double brackets +\mathchardef\RA="3221 % right arrow +\mathchardef\BA="3224 % double arrow +\def\({} % ) kludge for alphabetizing certain section names +\def\TeXxstring{\\{\TEX/\_string}} +\def\skipxTeX{\\{skip\_\TEX/}} +\def\copyxTeX{\\{copy\_\TEX/}} + +\def\title{CWEAVE (Version 3.4)} +\def\topofcontents{\null\vfill + \centerline{\titlefont The {\ttitlefont CWEAVE} processor} + \vskip 15pt + \centerline{(Version 3.4)} + \vfill} +\def\botofcontents{\vfill +\noindent +Copyright \copyright\ 1987, 1990, 1993 Silvio Levy and Donald E. Knuth +\bigskip\noindent +Permission is granted to make and distribute verbatim copies of this +document provided that the copyright notice and this permission notice +are preserved on all copies. + +\smallskip\noindent +Permission is granted to copy and distribute modified versions of this +document under the conditions for verbatim copying, provided that the +entire resulting derived work is given a different name and distributed +under the terms of a permission notice identical to this one. +} +\pageno=\contentspagenumber \advance\pageno by 1 +\let\maybe=\iftrue + +@** Introduction. +This is the \.{CWEAVE} program by Silvio Levy and Donald E. Knuth, +based on \.{WEAVE} by Knuth. +We are thankful to Steve Avery, +Nelson Beebe, Hans-Hermann Bode (to whom the \CPLUSPLUS/ adaptation is due), +Klaus Guntermann, Norman Ramsey, Tomas Rokicki, Joachim Schnitter, +Joachim Schrod, Lee Wittenberg, and others who have contributed improvements. + +The ``banner line'' defined here should be changed whenever \.{CWEAVE} +is modified. + +@d banner "This is CWEAVE (Version 3.4)\n" + +@c @<Include files@>@/ +@h +@<Common code for \.{CWEAVE} and \.{CTANGLE}@>@/ +@<Typedef declarations@>@/ +@<Global variables@>@/ +@<Predeclaration of procedures@> + +@ We predeclare several standard system functions here instead of including +their system header files, because the names of the header files are not as +standard as the names of the functions. (For example, some \CEE/ environments +have \.{<string.h>} where others have \.{<strings.h>}.) + +@<Predecl...@>= +extern int strlen(); /* length of string */ +extern int strcmp(); /* compare strings lexicographically */ +extern char* strcpy(); /* copy one string to another */ +extern int strncmp(); /* compare up to $n$ string characters */ +extern char* strncpy(); /* copy up to $n$ string characters */ + +@ \.{CWEAVE} has a fairly straightforward outline. It operates in +three phases: First it inputs the source file and stores cross-reference +data, then it inputs the source once again and produces the \TEX/ output +file, finally it sorts and outputs the index. + +Please read the documentation for \.{common}, the set of routines common +to \.{CTANGLE} and \.{CWEAVE}, before proceeding further. + +@c +int main (ac, av) +int ac; /* argument count */ +char **av; /* argument values */ +{ + argc=ac; argv=av; + program=cweave; + make_xrefs=force_lines=1; /* controlled by command-line options */ + common_init(); + @<Set initial values@>; + if (show_banner) printf(banner); /* print a ``banner line'' */ + @<Store all the reserved words@>; + phase_one(); /* read all the user's text and store the cross-references */ + phase_two(); /* read all the text again and translate it to \TEX/ form */ + phase_three(); /* output the cross-reference index */ + return wrap_up(); /* and exit gracefully */ +} + +@ The following parameters were sufficient in the original \.{WEAVE} to +handle \TEX/, so they should be sufficient for most applications of \.{CWEAVE}. +If you change |max_bytes|, |max_names|, |hash_size| or |buf_size| +you have to change them also in the file |"common.w"|. + +@d max_bytes 90000 /* the number of bytes in identifiers, + index entries, and section names */ +@d max_names 4000 /* number of identifiers, strings, section names; + must be less than 10240; used in |"common.w"| */ +@d max_sections 2000 /* greater than the total number of sections */ +@d hash_size 353 /* should be prime */ +@d buf_size 100 /* maximum length of input line, plus one */ +@d longest_name 1000 /* section names and strings shouldn't be longer than this */ +@d long_buf_size (buf_size+longest_name) +@d line_length 80 /* lines of \TEX/ output have at most this many characters; + should be less than 256 */ +@d max_refs 20000 /* number of cross-references; must be less than 65536 */ +@d max_toks 20000 /* number of symbols in \CEE/ texts being parsed; + must be less than 65536 */ +@d max_texts 4000 /* number of phrases in \CEE/ texts being parsed; + must be less than 10240 */ +@d max_scraps 2000 /* number of tokens in \CEE/ texts being parsed */ +@d stack_size 400 /* number of simultaneous output levels */ + +@ The next few sections contain stuff from the file |"common.w"| that must +be included in both |"ctangle.w"| and |"cweave.w"|. It appears in +file |"common.h"|, which needs to be updated when |"common.w"| changes. + +@i common.h + +@* Data structures exclusive to {\tt CWEAVE}. +As explained in \.{common.w}, the field of a |name_info| structure +that contains the |rlink| of a section name is used for a completely +different purpose in the case of identifiers. It is then called the +|ilk| of the identifier, and it is used to +distinguish between various types of identifiers, as follows: + +\yskip\hang |normal| identifiers are part of the \CEE/ program and +will appear in italic type. + +\yskip\hang |roman| identifiers are index entries that appear after +\.{@@\^} in the \.{CWEB} file. + +\yskip\hang |wildcard| identifiers are index entries that appear after +\.{@@:} in the \.{CWEB} file. + +\yskip\hang |typewriter| identifiers are index entries that appear after +\.{@@.} in the \.{CWEB} file. + +\yskip\hang |else_like|, \dots, |typedef_like| +identifiers are \CEE/ reserved words whose |ilk| explains how they are +to be treated when \CEE/ code is being formatted. + +@d ilk dummy.Ilk +@d normal 0 /* ordinary identifiers have |normal| ilk */ +@d roman 1 /* normal index entries have |roman| ilk */ +@d wildcard 2 /* user-formatted index entries have |wildcard| ilk */ +@d typewriter 3 /* `typewriter type' entries have |typewriter| ilk */ +@d abnormal(a) (a->ilk>typewriter) /* tells if a name is special */ +@d custom 4 /* identifiers with user-given control sequence */ +@d unindexed(a) (a->ilk>custom) /* tells if uses of a name are to be indexed */ +@d quoted 5 /* \.{NULL} */ +@d else_like 26 /* \&{else} */ +@d public_like 40 /* \&{public}, \&{private}, \&{protected} */ +@d operator_like 41 /* \&{operator} */ +@d new_like 42 /* \&{new} */ +@d catch_like 43 /* \&{catch} */ +@d for_like 45 /* \.{for}, \&{switch}, \&{while} */ +@d do_like 46 /* \&{do} */ +@d if_like 47 /* \&{if}, \&{ifdef}, \&{endif}, \&{pragma}, \dots */ +@d raw_rpar 48 /* `\.)' or `\.]' when looking for \&{const} following */ +@d raw_unorbin 49 /* `\.\&' or `\.*' when looking for \&{const} following */ +@d const_like 50 /* \&{const}, \&{volatile} */ +@d raw_int 51 /* \&{int}, \&{char}, \&{extern}, \dots */ +@d int_like 52 /* same, when not followed by left parenthesis */ +@d case_like 53 /* \&{case}, \&{return}, \&{goto}, \&{break}, \&{continue} */ +@d sizeof_like 54 /* \&{sizeof} */ +@d struct_like 55 /* \&{struct}, \&{union}, \&{enum}, \&{class} */ +@d typedef_like 56 /* \&{typedef} */ +@d define_like 57 /* \&{define} */ + +@ We keep track of the current section number in |section_count|, which +is the total number of sections that have started. Sections which have +been altered by a change file entry have their |changed_section| flag +turned on during the first phase. + +@<Global...@>= +boolean change_exists; /* has any section changed? */ + +@ The other large memory area in \.{CWEAVE} keeps the cross-reference data. +All uses of the name |p| are recorded in a linked list beginning at +|p->xref|, which points into the |xmem| array. The elements of |xmem| +are structures consisting of an integer, |num|, and a pointer |xlink| +to another element of |xmem|. If |x=p->xref| is a pointer into |xmem|, +the value of |x->num| is either a section number where |p| is used, +or |cite_flag| plus a section number where |p| is mentioned, +or |def_flag| plus a section number where |p| is defined; +and |x->xlink| points to the next such cross-reference for |p|, +if any. This list of cross-references is in decreasing order by +section number. The next unused slot in |xmem| is |xref_ptr|. +The linked list ends at |&xmem[0]|. + +The global variable |xref_switch| is set either to |def_flag| or to zero, +depending on whether the next cross-reference to an identifier is to be +underlined or not in the index. This switch is set to |def_flag| when +\.{@@!} or \.{@@d} is scanned, and it is cleared to zero when +the next identifier or index entry cross-reference has been made. +Similarly, the global variable |section_xref_switch| is either +|def_flag| or |cite_flag| or zero, depending +on whether a section name is being defined, cited or used in \CEE/ text. + +@<Type...@>= +typedef struct xref_info { + sixteen_bits num; /* section number plus zero or |def_flag| */ + struct xref_info *xlink; /* pointer to the previous cross-reference */ +} xref_info; +typedef xref_info *xref_pointer; + +@ @<Global...@>= +xref_info xmem[max_refs]; /* contains cross-reference information */ +xref_pointer xmem_end = xmem+max_refs-1; +xref_pointer xref_ptr; /* the largest occupied position in |xmem| */ +sixteen_bits xref_switch,section_xref_switch; /* either zero or |def_flag| */ + +@ A section that is used for multi-file output (with the \.{@@(} feature) +has a special first cross-reference whose |num| field is |file_flag|. + +@d file_flag (3*cite_flag) +@d def_flag (2*cite_flag) +@d cite_flag 10240 /* must be strictly larger than |max_sections| */ +@d xref equiv_or_xref + +@<Set init...@>= +xref_ptr=xmem; name_dir->xref=(char*)xmem; xref_switch=0; section_xref_switch=0; +xmem->num=0; /* sentinel value */ + +@ A new cross-reference for an identifier is formed by calling |new_xref|, +which discards duplicate entries and ignores non-underlined references +to one-letter identifiers or \CEE/'s reserved words. + +If the user has sent the |no_xref| flag (the \.{-x} option of the command line), +it is unnecessary to keep track of cross-references for identifiers. +If one were careful, one could probably make more changes around section +100 to avoid a lot of identifier looking up. + +@d append_xref(c) if (xref_ptr==xmem_end) overflow("cross-reference"); + else (++xref_ptr)->num=c; +@d no_xref (flags['x']==0) +@d make_xrefs flags['x'] /* should cross references be output? */ +@d is_tiny(p) ((p+1)->byte_start==(p)->byte_start+1) + +@c +void +new_xref(p) +name_pointer p; +{ + xref_pointer q; /* pointer to previous cross-reference */ + sixteen_bits m, n; /* new and previous cross-reference value */ + if (no_xref) return; + if ((unindexed(p) || is_tiny(p)) && xref_switch==0) return; + m=section_count+xref_switch; xref_switch=0; q=(xref_pointer)p->xref; + if (q != xmem) { + n=q->num; + if (n==m || n==m+def_flag) return; + else if (m==n+def_flag) { + q->num=m; return; + } + } + append_xref(m); xref_ptr->xlink=q; p->xref=(char*)xref_ptr; +} + +@ The cross-reference lists for section names are slightly different. +Suppose that a section name is defined in sections $m_1$, \dots, +$m_k$, cited in sections $n_1$, \dots, $n_l$, and used in sections +$p_1$, \dots, $p_j$. Then its list will contain $m_1+|def_flag|$, +\dots, $m_k+|def_flag|$, $n_1+|cite_flag|$, \dots, +$n_l+|cite_flag|$, $p_1$, \dots, $p_j$, in this order. + +Although this method of storage take quadratic time on the length of +the list, under foreseeable uses of \.{CWEAVE} this inefficiency is +insignificant. + +@c +void +new_section_xref(p) +name_pointer p; +{ + xref_pointer q,r; /* pointers to previous cross-references */ + q=(xref_pointer)p->xref; r=xmem; + if (q>xmem) + while (q->num>section_xref_switch) {r=q; q=q->xlink;} + if (r->num==section_count+section_xref_switch) + return; /* don't duplicate entries */ + append_xref(section_count+section_xref_switch); + xref_ptr->xlink=q; section_xref_switch=0; + if (r==xmem) p->xref=(char*)xref_ptr; + else r->xlink=xref_ptr; +} + +@ The cross-reference list for a section name may also begin with +|file_flag|. Here's how that flag gets put~in. + +@c +void +set_file_flag(p) +name_pointer p; +{ + xref_pointer q; + q=(xref_pointer)p->xref; + if (q->num==file_flag) return; + append_xref(file_flag); + xref_ptr->xlink = q; + p->xref = (char *)xref_ptr; +} + +@ A third large area of memory is used for sixteen-bit `tokens', which appear +in short lists similar to the strings of characters in |byte_mem|. Token lists +are used to contain the result of \CEE/ code translated into \TEX/ form; +further details about them will be explained later. A |text_pointer| variable +is an index into |tok_start|. + +@<Typed...@>= +typedef sixteen_bits token; +typedef token *token_pointer; +typedef token_pointer *text_pointer; + +@ The first position of |tok_mem| +that is unoccupied by replacement text is called |tok_ptr|, and the first +unused location of |tok_start| is called |text_ptr|. +Thus, we usually have |*text_ptr==tok_ptr|. + +@<Global...@>= +token tok_mem[max_toks]; /* tokens */ +token_pointer tok_mem_end = tok_mem+max_toks-1; /* end of |tok_mem| */ +token_pointer tok_start[max_texts]; /* directory into |tok_mem| */ +token_pointer tok_ptr; /* first unused position in |tok_mem| */ +text_pointer text_ptr; /* first unused position in |tok_start| */ +text_pointer tok_start_end = tok_start+max_texts-1; /* end of |tok_start| */ +token_pointer max_tok_ptr; /* largest value of |tok_ptr| */ +text_pointer max_text_ptr; /* largest value of |text_ptr| */ + +@ @<Set init...@>= +tok_ptr=tok_mem+1; text_ptr=tok_start+1; tok_start[0]=tok_mem+1; +tok_start[1]=tok_mem+1; +max_tok_ptr=tok_mem+1; max_text_ptr=tok_start+1; + +@ Here are the three procedures needed to complete |id_lookup|: +@c +int names_match(p,first,l,t) +name_pointer p; /* points to the proposed match */ +char *first; /* position of first character of string */ +int l; /* length of identifier */ +eight_bits t; /* desired ilk */ +{ + if (length(p)!=l) return 0; + if (p->ilk!=t && !(t==normal && abnormal(p))) return 0; + return !strncmp(first,p->byte_start,l); +} + +void +init_p(p,t) +name_pointer p; +eight_bits t; +{ + p->ilk=t; p->xref=(char*)xmem; +} + +void +init_node(p) +name_pointer p; +{ + p->xref=(char*)xmem; +} + +@ We have to get \CEE/'s +reserved words into the hash table, and the simplest way to do this is +to insert them every time \.{CWEAVE} is run. Fortunately there are relatively +few reserved words. (Some of these are not strictly ``reserved,'' but +are defined in header files of the ISO Standard \CEE/ Library.) +@^reserved words@> + +@<Store all the reserved words@>= +id_lookup("asm",NULL,sizeof_like); +id_lookup("auto",NULL,int_like); +id_lookup("break",NULL,case_like); +id_lookup("case",NULL,case_like); +id_lookup("catch",NULL,catch_like); +id_lookup("char",NULL,raw_int); +id_lookup("class",NULL,struct_like); +id_lookup("clock_t",NULL,raw_int); +id_lookup("const",NULL,const_like); +id_lookup("continue",NULL,case_like); +id_lookup("default",NULL,case_like); +id_lookup("define",NULL,define_like); +id_lookup("defined",NULL,sizeof_like); +id_lookup("delete",NULL,sizeof_like); +id_lookup("div_t",NULL,raw_int); +id_lookup("do",NULL,do_like); +id_lookup("double",NULL,raw_int); +id_lookup("elif",NULL,if_like); +id_lookup("else",NULL,else_like); +id_lookup("endif",NULL,if_like); +id_lookup("enum",NULL,struct_like); +id_lookup("error",NULL,if_like); +id_lookup("extern",NULL,int_like); +id_lookup("FILE",NULL,raw_int); +id_lookup("float",NULL,raw_int); +id_lookup("for",NULL,for_like); +id_lookup("fpos_t",NULL,raw_int); +id_lookup("friend",NULL,int_like); +id_lookup("goto",NULL,case_like); +id_lookup("if",NULL,if_like); +id_lookup("ifdef",NULL,if_like); +id_lookup("ifndef",NULL,if_like); +id_lookup("include",NULL,if_like); +id_lookup("inline",NULL,int_like); +id_lookup("int",NULL,raw_int); +id_lookup("jmp_buf",NULL,raw_int); +id_lookup("ldiv_t",NULL,raw_int); +id_lookup("line",NULL,if_like); +id_lookup("long",NULL,raw_int); +id_lookup("new",NULL,new_like); +id_lookup("NULL",NULL,quoted); +id_lookup("offsetof",NULL,sizeof_like); +id_lookup("operator",NULL,operator_like); +id_lookup("pragma",NULL,if_like); +id_lookup("private",NULL,public_like); +id_lookup("protected",NULL,public_like); +id_lookup("ptrdiff_t",NULL,raw_int); +id_lookup("public",NULL,public_like); +id_lookup("register",NULL,int_like); +id_lookup("return",NULL,case_like); +id_lookup("short",NULL,raw_int); +id_lookup("sig_atomic_t",NULL,raw_int); +id_lookup("signed",NULL,raw_int); +id_lookup("size_t",NULL,raw_int); +id_lookup("sizeof",NULL,sizeof_like); +id_lookup("static",NULL,int_like); +id_lookup("struct",NULL,struct_like); +id_lookup("switch",NULL,for_like); +id_lookup("template",NULL,int_like); +id_lookup("TeX",NULL,custom); +id_lookup("this",NULL,quoted); +id_lookup("throw",NULL,case_like); +id_lookup("time_t",NULL,raw_int); +id_lookup("try",NULL,else_like); +id_lookup("typedef",NULL,typedef_like); +id_lookup("undef",NULL,if_like); +id_lookup("union",NULL,struct_like); +id_lookup("unsigned",NULL,raw_int); +id_lookup("va_dcl",NULL,decl); /* Berkeley's variable-arg-list convention */ +id_lookup("va_list",NULL,raw_int); /* ditto */ +id_lookup("virtual",NULL,int_like); +id_lookup("void",NULL,raw_int); +id_lookup("volatile",NULL,const_like); +id_lookup("wchar_t",NULL,raw_int); +id_lookup("while",NULL,for_like); + +@* Lexical scanning. +Let us now consider the subroutines that read the \.{CWEB} source file +and break it into meaningful units. There are four such procedures: +One simply skips to the next `\.{@@\ }' or `\.{@@*}' that begins a +section; another passes over the \TEX/ text at the beginning of a +section; the third passes over the \TEX/ text in a \CEE/ comment; +and the last, which is the most interesting, gets the next token of +a \CEE/ text. They all use the pointers |limit| and |loc| into +the line of input currently being studied. + +@ Control codes in \.{CWEB}, which begin with `\.{@@}', are converted +into a numeric code designed to simplify \.{CWEAVE}'s logic; for example, +larger numbers are given to the control codes that denote more significant +milestones, and the code of |new_section| should be the largest of +all. Some of these numeric control codes take the place of |char| +control codes that will not otherwise appear in the output of the +scanning routines. +@^ASCII code dependencies@> + +@d ignore 00 /* control code of no interest to \.{CWEAVE} */ +@d verbatim 02 /* takes the place of extended ASCII \.{\char2} */ +@d begin_short_comment 03 /* \CPLUSPLUS/ short comment */ +@d begin_comment '\t' /* tab marks will not appear */ +@d underline '\n' /* this code will be intercepted without confusion */ +@d noop 0177 /* takes the place of ASCII delete */ +@d xref_roman 0203 /* control code for `\.{@@\^}' */ +@d xref_wildcard 0204 /* control code for `\.{@@:}' */ +@d xref_typewriter 0205 /* control code for `\.{@@.}' */ +@d TeX_string 0206 /* control code for `\.{@@t}' */ +@f TeX_string TeX +@d ord 0207 /* control code for `\.{@@'}' */ +@d join 0210 /* control code for `\.{@@\&}' */ +@d thin_space 0211 /* control code for `\.{@@,}' */ +@d math_break 0212 /* control code for `\.{@@\v}' */ +@d line_break 0213 /* control code for `\.{@@/}' */ +@d big_line_break 0214 /* control code for `\.{@@\#}' */ +@d no_line_break 0215 /* control code for `\.{@@+}' */ +@d pseudo_semi 0216 /* control code for `\.{@@;}' */ +@d macro_arg_open 0220 /* control code for `\.{@@[}' */ +@d macro_arg_close 0221 /* control code for `\.{@@]}' */ +@d trace 0222 /* control code for `\.{@@0}', `\.{@@1}' and `\.{@@2}' */ +@d translit_code 0223 /* control code for `\.{@@l}' */ +@d output_defs_code 0224 /* control code for `\.{@@h}' */ +@d format_code 0225 /* control code for `\.{@@f}' and `\.{@@s}' */ +@d definition 0226 /* control code for `\.{@@d}' */ +@d begin_C 0227 /* control code for `\.{@@c}' */ +@d section_name 0230 /* control code for `\.{@@<}' */ +@d new_section 0231 /* control code for `\.{@@\ }' and `\.{@@*}' */ + +@ Control codes are converted to \.{CWEAVE}'s internal +representation by means of the table |ccode|. + +@<Global...@>= +eight_bits ccode[256]; /* meaning of a char following \.{@@} */ + +@ @<Set ini...@>= +{int c; for (c=0; c<256; c++) ccode[c]=0;} +ccode[' ']=ccode['\t']=ccode['\n']=ccode['\v']=ccode['\r']=ccode['\f'] + =ccode['*']=new_section; +ccode['@@']='@@'; /* `quoted' at sign */ +ccode['=']=verbatim; +ccode['d']=ccode['D']=definition; +ccode['f']=ccode['F']=ccode['s']=ccode['S']=format_code; +ccode['c']=ccode['C']=ccode['p']=ccode['P']=begin_C; +ccode['t']=ccode['T']=TeX_string; +ccode['l']=ccode['L']=translit_code; +ccode['q']=ccode['Q']=noop; +ccode['h']=ccode['H']=output_defs_code; +ccode['&']=join; ccode['<']=ccode['(']=section_name; +ccode['!']=underline; ccode['^']=xref_roman; +ccode[':']=xref_wildcard; ccode['.']=xref_typewriter; ccode[',']=thin_space; +ccode['|']=math_break; ccode['/']=line_break; ccode['#']=big_line_break; +ccode['+']=no_line_break; ccode[';']=pseudo_semi; +ccode['[']=macro_arg_open; ccode[']']=macro_arg_close; +ccode['\'']=ord; +@<Special control codes for debugging@>@; + +@ Users can write +\.{@@2}, \.{@@1}, and \.{@@0} to turn tracing fully on, partly on, +and off, respectively. + +@<Special control codes...@>= +ccode['0']=ccode['1']=ccode['2']=trace; + +@ The |skip_limbo| routine is used on the first pass to skip through +portions of the input that are not in any sections, i.e., that precede +the first section. After this procedure has been called, the value of +|input_has_ended| will tell whether or not a section has actually been found. + +There's a complication that we will postpone until later: If the \.{@@s} +operation appears in limbo, we want to use it to adjust the default +interpretation of identifiers. + +@<Predec...@>= +void skip_limbo(); + +@ @c +void +skip_limbo() { + while(1) { + if (loc>limit && get_line()==0) return; + *(limit+1)='@@'; + while (*loc!='@@') loc++; /* look for '@@', then skip two chars */ + if (loc++ <=limit) { int c=ccode[(eight_bits)*loc++]; + if (c==new_section) return; + if (c==noop) skip_restricted(); + else if (c==format_code) @<Process simple format in limbo@>; + } + } +} + +@ The |skip_TeX| routine is used on the first pass to skip through +the \TEX/ code at the beginning of a section. It returns the next +control code or `\.{\v}' found in the input. A |new_section| is +assumed to exist at the very end of the file. + +@f skip_TeX TeX + +@c +unsigned +skip_TeX() /* skip past pure \TEX/ code */ +{ + while (1) { + if (loc>limit && get_line()==0) return(new_section); + *(limit+1)='@@'; + while (*loc!='@@' && *loc!='|') loc++; + if (*loc++ =='|') return('|'); + if (loc<=limit) return(ccode[(eight_bits)*(loc++)]); + } +} + +@*1 Inputting the next token. +As stated above, \.{CWEAVE}'s most interesting lexical scanning routine is the +|get_next| function that inputs the next token of \CEE/ input. However, +|get_next| is not especially complicated. + +The result of |get_next| is either a |char| code for some special character, +or it is a special code representing a pair of characters (e.g., `\.{!=}'), +or it is the numeric value computed by the |ccode| +table, or it is one of the following special codes: + +\yskip\hang |identifier|: In this case the global variables |id_first| and +|id_loc| will have been set to the beginning and ending-plus-one locations +in the buffer, as required by the |id_lookup| routine. + +\yskip\hang |string|: The string will have been copied into the array +|section_text|; |id_first| and |id_loc| are set as above (now they are +pointers into |section_text|). + +\yskip\hang |constant|: The constant is copied into |section_text|, with +slight modifications; |id_first| and |id_loc| are set. + +\yskip\noindent Furthermore, some of the control codes cause +|get_next| to take additional actions: + +\yskip\hang |xref_roman|, |xref_wildcard|, |xref_typewriter|, |TeX_string|, +|verbatim|: The values of |id_first| and |id_loc| will have been set to +the beginning and ending-plus-one locations in the buffer. + +\yskip\hang |section_name|: In this case the global variable |cur_section| will +point to the |byte_start| entry for the section name that has just been scanned. +The value of |cur_section_char| will be |'('| if the section name was +preceded by \.{@@(} instead of \.{@@<}. + +\yskip\noindent If |get_next| sees `\.{@@!}' +it sets |xref_switch| to |def_flag| and goes on to the next token. + +@d constant 0200 /* \CEE/ constant */ +@d string 0201 /* \CEE/ string */ +@d identifier 0202 /* \CEE/ identifier or reserved word */ + +@<Global...@>= +name_pointer cur_section; /* name of section just scanned */ +char cur_section_char; /* the character just before that name */ + +@ @<Include...@>= +#include <ctype.h> /* definition of |isalpha|, |isdigit| and so on */ +#include <stdlib.h> /* definition of |exit| */ + +@ 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)=='_') /* non-alpha character allowed in identifier */ +@d ishigh(c) ((eight_bits)(c)>0177) +@^high-bit character handling@> + +@<Predecl...@>= +eight_bits get_next(); + +@ @c +eight_bits +get_next() /* produces the next input token */ +{@+eight_bits c; /* the current character */ + while (1) { + @<Check if we're at the end of a preprocessor command@>; + if (loc>limit && get_line()==0) return(new_section); + c=*(loc++); + if (xisdigit(c) || c=='\\' || c=='.') @<Get a constant@>@; + else if (c=='\'' || c=='"' || (c=='L'&&(*loc=='\'' || *loc=='"'))@| + || (c=='<' && sharp_include_line==1)) + @<Get a string@>@; + else if (xisalpha(c) || isxalpha(c) || ishigh(c)) + @<Get an identifier@>@; + else if (c=='@@') @<Get control code and possible section name@>@; + else if (xisspace(c)) continue; /* ignore spaces and tabs */ + if (c=='#' && loc==buffer+1) @<Raise preprocessor flag@>; + mistake: @<Compress two-symbol operator@>@; + return(c); + } +} + +@ Because preprocessor commands do not fit in with the rest of the syntax +of \CEE/, +we have to deal with them separately. One solution is to enclose such +commands between special markers. Thus, when a \.\# is seen as the +first character of a line, |get_next| returns a special code +|left_preproc| and raises a flag |preprocessing|. + +We can use the same internal code number for |left_preproc| as we do +for |ord|, since |get_next| changes |ord| into a string. + +@d left_preproc ord /* begins a preprocessor command */ +@d right_preproc 0217 /* ends a preprocessor command */ + +@<Glob...@>= +boolean preprocessing=0; /* are we scanning a preprocessor command? */ + +@ @<Raise prep...@>= { + preprocessing=1; + @<Check if next token is |include|@>; + return (left_preproc); +} + +@ An additional complication is the freakish use of \.< and \.> to delimit +a file name in lines that start with \.{\#include}. We must treat this file +name as a string. + +@<Glob...@>= +boolean sharp_include_line=0; /* are we scanning a |#include| line? */ + +@ @<Check if next token is |include|@>= +while (loc<=buffer_end-7 && xisspace(*loc)) loc++; +if (loc<=buffer_end-6 && strncmp(loc,"include",7)==0) sharp_include_line=1; + +@ When we get to the end of a preprocessor line, +we lower the flag and send a code |right_preproc|, unless +the last character was a \.\\. + +@<Check if we're at...@>= + while (loc==limit-1 && preprocessing && *loc=='\\') + if (get_line()==0) return(new_section); /* still in preprocessor mode */ + if (loc>=limit && preprocessing) { + preprocessing=sharp_include_line=0; + return(right_preproc); + } + +@ The following code assigns values to the combinations \.{++}, +\.{--}, \.{->}, \.{>=}, \.{<=}, \.{==}, \.{<<}, \.{>>}, \.{!=}, \.{\v\v}, and +\.{\&\&}, and to the \CPLUSPLUS/ +combinations \.{...}, \.{::}, \.{.*} and \.{->*}. +The compound assignment operators (e.g., \.{+=}) are +treated as separate tokens. + +@d compress(c) if (loc++<=limit) return(c) + +@<Compress tw...@>= +switch(c) { + case '/': if (*loc=='*') {compress(begin_comment);} + else if (*loc=='/') compress(begin_short_comment); break; + case '+': if (*loc=='+') compress(plus_plus); break; + case '-': if (*loc=='-') {compress(minus_minus);} + else if (*loc=='>') if (*(loc+1)=='*') {loc++; compress(minus_gt_ast);} + else compress(minus_gt); break; + case '.': if (*loc=='*') {compress(period_ast);} + else if (*loc=='.' && *(loc+1)=='.') { + loc++; compress(dot_dot_dot); + } + break; + case ':': if (*loc==':') compress(colon_colon); break; + case '=': if (*loc=='=') compress(eq_eq); break; + case '>': if (*loc=='=') {compress(gt_eq);} + else if (*loc=='>') compress(gt_gt); break; + case '<': if (*loc=='=') {compress(lt_eq);} + else if (*loc=='<') compress(lt_lt); break; + case '&': if (*loc=='&') compress(and_and); break; + case '|': if (*loc=='|') compress(or_or); break; + case '!': if (*loc=='=') compress(not_eq); break; +} + +@ @<Get an identifier@>= { + id_first=--loc; + while (isalpha(*++loc) || isdigit(*loc) || isxalpha(*loc) || ishigh(*loc)); + id_loc=loc; return(identifier); +} + +@ Different conventions are followed by \TEX/ and \CEE/ to express octal +and hexadecimal numbers; it is reasonable to stick to each convention +within its realm. Thus the \CEE/ part of a \.{CWEB} file has octals +introduced by \.0 and hexadecimals by \.{0x}, but \.{CWEAVE} will print +in italics or typewriter font, respectively, and introduced by single +or double quotes. In order to simplify the \TEX/ macro used to print +such constants, we replace some of the characters. + +Notice that in this section and the next, |id_first| and |id_loc| +are pointers into the array |section_text|, not into |buffer|. + +@<Get a constant@>= { + id_first=id_loc=section_text+1; + if (*(loc-1)=='\\') {*id_loc++='~'; + while (xisdigit(*loc)) *id_loc++=*loc++;} /* octal constant */ + else if (*(loc-1)=='0') { + if (*loc=='x' || *loc=='X') {*id_loc++='^'; loc++; + while (xisxdigit(*loc)) *id_loc++=*loc++;} /* hex constant */ + else if (xisdigit(*loc)) {*id_loc++='~'; + while (xisdigit(*loc)) *id_loc++=*loc++;} /* octal constant */ + else goto dec; /* decimal constant */ + } + else { /* decimal constant */ + if (*(loc-1)=='.' && !xisdigit(*loc)) goto mistake; /* not a constant */ + dec: *id_loc++=*(loc-1); + while (xisdigit(*loc) || *loc=='.') *id_loc++=*loc++; + if (*loc=='e' || *loc=='E') { /* float constant */ + *id_loc++='_'; loc++; + if (*loc=='+' || *loc=='-') *id_loc++=*loc++; + while (xisdigit(*loc)) *id_loc++=*loc++; + } + } + while (*loc=='u' || *loc=='U' || *loc=='l' || *loc=='L' + || *loc=='f' || *loc=='F') { + *id_loc++='$'; *id_loc++=toupper(*loc); loc++; + } + return(constant); +} + +@ \CEE/ strings and character constants, delimited by double and single +quotes, respectively, can contain newlines or instances of their own +delimiters if they are protected by a backslash. We follow this +convention, but do not allow the string to be longer than |longest_name|. + +@<Get a string@>= { + char delim = c; /* what started the string */ + id_first = section_text+1; + id_loc = section_text; + if (delim=='\'' && *(loc-2)=='@@') {*++id_loc='@@'; *++id_loc='@@';} + *++id_loc=delim; + if (delim=='L') { /* wide character constant */ + delim=*loc++; *++id_loc=delim; + } + if (delim=='<') delim='>'; /* for file names in |#include| lines */ + while (1) { + if (loc>=limit) { + if(*(limit-1)!='\\') { + err_print("! String didn't end"); loc=limit; break; +@.String didn't end@> + } + if(get_line()==0) { + err_print("! Input ended in middle of string"); loc=buffer; break; +@.Input ended in middle of string@> + } + } + if ((c=*loc++)==delim) { + if (++id_loc<=section_text_end) *id_loc=c; + break; + } + if (c=='\\') if (loc>=limit) continue; + else if (++id_loc<=section_text_end) { + *id_loc = '\\'; c=*loc++; + } + if (++id_loc<=section_text_end) *id_loc=c; + } + if (id_loc>=section_text_end) { + printf("\n! String too long: "); +@.String too long@> + term_write(section_text+1,25); + printf("..."); mark_error; + } + id_loc++; + return(string); +} + +@ After an \.{@@} sign has been scanned, the next character tells us +whether there is more work to do. + +@<Get control code and possible section name@>= { + c=*loc++; + switch(ccode[(eight_bits)c]) { + case translit_code: err_print("! Use @@l in limbo only"); continue; +@.Use @@l in limbo...@> + case underline: xref_switch=def_flag; continue; + case trace: tracing=c-'0'; continue; + case xref_roman: case xref_wildcard: case xref_typewriter: + case noop: case TeX_string: c=ccode[c]; skip_restricted(); return(c); + case section_name: + @<Scan the section name and make |cur_section| point to it@>; + case verbatim: @<Scan a verbatim string@>; + case ord: @<Get a string@>; + default: return(ccode[(eight_bits)c]); + } +} + +@ The occurrence of a section name sets |xref_switch| to zero, +because the section name might (for example) follow \&{int}. + +@<Scan the section name...@>= { + char *k; /* pointer into |section_text| */ + cur_section_char=*(loc-1); + @<Put section name into |section_text|@>; + if (k-section_text>3 && strncmp(k-2,"...",3)==0) + cur_section=section_lookup(section_text+1,k-3,1); /* 1 indicates a prefix */ + else cur_section=section_lookup(section_text+1,k,0); + xref_switch=0; return(section_name); +} + +@ Section names are placed into the |section_text| array with consecutive spaces, +tabs, and carriage-returns replaced by single spaces. There will be no +spaces at the beginning or the end. (We set |section_text[0]=' '| to facilitate +this, since the |section_lookup| routine uses |section_text[1]| as the first +character of the name.) + +@<Set init...@>=section_text[0]=' '; + +@ @<Put section name...@>= +k=section_text; +while (1) { + if (loc>limit && get_line()==0) { + err_print("! Input ended in section name"); +@.Input ended in section name@> + loc=buffer+1; break; + } + c=*loc; + @<If end of name or erroneous control code, |break|@>; + loc++; if (k<section_text_end) k++; + if (xisspace(c)) { + c=' '; if (*(k-1)==' ') k--; + } +*k=c; +} +if (k>=section_text_end) { + printf("\n! Section name too long: "); +@.Section name too long@> + term_write(section_text+1,25); + printf("..."); mark_harmless; +} +if (*k==' ' && k>section_text) k--; + +@ @<If end of name...@>= +if (c=='@@') { + c=*(loc+1); + if (c=='>') { + loc+=2; break; + } + if (ccode[(eight_bits)c]==new_section) { + err_print("! Section name didn't end"); break; +@.Section name didn't end@> + } + if (c!='@@') { + err_print("! Control codes are forbidden in section name"); break; +@.Control codes are forbidden...@> + } + *(++k)='@@'; loc++; /* now |c==*loc| again */ +} + +@ This function skips over a restricted context at relatively high speed. + +@<Predecl...@>= +void skip_restricted(); + +@ @c +void +skip_restricted() +{ + id_first=loc; *(limit+1)='@@'; +false_alarm: + while (*loc!='@@') loc++; + id_loc=loc; + if (loc++>limit) { + err_print("! Control text didn't end"); loc=limit; +@.Control text didn't end@> + } + else { + if (*loc=='@@'&&loc<=limit) {loc++; goto false_alarm;} + if (*loc++!='>') + err_print("! Control codes are forbidden in control text"); +@.Control codes are forbidden...@> + } +} + +@ At the present point in the program we +have |*(loc-1)==verbatim|; we set |id_first| to the beginning +of the string itself, and |id_loc| to its ending-plus-one location in the +buffer. We also set |loc| to the position just after the ending delimiter. + +@<Scan a verbatim string@>= { + id_first=loc++; *(limit+1)='@@'; *(limit+2)='>'; + while (*loc!='@@' || *(loc+1)!='>') loc++; + if (loc>=limit) err_print("! Verbatim string didn't end"); +@.Verbatim string didn't end@> + id_loc=loc; loc+=2; + return (verbatim); +} + +@** Phase one processing. +We now have accumulated enough subroutines to make it possible to carry out +\.{CWEAVE}'s first pass over the source file. If everything works right, +both phase one and phase two of \.{CWEAVE} will assign the same numbers to +sections, and these numbers will agree with what \.{CTANGLE} does. + +The global variable |next_control| often contains the most recent output of +|get_next|; in interesting cases, this will be the control code that +ended a section or part of a section. + +@<Global...@>= +eight_bits next_control; /* control code waiting to be acting upon */ + +@ The overall processing strategy in phase one has the following +straightforward outline. + +@<Predecl...@>= +void phase_one(); + +@ @c +void +phase_one() { + phase=1; reset_input(); section_count=0; + skip_limbo(); change_exists=0; + while (!input_has_ended) + @<Store cross-reference data for the current section@>; + changed_section[section_count]=change_exists; + /* the index changes if anything does */ + phase=2; /* prepare for second phase */ + @<Print error messages about unused or undefined section names@>; +} + +@ @<Store cross-reference data...@>= +{ + if (++section_count==max_sections) overflow("section number"); + changed_section[section_count]=changing; + /* it will become 1 if any line changes */ + if (*(loc-1)=='*' && show_progress) { + printf("*%d",section_count); + update_terminal; /* print a progress report */ + } + @<Store cross-references in the \TEX/ part of a section@>; + @<Store cross-references in the definition part of a section@>; + @<Store cross-references in the \CEE/ part of a section@>; + if (changed_section[section_count]) change_exists=1; +} + +@ The |C_xref| subroutine stores references to identifiers in +\CEE/ text material beginning with the current value of |next_control| +and continuing until |next_control| is `\.\{' or `\.{\v}', or until the next +``milestone'' is passed (i.e., |next_control>=format_code|). If +|next_control>=format_code| when |C_xref| is called, nothing will happen; +but if |next_control=='|'| upon entry, the procedure assumes that this is +the `\.{\v}' preceding \CEE/ text that is to be processed. + +The parameter |spec_ctrl| is used to change this behavior. In most cases +|C_xref| is called with |spec_ctrl==ignore|, which triggers the default +processing described above. If |spec_ctrl==section_name|, section names will +be gobbled. This is used when \CEE/ text in the \TEX/ part or inside comments +is parsed: It allows for section names to appear in \pb, but these +strings will not be entered into the cross reference lists since they are not +definitions of section names. + +The program uses the fact that our internal code numbers satisfy +the relations |xref_roman==identifier+roman| and |xref_wildcard==identifier ++wildcard| and |xref_typewriter==identifier+typewriter|, +as well as |normal==0|. + +@<Predecl...@>= +void C_xref(); + +@ @c +void +C_xref( spec_ctrl ) /* makes cross-references for \CEE/ identifiers */ + eight_bits spec_ctrl; +{ + name_pointer p; /* a referenced name */ + while (next_control<format_code || next_control==spec_ctrl) { + if (next_control>=identifier && next_control<=xref_typewriter) { + if (next_control>identifier) @<Replace |"@@@@"| by |"@@"| @>@; + p=id_lookup(id_first, id_loc,next_control-identifier); new_xref(p); + } + if (next_control==section_name) { + section_xref_switch=cite_flag; + new_section_xref(cur_section); + } + next_control=get_next(); + if (next_control=='|' || next_control==begin_comment || + next_control==begin_short_comment) return; + } +} + +@ The |outer_xref| subroutine is like |C_xref| except that it begins +with |next_control!='|'| and ends with |next_control>=format_code|. Thus, it +handles \CEE/ text with embedded comments. + +@<Predecl...@>= +void outer_xref(); + +@ @c +void +outer_xref() /* extension of |C_xref| */ +{ + int bal; /* brace level in comment */ + while (next_control<format_code) + if (next_control!=begin_comment && next_control!=begin_short_comment) + C_xref(ignore); + else { + boolean is_long_comment=(next_control==begin_comment); + bal=copy_comment(is_long_comment,1); next_control='|'; + while (bal>0) { + C_xref(section_name); /* do not reference section names in comments */ + if (next_control=='|') bal=copy_comment(is_long_comment,bal); + else bal=0; /* an error message will occur in phase two */ + } + } +} + +@ In the \TEX/ part of a section, cross-reference entries are made only for +the identifiers in \CEE/ texts enclosed in \pb, or for control texts +enclosed in \.{@@\^}$\,\ldots\,$\.{@@>} or \.{@@.}$\,\ldots\,$\.{@@>} +or \.{@@:}$\,\ldots\,$\.{@@>}. + +@<Store cross-references in the \T...@>= +while (1) { + switch (next_control=skip_TeX()) { + case translit_code: err_print("! Use @@l in limbo only"); continue; +@.Use @@l in limbo...@> + case underline: xref_switch=def_flag; continue; + case trace: tracing=*(loc-1)-'0'; continue; + case '|': C_xref(section_name); break; + case xref_roman: case xref_wildcard: case xref_typewriter: + case noop: case section_name: + loc-=2; next_control=get_next(); /* scan to \.{@@>} */ + if (next_control>=xref_roman && next_control<=xref_typewriter) { + @<Replace |"@@@@"| by |"@@"| @>@; + new_xref(id_lookup(id_first, id_loc,next_control-identifier)); + } + break; + } + if (next_control>=format_code) break; +} + +@ @<Replace |"@@@@"| by |"@@"| @>= +{ + char *src=id_first,*dst=id_first; + while(src<id_loc){ + if(*src=='@@') src++; + *dst++=*src++; + } + id_loc=dst; + while (dst<src) *dst++=' '; /* clean up in case of error message display */ +} + +@ During the definition and \CEE/ parts of a section, cross-references +are made for all identifiers except reserved words. However, the right +identifier in a format definition is not referenced, and the left +identifier is referenced only if it has been explicitly +underlined (preceded by \.{@@!}). +The \TEX/ code in comments is, of course, ignored, except for +\CEE/ portions enclosed in \pb; the text of a section name is skipped +entirely, even if it contains \pb\ constructions. + +The variables |lhs| and |rhs| point to the respective identifiers involved +in a format definition. + +@<Global...@>= +name_pointer lhs, rhs; /* pointers to |byte_start| for format identifiers */ + +@ When we get to the following code we have |next_control>=format_code|. + +@<Store cross-references in the d...@>= +while (next_control<=definition) { /* |format_code| or |definition| */ + if (next_control==definition) { + xref_switch=def_flag; /* implied \.{@@!} */ + next_control=get_next(); + } else @<Process a format definition@>; + outer_xref(); +} + +@ Error messages for improper format definitions will be issued in phase +two. Our job in phase one is to define the |ilk| of a properly formatted +identifier, and to remove cross-references to identifiers that we now +discover should be unindexed. + +@<Process a form...@>= { + next_control=get_next(); + if (next_control==identifier) { + lhs=id_lookup(id_first, id_loc,normal); lhs->ilk=normal; + if (xref_switch) new_xref(lhs); + next_control=get_next(); + if (next_control==identifier) { + rhs=id_lookup(id_first, id_loc,normal); + lhs->ilk=rhs->ilk; + if (unindexed(lhs)) { /* retain only underlined entries */ + xref_pointer q,r=NULL; + for (q=(xref_pointer)lhs->xref;q>xmem;q=q->xlink) + if (q->num<def_flag) + if (r) r->xlink=q->xlink; + else lhs->xref=(char*)q->xlink; + else r=q; + } + next_control=get_next(); + } + } +} + +@ A much simpler processing of format definitions occurs when the +definition is found in limbo. + +@<Process simple format in limbo@>= +{ + if (get_next()!=identifier) + err_print("! Missing left identifier of @@s"); +@.Missing left identifier...@> + else { + lhs=id_lookup(id_first,id_loc,normal); + if (get_next()!=identifier) + err_print("! Missing right identifier of @@s"); +@.Missing right identifier...@> + else { + rhs=id_lookup(id_first,id_loc,normal); + lhs->ilk=rhs->ilk; + } + } +} + +@ Finally, when the \TEX/ and definition parts have been treated, we have +|next_control>=begin_C|. + +@<Store cross-references in the \CEE/...@>= +if (next_control<=section_name) { /* |begin_C| or |section_name| */ + if (next_control==begin_C) section_xref_switch=0; + else { + section_xref_switch=def_flag; + if(cur_section_char=='(' && cur_section!=name_dir) + set_file_flag(cur_section); + } + do { + if (next_control==section_name && cur_section!=name_dir) + new_section_xref(cur_section); + next_control=get_next(); outer_xref(); + } while ( next_control<=section_name); +} + +@ After phase one has looked at everything, we want to check that each +section name was both defined and used. The variable |cur_xref| will point +to cross-references for the current section name of interest. + +@<Global...@>= +xref_pointer cur_xref; /* temporary cross-reference pointer */ +boolean an_output; /* did |file_flag| precede |cur_xref|? */ + +@ The following recursive procedure +walks through the tree of section names and prints out anomalies. +@^recursion@> + +@<Predecl...@>= +void section_check(); + +@ @c +void +section_check(p) +name_pointer p; /* print anomalies in subtree |p| */ +{ + if (p) { + section_check(p->llink); + cur_xref=(xref_pointer)p->xref; + if (cur_xref->num==file_flag) {an_output=1; cur_xref=cur_xref->xlink;} + else an_output=0; + if (cur_xref->num <def_flag) { + printf("\n! Never defined: <"); print_section_name(p); putchar('>'); mark_harmless; +@.Never defined: <section name>@> + } + while (cur_xref->num >=cite_flag) cur_xref=cur_xref->xlink; + if (cur_xref==xmem && !an_output) { + printf("\n! Never used: <"); print_section_name(p); putchar('>'); mark_harmless; +@.Never used: <section name>@> + } + section_check(p->rlink); + } +} + +@ @<Print error messages about un...@>=section_check(root) + +@* Low-level output routines. +The \TEX/ output is supposed to appear in lines at most |line_length| +characters long, so we place it into an output buffer. During the output +process, |out_line| will hold the current line number of the line about to +be output. + +@<Global...@>= +char out_buf[line_length+1]; /* assembled characters */ +char *out_ptr; /* just after last character in |out_buf| */ +char *out_buf_end = out_buf+line_length; /* end of |out_buf| */ +int out_line; /* number of next line to be output */ + +@ The |flush_buffer| routine empties the buffer up to a given breakpoint, +and moves any remaining characters to the beginning of the next line. +If the |per_cent| parameter is 1 a |'%'| is appended to the line +that is being output; in this case the breakpoint |b| should be strictly +less than |out_buf_end|. If the |per_cent| parameter is |0|, +trailing blanks are suppressed. +The characters emptied from the buffer form a new line of output; +if the |carryover| parameter is true, a |"%"| in that line will be +carried over to the next line (so that \TEX/ will ignore the completion +of commented-out text). + +@d c_line_write(c) fflush(active_file),fwrite(out_buf+1,sizeof(char),c,active_file) +@d tex_putc(c) putc(c,active_file) +@d tex_new_line putc('\n',active_file) +@d tex_printf(c) fprintf(active_file,c) + +@c +void +flush_buffer(b,per_cent,carryover) +char *b; /* outputs from |out_buf+1| to |b|,where |b<=out_ptr| */ +boolean per_cent,carryover; +{ + char *j; j=b; /* pointer into |out_buf| */ + if (! per_cent) /* remove trailing blanks */ + while (j>out_buf && *j==' ') j--; + c_line_write(j-out_buf); + if (per_cent) tex_putc('%'); + tex_new_line; out_line++; + if (carryover) + while (j>out_buf) + if (*j--=='%' && (j==out_buf || *j!='\\')) { + *b--='%'; break; + } + if (b<out_ptr) strncpy(out_buf+1,b+1,out_ptr-b); + out_ptr-=b-out_buf; +} + +@ When we are copying \TEX/ source material, we retain line breaks +that occur in the input, except that an empty line is not +output when the \TEX/ source line was nonempty. For example, a line +of the \TEX/ file that contains only an index cross-reference entry +will not be copied. The |finish_line| routine is called just before +|get_line| inputs a new line, and just after a line break token has +been emitted during the output of translated \CEE/ text. + +@c +void +finish_line() /* do this at the end of a line */ +{ + char *k; /* pointer into |buffer| */ + if (out_ptr>out_buf) flush_buffer(out_ptr,0,0); + else { + for (k=buffer; k<=limit; k++) + if (!(xisspace(*k))) return; + flush_buffer(out_buf,0,0); + } +} + +@ In particular, the |finish_line| procedure is called near the very +beginning of phase two. We initialize the output variables in a slightly +tricky way so that the first line of the output file will be +`\.{\\input cwebmac}'. + +@<Set init...@>= +out_ptr=out_buf+1; out_line=1; active_file=tex_file; +*out_ptr='c'; tex_printf("\\input cwebma"); + +@ When we wish to append one character |c| to the output buffer, we write +`|out(c)|'; this will cause the buffer to be emptied if it was already +full. If we want to append more than one character at once, we say +|out_str(s)|, where |s| is a string containing the characters. + +A line break will occur at a space or after a single-nonletter +\TEX/ control sequence. + +@d out(c) {if (out_ptr>=out_buf_end) break_out(); *(++out_ptr)=c;} + +@c +void +out_str(s) /* output characters from |s| to end of string */ +char *s; +{ + while (*s) out(*s++); +} + +@ The |break_out| routine is called just before the output buffer is about +to overflow. To make this routine a little faster, we initialize position +0 of the output buffer to `\.\\'; this character isn't really output. + +@<Set init...@>= +out_buf[0]='\\'; + +@ A long line is broken at a blank space or just before a backslash that isn't +preceded by another backslash. In the latter case, a |'%'| is output at +the break. + +@<Predecl...@>= +void break_out(); + +@ @c +void +break_out() /* finds a way to break the output line */ +{ + char *k=out_ptr; /* pointer into |out_buf| */ + while (1) { + if (k==out_buf) @<Print warning message, break the line, |return|@>; + if (*k==' ') { + flush_buffer(k,0,1); return; + } + if (*(k--)=='\\' && *k!='\\') { /* we've decreased |k| */ + flush_buffer(k,1,1); return; + } + } +} + +@ We get to this section only in the unusual case that the entire output line +consists of a string of backslashes followed by a string of nonblank +non-backslashes. In such cases it is almost always safe to break the +line by putting a |'%'| just before the last character. + +@<Print warning message...@>= +{ + printf("\n! Line had to be broken (output l. %d):\n",out_line); +@.Line had to be broken@> + term_write(out_buf+1, out_ptr-out_buf-1); + new_line; mark_harmless; + flush_buffer(out_ptr-1,1,1); return; +} + +@ Here is a macro that outputs a section number in decimal notation. +The number to be converted by |out_section| is known to be less than +|def_flag|, so it cannot have more than five decimal digits. If +the section is changed, we output `\.{\\*}' just after the number. + +@c +void +out_section(n) +sixteen_bits n; +{ + char s[6]; + sprintf(s,"%d",n); out_str(s); + if(changed_section[n]) out_str ("\\*"); +@.\\*@> +} + +@ The |out_name| procedure is used to output an identifier or index +entry, enclosing it in braces. + +@c +void +out_name(p) +name_pointer p; +{ + char *k, *k_end=(p+1)->byte_start; /* pointers into |byte_mem| */ + out('{'); + for (k=p->byte_start; k<k_end; k++) { + if (isxalpha(*k)) out('\\'); + out(*k); + } + out('}'); +} + +@* Routines that copy \TEX/ material. +During phase two, we use subroutines |copy_limbo|, |copy_TeX|, and +|copy_comment| in place of the analogous |skip_limbo|, |skip_TeX|, and +|skip_comment| that were used in phase one. (Well, |copy_comment| +was actually written in such a way that it functions as |skip_comment| +in phase one.) + +The |copy_limbo| routine, for example, takes \TEX/ material that is not +part of any section and transcribes it almost verbatim to the output file. +The use of `\.{@@}' signs is severely restricted in such material: +`\.{@@@@}' pairs are replaced by singletons; `\.{@@l}' and `\.{@@q}' and +`\.{@@s}' are interpreted. + +@c +void +copy_limbo() +{ + char c; + while (1) { + if (loc>limit && (finish_line(), get_line()==0)) return; + *(limit+1)='@@'; + while (*loc!='@@') out(*(loc++)); + if (loc++<=limit) { + c=*loc++; + if (ccode[(eight_bits)c]==new_section) break; + switch (ccode[(eight_bits)c]) { + case translit_code: out_str("\\ATL"); break; +@.\\ATL@> + case '@@': out('@@'); break; + case noop: skip_restricted(); break; + case format_code: if (get_next()==identifier) get_next(); + if (loc>=limit) get_line(); /* avoid blank lines in output */ + break; /* the operands of \.{@@s} are ignored on this pass */ + default: err_print("! Double @@ should be used in limbo"); +@.Double @@ should be used...@> + out('@@'); + } + } + } +} + +@ The |copy_TeX| routine processes the \TEX/ code at the beginning of a +section; for example, the words you are now reading were copied in this +way. It returns the next control code or `\.{\v}' found in the input. +We don't copy spaces or tab marks into the beginning of a line. This +makes the test for empty lines in |finish_line| work. + +@ @f copy_TeX TeX +@c +eight_bits +copy_TeX() +{ + char c; /* current character being copied */ + while (1) { + if (loc>limit && (finish_line(), get_line()==0)) return(new_section); + *(limit+1)='@@'; + while ((c=*(loc++))!='|' && c!='@@') { + out(c); + if (out_ptr==out_buf+1 && (xisspace(c))) out_ptr--; + } + if (c=='|') return('|'); + if (loc<=limit) return(ccode[(eight_bits)*(loc++)]); + } +} + +@ The |copy_comment| function issues a warning if more braces are opened than +closed, and in the case of a more serious error it supplies enough +braces to keep \TEX/ from complaining about unbalanced braces. +Instead of copying the \TEX/ material +into the output buffer, this function copies it into the token memory +(in phase two only). +The abbreviation |app_tok(t)| is used to append token |t| to the current +token list, and it also makes sure that it is possible to append at least +one further token without overflow. + +@d app_tok(c) {if (tok_ptr+2>tok_mem_end) overflow("token"); *(tok_ptr++)=c;} + +@<Predec...@>= +int copy_comment(); + +@ @c +int copy_comment(is_long_comment,bal) /* copies \TEX/ code in comments */ +boolean is_long_comment; /* is this a traditional \CEE/ comment? */ +int bal; /* brace balance */ +{ + char c; /* current character being copied */ + while (1) { + if (loc>limit) { + if (is_long_comment) { + if (get_line()==0) { + err_print("! Input ended in mid-comment"); +@.Input ended in mid-comment@> + loc=buffer+1; goto done; + } + } + else { + if (bal>1) err_print("! Missing } in comment"); +@.Missing \} in comment@> + goto done; + } + } + c=*(loc++); + if (c=='|') return(bal); + if (is_long_comment) @<Check for end of comment@>; + if (phase==2) { + if (ishigh(c)) app_tok(quoted_char); + app_tok(c); + } + @<Copy special things when |c=='@@', '\\'|@>; + if (c=='{') bal++; + else if (c=='}') { + if(bal>1) bal--; + else {err_print("! Extra } in comment"); +@.Extra \} in comment@> + if (phase==2) tok_ptr--; + } + } + } +done:@<Clear |bal| and |return|@>; +} + +@ @<Check for end of comment@>= +if (c=='*' && *loc=='/') { + loc++; + if (bal>1) err_print("! Missing } in comment"); +@.Missing \} in comment@> + goto done; +} + +@ @<Copy special things when |c=='@@'...@>= +if (c=='@@') { + if (*(loc++)!='@@') { + err_print("! Illegal use of @@ in comment"); +@.Illegal use of @@...@> + loc-=2; if (phase==2) *(tok_ptr-1)=' '; goto done; + } +} +else if (c=='\\' && *loc!='@@') + if (phase==2) app_tok(*(loc++)) else loc++; + +@ We output +enough right braces to keep \TEX/ happy. + +@<Clear |bal|...@>= +if (phase==2) while (bal-- >0) app_tok('}'); +return(0); + +@** Parsing. +The most intricate part of \.{CWEAVE} is its mechanism for converting +\CEE/-like code into \TEX/ code, and we might as well plunge into this +aspect of the program now. A ``bottom up'' approach is used to parse the +\CEE/-like material, since \.{CWEAVE} must deal with fragmentary +constructions whose overall ``part of speech'' is not known. + +At the lowest level, the input is represented as a sequence of entities +that we shall call {\it scraps}, where each scrap of information consists +of two parts, its {\it category} and its {\it translation}. The category +is essentially a syntactic class, and the translation is a token list that +represents \TEX/ code. Rules of syntax and semantics tell us how to +combine adjacent scraps into larger ones, and if we are lucky an entire +\CEE/ text that starts out as hundreds of small scraps will join +together into one gigantic scrap whose translation is the desired \TEX/ +code. If we are unlucky, we will be left with several scraps that don't +combine; their translations will simply be output, one by one. + +The combination rules are given as context-sensitive productions that are +applied from left to right. Suppose that we are currently working on the +sequence of scraps $s_1\,s_2\ldots s_n$. We try first to find the longest +production that applies to an initial substring $s_1\,s_2\ldots\,$; but if +no such productions exist, we try to find the longest production +applicable to the next substring $s_2\,s_3\ldots\,$; and if that fails, we +try to match $s_3\,s_4\ldots\,$, etc. + +A production applies if the category codes have a given pattern. For +example, one of the productions (see rule~3) is +$$\hbox{|exp| }\left\{\matrix{\hbox{|binop|}\cr\hbox{|unorbinop|}}\right\} +\hbox{ |exp| }\RA\hbox{ |exp|}$$ +and it means that three consecutive scraps whose respective categories are +|exp|, |binop| (or |unorbinop|), +and |exp| are converted to one scrap whose category +is |exp|. The translations of the original +scraps are simply concatenated. The case of +$$\hbox{|exp| |comma| |exp| $\RA$ |exp|} \hskip4emE_1C\,\\{opt}9\,E_2$$ +(rule 4) is only slightly more complicated: +Here the resulting |exp| translation +consists not only of the three original translations, but also of the +tokens |opt| and 9 between the translations of the +|comma| and the following |exp|. +In the \TEX/ file, this will specify an optional line break after the +comma, with penalty 90. + +At each opportunity the longest possible production is applied. For +example, if the current sequence of scraps is |int_like| |cast| +|lbrace|, rule 31 is applied; but if the sequence is |int_like| |cast| +followed by anything other than |lbrace|, rule 32 takes effect. + +Translation rules such as `$E_1C\,\\{opt}9\,E_2$' above use subscripts +to distinguish between translations of scraps whose categories have the +same initial letter; these subscripts are assigned from left to right. + +@ Here is a list of the category codes that scraps can have. +(A few others, like |int_like|, have already been defined; the +|cat_name| array contains a complete list.) + +@d exp 1 /* denotes an expression, including perhaps a single identifier */ +@d unop 2 /* denotes a unary operator */ +@d binop 3 /* denotes a binary operator */ +@d unorbinop 4 + /* denotes an operator that can be unary or binary, depending on context */ +@d cast 5 /* denotes a cast */ +@d question 6 /* denotes a question mark and possibly the expressions flanking it */ +@d lbrace 7 /* denotes a left brace */ +@d rbrace 8 /* denotes a right brace */ +@d decl_head 9 /* denotes an incomplete declaration */ +@d comma 10 /* denotes a comma */ +@d lpar 11 /* denotes a left parenthesis or left bracket */ +@d rpar 12 /* denotes a right parenthesis or right bracket */ +@d prelangle 13 /* denotes `$<$' before we know what it is */ +@d prerangle 14 /* denotes `$>$' before we know what it is */ +@d langle 15 /* denotes `$<$' when it's used as angle bracket in a template */ +@d colcol 18 /* denotes `::' */ +@d base 19 /* denotes a colon that introduces a base specifier */ +@d decl 20 /* denotes a complete declaration */ +@d struct_head 21 /* denotes the beginning of a structure specifier */ +@d stmt 23 /* denotes a complete statement */ +@d function 24 /* denotes a complete function */ +@d fn_decl 25 /* denotes a function declarator */ +@d semi 27 /* denotes a semicolon */ +@d colon 28 /* denotes a colon */ +@d tag 29 /* denotes a statement label */ +@d if_head 30 /* denotes the beginning of a compound conditional */ +@d else_head 31 /* denotes a prefix for a compound statement */ +@d if_clause 32 /* pending \.{if} together with a condition */ +@d lproc 35 /* begins a preprocessor command */ +@d rproc 36 /* ends a preprocessor command */ +@d insert 37 /* a scrap that gets combined with its neighbor */ +@d section_scrap 38 /* section name */ +@d dead 39 /* scrap that won't combine */ +@d begin_arg 58 /* \.{@@[} */ +@d end_arg 59 /* \.{@@]} */ + +@<Glo...@>= +char cat_name[256][12]; +eight_bits cat_index; + +@ @<Set in...@>= + for (cat_index=0;cat_index<255;cat_index++) + strcpy(cat_name[cat_index],"UNKNOWN"); + strcpy(cat_name[exp],"exp"); + strcpy(cat_name[unop],"unop"); + strcpy(cat_name[binop],"binop"); + strcpy(cat_name[unorbinop],"unorbinop"); + strcpy(cat_name[cast],"cast"); + strcpy(cat_name[question],"?"); + strcpy(cat_name[lbrace],"{"@q}@>); + strcpy(cat_name[rbrace],@q{@>"}"); + strcpy(cat_name[decl_head],"decl_head"); + strcpy(cat_name[comma],","); + strcpy(cat_name[lpar],"("); + strcpy(cat_name[rpar],")"); + strcpy(cat_name[prelangle],"<"); + strcpy(cat_name[prerangle],">"); + strcpy(cat_name[langle],"\\<"); + strcpy(cat_name[colcol],"::"); + strcpy(cat_name[base],"\\:"); + strcpy(cat_name[decl],"decl"); + strcpy(cat_name[struct_head],"struct_head"); + strcpy(cat_name[stmt],"stmt"); + strcpy(cat_name[function],"function"); + strcpy(cat_name[fn_decl],"fn_decl"); + strcpy(cat_name[else_like],"else_like"); + strcpy(cat_name[semi],";"); + strcpy(cat_name[colon],":"); + strcpy(cat_name[tag],"tag"); + strcpy(cat_name[if_head],"if_head"); + strcpy(cat_name[else_head],"else_head"); + strcpy(cat_name[if_clause],"if()"); + strcpy(cat_name[lproc],"#{"@q}@>); + strcpy(cat_name[rproc],@q{@>"#}"); + strcpy(cat_name[insert],"insert"); + strcpy(cat_name[section_scrap],"section"); + strcpy(cat_name[dead],"@@d"); + strcpy(cat_name[public_like],"public"); + strcpy(cat_name[operator_like],"operator"); + strcpy(cat_name[new_like],"new"); + strcpy(cat_name[catch_like],"catch"); + strcpy(cat_name[for_like],"for"); + strcpy(cat_name[do_like],"do"); + strcpy(cat_name[if_like],"if"); + strcpy(cat_name[raw_rpar],")?"); + strcpy(cat_name[raw_unorbin],"unorbinop?"); + strcpy(cat_name[const_like],"const"); + strcpy(cat_name[raw_int],"raw"); + strcpy(cat_name[int_like],"int"); + strcpy(cat_name[case_like],"case"); + strcpy(cat_name[sizeof_like],"sizeof"); + strcpy(cat_name[struct_like],"struct"); + strcpy(cat_name[typedef_like],"typedef"); + strcpy(cat_name[define_like],"define"); + strcpy(cat_name[begin_arg],"@@["@q]@>); + strcpy(cat_name[end_arg],@q[@>"@@]"); + strcpy(cat_name[0],"zero"); + +@ This code allows \.{CWEAVE} to display its parsing steps. + +@c +void +print_cat(c) /* symbolic printout of a category */ +eight_bits c; +{ + printf(cat_name[c]); +} + +@ The token lists for translated \TEX/ output contain some special control +symbols as well as ordinary characters. These control symbols are +interpreted by \.{CWEAVE} before they are written to the output file. + +\yskip\hang |break_space| denotes an optional line break or an en space; + +\yskip\hang |force| denotes a line break; + +\yskip\hang |big_force| denotes a line break with additional vertical space; + +\yskip\hang |preproc_line| denotes that the line will be printed flush left; + +\yskip\hang |opt| denotes an optional line break (with the continuation +line indented two ems with respect to the normal starting position)---this +code is followed by an integer |n|, and the break will occur with penalty +$10n$; + +\yskip\hang |backup| denotes a backspace of one em; + +\yskip\hang |cancel| obliterates any |break_space|, |opt|, |force|, or +|big_force| tokens that immediately precede or follow it and also cancels any +|backup| tokens that follow it; + +\yskip\hang |indent| causes future lines to be indented one more em; + +\yskip\hang |outdent| causes future lines to be indented one less em. + +\yskip\noindent All of these tokens are removed from the \TEX/ output that +comes from \CEE/ text between \pb\ signs; |break_space| and |force| and +|big_force| become single spaces in this mode. The translation of other +\CEE/ texts results in \TEX/ control sequences \.{\\1}, \.{\\2}, +\.{\\3}, \.{\\4}, \.{\\5}, \.{\\6}, \.{\\7}, \.{\\8} +corresponding respectively to +|indent|, |outdent|, |opt|, |backup|, |break_space|, |force|, +|big_force| and |preproc_line|. +However, a sequence of consecutive `\.\ ', |break_space|, +|force|, and/or |big_force| tokens is first replaced by a single token +(the maximum of the given ones). + +The token |math_rel| will be translated into +\.{\\MRL\{}, and it will get a matching \.\} later. +Other control sequences in the \TEX/ output will be +`\.{\\\\\{}$\,\ldots\,$\.\}' +surrounding identifiers, `\.{\\\&\{}$\,\ldots\,$\.\}' surrounding +reserved words, `\.{\\.\{}$\,\ldots\,$\.\}' surrounding strings, +`\.{\\C\{}$\,\ldots\,$\.\}$\,$|force|' surrounding comments, and +`\.{\\X$n$:}$\,\ldots\,$\.{\\X}' surrounding section names, where +|n| is the section number. + +@d math_rel 0206 +@d big_cancel 0210 /* like |cancel|, also overrides spaces */ +@d cancel 0211 /* overrides |backup|, |break_space|, |force|, |big_force| */ +@d indent 0212 /* one more tab (\.{\\1}) */ +@d outdent 0213 /* one less tab (\.{\\2}) */ +@d opt 0214 /* optional break in mid-statement (\.{\\3}) */ +@d backup 0215 /* stick out one unit to the left (\.{\\4}) */ +@d break_space 0216 /* optional break between statements (\.{\\5}) */ +@d force 0217 /* forced break between statements (\.{\\6}) */ +@d big_force 0220 /* forced break with additional space (\.{\\7}) */ +@d preproc_line 0221 /* begin line without indentation (\.{\\8}) */ +@^high-bit character handling@> +@d quoted_char 0222 + /* introduces a character token in the range |0200|--|0377| */ +@d end_translation 0223 /* special sentinel token at end of list */ +@d inserted 0224 /* sentinel to mark translations of inserts */ + +@ The raw input is converted into scraps according to the following table, +which gives category codes followed by the translations. +\def\stars {\.{**}}% +The symbol `\stars' stands for `\.{\\\&\{{\rm identifier}\}}', +i.e., the identifier itself treated as a reserved word. +The right-hand column is the so-called |mathness|, which is explained +further below. + +An identifier |c| of length 1 is translated as \.{\\\v c} instead of +as \.{\\\\\{c\}}. An identifier \.{CAPS} in all caps is translated as +\.{\\.\{CAPS\}} instead of as \.{\\\\\{CAPS\}}. An identifier that has +become a reserved word via |typedef| is translated with \.{\\\&} replacing +\.{\\\\} and |raw_int| replacing |exp|. + +A string of length greater than 20 is broken into pieces of size at most~20 +with discretionary breaks in between. + +\yskip\halign{\quad#\hfil&\quad#\hfil&\quad\hfil#\hfil\cr +\.{!=}&|binop|: \.{\\I}&yes\cr +\.{<=}&|binop|: \.{\\Z}&yes\cr +\.{>=}&|binop|: \.{\\G}&yes\cr +\.{==}&|binop|: \.{\\E}&yes\cr +\.{\&\&}&|binop|: \.{\\W}&yes\cr +\.{\v\v}&|binop|: \.{\\V}&yes\cr +\.{++}&|binop|: \.{\\PP}&yes\cr +\.{--}&|binop|: \.{\\MM}&yes\cr +\.{->}&|binop|: \.{\\MG}&yes\cr +\.{>>}&|binop|: \.{\\GG}&yes\cr +\.{<<}&|binop|: \.{\\LL}&yes\cr +\.{::}&|colcol|: \.{\\DC}&maybe\cr +\.{.*}&|binop|: \.{\\PA}&yes\cr +\.{->*}&|binop|: \.{\\MGA}&yes\cr +\.{...}&|exp|: \.{\\,\\ldots\\,}&yes\cr +\."string\."&|exp|: \.{\\.\{}string with special characters quoted\.\}&maybe\cr +\.{@@=}string\.{@@>}&|exp|: \.{\\vb\{}string with special characters + quoted\.\}&maybe\cr +\.{@@'7'}&|exp|: \.{\\.\{@@'7'\}}&maybe\cr +\.{077} or \.{\\77}&|exp|: \.{\\T\{\\\~77\}}&maybe\cr +\.{0x7f}&|exp|: \.{\\T\{\\\^7f\}}&maybe\cr +\.{77}&|exp|: \.{\\T\{77\}}&maybe\cr +\.{77L}&|exp|: \.{\\T\{77\\\$L\}}&maybe\cr +\.{0.1E5}&|exp|: \.{\\T\{0.1\\\_5\}}&maybe\cr +\.+&|unorbinop|: \.+&yes\cr +\.-&|unorbinop|: \.-&yes\cr +\.*&|raw_unorbin|: \.*&yes\cr +\./&|binop|: \./&yes\cr +\.<&|prelangle|: \.{\\langle}&yes\cr +\.=&|binop|: \.{\\K}&yes\cr +\.>&|prerangle|: \.{\\rangle}&yes\cr +\..&|binop|: \..&yes\cr +\.{\v}&|binop|: \.{\\OR}&yes\cr +\.\^&|binop|: \.{\\XOR}&yes\cr +\.\%&|binop|: \.{\\MOD}&yes\cr +\.?&|question|: \.{\\?}&yes\cr +\.!&|unop|: \.{\\R}&yes\cr +\.\~&|unop|: \.{\\CM}&yes\cr +\.\&&|raw_unorbin|: \.{\\AND}&yes\cr +\.(&|lpar|: \.(&maybe\cr +\.[&|lpar|: \.[&maybe\cr +\.)&|raw_rpar|: \.)&maybe\cr +\.]&|raw_rpar|: \.]&maybe\cr +\.\{&|lbrace|: \.\{&yes\cr +\.\}&|lbrace|: \.\}&yes\cr +\.,&|comma|: \.,&yes\cr +\.;&|semi|: \.;&maybe\cr +\.:&|colon|: \.:&maybe\cr +\.\# (within line)&|unorbinop|: \.{\\\#}&yes\cr +\.\# (at beginning)&|lproc|: |force| |preproc_line| \.{\\\#}&no\cr +end of \.\# line&|rproc|: |force|&no\cr +identifier&|exp|: \.{\\\\\{}identifier with underlines quoted\.\}&maybe\cr +\.{asm}&|sizeof_like|: \stars&maybe\cr +\.{auto}&|int_like|: \stars&maybe\cr +\.{break}&|case_like|: \stars&maybe\cr +\.{case}&|case_like|: \stars&maybe\cr +\.{catch}&|catch_like|: \stars&maybe\cr +\.{char}&|raw_int|: \stars&maybe\cr +\.{class}&|struct_like|: \stars&maybe\cr +\.{clock\_t}&|raw_int|: \stars&maybe\cr +\.{const}&|const_like|: \stars&maybe\cr +\.{continue}&|case_like|: \stars&maybe\cr +\.{default}&|case_like|: \stars&maybe\cr +\.{define}&|define_like|: \stars&maybe\cr +\.{defined}&|sizeof_like|: \stars&maybe\cr +\.{delete}&|sizeof_like|: \stars&maybe\cr +\.{div\_t}&|raw_int|: \stars&maybe\cr +\.{do}&|do_like|: \stars&maybe\cr +\.{double}&|raw_int|: \stars&maybe\cr +\.{elif}&|if_like|: \stars&maybe\cr +\.{else}&|else_like|: \stars&maybe\cr +\.{endif}&|if_like|: \stars&maybe\cr +\.{enum}&|struct_like|: \stars&maybe\cr +\.{error}&|if_like|: \stars&maybe\cr +\.{extern}&|int_like|: \stars&maybe\cr +\.{FILE}&|raw_int|: \stars&maybe\cr +\.{float}&|raw_int|: \stars&maybe\cr +\.{for}&|for_like|: \stars&maybe\cr +\.{fpos\_t}&|raw_int|: \stars&maybe\cr +\.{friend}&|int_like|: \stars&maybe\cr +\.{goto}&|case_like|: \stars&maybe\cr +\.{if}&|if_like|: \stars&maybe\cr +\.{ifdef}&|if_like|: \stars&maybe\cr +\.{ifndef}&|if_like|: \stars&maybe\cr +\.{include}&|if_like|: \stars&maybe\cr +\.{inline}&|int_like|: \stars&maybe\cr +\.{int}&|raw_int|: \stars&maybe\cr +\.{jmp\_buf}&|raw_int|: \stars&maybe\cr +\.{ldiv\_t}&|raw_int|: \stars&maybe\cr +\.{line}&|if_like|: \stars&maybe\cr +\.{long}&|raw_int|: \stars&maybe\cr +\.{new}&|new_like|: \stars&maybe\cr +\.{NULL}&|exp|: \.{\\NULL}&yes\cr +\.{offsetof}&|sizeof_like|: \stars&maybe\cr +\.{operator}&|operator_like|: \stars&maybe\cr +\.{pragma}&|if_like|: \stars&maybe\cr +\.{private}&|public_like|: \stars&maybe\cr +\.{protected}&|public_like|: \stars&maybe\cr +\.{ptrdiff\_t}&|raw_int|: \stars&maybe\cr +\.{public}&|public_like|: \stars&maybe\cr +\.{register}&|int_like|: \stars&maybe\cr +\.{return}&|case_like|: \stars&maybe\cr +\.{short}&|raw_int|: \stars&maybe\cr +\.{sig\_atomic\_t}&|raw_int|: \stars&maybe\cr +\.{signed}&|raw_int|: \stars&maybe\cr +\.{size\_t}&|raw_int|: \stars&maybe\cr +\.{sizeof}&|sizeof_like|: \stars&maybe\cr +\.{static}&|int_like|: \stars&maybe\cr +\.{struct}&|struct_like|: \stars&maybe\cr +\.{switch}&|if_like|: \stars&maybe\cr +\.{template}&|int_like|: \stars&maybe\cr +\.{TeX}&|exp|: \.{\\TeX}&yes\cr +\.{this}&|exp|: \.{\\this}&yes\cr +\.{throw}&|case_like|: \stars&maybe\cr +\.{time\_t}&|raw_int|: \stars&maybe\cr +\.{try}&|else_like|: \stars&maybe\cr +\.{typedef}&|typedef_like|: \stars&maybe\cr +\.{undef}&|if_like|: \stars&maybe\cr +\.{union}&|struct_like|: \stars&maybe\cr +\.{unsigned}&|raw_int|: \stars&maybe\cr +\.{va\_dcl}&|decl|: \stars&maybe\cr +\.{va\_list}&|raw_int|: \stars&maybe\cr +\.{virtual}&|int_like|: \stars&maybe\cr +\.{void}&|raw_int|: \stars&maybe\cr +\.{volatile}&|const_like|: \stars&maybe\cr +\.{wchar\_t}&|raw_int|: \stars&maybe\cr +\.{while}&|if_like|: \stars&maybe\cr +\.{@@,}&|insert|: \.{\\,}&maybe\cr +\.{@@\v}&|insert|: |opt| \.0&maybe\cr +\.{@@/}&|insert|: |force|&no\cr +\.{@@\#}&|insert|: |big_force|&no\cr +\.{@@+}&|insert|: |big_cancel| \.{\{\}} |break_space| + \.{\{\}} |big_cancel|&no\cr +\.{@@;}&|semi|: &maybe\cr +\.{@@[@q]@>}&|begin_arg|: &maybe\cr +\.{@q[@>@@]}&|end_arg|: &maybe\cr +\.{@@\&}&|insert|: \.{\\J}&maybe\cr +\.{@@h}&|insert|: |force| \.{\\ATH} |force|&no\cr +\.{@@<}\thinspace section name\thinspace\.{@@>}&|section_scrap|: + \.{\\X}$n$\.:translated section name\.{\\X}&maybe\cr +\.{@@(@q)@>}\thinspace section name\thinspace\.{@@>}&|section_scrap|: + \.{\\X}$n$\.{:\\.\{}section name with special characters + quoted\.{\ \}\\X}&maybe\cr +\.{/*}comment\.{*/}&|insert|: |cancel| + \.{\\C\{}translated comment\.\} |force|&no\cr +\.{//}comment&|insert|: |cancel| + \.{\\SHC\{}translated comment\.\} |force|&no\cr +} + +The construction \.{@@t}\thinspace stuff\/\thinspace\.{@@>} contributes +\.{\\hbox\{}\thinspace stuff\/\thinspace\.\} to the following scrap. + +@i prod.w + +@* Implementing the productions. +More specifically, a scrap is a structure consisting of a category +|cat| and a |text_pointer| |trans|, which points to the translation in +|tok_start|. When \CEE/ text is to be processed with the grammar above, +we form an array |scrap_info| containing the initial scraps. +Our production rules have the nice property that the right-hand side is never +longer than the left-hand side. Therefore it is convenient to use sequential +allocation for the current sequence of scraps. Five pointers are used to +manage the parsing: + +\yskip\hang |pp| is a pointer into |scrap_info|. We will try to match +the category codes |pp->cat,@,@,(pp+1)->cat|$,\,\,\ldots\,$ +to the left-hand sides of productions. + +\yskip\hang |scrap_base|, |lo_ptr|, |hi_ptr|, and |scrap_ptr| are such that +the current sequence of scraps appears in positions |scrap_base| through +|lo_ptr| and |hi_ptr| through |scrap_ptr|, inclusive, in the |cat| and +|trans| arrays. Scraps located between |scrap_base| and |lo_ptr| have +been examined, while those in positions |>=hi_ptr| have not yet been +looked at by the parsing process. + +\yskip\noindent Initially |scrap_ptr| is set to the position of the final +scrap to be parsed, and it doesn't change its value. The parsing process +makes sure that |lo_ptr>=pp+3|, since productions have as many as four terms, +by moving scraps from |hi_ptr| to |lo_ptr|. If there are +fewer than |pp+3| scraps left, the positions up to |pp+3| are filled with +blanks that will not match in any productions. Parsing stops when +|pp==lo_ptr+1| and |hi_ptr==scrap_ptr+1|. + +Since the |scrap| structure will later be used for other purposes, we +declare its second element as unions. + +@<Type...@>= +typedef struct { + eight_bits cat; + eight_bits mathness; + union { + text_pointer Trans; + @<Rest of |trans_plus| union@>@; + } trans_plus; +} scrap; +typedef scrap *scrap_pointer; + +@ @d trans trans_plus.Trans /* translation texts of scraps */ + +@<Global...@>= +scrap scrap_info[max_scraps]; /* memory array for scraps */ +scrap_pointer scrap_info_end=scrap_info+max_scraps -1; /* end of |scrap_info| */ +scrap_pointer pp; /* current position for reducing productions */ +scrap_pointer scrap_base; /* beginning of the current scrap sequence */ +scrap_pointer scrap_ptr; /* ending of the current scrap sequence */ +scrap_pointer lo_ptr; /* last scrap that has been examined */ +scrap_pointer hi_ptr; /* first scrap that has not been examined */ +scrap_pointer max_scr_ptr; /* largest value assumed by |scrap_ptr| */ + +@ @<Set init...@>= +scrap_base=scrap_info+1; +max_scr_ptr=scrap_ptr=scrap_info; + +@ Token lists in |@!tok_mem| are composed of the following kinds of +items for \TEX/ output. + +\yskip\item{$\bullet$}Character codes and special codes like |force| and +|math_rel| represent themselves; + +\item{$\bullet$}|id_flag+p| represents \.{\\\\\{{\rm identifier $p$}\}}; + +\item{$\bullet$}|res_flag+p| represents \.{\\\&\{{\rm identifier $p$}\}}; + +\item{$\bullet$}|section_flag+p| represents section name |p|; + +\item{$\bullet$}|tok_flag+p| represents token list number |p|; + +\item{$\bullet$}|inner_tok_flag+p| represents token list number |p|, to be +translated without line-break controls. + +@d id_flag 10240 /* signifies an identifier */ +@d res_flag 2*id_flag /* signifies a reserved word */ +@d section_flag 3*id_flag /* signifies a section name */ +@d tok_flag 4*id_flag /* signifies a token list */ +@d inner_tok_flag 5*id_flag /* signifies a token list in `\pb' */ + +@c +void +print_text(p) /* 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| */ + default: @<Print token |r| in symbolic form@>; + } + } + fflush(stdout); +} + +@ @<Print token |r|...@>= +switch (r) { + case math_rel: printf("\\mathrel{"@q}@>); break; + case big_cancel: printf("[ccancel]"); break; + case cancel: printf("[cancel]"); break; + case indent: printf("[indent]"); break; + case outdent: printf("[outdent]"); break; + case backup: printf("[backup]"); break; + case opt: printf("[opt]"); break; + case break_space: printf("[break]"); break; + case force: printf("[force]"); break; + case big_force: printf("[fforce]"); break; + case preproc_line: printf("[preproc]"); break; + case quoted_char: j++; printf("[%o]",(unsigned)*j); break; + case end_translation: printf("[quit]"); break; + case inserted: printf("[inserted]"); break; + default: putxchar(r); +} + +@ The production rules listed above are embedded directly into \.{CWEAVE}, +since it is easier to do this than to write an interpretive system +that would handle production systems in general. Several macros are defined +here so that the program for each production is fairly short. + +All of our productions conform to the general notion that some |k| +consecutive scraps starting at some position |j| are to be replaced by a +single scrap of some category |c| whose translation is composed from the +translations of the disappearing scraps. After this production has been +applied, the production pointer |pp| should change by an amount |d|. Such +a production can be represented by the quadruple |(j,k,c,d)|. For example, +the production `|exp@,comma@,exp| $\RA$ |exp|' would be represented by +`|(pp,3,exp,-2)|'; in this case the pointer |pp| should decrease by 2 +after the production has been applied, because some productions with +|exp| in their second or third positions might now match, +but no productions have +|exp| in the fourth position of their left-hand sides. Note that +the value of |d| is determined by the whole collection of productions, not +by an individual one. +The determination of |d| has been +done by hand in each case, based on the full set of productions but not on +the grammar of \CEE/ or on the rules for constructing the initial +scraps. + +We also attach a serial number to each production, so that additional +information is available when debugging. For example, the program below +contains the statement `|reduce(pp,3,exp,-2,4)|' when it implements +the production just mentioned. + +Before calling |reduce|, the program should have appended the tokens of +the new translation to the |tok_mem| array. We commonly want to append +copies of several existing translations, and macros are defined to +simplify these common cases. For example, \\{app2}|(pp)| will append the +translations of two consecutive scraps, |pp->trans| and |(pp+1)->trans|, to +the current token list. If the entire new translation is formed in this +way, we write `|squash(j,k,c,d,n)|' instead of `|reduce(j,k,c,d,n)|'. For +example, `|squash(pp,3,exp,-2,3)|' is an abbreviation for `\\{app3}|(pp); +reduce(pp,3,exp,-2,3)|'. + +A couple more words of explanation: +Both |big_app| and |app| append a token (while |big_app1| to |big_app4| +append the specified number of scrap translations) to the current token list. +The difference between |big_app| and |app| is simply that |big_app| +checks whether there can be a conflict between math and non-math +tokens, and intercalates a `\.{\$}' token if necessary. When in +doubt what to use, use |big_app|. + +The |mathness| is an attribute of scraps that says whether they are +to be printed in a math mode context or not. It is separate from the +``part of speech'' (the |cat|) because to make each |cat| have +a fixed |mathness| (as in the original \.{WEAVE}) would multiply the +number of necessary production rules. + +The low two bits (i.e. |mathness % 4|) control the left boundary. +(We need two bits because we allow cases |yes_math|, |no_math| and +|maybe_math|, which can go either way.) +The next two bits (i.e. |mathness / 4|) control the right boundary. +If we combine two scraps and the right boundary of the first has +a different mathness from the left boundary of the second, we +insert a \.{\$} in between. Similarly, if at printing time some +irreducible scrap has a |yes_math| boundary the scrap gets preceded +or followed by a \.{\$}. The left boundary is |maybe_math| if and +only if the right boundary is. + +The code below is an exact translation of the production rules into +\CEE/, using such macros, and the reader should have no difficulty +understanding the format by comparing the code with the symbolic +productions as they were listed earlier. + +@d no_math 2 /* should be in horizontal mode */ +@d yes_math 1 /* should be in math mode */ +@d maybe_math 0 /* works in either horizontal or math mode */ +@d big_app2(a) big_app1(a);big_app1(a+1) +@d big_app3(a) big_app2(a);big_app1(a+2) +@d big_app4(a) big_app3(a);big_app1(a+3) +@d app(a) *(tok_ptr++)=a +@d app1(a) *(tok_ptr++)=tok_flag+(int)((a)->trans-tok_start) + +@<Global...@>= +int cur_mathness, init_mathness; + +@ @c +void +app_str(s) +char *s; +{ + while (*s) app_tok(*(s++)); +} + +void +big_app(a) +token a; +{ + if (a==' ' || (a>=big_cancel && a<=big_force)) /* non-math token */ { + if (cur_mathness==maybe_math) init_mathness=no_math; + else if (cur_mathness==yes_math) app_str("{}$"); + cur_mathness=no_math; + } + else { + if (cur_mathness==maybe_math) init_mathness=yes_math; + else if (cur_mathness==no_math) app_str("${}"); + cur_mathness=yes_math; + } + app(a); +} + +void +big_app1(a) +scrap_pointer a; +{ + switch (a->mathness % 4) { /* left boundary */ + case (no_math): + if (cur_mathness==maybe_math) init_mathness=no_math; + else if (cur_mathness==yes_math) app_str("{}$"); + cur_mathness=a->mathness / 4; /* right boundary */ + break; + case (yes_math): + if (cur_mathness==maybe_math) init_mathness=yes_math; + else if (cur_mathness==no_math) app_str("${}"); + cur_mathness=a->mathness / 4; /* right boundary */ + break; + case (maybe_math): /* no changes */ break; + } + app(tok_flag+(int)((a)->trans-tok_start)); +} + +@ Let us consider the big switch for productions now, before looking +at its context. We want to design the program so that this switch +works, so we might as well not keep ourselves in suspense about exactly what +code needs to be provided with a proper environment. + +@d cat1 (pp+1)->cat +@d cat2 (pp+2)->cat +@d cat3 (pp+3)->cat +@d lhs_not_simple (pp->cat!=semi && pp->cat!=raw_int && pp->cat!=raw_unorbin + && pp->cat!=raw_rpar && pp->cat!=const_like) + +@<Match a production at |pp|, or increase |pp| if there is no match@>= { + if (cat1==end_arg && lhs_not_simple) + if (pp->cat==begin_arg) squash(pp,2,exp,-2,110); + else squash(pp,2,end_arg,-1,111); + else if (cat1==insert) squash(pp,2,pp->cat,-2,0); + else if (cat2==insert) squash(pp+1,2,(pp+1)->cat,-1,0); + else if (cat3==insert) squash(pp+2,2,(pp+2)->cat,0,0); + else + switch (pp->cat) { + case exp: @<Cases for |exp|@>; @+break; + case lpar: @<Cases for |lpar|@>; @+break; + case question: @<Cases for |question|@>; @+break; + case unop: @<Cases for |unop|@>; @+break; + case unorbinop: @<Cases for |unorbinop|@>; @+break; + case binop: @<Cases for |binop|@>; @+break; + case cast: @<Cases for |cast|@>; @+break; + case sizeof_like: @<Cases for |sizeof_like|@>; @+break; + case int_like: @<Cases for |int_like|@>; @+break; + case decl_head: @<Cases for |decl_head|@>; @+break; + case decl: @<Cases for |decl|@>; @+break; + case typedef_like: @<Cases for |typedef_like|@>; @+break; + case struct_like: @<Cases for |struct_like|@>; @+break; + case struct_head: @<Cases for |struct_head|@>; @+break; + case fn_decl: @<Cases for |fn_decl|@>; @+break; + case function: @<Cases for |function|@>; @+break; + case lbrace: @<Cases for |lbrace|@>; @+break; + case do_like: @<Cases for |do_like|@>; @+break; + case if_like: @<Cases for |if_like|@>; @+break; + case for_like: @<Cases for |for_like|@>; @+break; + case else_like: @<Cases for |else_like|@>; @+break; + case if_clause: @<Cases for |if_clause|@>; @+break; + case if_head: @<Cases for |if_head|@>; @+break; + case else_head: @<Cases for |else_head|@>; @+break; + case case_like: @<Cases for |case_like|@>; @+break; + case stmt: @<Cases for |stmt|@>; @+break; + case tag: @<Cases for |tag|@>; @+break; + case semi: @<Cases for |semi|@>; @+break; + case lproc: @<Cases for |lproc|@>; @+break; + case section_scrap: @<Cases for |section_scrap|@>; @+break; + case insert: @<Cases for |insert|@>; @+break; + case prelangle: @<Cases for |prelangle|@>; @+break; + case prerangle: @<Cases for |prerangle|@>; @+break; + case langle: @<Cases for |langle|@>; @+break; + case public_like: @<Cases for |public_like|@>; @+break; + case colcol: @<Cases for |colcol|@>; @+break; + case new_like: @<Cases for |new_like|@>; @+break; + case operator_like: @<Cases for |operator_like|@>; @+break; + case catch_like: @<Cases for |catch_like|@>; @+break; + case base: @<Cases for |base|@>; @+break; + case raw_rpar: @<Cases for |raw_rpar|@>; @+break; + case raw_unorbin: @<Cases for |raw_unorbin|@>; @+break; + case const_like: @<Cases for |const_like|@>; @+break; + case raw_int: @<Cases for |raw_int|@>; @+break; + } + pp++; /* if no match was found, we move to the right */ +} + +@ In \CEE/, new specifier names can be defined via |typedef|, and we want +to make the parser recognize future occurrences of the identifier thus +defined as specifiers. This is done by the procedure |make_reserved|, +which changes the |ilk| of the relevant identifier. + +We first need a procedure to recursively seek the first +identifier in a token list, because the identifier might +be enclosed in parentheses, as when one defines a function +returning a pointer. + +@d no_ident_found 0 /* distinct from any identifier token */ + +@c +token_pointer +find_first_ident(p) +text_pointer p; +{ + token_pointer q; /* token to be returned */ + token_pointer j; /* token being looked at */ + sixteen_bits r; /* remainder of token after the flag has been stripped off */ + if (p>=text_ptr) confusion("find_first_ident"); + for (j=*p; j<*(p+1); j++) { + r=*j%id_flag; + switch (*j/id_flag) { + case 1: case 2: return j; + case 4: case 5: /* |tok_flag| or |inner_tok_flag| */ + if ((q=find_first_ident(tok_start+r))!=no_ident_found) + return q; + default: ; /* char, |section_flag|, fall thru: move on to next token */ + if (*j==inserted) return no_ident_found; /* ignore inserts */ + } + } + return no_ident_found; +} + +@ The scraps currently being parsed must be inspected for any +occurrence of the identifier that we're making reserved; hence +the |for| loop below. + +@c +void +make_reserved(p) /* 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| */ + if ((tok_loc=find_first_ident(p->trans))==no_ident_found) + return; /* this should not happen */ + tok_value=*tok_loc; + for (;p<=scrap_ptr; p==lo_ptr? p=hi_ptr: p++) { + if (p->cat==exp) { + if (**(p->trans)==tok_value) { + p->cat=raw_int; + **(p->trans)=tok_value%id_flag+res_flag; + } + } + } + (name_dir+(sixteen_bits)(tok_value%id_flag))->ilk=raw_int; + *tok_loc=tok_value%id_flag+res_flag; +} + +@ In the following situations we want to mark the occurrence of +an identifier as a definition: when |make_reserved| is just about to be +used; after a specifier, as in |char **argv|; +before a colon, as in \\{found}:; and in the declaration of a function, +as in \\{main}()$\{\ldots;\}$. This is accomplished by the invocation +of |make_underlined| at appropriate times. Notice that, in the declaration +of a function, we only find out that the identifier is being defined after +it has been swallowed up by an |exp|. + +@c +void +make_underlined(p) +/* underline the entry for the first identifier in |p->trans| */ +scrap_pointer p; +{ + token_pointer tok_loc; /* where the first identifier appears */ + if ((tok_loc=find_first_ident(p->trans))==no_ident_found) + return; /* this happens after parsing the |()| in |double f();| */ + xref_switch=def_flag; + underline_xref(*tok_loc%id_flag+name_dir); +} + +@ We cannot use |new_xref| to underline a cross-reference at this point +because this would just make a new cross-reference at the end of the list. +We actually have to search through the list for the existing +cross-reference. + +@<Predecl...@>= +void underline_xref(); + +@ @c +void +underline_xref(p) +name_pointer p; +{ + xref_pointer q=(xref_pointer)p->xref; /* pointer to cross-reference being examined */ + xref_pointer r; /* temporary pointer for permuting cross-references */ + sixteen_bits m; /* cross-reference value to be installed */ + sixteen_bits n; /* cross-reference value being examined */ + if (no_xref) return; + m=section_count+xref_switch; + while (q != xmem) { + n=q->num; + if (n==m) return; + else if (m==n+def_flag) { + q->num=m; return; + } + else if (n>=def_flag && n<m) break; + q=q->xlink; + } + @<Insert new cross-reference at |q|, not at beginning of list@>; +} + +@ We get to this section only when the identifier is one letter long, +so it didn't get a non-underlined entry during phase one. But it may +have got some explicitly underlined entries in later sections, so in order +to preserve the numerical order of the entries in the index, we have +to insert the new cross-reference not at the beginning of the list +(namely, at |p->xref|), but rather right before |q|. + +@<Insert new cross-reference at |q|...@>= + append_xref(0); /* this number doesn't matter */ + xref_ptr->xlink=(xref_pointer)p->xref; r=xref_ptr; + p->xref=(char*)xref_ptr; + while (r->xlink!=q) {r->num=r->xlink->num; r=r->xlink;} + r->num=m; /* everything from |q| on is left undisturbed */ + +@ Now comes the code that tries to match each production starting +with a particular type of scrap. Whenever a match is discovered, +the |squash| or |reduce| macro will cause the appropriate action +to be performed, followed by |goto found|. + +@<Cases for |exp|@>= +if (cat1==lbrace || cat1==int_like || cat1==decl) { + make_underlined(pp); big_app1(pp); big_app(indent); app(indent); + reduce(pp,1,fn_decl,0,1); +} +else if (cat1==unop) squash(pp,2,exp,-2,2); +else if ((cat1==binop || cat1==unorbinop) && cat2==exp) + squash(pp,3,exp,-2,3); +else if (cat1==comma && cat2==exp) { + big_app2(pp); + app(opt); app('9'); big_app1(pp+2); reduce(pp,3,exp,-2,4); +} +else if (cat1==exp || cat1==cast) squash(pp,2,exp,-2,5); +else if (cat1==semi) squash(pp,2,stmt,-1,6); +else if (cat1==colon) { + make_underlined (pp); squash(pp,2,tag,0,7); +} +else if (cat1==base) { + if (cat2==int_like && cat3==comma) { + big_app1(pp+1); big_app(' '); big_app2(pp+2); + app(opt); app('9'); reduce(pp+1,3,base,0,8); + } + else if (cat2==int_like && cat3==lbrace) { + big_app1(pp); big_app(' '); big_app1(pp+1); big_app(' '); big_app1(pp+2); + reduce(pp,3,exp,-1,9); + } +} +else if (cat1==rbrace) squash(pp,1,stmt,-1,10); + +@ @<Cases for |lpar|@>= +if ((cat1==exp||cat1==unorbinop) && cat2==rpar) squash(pp,3,exp,-2,11); +else if (cat1==rpar) { + big_app1(pp); app('\\'); app(','); big_app1(pp+1); +@.\\,@> + reduce(pp,2,exp,-2,12); +} +else if (cat1==decl_head || cat1==int_like || cat1==exp) { + if (cat2==rpar) squash(pp,3,cast,-2,13); + else if (cat2==comma) { + big_app3(pp); app(opt); app('9'); reduce(pp,3,lpar,0,14); + } +} +else if (cat1==stmt || cat1==decl) { + big_app2(pp); big_app(' '); reduce(pp,2,lpar,0,15); +} + +@ @<Cases for |question|@>= +if (cat1==exp && cat2==colon) squash(pp,3,binop,-2,16); + +@ @<Cases for |unop|@>= +if (cat1==exp || cat1==int_like) squash(pp,2,cat1,-2,17); + +@ @<Cases for |unorbinop|@>= +if (cat1==exp || cat1==int_like) { + big_app('{'); big_app1(pp); big_app('}'); big_app1(pp+1); + reduce(pp,2,cat1,-2,18); +} +else if (cat1==binop) { + big_app(math_rel); big_app1(pp); big_app('{'); big_app1(pp+1); big_app('}'); + big_app('}'); reduce(pp,2,binop,-1,19); +} + +@ @<Cases for |binop|@>= +if (cat1==binop) { + big_app(math_rel); big_app('{'); big_app1(pp); big_app('}'); + big_app('{'); big_app1(pp+1); big_app('}'); + big_app('}'); reduce(pp,2,binop,-1,20); +} + +@ @<Cases for |cast|@>= +if (cat1==exp) { + big_app1(pp); big_app(' '); big_app1(pp+1); reduce(pp,2,exp,-2,21); +} +else if (cat1==semi) squash(pp,1,exp,-2,22); + +@ @<Cases for |sizeof_like|@>= +if (cat1==cast) squash(pp,2,exp,-2,23); +else if (cat1==exp) { + big_app1(pp); big_app(' '); big_app1(pp+1); reduce(pp,2,exp,-2,24); +} + +@ @<Cases for |int_like|@>= +if (cat1==int_like|| cat1==struct_like) { + big_app1(pp); big_app(' '); big_app1(pp+1); reduce(pp,2,cat1,-2,25); +} +else if (cat1==exp && (cat2==raw_int||cat2==struct_like)) + squash(pp,2,int_like,-2,26); +else if (cat1==exp || cat1==unorbinop || cat1==semi) { + big_app1(pp); + if (cat1!=semi) big_app(' '); + reduce(pp,1,decl_head,-1,27); +} +else if (cat1==colon) { + big_app1(pp); big_app(' '); reduce(pp,1,decl_head,0,28); +} +else if (cat1==prelangle) squash(pp+1,1,langle,1,29); +else if (cat1==colcol && (cat2==exp||cat2==int_like)) squash(pp,3,cat2,-2,30); +else if (cat1==cast) { + if (cat2==lbrace) { + big_app2(pp); big_app(indent); big_app(indent); + reduce(pp,2,fn_decl,1,31); + } + else squash(pp,2,int_like,-2,32); +} + +@ @<Cases for |decl_head|@>= +if (cat1==comma) { + big_app2(pp); big_app(' '); reduce(pp,2,decl_head,-1,33); +} +else if (cat1==unorbinop) { + big_app1(pp); big_app('{'); big_app1(pp+1); big_app('}'); + reduce(pp,2,decl_head,-1,34); +} +else if (cat1==exp && cat2!=lpar && cat2!=exp) { + make_underlined(pp+1); squash(pp,2,decl_head,-1,35); +} +else if ((cat1==binop||cat1==colon) && cat2==exp && (cat3==comma || + cat3==semi || cat3==rpar)) + squash(pp,3,decl_head,-1,36); +else if (cat1==cast) squash(pp,2,decl_head,-1,37); +else if (cat1==lbrace || (cat1==int_like&&cat2!=colcol) || cat1==decl) { + big_app1(pp); big_app(indent); app(indent); reduce(pp,1,fn_decl,0,38); +} +else if (cat1==semi) squash(pp,2,decl,-1,39); + +@ @<Cases for |decl|@>= +if (cat1==decl) { + big_app1(pp); big_app(force); big_app1(pp+1); + reduce(pp,2,decl,-1,40); +} +else if (cat1==stmt || cat1==function) { + big_app1(pp); big_app(big_force); + big_app1(pp+1); reduce(pp,2,cat1,-1,41); +} + +@ @<Cases for |typedef_like|@>= +if (cat1==decl_head) + if ((cat2==exp&&cat3!=lpar&&cat3!=exp)||cat2==int_like) { + make_underlined(pp+2); make_reserved(pp+2); + big_app2(pp+1); reduce(pp+1,2,decl_head,0,42); + } + else if (cat2==semi) { + big_app1(pp); big_app(' '); big_app2(pp+1); reduce(pp,3,decl,-1,43); + } + +@ @<Cases for |struct_like|@>= +if (cat1==lbrace) { + big_app1(pp); big_app(' '); big_app1(pp+1); reduce(pp,2,struct_head,0,44); +} +else if (cat1==exp||cat1==int_like) { + if (cat2==lbrace || cat2==semi) { + make_underlined(pp+1); make_reserved(pp+1); + big_app1(pp); big_app(' '); big_app1(pp+1); + if (cat2==semi) reduce(pp,2,decl_head,0,45); + else { + big_app(' '); big_app1(pp+2);reduce(pp,3,struct_head,0,46); + } + } + else if (cat2==colon) squash(pp+2,1,base,-1,47); + else if (cat2!=base) { + big_app1(pp); big_app(' '); big_app1(pp+1); reduce(pp,2,int_like,-2,48); + } +} + +@ @<Cases for |struct_head|@>= +if ((cat1==decl || cat1==stmt || cat1==function) && cat2==rbrace) { + big_app1(pp); big_app(indent); big_app(force); big_app1(pp+1); + big_app(outdent); big_app(force); big_app1(pp+2); + reduce(pp,3,int_like,-2,49); +} +else if (cat1==rbrace) { + big_app1(pp); app_str("\\,"); big_app1(pp+1); +@.\\,@> + reduce(pp,2,int_like,-2,50); +} + +@ @<Cases for |fn_decl|@>= +if (cat1==decl) { + big_app1(pp); big_app(force); big_app1(pp+1); reduce(pp,2,fn_decl,0,51); +} +else if (cat1==stmt) { + big_app1(pp); app(outdent); app(outdent); big_app(force); + big_app1(pp+1); reduce(pp,2,function,-1,52); +} + +@ @<Cases for |function|@>= +if (cat1==function || cat1==decl || cat1==stmt) { + big_app1(pp); big_app(big_force); big_app1(pp+1); reduce(pp,2,cat1,-1,53); +} + +@ @<Cases for |lbrace|@>= +if (cat1==rbrace) { + big_app1(pp); app('\\'); app(','); big_app1(pp+1); +@.\\,@> + reduce(pp,2,stmt,-1,54); +} +else if ((cat1==stmt||cat1==decl||cat1==function) && cat2==rbrace) { + big_app(force); big_app1(pp); big_app(indent); big_app(force); + big_app1(pp+1); big_app(force); big_app(backup); big_app1(pp+2); + big_app(outdent); big_app(force); reduce(pp,3,stmt,-1,55); +} +else if (cat1==exp) { + if (cat2==rbrace) squash(pp,3,exp,-2,56); + else if (cat2==comma && cat3==rbrace) squash(pp,4,exp,-2,56); +} + +@ @<Cases for |if_like|@>= +if (cat1==exp) { + big_app1(pp); big_app(' '); big_app1(pp+1); reduce(pp,2,if_clause,0,57); +} + +@ @<Cases for |for_like|@>= +if (cat1==exp) { + big_app1(pp); big_app(' '); big_app1(pp+1); reduce(pp,2,else_like,-2,58); +} + +@ @<Cases for |else_like|@>= +if (cat1==lbrace) squash(pp,1,else_head,0,59); +else if (cat1==stmt) { + big_app(force); big_app1(pp); big_app(indent); big_app(break_space); + big_app1(pp+1); big_app(outdent); big_app(force); + reduce(pp,2,stmt,-1,60); +} + +@ @<Cases for |else_head|@>= +if (cat1==stmt || cat1==exp) { + big_app(force); big_app1(pp); big_app(break_space); app(noop); + big_app(cancel); big_app1(pp+1); big_app(force); + reduce(pp,2,stmt,-1,61); +} + +@ @<Cases for |if_clause|@>= +if (cat1==lbrace) squash(pp,1,if_head,0,62); +else if (cat1==stmt) { + if (cat2==else_like) { + big_app(force); big_app1(pp); big_app(indent); big_app(break_space); + big_app1(pp+1); big_app(outdent); big_app(force); big_app1(pp+2); + if (cat3==if_like) { + big_app(' '); big_app1(pp+3); reduce(pp,4,if_like,0,63); + }@+else reduce(pp,3,else_like,0,64); + } + else squash(pp,1,else_like,0,65); +} + +@ @<Cases for |if_head|@>= +if (cat1==stmt || cat1==exp) { + if (cat2==else_like) { + big_app(force); big_app1(pp); big_app(break_space); app(noop); + big_app(cancel); big_app1(pp+1); big_app(force); big_app1(pp+2); + if (cat3==if_like) { + big_app(' '); big_app1(pp+3); reduce(pp,4,if_like,0,66); + }@+else reduce(pp,3,else_like,0,67); + } + else squash(pp,1,else_head,0,68); +} + +@ @<Cases for |do_like|@>= +if (cat1==stmt && cat2==else_like && cat3==semi) { + big_app1(pp); big_app(break_space); app(noop); big_app(cancel); + big_app1(pp+1); big_app(cancel); app(noop); big_app(break_space); + big_app2(pp+2); reduce(pp,4,stmt,-1,69); +} + +@ @<Cases for |case_like|@>= +if (cat1==semi) squash(pp,2,stmt,-1,70); +else if (cat1==colon) squash(pp,2,tag,-1,71); +else if (cat1==exp) { + if (cat2==semi) { + big_app1(pp); big_app(' '); big_app1(pp+1); big_app1(pp+2); + reduce(pp,3,stmt,-1,72); + } + else if (cat2==colon) { + big_app1(pp); big_app(' '); big_app1(pp+1); big_app1(pp+2); + reduce(pp,3,tag,-1,73); + } +} + +@ @<Cases for |tag|@>= +if (cat1==tag) { + big_app1(pp); big_app(break_space); big_app1(pp+1); reduce(pp,2,tag,-1,74); +} +else if (cat1==stmt||cat1==decl||cat1==function) { + big_app(force); big_app(backup); big_app1(pp); big_app(break_space); + big_app1(pp+1); reduce(pp,2,cat1,-1,75); +} + +@ The user can decide at run-time whether short statements should be +grouped together on the same line. + +@d force_lines flags['f'] /* should each statement be on its own line? */ +@<Cases for |stmt|@>= +if (cat1==stmt||cat1==decl||cat1==function) { + big_app1(pp); + if (cat1==function) big_app(big_force); + else if (cat1==decl) big_app(big_force); + else if (force_lines) big_app(force); + else big_app(break_space); + big_app1(pp+1); reduce(pp,2,cat1,-1,76); +} + +@ @<Cases for |semi|@>= +big_app(' '); big_app1(pp); reduce(pp,1,stmt,-1,77); + +@ @<Cases for |lproc|@>= +if (cat1==define_like) make_underlined(pp+2); +if (cat1==else_like || cat1==if_like ||cat1==define_like) + squash(pp,2,lproc,0,78); +else if (cat1==rproc) { + app(inserted); big_app2(pp); reduce(pp,2,insert,-1,79); +} else if (cat1==exp || cat1==function) { + if (cat2==rproc) { + app(inserted); big_app1(pp); big_app(' '); big_app2(pp+1); + reduce(pp,3,insert,-1,80); + } + else if (cat2==exp && cat3==rproc && cat1==exp) { + app(inserted); big_app1(pp); big_app(' '); big_app1(pp+1); app_str(" \\5"); +@.\\5@> + big_app2(pp+2); reduce(pp,4,insert,-1,80); + } +} + +@ @<Cases for |section_scrap|@>= +if (cat1==semi) { + big_app2(pp); big_app(force); reduce(pp,2,stmt,-2,81); +} +else squash(pp,1,exp,-2,82); + +@ @<Cases for |insert|@>= +if (cat1) + squash(pp,2,cat1,0,83); + +@ @<Cases for |prelangle|@>= +init_mathness=cur_mathness=yes_math; +app('<'); reduce(pp,1,binop,-2,84); + +@ @<Cases for |prerangle|@>= +init_mathness=cur_mathness=yes_math; +app('>'); reduce(pp,1,binop,-2,85); + +@ @<Cases for |langle|@>= +if (cat1==exp && cat2==prerangle) squash(pp,3,cast,-1,86); +else if (cat1==prerangle) { + big_app1(pp); app('\\'); app(','); big_app1(pp+1); +@.\\,@> + reduce(pp,2,cast,-1,87); +} +else if (cat1==decl_head || cat1==int_like) { + if (cat2==prerangle) squash(pp,3,cast,-1,88); + else if (cat2==comma) { + big_app3(pp); app(opt); app('9'); reduce(pp,3,langle,0,89); + } +} + +@ @<Cases for |public_like|@>= +if (cat1==colon) squash(pp,2,tag,-1,90); +else squash(pp,1,int_like,-2,91); + +@ @<Cases for |colcol|@>= +if (cat1==exp||cat1==int_like) squash(pp,2,cat1,-2,92); + +@ @<Cases for |new_like|@>= +if (cat1==exp || (cat1==raw_int&&cat2!=prelangle&&cat2!=langle)) { + big_app1(pp); big_app(' '); big_app1(pp+1); reduce(pp,2,new_like,0,93); +} +else if (cat1==raw_unorbin || cat1==colcol) + squash(pp,2,new_like,0,94); +else if (cat1==cast) squash(pp,2,exp,-2,95); +else if (cat1!=lpar && cat1!=raw_int && cat1!=struct_like) + squash(pp,1,exp,-2,96); + +@ @<Cases for |operator_like|@>= +if (cat1==binop || cat1==unop || cat1==unorbinop) { + if (cat2==binop) break; + big_app1(pp); big_app('{'); big_app1(pp+1); big_app('}'); + reduce(pp,2,exp,-2,97); +} +else if (cat1==new_like || cat1==sizeof_like) { + big_app1(pp); big_app(' '); big_app1(pp+1); reduce(pp,2,exp,-2,98); +} +else squash(pp,1,new_like,0,99); + +@ @<Cases for |catch_like|@>= +if (cat1==cast || cat1==exp) { + big_app2(pp); big_app(indent); big_app(indent); + reduce(pp,2,fn_decl,0,100); +} + +@ @<Cases for |base|@>= +if (cat1==public_like && cat2==exp) { + if (cat3==comma) { + big_app2(pp); big_app(' '); big_app2(pp+2); + reduce(pp,4,base,0,101); + } else { + big_app1(pp+1); big_app(' '); big_app1(pp+2); + reduce(pp+1,2,int_like,-1,102); + } +} + +@ @<Cases for |raw_rpar|@>= +if (cat1==const_like && @| + (cat2==semi || cat2==lbrace || cat2==comma || cat2==binop + || cat2==const_like)) { + big_app1(pp); big_app(' '); + big_app1(pp+1); reduce(pp,2,raw_rpar,0,103); +} else squash(pp,1,rpar,-3,104); + +@ @<Cases for |raw_unorbin|@>= +if (cat1==const_like) { + big_app2(pp); app_str("\\ "); reduce(pp,2,raw_unorbin,0,105); +@.\\ @> +} else squash(pp,1,unorbinop,-2,106); + +@ @<Cases for |const_like|@>= +squash(pp,1,int_like,-2,107); + +@ @<Cases for |raw_int|@>= +if (cat1==lpar) squash(pp,1,exp,-2,108); +else squash(pp,1,int_like,-3,109); + +@ The `|freeze_text|' macro is used to give official status to a token list. +Before saying |freeze_text|, items are appended to the current token list, +and we know that the eventual number of this token list will be the current +value of |text_ptr|. But no list of that number really exists as yet, +because no ending point for the current list has been +stored in the |tok_start| array. After saying |freeze_text|, the +old current token list becomes legitimate, and its number is the current +value of |text_ptr-1| since |text_ptr| has been increased. The new +current token list is empty and ready to be appended to. +Note that |freeze_text| does not check to see that |text_ptr| hasn't gotten +too large, since it is assumed that this test was done beforehand. + +@d freeze_text *(++text_ptr)=tok_ptr + +@ Here's the |reduce| procedure used in our code for productions: + +@c +void +reduce(j,k,c,d,n) +scrap_pointer j; +eight_bits c; +short k, d, n; +{ + scrap_pointer i, i1; /* pointers into scrap memory */ + j->cat=c; j->trans=text_ptr; + j->mathness=4*cur_mathness+init_mathness; + freeze_text; + if (k>1) { + for (i=j+k, i1=j+1; i<=lo_ptr; i++, i1++) { + i1->cat=i->cat; i1->trans=i->trans; + i1->mathness=i->mathness; + } + lo_ptr=lo_ptr-k+1; + } + @<Change |pp| to $\max(|scrap_base|,|pp|+d)$@>; + @<Print a snapshot of the scrap list if debugging @>; + pp--; /* we next say |pp++| */ +} + +@ @<Change |pp| to $\max...@>= +if (pp+d>=scrap_base) pp=pp+d; +else pp=scrap_base; + +@ Here's the |squash| procedure, which +takes advantage of the simplification that occurs when |k==1|. + +@c +void +squash(j,k,c,d,n) +scrap_pointer j; +eight_bits c; +short k, d, n; +{ + scrap_pointer i; /* pointers into scrap memory */ + if (k==1) { + j->cat=c; @<Change |pp|...@>; + @<Print a snapshot...@>; + pp--; /* we next say |pp++| */ + return; + } + for (i=j; i<j+k; i++) big_app1(i); + reduce(j,k,c,d,n); +} + +@ Here now is the code that applies productions as long as possible. +Before applying the production mechanism, we must make sure +it has good input (at least four scraps, the length of the lhs of the +longest rules), and that there is enough room in the memory arrays +to hold the appended tokens and texts. Here we use a very +conservative test: it's more important to make sure the program +will still work if we change the production rules (within reason) +than to squeeze the last bit of space from the memory arrays. + +@d safe_tok_incr 20 +@d safe_text_incr 10 +@d safe_scrap_incr 10 + +@<Reduce the scraps using the productions until no more rules apply@>= +while (1) { + @<Make sure the entries |pp| through |pp+3| of |cat| are defined@>; + if (tok_ptr+safe_tok_incr>tok_mem_end) { + if (tok_ptr>max_tok_ptr) max_tok_ptr=tok_ptr; + overflow("token"); + } + if (text_ptr+safe_text_incr>tok_start_end) { + if (text_ptr>max_text_ptr) max_text_ptr=text_ptr; + overflow("text"); + } + if (pp>lo_ptr) break; + init_mathness=cur_mathness=maybe_math; + @<Match a production...@>; +} + +@ If we get to the end of the scrap list, category codes equal to zero are +stored, since zero does not match anything in a production. + +@<Make sure the entries...@>= +if (lo_ptr<pp+3) { + while (hi_ptr<=scrap_ptr && lo_ptr!=pp+3) { + (++lo_ptr)->cat=hi_ptr->cat; lo_ptr->mathness=(hi_ptr)->mathness; + lo_ptr->trans=(hi_ptr++)->trans; + } + for (i=lo_ptr+1;i<=pp+3;i++) i->cat=0; +} + +@ If \.{CWEAVE} is being run in debugging mode, the production numbers and +current stack categories will be printed out when |tracing| is set to 2; +a sequence of two or more irreducible scraps will be printed out when +|tracing| is set to 1. + +@<Global...@>= +int tracing; /* can be used to show parsing details */ + +@ @<Print a snapsh...@>= +{ scrap_pointer k; /* pointer into |scrap_info| */ + if (tracing==2) { + printf("\n%d:",n); + for (k=scrap_base; k<=lo_ptr; k++) { + if (k==pp) putxchar('*'); else putxchar(' '); + if (k->mathness %4 == yes_math) putchar('+'); + else if (k->mathness %4 == no_math) putchar('-'); + print_cat(k->cat); + if (k->mathness /4 == yes_math) putchar('+'); + else if (k->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 +positions |scrap_base| through |scrap_ptr| of |cat| and |trans|. It +applies productions as much as +possible. The result is a token list containing the translation of +the given sequence of scraps. + +After calling |translate|, we will have |text_ptr+3<=max_texts| and +|tok_ptr+6<=max_toks|, so it will be possible to create up to three token +lists with up to six tokens without checking for overflow. Before calling +|translate|, we should have |text_ptr<max_texts| and |scrap_ptr<max_scraps|, +since |translate| might add a new text and a new scrap before it checks +for overflow. + +@c +text_pointer +translate() /* converts a sequence of scraps */ +{ + scrap_pointer i, /* index into |cat| */ + j; /* runs through final scraps */ + pp=scrap_base; lo_ptr=pp-1; hi_ptr=pp; + @<If tracing, print an indication of where we are@>; + @<Reduce the scraps...@>; + @<Combine the irreducible scraps that remain@>; +} + +@ If the initial sequence of scraps does not reduce to a single scrap, +we concatenate the translations of all remaining scraps, separated by +blank spaces, with dollar signs surrounding the translations of scraps +where appropriate. + +@<Combine the irreducible...@>= { + @<If semi-tracing, show the irreducible scraps@>; + for (j=scrap_base; j<=lo_ptr; j++) { + if (j!=scrap_base) app(' '); + if (j->mathness % 4 == yes_math) app('$'); + app1(j); + if (j->mathness / 4 == yes_math) app('$'); + if (tok_ptr+6>tok_mem_end) overflow("token"); + } + freeze_text; return(text_ptr-1); +} + +@ @<If semi-tracing, show the irreducible scraps@>= +if (lo_ptr>scrap_base && tracing==1) { + printf("\nIrreducible scrap sequence in section %d:",section_count); +@.Irreducible scrap sequence...@> + mark_harmless; + for (j=scrap_base; j<=lo_ptr; j++) { + printf(" "); print_cat(j->cat); + } +} + +@ @<If tracing,...@>= +if (tracing==2) { + printf("\nTracing after l. %d:\n",cur_line); mark_harmless; +@.Tracing after...@> + if (loc>buffer+50) { + printf("..."); + term_write(loc-51,51); + } + else term_write(buffer,loc-buffer); +} + +@* Initializing the scraps. +If we are going to use the powerful production mechanism just developed, we +must get the scraps set up in the first place, given a \CEE/ text. A table +of the initial scraps corresponding to \CEE/ tokens appeared above in the +section on parsing; our goal now is to implement that table. We shall do this +by implementing a subroutine called |C_parse| that is analogous to the +|C_xref| routine used during phase one. + +Like |C_xref|, the |C_parse| procedure starts with the current +value of |next_control| and it uses the operation |next_control=get_next()| +repeatedly to read \CEE/ text until encountering the next `\.{\v}' or +`\.{/*}', or until |next_control>=format_code|. The scraps corresponding to +what it reads are appended into the |cat| and |trans| arrays, and |scrap_ptr| +is advanced. + +@c +void +C_parse(spec_ctrl) /* creates scraps from \CEE/ tokens */ + eight_bits spec_ctrl; +{ + int count; /* characters remaining before string break */ + while (next_control<format_code || next_control==spec_ctrl) { + @<Append the scrap appropriate to |next_control|@>; + next_control=get_next(); + if (next_control=='|' || next_control==begin_comment || + next_control==begin_short_comment) return; + } +} + +@ The following macro is used to append a scrap whose tokens have just +been appended: + +@d app_scrap(c,b) { + (++scrap_ptr)->cat=(c); scrap_ptr->trans=text_ptr; + scrap_ptr->mathness=5*(b); /* no no, yes yes, or maybe maybe */ + freeze_text; +} + +@ @<Append the scr...@>= +@<Make sure that there is room for the new scraps, tokens, and texts@>; +switch (next_control) { + case section_name: + app(section_flag+(int)(cur_section-name_dir)); + app_scrap(section_scrap,maybe_math); + app_scrap(exp,yes_math);@+break; + case string: case constant: case verbatim: @<Append a string or constant@>; + @+break; + case identifier: app_cur_id(1);@+break; + case TeX_string: @<Append a \TEX/ string, without forming a scrap@>;@+break; + case '/': case '.': + app(next_control); app_scrap(binop,yes_math);@+break; + case '<': app_str("\\langle");@+app_scrap(prelangle,yes_math);@+break; +@.\\langle@> + case '>': app_str("\\rangle");@+app_scrap(prerangle,yes_math);@+break; +@.\\rangle@> + case '=': app_str("\\K"); app_scrap(binop,yes_math);@+break; +@.\\K@> + case '|': app_str("\\OR"); app_scrap(binop,yes_math);@+break; +@.\\OR@> + case '^': app_str("\\XOR"); app_scrap(binop,yes_math);@+break; +@.\\XOR@> + case '%': app_str("\\MOD"); app_scrap(binop,yes_math);@+break; +@.\\MOD@> + case '!': app_str("\\R"); app_scrap(unop,yes_math);@+break; +@.\\R@> + case '~': app_str("\\CM"); app_scrap(unop,yes_math);@+break; +@.\\CM@> + case '+': case '-': app(next_control); app_scrap(unorbinop,yes_math);@+break; + case '*': app(next_control); app_scrap(raw_unorbin,yes_math);@+break; + case '&': app_str("\\AND"); app_scrap(raw_unorbin,yes_math);@+break; +@.\\AND@> + case '?': app_str("\\?"); app_scrap(question,yes_math);@+break; +@.\\?@> + case '#': app_str("\\#"); app_scrap(unorbinop,yes_math);@+break; +@.\\\#@> + case ignore: case xref_roman: case xref_wildcard: + case xref_typewriter: case noop:@+break; + case '(': case '[': app(next_control); app_scrap(lpar,maybe_math);@+break; + case ')': case ']': app(next_control); app_scrap(raw_rpar,maybe_math);@+break; + case '{': app_str("\\{"@q}@>); app_scrap(lbrace,yes_math);@+break; +@.\\\{@>@q}@> + case '}': app_str(@q{@>"\\}"); app_scrap(rbrace,yes_math);@+break; +@q{@>@.\\\}@> + case ',': app(','); app_scrap(comma,yes_math);@+break; + case ';': app(';'); app_scrap(semi,maybe_math);@+break; + case ':': app(':'); app_scrap(colon,maybe_math);@+break;@/ + @t\4@> @<Cases involving nonstandard characters@>@; + case thin_space: app_str("\\,"); app_scrap(insert,maybe_math);@+break; +@.\\,@> + case math_break: app(opt); app_str("0"); + app_scrap(insert,maybe_math);@+break; + case line_break: app(force); app_scrap(insert,no_math);@+break; + case left_preproc: app(force); app(preproc_line); + app_str("\\#"); app_scrap(lproc,no_math);@+break; +@.\\\#@> + case right_preproc: app(force); app_scrap(rproc,no_math);@+break; + case big_line_break: app(big_force); app_scrap(insert,no_math);@+break; + case no_line_break: app(big_cancel); app(noop); app(break_space); + app(noop); app(big_cancel); + app_scrap(insert,no_math);@+break; + case pseudo_semi: app_scrap(semi,maybe_math);@+break; + case macro_arg_open: app_scrap(begin_arg,maybe_math);@+break; + case macro_arg_close: app_scrap(end_arg,maybe_math);@+break; + case join: app_str("\\J"); app_scrap(insert,no_math);@+break; +@.\\J@> + case output_defs_code: app(force); app_str("\\ATH"); app(force); + app_scrap(insert,no_math);@+break; +@.\\ATH@> + default: app(inserted); app(next_control); + app_scrap(insert,maybe_math);@+break; +} + +@ @<Make sure that there is room for the new...@>= +if (scrap_ptr+safe_scrap_incr>scrap_info_end || + tok_ptr+safe_tok_incr>tok_mem_end @| || + text_ptr+safe_text_incr>tok_start_end) { + if (scrap_ptr>max_scr_ptr) max_scr_ptr=scrap_ptr; + if (tok_ptr>max_tok_ptr) max_tok_ptr=tok_ptr; + if (text_ptr>max_text_ptr) max_text_ptr=text_ptr; + overflow("scrap/token/text"); +} + +@ Some nonstandard characters may have entered \.{CWEAVE} by means of +standard ones. They are converted to \TEX/ control sequences so that it is +possible to keep \.{CWEAVE} from outputting unusual |char| codes. + +@<Cases involving nonstandard...@>= +case not_eq: app_str("\\I");@+app_scrap(binop,yes_math);@+break; +@.\\I@> +case lt_eq: app_str("\\Z");@+app_scrap(binop,yes_math);@+break; +@.\\Z@> +case gt_eq: app_str("\\G");@+app_scrap(binop,yes_math);@+break; +@.\\G@> +case eq_eq: app_str("\\E");@+app_scrap(binop,yes_math);@+break; +@.\\E@> +case and_and: app_str("\\W");@+app_scrap(binop,yes_math);@+break; +@.\\W@> +case or_or: app_str("\\V");@+app_scrap(binop,yes_math);@+break; +@.\\V@> +case plus_plus: app_str("\\PP");@+app_scrap(unop,yes_math);@+break; +@.\\PP@> +case minus_minus: app_str("\\MM");@+app_scrap(unop,yes_math);@+break; +@.\\MM@> +case minus_gt: app_str("\\MG");@+app_scrap(binop,yes_math);@+break; +@.\\MG@> +case gt_gt: app_str("\\GG");@+app_scrap(binop,yes_math);@+break; +@.\\GG@> +case lt_lt: app_str("\\LL");@+app_scrap(binop,yes_math);@+break; +@.\\LL@> +case dot_dot_dot: app_str("\\,\\ldots\\,");@+app_scrap(exp,yes_math);@+break; +@.\\,@> +@.\\ldots@> +case colon_colon: app_str("\\DC");@+app_scrap(colcol,maybe_math);@+break; +@.\\DC@> +case period_ast: app_str("\\PA");@+app_scrap(binop,yes_math);@+break; +@.\\PA@> +case minus_gt_ast: app_str("\\MGA");@+app_scrap(binop,yes_math);@+break; +@.\\MGA@> + +@ The following code must use |app_tok| instead of |app| in order to +protect against overflow. Note that |tok_ptr+1<=max_toks| after |app_tok| +has been used, so another |app| is legitimate before testing again. + +Many of the special characters in a string must be prefixed by `\.\\' so that +\TEX/ will print them properly. +@^special string characters@> + +@<Append a string or...@>= +count= -1; +if (next_control==constant) app_str("\\T{"@q}@>); +@.\\T@> +else if (next_control==string) { + count=20; app_str("\\.{"@q}@>); +} +@.\\.@> +else app_str("\\vb{"@q}@>); +@.\\vb@> +while (id_first<id_loc) { + if (count==0) { /* insert a discretionary break in a long string */ + app_str(@q(@>@q{@>"}\\)\\.{"@q}@>); count=20; +@q(@>@.\\)@> + } +@^high-bit character handling@> + if((eight_bits)(*id_first)>0177) { + app_tok(quoted_char); + app_tok((eight_bits)(*id_first++)); + } + else { + switch (*id_first) { + case ' ':case '\\':case '#':case '%':case '$':case '^': + case '{': case '}': case '~': case '&': case '_': app('\\'); break; +@.\\\ @> +@.\\\\@> +@.\\\#@> +@.\\\%@> +@.\\\$@> +@.\\\^@> +@.\\\{@>@q}@> +@q{@>@.\\\}@> +@.\\\~@> +@.\\\&@> +@.\\_@> @q CWEAVE does quote an underscore! @> + case '@@': if (*(id_first+1)=='@@') id_first++; + else err_print("! Double @@ should be used in strings"); +@.Double @@ should be used...@> + } + app_tok(*id_first++); + } + count--; +} +app(@q{@>'}'); +app_scrap(exp,maybe_math); + +@ We do not make the \TEX/ string into a scrap, because there is no +telling what the user will be putting into it; instead we leave it +open, to be picked up by the next scrap. If it comes at the end of a +section, it will be made into a scrap when |finish_C| is called. + +There's a known bug here, in cases where an adjacent scrap is +|prelangle| or |prerangle|. Then the \TEX/ string can disappear +when the \.{\\langle} or \.{\\rangle} becomes \.{<} or \.{>}. +For example, if the user writes \.{\v x<@@ty@@>\v}, the \TEX/ string +\.{\\hbox\{y\}} eventually becomes part of an |insert| scrap, which is combined +with a |prelangle| scrap and eventually lost. The best way to work around +this bug is probably to enclose the \.{@@t...@@>} in \.{@@[...@@]} so that +the \TEX/ string is treated as an expression. +@^bug, known@> + +@<Append a \TEX/ string, without forming a scrap@>= +app_str("\\hbox{"@q}@>); +@^high-bit character handling@> +while (id_first<id_loc) + if((eight_bits)(*id_first)>0177) { + app_tok(quoted_char); + app_tok((eight_bits)(*id_first++)); + } + else { + if (*id_first=='@@') id_first++; + app_tok(*id_first++); + } +app(@q{@>'}'); + +@ The function |app_cur_id| appends the current identifier to the +token list; it also builds a new scrap if |scrapping==1|. + +@<Predec...@>= +void app_cur_id(); + +@ @c +void +app_cur_id(scrapping) +boolean scrapping; /* are we making this into a scrap? */ +{ + name_pointer p=id_lookup(id_first,id_loc,normal); + if (p->ilk<=quoted) { /* not a reserved word */ + app(id_flag+(int)(p-name_dir)); + if (scrapping) app_scrap(exp,p->ilk>=custom? yes_math: maybe_math); +@.\\NULL@> + } else { + app(res_flag+(int)(p-name_dir)); + if (scrapping) app_scrap(p->ilk,maybe_math); + } +} + +@ When the `\.{\v}' that introduces \CEE/ text is sensed, a call on +|C_translate| will return a pointer to the \TEX/ translation of +that text. If scraps exist in |scrap_info|, they are +unaffected by this translation process. + +@c +text_pointer +C_translate() +{ + text_pointer p; /* points to the translation */ + scrap_pointer save_base; /* holds original value of |scrap_base| */ + save_base=scrap_base; scrap_base=scrap_ptr+1; + C_parse(section_name); /* get the scraps together */ + if (next_control!='|') err_print("! Missing '|' after C text"); +@.Missing '|'...@> + app_tok(cancel); app_scrap(insert,maybe_math); + /* place a |cancel| token as a final ``comment'' */ + p=translate(); /* make the translation */ + if (scrap_ptr>max_scr_ptr) max_scr_ptr=scrap_ptr; + scrap_ptr=scrap_base-1; scrap_base=save_base; /* scrap the scraps */ + return(p); +} + +@ The |outer_parse| routine is to |C_parse| as |outer_xref| +is to |C_xref|: it constructs a sequence of scraps for \CEE/ text +until |next_control>=format_code|. Thus, it takes care of embedded comments. + +@c +void +outer_parse() /* makes scraps from \CEE/ tokens and comments */ +{ + int bal; /* brace level in comment */ + text_pointer p, q; /* partial comments */ + while (next_control<format_code) + if (next_control!=begin_comment && next_control!=begin_short_comment) + C_parse(ignore); + else { + boolean is_long_comment=(next_control==begin_comment); + @<Make sure that there is room for the new...@>; + app(cancel); app(inserted); + if (is_long_comment) app_str("\\C{"@q}@>); +@.\\C@> + else app_str("\\SHC{"@q}@>); +@.\\SHC@> + bal=copy_comment(is_long_comment,1); next_control=ignore; + while (bal>0) { + p=text_ptr; freeze_text; q=C_translate(); + /* at this point we have |tok_ptr+6<=max_toks| */ + app(tok_flag+(int)(p-tok_start)); + app_str("\\PB{"); app(inner_tok_flag+(int)(q-tok_start)); app_tok('}'); +@.\\PB@> + if (next_control=='|') { + bal=copy_comment(is_long_comment,bal); + next_control=ignore; + } + else bal=0; /* an error has been reported */ + } + app(force); app_scrap(insert,no_math); + /* the full comment becomes a scrap */ + } +} + +@* Output of tokens. +So far our programs have only built up multi-layered token lists in +\.{CWEAVE}'s internal memory; we have to figure out how to get them into +the desired final form. The job of converting token lists to characters in +the \TEX/ output file is not difficult, although it is an implicitly +recursive process. Four main considerations had to be kept in mind when +this part of \.{CWEAVE} was designed. (a) There are two modes of output: +|outer| mode, which translates tokens like |force| into line-breaking +control sequences, and |inner| mode, which ignores them except that blank +spaces take the place of line breaks. (b) The |cancel| instruction applies +to adjacent token or tokens that are output, and this cuts across levels +of recursion since `|cancel|' occurs at the beginning or end of a token +list on one level. (c) The \TEX/ output file will be semi-readable if line +breaks are inserted after the result of tokens like |break_space| and +|force|. (d) The final line break should be suppressed, and there should +be no |force| token output immediately after `\.{\\Y\\B}'. + +@ The output process uses a stack to keep track of what is going on at +different ``levels'' as the token lists are being written out. Entries on +this stack have three parts: + +\yskip\hang |end_field| is the |tok_mem| location where the token list of a +particular level will end; + +\yskip\hang |tok_field| is the |tok_mem| location from which the next token +on a particular level will be read; + +\yskip\hang |mode_field| is the current mode, either |inner| or |outer|. + +\yskip\noindent The current values of these quantities are referred to +quite frequently, so they are stored in a separate place instead of in the +|stack| array. We call the current values |cur_end|, |cur_tok|, and +|cur_mode|. + +The global variable |stack_ptr| tells how many levels of output are +currently in progress. The end of output occurs when an |end_translation| +token is found, so the stack is never empty except when we first begin the +output process. + +@d inner 0 /* value of |mode| for \CEE/ texts within \TEX/ texts */ +@d outer 1 /* value of |mode| for \CEE/ texts in sections */ + +@<Typed...@>= typedef int mode; +typedef struct { + token_pointer end_field; /* ending location of token list */ + token_pointer tok_field; /* present location within token list */ + boolean mode_field; /* interpretation of control tokens */ +} output_state; +typedef output_state *stack_pointer; + +@ @d cur_end cur_state.end_field /* current ending location in |tok_mem| */ +@d cur_tok cur_state.tok_field /* location of next output token in |tok_mem| */ +@d cur_mode cur_state.mode_field /* current mode of interpretation */ +@d init_stack stack_ptr=stack;cur_mode=outer /* initialize the stack */ + +@<Global...@>= +output_state cur_state; /* |cur_end|, |cur_tok|, |cur_mode| */ +output_state stack[stack_size]; /* info for non-current levels */ +stack_pointer stack_ptr; /* first unused location in the output state stack */ +stack_pointer stack_end=stack+stack_size-1; /* end of |stack| */ +stack_pointer max_stack_ptr; /* largest value assumed by |stack_ptr| */ + +@ @<Set init...@>= +max_stack_ptr=stack; + +@ To insert token-list |p| into the output, the |push_level| subroutine +is called; it saves the old level of output and gets a new one going. +The value of |cur_mode| is not changed. + +@c +void +push_level(p) /* suspends the current level */ +text_pointer p; +{ + if (stack_ptr==stack_end) overflow("stack"); + if (stack_ptr>stack) { /* save current state */ + stack_ptr->end_field=cur_end; + stack_ptr->tok_field=cur_tok; + stack_ptr->mode_field=cur_mode; + } + stack_ptr++; + if (stack_ptr>max_stack_ptr) max_stack_ptr=stack_ptr; + cur_tok=*p; cur_end=*(p+1); +} + +@ Conversely, the |pop_level| routine restores the conditions that were in +force when the current level was begun. This subroutine will never be +called when |stack_ptr==1|. + +@c +void +pop_level() +{ + cur_end=(--stack_ptr)->end_field; + cur_tok=stack_ptr->tok_field; cur_mode=stack_ptr->mode_field; +} + +@ The |get_output| function returns the next byte of output that is not a +reference to a token list. It returns the values |identifier| or |res_word| +or |section_code| if the next token is to be an identifier (typeset in +italics), a reserved word (typeset in boldface) or a section name (typeset +by a complex routine that might generate additional levels of output). +In these cases |cur_name| points to the identifier or section name in +question. + +@<Global...@>= +name_pointer cur_name; + +@ @d res_word 0201 /* returned by |get_output| for reserved words */ +@d section_code 0200 /* returned by |get_output| for section names */ + +@c +eight_bits +get_output() /* returns the next token of output */ +{ + sixteen_bits a; /* current item read from |tok_mem| */ + restart: while (cur_tok==cur_end) pop_level(); + a=*(cur_tok++); + if (a>=0400) { + cur_name=a % id_flag + name_dir; + switch (a / id_flag) { + case 2: return(res_word); /* |a==res_flag+cur_name| */ + case 3: return(section_code); /* |a==section_flag+cur_name| */ + case 4: push_level(a % id_flag + tok_start); goto restart; + /* |a==tok_flag+cur_name| */ + case 5: push_level(a % id_flag + tok_start); cur_mode=inner; goto restart; + /* |a==inner_tok_flag+cur_name| */ + default: return(identifier); /* |a==id_flag+cur_name| */ + } + } + return(a); +} + +@ The real work associated with token output is done by |make_output|. +This procedure appends an |end_translation| token to the current token list, +and then it repeatedly calls |get_output| and feeds characters to the output +buffer until reaching the |end_translation| sentinel. It is possible for +|make_output| to be called recursively, since a section name may include +embedded \CEE/ text; however, the depth of recursion never exceeds one +level, since section names cannot be inside of section names. + +A procedure called |output_C| does the scanning, translation, and +output of \CEE/ text within `\pb' brackets, and this procedure uses +|make_output| to output the current token list. Thus, the recursive call +of |make_output| actually occurs when |make_output| calls |output_C| +while outputting the name of a section. +@^recursion@> + +The token list created from within `\pb' brackets is output as an argument +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. + +@c +void +output_C() /* outputs the current token list */ +{ + token_pointer save_tok_ptr; + text_pointer save_text_ptr; + sixteen_bits save_next_control; /* values to be restored */ + text_pointer p; /* translation of the \CEE/ text */ + save_tok_ptr=tok_ptr; save_text_ptr=text_ptr; + save_next_control=next_control; next_control=ignore; p=C_translate(); + app(inner_tok_flag+(int)(p-tok_start)); + out_str("\\PB{"); make_output(); out('}'); /* output the list */ +@.\\PB@> + if (text_ptr>max_text_ptr) max_text_ptr=text_ptr; + if (tok_ptr>max_tok_ptr) max_tok_ptr=tok_ptr; + text_ptr=save_text_ptr; tok_ptr=save_tok_ptr; /* forget the tokens */ + next_control=save_next_control; /* restore |next_control| to original state */ +} + +@ Here is \.{CWEAVE}'s major output handler. + +@<Predecl...@>= +void make_output(); + +@ @c +void +make_output() /* outputs the equivalents of tokens */ +{ + eight_bits a, /* current output byte */ + b; /* next output byte */ + int c; /* count of |indent| and |outdent| tokens */ + char scratch[longest_name]; /* scratch area for section names */ + char *k, *k_limit; /* indices into |scratch| */ + char *j; /* index into |buffer| */ + char *p; /* index into |byte_mem| */ + char delim; /* first and last character of string being copied */ + char *save_loc, *save_limit; /* |loc| and |limit| to be restored */ + name_pointer cur_section_name; /* name of section being output */ + boolean save_mode; /* value of |cur_mode| before a sequence of breaks */ + app(end_translation); /* append a sentinel */ + freeze_text; push_level(text_ptr-1); + while (1) { + a=get_output(); + reswitch: switch(a) { + case end_translation: return; + case identifier: case res_word: @<Output an identifier@>; break; + case section_code: @<Output a section name@>; break; + case math_rel: out_str("\\MRL{"@q}@>); +@.\\MRL@> + case noop: case inserted: break; + case cancel: case big_cancel: c=0; b=a; + while (1) { + a=get_output(); + if (a==inserted) continue; + if ((a<indent && !(b==big_cancel&&a==' ')) || a>big_force) break; + if (a==indent) c++; else if (a==outdent) c--; + else if (a==opt) a=get_output(); + } + @<Output saved |indent| or |outdent| tokens@>; + goto reswitch; + case indent: case outdent: case opt: case backup: case break_space: + case force: case big_force: case preproc_line: @<Output a control, + look ahead in case of line breaks, possibly |goto reswitch|@>; break; + case quoted_char: out(*(cur_tok++)); break; + default: out(a); /* otherwise |a| is an ordinary character */ + } + } +} + +@ An identifier of length one does not have to be enclosed in braces, and it +looks slightly better if set in a math-italic font instead of a (slightly +narrower) text-italic font. Thus we output `\.{\\\v}\.{a}' but +`\.{\\\\\{aa\}}'. + +@<Output an identifier@>= +out('\\'); +if (a==identifier) { + if (cur_name->ilk>=custom && cur_name->ilk<=quoted && !doing_format) { + for (p=cur_name->byte_start;p<(cur_name+1)->byte_start;p++) + out(isxalpha(*p)? 'x':*p); + break; + } else if (is_tiny(cur_name)) out('|') +@.\\|@> + else { delim='.'; + for (p=cur_name->byte_start;p<(cur_name+1)->byte_start;p++) + if (xislower(*p)) { /* not entirely uppercase */ + delim='\\'; break; + } + out(delim); + } +@.\\\\@> +@.\\.@> +} +else out('&') /* |a==res_word| */ +@.\\\&@> +if (is_tiny(cur_name)) { + if (isxalpha((cur_name->byte_start)[0])) + out('\\'); + out((cur_name->byte_start)[0]); +} +else out_name(cur_name); + +@ The current mode does not affect the behavior of \.{CWEAVE}'s output routine +except when we are outputting control tokens. + +@<Output a control...@>= +if (a<break_space || a==preproc_line) { + if (cur_mode==outer) { + out('\\'); out(a-cancel+'0'); +@.\\1@> +@.\\2@> +@.\\3@> +@.\\4@> +@.\\8@> + if (a==opt) { + b=get_output(); /* |opt| is followed by a digit */ + if (b!='0' || force_lines==0) out(b)@; + else out_str("{-1}"); /* |force_lines| encourages more \.{@@\v} breaks */ + } + } else if (a==opt) b=get_output(); /* ignore digit following |opt| */ + } +else @<Look ahead for strongest line break, |goto reswitch|@> + +@ If several of the tokens |break_space|, |force|, |big_force| occur in a +row, possibly mixed with blank spaces (which are ignored), +the largest one is used. A line break also occurs in the output file, +except at the very end of the translation. The very first line break +is suppressed (i.e., a line break that follows `\.{\\Y\\B}'). + +@<Look ahead for st...@>= { + b=a; save_mode=cur_mode; c=0; + while (1) { + a=get_output(); + if (a==inserted) continue; + if (a==cancel || a==big_cancel) { + @<Output saved |indent| or |outdent| tokens@>; + goto reswitch; /* |cancel| overrides everything */ + } + if ((a!=' ' && a<indent) || a==backup || a>big_force) { + if (save_mode==outer) { + if (out_ptr>out_buf+3 && strncmp(out_ptr-3,"\\Y\\B",4)==0) + goto reswitch; + @<Output saved |indent| or |outdent| tokens@>; + out('\\'); out(b-cancel+'0'); +@.\\5@> +@.\\6@> +@.\\7@> + if (a!=end_translation) finish_line(); + } + else if (a!=end_translation && cur_mode==inner) out(' '); + goto reswitch; + } + if (a==indent) c++; + else if (a==outdent) c--; + else if (a==opt) a=get_output(); + else if (a>b) b=a; /* if |a==' '| we have |a<b| */ + } +} + +@ @<Output saved...@>= + for (;c>0;c--) out_str("\\1"); +@.\\1@> + for (;c<0;c++) out_str("\\2"); +@.\\2@> + +@ The remaining part of |make_output| is somewhat more complicated. When we +output a section name, we may need to enter the parsing and translation +routines, since the name may contain \CEE/ code embedded in +\pb\ constructions. This \CEE/ code is placed at the end of the active +input buffer and the translation process uses the end of the active +|tok_mem| area. + +@<Output a section name@>= { + out_str("\\X"); +@.\\X@> + cur_xref=(xref_pointer)cur_name->xref; + if (cur_xref->num==file_flag) {an_output=1; cur_xref=cur_xref->xlink;} + else an_output=0; + if (cur_xref->num>=def_flag) { + out_section(cur_xref->num-def_flag); + if (phase==3) { + cur_xref=cur_xref->xlink; + while (cur_xref->num>=def_flag) { + out_str(", "); + out_section(cur_xref->num-def_flag); + cur_xref=cur_xref->xlink; + } + } + } + else out('0'); /* output the section number, or zero if it was undefined */ + out(':'); + if (an_output) out_str("\\.{"@q}@>); +@.\\.@> + @<Output the text of the section name@>; + if (an_output) out_str(@q{@>" }"); + out_str("\\X"); +} + +@ @<Output the text...@>= +sprint_section_name(scratch,cur_name); +k=scratch; +k_limit=scratch+strlen(scratch); +cur_section_name=cur_name; +while (k<k_limit) { + b=*(k++); + if (b=='@@') @<Skip next character, give error if not `\.{@@}'@>; + if (an_output) + switch (b) { + case ' ':case '\\':case '#':case '%':case '$':case '^': + case '{': case '}': case '~': case '&': case '_': + out('\\'); /* falls through */ +@.\\\ @> +@.\\\\@> +@.\\\#@> +@.\\\%@> +@.\\\$@> +@.\\\^@> +@.\\\{@>@q}@> +@q{@>@.\\\}@> +@.\\\~@> +@.\\\&@> +@.\\_@> @q CWEAVE does quote an underscore! @> + default: out(b); + } + else if (b!='|') out(b) + else { + @<Copy the \CEE/ text into the |buffer| array@>; + save_loc=loc; save_limit=limit; loc=limit+2; limit=j+1; + *limit='|'; output_C(); + loc=save_loc; limit=save_limit; + } +} + +@ @<Skip next char...@>= +if (*k++!='@@') { + printf("\n! Illegal control code in section name: <"); +@.Illegal control code...@> + print_section_name(cur_section_name); printf("> "); mark_error; +} + +@ The \CEE/ text enclosed in \pb\ should not contain `\.{\v}' characters, +except within strings. We put a `\.{\v}' at the front of the buffer, so that an +error message that displays the whole buffer will look a little bit sensible. +The variable |delim| is zero outside of strings, otherwise it +equals the delimiter that began the string being copied. + +@<Copy the \CEE/ text into...@>= +j=limit+1; *j='|'; delim=0; +while (1) { + if (k>=k_limit) { + printf("\n! C text in section name didn't end: <"); +@.C text...didn't end@> + print_section_name(cur_section_name); printf("> "); mark_error; break; + } + b=*(k++); + if (b=='@@' || (b=='\\' && delim!=0)) + @<Copy a quoted character into the buffer@> + else { + if (b=='\'' || b=='"') + if (delim==0) delim=b; + else if (delim==b) delim=0; + if (b!='|' || delim!=0) { + if (j>buffer+long_buf_size-3) overflow("buffer"); + *(++j)=b; + } + else break; + } +} + +@ @<Copy a quoted char...@>= { + if (j>buffer+long_buf_size-4) overflow("buffer"); + *(++j)=b; *(++j)=*(k++); +} + +@** Phase two processing. +We have assembled enough pieces of the puzzle in order to be ready to specify +the processing in \.{CWEAVE}'s main pass over the source file. Phase two +is analogous to phase one, except that more work is involved because we must +actually output the \TEX/ material instead of merely looking at the +\.{CWEB} specifications. + +@<Predecl...@>= +void phase_two(); + +@ @c +void +phase_two() { +reset_input(); if (show_progress) printf("\nWriting the output file..."); +@.Writing the output file...@> +section_count=0; format_visible=1; copy_limbo(); +finish_line(); flush_buffer(out_buf,0,0); /* insert a blank line, it looks nice */ +while (!input_has_ended) @<Translate the current section@>; +} + +@ The output file will contain the control sequence \.{\\Y} between non-null +sections of a section, e.g., between the \TEX/ and definition parts if both +are nonempty. This puts a little white space between the parts when they are +printed. However, we don't want \.{\\Y} to occur between two definitions +within a single section. The variables |out_line| or |out_ptr| will +change if a section is non-null, so the following macros `|save_position|' +and `|emit_space_if_needed|' are able to handle the situation: + +@d save_position save_line=out_line; save_place=out_ptr +@d emit_space_if_needed if (save_line!=out_line || save_place!=out_ptr) + out_str("\\Y"); + space_checked=1 +@.\\Y@> + +@<Global...@>= +int save_line; /* former value of |out_line| */ +char *save_place; /* former value of |out_ptr| */ +int sec_depth; /* the integer, if any, following \.{@@*} */ +boolean space_checked; /* have we done |emit_space_if_needed|? */ +boolean format_visible; /* should the next format declaration be output? */ +boolean doing_format=0; /* are we outputting a format declaration? */ +boolean group_found=0; /* has a starred section occurred? */ + +@ @<Translate the current section@>= { + section_count++; + @<Output the code for the beginning of a new section@>; + save_position; + @<Translate the \TEX/ part of the current section@>; + @<Translate the definition part of the current section@>; + @<Translate the \CEE/ part of the current section@>; + @<Show cross-references to this section@>; + @<Output the code for the end of a section@>; +} + +@ Sections beginning with the \.{CWEB} control sequence `\.{@@\ }' start in the +output with the \TEX/ control sequence `\.{\\M}', followed by the section +number. Similarly, `\.{@@*}' sections lead to the control sequence `\.{\\N}'. +In this case there's an additional parameter, representing one plus the +specified depth, immediately after the \.{\\N}. +If the section has changed, we put \.{\\*} just after the section number. + +@<Output the code for the beginning...@>= +if (*(loc-1)!='*') out_str("\\M"); +@.\\M@> +else { + while (*loc == ' ') loc++; + if (*loc=='*') { /* ``top'' level */ + sec_depth = -1; + loc++; + } + else { + for (sec_depth=0; xisdigit(*loc);loc++) + sec_depth = sec_depth*10 + (*loc) -'0'; + } + while (*loc == ' ') loc++; /* remove spaces before group title */ + group_found=1; + out_str("\\N"); +@.\\N@> + {@+ char s[32];@+sprintf(s,"{%d}",sec_depth+1);@+out_str(s);@+} + if (show_progress) + printf("*%d",section_count); update_terminal; /* print a progress report */ +} +out_str("{");out_section(section_count); out_str("}"); + +@ In the \TEX/ part of a section, we simply copy the source text, except that +index entries are not copied and \CEE/ text within \pb\ is translated. + +@<Translate the \T...@>= do { + next_control=copy_TeX(); + switch (next_control) { + case '|': init_stack; output_C(); break; + case '@@': out('@@'); break; + case TeX_string: case noop: + case xref_roman: case xref_wildcard: case xref_typewriter: + case section_name: loc-=2; next_control=get_next(); /* skip to \.{@@>} */ + if (next_control==TeX_string) + err_print("! TeX string should be in C text only"); break; +@.TeX string should be...@> + case thin_space: case math_break: case ord: + case line_break: case big_line_break: case no_line_break: case join: + case pseudo_semi: case macro_arg_open: case macro_arg_close: + case output_defs_code: + err_print("! You can't do that in TeX text"); break; +@.You can't do that...@> + } +} while (next_control<format_code); + +@ When we get to the following code we have |next_control>=format_code|, and +the token memory is in its initial empty state. + +@<Translate the d...@>= +space_checked=0; +while (next_control<=definition) { /* |format_code| or |definition| */ + init_stack; + if (next_control==definition) @<Start a macro definition@>@; + else @<Start a format definition@>; + outer_parse(); finish_C(format_visible); format_visible=1; + doing_format=0; +} + +@ The |finish_C| procedure outputs the translation of the current +scraps, preceded by the control sequence `\.{\\B}' and followed by the +control sequence `\.{\\par}'. It also restores the token and scrap +memories to their initial empty state. + +A |force| token is appended to the current scraps before translation +takes place, so that the translation will normally end with \.{\\6} or +\.{\\7} (the \TEX/ macros for |force| and |big_force|). This \.{\\6} or +\.{\\7} is replaced by the concluding \.{\\par} or by \.{\\Y\\par}. + +@<Predecl...@>= +void finish_C(); + +@ @c +void +finish_C(visible) /* finishes a definition or a \CEE/ part */ + boolean visible; /* nonzero if we should produce \TEX/ output */ +{ + text_pointer p; /* translation of the scraps */ + if (visible) { + out_str("\\B"); app_tok(force); app_scrap(insert,no_math); + p=translate(); +@.\\B@> + app(tok_flag+(int)(p-tok_start)); make_output(); /* output the list */ + if (out_ptr>out_buf+1) + if (*(out_ptr-1)=='\\') +@.\\6@> +@.\\7@> +@.\\Y@> + if (*out_ptr=='6') out_ptr-=2; + else if (*out_ptr=='7') *out_ptr='Y'; + out_str("\\par"); finish_line(); + } + if (text_ptr>max_text_ptr) max_text_ptr=text_ptr; + if (tok_ptr>max_tok_ptr) max_tok_ptr=tok_ptr; + if (scrap_ptr>max_scr_ptr) max_scr_ptr=scrap_ptr; + tok_ptr=tok_mem+1; text_ptr=tok_start+1; scrap_ptr=scrap_info; + /* forget the tokens and the scraps */ +} + +@ Keeping in line with the conventions of the \CEE/ preprocessor (and +otherwise contrary to the rules of \.{CWEB}) we distinguish here +between the case that `\.(' immediately follows an identifier and the +case that the two are separated by a space. In the latter case, and +if the identifier is not followed by `\.(' at all, the replacement +text starts immediately after the identifier. In the former case, +it starts after we scan the matching `\.)'. + +@<Start a macro...@>= { + if (save_line!=out_line || save_place!=out_ptr || space_checked) app(backup); + if(!space_checked){emit_space_if_needed;save_position;} + app_str("\\D"); /* this will produce `\&{define }' */ +@.\\D@> + if ((next_control=get_next())!=identifier) + err_print("! Improper macro definition"); +@.Improper macro definition@> + else { + app('$'); app_cur_id(0); + if (*loc=='(') + reswitch: switch (next_control=get_next()) { + case '(': case ',': app(next_control); goto reswitch; + case identifier: app_cur_id(0); goto reswitch; + case ')': app(next_control); next_control=get_next(); break; + default: err_print("! Improper macro definition"); break; + } + else next_control=get_next(); + app_str("$ "); app(break_space); + app_scrap(dead,no_math); /* scrap won't take part in the parsing */ + } +} + +@ @<Start a format...@>= { + doing_format=1; + if(*(loc-1)=='s' || *(loc-1)=='S') format_visible=0; + if(!space_checked){emit_space_if_needed;save_position;} + app_str("\\F"); /* this will produce `\&{format }' */ +@.\\F@> + next_control=get_next(); + if (next_control==identifier) { + app(id_flag+(int)(id_lookup(id_first, id_loc,normal)-name_dir)); + app(' '); + app(break_space); /* this is syntactically separate from what follows */ + next_control=get_next(); + if (next_control==identifier) { + app(id_flag+(int)(id_lookup(id_first, id_loc,normal)-name_dir)); + app_scrap(exp,maybe_math); app_scrap(semi,maybe_math); + next_control=get_next(); + } + } + if (scrap_ptr!=scrap_info+2) err_print("! Improper format definition"); +@.Improper format definition@> +} + +@ Finally, when the \TEX/ and definition parts have been treated, we have +|next_control>=begin_C|. We will make the global variable |this_section| +point to the current section name, if it has a name. + +@<Global...@>= +name_pointer this_section; /* the current section name, or zero */ + +@ @<Translate the \CEE/...@>= +this_section=name_dir; +if (next_control<=section_name) { + emit_space_if_needed; init_stack; + if (next_control==begin_C) next_control=get_next(); + else { + this_section=cur_section; + @<Check that '=' or '==' follows this section name, and + emit the scraps to start the section definition@>; + } + while (next_control<=section_name) { + outer_parse(); + @<Emit the scrap for a section name if present@>; + } + finish_C(1); +} + +@ The title of the section and an $\E$ or $\mathrel+\E$ are made +into a scrap that should not take part in the parsing. + +@<Check that '='...@>= +do next_control=get_next(); + while (next_control=='+'); /* allow optional `\.{+=}' */ +if (next_control!='=' && next_control!=eq_eq) + err_print("! You need an = sign after the section name"); +@.You need an = sign...@> + else next_control=get_next(); +if (out_ptr>out_buf+1 && *out_ptr=='Y' && *(out_ptr-1)=='\\') app(backup); + /* the section name will be flush left */ +@.\\Y@> +app(section_flag+(int)(this_section-name_dir)); +cur_xref=(xref_pointer)this_section->xref; +if(cur_xref->num==file_flag) cur_xref=cur_xref->xlink; +app_str("${}"); +if (cur_xref->num!=section_count+def_flag) { + app_str("\\mathrel+"); /*section name is multiply defined*/ + this_section=name_dir; /*so we won't give cross-reference info here*/ +} +app_str("\\E"); /* output an equivalence sign */ +@.\\E@> +app_str("{}$"); +app(force); app_scrap(dead,no_math); + /* this forces a line break unless `\.{@@+}' follows */ + +@ @<Emit the scrap...@>= +if (next_control<section_name) { + err_print("! You can't do that in C text"); +@.You can't do that...@> + next_control=get_next(); +} +else if (next_control==section_name) { + app(section_flag+(int)(cur_section-name_dir)); + app_scrap(section_scrap,maybe_math); + next_control=get_next(); +} + +@ Cross references relating to a named section are given +after the section ends. + +@<Show cross...@>= +if (this_section>name_dir) { + cur_xref=(xref_pointer)this_section->xref; + if (cur_xref->num==file_flag){an_output=1;cur_xref=cur_xref->xlink;} + else an_output=0; + if (cur_xref->num>def_flag) + cur_xref=cur_xref->xlink; /* bypass current section number */ + footnote(def_flag); footnote(cite_flag); footnote(0); +} + +@ The |footnote| procedure gives cross-reference information about +multiply defined section names (if the |flag| parameter is +|def_flag|), or about references to a section name +(if |flag==cite_flag|), or to its uses (if |flag==0|). It assumes that +|cur_xref| points to the first cross-reference entry of interest, and it +leaves |cur_xref| pointing to the first element not printed. Typical outputs: +`\.{\\A101.}'; `\.{\\Us 370\\ET1009.}'; +`\.{\\As 8, 27\\*\\ETs64.}'. + +Note that the output of \.{CWEAVE} is not English-specific; users may +supply new definitions for the macros \.{\\A}, \.{\\As}, etc. + +@<Predecl...@>= +void footnote(); + +@ @c +void +footnote(flag) /* outputs section cross-references */ +sixteen_bits flag; +{ + xref_pointer q; /* cross-reference pointer variable */ + if (cur_xref->num<=flag) return; + finish_line(); out('\\'); +@.\\A@> +@.\\Q@> +@.\\U@> + out(flag==0? 'U': flag==cite_flag? 'Q': 'A'); + @<Output all the section numbers on the reference list |cur_xref|@>; + out('.'); +} + +@ The following code distinguishes three cases, according as the number +of cross-references is one, two, or more than two. Variable |q| points +to the first cross-reference, and the last link is a zero. + +@<Output all the section numbers...@>= +q=cur_xref; if (q->xlink->num>flag) out('s'); /* plural */ +while (1) { + out_section(cur_xref->num-flag); + cur_xref=cur_xref->xlink; /* point to the next cross-reference to output */ + if (cur_xref->num<=flag) break; + if (cur_xref->xlink->num>flag) out_str(", "); /* not the last */ + else {out_str("\\ET"); /* the last */ +@.\\ET@> + if (cur_xref != q->xlink) out('s'); /* the last of more than two */ + } +} + +@ @<Output the code for the end of a section@>= +out_str("\\fi"); finish_line(); +@.\\fi@> +flush_buffer(out_buf,0,0); /* insert a blank line, it looks nice */ + +@** Phase three processing. +We are nearly finished! \.{CWEAVE}'s only remaining task is to write out the +index, after sorting the identifiers and index entries. + +If the user has set the |no_xref| flag (the \.{-x} option on the command line), +just finish off the page, omitting the index, section name list, and table of +contents. + +@<Predecl...@>= +void phase_three(); + +@ @c +void +phase_three() { +if (no_xref) { + finish_line(); + out_str("\\end"); +@.\\end@> + finish_line(); +} +else { + phase=3; if (show_progress) printf("\nWriting the index..."); +@.Writing the index...@> + finish_line(); + if ((idx_file=fopen(idx_file_name,"w"))==NULL) + fatal("! Cannot open index file ",idx_file_name); +@.Cannot open index file@> + if (change_exists) { + @<Tell about changed sections@>; finish_line(); finish_line(); + } + out_str("\\inx"); finish_line(); +@.\\inx@> + active_file=idx_file; /* change active file to the index file */ + @<Do the first pass of sorting@>; + @<Sort and output the index@>; + finish_line(); fclose(active_file); /* finished with |idx_file| */ + active_file=tex_file; /* switch back to |tex_file| for a tic */ + out_str("\\fin"); finish_line(); +@.\\fin@> + if ((scn_file=fopen(scn_file_name,"w"))==NULL) + fatal("! Cannot open section file ",scn_file_name); +@.Cannot open section file@> + active_file=scn_file; /* change active file to section listing file */ + @<Output all the section names@>; + finish_line(); fclose(active_file); /* finished with |scn_file| */ + active_file=tex_file; + if (group_found) out_str("\\con");@+else out_str("\\end"); +@.\\con@> +@.\\end@> + finish_line(); + fclose(active_file); +} +if (show_happiness) printf("\nDone."); +check_complete(); /* was all of the change file used? */ +} + +@ Just before the index comes a list of all the changed sections, including +the index section itself. + +@<Global...@>= +sixteen_bits k_section; /* runs through the sections */ + +@ @<Tell about changed sections@>= { + /* remember that the index is already marked as changed */ + k_section=0; + while (!changed_section[++k_section]); + out_str("\\ch "); +@.\\ch@> + out_section(k_section); + while (k_section<section_count) { + while (!changed_section[++k_section]); + out_str(", "); out_section(k_section); + } + out('.'); +} + +@ A left-to-right radix sorting method is used, since this makes it easy to +adjust the collating sequence and since the running time will be at worst +proportional to the total length of all entries in the index. We put the +identifiers into 102 different lists based on their first characters. +(Uppercase letters are put into the same list as the corresponding lowercase +letters, since we want to have `$t<\\{TeX}<\&{to}$'.) The +list for character |c| begins at location |bucket[c]| and continues through +the |blink| array. + +@<Global...@>= +name_pointer bucket[256]; +name_pointer next_name; /* successor of |cur_name| when sorting */ +name_pointer blink[max_names]; /* links in the buckets */ + +@ To begin the sorting, we go through all the hash lists and put each entry +having a nonempty cross-reference list into the proper bucket. + +@<Do the first pass...@>= { +int c; +for (c=0; c<=255; c++) bucket[c]=NULL; +for (h=hash; h<=hash_end; h++) { + next_name=*h; + while (next_name) { + cur_name=next_name; next_name=cur_name->link; + if (cur_name->xref!=(char*)xmem) { + c=(eight_bits)((cur_name->byte_start)[0]); + if (xisupper(c)) c=tolower(c); + blink[cur_name-name_dir]=bucket[c]; bucket[c]=cur_name; + } + } +} +} + +@ During the sorting phase we shall use the |cat| and |trans| arrays from +\.{CWEAVE}'s parsing algorithm and rename them |depth| and |head|. They now +represent a stack of identifier lists for all the index entries that have +not yet been output. The variable |sort_ptr| tells how many such lists are +present; the lists are output in reverse order (first |sort_ptr|, then +|sort_ptr-1|, etc.). The |j|th list starts at |head[j]|, and if the first +|k| characters of all entries on this list are known to be equal we have +|depth[j]==k|. + +@ @<Rest of |trans_plus| union@>= +name_pointer Head; + +@ @d depth cat /* reclaims memory that is no longer needed for parsing */ +@d head trans_plus.Head /* ditto */ +@f sort_pointer int +@d sort_pointer scrap_pointer /* ditto */ +@d sort_ptr scrap_ptr /* ditto */ +@d max_sorts max_scraps /* ditto */ + +@<Global...@>= +eight_bits cur_depth; /* depth of current buckets */ +char *cur_byte; /* index into |byte_mem| */ +sixteen_bits cur_val; /* current cross-reference number */ +sort_pointer max_sort_ptr; /* largest value of |sort_ptr| */ + +@ @<Set init...@>= +max_sort_ptr=scrap_info; + +@ The desired alphabetic order is specified by the |collate| array; namely, +$|collate|[0]<|collate|[1]<\cdots<|collate|[100]$. + +@<Global...@>= +eight_bits collate[102+128]; /* collation order */ +@^high-bit character handling@> + +@ We use the order $\hbox{null}<\.\ <\hbox{other characters}<{}$\.\_${}< +\.A=\.a<\cdots<\.Z=\.z<\.0<\cdots<\.9.$ Warning: The collation mapping +needs to be changed if ASCII code is not being used. +@^ASCII code dependencies@> +@^high-bit character handling@> + +We initialize |collate| by copying a few characters at a time, because +some \CEE/ compilers choke on long strings. + +@<Set init...@>= +collate[0]=0; +strcpy(collate+1," \1\2\3\4\5\6\7\10\11\12\13\14\15\16\17"); +/* 16 characters + 1 = 17 */ +strcpy(collate+17,"\20\21\22\23\24\25\26\27\30\31\32\33\34\35\36\37"); +/* 16 characters + 17 = 33 */ +strcpy(collate+33,"!\42#$%&'()*+,-./:;<=>?@@[\\]^`{|}~_"); +/* 32 characters + 33 = 65 */ +strcpy(collate+65,"abcdefghijklmnopqrstuvwxyz0123456789"); +/* (26 + 10) characters + 65 = 101 */ +strcpy(collate+101,"\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"); +/* 16 characters + 101 = 117 */ +strcpy(collate+117,"\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237"); +/* 16 characters + 117 = 133 */ +strcpy(collate+133,"\240\241\242\243\244\245\246\247\250\251\252\253\254\255\256\257"); +/* 16 characters + 133 = 149 */ +strcpy(collate+149,"\260\261\262\263\264\265\266\267\270\271\272\273\274\275\276\277"); +/* 16 characters + 149 = 165 */ +strcpy(collate+165,"\300\301\302\303\304\305\306\307\310\311\312\313\314\315\316\317"); +/* 16 characters + 165 = 181 */ +strcpy(collate+181,"\320\321\322\323\324\325\326\327\330\331\332\333\334\335\336\337"); +/* 16 characters + 181 = 197 */ +strcpy(collate+197,"\340\341\342\343\344\345\346\347\350\351\352\353\354\355\356\357"); +/* 16 characters + 197 = 213 */ +strcpy(collate+213,"\360\361\362\363\364\365\366\367\370\371\372\373\374\375\376\377"); +/* 16 characters + 213 = 229 */ + +@ Procedure |unbucket| goes through the buckets and adds nonempty lists +to the stack, using the collating sequence specified in the |collate| array. +The parameter to |unbucket| tells the current depth in the buckets. +Any two sequences that agree in their first 255 character positions are +regarded as identical. + +@d infinity 255 /* $\infty$ (approximately) */ + +@<Predecl...@>= +void unbucket(); + +@ @c +void +unbucket(d) /* empties buckets having depth |d| */ +eight_bits d; +{ + int c; /* index into |bucket|; cannot be a simple |char| because of sign + comparison below*/ + for (c=100+128; c>= 0; c--) if (bucket[collate[c]]) { +@^high-bit character handling@> + if (sort_ptr>=scrap_info_end) overflow("sorting"); + sort_ptr++; + if (sort_ptr>max_sort_ptr) max_sort_ptr=sort_ptr; + if (c==0) sort_ptr->depth=infinity; + else sort_ptr->depth=d; + sort_ptr->head=bucket[collate[c]]; bucket[collate[c]]=NULL; + } +} + +@ @<Sort and output...@>= +sort_ptr=scrap_info; unbucket(1); +while (sort_ptr>scrap_info) { + cur_depth=sort_ptr->depth; + if (blink[sort_ptr->head-name_dir]==0 || cur_depth==infinity) + @<Output index entries for the list at |sort_ptr|@>@; + else @<Split the list at |sort_ptr| into further lists@>; +} + +@ @<Split the list...@>= { + eight_bits c; + next_name=sort_ptr->head; + do { + cur_name=next_name; next_name=blink[cur_name-name_dir]; + cur_byte=cur_name->byte_start+cur_depth; + if (cur_byte==(cur_name+1)->byte_start) c=0; /* hit end of the name */ + else { + c=(eight_bits) *cur_byte; + if (xisupper(c)) c=tolower(c); + } + blink[cur_name-name_dir]=bucket[c]; bucket[c]=cur_name; + } while (next_name); + --sort_ptr; unbucket(cur_depth+1); +} + +@ @<Output index...@>= { + cur_name=sort_ptr->head; + do { + out_str("\\I"); +@.\\I@> + @<Output the name at |cur_name|@>; + @<Output the cross-references at |cur_name|@>; + cur_name=blink[cur_name-name_dir]; + } while (cur_name); + --sort_ptr; +} + +@ @<Output the name...@>= +switch (cur_name->ilk) { + case normal: if (is_tiny(cur_name)) out_str("\\|"); + else {char *j; + for (j=cur_name->byte_start;j<(cur_name+1)->byte_start;j++) + if (xislower(*j)) goto lowcase; + out_str("\\."); break; +lowcase: out_str("\\\\"); + } + break; +@.\\|@> +@.\\.@> +@.\\\\@> + case roman: break; + case wildcard: out_str("\\9"); break; +@.\\9@> + case typewriter: out_str("\\."); break; +@.\\.@> + case custom: case quoted: {char *j; out_str("$\\"); + for (j=cur_name->byte_start;j<(cur_name+1)->byte_start;j++) + out(isxalpha(*j)? 'x' : *j); + out('$'); + goto name_done; + } + default: out_str("\\&"); +@.\\\&@> +} +out_name(cur_name); +name_done: + +@ Section numbers that are to be underlined are enclosed in +`\.{\\[}$\,\ldots\,$\.]'. + +@<Output the cross-references...@>= +@<Invert the cross-reference list at |cur_name|, making |cur_xref| the head@>; +do { + out_str(", "); cur_val=cur_xref->num; + if (cur_val<def_flag) out_section(cur_val); + else {out_str("\\["); out_section(cur_val-def_flag); out(']');} +@.\\[@> + cur_xref=cur_xref->xlink; +} while (cur_xref!=xmem); +out('.'); finish_line(); + +@ List inversion is best thought of as popping elements off one stack and +pushing them onto another. In this case |cur_xref| will be the head of +the stack that we push things onto. +@<Global...@>= +xref_pointer next_xref, this_xref; + /* pointer variables for rearranging a list */ + +@ @<Invert the cross-reference list at |cur_name|, making |cur_xref| the head@>= +this_xref=(xref_pointer)cur_name->xref; cur_xref=xmem; +do { + next_xref=this_xref->xlink; this_xref->xlink=cur_xref; + cur_xref=this_xref; this_xref=next_xref; +} while (this_xref!=xmem); + +@ The following recursive procedure walks through the tree of section names and +prints them. +@^recursion@> + +@<Predecl...@>= +void section_print(); + +@ @c +void +section_print(p) /* print all section names in subtree |p| */ +name_pointer p; +{ + if (p) { + section_print(p->llink); out_str("\\I"); +@.\\I@> + tok_ptr=tok_mem+1; text_ptr=tok_start+1; scrap_ptr=scrap_info; init_stack; + app(p-name_dir+section_flag); make_output(); + footnote(cite_flag); + footnote(0); /* |cur_xref| was set by |make_output| */ + finish_line();@/ + section_print(p->rlink); + } +} + +@ @<Output all the section names@>=section_print(root) + +@ Because on some systems the difference between two pointers is a |long| +rather than an |int|, we use \.{\%ld} to print these quantities. + +@c +void +print_stats() { + printf("\nMemory usage statistics:\n"); +@.Memory usage statistics:@> + printf("%ld names (out of %ld)\n", + (long)(name_ptr-name_dir),(long)max_names); + printf("%ld cross-references (out of %ld)\n", + (long)(xref_ptr-xmem),(long)max_refs); + printf("%ld bytes (out of %ld)\n", + (long)(byte_ptr-byte_mem),(long)max_bytes); + printf("Parsing:\n"); + printf("%ld scraps (out of %ld)\n", + (long)(max_scr_ptr-scrap_info),(long)max_scraps); + printf("%ld texts (out of %ld)\n", + (long)(max_text_ptr-tok_start),(long)max_texts); + printf("%ld tokens (out of %ld)\n", + (long)(max_tok_ptr-tok_mem),(long)max_toks); + printf("%ld levels (out of %ld)\n", + (long)(max_stack_ptr-stack),(long)stack_size); + printf("Sorting:\n"); + printf("%ld levels (out of %ld)\n", + (long)(max_sort_ptr-scrap_info),(long)max_scraps); +} + +@** Index. +If you have read and understood the code for Phase III above, you know what +is in this index and how it got here. All sections in which an identifier is +used are listed with that identifier, except that reserved words are +indexed only when they appear in format definitions, and the appearances +of identifiers in section names are not indexed. Underlined entries +correspond to where the identifier was declared. Error messages, control +sequences put into the output, and a few +other things like ``recursion'' are indexed here too. diff --git a/web/c_cpp/c2cweb/cweb/cwebmac.ori b/web/c_cpp/c2cweb/cweb/cwebmac.ori new file mode 100644 index 0000000000..331a2eff46 --- /dev/null +++ b/web/c_cpp/c2cweb/cweb/cwebmac.ori @@ -0,0 +1,346 @@ +% This file is part of c2cweb package Version 1.5 + +% standard macros for CWEB listings (in addition to plain.tex) +% Version 3.0 --- June 1993 + +% modified by Werner Lemberg (a7971428@unet.univie.ac.at) 10-Nov-1996 + +\ifx\documentstyle\undefined\else\endinput\fi % LaTeX will use other macros +\xdef\fmtversion{\fmtversion+CWEB3.0} + +\let\:=\. % preserve a way to get the dot accent + % (all other accents will still work as usual) + +\parskip 0pt % no stretch between paragraphs +\parindent 1em % for paragraphs and for the first line of C text + +\font\ninerm=cmr9 +\let\mc=\ninerm % medium caps +\def\CEE/{{\mc C\spacefactor1000}} +\def\UNIX/{{\mc U\kern-.05emNIX\spacefactor1000}} +\def\TEX/{\TeX} +\def\CPLUSPLUS/{{\mc C\PP\spacefactor1000}} +\def\Cee{\CEE/} % for backward compatibility +\def\9#1{} +\font\eightrm=cmr8 +\let\sc=\eightrm % small caps (NOT a caps-and-small-caps font) +\let\mainfont=\tenrm +\let\cmntfont\tenrm +%\font\tenss=cmss10 \let\cmntfont\tenss % alternative comment font +\font\titlefont=cmr7 scaled\magstep4 % title on the contents page +\font\ttitlefont=cmtt10 scaled\magstep2 % typewriter type in title +\font\tentex=cmtex10 % TeX extended character set (used in strings) +\fontdimen7\tentex=0pt % no double space after sentences + +\def\${\ifmmode \hbox{\sl \char`\$} + \else \hbox{\ifdim \fontdimen1\font > 0pt \sl \fi \char`\$}\fi} + +\def\\#1{\leavevmode\hbox{\it#1\/\kern.05em}} % italic type for identifiers +\def\|#1{\leavevmode\hbox{$#1$}} % one-letter identifiers look better this way +\def\{\leavevmode\hbox{\bf + \def\_{\kern.04em\vbox{\hrule width.3em height .6pt}\kern.08em}% + #1\/\kern.05em}} % boldface type for reserved words +\def\.#1{\leavevmode\hbox{\tentex % typewriter type for strings + \let\\=\BS % backslash in a string + \let\{=\LB % left brace in a string + \let\}=\RB % right brace in a string + \let\~=\TL % tilde in a string + \let\ =\SP % space in a string + \let\_=\UL % underline in a string + \let\&=\AM % ampersand in a string + \let\^=\CF % circumflex in a string + #1\kern.05em}} +\def\){\discretionary{\hbox{\tentex\BS}}{}{}} +\def\AT{@} % at sign for control text (not needed in versions >= 2.9) +\def\ATL{\par\noindent\bgroup\catcode`\_=12 \postATL} % print @l in limbo +\def\postATL#1 #2 {\bf letter \\{\uppercase{\char"#1}} + tangles as \tentex "#2"\egroup\par} +\def\noATL#1 #2 {} +\def\noatl{\let\ATL=\noATL} % suppress output from @l +\def\ATH{\X\kern-.5em:Preprocessor definitions\X} +\let\PB=\relax % hook for program brackets |...| in TeX part or section name + +\chardef\AM=`\& % ampersand character in a string +\chardef\BS=`\\ % backslash in a string +\chardef\LB=`\{ % left brace in a string +\chardef\RB=`\} % right brace in a string +\def\SP{{\tt\char`\ }} % (visible) space in a string +\chardef\TL=`\~ % tilde in a string +\chardef\UL=`\_ % underline character in a string +\chardef\CF=`\^ % circumflex character in a string + +\newbox\PPbox % symbol for ++ +\setbox\PPbox=\hbox{\kern.5pt\raise1pt\hbox{\sevenrm+\kern-1pt+}\kern.5pt} +\def\PP{\copy\PPbox} +\newbox\MMbox \setbox\MMbox=\hbox{\kern.5pt\raise1pt\hbox{\sevensy\char0 + \kern-1pt\char0}\kern.5pt} +\def\MM{\copy\MMbox} +\newbox\MGbox % symbol for -> +\setbox\MGbox=\hbox{\kern-2pt\lower3pt\hbox{\teni\char'176}\kern1pt} +\def\MG{\copy\MGbox} +\newbox\NNbox % symbol for ## +\setbox\NNbox=\hbox{\kern.5pt\raise2pt\hbox{\#}\kern-4pt + \lower2pt\hbox{\#}\kern.5pt} +\def\NN{\copy\NNbox} +\def\MRL#1{\mathrel{\let\K==#1}} +%\def\MRL#1{\KK#1}\def\KK#1#2{\buildrel\;#1\over{#2}} +\let\GG=\gg +\let\LL=\ll +\let\NULL=\Lambda +\mathchardef\AND="2026 % bitwise and; also \& (unary operator) +\let\OR=\mid % bitwise or +\let\XOR=\oplus % bitwise exclusive or +\def\CM{{\sim}} % bitwise complement +\newbox\MODbox \setbox\MODbox=\hbox{\eightrm\%} +\def\MOD{\mathbin{\copy\MODbox}} +\def\DC{\kern.1em{::}\kern.1em} % symbol for :: +\def\PA{\mathbin{.*}} % symbol for .* +\def\MGA{\mathbin{\MG*}} % symbol for ->* +\def\this{\&{this}} + +\newbox\bak \setbox\bak=\hbox to -1em{} % backspace one em +\newbox\bakk\setbox\bakk=\hbox to -2em{} % backspace two ems + +\newcount\ind % current indentation in ems +\def\1{\global\advance\ind by1\hangindent\ind em} % indent one more notch +\def\2{\global\advance\ind by-1} % indent one less notch +\def\3#1{\hfil\penalty#10\hfilneg} % optional break within a statement +\def\4{\copy\bak} % backspace one notch +\def\5{\hfil\penalty-1\hfilneg\kern2.5em\copy\bakk\ignorespaces}% optional break +\def\6{\ifmmode\else\par % forced break + \hangindent\ind em\noindent\kern\ind em\copy\bakk\ignorespaces\fi} +\def\7{\Y\6} % forced break and a little extra space +\def\8{\hskip-\ind em\hskip 2em} % no indentation + +\newcount\gdepth % depth of current major group, plus one +\newcount\secpagedepth +\secpagedepth=3 % page breaks will occur for depths -1, 0, and 1 +\newtoks\gtitle % title of current major group +\newskip\intersecskip \intersecskip=12pt minus 3pt % space between sections +\let\yskip=\smallskip +\def\?{\mathrel?} +\def\note#1#2.{\Y\noindent{\hangindent2em\baselineskip10pt\eightrm#1~#2.\par}} +\def\lapstar{\rlap{*}} +\def\stsec{\rightskip=0pt % get out of C mode (cf. \B) + \sfcode`;=1500 \pretolerance 200 \hyphenpenalty 50 \exhyphenpenalty 50 + \noindent{\let\*=\lapstar\bf\secstar.\quad}} +\let\startsection=\stsec +\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 + \sfcode`;=3000 + \pretolerance 10000 + \hyphenpenalty 9999 % so strings can be broken (discretionary \ is inserted) + \exhyphenpenalty 10000 + \global\ind=2 \1\ \unskip} +\def\C#1{\5\5\quad$/\ast\,${\cmntfont #1}$\,\ast/$} +\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 +\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 +\def\F{\defin{format}} % format definition +\let\G=\ge % greater than or equal sign +% \H is long Hungarian umlaut accent +\let\I=\ne % unequal sign +\def\J{\.{@\&}} % TANGLE's join operation +\let\K== % assignment operator +%\let\K=\leftarrow % "honest" alternative to standard assignment operator +% \L is Polish letter suppressed-L +\outer\def\M#1{\MN{#1}\ifon\vfil\penalty-100\vfilneg % beginning of section + \vskip\intersecskip\startsection\ignorespaces} +\outer\def\N#1#2#3.{\gdepth=#1\gtitle={#3}\MN{#2}% beginning of starred section + \ifon\ifnum#1<\secpagedepth \vfil\eject % force page break if depth is small + \else\vfil\penalty-100\vfilneg\vskip\intersecskip\fi\fi + \message{*\secno} % progress report + \edef\next{\write\cont{\ZZ{#3}{#1}{\secno}% write to contents file + {\noexpand\the\pageno}}}\next % \ZZ{title}{depth}{sec}{page} + \ifon\startsection{\bf#3.\quad}\ignorespaces} +\def\MN#1{\par % common code for \M, \N + {\xdef\secstar{#1}\let\*=\empty\xdef\secno{#1}}% remove \* from section name + \ifx\secno\secstar \onmaybe \else\ontrue \fi + \mark{{{\tensy x}\secno}{\the\gdepth}{\the\gtitle}}} +% each \mark is {section reference or null}{depth plus 1}{group title} +% \O is Scandinavian letter O-with-slash +% \P is paragraph sign +\def\Q{\note{This code is cited in section}} % xref for mention of a section +\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\T#1{\leavevmode % octal, hex or decimal constant + \hbox{$\def\?{\kern.2em}% + \def\$##1{\egroup_{\,\rm##1}\bgroup}% suffix to constant + \def\_{\cdot 10^{\aftergroup}}% power of ten (via dirty trick) + \let\~=\oct \let\^=\hex {#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 +\let\W=\land % logical and +\def\X#1:#2\X{\ifmmode\gdef\XX{\null$\null}\else\gdef\XX{}\fi % section name + \XX$\langle\,${#2\eightrm\kern.5em#1}$\,\rangle$\XX} +\def\Y{\par\yskip} +\let\Z=\le +\let\ZZ=\let % now you can \write the control sequence \ZZ +\let\*=* + +%\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\vb#1{\leavevmode\hbox{\kern2pt\vrule\vtop{\vbox{\hrule + \hbox{\strut\kern2pt\.{#1}\kern2pt}} + \hrule}\vrule\kern2pt}} % verbatim string + +\def\onmaybe{\let\ifon=\maybe} \let\maybe=\iftrue +\newif\ifon \newif\iftitle \newif\ifpagesaved + +\def\lheader{\mainfont\the\pageno\eightrm\qquad\grouptitle\hfill\title\qquad + \mainfont\topsecno} % top line on left-hand pages +\def\rheader{\mainfont\topsecno\eightrm\qquad\title\hfill\grouptitle + \qquad\mainfont\the\pageno} % top line on right-hand pages +\def\grouptitle{\let\i=I\let\j=J\uppercase\expandafter{\expandafter + \takethree\topmark}} +\def\topsecno{\expandafter\takeone\topmark} +\def\takeone#1#2#3{#1} +\def\taketwo#1#2#3{#2} +\def\takethree#1#2#3{#3} +\def\nullsec{\eightrm\kern-2em} % the \kern-2em cancels \qquad in headers + +\let\page=\pagebody \raggedbottom +% \def\page{\box255 }\normalbottom % faster, but loses plain TeX footnotes +\def\normaloutput#1#2#3{\ifodd\pageno\hoffset=\pageshift\fi + \shipout\vbox{ + \vbox to\fullpageheight{ + \iftitle\global\titlefalse + \else\hbox to\pagewidth{\vbox to10pt{}\ifodd\pageno #3\else#2\fi}\fi + \vfill#1}} % parameter #1 is the page itself + \global\advance\pageno by1} + +\gtitle={\.{CWEB} output} % this running head is reset by starred sections +\mark{\noexpand\nullsec0{\the\gtitle}} +\def\title{\expandafter\uppercase\expandafter{\jobname}} +\def\topofcontents{\centerline{\titlefont\title}\vskip.7in + \vfill} % this material will start the table of contents page +\def\botofcontents{\vfill + \centerline{\covernote}} % this material will end the table of contents page +\def\covernote{} +\def\contentspagenumber{0} % default page number for table of contents +\newdimen\pagewidth \pagewidth=6.5in % the width of each page +\newdimen\pageheight \pageheight=8.7in % the height of each page +\newdimen\fullpageheight \fullpageheight=9in % page height including headlines +\newdimen\pageshift \pageshift=0in % shift righthand pages wrt lefthand ones +\def\magnify#1{\mag=#1\pagewidth=6.5truein\pageheight=8.7truein + \fullpageheight=9truein\setpage} +\def\setpage{\hsize\pagewidth\vsize\pageheight} % use after changing page size +\def\contentsfile{\jobname.toc} % file that gets table of contents info +\def\readcontents{\input \contentsfile} +\def\readindex{\input \jobname.idx} +\def\readsections{\input \jobname.scn} + +\newwrite\cont +\output{\setbox0=\page % the first page is garbage + \openout\cont=\contentsfile + \write\cont{\catcode `\noexpand\@=11\relax} % \makeatletter + \global\output{\normaloutput\page\lheader\rheader}} +\setpage +\vbox to \vsize{} % the first \topmark won't be null + +\def\ch{\note{The following sections were changed by the change file:} + \let\*=\relax} +\newbox\sbox % saved box preceding the index +\newbox\lbox % lefthand column in the index +\def\inx{\par\vskip6pt plus 1fil % we are beginning the index + \def\page{\box255 } \normalbottom + \write\cont{} % ensure that the contents file isn't empty + \write\cont{\catcode `\noexpand\@=12\relax} % \makeatother + \closeout\cont % the contents information has been fully gathered + \output{\ifpagesaved\normaloutput{\box\sbox}\lheader\rheader\fi + \global\setbox\sbox=\page \global\pagesavedtrue} + \pagesavedfalse \eject % eject the page-so-far and predecessors + \setbox\sbox\vbox{\unvbox\sbox} % take it out of its box + \vsize=\pageheight \advance\vsize by -\ht\sbox % the remaining height + \hsize=.5\pagewidth \advance\hsize by -10pt + % column width for the index (20pt between cols) + \parfillskip 0pt plus .6\hsize % try to avoid almost empty lines + \def\lr{L} % this tells whether the left or right column is next + \output{\if L\lr\global\setbox\lbox=\page \gdef\lr{R} + \else\normaloutput{\vbox to\pageheight{\box\sbox\vss + \hbox to\pagewidth{\box\lbox\hfil\page}}}\lheader\rheader + \global\vsize\pageheight\gdef\lr{L}\global\pagesavedfalse\fi} + \message{Index:} + \parskip 0pt plus .5pt + \outer\def\I##1, {\par\hangindent2em\noindent##1:\kern1em} % index entry + \def\[##1]{$\underline{##1}$} % underlined index item + \rm \rightskip0pt plus 2.5em \tolerance 10000 \let\*=\lapstar + \hyphenpenalty 10000 \parindent0pt + \readindex} +\def\fin{\par\vfill\eject % this is done when we are ending the index + \ifpagesaved\null\vfill\eject\fi % output a null index column + \if L\lr\else\null\vfill\eject\fi % finish the current page + \parfillskip 0pt plus 1fil + \def\grouptitle{NAMES OF THE SECTIONS} + \let\topsecno=\nullsec + \message{Section names:} + \output={\normaloutput\page\lheader\rheader} + \setpage + \def\note##1##2.{\quad{\eightrm##1~##2.}} + \def\Q{\note{Cited in section}} % crossref for mention of a section + \def\Qs{\note{Cited in sections}} % crossref for mentions of a section + \def\U{\note{Used in section}} % crossref for use of a section + \def\Us{\note{Used in sections}} % crossref for uses of a section + \def\I{\par\hangindent 2em}\let\*=* + \readsections} +\def\con{\par\vfill\eject % finish the section names +% \ifodd\pageno\else\titletrue\null\vfill\eject\fi % for duplex printers + \rightskip 0pt \hyphenpenalty 50 \tolerance 200 + \setpage \output={\normaloutput\page\lheader\rheader} + \titletrue % prepare to output the table of contents + \pageno=\contentspagenumber + \def\grouptitle{TABLE OF CONTENTS} + \message{Table of contents:} + \topofcontents + \line{\hfil Section\hbox to3em{\hss Page}} + \let\ZZ=\contentsline + \readcontents\relax % read the contents info + \botofcontents \end} % print the contents page(s) and terminate +\def\contentsline#1#2#3#4{\ifnum#2=0 \smallbreak\fi + \line{\consetup{#2}#1 + \rm\leaders\hbox to .5em{.\hfil}\hfil\ #3\hbox to3em{\hss#4}}} +\def\consetup#1{\ifcase#1 \bf % depth -1 (@**) + \or % depth 0 (@*) + \or \hskip2em % depth 1 (@*1) + \or \hskip4em % depth 2 (@*2) + \or \hskip6em % depth 3 (@*3) + \or \hskip8em % depth 4 (@*4) + \or \hskip10em % depth 5 (@*5) + \else \hskip12em \fi} % depth 6 or more +\def\noinx{\let\inx=\end} % no indexes or table of contents +\def\nosecs{\let\FIN=\fin \def\fin{\let\parfillskip=\end \FIN}} + % no index of section names or table of contents +\def\nocon{\let\con=\end} % no table of contents +\def\today{\ifcase\month\or + January\or February\or March\or April\or May\or June\or + July\or August\or September\or October\or November\or December\fi + \space\number\day, \number\year} +\newcount\twodigits +\def\hours{\twodigits=\time \divide\twodigits by 60 \printtwodigits + \multiply\twodigits by-60 \advance\twodigits by\time :\printtwodigits} +\def\gobbleone1{} +\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 +\def\datecontentspage{% + \def\topofcontents{\leftline{\sc\today\ at \hours}\bigskip + \centerline{\titlefont\title}\vfill}} % timestamps the contents page + + +% end of cwebmac.tex diff --git a/web/c_cpp/c2cweb/cweb/cwebmac.tex b/web/c_cpp/c2cweb/cweb/cwebmac.tex new file mode 100644 index 0000000000..8682fb7372 --- /dev/null +++ b/web/c_cpp/c2cweb/cweb/cwebmac.tex @@ -0,0 +1,375 @@ +% This file is part of c2cweb package Version 1.5 + +% standard macros for CWEB listings (in addition to plain.tex) +% Version 3.0 --- June 1993 + +% modified by Werner Lemberg (a7971428@unet.univie.ac.at) 10-Nov-1996 + +\ifx\documentstyle\undefined\else\endinput\fi % LaTeX will use other macros +\xdef\fmtversion{\fmtversion+CWEB3.2} + +\let\:=\. % preserve a way to get the dot accent + % (all other accents will still work as usual) + +%\parskip 0pt % no stretch between paragraphs +%\parindent 1em % for paragraphs and for the first line of C text + +\font\ninerm=cmr9 +\let\mc=\ninerm % medium caps +\def\CEE/{{\mc C\spacefactor1000}} +\def\UNIX/{{\mc U\kern-.05emNIX\spacefactor1000}} +\def\TEX/{\TeX} +\def\CPLUSPLUS/{{\mc C\PP\spacefactor1000}} +\def\Cee{\CEE/} % for backward compatibility +\def\9#1{} +\font\eightrm=cmr8 +\let\sc=\eightrm % small caps (NOT a caps-and-small-caps font) +\let\mainfont=\tenrm +\let\cmntfont\tenrm +%\font\tenss=cmss10 \let\cmntfont\tenss % alternative comment font +%\font\titlefont=cmr7 scaled\magstep4 % title on the contents page +\font\titlefont=cmssbx10 scaled\magstep2 % title on the contents page +\font\ttitlefont=cmtt10 scaled\magstep2 % typewriter type in title +\font\tentex=cmtex10 % TeX extended character set (used in strings) +\fontdimen7\tentex=0pt % no double space after sentences + +\font\sectionfont=cmssbx10 scaled\magstephalf + +\def\${\ifmmode \hbox{\sl \char`\$} + \else \hbox{\ifdim \fontdimen1\font > 0pt \sl \fi \char`\$}\fi} + +\def\\#1{\leavevmode\hbox{\it#1\/\kern.05em}} % italic type for identifiers +\def\|#1{\leavevmode\hbox{$#1$}} % one-letter identifiers look better this way +\def\{\leavevmode\hbox{\bf + \def\_{\kern.04em\vbox{\hrule width.3em height .6pt}\kern.08em}% + #1\/\kern.05em}} % boldface type for reserved words +\def\.#1{\leavevmode\hbox{\tentex % typewriter type for strings + \let\\=\BS % backslash in a string + \let\{=\LB % left brace in a string + \let\}=\RB % right brace in a string + \let\~=\TL % tilde in a string + \let\ =\SP % space in a string + \let\_=\UL % underline in a string + \let\&=\AM % ampersand in a string + \let\^=\CF % circumflex in a string + #1\kern.05em}} +\def\){\discretionary{\hbox{\tentex\BS}}{}{}} +\def\AT{@} % at sign for control text (not needed in versions >= 2.9) +\def\ATL{\par\noindent\bgroup\catcode`\_=12 \postATL} % print @l in limbo +\def\postATL#1 #2 {\bf letter \\{\uppercase{\char"#1}} + tangles as \tentex "#2"\egroup\par} +\def\noATL#1 #2 {} +\def\noatl{\let\ATL=\noATL} % suppress output from @l +\def\ATH{\X\kern-.5em:Preprocessor definitions\X} +\let\PB=\relax % hook for program brackets |...| in TeX part or section name + +\chardef\AM=`\& % ampersand character in a string +\chardef\BS=`\\ % backslash in a string +\chardef\LB=`\{ % left brace in a string +\chardef\RB=`\} % right brace in a string +\def\SP{{\tt\char`\ }} % (visible) space in a string +\chardef\TL=`\~ % tilde in a string +\chardef\UL=`\_ % underline character in a string +\chardef\CF=`\^ % circumflex character in a string + +\newbox\PPbox % symbol for ++ +\setbox\PPbox=\hbox{\kern.5pt\raise1pt\hbox{\sevenrm+\kern-1pt+}\kern.5pt} +\def\PP{\copy\PPbox} +\newbox\MMbox \setbox\MMbox=\hbox{\kern.5pt\raise1pt\hbox{\sevensy\char0 + \kern-1pt\char0}\kern.5pt} +\def\MM{\copy\MMbox} +\newbox\MGbox % symbol for -> +\setbox\MGbox=\hbox{\kern-2pt\lower3pt\hbox{\teni\char'176}\kern1pt} +\def\MG{\copy\MGbox} +\newbox\NNbox % symbol for ## +\setbox\NNbox=\hbox{\kern.5pt\raise2pt\hbox{\#}\kern-4pt + \lower2pt\hbox{\#}\kern.5pt} +\def\NN{\copy\NNbox} +\def\MRL#1{\mathrel{\let\K==#1}} +%\def\MRL#1{\KK#1}\def\KK#1#2{\buildrel\;#1\over{#2}} +\let\GG=\gg +\let\LL=\ll +\let\NULL=\Lambda +\mathchardef\AND="2026 % bitwise and; also \& (unary operator) +\let\OR=\mid % bitwise or +\let\XOR=\oplus % bitwise exclusive or +\def\CM{{\sim}} % bitwise complement +\newbox\MODbox \setbox\MODbox=\hbox{\eightrm\%} +\def\MOD{\mathbin{\copy\MODbox}} +\def\DC{\kern.1em{::}\kern.1em} % symbol for :: +\def\PA{\mathbin{.*}} % symbol for .* +\def\MGA{\mathbin{\MG*}} % symbol for ->* +\def\this{\&{this}} + +\newbox\bak \setbox\bak=\hbox to -1em{} % backspace one em +\newbox\bakk\setbox\bakk=\hbox to -2em{} % backspace two ems + +\newcount\ind % current indentation in ems +\def\1{\global\advance\ind by1\hangindent\ind em} % indent one more notch +\def\2{\global\advance\ind by-1} % indent one less notch +\def\3#1{\hfil\penalty#10\hfilneg} % optional break within a statement +\def\4{\copy\bak} % backspace one notch +\def\5{\hfil\penalty-1\hfilneg\kern2.5em\copy\bakk\ignorespaces}% optional break +\def\6{\ifmmode\else\par % forced break + \hangindent\ind em\noindent\kern\ind em\copy\bakk\ignorespaces\fi} +%\def\7{\Y\6} % forced break and a little extra space +\def\7{\Y\penalty-150\6} % forced break and a little extra space +\def\8{\hskip-\ind em\hskip 2em} % no indentation + +\newcount\gdepth % depth of current major group, plus one +\newcount\secpagedepth +\secpagedepth=3 % page breaks will occur for depths -1, 0, and 1 +\newtoks\gtitle % title of current major group +\newskip\intersecskip \intersecskip=12pt minus 3pt % space between sections +%\let\yskip=\smallskip +\def\yskip{\vskip 5pt plus 1pt minus 1pt} +\def\?{\mathrel?} +\def\note#1#2.{\Y\noindent{\hangindent2em\baselineskip10pt\eightrm#1~#2.\par}} +\def\lapstar{\rlap{*}} +%\def\stsec{\rightskip=0pt % get out of C mode (cf. \B) +% \sfcode`;=1500 \pretolerance 200 \hyphenpenalty 50 \exhyphenpenalty 50 +% \noindent{\let\*=\lapstar\bf\secstar.\quad}} +\def\stsec{\rightskip=0pt % get out of C mode (cf. \B) + \parskip=4pt \parindent=0pt + \sfcode`;=1500 \pretolerance 200 \hyphenpenalty 50 \exhyphenpenalty 50 + \noindent{\let\*=\lapstar\sectionfont\secstar.\quad}} +\let\startsection=\stsec +\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 +% \sfcode`;=3000 +% \pretolerance 10000 +% \hyphenpenalty 9999 % so strings can be broken (discretionary \ is inserted) +% \exhyphenpenalty 10000 +% \global\ind=2 \1\ \unskip} +\def\B{\rightskip=0pt plus 100pt minus 10pt % go into C mode + \parskip=0pt \parindent=1em + \sfcode`;=3000 + \pretolerance 10000 + \hyphenpenalty 9999 % so strings can be broken (discretionary \ is inserted) + \exhyphenpenalty 10000 + \global\ind=2 \1\ \unskip} +%\def\C#1{\5\5\quad$/\ast\,${\cmntfont #1}$\,\ast/$} +\def\C#1{\5\5\hfill$/\ast\,${\cmntfont #1}$\,\ast/$} +\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 +\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 +\def\F{\defin{format}} % format definition +\let\G=\ge % greater than or equal sign +% \H is long Hungarian umlaut accent +\let\I=\ne % unequal sign +\def\J{\.{@\&}} % TANGLE's join operation +\let\K== % assignment operator +%\let\K=\leftarrow % "honest" alternative to standard assignment operator +% \L is Polish letter suppressed-L +%\outer\def\M#1{\MN{#1}\ifon\vfil\penalty-100\vfilneg % beginning of section +% \vskip\intersecskip\startsection\ignorespaces} +\outer\def\M#1{\MN{#1}\ifon\vfil\penalty-100\vfilneg % beginning of section + \vskip\intersecskip\startsection\smallskip\noindent\ignorespaces} +%\outer\def\N#1#2#3.{\gdepth=#1\gtitle={#3}\MN{#2}% beginning of starred section +% \ifon\ifnum#1<\secpagedepth \vfil\eject % force page break if depth is small +% \else\vfil\penalty-100\vfilneg\vskip\intersecskip\fi\fi +% \message{*\secno} % progress report +% \edef\next{\write\cont{\ZZ{#3}{#1}{\secno}% write to contents file +% {\noexpand\the\pageno}}}\next % \ZZ{title}{depth}{sec}{page} +% \ifon\startsection{\bf#3.\quad}\ignorespaces} +\outer\def\N#1#2#3.{\gdepth=#1\gtitle={#3}\MN{#2}% beginning of starred section + \ifon\ifnum#1<\secpagedepth \vfil\eject % force page break if depth is small + \else\vfil\penalty-100\vfilneg\vskip\intersecskip\fi\fi + \message{*\secno} % progress report + \edef\next{\write\cont{\ZZ{#3}{#1}{\secno}% write to contents file + {\noexpand\the\pageno}}}\next % \ZZ{title}{depth}{sec}{page} + \ifon\startsection{\sectionfont#3.}\bigskip\noindent\ignorespaces} +\def\MN#1{\par % common code for \M, \N + {\xdef\secstar{#1}\let\*=\empty\xdef\secno{#1}}% remove \* from section name + \ifx\secno\secstar \onmaybe \else\ontrue \fi + \mark{{{\tensy x}\secno}{\the\gdepth}{\the\gtitle}}} +% each \mark is {section reference or null}{depth plus 1}{group title} +% \O is Scandinavian letter O-with-slash +% \P is paragraph sign +\def\Q{\note{This code is cited in section}} % xref for mention of a section +\def\Qs{\note{This code is cited in sections}} % xref for mentions of a section +%\let\R=\lnot % logical not +\def\R{\mathord ! \,} % logical not +% \S is section sign +\def\T#1{\leavevmode % octal, hex or decimal constant + \hbox{$\def\?{\kern.2em}% + \def\$##1{\egroup_{\,\rm##1}\bgroup}% suffix to constant + \def\_{\cdot 10^{\aftergroup}}% power of ten (via dirty trick) + \let\~=\oct \let\^=\hex {#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 +\let\W=\land % logical and +\def\X#1:#2\X{\ifmmode\gdef\XX{\null$\null}\else\gdef\XX{}\fi % section name + \XX$\langle\,${#2\eightrm\kern.5em#1}$\,\rangle$\XX} +\def\Y{\par\yskip} +\let\Z=\le +\let\ZZ=\let % now you can \write the control sequence \ZZ +\let\*=* + +%\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\vb#1{\leavevmode\hbox{\kern2pt\vrule\vtop{\vbox{\hrule + \hbox{\strut\kern2pt\.{#1}\kern2pt}} + \hrule}\vrule\kern2pt}} % verbatim string + +\def\onmaybe{\let\ifon=\maybe} \let\maybe=\iftrue +\newif\ifon \newif\iftitle \newif\ifpagesaved + +\def\lheader{\mainfont\the\pageno\eightrm\qquad\grouptitle\hfill\title\qquad + \mainfont\topsecno} % top line on left-hand pages +\def\rheader{\mainfont\topsecno\eightrm\qquad\title\hfill\grouptitle + \qquad\mainfont\the\pageno} % top line on right-hand pages +\def\grouptitle{\let\i=I\let\j=J\uppercase\expandafter{\expandafter + \takethree\topmark}} +\def\topsecno{\expandafter\takeone\topmark} +\def\takeone#1#2#3{#1} +\def\taketwo#1#2#3{#2} +\def\takethree#1#2#3{#3} +\def\nullsec{\eightrm\kern-2em} % the \kern-2em cancels \qquad in headers + +\let\page=\pagebody \raggedbottom +% \def\page{\box255 }\normalbottom % faster, but loses plain TeX footnotes +\def\normaloutput#1#2#3{\ifodd\pageno\hoffset=\pageshift\fi + \shipout\vbox{ + \vbox to\fullpageheight{ + \iftitle\global\titlefalse + \else\hbox to\pagewidth{\vbox to10pt{}\ifodd\pageno #3\else#2\fi}\fi + \vfill#1}} % parameter #1 is the page itself + \global\advance\pageno by1} + +\gtitle={\.{CWEB} output} % this running head is reset by starred sections +\mark{\noexpand\nullsec0{\the\gtitle}} +\def\title{\expandafter\uppercase\expandafter{\jobname}} +\def\topofcontents{\centerline{\titlefont\title}\vskip.7in + \vfill} % this material will start the table of contents page +\def\botofcontents{\vfill + \centerline{\covernote}} % this material will end the table of contents page +\def\covernote{} +\def\contentspagenumber{0} % default page number for table of contents +\newdimen\pagewidth \pagewidth=6.5in % the width of each page +\newdimen\pageheight \pageheight=8.7in % the height of each page +\newdimen\fullpageheight \fullpageheight=9in % page height including headlines +\newdimen\pageshift \pageshift=0in % shift righthand pages wrt lefthand ones +\def\magnify#1{\mag=#1\pagewidth=6.5truein\pageheight=8.7truein + \fullpageheight=9truein\setpage} +\def\setpage{\hsize\pagewidth\vsize\pageheight} % use after changing page size +\def\contentsfile{\jobname.toc} % file that gets table of contents info +\def\readcontents{\input \contentsfile} +\def\readindex{\input \jobname.idx} +\def\readsections{\input \jobname.scn} + +\newwrite\cont +\output{\setbox0=\page % the first page is garbage + \openout\cont=\contentsfile + \write\cont{\catcode `\noexpand\@=11\relax} % \makeatletter + \global\output{\normaloutput\page\lheader\rheader}} +\setpage +\vbox to \vsize{} % the first \topmark won't be null + +\def\ch{\note{The following sections were changed by the change file:} + \let\*=\relax} +\newbox\sbox % saved box preceding the index +\newbox\lbox % lefthand column in the index +\def\inx{\par\vskip6pt plus 1fil % we are beginning the index + \def\page{\box255 } \normalbottom + \write\cont{} % ensure that the contents file isn't empty + \write\cont{\catcode `\noexpand\@=12\relax} % \makeatother + \closeout\cont % the contents information has been fully gathered + \output{\ifpagesaved\normaloutput{\box\sbox}\lheader\rheader\fi + \global\setbox\sbox=\page \global\pagesavedtrue} + \pagesavedfalse \eject % eject the page-so-far and predecessors + \setbox\sbox\vbox{\unvbox\sbox} % take it out of its box + \vsize=\pageheight \advance\vsize by -\ht\sbox % the remaining height + \hsize=.5\pagewidth \advance\hsize by -10pt + % column width for the index (20pt between cols) + \parfillskip 0pt plus .6\hsize % try to avoid almost empty lines + \def\lr{L} % this tells whether the left or right column is next + \output{\if L\lr\global\setbox\lbox=\page \gdef\lr{R} + \else\normaloutput{\vbox to\pageheight{\box\sbox\vss + \hbox to\pagewidth{\box\lbox\hfil\page}}}\lheader\rheader + \global\vsize\pageheight\gdef\lr{L}\global\pagesavedfalse\fi} + \message{Index:} + \parskip 0pt plus .5pt + \outer\def\I##1, {\par\hangindent2em\noindent##1:\kern1em} % index entry + \def\[##1]{$\underline{##1}$} % underlined index item + \rm \rightskip0pt plus 2.5em \tolerance 10000 \let\*=\lapstar + \hyphenpenalty 10000 \parindent0pt + \readindex} +\def\fin{\par\vfill\eject % this is done when we are ending the index + \ifpagesaved\null\vfill\eject\fi % output a null index column + \if L\lr\else\null\vfill\eject\fi % finish the current page + \parfillskip 0pt plus 1fil + \def\grouptitle{NAMES OF THE SECTIONS} + \let\topsecno=\nullsec + \message{Section names:} + \output={\normaloutput\page\lheader\rheader} + \setpage + \def\note##1##2.{\quad{\eightrm##1~##2.}} + \def\Q{\note{Cited in section}} % crossref for mention of a section + \def\Qs{\note{Cited in sections}} % crossref for mentions of a section + \def\U{\note{Used in section}} % crossref for use of a section + \def\Us{\note{Used in sections}} % crossref for uses of a section + \def\I{\par\hangindent 2em}\let\*=* + \readsections} +\def\con{\par\vfill\eject % finish the section names +% \ifodd\pageno\else\titletrue\null\vfill\eject\fi % for duplex printers + \rightskip 0pt \hyphenpenalty 50 \tolerance 200 + \setpage \output={\normaloutput\page\lheader\rheader} + \titletrue % prepare to output the table of contents + \pageno=\contentspagenumber + \def\grouptitle{TABLE OF CONTENTS} + \message{Table of contents:} + \topofcontents + \line{\hfil Section\hbox to3em{\hss Page}} + \let\ZZ=\contentsline + \readcontents\relax % read the contents info + \botofcontents \end} % print the contents page(s) and terminate +\def\contentsline#1#2#3#4{\ifnum#2=0 \smallbreak\fi + \line{\consetup{#2}#1 + \rm\leaders\hbox to .5em{.\hfil}\hfil\ #3\hbox to3em{\hss#4}}} +\def\consetup#1{\ifcase#1 \bf % depth -1 (@**) + \or % depth 0 (@*) + \or \hskip2em % depth 1 (@*1) + \or \hskip4em % depth 2 (@*2) + \or \hskip6em % depth 3 (@*3) + \or \hskip8em % depth 4 (@*4) + \or \hskip10em % depth 5 (@*5) + \else \hskip12em \fi} % depth 6 or more +\def\noinx{\let\inx=\end} % no indexes or table of contents +\def\nosecs{\let\FIN=\fin \def\fin{\let\parfillskip=\end \FIN}} + % no index of section names or table of contents +\def\nocon{\let\con=\end} % no table of contents +\def\today{\ifcase\month\or + January\or February\or March\or April\or May\or June\or + July\or August\or September\or October\or November\or December\fi + \space\number\day, \number\year} +\newcount\twodigits +\def\hours{\twodigits=\time \divide\twodigits by 60 \printtwodigits + \multiply\twodigits by-60 \advance\twodigits by\time :\printtwodigits} +\def\gobbleone1{} +\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 +\def\datecontentspage{% + \def\topofcontents{\leftline{\sc\today\ at \hours}\bigskip + \centerline{\titlefont\title}\vfill}} % timestamps the contents page + +\endinput + + +% end of cwebmac.tex diff --git a/web/c_cpp/c2cweb/cweb/cwebmaca.tex b/web/c_cpp/c2cweb/cweb/cwebmaca.tex new file mode 100644 index 0000000000..307063f863 --- /dev/null +++ b/web/c_cpp/c2cweb/cweb/cwebmaca.tex @@ -0,0 +1,381 @@ +% This file is part of c2cweb package Version 1.5 + +% standard macros for CWEB listings (in addition to plain.tex) +% Version 3.0 --- June 1993 + +% modified by Werner Lemberg (a7971428@unet.univie.ac.at) 10-Nov-1996 +% to use with CWEAVE +a + +\ifx\documentstyle\undefined\else\endinput\fi % LaTeX will use other macros +\xdef\fmtversion{\fmtversion+CWEB3.2} + +\let\:=\. % preserve a way to get the dot accent + % (all other accents will still work as usual) + +%\parskip 0pt % no stretch between paragraphs +%\parindent 1em % for paragraphs and for the first line of C text + +\font\ninerm=cmr9 +\let\mc=\ninerm % medium caps +\def\CEE/{{\mc C\spacefactor1000}} +\def\UNIX/{{\mc U\kern-.05emNIX\spacefactor1000}} +\def\TEX/{\TeX} +\def\CPLUSPLUS/{{\mc C\PP\spacefactor1000}} +\def\Cee{\CEE/} % for backward compatibility +\def\9#1{} +\font\eightrm=cmr8 +\let\sc=\eightrm % small caps (NOT a caps-and-small-caps font) +\let\mainfont=\tenrm +\let\cmntfont\tenrm +%\font\tenss=cmss10 \let\cmntfont\tenss % alternative comment font +%\font\titlefont=cmr7 scaled\magstep4 % title on the contents page +\font\titlefont=cmssbx10 scaled\magstep2 % title on the contents page +\font\ttitlefont=cmtt10 scaled\magstep2 % typewriter type in title +\font\tentex=cmtex10 % TeX extended character set (used in strings) +\fontdimen7\tentex=0pt % no double space after sentences + +\font\sectionfont=cmssbx10 scaled\magstephalf + +\def\${\ifmmode \hbox{\sl \char`\$} + \else \hbox{\ifdim \fontdimen1\font > 0pt \sl \fi \char`\$}\fi} + +\def\\#1{\leavevmode\hbox{\it#1\/\kern.05em}} % italic type for identifiers +\def\|#1{\leavevmode\hbox{$#1$}} % one-letter identifiers look better this way +\def\{\leavevmode\hbox{\bf + \def\_{\kern.04em\vbox{\hrule width.3em height .6pt}\kern.08em}% + #1\/\kern.05em}} % boldface type for reserved words +\def\.#1{\leavevmode\hbox{\tentex % typewriter type for strings + \let\\=\BS % backslash in a string + \let\{=\LB % left brace in a string + \let\}=\RB % right brace in a string + \let\~=\TL % tilde in a string + \let\ =\SP % space in a string + \let\_=\UL % underline in a string + \let\&=\AM % ampersand in a string + \let\^=\CF % circumflex in a string + #1\kern.05em}} +\def\){\discretionary{\hbox{\tentex\BS}}{}{}} +\def\AT{@} % at sign for control text (not needed in versions >= 2.9) +\def\ATL{\par\noindent\bgroup\catcode`\_=12 \postATL} % print @l in limbo +\def\postATL#1 #2 {\bf letter \\{\uppercase{\char"#1}} + tangles as \tentex "#2"\egroup\par} +\def\noATL#1 #2 {} +\def\noatl{\let\ATL=\noATL} % suppress output from @l +\def\ATH{\X\kern-.5em:Preprocessor definitions\X} +%\let\PB=\relax % hook for program brackets |...| in TeX part or section name +\def\PB#1{{\def\LBR{\LB}\def\RBR{\RB}#1}} + +\chardef\AM=`\& % ampersand character in a string +\chardef\BS=`\\ % backslash in a string +\chardef\LB=`\{ % left brace in a string +\chardef\RB=`\} % right brace in a string +\def\SP{{\tt\char`\ }} % (visible) space in a string +\chardef\TL=`\~ % tilde in a string +\chardef\UL=`\_ % underline character in a string +\chardef\CF=`\^ % circumflex character in a string + +\newbox\PPbox % symbol for ++ +\setbox\PPbox=\hbox{\kern.5pt\raise1pt\hbox{\sevenrm+\kern-1pt+}\kern.5pt} +\def\PP{\copy\PPbox} +\newbox\MMbox \setbox\MMbox=\hbox{\kern.5pt\raise1pt\hbox{\sevensy\char0 + \kern-1pt\char0}\kern.5pt} +\def\MM{\copy\MMbox} +\newbox\MGbox % symbol for -> +\setbox\MGbox=\hbox{\kern-2pt\lower3pt\hbox{\teni\char'176}\kern1pt} +\def\MG{\copy\MGbox} +\newbox\NNbox % symbol for ## +\setbox\NNbox=\hbox{\kern.5pt\raise2pt\hbox{\#}\kern-4pt + \lower2pt\hbox{\#}\kern.5pt} +\def\NN{\copy\NNbox} +\def\MRL#1{\mathrel{\let\K==#1}} +%\def\MRL#1{\KK#1}\def\KK#1#2{\buildrel\;#1\over{#2}} +\let\GG=\gg +\let\LL=\ll +\let\NULL=\Lambda +\mathchardef\AND="2026 % bitwise and; also \& (unary operator) +\let\OR=\mid % bitwise or +\let\XOR=\oplus % bitwise exclusive or +\def\CM{{\sim}} % bitwise complement +\newbox\MODbox \setbox\MODbox=\hbox{\eightrm\%} +\def\MOD{\mathbin{\copy\MODbox}} +\def\DC{\kern.1em{::}\kern.1em} % symbol for :: +\def\PA{\mathbin{.*}} % symbol for .* +\def\MGA{\mathbin{\MG*}} % symbol for ->* +\def\this{\&{this}} + +\newbox\bak \setbox\bak=\hbox to -1em{} % backspace one em +\newbox\bakk\setbox\bakk=\hbox to -2em{} % backspace two ems + +\newbox\LBRbox \setbox\LBRbox=\hbox to 1em{\hss$\{$} +\newbox\RBRbox \setbox\RBRbox=\hbox to 1em{\hss$\}$} +\def\LBR{\copy\LBRbox} +\def\RBR{\copy\RBRbox} + +\newcount\ind % current indentation in ems +\def\1{\global\advance\ind by1\hangindent\ind em} % indent one more notch +\def\2{\global\advance\ind by-1} % indent one less notch +\def\3#1{\hfil\penalty#10\hfilneg} % optional break within a statement +\def\4{\copy\bak} % backspace one notch +\def\5{\hfil\penalty-1\hfilneg\kern2.5em\copy\bakk\ignorespaces}% optional break +\def\6{\ifmmode\else\par % forced break + \hangindent\ind em\noindent\kern\ind em\copy\bakk\ignorespaces\fi} +%\def\7{\Y\6} % forced break and a little extra space +\def\7{\Y\penalty-150\6} % forced break and a little extra space +\def\8{\hskip-\ind em\hskip 2em} % no indentation + +\newcount\gdepth % depth of current major group, plus one +\newcount\secpagedepth +\secpagedepth=3 % page breaks will occur for depths -1, 0, and 1 +\newtoks\gtitle % title of current major group +\newskip\intersecskip \intersecskip=12pt minus 3pt % space between sections +%\let\yskip=\smallskip +\def\yskip{\vskip 5pt plus 1pt minus 1pt} +\def\?{\mathrel?} +\def\note#1#2.{\Y\noindent{\hangindent2em\baselineskip10pt\eightrm#1~#2.\par}} +\def\lapstar{\rlap{*}} +%\def\stsec{\rightskip=0pt % get out of C mode (cf. \B) +% \sfcode`;=1500 \pretolerance 200 \hyphenpenalty 50 \exhyphenpenalty 50 +% \noindent{\let\*=\lapstar\bf\secstar.\quad}} +\def\stsec{\rightskip=0pt % get out of C mode (cf. \B) + \parskip=4pt \parindent=0pt + \sfcode`;=1500 \pretolerance 200 \hyphenpenalty 50 \exhyphenpenalty 50 + \noindent{\let\*=\lapstar\sectionfont\secstar.\quad}} +\let\startsection=\stsec +\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 +% \sfcode`;=3000 +% \pretolerance 10000 +% \hyphenpenalty 9999 % so strings can be broken (discretionary \ is inserted) +% \exhyphenpenalty 10000 +% \global\ind=2 \1\ \unskip} +\def\B{\rightskip=0pt plus 100pt minus 10pt % go into C mode + \parskip=0pt \parindent=1em + \sfcode`;=3000 + \pretolerance 10000 + \hyphenpenalty 9999 % so strings can be broken (discretionary \ is inserted) + \exhyphenpenalty 10000 + \global\ind=2 \1\ \unskip} +%\def\C#1{\5\5\quad$/\ast\,${\cmntfont #1}$\,\ast/$} +\def\C#1{\5\5\hfill$/\ast\,${\cmntfont #1}$\,\ast/$} +\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 +\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 +\def\F{\defin{format}} % format definition +\let\G=\ge % greater than or equal sign +% \H is long Hungarian umlaut accent +\let\I=\ne % unequal sign +\def\J{\.{@\&}} % TANGLE's join operation +\let\K== % assignment operator +%\let\K=\leftarrow % "honest" alternative to standard assignment operator +% \L is Polish letter suppressed-L +%\outer\def\M#1{\MN{#1}\ifon\vfil\penalty-100\vfilneg % beginning of section +% \vskip\intersecskip\startsection\ignorespaces} +\outer\def\M#1{\MN{#1}\ifon\vfil\penalty-100\vfilneg % beginning of section + \vskip\intersecskip\startsection\smallskip\noindent\ignorespaces} +%\outer\def\N#1#2#3.{\gdepth=#1\gtitle={#3}\MN{#2}% beginning of starred section +% \ifon\ifnum#1<\secpagedepth \vfil\eject % force page break if depth is small +% \else\vfil\penalty-100\vfilneg\vskip\intersecskip\fi\fi +% \message{*\secno} % progress report +% \edef\next{\write\cont{\ZZ{#3}{#1}{\secno}% write to contents file +% {\noexpand\the\pageno}}}\next % \ZZ{title}{depth}{sec}{page} +% \ifon\startsection{\bf#3.\quad}\ignorespaces} +\outer\def\N#1#2#3.{\gdepth=#1\gtitle={#3}\MN{#2}% beginning of starred section + \ifon\ifnum#1<\secpagedepth \vfil\eject % force page break if depth is small + \else\vfil\penalty-100\vfilneg\vskip\intersecskip\fi\fi + \message{*\secno} % progress report + \edef\next{\write\cont{\ZZ{#3}{#1}{\secno}% write to contents file + {\noexpand\the\pageno}}}\next % \ZZ{title}{depth}{sec}{page} + \ifon\startsection{\sectionfont#3.}\bigskip\noindent\ignorespaces} +\def\MN#1{\par % common code for \M, \N + {\xdef\secstar{#1}\let\*=\empty\xdef\secno{#1}}% remove \* from section name + \ifx\secno\secstar \onmaybe \else\ontrue \fi + \mark{{{\tensy x}\secno}{\the\gdepth}{\the\gtitle}}} +% each \mark is {section reference or null}{depth plus 1}{group title} +% \O is Scandinavian letter O-with-slash +% \P is paragraph sign +\def\Q{\note{This code is cited in section}} % xref for mention of a section +\def\Qs{\note{This code is cited in sections}} % xref for mentions of a section +%\let\R=\lnot % logical not +\def\R{\mathord ! \,} % logical not +% \S is section sign +\def\T#1{\leavevmode % octal, hex or decimal constant + \hbox{$\def\?{\kern.2em}% + \def\$##1{\egroup_{\,\rm##1}\bgroup}% suffix to constant + \def\_{\cdot 10^{\aftergroup}}% power of ten (via dirty trick) + \let\~=\oct \let\^=\hex {#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 +\let\W=\land % logical and +\def\X#1:#2\X{\ifmmode\gdef\XX{\null$\null}\else\gdef\XX{}\fi % section name + \XX$\langle\,${#2\eightrm\kern.5em#1}$\,\rangle$\XX} +\def\Y{\par\yskip} +\let\Z=\le +\let\ZZ=\let % now you can \write the control sequence \ZZ +\let\*=* + +%\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\vb#1{\leavevmode\hbox{\kern2pt\vrule\vtop{\vbox{\hrule + \hbox{\strut\kern2pt\.{#1}\kern2pt}} + \hrule}\vrule\kern2pt}} % verbatim string + +\def\onmaybe{\let\ifon=\maybe} \let\maybe=\iftrue +\newif\ifon \newif\iftitle \newif\ifpagesaved + +\def\lheader{\mainfont\the\pageno\eightrm\qquad\grouptitle\hfill\title\qquad + \mainfont\topsecno} % top line on left-hand pages +\def\rheader{\mainfont\topsecno\eightrm\qquad\title\hfill\grouptitle + \qquad\mainfont\the\pageno} % top line on right-hand pages +\def\grouptitle{\let\i=I\let\j=J\uppercase\expandafter{\expandafter + \takethree\topmark}} +\def\topsecno{\expandafter\takeone\topmark} +\def\takeone#1#2#3{#1} +\def\taketwo#1#2#3{#2} +\def\takethree#1#2#3{#3} +\def\nullsec{\eightrm\kern-2em} % the \kern-2em cancels \qquad in headers + +\let\page=\pagebody \raggedbottom +% \def\page{\box255 }\normalbottom % faster, but loses plain TeX footnotes +\def\normaloutput#1#2#3{\ifodd\pageno\hoffset=\pageshift\fi + \shipout\vbox{ + \vbox to\fullpageheight{ + \iftitle\global\titlefalse + \else\hbox to\pagewidth{\vbox to10pt{}\ifodd\pageno #3\else#2\fi}\fi + \vfill#1}} % parameter #1 is the page itself + \global\advance\pageno by1} + +\gtitle={\.{CWEB} output} % this running head is reset by starred sections +\mark{\noexpand\nullsec0{\the\gtitle}} +\def\title{\expandafter\uppercase\expandafter{\jobname}} +\def\topofcontents{\centerline{\titlefont\title}\vskip.7in + \vfill} % this material will start the table of contents page +\def\botofcontents{\vfill + \centerline{\covernote}} % this material will end the table of contents page +\def\covernote{} +\def\contentspagenumber{0} % default page number for table of contents +\newdimen\pagewidth \pagewidth=6.5in % the width of each page +\newdimen\pageheight \pageheight=8.7in % the height of each page +\newdimen\fullpageheight \fullpageheight=9in % page height including headlines +\newdimen\pageshift \pageshift=0in % shift righthand pages wrt lefthand ones +\def\magnify#1{\mag=#1\pagewidth=6.5truein\pageheight=8.7truein + \fullpageheight=9truein\setpage} +\def\setpage{\hsize\pagewidth\vsize\pageheight} % use after changing page size +\def\contentsfile{\jobname.toc} % file that gets table of contents info +\def\readcontents{\input \contentsfile} +\def\readindex{\input \jobname.idx} +\def\readsections{\input \jobname.scn} + +\newwrite\cont +\output{\setbox0=\page % the first page is garbage + \openout\cont=\contentsfile + \write\cont{\catcode `\noexpand\@=11\relax} % \makeatletter + \global\output{\normaloutput\page\lheader\rheader}} +\setpage +\vbox to \vsize{} % the first \topmark won't be null + +\def\ch{\note{The following sections were changed by the change file:} + \let\*=\relax} +\newbox\sbox % saved box preceding the index +\newbox\lbox % lefthand column in the index +\def\inx{\par\vskip6pt plus 1fil % we are beginning the index + \def\page{\box255 } \normalbottom + \write\cont{} % ensure that the contents file isn't empty + \write\cont{\catcode `\noexpand\@=12\relax} % \makeatother + \closeout\cont % the contents information has been fully gathered + \output{\ifpagesaved\normaloutput{\box\sbox}\lheader\rheader\fi + \global\setbox\sbox=\page \global\pagesavedtrue} + \pagesavedfalse \eject % eject the page-so-far and predecessors + \setbox\sbox\vbox{\unvbox\sbox} % take it out of its box + \vsize=\pageheight \advance\vsize by -\ht\sbox % the remaining height + \hsize=.5\pagewidth \advance\hsize by -10pt + % column width for the index (20pt between cols) + \parfillskip 0pt plus .6\hsize % try to avoid almost empty lines + \def\lr{L} % this tells whether the left or right column is next + \output{\if L\lr\global\setbox\lbox=\page \gdef\lr{R} + \else\normaloutput{\vbox to\pageheight{\box\sbox\vss + \hbox to\pagewidth{\box\lbox\hfil\page}}}\lheader\rheader + \global\vsize\pageheight\gdef\lr{L}\global\pagesavedfalse\fi} + \message{Index:} + \parskip 0pt plus .5pt + \outer\def\I##1, {\par\hangindent2em\noindent##1:\kern1em} % index entry + \def\[##1]{$\underline{##1}$} % underlined index item + \rm \rightskip0pt plus 2.5em \tolerance 10000 \let\*=\lapstar + \hyphenpenalty 10000 \parindent0pt + \readindex} +\def\fin{\par\vfill\eject % this is done when we are ending the index + \ifpagesaved\null\vfill\eject\fi % output a null index column + \if L\lr\else\null\vfill\eject\fi % finish the current page + \parfillskip 0pt plus 1fil + \def\grouptitle{NAMES OF THE SECTIONS} + \let\topsecno=\nullsec + \message{Section names:} + \output={\normaloutput\page\lheader\rheader} + \setpage + \def\note##1##2.{\quad{\eightrm##1~##2.}} + \def\Q{\note{Cited in section}} % crossref for mention of a section + \def\Qs{\note{Cited in sections}} % crossref for mentions of a section + \def\U{\note{Used in section}} % crossref for use of a section + \def\Us{\note{Used in sections}} % crossref for uses of a section + \def\I{\par\hangindent 2em}\let\*=* + \readsections} +\def\con{\par\vfill\eject % finish the section names +% \ifodd\pageno\else\titletrue\null\vfill\eject\fi % for duplex printers + \rightskip 0pt \hyphenpenalty 50 \tolerance 200 + \setpage \output={\normaloutput\page\lheader\rheader} + \titletrue % prepare to output the table of contents + \pageno=\contentspagenumber + \def\grouptitle{TABLE OF CONTENTS} + \message{Table of contents:} + \topofcontents + \line{\hfil Section\hbox to3em{\hss Page}} + \let\ZZ=\contentsline + \readcontents\relax % read the contents info + \botofcontents \end} % print the contents page(s) and terminate +\def\contentsline#1#2#3#4{\ifnum#2=0 \smallbreak\fi + \line{\consetup{#2}#1 + \rm\leaders\hbox to .5em{.\hfil}\hfil\ #3\hbox to3em{\hss#4}}} +\def\consetup#1{\ifcase#1 \bf % depth -1 (@**) + \or % depth 0 (@*) + \or \hskip2em % depth 1 (@*1) + \or \hskip4em % depth 2 (@*2) + \or \hskip6em % depth 3 (@*3) + \or \hskip8em % depth 4 (@*4) + \or \hskip10em % depth 5 (@*5) + \else \hskip12em \fi} % depth 6 or more +\def\noinx{\let\inx=\end} % no indexes or table of contents +\def\nosecs{\let\FIN=\fin \def\fin{\let\parfillskip=\end \FIN}} + % no index of section names or table of contents +\def\nocon{\let\con=\end} % no table of contents +\def\today{\ifcase\month\or + January\or February\or March\or April\or May\or June\or + July\or August\or September\or October\or November\or December\fi + \space\number\day, \number\year} +\newcount\twodigits +\def\hours{\twodigits=\time \divide\twodigits by 60 \printtwodigits + \multiply\twodigits by-60 \advance\twodigits by\time :\printtwodigits} +\def\gobbleone1{} +\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 +\def\datecontentspage{% + \def\topofcontents{\leftline{\sc\today\ at \hours}\bigskip + \centerline{\titlefont\title}\vfill}} % timestamps the contents page + +\endinput + +% end of cwebmaca.tex diff --git a/web/c_cpp/c2cweb/cweb/prod-alt.w b/web/c_cpp/c2cweb/cweb/prod-alt.w new file mode 100644 index 0000000000..f7849d830a --- /dev/null +++ b/web/c_cpp/c2cweb/cweb/prod-alt.w @@ -0,0 +1,303 @@ +% This file is part of CWEB. +% This program by Silvio Levy and Donald E. Knuth +% is based on a program by Knuth. +% It is distributed WITHOUT ANY WARRANTY, express or implied. +% Version 3.0 --- June 1993 + +% this file is part of the c2cweb package Version 1.5 +% modified by Werner Lemberg (a7971428@@unet.univie.ac.at) 10-Nov-1996 + +@ +\def\v{\char'174} +\mathchardef\RA="3221 % right arrow +\mathchardef\BA="3224 % double arrow +Here is a table of all the productions if you use the \.{a} switch. +Each production that combines two or more consecutive scraps implicitly +inserts a {\tt \$} where necessary, that is, between scraps whose abutting +boundaries have different |mathness|. In this way we never get double +{\tt\$\$}. + +A translation is provided when the resulting scrap is not merely a +juxtaposition of the scraps it comes from. An asterisk$^*$ next to a scrap +means that its first identifier gets an underlined entry in the index, +via the function |make_underlined|. Two asterisks$^{**}$ means that both +|make_underlined| and |make_reserved| are called; that is, the +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. + +\begingroup \lineskip=4pt +\def\alt #1 #2 +{$\displaystyle\Bigl\{\!\matrix{\strut\hbox{#1}\cr + \strut\hbox{#2}\cr}\!\Bigr\}$ } +\def\altt #1 #2 #3 +{$\displaystyle\Biggl\{\!\matrix{\strut\hbox{#1}\cr\hbox{#2}\cr + \strut\hbox{#3}\cr}\!\Biggr\}$ } +\def\altq #1 #2 #3 #4 +{$\displaystyle\left\{\!\matrix{\strut\hbox{#1}\cr\hbox{#2}\cr + \hbox{#3}\cr\strut\hbox{#4}\cr}\!\right\}$ } +\def\malt #1 #2 +{$\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 + \strut\hbox{#3}\hfill\cr}$} +\yskip\newcount\prodno\prodno=0 +\newdimen\midcol \midcol=2.5in +\def\theprodno{\number\prodno \global\advance\prodno by1\enspace} +\def\+#1\cr{\def\next{#1}% + \line{\hbox to 2em{\hss + \ifx\next\empty\theprodno\else\next\fi}\strut + \ignorespaces#2\hfil\hbox to\midcol{$\RA$ + \ignorespaces#3\hfil}\quad \hbox to1.45in{\ignorespaces#4\hfil}}} +\+\relax & LHS & RHS \hfill Translation & Example\cr +\yskip +\+& \altt\\{any} {\\{any} \\{any}} {\\{any} \\{any} \\{any}} +|insert| & \altt\\{any} {\\{any} \\{any}} {\\{any} \\{any} \\{any}} +& stmt; \ /$\ast\,$comment$\,*$/\cr +\+& |exp| \altt|lbrace| |int_like| |decl| + & |fn_decl| \altt|lbrace| |int_like| |decl| + \hfill $F=E^*\,|in|\,|in|$ & \malt {\\{main}()$\{$} + {\\{main}$(\\{ac},\\{av})$ \&{int} \\{ac};} \cr +\+& |exp| |unop| & |exp| & |x++|\cr +\+& |exp| \alt |binop| |unorbinop| |exp| & |exp| & \malt {|x/y|} {|x+y|} \cr +\+& |exp| |comma| |exp| & |exp| \hfill $EC\,|opt|9\,E$& |f(x,y)|\cr +\+& |exp| \alt |exp| |cast| & |exp| & |time()|\cr +\+& |exp| |semi| & |stmt| & |x=0;|\cr +\+& |exp| |colon| & |label| \hfill $E^*C$ & |found:|\cr +\+& |exp| |base| |int_like| |comma| & |base| \hfill $B\.\ IC$\,|opt|9 + & \&D : \&C,\cr +\+& |exp| |base| |int_like| |lbrace| & |exp| |lbrace| \hfill + $E=E\.\ B\.\ I$ & \&D : \&C $\{$\cr +\+& |exp| |rbrace| & |stmt| |rbrace| & end of \&{enum} list\cr +\+& |lpar| \alt |exp| |unorbinop| |rpar| & |exp| & \malt{|(x)|} {|(*)|} \cr +\+& |lpar| |rpar| & |exp| \hfill $L\.{\\,}R$ & functions, declarations\cr +\+& |lpar| \alt |decl_head| |int_like| |rpar| & |cast| & |(char*)|\cr +\+& |lpar| \altt |decl_head| |int_like| |exp| |comma| & |lpar| \hfill + L\,\altt $D$ $I$ $E$ C\,|opt|9 & |(int,|\cr +\+& |lpar| \alt |stmt| |decl| & |lpar| \hfill \alt {$LS\.\ $} {$LD\.\ $} & + \alt {|(k=5;|} {|(int k=5;|} \cr +\+& |question| |exp| |colon| & |binop| & |?x:|\cr +\+& |unop| \alt |exp| |int_like| & \alt |exp| |int_like| & + \malt |!x| |~|\&C \cr +\+& |unorbinop| \alt|exp| |int_like| & \alt|exp| |int_like| \hfill + $\.\{U\.\}E$ & |*x|\cr +\+& |unorbinop| |binop| & |binop| \hfill $|math_rel|\,U\.\{B\.\}\.\}$ & |*=|\cr +\+& |binop| |binop| & |binop| \hfill + $|math_rel|\,\.\{B_1\.\}\.\{B_2\.\}\.\}$ & |>>=|\cr +\+& |cast| |exp| & |exp| \hfill $C\.\ E$ & |(double)x|\cr +\+& |cast| |semi| & |exp| |semi| & |(int);|\cr +\+& |sizeof_like| |cast| & |exp| & |sizeof (double)|\cr +\+& |sizeof_like| |exp| & |exp| \hfill $S\.\ E$ & |sizeof x|\cr +\+& |int_like| \alt|int_like| |struct_like| & + \alt|int_like| |struct_like| \hfill $I\.\ $\alt $I$ $S$ + \unskip& |extern char|\cr +\+& |int_like| |exp| \alt|raw_int| |struct_like| & + |int_like| \alt|int_like| |struct_like| & |extern "Ada" int|\cr +\+& |int_like| \altt|exp| |unorbinop| |semi| & |decl_head| + \altt|exp| |unorbinop| |semi| \hfill + $D=I$\altt{\.\ } {\.\ } {} \unskip & |int x|\cr +\+& |int_like| |colon| & |decl_head| |colon| \hfill $D=I\.\ $ & |unsigned:|\cr +\+& |int_like| |prelangle| & |int_like| |langle| & \&C$\langle$\cr +\+& |int_like| |colcol| \alt |exp| |int_like| & \alt |exp| |int_like| & + \malt {\&C\DC$x$} {\&C\DC\&B} \cr +\+& |int_like| |cast| |lbrace| & |fn_decl| |lbrace| \hfill $IC\,|in|\,|in|$& + \&C$\langle\&{void}\ast\rangle\{$\cr +\+& |int_like| |cast| & |int_like| & \&C$\langle\&{class}\ \&T\rangle$\cr +\+& |decl_head| |comma| & |decl_head| \hfill $DC\.\ $ & |int x,|\cr +\+& |decl_head| |unorbinop| & |decl_head| \hfill $D\.\{U\.\}$ & |int *|\cr +\+\dag\theprodno& |decl_head| |exp| & |decl_head| \hfill $DE^*$ & |int x|\cr +\+& |decl_head| \alt|binop| |colon| |exp| \altt|comma| |semi| |rpar| & + |decl_head| \altt|comma| |semi| |rpar| \hfill + $D=D$\alt $B$ $C$ \unskip$E$ & \maltt initialization {fields or} + {default argument} \cr +\+& |decl_head| |cast| & |decl_head| & |int f(int)|\cr +\+\dag\theprodno& |decl_head| \altt|int_like| |lbrace| |decl| & |fn_decl| + \altt|int_like| |lbrace| |decl| \hfill $F=D\,|in|\,|in|$ + & |long time () {|\cr +\+& |decl_head| |semi| & |decl| & |int n;|\cr +\+& |decl| |decl| & |decl| \hfill $D\,|force|\,D$ & |int n;double x;|\cr +\+& |decl| \alt|stmt| |function| & \alt|stmt| |function| + \hfill $D\,|big_force|\,$\alt $S$ $F$ \unskip& \&{extern} $n$; + \\{main} ()|{}|\cr +\+\dag\theprodno& |typedef_like| |decl_head| \alt|exp| |int_like| & + |typedef_like| |decl_head| \hfill $D=D$\alt $E^{**}$ $I^{**}$ \unskip & + \&{typedef} \&{char} \&{ch};\cr +\+& |typedef_like| |decl_head| |semi| & |decl| \hfill $T\.\ D$ & + \&{typedef} \&{int} $\&x,\&y$;\cr +\+& |struct_like| |lbrace| & |struct_head| \hfill + $S\,\\{in}\,|force|\\{back}\,L$ & |struct {|\cr +\+& |struct_like| \alt|exp| |int_like| |semi| & |decl_head| + \hfill $S\.\ $\alt $E^{**}$ $I^{**}$ & \&{struct} \&{forward};\cr +\+& |struct_like| \alt|exp| |int_like| |lbrace| & |struct_head| \hfill + $S\.\ $\alt $E^{**}$ $I^{**}$ \unskip $\\{in}\,|force|\,\\{back}\,L$ & + \&{struct} \&{name\_info} $\{$\cr +\+& |struct_like| \alt|exp| |int_like| |colon| & + |struct_like| \alt|exp| |int_like| |base| & |class| \&C :\cr +\+\dag\theprodno& |struct_like| \alt|exp| |int_like| & |int_like| + \hfill $S\.\ $\alt$E$ $I$ & \&{struct} \&{name\_info} $z$;\cr +\+& |struct_head| \altt|decl| |stmt| |function| |rbrace| & |int_like|\hfill + $SD\,|force|\,\\{back}\,R\,\.\ |out|$ & + |struct {| declaration |}|\cr +\+& |struct_head| |rbrace| & |int_like|\hfill $S\.{\\,}R$ & |class C{}|\cr +\+& |fn_decl| |decl| & |fn_decl| \hfill $F\,|force|\,D$ + & $f(z)$ \&{double} $z$; \cr +\+& |fn_decl| |stmt| & |function| \hfill $F\,|out|\,|out|\,|force|\,S$ + & \\{main}() {\dots}\cr +\+& |function| \altt|stmt| |decl| |function| & \altt |stmt| |decl| |function| + \hfill $F\,|big_force|\,$\altt $S$ $D$ $F$ & outer block\cr +\+& |lbrace| |rbrace| & |stmt| \hfill $L\.{\\,}R$ & empty statement\cr +\advance\midcol15pt +\+& |lbrace| \altt|stmt| |decl| |function| |rbrace| & |stmt| \hfill + $\matrix{\\{in}\,|force|\,\\{back}\,L\,|noop|\,|cancel|\,S\cr + |force|\,\\{back}\,R\,\\{out}\,|force|}$ & compound statement\cr +\+& |lbrace| |exp| [|comma|] |rbrace| & |exp| & initializer\cr +\+& |if_like| |exp| & |if_clause| \hfill $I\.{\ }E$ & |if (z)|\cr +\+& |for_like| |exp| & |else_like| \hfill $F\.{\ }E$ & |while (1)|\cr +\+& |else_like| |lbrace| & |else_head| |lbrace| & \&{else} $\{$\cr +\+& |else_like| |stmt| & |stmt| \hfill + $|force|\,E\,\\{in}\,|force|\,S\,\\{out}\,|force|$ & |else x=0;|\cr +\+& |else_head| \alt|stmt| |exp| & |stmt| \hfill + $|force|\,E\,\\{bsp}\,S\,\\{force}$ & |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}\,|force|\,S\,\\{out}\,|force|\,E\,\.\ I$ & + |if (x) y; else if|\cr +\+& |if_clause| |stmt| |else_like| & |else_like| \hfill + $|force|\,I\,\\{in}\,|force|\,S\,\\{out}\,|force|\,E$ & + |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}\,S\,|force|\,E\,\.\ I$ & + |if (x){y;}else if|\cr +\+& |if_head| \alt|stmt| |exp| |else_like| & |else_like| \hfill + $|force|\,I\,\\{bsp}\,S\,|force|\,E$ & + |if (x){y;}else|\cr +\+& |if_head| \alt|stmt| |exp| & |else_head| \alt|stmt| |exp| & |if (x){y;}|\cr +\+& |do_like| |stmt| |else_like| |semi| & |stmt| \hfill + $\matrix{|force|\,D\,\\{in}\,|force|\,S\,|cancel|\,|noop|\cr + \,\\{bsp}\,ES\,\\{out}\,|force|}$ & |do f(x); while (g(x));|\cr +\+& |case_like| |semi| & |stmt| & |return;|\cr +\+& |case_like| |colon| & |tag| & |default:|\cr +\+& |case_like| |exp| |semi| & |stmt| \hfill $C\.\ ES$ & |return 0;|\cr +\+& |case_like| |exp| |colon| & |tag| \hfill $C\.\ EC$ & |case 0:|\cr +\+& |tag| |tag| & |tag| \hfill $T_1\,|force|\,T_2$ & |case 0: case 1:|\cr +\advance\midcol20pt +\+& |tag| \altt|stmt| |decl| |function| \alt|rbrace| |tag| + & \altt|stmt| |decl| |function| \alt|rbrace| |tag| + \hfill $|force|\,T\,\\{in}\,|force|\,S\,\\{out}$ & |case 0: z=0;|\cr +\advance\midcol-20pt +\+\dag\theprodno& |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 +\+\dag\theprodno& |lproc| \altt |if_like| |else_like| |define_like| & |lproc| & + \maltt {{\bf \#include}} {\bf\#else} {\bf\#define} \cr +\+& |lproc| |rproc| & |insert| & {\bf\#endif} \cr +\+\dag\theprodno& |lproc| \altt|exp| |function| |int_like| |rproc| & + |insert| \hfill + $I$\.\ \altt {$E$} {$F$} {$I$} & {\bf\#define} $a$\enspace 1 \cr +\+& |section_scrap| |semi| & |stmt|\hfill $MS$ |force| + &$\langle\,$section name$\,\rangle$;\cr +\+& |section_scrap| & |exp| &$\langle\,$section name$\,\rangle$\cr +\+& |insert| |any| & |any| & \.{\v\#include\v}\cr +\+& |prelangle| & |binop| \hfill $<$ & $<$ not in template\cr +\+& |prerangle| & |binop| \hfill $>$ & $>$ not in template\cr +\+& |langle| |exp| |prerangle| & |cast| & $\langle\,0\,\rangle$\cr +\+& |langle| |prerangle| & |cast| \hfill $L\.{\\,}P$ & $\langle\,\rangle$\cr +\+& |langle| \alt|decl_head| |int_like| |prerangle| & |cast| & + $\langle\&{class}\,\&C\rangle$\cr +\+& |langle| \alt|decl_head| |int_like| |comma| & |langle| \hfill + L\,\alt $D$ $I$ C\,|opt|9 & $\langle\&{class}\,\&C,$\cr +\+& |public_like| |colon| & |tag| & \&{private}:\cr +\+& |public_like| & |int_like| & \&{private}\cr +\+& |colcol| \alt|exp| |int_like| & \alt|exp| |int_like| & |::x|\cr +\+\dag\theprodno& + |new_like| \alt|exp| |raw_int| & |new_like| \hfill $N\.\ E$ & |new(1)|\cr +\+& |new_like| \alt|raw_unorbin| |colcol| & |new_like| & |new ::*|\cr +\+& |new_like| |cast| & |exp| & |new(*)|\cr +\+\dag\theprodno& |new_like| & |exp| & |new|\cr +\+\dag\theprodno& |operator_like| \altq|binop| |unop| |unorbinop| |raw_unorbin| + & |exp| \hfill $O$\.\{\altq $B$ $U$ $U$ $R$ \unskip \.\} & |operator+|\cr +\+& |operator_like| \alt|new_like| |sizeof_like| & |exp| \hfill $O\.\ N$ + & |operator delete|\cr +\+& |operator_like| & |new_like| & conversion operator\cr +\+& |catch_like| \alt|cast| |exp| & |fn_decl| \hfill $CE\,\\{in}\,\\{in}$ & + |catch (...)|\cr +\+& |base| |public_like| |exp| |comma| & |base| \hfill $BP\.\ EC$ & + : \&{public} $a$,\cr +\+& |base| |public_like| |exp| & |base| |int_like| \hfill $I=P\.\ E$ & + : \&{public} $a$\cr +\+& |raw_rpar| |const_like| & |raw_rpar| \hfill $R\.\ C$ & ) \&{const};\cr +\+& |raw_rpar| & |rpar| & );\cr +\+& |raw_unorbin| |const_like| & |raw_unorbin| \hfill $RC$\.{\\\ } + & $*$\&{const} |x|\cr +\+& |raw_unorbin| & |unorbinop| & $*$ |x|\cr +\+& |const_like| & |int_like| & \&{const} |x|\cr +\+& |raw_int| |lpar| & |exp| |lpar| & \&{complex}$(x,y)$\cr +\+& |raw_int| & |int_like| & \&{complex} |z|\cr +\+& |begin_arg| |end_arg| & |exp| & \.{@@[}\&{char}$*$\.{@@]}\cr +\+& |any_other| |end_arg| & |end_arg| & \&{char}$*$\.{@@]}\cr +\+& |label| |label| & |label| \hfill $L_1\,|force|\,L_2$ & cf. tags\cr +\+& |label| \altt|stmt| |decl| |function| & \altt|stmt| |decl| |function| + \hfill $\matrix{|cancel|\,|noop|\,\\{out}\,\\{out}\,|force|\cr + L\,\\{in}\,\\{in}\,|force|\,S}$ & cf. tags\cr +\+& |do_like| |lbrace| & |do_head| |lbrace| & \&{do} $\{$ \cr +\+& |do_head| |stmt| |else_like| |semi| & |stmt| \hfill + $D\,\\{bsp}\,S\,|cancel|\,|noop|\,\\{bsp}\,ES$ & |do {x;} while(y);|\cr +\+\dag\theprodno& |typedef_like| |exp| & |typedef_like| |raw_int| & + \&{typedef} \&{?} \&{type} \cr +\+& |int_like| |binop| |exp| & |int_like| & ? (\CPLUSPLUS/)\cr +\+& |operator_like| \altt|raw_int| |int_like| |const_like| & + |operator_like| \hfill $O$\.{\ }$R$ & \&{operator} \&{name\_info} \cr +\+\dag\theprodno& |lproc| \altt|exp| |int_like| |const_like| |pp_space| & + |lproc| \hfill $I\.\ E\.{\ \\5}$ & {\bf\#define} $a$ $\ldots$ \cr +\+& |lproc| |exp| |exp| |pp_space| & |lproc| \hfill $I\.\ E_1 E_2\.{\ \\5}$ + & {\bf\#define} $a(b)$ $\ldots$\cr +\yskip +\yskip +\yskip +\parindent=0pt +\dag{\bf Notes} +\yskip +Rule 35: The |exp| must not be immediately followed by |lpar| or~|exp|. + +Rule 38: The |int_like| must not be immediately followed by |colcol|. + +Rule 42: The |exp| must not be immediately followed by |lpar| or~|exp|. + +Rule 48: The |exp| or |int_like| must not be immediately followed by |base|, +|raw_int|, |int_like|, or |const_like|. + +Rule 76: The |force| in the |stmt| line becomes \\{bsp} if \.{CWEAVE} has +been invoked with the \.{-f} option. + +Rule 78: The |define_like| case calls |make_underlined| on the following scrap. + +Rule 80: Makes the scrap following |lproc| reserved without changing the +category. + +Rule 93: The |raw_int| must not be immediately followed by +|prelangle| or |langle|. + +Rule 96: The |new_like| must not be immediately followed by |lpar|, +|raw_int|, or |struct_like|. + +Rule 97: The operator after |operator_like| +must not be immediately followed by a |binop|. + +Rule 116: This rule only holds outside of {\bf\#define} lines; |exp| must not +be followed by a |lpar|. + +Rule 119: Makes the scrap following |lproc| reserved using the category +of the scrap following |pp_space| if this scrap is |int_like|, |const_like|, +or |raw_int|. + +\endgroup + + +@q end of prod-alt.w @> |