From e0c6872cf40896c7be36b11dcc744620f10adf1d Mon Sep 17 00:00:00 2001 From: Norbert Preining Date: Mon, 2 Sep 2019 13:46:59 +0900 Subject: Initial commit --- web/c_cpp/cweb/Makefile | 197 ++ web/c_cpp/cweb/README | 110 + web/c_cpp/cweb/c++lib.w | 85 + web/c_cpp/cweb/comm-amiga.ch | 17 + web/c_cpp/cweb/comm-bs.ch | 229 +++ web/c_cpp/cweb/comm-mac.ch | 150 ++ web/c_cpp/cweb/comm-man.ch | 22 + web/c_cpp/cweb/comm-os2.ch | 24 + web/c_cpp/cweb/comm-pc.ch | 33 + web/c_cpp/cweb/comm-ql.ch | 332 +++ web/c_cpp/cweb/comm-vms.ch | 81 + web/c_cpp/cweb/comm-w32.ch | 94 + web/c_cpp/cweb/common.c | 1242 +++++++++++ web/c_cpp/cweb/common.h | 193 ++ web/c_cpp/cweb/common.w | 1418 +++++++++++++ web/c_cpp/cweb/ctang-bs.ch | 202 ++ web/c_cpp/cweb/ctang-man.ch | 22 + web/c_cpp/cweb/ctang-pc.ch | 24 + web/c_cpp/cweb/ctang-ql.ch | 25 + web/c_cpp/cweb/ctang-vms.ch | 35 + web/c_cpp/cweb/ctang-w32.ch | 66 + web/c_cpp/cweb/ctangle.c | 1579 ++++++++++++++ web/c_cpp/cweb/ctangle.w | 1557 ++++++++++++++ web/c_cpp/cweb/cweav-bs.ch | 302 +++ web/c_cpp/cweb/cweav-man.ch | 22 + web/c_cpp/cweb/cweav-pc.ch | 39 + web/c_cpp/cweb/cweav-ql.ch | 32 + web/c_cpp/cweb/cweav-vms.ch | 37 + web/c_cpp/cweb/cweav-w32.ch | 52 + web/c_cpp/cweb/cweave.w | 4652 ++++++++++++++++++++++++++++++++++++++++++ web/c_cpp/cweb/cweb.1 | 138 ++ web/c_cpp/cweb/cweb.el | 218 ++ web/c_cpp/cweb/cwebmac.tex | 553 +++++ web/c_cpp/cweb/cwebman.tex | 1763 ++++++++++++++++ web/c_cpp/cweb/makefile.bs | 60 + web/c_cpp/cweb/prod.w | 307 +++ web/c_cpp/cweb/readme.ql | 84 + 37 files changed, 15996 insertions(+) create mode 100644 web/c_cpp/cweb/Makefile create mode 100644 web/c_cpp/cweb/README create mode 100644 web/c_cpp/cweb/c++lib.w create mode 100644 web/c_cpp/cweb/comm-amiga.ch create mode 100644 web/c_cpp/cweb/comm-bs.ch create mode 100644 web/c_cpp/cweb/comm-mac.ch create mode 100644 web/c_cpp/cweb/comm-man.ch create mode 100644 web/c_cpp/cweb/comm-os2.ch create mode 100644 web/c_cpp/cweb/comm-pc.ch create mode 100644 web/c_cpp/cweb/comm-ql.ch create mode 100644 web/c_cpp/cweb/comm-vms.ch create mode 100644 web/c_cpp/cweb/comm-w32.ch create mode 100644 web/c_cpp/cweb/common.c create mode 100644 web/c_cpp/cweb/common.h create mode 100644 web/c_cpp/cweb/common.w create mode 100644 web/c_cpp/cweb/ctang-bs.ch create mode 100644 web/c_cpp/cweb/ctang-man.ch create mode 100644 web/c_cpp/cweb/ctang-pc.ch create mode 100644 web/c_cpp/cweb/ctang-ql.ch create mode 100644 web/c_cpp/cweb/ctang-vms.ch create mode 100644 web/c_cpp/cweb/ctang-w32.ch create mode 100644 web/c_cpp/cweb/ctangle.c create mode 100644 web/c_cpp/cweb/ctangle.w create mode 100644 web/c_cpp/cweb/cweav-bs.ch create mode 100644 web/c_cpp/cweb/cweav-man.ch create mode 100644 web/c_cpp/cweb/cweav-pc.ch create mode 100644 web/c_cpp/cweb/cweav-ql.ch create mode 100644 web/c_cpp/cweb/cweav-vms.ch create mode 100644 web/c_cpp/cweb/cweav-w32.ch create mode 100644 web/c_cpp/cweb/cweave.w create mode 100644 web/c_cpp/cweb/cweb.1 create mode 100644 web/c_cpp/cweb/cweb.el create mode 100644 web/c_cpp/cweb/cwebmac.tex create mode 100644 web/c_cpp/cweb/cwebman.tex create mode 100644 web/c_cpp/cweb/makefile.bs create mode 100644 web/c_cpp/cweb/prod.w create mode 100644 web/c_cpp/cweb/readme.ql (limited to 'web/c_cpp/cweb') diff --git a/web/c_cpp/cweb/Makefile b/web/c_cpp/cweb/Makefile new file mode 100644 index 0000000000..1367d00892 --- /dev/null +++ b/web/c_cpp/cweb/Makefile @@ -0,0 +1,197 @@ +# This file is part of CWEB. +# It is distributed WITHOUT ANY WARRANTY, express or implied. +# Version 3.64 --- February 2002 + +# Copyright (C) 1987,1990,1993,2000 Silvio Levy and Donald E. Knuth + +# Permission is granted to make and distribute verbatim copies of this +# document provided that the copyright notice and this permission notice +# are preserved on all copies. + +# Permission is granted to copy and distribute modified versions of this +# document under the conditions for verbatim copying, provided that the +# entire resulting derived work is given a different name and distributed +# under the terms of a permission notice identical to this one. + +# +# Read the README file, then edit this file to reflect local conditions +# + +# directory for TeX inputs (cwebmac.tex goes here) +MACROSDIR= /usr/share/texmf/tex/generic + +# directory for CWEB inputs in @i files +CWEBINPUTS= /usr/local/lib/cweb + +# extension for manual pages ("l" distinguishes local from system stuff) +MANEXT= l +#MANEXT= 1 + +# directory for manual pages (cweb.1 goes here) +MANDIR= /usr/share/man/man$(MANEXT) + +# destination directory for executables; must end in / +DESTDIR= /usr/local/bin/ + +# directory for GNU EMACS Lisp code (cweb.el goes here) +EMACSDIR= /usr/share/emacs/site-lisp + +# Set DESTPREF to null if you want to call the executables "tangle" and "weave" +# (probably NOT a good idea; we recommend leaving DESTPREF=c) +DESTPREF=c + +# Set CCHANGES to comm-foo.ch if you need changes to common.w +CCHANGES= + +# Set TCHANGES to ctang-foo.ch if you need changes to ctangle.w +TCHANGES= + +# Set WCHANGES to cweav-foo.ch if you need changes to cweave.w +WCHANGES= + +# We keep debugging info around, for fun, but most users don't need it +CFLAGS = -g +#CFLAGS = -O +LINKFLAGS = -g +#LINKFLAGS = -s # for smaller (stripped) executables on many UNIX systems + +# What C compiler are you using? +CC = cc + +# RM and CP are used below in case rm and cp are aliased +RM= /bin/rm +CP= /bin/cp + +# uncomment the second line if you use pdftex to bypass .dvi files +PDFTEX = dvipdfm +#PDFTEX = pdftex + +########## You shouldn't have to change anything after this point ####### + +CWEAVE = ./cweave +CTANGLE = ./ctangle +SOURCES = cweave.w common.w ctangle.w +ALL = common.w ctangle.w cweave.w prod.w \ + Makefile common.c common.h ctangle.c \ + cwebman.tex cwebmac.tex comm-vms.ch ctang-vms.ch \ + cweav-vms.ch comm-man.ch ctang-man.ch cweav-man.ch \ + comm-pc.ch ctang-pc.ch cweav-pc.ch comm-amiga.ch \ + comm-bs.ch ctang-bs.ch cweav-bs.ch makefile.bs \ + comm-ql.ch ctang-ql.ch cweav-ql.ch readme.ql \ + comm-w32.ch ctang-w32.ch cweav-w32.ch \ + comm-os2.ch comm-mac.ch cweb.1 cweb.el c++lib.w README + +.SUFFIXES: .dvi .tex .w .pdf + +.w.tex: + $(CWEAVE) $* + +.tex.dvi: + tex $< + +.w.dvi: + make $*.tex + make $*.dvi + +.w.c: + $(CTANGLE) $* + +.w.o: + make $*.c + make $*.o + +.w.pdf: + make $*.tex + case "$(PDFTEX)" in \ + dvipdfm ) tex "\let\pdf+ \input $*"; dvipdfm $* ;; \ + pdftex ) pdftex $* ;; \ + esac + +all: ctangle cweave + +cautiously: ctangle + $(CP) common.c SAVEcommon.c + ./ctangle common $(CCHANGES) + diff common.c SAVEcommon.c + $(RM) SAVEcommon.c + $(CP) ctangle.c SAVEctangle.c + ./ctangle ctangle $(TCHANGES) + diff ctangle.c SAVEctangle.c + $(RM) SAVEctangle.c + +SAVEctangle.c: + $(CP) ctangle.c SAVEctangle.c + +SAVEcommon.c: + $(CP) common.c SAVEcommon.c + +common.c: common.w $(CCHANGES) + $(CTANGLE) common $(CCHANGES) + +common.o: common.c + $(CC) $(CFLAGS) -DCWEBINPUTS=\"$(CWEBINPUTS)\" -c common.c + +ctangle: ctangle.o common.o + $(CC) $(LINKFLAGS) -o ctangle ctangle.o common.o + +ctangle.c: ctangle.w $(TCHANGES) + $(CTANGLE) ctangle $(TCHANGES) + +cweave: cweave.o common.o + $(CC) $(LINKFLAGS) -o cweave cweave.o common.o + +cweave.c: cweave.w $(WCHANGES) + $(CTANGLE) cweave $(WCHANGES) + +doc: $(SOURCES:.w=.dvi) + +usermanual: cwebman.tex cwebmac.tex + tex cwebman + +fullmanual: usermanual $(SOURCES) comm-man.ch ctang-man.ch cweav-man.ch + make cweave + ./cweave common.w comm-man.ch + tex common.tex + ./cweave ctangle.w ctang-man.ch + tex ctangle.tex + ./cweave cweave.w cweav-man.ch + tex cweave.tex + +# be sure to leave ctangle.c and common.c for bootstrapping +clean: + $(RM) -f -r *~ *.o common.tex cweave.tex cweave.c ctangle.tex \ + *.log *.dvi *.toc *.idx *.scn *.pdf core cweave ctangle + +install: all + - mkdir $(DESTDIR) + $(CP) cweave $(DESTDIR)$(DESTPREF)weave + chmod 755 $(DESTDIR)$(DESTPREF)weave + $(CP) ctangle $(DESTDIR)$(DESTPREF)tangle + chmod 755 $(DESTDIR)$(DESTPREF)tangle + - mkdir $(MANDIR) + $(CP) cweb.1 $(MANDIR)/cweb.$(MANEXT) + chmod 644 $(MANDIR)/cweb.$(MANEXT) + - mkdir $(MACROSDIR) + $(CP) cwebmac.tex $(MACROSDIR) + chmod 644 $(MACROSDIR)/cwebmac.tex + - mkdir $(EMACSDIR) + $(CP) cweb.el $(EMACSDIR) + chmod 644 $(EMACSDIR)/cweb.el + - mkdir $(CWEBINPUTS) + $(CP) c++lib.w $(CWEBINPUTS) + chmod 644 $(CWEBINPUTS)/c++lib.w + +floppy: $(ALL) examples + bar cvhf /dev/rfd0 $(ALL) examples + bar tvf /dev/rfd0 + eject + +tags: $(ALL) + etags -lnone $(ALL) + +tarfile: $(ALL) examples + tar cvhf /tmp/cweb.tar $(ALL) examples + gzip -9 /tmp/cweb.tar + +tarball: + tar zcvhf /tmp/cweb.tgz $(ALL) examples diff --git a/web/c_cpp/cweb/README b/web/c_cpp/cweb/README new file mode 100644 index 0000000000..6429dabfa8 --- /dev/null +++ b/web/c_cpp/cweb/README @@ -0,0 +1,110 @@ +% This file is part of CWEB. +% The CWEB programs by Silvio Levy are based on programs by D. E. Knuth. +% They are distributed WITHOUT ANY WARRANTY, express or implied. +% This README file last updated January 2016 by Don Knuth + +% Copyright (C) 1987,1990,1993,2000,2016 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. + +% Please send comments, suggestions, etc. to tex-k@tug.org, and people +% there will verify and forward bug reports. +% +% DEK takes no responsibility for the changefiles; they should be +% maintained independently. His job is to correct errors in +% ctangle.w, cweave.w, prod.w, common.w, cwebmac.tex, cwebman.tex, +% and in the files of examples/*.w, nothing more. + +This directory contains the following files: + +Makefile +README +comm-amiga.ch +comm-bs.ch +comm-mac.ch +comm-man.ch +comm-pc.ch +comm-ql.ch +comm-vms.ch +comm-w32.ch +common.c +common.h +common.w +ctang-bs.ch +ctang-man.ch +ctang-pc.ch +ctang-ql.ch +ctang-vms.ch +ctang-w32.ch +ctangle.c +ctangle.w +cweav-bs.ch +cweav-man.ch +cweav-pc.ch +cweav-ql.ch +cweav-vms.ch +cweave-w32.ch +cweave.w +cweb.1 +cweb.el +cwebmac.tex +cwebman.tex +examples/ +makefile.bs +prod.w +readme.ql +c++lib.w + +The file cwebman.tex is the user manual. +The examples directory contains additional examples of the use of CWEB. +The files common.c and ctangle.c are used for bootstrapping. +The file cweb.1 is a manual page. +The file cweb.el is suggested for GNU-Emacs users. +The file c++lib.w is for C++ users (say `@i c++lib.w' at beginning of program). +The files *-man.ch are used if you want to make the full 239-page CWEB manual. +The files *-bs.ch are used instead of *-pc.ch if you are doing BIG programs. +You can use makefile.bs to make CWEB with *-bs.ch. +The files *-ql.ch are for QDOS/SMSQ systems; see readme.ql for further info. +The files *-w32.ch use __fastcall conventions on win32 systems. +The file comm-mac.ch is for Macintosh conventions. +The other files named *.ch are sample change files for local customization. + +IMPORTANT: Please touch *.c before proceeding. +Then edit the opening lines of Makefile so that it has the proper +directory information for your local system. + +To make ctangle and cweave say `make all'; this should produce roughly +the following actions (possibly with harmless warning messages from cc): + +cc -g -w -c ctangle.c +cc -g -w -DCWEBINPUTS=\"/usr/local/lib/cweb\" -c common.c +cc -g -o ctangle ctangle.o common.o +./ctangle cweave +cc -g -w -c cweave.c +cc -g -w -o cweave cweave.o common.o + +To get some reassurance that things are OK, you can say `make cautiously', +which ensures that CTANGLE will reproduce itself. (Otherwise the source +files common.w and ctangle.w won't actually have been used.) + +To install cweave and ctangle say `make install'. You probably need to +be superuser to do this; but it's wise to `make all' first, BEFORE +becoming superuser and saying `make install'. + +Note that change files for VMS, AMIGA, MAC, and PCs are provided. When you +are first bootstrapping to a new system, you may need to edit common.c and +ctangle.c by hand, but the vast majority of the change-file changes are +minor refinements that are not necessary for a rudimentary ctangle. + +----------------------------------------- +These archival sources are maintained only to the extent of fixing +significant bugs that were unintended at the time of writing. +A multi-decade ongoing project to improve and extend CWEB can be found at + https://github.com/ascherer/cwebbin diff --git a/web/c_cpp/cweb/c++lib.w b/web/c_cpp/cweb/c++lib.w new file mode 100644 index 0000000000..15e59cc885 --- /dev/null +++ b/web/c_cpp/cweb/c++lib.w @@ -0,0 +1,85 @@ +@q This file defines standard C++ namespaces and classes @> +@q Please send corrections to saroj-tamasa@@worldnet.att.net @> +@s std int +@s rel_ops int +@s bitset int +@s char_traits int +@s deque int +@s list int +@s map int +@s multimap int +@s multiset int +@s pair int +@s set int +@s stack int +@s exception int +@s logic_error int +@s runtime_error int +@s domain_error int +@s invalid_argument int +@s length_error int +@s out_of_range int +@s range_error int +@s overflow_error int +@s underflow_error int +@s back_insert_iterator int +@s front_insert_iterator int +@s insert_iterator int +@s reverse_iterator int +@s istream_iterator int +@s ostream_iterator int +@s istreambuf_iterator int +@s ostreambuf_iterator int +@s iterator_traits int +@s queue int +@s vector int +@s basic_string int +@s string int +@s auto_ptr int +@s valarray int +@s ios_base int +@s basic_ios int +@s basic_streambuf int +@s basic_istream int +@s basic_ostream int +@s basic_iostream int +@s basic_stringbuf int +@s basic_istringstream int +@s basic_ostringstream int +@s basic_stringstream int +@s basic_filebuf int +@s basic_ifstream int +@s basic_ofstream int +@s basic_fstream int +@s ctype int +@s collate int +@s collate_byname int +@s streambuf int +@s istream int +@s ostream int +@s iostream int +@s stringbuf int +@s istringstream int +@s ostringstream int +@s stringstream int +@s filebuf int +@s ifstream int +@s ofstream int +@s fstream int +@s wstreambuf int +@s wistream int +@s wostream int +@s wiostram int +@s wstringbuf int +@s wistringstream int +@s wostringstream int +@s wstringstream int +@s wfilebuf int +@s wifstream int +@s wofstream int +@s wfstream int +@s streamoff int +@s streamsize int +@s fpos int +@s streampos int +@s wstreampos int diff --git a/web/c_cpp/cweb/comm-amiga.ch b/web/c_cpp/cweb/comm-amiga.ch new file mode 100644 index 0000000000..57e65d1ccd --- /dev/null +++ b/web/c_cpp/cweb/comm-amiga.ch @@ -0,0 +1,17 @@ +This is the change file for CWEB's COMMON on the Amiga +(Contributed by Tomas Rokicki, June 1993) + +With Lattice C 5.1, use compilation switches -b0 -r0, and ignore the +compiler warnings. With SAS 6.0, use compilation switches Code=far Data=far. + +@x section 69 +An omitted change file argument means that |"/dev/null"| should be used, +@y +An omitted change file argument means that |"nil:"| should be used, +@z + +@x section 70 + if (found_change<=0) strcpy(change_file_name,"/dev/null"); +@y + if (found_change<=0) strcpy(change_file_name,"nil:"); +@z diff --git a/web/c_cpp/cweb/comm-bs.ch b/web/c_cpp/cweb/comm-bs.ch new file mode 100644 index 0000000000..26f79b160d --- /dev/null +++ b/web/c_cpp/cweb/comm-bs.ch @@ -0,0 +1,229 @@ +Changes for code common to CTANGLE and CWEAVE, for MSDOS +and Borland C++ 3.1 using the following options (and perhaps others): + + -mc -w-pro -Ff=5000 -Z- -O-p + +The options -Z- and -O-p explicitly turn off optimizations that seem to be +dangerous for the style of code in the CWEB sources. (See makefile.bs.) + +The main purpose of these changes is to support MSDOS with full-size arrays +by using "huge" pointers. + +(This file contributed by Barry Schwartz, trashman@crud.mn.org, 28 Jun 94; + revised 24 Jul 94.) + + +@x Section 23. + cur_file_name[l]='/'; /* \UNIX/ pathname separator */ +@y + cur_file_name[l]='/'; /* A valid {\mc MSDOS} pathname separator */ +@z + + +@x Section 27. +@d max_names 4000 /* number of identifiers, strings, section names; + must be less than 10240 */ + +@= +typedef struct name_info { + char *byte_start; /* beginning of the name in |byte_mem| */ + @@; +} 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| */ +@y +@d max_names 4000 /* number of identifiers, strings, section names; + must be less than 10240 */ + +@f huge extern + +@= +typedef struct name_info { + char huge* byte_start; /* beginning of the name in |byte_mem| */ + @@; +} name_info; /* contains information about an identifier or section name */ +typedef name_info *name_pointer; /* pointer into array of |name_info|s */ +char huge byte_mem[max_bytes]; /* characters of names */ +char huge* byte_mem_end; /* end of |byte_mem| */ +name_info name_dir[max_names]; /* information about names */ +name_pointer name_dir_end = name_dir+max_names-1; +@z + + +@x Section 29. +char *byte_ptr; /* first unused position in |byte_mem| */ +@y +char huge* byte_ptr; /* first unused position in |byte_mem| */ +@z + + +@x Section 30. +@ @= +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 */ +@y +@ @= +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 */ +byte_mem_end = byte_mem+max_bytes-1; +@z + + +@x Section 42. +void +print_section_name(p) +name_pointer p; +{ + char *ss, *s = first_chunk(p); +@y +void +print_section_name(p) +name_pointer p; +{ + char huge* ss, huge* s = first_chunk(p); +@z + + +@x Section 43. +void +sprint_section_name(dest,p) + char*dest; + name_pointer p; +{ + char *ss, *s = first_chunk(p); +@y +void +sprint_section_name(dest,p) + char*dest; + name_pointer p; +{ + char huge* ss, huge* s = first_chunk(p); +@z + + +@x Section 44. +void +print_prefix_name(p) +name_pointer p; +{ + char *s = first_chunk(p); +@y +void +print_prefix_name(p) +name_pointer p; +{ + char huge* s = first_chunk(p); +@z + + +@x Section 47. +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); +@y +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 huge* s=first_chunk(p); +@z + + +@x Section 48. +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; +@y +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 huge* s; +@z + + +@x Section 54. +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); +@y +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 huge* ss, huge* s=first_chunk(r); +@z + + +@x Section 55. +source files, respectively; here we just declare a common field +|equiv_or_xref| as a pointer to a |char|. + +@= +char *equiv_or_xref; /* info corresponding to names */ +@y +source files, respectively. Here we just declare a common field +|ptr_union| as a union of pointers to |char|, which happen to have +different addressing attributes. + +@= +union { + char *equiv_member; + char huge* xref_member; +} ptr_union; /* info corresponding to names */ +@z + + +@x Section 69. +An omitted change file argument means that |"/dev/null"| should be used, +@y +An omitted change file argument means that |"NUL"| should be used, +@z + + +@x Section 70. + else if (*s=='/') dot_pos=NULL,name_pos=++s; +@y + else if (*s == ':' || *s == '\\' || *s == '/') + dot_pos=NULL,name_pos=++s; +@z + + +@x Section 70. + if (found_change<=0) strcpy(change_file_name,"/dev/null"); +@y + if (found_change<=0) strcpy(change_file_name,"NUL"); +@z diff --git a/web/c_cpp/cweb/comm-mac.ch b/web/c_cpp/cweb/comm-mac.ch new file mode 100644 index 0000000000..b9bd408655 --- /dev/null +++ b/web/c_cpp/cweb/comm-mac.ch @@ -0,0 +1,150 @@ +This is the change file to CWEB's COMMON for porting to Macintoshes. +No changes to CTANGLE or CWEAVE are needed. + +(Contributed 13 Oct 2000 by AndPio@aol.com; slightly edited by Don Knuth) + +@x in limbo, change the title page document to specify Mac version + \centerline{(Version 3.64)} +@y + \centerline{(Version 3.64 for MacOS)} +@z + +@x section 9: Make input_ln accept \n, \r, \n\r, or \r\n as line endings +@ In the unlikely event that your standard I/O library does not +support |feof|, |getc|, and |ungetc| you may have to change things here. +@^system dependencies@> + +@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); +} +@y +@ In the unlikely event that your standard I/O library does not +support |feof|, |getc|, and |ungetc| you may have to change things here. + +This |input_ln| function accepts |"\n"|, |"\r"|, |"\n\r"| and |"\r\n"| as +line endings, so that \.{CWEB} will works with ASCII files stored in +\UNIX/, {\mc DOS} or {\mc MAC} format. +@^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 (1) { + c = getc(fp); + if (c==EOF) return (limit!=buffer); /* 0, if there was nothing after + the last newline */ + else if (c=='\n' || c=='\r') { /* we have hit end-of-line */ + int d = getc(fp); + if (c+d!='\n'+'\r') /* no combination |"\n\r"| or |"\r\n"| */ + ungetc(d,fp); + return (1); + } + else if (k>buffer_end) { + ungetc(c,fp); loc=buffer; err_print("! Input line too long"); + return (1); +@.Input line too long@> + } + else + if ((*(k++)=c) != ' ') limit = k; + } +} +@z + +@x section 12, simply return if no change file was specified + change_limit=change_buffer; /* this value is used if the change file ends */ + @; +@y + change_limit=change_buffer; /* this value is used if the change file ends */ + if (change_file_name[0] == '\0') /* no change file specified */ + return; /* so we have reached the end of that file */ + @; +@z + +@x section 19, don't try to open a change file if none was specified +if ((change_file=fopen(change_file_name,"r"))==NULL) + fatal("! Cannot open change file ", change_file_name); +@y +if (change_file_name[0] == '\0') /* no change file specified */ + change_file = NULL; /* reset at least the |change_file| */ +else if ((change_file=fopen(change_file_name,"r"))==NULL) + fatal("! Cannot open change file ", change_file_name); +@z + +@x section 22, declare colon as Mac's path separator +(Colon-separated paths are not supported.) +The remainder of the \.{@@i} line after the file name is ignored. + +@y +(Colon-separated path alternatives in the style of \UNIX/ or Kpathsea +are not supported. On a Macintosh, colons are used to separate the names on +different levels of a path.) +The remainder of the \.{@@i} line after the file name is ignored. + +@d PATH_SEP ':' /* MacOS pathname separator */ +@^system dependencies@> +@z + +@x section 23, use the path separator constant + cur_file_name[l]='/'; /* \UNIX/ pathname separator */ +@y + cur_file_name[l]=PATH_SEP; /* pathname separator */ +@z + +@x section 69, explain the convention for omitted change files +An omitted change file argument means that |"/dev/null"| should be used, +@y +An omitted change file argument means that no change file should be used, +@z + +@x section 70, use the Metrowerks |ccommand| to access command lines + while (--argc > 0) { +@y + argc = ccommand (&argv); /* use Mac interface to command line */ +@^system dependencies@> + while (--argc > 0) { +@z +@x section 70, use the path separator constant + else if (*s=='/') dot_pos=NULL,name_pos=++s; +@y + else if (*s==PATH_SEP) dot_pos=NULL,name_pos=++s; +@z +@x section 70, make change file name empty when it is unspecified + if (found_change<=0) strcpy(change_file_name,"/dev/null"); +@y + if (found_change<=0) change_file_name[0]='\0'; /* empty string */ +@z + +@x section 82, insert an extra module before the index +@** Index. +@y by putting the new module here, we preserve all the previous section numbers +@ We assume an interface to \CEE/ command-line emulation as supplied by +the |ccommand| function of Metrowerks CodeWarrior, as defined in +the header file \.{console.h}. + +@= +#include +@^system dependencies@> + +@** Index. +@z diff --git a/web/c_cpp/cweb/comm-man.ch b/web/c_cpp/cweb/comm-man.ch new file mode 100644 index 0000000000..c922c03631 --- /dev/null +++ b/web/c_cpp/cweb/comm-man.ch @@ -0,0 +1,22 @@ +Change file to help make Appendix D of the full CWEB manual +@x +\def\botofcontents{\vfill +\noindent +Copyright \copyright\ 1987, 1990, 1993, 2000 Silvio Levy and Donald E. Knuth +\bigskip\noindent +Permission is granted to make and distribute verbatim copies of this +document provided that the copyright notice and this permission notice +are preserved on all copies. + +\smallskip\noindent +Permission is granted to copy and distribute modified versions of this +document under the conditions for verbatim copying, provided that the +entire resulting derived work is given a different name and distributed +under the terms of a permission notice identical to this one. +} +@y +\def\botofcontents{\vfill\titlefalse} +\def\contentspagenumber{28} +\def\title{APPENDIX D: COMMON} +\let\K=\leftarrow +@z diff --git a/web/c_cpp/cweb/comm-os2.ch b/web/c_cpp/cweb/comm-os2.ch new file mode 100644 index 0000000000..5e20a6706c --- /dev/null +++ b/web/c_cpp/cweb/comm-os2.ch @@ -0,0 +1,24 @@ +This is the change file for CWEB's COMMON under OS/2 +(Contributed by Jim Nutt, jnutt@PrimeNet.Com, May 1995) + +These changes tested with WATCOM C v10.0a. +No changes to CTANGLE or CWEAVE are needed with OS/2. + +@x section 69 +An omitted change file argument means that |"/dev/null"| should be used, +@y +An omitted change file argument means that |"NUL"| should be used, +@z + +@x section 70 (this change copied from comm-pc.ch) + else if (*s=='/') dot_pos=NULL,name_pos=++s; +@y + else if (*s == ':' || *s == '\\' || *s == '/') + dot_pos=NULL,name_pos=++s; +@z + +@x section 70 + if (found_change<=0) strcpy(change_file_name,"/dev/null"); +@y + if (found_change<=0) strcpy(change_file_name,"NUL"); +@z diff --git a/web/c_cpp/cweb/comm-pc.ch b/web/c_cpp/cweb/comm-pc.ch new file mode 100644 index 0000000000..e69bafb524 --- /dev/null +++ b/web/c_cpp/cweb/comm-pc.ch @@ -0,0 +1,33 @@ +This is the change file for CWEB's COMMON under DOS +(Contributed by Lee Wittenberg, March 1993) + +Changes necessary for compiling with Borland C/C++ +Use compilation switches -mc -w-pro -Ff=5000 + +Note: The change to section 27 is not necessary if using a compiler +that allows >64K arrays. + +@x section 27 +@d max_bytes 90000 /* the number of bytes in identifiers, +@y +@d max_bytes (unsigned)60000 /* the number of bytes in identifiers, +@z + +@x section 69 +An omitted change file argument means that |"/dev/null"| should be used, +@y +An omitted change file argument means that |"NUL"| should be used, +@z + +@x section 70 (this change copied from comm-bs.ch, July 94) + else if (*s=='/') dot_pos=NULL,name_pos=++s; +@y + else if (*s == ':' || *s == '\\' || *s == '/') + dot_pos=NULL,name_pos=++s; +@z + +@x section 70 + if (found_change<=0) strcpy(change_file_name,"/dev/null"); +@y + if (found_change<=0) strcpy(change_file_name,"NUL"); +@z diff --git a/web/c_cpp/cweb/comm-ql.ch b/web/c_cpp/cweb/comm-ql.ch new file mode 100644 index 0000000000..8859e215b2 --- /dev/null +++ b/web/c_cpp/cweb/comm-ql.ch @@ -0,0 +1,332 @@ +This is the change file for CWEB's COMMON under QSOD/SMSQ +(Contributed by Robert H. Klein, September 1994) + +This change file is intended for use with C68 v4.13 (or later). +compile with +ex cc;'-v -h -c -=500000 -DCWEBINPUTS=flp2_ common_c' + + + +@x +\def\v{\char'174} % vertical (|) in typewriter font + +\def\title{Common code for CTANGLE and CWEAVE (Version 3.64)} +\def\topofcontents{\null\vfill + \centerline{\titlefont Common code for {\ttitlefont CTANGLE} and + {\ttitlefont CWEAVE}} + \vskip 15pt + \centerline{(Version 3.64)} + \vfill} +\def\botofcontents{\vfill +\noindent +@y +\def\v{\char'174} % vertical (|) in typewriter font + +\def\title{Common code for CTANGLE and CWEAVE (QL Version 3.64)} +\def\topofcontents{\null\vfill + \centerline{\titlefont Common code for {\ttitlefont CTANGLE} and + {\ttitlefont CWEAVE}} + \vskip 15pt + \centerline{(Version 3.64)} + \vfill} +\def\botofcontents{\vfill +\noindent +@z + +@x +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 */ +@y +The line number of each open file is also kept for error reporting and +for the benefit of \.{CTANGLE}. + +For use on QDOS/SMSQ systems the variable |max_file_name_length| is shortened +to 42 characters, i.e. 5 characters for the device name, 36 characters +for the file name plus one character as string terminator. (Note that +(current) QDOS/SMSQ file systems have a limitation of 36 characters as +maximum length for a file name. + +@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 42 +@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 */ +@z + + +@x + cur_file_name[l]='/'; /* \UNIX/ pathname separator */ +@y + cur_file_name[l]='_'; /* QDOS/SMSQ pathname separator */ +@z + + +@x +@ 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. + +@= +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)) @@; + 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) @@; + else if (!found_change) @@; + else if (!found_out) @@; + else @; + } + } + if (!found_web) @; + 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. + +@= +{ + if (s-*argv > max_file_name_length-5) + @; + 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; +} + +@ @= +{ + if (strcmp(*argv,"-")==0) found_change=-1; + else { + if (s-*argv > max_file_name_length-4) + @; + if (dot_pos==NULL) + sprintf(change_file_name,"%s.ch",*argv); + else strcpy(change_file_name,*argv); + found_change=1; + } +} + +@ @= +{ + if (s-*argv > max_file_name_length-5) + @; + 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); + strcpy(C_file_name,*argv); + if (flags['x']) { /* indexes will be generated */ + *dot_pos=0; + sprintf(idx_file_name,"%s.idx",*argv); + sprintf(scn_file_name,"%s.scn",*argv); + } + } + found_out=1; +} +@y +@ 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 |"NUL"| should be used, +when no changes are desired. +@^system dependencies@> + +If there's a third file name, it will be the output file. + +Because |"_"| is a directory {\em and} extension separator, \.{CWEB} will +always use the {\em full} name (i.e. with full path). Fortunately the +routine has been written to search for the last ``dot'', so the altered +version will search for the last |"_"| (including directory separators), +so we have what we want. + +@= +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)) @@; + 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) @@; + else if (!found_change) @@; + else if (!found_out) @@; + else @; + } + } + if (!found_web) @; + if (found_change<=0) strcpy(change_file_name,"NUL"); +} + +@ 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. + +If you've read the section before carefully you'll have noticed, that +QDOS/SMSQ file names contain almost a |"_"|, so this routine will not work, +i.e. you'll {\em have} to add the |"_w"| always. Nevertheless I adapted +the routine as if it would work. + +@= +{ + if (s-*argv > max_file_name_length-5) + @; + 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; +} + +@ @= +{ + if (strcmp(*argv,"-")==0) found_change=-1; + else { + if (s-*argv > max_file_name_length-4) + @; + if (dot_pos==NULL) + sprintf(change_file_name,"%s_ch",*argv); + else strcpy(change_file_name,*argv); + found_change=1; + } +} + +@ @= +{ + if (s-*argv > max_file_name_length-5) + @; + 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); + strcpy(C_file_name,*argv); + if (flags['x']) { /* indexes will be generated */ + *dot_pos=0; + sprintf(idx_file_name,"%s_idx",*argv); + sprintf(scn_file_name,"%s_scn",*argv); + } + } + found_out=1; +} +@z + + +@x +@ @= +{ +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" + ,""); +} +@y +@ @= +{ +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" + ,""); +} +@z diff --git a/web/c_cpp/cweb/comm-vms.ch b/web/c_cpp/cweb/comm-vms.ch new file mode 100644 index 0000000000..cd5fe52439 --- /dev/null +++ b/web/c_cpp/cweb/comm-vms.ch @@ -0,0 +1,81 @@ +This is the change file for CWEB's COMMON under VAX/VMS. + +created: + 1987 BL (Bjorn Larsen, University of Oslo) + +modified: + 01-FEB-1992 ST (Stephan Trebels ) + > include ctype,stdio,ssdef from textlibrary SYS$SHARE:VAXCDEF.TLB + > change error return code to SS$_ABORT + (perhaps better than %NONAME-E-NOMSG, Message number 2 ) + +(also modified by Don Knuth to match changes in the master file) +(only the two changes by BL are necessary for initial bootstrapping + via hand-editing of common.c) + +@x section 5 (01-FEB-1992 ST) +#include +@y +#include ctype /* VMS searches Textlibraries faster */ +@z + +@x section 8 (01-FEB-1992 ST) +#include +@y +#include stdio /* VMS searches Textlibraries faster */ +@z + +@x section 61 (01-FEB-1992 ST) +programs are started. Here, for instance, we pass the operating system +a status of 0 if and only if only harmless messages were printed. +@y +programs are started. Here, for instance, we pass VAX/VMS +a status of |SS$_NORMAL| if and only if only harmless +messages have been printed. +A suitable status to signal an error condition to VAX/VMS could be +|SS$_ABORT|, telling the operating system to +print |"%SYSTEM-F-ABORT, abort"|, if |history > harmless_message|. +@z + +@x section 61 (1987 BL) (01-FEB-1992 ST) (11-JAN-1993 DEK) + if (history > harmless_message) return(1); + else return(0); +@y +/* + VAX/VMS and UNIX have different error status conventions. + VAX/VMS uses odd values (for example |SS$_NORMAL|) to indicate success, + even values indicate errors, resulting in messages displayed + on the screen. |SS$_ABORT| has been chosen, to indicate an + error and display something that's not complete nonsense. +*/ + if (history > harmless_message) exit(SS$_ABORT); + else exit(SS$_NORMAL); +@z + +@x section 69 (01-FEB-1992 ST) +An omitted change file argument means that |"/dev/null"| should be used, +when no changes are desired. +@y +An omitted change file argument means that the +null device |"NL:"| should be used, when no changes are desired. +@z + +@x section 70 (1987 BL) (01-FEB-1992 ST) (05-APR-1992 DEK) + if (found_change<=0) strcpy(change_file_name,"/dev/null"); +@y + if (found_change<=) strcpy(change_file_name,"NL:"); + /* {\tt NL:} is the VAX/VMS notation for {\tt /dev/null} */ +@z + +@x section 82 (01-FEB-1992 ST) +@** Index. +@y +@* VAX/VMS specific code. +We have used |SS$_NORMAL| and |SS$_ABORT| as return codes, +so we have to include the system message codes. + +@= +#include ssdef /* we need VAX/VMS system messages */ + +@** Index. +@z diff --git a/web/c_cpp/cweb/comm-w32.ch b/web/c_cpp/cweb/comm-w32.ch new file mode 100644 index 0000000000..b300f496d2 --- /dev/null +++ b/web/c_cpp/cweb/comm-w32.ch @@ -0,0 +1,94 @@ +This is the change file for CWEB's COMMON under Win32 +(Contributed by Fabrice Popineau, February 2002 ) + +The Microsoft C compiler included in Visual Studio allows for different +parameter passing conventions than the standard one. This is actually +specified with the Intel IA32 architecture. There exist three +calling conventions under the IA32 architecture as defined by Intel. + +One of them is the standard C calling convention: Parameters are passed on +the stack, calling function is responsible to unstack arguments. Names are +decorated with a prefixed underscore. It is called the __cdecl convention. + +Another calling convention is the __fastcall convention. The first two 32bits +arguments are passed on the stack. The called function is responsible for +stack maintenance. Names are decorated with an @ sign as prefix, and another +@ sign followed by the size of the arguments as suffix. + +The third one is the __stdcall convention and is basically the Pascal calling +convention. + +Using the __fastcall convention is usually faster on Intel architecture. Names +are decorated because obviously a __cdecl function can't behave the same way +as a __fastcall one of the same prototype. So the new full prototype includes +the keyword __cdecl or __fastcall. A compiler option allows to compile all +functions using one or the other calling convention. If you compile using +__fastcall, then you are bound to explicitly declare a few functions as +__cdecl : the ones that are passed to the C library (like function pointers +for qsort() or signal()) or functions that replace functions from the C +library, because the standard headers have a __cdecl prototype for these +functions. Also, you cannot declare a library function without giving it the +exact prototype used in the library headers files. So you'd better use the +header files to be safe. + +Admittedly, this is not vital for cweb, except that I build the whole texlive +set of programs using the __fastcall convention. + +@x +@= +#include +@y +@= +#include +#include +@z + +@x +@ @= +extern int names_match(); +@y +@ @= +extern int __cdecl names_match(); +@z + +@x +@= +void init_p(); +@y +@= +void __cdecl init_p(); +@z + +@x section 69 +An omitted change file argument means that |"/dev/null"| should be used, +@y +An omitted change file argument means that |"NUL"| should be used, +@z + +@x section 70 (this change copied from comm-bs.ch, July 94) + else if (*s=='/') dot_pos=NULL,name_pos=++s; +@y + else if (*s == ':' || *s == '\\' || *s == '/') + dot_pos=NULL,name_pos=++s; +@z + +@x section 70 + if (found_change<=0) strcpy(change_file_name,"/dev/null"); +@y + if (found_change<=0) strcpy(change_file_name,"NUL"); +@z + +@x +@ 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 \.{} where others have \.{}.) + +@= +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 */ +@y +@z diff --git a/web/c_cpp/cweb/common.c b/web/c_cpp/cweb/common.c new file mode 100644 index 0000000000..2bf7a9d4a8 --- /dev/null +++ b/web/c_cpp/cweb/common.c @@ -0,0 +1,1242 @@ +/*1:*/ +#line 58 "common.w" + +/*5:*/ +#line 102 "common.w" + +#include + +/*:5*//*8:*/ +#line 165 "common.w" + +#include + +/*:8*//*22:*/ +#line 471 "common.w" + +#include + +/*:22*/ +#line 59 "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 100 +#define longest_name 10000 +#define long_buf_size (buf_size+longest_name) +#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 90000 \ + +#define max_names 4000 \ + \ + +#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 60 "common.w" + +/*2:*/ +#line 73 "common.w" + +typedef short boolean; +boolean program; + +/*:2*//*7:*/ +#line 159 "common.w" + +char buffer[long_buf_size]; +char*buffer_end= buffer+buf_size-2; +char*limit= buffer; +char*loc= buffer; + +/*:7*//*10:*/ +#line 214 "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 418 "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 594 "common.w" + +typedef struct name_info{ +char*byte_start; +/*31:*/ +#line 631 "common.w" + +struct name_info*link; + +/*:31*//*40:*/ +#line 730 "common.w" + +union{ +struct name_info*Rlink; + +char Ilk; +}dummy; + +/*:40*//*55:*/ +#line 1062 "common.w" + +char*equiv_or_xref; + +/*:55*/ +#line 597 "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 617 "common.w" + +name_pointer name_ptr; +char*byte_ptr; + +/*:29*//*32:*/ +#line 644 "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 1082 "common.w" + +int history= spotless; + +/*:56*//*67:*/ +#line 1220 "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 1370 "common.w" + +FILE*C_file; +FILE*tex_file; +FILE*idx_file; +FILE*scn_file; +FILE*active_file; + +/*:77*/ +#line 61 "common.w" + +/*3:*/ +#line 83 "common.w" +int phase; + +/*:3*//*11:*/ +#line 240 "common.w" + +char change_buffer[buf_size]; +char*change_limit; + +/*:11*/ +#line 62 "common.w" + +/*33:*/ +#line 650 "common.w" + +extern int names_match(); + +/*:33*//*38:*/ +#line 703 "common.w" + +void init_p(); + +/*:38*//*46:*/ +#line 852 "common.w" + +extern void init_node(); + +/*:46*//*53:*/ +#line 1017 "common.w" + +int section_name_cmp(); + +/*:53*//*57:*/ +#line 1092 "common.w" + +void err_print(); + +/*:57*//*60:*/ +#line 1140 "common.w" + +int wrap_up(); +extern void print_stats(); + +/*:60*//*63:*/ +#line 1173 "common.w" + +void fatal(),overflow(); + +/*:63*//*69:*/ +#line 1251 "common.w" + +void scan_args(); + +/*:69*//*81:*/ +#line 1411 "common.w" + +extern int strlen(); +extern int strcmp(); +extern char*strcpy(); +extern int strncmp(); +extern char*strncpy(); + +/*:81*/ +#line 63 "common.w" + + +/*:1*//*4:*/ +#line 89 "common.w" + +void +common_init() +{ +/*30:*/ +#line 621 "common.w" + +name_dir->byte_start= byte_ptr= byte_mem; +name_ptr= name_dir+1; +name_ptr->byte_start= byte_mem; + +/*:30*//*34:*/ +#line 655 "common.w" + +for(h= hash;h<=hash_end;*h++= NULL); + +/*:34*//*41:*/ +#line 737 "common.w" + +root= NULL; + +/*:41*/ +#line 93 "common.w" +; +/*68:*/ +#line 1233 "common.w" + +show_banner= show_happiness= show_progress= 1; + +/*:68*/ +#line 94 "common.w" +; +/*78:*/ +#line 1377 "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 95 "common.w" +; +} + +/*:4*//*9:*/ +#line 172 "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 251 "common.w" + +void +prime_the_change_buffer() +{ +change_limit= change_buffer; +/*13:*/ +#line 265 "common.w" + +while(1){ +change_line++; +if(!input_ln(change_file))return; +if(limit buffer+1&&buffer[0]=='@'){ +char xyz_code= xisupper(buffer[1])?tolower(buffer[1]):buffer[1]; +/*17:*/ +#line 358 "common.w" + +if(xyz_code=='x'||xyz_code=='z'){ +loc= buffer+2;err_print("! Where is the matching @y?"); + +} +else if(xyz_code=='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 342 "common.w" +; +} +/*15:*/ +#line 292 "common.w" + +{ +change_limit= change_buffer+(limit-buffer); +strncpy(change_buffer,buffer,limit-buffer+1); +} + +/*:15*/ +#line 344 "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 378 "common.w" + +void +reset_input() +{ +limit= buffer;loc= buffer+1;buffer[0]= ' '; +/*19:*/ +#line 393 "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 383 "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 426 "common.w" + +int get_line() +{ +restart: +if(changing&&include_depth==change_depth) +/*25:*/ +#line 537 "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 431 "common.w" +; +if(!changing||include_depth> change_depth){ +/*24:*/ +#line 520 "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 433 "common.w" +; +if(changing&&include_depth==change_depth)goto restart; +} +if(input_has_ended)return 0; +loc= buffer;*limit= ' '; +if(buffer[0]=='@'&&(buffer[1]=='i'||buffer[1]=='I')){ +loc= buffer+2;*limit= '"'; +while(*loc==' '||*loc=='\t')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 474 "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; + +if(*loc=='"'){ +loc++; +while(*loc!='"'&&k<=cur_file_name_end)*k++= *loc++; +if(loc==limit)k= cur_file_name_end+1; +}else +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 452 "common.w" +; +} +return 1; +} + +/*:21*//*26:*/ +#line 569 "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 660 "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 683 "common.w" + +h= (unsigned char)*i; +while(++ilink; +if(p==NULL){ +p= name_ptr; +p->link= hash[h];hash[h]= p; +} + +/*:37*/ +#line 674 "common.w" +; +if(p==name_ptr)/*39:*/ +#line 706 "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 675 "common.w" +; +return(p); +} + +/*:35*//*42:*/ +#line 764 "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 783 "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 804 "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 825 "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 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 884 "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 912 "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 936 "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 926 "common.w" +; +/*51:*/ +#line 961 "common.w" + +if(r==NULL) +return add_section_name(par,c,first,last+1,ispref); + +/*:51*/ +#line 927 "common.w" +; +/*52:*/ +#line 969 "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"); +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 928 "common.w" +; +} + +/*:49*//*54:*/ +#line 1020 "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 1095 "common.w" + +void +err_print(s) +char*s; +{ +char*k,*l; +printf(*s=='!'?"\n%s":"%s",s); +if(web_file_open)/*59:*/ +#line 1115 "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 harmless_message)return(1); +else return(0); +} + +/*:61*//*64:*/ +#line 1179 "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 1190 "common.w" +void +overflow(t) +char*t; +{ +printf("\n! Sorry, %s capacity exceeded",t);fatal("",""); +} + + +/*:65*//*70:*/ +#line 1254 "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 1344 "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 1266 "common.w" + +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)/*71:*/ +#line 1292 "common.w" + +{ +if(s-*argv> max_file_name_length-5) +/*76:*/ +#line 1364 "common.w" +fatal("! Filename too long\n",*argv); + + +/*:76*/ +#line 1295 "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 1275 "common.w" + +else if(!found_change)/*72:*/ +#line 1310 "common.w" + +{ +if(strcmp(*argv,"-")==0)found_change= -1; +else{ +if(s-*argv> max_file_name_length-4) +/*76:*/ +#line 1364 "common.w" +fatal("! Filename too long\n",*argv); + + +/*:76*/ +#line 1315 "common.w" +; +if(dot_pos==NULL) +sprintf(change_file_name,"%s.ch",*argv); +else strcpy(change_file_name,*argv); +found_change= 1; +} +} + +/*:72*/ +#line 1276 "common.w" + +else if(!found_out)/*73:*/ +#line 1323 "common.w" + +{ +if(s-*argv> max_file_name_length-5) +/*76:*/ +#line 1364 "common.w" +fatal("! Filename too long\n",*argv); + + +/*:76*/ +#line 1326 "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); +strcpy(C_file_name,*argv); +if(flags['x']){ +*dot_pos= 0; +sprintf(idx_file_name,"%s.idx",*argv); +sprintf(scn_file_name,"%s.scn",*argv); +} +} +found_out= 1; +} + +/*:73*/ +#line 1277 "common.w" + +else/*75:*/ +#line 1352 "common.w" + +{ +if(program==ctangle) +fatal( +"! Usage: ctangle [options] webfile[.w] [{changefile[.ch]|-} [outfile[.c]]]\n" +,""); + +else fatal( +"! Usage: cweave [options] webfile[.w] [{changefile[.ch]|-} [outfile[.tex]]]\n" +,""); +} + +/*:75*/ +#line 1278 "common.w" +; +} +} +if(!found_web)/*75:*/ +#line 1352 "common.w" + +{ +if(program==ctangle) +fatal( +"! Usage: ctangle [options] webfile[.w] [{changefile[.ch]|-} [outfile[.c]]]\n" +,""); + +else fatal( +"! Usage: cweave [options] webfile[.w] [{changefile[.ch]|-} [outfile[.tex]]]\n" +,""); +} + +/*:75*/ +#line 1281 "common.w" +; +if(found_change<=0)strcpy(change_file_name,"/dev/null"); +} + +/*:70*/ diff --git a/web/c_cpp/cweb/common.h b/web/c_cpp/cweb/common.h new file mode 100644 index 0000000000..d6c0bfb601 --- /dev/null +++ b/web/c_cpp/cweb/common.h @@ -0,0 +1,193 @@ +% 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.64 --- February 2017 (works also with later versions) + +% 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 distributed under the terms of a +% permission notice identical to this one. + +% Please send comments, suggestions, etc. to levy@@math.berkeley.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 + +@= +typedef short boolean; +typedef char unsigned eight_bits; +extern boolean program; /* \.{CWEAVE} or \.{CTANGLE}? */ +extern int phase; /* which phase are we in? */ + +@ @= +#include + +@ 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} */ + +@= +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)) + +@= +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 + +@= +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 */ + char Ilk; /* used by identifiers in \.{CWEAVE} only */ + } 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 |name_dir| */ +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) + +@= +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 */ + +@= +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 change_depth; /* where \.{@@y} originated during a change */ +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: +@= +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? */ + +@= +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) + +@= +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: + +@= +extern void common_init(); diff --git a/web/c_cpp/cweb/common.w b/web/c_cpp/cweb/common.w new file mode 100644 index 0000000000..d8aacfb7b9 --- /dev/null +++ b/web/c_cpp/cweb/common.w @@ -0,0 +1,1418 @@ +% 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.64 --- January 2002 + +% Copyright (C) 1987,1990,1993,2000 Silvio Levy and Donald E. Knuth + +% Permission is granted to make and distribute verbatim copies of this +% document provided that the copyright notice and this permission notice +% are preserved on all copies. + +% Permission is granted to copy and distribute modified versions of this +% document under the conditions for verbatim copying, provided that the +% entire resulting derived work is given a different name and distributed +% under the terms of a permission notice identical to this one. + +\def\v{\char'174} % vertical (|) in typewriter font + +\def\title{Common code for CTANGLE and CWEAVE (Version 3.64)} +\def\topofcontents{\null\vfill + \centerline{\titlefont Common code for {\ttitlefont CTANGLE} and + {\ttitlefont CWEAVE}} + \vskip 15pt + \centerline{(Version 3.64)} + \vfill} +\def\botofcontents{\vfill +\noindent +Copyright \copyright\ 1987, 1990, 1993, 2000 Silvio Levy and Donald E. Knuth +\bigskip\noindent +Permission is granted to make and distribute verbatim copies of this +document provided that the copyright notice and this permission notice +are preserved on all copies. + +\smallskip\noindent +Permission is granted to copy and distribute modified versions of this +document under the conditions for verbatim copying, provided that the +entire resulting derived work is given a different name and distributed +under the terms of a permission notice identical to this one. +} + +\pageno=\contentspagenumber \advance\pageno by 1 +\let\maybe=\iftrue +@s not_eq normal @q unreserve a C++ keyword @> + +@** 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 +@@/ +@h +@@/ +@@/ +@@/ + +@ 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 + +@= +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. + +@= 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() +{ + @; + @; + @; +} + +@* The character set. +\.{CWEB} uses the conventions of \CEE/ programs found in the standard +\.{ctype.h} header file. + +@= +#include + +@ 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 10000 +@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)) + +@= +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 + +@ 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 */ + +@= +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)) + +@= +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 */ + @; + @; + @; +} + +@ 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). + +@= +while(1) { + change_line++; + if (!input_ln(change_file)) return; + if (limit + } +} + +@ Here we are looking at lines following the \.{@@x}. + +@= +do { + change_line++; + if (!input_ln(change_file)) { + err_print("! Change file ended after @@x"); +@.Change file ended...@> + return; + } +} while (limit==buffer); + +@ @= +{ + change_limit=change_buffer+(limit-buffer); + 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 + change_limit=change_buffer; changing=0; + return; + } + if (limit>buffer+1 && buffer[0]=='@@') { + char xyz_code=xisupper(buffer[1])? tolower(buffer[1]): buffer[1]; + @; + } + @; + 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 (xyz_code=='x' || xyz_code=='z') { + loc=buffer+2; err_print("! Where is the matching @@y?"); +@.Where is the match...@> + } +else if (xyz_code=='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]=' '; + @; + 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@> + +@= +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 */ + +@= +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) + @; + if (! changing || include_depth>change_depth) { + @; + if (changing && include_depth==change_depth) goto restart; + } + if (input_has_ended) return 0; + loc=buffer; *limit=' '; + if (buffer[0]=='@@' && (buffer[1]=='i' || buffer[1]=='I')) { + loc=buffer+2; *limit='"'; + while (*loc==' '||*loc=='\t') 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 */ + @; + } + return 1; +} + +@ 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 /* declaration of |getenv| and |exit| */ + +@ @= { + 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 */ + + if (*loc=='"') { + loc++; + while (*loc!='"' && k<=cur_file_name_end) *k++=*loc++; + if (loc==limit) k=cur_file_name_end+1; /* unmatched quote is `too long' */ + } else + 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; +} + +@ @= { + 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(); +} + +@ @= { + 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 */ + +@= +typedef struct name_info { + char *byte_start; /* beginning of the name in |byte_mem| */ + @@; +} 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|. + +@= +name_pointer name_ptr; /* first unused position in |name_dir| */ +char *byte_ptr; /* first unused position in |byte_mem| */ + +@ @= +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. + +@= +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 */ + +@= +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 */ + +@ @= +extern int names_match(); + +@ Initially all the hash lists are empty. + +@= +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 */ + @; + @; + if (p==name_ptr) @; + 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|.$$ + +@= +h=(unsigned char)*i; +while (++i + +@ If the identifier is new, it will be placed in position |p=name_ptr|, +otherwise |p| will point to its existing 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. + +@= +void init_p(); + +@ @= { + 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 */ + +@= +union { + struct name_info *Rlink; /* right link in binary search tree for section + names */ + char Ilk; /* used by identifiers in \.{CWEAVE} only */ +} dummy; + +@ @= +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= +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; + @; + @; + @; +} + +@ 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. + +@= +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 (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. + +@= +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 + 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 \.{@@} should be an acceptable ``abbreviation'' +for \.{@@}. 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 \.{@@} as an ``extension'' of itself. + +@d bad_extension 5 + +@= +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|. + +@= +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 + +@= +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 |"!"|. + +@= +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) @; + 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@> + +@= +{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= +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 */ + @; + if (history > harmless_message) return(1); + else return(0); +} + +@ @= +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. + +@= +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? */ + +@= +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|. + +@= +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. + +@= +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 been seen? */ + boolean flag_change; + + while (--argc > 0) { + if ((**(++argv)=='-'||**argv=='+')&&*(*argv+1)) @@; + 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) @@; + else if (!found_change) @@; + else if (!found_out) @@; + else @; + } + } + if (!found_web) @; + 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. + +@= +{ + if (s-*argv > max_file_name_length-5) + @; + 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; +} + +@ @= +{ + if (strcmp(*argv,"-")==0) found_change=-1; + else { + if (s-*argv > max_file_name_length-4) + @; + if (dot_pos==NULL) + sprintf(change_file_name,"%s.ch",*argv); + else strcpy(change_file_name,*argv); + found_change=1; + } +} + +@ @= +{ + if (s-*argv > max_file_name_length-5) + @; + 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); + strcpy(C_file_name,*argv); + if (flags['x']) { /* indexes will be generated */ + *dot_pos=0; + sprintf(idx_file_name,"%s.idx",*argv); + sprintf(scn_file_name,"%s.scn",*argv); + } + } + found_out=1; +} + +@ @= +{ + if (**argv=='-') flag_change=0; + else flag_change=1; + for(dot_pos=*argv+1;*dot_pos>'\0';dot_pos++) + flags[*dot_pos]=flag_change; +} + +@ @= +{ +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" + ,""); +} + +@ @= fatal("! Filename too long\n", *argv); +@.Filename too long@> + +@** Output. Here is the code that opens the output file: +@^system dependencies@> + +@= +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_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 \.{} where others have \.{}.) + +@= +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/cweb/ctang-bs.ch b/web/c_cpp/cweb/ctang-bs.ch new file mode 100644 index 0000000000..c4062c4064 --- /dev/null +++ b/web/c_cpp/cweb/ctang-bs.ch @@ -0,0 +1,202 @@ +Changes for CTANGLE for MSDOS and Borland C++ 3.1 using the following +options (and perhaps others): + + -mc -w-pro -Ff=5000 -Z- -O-p + +The options -Z- and -O-p explicitly turn off optimizations that break +the code. (See makefile.bs.) + +The main purpose of these changes is to support MSDOS with full-size arrays +by using "huge" pointers. + +(This file contributed by Barry Schwartz, trashman@crud.mn.org, 28 Jun 94; + revised 24 Jul 94.) + + +@x Section 1. +The ``banner line'' defined here should be changed whenever \.{CTANGLE} +is modified. + +@d banner "This is CTANGLE (Version 3.64)\n" +@y +The ``banner line'' defined here should be changed whenever \.{CTANGLE} +is modified. + +@d banner "This is CTANGLE (Version 3.64pc/big)\n" +@z + + +@x Section 4. +@ The following parameters were sufficient in the original \.{TANGLE} to +handle \TEX/, +so they should be sufficient for most applications of \.{CTANGLE}. +If you change |max_bytes|, |max_names| or |hash_size| you should also +change them in the file |"common.w"|. + +@d max_bytes 90000 /* the number of bytes in identifiers, + index entries, and section names; used in |"common.w"| */ +@d max_toks 270000 /* number of bytes in compressed \CEE/ code */ +@d max_names 4000 /* number of identifiers, strings, section names; + must be less than 10240; used in |"common.w"| */ +@d max_texts 2500 /* number of replacement texts, must be less than 10240 */ +@d hash_size 353 /* should be prime; used in |"common.w"| */ +@d longest_name 10000 /* section names shouldn't be longer than this */ +@d stack_size 50 /* number of simultaneous levels of macro expansion */ +@d buf_size 100 /* for \.{CWEAVE} and \.{CTANGLE} */ +@y +@ The following parameters were sufficient in the original \.{TANGLE} to +handle \TEX/, +so they should be sufficient for most applications of \.{CTANGLE}. +If you change |max_bytes|, |max_names| or |hash_size| you should also +change them in the file |"common.w"|. + +(This is a modified version of \.{CTANGLE}, and in fact one of the parameters +has been reduced in value. The parameter |max_toks| +has been reduced from 270000 [which +was sufficient to handle \TEX/] to +170000, so that \.{CTANGLE} +may be run on {\mc MSDOS} +systems that are tight on memory. Consider, for +instance, an 80286-based machine with several TSRs and drivers, trying +to run \.{CTANGLE} from a makefile.) + +@d max_bytes 90000 /* the number of bytes in identifiers, + index entries, and section names; used in |"common.w"| */ +@d max_toks 170000 /* number of bytes in compressed \CEE/ code */ +@d max_names 4000 /* number of identifiers, strings, section names; + must be less than 10240; used in |"common.w"| */ +@d max_texts 2500 /* number of replacement texts, must be less than 10240 */ +@d hash_size 353 /* should be prime; used in |"common.w"| */ +@d longest_name 10000 /* section names shouldn't be longer than this */ +@d stack_size 50 /* number of simultaneous levels of macro expansion */ +@d buf_size 100 /* for \.{CWEAVE} and \.{CTANGLE} */ +@z + + +@x Section 9. +@d chunk_marker 0 + +@= +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 */ + char Ilk; /* used by identifiers in \.{CWEAVE} only */ + } 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 |name_dir| */ +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(); +@y +@d chunk_marker 0 + +@f huge extern + +@= +typedef struct name_info { + char huge* 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 */ + char Ilk; /* used by identifiers in \.{CWEAVE} only */ + } dummy; + union { + char *equiv_member; + char huge* xref_member; + } ptr_union; /* info corresponding to names */ +} name_info; /* contains information about an identifier or section name */ +typedef name_info *name_pointer; /* pointer into array of \&{name\_info}s */ +typedef name_pointer *hash_pointer; +extern char huge byte_mem[]; /* characters of names */ +extern char huge* 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 |name_dir| */ +extern char huge* 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(); +@z + + +@x Section 16. + eight_bits *tok_start; /* pointer into |tok_mem| */ + sixteen_bits text_link; /* relates replacement texts */ +} text; +typedef text *text_pointer; +@y + eight_bits huge* tok_start; /* pointer into |tok_mem| */ + sixteen_bits text_link; /* relates replacement texts */ +} text; +typedef text *text_pointer; +@z + + +@x Section 17. +eight_bits tok_mem[max_toks]; +eight_bits *tok_mem_end=tok_mem+max_toks-1; +eight_bits *tok_ptr; /* first unused position in |tok_mem| */ +@y +eight_bits huge tok_mem[max_toks]; +eight_bits huge* tok_mem_end; +eight_bits huge* tok_ptr; /* first unused position in |tok_mem| */ +@z + + +@x Section 18. +text_info->tok_start=tok_ptr=tok_mem; +text_ptr=text_info+1; text_ptr->tok_start=tok_mem; + /* this makes replacement text 0 of length zero */ +@y +tok_mem_end=tok_mem+max_toks-1; +text_info->tok_start=tok_ptr=tok_mem; +text_ptr=text_info+1; text_ptr->tok_start=tok_mem; + /* this makes replacement text 0 of length zero */ +@z + + +@x Section 19. +@d equiv equiv_or_xref /* info corresponding to names */ +@y +@d equiv ptr_union.equiv_member /* info corresponding to names */ +@z + + +@x Section 27. + eight_bits *end_field; /* ending location of replacement text */ + eight_bits *byte_field; /* present location within replacement text */ +@y + eight_bits huge* end_field; /* ending location of replacement text */ + eight_bits huge* byte_field; /* present location within replacement text */ +@z + + +@x Section 49. +out_char(cur_char) +eight_bits cur_char; +{ + char *j, *k; /* pointer into |byte_mem| */ +@y +out_char(cur_char) +eight_bits cur_char; +{ + char huge* j, huge* k; /* pointer into |byte_mem| */ +@z diff --git a/web/c_cpp/cweb/ctang-man.ch b/web/c_cpp/cweb/ctang-man.ch new file mode 100644 index 0000000000..12e9d3248e --- /dev/null +++ b/web/c_cpp/cweb/ctang-man.ch @@ -0,0 +1,22 @@ +Change file to help make Appendix E of the full CWEB manual +@x +\def\botofcontents{\vfill +\noindent +Copyright \copyright\ 1987, 1990, 1993, 2000 Silvio Levy and Donald E. Knuth +\bigskip\noindent +Permission is granted to make and distribute verbatim copies of this +document provided that the copyright notice and this permission notice +are preserved on all copies. + +\smallskip\noindent +Permission is granted to copy and distribute modified versions of this +document under the conditions for verbatim copying, provided that the +entire resulting derived work is given a different name and distributed +under the terms of a permission notice identical to this one. +} +@y +\def\botofcontents{\vfill\titlefalse} +\def\contentspagenumber{63} +\def\title{APPENDIX E: CTANGLE} +\let\K=\leftarrow +@z diff --git a/web/c_cpp/cweb/ctang-pc.ch b/web/c_cpp/cweb/ctang-pc.ch new file mode 100644 index 0000000000..67f32fae0c --- /dev/null +++ b/web/c_cpp/cweb/ctang-pc.ch @@ -0,0 +1,24 @@ +This is the change file for CWEB's CTANGLE under DOS +(Contributed by Lee Wittenberg, March 1993) + +Changes necessary for compiling with Borland C/C++ +Use compilation switches -mc -w-pro -Ff=5000 + +Note: The changes to section 4 are not necessary if using a compiler +that allows >64K arrays. If you need lots of bytes and toks, try the +alternate change files with -bs suffix instead of -pc. + +@x section 1 +@d banner "This is CTANGLE (Version 3.64)\n" +@y +@d banner "This is CTANGLE (Version 3.64pc)\n" +@z +@x section 4 +@d max_bytes 90000 /* the number of bytes in identifiers, + index entries, and section names; used in |"common.w"| */ +@d max_toks 270000 /* number of bytes in compressed \CEE/ code */ +@y (note that CWEAVE itself needs only about 42K toks) +@d max_bytes (unsigned)60000 /* the number of bytes in identifiers, + index entries, and section names; used in |"common.w"| */ +@d max_toks (unsigned)60000 /* number of bytes in compressed \CEE/ code */ +@z diff --git a/web/c_cpp/cweb/ctang-ql.ch b/web/c_cpp/cweb/ctang-ql.ch new file mode 100644 index 0000000000..a0920243a9 --- /dev/null +++ b/web/c_cpp/cweb/ctang-ql.ch @@ -0,0 +1,25 @@ +This is the change file for CWEB's CTANGLE under QDOS/SMSQ +(Contributed by Robert H. Klein, September 1994) + +This change file is intended for use with C68 v4.13 (or later). +compile with +ex cc;"-v -h -c -=500000 ctangle_c" + + +@x +\def\title{CTANGLE (Version 3.64)} +@y +\def\title{CTANGLE (QL Version 3.64)} +@z + +@x section 1 +@d banner "This is CTANGLE (Version 3.64)\n" +@y +@d banner "This is CTANGLE (QL Version 3.64)\n" +@z + +@x +@i common.h +@y +@i common_h +@z diff --git a/web/c_cpp/cweb/ctang-vms.ch b/web/c_cpp/cweb/ctang-vms.ch new file mode 100644 index 0000000000..7e538abc27 --- /dev/null +++ b/web/c_cpp/cweb/ctang-vms.ch @@ -0,0 +1,35 @@ +This is the change file for CWEB's CTANGLE for VAX/VMS. + +created: + 01-FEB-1992 ST (Stephan Trebels ) + > include ctype,stdio from textlibrary SYS$SHARE:VAXCDEF.TLB + > change banner line to include (VAX/VMS) + ? will someone make a CLD interface? (should be easy) + +(also modified by Don Knuth to keep version numbers uptodate) +(these changes not necessary for initial bootstrapping) + +@x section 1 (01-FEB-1992 ST) +@d banner "This is CTANGLE (Version 3.64)\n" +@y +@d banner "This is CTANGLE (VAX/VMS Version 3.64)\n" +@z + +@x section 6 (from common.h) (01-FEB-1992 ST) +#include +@y +#include stdio /* VMS searches Textlibraries faster */ +@z + +@x section 62 (01-FEB-1992 ST) +#include /* definition of |isalpha|, |isdigit| and so on */ +@y +#include ctype /* definition of |isalpha|, |isdigit| and so on */ + /* VMS searches text libraries faster */ +@z + +@x section 63 (01-FEB-1992 ST) +@d isxalpha(c) ((c)=='_') /* non-alpha character allowed in identifier */ +@y +@d isxalpha(c) ((c)=='_' || (c)=='$') /* non-alpha characters allowed in id */ +@z diff --git a/web/c_cpp/cweb/ctang-w32.ch b/web/c_cpp/cweb/ctang-w32.ch new file mode 100644 index 0000000000..523985ce3d --- /dev/null +++ b/web/c_cpp/cweb/ctang-w32.ch @@ -0,0 +1,66 @@ +This is the change file for CWEB's CTANGLE under Win32 +(Contributed by Fabrice Popineau, February 2002) + +Changes necessary for compiling with Borland C/C++ + +@x section 1 +@d banner "This is CTANGLE (Version 3.64)\n" +@y +@d banner "This is CTANGLE (Version 3.64win32)\n" +@z + +@x +@ 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 \.{} where others have \.{}.) + +@= +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 */ +@y +@z + +@x +int names_match(p,first,l) +name_pointer p; /* points to the proposed match */ +char *first; /* position of first character of string */ +@y +int __cdecl names_match(p,first,l) +name_pointer p; /* points to the proposed match */ +char *first; /* position of first character of string */ +@z + +@x +void +init_node(node) +name_pointer node; +{ + node->equiv=(char *)text_info; +} +void +init_p() {} +@y +void +init_node(node) +name_pointer node; +{ + node->equiv=(char *)text_info; +} +void __cdecl +init_p() {} +@z + +@x +@ @= +#include /* definition of |isalpha|, |isdigit| and so on */ +#include /* definition of |exit| */ +@y +@ @= +#include /* definition of |isalpha|, |isdigit| and so on */ +#include /* definition of |exit| */ +#include +@z diff --git a/web/c_cpp/cweb/ctangle.c b/web/c_cpp/cweb/ctangle.c new file mode 100644 index 0000000000..b7a1b553ce --- /dev/null +++ b/web/c_cpp/cweb/ctangle.c @@ -0,0 +1,1579 @@ +/*1:*/ +#line 64 "ctangle.w" + +/*6:*/ +#line 35 "common.h" + +#include + +/*:6*//*62:*/ +#line 888 "ctangle.w" + +#include +#include + +/*:62*/ +#line 65 "ctangle.w" + +#define banner "This is CTANGLE (Version 3.64)\n" \ + +#define max_bytes 90000 \ + +#define max_toks 270000 +#define max_names 4000 \ + +#define max_texts 2500 +#define hash_size 353 +#define longest_name 10000 +#define stack_size 50 +#define buf_size 100 \ + +#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 equiv equiv_or_xref \ + +#define section_flag max_texts \ + +#define string 02 +#define join 0177 +#define output_defs_flag (2*024000-1) \ + +#define cur_end cur_state.end_field +#define cur_byte cur_state.byte_field +#define cur_name cur_state.name_field +#define cur_repl cur_state.repl_field +#define cur_section cur_state.section_field \ + +#define section_number 0201 +#define identifier 0202 \ + +#define normal 0 +#define num_or_id 1 +#define post_slash 2 +#define unbreakable 3 +#define verbatim 4 \ + +#define max_files 256 +#define translit_length 10 \ + +#define ignore 0 +#define ord 0302 +#define control_text 0303 +#define translit_code 0304 +#define output_defs_code 0305 +#define format_code 0306 +#define definition 0307 +#define begin_C 0310 +#define section_name 0311 +#define new_section 0312 \ + +#define constant 03 \ + +#define isxalpha(c) ((c) =='_'||(c) =='$') \ + +#define ishigh(c) ((unsigned char) (c) > 0177) \ + \ + +#define compress(c) if(loc++<=limit) return(c) \ + +#define macro 0 +#define app_repl(c) {if(tok_ptr==tok_mem_end) overflow("token") ;*tok_ptr++= c;} \ + + +#line 66 "ctangle.w" + +/*5:*/ +#line 29 "common.h" + +typedef short boolean; +typedef char unsigned eight_bits; +extern boolean program; +extern int phase; + +/*:5*//*7:*/ +#line 57 "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 72 "common.h" + +extern char buffer[]; +extern char*buffer_end; +extern char*loc; +extern char*limit; + +/*:8*//*9:*/ +#line 87 "common.h" + +typedef struct name_info{ +char*byte_start; +struct name_info*link; +union{ +struct name_info*Rlink; + +char Ilk; +}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 122 "common.h" + +extern history; +extern err_print(); +extern wrap_up(); +extern void fatal(); +extern void overflow(); + +/*:10*//*11:*/ +#line 137 "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 change_depth; +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 159 "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 171 "common.h" + +extern int argc; +extern char**argv; +extern boolean flags[]; + +/*:13*//*14:*/ +#line 183 "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 192 "common.h" + +extern void common_init(); +#line 128 "ctangle.w" + +/*:15*/ +#line 67 "ctangle.w" + +/*16:*/ +#line 152 "ctangle.w" + +typedef struct{ +eight_bits*tok_start; +sixteen_bits text_link; +}text; +typedef text*text_pointer; + +/*:16*//*27:*/ +#line 296 "ctangle.w" + +typedef struct{ +eight_bits*end_field; +eight_bits*byte_field; +name_pointer name_field; +text_pointer repl_field; +sixteen_bits section_field; +}output_state; +typedef output_state*stack_pointer; + +/*:27*/ +#line 68 "ctangle.w" + +/*17:*/ +#line 159 "ctangle.w" + +text text_info[max_texts]; +text_pointer text_info_end= text_info+max_texts-1; +text_pointer text_ptr; +eight_bits tok_mem[max_toks]; +eight_bits*tok_mem_end= tok_mem+max_toks-1; +eight_bits*tok_ptr; + +/*:17*//*23:*/ +#line 227 "ctangle.w" + +text_pointer last_unnamed; + +/*:23*//*28:*/ +#line 312 "ctangle.w" + +output_state cur_state; + +output_state stack[stack_size+1]; +stack_pointer stack_ptr; +stack_pointer stack_end= stack+stack_size; + +/*:28*//*32:*/ +#line 384 "ctangle.w" + +int cur_val; + +/*:32*//*36:*/ +#line 473 "ctangle.w" + +eight_bits out_state; +boolean protect; + +/*:36*//*38:*/ +#line 502 "ctangle.w" + +name_pointer output_files[max_files]; +name_pointer*cur_out_file,*end_output_files,*an_output_file; +char cur_section_name_char; +char output_file_name[longest_name]; + +/*:38*//*45:*/ +#line 599 "ctangle.w" + +boolean output_defs_seen= 0; + +/*:45*//*51:*/ +#line 710 "ctangle.w" + +char translit[128][translit_length]; + +/*:51*//*56:*/ +#line 789 "ctangle.w" + +eight_bits ccode[256]; + +/*:56*//*59:*/ +#line 845 "ctangle.w" + +boolean comment_continues= 0; + +/*:59*//*61:*/ +#line 884 "ctangle.w" + +name_pointer cur_section_name; +int no_where; + +/*:61*//*75:*/ +#line 1195 "ctangle.w" + +text_pointer cur_text; +eight_bits next_control; + +/*:75*//*82:*/ +#line 1353 "ctangle.w" + +extern sixteen_bits section_count; + +/*:82*/ +#line 69 "ctangle.w" + +/*2:*/ +#line 77 "ctangle.w" + +extern int strlen(); +extern int strcmp(); +extern char*strcpy(); +extern int strncmp(); +extern char*strncpy(); + +/*:2*//*41:*/ +#line 533 "ctangle.w" + +void phase_two(); + +/*:41*//*46:*/ +#line 602 "ctangle.w" + +void output_defs(); + +/*:46*//*48:*/ +#line 648 "ctangle.w" + +static void out_char(); + +/*:48*//*90:*/ +#line 1460 "ctangle.w" + +void phase_one(); + +/*:90*//*92:*/ +#line 1478 "ctangle.w" + +void skip_limbo(); + +/*:92*/ +#line 70 "ctangle.w" + + +/*:1*//*3:*/ +#line 91 "ctangle.w" + +int main(ac,av) +int ac; +char**av; +{ +argc= ac;argv= av; +program= ctangle; +/*18:*/ +#line 167 "ctangle.w" + +text_info->tok_start= tok_ptr= tok_mem; +text_ptr= text_info+1;text_ptr->tok_start= tok_mem; + + +/*:18*//*20:*/ +#line 177 "ctangle.w" + +name_dir->equiv= (char*)text_info; + +/*:20*//*24:*/ +#line 230 "ctangle.w" +last_unnamed= text_info;text_info->text_link= 0; + +/*:24*//*39:*/ +#line 512 "ctangle.w" + +cur_out_file= end_output_files= output_files+max_files; + +/*:39*//*52:*/ +#line 713 "ctangle.w" + +{ +int i; +for(i= 0;i<128;i++)sprintf(translit[i],"X%02X",(unsigned)(128+i)); +} + +/*:52*//*57:*/ +#line 792 "ctangle.w" +{ +int c; +for(c= 0;c<256;c++)ccode[c]= ignore; +ccode[' ']= ccode['\t']= ccode['\n']= ccode['\v']= ccode['\r']= ccode['\f'] += ccode['*']= new_section; +ccode['@']= '@';ccode['=']= string; +ccode['d']= ccode['D']= definition; +ccode['f']= ccode['F']= ccode['s']= ccode['S']= format_code; +ccode['c']= ccode['C']= ccode['p']= ccode['P']= begin_C; +ccode['^']= ccode[':']= ccode['.']= ccode['t']= ccode['T']= +ccode['q']= ccode['Q']= control_text; +ccode['h']= ccode['H']= output_defs_code; +ccode['l']= ccode['L']= translit_code; +ccode['&']= join; +ccode['<']= ccode['(']= section_name; +ccode['\'']= ord; +} + +/*:57*//*71:*/ +#line 1116 "ctangle.w" +section_text[0]= ' '; + +/*:71*/ +#line 98 "ctangle.w" +; +common_init(); +if(show_banner)printf(banner); +phase_one(); +phase_two(); +return wrap_up(); +} + +/*:3*//*21:*/ +#line 183 "ctangle.w" + +int names_match(p,first,l) +name_pointer p; +char*first; +int l; +{ +if(length(p)!=l)return 0; +return!strncmp(first,p->byte_start,l); +} + +/*:21*//*22:*/ +#line 198 "ctangle.w" + +void +init_node(node) +name_pointer node; +{ +node->equiv= (char*)text_info; +} +void +init_p(){} + +/*:22*//*26:*/ +#line 260 "ctangle.w" + +void +store_two_bytes(x) +sixteen_bits x; +{ +if(tok_ptr+2> tok_mem_end)overflow("token"); +*tok_ptr++= x>>8; +*tok_ptr++= x&0377; +} + +/*:26*//*30:*/ +#line 336 "ctangle.w" + +void +push_level(p) +name_pointer p; +{ +if(stack_ptr==stack_end)overflow("stack"); +*stack_ptr= cur_state; +stack_ptr++; +if(p!=NULL){ +cur_name= p;cur_repl= (text_pointer)p->equiv; +cur_byte= cur_repl->tok_start;cur_end= (cur_repl+1)->tok_start; +cur_section= 0; +} +} + +/*:30*//*31:*/ +#line 355 "ctangle.w" + +void +pop_level(flag) +int flag; +{ +if(flag&&cur_repl->text_linktext_link+text_info; +cur_byte= cur_repl->tok_start;cur_end= (cur_repl+1)->tok_start; +return; +} +stack_ptr--; +if(stack_ptr> stack)cur_state= *stack_ptr; +} + +/*:31*//*33:*/ +#line 391 "ctangle.w" + +void +get_output() +{ +sixteen_bits a; +restart:if(stack_ptr==stack)return; +if(cur_byte==cur_end){ +cur_val= -((int)cur_section); +pop_level(1); +if(cur_val==0)goto restart; +out_char(section_number);return; +} +a= *cur_byte++; +if(out_state==verbatim&&a!=string&&a!=constant&&a!='\n') +C_putc(a); +else if(a<0200)out_char(a); +else{ +a= (a-0200)*0400+*cur_byte++; +switch(a/024000){ +case 0:cur_val= a;out_char(identifier);break; +case 1:if(a==output_defs_flag)output_defs(); +else/*34:*/ +#line 423 "ctangle.w" + +{ +a-= 024000; +if((a+name_dir)->equiv!=(char*)text_info)push_level(a+name_dir); +else if(a!=0){ +printf("\n! Not present: <"); +print_section_name(a+name_dir);err_print(">"); + +} +goto restart; +} + +/*:34*/ +#line 412 "ctangle.w" +; +break; +default:cur_val= a-050000;if(cur_val> 0)cur_section= cur_val; +out_char(section_number); +} +} +} + +/*:33*//*37:*/ +#line 481 "ctangle.w" + +void +flush_buffer() +{ +C_putc('\n'); +if(cur_line%100==0&&show_progress){ +printf("."); +if(cur_line%500==0)printf("%d",cur_line); +update_terminal; +} +cur_line++; +} + +/*:37*//*42:*/ +#line 536 "ctangle.w" + +void +phase_two(){ +web_file_open= 0; +cur_line= 1; +/*29:*/ +#line 325 "ctangle.w" + +stack_ptr= stack+1;cur_name= name_dir;cur_repl= text_info->text_link+text_info; +cur_byte= cur_repl->tok_start;cur_end= (cur_repl+1)->tok_start;cur_section= 0; + +/*:29*/ +#line 541 "ctangle.w" +; +/*44:*/ +#line 595 "ctangle.w" + +if(!output_defs_seen) +output_defs(); + +/*:44*/ +#line 542 "ctangle.w" +; +if(text_info->text_link==0&&cur_out_file==end_output_files){ +printf("\n! No program text was specified.");mark_harmless; + +} +else{ +if(cur_out_file==end_output_files){ +if(show_progress) +printf("\nWriting the output file (%s):",C_file_name); +} +else{ +if(show_progress){ +printf("\nWriting the output files:"); + +printf(" (%s)",C_file_name); +update_terminal; +} +if(text_info->text_link==0)goto writeloop; +} +while(stack_ptr> stack)get_output(); +flush_buffer(); +writeloop:/*43:*/ +#line 572 "ctangle.w" + +for(an_output_file= end_output_files;an_output_file> cur_out_file;){ +an_output_file--; +sprint_section_name(output_file_name,*an_output_file); +fclose(C_file); +C_file= fopen(output_file_name,"w"); +if(C_file==0)fatal("! Cannot open output file:",output_file_name); + +printf("\n(%s)",output_file_name);update_terminal; +cur_line= 1; +stack_ptr= stack+1; +cur_name= (*an_output_file); +cur_repl= (text_pointer)cur_name->equiv; +cur_byte= cur_repl->tok_start; +cur_end= (cur_repl+1)->tok_start; +while(stack_ptr> stack)get_output(); +flush_buffer(); +} + +/*:43*/ +#line 563 "ctangle.w" +; +if(show_happiness)printf("\nDone."); +} +} + +/*:42*//*47:*/ +#line 605 "ctangle.w" + +void +output_defs() +{ +sixteen_bits a; +push_level(NULL); +for(cur_text= text_info+1;cur_texttext_link==0){ +cur_byte= cur_text->tok_start; +cur_end= (cur_text+1)->tok_start; +C_printf("%s","#define "); +out_state= normal; +protect= 1; +while(cur_bytebyte_start; +k= (cur_val+name_dir+1)->byte_start; +while(j 0)C_printf("/*%d:*/",cur_val); +else if(cur_val<0)C_printf("/*:%d*/",-cur_val); +else if(protect){ +cur_byte+= 4; +cur_char= '\n'; +goto restart; +}else{ +sixteen_bits a; +a= 0400**cur_byte++; +a+= *cur_byte++; +C_printf("\n#line %d \"",a); + +cur_val= *cur_byte++; +cur_val= 0400*(cur_val-0200)+*cur_byte++; +for(j= (cur_val+name_dir)->byte_start,k= (cur_val+name_dir+1)->byte_start; +j');out_state= normal;break; +case gt_gt:C_putc('>');C_putc('>');out_state= normal;break; +case eq_eq:C_putc('=');C_putc('=');out_state= normal;break; +case lt_lt:C_putc('<');C_putc('<');out_state= normal;break; +case gt_eq:C_putc('>');C_putc('=');out_state= normal;break; +case lt_eq:C_putc('<');C_putc('=');out_state= normal;break; +case not_eq:C_putc('!');C_putc('=');out_state= normal;break; +case and_and:C_putc('&');C_putc('&');out_state= normal;break; +case or_or:C_putc('|');C_putc('|');out_state= normal;break; +case dot_dot_dot:C_putc('.');C_putc('.');C_putc('.');out_state= normal; +break; +case colon_colon:C_putc(':');C_putc(':');out_state= normal;break; +case period_ast:C_putc('.');C_putc('*');out_state= normal;break; +case minus_gt_ast:C_putc('-');C_putc('>');C_putc('*');out_state= normal; +break; + +/*:50*/ +#line 664 "ctangle.w" +; +case'=':case'>':C_putc(cur_char);C_putc(' '); +out_state= normal;break; +case join:out_state= unbreakable;break; +case constant:if(out_state==verbatim){ +out_state= num_or_id;break; +} +if(out_state==num_or_id)C_putc(' ');out_state= verbatim;break; +case string:if(out_state==verbatim)out_state= normal; +else out_state= verbatim;break; +case'/':C_putc('/');out_state= post_slash;break; +case'*':if(out_state==post_slash)C_putc(' '); + +default:C_putc(cur_char);out_state= normal;break; +} +} + +/*:49*//*58:*/ +#line 813 "ctangle.w" + +eight_bits +skip_ahead() +{ +eight_bits c; +while(1){ +if(loc> limit&&(get_line()==0))return(new_section); +*(limit+1)= '@'; +while(*loc!='@')loc++; +if(loc<=limit){ +loc++;c= ccode[(eight_bits)*loc];loc++; +if(c!=ignore||*(loc-1)=='>')return(c); +} +} +} + +/*:58*//*60:*/ +#line 848 "ctangle.w" + +int skip_comment(is_long_comment) +boolean is_long_comment; +{ +char c; +while(1){ +if(loc> limit){ +if(is_long_comment){ +if(get_line())return(comment_continues= 1); +else{ +err_print("! Input ended in mid-comment"); + +return(comment_continues= 0); +} +} +else return(comment_continues= 0); +} +c= *(loc++); +if(is_long_comment&&c=='*'&&*loc=='/'){ +loc++;return(comment_continues= 0); +} +if(c=='@'){ +if(ccode[(eight_bits)*loc]==new_section){ +err_print("! Section name ended in mid-comment");loc--; + +return(comment_continues= 0); +} +else loc++; +} +} +} + +/*:60*//*63:*/ +#line 900 "ctangle.w" + +eight_bits +get_next() +{ +static int preprocessing= 0; +eight_bits c; +while(1){ +if(loc> limit){ +if(preprocessing&&*(limit-1)!='\\')preprocessing= 0; +if(get_line()==0)return(new_section); +else if(print_where&&!no_where){ +print_where= 0; +/*77:*/ +#line 1225 "ctangle.w" + +store_two_bytes(0150000); +if(changing&&include_depth==change_depth){ +id_first= change_file_name; +store_two_bytes((sixteen_bits)change_line); +}else{ +id_first= cur_file_name; +store_two_bytes((sixteen_bits)cur_line); +} +id_loc= id_first+strlen(id_first); +{int a= id_lookup(id_first,id_loc,0)-name_dir;app_repl((a/0400)+0200); +app_repl(a%0400);} + +/*:77*/ +#line 912 "ctangle.w" +; +} +else return('\n'); +} +c= *loc; +if(comment_continues||(c=='/'&&(*(loc+1)=='*'||*(loc+1)=='/'))){ +skip_comment(comment_continues||*(loc+1)=='*'); + +if(comment_continues)return('\n'); +else continue; +} +loc++; +if(xisdigit(c)||c=='.')/*66:*/ +#line 978 "ctangle.w" +{ +id_first= loc-1; +if(*id_first=='.'&&!xisdigit(*loc))goto mistake; +if(*id_first=='0'){ +if(*loc=='x'||*loc=='X'){ +loc++;while(xisxdigit(*loc))loc++;goto found; +} +} +while(xisdigit(*loc))loc++; +if(*loc=='.'){ +loc++; +while(xisdigit(*loc))loc++; +} +if(*loc=='e'||*loc=='E'){ +if(*++loc=='+'||*loc=='-')loc++; +while(xisdigit(*loc))loc++; +} +found:while(*loc=='u'||*loc=='U'||*loc=='l'||*loc=='L' +||*loc=='f'||*loc=='F')loc++; +id_loc= loc; +return(constant); +} + +/*:66*/ +#line 924 "ctangle.w" + +else if(c=='\''||c=='"'||(c=='L'&&(*loc=='\''||*loc=='"'))) +/*67:*/ +#line 1006 "ctangle.w" +{ +char delim= c; +id_first= section_text+1; +id_loc= section_text;*++id_loc= delim; +if(delim=='L'){ +delim= *loc++;*++id_loc= 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; + +} +else if(++id_loc<=section_text_end)*id_loc= '\n'; + +} +if((c= *loc++)==delim){ +if(++id_loc<=section_text_end)*id_loc= c; +break; +} +if(c=='\\'){ +if(loc>=limit)continue; +if(++id_loc<=section_text_end)*id_loc= '\\'; +c= *loc++; +} +if(++id_loc<=section_text_end)*id_loc= c; +} +if(id_loc>=section_text_end){ +printf("\n! String too long: "); + +term_write(section_text+1,25); +err_print("..."); +} +id_loc++; +return(string); +} + +/*:67*/ +#line 926 "ctangle.w" + +else if(isalpha(c)||isxalpha(c)||ishigh(c)) +/*65:*/ +#line 972 "ctangle.w" +{ +id_first= --loc; +while(isalpha(*++loc)||isdigit(*loc)||isxalpha(*loc)||ishigh(*loc)); +id_loc= loc;return(identifier); +} + +/*:65*/ +#line 928 "ctangle.w" + +else if(c=='@')/*68:*/ +#line 1050 "ctangle.w" +{ +c= ccode[(eight_bits)*loc++]; +switch(c){ +case ignore:continue; +case translit_code:err_print("! Use @l in limbo only");continue; + +case control_text:while((c= skip_ahead())=='@'); + +if(*(loc-1)!='>') +err_print("! Double @ should be used in control text"); + +continue; +case section_name: +cur_section_name_char= *(loc-1); +/*70:*/ +#line 1098 "ctangle.w" +{ +char*k; +/*72:*/ +#line 1118 "ctangle.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; +/*73:*/ +#line 1142 "ctangle.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(ccode[(eight_bits)c]==section_name){ +err_print("! Nesting of section names not allowed");break; + +} +*(++k)= '@';loc++; +} + +/*:73*/ +#line 1127 "ctangle.w" +; +loc++;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--; + +/*:72*/ +#line 1100 "ctangle.w" +; +if(k-section_text> 3&&strncmp(k-2,"...",3)==0) +cur_section_name= section_lookup(section_text+1,k-3,1); +else cur_section_name= section_lookup(section_text+1,k,0); +if(cur_section_name_char=='(') +/*40:*/ +#line 516 "ctangle.w" + +{ +for(an_output_file= cur_out_file; +an_output_file output_files) +*--cur_out_file= cur_section_name; +else{ +overflow("output files"); +} +} +} + +/*:40*/ +#line 1106 "ctangle.w" +; +return(section_name); +} + +/*:70*/ +#line 1064 "ctangle.w" +; +case string:/*74:*/ +#line 1164 "ctangle.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(string); +} + +/*:74*/ +#line 1065 "ctangle.w" +; +case ord:/*69:*/ +#line 1077 "ctangle.w" + +id_first= loc; +if(*loc=='\\'){ +if(*++loc=='\'')loc++; +} +while(*loc!='\''){ +if(*loc=='@'){ +if(*(loc+1)!='@') +err_print("! Double @ should be used in ASCII constant"); + +else loc++; +} +loc++; +if(loc> limit){ +err_print("! String didn't end");loc= limit-1;break; + +} +} +loc++; +return(ord); + +/*:69*/ +#line 1066 "ctangle.w" +; +default:return(c); +} +} + +/*:68*/ +#line 929 "ctangle.w" + +else if(xisspace(c)){ +if(!preprocessing||loc> limit)continue; + +else return(' '); +} +else if(c=='#'&&loc==buffer+1)preprocessing= 1; +mistake:/*64:*/ +#line 950 "ctangle.w" + +switch(c){ +case'+':if(*loc=='+')compress(plus_plus);break; +case'-':if(*loc=='-'){compress(minus_minus);} +else if(*loc=='>')if(*(loc+1)=='*'){loc++;compress(minus_gt_ast);} +else compress(minus_gt);break; +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; +} + +/*:64*/ +#line 936 "ctangle.w" + +return(c); +} +} + +/*:63*//*76:*/ +#line 1199 "ctangle.w" + +void +scan_repl(t) +eight_bits t; +{ +sixteen_bits a; +if(t==section_name){/*77:*/ +#line 1225 "ctangle.w" + +store_two_bytes(0150000); +if(changing&&include_depth==change_depth){ +id_first= change_file_name; +store_two_bytes((sixteen_bits)change_line); +}else{ +id_first= cur_file_name; +store_two_bytes((sixteen_bits)cur_line); +} +id_loc= id_first+strlen(id_first); +{int a= id_lookup(id_first,id_loc,0)-name_dir;app_repl((a/0400)+0200); +app_repl(a%0400);} + +/*:77*/ +#line 1205 "ctangle.w" +;} +while(1)switch(a= get_next()){ +/*78:*/ +#line 1238 "ctangle.w" + +case identifier:a= id_lookup(id_first,id_loc,0)-name_dir; +app_repl((a/0400)+0200); +app_repl(a%0400);break; +case section_name:if(t!=section_name)goto done; +else{ +/*79:*/ +#line 1271 "ctangle.w" +{ +char*try_loc= loc; +while(*try_loc==' '&&try_loc='0'&&c<='7'){ +c-= '0'; +if(*(id_first+1)>='0'&&*(id_first+1)<='7'){ +c= 8*c+*(++id_first)-'0'; +if(*(id_first+1)>='0'&&*(id_first+1)<='7'&&c<32) +c= 8*c+*(++id_first)-'0'; +} +} +else switch(c){ +case't':c= '\t';break; +case'n':c= '\n';break; +case'b':c= '\b';break; +case'f':c= '\f';break; +case'v':c= '\v';break; +case'r':c= '\r';break; +case'a':c= '\7';break; +case'?':c= '?';break; +case'x': +if(xisdigit(*(id_first+1)))c= *(++id_first)-'0'; +else if(xisxdigit(*(id_first+1))){ +++id_first; +c= toupper(*id_first)-'A'+10; +} +if(xisdigit(*(id_first+1)))c= 16*c+*(++id_first)-'0'; +else if(xisxdigit(*(id_first+1))){ +++id_first; +c= 16*c+toupper(*id_first)-'A'+10; +} +break; +case'\\':c= '\\';break; +case'\'':c= '\'';break; +case'\"':c= '\"';break; +default:err_print("! Unrecognized escape sequence"); + +} +} + +app_repl(constant); +if(c>=100)app_repl('0'+c/100); +if(c>=10)app_repl('0'+(c/10)%10); +app_repl('0'+c%10); +app_repl(constant); +} +break; + +/*:81*/ +#line 1263 "ctangle.w" +; +case definition:case format_code:case begin_C:if(t!=section_name)goto done; +else{ +err_print("! @d, @f and @c are ignored in C text");continue; + +} +case new_section:goto done; + +/*:78*/ +#line 1210 "ctangle.w" + +case')':app_repl(a); +if(t==macro)app_repl(' '); +break; +default:app_repl(a); +} +done:next_control= (eight_bits)a; +if(text_ptr> text_info_end)overflow("text"); +cur_text= text_ptr;(++text_ptr)->tok_start= tok_ptr; +} + +/*:76*//*83:*/ +#line 1360 "ctangle.w" + +void +scan_section() +{ +name_pointer p; +text_pointer q; +sixteen_bits a; +section_count++;no_where= 1; +if(*(loc-1)=='*'&&show_progress){ +printf("*%d",section_count);update_terminal; +} +next_control= 0; +while(1){ +/*84:*/ +#line 1399 "ctangle.w" + +while(next_controltext_link= 0; +} + +/*:85*/ +#line 1376 "ctangle.w" + +continue; +} +if(next_control==begin_C){ +p= name_dir;break; +} +if(next_control==section_name){ +p= cur_section_name; +/*86:*/ +#line 1431 "ctangle.w" + +while((next_control= get_next())=='+'); +if(next_control!='='&&next_control!=eq_eq) +continue; + +/*:86*/ +#line 1384 "ctangle.w" +; +break; +} +return; +} +no_where= print_where= 0; +/*87:*/ +#line 1436 "ctangle.w" + +/*88:*/ +#line 1441 "ctangle.w" + +store_two_bytes((sixteen_bits)(0150000+section_count)); + + +/*:88*/ +#line 1437 "ctangle.w" +; +scan_repl(section_name); +/*89:*/ +#line 1445 "ctangle.w" + +if(p==name_dir||p==0){ +(last_unnamed)->text_link= cur_text-text_info;last_unnamed= cur_text; +} +else if(p->equiv==(char*)text_info)p->equiv= (char*)cur_text; + +else{ +q= (text_pointer)p->equiv; +while(q->text_linktext_link+text_info; +q->text_link= cur_text-text_info; +} +cur_text->text_link= section_flag; + + +/*:89*/ +#line 1439 "ctangle.w" +; + +/*:87*/ +#line 1390 "ctangle.w" +; +} + +/*:83*//*91:*/ +#line 1463 "ctangle.w" + +void +phase_one(){ +phase= 1; +section_count= 0; +reset_input(); +skip_limbo(); +while(!input_has_ended)scan_section(); +check_complete(); +phase= 2; +} + +/*:91*//*93:*/ +#line 1481 "ctangle.w" + +void +skip_limbo() +{ +char c; +while(1){ +if(loc> limit&&get_line()==0)return; +*(limit+1)= '@'; +while(*loc!='@')loc++; +if(loc++<=limit){ +c= *loc++; +if(ccode[(eight_bits)c]==new_section)break; +switch(ccode[(eight_bits)c]){ +case translit_code:/*94:*/ +#line 1510 "ctangle.w" + +while(xisspace(*loc)&&loc limit||!xisxdigit(*(loc-3))||!xisxdigit(*(loc-2)) +||(*(loc-3)>='0'&&*(loc-3)<='7')||!xisspace(*(loc-1))) +err_print("! Improper hex number following @l"); + +else{ +unsigned i; +char*beg; +sscanf(loc-3,"%x",&i); +while(xisspace(*loc)&&loc=translit_length) +err_print("! Replacement string in @l too long"); + +else{ +strncpy(translit[i-0200],beg,loc-beg); +translit[i-0200][loc-beg]= '\0'; +} +} + +/*:94*/ +#line 1494 "ctangle.w" +;break; +case format_code:case'@':break; +case control_text:if(c=='q'||c=='Q'){ +while((c= skip_ahead())=='@'); +if(*(loc-1)!='>') +err_print("! Double @ should be used in control text"); + +break; +} +default:err_print("! Double @ should be used in limbo"); + +} +} +} +} + +/*:93*//*95:*/ +#line 1536 "ctangle.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 replacement texts (out of %ld)\n", +(long)(text_ptr-text_info),(long)max_texts); +printf("%ld bytes (out of %ld)\n", +(long)(byte_ptr-byte_mem),(long)max_bytes); +printf("%ld tokens (out of %ld)\n", +(long)(tok_ptr-tok_mem),(long)max_toks); +} + +/*:95*/ diff --git a/web/c_cpp/cweb/ctangle.w b/web/c_cpp/cweb/ctangle.w new file mode 100644 index 0000000000..130800210e --- /dev/null +++ b/web/c_cpp/cweb/ctangle.w @@ -0,0 +1,1557 @@ +% 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.64 --- February 2002 +% (same as Version 3.5 except for minor corrections) +% (also quotes backslashes in file names of #line directives) + +% Copyright (C) 1987,1990,1993,2000 Silvio Levy and Donald E. Knuth + +% Permission is granted to make and distribute verbatim copies of this +% document provided that the copyright notice and this permission notice +% are preserved on all copies. + +% Permission is granted to copy and distribute modified versions of this +% document under the conditions for verbatim copying, provided that the +% entire resulting derived work is given a different name and distributed +% under the terms of a permission notice identical to this one. + +% Here is TeX material that gets inserted after \input cwebmac +\def\hang{\hangindent 3em\indent\ignorespaces} +\def\pb{$\.|\ldots\.|$} % C brackets (|...|) +\def\v{\char'174} % vertical (|) in typewriter font +\mathchardef\RA="3221 % right arrow +\mathchardef\BA="3224 % double arrow + +\def\title{CTANGLE (Version 3.64)} +\def\topofcontents{\null\vfill + \centerline{\titlefont The {\ttitlefont CTANGLE} processor} + \vskip 15pt + \centerline{(Version 3.64)} + \vfill} +\def\botofcontents{\vfill +\noindent +Copyright \copyright\ 1987, 1990, 1993, 2000 Silvio Levy and Donald E. Knuth +\bigskip\noindent +Permission is granted to make and distribute verbatim copies of this +document provided that the copyright notice and this permission notice +are preserved on all copies. + +\smallskip\noindent +Permission is granted to copy and distribute modified versions of this +document under the conditions for verbatim copying, provided that the +entire resulting derived work is given a different name and distributed +under the terms of a permission notice identical to this one. +} +\pageno=\contentspagenumber \advance\pageno by 1 +\let\maybe=\iftrue +@s not_eq normal @q unreserve a C++ keyword @> + +@** Introduction. +This is the \.{CTANGLE} program by Silvio Levy and Donald E. Knuth, +based on \.{TANGLE} by Knuth. +We are thankful to +Nelson Beebe, Hans-Hermann Bode (to whom the \CPLUSPLUS/ adaptation is due), +Klaus Guntermann, Norman Ramsey, Tomas Rokicki, Joachim Schnitter, +Joachim Schrod, Lee Wittenberg, and others who have contributed improvements. + +The ``banner line'' defined here should be changed whenever \.{CTANGLE} +is modified. + +@d banner "This is CTANGLE (Version 3.64)\n" + +@c +@@/ +@h +@@/ +@@/ +@@/ +@@/ + +@ 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 \.{} where others have \.{}.) + +@= +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 */ + +@ \.{CTANGLE} has a fairly straightforward outline. It operates in +two phases: First it reads the source file, saving the \CEE/ code in +compressed form; then it shuffles and outputs the code. + +Please read the documentation for \.{common}, the set of routines common +to \.{CTANGLE} and \.{CWEAVE}, before proceeding further. + +@c +int main (ac, av) +int ac; +char **av; +{ + argc=ac; argv=av; + program=ctangle; + @; + common_init(); + if (show_banner) printf(banner); /* print a ``banner line'' */ + phase_one(); /* read all the user's text and compress it into |tok_mem| */ + phase_two(); /* output the contents of the compressed tables */ + return wrap_up(); /* and exit gracefully */ +} + +@ The following parameters were sufficient in the original \.{TANGLE} to +handle \TEX/, +so they should be sufficient for most applications of \.{CTANGLE}. +If you change |max_bytes|, |max_names|, or |hash_size| you should also +change them in the file |"common.w"|. + +@d max_bytes 90000 /* the number of bytes in identifiers, + index entries, and section names; used in |"common.w"| */ +@d max_toks 270000 /* number of bytes in compressed \CEE/ code */ +@d max_names 4000 /* number of identifiers, strings, section names; + must be less than 10240; used in |"common.w"| */ +@d max_texts 2500 /* number of replacement texts, must be less than 10240 */ +@d hash_size 353 /* should be prime; used in |"common.w"| */ +@d longest_name 10000 /* section names and strings shouldn't be longer than this */ +@d stack_size 50 /* number of simultaneous levels of macro expansion */ +@d buf_size 100 /* for \.{CWEAVE} and \.{CTANGLE} */ + +@ The next few sections contain stuff from the file |"common.w"| that must +be included in both |"ctangle.w"| and |"cweave.w"|. It appears in +file |"common.h"|, which needs to be updated when |"common.w"| changes. + +@i common.h + +@* Data structures exclusive to {\tt CTANGLE}. +We've already seen that the |byte_mem| array holds the names of identifiers, +strings, and sections; +the |tok_mem| array holds the replacement texts +for sections. Allocation is sequential, since things are deleted only +during Phase II, and only in a last-in-first-out manner. + +A \&{text} variable is a structure containing a pointer into +|tok_mem|, which tells where the corresponding text starts, and an +integer |text_link|, which, as we shall see later, is used to connect +pieces of text that have the same name. All the \&{text}s are stored in +the array |text_info|, and we use a |text_pointer| variable to refer +to them. + +The first position of |tok_mem| that is unoccupied by +replacement text is called |tok_ptr|, and the first unused location of +|text_info| is called |text_ptr|. Thus we usually have the identity +|text_ptr->tok_start==tok_ptr|. + +If your machine does not support |unsigned char| you should change +the definition of \&{eight\_bits} to |unsigned short|. +@^system dependencies@> + +@= +typedef struct { + eight_bits *tok_start; /* pointer into |tok_mem| */ + sixteen_bits text_link; /* relates replacement texts */ +} text; +typedef text *text_pointer; + +@ @= +text text_info[max_texts]; +text_pointer text_info_end=text_info+max_texts-1; +text_pointer text_ptr; /* first unused position in |text_info| */ +eight_bits tok_mem[max_toks]; +eight_bits *tok_mem_end=tok_mem+max_toks-1; +eight_bits *tok_ptr; /* first unused position in |tok_mem| */ + +@ @= +text_info->tok_start=tok_ptr=tok_mem; +text_ptr=text_info+1; text_ptr->tok_start=tok_mem; + /* this makes replacement text 0 of length zero */ + +@ If |p| is a pointer to a section name, |p->equiv| is a pointer to its +replacement text, an element of the array |text_info|. + +@d equiv equiv_or_xref /* info corresponding to names */ + +@ @= +name_dir->equiv=(char *)text_info; /* the undefined section has no replacement text */ + +@ Here's the procedure that decides whether a name of length |l| +starting at position |first| equals the identifier pointed to by |p|: + +@c +int names_match(p,first,l) +name_pointer p; /* points to the proposed match */ +char *first; /* position of first character of string */ +int l; /* length of identifier */ +{ + if (length(p)!=l) return 0; + return !strncmp(first,p->byte_start,l); +} + +@ The common lookup routine refers to separate routines |init_node| and +|init_p| when the data structure grows. Actually |init_p| is called only by +\.{CWEAVE}, but we need to declare a dummy version so that +the loader won't complain of its absence. + +@c +void +init_node(node) +name_pointer node; +{ + node->equiv=(char *)text_info; +} +void +init_p() {} + +@* Tokens. +Replacement texts, which represent \CEE/ code in a compressed format, +appear in |tok_mem| as mentioned above. The codes in +these texts are called `tokens'; some tokens occupy two consecutive +eight-bit byte positions, and the others take just one byte. + +If $p$ points to a replacement text, |p->tok_start| is the |tok_mem| position +of the first eight-bit code of that text. If |p->text_link==0|, +this is the replacement text for a macro, otherwise it is the replacement +text for a section. In the latter case |p->text_link| is either equal to +|section_flag|, which means that there is no further text for this section, or +|p->text_link| points to a continuation of this replacement text; such +links are created when several sections have \CEE/ texts with the same +name, and they also tie together all the \CEE/ texts of unnamed sections. +The replacement text pointer for the first unnamed section appears in +|text_info->text_link|, and the most recent such pointer is |last_unnamed|. + +@d section_flag max_texts /* final |text_link| in section replacement texts */ + +@= +text_pointer last_unnamed; /* most recent replacement text of unnamed section */ + +@ @= last_unnamed=text_info; text_info->text_link=0; + +@ If the first byte of a token is less than |0200|, the token occupies a +single byte. Otherwise we make a sixteen-bit token by combining two consecutive +bytes |a| and |b|. If |0200<=a<0250|, then |(a-0200)@t${}\times2^8$@>+b| +points to an identifier; if |0250<=a<0320|, then +|(a-0250)@t${}\times2^8$@>+b| points to a section name +(or, if it has the special value |output_defs_flag|, +to the area where the preprocessor definitions are stored); and if +|0320<=a<0400|, then |(a-0320)@t${}\times2^8$@>+b| is the number of the section +in which the current replacement text appears. + +Codes less than |0200| are 7-bit |char| codes that represent themselves. +Some of the 7-bit codes will not be present, however, so we can +use them for special purposes. The following symbolic names are used: + +\yskip \hang |join| denotes the concatenation of adjacent items with no +space or line breaks allowed between them (the \.{@@\&} operation of \.{CWEB}). + +\hang |string| denotes the beginning or end of a string, verbatim +construction or numerical constant. +@^ASCII code dependencies@> + +@d string 02 /* takes the place of extended ASCII \.{\char2} */ +@d join 0177 /* takes the place of ASCII delete */ +@d output_defs_flag (2*024000-1) + +@ The following procedure is used to enter a two-byte value into +|tok_mem| when a replacement text is being generated. + +@c +void +store_two_bytes(x) +sixteen_bits x; +{ + if (tok_ptr+2>tok_mem_end) overflow("token"); + *tok_ptr++=x>>8; /* store high byte */ + *tok_ptr++=x&0377; /* store low byte */ +} + +@** Stacks for output. The output process uses a stack to keep track +of what is going on at different ``levels'' as the sections are being +written out. Entries on this stack have five parts: + +\yskip\hang |end_field| is the |tok_mem| location where the replacement +text of a particular level will end; + +\hang |byte_field| is the |tok_mem| location from which the next token +on a particular level will be read; + +\hang |name_field| points to the name corresponding to a particular level; + +\hang |repl_field| points to the replacement text currently being read +at a particular level; + +\hang |section_field| is the section number, or zero if this is a macro. + +\yskip\noindent The current values of these five quantities are referred to +quite frequently, so they are stored in a separate place instead of in +the |stack| array. We call the current values |cur_end|, |cur_byte|, +|cur_name|, |cur_repl|, and |cur_section|. + +The global variable |stack_ptr| tells how many levels of output are +currently in progress. The end of all output occurs when the stack is +empty, i.e., when |stack_ptr==stack|. + +@= +typedef struct { + eight_bits *end_field; /* ending location of replacement text */ + eight_bits *byte_field; /* present location within replacement text */ + name_pointer name_field; /* |byte_start| index for text being output */ + text_pointer repl_field; /* |tok_start| index for text being output */ + sixteen_bits section_field; /* section number or zero if not a section */ +} output_state; +typedef output_state *stack_pointer; + +@ @d cur_end cur_state.end_field /* current ending location in |tok_mem| */ +@d cur_byte cur_state.byte_field /* location of next output byte in |tok_mem|*/ +@d cur_name cur_state.name_field /* pointer to current name being expanded */ +@d cur_repl cur_state.repl_field /* pointer to current replacement text */ +@d cur_section cur_state.section_field /* current section number being expanded */ + +@= +output_state cur_state; /* |cur_end|, |cur_byte|, |cur_name|, |cur_repl|, + and |cur_section| */ +output_state stack[stack_size+1]; /* info for non-current levels */ +stack_pointer stack_ptr; /* first unused location in the output state stack */ +stack_pointer stack_end=stack+stack_size; /* end of |stack| */ + +@ To get the output process started, we will perform the following +initialization steps. We may assume that |text_info->text_link| is nonzero, +since it points to the \CEE/ text in the first unnamed section that generates +code; if there are no such sections, there is nothing to output, and an +error message will have been generated before we do any of the initialization. + +@= +stack_ptr=stack+1; cur_name=name_dir; cur_repl=text_info->text_link+text_info; +cur_byte=cur_repl->tok_start; cur_end=(cur_repl+1)->tok_start; cur_section=0; + +@ When the replacement text for name |p| is to be inserted into the output, +the following subroutine is called to save the old level of output and get +the new one going. + +We assume that the \CEE/ compiler can copy structures. +@^system dependencies@> + +@c +void +push_level(p) /* suspends the current level */ +name_pointer p; +{ + if (stack_ptr==stack_end) overflow("stack"); + *stack_ptr=cur_state; + stack_ptr++; + if (p!=NULL) { /* |p==NULL| means we are in |output_defs| */ + cur_name=p; cur_repl=(text_pointer)p->equiv; + cur_byte=cur_repl->tok_start; cur_end=(cur_repl+1)->tok_start; + cur_section=0; + } +} + +@ When we come to the end of a replacement text, the |pop_level| subroutine +does the right thing: It either moves to the continuation of this replacement +text or returns the state to the most recently stacked level. + +@c +void +pop_level(flag) /* do this when |cur_byte| reaches |cur_end| */ +int flag; /* |flag==0| means we are in |output_defs| */ +{ + if (flag && cur_repl->text_linktext_link+text_info; /* stay on the same level */ + cur_byte=cur_repl->tok_start; cur_end=(cur_repl+1)->tok_start; + return; + } + stack_ptr--; /* go down to the previous level */ + if (stack_ptr>stack) cur_state=*stack_ptr; +} + +@ The heart of the output procedure is the function |get_output|, +which produces the next token of output and sends it on to the lower-level +function |out_char|. The main purpose of |get_output| is to handle the +necessary stacking and unstacking. It sends the value |section_number| +if the next output begins or ends the replacement text of some section, +in which case |cur_val| is that section's number (if beginning) or the +negative of that value (if ending). (A section number of 0 indicates +not the beginning or ending of a section, but a \&{\#line} command.) +And it sends the value |identifier| +if the next output is an identifier, in which case +|cur_val| points to that identifier name. + +@d section_number 0201 /* code returned by |get_output| for section numbers */ +@d identifier 0202 /* code returned by |get_output| for identifiers */ + +@= +int cur_val; /* additional information corresponding to output token */ + +@ If |get_output| finds that no more output remains, it returns with +|stack_ptr==stack|. +@^high-bit character handling@> + +@c +void +get_output() /* sends next token to |out_char| */ +{ + sixteen_bits a; /* value of current byte */ + restart: if (stack_ptr==stack) return; + if (cur_byte==cur_end) { + cur_val=-((int)cur_section); /* cast needed because of sign extension */ + pop_level(1); + if (cur_val==0) goto restart; + out_char(section_number); return; + } + a=*cur_byte++; + if (out_state==verbatim && a!=string && a!=constant && a!='\n') + C_putc(a); /* a high-bit character can occur in a string */ + else if (a<0200) out_char(a); /* one-byte token */ + else { + a=(a-0200)*0400+*cur_byte++; + switch (a/024000) { /* |024000==(0250-0200)*0400| */ + case 0: cur_val=a; out_char(identifier); break; + case 1: if (a==output_defs_flag) output_defs(); + else @; + break; + default: cur_val=a-050000; if (cur_val>0) cur_section=cur_val; + out_char(section_number); + } + } +} + +@ The user may have forgotten to give any \CEE/ text for a section name, +or the \CEE/ text may have been associated with a different name by mistake. + +@= +{ + a-=024000; + if ((a+name_dir)->equiv!=(char *)text_info) push_level(a+name_dir); + else if (a!=0) { + printf("\n! Not present: <"); + print_section_name(a+name_dir); err_print(">"); +@.Not present:
@> + } + goto restart; +} + +@* Producing the output. +The |get_output| routine above handles most of the complexity of output +generation, but there are two further considerations that have a nontrivial +effect on \.{CTANGLE}'s algorithms. + +@ First, +we want to make sure that the output has spaces and line breaks in +the right places (e.g., not in the middle of a string or a constant or an +identifier, not at a `\.{@@\&}' position +where quantities are being joined together, and certainly after an \.= +because the \CEE/ compiler thinks \.{=-} is ambiguous). + +The output process can be in one of following states: + +\yskip\hang |num_or_id| means that the last item in the buffer is a number or +identifier, hence a blank space or line break must be inserted if the next +item is also a number or identifier. + +\yskip\hang |unbreakable| means that the last item in the buffer was followed +by the \.{@@\&} operation that inhibits spaces between it and the next item. + +\yskip\hang |verbatim| means we're copying only character tokens, and +that they are to be output exactly as stored. This is the case during +strings, verbatim constructions and numerical constants. + +\yskip\hang |post_slash| means we've just output a slash. + +\yskip\hang |normal| means none of the above. + +\yskip\noindent Furthermore, if the variable |protect| is positive, newlines +are preceded by a `\.\\'. + +@d normal 0 /* non-unusual state */ +@d num_or_id 1 /* state associated with numbers and identifiers */ +@d post_slash 2 /* state following a \./ */ +@d unbreakable 3 /* state associated with \.{@@\&} */ +@d verbatim 4 /* state in the middle of a string */ + +@= +eight_bits out_state; /* current status of partial output */ +boolean protect; /* should newline characters be quoted? */ + +@ Here is a routine that is invoked when we want to output the current line. +During the output process, |cur_line| equals the number of the next line +to be output. + +@c +void +flush_buffer() /* writes one line to output file */ +{ + C_putc('\n'); + if (cur_line % 100 == 0 && show_progress) { + printf("."); + if (cur_line % 500 == 0) printf("%d",cur_line); + update_terminal; /* progress report */ + } + cur_line++; +} + +@ Second, we have modified the original \.{TANGLE} so that it will write output +on multiple files. +If a section name is introduced in at least one place by \.{@@(} +instead of \.{@@<}, we treat it as the name of a file. +All these special sections are saved on a stack, |output_files|. +We write them out after we've done the unnamed section. + +@d max_files 256 +@= +name_pointer output_files[max_files]; +name_pointer *cur_out_file, *end_output_files, *an_output_file; +char cur_section_name_char; /* is it |'<'| or |'('| */ +char output_file_name[longest_name]; /* name of the file */ + +@ We make |end_output_files| point just beyond the end of +|output_files|. The stack pointer +|cur_out_file| starts out there. Every time we see a new file, we +decrement |cur_out_file| and then write it in. +@= +cur_out_file=end_output_files=output_files+max_files; + +@ @= +{ + for (an_output_file=cur_out_file; + an_output_fileoutput_files) + *--cur_out_file=cur_section_name; + else { + overflow("output files"); + } + } +} + +@* The big output switch. Here then is the routine that does the +output. + +@= +void phase_two(); + +@ @c +void +phase_two () { + web_file_open=0; + cur_line=1; + @; + @; + if (text_info->text_link==0 && cur_out_file==end_output_files) { + printf("\n! No program text was specified."); mark_harmless; +@.No program text...@> + } + else { + if(cur_out_file==end_output_files) { + if(show_progress) + printf("\nWriting the output file (%s):",C_file_name); + } + else { + if (show_progress) { + printf("\nWriting the output files:"); +@.Writing the output...@> + printf(" (%s)",C_file_name); + update_terminal; + } + if (text_info->text_link==0) goto writeloop; + } + while (stack_ptr>stack) get_output(); + flush_buffer(); +writeloop: @; + if(show_happiness) printf("\nDone."); + } +} + +@ To write the named output files, we proceed as for the unnamed +section. +The only subtlety is that we have to open each one. + +@= +for (an_output_file=end_output_files; an_output_file>cur_out_file;) { + an_output_file--; + sprint_section_name(output_file_name,*an_output_file); + fclose(C_file); + C_file=fopen(output_file_name,"w"); + if (C_file ==0) fatal("! Cannot open output file:",output_file_name); +@.Cannot open output file@> + printf("\n(%s)",output_file_name); update_terminal; + cur_line=1; + stack_ptr=stack+1; + cur_name= (*an_output_file); + cur_repl= (text_pointer)cur_name->equiv; + cur_byte=cur_repl->tok_start; + cur_end=(cur_repl+1)->tok_start; + while (stack_ptr > stack) get_output(); + flush_buffer(); +} + +@ If a \.{@@h} was not encountered in the input, +we go through the list of replacement texts and copy the ones +that refer to macros, preceded by the \.{\#define} preprocessor command. + +@= + if (!output_defs_seen) + output_defs(); + +@ @= +boolean output_defs_seen=0; + +@ @= +void output_defs(); + +@ @c +void +output_defs() +{ + sixteen_bits a; + push_level(NULL); + for (cur_text=text_info+1; cur_texttext_link==0) { /* |cur_text| is the text for a macro */ + cur_byte=cur_text->tok_start; + cur_end=(cur_text+1)->tok_start; + C_printf("%s","#define "); + out_state=normal; + protect=1; /* newlines should be preceded by |'\\'| */ + while (cur_byte + else if (a<0200) out_char(a); /* one-byte token */ + else { + a=(a-0200)*0400+*cur_byte++; + if (a<024000) { /* |024000==(0250-0200)*0400| */ + cur_val=a; out_char(identifier); + } + else if (a<050000) { confusion("macro defs have strange char");} + else { + cur_val=a-050000; cur_section=cur_val; out_char(section_number); + } + /* no other cases */ + } + } + protect=0; + flush_buffer(); + } + pop_level(0); +} + +@ A many-way switch is used to send the output. Note that this function +is not called if |out_state==verbatim|, except perhaps with arguments +|'\n'| (protect the newline), |string| (end the string), or |constant| +(end the constant). + +@= +static void out_char(); + +@ @c +static void +out_char(cur_char) +eight_bits cur_char; +{ + char *j, *k; /* pointer into |byte_mem| */ +restart: + switch (cur_char) { + case '\n': if (protect && out_state!=verbatim) C_putc(' '); + if (protect || out_state==verbatim) C_putc('\\'); + flush_buffer(); if (out_state!=verbatim) out_state=normal; break; + @/@t\4@>@; + @/@t\4@>@; + @/@t\4@>@; + case '=': case '>': C_putc(cur_char); C_putc(' '); + out_state=normal; break; + case join: out_state=unbreakable; break; + case constant: if (out_state==verbatim) { + out_state=num_or_id; break; + } + if(out_state==num_or_id) C_putc(' '); out_state=verbatim; break; + case string: if (out_state==verbatim) out_state=normal; + else out_state=verbatim; break; + case '/': C_putc('/'); out_state=post_slash; break; + case '*': if (out_state==post_slash) C_putc(' '); + /* fall through */ + default: C_putc(cur_char); out_state=normal; break; + } +} + +@ @= +case plus_plus: C_putc('+'); C_putc('+'); out_state=normal; break; +case minus_minus: C_putc('-'); C_putc('-'); out_state=normal; break; +case minus_gt: C_putc('-'); C_putc('>'); out_state=normal; break; +case gt_gt: C_putc('>'); C_putc('>'); out_state=normal; break; +case eq_eq: C_putc('='); C_putc('='); out_state=normal; break; +case lt_lt: C_putc('<'); C_putc('<'); out_state=normal; break; +case gt_eq: C_putc('>'); C_putc('='); out_state=normal; break; +case lt_eq: C_putc('<'); C_putc('='); out_state=normal; break; +case not_eq: C_putc('!'); C_putc('='); out_state=normal; break; +case and_and: C_putc('&'); C_putc('&'); out_state=normal; break; +case or_or: C_putc('|'); C_putc('|'); out_state=normal; break; +case dot_dot_dot: C_putc('.'); C_putc('.'); C_putc('.'); out_state=normal; + break; +case colon_colon: C_putc(':'); C_putc(':'); out_state=normal; break; +case period_ast: C_putc('.'); C_putc('*'); out_state=normal; break; +case minus_gt_ast: C_putc('-'); C_putc('>'); C_putc('*'); out_state=normal; + break; + +@ When an identifier is output to the \CEE/ file, characters in the +range 128--255 must be changed into something else, so the \CEE/ +compiler won't complain. By default, \.{CTANGLE} converts the +character with code $16 x+y$ to the three characters `\.X$xy$', but +a different transliteration table can be specified. Thus a German +might want {\it gr\"un\/} to appear as a still readable \.{gruen}. +This makes debugging a lot less confusing. + +@d translit_length 10 + +@= +char translit[128][translit_length]; + +@ @= +{ + int i; + for (i=0;i<128;i++) sprintf(translit[i],"X%02X",(unsigned)(128+i)); +} + +@ @= +case identifier: + if (out_state==num_or_id) C_putc(' '); + j=(cur_val+name_dir)->byte_start; + k=(cur_val+name_dir+1)->byte_start; + while (j + else C_printf("%s",translit[(unsigned char)(*j)-0200]); + j++; + } + out_state=num_or_id; break; + +@ @= +case section_number: + if (cur_val>0) C_printf("/*%d:*/",cur_val); + else if(cur_val<0) C_printf("/*:%d*/",-cur_val); + else if (protect) { + cur_byte +=4; /* skip line number and file name */ + cur_char = '\n'; + goto restart; + } else { + sixteen_bits a; + a=0400* *cur_byte++; + a+=*cur_byte++; /* gets the line number */ + C_printf("\n#line %d \"",a); +@:line}{\.{\#line}@> + cur_val=*cur_byte++; + cur_val=0400*(cur_val-0200)+ *cur_byte++; /* points to the file name */ + for (j=(cur_val+name_dir)->byte_start, k=(cur_val+name_dir+1)->byte_start; + j= +eight_bits ccode[256]; /* meaning of a char following \.{@@} */ + +@ @= { + int c; /* must be |int| so the |for| loop will end */ + for (c=0; c<256; c++) ccode[c]=ignore; + ccode[' ']=ccode['\t']=ccode['\n']=ccode['\v']=ccode['\r']=ccode['\f'] + =ccode['*']=new_section; + ccode['@@']='@@'; ccode['=']=string; + ccode['d']=ccode['D']=definition; + ccode['f']=ccode['F']=ccode['s']=ccode['S']=format_code; + ccode['c']=ccode['C']=ccode['p']=ccode['P']=begin_C; + ccode['^']=ccode[':']=ccode['.']=ccode['t']=ccode['T']= + ccode['q']=ccode['Q']=control_text; + ccode['h']=ccode['H']=output_defs_code; + ccode['l']=ccode['L']=translit_code; + ccode['&']=join; + ccode['<']=ccode['(']=section_name; + ccode['\'']=ord; +} + +@ The |skip_ahead| procedure reads through the input at fairly high speed +until finding the next non-ignorable control code, which it returns. + +@c +eight_bits +skip_ahead() /* skip to next control code */ +{ + eight_bits c; /* control code found */ + while (1) { + if (loc>limit && (get_line()==0)) return(new_section); + *(limit+1)='@@'; + while (*loc!='@@') loc++; + if (loc<=limit) { + loc++; c=ccode[(eight_bits)*loc]; loc++; + if (c!=ignore || *(loc-1)=='>') return(c); + } + } +} + +@ The |skip_comment| procedure reads through the input at somewhat high +speed in order to pass over comments, which \.{CTANGLE} does not transmit +to the output. If the comment is introduced by \.{/*}, |skip_comment| +proceeds until finding the end-comment token \.{*/} or a newline; in the +latter case |skip_comment| will be called again by |get_next|, since the +comment is not finished. This is done so that each newline in the +\CEE/ part of a section is copied to the output; otherwise the \&{\#line} +commands inserted into the \CEE/ file by the output routines become useless. +On the other hand, if the comment is introduced by \.{//} (i.e., if it +is a \CPLUSPLUS/ ``short comment''), it always is simply delimited by the next +newline. The boolean argument |is_long_comment| distinguishes between +the two types of comments. + +If |skip_comment| comes to the end of the section, it prints an error message. +No comment, long or short, is allowed to contain `\.{@@\ }' or `\.{@@*}'. + +@= +boolean comment_continues=0; /* are we scanning a comment? */ + +@ @c +int skip_comment(is_long_comment) /* skips over comments */ +boolean is_long_comment; +{ + char c; /* current character */ + while (1) { + if (loc>limit) { + if (is_long_comment) { + if(get_line()) return(comment_continues=1); + else{ + err_print("! Input ended in mid-comment"); +@.Input ended in mid-comment@> + return(comment_continues=0); + } + } + else return(comment_continues=0); + } + c=*(loc++); + if (is_long_comment && c=='*' && *loc=='/') { + loc++; return(comment_continues=0); + } + if (c=='@@') { + if (ccode[(eight_bits)*loc]==new_section) { + err_print("! Section name ended in mid-comment"); loc--; +@.Section name ended in mid-comment@> + return(comment_continues=0); + } + else loc++; + } + } +} + +@* Inputting the next token. + +@d constant 03 + +@= +name_pointer cur_section_name; /* name of section just scanned */ +int no_where; /* suppress |print_where|? */ + +@ @= +#include /* definition of |isalpha|, |isdigit| and so on */ +#include /* 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)=='_' || (c)=='$') + /* non-alpha characters allowed in identifier */ +@d ishigh(c) ((unsigned char)(c)>0177) +@^high-bit character handling@> + +@c +eight_bits +get_next() /* produces the next input token */ +{ + static int preprocessing=0; + eight_bits c; /* the current character */ + while (1) { + if (loc>limit) { + if (preprocessing && *(limit-1)!='\\') preprocessing=0; + if (get_line()==0) return(new_section); + else if (print_where && !no_where) { + print_where=0; + @; + } + else return ('\n'); + } + c=*loc; + if (comment_continues || (c=='/' && (*(loc+1)=='*' || *(loc+1)=='/'))) { + skip_comment(comment_continues||*(loc+1)=='*'); + /* scan to end of comment or newline */ + if (comment_continues) return('\n'); + else continue; + } + loc++; + if (xisdigit(c) || c=='.') @@; + else if (c=='\'' || c=='"' || (c=='L'&&(*loc=='\'' || *loc=='"'))) + @@; + else if (isalpha(c) || isxalpha(c) || ishigh(c)) + @@; + else if (c=='@@') @@; + else if (xisspace(c)) { + if (!preprocessing || loc>limit) continue; + /* we don't want a blank after a final backslash */ + else return(' '); /* ignore spaces and tabs, unless preprocessing */ + } + else if (c=='#' && loc==buffer+1) preprocessing=1; + mistake: @@; + return(c); + } +} + +@ The following code assigns values to the combinations \.{++}, +\.{--}, \.{->}, \.{>=}, \.{<=}, \.{==}, \.{<<}, \.{>>}, \.{!=}, \.{||} and +\.{\&\&}, and to the \CPLUSPLUS/ +combinations \.{...}, \.{::}, \.{.*} and \.{->*}. +The compound assignment operators (e.g., \.{+=}) are +treated as separate tokens. + +@d compress(c) if (loc++<=limit) return(c) + +@= +switch(c) { + case '+': if (*loc=='+') compress(plus_plus); break; + case '-': if (*loc=='-') {compress(minus_minus);} + else if (*loc=='>') if (*(loc+1)=='*') {loc++; compress(minus_gt_ast);} + else compress(minus_gt); break; + case '.': if (*loc=='*') {compress(period_ast);} + else if (*loc=='.' && *(loc+1)=='.') { + loc++; compress(dot_dot_dot); + } + break; + case ':': if (*loc==':') compress(colon_colon); break; + case '=': if (*loc=='=') compress(eq_eq); break; + case '>': if (*loc=='=') {compress(gt_eq);} + else if (*loc=='>') compress(gt_gt); break; + case '<': if (*loc=='=') {compress(lt_eq);} + else if (*loc=='<') compress(lt_lt); break; + case '&': if (*loc=='&') compress(and_and); break; + case '|': if (*loc=='|') compress(or_or); break; + case '!': if (*loc=='=') compress(not_eq); break; +} + +@ @= { + id_first=--loc; + while (isalpha(*++loc) || isdigit(*loc) || isxalpha(*loc) || ishigh(*loc)); + id_loc=loc; return(identifier); +} + +@ @= { + id_first=loc-1; + if (*id_first=='.' && !xisdigit(*loc)) goto mistake; /* not a constant */ + if (*id_first=='0') { + if (*loc=='x' || *loc=='X') { /* hex constant */ + loc++; while (xisxdigit(*loc)) loc++; goto found; + } + } + while (xisdigit(*loc)) loc++; + if (*loc=='.') { + loc++; + while (xisdigit(*loc)) loc++; + } + if (*loc=='e' || *loc=='E') { /* float constant */ + if (*++loc=='+' || *loc=='-') loc++; + while (xisdigit(*loc)) loc++; + } + found: while (*loc=='u' || *loc=='U' || *loc=='l' || *loc=='L' + || *loc=='f' || *loc=='F') loc++; + id_loc=loc; + return(constant); +} + +@ \CEE/ strings and character constants, delimited by double and single +quotes, respectively, can contain newlines or instances of their own +delimiters if they are protected by a backslash. We follow this +convention, but do not allow the string to be longer than |longest_name|. + +@= { + char delim = c; /* what started the string */ + id_first = section_text+1; + id_loc = section_text; *++id_loc=delim; + if (delim=='L') { /* wide character constant */ + delim=*loc++; *++id_loc=delim; + } + 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@> + } + else if (++id_loc<=section_text_end) *id_loc='\n'; /* will print as + \.{"\\\\\\n"} */ + } + if ((c=*loc++)==delim) { + if (++id_loc<=section_text_end) *id_loc=c; + break; + } + if (c=='\\') { + if (loc>=limit) continue; + if (++id_loc<=section_text_end) *id_loc = '\\'; + c=*loc++; + } + if (++id_loc<=section_text_end) *id_loc=c; + } + if (id_loc>=section_text_end) { + printf("\n! String too long: "); +@.String too long@> + term_write(section_text+1,25); + err_print("..."); + } + id_loc++; + return(string); +} + +@ After an \.{@@} sign has been scanned, the next character tells us +whether there is more work to do. + +@= { + c=ccode[(eight_bits)*loc++]; + switch(c) { + case ignore: continue; + case translit_code: err_print("! Use @@l in limbo only"); continue; +@.Use @@l in limbo...@> + case control_text: while ((c=skip_ahead())=='@@'); + /* only \.{@@@@} and \.{@@>} are expected */ + if (*(loc-1)!='>') + err_print("! Double @@ should be used in control text"); +@.Double @@ should be used...@> + continue; + case section_name: + cur_section_name_char=*(loc-1); + @; + case string: @; + case ord: @; + default: return(c); + } +} + +@ After scanning a valid ASCII constant that follows +\.{@@'}, this code plows ahead until it finds the next single quote. +(Special care is taken if the quote is part of the constant.) +Anything after a valid ASCII constant is ignored; +thus, \.{@@'\\nopq'} gives the same result as \.{@@'\\n'}. + +@= + id_first=loc; + if (*loc=='\\') { + if (*++loc=='\'') loc++; + } + while (*loc!='\'') { + if (*loc=='@@') { + if (*(loc+1)!='@@') + err_print("! Double @@ should be used in ASCII constant"); +@.Double @@ should be used...@> + else loc++; + } + loc++; + if (loc>limit) { + err_print("! String didn't end"); loc=limit-1; break; +@.String didn't end@> + } + } + loc++; + return(ord); + +@ @= { + char *k; /* pointer into |section_text| */ + @; + if (k-section_text>3 && strncmp(k-2,"...",3)==0) + cur_section_name=section_lookup(section_text+1,k-3,1); /* 1 means is a prefix */ + else cur_section_name=section_lookup(section_text+1,k,0); + if (cur_section_name_char=='(') + @; + 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.) + +@=section_text[0]=' '; + +@ @= +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; + @; + loc++; 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 (c=='@@') { + c=*(loc+1); + if (c=='>') { + loc+=2; break; + } + if (ccode[(eight_bits)c]==new_section) { + err_print("! Section name didn't end"); break; +@.Section name didn't end@> + } + if (ccode[(eight_bits)c]==section_name) { + err_print("! Nesting of section names not allowed"); break; +@.Nesting of section names...@> + } + *(++k)='@@'; loc++; /* now |c==*loc| again */ +} + +@ At the present point in the program we +have |*(loc-1)==string|; we set |id_first| to the beginning +of the string itself, and |id_loc| to its ending-plus-one location in the +buffer. We also set |loc| to the position just after the ending delimiter. + +@= { + id_first=loc++; *(limit+1)='@@'; *(limit+2)='>'; + while (*loc!='@@' || *(loc+1)!='>') loc++; + if (loc>=limit) err_print("! Verbatim string didn't end"); +@.Verbatim string didn't end@> + id_loc=loc; loc+=2; + return(string); +} + +@* Scanning a macro definition. +The rules for generating the replacement texts corresponding to macros and +\CEE/ texts of a section are almost identical; the only differences are that + +\yskip \item{a)}Section names are not allowed in macros; +in fact, the appearance of a section name terminates such macros and denotes +the name of the current section. + +\item{b)}The symbols \.{@@d} and \.{@@f} and \.{@@c} are not allowed after +section names, while they terminate macro definitions. + +\item{c)}Spaces are inserted after right parentheses in macros, because the +ANSI \CEE/ preprocessor sometimes requires it. + +\yskip Therefore there is a single procedure |scan_repl| whose parameter +|t| specifies either |macro| or |section_name|. After |scan_repl| has +acted, |cur_text| will point to the replacement text just generated, and +|next_control| will contain the control code that terminated the activity. + +@d macro 0 +@d app_repl(c) {if (tok_ptr==tok_mem_end) overflow("token"); *tok_ptr++=c;} + +@= +text_pointer cur_text; /* replacement text formed by |scan_repl| */ +eight_bits next_control; + +@ @c +void +scan_repl(t) /* creates a replacement text */ +eight_bits t; +{ + sixteen_bits a; /* the current token */ + if (t==section_name) {@;} + while (1) switch (a=get_next()) { + @@; + case ')': app_repl(a); + if (t==macro) app_repl(' '); + break; + default: app_repl(a); /* store |a| in |tok_mem| */ + } + done: next_control=(eight_bits) a; + if (text_ptr>text_info_end) overflow("text"); + cur_text=text_ptr; (++text_ptr)->tok_start=tok_ptr; +} + +@ Here is the code for the line number: first a |sixteen_bits| equal +to |0150000|; then the numeric line number; then a pointer to the +file name. + +@= +store_two_bytes(0150000); +if (changing && include_depth==change_depth) { /* correction made Feb 2017 */ + id_first=change_file_name; + store_two_bytes((sixteen_bits)change_line); +}@+else { + id_first=cur_file_name; + store_two_bytes((sixteen_bits)cur_line); +} +id_loc=id_first+strlen(id_first); +{int a=id_lookup(id_first,id_loc,0)-name_dir; app_repl((a / 0400)+0200); + app_repl(a % 0400);} + +@ @= +case identifier: a=id_lookup(id_first,id_loc,0)-name_dir; + app_repl((a / 0400)+0200); + app_repl(a % 0400); break; +case section_name: if (t!=section_name) goto done; + else { + @; + a=cur_section_name-name_dir; + app_repl((a / 0400)+0250); + app_repl(a % 0400); + @; break; + } +case output_defs_code: if (t!=section_name) err_print("! Misplaced @@h"); +@.Misplaced @@h@> + else { + output_defs_seen=1; + a=output_defs_flag; + app_repl((a / 0400)+0200); + app_repl(a % 0400); + @; + } + break; +case constant: case string: + @; +case ord: + @; +case definition: case format_code: case begin_C: if (t!=section_name) goto done; + else { + err_print("! @@d, @@f and @@c are ignored in C text"); continue; +@.@@d, @@f and @@c are ignored in C text@> + } +case new_section: goto done; + +@ @= { + char *try_loc=loc; + while (*try_loc==' ' && try_loc + /* user who isn't defining a section should put newline after the name, + as explained in the manual */ +} + +@ @= + app_repl(a); /* |string| or |constant| */ + while (id_first < id_loc) { /* simplify \.{@@@@} pairs */ + if (*id_first=='@@') { + if (*(id_first+1)=='@@') id_first++; + else err_print("! Double @@ should be used in string"); +@.Double @@ should be used...@> + } + app_repl(*id_first++); + } + app_repl(a); break; + +@ This section should be rewritten on machines that don't use ASCII +code internally. +@^ASCII code dependencies@> + +@= { + int c=(eight_bits) *id_first; + if (c=='\\') { + c=*++id_first; + if (c>='0' && c<='7') { + c-='0'; + if (*(id_first+1)>='0' && *(id_first+1)<='7') { + c=8*c+*(++id_first) - '0'; + if (*(id_first+1)>='0' && *(id_first+1)<='7' && c<32) + c=8*c+*(++id_first)- '0'; + } + } + else switch (c) { + case 't':c='\t';@+break; + case 'n':c='\n';@+break; + case 'b':c='\b';@+break; + case 'f':c='\f';@+break; + case 'v':c='\v';@+break; + case 'r':c='\r';@+break; + case 'a':c='\7';@+break; + case '?':c='?';@+break; + case 'x': + if (xisdigit(*(id_first+1))) c=*(++id_first)-'0'; + else if (xisxdigit(*(id_first+1))) { + ++id_first; + c=toupper(*id_first)-'A'+10; + } + if (xisdigit(*(id_first+1))) c=16*c+*(++id_first)-'0'; + else if (xisxdigit(*(id_first+1))) { + ++id_first; + c=16*c+toupper(*id_first)-'A'+10; + } + break; + case '\\':c='\\';@+break; + case '\'':c='\'';@+break; + case '\"':c='\"';@+break; + default: err_print("! Unrecognized escape sequence"); +@.Unrecognized escape sequence@> + } + }@/ + /* at this point |c| should have been converted to its ASCII code number */ + app_repl(constant); + if (c>=100) app_repl('0'+c/100); + if (c>=10) app_repl('0'+(c/10)%10); + app_repl('0'+c%10); + app_repl(constant); +} +break; + +@* Scanning a section. +The |scan_section| procedure starts when `\.{@@\ }' or `\.{@@*}' has been +sensed in the input, and it proceeds until the end of that section. It +uses |section_count| to keep track of the current section number; with luck, +\.{CWEAVE} and \.{CTANGLE} will both assign the same numbers to sections. + +@= +extern sixteen_bits section_count; /* the current section number */ + +@ The body of |scan_section| is a loop where we look for control codes +that are significant to \.{CTANGLE}: those +that delimit a definition, the \CEE/ part of a module, or a new module. + +@c +void +scan_section() +{ + name_pointer p; /* section name for the current section */ + text_pointer q; /* text for the current section */ + sixteen_bits a; /* token for left-hand side of definition */ + section_count++; @+ no_where=1; + if (*(loc-1)=='*' && show_progress) { /* starred section */ + printf("*%d",section_count); update_terminal; + } + next_control=0; + while (1) { + @; + if (next_control == definition) { /* \.{@@d} */ + @@; + continue; + } + if (next_control == begin_C) { /* \.{@@c} or \.{@@p} */ + p=name_dir; break; + } + if (next_control == section_name) { /* \.{@@<} or \.{@@(} */ + p=cur_section_name; + @; + break; + } + return; /* \.{@@\ } or \.{@@*} */ + } + no_where=print_where=0; + @; +} + +@ At the top of this loop, if |next_control==section_name|, the +section name has already been scanned (see |@|). Thus, if we encounter |next_control==section_name| in the +skip-ahead process, we should likewise scan the section name, so later +processing will be the same in both cases. + +@= +while (next_control= { + while ((next_control=get_next())=='\n'); /*allow newline before definition */ + if (next_control!=identifier) { + err_print("! Definition flushed, must start with identifier"); +@.Definition flushed...@> + continue; + } + app_repl(((a=id_lookup(id_first,id_loc,0)-name_dir) / 0400)+0200); + /* append the lhs */ + app_repl(a % 0400); + if (*loc!='(') { /* identifier must be separated from replacement text */ + app_repl(string); app_repl(' '); app_repl(string); + } + scan_repl(macro); + cur_text->text_link=0; /* |text_link==0| characterizes a macro */ +} + +@ If the section name is not followed by \.{=} or \.{+=}, no \CEE/ +code is forthcoming: the section is being cited, not being +defined. This use is illegal after the definition part of the +current section has started, except inside a comment, but +\.{CTANGLE} does not enforce this rule; it simply ignores the offending +section name and everything following it, up to the next significant +control code. + +@= +while ((next_control=get_next())=='+'); /* allow optional \.{+=} */ +if (next_control!='=' && next_control!=eq_eq) + continue; + +@ @= +@; +scan_repl(section_name); /* now |cur_text| points to the replacement text */ +@; + +@ @= +store_two_bytes((sixteen_bits)(0150000+section_count)); + /* |0150000==0320*0400| */ + +@ @= +if (p==name_dir||p==0) { /* unnamed section, or bad section name */ + (last_unnamed)->text_link=cur_text-text_info; last_unnamed=cur_text; +} +else if (p->equiv==(char *)text_info) p->equiv=(char *)cur_text; + /* first section of this name */ +else { + q=(text_pointer)p->equiv; + while (q->text_linktext_link+text_info; /* find end of list */ + q->text_link=cur_text-text_info; +} +cur_text->text_link=section_flag; + /* mark this replacement text as a nonmacro */ + +@ @= +void phase_one(); + +@ @c +void +phase_one() { + phase=1; + section_count=0; + reset_input(); + skip_limbo(); + while (!input_has_ended) scan_section(); + check_complete(); + phase=2; +} + +@ Only a small subset of the control codes is legal in limbo, so limbo +processing is straightforward. + +@= +void skip_limbo(); + +@ @c +void +skip_limbo() +{ + char c; + while (1) { + if (loc>limit && get_line()==0) return; + *(limit+1)='@@'; + while (*loc!='@@') loc++; + if (loc++<=limit) { + c=*loc++; + if (ccode[(eight_bits)c]==new_section) break; + switch (ccode[(eight_bits)c]) { + case translit_code: @; break; + case format_code: case '@@': break; + case control_text: if (c=='q' || c=='Q') { + while ((c=skip_ahead())=='@@'); + if (*(loc-1)!='>') + err_print("! Double @@ should be used in control text"); +@.Double @@ should be used...@> + break; + } /* otherwise fall through */ + default: err_print("! Double @@ should be used in limbo"); +@.Double @@ should be used...@> + } + } + } +} + +@ @= + while(xisspace(*loc)&&loclimit || !xisxdigit(*(loc-3)) || !xisxdigit(*(loc-2)) @| + || (*(loc-3)>='0' && *(loc-3)<='7') || !xisspace(*(loc-1))) + err_print("! Improper hex number following @@l"); +@.Improper hex number...@> + else { + unsigned i; + char *beg; + sscanf(loc-3,"%x",&i); + while(xisspace(*loc)&&loc=translit_length) + err_print("! Replacement string in @@l too long"); +@.Replacement string in @@l...@> + else{ + strncpy(translit[i-0200],beg,loc-beg); + translit[i-0200][loc-beg]='\0'; + } + } + +@ Because on some systems the difference between two pointers is a |long| +but not an |int|, we use \.{\%ld} to print these quantities. + +@c +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 replacement texts (out of %ld)\n", + (long)(text_ptr-text_info),(long)max_texts); + printf("%ld bytes (out of %ld)\n", + (long)(byte_ptr-byte_mem),(long)max_bytes); + printf("%ld tokens (out of %ld)\n", + (long)(tok_ptr-tok_mem),(long)max_toks); +} + +@** Index. +Here is a cross-reference table for \.{CTANGLE}. +All sections in which an identifier is +used are listed with that identifier, except that reserved words are +indexed only when they appear in format definitions, and the appearances +of identifiers in section names are not indexed. Underlined entries +correspond to where the identifier was declared. Error messages and +a few other things like ``ASCII code dependencies'' are indexed here too. diff --git a/web/c_cpp/cweb/cweav-bs.ch b/web/c_cpp/cweb/cweav-bs.ch new file mode 100644 index 0000000000..8c4c1fe8ff --- /dev/null +++ b/web/c_cpp/cweb/cweav-bs.ch @@ -0,0 +1,302 @@ +Changes for CWEAVE for MSDOS and Borland C++ 3.1 using the following +options (and perhaps others): + + -mc -w-pro -Ff=5000 -Z- -O-p + +The options -Z- and -O-p explicitly turn off optimizations that break +the code. (See makefile.bs.) + +The main purpose of these changes is to support MSDOS with full-size arrays +by using "huge" pointers. + +This file contributed by Barry Schwartz, trashman@crud.mn.org, 28 Jun 94. +(Includes workaround for compiler bug [pointers wrapping around at + segment boundaries], November 1993, contributed by Jorge Fernandez Arnaiz + -- arnaiz@redvax1.dgsca.unam.mx) +(Last revised 5 Dec 94 with help of bob@microprograms.com.) + + +@x Section 1. +The ``banner line'' defined here should be changed whenever \.{CWEAVE} +is modified. + +@d banner "This is CWEAVE (Version 3.64)\n" +@y +The ``banner line'' defined here should be changed whenever \.{CWEAVE} +is modified. + +@d banner "This is CWEAVE (Version 3.64pc/big)\n" +@z + + +@x Section 9. +@d chunk_marker 0 + +@= +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 */ + char Ilk; /* used by identifiers in \.{CWEAVE} only */ + } 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 |name_dir| */ +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(); +@y +@d chunk_marker 0 + +@f huge extern + +@= +typedef struct name_info { + char huge* 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 */ + char Ilk; /* used by identifiers in \.{CWEAVE} only */ + } dummy; + union { + char *equiv_member; + char huge* xref_member; + } ptr_union; /* info corresponding to names */ +} name_info; /* contains information about an identifier or section name */ +typedef name_info *name_pointer; /* pointer into array of \&{name\_info}s */ +typedef name_pointer *hash_pointer; +extern char huge byte_mem[]; /* characters of names */ +extern char huge* 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 |name_dir| */ +extern char huge* 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(); +@z + + +@x Section 18. +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; +@y +typedef struct xref_info { + sixteen_bits num; /* section number plus zero or |def_flag| */ + struct xref_info huge* xlink; /* pointer to the previous cross-reference */ +} xref_info; +typedef xref_info huge* xref_pointer; +@z + + +@x Section 19. +xref_info xmem[max_refs]; /* contains cross-reference information */ +xref_pointer xmem_end = xmem+max_refs-1; +@y +xref_info huge xmem[max_refs]; /* contains cross-reference information */ +xref_pointer xmem_end; +@z + + +@x Section 20. +@d xref equiv_or_xref +@y +@d xref ptr_union.xref_member +@z + + +@x Section 20. +xref_ptr=xmem; name_dir->xref=(char*)xmem; xref_switch=0; section_xref_switch=0; +xmem->num=0; /* sentinel value */ +@y +xmem_end = xmem + max_refs - 1; +xref_ptr=xmem; name_dir->xref=(char*)xmem; xref_switch=0; section_xref_switch=0; +xmem->num=0; /* sentinel value */ +@z + + +@x Section 21. + append_xref(m); xref_ptr->xlink=q; p->xref=(char*)xref_ptr; +@y + append_xref(m); xref_ptr->xlink=q; p->xref=(char huge*)xref_ptr; +@z + + +@x Section 22. + if (r==xmem) p->xref=(char*)xref_ptr; +@y + if (r==xmem) p->xref=(char huge*)xref_ptr; +@z + + +@x Section 23. + q=(xref_pointer)p->xref; + if (q->num==file_flag) return; + append_xref(file_flag); + xref_ptr->xlink = q; + p->xref = (char *)xref_ptr; +@y + q=(xref_pointer)p->xref; + if (q->num==file_flag) return; + append_xref(file_flag); + xref_ptr->xlink = q; + p->xref = (char huge*)xref_ptr; +@z + +@x Section 25. (to please Borland's C++, version 4.02) +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| */ +@y +token tok_mem[max_toks]; /* tokens */ +token_pointer tok_mem_end; /* 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; /* end of |tok_start| */ +token_pointer max_tok_ptr; /* largest value of |tok_ptr| */ +@z + +@x Section 26. (goes with the previous change) +tok_start[1]=tok_mem+1; +max_tok_ptr=tok_mem+1; max_text_ptr=tok_start+1; +@y +tok_start[1]=tok_mem+1; +tok_mem_end=tok_mem+max_toks-1; +tok_start_end=tok_start+max_texts-1; +max_tok_ptr=tok_mem+1; max_text_ptr=tok_start+1; +@z + + +@x Section 27. + p->ilk=t; p->xref=(char*)xmem; +@y + p->ilk=t; p->xref=(char huge*)xmem; +@z + + +@x Section 27. + p->xref=(char*)xmem; +@y + p->xref=(char huge*)xmem; +@z + + +@x Section 70. + 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->numxlink=q->xlink; + else lhs->xref=(char*)q->xlink; + else r=q; + } +@y + 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->numxlink=q->xlink; + else lhs->xref=(char huge*)q->xlink; + else r=q; + } +@z + + +@x Section 87. + char *k, *k_end=(p+1)->byte_start; /* pointers into |byte_mem| */ + out('{'); + for (k=p->byte_start; kbyte_start; /* pointers into |byte_mem| */ + out('{'); + for (k=p->byte_start; kxlink=(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 */ +@y + append_xref(0); /* this number doesn't matter */ + xref_ptr->xlink=(xref_pointer)p->xref; r=xref_ptr; + p->xref=(char huge*)xref_ptr; + while (r->xlink!=q) {r->num=r->xlink->num; r=r->xlink;} + r->num=m; /* everything from |q| on is left undisturbed */ +@z + + +@x Section 163. +@ @= +@y +@ @= +#ifdef __MSDOS__ +if (d<0 && pp+d>pp) pp=scrap_base; /* segmented architecture caused wrap */ +else +#endif +@z + + +@x Section 194. + char *p; /* index into |byte_mem| */ +@y + char huge *p; /* index into |byte_mem| */ +@z + + +@x Section 229. + if (cur_name->xref!=(char*)xmem) { +@y + if (cur_name->xref!=(char huge*)xmem) { +@z + + +@x Section 232. +char *cur_byte; /* index into |byte_mem| */ +@y +char huge* cur_byte; /* index into |byte_mem| */ +@z + + +@x Section 241. +switch (cur_name->ilk) { + case normal: if (is_tiny(cur_name)) out_str("\\|"); + else {char *j; +@y +switch (cur_name->ilk) { + case normal: if (is_tiny(cur_name)) out_str("\\|"); + else {char huge* j; +@z + + +@x Section 241. + case custom: case quoted: {char *j; out_str("$\\"); +@y + case custom: case quoted: {char huge* j; out_str("$\\"); +@z diff --git a/web/c_cpp/cweb/cweav-man.ch b/web/c_cpp/cweb/cweav-man.ch new file mode 100644 index 0000000000..6cfcc8fe2d --- /dev/null +++ b/web/c_cpp/cweb/cweav-man.ch @@ -0,0 +1,22 @@ +Change file to help make Appendix F of the full CWEB manual +@x +\def\botofcontents{\vfill +\noindent +Copyright \copyright\ 1987, 1990, 1993, 2000 Silvio Levy and Donald E. Knuth +\bigskip\noindent +Permission is granted to make and distribute verbatim copies of this +document provided that the copyright notice and this permission notice +are preserved on all copies. + +\smallskip\noindent +Permission is granted to copy and distribute modified versions of this +document under the conditions for verbatim copying, provided that the +entire resulting derived work is given a different name and distributed +under the terms of a permission notice identical to this one. +} +@y +\def\botofcontents{\vfill\titlefalse} +\def\contentspagenumber{109} +\def\title{APPENDIX F: CWEAVE} +\let\K=\leftarrow +@z diff --git a/web/c_cpp/cweb/cweav-pc.ch b/web/c_cpp/cweb/cweav-pc.ch new file mode 100644 index 0000000000..28cd94f5a3 --- /dev/null +++ b/web/c_cpp/cweb/cweav-pc.ch @@ -0,0 +1,39 @@ +This is the change file for CWEB's CWEAVE under DOS +(Contributed by Lee Wittenberg, March 1993) +(Also includes workaround for compiler bug, November 1993, + contributed by Jorge Fernandez Arnaiz -- arnaiz@redvax1.dgsca.unam.mx) + +Changes necessary for compiling with Borland C/C++ +Use compilation switches -mc -w-pro -Ff=5000 + +Note: The changes to section 4 are not necessary if using a compiler +that allows >64K arrays. (If you need lots more bytes, try the alternate +change files that have -bs in their name instead of -pc.) + +@x section 1 +@d banner "This is CWEAVE (Version 3.64)\n" +@y +@d banner "This is CWEAVE (Version 3.64pc)\n" +@z + +@x section 4 +@d max_bytes 90000 /* the number of bytes in identifiers, +@y +@d max_bytes (unsigned)60000 /* the number of bytes in identifiers, +@z +@x +@d max_refs 20000 /* number of cross-references; must be less than 65536 */ +@y +@d max_refs 10000 /* number of cross-references; must be less than 65536 */ +@z + +@x section 163 +@ @= +@y +@ @= +#ifdef __MSDOS__ +if (d<0 && pp+d>pp) pp=scrap_base; /* segmented architecture caused wrap */ +else +#endif +@z + diff --git a/web/c_cpp/cweb/cweav-ql.ch b/web/c_cpp/cweb/cweav-ql.ch new file mode 100644 index 0000000000..3e37ba2352 --- /dev/null +++ b/web/c_cpp/cweb/cweav-ql.ch @@ -0,0 +1,32 @@ +This is the change file for CWEB's CWEAVE under QDOS/SMSQ +(Contributed by Robert H. Klein, September 1994) + +This change file is intended for use with C68 v4.14 (or later). +compile with +ex cc;"-v -h -c =500000 cweave_c" + + +@x +\def\title{CWEAVE (Version 3.64)} +@y +\def\title{CWEAVE (QL Version 3.64)} +@z + +@x section 1 +@d banner "This is CWEAVE (Version 3.64)\n" +@y +@d banner "This is CWEAVE (QL Version 3.64)\n" +@z + +@x +@i common.h +@y +@i common_h +@z + + +@x +@i prod.w +@y +@i prod_w +@z diff --git a/web/c_cpp/cweb/cweav-vms.ch b/web/c_cpp/cweb/cweav-vms.ch new file mode 100644 index 0000000000..b6f46559cc --- /dev/null +++ b/web/c_cpp/cweb/cweav-vms.ch @@ -0,0 +1,37 @@ +This is the change file for CWEB's CWEAVE for VAX/VMS. + +created: + 1991 JM (John Mulhollen, Science Applications International Corporation) + +modified: + 01-FEB-1992 ST (Stephan Trebels ) + > include ctype,stdio from textlibrary SYS$SHARE:VAXCDEF.TLB + > change banner line to include (VAX/VMS) + > allow $ in identifiers (*necessary* for VAX/VMS) + ? will someone eventally make a CLD interface? (should be easy) + +(also modified by Don Knuth to keep version numbers uptodate) + +@x section 1 (01-FEB-1992 ST) +@d banner "This is CWEAVE (Version 3.64)\n" +@y +@d banner "This is CWEAVE (VAX/VMS Version 3.64)\n" +@z + +@x section 6 (from common.h) (01-FEB-1992 ST) +#include +@y +#include stdio /* VMS searches Textlibraries faster */ +@z + +@x section 38 (1991 JM) (01-FEB-1992 ST) +#include /* definition of |isalpha|, |isdigit| and so on */ +@y +#include ctype /* VMS searches Textlibraries faster */ +@z + +@x section 39 (01-FEB-1992 ST) +@d isxalpha(c) ((c)=='_') /* non-alpha character allowed in identifier */ +@y +@d isxalpha(c) ((c)=='_' || (c)=='$') /* non-alpha characters allowed in id */ +@z diff --git a/web/c_cpp/cweb/cweav-w32.ch b/web/c_cpp/cweb/cweav-w32.ch new file mode 100644 index 0000000000..26825b0bfd --- /dev/null +++ b/web/c_cpp/cweb/cweav-w32.ch @@ -0,0 +1,52 @@ +This is the change file for CWEB's CWEAVE under Win32 +(Contributed by Fabrice Popineau, February 2002) + +@x section 1 +@d banner "This is CWEAVE (Version 3.64)\n" +@y +@d banner "This is CWEAVE (Version 3.64win32)\n" +@z + +@x +@ 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 \.{} where others have \.{}.) + +@= +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 */ +@y +@z + +@x +int names_match(p,first,l,t) +name_pointer p; /* points to the proposed match */ +@y +int __cdecl names_match(p,first,l,t) +name_pointer p; /* points to the proposed match */ +@z + +@x +void +init_p(p,t) +name_pointer p; +@y +void __cdecl +init_p(p,t) +name_pointer p; +@z + +@x +@ @= +#include /* definition of |isalpha|, |isdigit| and so on */ +#include /* definition of |exit| */ +@y +@ @= +#include /* definition of |isalpha|, |isdigit| and so on */ +#include /* definition of |exit| */ +#include /* definition of |strncmp| and |strncpy| */ +@z diff --git a/web/c_cpp/cweb/cweave.w b/web/c_cpp/cweb/cweave.w new file mode 100644 index 0000000000..e06762b1fc --- /dev/null +++ b/web/c_cpp/cweb/cweave.w @@ -0,0 +1,4652 @@ +% 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.64 --- February 2002 +% (essentially the same as version 3.6, which added +% recently introduced features of standard C++ to version 3.4) +% (In November 2016 I made minor adjustments but changed no code -- DEK) + +% Copyright (C) 1987,1990,1993,2000 Silvio Levy and Donald E. Knuth + +% Permission is granted to make and distribute verbatim copies of this +% document provided that the copyright notice and this permission notice +% are preserved on all copies. + +% Permission is granted to copy and distribute modified versions of this +% document under the conditions for verbatim copying, provided that the +% entire resulting derived work is given a different name and distributed +% under the terms of a permission notice identical to this one. + +% 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.64)} +\def\topofcontents{\null\vfill + \centerline{\titlefont The {\ttitlefont CWEAVE} processor} + \vskip 15pt + \centerline{(Version 3.64)} + \vfill} +\def\botofcontents{\vfill +\noindent +Copyright \copyright\ 1987, 1990, 1993, 2000 Silvio Levy and Donald E. Knuth +\bigskip\noindent +Permission is granted to make and distribute verbatim copies of this +document provided that the copyright notice and this permission notice +are preserved on all copies. + +\smallskip\noindent +Permission is granted to copy and distribute modified versions of this +document under the conditions for verbatim copying, provided that the +entire resulting derived work is given a different name and distributed +under the terms of a permission notice identical to this one. +} +\pageno=\contentspagenumber \advance\pageno by 1 +\let\maybe=\iftrue +@s not_eq normal @q unreserve a C++ keyword @> + +@** 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 original \CPLUSPLUS/ adaptation +is due), Klaus Guntermann, Norman Ramsey, Tomas Rokicki, Joachim Schnitter, +Joachim Schrod, Lee Wittenberg, Saroj Mahapatra, Cesar Augusto Rorato +Crusius, and others who have contributed improvements. + +The ``banner line'' defined here should be changed whenever \.{CWEAVE} +is modified. + +@d banner "This is CWEAVE (Version 3.64)\n" + +@c @@/ +@h +@@/ +@@/ +@@/ +@ + +@ 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 \.{} where others have \.{}.) + +@= +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=make_pb=1; /* controlled by command-line options */ + common_init(); + @; + if (show_banner) printf(banner); /* print a ``banner line'' */ + @; + 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 10000 /* 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| and |func_template| identifiers are part of the +\CEE/ program that will appear in italic type (or in typewriter type +if all uppercase). + +\yskip\hang |custom| identifiers are part of the \CEE/ program that +will be typeset in special ways. + +\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 |alfop|, \dots, |template_like| +identifiers are \CEE/ or \CPLUSPLUS/ 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 func_template 4 /* identifiers that can be followed by optional template */ +@d custom 5 /* identifiers with user-given control sequence */ +@d alfop 22 /* alphabetic operators like \&{and} or \&{not\_eq} */ +@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 delete_like 48 /* \&{delete} */ +@d raw_ubin 49 /* `\.\&' or `\.*' when looking for \&{const} following */ +@d const_like 50 /* \&{const}, \&{volatile} */ +@d raw_int 51 /* \&{int}, \&{char}, \dots; also structure and class names */ +@d int_like 52 /* same, when not followed by left parenthesis or \DC\ */ +@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} */ +@d template_like 58 /* \&{template} */ + +@ 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. + +@= +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. + +@= +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; + +@ @= +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 + +@= +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) +@d unindexed(a) (ailk>=custom) + /* tells if uses of a name are to be indexed */ + +@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 takes quadratic time with respect to +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|. + +@= +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|. + +@= +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| */ + +@ @= +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@> + +@= +id_lookup("and",NULL,alfop); +id_lookup("and_eq",NULL,alfop); +id_lookup("asm",NULL,sizeof_like); +id_lookup("auto",NULL,int_like); +id_lookup("bitand",NULL,alfop); +id_lookup("bitor",NULL,alfop); +id_lookup("bool",NULL,raw_int); +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("compl",NULL,alfop); +id_lookup("const",NULL,const_like); +id_lookup("const_cast",NULL,raw_int); +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,delete_like); +id_lookup("div_t",NULL,raw_int); +id_lookup("do",NULL,do_like); +id_lookup("double",NULL,raw_int); +id_lookup("dynamic_cast",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("explicit",NULL,int_like); +id_lookup("export",NULL,int_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("mutable",NULL,int_like); +id_lookup("namespace",NULL,struct_like); +id_lookup("new",NULL,new_like); +id_lookup("not",NULL,alfop); +id_lookup("not_eq",NULL,alfop); +id_lookup("NULL",NULL,custom); +id_lookup("offsetof",NULL,raw_int); +id_lookup("operator",NULL,operator_like); +id_lookup("or",NULL,alfop); +id_lookup("or_eq",NULL,alfop); +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("reinterpret_cast",NULL,raw_int); +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("static_cast",NULL,raw_int); +id_lookup("struct",NULL,struct_like); +id_lookup("switch",NULL,for_like); +id_lookup("template",NULL,template_like); +id_lookup("this",NULL,custom); +id_lookup("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("typeid",NULL,raw_int); +id_lookup("typename",NULL,struct_like); +id_lookup("undef",NULL,if_like); +id_lookup("union",NULL,struct_like); +id_lookup("unsigned",NULL,raw_int); +id_lookup("using",NULL,int_like); +id_lookup("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); +id_lookup("xor",NULL,alfop); +id_lookup("xor_eq",NULL,alfop); +res_wd_end=name_ptr; +id_lookup("TeX",NULL,custom); +id_lookup("make_pair",NULL,func_template); + +@* 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|. + +@= +eight_bits ccode[256]; /* meaning of a char following \.{@@} */ + +@ @= +{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; +@@; + +@ Users can write +\.{@@2}, \.{@@1}, and \.{@@0} to turn tracing fully on, partly on, +and off, respectively. + +@= +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. + +@= +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) @; + } + } +} + +@ 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 */ + +@= +name_pointer cur_section; /* name of section just scanned */ +char cur_section_char; /* the character just before that name */ + +@ @= +#include /* definition of |isalpha|, |isdigit| and so on */ +#include /* 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. +\CEE/ allows underscores to appear in identifiers, and some \CEE/ +compilers even allow the dollar sign. + +@d isxalpha(c) ((c)=='_' || (c)=='$') + /* non-alpha characters allowed in identifier */ +@d ishigh(c) ((eight_bits)(c)>0177) +@^high-bit character handling@> + +@= +eight_bits get_next(); + +@ @c +eight_bits +get_next() /* produces the next input token */ +{@+eight_bits c; /* the current character */ + while (1) { + @; + if (loc>limit && get_line()==0) return(new_section); + c=*(loc++); + if (xisdigit(c) || c=='.') @@; + else if (c=='\'' || c=='"' || (c=='L'&&(*loc=='\'' || *loc=='"'))@| + || (c=='<' && sharp_include_line==1)) + @@; + else if (xisalpha(c) || isxalpha(c) || ishigh(c)) + @@; + else if (c=='@@') @@; + else if (xisspace(c)) continue; /* ignore spaces and tabs */ + if (c=='#' && loc==buffer+1) @; + mistake: @@; + 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 */ + +@= +boolean preprocessing=0; /* are we scanning a preprocessor command? */ + +@ @= { + preprocessing=1; + @; + 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. + +@= +boolean sharp_include_line=0; /* are we scanning a |#include| line? */ + +@ @= +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 \.\\. + +@= + 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) + +@= +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; +} + +@ @= { + 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 +with \TEX/ macros that the user can redefine to fit the context. +In order to simplify such macros, 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|. + +@= { + id_first=id_loc=section_text+1; + 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|. + +@= { + 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. + +@= { + 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: + @; + case verbatim: @; + case ord: @; + 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}. + +@= { + char *k; /* pointer into |section_text| */ + cur_section_char=*(loc-1); + @; + if (k-section_text>3 && strncmp(k-2,"...",3)==0) + cur_section=section_lookup(section_text+1,k-3,1); /* 1 indicates a prefix */ + else cur_section=section_lookup(section_text+1,k,0); + 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.) + +@=section_text[0]=' '; + +@ @= +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; + @; + loc++; 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 (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. + +@= +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. + +@= { + 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. + +@= +eight_bits next_control; /* control code waiting to be acting upon */ + +@ The overall processing strategy in phase one has the following +straightforward outline. + +@= +void phase_one(); + +@ @c +void +phase_one() { + phase=1; reset_input(); section_count=0; + skip_limbo(); change_exists=0; + while (!input_has_ended) + @; + changed_section[section_count]=change_exists; + /* the index changes if anything does */ + phase=2; /* prepare for second phase */ + @; +} + +@ @= +{ + 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 */ + } + @; + @; + @; + 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|. + +@= +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=identifier && next_control<=xref_typewriter) { + if (next_control>identifier) @@; + 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. + +@= +void outer_xref(); + +@ @c +void +outer_xref() /* extension of |C_xref| */ +{ + int bal; /* brace level in comment */ + while (next_control0) { + 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\,$\.{@@>}. + +@= +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) { + @@; + new_xref(id_lookup(id_first, id_loc,next_control-identifier)); + } + break; + } + if (next_control>=format_code) break; +} + +@ @= +{ + char *src=id_first,*dst=id_first; + while(src= +name_pointer lhs, rhs; /* pointers to |byte_start| for format identifiers */ +name_pointer res_wd_end; /* pointer to the first nonreserved identifier */ + +@ When we get to the following code we have |next_control>=format_code|. + +@= +while (next_control<=definition) { /* |format_code| or |definition| */ + if (next_control==definition) { + xref_switch=def_flag; /* implied \.{@@!} */ + next_control=get_next(); + } else @; + 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. + +@= { + 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->numxlink=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. + +@= +{ + 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|. + +@= +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. + +@= +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@> + +@= +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 '); mark_harmless; +@.Never defined:
@> + } + 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_check(p->rlink); + } +} + +@ @=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. + +@= +char out_buf[line_length+1]; /* assembled characters */ +char *out_ptr; /* 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 (bout_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}'. + +@= +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. + +@= +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. + +@= +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) @; + 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. + +@= +{ + 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,quote_xalpha) +name_pointer p; +boolean quote_xalpha; +{ + char *k, *k_end=(p+1)->byte_start; /* pointers into |byte_mem| */ + out('{'); + for (k=p->byte_start; k +@.\\\_@> + 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;} + +@= +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) @; + if (phase==2) { + if (ishigh(c)) app_tok(quoted_char); + app_tok(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:@; +} + +@ @= +if (c=='*' && *loc=='/') { + loc++; + if (bal>1) err_print("! Missing } in comment"); +@.Missing \} in comment@> + goto done; +} + +@ @= +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. + +@= +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{|ubinop|}}\right\} +\hbox{ |exp| }\RA\hbox{ |exp|}$$ +and it means that three consecutive scraps whose respective categories are +|exp|, |binop| (or |ubinop|), +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 ubinop 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 ftemplate 59 /* \\{make\_pair} */ +@d new_exp 60 /* \&{new} and a following type identifier */ +@d begin_arg 61 /* \.{@@[} */ +@d end_arg 62 /* \.{@@]} */ + +@= +char cat_name[256][12]; +eight_bits cat_index; + +@ @= + for (cat_index=0;cat_index<255;cat_index++) + strcpy(cat_name[cat_index],"UNKNOWN"); +@.UNKNOWN@> + strcpy(cat_name[exp],"exp"); + strcpy(cat_name[unop],"unop"); + strcpy(cat_name[binop],"binop"); + strcpy(cat_name[ubinop],"ubinop"); + 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[alfop],"alfop"); + 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[delete_like],"delete"); + strcpy(cat_name[raw_ubin],"ubinop?"); + 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[template_like],"template"); + strcpy(cat_name[ftemplate],"ftemplate"); + strcpy(cat_name[new_exp],"new_exp"); + 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 */ +@d qualifier 0225 /* introduces an explicit namespace qualifier */ + +@ 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 +\.{++}&|unop|: \.{\\PP}&yes\cr +\.{--}&|unop|: \.{\\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 +\.{...}&|raw_int|: \.{\\,\\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 +\.+&|ubinop|: \.+&yes\cr +\.-&|ubinop|: \.-&yes\cr +\.*&|raw_ubin|: \.*&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_ubin|: \.{\\AND}&yes\cr +\.(&|lpar|: \.(&maybe\cr +\.[&|lpar|: \.[&maybe\cr +\.)&|rpar|: \.)&maybe\cr +\.]&|rpar|: \.]&maybe\cr +\.\{&|lbrace|: \.\{&yes\cr +\.\}&|lbrace|: \.\}&yes\cr +\.,&|comma|: \.,&yes\cr +\.;&|semi|: \.;&maybe\cr +\.:&|colon|: \.:&no\cr +\.\# (within line)&|ubinop|: \.{\\\#}&yes\cr +\.\# (at beginning)&|lproc|: |force| |preproc_line| \.{\\\#}&no\cr +end of \.\# line&|rproc|: |force|&no\cr +identifier&|exp|: \.{\\\\\{}identifier with underlines and + dollar signs quoted\.\}&maybe\cr +\.{and}&|alfop|: \stars&yes\cr +\.{and\_eq}&|alfop|: \stars&yes\cr +\.{asm}&|sizeof_like|: \stars&maybe\cr +\.{auto}&|int_like|: \stars&maybe\cr +\.{bitand}&|alfop|: \stars&yes\cr +\.{bitor}&|alfop|: \stars&yes\cr +\.{bool}&|raw_int|: \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 +\.{compl}&|alfop|: \stars&yes\cr +\.{const}&|const_like|: \stars&maybe\cr +\.{const\_cast}&|raw_int|: \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}&|delete_like|: \stars&maybe\cr +\.{div\_t}&|raw_int|: \stars&maybe\cr +\.{do}&|do_like|: \stars&maybe\cr +\.{double}&|raw_int|: \stars&maybe\cr +\.{dynamic\_cast}&|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 +\.{explicit}&|int_like|: \stars&maybe\cr +\.{export}&|int_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 +\.{make\_pair}&|ftemplate|: \.{\\\\\{make\\\_pair\}}&maybe\cr +\.{mutable}&|int_like|: \stars&maybe\cr +\.{namespace}&|struct_like|: \stars&maybe\cr +\.{new}&|new_like|: \stars&maybe\cr +\.{not}&|alfop|: \stars&yes\cr +\.{not\_eq}&|alfop|: \stars&yes\cr +\.{NULL}&|exp|: \.{\\NULL}&yes\cr +\.{offsetof}&|raw_int|: \stars&maybe\cr +\.{operator}&|operator_like|: \stars&maybe\cr +\.{or}&|alfop|: \stars&yes\cr +\.{or\_eq}&|alfop|: \stars&yes\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 +\.{reinterpret\_cast}&|raw_int|: \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 +\.{static\_cast}&|raw_int|: \stars&maybe\cr +\.{struct}&|struct_like|: \stars&maybe\cr +\.{switch}&|for_like|: \stars&maybe\cr +\.{template}&|template_like|: \stars&maybe\cr +\.{TeX}&|exp|: \.{\\TeX}&yes\cr +\.{this}&|exp|: \.{\\this}&yes\cr +\.{throw}&|case_like|: \stars&maybe\cr +\.{time\_t}&|raw_int|: \stars&maybe\cr +\.{try}&|else_like|: \stars&maybe\cr +\.{typedef}&|typedef_like|: \stars&maybe\cr +\.{typeid}&|raw_int|: \stars&maybe\cr +\.{typename}&|struct_like|: \stars&maybe\cr +\.{undef}&|if_like|: \stars&maybe\cr +\.{union}&|struct_like|: \stars&maybe\cr +\.{unsigned}&|raw_int|: \stars&maybe\cr +\.{using}&|int_like|: \stars&maybe\cr +\.{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}&|for_like|: \stars&maybe\cr +\.{xor}&|alfop|: \stars&yes\cr +\.{xor\_eq}&|alfop|: \stars&yes\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 +} + +\smallskip +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 a union. + +@= +typedef struct { + eight_bits cat; + eight_bits mathness; + union { + text_pointer Trans; + @@; + } trans_plus; +} scrap; +typedef scrap *scrap_pointer; + +@ @d trans trans_plus.Trans /* translation texts of scraps */ + +@= +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| */ + +@ @= +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: @; + } + } + fflush(stdout); +} + +@ @= +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) + +@= +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!=public_like + && pp->cat!=semi + && pp->cat!=prelangle + && pp->cat!=prerangle + && pp->cat!=template_like + && pp->cat!=new_like + && pp->cat!=new_exp + && pp->cat!=ftemplate + && pp->cat!=raw_ubin + && pp->cat!=const_like + && pp->cat!=raw_int + && pp->cat!=operator_like) + /* not a production with left side length 1 */ + +@= { + if (cat1==end_arg && lhs_not_simple) + if (pp->cat==begin_arg) squash(pp,2,exp,-2,124); + else squash(pp,2,end_arg,-1,125); + else if (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: @; @+break; + case lpar: @; @+break; + case unop: @; @+break; + case ubinop: @; @+break; + case binop: @; @+break; + case cast: @; @+break; + case sizeof_like: @; @+break; + case int_like: @; @+break; + case public_like: @; @+break; + case colcol: @; @+break; + case decl_head: @; @+break; + case decl: @; @+break; + case base: @; @+break; + case struct_like: @; @+break; + case struct_head: @; @+break; + case fn_decl: @; @+break; + case function: @; @+break; + case lbrace: @; @+break; + case if_like: @; @+break; + case else_like: @; @+break; + case else_head: @; @+break; + case if_clause: @; @+break; + case if_head: @; @+break; + case do_like: @; @+break; + case case_like: @; @+break; + case catch_like: @; @+break; + case tag: @; @+break; + case stmt: @; @+break; + case semi: @; @+break; + case lproc: @; @+break; + case section_scrap: @; @+break; + case insert: @; @+break; + case prelangle: @; @+break; + case prerangle: @; @+break; + case langle: @; @+break; + case template_like: @; @+break; + case new_like: @; @+break; + case new_exp: @; @+break; + case ftemplate: @; @+break; + case for_like: @; @+break; + case raw_ubin: @; @+break; + case const_like: @; @+break; + case raw_int: @; @+break; + case operator_like: @; @+break; + case typedef_like: @; @+break; + case delete_like: @; @+break; + case question: @; @+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. + +If the first identifier found is a keyword like `\&{case}', we +return the special value |case_found|; this prevents underlining +of identifiers in case labels. + +If the first identifier is the keyword `\&{operator}', we give up; +users who want to index definitions of overloaded \CPLUSPLUS/ operators +should say, for example, `\.{@@!@@\^\\\&\{operator\} \$+\{=\}\$@@>}' (or, +more properly alphebetized, +`\.{@@!@@:operator+=\}\{\\\&\{operator\} \$+\{=\}\$@@>}'). + +@d no_ident_found (token_pointer)0 /* distinct from any identifier token */ +@d case_found (token_pointer)1 /* likewise */ +@d operator_found (token_pointer)2 /* likewise */ + +@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 2: /* |res_flag| */ + if (name_dir[r].ilk==case_like) return case_found; + if (name_dir[r].ilk==operator_like) return operator_found; + if (name_dir[r].ilk!=raw_int) break; + case 1: 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 */ + else if (*j==qualifier) j++; /* bypass namespace qualifier */ + } + } + 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))<=operator_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 find out that the identifier is being defined only 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))<=operator_found) + return; /* this happens, for example, in |case found:| */ + 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. + +@= +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 && nxlink; + } + @; +} + +@ 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|. + +@= + 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|. + +@= +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==ubinop) && 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==lpar && cat2==rpar && cat3==colon) squash(pp+3,1,base,0,5); +else if (cat1==cast && cat2==colon) squash(pp+2,1,base,0,5); +else if (cat1==semi) squash(pp,2,stmt,-1,6); +else if (cat1==colon) { + make_underlined (pp); squash(pp,2,tag,-1,7); +} +else if (cat1==rbrace) squash(pp,1,stmt,-1,8); +else if (cat1==lpar && cat2==rpar && (cat3==const_like || cat3==case_like)) { + big_app1(pp+2); big_app(' '); big_app1(pp+3); reduce(pp+2,2,rpar,0,9); +} +else if (cat1==cast && (cat2==const_like || cat2==case_like)) { + big_app1(pp+1); big_app(' '); big_app1(pp+2); reduce(pp+1,2,cast,0,9); +} +else if (cat1==exp || cat1==cast) squash(pp,2,exp,-2,10); + +@ @= +if ((cat1==exp||cat1==ubinop) && 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==cast) && cat2==rpar) + squash(pp,3,cast,-2,13); +else if ((cat1==decl_head || cat1==int_like || cat1==exp) && cat2==comma) { + big_app3(pp); app(opt); app('9'); reduce(pp,3,lpar,-1,14); +} +else if (cat1==stmt || cat1==decl) { + big_app2(pp); big_app(' '); reduce(pp,2,lpar,-1,15); +} + +@ @= +if (cat1==exp || cat1==int_like) squash(pp,2,exp,-2,16); + +@ @= +if (cat1==cast && cat2==rpar) { + big_app('{'); big_app1(pp); big_app('}'); big_app1(pp+1); + reduce(pp,2,cast,-2,17); +} +else 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); +} + +@ @= +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); +} + +@ @= +if (cat1==lpar) squash(pp,2,lpar,-1,21); +else if (cat1==exp) { + big_app1(pp); big_app(' '); big_app1(pp+1); reduce(pp,2,exp,-2,21); +} +else if (cat1==semi) squash(pp,1,exp,-2,22); + +@ @= +if (cat1==cast) squash(pp,2,exp,-2,23); +else if (cat1==exp) { + big_app1(pp); big_app(' '); big_app1(pp+1); reduce(pp,2,exp,-2,24); +} + +@ @= +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==ubinop || cat1==colon) { + big_app1(pp); big_app(' '); reduce(pp,1,decl_head,-1,27); +} +else if (cat1==semi || cat1==binop) squash(pp,1,decl_head,0,28); + +@ @= +if (cat1==colon) squash(pp,2,tag,-1,29); +else squash(pp,1,int_like,-2,30); + +@ @= +if (cat1==exp||cat1==int_like) { + app(qualifier); squash(pp,2,cat1,-2,31); +}@+else if (cat1==colcol) squash(pp,2,colcol,-1,32); + +@ @= +if (cat1==comma) { + big_app2(pp); big_app(' '); reduce(pp,2,decl_head,-1,33); +} +else if (cat1==ubinop) { + big_app1(pp); big_app('{'); big_app1(pp+1); big_app('}'); + reduce(pp,2,decl_head,-1,34); +} +else if (cat1==exp && cat2!=lpar && cat2!=exp && cat2!=cast) { + make_underlined(pp+1); squash(pp,2,decl_head,-1,35); +} +else if ((cat1==binop||cat1==colon) && cat2==exp && (cat3==comma || + 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 || 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); + +@ @= +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); +} + +@ @= +if (cat1==int_like || cat1==exp) { + if (cat2==comma) { + big_app1(pp); big_app(' '); big_app2(pp+1); + app(opt); app('9'); reduce(pp,3,base,0,42); + } + else if (cat2==lbrace) { + big_app1(pp); big_app(' '); big_app1(pp+1); big_app(' '); big_app1(pp+2); + reduce(pp,3,lbrace,-2,43); + } +} + +@ @= +if (cat1==lbrace) { + big_app1(pp); big_app(' '); big_app1(pp+1); reduce(pp,2,struct_head,0,44); +} +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,2,47); + else if (cat2!=base) { + big_app1(pp); big_app(' '); big_app1(pp+1); reduce(pp,2,int_like,-2,48); + } +} + +@ @= +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); +} + +@ @= +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); +} + +@ @= +if (cat1==function || cat1==decl || cat1==stmt) { + big_app1(pp); big_app(big_force); big_app1(pp+1); reduce(pp,2,cat1,-1,53); +} + +@ @= +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); +} + +@ @= +if (cat1==exp) { + big_app1(pp); big_app(' '); big_app1(pp+1); reduce(pp,2,if_clause,0,57); +} + +@ @= +if (cat1==colon) squash(pp+1,1,base,1,58); +else 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); +} + +@ @= +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); +} + +@ @= +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); +} + +@ @= +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); +} + +@ @= +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); +} + +@ @= +if (cat1==semi) squash(pp,2,stmt,-1,70); +else if (cat1==colon) squash(pp,2,tag,-1,71); +else if (cat1==exp) { + big_app1(pp); big_app(' '); big_app1(pp+1); reduce(pp,2,exp,-2,72); +} + +@ @= +if (cat1==cast || cat1==exp) { + big_app2(pp); big_app(indent); big_app(indent); reduce(pp,2,fn_decl,0,73); +} + +@ @= +if (cat1==tag) { + big_app1(pp); big_app(break_space); big_app1(pp+1); reduce(pp,2,tag,-1,74); +} +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? */ +@= +if (cat1==stmt||cat1==decl||cat1==function) { + big_app1(pp); + if (cat1==function) big_app(big_force); + else if (cat1==decl) big_app(big_force); + else if (force_lines) big_app(force); + else big_app(break_space); + big_app1(pp+1); reduce(pp,2,cat1,-1,76); +} + +@ @= +big_app(' '); big_app1(pp); reduce(pp,1,stmt,-1,77); + +@ @= +if (cat1==define_like) make_underlined(pp+2); +if (cat1==else_like || cat1==if_like ||cat1==define_like) + 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); + } +} + +@ @= +if (cat1==semi) { + big_app2(pp); big_app(force); reduce(pp,2,stmt,-2,81); +} +else squash(pp,1,exp,-2,82); + +@ @= +if (cat1) + squash(pp,2,cat1,0,83); + +@ @= +init_mathness=cur_mathness=yes_math; +app('<'); reduce(pp,1,binop,-2,84); + +@ @= +init_mathness=cur_mathness=yes_math; +app('>'); reduce(pp,1,binop,-2,85); + +@ @= +if (cat1==prerangle) { + big_app1(pp); app('\\'); app(','); big_app1(pp+1); +@.\\,@> + reduce(pp,2,cast,-1,86); +} +else if (cat1==decl_head || cat1==int_like || cat1==exp) { + if (cat2==prerangle) squash(pp,3,cast,-1,87); + else if (cat2==comma) { + big_app3(pp); app(opt); app('9'); reduce(pp,3,langle,0,88); + } +} + +@ @= +if (cat1==exp && cat2==prelangle) squash(pp+2,1,langle,2,89); +else if (cat1==exp || cat1==raw_int) { + big_app1(pp); big_app(' '); big_app1(pp+1); reduce(pp,2,cat1,-2,90); +}@+ else squash(pp,1,raw_int,0,91); + +@ @= +if (cat1==lpar && cat2==exp && cat3==rpar) squash(pp,4,new_like,0,92); +else if (cat1==cast) { + big_app1(pp); big_app(' '); big_app1(pp+1); reduce(pp,2,exp,-2,93); +} +else if (cat1!=lpar) squash(pp,1,new_exp,0,94); + +@ @= +if (cat1==int_like || cat1==const_like) { + big_app1(pp); big_app(' '); big_app1(pp+1); reduce(pp,2,new_exp,0,95); +} +else if (cat1==struct_like && (cat2==exp || cat2==int_like)) { + big_app1(pp); big_app(' '); big_app1(pp+1); big_app(' '); + big_app1(pp+2); reduce(pp,3,new_exp,0,96); +} +else if (cat1==raw_ubin) { + big_app1(pp); big_app('{'); big_app1(pp+1); big_app('}'); + reduce(pp,2,new_exp,0,97); +} +else if (cat1==lpar) squash(pp,1,exp,-2,98); +else if (cat1==exp) { + big_app1(pp); big_app(' '); reduce(pp,1,exp,-2,98); +} +else if (cat1!=raw_int && cat1!=struct_like && cat1!=colcol) + squash(pp,1,exp,-2,99); + +@ @= +if (cat1==prelangle) squash(pp+1,1,langle,1,100); +else squash(pp,1,exp,-2,101); + +@ @= +if (cat1==exp) { + big_app1(pp); big_app(' '); big_app1(pp+1); reduce(pp,2,else_like,-2,102); +} + +@ @= +if (cat1==const_like) { + big_app2(pp); app_str("\\ "); reduce(pp,2,raw_ubin,0,103); +@.\\\ @> +} else squash(pp,1,ubinop,-2,104); + +@ @= +squash(pp,1,int_like,-2,105); + +@ @= +if (cat1==prelangle) squash(pp+1,1,langle,1,106); +else if (cat1==colcol) squash(pp,2,colcol,-1,107); +else if (cat1==cast) squash(pp,2,raw_int,0,108); +else if (cat1==lpar) squash(pp,1,exp,-2,109); +else if (cat1!=langle) squash(pp,1,int_like,-3,110); + +@ @= +if (cat1==binop || cat1==unop || cat1==ubinop) { + if (cat2==binop) break; + big_app1(pp); big_app('{'); big_app1(pp+1); big_app('}'); + reduce(pp,2,exp,-2,111); +} +else if (cat1==new_like || cat1==delete_like) { + big_app1(pp); big_app(' '); big_app1(pp+1); reduce(pp,2,exp,-2,112); +} +else if (cat1==comma) squash(pp,2,exp,-2,113); +else if (cat1!=raw_ubin) squash(pp,1,new_exp,0,114); + +@ @= +if ((cat1==int_like || cat1==cast) && (cat2==comma || cat2==semi)) + squash(pp+1,1,exp,-1,115); +else if (cat1==int_like) { + big_app1(pp); big_app(' '); big_app1(pp+1); reduce(pp,2,typedef_like,0,116); +} +else if (cat1==exp && cat2!=lpar && cat2!=exp && cat2!=cast) { + make_underlined(pp+1); make_reserved(pp+1); + big_app1(pp); big_app(' '); big_app1(pp+1); reduce(pp,2,typedef_like,0,117); +} +else if (cat1==comma) { + big_app2(pp); big_app(' '); reduce(pp,2,typedef_like,0,118); +} +else if (cat1==semi) squash(pp,2,decl,-1,119); +else if (cat1==ubinop && (cat2==ubinop || cat2==cast)) { + big_app('{'); big_app1(pp+1); big_app('}'); big_app1(pp+2); + reduce(pp+1,2,cat2,0,120); +} + +@ @= +if (cat1==lpar && cat2==rpar) { + big_app2(pp); app('\\'); app(','); big_app1(pp+2); +@.\\,@> + reduce(pp,3,delete_like,0,121); +} +else if (cat1==exp) { + big_app1(pp); big_app(' '); big_app1(pp+1); reduce(pp,2,exp,-2,122); +} + +@ @= +if (cat1==exp && (cat2==colon || cat2==base)) { + (pp+2)->mathness=5*yes_math; /* this colon should be in math mode */ + squash(pp,3,binop,-2,123); +} + +@ Now here's the |reduce| procedure used in our code for productions. + +The `|freeze_text|' macro is used to give official status to a token list. +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 + +@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; + } + pp=(pp+d; + pp--; /* we next say |pp++| */ +} + +@ 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; pp=(pp+d; + pp--; /* we next say |pp++| */ + return; + } + for (i=j; i= +while (1) { + @; + 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; + @; +} + +@ 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. + +@= +if (lo_ptrcat=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. + +@= +int tracing; /* can be used to show parsing details */ + +@ @= +{ 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; + @; + @; +} + +@ 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. + +@= { + @; + 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 (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==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; + 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; +} + +@ @= +@; +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: @; + @+break; + case identifier: app_cur_id(1);@+break; + case TeX_string: @;@+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(ubinop,yes_math);@+break; + case '*': app(next_control); app_scrap(raw_ubin,yes_math);@+break; + case '&': app_str("\\AND"); app_scrap(raw_ubin,yes_math);@+break; +@.\\AND@> + case '?': app_str("\\?"); app_scrap(question,yes_math);@+break; +@.\\?@> + case '#': app_str("\\#"); app_scrap(ubinop,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(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,no_math);@+break;@/ + @t\4@> @@; + 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; +} + +@ @= +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. + +@= +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(raw_int,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@> + +@= +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@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{@>@.\\\}@> +@.\\\~@> +@.\\\&@> +@.\\\_@> + 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@> + +@= +app_str("\\hbox{"@q}@>); +@^high-bit character handling@> +while (id_first0177) { + 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|. + +@= +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<=custom) { /* not a reserved word */ + app(id_flag+(int)(p-name_dir)); + if (scrapping) app_scrap(p->ilk==func_template? ftemplate: exp, + p->ilk==custom? yes_math: maybe_math); +@.\\NULL@> + } else { + app(res_flag+(int)(p-name_dir)); + if (scrapping) { + if (p->ilk==alfop) app_scrap(ubinop,yes_math)@; + else 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. + +The token list created from within `\pb' brackets is output as an argument +to \.{\\PB}, if the user has invoked \.{CWEAVE} with the \.{+e} flag. +Although \.{cwebmac} ignores \.{\\PB}, other macro packages +might use it to localize the special meaning of the macros that mark up +program text. + +@d make_pb flags['e'] + +@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; + 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)); + if (make_pb) app_str("\\PB{"); +@.\\PB@> + app(inner_tok_flag+(int)(q-tok_start)); + if (make_pb) app_tok('}'); + 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 */ + +@= 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 */ + +@= +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| */ + +@ @= +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. + +@= +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@> + +@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)); + if (make_pb) { + out_str("\\PB{"); make_output(); out('}'); +@.\\PB@> + }@+else make_output(); /* output the list */ + 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. + +@= +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: @; break; + case section_code: @; 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 ((abig_force) break; + if (a==indent) c++; else if (a==outdent) c--; + else if (a==opt) a=get_output(); + } + @; + goto reswitch; + case indent: case outdent: case opt: case backup: case break_space: + case force: case big_force: case preproc_line: @; break; + case quoted_char: out(*(cur_tok++)); + case qualifier: 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\}}'. + +@= +out('\\'); +if (a==identifier) { + if (cur_name->ilk==custom && !doing_format) { + custom_out: + for (p=cur_name->byte_start;p<(cur_name+1)->byte_start;p++) + out(*p=='_'? 'x': *p=='$'? 'X': *p); + break; + } else if (is_tiny(cur_name)) out('|')@; +@.\\|@> + else { 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 if (cur_name->ilk==alfop) { + out('X'); + goto custom_out; +}@+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,1); + +@ The current mode does not affect the behavior of \.{CWEAVE}'s output routine +except when we are outputting control tokens. + +@= +if (a +@.\\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 @ + +@ 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}'). + +@= { + b=a; save_mode=cur_mode; c=0; + while (1) { + a=get_output(); + if (a==inserted) continue; + if (a==cancel || a==big_cancel) { + @; + goto reswitch; /* |cancel| overrides everything */ + } + if ((a!=' ' && abig_force) { + if (save_mode==outer) { + if (out_ptr>out_buf+3 && strncmp(out_ptr-3,"\\Y\\B",4)==0) + goto reswitch; + @; + 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= + 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. + +@= { + 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}@>); +@.\\.@> + @; + if (an_output) out_str(@q{@>" }"); + out_str("\\X"); +} + +@ @= +sprint_section_name(scratch,cur_name); +k=scratch; +k_limit=scratch+strlen(scratch); +cur_section_name=cur_name; +while (k; + if (an_output) + switch (b) { + case ' ':case '\\':case '#':case '%':case '$':case '^': + case '{': case '}': case '~': case '&': case '_': + out('\\'); /* falls through */ +@.\\\ @> +@.\\\\@> +@.\\\#@> +@.\\\%@> +@.\\\$@> +@.\\\^@> +@.\\\{@>@q}@> +@q{@>@.\\\}@> +@.\\\~@> +@.\\\&@> +@.\\\_@> + default: out(b); + } + else if (b!='|') out(b)@; + else { + @; + save_loc=loc; save_limit=limit; loc=limit+2; limit=j+1; + *limit='|'; output_C(); + loc=save_loc; limit=save_limit; + } +} + +@ @= +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. + +@= +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)) + @@; + 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; + } +} + +@ @= { + 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. + +@= +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) @; +} + +@ 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@> + +@= +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? */ + +@ @= { + section_count++; + @; + save_position; + @; + @; + @; + @; + @; +} + +@ 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. + +@= +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. + +@= 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|, and +the token memory is in its initial empty state. + +@= +space_checked=0; +while (next_control<=definition) { /* |format_code| or |definition| */ + init_stack; + if (next_control==definition) @@; + else @; + 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}. + +@= +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 `\.)'. + +@= { + 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 */ + } +} + +@ @= { + 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. + +@= +name_pointer this_section; /* the current section name, or zero */ + +@ @= +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; + @= +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 */ + +@ @= +if (next_control + 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. + +@= +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. + +@= +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'); + @; + 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. + +@= +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 */ + } +} + +@ @= +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. + +@= +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) { + @; finish_line(); finish_line(); + } + out_str("\\inx"); finish_line(); +@.\\inx@> + active_file=idx_file; /* change active file to the index file */ + @; + @; + 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 */ + @; + 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. + +@= +sixteen_bits k_section; /* runs through the 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= +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. + +@= { +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|. + +@ @= +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 */ + +@= +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| */ + +@ @= +max_sort_ptr=scrap_info; + +@ The desired alphabetic order is specified by the |collate| array; namely, +$|collate|[0]<|collate|[1]<\cdots<|collate|[100]$. + +@= +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. + +@= +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) */ + +@= +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_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) + @@; + else @; +} + +@ @= { + 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); +} + +@ @= { + cur_name=sort_ptr->head; + do { + out_str("\\I"); +@.\\I@> + @; + @; + cur_name=blink[cur_name-name_dir]; + } while (cur_name); + --sort_ptr; +} + +@ @= +switch (cur_name->ilk) { + case normal: case func_template: 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 wildcard: out_str("\\9");@+ goto not_an_identifier; +@.\\9@> + case typewriter: out_str("\\."); +@.\\.@> + case roman: not_an_identifier: out_name(cur_name,0); goto name_done; + case custom: {char *j; out_str("$\\"); + for (j=cur_name->byte_start;j<(cur_name+1)->byte_start;j++) + out(*j=='_'? 'x': *j=='$'? 'X': *j); + out('$'); + goto name_done; + } + default: out_str("\\&"); +@.\\\&@> +} +out_name(cur_name,1); +name_done:@; + +@ Section numbers that are to be underlined are enclosed in +`\.{\\[}$\,\ldots\,$\.]'. + +@= +@; +do { + out_str(", "); cur_val=cur_xref->num; + if (cur_val + 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. +@= +xref_pointer next_xref, this_xref; + /* pointer variables for rearranging a list */ + +@ @= +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@> + +@= +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); + } +} + +@ @=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/cweb/cweb.1 b/web/c_cpp/cweb/cweb.1 new file mode 100644 index 0000000000..ad41c427ea --- /dev/null +++ b/web/c_cpp/cweb/cweb.1 @@ -0,0 +1,138 @@ +.TH CWEB 1L 2002-Apr-13 +. +.SH NAME +ctangle, cweave \- translate CWEB to C and/or TeX +. +.SH SYNOPSIS +.na +.B ctangle +[ +.B \-bhp +] [ +.B +s +] webfile[.w] [changefile[.ch]] [outputfile[.c]] +.br +.B cweave +[ +.B \-befhpx +] [ +.B +s +] webfile[.w] [changefile[.ch]] [outputfile[.tex]] +.ad +. +.SH DESCRIPTION +The +.I ctangle +program converts a CWEB +source document into a C\ program that may be compiled in the usual way. +The output file includes #line specifications so that debugging can be +done in terms of the CWEB source file. +.PP +The +.I cweave +program converts the same CWEB file into a TeX file that may be +formatted and printed in the usual way. +It takes appropriate care of typographic details like page +layout and the use of indentation, italics, boldface, etc., and it supplies +extensive cross-index information that it gathers automatically. +.PP +CWEB allows you to prepare a single +document containing all the information that is needed both to produce +a compilable C\ program and to produce a well-formatted document +describing the program in as much detail as the writer may desire. +The user of CWEB ought to be familiar with TeX as well as\ C. +.PP +The command line should have one, two, or three names on it. +The first is taken as the CWEB file (and .w is added if there is no +extension). +If that file cannot be opened, the extension .web is tried instead. +(But .w is recommended, since .web usually implies Pascal.) +If there is a second name, it is a change file (and .ch is added if there is +no extension). +The change file overrides parts of the WEB file, +as described in the documentation. +If there is a third name, it overrides +the default name of the output file, which is ordinarily the same as +the name of the input file (but on the current directory) with the +extension .c or .tex. +.PP +Options in the command line may be either turned off with\ \- +(if they are on by default) or turned on with\ + (if they are off by +default). +In fact, the options are processed from left to right, +so a sequence like -f\ +f corresponds to +f (which is the default). +.PP +The +.B \-b +option suppresses the banner line that normally appears on your terminal +when ctangle or cweave begins. +The +.B \-h +option suppresses the happy message that normally appears if the processing +was successful. +The +.B \-p +option suppresses progress reports (starred module numbers) as the processing +takes place. +If you say -bhp, you get nothing but error messages. +.PP +The +.B +s +option prints statistics about memory usage at the end of a run +(assuming that the programs have been compiled with the -DSTAT switch). +.PP +There are three other options applicable to +.I cweave +only: +.B \-f +means do not force a newline after every statement in the formatted output. +.B \-e +inhibits the enclosure of C\ material formatted by +.I cweave +in brackets +\ePB{...}. +Such brackets are normally inserted so that special hooks +can be used by +.I cweb-latex +and similar programs. +.B \-x +means omit the index and table of contents. +. +.SH FILES +.TP +/usr/local/lib/tex/inputs/cwebmac.tex +TeX macros used by cweave output. +.TP +/usr/local/src/cweb/cwebman.tex +The user manual. +.TP +/usr/local/src/cweb/examples/wc.w +An introductory example. +.TP +/usr/local/src/cweb/examples/wmerge.w +Patch program based on CWEB-style change files. +.TP +/usr/local/lib/cweb +Directory for cweb "include" files. +. +.SH "SEE ALSO" +.TP +.I Literate Programming +by D. E. Knuth +.TP +.I Weaving a Program +by Wayne Sewell +.TP +.I The CWEB System of Structured Documentation +by Donald E. Knuth and Silvio Levy (hardcopy version of cwebman.tex +and the source code listings) +.TP +tex(1), cc(1) +. +.SH AUTHORS +Don Knuth wrote WEB for TeX and Pascal. +Silvio Levy designed and developed CWEB +by adapting the WEB conventions to\ C and by recoding everything in CWEB. +Knuth began using CWEB and made further refinements. +Many other helpers are acknowledged in the CWEB manual. + diff --git a/web/c_cpp/cweb/cweb.el b/web/c_cpp/cweb/cweb.el new file mode 100644 index 0000000000..c243f35b2e --- /dev/null +++ b/web/c_cpp/cweb/cweb.el @@ -0,0 +1,218 @@ +;; This file contains extensions to GNU-Emacs, to wit: +; (1) some WEB-oriented functions that are also of general use +; (2) changes to the GNU-distributed TeX mode +; (3) definitions of simple WEB and CWEB modes + +; To use: Put this in your EMACS-lisp library and say (load-library "cweb") +; in your .emacs init file. + +; Contributed by Don Knuth, July 1990 + +;; OK, here's part (1): some WEB-oriented functions whose main purpose is +; to maintain a stack of module names that are "pending" as you are writing +; a program. When you first think of a module that needs to be written later, +; put it into the pending list (by typing CTL-Z instead of @> after the +; name). Later you can say CTL-\ to retrieve a pending name (and if +; you want to cycle through the pending names, ESC-y after CTL-\ will +; do it, just as ESC-y works after a yank). +; After you've said CTL-\, the current region is the name just removed from +; the pending list. If you change your mind, you can put it back again by +; saying ESC-\. If you had put it into the pending list by mistake, you +; can get rid of it by using the normal CTL-W operation (kill-region). +; The following code binds the new commands to CTL-Z, CTL-\, and ESC-\ +; in all modes. You may prefer other bindings, of course. +; CTL-Z is normally "suspend emacs", but it is best not used when emacs +; has its own window as it usually does nowadays; if you need the +; old CTL-Z, you might rather bind it to CTL-X CTL-Z. +; CTL-\ is normally undefined. +; ESC-\ is normally "delete space", but ESC-space DEL does that easily too. + +(defvar pending-list nil + "List of strings (usually WEB module names) still pending.") + +(defun into-pending-list (beg end) + "Copy region into pending-list." + (interactive "r") + (indicate-region) + (setq pending-list (cons (buffer-substring beg end) pending-list))) + +(defun new-module-name-pending () + "Insert @> to complete a module name, then put it into pending-list." + (interactive) + (insert "@>") + (push-mark) + (if (search-backward "@<" nil t) + (progn + (exchange-point-and-mark) + (into-pending-list (point) (mark)) + ) + (message "There's no @< to begin the module name!"))) +(global-set-key "\C-z" 'new-module-name-pending) + +(defun pop-pending-list (arg) + "Remove first element of pending-list and insert it as current region. +With argument, put point at left; otherwise point will follow the insertion. +Say \\[new-yank-pop] to replace this by another element of the list. +Say \\[into-pending-list] to put it back in the list." + (interactive "*P") + (if (consp pending-list) + (progn + (push-mark (point)) + (insert (car pending-list)) + (setq pending-list (cdr pending-list)) + (if arg + (exchange-point-and-mark))) + (message "Nothing is pending.") + (setq this-command nil))) +(global-set-key "\C-\\" 'pop-pending-list) +(global-set-key "\M-\\" 'into-pending-list) + +(defun new-yank-pop (arg) + "If previous command was \\[pop-pending-list], pop a different string; +otherwise do an ordinary Meta-y." + (interactive "*p") + (if (eq last-command 'pop-pending-list) + (let (xch) + (setq xch (< (point) (mark))) + (setq pending-list (append pending-list + (list (buffer-substring (point) (mark))))) + (delete-region (point) (mark)) + (setq this-command 'pop-pending-list) + (pop-pending-list xch)) + (yank-pop arg))) +(global-set-key "\M-y" 'new-yank-pop) + +(defun indicate-region () + "Bounce cursor to mark and back again" + (let ((point-save (point))) + (unwind-protect + (progn (goto-char (mark)) + (sit-for 0 300)) ;; wait 300 milliseconds + (goto-char point-save)))) + +; I prefer to change the standard copy-region command to the following, +; which gives me visual feedback about what I've copied to the kill ring: +(defun indicate-and-copy-region (beg end) + "Indicate current region, then copy it to the kill ring." + (interactive "r")(indicate-region)(copy-region-as-kill beg end)) +(global-set-key "\M-w" 'indicate-and-copy-region) + +; Here's another convenient command, bound to the usually unused ESC-". +(defun ditto (arg) + "Copy ARG characters from the line above." + (interactive "*p") + (let (ch) + (while (> arg 0) + (setq temporary-goal-column (current-column)) + (save-excursion + (previous-line 1) + (setq ch (following-char))) + (insert ch) + (setq arg (1- arg))))) +(global-set-key "\M-\"" 'ditto) +; If "ditto" suddenly fails to work, you have probably set goal-column +; inadvertently. To unset it, say C-u C-x C-n. + +;; OK, here's part (2): Changes to TeX mode. +; The WEB modes below are very much like TeX mode, but some improvements were +; desirable in TeX mode: +; I made newline act as it does in indented-text mode, since this +; works nicely for both TeX and WEB (Pascal or C code). +; I made RET check for unmatched delimiters if it ends a paragraph. +; Otherwise TeX mode remains as it was before. + +(setq TeX-mode-map (make-sparse-keymap)) +(define-key TeX-mode-map "\C-c\C-k" 'TeX-kill-job) +(define-key TeX-mode-map "\C-c\C-l" 'TeX-recenter-output-buffer) +(define-key TeX-mode-map "\C-c\C-q" 'TeX-show-print-queue) +(define-key TeX-mode-map "\C-c\C-p" 'TeX-print) +(define-key TeX-mode-map "\"" 'TeX-insert-quote) +(define-key TeX-mode-map "\e}" 'up-list) +(define-key TeX-mode-map "\e{" 'TeX-insert-braces) +(define-key TeX-mode-map "\C-c\C-r" 'TeX-region) +(define-key TeX-mode-map "\C-c\C-b" 'TeX-buffer) +(define-key TeX-mode-map "\C-c\C-f" 'TeX-close-LaTeX-block) +(define-key TeX-mode-map "\r" 'TeX-newline) +(define-key TeX-mode-map "\t" 'indent-relative) +(setq TeX-mode-hook '(lambda () + (make-local-variable 'indent-line-function) + (setq indent-line-function 'indent-relative-maybe))) + +(defun TeX-newline (arg) +"If previous character is newline and no ARG, check for unbalanced braces +and/or dollar signs in previous paragraph. If ARG is \\[universal-argument], +do a single newline; otherwise do ordinary newline." + (interactive "*P") + (if (and (eq (preceding-char) ?\n) (not arg)) + (TeX-check-paragraph) + (if (listp arg) + (newline) + (newline arg)))) + +(defun TeX-check-paragraph () +"Insert a newline following a newline, breaking a paragraph for TeX. +Check for mismatched delimiters in paragraph being terminated." + (interactive) + (if (TeX-validate-paragraph + (save-excursion + (search-backward "\n\n" nil 'move) + (point)) + (point)) + (insert ?\n) + (insert ?\n) + (error "Mismatched delimiters in that paragraph?"))) + +;; and now, part (3): WEB and CWEB modes. +; These are like plain TeX mode except that the automatic conversion of +; " to `` or '' is disabled. (Personally I never liked that feature anyway, +; since it's easy to get used to typing `` and ''. In WEB modes, the +; feature soon becomes intolerable, unless you never use string constants!) +; Another thing distinguishing WEB mode from TeX is ESC-p and ESC-n, to +; move to previous or next module. These keys are usually unbound, except +; when processing email. + +(defun forward-module (arg) +"Advance past next WEB module beginning; with ARG, repeat ARG times." + (interactive "p") + (move-to-module arg)) +(defun backward-module (arg) +"Advance to previous WEB module beginning; with ARG, repeat ARG times." + (interactive "p") + (move-to-module (- arg))) +(defun move-to-module (arg) + (while (> arg 0) + (re-search-forward "@ \\|@\\*\\|@\n") + (setq arg (1- arg))) + (while (< arg 0) + (re-search-backward "@ \\|@\\*\\|@\n") + (setq arg (1+ arg)))) + +(defun web-mode () + "Major mode like TeX mode plus \\[forward-module] and \\[backward-module] +for relative module movement. The automatic \" feature is disabled." + (interactive) + (plain-tex-mode) + (local-set-key "\M-n" 'forward-module) + (local-set-key "\M-p" 'backward-module) + (local-set-key "\"" 'self-insert-command) + (setq mode-name "WEB") + (setq major-mode 'web-mode) + (run-hooks 'web-mode-hook)) +(setq auto-mode-alist (cons '("\\.web$" . web-mode) auto-mode-alist)) + +(defun cweb-mode () + "Major mode like TeX mode plus \\[forward-module] and \\[backward-module] +for relative module movement. The automatic \" feature is disabled." + (interactive) + (plain-tex-mode) + (local-set-key "\M-n" 'forward-module) + (local-set-key "\M-p" 'backward-module) + (local-set-key "\"" 'self-insert-command) + (setq comment-start nil) + (modify-syntax-entry ?% "@") + (setq mode-name "CWEB") + (setq major-mode 'cweb-mode) + (setq tex-fontify-script nil) ;; needed in GNU Emacs version 22? + (run-hooks 'cweb-mode-hook)) +(setq auto-mode-alist (cons '("\\.w$" . cweb-mode) auto-mode-alist)) +(setq auto-mode-alist (cons '("\\.ch$" . cweb-mode) auto-mode-alist)) diff --git a/web/c_cpp/cweb/cwebmac.tex b/web/c_cpp/cweb/cwebmac.tex new file mode 100644 index 0000000000..60f86ce5a9 --- /dev/null +++ b/web/c_cpp/cweb/cwebmac.tex @@ -0,0 +1,553 @@ +% standard macros for CWEB listings (in addition to plain.tex) +% Version 3.70 --- July 2017 +\ifx\renewenvironment\undefined\else\endinput\fi % LaTeX will use other macros +\xdef\fmtversion{\fmtversion+CWEB3.70} +\chardef\cwebversion=3 \chardef\cwebrevision=70 +\newif\ifpdf +\ifx\pdf+\pdftrue\fi +% Uncomment the following line if you want PDF goodies to be the default +%\ifx\pdf-\else\pdftrue\fi +\def\pdflinkcolor{0 0 1} % the RGB values for hyperlink color +\newif\ifpdftex +\ifx\pdfoutput\undefined \pdftexfalse \else\ifnum\pdfoutput=0 \pdftexfalse +%\else \pdftextrue \pdfoutput=1 \input pdfcolor \let\setcolor\pdfsetcolor \fi\fi +\else \pdftextrue \pdfoutput=1 % changed in 3.69 + \def\Black{\pdfliteral{0 g 0 G}} % use rgb colors for direct PDF output too + \def\Blue{\pdfliteral{0 0 1 rg 0 0 1 RG}} +\fi\fi +\newif\ifacro \ifpdf\acrotrue\fi \ifpdftex\acrotrue\fi + +\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{} + % with this definition of \9 you can say @:sort key}{TeX code@> + % to alphabetize an index entry by the sort key but format with the TeX code +\font\eightrm=cmr8 +\let\sc=\eightrm % for smallish 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\\#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\){{\tentex\kern-.05em}\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{{\acrofalse\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} +\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~\ifacro{\pdfnote#2.}\else#2\fi.\par}} + +\newtoks\toksA \newtoks\toksB \newtoks\toksC \newtoks\toksD +\newtoks\toksE \newtoks\toksF \newtoks\usersanitizer +\newcount\countA \countA=0 \newcount\countB \countB=0 +\newcount\countC \countC=0 +\newif\iftokprocessed \newif\ifTnum \newif\ifinstr +{\def\\{\global\let\spacechar= }\\ } + +\ifacro % The following are pdf macros +\def\thewidth{\the\wd0 \space} +\def\theheight{\the\ht\strutbox\space} +\def\thedepth{\the\dp\strutbox\space} +\ifpdftex + \ifx\pdfannotlink\undefined\let\pdfannotlink\pdfstartlink\fi% for pdfTeX 0.14 + \def\pdflink#1#2{\hbox{\pdfannotlink height\ht\strutbox depth\dp\strutbox + attr{/Border [0 0 0]} goto num #1 \Blue #1\Black\pdfendlink}} % changed 3.69 +\else\def\pdflink#1#2{\setbox0=\hbox{\special{pdf: bc [ \pdflinkcolor ]}{#1}% + \special{pdf: ec}}\special{pdf: ann width \thewidth height \theheight + depth \thedepth << /Type /Annot /Subtype /Link + /Border [0 0 0] /A << /S /GoTo /D (#2) >> >>}\box0\relax}\fi +\def\pdfnote#1.{\setbox0=\hbox{\toksA={#1.}\toksB={}\maketoks}\the\toksA} +\def\firstsecno#1.{\setbox0=\hbox{\toksA={#1.}\toksB={}% + \def\makenote{\addtokens\toksB{\the\toksC}\def\makenote{\toksD={} + \toksC={}\let\space\empty}\makenote}\maketoks}} +\def\addtokens#1#2{\edef\addtoks{\noexpand#1={\the#1#2}}\addtoks} +\def\poptoks#1#2|ENDTOKS|{\let\first=#1\toksD={#1}% + \ifcat\noexpand\first0\countB=`#1\else\countB=0\fi\toksA={#2}} +\def\maketoks{\expandafter\poptoks\the\toksA|ENDTOKS|% + \ifnum\countB>`9 \countB=0 \fi + \ifnum\countB<`0 + \ifnum0=\countC\else\makenote\fi + \ifx\first.\let\next=\maketoksdone\else + \let\next=\maketoks + \addtokens\toksB{\the\toksD} + \ifx\first,\addtokens\toksB{\space}\fi + \fi + \else \addtokens\toksC{\the\toksD}\global\countC=1\let\next=\maketoks + \fi + \next +} +\def\makenote{\addtokens\toksB + {\noexpand\pdflink{\the\toksC}{\romannumeral\the\toksC}}\toksC={}\global\countC=0} +\def\maketoksdone{\edef\st{\global\noexpand\toksA={\the\toksB}}\st} +\def\pdfURL#1#2{\ifpdftex\pdfannotlink height\ht\strutbox depth\dp\strutbox + attr {/Border [0 0 0]} user { /Type /Action /Subtype /Link /A + << /S /URI /URI (#2) >>}\Blue #1\Black \pdfendlink % changed in 3.69 + \else \ifpdf{\setbox0=\hbox{\special{pdf: bc [ \pdflinkcolor ]}{#1}% + \special{pdf: ec}}\special{pdf: ann width \thewidth\space height \theheight + \space depth \thedepth\space << /Border [0 0 0] + /Type /Action /Subtype /Link /A << /S /URI /URI (#2) >> >>}\box0\relax}% + \else #1 ({\tt#2})\fi\fi} +{\catcode`\~=12 \gdef\TILDE/{~}} % ~ in a URL +{\catcode`\_=12 \gdef\UNDER/{_}} % _ in a URL +\def\sanitizecommand#1#2{\addtokens\usersanitizer + {\noexpand\dosanitizecommand\noexpand#1{#2}}} +\def\dosanitizecommand#1#2{\ifx\nxt#1\addF{#2}\fi} + +\catcode`\[=1 \catcode`\]=2 \catcode`\{=12 \catcode`\}=12 + \def\lbchar[{] \def\rbchar[}] +\catcode`\[=12 \catcode`\]=12 \catcode`\{=1 \catcode`\}=2 +\catcode`\~=12 \def\tildechar{~} \catcode`\~=13 +\catcode`\|=0 |catcode`|\=12 |def|bschar{\} |catcode`|\=0 \catcode`\|=12 +\def\makeoutlinetoks{\Tnumfalse\afterassignment\makeolproctok\let\nxt= } +\def\makeolnexttok{\afterassignment\makeolproctok\let\nxt= } +\def\makeolgobbletok{\afterassignment\makeolnexttok\let\nxt= } +\def\addF#1{\addtokens\toksF{#1}\tokprocessedtrue} +% now comes a routine to "sanitize" section names, for pdf outlines +\def\makeolproctok{\tokprocessedfalse + \let\next\makeolnexttok % default + \ifx\nxt\outlinedone\let\next\outlinedone + \else\ifx{\nxt \else\ifx}\nxt \Tnumfalse \instrfalse % skip braces + \else\ifx$\nxt % or a $ sign + \else\ifx^\nxt \addF^\else\ifx_\nxt \addF_% sanitize ^ and _ + \else\ifx\nxt\spacechar \addF\space + \else\if\noexpand\nxt\relax % we have a control sequence; is it one we know? + \ifx\nxt~\addF\space + \else\ifx\nxt\onespace\addF\space + \else\the\usersanitizer + \iftokprocessed\else\makeolproctokctli + \iftokprocessed\else\makeolproctokctlii + \iftokprocessed\else\makeolproctokctliii % if not recognised, skip it + \fi\fi\fi\fi\fi + \else % we don't have a control sequence, it's an ordinary char + \ifx/\nxt \addF{\string\/}% quote chars special to PDF with backslash + \else\ifx(\nxt \addF{\string\(}\else\ifx)\nxt \addF{\string\)}% + \else\ifx[\nxt \addF{\string\[}\else\ifx]\nxt \addF{\string\]}% + \else\expandafter\makeolproctokchar\meaning\nxt + \fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi + \next +} +\def\makeolproctokchar#1 #2 #3{\addF{#3}} +\def\makeolproctokctli{% + \ifx\nxt\CEE\addF{C}\let\next\makeolgobbletok % \CEE/ + \else\ifx\nxt\UNIX\addF{UNIX}\let\next\makeolgobbletok % \UNIX/ + \else\ifx\nxt\TEX\addF{TeX}\let\next\makeolgobbletok % \TEX/ + \else\ifx\nxt\TeX\addF{TeX}\else\ifx\nxt\LaTeX\addF{LaTeX}% + \else\ifx\nxt\CPLUSPLUS\addF{C++}\let\next\makeolgobbletok % \CPLUSPLUS/ + \else\ifx\nxt\Cee\addF{C}% + \else\ifx\nxt\PB \let\next\makeolgobbletok \tokprocessedtrue % \PB{...} + \else\ifx\nxt\.\tokprocessedtrue\instrtrue % \.{...} + % skip \| + \else\ifx\nxt\\\ifinstr\addF{\bschar\bschar}\else\tokprocessedtrue\fi + \else\ifx\nxt\&\ifinstr\addF&\else\tokprocessedtrue\fi + \else\ifx\nxt\~\ifTnum\addF{0}\else\addF\tildechar\fi % 077->\T{\~77} + \else\ifx\nxt\_\ifTnum\addF{E}\else\addF_\fi % 0.1E5->\T{0.1\_5} + \else\ifx\nxt\^\ifTnum\addF{0x}\else\addF^\fi % 0x77 -> \T{\^77} + \else\ifx\nxt\$\ifTnum\tokprocessedtrue\else\addF$\fi % \T{77\$L} + \else\ifx\nxt\{\addF\lbchar \else\ifx\nxt\}\addF\rbchar + \else\ifx\nxt\ \addF\space \else\ifx\nxt\#\addF{\string\#}% + \else\ifx\nxt\PP\addF{++}\else\ifx\nxt\MM\addF{--}% + \fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi +} +\def\makeolproctokctlii{% + \ifx\nxt\MG\addF{->}\else\ifx\nxt\GG\addF{>>}% + \else\ifx\nxt\LL\addF{<<}\else\ifx\nxt\NULL\addF{NULL}% + \else\ifx\nxt\AND\addF&\else\ifx\nxt\OR\addF|% + \else\ifx\nxt\XOR\addF^\else\ifx\nxt\CM\addF\tildechar + \else\ifx\nxt\MOD\addF{\string\%}\else\ifx\nxt\DC\addF{::}% + \else\ifx\nxt\PA\addF{.*}\else\ifx\nxt\MGA\addF{->*}% + \else\ifx\nxt\this\addF{this}\else\ifx\nxt\?\addF?% + \else\ifx\nxt\E\addF{==}\else\ifx\nxt\G\addF{>=}% + \else\ifx\nxt\I\addF{!=}\else\ifx\nxt\K\addF{=}% + \else\ifx\nxt\l\addF{l}\else\ifx\nxt\L\addF{L}% + \else\ifx\nxt\o\addF{o}\else\ifx\nxt\O\addF{O}% + \else\ifx\nxt\R\addF!% + \else\ifx\nxt\T \Tnumtrue \let\next\makeolgobbletok + \tokprocessedtrue % \T{number} + \else\ifx\nxt\AM\addF&\else\ifx\nxt\%\addF{\string\%}% + \fi\fi\fi\fi\fi \fi\fi\fi\fi\fi + \fi\fi\fi\fi\fi \fi\fi\fi\fi\fi + \fi\fi\fi\fi\fi\fi +} +\def\makeolproctokctliii{% + \ifx\nxt\V\addF{||}\else\ifx\nxt\W\addF{&&}\else\ifx\nxt\Z\addF{<=}% + \else\ifx\nxt\*\addF*\else\ifx\nxt\Xand\addF{\space and\space}% + \else\ifx\nxt\Xandxeq\addF{\space and_eq\space}% + \else\ifx\nxt\Xbitand\addF{\space bitand\space}% + \else\ifx\nxt\Xbitor\addF{\space bitor\space}% + \else\ifx\nxt\Xcompl\addF{\space compl\space}% + \else\ifx\nxt\Xnot\addF{\space not\space}% + \else\ifx\nxt\Xnotxeq\addF{\space not_eq\space}% + \else\ifx\nxt\Xor\addF{\space or\space}% + \else\ifx\nxt\Xorxeq\addF{\space or_eq\space}% + \else\ifx\nxt\Xxor\addF{\space xor\space}% + \else\ifx\nxt\Xxorxeq\addF{\space xor_eq\space}% + \fi\fi\fi\fi\fi\fi\fi\fi\fi\fi + \fi\fi\fi\fi\fi +} +\def\outlinedone{\edef\outlinest{\global\noexpand\toksE={\the\toksF}}% + \outlinest\let\outlinedone=\relax} +\fi % End of pdf macros + +\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}% + \ifpdftex\smash{\raise\baselineskip\hbox to0pt{% +% \let\*=\empty\pdfdest num \secstar fith}} % bad space in versions < 3.68 + \let\*=\empty\pdfdest num \secstar fith}}% changed in version 3.68 + \else\ifpdf\smash{\raise\baselineskip\hbox to0pt{% + \let\*=\empty\special{% + pdf: dest (\romannumeral\secstar) [ @thispage /FitH @ypos ]}}}\fi\fi} +\let\startsection=\stsec +\def\defin#1{\global\advance\ind by 2 \1\&{#1 } } % begin `define' or `format' +\def\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 1000 % 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.{% beginning of starred section + \ifacro{\toksF={}\makeoutlinetoks#3\outlinedone\outlinedone}\fi + \gdepth=#1\gtitle={#3}\MN{#2}% + \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 + \def\stripprefix##1>{}\def\gtitletoks{#3}% + \edef\gtitletoks{\expandafter\stripprefix\meaning\gtitletoks}% + \edef\next{\write\cont{\ZZ{\gtitletoks}{#1}{\secno}% write to contents file + {\noexpand\the\pageno}{\the\toksE}}}\next % \ZZ{title}{depth}{sec}{page}{ss} + \ifpdftex\expandafter\xdef\csname curr#1\endcsname{\secno} + \ifnum#1>0\countB=#1 \advance\countB by-1 + \advancenumber{chunk\the\countB.\expnumber{curr\the\countB}}\fi\fi + \ifpdf\special{pdf: outline #1 << /Title (\the\toksE) /Dest + [ @thispage /FitH @ypos ] >>}\fi + \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 % versions < 3.67 + \def\$##1{\egroup_{\rm##1}\bgroup}% suffix to constant % in version 3.67 + \def\_{\cdot 10^{\aftergroup}}% power of ten (via dirty trick) + \let\~=\oct \let\^=\hex {#1}$}} +\def\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\,${\let\I=\ne#2\eightrm\kern.5em + \ifacro{\pdfnote#1.}\else#1\fi}$\,\rangle$\XX} +\def\Y{\par\yskip} +\let\Z=\le +\let\ZZ=\let % now you can \write the control sequence \ZZ +\let\*=* + +\def\Xand{\W} \def\Xandxeq{\MRL{{\AND}{\K}}} \def\Xbitand{\AND} +\def\Xbitor{\OR} \def\Xcompl{\CM} \def\Xnot{\R} \def\Xnotxeq{\I} \def\Xor{\V} +\def\Xorxeq{\MRL{{\OR}{\K}}} \def\Xxor{\XOR} \def\Xxorxeq{\MRL{{\XOR}{\K}}} + +%\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 + +\newif\ifheader +\def\lheader{\headertrue\mainfont\the\pageno\eightrm\qquad\grouptitle + \hfill\title\qquad\mainfont\topsecno} % top line on left-hand pages +\def\rheader{\headertrue\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\startpdf{\ifpdftex\pdfcatalog{/PageMode /UseOutlines}\else + \ifpdf{\special{pdf: docview << /PageMode /UseOutlines >>}}\fi\fi} +\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=\hoffset + % shift righthand pages wrt lefthand ones (changed in version 3.70) +\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, ##2.{\par\hangindent2em\noindent##1:\kern1em + \ifacro\pdfnote##2.\else##2\fi.} % 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 + \ifpdftex \makebookmarks \fi % added in Version 3.68 + \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~\ifacro{\pdfnote##2.}\else{##2}\fi.}} + \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\*=* + \ifacro \def\outsecname{Names of the sections} \let\Xpdf\X +% \ifpdftex \makebookmarks \pdfdest name {NOS} fitb % in versions < 3.68 + \ifpdftex \pdfdest name {NOS} fith % changed in version 3.69 + \pdfoutline goto name {NOS} count -\secno {\outsecname} + \def\X##1:##2\X{\Xpdf##1:##2\X \firstsecno##1.% + {\toksF={}\makeoutlinetoks##2\outlinedone\outlinedone}% + \pdfoutline goto num \the\toksA \expandafter{\the\toksE}} + \else\ifpdf + \special{pdf: outline -1 << /Title (\outsecname) + /Dest [ @thispage /FitH @ypos ] >>} + \def\X##1:##2\X{\Xpdf##1:##2\X \firstsecno##1.% + {\toksF={}\makeoutlinetoks##2\outlinedone\outlinedone}% + \special{pdf: outline 0 << /Title (\the\toksE) + /A << /S /GoTo /D (\romannumeral\the\toksA) >> >>}} + \fi\fi\fi + \readsections} +\def\makebookmarks{\let\ZZ=\writebookmarkline \readcontents\relax} +\def\expnumber#1{\expandafter\ifx\csname#1\endcsname\relax 0% + \else \csname#1\endcsname \fi} % Petr Olsak's macros from texinfo.tex +\def\advancenumber#1{\countA=\expnumber{#1}\relax \advance\countA by1 + \expandafter\xdef\csname#1\endcsname{\the\countA}} +\def\writebookmarkline#1#2#3#4#5{{% + \let\(=\let \let\)=\let \let\[=\let \let\]=\let \let\/=\let + \pdfoutline goto num #3 count -\expnumber{chunk#2.#3} {#5}}} +\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 \startpdf + \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#5{\ifnum#2=0 \smallbreak\fi + \line{\consetup{#2}#1 + \rm\leaders\hbox to .5em{.\hfil}\hfil + \ \ifacro\pdflink{#3}{\romannumeral#3}\else#3\fi\hbox to3em{\hss#4}}} +\def\consetup#1{\ifcase#1 \bf % depth -1 (@**) + \or % depth 0 (@*) + \or \hskip2em % depth 1 (@*1) + \or \hskip4em \or \hskip6em \or \hskip8em \or \hskip10em % depth 2,3,4,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{% versions up to 3.65 +% \def\topofcontents{\leftline{\sc\today\ at \hours}\bigskip +% \centerline{\titlefont\title}\vfill}} % timestamps the contents page +\def\datecontentspage{% changed in version 3.66 + \def\botofcontents{\vfill + \centerline{\covernote} + \bigskip + \leftline{\sc\today\ at \hours}}} % timestamps the contents page diff --git a/web/c_cpp/cweb/cwebman.tex b/web/c_cpp/cweb/cwebman.tex new file mode 100644 index 0000000000..2e4ec65ea5 --- /dev/null +++ b/web/c_cpp/cweb/cwebman.tex @@ -0,0 +1,1763 @@ +% This file generates the user manual; TeX it, don't read it! +% update 14 Nov 2016 by DEK: corrected obsolete remarks re debugging info + +\def\tangref{3} % where the main explanation of CTANGLing is given +\input cwebmac +\acrofalse\pdffalse\pdftexfalse +\def\page{\box255 } \normalbottom +\parskip 0pt plus 1pt +\def\RA{\char'31 } % right arrow +\def\hang{\hangindent 4em\ignorespaces} +\font\eightrm=cmr8 +\font\ninerm=cmr9 +\font\ninett=cmtt9 +\font\eighttt=cmtt8 +\font\twelvett=cmtt12 +\font\quoterm=cmssq8 +\font\quoteit=cmssqi8 +\font\authorfont=cmr12 +\font\sectionfont=cmbx12 + +\def\pb{\.{|...|}} +\def\v{\.{\char'174}} % vertical (|) in typewriter font +\def\lpile{\def\cr{\hfill\endline}\matrix} % I only use \lpile by itself +\abovedisplayskip=.5\abovedisplayskip +\belowdisplayskip=.5\belowdisplayskip +\abovedisplayshortskip=.5\abovedisplayshortskip +\belowdisplayshortskip=.5\belowdisplayshortskip +\advance\baselineskip by -.5pt +\advance\pageheight by \baselineskip % the manual just got a bit longer +\advance\fullpageheight by \baselineskip +\setpage + +\outer\def\section #1.{\penalty-500\bigskip + \centerline{\sectionfont\def\.##1{{\twelvett##1}} #1}\nobreak\vskip 6pt + \everypar{\hskip-\parindent\everypar{}}} + +\def\lheader{\mainfont\the\pageno\hfill\sc\runninghead\hfill} +\def\rheader{\hfill\sc\runninghead\hfill\mainfont\the\pageno} +\def\runninghead{{\tentt CWEB} USER MANUAL (VERSION 3.64)} + +% This verbatim mode assumes that ! marks are !! in the text being copied. +\def\verbatim{\begingroup + \def\do##1{\catcode`##1=12 } \dospecials + \parskip 0pt \parindent 0pt \let\!=! + \catcode`\ =13 \catcode`\^^M=13 + \tt \catcode`\!=0 \verbatimdefs \verbatimgobble} +{\catcode`\^^M=13{\catcode`\ =13\gdef\verbatimdefs{\def^^M{\ \par}\let =\ }} % + \gdef\verbatimgobble#1^^M{}} + +\null\vfill +\centerline{\titlefont The {\ttitlefont CWEB} System of + Structured Documentation} +\vskip 18pt\centerline{(Version 3.64 --- February 2002)} +\vskip 24pt +\centerline{\authorfont Donald E. Knuth and Silvio Levy} +\vfill + +\noindent +\TeX\ is a trademark of the American Mathematical Society. + +\noindent +Acrobat Reader is a trademark of Adobe Systems Incorporated. + +\bigskip\noindent +The printed form of this manual is copyright \copyright\ 1994 + by Addison-Wesley Publishing Company, Inc. All rights reserved. +\smallskip\noindent +The electronic form is copyright \copyright\ 1987, 1990, 1993, 2000 + by Silvio Levy and Donald E. Knuth. + +\bigskip\noindent +Permission is granted to make and distribute verbatim copies of the +electronic form of this document provided that the electronic copyright +notice and this permission notice are preserved on all copies. + +\smallskip\noindent +Permission is granted to copy and distribute modified versions of the +electronic form 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. + +\smallskip\noindent +Individuals may make copies of the documentation from the electronic files +for their own personal use. + +\smallskip\noindent +Internet page \.{http://www-cs-faculty.stanford.edu/\char`\~knuth/cweb.html} +contains current info about \.{CWEB} and related topics. + +\pageno=0 \titletrue\eject + +\titletrue +\centerline{\titlefont The {\ttitlefont CWEB} System of + Structured Documentation} + +\vskip 15pt plus 3pt minus 3pt +\centerline{\authorfont Donald E. Knuth and Silvio Levy} + +\vskip 24pt plus 3pt minus 3pt +\noindent +This document describes a version of Don Knuth's \.{WEB} system, +adapted to \CEE/ by Silvio Levy. Since its creation in 1987, \.{CWEB} +has been revised and enhanced in various ways, by both Knuth and Levy. +We now believe that its evolution is near an end; however, bug +reports, suggestions and comments are still welcome, and +should be sent to Levy (\.{levy@math.berkeley.edu}). + +Readers who are familiar with Knuth's memo ``The \.{WEB} System of Structured +Documentation'' will be able +to skim this material rapidly, because \.{CWEB} and \.{WEB} share +the same philosophy and (essentially) the same syntax. In some respects +\.{CWEB} is a simplification +of \.{WEB}: for example, \.{CWEB} does not need \.{WEB}'s features +for macro definition and string handling, because \CEE/ and its +preprocessor already take care of macros and strings. Similarly, the \.{WEB} +conventions of denoting octal and hexadecimal constants by \.{@'77} +and \.{@"3f} are replaced by \CEE/'s conventions \.{077} and +\.{0x3f}. All other features of \.{WEB} have been +retained, and new features have been added. + +We thank all who contributed suggestions and criticism to +the development of \.{CWEB}. We are especially grateful to Steve +Avery, Nelson Beebe, Hans-Hermann Bode, Klaus Guntermann, Norman Ramsey, +Joachim Schnitter, and Saroj Mahapatra, +who contributed code, and to Cameron Smith, who +made many suggestions improving the manual. Ramsey has made +literate programming accessible to users of yet other languages by means of +his \.{SPIDER} system [see {\sl Communications of the ACM\/ \bf32} (1989), +1051--1055]. The book {\sl Literate Programming\/} by Knuth (1992) contains +a comprehensive bibliography of related early work. +Bode, Schnitter, and Mahapatra adapted \.{CWEB} so that it works +for \CPLUSPLUS/ as well; therefore in the text below you can read \CPLUSPLUS/ +for \CEE/ if you so desire. + +\section Introduction. +The philosophy behind \.{CWEB} is +that programmers who want to provide the best +possible documentation for their programs need two things +simultaneously: a language like \TEX/ for formatting, and a language like +\CEE/ for programming. Neither type of language can provide the +best documentation by itself. But when both are appropriately combined, we +obtain a system that is much more useful than either language separately. + +The structure of a software program may be thought of as a ``web'' that is +made up of many interconnected pieces. To document such a program, we want +to explain each individual part of the web and how it relates to its +neighbors. The typographic tools provided by \TEX/ give us an opportunity +to explain the local structure of each part by making that structure +visible, and the programming tools provided by \CEE/ make it possible +for us to specify the algorithms formally and unambiguously. By combining +the two, we can develop a style of programming that maximizes our ability +to perceive the structure of a complex piece of software, and at the same +time the documented programs can be mechanically translated into a working +software system that matches the documentation. + +The \.{CWEB} system consists of two programs named \.{CWEAVE} and \.{CTANGLE}. +When writing a \.{CWEB} program the user keeps the +\CEE/ code and the documentation in the same file, called the \.{CWEB} +file and generally named \.{something.w}. The command +`\.{cweave} \.{something}' creates an output file \.{something.tex}, which +can then be fed to \TEX/, yielding a ``pretty printed'' version of +\.{something.w} that correctly handles +typographic details like page layout and the use of indentation, +italics, boldface, and mathematical symbols. The typeset output also +includes extensive cross-index +information that is gathered automatically. Similarly, if you run the +command `\.{ctangle} \.{something}' you will get a \CEE/ file \.{something.c}, +which can then be compiled to yield executable code. + +Besides providing a documentation tool, \.{CWEB} enhances the \CEE/ +language by providing the +ability to permute pieces of the program text, so that a large system can +be understood entirely in terms of small sections and their local +interrelationships. The \.{CTANGLE} program is so named because it takes a +given web and moves the sections from their web structure into the order +required by \CEE/; the advantage of programming in \.{CWEB} is that the +algorithms can be expressed in ``untangled'' form, with each section +explained separately. The \.{CWEAVE} program is so named because it takes +a given web and intertwines the \TEX/ and \CEE/ portions contained in +each section, then it knits the whole fabric into a structured document. +(Get it? Wow.) Perhaps there is some deep connection here with the fact +that the German word for ``weave'' is ``{\it webe\/}'', and the +corresponding Latin imperative is ``{\it texe\/}''! + +A user of \.{CWEB} should be fairly familiar with the \CEE/ +programming language. A minimal amount of acquaintance with \TEX/ is also +desirable, but in fact it can be acquired as one uses \.{CWEB}, since +straight text can be typeset in \TEX/ with virtually no knowledge of +that language. To someone familiar with both \CEE/ and \TEX/ the amount of +effort necessary to learn the commands of \.{CWEB} is small. + +\section Overview. +Two kinds of material go into \.{CWEB} files: \TEX/ text and \CEE/ text. +A programmer writing in \.{CWEB} should be thinking both of the +documentation and of the \CEE/ program being created; +i.e., the programmer should be instinctively aware of the different +actions that \.{CWEAVE} and \.{CTANGLE} will perform on the \.{CWEB} file. +\TEX/ text is essentially copied without change by \.{CWEAVE}, and it is +entirely deleted by \.{CTANGLE}; the \TEX/ text is ``pure +documentation.'' \CEE/ text, on the other hand, is formatted by +\.{CWEAVE} and it is shuffled around by \.{CTANGLE}, according to rules that +will become clear later. For now the important point to keep in mind is +that there are two kinds of text. Writing \.{CWEB} programs is something +like writing \TEX/ documents, but with an additional ``\CEE/ mode'' +that is added to \TEX/'s horizontal mode, vertical mode, and math mode. + +A \.{CWEB} file is built up from units called {\sl sections\/} that are more +or less self-contained. Each section has three parts: + +\yskip\item{$\bullet$} A \TEX/ part, containing explanatory material about what +is going on in the section. + +\item{$\bullet$} A middle part, containing macro definitions that serve as +abbreviations for \CEE/ constructions that would be less comprehensible +if written out in full each time. They are turned by \.{CTANGLE} into +preprocessor macro definitions. + +\item{$\bullet$} A \CEE/ part, containing a piece of the program that +\.{CTANGLE} will produce. This \CEE/ code should ideally be about a +dozen lines long, so that it is easily comprehensible as a unit and so +that its structure is readily perceived. + +\yskip\noindent The three parts of each section must appear in this order; +i.e., the \TEX/ commentary must come first, then the middle part, and +finally the \CEE/ code. Any of the parts may be empty. + +A section begins with either of the symbols `\.{@\ }' or `\.{@*}', where +`\.{\ }' denotes a blank space. A section ends +at the beginning of the next section (i.e., at the next +`\.{@\ }' or `\.{@*}'), or at the end of the file, whichever comes first. +The \.{CWEB} file may also contain material that is not part of any section +at all, namely the text (if any) that occurs before the first section. +Such text is said to be ``in limbo''; it is ignored by \.{CTANGLE} +and copied essentially verbatim by \.{CWEAVE}, so its function is to +provide any additional formatting instructions that may be desired in the +\TEX/ output. Indeed, it is customary to begin a \.{CWEB} file with +\TEX/ code in limbo that loads special fonts, defines special macros, +changes the page sizes, and/or produces a title page. + +Sections are numbered consecutively, starting with 1. These numbers appear +at the beginning of each section of the \TEX/ documentation output by +\.{CWEAVE}, and they appear +as bracketed comments at the beginning and end of the code generated by that +section in the \CEE/ program output by \.{CTANGLE}. + +\section Section Names. +Fortunately, you never mention these numbers yourself when you are writing +in \.{CWEB}. You just say `\.{@\ }' or `\.{@*}' at the beginning of each +new section, and the numbers are supplied automatically by \.{CWEAVE} and +\.{CTANGLE}. As far as you are concerned, a section has a +{\sl name\/} instead of a number; its name is specified by writing +`\.{@<}' followed by \TEX/ text followed by `\.{@>}'. When \.{CWEAVE} +outputs a section name, it replaces the `\.{@<}' and `\.{@>}' by +angle brackets and inserts the section number in small type. Thus, when you +read the output of \.{CWEAVE} it is easy to locate any section that is +referred to in another section. + +For expository purposes, a section name should be a good description of the +contents of that section; i.e., it should stand for the abstraction +represented by the section. Then the section can be ``plugged into'' one or +more other sections in such a way +that unimportant details of its inner workings +are suppressed. A section name therefore ought to be long enough to convey +the necessary meaning. + +Unfortunately, it is laborious to type +such long names over and over again, and it is also difficult to specify a +long name twice in exactly the same way so that \.{CWEAVE} and \.{CTANGLE} +will be able to match the names to the sections. To ameliorate this situation, +\.{CWEAVE} and \.{CTANGLE} let you abbreviate a section name, so long as +the full name appears somewhere in the \.{CWEB} file; you can type simply +`\.{@<$\alpha$...@>}', where $\alpha$ is any string that is a prefix of +exactly one section name appearing in the file. For example, `\.{@}' can be abbreviated to `\.{@}' if no other section +name begins with the five letters `\.{Clear}'. Elsewhere +you might use the abbreviation `\.{@}', and so on. + +Section names must otherwise match character for character, except +that consecutive characters of white space (spaces, tab marks, newlines, and/or +form feeds) are treated as equivalent to a single space, and such spaces are +deleted at the beginning and end of the name. Thus, `\.{@< Clear { }the +arrays @>}' will also match the name in the previous example. +Spaces following the ellipsis in abbreviations are ignored as well, but +not those before, so that `\.{@}' would not match +`\.{@}'. + +\section What \.{CTANGLE} Does. +We have said that a section begins with `\.{@\ }' or `\.{@*}', but we +didn't say how it gets divided up into a \TEX/ part, a middle part, +and a \CEE/ part. The middle part begins with the first appearance of +`\.{@d}' or `\.{@f}' in the section, and the \CEE/ part begins with +the first appearance of `\.{@c}' or `\.{@
=}'. In the +latter case you are saying, in effect, that the section name stands +for the \CEE/ text that follows. Alternatively, if the \CEE/ part +begins with `\.{@c}' instead of a section name, the current section is +said to be {\sl unnamed}. + +The construct `\.{@
}' can appear +any number of times in the \CEE/ part of a section: +Subsequent appearances indicate that a named section is being +``used'' rather than ``defined.'' In other words, the +\CEE/ code for the named section, presumably defined elsewhere, should be +spliced in at this point in the \CEE/ program. Indeed, +the main idea of \.{CTANGLE} is to make a \CEE/ program out of +individual sections, named and unnamed. The exact way in which this is done +is this: First all the macro definitions +indicated by `\.{@d}' are turned into \CEE/ preprocessor macro definitions +and copied at the beginning. +Then the \CEE/ parts of unnamed sections are copied down, +in order; this constitutes the first-order +approximation to the text of the program. (There should be at least +one unnamed section, otherwise there will be no program.) Then all section +names that appear in the first-order approximation are replaced by the \CEE/ +parts of the corresponding sections, and this substitution process +continues until no section names remain. All comments are removed, because +the \CEE/ program is intended only for the eyes of the \CEE/ compiler. + +If the same name has been given to more than one section, the \CEE/ text +for that name is obtained by putting together all of the \CEE/ parts in +the corresponding sections. This feature is useful, for example, in a +section named `Global variables', since one can then +declare global variables in whatever sections those variables are +introduced. When several sections have the same name, \.{CWEAVE} assigns the +first section number as the number corresponding to that name, and it +inserts a note at the bottom of that section telling the reader to `See +also sections so-and-so'; this footnote gives the numbers of all the other +sections having the same name as the present one. The \CEE/ text +corresponding to a section is usually formatted by \.{CWEAVE} so that the +output has an equivalence sign in place of the equals sign in the \.{CWEB} +file; i.e., the output says `$\langle\,$section +name$\,\rangle\equiv\null$\CEE/ text'. However, in the case of the second +and subsequent appearances of a section with the same name, this `$\equiv$' +sign is replaced by `$\mathrel+\equiv$', as an indication that the +following \CEE/ text is being appended to the \CEE/ text of another section. + +As \.{CTANGLE} enters and leaves sections, it inserts preprocessor +\.{\#line} commands into the \CEE/ output file. This means that +when the compiler gives you error messages, or when you debug your program, +the messages refer to line numbers in the \.{CWEB} file, and not in the +\CEE/ file. In most cases you can therefore +forget about the \CEE/ file altogether. + +\section What \.{CWEAVE} Does. +The general idea of \.{CWEAVE} is to make a \.{.tex} file from the \.{CWEB} +file in the following way: The first line of the \.{.tex} file +tells \TEX/ to input a file with macros that +define \.{CWEB}'s documentation conventions. The next lines of the file +will be copied from whatever \TEX/ text is in limbo before the first +section. Then comes the output for each section in turn, possibly +interspersed with end-of-page marks. Finally, \.{CWEAVE} will generate a +cross-reference index that lists each section number in which each \CEE/ +identifier appears, and it will also generate an alphabetized list +of the section names, as well as a table of contents that +shows the page and section numbers for each ``starred'' section. + +What is a ``starred'' section, you ask? A section that begins with `\.{@*}' +instead of `\.{@\ }' is slightly special in that it denotes a new major +group of sections. The `\.{@*}' should be followed by the title of this +group, followed by a period. Such sections will always start on a new page +in the \TEX/ output, and the group title will appear as a running headline +on all subsequent pages until the next starred section. The title will also +appear in the table of contents, and in boldface type at the beginning of +its section. Caution: Do not use \TEX/ control sequences in such titles, +unless you know that the \.{cwebmac} macros will do the right thing with +them. The reason is that these titles are converted to uppercase when +they appear as running heads, and they are converted to boldface when they +appear at the beginning of their sections, and they are also written out to +a table-of-contents file used for temporary storage while \TEX/ is +working; whatever control sequences you use must be meaningful in all +three of these modes. + +The \TEX/ output produced by \.{CWEAVE} for each section consists of +the following: First comes the section number (e.g., `\.{\\M123.}' +at the beginning of section 123, except that `\.{\\N}' appears in place of +`\.{\\M}' at the beginning of a starred section). Then comes the +\TEX/ part of the section, copied almost verbatim except as noted +below. Then comes the middle part and the \CEE/ part, formatted +so that there will be a little extra space between them if both are +nonempty. The middle and \CEE/ parts are obtained by inserting +a bunch of funny-looking \TEX/ macros into the \CEE/ program; these +macros handle typographic details about fonts and proper math spacing, +as well as line breaks and indentation. + +\section C Code in \TEX/ Text and Vice Versa. +When you are typing \TEX/ text, you will probably want to make frequent +reference to variables and other quantities in your \CEE/ code, and you +will want those variables to have the same typographic treatment +when they appear in your text as when they appear in your +program. Therefore the \.{CWEB} language allows you to get the effect of +\CEE/ editing within \TEX/ text, if you place `\.|' marks before and +after the \CEE/ material. For example, suppose you want to say something +like this: +$$\hbox{ If \\{pa} is declared as `\&{int} ${}{*}\\{pa}$', +the assignment $\\{pa}\K{\AND}\|a[\T{0}]$ makes \\{pa} +point to the zeroth element of \|a.}$$ +The \TEX/ text would look like this in your \.{CWEB} file: +$$\lpile{\.{If |pa| is declared as `|int *pa|', the}\cr +\.{assignment |pa=\&a[0]| makes |pa| point +to the zeroth element of |a|.}\cr}$$ +And \.{CWEAVE} translates this into something you are glad you didn't have +to type: +$$\lpile{\.{If \\\\\{pa\} is declared as + `\\\&\{int\} \$\{\}\{*\}\\\\\{pa\}\$',}\cr +\.{the assignment \$\\\\\{pa\}\\K\{\\AND\}\\|a[\\T\{0\}]\$}\cr +\.{makes \\\\\{pa\} point to the zeroth element of \\|a.}\cr}$$ +Incidentally, the cross-reference index that \.{CWEAVE} would make, in +the presence of a comment like this, would include +the current section number as one of the index entries for \\{pa}, +even though \\{pa} might not appear in the \CEE/ part of +this section. Thus, the index covers references to identifiers in +the explanatory comments as well as in the program itself; you will +soon learn to appreciate this feature. However, the identifiers +\&{int} and \|a\ would not be indexed, +because \.{CWEAVE} does not make index entries for reserved words or +single-letter identifiers. Such identifiers are felt to be so ubiquitous +that it would be pointless to mention every place where they occur. + +Although a section begins with \TEX/ text and ends with \CEE/ text, we +have noted that the dividing line isn't sharp, since \CEE/ text can be +included in \TEX/ text if it is enclosed in `\pb'. Conversely, \TEX/ text +appears frequently within \CEE/ text, because everything in +comments (i.e., between \.{/*} and \.{*/}, or following \.{//}) +is treated as \TEX/ text. +Likewise, the text of a section name consists of \TEX/ text, but +the construct \.{@
} as a whole is expected to be found +in \CEE/ text; thus, one typically goes back and forth +between the \CEE/ and \TEX/ environments in a natural way, as in these +examples: +$$ +\displaylines{ +\hbox{\.{if} \.{(x==0)} \.{@}} \cr +\hbox{\.{...} \.{using} \.{the} \.{algorithm} +\.{in} \.{|@|.}} } +$$ +The first of these excerpts +would be found in the \CEE/ part of a section, into which the code +from the section +named ``Empty the \\{buffer} array'' is being spliced. The second excerpt +would be found in the \TEX/ part of the section, and the named section +is being ``cited'', rather than defined or used. +(Note the `\pb' surrounding the section name in this case.) + +\section Macros. +The control code \.{@d} followed by +$$\\{identifier}\.{ }\hbox{\CEE/ text}\qquad\hbox{or by}\qquad +\\{identifier}\.(\\{par}_1,\ldots,\\{par}_n\.{) }\hbox{\CEE/ text}$$ +(where there is no blank between the +\\{identifier} and the parentheses in the second case) is +transformed by \.{CTANGLE} into a preprocessor command, starting with +\.{\#define}, which is printed at the top of the \CEE/ output file +as explained earlier. + +A `\.{@d}' macro definition can go on for several lines, and the +newlines don't have to be protected by backslashes, since \.{CTANGLE} +itself inserts the backslashes. If +for any reason you need a \.{\#define} command at a specific spot in +your \CEE/ file, you can treat it as \CEE/ code, instead of as a +\.{CWEB} macro; but then you do have to protect newlines yourself. + +\section Strings and constants. +If you want a string to appear in the \CEE/ file, delimited by pairs of +\.' or \." marks as usual, you can type it exactly so in the \.{CWEB} file, +except that the character `\.@' should be typed `\.{@@}' (it becomes a +control code, the only one that can appear in strings; see below). +Strings should end on the same line as they begin, unless there's a +backslash at the end of lines within them. + +\TEX/ and \CEE/ have different ways to refer to octal and hex constants, +because \TEX/ is oriented to technical writing while \CEE/ is oriented to +computer processing. In \TEX/ you +make a constant octal or hexadecimal by prepending \.' or \.", +respectively, to it; in \CEE/ the constant should be preceded by \.0 +or \.{0x}. In \.{CWEB} it seems reasonable to let each convention hold +in its respective realm; so in \CEE/ text you get $40_8$ by typing +`\.{040}', which \.{CTANGLE} faithfully copies into the \CEE/ file (for +the compiler's benefit) and which \.{CWEAVE} prints as $\T{\~40}$. +Similarly, \.{CWEAVE} prints the hexadecimal \CEE/ constant `\.{0x20}' +as \T{\^20}. The use of italic font for octal digits and typewriter font +for hexadecimal digits makes the meaning of such constants clearer in +a document. For consistency, then, you +should type `\.{|040|}' or `\.{|0x20|}' +in the \TEX/ part of the section. + +\section Control codes. +A \.{CWEB} {\sl control code\/} +is a two-character combination of which the first is `\.@'. +We've already seen the meaning of several control codes; it's time to +list them more methodically. + +In the following list, +the letters in brackets after a control code indicate in what contexts that +code is allowed. $L$ indicates that the code is allowed in limbo; $T$ +(for \TEX/), $M$ (for middle), and $C$ (for \CEE/) mean that the code is +allowed in each of the three parts of a section, at top level---that +is, outside such constructs as `\pb' and section names. An arrow $\to$ +means that the control code terminates the present part of the \.{CWEB} +file, and inaugurates the part indicated by the letter following the +arrow. Thus $[LTMC\to T]$ next to \.{@\ } indicates that this control +code can occur in limbo, or in any of the three parts of a section, and +that it starts the (possibly empty) \TEX/ part of the following section. + +Two other abbreviations can occur in these brackets: The letter $r$ stands for +{\it restricted context}, that is, material inside \CEE/ comments, section +names, \CEE/ strings and control texts (defined below); the letter +$c$ stands for {\it inner \CEE/ context}, that is, \CEE/ material +inside `\pb' (including `\pb's inside comments, but not those +occurring in other restricted contexts). An asterisk $*$ following +the brackets means +that the context from this control code to the matching \.{@>} is +restricted. + +Control codes involving letters are case-insensitive; thus \.{@d} and +\.{@D} are equivalent. Only the lowercase versions are mentioned +specifically below. + +\gdef\@#1[#2] {\penalty-50\yskip\hangindent 2em\noindent\.{@#1\unskip + \spacefactor1000{ }}$[#2]$\quad} +\def\more{\hangindent 2em \hangafter0} +\def\subsec{\penalty-300\medskip\noindent} + +\@@ [LTMCrc] A double \.@ denotes the single character `\.@'. This is +the only control code that is legal everywhere. +Note that you must use this convention if you are giving an internet +email address in a \.{CWEB} file (e.g., \.{levy@@math.berkeley.edu}). + +\subsec +Here are the codes that introduce the \TEX/ part of a section. + +\@\ [LTMC\to T] This denotes the beginning of a new (unstarred) +section. A tab mark or form feed or +end-of-line character is equivalent to a space when it follows an \.@ +sign (and in most other cases). + +\@* [LTMC\to T] This denotes the beginning of a new starred +section, i.e., a section that begins a new major group. The title of the new +group should appear after the \.{@*}, followed by a period. As explained +above, \TEX/ control sequences should be avoided in such titles unless +they are quite simple. When \.{CWEAVE} and \.{CTANGLE} read a \.{@*}, they +print an asterisk on the terminal +followed by the current section number, so that the user +can see some indication of progress. The very first section should be starred. + +\more You can specify the ``depth'' of a starred section by typing \.* or a +decimal number after the \.{@*}; this indicates the relative ranking +of the current group of sections in the program hierarchy. Top-level +portions of the program, introduced by \.{@**}, get their names typeset +in boldface type in the table of contents; they are said to have +depth~$-1$. Otherwise the depth is a nonnegative number, which governs +the amount of indentation on the contents page. Such indentation helps +clarify the structure of a long program. The depth is assumed to be 0 +if it is not specified explicitly; when your program is short, you +might as well leave all depths zero. A starred section always begins +a new page in the output, unless the depth is greater than~1. + +\subsec +The middle part of each section consists of any number of +macro definitions (beginning with \.{@d}) and format definitions (beginning +with \.{@f} or \.{@s}), intermixed in any order. + +\@d [TM\to M] Macro definitions begin with \.{@d}, followed by +an identifier and optional parameters and \CEE/ text as explained earlier. + +\@f [TM\to M] Format definitions begin with \.{@f}; they cause +\.{CWEAVE} to treat identifiers in a special way when they appear in +\CEE/ text. The general form of a format definition is `\.{@f} \|l +\|r', followed by an optional comment enclosed between +\.{/*} and \.{*/}, where \|l and \|r +are identifiers; \.{CWEAVE} will subsequently treat identifier \|l as it +currently treats \|r. This feature allows a \.{CWEB} programmer to invent +new reserved words and/or to unreserve some of \CEE/'s reserved +identifiers. For example, the common words `error' and `line' +have been given a special meaning in the \CEE/ preprocessor, +so \.{CWEAVE} is set up to format them specially; if you want a variable +named \\{error} or \\{line}, you should say +$$\.{@f error normal}\qquad\qquad\.{@f line normal}$$ +somewhere in your program. + +\more If \|r is the special identifier `\\{TeX}', identifier \|l +will be formatted as a \TEX/ control sequence; for example, +`\.{@f foo TeX}' in the \.{CWEB} file will cause identifier \\{foo} to +be output as \.{\\foo} by \.{CWEAVE}. The programmer should define +\.{\\foo} to have whatever custom format is desired, assuming \TEX/ +math mode. (Each underline +character is converted to \.{x} when making the \TEX/ control sequence, +and each dollar sign is converted to~\.X; +thus \\{foo\_bar} becomes \.{\\fooxbar}. Other characters, including digits, +are left untranslated, so \TEX/ will consider them as macro parameters, +not as part of the control sequence itself. For example, +$$\.{\\def\\x\#1\{x\_\{\#1\}\} @f x1 TeX @f x2 TeX}$$ +will format \.{x1} and \.{x2} not as \\{x1} and \\{x2} but as $x_1$ and $x_2$.) + +\more If \|r is the special identifier `\\{make\_pair}', identifier \|l will +be treated as a \CPLUSPLUS/ function template. For example, after +\.{@f}~\.{convert}~\.{make\_pair} one can say `\.{convert(2.5)}' without +having \.< and \.> misunderstood as less-than and greater-than signs. + +\more \.{CWEAVE} knows that identifiers being +defined with a \&{typedef} should become reserved words; thus you +don't need format definitions very often. + +\@s [TM\to M;\;L] Same as \.{@f}, but \.{CWEAVE} does not show the format +definition in the output, and the optional \CEE/ comment is not +allowed. This is used mostly in \.{@i} files. + +\subsec +Next come the codes that govern the \CEE/ part of a section. + +\@{c @p} [TM\to C] The \CEE/ part of an unnamed section begins with \.{@c} +(or with \.{@p} for ``program''; both control codes do the same thing). +This causes \.{CTANGLE} to append the following \CEE/ code +to the first-order program text, as explained on page~\tangref. +Note that \.{CWEAVE} does not print a `\.{@c}' in the \TEX/ +output, so if you are creating a \.{CWEB} file based on a \TEX/-printed +\.{CWEB} documentation you have to remember to insert \.{@c} in the +appropriate places of the unnamed sections. + +\@< [TM\to C;\; C;\; c] $*$ This control code introduces a +section name (or unambiguous prefix, as discussed above), which +consists of \TEX/ text and extends to the matching \.{@>}. +The whole construct \.{@<...@>} is conceptually a \CEE/ element. +The behavior is different depending on the context: + +\more A \.{@<} appearing in contexts $T$ and $M$ attaches the +following section name to the current section, and inaugurates the +\CEE/ part of the section. The closing \.{@>} should be followed by +\.{=} or \.{+=}. + +\more +In context $C$, \.{@<} indicates that the named +section is being used---its \CEE/ definition is spliced in by +\.{CTANGLE}, as explained on page~\tangref. +As an error-detection measure, +\.{CTANGLE} and \.{CWEAVE} complain if such a section name is followed +by \.=, because most likely this is meant as the definition of a new +section, and so should be preceded by \.{@\ }. If you really want to +say $\langle\,$foo$\,\rangle=\\{bar}$, where $\langle\,$foo$\,\rangle$ +is being used and not defined, put a newline before the \.=. + +\more +Finally, in inner \CEE/ context (that is, within `\pb' in the \TEX/ part +of a section or in a comment), \.{@<...@>} +means that the named section is being +cited. Such an occurrence is ignored by \.{CTANGLE}. Note that +even here we think of the section name as being a \CEE/ element, hence the \pb. + +\@( [TM\to C;\;C;\;c] $*$ A section name can begin with \.{@(}. +Everything works just as for \.{@<}, except that the \CEE/ code +of the section named \.{@(foo@>} is written by \.{CTANGLE} +to file \.{foo}. In this way you can get multiple-file output from +a single \.{CWEB} file. (The \.{@d} definitions are not output +to such files, only to the master \.{.c} file.) One use of this feature +is to produce header files for other program modules that will be loaded +with the present one. Another use is to produce a test routine that +goes with your program. By keeping the sources for a program and its +header and test routine together, you are more likely to keep +all three consistent with each other. Notice that the output of a named +section can be incorporated in several different output files, because +you can mention \.{@} in both \.{@(bar1@>} and \.{@(bar2@>}. + +\@h [Cc] Causes \.{CTANGLE} +to insert at the current spot the \.{\#define} statements +from the middle parts of all sections, +and {\it not\/} to write them at the beginning of the \CEE/ file. +Useful when you want the macro definitions to come after the include files, +say. (Ignored by \.{CTANGLE} inside `\pb'.) + +\subsec +The next several control codes introduce ``control +texts,'' which end with the next `\.{@>}'. The closing `\.{@>}' must be on +the same line of the \.{CWEB} file as the line where the control text began. +The context from each of these control codes to the matching \.{@>} is +restricted. + +\@\^ [TMCc] $*$ The control text that follows, up to the next +`\.{@>}', will be entered into the index together with the identifiers of +the \CEE/ program; this text will appear in roman type. For example, to +put the phrase ``system dependencies'' into the index that is output by +\.{CWEAVE}, type +`\.{@\^system dependencies@>}' in each section +that you want to index as system dependent. + +\@. [TMCc] $*$ The control text that follows will be entered into the index +in \.{typewriter} \.{type}. + +\@: [TMCc] $*$ The control text that follows will be entered into the index +in a format controlled by the \TEX/ macro `\.{\\9}', which you +should define as desired. + +\@t [MCc] $*$ The control text that follows will +be put into a \TEX/ \.{\\hbox} and formatted along with the neighboring +\CEE/ program. This text is ignored by \.{CTANGLE}, but it can be used +for various purposes within \.{CWEAVE}. For example, you can make comments +that mix \CEE/ and classical mathematics, as in `$\\{size}<2^{15}$', by +typing `\.{|size < 2@t\$\^\{15\}\$@>|}'. + +\@= [MCc] $*$ The control text that follows will +be passed verbatim to the \CEE/ program. + +\@q [LTMCc] $*$ The control text that follows will +be totally ignored---it's a comment for readers of the \.{CWEB} file only. +A file intended to be included in +limbo, with \.{@i}, can identify itself with \.{@q} comments. +Another use is to balance unbalanced parentheses in \CEE/ strings, +so that your text editor's parenthesis matcher doesn't go into a tailspin. + +\@! [TMCc] $*$ +The section number in an index entry will be underlined if `\.{@!}' +immediately precedes the identifier or control text being indexed. This +convention is used to distinguish the sections where an identifier is +defined, or where it is explained in some special way, from the sections +where it is used. A~reserved word or an identifier of length one will not +be indexed except for underlined entries. An `\.{@!}' is implicitly inserted +by \.{CWEAVE} when an identifier is being defined or declared in \CEE/ +code; for example, the definition +$$\hbox{\&{int} \\{array}[\\{max\_dim}], \\{count}${}=\\{old\_count};$}$$ +makes the names \\{array} and \\{count} get an underlined entry in the +index. Statement labels, function definitions like +\\{main}(\&{int}~\\{argc},\,\&{char}~$*$\\{argv}[\,]), +and \&{typedef} definitions also +imply underlining. An old-style +function definition (without prototyping) doesn't define its arguments; +the arguments will, however, be considered to be defined +(i.e., their index entries will be underlined) if their types are +declared before the body of the function in the usual way +(e.g., `\&{int}~\\{argc}; \&{char}~${*}\\{argv}[\,]$; $\{\,\ldots\,\}$'). +Thus \.{@!} is not needed very often, except in unusual constructions +or in cases like +$$\.{enum boolean \{@!false, @!true\};}$$ +here \.{@!} gives the best results because individual constants enumerated +by \.{enum} are not automatically underlined in the index at their +point of definition. + +\subsec +We now turn to control codes that affect only the operation of +\.{CTANGLE}. + +\@' [MCc] This control code is dangerous because it has quite different +meanings in \.{CWEB} and the original \.{WEB}. In \.{CWEB} it produces the +decimal constant corresponding to the ASCII code for a string of length~1 +(e.g., \.{@'a'} is \.{CTANGLE}d into \.{97} and \.{@'\\t'} into +\.9). You might want to use this if you need to work in ASCII on a +non-ASCII machine; but in most cases the \CEE/ conventions of +\.{} are adequate for character-set-independent programming. + +\@\& [MCc] The \.{@\&} operation causes whatever is on its left to be +adjacent to whatever is on its right, in the \CEE/ output. No spaces or +line breaks will separate these two items. + +\@l [L] \.{CWEB} programmers have the option of using any 8-bit character +code from the often-forbidden range 128--255 within \TEX/ text; such +characters are also permitted in strings and even in identifiers of the +\CEE/ program. +Under various extensions of the basic +ASCII standard, the higher 8-bit codes correspond +to accented letters, letters from non-Latin alphabets, +and so on. When such characters occur in identifiers, \.{CTANGLE} must replace +them by standard ASCII alphanumeric characters or +\.{\_}, in order to generate legal \CEE/ code. It does this by means +of a transliteration table, which by default associates the string +\.{Xab} to the character with ASCII code \T{\^}$ab$ (where $a$ and $b$ are +hexadecimal digits, and $a\ge8$). By placing the +construction \.{@l\ ab\ newstring} in limbo, you are telling +\.{CTANGLE} to replace this character by \.{newstring} instead. +For example, the ISO Latin-1 code for the letter `\"u' is \T{\^FC} +(or \.{'\char`\\374'}), +and \.{CTANGLE} will normally change this code to the +three-character sequence \.{XFC} if it +appears in an identifier. If you say \.{@l} \.{fc} \.{ue}, the code will +be transliterated into \.{ue} instead. + +\more +\.{CWEAVE} passes 8-bit characters straight through to \TEX/ without +transliteration; therefore \TEX/ must be prepared to receive them. +If you are formatting all your nonstandard identifiers as ``custom'' +control sequences, you should +make \TEX/ treat all their characters as letters. Otherwise you should either +make your 8-bit codes ``active'' in \TEX/, or load fonts that +contain the special characters you need in the correct positions. +(The font selected by \TEX/ control sequence \.{\\it} is used for +identifiers.) +Look for special macro packages designed for \.{CWEB} users in your language; +or, if you are brave, write one yourself. + +\subsec +The next eight control codes (namely `\.{@,}', `\.{@/}', `\.{@|}', `\.{@\#}', +`\.{@+}', `\.{@;}', `\.{@[}', and `\.{@]}') have no effect on the \CEE/ +program output by \.{CTANGLE}; they merely help to improve the readability +of the \TEX/-formatted \CEE/ that is output by \.{CWEAVE}, in unusual +circumstances. \.{CWEAVE}'s built-in formatting method is fairly good +when dealing with syntactically correct \CEE/ text, but +it is incapable of handling all possible cases, because it must deal with +fragments of text involving macros and section names; these fragments do +not necessarily obey \CEE/'s syntax. Although \.{CWEB} allows you to +override the automatic formatting, your best strategy is not to worry +about such things until you have seen what \.{CWEAVE} produces automatically, +since you will probably need to make only a few corrections when you are +touching up your documentation. + +\@, [MCc] This control code inserts a thin space in \.{CWEAVE}'s output. +Sometimes you need this extra space if you are using +macros in an unusual way, e.g., if two identifiers are adjacent. + +\@/ [MC] This control code causes a line break to occur within a \CEE/ +program formatted by \.{CWEAVE}. Line breaks +are chosen automatically by \TEX/ according to a scheme that works 99\%\ +of the time, but sometimes you will prefer to force a line break so that +the program is segmented according to logical rather than visual +criteria. If a comment follows, say `\.{@/@,}' to break the line +before the comment. + +\@| [MC] This control code specifies an optional line break in the midst of +an expression. For example, if you have +a long expression on the right-hand side of an assignment +statement, you can use `\.{@|}' to specify breakpoints more logical than +the ones that \TEX/ might choose on visual grounds. + +\@\# [MC] This control code forces a line break, like \.{@/} does, +and it also causes a little extra white space to appear between the lines at +this break. You might use it, for example, +between groups of macro definitions that are logically separate but within +the same section. \.{CWEB} automatically inserts this extra space +between functions, between external declarations and functions, and +between declarations and statements within a function. + +\@+ [MC] This control code cancels a line break that might otherwise be +inserted by \.{CWEAVE}, e.g., before the word `\&{else}', if you want to +put a short if--else construction on a single line. +If you say `\.{\{@+}' at the beginning of a compound statement +that is the body of a function, the first declaration or +statement of the function will appear on the same line as the +left brace, and it will be indented by the same amount as the +second declaration or statement on the next line. + +\@; [MC] This control code is treated like a semicolon, for formatting +purposes, except that it is invisible. You can use it, for example, after +a section name or macro when the \CEE/ text represented by that section or macro +is a compound statement or ends +with a semicolon. Consider constructions like +$$\lpile{\.{if (condition) macro @;}\cr +\.{else break;}\cr}$$ +where \\{macro} is defined to be a compound statement (enclosed in braces). +This is a well-known infelicity of \CEE/ syntax. + +\@{[} [MC] See \.{@]}. + +\@] [MC] Place \.{@[...@]} brackets around program text that \.{CWEAVE} is +supposed to format as an expression, if it doesn't already do so. (This +occasionally applies to unusual macro arguments.) Also +insert `\.{@[@]}' between a simple type name and a left parenthesis +when declaring a pointer to a function, as in +$$\.{int @[@] (*f)();}$$ +otherwise \.{CWEAVE} will confuse the first part of that declaration with +the \CPLUSPLUS/ expression `\&{int}($*f$)'. Another example, for people +who want to use low-level \.{\#define} commands in the midst of \CEE/ code +and the definition begins with a cast: +$$\.{\#define foo @[(int)(bar)@]}$$ + +\subsec +The remaining control codes govern the input that \.{CWEB} sees. + +\@{x @y @z}[\\{change\_file}] +\.{CWEAVE} and \.{CTANGLE} are designed to work with two input files, +called \\{web\_file} and \\{change\_file}, where \\{change\_file} contains +data that overrides selected portions of \\{web\_file}. The resulting merged +text is actually what has been called the \.{CWEB} file elsewhere in this +report. + +\more Here's how it works: The change file consists of zero or more ``changes,'' +where a change has the form `\.{@x}$\langle$old lines$\rangle$\.{@y}$\langle$% +new lines$\rangle$\.{@z}'. The special control codes \.{@x}, \.{@y}, \.{@z}, +which are allowed only in change files, must appear at the beginning of a line; +the remainder of such a line is ignored. +The $\langle$old lines$\rangle$ represent material that exactly matches +consecutive lines of the \\{web\_file}; the $\langle$new lines$\rangle$ +represent zero or more lines that are supposed to replace the old. Whenever +the first ``old line'' of a change is found to match a line in the +\\{web\_file}, all the other lines in that change must match too. + +\more Between changes, before the first change, and after the last change, +the change file can have any number of lines that do not begin with +`\.{@x}', `\.{@y}', or~`\.{@z}'. Such lines are bypassed and not used for +matching purposes. + +\more This dual-input feature is useful when working with a master \.{CWEB} +file that has been received from elsewhere (e.g., \.{tangle.w} or +\.{weave.w} or \.{tex.web}), when changes are desirable to customize the +program for your local computer system. You will be able to debug your +system-dependent changes without clobbering the master web file; and once +your changes are working, you will be able to incorporate them readily +into new releases of the master web file that you might receive from time +to time. + +\@i [\\{web\_file}] +Furthermore the \\{web\_file} itself can be a combination of +several files. When either \.{CWEAVE} or \.{CTANGLE} is reading a file and +encounters the control code \.{@i} at the beginning of a line, it +interrupts normal reading and starts looking at the file named after the +\.{@i}, much as the \CEE/ preprocessor does when it encounters an \.{\#include} +line. After the included file has been entirely read, the program +goes back to the next line +of the original file. The file name following \.{@i} can be +surrounded by \." characters, but such delimiters are +optional. Include files can nest. + +\more +Change files can have lines starting with \.{@i}. In this way +you can replace one included file with another. Conceptually, the +replacement mechanism described above does its work first, and +its output is then checked for \.{@i} lines. If \.{@i} \.{foo} +occurs between \.{@y} and \.{@z} in a change file, individual lines +of file \.{foo} and files it includes are not changeable; but changes +can be made to lines from files that were included by unchanged input. + +\more On \UNIX/ systems (and others that support environment variables), +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. + +\section Additional features and caveats. + +1. In certain installations of \.{CWEB} that +{\def\\#1#2{`{\tentex\char'#1#2}'}% +have an extended character set, the characters +\\13, \\01, \\31, \\32, \\34, \\35, +\\36, \\37, \\04, \\20, and \\21} +can be typed as abbreviations for `\.{++}', `\.{--}', `\.{->}', +`\.{!=}', `\.{<=}', `\.{>=}', `\.{==}', `\.{\v\v}', `\.{\&\&}', +`\.{<<}', and `\.{>>}', +respectively. + +2. If you have an extended character set, you can use it with only minimal +restrictions, as discussed under the rules for \.{@l} above. But you should +stick to standard ASCII characters if you want to write programs that will +be useful to all the poor souls out there who don't have extended +character sets. + +3. The \TEX/ file output by \.{CWEAVE} is broken into lines having at most +80 characters each. When +\TEX/ text is being copied, the existing line breaks are copied as well. +If you aren't doing anything too tricky, \.{CWEAVE} will recognize when +a \TEX/ comment is being split across two or more lines, and it will +append `\.\%' to the beginning of such continued comments. + +4. \CEE/ text is translated by a ``bottom up'' procedure that +identifies each token as a ``part of speech'' and combines parts of speech +into larger and larger phrases as much as possible according to a special +grammar that is explained in the documentation of \.{CWEAVE}. It is easy to +learn the translation scheme for simple constructions like single +identifiers and short expressions, just by looking at a few examples of +what \.{CWEAVE} does, but the general mechanism is somewhat complex because +it must handle much more than \CEE/ itself. Furthermore the output +contains embedded codes that cause \TEX/ to indent and break lines as +necessary, depending on the fonts used and the desired page width. For +best results it is wise to avoid enclosing long \CEE/ texts in \pb, since the +indentation and line breaking codes are omitted when the \pb\ text is +translated from \CEE/ to \TEX/. Stick to simple expressions or +statements. If a \CEE/ preprocessor command is enclosed in \pb, +the \.\# that introduces it must be at the beginning of a line, +or \.{CWEAVE} won't print it correctly. + +5. Comments are not permitted in \pb\ text. After a `\.|' +signals the change from \TEX/ text to \CEE/ text, the next `\.|' that is +not part of a string or control text or section name ends the \CEE/ text. + +6. A comment must have properly nested occurrences of left and right +braces, otherwise \.{CWEAVE} will complain. But it +does try to balance the braces, so that \TEX/ won't foul up too much. + +7. When you're debugging a program and decide to omit some of your +\CEE/ code, do NOT simply ``comment it out.'' Such comments are not +in the spirit of \.{CWEB} documentation; they will appear to readers +as if they were explanations of the uncommented-out instructions. +Furthermore, comments of a program must be valid \TEX/ text; hence +\.{CWEAVE} will get confused if you enclose \CEE/ statements in +\.{/*...*/} instead of in \.{/*|...|*/}. If you must comment out +\CEE/ code, you can surround it with preprocessor commands +like \.{\#if 0==1} and \.{\#endif}. + +8. The \.{@f} feature allows you to define one identifier to act like +another, and these format definitions are carried out sequentially. +In general, a given identifier has only one printed format +throughout the entire document, and this format is used even before +the \.{@f} that defines it. The reason is that \.{CWEAVE} operates in two +passes; it processes \.{@f}'s and cross-references on the first pass and +it does the output on the second. (However, identifiers that +implicitly get a boldface format, thanks to a \.{typedef} declaration, +don't obey this rule; they are printed differently before and after +the relevant \.{typedef}. This is unfortunate, but hard to fix. You can +get around the restriction by saying, say, `\.{@s} \.{foo} \.{int}', +before or after the \.{typedef}.) + +9. Sometimes it is desirable to insert spacing into formatted \CEE/ code that +is more general than the thin space provided by `\.{@,}'. The \.{@t} feature +can be used for this purpose; e.g., `\.{@t\\hskip 1in@>}' will +leave one inch of blank space. Furthermore, `\.{@t\\4@>}' can be +used to backspace by one unit of indentation, since the control sequence +\.{\\4} is defined in \.{cwebmac} to be such a backspace. (This +control sequence is used, for example, at the beginning of lines that +contain labeled statements, so that the label will stick out a little at +the left.) You can also use `\.{@t\}\\3\{-5@>}' to force a break +in the middle of an expression. + +10. Each identifier in \.{CWEB} has a single formatting convention. Therefore +you shouldn't use the same identifier to denote, say, both a type name and +part of a \.{struct}, even though \CEE/ does allow this. + +\section Running the programs. +The \UNIX/ command line for \.{CTANGLE} is +$$\.{ctangle [options] web\_file[.w] [\{change\_file[.ch]|-\} [out\_file]]}$$ +and the same conventions apply to \.{CWEAVE}. If `\.-' or no change file is +specified, the change file is null. The extensions \.{.w} and \.{.ch} +are appended only if the given file names contain no dot. If the +web file defined in this way cannot be found, the extension \.{.web} +will be tried. For example, `\.{cweave} \.{cob}' will try to read +\.{cob.w}; failing that, it will try \.{cob.web} before giving up. +If no output file name is specified, the name of the \CEE/ file output by +\.{CTANGLE} is obtained by appending the extension \.{.c}; +the name of the \TEX/ file output by \.{CWEAVE} gets the extension \.{.tex}. +Index files output by \.{CWEAVE} replace \.{.tex} by \.{.idx} and \.{.scn}. + +Programmers who like terseness might choose to set up their + operating shell so that `\.{wv}' expands to +`\.{cweave -bhp}'; this will suppress most terminal output from \.{CWEAVE} +except for error messages. + +Options are introduced either by a \.- sign, to turn an option off, +or by a \.+ sign to turn one on. For example, `\.{-fb}' turns off +options \.f and \.b; `\.{+s}' turns on option \.s. Options can be +specified before the file names, after the file names, or both. The following +options are currently implemented: + +\yskip +\def\option#1 {\textindent{\.#1}\hangindent2\parindent} + +\option b Print a banner line at the beginning of execution. (On +by default.) + +\option e Enclose \CEE/ material formatted by \.{CWEAVE} in +brackets \.{\\PB\{...\}}, so that special hooks can be used. +(Off by default; has no effect on \.{CTANGLE}.) + +\option f Force line breaks after each \CEE/ statement formatted +by \.{CWEAVE}. (On by default; \.{-f} saves paper but looks less \CEE/-like +to some people.) (Has no effect on \.{CTANGLE}.) + +\option h Print a happy message at the conclusion of a successful +run. (On by default.) + +\option p Give progress reports as the program runs. (On by default.) + +\option s Show statistics about memory usage after the program +runs to completion. (Off by default.) +If you +have large \.{CWEB} files or sections, you may need to see +how close you come to exceeding the capacity of \.{CTANGLE} and/or \.{CWEAVE}. + +\option x Include indexes and a table of contents in the \TEX/ file +output by \.{CWEAVE}. (On by default.) (Has no effect on \.{CTANGLE}.) + +\section Further details about formatting. +You may not like the way \.{CWEAVE} handles certain +situations. If you're desperate, you can customize \.{CWEAVE} +by changing its grammar. This means changing the source code, +a task that you might find amusing. A table of grammar rules +appears in the \.{CWEAVE} source listing, and you can make a separate +copy of that table by copying the file \.{prod.w} found in the \.{CWEB} +sources and saying `\.{cweave}~\.{-x}~\.{prod}', followed by +`\.{tex}~\.{prod}'. + +You can see exactly +how \.{CWEAVE} is parsing your \CEE/ code by preceding +it with the line `\.{@ @c @2}'. (The control code `\.{@2}' +turns on a ``peeping'' mode, and `\.{@0}' turns it off.) +For example, if you run \.{CWEAVE} on the file +\medskip +\begingroup +\verbatim +@ @c @2 +main (argc,argv) +char **argv; +{ for (;argc>0;argc--) printf("%s\n",argv[argc-1]); } +!endgroup +\endgroup +\medskip\noindent +you get the following gibberish on your screen: +\medskip +\begingroup +\verbatim +[...] +14:*exp +(+ exp... +11:*exp +exp+ raw... +10:*+exp+ raw +ubinop?+... +[...] +60: +fn_decl+*+{+ -stmt- +}- +55:*+fn_decl+ -stmt- +52:*+function- +[...] +!endgroup +\endgroup +\medskip +The first line says that grammar rule 14 has just been applied, and \.{CWEAVE} +currently has in its memory a sequence of chunks of \TEX/ code (called +``scraps'') that are respectively +of type \\{exp} (for expression), open-parenthesis, +\\{exp} again, close-parenthesis, and further scraps that haven't yet +been considered by the parser. (The \.+ and \.- signs stipulate that +\TEX/ should be in or out of math mode at the scrap boundaries. The \.* shows +the parser's current position.) +Then rule 11 is applied, and +the sequence $(\,exp\,)$ becomes an \\{exp} and so on. In the +end the whole \CEE/ text has become one big scrap of type \\{function}. + +Sometimes things don't work as smoothly, and you get a bunch of +lines lumped together. This means that \.{CWEAVE} could not +digest something in your \CEE/ code. For instance, suppose +`\.{@}' had appeared instead of +`\.{char **argv;}' in the program above. Then \.{CWEAVE} would have +been somewhat mystified, since it thinks that section names +are just \\{exp}s. Thus it would tell \TEX/ to format +`\X2:Argument declarations\X' on the same line as +`$\\{main}(\\{argc},\39\\{argv}{}$)'. +In this case you should help \.{CWEAVE} by putting `\.{@/}' after +`\.{main(argc,argv)}'. + +\.{CWEAVE} automatically inserts a bit of extra space between declarations +and the first apparent statement of a block. One way to defeat this +spacing locally is +$$\vbox{\halign{#\hfil\cr +\.{int x;@+@t\}\\6\{@>}\cr +\.{@@;@\#}\cr}}$$ +the `\.{@\#}' will put extra space after `$\langle\,$Other locals$\,\rangle$'. + +\section Hypertext and hyperdocumentation. + +Many people have of course noticed analogies between \.{CWEB} and the +World Wide Web. The \.{CWEB} macros are in fact set up so that the output of +\.{CWEAVE} can be converted easily into Portable Document Format, +with clickable hyperlinks that can be read with Adobe's Acrobat Reader, +using a widely available open-source program called \.{dvipdfm} developed +by Mark~A. Wicks. After using \.{CWEAVE} to convert \.{cob.w} into +\.{cob.tex}, you can prepare and view a hypertext version of the program +by giving the commands +$$\vbox{\halign{\.{#}\hfil\cr +tex "\\let\\pdf+ \\input cob"\cr +dvipdfm cob\cr +acroread cob.pdf\cr}}$$ +instead of invoking \TeX\ in the normal way. (Thanks to Hans Hagen, +C\'esar Augusto Rorato Crusius, and Julian Gilbey +for the macros that make this work.) +Alternatively, thanks to H\`an Th\^e\kern-.3em\raise.3ex\hbox{\'{}} Th\`anh +and Andreas Scherer, you can generate \.{cob.pdf} in one step by simply +saying `\.{pdftex}~\.{cob}'. + +A more elaborate system called \.{CTWILL}, which extends the usual cross +references of \.{CWEAVE} by preparing links from the uses of identifiers +to their definitions, is also available---provided that you are willing +to work a bit harder in cases where an identifier is multiply defined. +\.{CTWILL} is intended primarily for hardcopy output, but its principles +could be used for hypertext as well. +See Chapter 11 of {\sl Digital Typography\/} by D.~E. Knuth (1999), and +the program sources at \.{ftp://ftp.cs.stanford.edu/pub/ctwill}. + +\section Appendices. + +As an example of a real program written in \.{CWEB}, Appendix~A +contains an excerpt from the \.{CWEB} program itself. The reader who +examines the listings in this appendix carefully will get a good +feeling for the basic ideas of \.{CWEB}. + +Appendix B is the file that sets \TEX/ up to accept +the output of \.{CWEAVE}, and Appendix~C discusses how to use some of those +macros to vary the output formats. + +A ``long'' version of this manual, which can be produced from the \.{CWEB} +sources via the \UNIX/ command \.{make} \.{fullmanual}, also contains +appendices D, E, and~F, which exhibit the complete source code for +\.{CTANGLE} and \.{CWEAVE}. + +\vfil\eject\titletrue + +\def\runninghead{APPENDIX A --- {\tentt CWEB} FILE FORMAT} +\section Appendix A: Excerpts from a \.{CWEB} Program. + +This appendix consists +of four listings. The first shows the \.{CWEB} input that +generated sections 12--15 of the file \.{common.w}, which contains +routines common to \.{CWEAVE} and \.{CTANGLE}. +Note that some of the lines are indented to show the program structure; +the indentation is ignored by \.{CWEAVE} and \.{CTANGLE}, but users find +that \.{CWEB} files are quite readable if they have some such indentation. + +The second and third listings +show corresponding parts +of the \CEE/ code output by \.{CTANGLE} and of +the corresponding \TEX/ code output by \.{CWEAVE}, when run on \.{common.w}. +The fourth listing shows how that output looks when printed out. + +\vskip 6pt +\begingroup \def\tt{\eighttt} \baselineskip9pt +\verbatim +@ 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 */ + @; + @; + @; +} + +@ 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). + +@= +while(1) { + change_line++; + if (!!input_ln(change_file)) return; + if (limit + } +} + +@ Here we are looking at lines following the \.{@@x}. + +@= +do { + change_line++; + if (!!input_ln(change_file)) { + err_print("!! Change file ended after @@x"); +@.Change file ended...@> + return; + } +} while (limit==buffer); + +@ @= +{ + change_limit=change_buffer-buffer+limit; + strncpy(change_buffer,buffer,limit-buffer+1); +} + +!endgroup +\endgroup +\vfill\eject + +\def\runninghead{APPENDIX A --- TRANSLATION BY {\tentt CTANGLE}} + +Here's the portion of the \CEE/ code generated by \.{CTANGLE} that corresponds +to the source on the preceding page. Notice that sections~13, 14 and~15 +have been tangled into section~12. + +\vskip6pt +\begingroup \def\tt{\eighttt} \baselineskip9pt +\verbatim +/*:9*//*12:*/ +#line 247 "common.w" + +void +prime_the_change_buffer() +{ +change_limit= change_buffer; +/*13:*/ +#line 261 "common.w" + +while(1){ +change_line++; +if(!!input_ln(change_file))return; +if(limit}', the backslash character gets in the way, +and this entry wouldn't appear in the index with the T's. + +The solution is to use the `\.{@:}' feature, declaring a macro that +simply removes a sort key as follows: +$$\.{\\def\\9\#1\{\}}$$ +Now you can say, e.g., `\.{@:TeX\}\{\\TeX@>}' in your \.{CWEB} file; \.{CWEAVE} +puts it into the index alphabetically, based on the sort key, and +produces the macro call `\.{\\9\{TeX\}\{\\TeX\}}' which will ensure that +the sort key isn't printed. + +A similar idea can be used to insert hidden material into section +names so that they are alphabetized in whatever way you might wish. +Some people call these tricks ``special refinements''; others call +them ``kludges.'' + +\point 12. The control sequence \.{\\secno} is set to the number of the +section being typeset. + +\point 13. If you want to list only the sections that have changed, +together with the index, put the command `\.{\\let\\maybe=\\iffalse}' in +the limbo section before the first section of your \.{CWEB} file. It's +customary to make this the first change in your change file. + +This feature has a \TeX nical limitation, however: You cannot use it +together with control sequences like \.{\\proclaim} or \.{\\+} or +\.{\\newcount} that plain \TeX\ has declared to be `\.{\\outer}', +because \TeX\ refuses to skip silently over such control sequences. +One way to work around this limitation is to say +$$\.{\\fi \\let\\proclaim\\relax \\def\\proclaim\{...\} \\ifon}$$ +where \.{\\proclaim} is redefined to be the same as usual but without +an \.{\\outer} qualification. (The \.{\\fi} here stops the conditional +skipping, and the \.{\\ifon} turns it back on again.) Similarly, +$$\.{\\fi \\newcount\\n \\ifon}$$ +is a safe way to use \.{\\newcount}. Plain \TeX\ already provides a +non-outer macro \.{\\tabalign} that does the work of \.{\\+}; you can say +$$\postdisplaypenalty=10000 +\.{\\fi \\let\\+\\tabalign \\ifon}$$ +if you prefer the shorter notation \.{\\+}. + +\point 14. To get output in languages other than English, redefine the +macros \.{\\A}, \.{\\As}, \.{\\ATH}, +\.{\\ET}, \.{\\ETs}, \.{\\Q}, \.{\\Qs}, \.{\\U}, +\.{\\Us}, \.{\\ch}, \.{\\fin}, \.{\\con}, \.{\\today}, \.{\\datethis}, and +\.{\\datecontentspage}. \.{CWEAVE} itself need not be changed. + +\point 15. Some output can be selectively suppressed with the macros +\.{\\noatl}, \.{\\noinx}, \.{\\nosecs}, \.{\\nocon}. + +\point 16. All accents and special text symbols of plain \TEX/ format +will work in \.{CWEB} documents just as they are described in +Chapter~9 of {\sl The \TEX/book}, with one exception. +The dot accent (normally \.{\\.}) must be typed \.{\\:} instead. + +\point 17. Several commented-out lines in \.{cwebmac.tex} are suggestions +that users may wish to adopt. For example, one such line inserts a blank page +if you have a duplex printer. Appendices D, E, and F of the complete +version of this manual are printed using a commented-out option that +substitutes `$\gets$' for `$=$' in the program listings. Looking at those +appendices might help you decide which format you like better. + +\point 18. Andreas Scherer has contributed a macro called \.{\\pdfURL} +with which one can say things like the following, anywhere in the \TeX\ parts +or the \CEE/ comments of a \.{CWEB} file: +$$\vbox{\halign{\.{#}\hfil\cr +You can send email to + \\pdfURL\{the author\}\{mailto:andreas.scherer@@pobox.com\}\cr +or visit \\pdfURL\{his home page\}\{http://www.pobox.com/% + \\TILDE/scherer\}.\cr}}$$ +In a {\mc PDF} document, the first argument will appear in blue as +clickable text; the Acrobat reader, if correctly configured, will then +redirect those links to the user's browser and open either the +email client or the HTML viewer. In a hardcopy document, both arguments +will be printed ({\tt the second in parentheses and typewriter type}). +Certain special characters in an Internet address need to be handled +in a somewhat awkward way, so that \.{CWEAVE} and/or \TeX\ +will not confuse them with formatting controls: Use \.{@@} for \.@ +and \.{\\TILDE/} for \.\~ and \.{\\UNDER/} for \.\_. + +\point 19. {\mc PDF} documents contain bookmarks that list all the major group +titles in the table of contents, some of which will be subsidiary to +others if the depth feature of \.{@*} has been used. +Such bookmark entries are also known as ``outlines.'' +Moreover, the final group title, `Names of the sections', +can be opened up to list every section name; Acrobat users can therefore +navigate easily to any desired section. + +The macros of \.{cwebmac.tex} are careful to ``sanitize'' all the names +that appear as bookmarks, by removing special characters and +formatting codes that are inappropriate for the limited typographic +capabilities of {\mc PDF} outlines. For example, one section of \.{CWEAVE} +is named `Cases for \\{case\_like}', which is represented by the \TeX\ code +`\.{Cases} \.{for} \.{\\PB\{\\\\\{case\\\_like\}\}}' in \.{cweave.tex}; its +sanitized name is simply `\.{Cases} \.{for} \.{case\_like}'. +(When \.{.pdf} files are produced, the fifth parameter of every \.{\\ZZ} in +the \.{.toc} file is set to the sanitized form of the first parameter; +see point~9 above and point~20 below.) + +In general, sanitization removes \TeX\ control sequences and braces, +except for control sequences defined by \.{CWEB} itself. Such a translation +works most of the time, but you can override the defaults and obtain any +translation that you want by using \TeX nical tricks. For example, after +$$\.{\\sanitizecommand\\foo\{bar\}}$$ +the control sequence \.{\\foo} will sanitize to `\.{bar}'. And after +$$\.{\\def\\kluj\#1\\\\\{foo\}}$$ +the \TeX\ code `\.{\\kluj bar\\\\}' will print as `foo' but sanitize +to `\.{bar}', because the control sequences \.{\\kluj} and +\.{\\\\} are removed by sanitization. + +\point 20. Furthermore, group titles can be converted to an arbitrary +sanitized text while also changing their form in running headlines, by +using \.{\\ifheader}. Consider, for example, a \.{CWEB} source file that +begins with the two lines +$$\lpile{\.{\\def\\klujj\#1\\\\\{\\ifheader FOO\\else foo\\fi\}}\cr +\.{@*Chinese \\klujj bar\\.}\cr}$$ +This coding introduces a major group entitled `{\bf Chinese foo}', with +running headline `{\eightrm CHINESE FOO}' and table-of-contents entry +`Chinese foo'. The corresponding bookmark is, however, `\.{Chinese} \.{bar}'. +And the corresponding \.{.toc} file entry is +`\.{\\ZZ \{Chinese \\klujj bar\\\\\}\{1\}\{1\}\{1\}\{Chinese bar\}}'. + +\vfill\end + diff --git a/web/c_cpp/cweb/makefile.bs b/web/c_cpp/cweb/makefile.bs new file mode 100644 index 0000000000..5e97012804 --- /dev/null +++ b/web/c_cpp/cweb/makefile.bs @@ -0,0 +1,60 @@ +# Makefile for CTANGLE and CWEAVE, pc/big versions, using +# Borland C++ 3.1 and Borland Make. +# +# (This file contributed by Barry Schwartz, trashman@crud.mn.org, +# 24 Jul 94.) + + + +CC = bcc + +# Redundant Load Suppression (-Z) is turned off, because it seems to +# break the code. Likewise for Copy Propagation (-Op). (These +# optimizations don't seem to cause any problems in common.w, but +# better safe than sorry--compile everything with them turned off.) +OPT = -O2-p -Z- + +# Compile with symbols. That way you'll be able to use the debugger if +# you run into trouble. You can always use tdstrip later, to remove the +# symbols. +DEBUG = -v + +LCFLAGS = -mc -Ff=5000 -d -w-pro $(DEBUG) +CFLAGS = $(LCFLAGS) $(OPT) +COMPILE = $(CC) $(CFLAGS) + +LINK = $(CC) $(LCFLAGS) -e + + + +# Where to find an "old" version of ctangle, for bootstrapping. The first +# time you make ctangle, you may have to edit the distributed ctangle.c +# and/or common.c by hand to reduce the size of one or more arrays. +# This will give you a functional ctangle.exe, which you can use to bootstrap +# the "real" ctangle.exe. +CTANGLE = ctangle + + + + +all default: ctangle.exe cweave.exe + + +ctangle.exe: ctangle.obj common.obj + $(LINK)$* $** + +cweave.exe: cweave.obj common.obj + $(LINK)$* $** + + +common.obj: common.w comm-bs.ch + $(CTANGLE) common.w comm-bs.ch + $(COMPILE) -c common.c + +ctangle.obj: ctangle.w common.h ctang-bs.ch + $(CTANGLE) ctangle.w ctang-bs.ch + $(COMPILE) -c ctangle.c + +cweave.obj: cweave.w common.h cweav-bs.ch + $(CTANGLE) cweave.w cweav-bs.ch + $(COMPILE) -c cweave.c diff --git a/web/c_cpp/cweb/prod.w b/web/c_cpp/cweb/prod.w new file mode 100644 index 0000000000..5f76a19379 --- /dev/null +++ b/web/c_cpp/cweb/prod.w @@ -0,0 +1,307 @@ +% 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.6 --- May 2000 +% +@ Here is a table of all the productions. 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\$\$}. + +% The following kludge is needed because \newcount, \newdimen, and \+ +% are "\outer" control sequences that cannot be used in skipped text! +\fi \newcount\prodno \newdimen\midcol \let\+\relax \ifon + +\def\v{\char'174} +\mathchardef\RA="3221 % right arrow +\mathchardef\BA="3224 % double arrow + +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\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 +\prodno=0 \midcol=2.5in +\def\theprodno{\number\prodno \global\advance\prodno by1\enspace} +\def\dagit{\dag\theprodno} +\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| |ubinop| |exp| & |exp| & \malt {|x/y|} {|x+y|} \cr +\+& |exp| |comma| |exp| & |exp| \hfill $EC\,|opt|9\,E$& |f(x,y)|\cr +\+& |exp| \alt {|lpar| |rpar|} |cast| |colon| & + |exp| \alt {|lpar| |rpar|} |cast| |base| & + \malt \&C|()|: {\&C|int i)|:} \cr +\+& |exp| |semi| & |stmt| & |x=0;|\cr +\+& |exp| |colon| & |tag| \hfill $E^*C$ & |found:|\cr +\+& |exp| |rbrace| & |stmt| |rbrace| & end of \&{enum} list\cr +\+& |exp| \alt {|lpar| |rpar|} |cast| \alt|const_like| |case_like| & + |exp| \alt {|lpar| |rpar|} |cast| \hfill + \alt $R=R\.\ C$ $C_1=C_1\.\ C_2$ & + \malt {|f() const|} {|f(int) throw|} \cr +\+& |exp| \alt |exp| |cast| & |exp| & |time()|\cr +\+& |lpar| \alt |exp| |ubinop| |rpar| & |exp| & \malt{|(x)|} {|(*)|} \cr +\+& |lpar| |rpar| & |exp| \hfill $L\.{\\,}R$ & functions, declarations\cr +\+& |lpar| \altt |decl_head| |int_like| |cast| |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\.\ $} & + \malt {|(k=5;|} {|(int k=5;|} \cr +\+& |unop| \alt |exp| |int_like| & |exp| & + \malt |!x| |~|\&C \cr +\+& |ubinop| |cast| |rpar| & |cast| |rpar| \hfill + $C=\.\{U\.\}C$ & |*|\&{CPtr}) \cr +\+& |ubinop| \alt|exp| |int_like| & \alt|exp| |int_like| \hfill + \.\{$U$\.\}\alt$E$ $I$ & \malt |*x| |*|\&{CPtr} \cr +\+& |ubinop| |binop| & |binop| \hfill $|math_rel|\,U\.\{B\.\}\.\}$ & |*=|\cr +\+& |binop| |binop| & |binop| \hfill + $|math_rel|\,\.\{B_1\.\}\.\{B_2\.\}\.\}$ & |>>=|\cr +\+& |cast| \alt |lpar| |exp| & \alt |lpar| |exp| \hfill + \alt $CL$ $C\.\ E$ & \malt |(double)(x+2)| |(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|raw_int| |struct_like| & |extern "Ada" int|\cr +\+& |int_like| \altt|exp| |ubinop| |colon| & + |decl_head| \altt|exp| |ubinop| |colon| \hfill + $D=I$\.\ & \maltt|int x| |int*x| |unsigned:| \cr +\+& |int_like| \alt |semi| |binop| & |decl_head| \alt |semi| |binop| & + \malt |int x;| {\&{int} $f(\&{int}=4)$} \cr +\+& |public_like| |colon| & |tag| & \&{private}:\cr +\+& |public_like| & |int_like| & \&{private}\cr +\+& |colcol| \alt|exp| |int_like| & \alt|exp| |int_like| \hfill + |qualifier| $C$ \alt$E$ $I$ & \&C\DC$x$\cr +\+& |colcol| |colcol| & |colcol| & \&C\DC\&B\DC\cr +\+& |decl_head| |comma| & |decl_head| \hfill $DC\.\ $ & |int x,|\cr +\+& |decl_head| |ubinop| & |decl_head| \hfill $D\.\{U\.\}$ & |int *|\cr +\+\dagit& |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$ & \malt {\&{int} $f(\&{int}\ x=2)$} |int b:1| \cr +\+& |decl_head| |cast| & |decl_head| & |int f(int)|\cr +\+& |decl_head| \altt|int_like| |lbrace| |decl| & |fn_decl| + \altt|int_like| |lbrace| |decl| \hfill $F=D\,|in|\,|in|$ + & |long time () {|\cr +\+& |decl_head| |semi| & |decl| & |int n;|\cr +\+& |decl| |decl| & |decl| \hfill $D_1\,|force|\,D_2$ & |int n;double x;|\cr +\+& |decl| \alt|stmt| |function| & \alt|stmt| |function| + \hfill $D\,|big_force|\,$\alt $S$ $F$ \unskip& \&{extern} $n$; + \\{main} ()|{}|\cr +\+& |base| \alt |int_like| |exp| |comma| & |base| \hfill + $B$\.\ \alt $I$ $E$ \unskip$C$\,|opt|9 + & \malt {: \&{public} \&A,} {: $i(5)$,} \cr +\+& |base| \alt |int_like| |exp| |lbrace| & |lbrace| \hfill + $B$\.\ \alt $I$ $E$ \unskip\.\ $L$ & \&D : \&{public} \&A $\{$\cr +\+& |struct_like| |lbrace| & |struct_head| \hfill $S\.\ L$ & |struct {|\cr +\+& |struct_like| \alt|exp| |int_like| |semi| & |decl_head| |semi| + \hfill $S\.\ $\alt $E^{**}$ $I^{**}$ & \&{struct} \&{forward};\cr +\+& |struct_like| \alt|exp| |int_like| |lbrace| & |struct_head| \hfill + $S\.\ $\alt $E^{**}$ $I^{**}$ \unskip $\.\ L$ & + \&{struct} \&{name\_info} $\{$\cr +\+& |struct_like| \alt|exp| |int_like| |colon| & + |struct_like| \alt|exp| |int_like| |base| & |class| \&C :\cr +\+\dagit& |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 + $S\,\\{in}\,|force|$\altt$D$ $S$ $F$ $\\{out}\,|force|\,R$ & + |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\midcol35pt +\+& |lbrace| \altt|stmt| |decl| |function| |rbrace| & |stmt| \hfill + $|force|\,L\,\\{in}\,|force|\,S\, + |force|\,\\{back}\,R\,\\{out}\,|force|$ & compound statement\cr +\advance\midcol-20pt +\+& |lbrace| |exp| [|comma|] |rbrace| & |exp| & initializer\cr +\+& |if_like| |exp| & |if_clause| \hfill $I\.{\ }E$ & |if (z)|\cr +\+& |else_like| |colon| & |else_like| |base| & \&{try} :\cr +\+& |else_like| |lbrace| & |else_head| |lbrace| & \&{else} $\{$\cr +\+& |else_like| |stmt| & |stmt| \hfill + $|force|\,E\,\\{in}\,\\{bsp}\,S\,\\{out}\,|force|$ & |else x=0;|\cr +\+& |else_head| \alt|stmt| |exp| & |stmt| \hfill + $|force|\,E\,\\{bsp}\,|noop|\,|cancel|\,S\,\\{bsp}$ & |else{x=0;}|\cr +\+& |if_clause| |lbrace| & |if_head| |lbrace| & |if (x) {|\cr +\+& |if_clause| |stmt| |else_like| |if_like| & |if_like| \hfill + $|force|\,I\,\\{in}\,\\{bsp}\,S\,\\{out}\,|force|\,E\,\.\ I$ & + |if (x) y; else if|\cr +\+& |if_clause| |stmt| |else_like| & |else_like| \hfill + $|force|\,I\,\\{in}\,\\{bsp}\,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}\,|noop|\,|cancel|\,S\,|force|\,E\,\.\ I$ & + |if (x){y;}else if|\cr +\+& |if_head| \alt|stmt| |exp| |else_like| & |else_like| \hfill + $|force|\,I\,\\{bsp}\,|noop|\,|cancel|\,S\,|force|\,E$ & + |if (x){y;}else|\cr +\+& |if_head| \alt|stmt| |exp| & |else_head| \alt|stmt| |exp| & |if (x){y;}|\cr +\advance\midcol20pt +\+& |do_like| |stmt| |else_like| |semi| & |stmt| \hfill + $D\,\\{bsp}\,|noop|\,|cancel|\,S\,|cancel|\,|noop|\,\\{bsp}\,ES$% + & |do f(x); while (g(x));|\cr +\advance\midcol-20pt +\+& |case_like| |semi| & |stmt| & |return;|\cr +\+& |case_like| |colon| & |tag| & |default:|\cr +\+& |case_like| |exp| & |exp| \hfill $C\.\ E$ & |return 0|\cr +\+& |catch_like| \alt|cast| |exp| & |fn_decl| \hfill + $C$\alt $C$ $E$ \\{in}\,\\{in} & |catch (...)|\cr +\+& |tag| |tag| & |tag| \hfill $T_1\,\\{bsp}\,T_2$ & |case 0: case 1:|\cr +\+& |tag| \altt|stmt| |decl| |function| & \altt|stmt| |decl| |function| + \hfill $|force|\,\\{back}\,T\,\\{bsp}\,S$ & |case 0: z=0;|\cr +\+\dagit& |stmt| \altt|stmt| |decl| |function| & + \altt|stmt| |decl| |function| + \hfill $S\,$\altt$|force|\,S$ $|big_force|\,D$ $|big_force|\,F$ & + |x=1;y=2;|\cr +\+& |semi| & |stmt| \hfill \.\ $S$& empty statement\cr +\+\dagit& |lproc| \altt |if_like| |else_like| |define_like| & |lproc| & + \maltt {{\bf \#include}} {\bf\#else} {\bf\#define} \cr +\+& |lproc| |rproc| & |insert| & {\bf\#endif} \cr +\+& |lproc| \alt {|exp| [|exp|]} |function| |rproc| & |insert| \hfill + $I$\.\ \alt {$E{[\.{\ \\5}E]}$} {$F$} & + \malt{{\bf\#define} $a$\enspace 1} {{\bf\#define} $a$\enspace$\{\,b;\,\}$} \cr +\+& |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| |prerangle| & |cast| \hfill $L\.{\\,}P$ & $\langle\,\rangle$\cr +\+& |langle| \altt|decl_head| |int_like| |exp| |prerangle| & |cast| & + $\langle\&{class}\,\&C\rangle$\cr +\+& |langle| \altt|decl_head| |int_like| |exp| |comma| & |langle| \hfill + $L$\,\altt $D$ $I$ $E$ $C$\,|opt|9 & $\langle\&{class}\,\&C,$\cr +\+& |template_like| |exp| |prelangle| & |template_like| |exp| |langle| & + \&{template} $a\langle100\rangle$\cr +\+& |template_like| \alt|exp| |raw_int| & \alt|exp| |raw_int| \hfill + $T$\.\ \alt$E$ $R$ & \&C\DC\&{template} |a()|\cr +\+& |template_like| & |raw_int| & \&{template}$\langle\&{class}\,\&T\rangle$\cr +\+& |new_like| |lpar| |exp| |rpar| & |new_like| & \&{new}(\\{nothrow})\cr +\+& |new_like| |cast| & |exp| \hfill $N\.\ C$ & |new(int*)|\cr +\+\dagit& |new_like| & |new_exp| & \&{new} \&C|()|\cr +\+& |new_exp| \alt|int_like| |const_like| & |new_exp| \hfill + $N$\.\ \alt $I$ $C$ & |new const int|\cr +\+& |new_exp| |struct_like| \alt |exp| |int_like| & |new_exp| \hfill + $N\.\ S$\.\ \alt $E$ $I$ & \&{new} \&{struct} \&S\cr +\+& |new_exp| |raw_ubin| & |new_exp| \hfill $N\.\{R\.\}$ & |new int*[2]|\cr +\+& |new_exp| \alt |lpar| |exp| & |exp| \alt |lpar| |exp| \hfill + $E=N$\,\alt {} {\.\ } & \malt |operator[](int)| {|new int(2)|} \cr +\+\dagit& |new_exp| & |exp| & |new int;|\cr +\+& |ftemplate| |prelangle| & |ftemplate| |langle| & |make_pair|\cr +\+& |ftemplate| & |exp| & |make_pair(1,2)|\cr +\+& |for_like| |exp| & |else_like| \hfill $F\.\ E$ & |while (1)|\cr +\+& |raw_ubin| |const_like| & |raw_ubin| \hfill $RC$\.{\\\ } + & $*$\&{const} |x|\cr +\+& |raw_ubin| & |ubinop| & $*$ |x|\cr +\+& |const_like| & |int_like| & \&{const} |x|\cr +\+& |raw_int| |prelangle| & |raw_int| |langle| & \&C$\langle$\cr +\+& |raw_int| |colcol| & |colcol| & \&C\DC\cr +\+& |raw_int| |cast| & |raw_int| & \&C$\langle\&{class}\ \&T\rangle$\cr +\+& |raw_int| |lpar| & |exp| |lpar| & \&{complex}$(x,y)$\cr +\+\dagit& |raw_int| & |int_like| & \&{complex} |z|\cr +\+\dagit& |operator_like| \altt|binop| |unop| |ubinop| & |exp| + \hfill $O$\.\{\altt $B$ $U$ $U$ \unskip\.\} & |operator+|\cr +\+& |operator_like| \alt|new_like| |delete_like| & |exp| \hfill + $O$\.\ \alt $N$ $S$ & |operator delete|\cr +\+& |operator_like| |comma| & |exp| & \&{operator},\cr +\+\dagit& |operator_like| & |new_exp| & |operator char*|\cr +\advance\midcol-8pt +\+& |typedef_like| \alt|int_like| |cast| \alt|comma| |semi| & + |typedef_like| |exp| \alt|comma| |semi| & \&{typedef} \&{int} \&I,\cr +\advance\midcol+8pt +\+& |typedef_like| |int_like| & |typedef_like| \hfill $T\.\ I$ & + \&{typedef} \&{char}\cr +\+\dagit& |typedef_like| |exp| & |typedef_like| \hfill $T\.\ E^{**}$ & + \&{typedef} \&I \.{@@[@@]} (|*|\&P)\cr +\+& |typedef_like| |comma| & |typedef_like| \hfill $TC\.\ $ & + \&{typedef} \&{int} \&x,\cr +\+& |typedef_like| |semi| & |decl| & \&{typedef} \&{int} $\&x,\&y$;\cr +\+& |typedef_like| |ubinop| \alt |cast| |ubinop| & + |typedef_like| \alt |cast| |ubinop| \hfill + \alt $C=\.\{U\.\}C$ $U_2=\.\{U_1\.\}U_2$ \unskip & + \&{typedef} |*|{}|*|(\&{CPtr})\cr +\+& |delete_like| |lpar| |rpar| & |delete_like|\hfill $DL\.{\\,}R$ & + \&{delete}|[]| \cr +\+& |delete_like| |exp| & |exp| \hfill $D\.\ E$ & |delete p| \cr +\+\dagit& |question| |exp| \alt |colon| |base| & |binop| & + \malt |?x:| |?f():| \cr +\+& |begin_arg| |end_arg| & |exp| & \.{@@[}\&{char}$*$\.{@@]}\cr +\+& |any_other| |end_arg| & |end_arg| & \&{char}$*$\.{@@]}\cr +\yskip +\yskip +\yskip +\parindent=0pt +\dag{\bf Notes} +\yskip +Rule 35: The |exp| must not be immediately followed by |lpar|, |exp|, + or~|cast|. + +Rule 48: The |exp| or |int_like| must not be immediately followed by |base|. + +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 94: The |new_like| must not be immediately followed by |lpar|. + +Rule 99: The |new_exp| must not be immediately followed by |raw_int|, +|struct_like|, or |colcol|. + +Rule 110: The |raw_int| must not be immediately followed by |langle|. + +Rule 111: The operator after |operator_like| +must not be immediately followed by a |binop|. + +Rule 114: The |operator_like| must not be immediately followed by +|raw_ubin|. + +Rule 117: The |exp| must not be immediately followed by |lpar|, |exp|, +or |cast|. + +Rule 123: The mathness of the |colon| or |base| changes to `yes'. + +\endgroup diff --git a/web/c_cpp/cweb/readme.ql b/web/c_cpp/cweb/readme.ql new file mode 100644 index 0000000000..907d4c3192 --- /dev/null +++ b/web/c_cpp/cweb/readme.ql @@ -0,0 +1,84 @@ +This is the readme file for CWEB for QDOS/SMSQ systems + +(These instructions are for systems with Toolkit II, + please report any problems to me, the address is at the + end of the file) + +If you want to compile CWEB for your QL system, you must first +convert the ASCII code to the QL's character set. Therefore you +can use the little BASIC program appended at the end of the file. + +For a first version you have to alter the supplied ctangle_c file. +Set your DATA_USE to the directory you have the CWEB sources in, and +the PROG_USE to C68's directory. +compile it with: +ex cc;'common_c ctangle_c -bufp500K -octangle' + +then ctangle the source files with: +ex datad$&'ctangle';'common_w comm-ql_ch' +ex datad$&'ctangle';'ctangle_w ctang-ql_ch' +ex datad$&'ctangle';'cweave_w cweav-ql_ch' + +Compile the following way (C68v4.14 +): + +ex cc;'-c common_c' +ex cc;'-c ctangle_c' +ex cc;'-c cweave_c' +ex ld;'-bufp500K common_o ctangle_o -octangle' +ex ld;'-bufp500K common_o cweave_o -ocweave' + +After that copy the ctangle and cweave executables into your +programs directory (if you want them there). + +The DATA default may be used as usual. E.g. if you have +a file win2_data_test_w and the DATA default set to +win2_data_ you may call ctangle with + ex ctangle;'test' +assuming that ctangle is in your PROG default. + +Please report any problems with the QL version to: +Robert Klein +Bluecherstrasse 24 +D-56349 Kaub +Germany + + +**************** ASCII Conversion program *************** +With this program you can convert DOS and Unix 7-Bit ASCII +files to the QL's character set. You'll need Toolkit II. +The program will take all the files in the source directory +and put them converted into the destination&source directory, +e.g. you have as drive1$='win2_', drive2$='win3_', +path1$='cweb_' and path2$='ql_'. Then the routine will take +all files in win2_cweb_ (wthout subdirectories!) convert them +and write them to 'win3_ql_cweb_'. It's only a lousy hack, +but it'll do it's job. + +1000 DEFine PROCedure dos2ql (drive1$,path1$,drive2$,path2$) +1002 LOCal zx$,zx%,ishl,ashl +1005 DELETE drive2$&path2$&'dirlist' +1010 OPEN_NEW#5,drive2$&path2$&'dirlist' +1020 DIR#5,drive1$&path1$ +1030 CLOSE#5 +1040 OPEN_IN#5,drive2$&path2$&'dirlist' +1050 INPUT#5,zx$:INPUT#5,zx$:REMark devicename and sectors +1060 REPeat ashl +1070 IF EOF(#5)THEN EXIT ashl +1080 INPUT#5,zx$ +1085 IF '->' INSTR zx$ THEN NEXT ashl +1090 OPEN_IN#3,drive1$&zx$ +1100 OPEN_NEW#4,drive2$&path2$&zx$ +1110 REPeat ishl +1120 IF EOF(#3)THEN EXIT ishl +1130 BGET#3,zx% +1140 SELect ON zx% +1150 = 13:REMark do nothing (DOS LineFeed) +1155 = 26:REMark do nothing (DOS EOF sign) +1160 = 96: BPUT#4,159:REMark Unix/DOS beginning quote sign +1170 = REMAINDER : BPUT#4,zx% +1180 END SELect +1190 END REPeat ishl +1195 CLOSE#3:CLOSE#4 +1200 END REPeat ashl +1205 CLOSE#5 +1210 END DEFine dos2ql -- cgit v1.2.3